情報学部 | 菅沼ホーム | 目次 | 索引 |
/****************************/ /* back propagation model */ /* coded by Y.Suganuma */ /****************************/ #include#include #include #include #include "MT.h" /******************************************************/ /* バックプロパゲーションの制御(クラス BackControl) */ /******************************************************/ class BackControl { protected: double alpha, eata; //重み及びバイアス修正パラメータ double eps; // 許容誤差 unsigned long seed; // 乱数の初期値; int order; // 入力パターンの与え方(=0:順番,=1:ランダム) int p_type; // 出力先・方法の指定 // =0 : 誤って認識した数だけ出力 // =1 : 認識結果を出力 // =2 : 認識結果と重みを出力 // (負の時は,認識結果と重みをファイルへも出力) char o_file[100]; // 出力ファイル名 public: BackControl(char *); // コンストラクタ }; /*****************************************************/ /* バックプロパゲーションのデータ(クラス BackData) */ /*****************************************************/ class BackData { int noiu; // 入力ユニットの数 int noou; // 出力ユニットの数 int noip; // 入力パターンの数 double **iptn; // iptn[i][j] : (i+1)番目の入力パターンの(j+1)番目の // 入力ユニットの入力値 // i=0,noip-1 j=0,noiu-1 double **optn; // optn[i][j] : (i+1)番目の入力パターンに対する(j+1) // 番目の出力ユニットの目標出力値 // i=0,noip-1 j=0,noou-1 public: BackData(char *); // コンストラクタ ~BackData(); // デストラクタ friend class Backpr; }; /*******************************************/ /* バックプロパゲーション(クラス Backpr) */ /*******************************************/ class Backpr : BackControl { char **con; // con[i][j] : 各ユニットに対するバイアスの与え方,及び, // 接続方法 // [i][i] : ユニット(i+1)のバイアスの与え方 // =-3 : 入力値で固定 // =-2 : 入力値を初期値として,学習により変更 // =-1 : 乱数で初期値を設定し,学習により変更 // [i][j] : ユニット(i+1)と(j+1)の接続方法(j>i) // =0 : 接続しない // =1 : 接続する(重みの初期値を乱数で設定し,学習) // =2 : 接続する(重みの初期値を入力で与え,学習) // =3 : 接続する(重みを入力値に固定) // i=0,nou-1 j=0,nou-1 int f_type; // シグモイド関数のタイプ // 0 : [0,1] // 1 : [-1,1]) int noiu; // 入力ユニットの数 int noou; // 出力ユニットの数 int *nohu; // nohu[i] : レベル(i+1)の隠れ層のユニット数(隠れ層 // には下から順に番号が付けられ,出力層はレ // ベル(nolvl+1)の隠れ層とも見做される) // i=0,nolvl int nolvl; // 隠れユニットの階層数 int nou; // 入力,出力,及び,隠れ層の各ユニットの数の和(各ユニ // ットには最も上の出力ユニットから,隠れ層の各ユニット, // 及び,入力ユニットに至る一連のユニット番号が付けられ // る) double *dp; // dp[i] : ユニット(i+1)の誤差 i=0,nou-1 double *op; // op[i] : ユニット(i+1)の出力 i=0,nou-1 double *theta; //theta[i] : ユニット(i+1)のバイアス i=0,nou double **w; // w[i][j] : ユニット(i+1)から(j+1)への重み(j>i) // w[j][i] : (i+1)から(j+1)への重みの前回修正量(j>i) // w[i][i] : ユニット(i+1)のバイアスの前回修正量 // i=0,nou-1 j=0,nou-1 public: Backpr(char *, char *); // コンストラクタ ~Backpr(); // デストラクタ void Err_back(double *); // 重みの修正 void Forward(); // 誤差の計算 void Learn(BackData &, int); // 学習 int Recog(BackData &, int, int); // 認識と学習 }; /*************************************/ /* クラスBackControlのコンストラクタ */ /* name : 入力データファイル名 */ /*************************************/ BackControl::BackControl(char *name) { FILE *in; in = fopen(name, "r"); fscanf(in, "%*s %lf %*s %d", &eps, &p_type); if (p_type < 0) fscanf(in, "%*s %s", o_file); fscanf(in, "%*s %d %*s %lf %*s %lf", &order, &eata, &alpha); fclose(in); seed = (unsigned long)time(NULL); } /************************************/ /* クラスBackDataのコンストラクタ */ /* name : 入力データファイル名 */ /************************************/ BackData::BackData(char *name) { int i1, i2; FILE *in; in = fopen(name, "r"); /* 入力パターン数等 */ fscanf(in, "%*s %d %*s %d %*s %d", &noip, &noiu, &noou); /* 領域の確保 */ iptn = new double * [noip]; for (i1 = 0; i1 < noip; i1++) iptn[i1] = new double [noiu]; optn = new double * [noip]; for (i1 = 0; i1 < noip; i1++) optn[i1] = new double [noou]; /* 入力パターン及び各入力パターンに対する出力パターンの入力 */ for (i1 = 0; i1 < noip; i1++) { fscanf(in, "%*s"); for (i2 = 0; i2 < noiu; i2++) fscanf(in, "%lf", &(iptn[i1][i2])); fscanf(in, "%*s"); for (i2 = 0; i2 < noou; i2++) fscanf(in, "%lf", &(optn[i1][i2])); } fclose(in); } /**************************/ /* BackDataのデストラクタ */ /**************************/ BackData::~BackData() { int i1; for (i1 = 0; i1 < noip; i1++) delete [] iptn[i1]; delete [] iptn; for (i1 = 0; i1 < noip; i1++) delete [] optn[i1]; delete [] optn; } /************************************************/ /* クラスBackprのコンストラクタ */ /* name_c : 制御データ用入力ファイル名 */ /* name_s : ネットワーク記述入力ファイル名 */ /************************************************/ Backpr::Backpr(char *name_c, char *name_s) : BackControl(name_c) { double x1, x2; int i0, i1, i2, id, k, k1, k2, k3, k4, l1, l2, n, sw; FILE *in; in = fopen(name_s, "r"); /* 乱数の初期化 */ init_genrand(seed); /* 入力ユニット,出力ユニットの数,関数タイプ */ fscanf(in, "%*s %d %*s %d %*s %d", &noiu, &noou, &f_type); nou = noiu + noou; // 入力ユニットと出力ユニットの和 /* 隠れユニットの階層数と各階層のユニット数 */ fscanf(in, "%*s %d", &nolvl); nohu = new int [nolvl+1]; nohu[nolvl] = noou; // 出力ユニットの数 if (nolvl > 0) { fscanf(in, "%*s"); for (i1 = 0; i1 < nolvl; i1++) { fscanf(in, "%d", &(nohu[i1])); nou += nohu[i1]; } } /* 領域の確保 */ con = new char * [nou]; for (i1 = 0; i1 < nou; i1++) { con[i1] = new char [nou]; for (i2 = 0; i2 < nou; i2++) con[i1][i2] = (i1 == i2) ? -1 : 0; } w = new double * [nou]; for (i1 = 0; i1 < nou; i1++) { w[i1] = new double [nou]; for (i2 = 0; i2 < nou; i2++) w[i1][i2] = 0.0; } dp = new double [nou]; op = new double [nou]; theta = new double [nou]; for (i1 = 0; i1 < nou; i1++) theta[i1] = 0.2 * genrand_real3() - 0.1; /* 各ユニットのバイアスとユニット間の接続関係 */ // バイアス // バイアスデータの数 fscanf(in, "%*s %d", &n); fscanf(in, "%*s %*s %*s"); if (n > 0) { // バイアスデータの処理 for (i0 = 0; i0 < n; i0++) { // ユニット番号 fscanf(in, "%d", &k1); // 不適当なユニット番号のチェック if (k1 < 1 || k1 > (nou-noiu)) { printf("***error ユニット番号 %d が不適当\n", k1); exit(1); } // バイアスの与え方 k1--; fscanf(in, "%d", &id); con[k1][k1] = id; // バイアスの初期設定 switch (con[k1][k1]) { case -1: fscanf(in, "%lf %lf", &x1, &x2); theta[k1] = (x2 - x1) * genrand_real3() + x1; break; case -2: fscanf(in, "%lf", &(theta[k1])); break; case -3: fscanf(in, "%lf", &(theta[k1])); break; default: printf("***error バイアスの与え方が不適当\n"); exit(1); } } } // 接続方法 // 接続データの数 fscanf(in, "%*s %d", &n); fscanf(in, "%*s %*s %*s"); if (n > 0) { // 接続データの処理 for (i0 = 0; i0 < n; i0++) { // 接続情報 fscanf(in, "%d %d %d %d", &k1, &k2, &k3, &k4); // 不適切な接続のチェック sw = 0; if (k1 < 1 || k2 < 1 || k3 < 1 || k4 < 1) sw = 1; else { if (k1 > nou || k2 > nou || k3 > nou || k4 > nou) sw = 1; else { if (k1 > k2 || k3 > k4) sw = 1; else { if (k4 >= k1) sw = 1; else { l1 = -1; k = 0; for (i1 = nolvl; i1 >= 0 && l1 < 0; i1--) { k += nohu[i1]; if (k1 <= k) l1 = i1; } l2 = -1; k = 0; for (i1 = nolvl; i1 >= 0 && l2 < 0; i1--) { k += nohu[i1]; if (k4 <= k) l2 = i1; } if (l2 <= l1) sw = 1; } } } } if (sw > 0) { printf("***error ユニット番号が不適当(%d %d %d %d)\n", k1, k2, k3, k4); exit(1); } // 重みの初期値の与え方 k1--; k2--; k3--; k4--; fscanf(in, "%d", &id); if (id == 1) fscanf(in, "%lf %lf", &x1, &x2); else { if (id > 1) fscanf(in, "%lf", &x1); else { if (id != 0) { printf("***error 接続方法が不適当\n"); exit(1); } } } // 重みの初期値の設定 for (i1 = k3; i1 <= k4; i1++) { for (i2 = k1; i2 <= k2; i2++) { con[i1][i2] = id; switch (id) { case 0: w[i1][i2] = 0.0; break; case 1: w[i1][i2] = (x2 - x1) * genrand_real3() + x1; break; case 2: w[i1][i2] = x1; break; case 3: w[i1][i2] = x1; break; } } } } } fclose(in); } /************************/ /* Backprのデストラクタ */ /************************/ Backpr::~Backpr() { int i1; for (i1 = 0; i1 < nou; i1++) delete [] con[i1]; delete [] con; for (i1 = 0; i1 < nou; i1++) delete [] w[i1]; delete [] w; delete [] nohu; delete [] dp; delete [] op; delete [] theta; } /******************************************/ /* 誤差の計算,及び,重みとバイアスの修正 */ /* ptn[i1] : 出力パターン */ /******************************************/ void Backpr::Err_back(double *ptn) { double x1; int i1, i2; for (i1 = 0; i1 < nou-noiu; i1++) { // 誤差の計算 if (i1 < noou) { if (f_type == 0) dp[i1] = (ptn[i1] - op[i1]) * op[i1] * (1.0 - op[i1]); else dp[i1] = 0.5 * (ptn[i1] - op[i1]) * (op[i1] - 1.0) * (op[i1] + 1.0); } else { x1 = 0.0; for (i2 = 0; i2 < i1; i2++) { if (con[i2][i1] > 0) x1 += dp[i2] * w[i2][i1]; } if (f_type == 0) dp[i1] = op[i1] * (1.0 - op[i1]) * x1; else dp[i1] = 0.5 * (op[i1] - 1.0) * (op[i1] + 1.0) * x1; } // 重みの修正 for (i2 = i1+1; i2 < nou; i2++) { if (con[i1][i2] == 1 || con[i1][i2] == 2) { x1 = eata * dp[i1] * op[i2] + alpha * w[i2][i1]; w[i2][i1] = x1; w[i1][i2] += x1; } } // バイアスの修正 if (con[i1][i1] >= -2) { x1 = eata * dp[i1] + alpha * w[i1][i1]; w[i1][i1] = x1; theta[i1] += x1; } } } /********************************************************/ /* 与えられた入力パターンに対する各ユニットの出力の計算 */ /********************************************************/ void Backpr::Forward() { double sum; int i1, i2; for (i1 = nou-noiu-1; i1 >= 0; i1--) { sum = -theta[i1]; for (i2 = i1+1; i2 < nou; i2++) { if (con[i1][i2] > 0) sum -= w[i1][i2] * op[i2]; } op[i1] = (f_type == 0) ? 1.0 / (1.0 + exp(sum)) : 1.0 - 2.0 / (1.0 + exp(sum)); } } /*****************************/ /* 学習の実行 */ /* p : 認識パターン */ /* m_tri : 最大学習回数 */ /*****************************/ void Backpr::Learn(BackData &p, int m_tri) { int i1, i2, k0 = -1, k1; /* エラーチェック */ if (noiu != p.noiu || noou != p.noou) { printf("***error 入力または出力ユニットの数が違います\n"); exit(1); } for (i1 = 0; i1 < m_tri; i1++) { /* パターンを与える順番の決定 */ if (order == 0) { // 順番 k0++; if (k0 >= p.noip) k0 = 0; } else { // ランダム k0 = (int)(genrand_real3() * p.noip); if (k0 >= p.noip) k0 = p.noip - 1; } /* 出力ユニットの結果を計算 */ k1 = nou - noiu; for (i2 = 0; i2 < noiu; i2++) op[k1+i2] = p.iptn[k0][i2]; Forward(); /* 重みとバイアスの修正 */ Err_back(&(p.optn[k0][0])); } } /***********************************************/ /* 与えられた対象の認識と出力 */ /* p : 認識パターン */ /* pr : =0 : 出力を行わない */ /* =1 : 出力を行う */ /* =2 : 出力を行う(未学習パターン) */ /* tri : 現在の学習回数 */ /* return : 誤って認識したパターンの数 */ /***********************************************/ int Backpr::Recog(BackData &p, int pr, int tri) { int i1, i2, k1, No = 0, ln, sw; FILE *out = NULL; /* ファイルのオープン */ if (p_type < 0 && pr > 0) { if (pr == 1) { out = fopen(o_file, "w"); fprintf(out, "***学習パターン***\n\n"); } else { out = fopen(o_file, "a"); fprintf(out, "\n***未学習パターン***\n\n"); } } /* 各パターンに対する出力 */ for (i1 = 0; i1 < p.noip; i1++) { // 入力パターンの設定 k1 = nou - noiu; for (i2 = 0; i2 < noiu; i2++) op[k1+i2] = p.iptn[i1][i2]; // 出力の計算 Forward(); // 結果の表示 if (p_type != 0 && pr > 0) { printf("入力パターン%4d ", i1+1); for (i2 = 0; i2 < noiu; i2++) { printf("%5.2f", op[k1+i2]); if (i2 == noiu-1) printf("\n"); else { if(((i2+1) % 10) == 0) printf("\n "); } } printf("\n 出力パターン(理想) "); for (i2 = 0; i2 < noou; i2++) { printf("%10.3f", p.optn[i1][i2]); if (i2 == noou-1) printf("\n"); else { if(((i2+1) % 5) == 0) printf("\n "); } } } sw = 0; if (p_type != 0 && pr > 0) printf(" (実際) "); for (i2 = 0; i2 < noou; i2++) { if (p_type != 0 && pr > 0) { printf("%10.3f", op[i2]); if (i2 == noou-1) printf("\n"); else { if(((i2+1) % 5) == 0) printf("\n "); } } if (fabs(op[i2]-p.optn[i1][i2]) > eps) sw = 1; } if (sw > 0) No++; if (p_type < 0 && pr > 0) { fprintf(out, "入力パターン%4d ", i1+1); for (i2 = 0; i2 < noiu; i2++) { fprintf(out, "%5.2f", op[k1+i2]); if (i2 == noiu-1) fprintf(out, "\n"); else { if(((i2+1) % 10) == 0) fprintf(out, "\n "); } } fprintf(out, "\n 出力パターン(理想) "); for (i2 = 0; i2 < noou; i2++) { fprintf(out, "%10.3f", p.optn[i1][i2]); if (i2 == noou-1) fprintf(out, "\n"); else { if(((i2+1) % 5) == 0) fprintf(out, "\n "); } } fprintf(out, " (実際) "); for (i2 = 0; i2 < noou; i2++) { fprintf(out, "%10.3f", op[i2]); if (i2 == noou-1) fprintf(out, "\n"); else { if(((i2+1) % 5) == 0) fprintf(out, "\n "); } } } if (p_type != 0 && pr > 0) { getchar(); if (i1 == 0) getchar(); } } /* 重みの出力 */ if ((p_type < -1 || p_type > 1) && pr == 1) { printf(" 重み\n"); for (i1 = 0; i1 < nou-noiu; i1++) { printf(" to%4d from ", i1+1); ln = -1; for (i2 = 0; i2 < nou; i2++) { if (con[i1][i2] > 0) { if (ln <= 0) { if (ln < 0) ln = 0; else printf("\n "); } printf("%4d%11.3f", i2+1, w[i1][i2]); ln += 1; if (ln == 4) ln = 0; } } printf("\n"); } printf("\n バイアス "); ln = 0; for (i1 = 0; i1 < nou-noiu; i1++) { printf("%4d%11.3f", i1+1, theta[i1]); ln += 1; if (ln == 4 && i1 != nou-noiu-1) { ln = 0; printf("\n "); } } if (ln != 0) printf("\n"); getchar(); } if (p_type < 0 && pr == 1) { fprintf(out, " 重み\n"); for (i1 = 0; i1 < nou-noiu; i1++) { fprintf(out, " to%4d from ", i1+1); ln = -1; for (i2 = 0; i2 < nou; i2++) { if (con[i1][i2] > 0) { if (ln <= 0) { if (ln < 0) ln = 0; else fprintf(out, "\n "); } fprintf(out, "%4d%11.3f", i2+1, w[i1][i2]); ln += 1; if (ln == 4) ln = 0; } } fprintf(out, "\n"); } fprintf(out, "\n バイアス "); ln = 0; for (i1 = 0; i1 < nou-noiu; i1++) { fprintf(out, "%4d%11.3f", i1+1, theta[i1]); ln += 1; if (ln == 4 && i1 != nou-noiu-1) { ln = 0; fprintf(out, "\n "); } } if (ln != 0) fprintf(out, "\n"); } if (p_type < 0 && pr > 0) fclose(out); return No; } /****************/ /* main program */ /****************/ int main(int argc, char *argv[]) { int conv; // 収束確認回数 int m_tri; // 最大学習回数 int max = 0, no = 1, sw, tri; char f_name[100]; // エラー if (argc != 3) { printf("***error 入力データファイル名を指定して下さい\n"); exit(1); } else { // ネットワークの定義 Backpr net(argv[1], argv[2]); // 学習パターン等の入力 printf("学習回数は? "); scanf("%d", &m_tri); printf("何回毎に収束を確認しますか? "); scanf("%d", &conv); printf("学習パターンのファイル名は? "); scanf("%s", f_name); BackData dt1(f_name); // 学習 while (max < m_tri && no > 0) { tri = ((max + conv) < m_tri) ? conv : m_tri - max; max += tri; net.Learn(dt1, tri); // 学習 no = net.Recog(dt1, 0, max); // 学習対象の認識 printf(" 回数 %d 誤って認識したパターン数 %d\n", max, no); } no = net.Recog(dt1, 1, max); // 学習対象の認識と出力 // 未学習パターンの認識 printf("未学習パターンの認識を行いますか?(=1:行う,=0:行わない) "); scanf("%d", &sw); if (sw > 0) { printf("未学習パターンのファイル名は? "); scanf("%s", f_name); BackData dt2(f_name); no = net.Recog(dt2, 2, max); // 未学習対象の認識と出力 } } return 0; } /* ------------------------制御データ---------------- 誤差 0.1 出力 -2 出力ファイル kekka 順番 0 η 0.5 α 0.8 ------------------------構造データ---------------- 入力ユニット数 2 出力ユニット数 1 関数タイプ 0 隠れ層の数 1 各隠れ層のユニット数(下から) 1 バイアス入力ユニット数 1 ユニット番号:出力ユニットから順に番号付け 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1])) 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限) 1 -1 -0.05 0.05 接続方法の数 2 ユニット番号:ユニットk1からk2を,k3からk4に接続 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限) 3 4 1 2 1 -0.1 0.1 2 2 1 1 1 -0.1 0.1 ------------------------学習データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 ------------------------認識データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 //---------------------MT.h--------------------------- // A C-program for MT19937, with initialization improved 2002/1/26. // Coded by Takuji Nishimura and Makoto Matsumoto. // // Before using, initialize the state by using init_genrand(seed) // or init_by_array(init_key, key_length). // // Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. The names of its contributors may not be used to endorse or promote // products derived from this software without specific prior written // permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // // Any feedback is very welcome. // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html // email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) // The original version of http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c was modified by Takahiro Omi as // - delete line 47 "#include " // - delete line 174 int main(void){...} // - change N -> MT_N // - change N -> MT_N // - change the file name "mt19937ar.c" -> "MT.h" // Period parameters #define MT_N 624 #define MT_M 397 #define MATRIX_A 0x9908b0dfUL // constant vector a #define UPPER_MASK 0x80000000UL // most significant w-r bits #define LOWER_MASK 0x7fffffffUL // least significant r bits static unsigned long mt[MT_N]; // the array for the state vector static int mti=MT_N+1; // mti==MT_N+1 means mt[MT_N] is not initialized // initializes mt[MT_N] with a seed void init_genrand(unsigned long s) { mt[0]= s & 0xffffffffUL; for (mti=1; mti > 30)) + mti); // See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. // In the previous versions, MSBs of the seed affect // only MSBs of the array mt[]. // 2002/01/09 modified by Makoto Matsumoto mt[mti] &= 0xffffffffUL; // for >32 bit machines } } // initialize by an array with array-length // init_key is the array for initializing keys // key_length is its length // slight change for C++, 2004/2/26 void init_by_array(unsigned long init_key[], int key_length) { int i, j, k; init_genrand(19650218UL); i=1; j=0; k = (MT_N>key_length ? MT_N : key_length); for (; k; k--) { mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + init_key[j] + j; // non linear mt[i] &= 0xffffffffUL; // for WORDSIZE > 32 machines i++; j++; if (i>=MT_N) { mt[0] = mt[MT_N-1]; i=1; } if (j>=key_length) j=0; } for (k=MT_N-1; k; k--) { mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) - i; // non linear mt[i] &= 0xffffffffUL; // for WORDSIZE > 32 machines i++; if (i>=MT_N) { mt[0] = mt[MT_N-1]; i=1; } } mt[0] = 0x80000000UL; // MSB is 1; assuring non-zero initial array } // generates a random number on [0,0xffffffff]-interval unsigned long genrand_int32(void) { unsigned long y; static unsigned long mag01[2]={0x0UL, MATRIX_A}; // mag01[x] = x * MATRIX_A for x=0,1 if (mti >= MT_N) { // generate N words at one time int kk; if (mti == MT_N+1) // if init_genrand() has not been called, init_genrand(5489UL); // a default initial seed is used for (kk=0;kk > 1) ^ mag01[y & 0x1UL]; } for (;kk > 1) ^ mag01[y & 0x1UL]; } y = (mt[MT_N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); mt[MT_N-1] = mt[MT_M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; mti = 0; } y = mt[mti++]; // Tempering y ^= (y >> 11); y ^= (y << 7) & 0x9d2c5680UL; y ^= (y << 15) & 0xefc60000UL; y ^= (y >> 18); return y; } // generates a random number on [0,0x7fffffff]-interval long genrand_int31(void) { return (long)(genrand_int32()>>1); } // generates a random number on [0,1]-real-interval double genrand_real1(void) { return genrand_int32()*(1.0/4294967295.0); // divided by 2^32-1 } // generates a random number on [0,1)-real-interval double genrand_real2(void) { return genrand_int32()*(1.0/4294967296.0); // divided by 2^32 } // generates a random number on (0,1)-real-interval double genrand_real3(void) { return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0); // divided by 2^32 } // generates a random number on [0,1) with 53-bit resolution double genrand_res53(void) { unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; return(a*67108864.0+b)*(1.0/9007199254740992.0); } // These real versions are due to Isaku Wada, 2002/01/09 added */
/****************************/ /* back propagation model */ /* coded by Y.Suganuma */ /****************************/ import java.io.*; import java.awt.*; import java.awt.event.*; import java.util.Random; import java.util.StringTokenizer; class Test { /****************/ /* main program */ /****************/ public static void main(String args[]) throws IOException, FileNotFoundException { int conv; // 収束確認回数 int m_tri; // 最大学習回数 int max = 0, no = 1, sw, tri; String f_name; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); // エラー if (args.length != 2) { System.out.print("***error 入力データファイル名を指定して下さい\n"); System.exit(1); } else { // ネットワークの定義 Backpr net = new Backpr (args[0], args[1]); // 学習パターン等の入力 System.out.print("学習回数は? "); m_tri = Integer.parseInt(in.readLine()); System.out.print("何回毎に収束を確認しますか? "); conv = Integer.parseInt(in.readLine()); System.out.print("学習パターンのファイル名は? "); f_name = in.readLine(); BackData dt1 = new BackData(f_name); // 学習 while (max < m_tri && no > 0) { tri = ((max + conv) < m_tri) ? conv : m_tri - max; max += tri; net.Learn(dt1, tri); // 学習 no = net.Recog(dt1, 0, max); // 学習対象の認識 System.out.println(" 回数 " + max + " 誤って認識したパターン数 " + no); } no = net.Recog(dt1, 1, max); // 学習対象の認識と出力 // 未学習パターンの認識 System.out.print("未学習パターンの認識を行いますか?(=1:行う,=0:行わない) "); sw = Integer.parseInt(in.readLine()); if (sw > 0) { System.out.print("未学習パターンのファイル名は? "); f_name = in.readLine(); BackData dt2 = new BackData(f_name); no = net.Recog(dt2, 2, max); // 未学習対象の認識と出力 } } in.close(); } } /******************************************************/ /* バックプロパゲーションの制御(クラス BackControl) */ /******************************************************/ class BackControl { protected double alpha, eata; //重み及びバイアス修正パラメータ protected double eps; // 許容誤差 protected int order; // 入力パターンの与え方(=0:順番,=1:ランダム) protected int p_type; // 出力先・方法の指定 // =0 : 誤って認識した数だけ出力 // =1 : 認識結果を出力 // =2 : 認識結果と重みを出力 // (負の時は,認識結果と重みをファイルへも出力) protected int c_size; // 円の大きさ(直径,0のときは画面を表示しない) protected int f_size; // フォントサイズ(0のときはユニット番号を表示しない) protected int width; // 画面の幅 protected int hight; // 画面の高さ protected String o_file; // 出力ファイル名 /*************************************/ /* クラスBackControlのコンストラクタ */ /* name : 入力データファイル名 */ /*************************************/ BackControl(String name) throws IOException, FileNotFoundException { StringTokenizer str; BufferedReader in = new BufferedReader(new FileReader(name)); str = new StringTokenizer(in.readLine(), " "); str.nextToken(); eps = Double.parseDouble(str.nextToken()); str.nextToken(); p_type = Integer.parseInt(str.nextToken()); if (p_type < 0) { str.nextToken(); o_file = str.nextToken(); } str = new StringTokenizer(in.readLine(), " "); str.nextToken(); order = Integer.parseInt(str.nextToken()); str.nextToken(); eata = Double.parseDouble(str.nextToken()); str.nextToken(); alpha = Double.parseDouble(str.nextToken()); str = new StringTokenizer(in.readLine(), " "); str.nextToken(); c_size = Integer.parseInt(str.nextToken()); if (c_size > 0) { f_size = Integer.parseInt(str.nextToken()); width = Integer.parseInt(str.nextToken()); hight = Integer.parseInt(str.nextToken()); } in.close(); } } /*****************************************************/ /* バックプロパゲーションのデータ(クラス BackData) */ /*****************************************************/ class BackData { int noiu; // 入力ユニットの数 int noou; // 出力ユニットの数 int noip; // 入力パターンの数 double iptn[][]; // iptn[i][j] : (i+1)番目の入力パターンの(j+1)番目の // 入力ユニットの入力値 // i=0,noip-1 j=0,noiu-1 double optn[][]; // optn[i][j] : (i+1)番目の入力パターンに対する(j+1) // 番目の出力ユニットの目標出力値 // i=0,noip-1 j=0,noou-1 /************************************/ /* クラスBackDataのコンストラクタ */ /* name : 入力データファイル名 */ /************************************/ BackData(String name) throws IOException, FileNotFoundException { int i1, i2; StringTokenizer str; BufferedReader in = new BufferedReader(new FileReader(name)); /* 入力パターン数等 */ str = new StringTokenizer(in.readLine(), " "); str.nextToken(); noip = Integer.parseInt(str.nextToken()); str.nextToken(); noiu = Integer.parseInt(str.nextToken()); str.nextToken(); noou = Integer.parseInt(str.nextToken()); /* 領域の確保 */ iptn = new double [noip][noiu]; optn = new double [noip][noou]; /* 入力パターン及び各入力パターンに対する出力パターンの入力 */ for (i1 = 0; i1 < noip; i1++) { str = new StringTokenizer(in.readLine(), " "); str.nextToken(); for (i2 = 0; i2 < noiu; i2++) iptn[i1][i2] = Double.parseDouble(str.nextToken()); str = new StringTokenizer(in.readLine(), " "); str.nextToken(); for (i2 = 0; i2 < noou; i2++) optn[i1][i2] = Double.parseDouble(str.nextToken()); } in.close(); } } /*******************************************/ /* バックプロパゲーション(クラス Backpr) */ /*******************************************/ class Backpr extends BackControl { private byte con[][]; // con[i][j] : 各ユニットに対するバイアスの与え方,及び, // 接続方法 // [i][i] : ユニット(i+1)のバイアスの与え方 // =-3 : 入力値で固定 // =-2 : 入力値を初期値として,学習により変更 // =-1 : 乱数で初期値を設定し,学習により変更 // [i][j] : ユニット(i+1)と(j+1)の接続方法(j>i) // =0 : 接続しない // =1 : 接続する(重みの初期値を乱数で設定し,学習) // =2 : 接続する(重みの初期値を入力で与え,学習) // =3 : 接続する(重みを入力値に固定) // i=0,nou-1 j=0,nou-1 private int f_type; // シグモイド関数のタイプ // 0 : [0,1] // 1 : [-1,1]) private int noiu; // 入力ユニットの数 private int noou; // 出力ユニットの数 private int nohu[]; // nohu[i] : レベル(i+1)の隠れ層のユニット数(隠れ層 // には下から順に番号が付けられ,出力層はレ // ベル(nolvl+1)の隠れ層とも見做される) // i=0,nolvl private int nolvl; // 隠れユニットの階層数 private int nou; // 入力,出力,及び,隠れ層の各ユニットの数の和(各ユニ // ットには最も上の出力ユニットから,隠れ層の各ユニット, // 及び,入力ユニットに至る一連のユニット番号が付けられ // る) private double dp[]; // dp[i] : ユニット(i+1)の誤差 i=0,nou-1 private double op[]; // op[i] : ユニット(i+1)の出力 i=0,nou-1 private double theta[]; //theta[i] : ユニット(i+1)のバイアス i=0,nou private double w[][]; // w[i][j] : ユニット(i+1)から(j+1)への重み(j>i) // w[j][i] : (i+1)から(j+1)への重みの前回修正量(j>i) // w[i][i] : ユニット(i+1)のバイアスの前回修正量 // i=0,nou-1 j=0,nou-1 private Random rn; // 乱数 /************************************************/ /* クラスBackprのコンストラクタ */ /* name_c : 制御データ用入力ファイル名 */ /* name_s : ネットワーク記述入力ファイル名 */ /************************************************/ Backpr(String name_c, String name_s) throws IOException, FileNotFoundException { super(name_c); double x1, x2; int i0, i1, i2, id, k, k1, k2, k3, k4, l1, l2, n, sw; StringTokenizer str; BufferedReader in = new BufferedReader(new FileReader(name_s)); /* 乱数の初期化 */ rn = new Random(); // 乱数の初期設定 /* 入力ユニット,出力ユニットの数,関数タイプ */ str = new StringTokenizer(in.readLine(), " "); str.nextToken(); noiu = Integer.parseInt(str.nextToken()); str.nextToken(); noou = Integer.parseInt(str.nextToken()); str.nextToken(); f_type = Integer.parseInt(str.nextToken()); nou = noiu + noou; // 入力ユニットと出力ユニットの和 /* 隠れユニットの階層数と各階層のユニット数 */ str = new StringTokenizer(in.readLine(), " "); str.nextToken(); nolvl = Integer.parseInt(str.nextToken()); nohu = new int [nolvl+1]; nohu[nolvl] = noou; // 出力ユニットの数 if (nolvl > 0) { str.nextToken(); for (i1 = 0; i1 < nolvl; i1++) { nohu[i1] = Integer.parseInt(str.nextToken()); nou += nohu[i1]; } } /* 領域の確保 */ con = new byte [nou][nou]; for (i1 = 0; i1 < nou; i1++) { for (i2 = 0; i2 < nou; i2++) con[i1][i2] = (i1 == i2) ? (byte)-1 : (byte)0; } w = new double [nou][nou]; for (i1 = 0; i1 < nou; i1++) { for (i2 = 0; i2 < nou; i2++) w[i1][i2] = 0.0; } dp = new double [nou]; op = new double [nou]; theta = new double [nou]; for (i1 = 0; i1 < nou; i1++) theta[i1] = 0.2 * rn.nextDouble() - 0.1; /* 各ユニットのバイアスとユニット間の接続関係 */ // バイアス // バイアスデータの数 str = new StringTokenizer(in.readLine(), " "); str.nextToken(); n = Integer.parseInt(str.nextToken()); in.readLine(); in.readLine(); in.readLine(); if (n > 0) { // バイアスデータの処理 for (i0 = 0; i0 < n; i0++) { // ユニット番号 str = new StringTokenizer(in.readLine(), " "); k1 = Integer.parseInt(str.nextToken()); // 不適当なユニット番号のチェック if (k1 < 1 || k1 > (nou-noiu)) { System.out.print("***error ユニット番号 " + k1 + " が不適当\n"); System.exit(1); } // バイアスの与え方 k1--; id = Integer.parseInt(str.nextToken()); con[k1][k1] = (byte)id; // バイアスの初期設定 switch (con[k1][k1]) { case -1: x1 = Double.parseDouble(str.nextToken()); x2 = Double.parseDouble(str.nextToken()); theta[k1] = (x2 - x1) * rn.nextDouble() + x1; break; case -2: theta[k1] = Double.parseDouble(str.nextToken()); break; case -3: theta[k1] = Double.parseDouble(str.nextToken()); break; default: System.out.print("***error バイアスの与え方が不適当\n"); System.exit(1); } } } // 接続方法 // 接続データの数 str = new StringTokenizer(in.readLine(), " "); str.nextToken(); n = Integer.parseInt(str.nextToken()); in.readLine(); in.readLine(); in.readLine(); if (n > 0) { // 接続データの処理 for (i0 = 0; i0 < n; i0++) { // 接続情報 str = new StringTokenizer(in.readLine(), " "); k1 = Integer.parseInt(str.nextToken()); k2 = Integer.parseInt(str.nextToken()); k3 = Integer.parseInt(str.nextToken()); k4 = Integer.parseInt(str.nextToken()); // 不適切な接続のチェック sw = 0; if (k1 < 1 || k2 < 1 || k3 < 1 || k4 < 1) sw = 1; else { if (k1 > nou || k2 > nou || k3 > nou || k4 > nou) sw = 1; else { if (k1 > k2 || k3 > k4) sw = 1; else { if (k4 >= k1) sw = 1; else { l1 = -1; k = 0; for (i1 = nolvl; i1 >= 0 && l1 < 0; i1--) { k += nohu[i1]; if (k1 <= k) l1 = i1; } l2 = -1; k = 0; for (i1 = nolvl; i1 >= 0 && l2 < 0; i1--) { k += nohu[i1]; if (k4 <= k) l2 = i1; } if (l2 <= l1) sw = 1; } } } } if (sw > 0) { System.out.print("***error ユニット番号が不適当(" + k1 + " " + k2 + " " + k3 + " " + k4 + ")\n"); System.exit(1); } // 重みの初期値の与え方 k1--; k2--; k3--; k4--; id = Integer.parseInt(str.nextToken()); x1 = 0.0; x2 = 0.0; if (id == 1) { x1 = Double.parseDouble(str.nextToken()); x2 = Double.parseDouble(str.nextToken()); } else { if (id > 1) x1 = Double.parseDouble(str.nextToken()); else { if (id != 0) { System.out.print("***error 接続方法が不適当\n"); System.exit(1); } } } // 重みの初期値の設定 for (i1 = k3; i1 <= k4; i1++) { for (i2 = k1; i2 <= k2; i2++) { con[i1][i2] = (byte)id; switch (id) { case 0: w[i1][i2] = 0.0; break; case 1: w[i1][i2] = (x2 - x1) * rn.nextDouble() + x1; break; case 2: w[i1][i2] = x1; break; case 3: w[i1][i2] = x1; break; } } } } } in.close(); /* 画面表示 */ Win win; if (c_size > 0) win = new Win("Network Structure", c_size, f_size, width, hight, noiu, nohu, nolvl, con); } /******************************************/ /* 誤差の計算,及び,重みとバイアスの修正 */ /* ptn[i1] : 出力パターン */ /******************************************/ void Err_back(double ptn[]) { double x1; int i1, i2; for (i1 = 0; i1 < nou-noiu; i1++) { // 誤差の計算 if (i1 < noou) { if (f_type == 0) dp[i1] = (ptn[i1] - op[i1]) * op[i1] * (1.0 - op[i1]); else dp[i1] = 0.5 * (ptn[i1] - op[i1]) * (op[i1] - 1.0) * (op[i1] + 1.0); } else { x1 = 0.0; for (i2 = 0; i2 < i1; i2++) { if (con[i2][i1] > 0) x1 += dp[i2] * w[i2][i1]; } if (f_type == 0) dp[i1] = op[i1] * (1.0 - op[i1]) * x1; else dp[i1] = 0.5 * (op[i1] - 1.0) * (op[i1] + 1.0) * x1; } // 重みの修正 for (i2 = i1+1; i2 < nou; i2++) { if (con[i1][i2] == 1 || con[i1][i2] == 2) { x1 = eata * dp[i1] * op[i2] + alpha * w[i2][i1]; w[i2][i1] = x1; w[i1][i2] += x1; } } // バイアスの修正 if (con[i1][i1] >= -2) { x1 = eata * dp[i1] + alpha * w[i1][i1]; w[i1][i1] = x1; theta[i1] += x1; } } } /********************************************************/ /* 与えられた入力パターンに対する各ユニットの出力の計算 */ /********************************************************/ void Forward() { double sum; int i1, i2; for (i1 = nou-noiu-1; i1 >= 0; i1--) { sum = -theta[i1]; for (i2 = i1+1; i2 < nou; i2++) { if (con[i1][i2] > 0) sum -= w[i1][i2] * op[i2]; } op[i1] = (f_type == 0) ? 1.0 / (1.0 + Math.exp(sum)) : 1.0 - 2.0 / (1.0 + Math.exp(sum)); } } /*****************************/ /* 学習の実行 */ /* p : 認識パターン */ /* m_tri : 最大学習回数 */ /*****************************/ void Learn(BackData p, int m_tri) { int i1, i2, k0 = -1, k1; /* エラーチェック */ if (noiu != p.noiu || noou != p.noou) { System.out.print("***error 入力または出力ユニットの数が違います\n"); System.exit(1); } for (i1 = 0; i1 < m_tri; i1++) { /* パターンを与える順番の決定 */ if (order == 0) { // 順番 k0++; if (k0 >= p.noip) k0 = 0; } else { // ランダム k0 = (int)(rn.nextDouble() * p.noip); if (k0 >= p.noip) k0 = p.noip - 1; } /* 出力ユニットの結果を計算 */ k1 = nou - noiu; for (i2 = 0; i2 < noiu; i2++) op[k1+i2] = p.iptn[k0][i2]; Forward(); /* 重みとバイアスの修正 */ Err_back(p.optn[k0]); } } /***********************************************/ /* 与えられた対象の認識と出力 */ /* p : 認識パターン */ /* pr : =0 : 出力を行わない */ /* =1 : 出力を行う */ /* =2 : 出力を行う(未学習パターン) */ /* tri : 現在の学習回数 */ /* return : 誤って認識したパターンの数 */ /***********************************************/ int Recog(BackData p, int pr, int tri) throws IOException, FileNotFoundException { int i1, i2, k1, No = 0, ln, sw; String next; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); /* ファイルのオープン */ PrintStream out = null; if (p_type < 0 && pr > 0) { if (pr == 1) { out = new PrintStream(new FileOutputStream(o_file)); out.print("***学習パターン***\n\n"); } else { out = new PrintStream(new FileOutputStream(o_file, true)); out.print("\n***未学習パターン***\n\n"); } } /* 各パターンに対する出力 */ for (i1 = 0; i1 < p.noip; i1++) { // 入力パターンの設定 k1 = nou - noiu; for (i2 = 0; i2 < noiu; i2++) op[k1+i2] = p.iptn[i1][i2]; // 出力の計算 Forward(); // 結果の表示 if (p_type != 0 && pr > 0) { System.out.print("入力パターン" + (i1+1) + " "); for (i2 = 0; i2 < noiu; i2++) { System.out.print(" " + op[k1+i2]); if (i2 == noiu-1) System.out.print("\n"); else { if(((i2+1) % 10) == 0) System.out.print("\n "); } } System.out.print("\n 出力パターン(理想) "); for (i2 = 0; i2 < noou; i2++) { System.out.print(" " + p.optn[i1][i2]); if (i2 == noou-1) System.out.print("\n"); else { if(((i2+1) % 5) == 0) System.out.print("\n "); } } } sw = 0; if (p_type != 0 && pr > 0) System.out.print(" (実際) "); for (i2 = 0; i2 < noou; i2++) { if (p_type != 0 && pr > 0) { System.out.print(" " + op[i2]); if (i2 == noou-1) System.out.print("\n"); else { if(((i2+1) % 5) == 0) System.out.print("\n "); } } if (Math.abs(op[i2]-p.optn[i1][i2]) > eps) sw = 1; } if (sw > 0) No++; if (p_type < 0 && pr > 0) { out.print("入力パターン" + (i1+1) + " "); for (i2 = 0; i2 < noiu; i2++) { out.print(" " + op[k1+i2]); if (i2 == noiu-1) out.print("\n"); else { if(((i2+1) % 10) == 0) out.print("\n "); } } out.print("\n 出力パターン(理想) "); for (i2 = 0; i2 < noou; i2++) { out.print(" " + p.optn[i1][i2]); if (i2 == noou-1) out.print("\n"); else { if(((i2+1) % 5) == 0) out.print("\n "); } } out.print(" (実際) "); for (i2 = 0; i2 < noou; i2++) { out.print(" " + op[i2]); if (i2 == noou-1) out.print("\n"); else { if(((i2+1) % 5) == 0) out.print("\n "); } } } if (p_type != 0 && pr > 0) next = in.readLine(); } /* 重みの出力 */ if ((p_type < -1 || p_type > 1) && pr == 1) { System.out.print(" 重み\n"); for (i1 = 0; i1 < nou-noiu; i1++) { System.out.print(" to " + (i1+1) + " from "); ln = -1; for (i2 = 0; i2 < nou; i2++) { if (con[i1][i2] > 0) { if (ln <= 0) { if (ln < 0) ln = 0; else System.out.print("\n "); } System.out.print(" " + (i2+1) + " " + w[i1][i2]); ln += 1; if (ln == 4) ln = 0; } } System.out.print("\n"); } System.out.print("\n バイアス "); ln = 0; for (i1 = 0; i1 < nou-noiu; i1++) { System.out.print(" " + (i1+1) + " " + theta[i1]); ln += 1; if (ln == 4 && i1 != nou-noiu-1) { ln = 0; System.out.print("\n "); } } if (ln != 0) System.out.print("\n"); next = in.readLine(); } if (p_type < 0 && pr == 1) { out.print(" 重み\n"); for (i1 = 0; i1 < nou-noiu; i1++) { out.print(" to " + (i1+1) + " from "); ln = -1; for (i2 = 0; i2 < nou; i2++) { if (con[i1][i2] > 0) { if (ln <= 0) { if (ln < 0) ln = 0; else out.print("\n "); } out.print(" " + (i2+1) + " " + w[i1][i2]); ln += 1; if (ln == 4) ln = 0; } } out.print("\n"); } out.print("\n バイアス "); ln = 0; for (i1 = 0; i1 < nou-noiu; i1++) { out.print(" " + (i1+1) + " " + theta[i1]); ln += 1; if (ln == 4 && i1 != nou-noiu-1) { ln = 0; out.print("\n "); } } if (ln != 0) out.print("\n"); } if (p_type < 0 && pr > 0) out.close(); return No; } } /*******************/ /* クラスWinの定義 */ /*******************/ class Win extends Frame { byte con[][]; // 接続関係 int nohu[]; // 各層のユニット数(入力層から出力層) int nolvl; // 層の数 int nou; // ユニット数 int c_size; // 円の大きさ(直径) int f_size; // フォントサイズ int width; // 画面の幅 int height; // 画面の高さ int x[], y[]; // ユニットの位置 /**************************************************/ /* コンストラクタ */ /* name : Windowのタイトル */ /* c_size_i : 円の大きさ(直径) */ /* f_size_i : フォントサイズ */ /* width_i : 画面の幅 */ /* height_i : 画面の高さ */ /* noiu_i : 入力層のユニット数 */ /* nohu_i : 各層のユニット数(入力層を除く) */ /* nolvl_i : 層の数(入力層を除く) */ /* con_i : 接続関係 */ /**************************************************/ Win (String name, int c_size_i, int f_size_i, int width_i, int height_i, int noiu_i, int nohu_i[], int nolvl_i, byte con_i[][]) { // Frameクラスのコンストラクタ(Windowのタイトルを引き渡す) super(name); // データの設定 int i1, i2; c_size = c_size_i; f_size = f_size_i; width = width_i; height = height_i; nou = noiu_i; for (i1 = 0; i1 <= nolvl_i; i1++) nou += nohu_i[i1]; nolvl = nolvl_i + 2; nohu = new int [nolvl]; for (i1 = 0; i1 <= nolvl_i; i1++) nohu[i1+1] = nohu_i[i1]; nohu[0] = noiu_i; con = new byte [nou][nou]; for (i1 = 0; i1 < nou; i1++) { for (i2 = 0; i2 < nou; i2++) con[i1][i2] = con_i[i1][i2]; } x = new int [nou]; y = new int [nou]; // Windowの大きさ setSize(width, height); // ウィンドウを表示 setVisible(true); // イベントアダプタ addWindowListener(new WinEnd()); } /********/ /* 描画 */ /********/ public void paint (Graphics g) { // 初期設定 int y_s = (f_size > 25) ? 25 + f_size : 50; int y_e = (c_size > 20 ) ? height - c_size - 10 : height - 30; int c_x, c_y = y_s; int i1, i2, k = 0; int x_step, y_step = (y_e - y_s) / (nolvl - 1); Font f; // フォントサイズ if (f_size > 0) { f = new Font("TimesRoman", Font.PLAIN, f_size); g.setFont(f); } // 各ユニットを描く for (i1 = nolvl-1; i1 >= 0; i1--) { x_step = width / nohu[i1]; c_x = x_step / 2; for (i2 = 0; i2 < nohu[i1]; i2++) { x[k] = c_x; y[k] = c_y; g.fillOval(x[k], y[k], c_size, c_size); if (f_size > 0) g.drawString(Integer.toString(k+1), x[k]-f_size/2, y[k]); c_x += x_step; k++; } c_y += y_step; } // 接続関係を描く k = c_size / 2; for (i1 = 0; i1 < nou-nohu[0]; i1++) { for (i2 = i1+1; i2 < nou; i2++ ) { if (con[i1][i2] != 0) g.drawLine(x[i1]+k, y[i1]+k, x[i2]+k, y[i2]+k); } } } /************/ /* 終了処理 */ /************/ class WinEnd extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } } /* ------------------------制御データ---------------- 誤差 0.1 出力 -2 出力ファイル kekka 順番 0 η 0.5 α 0.8 画面表示(円の大きさ,フォントサイズ,幅,高さ) 20 20 400 300 ------------------------構造データ---------------- 入力ユニット数 2 出力ユニット数 1 関数タイプ 0 隠れ層の数 1 各隠れ層のユニット数(下から) 1 バイアス入力ユニット数 1 ユニット番号:出力ユニットから順に番号付け 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1])) 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限) 1 -1 -0.05 0.05 接続方法の数 2 ユニット番号:ユニットk1からk2を,k3からk4に接続 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限) 3 4 1 2 1 -0.1 0.1 2 2 1 1 1 -0.1 0.1 ------------------------学習データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 ------------------------認識データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 */
<!DOCTYPE HTML> <HTML> <HEAD> <TITLE>back propagation model</TITLE> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8"> <SCRIPT TYPE="text/javascript"> res = ""; net = null; dt1 = null; dt2 = null; /****************/ /* main program */ /****************/ function main() { let m_tri = parseInt(document.getElementById("m_tri").value); // ネットワークの定義 net = new Backpr(); // 学習パターンの入力 dt1 = new BackData("ptn1"); // 学習 net.Learn(dt1, m_tri); // 学習 let no = net.Recog(dt1, 1, m_tri); // 学習対象の認識 res += ("\n+++学習終了 回数 " + m_tri + " 誤って認識したパターン数 " + no + "\n\n"); // 未学習パターンの認識 dt2 = new BackData("ptn2"); no = net.Recog(dt2, 2, m_tri); // 未学習対象の認識と出力 document.getElementById("result").value = res; } /********************************/ /* BackDataオブジェクト */ /* name : テキストエリア名 */ /********************************/ function BackData(name) { let lines = (document.getElementById(name).value).split('\n'); // // 入力パターン数等 // let str = lines[0].split(' ').filter(function(e){return e.length > 0;}); this.noip = parseInt(str[1]); // 入力ユニットの数 this.noiu = parseInt(str[3]); // 出力ユニットの数 this.noou = parseInt(str[5]); // 入力パターンの数 // // 領域の確保 // this.iptn = new Array(this.noip); // iptn[i][j] : (i+1)番目の入力パターンの(j+1)番目の // 入力ユニットの入力値 // i=0,noip-1 j=0,noiu-1 this.optn = new Array(this.noip); // optn[i][j] : (i+1)番目の入力パターンに対する(j+1) // 番目の出力ユニットの目標出力値 // i=0,noip-1 j=0,noou-1 for (let i1 = 0; i1 < this.noip; i1++) { this.iptn[i1] = new Array(this.noiu); this.optn[i1] = new Array(this.noou); } // // 入力パターン及び各入力パターンに対する出力パターンの入力 // for (let i1 = 0; i1 < this.noip; i1++) { let k = 2 * i1 + 1; str = lines[k].split(' ').filter(function(e){return e.length > 0;}); for (let i2 = 0; i2 < this.noiu; i2++) this.iptn[i1][i2] = parseFloat(str[i2+1]); str = lines[k+1].split(' ').filter(function(e){return e.length > 0;}); for (let i2 = 0; i2 < this.noou; i2++) this.optn[i1][i2] = parseFloat(str[i2+1]); } } /**********************/ /* Backprオブジェクト */ /**********************/ function Backpr() { // // 制御用データ // let lines = (document.getElementById("data1").value).split('\n'); // 1 行目 let str = lines[0].split(' ').filter(function(e){return e.length > 0;}); this.eps = parseFloat(str[1]); // 許容誤差 this.p_type = parseInt(str[3]); // 出力先・方法の指定 // =0 : 誤って認識した数だけ出力 // =1 : 認識結果を出力 // =2 : 認識結果と重みを出力 // 2 行目 str = lines[1].split(' ').filter(function(e){return e.length > 0;}); this.order = parseInt(str[1]); // 入力パターンの与え方(=0:順番,=1:ランダム) this.eata = parseFloat(str[3]); //重み及びバイアス修正パラメータ this.alpha = parseFloat(str[5]); //重み及びバイアス修正パラメータ // // 入力ユニット,出力ユニットの数,関数タイプ // lines = (document.getElementById("data2").value).split('\n'); str = lines[0].split(' ').filter(function(e){return e.length > 0;}); this.noiu = parseInt(str[1]); // 入力ユニットの数 this.noou = parseInt(str[3]); // 出力ユニットの数 this.f_type = parseInt(str[5]); // シグモイド関数のタイプ // 0 : [0,1] // 1 : [-1,1]) this.nou = this.noiu + this.noou; // 入力ユニットと出力ユニットの和 // // 隠れユニットの階層数と各階層のユニット数 // str = lines[1].split(' ').filter(function(e){return e.length > 0;}); this.nolvl = parseInt(str[1]); // 隠れユニットの階層数 this.nohu = new Array(this.nolvl+1); // nohu[i] : レベル(i+1)の隠れ層のユニット数(隠れ層 // には下から順に番号が付けられ,出力層はレ // ベル(nolvl+1)の隠れ層とも見做される) // i=0,nolvl this.nohu[this.nolvl] = this.noou; // 出力ユニットの数 if (this.nolvl > 0) { for (let i1 = 0; i1 < this.nolvl; i1++) { this.nohu[i1] = parseInt(str[i1+3]); this.nou += this.nohu[i1]; } } // // 領域の確保 // this.con = new Array(this.nou); // con[i][j] : 各ユニットに対するバイアスの与え方,及び, // 接続方法 // [i][i] : ユニット(i+1)のバイアスの与え方 // =-3 : 入力値で固定 // =-2 : 入力値を初期値として,学習により変更 // =-1 : 乱数で初期値を設定し,学習により変更 // [i][j] : ユニット(i+1)と(j+1)の接続方法(j>i) // =0 : 接続しない // =1 : 接続する(重みの初期値を乱数で設定し,学習) // =2 : 接続する(重みの初期値を入力で与え,学習) // =3 : 接続する(重みを入力値に固定) // i=0,nou-1 j=0,nou-1 for (let i1 = 0; i1 < this.nou; i1++) { this.con[i1] = new Array(this.nou); for (let i2 = 0; i2 < this.nou; i2++) this.con[i1][i2] = (i1 == i2) ? -1 : 0; } this.w = new Array(this.nou); // w[i][j] : ユニット(i+1)から(j+1)への重み(j>i) // w[j][i] : (i+1)から(j+1)への重みの前回修正量(j>i) // w[i][i] : ユニット(i+1)のバイアスの前回修正量 // i=0,nou-1 j=0,nou-1 for (let i1 = 0; i1 < this.nou; i1++) { this.w[i1] = new Array(this.nou); for (let i2 = 0; i2 < this.nou; i2++) this.w[i1][i2] = 0.0; } this.dp = new Array(this.nou); // dp[i] : ユニット(i+1)の誤差 i=0,nou-1 this.op = new Array(this.nou); // op[i] : ユニット(i+1)の出力 i=0,nou-1 this.theta = new Array(this.nou); //theta[i] : ユニット(i+1)のバイアス i=0,nou for (let i1 = 0; i1 < this.nou; i1++) this.theta[i1] = 0.2 * Math.random() - 0.1; // // 各ユニットのバイアスとユニット間の接続関係 // // バイアス // バイアスデータの数 str = lines[2].split(' ').filter(function(e){return e.length > 0;}); let nb = parseInt(str[1]); if (nb > 0) { // バイアスデータの処理 for (let i0 = 0; i0 < nb; i0++) { // ユニット番号 str = lines[i0+6].split(' ').filter(function(e){return e.length > 0;}); let k1 = parseInt(str[0]); // 不適当なユニット番号のチェック if (k1 < 1 || k1 > (this.nou-this.noiu)) alert("***error ユニット番号 " + k1 + " が不適当"); // バイアスの与え方 k1--; let id = parseInt(str[1]); this.con[k1][k1] = id; // バイアスの初期設定 switch (this.con[k1][k1]) { case -1: let x1 = parseFloat(str[2]); let x2 = parseFloat(str[3]); this.theta[k1] = (x2 - x1) * Math.random() + x1; break; case -2: this.theta[k1] = parseFloat(str[2]); break; case -3: this.theta[k1] = parseFloat(str[2]); break; default: alert("***error バイアスの与え方が不適当"); break; } } } // 接続方法 // 接続データの数 str = lines[nb+6].split(' ').filter(function(e){return e.length > 0;}); let n = parseInt(str[1]); if (n > 0) { // 接続データの処理 for (let i0 = 0; i0 < n; i0++) { // 接続情報 str = lines[nb+10+i0].split(' ').filter(function(e){return e.length > 0;}); let k1 = parseInt(str[0]); let k2 = parseInt(str[1]); let k3 = parseInt(str[2]); let k4 = parseInt(str[3]); // 不適切な接続のチェック let sw = 0; if (k1 < 1 || k2 < 1 || k3 < 1 || k4 < 1) sw = 1; else { if (k1 > this.nou || k2 > this.nou || k3 > this.nou || k4 > this.nou) sw = 1; else { if (k1 > k2 || k3 > k4) sw = 1; else { if (k4 >= k1) sw = 1; else { let l1 = -1; let k = 0; for (let i1 = this.nolvl; i1 >= 0 && l1 < 0; i1--) { k += this.nohu[i1]; if (k1 <= k) l1 = i1; } let l2 = -1; k = 0; for (let i1 = this.nolvl; i1 >= 0 && l2 < 0; i1--) { k += this.nohu[i1]; if (k4 <= k) l2 = i1; } if (l2 <= l1) sw = 1; } } } } if (sw > 0) alert("***error ユニット番号が不適当(" + k1 + " " + k2 + " " + k3 + " " + k4 + ")"); // 重みの初期値の与え方 k1--; k2--; k3--; k4--; let id = parseInt(str[4]); let x1 = 0.0; let x2 = 0.0; if (id == 1) { x1 = parseFloat(str[5]); x2 = parseFloat(str[6]); } else { if (id > 1) x1 = parseFloat(str[5]); else { if (id != 0) alert("***error 接続方法が不適当"); } } // 重みの初期値の設定 for (let i1 = k3; i1 <= k4; i1++) { for (let i2 = k1; i2 <= k2; i2++) { this.con[i1][i2] = id; switch (id) { case 0: this.w[i1][i2] = 0.0; break; case 1: this.w[i1][i2] = (x2 - x1) * Math.random() + x1; break; case 2: this.w[i1][i2] = x1; break; case 3: this.w[i1][i2] = x1; break; } } } } } } /******************************************/ /* 誤差の計算,及び,重みとバイアスの修正 */ /* ptn[i1] : 出力パターン */ /******************************************/ Backpr.prototype.Err_back = function(ptn) { for (let i1 = 0; i1 < net.nou-net.noiu; i1++) { // 誤差の計算 if (i1 < net.noou) { if (net.f_type == 0) net.dp[i1] = (ptn[i1] - net.op[i1]) * net.op[i1] * (1.0 - net.op[i1]); else net.dp[i1] = 0.5 * (ptn[i1] - net.op[i1]) * (net.op[i1] - 1.0) * (net.op[i1] + 1.0); } else { let x1 = 0.0; for (let i2 = 0; i2 < i1; i2++) { if (net.con[i2][i1] > 0) x1 += net.dp[i2] * net.w[i2][i1]; } if (net.f_type == 0) net.dp[i1] = net.op[i1] * (1.0 - net.op[i1]) * x1; else net.dp[i1] = 0.5 * (net.op[i1] - 1.0) * (net.op[i1] + 1.0) * x1; } // 重みの修正 for (let i2 = i1+1; i2 < net.nou; i2++) { if (net.con[i1][i2] == 1 || net.con[i1][i2] == 2) { let x1 = net.eata * net.dp[i1] * net.op[i2] + net.alpha * net.w[i2][i1]; net.w[i2][i1] = x1; net.w[i1][i2] += x1; } } // バイアスの修正 if (net.con[i1][i1] >= -2) { let x1 = net.eata * net.dp[i1] + net.alpha * net.w[i1][i1]; net.w[i1][i1] = x1; net.theta[i1] += x1; } } } /********************************************************/ /* 与えられた入力パターンに対する各ユニットの出力の計算 */ /********************************************************/ Backpr.prototype.Forward = function() { for (let i1 = net.nou-net.noiu-1; i1 >= 0; i1--) { let sum = -net.theta[i1]; for (let i2 = i1+1; i2 < net.nou; i2++) { if (net.con[i1][i2] > 0) sum -= net.w[i1][i2] * net.op[i2]; } net.op[i1] = (net.f_type == 0) ? 1.0 / (1.0 + Math.exp(sum)) : 1.0 - 2.0 / (1.0 + Math.exp(sum)); } } /*****************************/ /* 学習の実行 */ /* p : 認識パターン */ /* m_tri : 最大学習回数 */ /*****************************/ Backpr.prototype.Learn = function(p, m_tri) { // // エラーチェック // if (net.noiu != p.noiu || net.noou != p.noou) alert("***error 入力または出力ユニットの数が違います"); let k0 = -1; for (let i1 = 0; i1 < m_tri; i1++) { // // パターンを与える順番の決定 // if (net.order == 0) { // 順番 k0++; if (k0 >= p.noip) k0 = 0; } else { // ランダム k0 = Math.floor(Math.random() * p.noip); if (k0 >= p.noip) k0 = p.noip - 1; } // // 出力ユニットの結果を計算 // let k1 = net.nou - net.noiu; for (let i2 = 0; i2 < net.noiu; i2++) net.op[k1+i2] = p.iptn[k0][i2]; net.Forward(); // // 重みとバイアスの修正 // net.Err_back(p.optn[k0]); } } /********************************************/ /* 与えられた対象の認識と出力 */ /* p : 認識パターン */ /* pr : =1 : 学習パターン */ /* =2 : 未学習パターン */ /* tri : 現在の学習回数 */ /* return : 誤って認識したパターンの数 */ /********************************************/ Backpr.prototype.Recog = function(p, pr, tri) { if (pr == 1) res = "***学習パターン***\n"; else res += "***未学習パターン***\n"; // // 各パターンに対する出力 // let No = 0; for (let i1 = 0; i1 < p.noip; i1++) { // 入力パターンの設定 let k1 = net.nou - net.noiu; for (let i2 = 0; i2 < net.noiu; i2++) net.op[k1+i2] = p.iptn[i1][i2]; // 出力の計算 net.Forward(); // 結果の表示 if (net.p_type != 0 && pr > 0) { res += ("入力パターン" + (i1+1) + " "); for (let i2 = 0; i2 < net.noiu; i2++) { res += (" " + net.op[k1+i2]); if (i2 == net.noiu-1) res += "\n"; else { if(((i2+1) % 10) == 0) { res += "\n"; res += " "; } } } res += "\n"; res += (" 出力パターン(理想) "); for (let i2 = 0; i2 < net.noou; i2++) { res += (" " + p.optn[i1][i2]); if (i2 == net.noou-1) res += "\n"; else { if(((i2+1) % 5) == 0) { res += "\n"; res += " "; } } } } let sw = 0; if (net.p_type != 0 && pr > 0) res += (" (実際) "); for (let i2 = 0; i2 < net.noou; i2++) { if (net.p_type != 0 && pr > 0) { res += (" " + net.op[i2]); if (i2 == net.noou-1) res += "\n"; else { if(((i2+1) % 5) == 0) { res += "\n"; res += " "; } } } if (Math.abs(net.op[i2]-p.optn[i1][i2]) > net.eps) sw = 1; } if (sw > 0) No++; } // // 重みの出力 // let ln; if ((net.p_type < -1 || net.p_type > 1) && pr == 1) { res += (" 重み"); for (let i1 = 0; i1 < net.nou-net.noiu; i1++) { res += (" to " + (i1+1) + " from "); ln = -1; for (let i2 = 0; i2 < net.nou; i2++) { if (net.con[i1][i2] > 0) { if (ln <= 0) { if (ln < 0) ln = 0; else { res += "\n"; res += (" "); } } res += (" " + (i2+1) + " " + net.w[i1][i2]); ln += 1; if (ln == 4) ln = 0; } } res += "\n"; } res += "\n"; res += (" バイアス "); ln = 0; for (let i1 = 0; i1 < net.nou-net.noiu; i1++) { res += (" " + (i1+1) + " " + net.theta[i1]); ln += 1; if (ln == 4 && i1 != net.nou-net.noiu-1) { ln = 0; res += "\n"; res += (" "); } } if (ln != 0) res += "\n"; } return No; } </SCRIPT> </HEAD> <BODY STYLE="font-size: 130%; text-align:center; background-color: #eeffee;"> <H2><B>back propagation model</B></H2> 学習回数:<INPUT ID="m_tri" STYLE="font-size: 100%" TYPE="text" SIZE="5" VALUE="5000"> <BUTTON STYLE="font-size: 100%; background-color: pink" onClick="return main()">実行</BUTTON><BR> <DIV STYLE="width: 800px; margin-right: auto; margin-left: auto"> <DIV STYLE="text-align:center; float: right; width: 400px"> <DIV STYLE="text-align:center">構造データ</DIV> <TEXTAREA ID="data2" COLS="35" ROWS="10" STYLE="font-size: 100%; width: 380px"> 入力ユニット数 2 出力ユニット数 1 関数タイプ 0 隠れ層の数 1 各隠れ層のユニット数(下から) 1 バイアス入力ユニット数 1 ユニット番号:出力ユニットから順に番号付け 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1])) 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限) 1 -1 -0.1 0.1 接続方法の数 2 ユニット番号:ユニットk1からk2を,k3からk4に接続 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限) 3 4 1 2 1 -0.1 0.1 2 2 1 1 1 -0.1 0.1 </TEXTAREA> </DIV> <DIV STYLE="text-align:center; width: 400px"> <DIV STYLE="text-align:center">制御データ</DIV> <TEXTAREA ID="data1" COLS="35" ROWS="10" STYLE="font-size: 100%; width: 380px"> 誤差 0.1 出力 2 出力ファイル kekka 順番 0 η 0.5 α 0.8 </TEXTAREA> </DIV> <DIV STYLE="text-align:center; float: right; width: 400px"> <DIV STYLE="text-align:center">未学習パターン</DIV> <TEXTAREA ID="ptn2" COLS="35" ROWS="10" STYLE="font-size: 100%; width: 380px"> パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 </TEXTAREA> </DIV> <DIV STYLE="text-align:center; width: 400px"> <DIV STYLE="text-align:center">学習パターン</DIV> <TEXTAREA ID="ptn1" COLS="35" ROWS="10" STYLE="font-size: 100%; width: 380px"> パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 </TEXTAREA> </DIV> <DIV STYLE="text-align:center">結果</DIV> <TEXTAREA ID="result" COLS="70" ROWS="10" STYLE="font-size: 100%;"> </TEXTAREA> </DIV> </BODY> </HTML>
<?php /****************************/ /* back propagation model */ /* coded by Y.Suganuma */ /****************************/ /******************************************************/ /* バックプロパゲーションの制御(クラス BackControl) */ /******************************************************/ class BackControl { protected $alpha; //重み及びバイアス修正パラメータ protected $eata; protected $eps; // 許容誤差 protected $order; // 入力パターンの与え方(=0:順番,=1:ランダム) protected $p_type; // 出力先・方法の指定 // =0 : 誤って認識した数だけ出力 // =1 : 認識結果を出力 // =2 : 認識結果と重みを出力 // (負の時は,認識結果と重みをファイルへも出力) protected $o_file; // 出力ファイル名 /*************************************/ /* クラスBackControlのコンストラクタ */ /* name : 入力データファイル名 */ /*************************************/ function BackControl($name) { $in = fopen($name, "rb"); $str = trim(fgets($in)); strtok($str, " "); $this->eps = floatval(strtok(" ")); strtok(" "); $this->p_type = intval(strtok(" ")); if ($this->p_type < 0) { strtok(" "); $this->o_file = strtok(" "); } fscanf($in, "%*s %d %*s %lf %*s %lf", $this->order, $this->eata, $this->alpha); fclose($in); } } /*****************************************************/ /* バックプロパゲーションのデータ(クラス BackData) */ /*****************************************************/ class BackData { public $noiu; // 入力ユニットの数 public $noou; // 出力ユニットの数 public $noip; // 入力パターンの数 public $iptn; // iptn[i][j] : (i+1)番目の入力パターンの(j+1)番目の // 入力ユニットの入力値 // i=0,noip-1 j=0,noiu-1 public $optn; // optn[i][j] : (i+1)番目の入力パターンに対する(j+1) // 番目の出力ユニットの目標出力値 // i=0,noip-1 j=0,noou-1 /************************************/ /* クラスBackDataのコンストラクタ */ /* name : 入力データファイル名 */ /************************************/ function BackData($name) { $in = fopen($name, "rb"); /* 入力パターン数等 */ fscanf($in, "%*s %d %*s %d %*s %d", $this->noip, $this->noiu, $this->noou); /* 領域の確保 */ $this->iptn = array($this->noip); for ($i1 = 0; $i1 < $this->noip; $i1++) $this->iptn[$i1] = array($this->noiu); $this->optn = array($this->noip); for ($i1 = 0; $i1 < $this->noip; $i1++) $this->optn[$i1] = array($this->noou); /* 入力パターン及び各入力パターンに対する出力パターンの入力 */ for ($i1 = 0; $i1 < $this->noip; $i1++) { $str = trim(fgets($in)); strtok($str, " "); for ($i2 = 0; $i2 < $this->noiu; $i2++) $this->iptn[$i1][$i2] = intval(strtok(" ")); $str = trim(fgets($in)); strtok($str, " "); for ($i2 = 0; $i2 < $this->noou; $i2++) $this->optn[$i1][$i2] = intval(strtok(" ")); } fclose($in); } } /*******************************************/ /* バックプロパゲーション(クラス Backpr) */ /*******************************************/ class Backpr extends BackControl { public $con; // con[i][j] : 各ユニットに対するバイアスの与え方,及び, // 接続方法 // [i][i] : ユニット(i+1)のバイアスの与え方 // =-3 : 入力値で固定 // =-2 : 入力値を初期値として,学習により変更 // =-1 : 乱数で初期値を設定し,学習により変更 // [i][j] : ユニット(i+1)と(j+1)の接続方法(j>i) // =0 : 接続しない // =1 : 接続する(重みの初期値を乱数で設定し,学習) // =2 : 接続する(重みの初期値を入力で与え,学習) // =3 : 接続する(重みを入力値に固定) // i=0,nou-1 j=0,nou-1 public $f_type; // シグモイド関数のタイプ // 0 : [0,1] // 1 : [-1,1]) public $noiu; // 入力ユニットの数 public $noou; // 出力ユニットの数 public $nohu; // nohu[i] : レベル(i+1)の隠れ層のユニット数(隠れ層 // には下から順に番号が付けられ,出力層はレ // ベル(nolvl+1)の隠れ層とも見做される) // i=0,nolvl public $nolvl; // 隠れユニットの階層数 public $nou; // 入力,出力,及び,隠れ層の各ユニットの数の和(各ユニ // ットには最も上の出力ユニットから,隠れ層の各ユニット, // 及び,入力ユニットに至る一連のユニット番号が付けられ // る) public $dp; // dp[i] : ユニット(i+1)の誤差 i=0,nou-1 public $op; // op[i] : ユニット(i+1)の出力 i=0,nou-1 public $theta; //theta[i] : ユニット(i+1)のバイアス i=0,nou public $w; // w[i][j] : ユニット(i+1)から(j+1)への重み(j>i) // w[j][i] : (i+1)から(j+1)への重みの前回修正量(j>i) // w[i][i] : ユニット(i+1)のバイアスの前回修正量 // i=0,nou-1 j=0,nou-1 /************************************************/ /* クラスBackprのコンストラクタ */ /* name_c : 制御データ用入力ファイル名 */ /* name_s : ネットワーク記述入力ファイル名 */ /************************************************/ function Backpr($name_c, $name_s) { parent::BackControl($name_c); $in = fopen($name_s, "rb"); /* 乱数の初期化 */ mt_srand(); /* 入力ユニット,出力ユニットの数,関数タイプ */ fscanf($in, "%*s %d %*s %d %*s %d", $this->noiu, $this->noou, $this->f_type); $this->nou = $this->noiu + $this->noou; // 入力ユニットと出力ユニットの和 /* 隠れユニットの階層数と各階層のユニット数 */ $str = trim(fgets($in)); strtok($str, " "); $this->nolvl = intval(strtok(" ")); $this->nohu = array($this->nolvl+1); $this->nohu[$this->nolvl] = $this->noou; // 出力ユニットの数 if ($this->nolvl > 0) { strtok(" "); for ($i1 = 0; $i1 < $this->nolvl; $i1++) { $this->nohu[$i1] = intval(strtok(" ")); $this->nou += $this->nohu[$i1]; } } /* 領域の確保 */ $this->con = array($this->nou); for ($i1 = 0; $i1 < $this->nou; $i1++) { $this->con[$i1] = array($this->nou); for ($i2 = 0; $i2 < $this->nou; $i2++) $this->con[$i1][$i2] = ($i1 == $i2) ? -1 : 0; } $this->w = array($this->nou); for ($i1 = 0; $i1 < $this->nou; $i1++) { $this->w[$i1] = array($this->nou); for ($i2 = 0; $i2 < $this->nou; $i2++) $this->w[$i1][$i2] = 0.0; } $this->dp = array($this->nou); $this->op = array($this->nou); $this->theta = array($this->nou); for ($i1 = 0; $i1 < $this->nou; $i1++) $this->theta[$i1] = 0.2 * mt_rand() / mt_getrandmax() - 0.1; /* 各ユニットのバイアスとユニット間の接続関係 */ // バイアス // バイアスデータの数 fscanf($in, "%*s %d", $n); fgets($in); fgets($in); fgets($in); if ($n > 0) { // バイアスデータの処理 for ($i0 = 0; $i0 < $n; $i0++) { $str = trim(fgets($in)); // ユニット番号 $k1 = intval(strtok($str, " ")); // 不適当なユニット番号のチェック if ($k1 < 1 || $k1 > ($this->nou-$this->noiu)) exit("***error ユニット番号 ".$k1." が不適当\n"); // バイアスの与え方 $k1--; $id = intval(strtok(" ")); $this->con[$k1][$k1] = $id; // バイアスの初期設定 switch ($this->con[$k1][$k1]) { case -1: $x1 = floatval(strtok(" ")); $x2 = floatval(strtok(" ")); $this->theta[$k1] = ($x2 - $x1) * mt_rand() / mt_getrandmax() + $x1; break; case -2: $this->theta[$k1] = floatval(strtok(" ")); break; case -3: $this->theta[$k1] = floatval(strtok(" ")); break; default: exit("***error バイアスの与え方が不適当\n"); } } } // 接続方法 // 接続データの数 fscanf($in, "%*s %d", $n); fgets($in); fgets($in); fgets($in); if ($n > 0) { // 接続データの処理 for ($i0 = 0; $i0 < $n; $i0++) { $str = trim(fgets($in)); // 接続情報 $k1 = intval(strtok($str, " ")); $k2 = intval(strtok(" ")); $k3 = intval(strtok(" ")); $k4 = intval(strtok(" ")); // 不適切な接続のチェック $sw = 0; if ($k1 < 1 || $k2 < 1 || $k3 < 1 || $k4 < 1) $sw = 1; else { if ($k1 > $this->nou || $k2 > $this->nou || $k3 > $this->nou || $k4 > $this->nou) $sw = 1; else { if ($k1 > $k2 || $k3 > $k4) $sw = 1; else { if ($k4 >= $k1) $sw = 1; else { $l1 = -1; $k = 0; for ($i1 = $this->nolvl; $i1 >= 0 && $l1 < 0; $i1--) { $k += $this->nohu[$i1]; if ($k1 <= $k) $l1 = $i1; } $l2 = -1; $k = 0; for ($i1 = $this->nolvl; $i1 >= 0 && $l2 < 0; $i1--) { $k += $this->nohu[$i1]; if ($k4 <= $k) $l2 = $i1; } if ($l2 <= $l1) $sw = 1; } } } } if ($sw > 0) exit("***error ユニット番号が不適当(".$k1." ".$k2." ".$k3." ".$k4."\n"); // 重みの初期値の与え方 $k1--; $k2--; $k3--; $k4--; $id = intval(strtok(" ")); if ($id == 1) { $x1 = floatval(strtok(" ")); $x2 = floatval(strtok(" ")); } else { if ($id > 1) $x1 = floatval(strtok(" ")); else { if ($id != 0) exit("***error 接続方法が不適当\n"); } } // 重みの初期値の設定 for ($i1 = $k3; $i1 <= $k4; $i1++) { for ($i2 = $k1; $i2 <= $k2; $i2++) { $this->con[$i1][$i2] = $id; switch ($id) { case 0: $this->w[$i1][$i2] = 0.0; break; case 1: $this->w[$i1][$i2] = ($x2 - $x1) * mt_rand() / mt_getrandmax() + $x1; break; case 2: $this->w[$i1][$i2] = $x1; break; case 3: $this->w[$i1][$i2] = $x1; break; } } } } } fclose($in); } /******************************************/ /* 誤差の計算,及び,重みとバイアスの修正 */ /* ptn[$i1] : 出力パターン */ /******************************************/ function Err_back($k0, $ptn) { for ($i1 = 0; $i1 < $this->nou-$this->noiu; $i1++) { // 誤差の計算 if ($i1 < $this->noou) { if ($this->f_type == 0) $this->dp[$i1] = ($ptn[$i1] - $this->op[$i1]) * $this->op[$i1] * (1.0 - $this->op[$i1]); else $this->dp[$i1] = 0.5 * ($ptn[$i1] - $this->op[$i1]) * ($this->op[$i1] - 1.0) * ($this->op[$i1] + 1.0); } else { $x1 = 0.0; for ($i2 = 0; $i2 < $i1; $i2++) { if ($this->con[$i2][$i1] > 0) $x1 += $this->dp[$i2] * $this->w[$i2][$i1]; } if ($this->f_type == 0) $this->dp[$i1] = $this->op[$i1] * (1.0 - $this->op[$i1]) * $x1; else $this->dp[$i1] = 0.5 * ($this->op[$i1] - 1.0) * ($this->op[$i1] + 1.0) * $x1; } // 重みの修正 for ($i2 = $i1+1; $i2 < $this->nou; $i2++) { if ($this->con[$i1][$i2] == 1 || $this->con[$i1][$i2] == 2) { $x1 = $this->eata * $this->dp[$i1] * $this->op[$i2] + $this->alpha * $this->w[$i2][$i1]; $this->w[$i2][$i1] = $x1; $this->w[$i1][$i2] += $x1; } } // バイアスの修正 if ($this->con[$i1][$i1] >= -2) { $x1 = $this->eata * $this->dp[$i1] + $this->alpha * $this->w[$i1][$i1]; $this->w[$i1][$i1] = $x1; $this->theta[$i1] += $x1; } } } /********************************************************/ /* 与えられた入力パターンに対する各ユニットの出力の計算 */ /********************************************************/ function Forward() { for ($i1 = $this->nou-$this->noiu-1; $i1 >= 0; $i1--) { $sum = -$this->theta[$i1]; for ($i2 = $i1+1; $i2 < $this->nou; $i2++) { if ($this->con[$i1][$i2] > 0) $sum -= $this->w[$i1][$i2] * $this->op[$i2]; } $this->op[$i1] = ($this->f_type == 0) ? 1.0 / (1.0 + exp($sum)) : 1.0 - 2.0 / (1.0 + exp($sum)); } } /*****************************/ /* 学習の実行 */ /* p : 認識パターン */ /* m_tri : 最大学習回数 */ /*****************************/ function Learn($p, $m_tri) { $k0 = -1; /* エラーチェック */ if ($this->noiu != $p->noiu || $this->noou != $p->noou) exit("***error 入力または出力ユニットの数が違います\n"); for ($i1 = 0; $i1 < $m_tri; $i1++) { /* パターンを与える順番の決定 */ if ($this->order == 0) { // 順番 $k0 += 1; if ($k0 >= $p->noip) $k0 = 0; } else { // ランダム $k0 = intval(mt_rand() / mt_getrandmax() * $p->noip); if ($k0 >= $p->noip) $k0 = $p->noip - 1; } /* 出力ユニットの結果を計算 */ $k1 = $this->nou - $this->noiu; for ($i2 = 0; $i2 < $this->noiu; $i2++) $this->op[$k1+$i2] = $p->iptn[$k0][$i2]; $this->Forward(); /* 重みとバイアスの修正 */ $this->Err_back($k0, $p->optn[$k0]); } } /***********************************************/ /* 与えられた対象の認識と出力 */ /* p : 認識パターン */ /* pr : =0 : 出力を行わない */ /* =1 : 出力を行う */ /* =2 : 出力を行う(未学習パターン) */ /* tri : 現在の学習回数 */ /* return : 誤って認識したパターンの数 */ /***********************************************/ function Recog($p, $pr, $tri) { $No = 0; /* ファイルのオープン */ if ($this->p_type < 0 && $pr > 0) { if ($pr == 1) { $out = fopen($this->o_file, "wb"); fwrite($out, "***学習パターン***\n\n"); } else { $out = fopen($this->o_file, "ab"); fwrite($out, "\n***未学習パターン***\n\n"); } } /* 各パターンに対する出力 */ for ($i1 = 0; $i1 < $p->noip; $i1++) { // 入力パターンの設定 $k1 = $this->nou - $this->noiu; for ($i2 = 0; $i2 < $this->noiu; $i2++) $this->op[$k1+$i2] = $p->iptn[$i1][$i2]; // 出力の計算 $this->Forward(); // 結果の表示 if ($this->p_type != 0 && $pr > 0) { printf("入力パターン%4d ", $i1+1); for ($i2 = 0; $i2 < $this->noiu; $i2++) { printf("%5.2f", $this->op[$k1+$i2]); if ($i2 == $this->noiu-1) printf("\n"); else { if((($i2+1) % 10) == 0) printf("\n "); } } printf("\n 出力パターン(理想) "); for ($i2 = 0; $i2 < $this->noou; $i2++) { printf("%10.3f", $p->optn[$i1][$i2]); if ($i2 == $this->noou-1) printf("\n"); else { if((($i2+1) % 5) == 0) printf("\n "); } } } $sw = 0; if ($this->p_type != 0 && $pr > 0) printf(" (実際) "); for ($i2 = 0; $i2 < $this->noou; $i2++) { if ($this->p_type != 0 && $pr > 0) { printf("%10.3f", $this->op[$i2]); if ($i2 == $this->noou-1) printf("\n"); else { if((($i2+1) % 5) == 0) printf("\n "); } } if (abs($this->op[$i2]-$p->optn[$i1][$i2]) > $this->eps) $sw = 1; } if ($sw > 0) $No++; if ($this->p_type < 0 && $pr > 0) { $str = "入力パターン".($i1+1)." "; for ($i2 = 0; $i2 < $this->noiu; $i2++) { $str = $str." ".$this->op[$k1+$i2]; if ($i2 == $this->noiu-1) $str = $str."\n"; else { if((($i2+1) % 10) == 0) $str = $str."\n "; } } fwrite($out, $str); $str = "\n 出力パターン(理想) "; for ($i2 = 0; $i2 < $this->noou; $i2++) { $str = $str." ".$p->optn[$i1][$i2]; if ($i2 == $this->noou-1) $str = $str."\n"; else { if((($i2+1) % 5) == 0) $str = $str."\n "; } } fwrite($out, $str); $str = " (実際) "; for ($i2 = 0; $i2 < $this->noou; $i2++) { $str = $str." ".$this->op[$i2]; if ($i2 == $this->noou-1) $str = $str."\n"; else { if((($i2+1) % 5) == 0) $str = $str."\n "; } } fwrite($out, $str); } if ($this->p_type != 0 && $pr > 0) { fgets(STDIN); if ($i1 == 0) fgets(STDIN); } } /* 重みの出力 */ if (($this->p_type < -1 || $this->p_type > 1) && $pr == 1) { printf(" 重み\n"); for ($i1 = 0; $i1 < $this->nou-$this->noiu; $i1++) { printf(" to%4d from ", $i1+1); $ln = -1; for ($i2 = 0; $i2 < $this->nou; $i2++) { if ($this->con[$i1][$i2] > 0) { if ($ln <= 0) { if ($ln < 0) $ln = 0; else printf("\n "); } printf("%4d%11.3f", $i2+1, $this->w[$i1][$i2]); $ln += 1; if ($ln == 4) $ln = 0; } } printf("\n"); } printf("\n バイアス "); $ln = 0; for ($i1 = 0; $i1 < $this->nou-$this->noiu; $i1++) { printf("%4d%11.3f", $i1+1, $this->theta[$i1]); $ln += 1; if ($ln == 4 && $i1 != $this->nou-$this->noiu-1) { $ln = 0; printf("\n "); } } if ($ln != 0) printf("\n"); fgets(STDIN); } if ($this->p_type < 0 && $pr == 1) { $str = " 重み\n"; for ($i1 = 0; $i1 < $this->nou-$this->noiu; $i1++) { $str = $str." to ".( $i1+1)." from "; $ln = -1; for ($i2 = 0; $i2 < $this->nou; $i2++) { if ($this->con[$i1][$i2] > 0) { if ($ln <= 0) { if ($ln < 0) $ln = 0; else $str = $str."\n "; } $str = $str.($i2+1)." ".$this->w[$i1][$i2]; $ln += 1; if ($ln == 4) $ln = 0; } } $str = $str."\n"; } fwrite($out, $str); $str = "\n バイアス "; $ln = 0; for ($i1 = 0; $i1 < $this->nou-$this->noiu; $i1++) { $str = $str.($i1+1)." ".$this->theta[$i1]; $ln += 1; if ($ln == 4 && $i1 != $this->nou-$this->noiu-1) { $ln = 0; $str = $str."\n "; } } if ($ln != 0) $str = $str."\n"; fwrite($out, $str); } if ($this->p_type < 0 && $pr > 0) fclose($out); return $No; } } /****************/ /* main program */ /****************/ $max = 0; $no = 1; // エラー if (count($argv) != 3) exit("***error 入力データファイル名を指定して下さい\n"); else { // ネットワークの定義 $net = new Backpr($argv[1], $argv[2]); // 学習パターン等の入力 printf("学習回数は? "); fscanf(STDIN, "%d", $m_tri); // 最大学習回数 printf("何回毎に収束を確認しますか? "); fscanf(STDIN, "%d", $conv); // 収束確認回数 printf("学習パターンのファイル名は? "); fscanf(STDIN, "%s", $f_name); $dt1 = new BackData($f_name); // 学習 while ($max < $m_tri && $no > 0) { $tri = (($max + $conv) < $m_tri) ? $conv : $m_tri - $max; $max += $tri; $net->Learn($dt1, $tri); // 学習 $no = $net->Recog($dt1, 0, $max); // 学習対象の認識 printf(" 回数 %d 誤って認識したパターン数 %d\n", $max, $no); } $no = $net->Recog($dt1, 1, $max); // 学習対象の認識と出力 // 未学習パターンの認識 printf("未学習パターンの認識を行いますか?(=1:行う,=0:行わない) "); fscanf(STDIN, "%d", $sw); if ($sw > 0) { printf("未学習パターンのファイル名は? "); fscanf(STDIN, "%s", $f_name); $dt2 = new BackData($f_name); $no = $net->Recog($dt2, 2, $max); // 未学習対象の認識と出力 } } /* ------------------------制御データ---------------- 誤差 0.1 出力 -2 出力ファイル kekka 順番 0 η 0.5 α 0.8 ------------------------構造データ---------------- 入力ユニット数 2 出力ユニット数 1 関数タイプ 0 隠れ層の数 1 各隠れ層のユニット数(下から) 1 バイアス入力ユニット数 1 ユニット番号:出力ユニットから順に番号付け 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1])) 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限) 1 -1 -0.05 0.05 接続方法の数 2 ユニット番号:ユニットk1からk2を,k3からk4に接続 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限) 3 4 1 2 1 -0.1 0.1 2 2 1 1 1 -0.1 0.1 ------------------------学習データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 ------------------------認識データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 */ ?>
########################## # back propagation model # coded by Y.Suganuma ########################## ###################################################### # バックプロパゲーションの制御(クラス BackControl) ###################################################### class BackControl #################################### # クラスBackControlのコンストラクタ # name : 入力データファイル名 #################################### def initialize(name) f = open(name, "r") s = f.gets().split(" ") @_eps = Float(s[1]) # 許容誤差 @_p_type = Integer(s[3]) # 出力先・方法の指定 # =0 : 誤って認識した数だけ出力 # =1 : 認識結果を出力 # =2 : 認識結果と重みを出力 # (負の時は,認識結果と重みをファイルへも出力) if @_p_type < 0 @_o_file = s[5] # 出力ファイル名 end s = f.gets().split(" ") @_order = Integer(s[1]) # 入力パターンの与え方(=0:順番,=1:ランダム) @_eata = Float(s[3]) # 重み及びバイアス修正パラメータ @_alpha = Float(s[5]) # 重み及びバイアス修正パラメータ f.close() srand() end end ###################################################### # バックプロパゲーションのデータ(クラス BackData) ###################################################### class BackData #################################### # クラスBackDataのコンストラクタ # name : 入力データファイル名 #################################### def initialize(name) # 入力パターン数等 f = open(name, "r") s = f.gets().split(" ") @_noip = Integer(s[1]) # 入力パターンの数 @_noiu = Integer(s[3]) # 入力ユニットの数 @_noou = Integer(s[5]) # 出力ユニットの数 # 領域の確保 @_iptn = Array.new(@_noip) for i1 in 0 ... @_noip @_iptn[i1] = Array.new(@_noiu) end # iptn[i][j] : (i+1)番目の入力パターンの(j+1)番目の # 入力ユニットの入力値 # i=0,noip-1 j=0,noiu-1 @_optn = Array.new(@_noip) for i1 in 0 ... @_noip @_optn[i1] = Array.new(@_noou) end # optn[i][j] : (i+1)番目の入力パターンに対する(j+1) # 番目の出力ユニットの目標出力値 # i=0,noip-1 j=0,noou-1 # 入力パターン及び各入力パターンに対する出力パターンの入力 for i1 in 0 ... @_noip s = f.gets().split(" ") for i2 in 0 ... @_noiu @_iptn[i1][i2] = Float(s[i2+1]) end s = f.gets().split(" ") for i2 in 0 ... @_noou @_optn[i1][i2] = Float(s[i2+1]) end end f.close() end attr_accessor("_noip", "_noiu", "_noou", "_iptn", "_optn") end ########################################### # バックプロパゲーション(クラス Backpr) ########################################### class Backpr < BackControl ################################################ # クラスBackprのコンストラクタ # name_c : 制御データ用入力ファイル名 # name_s : ネットワーク記述入力ファイル名 ################################################ def initialize(name_c, name_s) super(name_c) # 親のコンストラクタ f = open(name_s, "r") # 入力ユニット,出力ユニットの数,関数タイプ s = f.gets().split(" ") @_noiu = Integer(s[1]) # 入力ユニットの数 @_noou = Integer(s[3]) # 出力ユニットの数 @_f_type = Integer(s[5]) # シグモイド関数のタイプ,0 : [0,1],1 : [-1,1] @_nou = @_noiu + @_noou # 入力ユニットと出力ユニットの和 # 各ユニットには最も上の出力ユニットから, # 隠れ層の各ユニット,及び,入力ユニットに至る # 一連のユニット番号が付けられる # 隠れユニットの階層数と各階層のユニット数 s = f.gets().split(" ") @_nolvl = Integer(s[1]) # 隠れユニットの階層数 @_nohu = Array.new(@_nolvl+1) # nohu[i] : レベル(i+1)の隠れ層のユニット数(隠れ層 # には下から順に番号が付けられ,出力層はレ # ベル(nolvl+1)の隠れ層とも見做される) # i=0,nolvl @_nohu[@_nolvl] = @_noou if @_nolvl > 0 for i1 in 0 ... @_nolvl @_nohu[i1] = Integer(s[i1+3]) @_nou += @_nohu[i1] end end # 領域の確保 @_con = Array.new(@_nou) for i1 in 0 ... @_nou @_con[i1] = Array.new(@_nou) end for i1 in 0 ... @_nou for i2 in 0 ... @_nou if i1 == i2 @_con[i1][i2] = -1 else @_con[i1][i2] = 0 # con[i][j] : 各ユニットに対するバイアスの与え方,及び,接続方法 # [i][i] : ユニット(i+1)のバイアスの与え方 # =-3 : 入力値で固定 # =-2 : 入力値を初期値として,学習により変更 # =-1 : 乱数で初期値を設定し,学習により変更 # [i][j] : ユニット(i+1)と(j+1)の接続方法(j>i) # =0 : 接続しない # =1 : 接続する(重みの初期値を乱数で設定し,学習) # =2 : 接続する(重みの初期値を入力で与え,学習) # =3 : 接続する(重みを入力値に固定) # i=0,nou-1 j=0,nou-1 end end end @_w = Array.new(@_nou) for i1 in 0 ... @_nou @_w[i1] = Array.new(@_nou) end for i1 in 0 ... @_nou for i2 in 0 ... @_nou @_w[i1][i2] = 0.0 # w[i][j] : ユニット(i+1)から(j+1)への重み(j>i) # w[j][i] : (i+1)から(j+1)への重みの前回修正量(j>i) # w[i][i] : ユニット(i+1)のバイアスの前回修正量 # i=0,nou-1 j=0,nou-1 end end @_dp = Array.new(@_nou) # ユニット(i+1)の誤差 i=0,nou-1 @_op = Array.new(@_nou) # ユニット(i+1)の出力 i=0,nou-1 @_theta = Array.new(@_nou) # ユニット(i+1)のバイアス i=0,nou for i1 in 0 ... @_nou @_theta[i1] = 0.2 * rand(0) - 0.1 end # 各ユニットのバイアスとユニット間の接続関係 # バイアス # バイアスデータの数 s = f.gets().split(" ") n = Integer(s[1]) f.gets() f.gets() f.gets() if n > 0 # バイアスデータの処理 for i0 in 0 ... n s = f.gets().split(" ") # ユニット番号 k1 = Integer(s[0]) # 不適当なユニット番号のチェック if k1 < 1 or k1 > (@_nou-@_noiu) print("***error ユニット番号 " + String(k1) + " が不適当" + "\n") end # バイアスの与え方 k1 -= 1 id = Integer(s[1]) @_con[k1][k1] = id # バイアスの初期設定 if @_con[k1][k1] == -1 x1 = Float(s[2]) x2 = Float(s[3]) @_theta[k1] = (x2 - x1) * rand(0) + x1 elsif @_con[k1][k1] == -2 or @_con[k1][k1] == -3 @_theta[k1] = Float(s[2]) else print("***error バイアスの与え方が不適当\n") end end end # 接続方法 # 接続データの数 s = f.gets().split(" ") n = Integer(s[1]) f.gets() f.gets() f.gets() if n > 0 # 接続データの処理 for i0 in 0 ... n s = f.gets().split(" ") # 接続情報 k1 = Integer(s[0]) k2 = Integer(s[1]) k3 = Integer(s[2]) k4 = Integer(s[3]) # 不適切な接続のチェック sw = 0 if k1 < 1 or k2 < 1 or k3 < 1 or k4 < 1 sw = 1 else if k1 > @_nou or k2 > @_nou or k3 > @_nou or k4 > @_nou sw = 1 else if k1 > k2 or k3 > k4 sw = 1 else if k4 >= k1 sw = 1 else l1 = -1 k = 0 i1 = @_nolvl while i1 > -1 k += @_nohu[i1] if k1 <= k l1 = i1 break end i1 -= 1 end l2 = -1 k = 0 i1 = @_nolvl while i1 > -1 k += @_nohu[i1] if k4 <= k l2 = i1 break end i1 -= 1 end if l2 <= l1 sw = 1 end end end end end if sw > 0 print("***error ユニット番号が不適当(" + String(k1) + " " + String(k2) + " " + String(k3) + " " + String(k4) + ")\n") end # 重みの初期値の与え方 k1 -= 1 k2 -= 1 k3 -= 1 k4 -= 1 id = Integer(s[4]) if id == 1 x1 = Float(s[5]) x2 = Float(s[6]) else if id > 1 x1 = Float(s[5]) else if id != 0 print("***error 接続方法が不適当\n") end end end # 重みの初期値の設定 for i1 in k3 ... k4+1 for i2 in k1 ... k2+1 @_con[i1][i2] = id if id == 0 @_w[i1][i2] = 0.0 elsif id == 1 @_w[i1][i2] = (x2 - x1) * rand(0) + x1 elsif id == 2 @_w[i1][i2] = x1 elsif id == 3 @_w[i1][i2] = x1 end end end end end f.close() end ########################################## # 誤差の計算,及び,重みとバイアスの修正 # ptn[i1] : 出力パターン ########################################## def Err_back(ptn) for i1 in 0 ... @_nou-@_noiu # 誤差の計算 if i1 < @_noou if @_f_type == 0 @_dp[i1] = (ptn[i1] - @_op[i1]) * @_op[i1] * (1.0 - @_op[i1]) else @_dp[i1] = 0.5 * (ptn[i1] - @_op[i1]) * (@_op[i1] - 1.0) * (@_op[i1] + 1.0) end else x1 = 0.0 for i2 in 0 ... i1 if @_con[i2][i1] > 0 x1 += @_dp[i2] * @_w[i2][i1] end end if @_f_type == 0 @_dp[i1] = @_op[i1] * (1.0 - @_op[i1]) * x1 else @_dp[i1] = 0.5 * (@_op[i1] - 1.0) * (@_op[i1] + 1.0) * x1 end end # 重みの修正 for i2 in i1+1 ... @_nou if @_con[i1][i2] == 1 or @_con[i1][i2] == 2 x1 = @_eata * @_dp[i1] * @_op[i2] + @_alpha * @_w[i2][i1] @_w[i2][i1] = x1 @_w[i1][i2] += x1 end end # バイアスの修正 if @_con[i1][i1] >= -2 x1 = @_eata * @_dp[i1] + @_alpha * @_w[i1][i1] @_w[i1][i1] = x1 @_theta[i1] += x1 end end end ######################################################## # 与えられた入力パターンに対する各ユニットの出力の計算 ######################################################## def Forward() i1 = @_nou - @_noiu - 1 while i1 > -1 sum = -@_theta[i1] for i2 in i1+1 ... @_nou if @_con[i1][i2] > 0 sum -= @_w[i1][i2] * @_op[i2] end end if @_f_type == 0 @_op[i1] = 1.0 / (1.0 + Math.exp(sum)) else @_op[i1] = 1.0 - 2.0 / (1.0 + Math.exp(sum)) end i1 -= 1 end end ############################# # 学習の実行 # p : 認識パターン # m_tri : 最大学習回数 ############################# def Learn(p, m_tri) k0 = -1 # エラーチェック if @_noiu != p._noiu or @_noou != p._noou print("***error 入力または出力ユニットの数が違います\n") end for i1 in 0 ... m_tri # パターンを与える順番の決定 if @_order == 0 # 順番 k0 += 1 if k0 >= p._noip k0 = 0 end else # ランダム k0 = Integer(rand(0) * p._noip) if k0 >= p._noip k0 = p._noip - 1 end end # 出力ユニットの結果を計算 k1 = @_nou - @_noiu for i2 in 0 ... @_noiu @_op[k1+i2] = p._iptn[k0][i2] end Forward() # 重みとバイアスの修正 Err_back(p._optn[k0]) end end ################################################ # 与えられた対象の認識と出力 # p : 認識パターン # pr : =0 : 出力を行わない # =1 : 出力を行う # =2 : 出力を行う(未学習パターン) # tri : 現在の学習回数 # return : 誤って認識したパターンの数 ################################################ def Recog(p, pr, tri) no = 0 # ファイルのオープン if @_p_type < 0 and pr > 0 if pr == 1 out = open(@_o_file, "w") out.print("***学習パターン***\n\n") else out = open(@_o_file, "a") out.print("\n***未学習パターン***\n\n") end end # 各パターンに対する出力 for i1 in 0 ... p._noip # 入力パターンの設定 k1 = @_nou - @_noiu for i2 in 0 ... @_noiu @_op[k1+i2] = p._iptn[i1][i2] end # 出力の計算 Forward() # 結果の表示 if @_p_type != 0 and pr > 0 printf("入力パターン%4d ", (i1+1)) for i2 in 0 ... @_noiu printf("%5.2f", @_op[k1+i2]) if i2 == @_noiu-1 print("\n") else if ((i2+1) % 10) == 0 print("\n ") end end end print("\n 出力パターン(理想) ") for i2 in 0 ... @_noou printf("%10.3f", p._optn[i1][i2]) if i2 == @_noou-1 print("\n") else if ((i2+1) % 5) == 0 print("\n ") end end end end sw = 0 if @_p_type != 0 and pr > 0 print(" (実際) ") end for i2 in 0 ... @_noou if @_p_type != 0 and pr > 0 printf("%10.3f", @_op[i2]) if i2 == @_noou-1 print("\n") else if ((i2+1) % 5) == 0 print("\n ") end end end if (@_op[i2]-p._optn[i1][i2]).abs() > @_eps sw = 1 end end if sw > 0 no += 1 end if @_p_type < 0 and pr > 0 out.printf("入力パターン%4d ", (i1+1)) for i2 in 0 ... @_noiu out.printf("%5.2f", @_op[k1+i2]) if i2 == @_noiu-1 out.print("\n") else if ((i2+1) % 10) == 0 out.print("\n ") end end end out.print("\n 出力パターン(理想) ") for i2 in 0 ... @_noou out.printf("%10.3f", p._optn[i1][i2]) if i2 == @_noou-1 out.print("\n") else if ((i2+1) % 5) == 0 out.print("\n ") end end end out.print(" (実際) ") for i2 in 0 ... @_noou out.printf("%10.3f", @_op[i2]) if i2 == @_noou-1 out.print("\n") else if ((i2+1) % 5) == 0 out.print("\n ") end end end end if @_p_type != 0 and pr > 0 $stdin.gets() end end # 重みの出力 if (@_p_type < -1 or @_p_type > 1) and pr == 1 print(" 重み") for i1 in 0 ... @_nou-@_noiu printf(" to%4d from ", (i1+1)) ln = -1 for i2 in 0 ... @_nou if @_con[i1][i2] > 0 if ln <= 0 if ln < 0 ln = 0 else print("\n ") end end printf("%4d%11.3f", i2+1, @_w[i1][i2]) ln += 1 if ln == 4 ln = 0 end end end print("\n") end print("\n バイアス ") ln = 0 for i1 in 0 ... @_nou-@_noiu printf("%4d%11.3f", i1+1, @_theta[i1]) ln += 1 if ln == 4 and i1 != @_nou-@_noiu-1 ln = 0 print("\n ") end end print("\n") $stdin.gets() end if @_p_type < 0 and pr == 1 out.print(" 重み\n") for i1 in 0 ... @_nou-@_noiu out.printf(" to%4d from ", (i1+1)) ln = -1 for i2 in 0 ... @_nou if @_con[i1][i2] > 0 if ln <= 0 if ln < 0 ln = 0 else out.print("\n ") end end out.printf("%4d%11.3f", i2+1, @_w[i1][i2]) ln += 1 if ln == 4 ln = 0 end end end out.print("\n") end out.print("\n バイアス ") ln = 0 for i1 in 0 ... @_nou-@_noiu out.printf("%4d%11.3f", i1+1, @_theta[i1]) ln += 1 if ln == 4 and i1 != @_nou-@_noiu-1 ln = 0 out.print("\n ") end end if ln != 0 out.print("\n") end end if @_p_type < 0 and pr > 0 out.close() end return no end end ct = 0 no = 1 # エラー if ARGV.length != 2 print("***error 入力データファイル名を指定して下さい\n") else # ネットワークの定義 net = Backpr.new(ARGV[0], ARGV[1]) # 学習パターン等の入力 print("学習回数は? ") m_tri = Integer($stdin.gets()) print("何回毎に収束を確認しますか? ") conv = Integer($stdin.gets()) print("学習パターンのファイル名は? ") f_name = $stdin.gets().strip() dt1 = BackData.new(f_name) # 学習 while ct < m_tri and no > 0 if (ct + conv) < m_tri tri = conv else tri = m_tri - ct end ct += tri net.Learn(dt1, tri) # 学習 no = net.Recog(dt1, 0, ct) # 学習対象の認識 print(" 回数 " + String(ct) + " 誤って認識したパターン数 " + String(no) + "\n") end no = net.Recog(dt1, 1, ct) # 学習対象の認識と出力 # 未学習パターンの認識 print("未学習パターンの認識を行いますか?(=1:行う,=0:行わない) ") sw = Integer($stdin.gets()) if sw > 0 print("未学習パターンのファイル名は? ") f_name = $stdin.gets().strip() dt2 = BackData.new(f_name) no = net.Recog(dt2, 2, ct) # 未学習対象の認識と出力 end end =begin ------------------------制御データ---------------- 誤差 0.1 出力 -2 出力ファイル kekka 順番 0 η 0.5 α 0.8 ------------------------構造データ---------------- 入力ユニット数 2 出力ユニット数 1 関数タイプ 0 隠れ層の数 1 各隠れ層のユニット数(下から) 1 バイアス入力ユニット数 1 ユニット番号:出力ユニットから順に番号付け 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1])) 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限) 1 -1 -0.05 0.05 接続方法の数 2 ユニット番号:ユニットk1からk2を,k3からk4に接続 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限) 3 4 1 2 1 -0.1 0.1 2 2 1 1 1 -0.1 0.1 ------------------------学習データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 ------------------------認識データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 =end
# -*- coding: UTF-8 -*- import numpy as np import sys from math import * from random import * ###################################################### # バックプロパゲーションの制御(クラス BackControl) ###################################################### class BackControl : #################################### # クラスBackControlのコンストラクタ # name : 入力データファイル名 #################################### def __init__(self, name) : f = open(name, "r") s = f.readline().split() self.eps = float(s[1]) # 許容誤差 self.p_type = int(s[3]) # 出力先・方法の指定 # =0 : 誤って認識した数だけ出力 # =1 : 認識結果を出力 # =2 : 認識結果と重みを出力 # (負の時は,認識結果と重みをファイルへも出力) if self.p_type < 0 : self.o_file = s[5] # 出力ファイル名 s = f.readline().split() self.order = int(s[1]) # 入力パターンの与え方(=0:順番,=1:ランダム) self.eata = float(s[3]) # 重み及びバイアス修正パラメータ self.alpha = float(s[5]) # 重み及びバイアス修正パラメータ f.close() seed() ###################################################### # バックプロパゲーションのデータ(クラス BackData) ###################################################### class BackData : #################################### # クラスBackDataのコンストラクタ # name : 入力データファイル名 #################################### def __init__(self, name) : # 入力パターン数等 f = open(name, "r") s = f.readline().split() self.noip = int(s[1]) # 入力パターンの数 self.noiu = int(s[3]) # 入力ユニットの数 self.noou = int(s[5]) # 出力ユニットの数 # 領域の確保 self.iptn = np.empty((self.noip, self.noiu), np.float) # iptn[i][j] : (i+1)番目の入力パターンの(j+1)番目の # 入力ユニットの入力値 # i=0,noip-1 j=0,noiu-1 self.optn = np.empty((self.noip, self.noou), np.float) # optn[i][j] : (i+1)番目の入力パターンに対する(j+1) # 番目の出力ユニットの目標出力値 # i=0,noip-1 j=0,noou-1 # 入力パターン及び各入力パターンに対する出力パターンの入力 for i1 in range(0, self.noip) : s = f.readline().split() for i2 in range(0, self.noiu) : self.iptn[i1][i2] = float(s[i2+1]) s = f.readline().split() for i2 in range(0, self.noou) : self.optn[i1][i2] = float(s[i2+1]) f.close() ########################################### # バックプロパゲーション(クラス Backpr) ########################################### class Backpr(BackControl) : ################################################ # クラスBackprのコンストラクタ # name_c : 制御データ用入力ファイル名 # name_s : ネットワーク記述入力ファイル名 ################################################ def __init__(self, name_c, name_s) : BackControl.__init__(self, name_c) # 親のコンストラクタ f = open(name_s, "r") # 入力ユニット,出力ユニットの数,関数タイプ s = f.readline().split() self.noiu = int(s[1]) # 入力ユニットの数 self.noou = int(s[3]) # 出力ユニットの数 self.f_type = int(s[5]) # シグモイド関数のタイプ,0 : [0,1],1 : [-1,1] self.nou = self.noiu + self.noou # 入力ユニットと出力ユニットの和 # 各ユニットには最も上の出力ユニットから, # 隠れ層の各ユニット,及び,入力ユニットに至る # 一連のユニット番号が付けられる # 隠れユニットの階層数と各階層のユニット数 s = f.readline().split() self.nolvl = int(s[1]) # 隠れユニットの階層数 self.nohu = np.empty(self.nolvl+1, np.int) # nohu[i] : レベル(i+1)の隠れ層のユニット数(隠れ層 # には下から順に番号が付けられ,出力層はレ # ベル(nolvl+1)の隠れ層とも見做される) # i=0,nolvl self.nohu[self.nolvl] = self.noou if self.nolvl > 0 : for i1 in range(0, self.nolvl) : self.nohu[i1] = int(s[i1+3]) self.nou += self.nohu[i1] # 領域の確保 self.con = np.empty((self.nou, self.nou), np.int) for i1 in range(0, self.nou) : for i2 in range(0, self.nou) : if i1 == i2 : self.con[i1][i2] = -1 else : self.con[i1][i2] = 0 # con[i][j] : 各ユニットに対するバイアスの与え方,及び,接続方法 # [i][i] : ユニット(i+1)のバイアスの与え方 # =-3 : 入力値で固定 # =-2 : 入力値を初期値として,学習により変更 # =-1 : 乱数で初期値を設定し,学習により変更 # [i][j] : ユニット(i+1)と(j+1)の接続方法(j>i) # =0 : 接続しない # =1 : 接続する(重みの初期値を乱数で設定し,学習) # =2 : 接続する(重みの初期値を入力で与え,学習) # =3 : 接続する(重みを入力値に固定) # i=0,nou-1 j=0,nou-1 self.w = np.empty((self.nou, self.nou), np.float) for i1 in range(0, self.nou) : for i2 in range(0, self.nou) : self.w[i1][i2] = 0.0 # w[i][j] : ユニット(i+1)から(j+1)への重み(j>i) # w[j][i] : (i+1)から(j+1)への重みの前回修正量(j>i) # w[i][i] : ユニット(i+1)のバイアスの前回修正量 # i=0,nou-1 j=0,nou-1 self.dp = np.empty(self.nou, np.float) # ユニット(i+1)の誤差 i=0,nou-1 self.op = np.empty(self.nou, np.float) # ユニット(i+1)の出力 i=0,nou-1 self.theta = np.empty(self.nou, np.float) # ユニット(i+1)のバイアス i=0,nou for i1 in range(0, self.nou) : self.theta[i1] = 0.2 * random() - 0.1 # 各ユニットのバイアスとユニット間の接続関係 # バイアス # バイアスデータの数 s = f.readline().split() n = int(s[1]) f.readline() f.readline() f.readline() if n > 0 : # バイアスデータの処理 for i0 in range(0, n) : s = f.readline().split() # ユニット番号 k1 = int(s[0]) # 不適当なユニット番号のチェック if k1 < 1 or k1 > (self.nou-self.noiu) : print("***error ユニット番号 " + str(k1) + " が不適当") # バイアスの与え方 k1 -= 1 id = int(s[1]) self.con[k1][k1] = id # バイアスの初期設定 if self.con[k1][k1] == -1 : x1 = float(s[2]) x2 = float(s[3]) self.theta[k1] = (x2 - x1) * random() + x1 elif self.con[k1][k1] == -2 or self.con[k1][k1] == -3 : self.theta[k1] = float(s[2]) else : print("***error バイアスの与え方が不適当") # 接続方法 # 接続データの数 s = f.readline().split() n = int(s[1]) f.readline() f.readline() f.readline() if n > 0 : # 接続データの処理 for i0 in range(0, n) : s = f.readline().split() # 接続情報 k1 = int(s[0]) k2 = int(s[1]) k3 = int(s[2]) k4 = int(s[3]) # 不適切な接続のチェック sw = 0 if k1 < 1 or k2 < 1 or k3 < 1 or k4 < 1 : sw = 1 else : if k1 > self.nou or k2 > self.nou or k3 > self.nou or k4 > self.nou : sw = 1 else : if k1 > k2 or k3 > k4 : sw = 1 else : if k4 >= k1 : sw = 1 else : l1 = -1 k = 0 for i1 in range(self.nolvl, -1, -1) : k += self.nohu[i1] if k1 <= k : l1 = i1 break l2 = -1 k = 0 for i1 in range(self.nolvl, -1, -1) : k += self.nohu[i1] if k4 <= k : l2 = i1 break if l2 <= l1 : sw = 1 if sw > 0 : print("***error ユニット番号が不適当(" + str(k1) + " " + str(k2) + " " + str(k3) + " " + str(k4) + ")") # 重みの初期値の与え方 k1 -= 1 k2 -= 1 k3 -= 1 k4 -= 1 id = int(s[4]) if id == 1 : x1 = float(s[5]) x2 = float(s[6]) else : if id > 1 : x1 = float(s[5]) else : if id != 0 : print("***error 接続方法が不適当") # 重みの初期値の設定 for i1 in range(k3, k4+1) : for i2 in range(k1, k2+1) : self.con[i1][i2] = id if id == 0 : self.w[i1][i2] = 0.0 elif id == 1 : self.w[i1][i2] = (x2 - x1) * random() + x1 elif id == 2 : self.w[i1][i2] = x1 elif id == 3 : self.w[i1][i2] = x1 f.close() ########################################## # 誤差の計算,及び,重みとバイアスの修正 # ptn[i1] : 出力パターン ########################################## def Err_back(self, ptn) : for i1 in range(0, self.nou-self.noiu) : # 誤差の計算 if i1 < self.noou : if self.f_type == 0 : self.dp[i1] = (ptn[i1] - self.op[i1]) * self.op[i1] * (1.0 - self.op[i1]) else : self.dp[i1] = 0.5 * (ptn[i1] - self.op[i1]) * (self.op[i1] - 1.0) * (self.op[i1] + 1.0) else : x1 = 0.0 for i2 in range(0, i1) : if self.con[i2][i1] > 0 : x1 += self.dp[i2] * self.w[i2][i1] if self.f_type == 0 : self.dp[i1] = self.op[i1] * (1.0 - self.op[i1]) * x1 else : self.dp[i1] = 0.5 * (self.op[i1] - 1.0) * (self.op[i1] + 1.0) * x1 # 重みの修正 for i2 in range(i1+1, self.nou) : if self.con[i1][i2] == 1 or self.con[i1][i2] == 2 : x1 = self.eata * self.dp[i1] * self.op[i2] + self.alpha * self.w[i2][i1] self.w[i2][i1] = x1 self.w[i1][i2] += x1 # バイアスの修正 if self.con[i1][i1] >= -2 : x1 = self.eata * self.dp[i1] + self.alpha * self.w[i1][i1] self.w[i1][i1] = x1 self.theta[i1] += x1 ######################################################## # 与えられた入力パターンに対する各ユニットの出力の計算 ######################################################## def Forward(self) : for i1 in range(self.nou-self.noiu-1, -1, -1) : sum = -self.theta[i1] for i2 in range(i1+1, self.nou) : if self.con[i1][i2] > 0 : sum -= self.w[i1][i2] * self.op[i2] if self.f_type == 0 : self.op[i1] = 1.0 / (1.0 + exp(sum)) else : self.op[i1] = 1.0 - 2.0 / (1.0 + exp(sum)) ############################# # 学習の実行 # p : 認識パターン # m_tri : 最大学習回数 ############################# def Learn(self, p, m_tri) : k0 = -1 # エラーチェック if self.noiu != p.noiu or self.noou != p.noou : print("***error 入力または出力ユニットの数が違います") for i1 in range(0, m_tri) : # パターンを与える順番の決定 if self.order == 0 : # 順番 k0 += 1 if k0 >= p.noip : k0 = 0 else : # ランダム k0 = int(random() * p.noip) if k0 >= p.noip : k0 = p.noip - 1 # 出力ユニットの結果を計算 k1 = self.nou - self.noiu for i2 in range(0, self.noiu) : self.op[k1+i2] = p.iptn[k0][i2] self.Forward() # 重みとバイアスの修正 self.Err_back(p.optn[k0]) ################################################ # 与えられた対象の認識と出力 # p : 認識パターン # pr : =0 : 出力を行わない # =1 : 出力を行う # =2 : 出力を行う(未学習パターン) # tri : 現在の学習回数 # return : 誤って認識したパターンの数 ################################################ def Recog(self, p, pr, tri) : No = 0 # ファイルのオープン if self.p_type < 0 and pr > 0 : if pr == 1 : out = open(self.o_file, "w") out.write("***学習パターン***\n\n") else : out = open(self.o_file, "a") out.write("\n***未学習パターン***\n\n") # 各パターンに対する出力 for i1 in range(0, p.noip) : # 入力パターンの設定 k1 = self.nou - self.noiu for i2 in range(0, self.noiu) : self.op[k1+i2] = p.iptn[i1][i2] # 出力の計算 self.Forward() # 結果の表示 if self.p_type != 0 and pr > 0 : print("入力パターン{0:4d} ".format(i1+1), end="") for i2 in range(0, self.noiu) : print("{0:5.2f}".format(self.op[k1+i2]), end="") if i2 == self.noiu-1 : print("") else : if ((i2+1) % 10) == 0 : print("\n ", end="") print("\n 出力パターン(理想) ", end="") for i2 in range(0, self.noou) : print("{0:10.3f}".format(p.optn[i1][i2]), end="") if i2 == self.noou-1 : print("") else : if ((i2+1) % 5) == 0 : print("\n ", end="") sw = 0 if self.p_type != 0 and pr > 0 : print(" (実際) ", end="") for i2 in range(0, self.noou) : if self.p_type != 0 and pr > 0 : print("{0:10.3f}".format(self.op[i2]), end="") if i2 == self.noou-1 : print("\n") else : if ((i2+1) % 5) == 0 : print("\n ", end="") if abs(self.op[i2]-p.optn[i1][i2]) > self.eps : sw = 1 if sw > 0 : No += 1 if self.p_type < 0 and pr > 0 : out.write("入力パターン{0:4d} ".format(i1+1)) for i2 in range(0, self.noiu) : out.write("{0:5.2f}".format(self.op[k1+i2])) if i2 == self.noiu-1 : out.write("\n") else : if ((i2+1) % 10) == 0 : out.write("\n ") out.write("\n 出力パターン(理想) ") for i2 in range(0, self.noou) : out.write("{0:10.3f}".format(p.optn[i1][i2])) if i2 == self.noou-1 : out.write("\n") else : if ((i2+1) % 5) == 0 : out.write("\n ") out.write(" (実際) ") for i2 in range(0, self.noou) : out.write("{0:10.3f}".format(self.op[i2])) if i2 == self.noou-1 : out.write("\n") else : if ((i2+1) % 5) == 0 : out.write("\n ") if self.p_type != 0 and pr > 0 : input("") # 重みの出力 if (self.p_type < -1 or self.p_type > 1) and pr == 1 : print(" 重み") for i1 in range(0, self.nou-self.noiu) : print(" to{0:4d} from ".format(i1+1), end="") ln = -1 for i2 in range(0, self.nou) : if self.con[i1][i2] > 0 : if ln <= 0 : if ln < 0 : ln = 0 else : print("\n ", end="") print("{0:4d}{1:11.3f}".format(i2+1, self.w[i1][i2]), end="") ln += 1 if ln == 4 : ln = 0 print("") print("\n バイアス ", end="") ln = 0 for i1 in range(0, self.nou-self.noiu) : print("{0:4d}{1:11.3f}".format(i1+1, self.theta[i1]), end="") ln += 1 if ln == 4 and i1 != self.nou-self.noiu-1 : ln = 0 print("\n ", end="") print("") input("") if self.p_type < 0 and pr == 1 : out.write(" 重み\n") for i1 in range(0, self.nou-self.noiu) : out.write(" to{0:4d} from ".format(i1+1)) ln = -1 for i2 in range(0, self.nou) : if self.con[i1][i2] > 0 : if ln <= 0 : if ln < 0 : ln = 0 else : out.write("\n ") out.write("{0:4d}{1:11.3f}".format(i2+1, self.w[i1][i2])) ln += 1 if ln == 4 : ln = 0 out.write("\n") out.write("\n バイアス ") ln = 0 for i1 in range(0, self.nou-self.noiu) : out.write("{0:4d}{1:11.3f}".format(i1+1, self.theta[i1])) ln += 1 if ln == 4 and i1 != self.nou-self.noiu-1 : ln = 0 out.write("\n ") if ln != 0 : out.write("\n") if self.p_type < 0 and pr > 0 : out.close() return No ########################## # back propagation model # coded by Y.Suganuma ########################## ct = 0 no = 1 # エラー if len(sys.argv) != 3 : print("***error 入力データファイル名を指定して下さい") else : # ネットワークの定義 net = Backpr(sys.argv[1], sys.argv[2]) # 学習パターン等の入力 m_tri = int(input("学習回数は? ")) conv = int(input("何回毎に収束を確認しますか? ")) f_name = input("学習パターンのファイル名は? ") dt1 = BackData(f_name) # 学習 while ct < m_tri and no > 0 : if (ct + conv) < m_tri : tri = conv else : tri = m_tri - ct ct += tri net.Learn(dt1, tri) # 学習 no = net.Recog(dt1, 0, ct) # 学習対象の認識 print(" 回数 " + str(ct) + " 誤って認識したパターン数 " + str(no)) no = net.Recog(dt1, 1, ct) # 学習対象の認識と出力 # 未学習パターンの認識 sw = int(input("未学習パターンの認識を行いますか?(=1:行う,=0:行わない) ")) if sw > 0 : f_name = input("未学習パターンのファイル名は? ") dt2 = BackData(f_name) no = net.Recog(dt2, 2, ct) # 未学習対象の認識と出力 """ ------------------------制御データ---------------- 誤差 0.1 出力 -2 出力ファイル kekka 順番 0 η 0.5 α 0.8 ------------------------構造データ---------------- 入力ユニット数 2 出力ユニット数 1 関数タイプ 0 隠れ層の数 1 各隠れ層のユニット数(下から) 1 バイアス入力ユニット数 1 ユニット番号:出力ユニットから順に番号付け 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1])) 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限) 1 -1 -0.05 0.05 接続方法の数 2 ユニット番号:ユニットk1からk2を,k3からk4に接続 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限) 3 4 1 2 1 -0.1 0.1 2 2 1 1 1 -0.1 0.1 ------------------------学習データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 ------------------------認識データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 """ """ ------------------------制御データ---------------- 誤差 0.1 出力 -2 出力ファイル kekka 順番 0 η 0.5 α 0.8 ------------------------構造データ---------------- 入力ユニット数 2 出力ユニット数 1 関数タイプ 0 隠れ層の数 1 各隠れ層のユニット数(下から) 1 バイアス入力ユニット数 1 ユニット番号:出力ユニットから順に番号付け 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1])) 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限) 1 -1 -0.05 0.05 接続方法の数 2 ユニット番号:ユニットk1からk2を,k3からk4に接続 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限) 3 4 1 2 1 -0.1 0.1 2 2 1 1 1 -0.1 0.1 ------------------------学習データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 ------------------------認識データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 """
/****************************/ /* back propagation model */ /* coded by Y.Suganuma */ /****************************/ using System; using System.IO; class Program { /****************/ /* main program */ /****************/ static void Main(String[] args) { // エラー if (args.Length != 2) { Console.WriteLine("***error 入力データファイル名を指定して下さい"); Environment.Exit(1); } else { // ネットワークの定義 Backpr net = new Backpr (args[0], args[1]); // 学習パターン等の入力 Console.Write("学習回数は? "); int m_tri = int.Parse(Console.ReadLine()); // 最大学習回数 Console.Write("何回毎に収束を確認しますか? "); int conv = int.Parse(Console.ReadLine()); // 収束確認回数 Console.Write("学習パターンのファイル名は? "); String f_name = Console.ReadLine(); BackData dt1 = new BackData(f_name); // 学習 int max = 0, no = 1; while (max < m_tri && no > 0) { int tri = ((max + conv) < m_tri) ? conv : m_tri - max; max += tri; net.Learn(dt1, tri); // 学習 no = net.Recog(dt1, 0, max); // 学習対象の認識 Console.WriteLine(" 回数 " + max + " 誤って認識したパターン数 " + no); } no = net.Recog(dt1, 1, max); // 学習対象の認識と出力 // 未学習パターンの認識 Console.Write("未学習パターンの認識を行いますか?(=1:行う,=0:行わない) "); int sw = int.Parse(Console.ReadLine()); if (sw > 0) { Console.Write("未学習パターンのファイル名は? "); f_name = Console.ReadLine(); BackData dt2 = new BackData(f_name); no = net.Recog(dt2, 2, max); // 未学習対象の認識と出力 } } } } /******************************************************/ /* バックプロパゲーションの制御(クラス BackControl) */ /******************************************************/ class BackControl { protected double alpha, eata; //重み及びバイアス修正パラメータ protected double eps; // 許容誤差 protected int order; // 入力パターンの与え方(=0:順番,=1:ランダム) protected int p_type; // 出力先・方法の指定 // =0 : 誤って認識した数だけ出力 // =1 : 認識結果を出力 // =2 : 認識結果と重みを出力 // (負の時は,認識結果と重みをファイルへも出力) protected String o_file; // 出力ファイル名 /*************************************/ /* クラスBackControlのコンストラクタ */ /* name : 入力データファイル名 */ /*************************************/ public BackControl(String name) { char[] charSep = new char[] {' '}; String[] lines = File.ReadAllLines(name); String[] str = lines[0].Split(charSep, StringSplitOptions.RemoveEmptyEntries); eps = double.Parse(str[1]); p_type = int.Parse(str[3]); if (p_type < 0) o_file = str[5]; str = lines[1].Split(charSep, StringSplitOptions.RemoveEmptyEntries); order = int.Parse(str[1]); eata = double.Parse(str[3]); alpha = double.Parse(str[5]); } } /*****************************************************/ /* バックプロパゲーションのデータ(クラス BackData) */ /*****************************************************/ class BackData { public int noiu; // 入力ユニットの数 public int noou; // 出力ユニットの数 public int noip; // 入力パターンの数 public double[][] iptn; // iptn[i][j] : (i+1)番目の入力パターンの(j+1)番目の // 入力ユニットの入力値 // i=0,noip-1 j=0,noiu-1 public double[][] optn; // optn[i][j] : (i+1)番目の入力パターンに対する(j+1) // 番目の出力ユニットの目標出力値 // i=0,noip-1 j=0,noou-1 /************************************/ /* クラスBackDataのコンストラクタ */ /* name : 入力データファイル名 */ /************************************/ public BackData(String name) { char[] charSep = new char[] {' '}; String[] lines = File.ReadAllLines(name); // // 入力パターン数等 // String[] str = lines[0].Split(charSep, StringSplitOptions.RemoveEmptyEntries); noip = int.Parse(str[1]); noiu = int.Parse(str[3]); noou = int.Parse(str[5]); // // 領域の確保 // iptn = new double [noip][]; optn = new double [noip][]; for (int i1 = 0; i1 < noip; i1++) { iptn[i1] = new double [noiu]; optn[i1] = new double [noou]; } // // 入力パターン及び各入力パターンに対する出力パターンの入力 // for (int i1 = 0; i1 < noip; i1++) { int k = 2 * i1 + 1; str = lines[k].Split(charSep, StringSplitOptions.RemoveEmptyEntries); for (int i2 = 0; i2 < noiu; i2++) iptn[i1][i2] = double.Parse(str[i2+1]); str = lines[k+1].Split(charSep, StringSplitOptions.RemoveEmptyEntries); for (int i2 = 0; i2 < noou; i2++) optn[i1][i2] = double.Parse(str[i2+1]); } } } /*******************************************/ /* バックプロパゲーション(クラス Backpr) */ /*******************************************/ class Backpr : BackControl { sbyte[][] con; // con[i][j] : 各ユニットに対するバイアスの与え方,及び, // 接続方法 // [i][i] : ユニット(i+1)のバイアスの与え方 // =-3 : 入力値で固定 // =-2 : 入力値を初期値として,学習により変更 // =-1 : 乱数で初期値を設定し,学習により変更 // [i][j] : ユニット(i+1)と(j+1)の接続方法(j>i) // =0 : 接続しない // =1 : 接続する(重みの初期値を乱数で設定し,学習) // =2 : 接続する(重みの初期値を入力で与え,学習) // =3 : 接続する(重みを入力値に固定) // i=0,nou-1 j=0,nou-1 int f_type; // シグモイド関数のタイプ // 0 : [0,1] // 1 : [-1,1]) int noiu; // 入力ユニットの数 int noou; // 出力ユニットの数 int[] nohu; // nohu[i] : レベル(i+1)の隠れ層のユニット数(隠れ層 // には下から順に番号が付けられ,出力層はレ // ベル(nolvl+1)の隠れ層とも見做される) // i=0,nolvl int nolvl; // 隠れユニットの階層数 int nou; // 入力,出力,及び,隠れ層の各ユニットの数の和(各ユニ // ットには最も上の出力ユニットから,隠れ層の各ユニット, // 及び,入力ユニットに至る一連のユニット番号が付けられ // る) double[] dp; // dp[i] : ユニット(i+1)の誤差 i=0,nou-1 double[] op; // op[i] : ユニット(i+1)の出力 i=0,nou-1 double[] theta; //theta[i] : ユニット(i+1)のバイアス i=0,nou double[][] w; // w[i][j] : ユニット(i+1)から(j+1)への重み(j>i) // w[j][i] : (i+1)から(j+1)への重みの前回修正量(j>i) // w[i][i] : ユニット(i+1)のバイアスの前回修正量 // i=0,nou-1 j=0,nou-1 Random rn; // 乱数 /************************************************/ /* クラスBackprのコンストラクタ */ /* name_c : 制御データ用入力ファイル名 */ /* name_s : ネットワーク記述入力ファイル名 */ /************************************************/ public Backpr(String name_c, String name_s) : base(name_c) { char[] charSep = new char[] {' '}; String[] lines = File.ReadAllLines(name_s); // // 乱数の初期化 // rn = new Random(); // 乱数の初期設定 // // 入力ユニット,出力ユニットの数,関数タイプ // String[] str = lines[0].Split(charSep, StringSplitOptions.RemoveEmptyEntries); noiu = int.Parse(str[1]); noou = int.Parse(str[3]); f_type = int.Parse(str[5]); nou = noiu + noou; // 入力ユニットと出力ユニットの和 // // 隠れユニットの階層数と各階層のユニット数 // str = lines[1].Split(charSep, StringSplitOptions.RemoveEmptyEntries); nolvl = int.Parse(str[1]); nohu = new int [nolvl+1]; nohu[nolvl] = noou; // 出力ユニットの数 if (nolvl > 0) { for (int i1 = 0; i1 < nolvl; i1++) { nohu[i1] = int.Parse(str[i1+3]); nou += nohu[i1]; } } // // 領域の確保 // con = new sbyte [nou][]; for (int i1 = 0; i1 < nou; i1++) { con[i1] = new sbyte [nou]; for (int i2 = 0; i2 < nou; i2++) con[i1][i2] = (i1 == i2) ? (sbyte)-1 : (sbyte)0; } w = new double [nou][]; for (int i1 = 0; i1 < nou; i1++) { w[i1] = new double [nou]; for (int i2 = 0; i2 < nou; i2++) w[i1][i2] = 0.0; } dp = new double [nou]; op = new double [nou]; theta = new double [nou]; for (int i1 = 0; i1 < nou; i1++) theta[i1] = 0.2 * rn.NextDouble() - 0.1; // // 各ユニットのバイアスとユニット間の接続関係 // // バイアス // バイアスデータの数 str = lines[2].Split(charSep, StringSplitOptions.RemoveEmptyEntries); int nb = int.Parse(str[1]); if (nb > 0) { // バイアスデータの処理 for (int i0 = 0; i0 < nb; i0++) { // ユニット番号 str = lines[i0+6].Split(charSep, StringSplitOptions.RemoveEmptyEntries); int k1 = int.Parse(str[0]); // 不適当なユニット番号のチェック if (k1 < 1 || k1 > (nou-noiu)) { Console.WriteLine("***error ユニット番号 " + k1 + " が不適当"); Environment.Exit(1); } // バイアスの与え方 k1--; int id = int.Parse(str[1]); con[k1][k1] = (sbyte)id; // バイアスの初期設定 switch (con[k1][k1]) { case -1: double x1 = double.Parse(str[2]); double x2 = double.Parse(str[3]); theta[k1] = (x2 - x1) * rn.NextDouble() + x1; break; case -2: theta[k1] = double.Parse(str[2]); break; case -3: theta[k1] = double.Parse(str[2]); break; default: Console.WriteLine("***error バイアスの与え方が不適当"); Environment.Exit(1); break; } } } // 接続方法 // 接続データの数 str = lines[nb+6].Split(charSep, StringSplitOptions.RemoveEmptyEntries); int n = int.Parse(str[1]); if (n > 0) { // 接続データの処理 for (int i0 = 0; i0 < n; i0++) { // 接続情報 str = lines[nb+10+i0].Split(charSep, StringSplitOptions.RemoveEmptyEntries); int k1 = int.Parse(str[0]); int k2 = int.Parse(str[1]); int k3 = int.Parse(str[2]); int k4 = int.Parse(str[3]); // 不適切な接続のチェック int sw = 0; if (k1 < 1 || k2 < 1 || k3 < 1 || k4 < 1) sw = 1; else { if (k1 > nou || k2 > nou || k3 > nou || k4 > nou) sw = 1; else { if (k1 > k2 || k3 > k4) sw = 1; else { if (k4 >= k1) sw = 1; else { int l1 = -1; int k = 0; for (int i1 = nolvl; i1 >= 0 && l1 < 0; i1--) { k += nohu[i1]; if (k1 <= k) l1 = i1; } int l2 = -1; k = 0; for (int i1 = nolvl; i1 >= 0 && l2 < 0; i1--) { k += nohu[i1]; if (k4 <= k) l2 = i1; } if (l2 <= l1) sw = 1; } } } } if (sw > 0) { Console.WriteLine("***error ユニット番号が不適当(" + k1 + " " + k2 + " " + k3 + " " + k4 + ")"); Environment.Exit(1); } // 重みの初期値の与え方 k1--; k2--; k3--; k4--; int id = int.Parse(str[4]); double x1 = 0.0; double x2 = 0.0; if (id == 1) { x1 = double.Parse(str[5]); x2 = double.Parse(str[6]); } else { if (id > 1) x1 = double.Parse(str[5]); else { if (id != 0) { Console.WriteLine("***error 接続方法が不適当"); Environment.Exit(1); } } } // 重みの初期値の設定 for (int i1 = k3; i1 <= k4; i1++) { for (int i2 = k1; i2 <= k2; i2++) { con[i1][i2] = (sbyte)id; switch (id) { case 0: w[i1][i2] = 0.0; break; case 1: w[i1][i2] = (x2 - x1) * rn.NextDouble() + x1; break; case 2: w[i1][i2] = x1; break; case 3: w[i1][i2] = x1; break; } } } } } } /******************************************/ /* 誤差の計算,及び,重みとバイアスの修正 */ /* ptn[i1] : 出力パターン */ /******************************************/ void Err_back(double[] ptn) { for (int i1 = 0; i1 < nou-noiu; i1++) { // 誤差の計算 if (i1 < noou) { if (f_type == 0) dp[i1] = (ptn[i1] - op[i1]) * op[i1] * (1.0 - op[i1]); else dp[i1] = 0.5 * (ptn[i1] - op[i1]) * (op[i1] - 1.0) * (op[i1] + 1.0); } else { double x1 = 0.0; for (int i2 = 0; i2 < i1; i2++) { if (con[i2][i1] > 0) x1 += dp[i2] * w[i2][i1]; } if (f_type == 0) dp[i1] = op[i1] * (1.0 - op[i1]) * x1; else dp[i1] = 0.5 * (op[i1] - 1.0) * (op[i1] + 1.0) * x1; } // 重みの修正 for (int i2 = i1+1; i2 < nou; i2++) { if (con[i1][i2] == 1 || con[i1][i2] == 2) { double x1 = eata * dp[i1] * op[i2] + alpha * w[i2][i1]; w[i2][i1] = x1; w[i1][i2] += x1; } } // バイアスの修正 if (con[i1][i1] >= -2) { double x1 = eata * dp[i1] + alpha * w[i1][i1]; w[i1][i1] = x1; theta[i1] += x1; } } } /********************************************************/ /* 与えられた入力パターンに対する各ユニットの出力の計算 */ /********************************************************/ void Forward() { for (int i1 = nou-noiu-1; i1 >= 0; i1--) { double sum = -theta[i1]; for (int i2 = i1+1; i2 < nou; i2++) { if (con[i1][i2] > 0) sum -= w[i1][i2] * op[i2]; } op[i1] = (f_type == 0) ? 1.0 / (1.0 + Math.Exp(sum)) : 1.0 - 2.0 / (1.0 + Math.Exp(sum)); } } /*****************************/ /* 学習の実行 */ /* p : 認識パターン */ /* m_tri : 最大学習回数 */ /*****************************/ public void Learn(BackData p, int m_tri) { // // エラーチェック // if (noiu != p.noiu || noou != p.noou) { Console.WriteLine("***error 入力または出力ユニットの数が違います"); Environment.Exit(1); } int k0 = -1; for (int i1 = 0; i1 < m_tri; i1++) { // // パターンを与える順番の決定 // if (order == 0) { // 順番 k0++; if (k0 >= p.noip) k0 = 0; } else { // ランダム k0 = (int)(rn.NextDouble() * p.noip); if (k0 >= p.noip) k0 = p.noip - 1; } // // 出力ユニットの結果を計算 // int k1 = nou - noiu; for (int i2 = 0; i2 < noiu; i2++) op[k1+i2] = p.iptn[k0][i2]; Forward(); // // 重みとバイアスの修正 // Err_back(p.optn[k0]); } } /***********************************************/ /* 与えられた対象の認識と出力 */ /* p : 認識パターン */ /* pr : =0 : 出力を行わない */ /* =1 : 出力を行う */ /* =2 : 出力を行う(未学習パターン) */ /* tri : 現在の学習回数 */ /* return : 誤って認識したパターンの数 */ /***********************************************/ public int Recog(BackData p, int pr, int tri) { // // ファイルのオープン // StreamWriter OUT = null; if (p_type < 0 && pr > 0) { OUT = new StreamWriter(o_file, true); if (pr == 1) { OUT.WriteLine("***学習パターン***"); OUT.WriteLine(); } else { OUT.WriteLine(); OUT.WriteLine("***未学習パターン***"); OUT.WriteLine(); } } // // 各パターンに対する出力 // int No = 0; for (int i1 = 0; i1 < p.noip; i1++) { // 入力パターンの設定 int k1 = nou - noiu; for (int i2 = 0; i2 < noiu; i2++) op[k1+i2] = p.iptn[i1][i2]; // 出力の計算 Forward(); // 結果の表示 if (p_type != 0 && pr > 0) { Console.Write("入力パターン" + (i1+1) + " "); for (int i2 = 0; i2 < noiu; i2++) { Console.Write(" " + op[k1+i2]); if (i2 == noiu-1) Console.WriteLine(); else { if(((i2+1) % 10) == 0) { Console.WriteLine(); Console.Write(" "); } } } Console.WriteLine(); Console.Write(" 出力パターン(理想) "); for (int i2 = 0; i2 < noou; i2++) { Console.Write(" " + p.optn[i1][i2]); if (i2 == noou-1) Console.WriteLine(); else { if(((i2+1) % 5) == 0) { Console.WriteLine(); Console.Write(" "); } } } } int sw = 0; if (p_type != 0 && pr > 0) Console.Write(" (実際) "); for (int i2 = 0; i2 < noou; i2++) { if (p_type != 0 && pr > 0) { Console.Write(" " + op[i2]); if (i2 == noou-1) Console.WriteLine(); else { if(((i2+1) % 5) == 0) { Console.WriteLine(); Console.Write(" "); } } } if (Math.Abs(op[i2]-p.optn[i1][i2]) > eps) sw = 1; } if (sw > 0) No++; if (p_type < 0 && pr > 0) { OUT.Write("入力パターン" + (i1+1) + " "); for (int i2 = 0; i2 < noiu; i2++) { OUT.Write(" " + op[k1+i2]); if (i2 == noiu-1) OUT.WriteLine(); else { if(((i2+1) % 10) == 0) { OUT.WriteLine(); OUT.Write(" "); } } } OUT.WriteLine(); OUT.Write(" 出力パターン(理想) "); for (int i2 = 0; i2 < noou; i2++) { OUT.Write(" " + p.optn[i1][i2]); if (i2 == noou-1) OUT.WriteLine(); else { if(((i2+1) % 5) == 0) { OUT.WriteLine(); OUT.Write(" "); } } } OUT.Write(" (実際) "); for (int i2 = 0; i2 < noou; i2++) { OUT.Write(" " + op[i2]); if (i2 == noou-1) OUT.WriteLine(); else { if(((i2+1) % 5) == 0) { OUT.WriteLine(); OUT.Write(" "); } } } } if (p_type != 0 && pr > 0) Console.ReadLine(); } // // 重みの出力 // int ln; if ((p_type < -1 || p_type > 1) && pr == 1) { Console.WriteLine(" 重み"); for (int i1 = 0; i1 < nou-noiu; i1++) { Console.Write(" to " + (i1+1) + " from "); ln = -1; for (int i2 = 0; i2 < nou; i2++) { if (con[i1][i2] > 0) { if (ln <= 0) { if (ln < 0) ln = 0; else { Console.WriteLine(); Console.Write(" "); } } Console.Write(" " + (i2+1) + " " + w[i1][i2]); ln += 1; if (ln == 4) ln = 0; } } Console.WriteLine(); } Console.WriteLine(); Console.Write(" バイアス "); ln = 0; for (int i1 = 0; i1 < nou-noiu; i1++) { Console.Write(" " + (i1+1) + " " + theta[i1]); ln += 1; if (ln == 4 && i1 != nou-noiu-1) { ln = 0; Console.WriteLine(); Console.Write(" "); } } if (ln != 0) Console.WriteLine(); Console.ReadLine(); } if (p_type < 0 && pr == 1) { OUT.WriteLine(" 重み"); for (int i1 = 0; i1 < nou-noiu; i1++) { OUT.Write(" to " + (i1+1) + " from "); ln = -1; for (int i2 = 0; i2 < nou; i2++) { if (con[i1][i2] > 0) { if (ln <= 0) { if (ln < 0) ln = 0; else { OUT.WriteLine(); OUT.Write(" "); } } OUT.Write(" " + (i2+1) + " " + w[i1][i2]); ln += 1; if (ln == 4) ln = 0; } } OUT.WriteLine(); } OUT.WriteLine(); OUT.Write(" バイアス "); ln = 0; for (int i1 = 0; i1 < nou-noiu; i1++) { OUT.Write(" " + (i1+1) + " " + theta[i1]); ln += 1; if (ln == 4 && i1 != nou-noiu-1) { ln = 0; OUT.WriteLine(); OUT.Write("\n "); } } if (ln != 0) OUT.WriteLine(); } if (p_type < 0 && pr > 0) OUT.Close(); return No; } } /* ------------------------制御データ---------------- 誤差 0.1 出力 -2 出力ファイル kekka 順番 0 η 0.5 α 0.8 画面表示(円の大きさ,フォントサイズ,幅,高さ) 20 20 400 300 ------------------------構造データ---------------- 入力ユニット数 2 出力ユニット数 1 関数タイプ 0 隠れ層の数 1 各隠れ層のユニット数(下から) 1 バイアス入力ユニット数 1 ユニット番号:出力ユニットから順に番号付け 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1])) 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限) 1 -1 -0.05 0.05 接続方法の数 2 ユニット番号:ユニットk1からk2を,k3からk4に接続 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限) 3 4 1 2 1 -0.1 0.1 2 2 1 1 1 -0.1 0.1 ------------------------学習データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 ------------------------認識データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 */
'**************************' ' back propagation model ' ' coded by Y.Suganuma ' '**************************' Imports System.IO Imports System.Text.RegularExpressions Module Test Sub Main(args() As String) ' エラー If args.Length <> 2 Console.WriteLine("***error 入力データファイル名を指定して下さい") Environment.Exit(1) Else ' ネットワークの定義 Dim net As Backpr = new Backpr(args(0), args(1)) ' 学習パターン等の入力 Console.Write("学習回数は? ") Dim m_tri As Integer = Integer.Parse(Console.ReadLine()) ' 最大学習回数 Console.Write("何回毎に収束を確認しますか? ") Dim conv As Integer = Integer.Parse(Console.ReadLine()) ' 収束確認回数 Console.Write("学習パターンのファイル名は? ") Dim f_name As String = Console.ReadLine() Dim dt1 As BackData = new BackData(f_name) ' 学習 Dim max As Integer = 0 Dim no As Integer = 1 Do While max < m_tri and no > 0 Dim tri As Integer If (max + conv) < m_tri tri = conv Else tri = m_tri - max End If max += tri net.Learn(dt1, tri) ' 学習 no = net.Recog(dt1, 0, max) ' 学習対象の認識 Console.WriteLine(" 回数 " & max & " 誤って認識したパターン数 " & no) Loop no = net.Recog(dt1, 1, max) ' 学習対象の認識と出力 ' 未学習パターンの認識 Console.Write("未学習パターンの認識を行いますか?(=1:行う,=0:行わない) ") Dim sw As Integer = Integer.Parse(Console.ReadLine()) If sw > 0 Console.Write("未学習パターンのファイル名は? ") f_name = Console.ReadLine() Dim dt2 As BackData = new BackData(f_name) no = net.Recog(dt2, 2, max) ' 未学習対象の認識と出力 End If End If End Sub '****************************************************' ' バックプロパゲーションの制御(クラス BackControl) ' '****************************************************' Class BackControl Protected alpha As Double '重み及びバイアス修正パラメータ Protected eata As Double '重み及びバイアス修正パラメータ Protected eps As Double ' 許容誤差 Protected order As Integer ' 入力パターンの与え方(=0:順番,=1:ランダム) Protected p_type As Integer ' 出力先・方法の指定 ' =0 : 誤って認識した数だけ出力 ' =1 : 認識結果を出力 ' =2 : 認識結果と重みを出力 ' (負の時は,認識結果と重みをファイルへも出力) Protected o_file As String ' 出力ファイル名 '***********************************' ' クラスBackControlのコンストラクタ ' ' name : 入力データファイル名 ' '***********************************' Public Sub New(name As String) Dim inp As StreamReader = New StreamReader(name) Dim MS As Regex = New Regex("\s+") Dim str() As String = MS.Split(inp.ReadLine().Trim()) eps = Double.Parse(str(1)) p_type = Integer.Parse(str(3)) If p_type < 0 o_file = str(5) End If str = MS.Split(inp.ReadLine().Trim()) order = Integer.Parse(str(1)) eata = Double.Parse(str(3)) alpha = Double.Parse(str(5)) inp.Close() End Sub End Class '***************************************************' ' バックプロパゲーションのデータ(クラス BackData) ' '***************************************************' Class BackData Public noiu As Integer ' 入力ユニットの数 Public noou As Integer ' 出力ユニットの数 Public noip As Integer ' 入力パターンの数 Public iptn(,) As Double ' iptn(i,j) : (i+1)番目の入力パターンの(j+1)番目の ' 入力ユニットの入力値 ' i=0,noip-1 j=0,noiu-1 Public optn(,) As Double ' optn(i,j) : (i+1)番目の入力パターンに対する(j+1) ' 番目の出力ユニットの目標出力値 ' i=0,noip-1 j=0,noou-1 '**********************************' ' クラスBackDataのコンストラクタ ' ' name : 入力データファイル名 ' '**********************************' Public Sub New(name As String) Dim MS As Regex = New Regex("\s+") Dim inp As StreamReader = New StreamReader(name) ' ' 入力パターン数等 ' Dim str() As String = MS.Split(inp.ReadLine().Trim()) noip = Integer.Parse(str(1)) noiu = Integer.Parse(str(3)) noou = Integer.Parse(str(5)) ' ' 領域の確保 ' ReDim iptn(noip,noiu) ReDim optn(noip,noou) ' ' 入力パターン及び各入力パターンに対する出力パターンの入力 ' For i1 As Integer = 0 To noip-1 str = MS.Split(inp.ReadLine().Trim()) For i2 As Integer = 0 To noiu-1 iptn(i1,i2) = Double.Parse(str(i2+1)) Next str = MS.Split(inp.ReadLine().Trim()) For i2 As Integer = 0 To noou-1 optn(i1,i2) = Double.Parse(str(i2+1)) Next Next inp.Close() End Sub End Class '*****************************************' ' バックプロパゲーション(クラス Backpr) ' '*****************************************' Class Backpr Inherits BackControl ' クラス BackControl を継承 Private con(,) As Integer ' バイアスの与え方,及び,接続方法 ' (i,i) : ユニット(i+1)のバイアスの与え方 ' =-3 : 入力値で固定 ' =-2 : 入力値を初期値として,学習により変更 ' =-1 : 乱数で初期値を設定し,学習により変更 ' (i,j) : ユニット(i+1)と(j+1)の接続方法(j>i) ' =0 : 接続しない ' =1 : 接続する(重みの初期値を乱数で設定し,学習) ' =2 : 接続する(重みの初期値を入力で与え,学習) ' =3 : 接続する(重みを入力値に固定) ' i=0,nou-1 j=0,nou-1 Private f_type As Integer ' シグモイド関数のタイプ ' 0 : (0,1) ' 1 : (-1,1)) Private noiu As Integer ' 入力ユニットの数 Private noou As Integer ' 出力ユニットの数 Private nohu() As Integer ' nohu(i) : レベル(i+1)の隠れ層のユニット数(隠れ層 ' には下から順に番号が付けられ,出力層はレ ' ベル(nolvl+1)の隠れ層とも見做される) ' i=0,nolvl Private nolvl As Integer ' 隠れユニットの階層数 Private nou As Integer ' 入力,出力,及び,隠れ層の各ユニットの数の和(各ユニ ' ットには最も上の出力ユニットから,隠れ層の各ユニット, ' 及び,入力ユニットに至る一連のユニット番号が付けられ ' る) Private dp() As Double ' dp(i) : ユニット(i+1)の誤差 i=0,nou-1 Private op() As Double ' op(i) : ユニット(i+1)の出力 i=0,nou-1 Private theta() As Double 'theta(i) : ユニット(i+1)のバイアス i=0,nou Private w(,) As Double ' w(i,j) : ユニット(i+1)から(j+1)への重み(j>i) ' w(j,i) : (i+1)から(j+1)への重みの前回修正量(j>i) ' w(i,i) : ユニット(i+1)のバイアスの前回修正量 ' i=0,nou-1 j=0,nou-1 Private rn As Random ' 乱数 '**********************************************' ' クラスBackprのコンストラクタ ' ' name_c : 制御データ用入力ファイル名 ' ' name_s : ネットワーク記述入力ファイル名 ' '**********************************************' Public Sub New(name_c As String, name_s As String) MyBase.new(name_c) ' 基底クラスのコンストラクタ Dim MS As Regex = New Regex("\s+") Dim inp As StreamReader = New StreamReader(name_s) ' ' 乱数の初期化 ' rn = new Random() ' 乱数の初期設定 ' ' 入力ユニット,出力ユニットの数,関数タイプ ' Dim str() As String = MS.Split(inp.ReadLine().Trim()) noiu = Integer.Parse(str(1)) noou = Integer.Parse(str(3)) f_type = Integer.Parse(str(5)) nou = noiu + noou ' 入力ユニットと出力ユニットの和 ' ' 隠れユニットの階層数と各階層のユニット数 ' str = MS.Split(inp.ReadLine().Trim()) nolvl = Integer.Parse(str(1)) ReDim nohu(nolvl+1) nohu(nolvl) = noou ' 出力ユニットの数 If nolvl > 0 For i1 As Integer = 0 To nolvl-1 nohu(i1) = Integer.Parse(str(i1+3)) nou += nohu(i1) Next End If ' ' 領域の確保 ' ReDim con(nou,nou) For i1 As Integer = 0 To nou-1 For i2 As Integer = 0 To nou-1 If i1 = i2 con(i1,i2) = -1 Else con(i1,i2) = 0 End If Next Next ReDim w(nou,nou) For i1 As Integer = 0 To nou-1 For i2 As Integer = 0 To nou-1 w(i1,i2) = 0.0 Next Next ReDim dp(nou) ReDim op(nou) ReDim theta(nou) For i1 As Integer = 0 To nou-1 theta(i1) = 0.2 * rn.NextDouble() - 0.1 Next ' ' 各ユニットのバイアスとユニット間の接続関係 ' ' バイアス ' バイアスデータの数 str = MS.Split(inp.ReadLine().Trim()) Dim nb As Integer = Integer.Parse(str(1)) inp.ReadLine() inp.ReadLine() inp.ReadLine() If nb > 0 ' バイアスデータの処理 For i0 As Integer = 0 To nb-1 ' ユニット番号 str = MS.Split(inp.ReadLine().Trim()) Dim k1 As Integer = Integer.Parse(str(0)) ' 不適当なユニット番号のチェック If k1 < 1 or k1 > (nou-noiu) Console.WriteLine("***error ユニット番号 " & k1 & " が不適当") Environment.Exit(1) End If ' バイアスの与え方 k1 -= 1 Dim id As Integer = Integer.Parse(str(1)) con(k1,k1) = id ' バイアスの初期設定 Select Case con(k1,k1) Case -1 Dim x1 As Double = Double.Parse(str(2)) Dim x2 As Double = Double.Parse(str(3)) theta(k1) = (x2 - x1) * rn.NextDouble() + x1 Case -2 theta(k1) = Double.Parse(str(2)) Case -3 theta(k1) = Double.Parse(str(2)) Case Else Console.WriteLine("***error バイアスの与え方が不適当") Environment.Exit(1) End Select Next End If ' 接続方法 ' 接続データの数 str = MS.Split(inp.ReadLine().Trim()) Dim n As Integer = Integer.Parse(str(1)) inp.ReadLine() inp.ReadLine() inp.ReadLine() If n > 0 ' 接続データの処理 For i0 As Integer = 0 To n-1 ' 接続情報 str = MS.Split(inp.ReadLine().Trim()) Dim k1 As Integer = Integer.Parse(str(0)) Dim k2 As Integer = Integer.Parse(str(1)) Dim k3 As Integer = Integer.Parse(str(2)) Dim k4 As Integer = Integer.Parse(str(3)) ' 不適切な接続のチェック Dim sw As Integer = 0 If k1 < 1 or k2 < 1 or k3 < 1 or k4 < 1 sw = 1 Else If k1 > nou or k2 > nou or k3 > nou or k4 > nou sw = 1 Else If k1 > k2 or k3 > k4 sw = 1 Else If k4 >= k1 sw = 1 Else Dim l1 As Integer = -1 Dim k As Integer = 0 Dim i1t As Integer = nolvl Do While i1t >= 0 and l1 < 0 k += nohu(i1t) If k1 <= k l1 = i1t End If i1t -= 1 Loop Dim l2 As Integer = -1 k = 0 i1t = nolvl Do While i1t >= 0 and l2 < 0 k += nohu(i1t) If k4 <= k l2 = i1t End If i1t -= 1 Loop If l2 <= l1 sw = 1 End If End If End If End If End If If sw > 0 Console.WriteLine("***error ユニット番号が不適当(" & k1 & " " & k2 & " " & k3 & " " & k4 & ")") Environment.Exit(1) End If ' 重みの初期値の与え方 k1 -= 1 k2 -= 1 k3 -= 1 k4 -= 1 Dim id As Integer = Integer.Parse(str(4)) Dim x1 As Double = 0.0 Dim x2 As Double = 0.0 If id = 1 x1 = Double.Parse(str(5)) x2 = Double.Parse(str(6)) Else If (id > 1) x1 = Double.Parse(str(5)) Else If id <> 0 Console.WriteLine("***error 接続方法が不適当") Environment.Exit(1) End If End If End If ' 重みの初期値の設定 For i1 As Integer = k3 To k4 For i2 As Integer = k1 To k2 con(i1,i2) = id Select Case id Case 0 w(i1,i2) = 0.0 Case 1 w(i1,i2) = (x2 - x1) * rn.NextDouble() + x1 Case 2 w(i1,i2) = x1 Case 3 w(i1,i2) = x1 End Select Next Next Next End If inp.Close() End Sub '***************************' ' 学習の実行 ' ' p : 認識パターン ' ' m_tri : 最大学習回数 ' '***************************' Public Sub Learn(p As BackData, m_tri As Integer) ' ' エラーチェック ' If noiu <> p.noiu or noou <> p.noou Console.WriteLine("***error 入力または出力ユニットの数が違います") Environment.Exit(1) End If Dim k0 As Integer = -1 For i1 As Integer = 0 To m_tri-1 ' ' パターンを与える順番の決定 ' If order = 0 ' 順番 k0 += 1 If k0 >= p.noip k0 = 0 End If Else ' ランダム k0 = Math.Floor(rn.NextDouble() * p.noip) If k0 >= p.noip k0 = p.noip - 1 End If End If ' ' 出力ユニットの結果を計算 ' Dim k1 As Integer = nou - noiu For i2 As Integer = 0 To noiu-1 op(k1+i2) = p.iptn(k0,i2) Next Forward() ' ' 重みとバイアスの修正 ' Dim ptn(noou) As Double For i2 As Integer = 0 To noou-1 ptn(i2) = p.optn(k0,i2) Next Err_back(ptn) Next End Sub '******************************************************' ' 与えられた入力パターンに対する各ユニットの出力の計算 ' '******************************************************' Sub Forward() For i1 As Integer = nou-noiu-1 To 0 Step -1 Dim sum As Double = -theta(i1) For i2 As Integer = i1+1 To nou-1 If con(i1,i2) > 0 sum -= w(i1,i2) * op(i2) End If Next If f_type = 0 op(i1) = 1.0 / (1.0 + Math.Exp(sum)) : Else op(i1) = 1.0 - 2.0 / (1.0 + Math.Exp(sum)) End If Next End Sub '****************************************' ' 誤差の計算,及び,重みとバイアスの修正 ' ' ptn(i1) : 出力パターン ' '****************************************' Sub Err_back(ptn() As Double) For i1 As Integer = 0 To nou-noiu-1 ' 誤差の計算 If i1 < noou If f_type = 0 dp(i1) = (ptn(i1) - op(i1)) * op(i1) * (1.0 - op(i1)) Else dp(i1) = 0.5 * (ptn(i1) - op(i1)) * (op(i1) - 1.0) * (op(i1) + 1.0) End If Else Dim x1 As Double = 0.0 For i2 As Integer = 0 To i1-1 If con(i2,i1) > 0 x1 += dp(i2) * w(i2,i1) End If Next If f_type = 0 dp(i1) = op(i1) * (1.0 - op(i1)) * x1 Else dp(i1) = 0.5 * (op(i1) - 1.0) * (op(i1) + 1.0) * x1 End If End If ' 重みの修正 For i2 As Integer = i1+1 To nou-1 If con(i1,i2) = 1 or con(i1,i2) = 2 Dim x1 As Double = eata * dp(i1) * op(i2) + alpha * w(i2,i1) w(i2,i1) = x1 w(i1,i2) += x1 End If Next ' バイアスの修正 If con(i1,i1) >= -2 Dim x1 As Double = eata * dp(i1) + alpha * w(i1,i1) w(i1,i1) = x1 theta(i1) += x1 End If Next End Sub '*********************************************' ' 与えられた対象の認識と出力 ' ' p : 認識パターン ' ' pr : =0 : 出力を行わない ' ' =1 : 出力を行う ' ' =2 : 出力を行う(未学習パターン) ' ' tri : 現在の学習回数 ' ' return : 誤って認識したパターンの数 ' '*********************************************' Public Function Recog(p As BackData, pr As Integer, tri As Integer) ' ' ファイルのオープン ' Dim Out As StreamWriter If p_type < 0 and pr > 0 OUT = new StreamWriter(o_file, true) If pr = 1 OUT.WriteLine("***学習パターン***") OUT.WriteLine() Else OUT.WriteLine() OUT.WriteLine("***未学習パターン***") OUT.WriteLine() End If End If ' ' 各パターンに対する出力 ' Dim No As Integer = 0 For i1 As Integer = 0 To p.noip-1 ' 入力パターンの設定 Dim k1 As Integer = nou - noiu For i2 As Integer = 0 To noiu-1 op(k1+i2) = p.iptn(i1,i2) Next ' 出力の計算 Forward() ' 結果の表示 If p_type <> 0 and pr > 0 Console.Write("入力パターン" & (i1+1) & " ") For i2 As Integer = 0 To noiu-1 Console.Write(" " & op(k1+i2)) If i2 = noiu-1 Console.WriteLine() Else If ((i2+1) Mod 10) = 0 Console.WriteLine() Console.Write(" ") End If End If Next Console.WriteLine() Console.Write(" 出力パターン(理想) ") For i2 As Integer = 0 To noou-1 Console.Write(" " & p.optn(i1,i2)) If i2 = noou-1 Console.WriteLine() Else If((i2+1) Mod 5) = 0 Console.WriteLine() Console.Write(" ") End If End If Next End If Dim sw As Integer = 0 If p_type <> 0 and pr > 0 Console.Write(" (実際) ") End If For i2 As Integer = 0 To noou-1 If p_type <> 0 and pr > 0 Console.Write(" " & op(i2)) If i2 = noou-1 Console.WriteLine() Else If ((i2+1) Mod 5) = 0 Console.WriteLine() Console.Write(" ") End If End If End If If Math.Abs(op(i2)-p.optn(i1,i2)) > eps sw = 1 End If Next If sw > 0 No += 1 End If If p_type < 0 and pr > 0 OUT.Write("入力パターン" & (i1+1) & " ") For i2 As Integer = 0 To noiu-1 OUT.Write(" " & op(k1+i2)) If i2 = noiu-1 OUT.WriteLine() Else If ((i2+1) Mod 10) = 0 OUT.WriteLine() OUT.Write(" ") End If End If Next OUT.WriteLine() OUT.Write(" 出力パターン(理想) ") For i2 As Integer = 0 To noou-1 OUT.Write(" " & p.optn(i1,i2)) If i2 = noou-1 OUT.WriteLine() Else If ((i2+1) Mod 5) = 0 OUT.WriteLine() OUT.Write(" ") End If End If Next OUT.Write(" (実際) ") For i2 As Integer = 0 To noou-1 OUT.Write(" " & op(i2)) If i2 = noou-1 OUT.WriteLine() Else If ((i2+1) Mod 5) = 0 OUT.WriteLine() OUT.Write(" ") End If End If Next End If If p_type <> 0 and pr > 0 Console.ReadLine() End If Next ' ' 重みの出力 ' Dim ln As Integer If (p_type < -1 or p_type > 1) and pr = 1 Console.WriteLine(" 重み") For i1 As Integer = 0 To nou-noiu-1 Console.Write(" to " & (i1+1) & " from ") ln = -1 For i2 As Integer = 0 To nou-1 If con(i1,i2) > 0 If ln <= 0 If ln < 0 ln = 0 Else Console.WriteLine() Console.Write(" ") End If End If Console.Write(" " & (i2+1) & " " & w(i1,i2)) ln += 1 If ln = 4 ln = 0 End If End If Next Console.WriteLine() Next Console.WriteLine() Console.Write(" バイアス ") ln = 0 For i1 As Integer = 0 To nou-noiu-1 Console.Write(" " & (i1+1) & " " & theta(i1)) ln += 1 If ln = 4 and i1 <> nou-noiu-1 ln = 0 Console.WriteLine() Console.Write(" ") End If Next If ln <> 0 Console.WriteLine() End If Console.ReadLine() End If If p_type < 0 and pr = 1 OUT.WriteLine(" 重み") For i1 As Integer = 0 To nou-noiu-1 OUT.Write(" to " & (i1+1) & " from ") ln = -1 For i2 As Integer = 0 To nou-1 If con(i1,i2) > 0 If ln <= 0 If ln < 0 ln = 0 Else OUT.WriteLine() OUT.Write(" ") End If End If OUT.Write(" " & (i2+1) & " " & w(i1,i2)) ln += 1 If ln = 4 ln = 0 End If End If Next OUT.WriteLine() Next OUT.WriteLine() OUT.Write(" バイアス ") ln = 0 For i1 As Integer = 0 To nou-noiu-1 OUT.Write(" " & (i1+1) & " " & theta(i1)) ln += 1 If ln = 4 and i1 <> nou-noiu-1 ln = 0 OUT.WriteLine() OUT.WriteLine() OUT.Write(" ") End If Next If ln <> 0 OUT.WriteLine() End If End If If p_type < 0 and pr > 0 OUT.Close() End If Return No End Function End Class End Module /* ------------------------制御データ---------------- 誤差 0.1 出力 -2 出力ファイル kekka 順番 0 η 0.5 α 0.8 画面表示(円の大きさ,フォントサイズ,幅,高さ) 20 20 400 300 ------------------------構造データ---------------- 入力ユニット数 2 出力ユニット数 1 関数タイプ 0 隠れ層の数 1 各隠れ層のユニット数(下から) 1 バイアス入力ユニット数 1 ユニット番号:出力ユニットから順に番号付け 入力方法:=-3:固定,=-2:入力後学習,=-1:乱数(default,[-0.1,0.1])) 値:バイアス値(ー2またはー3の時)または一様乱数の範囲(下限,上限) 1 -1 -0.05 0.05 接続方法の数 2 ユニット番号:ユニットk1からk2を,k3からk4に接続 接続方法:=0:接続なし,=1:乱数,=2:重み入力後学習,=3:重み固定 値:重み(2または3の時)または一様乱数の範囲(1の時:下限,上限) 3 4 1 2 1 -0.1 0.1 2 2 1 1 1 -0.1 0.1 ------------------------学習データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 ------------------------認識データ---------------- パターンの数 4 入力ユニット数 2 出力ユニット数 1 入力1 0 0 出力1 0 入力2 0 1 出力2 1 入力3 1 0 出力3 1 入力4 1 1 出力4 0 */
情報学部 | 菅沼ホーム | 目次 | 索引 |