○ パターンマッチングをしてみよう

注意→聞いた事を勝手に考えた理屈の上に作成しています、一般的に正しくない事が多いと思われます(とりあえず動けばヨシの精神です)
パターンマッチングとは特定のパターンにマッチするデータを探し出す処理です。
いわゆる機械学習とかディープラーニングとか言うものを作成してみます。

■ ニューロンモデル
生物のニューロンを模したモデルです。

入力一つ一つに重みが付けられており、入力に対して掛け算が行われます。
入力の合計が閾値を超えたら出力→発火(ON)します。

しかし、このモデルの場合には出力がONもしくはOFFであり、中間の値が無いため重みや閾値の調整ができません。
(重みや閾値をちょっと増やした結果が正しいのか間違っているのかわからない)
そこで、合計を閾値から引いた値(本来は発火を起こす値)をシグモイド関数に入れて1〜0のなめらかな出力をするようにします(どのような値を入れても1〜0の範囲になります)

このシグモイド関数の数式をエクセルの数式に置き換えると、= 1 / ( 1 + EXP( -x ) ) になります、シグモイド関数のグラフを作成してみました。

この数式をニューロンの出力に当てはめるとエクセルの数式では、= 1 / ( 1 + EXP( -( 入力 × 重み ) + 閾値)) となり、これをシグモイドニューロンと呼ぶらしいです。

このニューロンを複数配置し、答えに向けて収束させるようにしたのが次のようなニューラルネットワークです。


■ ニューラルネットワークの学習方法
答えがわかっているテストデータをたくさん用意して、それを使用して学習する教師あり学習をしたいと思います。
最適化とも言うのですが、どのように最適化していいのかよくわからないのでコンピュータのチカラワザで解決したいと思います。

まず、そのために必要なのが出力された結果がどれだけ答えからズレているのかが数値としてわかる必要がありますので、
そこで使用するのが、(データと平均値の差の2乗の合計の値) 平方和によりズレの統計量を計ります。
(出力 - 答え)^2 = ズレの量 (^2は2乗を意味します)

出力に対して答え0の場合にはズレが少なくなるほど0に近づきます


出力に対して答え1の場合でもズレが少なくなるほど0に近づきます

エクセルの関数だと、= SUMXMY2( 出力範囲 , 答え範囲 ) にて指定範囲のズレの合計(平方和)が計算できます。

▼ ニューラルネットワークの学習
結果が答えに対するズレの量が判断できるようになりました。
これで、沢山の学習データと答えのセットを使ってチカラワザで学習をさせる事ができます。

まず初期値として、全ての重みと閾値にランダムな数値を当てはめます。

(1) 一つ目の学習データを読み込ませて答えとのズレを求め、それを繰り返し、複数の学習データのズレの合計を計算します。
(2) 重みと閾値の値の一つを選択しわずかな数を足します。
(3) 再び、複数の学習データを読み込ませズレの合計を計算します。
(4) ズレの合計が目標とする値以下になったら終了します。
(5) ズレの合計が前回より悪くなったら、選択した値からわずかな数を引き算します。

(1)から(5)をひたすらに繰り返す事により、チカラワザでズレを目標値まで収束させることができます(初期値により収束しない事があります)
最適化が行き詰まる時は順番をランダムにして学習させます(なんかよくわからんがうまく動いたコレが回帰分析らしい)

▼ ここまでで思った事
ちょっと重みや閾値を変更するだけで、テストデータに対して結果が良くなったか悪くなったかがわかるようにするために、シグモイド関数や平方和を利用しています。
全ては最適化が行えるようにするための工夫のようです。
複雑な状態を受け入れられて最適化で答えに導けるのならニューロンモデルでなくても動作するという事じゃないでしょうか?

■ 学習後のテスト
ズレを目標値まで収束したら、学習完了です。
色々なデータを入れて学習されたニューラルネットワークがちゃんと動作するか確認します。


● 縦線、横線を判断するニューラルネットワーク
単純化するために5×5のマトリックス表内での縦線、横線を判断できるようにします。

5×5の信号を3個のニューロン(1、2、3)に渡し、その出力を2個のニューロン(4、5)で受け取り、その出力の比率で縦線、横線を判断します。
ニューロンおよび学習データをエクセルで作成し、VBAで学習し、テストも出来るようにしました。

エクセルファイル ptmatch_5_5h.xls

▼ エクセルシートを開くとこのような構成になっています。


▼ 学習データおよび、学習データ毎の計算がこの場所に配置されています。


▼ 5個のニューラルネットワークがこの場所に配置されています。


▼ 学習開始ボタンです。

