-
-
Save KUKDfhia/850b3462bae3be62909f61460d62ebaa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* プログラム名:neurallearn.c */ | |
/* copyright "© 2017 KUKDfhia." */ | |
/* link "http://qiita.com/KUKDfhia" */ | |
#include<stdio.h> | |
#include<stdlib.h> | |
#include<math.h> | |
#include<time.h> | |
/* パラメータを設定する(今書いてある値は例であるため、好きに設定してよい) */ | |
#define NUM_LEARN 15000 /* 学習回数 */ | |
#define NUM_SAMPLE 10 /* 訓練データ数(今回は10パターン用意する)*/ | |
#define NUM_INPUT 4 /* 入力層の数(7セグメント表示器の入力)*/ | |
#define NUM_HIDDEN_ONE 12 /* 中間層1の数(自由)*/ | |
#define NUM_HIDDEN_TWO 10 /* 中間層2の数(自由)*/ | |
#define NUM_HIDDEN_THREE 8 /* 中間層3の数(自由)*/ | |
#define NUM_OUTPUT 7 /* 出力層の数(7セグメント表示器の出力)*/ | |
#define EPSILON 0.5 /* 学習係数ε */ | |
#define ALPHA 1 /* 慣性係数α ※振動を避けるために設定するものであるが、基本的に1に設定しておけば問題なし */ | |
/* シグモイド関数 */ | |
double sigmoid(double x){ | |
double f; | |
f=1.0/(1.0+exp(-x)); | |
return f; /* 戻り値が関数値 */ | |
} | |
int tx[NUM_SAMPLE][NUM_INPUT],ty[NUM_SAMPLE][NUM_OUTPUT]; /* txが入力、tyが出力 教師データを格納する */ | |
double x[NUM_INPUT+1],h1[NUM_HIDDEN_ONE+1],h2[NUM_HIDDEN_TWO+1],h3[NUM_HIDDEN_THREE+1],y[NUM_OUTPUT]; /* xが入力、h1が中間1、h2が中間2、h3が中間3、yが出力 それぞれニューロンの値。+1は閾値表現用 */ | |
double w1[NUM_INPUT+1][NUM_HIDDEN_ONE],w2[NUM_HIDDEN_ONE+1][NUM_HIDDEN_TWO],w3[NUM_HIDDEN_TWO+1][NUM_HIDDEN_THREE],w4[NUM_HIDDEN_THREE+1][NUM_OUTPUT]; /* w1が入力ー中間1、w2が中間1ー中間2、w3が中間2ー中間3、w4が中間3ー出力の結合荷重の値 */ | |
double h1_back[NUM_HIDDEN_ONE+1],h2_back[NUM_HIDDEN_TWO+1],h3_back[NUM_HIDDEN_THREE+1],y_back[NUM_OUTPUT]; /* h1_backが中間1、h2_backが中間2、h3_backが中間3、y_backが出力の逆伝播量 */ | |
int main(void){ | |
int ilearn,isample,i,j; | |
double net_input,epsilon,alpha; | |
FILE *csv; | |
srand((unsigned)time(NULL)); | |
epsilon=(double)EPSILON; | |
alpha=(double)ALPHA; | |
/* input.csvから入力に用いる教師データを配列txに設定する */ | |
csv=fopen("input.csv", "r"); | |
if(csv==NULL){ | |
printf("ファイルがオープンできません\n"); | |
return -1; | |
} | |
for(i=0;i<NUM_SAMPLE;i++){ | |
for(j=0;j<NUM_INPUT;j++){ | |
if(fscanf(csv,"%d,",&tx[i][j])!='\0'); | |
} | |
} | |
fclose(csv); | |
/* output.csvから出力に用いる教師データを配列tyに設定する */ | |
csv=fopen("output.csv", "r"); | |
if(csv==NULL){ | |
printf("ファイルがオープンできません\n"); | |
return -1; | |
} | |
for(i=0;i<NUM_SAMPLE;i++){ | |
for(j=0;j<NUM_OUTPUT;j++){ | |
if(fscanf(csv,"%d,",&ty[i][j])!='\0'); | |
} | |
} | |
fclose(csv); | |
/* 結合荷重にランダムな初期値を設定(-0.1~0.1の範囲) */ | |
for(i=0;i<NUM_INPUT+1;i++){ | |
for(j=0;j<NUM_HIDDEN_ONE;j++){ | |
w1[i][j]=(double)rand()/RAND_MAX/10.0; | |
if((rand()%100+1)>=51){ | |
w1[i][j]=-w1[i][j]; | |
} | |
} | |
} | |
for(i=0;i<NUM_HIDDEN_ONE+1;i++){ | |
for(j=0;j<NUM_HIDDEN_TWO;j++){ | |
w2[i][j]=(double)rand()/RAND_MAX/10.0; | |
if((rand()%100+1)>=51){ | |
w2[i][j]=-w2[i][j]; | |
} | |
} | |
} | |
for(i=0;i<NUM_HIDDEN_TWO+1;i++){ | |
for(j=0;j<NUM_HIDDEN_THREE;j++){ | |
w3[i][j]=(double)rand()/RAND_MAX/10.0; | |
if((rand()%100+1)>=51){ | |
w3[i][j]=-w3[i][j]; | |
} | |
} | |
} | |
for(i=0;i<NUM_HIDDEN_THREE+1;i++){ | |
for(j=0;j<NUM_OUTPUT;j++){ | |
w4[i][j]=(double)rand()/RAND_MAX/10.0; | |
if((rand()%100+1)>=51){ | |
w4[i][j]=-w4[i][j]; | |
} | |
} | |
} | |
/* 学習の繰り返し */ | |
printf("学習を開始します\n"); | |
for(ilearn=0;ilearn<NUM_LEARN;ilearn++){ | |
/* 訓練データの繰り返し */ | |
for(isample=0;isample<NUM_SAMPLE;isample++){ | |
/* 順方向の動作 */ | |
/* 訓練データに従って、ネットワークへの入力設定 */ | |
for(i=0;i<NUM_INPUT;i++){ | |
x[i]=tx[isample][i]; | |
} | |
/* 閾値設定x */ | |
x[NUM_INPUT]=(double)1.0; | |
/* 隠れ素子1の計算 */ | |
for(j=0;j<NUM_HIDDEN_ONE;j++){ | |
net_input=0; | |
for(i=0;i<NUM_INPUT+1;i++){ | |
net_input=net_input+w1[i][j]*x[i]; | |
} | |
/* シグモイドの適用 */ | |
h1[j]=sigmoid(net_input); | |
} | |
/* 閾値設定h1 */ | |
h1[NUM_HIDDEN_ONE]=(double)1.0; | |
/* 隠れ素子2の計算 */ | |
for(j=0;j<NUM_HIDDEN_TWO;j++){ | |
net_input=0; | |
for(i=0;i<NUM_HIDDEN_ONE+1;i++){ | |
net_input=net_input+w2[i][j]*h1[i]; | |
} | |
/* シグモイドの適用 */ | |
h2[j]=sigmoid(net_input); | |
} | |
/* 閾値設定h2 */ | |
h2[NUM_HIDDEN_TWO]=(double)1.0; | |
/* 隠れ素子3の計算 */ | |
for(j=0;j<NUM_HIDDEN_THREE;j++){ | |
net_input=0; | |
for(i=0;i<NUM_HIDDEN_TWO+1;i++){ | |
net_input=net_input+w3[i][j]*h2[i]; | |
} | |
/* シグモイドの適用 */ | |
h3[j]=sigmoid(net_input); | |
} | |
/* 閾値設定h3 */ | |
h3[NUM_HIDDEN_THREE]=(double)1.0; | |
/* 出力素子の計算 */ | |
for (j=0;j<NUM_OUTPUT;j++){ | |
net_input=0; | |
for(i=0;i<NUM_HIDDEN_THREE+1;i++){ | |
net_input=net_input+w4[i][j]*h3[i]; | |
} | |
/* シグモイドの適用 */ | |
y[j]=sigmoid(net_input); | |
} | |
/* 逆方向の動作 */ | |
/* 出力層の逆伝播 */ | |
for(j=0;j<NUM_OUTPUT;j++){ | |
y_back[j]=(y[j]-ty[isample][j])*((double)1.0-y[j])*y[j]; | |
} | |
/* 隠れ層3の逆伝播 */ | |
for(i=0;i<NUM_HIDDEN_THREE;i++){ | |
net_input=0; | |
for(j=0;j<NUM_OUTPUT;j++){ | |
net_input=net_input+w4[i][j]*y_back[j]; | |
} | |
h3_back[i]=net_input*((double)1.0-h3[i])*h3[i]; | |
} | |
/* 隠れ層2の逆伝播 */ | |
for(i=0;i<NUM_HIDDEN_TWO;i++){ | |
net_input=0; | |
for(j=0;j<NUM_HIDDEN_THREE;j++){ | |
net_input=net_input+w3[i][j]*h3_back[j]; | |
} | |
h2_back[i]=net_input*((double)1.0-h2[i])*h2[i]; | |
} | |
/* 隠れ層1の逆伝播 */ | |
for(i=0;i<NUM_HIDDEN_ONE;i++){ | |
net_input=0; | |
for(j=0;j<NUM_HIDDEN_TWO;j++){ | |
net_input=net_input+w2[i][j]*h2_back[j]; | |
} | |
h1_back[i]=net_input*((double)1.0-h1[i])*h1[i]; | |
} | |
/* 結合荷重の修正 */ | |
for(i=0;i<NUM_INPUT+1;i++){ | |
for(j=0;j<NUM_HIDDEN_ONE;j++){ | |
w1[i][j]=(alpha*w1[i][j])-(epsilon*x[i]*h1_back[j]); | |
} | |
} | |
for(i=0;i<NUM_HIDDEN_ONE+1;i++){ | |
for(j=0;j<NUM_HIDDEN_TWO;j++){ | |
w2[i][j]=(alpha*w2[i][j])-(epsilon*h1[i]*h2_back[j]); | |
} | |
} | |
for(i=0;i<NUM_HIDDEN_TWO+1;i++){ | |
for(j=0;j<NUM_HIDDEN_THREE;j++){ | |
w3[i][j]=(alpha*w3[i][j])-(epsilon*h2[i]*h3_back[j]); | |
} | |
} | |
for(i=0;i<NUM_HIDDEN_THREE+1;i++){ | |
for(j=0;j<NUM_OUTPUT;j++){ | |
w4[i][j]=(alpha*w4[i][j])-(epsilon*h3[i]*y_back[j]); | |
} | |
} | |
} | |
} | |
/* 学習後の結合荷重の値をcsvに記録する(この値をneuralfuture.cのプログラムに適用する事で7セグメント表示器の出力についての予測値を求める) */ | |
/* kekka1.csvに学習後の結合荷重w1の値を記録する */ | |
csv=fopen("kekka1.csv", "w"); | |
if(csv==NULL){ | |
printf("ファイルがオープンできません\n"); | |
return -1; | |
} | |
for(i=0;i<NUM_INPUT+1;i++){ | |
for(j=0;j<NUM_HIDDEN_ONE;j++){ | |
fprintf(csv,"%f\n",w1[i][j]); | |
} | |
} | |
fclose(csv); | |
/* kekka2.csvに学習後の結合荷重w2の値を記録する */ | |
csv=fopen("kekka2.csv", "w"); | |
if(csv==NULL){ | |
printf("ファイルがオープンできません\n"); | |
return -1; | |
} | |
for(i=0;i<NUM_HIDDEN_ONE+1;i++){ | |
for(j=0;j<NUM_HIDDEN_TWO;j++){ | |
fprintf(csv,"%f\n",w2[i][j]); | |
} | |
} | |
fclose(csv); | |
/* kekka3.csvに学習後の結合荷重w3の値を記録する */ | |
csv=fopen("kekka3.csv", "w"); | |
if(csv==NULL){ | |
printf("ファイルがオープンできません\n"); | |
return -1; | |
} | |
for(i=0;i<NUM_HIDDEN_TWO+1;i++){ | |
for(j=0;j<NUM_HIDDEN_THREE;j++){ | |
fprintf(csv,"%f\n",w3[i][j]); | |
} | |
} | |
fclose(csv); | |
/* kekka4.csvに学習後の結合荷重w4の値を記録する */ | |
csv=fopen("kekka4.csv", "w"); | |
if(csv==NULL){ | |
printf("ファイルがオープンできません\n"); | |
return -1; | |
} | |
for(i=0;i<NUM_HIDDEN_THREE+1;i++){ | |
for(j=0;j<NUM_OUTPUT;j++){ | |
fprintf(csv,"%f\n",w4[i][j]); | |
} | |
} | |
fclose(csv); | |
printf("学習が終了しました\n"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment