• 締切済み

階層型ニューラルネットに準ニュートン法のDFPを用いて学習するプログラムをC言語で作成する

//出力層と中間層2の結合荷重を更新 for ( i = 0; i < NUM_hh+1; i++)   {  for ( j = 0; j < NUM_o; j++) { deltaw3[i][j][ilearn+1] = (y[j] - teach[j]) * y[j] * (1.0 - y[j]) * hh[i]; w3[i][j][ilearn+1] = w3[i][j][ilearn] -0.05 * H2[i][j][ilearn] * deltaw3[i][j][ilearn]; //中間層2と中間層1の結合荷重更新 for ( i = 0; i < NUM_hh+1; i++ )  {   net_input1[j] = 0;  for ( j = 0; j < NUM_o; j++ )   { net_input1[j] += w3[i][j][ilearn] * deltaw3[i][j][ilearn];   }     net_input1[i] = net_input1[j];  } for ( i = 0; i < NUM_h+1; i++)  {  for ( j = 0; j < NUM_hh; j++)   { deltaw2[i][j][ilearn+1] = net_input1[j] * (1.0 - hh[j]) * h[i]; w2[i][j][ilearn+1] = w2[i][j][ilearn] - (0.005 * H2[i][j][ilearn] * deltaw2[i][j][ilearn] );   }  } //中間層1と入力層の結合荷重更新 for ( i = 0; i < NUM_h; i++ )  {  net_input2[j] = 0;  for ( j = 0; j < NUM_hh; j++ )   {  net_input2[j] += w2[i][j][ilearn] * deltaw2[i][j][ilearn];   }  net_input2[i] = net_input2[j];  } for ( i = 0; i < NUM_i+1; i++)  {  for ( j = 0; j < NUM_h; j++)   { deltaw1[i][j][ilearn+1] = net_input2[j] * (1.0 - h[j]) * x[i]; w1[i][j][ilearn+1] = w1[i][j][ilearn] - (0.005 * H2[i][j][ilearn] * deltaw1[i][j][ilearn] );   }  } for ( i = 0; i < NUM_h; i++) // Hの更新 //  {   for ( j = 0; j < NUM_hh; j++)   { sigma2[i][j] = w2[i][j][ilearn+1] - w2[i][j][ilearn]; gamma2[i][j] = deltaw2[i][j][ilearn+1] - deltaw2[i][j][ilearn];   }  } for ( i = 0; i < NUM_h; i++) {  for ( j = 0; j < NUM_hh; j++)   { H2[i][j][ilearn+1] = H2[i][j][ilearn] + ((sigma2[i][j] * sigma2[j][i]) / (sigma2[j][i] * gamma2[i][j])) - ((H2[i][j][ilearn]*gamma2[i][j]*gamma2[j][i]*H2[i][j][ilearn])/(gamma2[j][i]*H2[i][j][ilearn]*gamma2[i][j]));   } } プログラムの最初に戻り学習を繰り返す。 準ニュートン法(DFP)を階層型ニューラルネットに用いて学習を行うプログラムを作成しているのですが、ヘッセ行列の逆行列を更新がうまくできず、学習ができません。どこに問題があるのかわからず困っています。。 ※各層のニューロン数は、NUM_i:5 NUM_hhとNUM_h:30 NUM_o:31 w123は結合荷重、deltaw123は勾配 gamma2は勾配の差分 sigma2は結合係数の差分 学習結果を見るために関数近似を行ってます。誤差は二乗誤差を用いているのですが、結果が学習回数2回目辺りから1.#qNaN0になり、それ以降は-1.#ind00という出力になってしまいます。

みんなの回答

