1. FPGAでニューラルネットワークする。まずC言語でやってみる2

前回は同じ値で何度も学習させたら100回以内に収束していました。
今回はちゃんと違うデータを渡して関数の近似が出来るのかやってみます。

ちょっと変えたところ

前回最終段はただのSUMでしたが、そうすると誤差がより伝搬しないと思ったので(最終段で値の調整がかなり効くので)最終段も普通のノードにしました。
下の画像で言うと黄色いのが全てシグモイド関数で動き、赤いのが重み付けの存在する経路です。

Screen Shot 2015-01-25 at 10.44.17

x^2

最終段をシグモイド関数にしたことで出力範囲が0~1となりました。増幅してもいいですが、とりあえずx^2におけるx=0~1の範囲で学習させてみます。

Screen Shot 2015-01-25 at 10.36.57

これが結果です。左下のがプロットしたもので、赤がx^2の曲線で、緑がニューラルネットワークの出力です。
教師データはx^2の0~1にある等間隔な100個のデータです。100このデータを回して使って1000回やった結果(同じデータは10回使われていることになります)がこれになります。
グラフを見ると全く近似できてないですね。わずかに右肩上がりにはなってますが。
同じデータなら30回もやれば同じ値になったのに(前回ね)全くだめですね。
プログラムがおかしいのかと思ってさんざん見なおしたんですが、どうも回数の問題だったようです。10倍にして10,000回やってみます

Screen Shot 2015-01-25 at 10.37.06

割と近似できてますね。およそ5,000回目ぐらいで収束し始めているのが分かります。
こんなにやらなきゃいけないんですね^^;

レイヤー数を下げてみる

ちょっとレイヤー数を下げてみようと思いました。

Screen Shot 2015-01-25 at 11.01.54

こうしたらどうなるんでしょう。
同じく最初は1000回
Screen Shot 2015-01-25 at 10.36.38

いきなり曲線っぽくなってますね。レイヤーが少ないほうが柔軟に対応するんでしょうか。
回数を上げてみましょう。

Screen Shot 2015-01-25 at 10.36.47

10,000回にしてみました。さっきのレイヤー数の時は5,000回ぐらいで収束していきましたが、今回は1,000回ぐらいでかなり収束していますね。さらに10倍にしてみましょう。

Screen Shot 2015-01-25 at 10.37.45

おぉ。こんなに近似できるもんなんですね。あんなに簡単な回路なのにね(笑)
まぁ、学習量は半端無いわけですがそれでもすごい。

sin(x)

x^2だとキレイすぎるのでsin(x)をやってみました。sin(x)/2+0.5の関数を近似してみます。
レイヤー数は少ない方にしてみましょう。10,000回やった結果がこちら
Screen Shot 2015-01-25 at 10.39.45

それっぽいですね。でもx^2のときは10,000回やったらほぼ似てたのに、それに比べて大分ズレてますね。さらに10倍の100,000回にしてみましょう。

Screen Shot 2015-01-25 at 10.39.55

割りといい感じです。やっぱり最初の方はちょっと微妙ですが、かなり近いですね。
こんな簡単な回路でもここまで近似できるんですね。

速度的な話

何秒ぐらいかかったのか見てみます。さっきのレイヤーを減らした方でみてみましょう。
ちなみに重み付けできる経路は12ですね。
Screen Shot 2015-01-25 at 11.01.54

100,000回で

0.037208 sec

でした。1秒でおよそ 2,687,594回出来そうですね。
教師データはその都度計算してますから、x^2の計算も100,000回してるのですが、まぁ大したことはないでしょう。

ちなみにレイヤーの多い方は
Screen Shot 2015-01-25 at 10.44.17

100,000回で

0.060529 sec

でした。重み付けできる経路数が12から21になってますからこんなもんでしょうか。

FPGAでの実装に向けて

今回はfloatを使ってますが、浮動小数はめんどくさそうですね。signed shortとかでちょっと実装しなおしてみましょうか。