| 情報学部 | 菅沼ホーム | 目次 | 索引 |
/****************************/ /* 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
*/
| 情報学部 | 菅沼ホーム | 目次 | 索引 |