実現したいこと
ファイルから入力層のニューロン数N, 隠れ層のニューロン数L, 出力層のニューロン数M, データの数Tを読み込み, xor関数を隠れ層ニューロン数2個のネットワークで学習したいです。
今起きている問題
学習後の誤差関数Eの値を表示しているのですが, 乱数で実装していることもあり学習に失敗するケースがあるところまでは承知しています。しかし, Eの値が0.01以下になるようにしたいのにも関わらず, だいたい1.9の値を取っているため思ったような実装ができていません。その原因が分からないので, 教えていただきたいです。
実装コード・結果
C++
1#include<iostream> 2#include<cmath> 3#include<cstdlib> 4using namespace std; 5 6double neuron(double x[], double weight[], double b, int n){ 7 double sum=0; 8 for (int i=0; i<n; i++) { 9 sum+=x[i]*weight[i]; 10 } 11 sum+=b; 12 return 1/(1+exp(-sum)); 13} 14 15int main() { 16 int N; 17 int L; 18 int M; 19 int T; 20 double E; 21 cin>>N>>L>>M>>T; 22 23 double x[200][10]; 24 double z[10]; 25 double y[10]; 26 double v[10]; 27 28 double t[200][10]; 29 double gamma=5; 30 31 double w1[10][10]; 32 double w2[10][10]; 33 double b1[10]; 34 double b2[10]; 35 srand((unsigned)time(NULL)); 36 for (int k=0; k<L; k++) { 37 for (int i=0; i<N; i++) { 38 w1[k][i]=(double)rand()/((double)RAND_MAX+1); 39 } 40 b1[k]=(double)rand()/((double)RAND_MAX+1); 41 } 42 for (int j=0; j<M; j++) { 43 for (int k=0; k<L; k++) { 44 w2[j][k]=(double)rand()/((double)RAND_MAX+1); 45 } 46 b2[j]=(double)rand()/((double)RAND_MAX+1); 47 } 48 49 for(int c=0; c<1000; c++) { 50 for(int p=0; p<T; p++) { 51 for(int k=0; k<L; k++) { 52 z[k]=neuron(x[p],w1[k],b1[k],N); 53 } 54 for (int j=0; j<M; j++) { 55 y[j]=neuron(z,w2[j],b2[j],L); 56 } 57 for (int k=0; k<L; k++){ 58 v[k]=0; 59 for(int j=0; j<M; j++){ 60 v[k]+=(y[j]-t[p][j])*(1-y[j])*y[j]*w2[j][k]; 61 } 62 } 63 for (int j=0; j<M; j++) { 64 for (int k=0; k<L; k++) { 65 w2[j][k]-=gamma*z[k]*(y[j]-t[p][j])*(1-y[j])*y[j]; 66 } 67 b2[j]-=gamma*(y[j]-t[p][j])*(1-y[j])*y[j]; 68 } 69 for (int k=0; k<L; k++) { 70 for (int i=0; i<N; i++) { 71 w1[k][i]-=gamma*x[p][i]*(1-z[k])*z[k]*v[k]; 72 } 73 b1[k]-=gamma*(1-z[k])*z[k]*v[k]; 74 } 75 } 76 } 77 78 for (int p=0; p<T; p++) { 79 for (int i=0; i<N; i++) { 80 cin>>x[p][i]; 81 } 82 for (int j=0; j<M; j++) { 83 cin>>t[p][j]; 84 } 85 cout<<"x:"; 86 for(int i=0; i<N; i++){ 87 cout<<x[p][i]<<" "; 88 } 89 cout<<"z:"; 90 for(int k=0; k<L; k++){ 91 z[k]=neuron(x[p],w1[k],b1[k],N); 92 cout<<z[k]<<" "; 93 } 94 cout<<"y:"; 95 for(int j=0; j<M; j++){ 96 y[j]=neuron(z,w2[j],b2[j],L); 97 E+=(t[p][j]-y[j])*(t[p][j]-y[j]); 98 cout<<y[j]<<" "; 99 } 100 cout<<endl; 101 } 102 cout<<"E:"<<E<<endl; 103 104 for(int k=0; k<L; k++){ 105 cout<<"z"<<k<<" "; 106 cout<<"w1:"; 107 for(int i=0; i<N; i++){ 108 cout<<w1[k][i]<<" "; 109 } 110 cout<<"b1:"; 111 cout<<b1[k]<<endl; 112 } 113 114 for(int j=0; j<M; j++) { 115 cout<<"y"<<j<<" "; 116 cout<<"w2:"; 117 for(int k=0; k<L; k++) { 118 cout<<w2[j][k]<<" "; 119 } 120 cout<<"b2:"; 121 cout<<b2[j]<<endl; 122 } 123 return 0; 124}
xor.txt
12 2 1 4 //xor.txt 20 0 0 31 0 1 40 1 1 51 1 0
実行結果
$./a.exe<xor.txt
x:0 0 z:0.724001 0.748752 y:0.00337414
x:1 0 z:0.735373 0.782302 y:0.00313582
x:0 1 z:0.778374 0.842381 y:0.0026458
x:1 1 z:0.788161 0.865672 y:0.00250641
E:1.98847
z0 w1:0.0576604 0.291822 b1:0.964394
z1 w1:0.187169 0.584085 b1:1.09196
y0 w2:-1.71473 -1.60915 b2:-3.24191
x:0 0 z:0.658774 0.775888 y:0.00337317
x:1 0 z:0.806224 0.831015 y:0.00237437
x:0 1 z:0.832161 0.856353 y:0.00215879
x:1 1 z:0.91442 0.894382 y:0.0017471
E:1.99096
z0 w1:0.767824 0.943183 b1:0.657835
z1 w1:0.350974 0.543466 b1:1.24186
y0 w2:-1.58821 -2.13942 b2:-2.98231
x:0 0 z:0.677479 0.578337 y:0.00358413
x:1 0 z:0.844232 0.702535 y:0.00222868
x:0 1 z:0.835425 0.727025 y:0.00219048
x:1 1 z:0.929065 0.820985 y:0.00162254
E:1.99119
z0 w1:0.947847 0.882365 b1:0.74221
z1 w1:0.543451 0.663632 b1:0.31595
y0 w2:-1.83804 -1.36851 b2:-3.59096
x:0 0 z:0.735721 0.798222 y:0.00329615
x:1 0 z:0.800865 0.905335 y:0.00236951
x:0 1 z:0.829731 0.865813 y:0.00245969
x:1 1 z:0.87562 0.939754 y:0.00195537
E:1.99037
z0 w1:0.367866 0.559878 b1:1.02384
z1 w1:0.882749 0.489222 b1:1.37522
y0 w2:-1.60078 -2.11665 b2:-2.84442
試したこと
まず, xやyの配列がdouble型になっているかを確認しました。その次に, Eを求めるところで(t[p][j]-y[j])(t[p][j]-y[j])を(y[j]-t[p][j])(y[j]-t[p][j])と値の順序を変えてみました。
補足
C++17を使用しています。
あなたの回答
tips
プレビュー