最初から学習済みですが、再度学習をさせるにはボタンを押してVBAのマクロを走らせます。
マクロ内では、各ニューロンの重みと閾値を初期化の為にランダムな値を入れてから学習を開始します(パソコンの性能により時間がかかるかもしれません)
しばらくしても(7世代Corei5で1〜2分程度で)学習が終わらない場合にはESCキーを2回押してVBAを止めて再挑戦する必要があります(そのままでは永遠に終わりません)
マクロはインターネットからダウンロードしたファイルそのままではセキュリティの問題で実行が出来ないようですが 開発 → Visual Basic Editor を開くとコードを見る事は出来るようです。

▼ 学習後のテスト個所です、マトリックス表に1を入れたり消したりすると学習結果を元にリアルタイムに計算されて結果が出力されます。

縦線らしい配置や横線らしい配置を入力するとニューラルネットワークが判断してそれらしい答えが出力されます。
この結果は初期値のランダムな重み閾値や学習により、かしこい判断が出来る時もありますしダメな時もあります。
それなりに動作するのを確認できるはずです。


■ MNIST(エムニスト)データを読み込む
機械学習の画像認識の分野で広く使われる、手書き数字の画像データセットをプログラムから読み込んで見たいと思います。
まずは、データのダウンロード
train-images-idx3-ubyte.gz 学習用画像データ
train-labels-idx1-ubyte.gz 学習用正解ラベル
t10k-images-idx3-ubyte.gz テスト用画像データ
t10k-labels-idx1-ubyte.gz テスト用正解ラベル

4つのファイルをダウンロードして解凍(Linuxなら gzip -d *.gz )します。

学習画像データのファイルは先頭16バイトはヘッダーになっています。
ヘッダーの後に1byte(0 白 〜 255 黒)が1ピクセルとして28×28形式のデータが連続しています。
学習正解ラベルのファイルは先頭8バイトはヘッダーになっています。
ヘッダーの後に1byteの正解の値が連続しています。

以上の事柄を踏まえてC言語でデータを読み出すプログラムを作成しました。
#include <stdio.h>

int main(){
	FILE * fp,* fp_label;
	int i;
	unsigned char buff;

	if((fp=fopen("../train-images-idx3-ubyte","rb"))==NULL
		|| (fp_label=fopen("../train-labels-idx1-ubyte","rb"))==NULL){
		//エラー処理
		printf("error\n");
	}else{
		for(i=0;i<16;i++){//ヘッダーを読み飛ばす
			fread(&buff,1,1,fp);
		}
		for(i=0;i<8;i++){//ヘッダーを読み飛ばす
			fread(&buff,1,1,fp_label);
		}
		while(!feof(fp)){
			fread(&buff,1,1,fp_label);
			printf("---------------------------- %d\n",buff);
			for(int x=0;x<28;x++){
				for(int y=0;y<28;y++){
					fread(&buff,1,1,fp);
					if(buff){
						printf("#");
					}else{
						printf(" ");
					}
				}
				printf("\n");
			}
			getchar();

		}
	    fclose(fp);
	}
	return 0;
}

上記プログラムを走らせると、学習に必要な画像と正解が表示されます。


● 畳み込みネットワーク
マトリックス表が大きくなっても、大きなニューラルネットワークを用意すれば理屈の上ではうまいこと動作するはずです。
しかし、データー量が物凄く増えて最適化の処理に時間がかかり現実的でありません。
そこで、データー量が少なくなるように工夫を凝らしたのが畳み込みネットワークのようです。

■ 畳み込み層
しかし、こんな画像の全体を見てもどうやって判定するのか考えられません。
そこで細かく刻んで特徴と位置を抽出し判定します。

一つの全体より小さなニューラルネットワークをXY軸1ピクセル毎に一つ一つずらして特徴と位置を抽出します。
この一つのニューラルネットワークは一つの特徴と位置を検出できるようになります→これをフィルタと呼ぶらしい。

▼ 複数の特徴と位置を検出

フィルタを複数用意して学習させます。
そうすると、特徴と位置が異なったフィルタが作成され、複数の特徴と位置が認識できるようになります。
このフィルタの集まりをチャネルと呼ぶそうです。

■ プーリング層
フィルタ毎に特徴と位置が判定できるようになりましたが、実際にその位置にあるとは限りません。
そこで、フィルタのある範囲の重みの最大値を取り(最大プーリング)まとめます。

これにより多少ズレた位置に特徴が現れても判定できるようになります。


■ 出力層
プーリング層を考えられる特徴の数ぐらい作成し、必要な答えの数のニューロンに接続して、出力値の一番高いニューロンにより答えを導き出します。


● 縦線、横線を判断する畳み込みネットワーク
単純化するために10×10のマトリックス表内での縦線、横線を判断できるようにしました。
エクセルシートの構造は上で作成したニューラルネットワークの時とほぼ同じです。

エクセルファイル ptmatch_10_10h.xls
学習完了済みですが、学習には思ったより時間がかかります(10分ぐらい)、収束しない場合には無限ループになってますので学習をもう一度やり直す必要があります。



作成中


▲トップページ