2015年8月1日土曜日

C言語でニューラルネット(2次元平面での分離)

前回に引き続き,ニューラルネットワークです.

前回は,ニューラルネットによる関数近似を行いましたが,今回はちょっとパターン認識寄り.
というのも,2次元平面上のある点が,AとBどちらに分類されるのかという問題なためです.

たとえば,以下の様な状況の場合.

2D

これを2種類に分類したいとします.
理想的な場合,このように分類できると想像できると思います.

2D2

先ほどの4点を与えたとき,大体の人はこのように線を引いて分けると思います.
このような1本の線では分離ができない問題のことを,線形分離不可能な問題と言ったりします.

線形分離可能な例はこんな感じ.

2D3

1本の直線で,分類できています.

線形分離可能な問題は,単純パーセプトロンなどでも解けますが,線形分離不可能の場合には,隠れ層を持つようなニューラルネットワークの構成である必要があります.

このような隠れ層を持つニューラルネットワークの学習方法のひとつが,誤差逆伝播法(Back Propagation)です.

というわけで,2次元での分類を行っていきます.

まず,2次元の入力(x軸,y軸)に対して出力(●,×)があるので,入力次元は2,出力次元は1です.

data.datrho.dat
001
010
100
110

まずは,線形分離可能なパターンから試してみます.
ここで,data.datの左側がx軸,右側がy軸で,rho.datの0が●,1が×を表しています.
よって,このデータは先ほどの直線で分離できるデータを数字で表したものとなっています.

これをニューラルネットワークに入力として与えると,以下のようになります.

2D4

このように,確りと分離できていることがわかります.
プログラム中では,positive.datに0.5以上(厳密には超過)の出力群を,negative.datに0.5以下の出力群をファイル出力しています.

次に,線形分離不可能の場合.

data.datrho.dat
001
010
100
111

これは最初の図に対応します.
このときの出力は,以下のようになります.

2D5

左下と右上で,×になっています.
ここからわかるように,非線形の分離問題(EX-OR問題)に対しても分離を行えていることがわかります.

プログラムリストは,前回の物から少し変えてあります.(主にTest関数内)
以下リスト.

C言語でニューラルネット(関数近似)

C言語で関数近似を行うためのニューラルネットワーク(誤差逆伝播法,B ack P ropagation N eural N etwork)のプログラムです.

プログラム中で,Input_sizeは学習用データの入力の長さ,Input_dimは学習用データの次元,test_sizeは検証用データの入力の長さです.

たとえば,以下のような点の集合を関数で近似したい場合を考えます.
teacher

このとき,学習用データは次のように与えられます.

data.dat rho.dat
0 1
1 3
2 2
3 4

というわけで,上のように実行ファイルの場所に,data.datrho.datを作成します.
見て分かる通り,data.datがx軸,rho.datがy軸を表しています(一次元の場合).

この2種類のファイルから,Input_sizeInput_dimを設定します.
この場合,Input_sizeは,データが横軸に4つなので,Input_size=4とします.
また,入力は1次元なのでInput_dim=1です.

また,test_sizeは,学習が終わったあとのデータ点の数で,x軸の0~3を何分割するかを決める滑らかさの値です.
理想的な場合学習が起こった場合では,test_size=4とすると,上の図の点と同じ位置に点が打たれるはずです.
ここでは,どのように近似されたかを詳細に見るために,test_size=100とします.

これらのデータから実行した結果が以下の図.(学習回数1,000,000回,test_size=100

approx

このように,学習データとして与えた点を全て通るような曲線が描かれています.
これが,ニューラルネットワークによる関数近似です.

先ほど与えた点の値と,現在のニューラルネットワークの出力の誤差がどんどん小さくなっていくことで,与えた点を通る曲線が描かれています.
この曲線を拡大してみると,100個の点からなる直線の集合です(=test_sizeの値).

test_sizeを小さくするとこんな感じに.(学習回数1,000,000回,test_size=10

approx2

また,学習回数が少ない場合など.(学習回数10,000回,test_size=100

approx3

学習回数が少ないと,与えた点との近似率が落ちています.(点を通っていない)

学習回数が更に少ない場合.(学習回数1,000回,test_size=100

approx3

ここまでくると,もはや点を通ってすらいないです.

このように,ニューラルネットワークでの関数近似は,与えられた点と現在のニューラルネットワークによる出力の誤差が小さくなるように繰り返し学習することで,与えられた点を通る出力を得られるというものです.

というわけで以下リスト.

プログラム内の変数の詳細についてまとめておくと以下のようになっています.

label details
Input_size 入力の長さ(大きさ)
Input_dim 入力の次元
Hidden_dim 中間層の数
alpha シグモイド関数の傾き(後述)
eta 学習係数(他サイト参照)
gain ゲイン(後述)
test_size 学習後の検証用データの量(大きさ)
th 未使用

ここで,ニューラルネットワークに使用しているシグモイド関数は,0~1の範囲の実数しか取ることができないので,このままでは0~1の出力の範囲の点の近似しかできません.

このため,シグモイド関数にgainを掛けることで,擬似的にシグモイド関数の出力範囲を広げています.
たとえば,gain=100の場合では,シグモイド関数の出力範囲は-50~50の実数となります.
一応,負の値も取れるように,負方向にgainの半分だけずらしています.

これらの処理により,ニューラルネットワークで-50~50までの範囲の点を近似することができるようになっています.