回答No.1

 Cは、ソースを部分的に明示されてもそれに精通した人でないと解答することは極めて困難です。というか、プログラムは走らせてみないとわからないので、特にこのような専門的な内容の場合は質問自体が無謀のように思います。とりあえずいわせてもらえば「学習」がテーマということですので、学習の係数マトリックスが係数として本当に予想通り更新されているかどうか内容をチェックされることがまず初めにやるべきことではないでしょうか(あてずっぽうです)。  その代わり、ここであなたに解答できないものの助言することはできます。それは「自身で何処に間違いがあるかを見つける方法」を教えてあげることです。  ここでは Linux や Mac OSX などのUNIX系OSのパソコンを使っている場合の話をします。チェックの仕方は、プログラムの頭の方からあなたが想定した数値となっているかどうかを調べる、いわゆる「人間デバッガ」のやり方です。使うのは fprintf(stderr, “○×△ ....) を使います。  たとえば↓のように、ループの中に fprintf() を組み入れて(間違えても、ループ内では複数の別の処理を入れないこと)コンパイルし、 //出力層と中間層2の結合荷重を更新 ?fprintf(stderr,”\nコメント\n”); //ループ前に置き、 一行あけて見易く区切りを付ける for ( i = 0; i < NUM_hh+1; i++) {?  for ( j = 0; j < NUM_o; j++) { ?fprintf(stderr, “teach[%d]=%f deltaw3[%d][%d][%d]....?n”, j, teach[j], i, j, ilearn+1, deltaw3[i][j][ilearn+1], ....);   deltaw3[i][j][ilearn+1] = (y[j] - teach[j]) * y[j] * (1.0 - y[j]) * hh[i];? w3[i][j][ilearn+1] = w3[i][j][ilearn] -0.05 * H2[i][j][ilearn] * deltaw3[i][j][ilearn];?}}   ...... exit(0); // ループ毎にひとつひとつ区切ってチェックする プログラムの起動の際に、シェルプロンプトから    ./a.out 2>>my_errfile と打鍵して、エラー出力パスを my_errfile という名のファイルにリダイレクトして追加書き込みし、実行後、その都度ファイルをエディタなどで開いては各数値がどのように展開しているのか確認するやり方です。最初はひとつのループ毎に終わるようにして、各ループにおける諸数値がどのような状況となっているのか my_errfile を開いて確認します。なお、出力ファイル名はとりあえず my_errfile としましたが、それは自由です。  一通り最初のこの人間デバッグ作業が終われば、次は if() を使って、任意ループ回数毎に 同じように my_errfile に追加書き込みするようにします。これで、どこでどのように数値が変わったのか更にわかるでしょう。  ただし、これはひとつひとつの項目についてチェックする気の遠くなる作業です。焦らず、根気よく確認するしかありません。ちょっと大きな、あるいは難解なプログラムのデバッグはそのようなものです。プログラム作成が1日なら、間違い探しのデバックはその数倍の3日以上の労力を必要とします。頑張ってください。

G_MANT
質問者

お礼

