Home › Monthly Archives › 9月 2014

(35) ニューラルネットでちょっと複雑な関数を近似

(33) ニューラルネットでsin関数を近似 をちょっとだけ複雑な式に変えても近似できるか? を試してみる。

使うのは心電図の波形のようなこんな関数にする。
20140920_04

nnet_sin_4

(1) 学習データを作成

data_IN  = [-5 : 0.1 : 5];
data_OUT = sin(data_IN) + cos(power(data_IN,2)) + tan(data_IN);

(2) 4層ニューラルネットワークを作成

S = [16 32 1];
R = [min(data_IN), max(data_IN)]
NNet = newff( R, S );
NNet.trainParam.epochs = 3000;

(3) 学習を実行

VV.P = data_IN;
VV.T = data_OUT;
NNet = train( NNet, data_IN, data_OUT, [], [], VV );
data_RES = sim( NNet, data_IN );
plot( data_IN, data_RES, 'b','LineWidth',2', ...
      data_IN, data_OUT, 'r','LineWidth',2' );

(4) 未学習のデータで検証

test_IN  = rand(1,100) * 10 - 5;
test_OUT = sim( NNet, test_IN );
plot(data_IN, data_OUT, 'r', 'LineWidth',2',...
     test_IN, test_OUT, 'b+','LineWidth',2' );

3,000エポックではまだまだのようだが、なんとなく近似できているようだ。
20140920_05

(34) ニューラルネットでsin関数を近似(その2)

(33) ニューラルネットでsin関数を近似 では、3層(1-3-1)のニューラルネットワークにsin関数を学習させてみた。

今回は下表の3種類のネットワーク構成で比較してみた。

1 3層 [I 1] – [H 3] – [O 1]
2 3層 [I 1] – [H 5] – [O 1]
3 4層 [I 1] – [H 5] – [H 3] – [O 1] 水色

nnet_sin_2
隠れ層のユニット数が多い方が、学習開始直後の学習進捗が速いようだ。
問題が簡単なためか、50エポック辺りからは差がわからない。

pkg load nnet
rand('state', 0)
randn('state', 0)

% 学習データを作成
data_IN  = [ -pi*2 : 0.1 : pi*2 ];
data_OUT = sin(data_IN);
Rx2      = [min(data_IN), max(data_IN)];

% 3層ニューラルネットワーク(#1)を作成
S01 = [3 1];
NNet01 = newff( Rx2, S01 );
NNet01.trainParam.epochs = 60;

% 3層ニューラルネットワーク(#2)を作成
S02 = [5 1];
NNet02 = newff( Rx2, S02 );
NNet02.trainParam.epochs = 60;

% 4層ニューラルネットワークを作成
S03 = [5 3 1];
NNet03 = newff( Rx2, S03 );
NNet03.trainParam.epochs = 60;

% 学習を実行
VV.P = data_IN;
VV.T = data_OUT;

% net1
NNet01 = train( NNet01, data_IN, data_OUT, [], [], VV );
res01  = sim( NNet01, data_IN );

% net2
NNet02 = train( NNet02, data_IN, data_OUT, [], [], VV );
res02  = sim( NNet02, data_IN );

% net3
NNet03 = train( NNet03, data_IN, data_OUT, [], [], VV );
res03  = sim( NNet03, data_IN );

plot(data_IN, res01,    'b','LineWidth',2',    ...
     data_IN, res02,    'g','LineWidth',2',    ...
     data_IN, res03,    'c','LineWidth',2,
     data_IN, data_OUT, 'r','LineWidth',2' );

不明点
仕様上は train 戻り値は 4個あるはず。3番目のout はおそらく出力値のこと。
もしこれが取得できれば、上記プログラムの sim は不要になるはずだ。
しかし、現状の trainは戻り値を 1個しか返さない… なぜだ?

[net,tr,out,E] = train(MLPnet,mInputN,mOutput,[],[],VV);

(33) ニューラルネットでsin関数を近似

octaveには MATLABの Neural Network Toolbox に似せた nnet package がある。
http://octave.sourceforge.net/nnet/overview.html
注意 nnet packageは、Octave-Forgeで Unmaintained packages に分類されている。

これを使ってニューラルネットワークによる sin関数の近似 を試してみたい。
まずは nnet packageの簡単な使い方を調べながら実際に動かしてみた。

nnet_sin

(1) 学習データを作る

入力データは、-π x 2 ~ π x 2 までの範囲を 0.1刻みとする。
出力期待値データは、sin( 入力データ ) とする。

pkg load nnet
data_IN  = [ -pi*2 : 0.1 : pi*2 ];
data_OUT = sin(data_IN);

(2) ニューラルネットワークを作成

ネットワーク構成は隠れ層(ニューロン数3個)を1層のみとする。
学習時のエポック数は100回とする。
結合荷重、バイアスの初期値をどうしているかは未調査。
※初期値によってはうまく収束しない場合もある。

Rx2 = [min(data_IN), max(data_IN)];
S   = [3 1];
rand('state', 0)
randn('state', 0)
NNet = newff( Rx2, S );
NNet.trainParam.epochs = 100;

(3) 学習を実行

戻り値 net には、学習済みのニューラルネットが出力される。

VV.P = data_IN;
VV.T = data_OUT;
net = train( NNet, data_IN, data_OUT, [], [], VV );

誤差は順調に収束しているようだ。
20140920_01

(4) 学習に使用したデータの出力を確認

学習済みのニューラルネットに、学習に使用したデータを入力してみる。
学習に使用したデータに対して、ニューラルネットが sin関数をどれだけ近似できているか?を見たい。

res = sim( net, data_IN );
plot(data_IN, data_OUT, 'r', data_IN, res, 'b')

本物のsin関数の出力値を赤線、ニューラルネットの出力値を青線で表示した。
グラフ表示した結果はほぼ重なっているため、下側に表示した赤線がほとんど見えない。
20140920_02

両者の差を数値(最大値、最小値、標準偏差)で見てみる。

> diff = data_OUT - res;
> max(diff)
ans =  0.021823
> min(diff)
ans = -0.018701
> std(diff)
ans =  0.0057264

(5) 未学習の入力データの出力を確認

学習に使用していないデータを入力した場合に対応できているか?を見たい。

test_IN = rand(1,100) * 12 - 6;
res = sim( net, test_IN );
figure;
plot(data_IN, data_OUT, 'r', 'LineWidth',2', test_IN, res, 'b+');
grid on;
ylim([-1.2 1.2]);

本物のsin関数の出力値を赤線、ニューラルネットの出力値を青十字で表示した。
結果をグラフ表示すると、両者はほぼ重なっている。
20140920_06