回答ありがとうございます。 自分が使ってる開発環境はvisual c++ 2005/2008なのでwindowsを使ってます。LinuxやUNIXはあまり手を付けたことが無いのですいません。。 デバッグ機能は付いているのでそれを頼りにいろいろ値の変化を調べることは行っているのですが、それだけでは足りないのですね。。確かに一つ一つチェックするのは時間が掛かってしまうかもしれないですがそれが一番いいですよね。 アドバイスありがとうございました。fprintfでファイル出力なども行ったりして変化を見てみたりして、もっと頑張ってみます。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 4階層型ニューラルネットワークで学習(準ニュートン法)

    準ニュートン法の学習方法の中に出てくるヘッセ行列の逆行列の近似行列Hについてなんですが、よく最適化についての本に更新式が載っているのを見るのですけど、(DFP法やBFGS法)アルゴリズムの中に探索方向の計算についてあるんですが、4層のニューラルネットに準ニュートン法を導入すると、それぞれ入力層-中間層1と中間層1-中間層2と中間層2-出力層の3つの所でそれぞれ重みwや微分式∇f(w)の更新を行うと思うのですが、このときにHをそれぞれの層間で探索方向を用いて次のHを更新するみたいですが、このHはよく初期値として単位行列を設定しているようなのですが、これはそれぞれの層のユニット数を同じにする必要とかあるのでしょうか?例えば中間1-2層のユニット数は10個とか

  • c言語 プログラム ピラミッド

    プログラミングについて教えてください プログラムは ピラミッドの図形をユーザーが指定した数字で正三角形の ピラミッドの段数を指定できるプログラムです 例えば「5」と打てば ********* ■ ********■■■ ******■■■■■ ****■■■■■■■ **■■■■■■■■■ このような感じに表示されます *の部分は空白です #include<stdio.h> int main (void) { int num,i,j,h; printf("ピラミッドの高さを入力してください : "); scanf("%d" ,&num); for(i=1; i<=num; i++){ for(j=num; j>=i+1; j--){ printf(" ",j); } for(h=1; h<=j; h++){ printf("■"); } printf("\n"); } return 0; } ここまで出来ています、詰まっているのでご教授ください よろしくお願いします

  • 4階層型ニューラルネット(逆伝播法)

     現在、実験のために4階層型のニューラルネットを作成しているのですが上手く収束しません。使用は入力層、中間層2層、出力層の計4層です。  各変数はo1が入力ユニットからの出力、o2とo3は中間層ユニットの出力、o4が出力層ユニットの出力です。w43,w32,w21はそれぞれの結合強度です。biasはそのままバイアスです。変数の前にdがついてるものは変化を表したものです。etaは学習率、alphaは慣性項係数です。この値と中間層ユニット数を変更してみても収束しませんでした。  問題があるのは逆伝播法での結合強度の更新です。以下にそのルーチンを示しますのでお気づきの点がありましたらお願いします。特に問題があるのは中間層~入力層間についてだと思うのですが。。  ご意見お願いします。また、よろしければ4層以上のニューラルネットについてのサイトがあればお願いします。

  • C言語のプログラムなのですが、エラーの原因がわからずに困っています。

    C言語のプログラムなのですが、エラーの原因がわからずに困っています。 ./moji/learn/data/0-00.dat ./moji/learn/data/0-01.dat のようにファイル名が並んでいるテキストファイルをオープンし、 fscanfでファイル名をfileName[256]という配列に代入し、 そのファイル名のテキストファイルをオープンしてデータを読んでいくというものです。 void fv(char *files, int i) { FILE *data; data = fopen(files,"r");     if(data == NULL) { printf("Error\n"); exit(1); } int j, k, l, m, w, h, ww, hh, t; int dw[DN], dh[DN]; fscanf(data, "%d", &w); fscanf(data, "%d", &h); ww = w % DN; hh = h % DN; for(j = 0;j < DN;j++) { dw[j] = w / DN; dh[j] = h / DN; if(ww > 0) { dw[j] += 1; ww--; } if(hh > 0) { dh[j] += 1; hh--; } } for(l = 0;l < DN;l++) { for(m = 0;m < dh[l];m++) { for(j = 0;j < DN;j++) { for(k = 0;k < dw[j];k++) { fscanf(data, "%d", &t); t = 1; feature[i][l][j] += t; } } } } for(l = 0;l < DN;l++) { for(j = 0;j < DN;j++) { feature[i][l][j] = feature[i][l][j] * 10000 / (w * h); } } } 読み込んだファイル名をfvに渡して、 fvを繰り返し実行して計算を行うのですが、 最初の1000回は問題なく実行できるのですが、 1020回実行したところで、 Error が表示されてしまいます。 ファイルは存在しているため、なぜfopenで失敗するのかがわかりません。 原因として考えられることは何があるのでしょうか?

  • C言語  プログラムのチェックと質問

    プログラミング初心者です プログラミングの練習のためにプログラムを組みました ですがあまり綺麗なプログラムにならなかったのでもっとこうしたらいい というところがあれば教えていただけないでしょうか また組んでいて改善したいところがあったのですが 自分ではどうしたらいいかわからなかったので教えていただけませんか プログラムの説明 1から43の数字からランダムに6つ選び小さい順に並べる それを5回繰り返すプログラム つまりロト6のクイックピックのようなことをするプログラムです 改善したい点 異なる行で2つ以上同じ数がないようにしたい 以下ソースコード #include<stdio.h> #include<stdlib.h> #include<time.h> int main(){ int sai[10][10],i1,i2,i3,j1,j2,j3,num[50],temp; srand((unsigned)time(NULL)); for(i1=0; i1 < 6; i1++){ for(i2= 1; i2 < 44; i2++){ num[i2] = i2; } for(i3 = 0; i3 < 6 ; i3++){ sai[i3][i1] = rand() % 43 + 1; while( num[sai[i3][i1]] == 0){ sai[i3][i1] = rand() % 43 + 1; } num[sai[i3][i1]] = 0; } } for(j1 = 0; j1 < 6 ; j1++){ for(j2 = 0; j2 < 10 ; j2++){ for(j3 = 0; j3 < 5 ; j3++){ if(sai[j3][j1] > sai[j3 + 1][j1]){ temp = sai[j3][j1]; sai[j3][j1] = sai[j3 + 1][j1]; sai[j3 + 1][j1] = temp; } } } } for(j1 = 0; j1 < 5 ; j1++){ for(j2 = 0; j2 < 6 ; j2++){ printf("%d ",sai[j2][j1]); } printf("\n"); } return 0; } 以上

  • C言語でのプログラム

    全対最短経路(フロイドのアルゴリズム)のプログラムを作成したんですが、以下のようなメッセージが出てしまい、どこが悪いのかさっぱりわかりません。どなたかご教授願えないでしょうか? <プログラム> #include<stdio.h> #define NC 999 /* It should be large enough. */ #define N 5 void floyd(int, int [][], int [][], int [][]); int W[N][N] = { { 0, 1, NC, 1, 5 }, { 9, 0, 3, 2, NC }, { NC, NC, 0, 4, NC }, { NC, NC, 2, 0, 3 }, { 3, NC, NC, NC, 0 }, }; int P[N][N]; int D[N][N]; main() { floyd(N, W, D, P); } void floyd(int n, int W[][], int D[][], int P[][]) { int i, j, k; for(i=0;i<n;i++){ for(j=0;j<n;j++){ P[i][j] = 0; } } for(i=0;i<n;i++){ for(j=0;j<n;j++){ D[i][j] = W[i][j]; } } for(k=0;k<n;k++){ for(i=0;i<n;j++){ for(j=0;j<n;j++){ if(D[i][k]+D[k][j]<D[i][j]){ P[i][j] = k; D[i][j] = D[i][k] + D[k][j]; } } } } printf("?nall pairs of the shortest pathes:?n"); for(i=0;i<n;i++){ for(j=0;j<n;j++){ printf("%3d ", D[i][j]); } printf("?n"); } printf("?n"); } <エラーメッセージ> In function `floyd': :30: error: invalid use of array with unspecified bounds :36: error: invalid use of array with unspecified bounds :43: error: invalid use of array with unspecified bounds :44: error: invalid use of array with unspecified bounds :45: error: invalid use of array with unspecified bounds :54: error: invalid use of array with unspecified bounds

  • c言語 行列のn階乗のプログラム

      1 2 -1 D= 3 0 -2   -1 1 2 の3次正方行列のn乗を計算するプログラムを作成しています。 いろいろと試してみましたがうまくいきません。 どなたか教えていただけるとうれしいです。 よろしくおねがいします。 #include <stdio.h> int main(void) { int a[3][3]={ {-1,2,-1},{3,0,-2},{-1,1,2} }; int b[3][3]={ {-1,2,-1},{3,0,-2},{-1,1,2} }; int s[3][3]; int m,n; int i,j,k; printf("[A]^n;n = ");scanf("%d",&n); for (m=2;m <= n;m++){ for (i=0;i<3;i++){ for (j=0;j<3;j++){ s[i][j] = 0; for(k=0;k<3;k++){ s[i][j] =s[i][j] + a[i][k] * b[k][j]; } } } for(i=0;i<3;i++){ for(j=0;j<3;j++){ b[i][j]=s[i][j]; } } printf("%3d",s[i][j]); putchar('\n'); } return (0); }

  • ガンマ変換 C言語でプログラムの作成

    次式のように、原画像の任意の階調値fから、点線の矢印のようにして交換後の階調値gを決める。このような階調値の変換を表す配列 unsigned char trans[256];を用いて画像の濃度補正を行うプログラム作成せよとあるのですが、どのような計算式を用いて任意の変換の プログラムを作成してよいかわかりません。 同、問題でガンマ変換のプログラムは作成したのですが、 詳しい方で添付画像のようなプログラムを作成できる方がいましたらよろしくお願いします。 ESPライブラリを使用していますので、添付ファイルにソースとヘッダファイルと図を添付しています   プログラムの開始: sを押す         終了: xを押す --------------------------------------------------------------*/ #include <stdio.h> #include <stdlib.h> #include "mypgmesp.h" /* ESP関係の関数が定義されているヘッダファイル */ #define FINAL_LEVEL 64 //最終的な表現階調数// // 関数のプロトタイプ宣言 void gamma_histgram(void); /*************************************************************************    このプログラムを実行したとき、はじめに実行される処理を書く *************************************************************************/ void ESP_Ready(void) { ESP_Open_Window(); } /*************************************************************************    このプログラムが終了したとき、実行される処理を書く *************************************************************************/ void ESP_Finish(void) { } /*************************************************************************    startボタンが押されたときに、実行される処理を書く *************************************************************************/ void ESP_Main(void) { int ret; /* 準備 */ ESP_Prepare(); /* 画像データを image1 に読み込んで表示する */ ret = ESP_load_image_data(); if(ret){ ESP_StartMenu(); return; } /////////////////////////////////////////////////// // 以下に関数や命令を記述する gamma_histgram(); // ここまで /////////////////////////////////////////////////// /* image2 を保存し表示する */ ESP_save_image_data(); /* メッセージの表示 */ ESP_StartMenu( ); } ////////////////////////////////////////////////// // 以下の関数内にプログラムを追加する /////////////////////////////////////////////////// void gamma_histgram(void) { int i, x, y,g; /* ループ変数 */ long int target_value;//変換後の頻度の目標値// double gam = 2.0,j; unsigned char trans[256]; ESP_Printf("ガンマ補正を行う\n"); for (i = 0; i < 256; i ++){ j=i; g=255*pow(j/255.0,1.0/gam); if(g>255) { trans[i]=255; } else if (g<0) { trans[i]=0; } else { trans[i]=(unsigned char)g; } x_size2=x_size1; y_size2=y_size1; for ( y = 0; y < y_size2; y ++ ) { for ( x = 0; x < x_size2; x ++ ) image2[y][x] = trans[image1[y][x]]; } } }

  • C言語のプログラムのメモリリークに関して

    動的メモリ管理を用いて,キーボードからの入力を行単位で辞書順にソートして出力するプログラムで、メモリリークが有るため解消したいのですが、freeをどのように用いれば良いのかが分かりません。 動的メモリについての理解が不十分であるため、自分なりにfreeを用いてみるとプログラムが途中で止まってしまい、解消することができません。 以下のプログラムは、自分なりにfreeを用いた部分を除けば、ソート後の出力は正しく出力されます。(メモリリークは発生します。) アドバイス、間違いの指摘等していただければと思います。お願いします。 環境は、Windows XP Professional SP3 32bitでVisual C++ 2008 Expressを使用しています。 #include <stdio.h> #include <string.h> #include <crtdbg.h> #include <stdlib.h> #define MAXLINES 20000 // 最大行数 #define LINELENGTH 20 // 1行の最大文字数 /* 標準入力からの入力を,一行づつ動的に確保したメモリに格納し, そのアドレスを文字列へのポインタ配列に保存する. Ctrl+Zで入力を終了する. lines : 文字列へのポインタの配列 numMax : 最大の読み込み行数*/ int ReadLines(char *lines[], int numMax){ int cnt = 0; static char buf[LINELENGTH]; while (cnt < numMax && gets(buf)) { lines[cnt] = malloc(strlen(buf) + 1); if (lines[cnt] == NULL) { printf("Allocation error.\n"); break; } strcpy(lines[cnt], buf); cnt++; } return cnt; } /* ポインタ配列の指す文字列を標準出力に表示 lines : 文字列へのポインタの配列 num : 行数*/ void PrintLines(char *lines[], int num){ int i; for (i = 0;i < num;i++) printf("%s\n", lines[i]); } /* ポインタの配列を,辞書順にソート lines : 文字列へのポインタの配列 num : 行数*/ void Sort(char *lines[], int num){ int i,j; char temp[LINELENGTH]; for(i=0;i<num;i++){ for(j=num-1;j>i;j--){ if(strcmp(lines[j],lines[j-1])<0){ strcpy(temp,lines[j]); strcpy(lines[j],lines[j-1]); strcpy(lines[j-1],temp); } } } } int main(){ int cnt,i; static char *lines[MAXLINES]; cnt = ReadLines(lines, MAXLINES); printf("----- %d lines -----\n", cnt); Sort(lines, cnt); PrintLines(lines, cnt); /*自分なりにfreeを用いた部分*/ for(i=0;i<cnt;i++){ free(lines[i]); } //メモリリーク情報の表示 _CrtDumpMemoryLeaks(); return 0; }

  • C言語でこのプログラムを完成させるには

    C言語でこのプログラムを完成させるには C言語初心者です。 1~6の乱数を100回発生させて、それぞれの出現回数をカウントし、ヒストグラムとして表示するプログラムを作成したいのですが上手くいきません。 #include <stdio.h> #include <time.h> #include <stdlib.h> int rnd(int m, int n) { return (int)(n-m+1)*(rand()/(RAND_MAX+0.1))+m; } int main(void) { int i, j, r; int hist[7]; for (i=1; i<7; i++) hist[i]=0; srand((unsigned)time(NULL)); for (i=0; i<100; i++) { r=6; while (6-- > 0) putchar('*'); putchar('\n'); } for (i=1; i<7; i++) { printf("%2d:", i); for (j=0; j<hist[i]; j++) printf("*"); printf("\n"); } return 0; } 何がいけないのでしょうか? よろしくお願いします。

このQ&Aのポイント
  • 女性好きなのにゲイでは?悩む中学生男子の心の声
  • 自◯やゲイについて長年悩んでいるが、思い込みか本当かわからない
  • LGBTに強い抵抗感があり、影響されやすい性格が悩みの要因に
回答を見る

専門家に質問してみよう