#概要
FPGA上で動くNeuralNetworkジェネレータを作りました.
機能
- FeedForwardニューラルネットワークが製作可能
- 出力は0,1のみ
- VerilogHDLで出力
- 非同期回路(クロックに依存しない)
- 任意bit幅の固定小数に対応
- 活性化関数はシグマ関数
- 推論のみ(学習はできない)
リポジトリはここ
https://github.com/kotauchisunsun/NN_FPGA
#動作環境
- Python 2.7以上3未満
- Icarus Verilog
Python2.7はジェネレータに必須ですが,Icurus Verilogはシミュレーションしなければ必須ではありません.特にライブラリは必要とせず,Python標準ライブラリのみで動きます.
#ライセンス
Affero GPL v3
#使い方
NeuralNetworkの構造部分
基本文法は
$ python script/main.py width input_num structure output_num
width : 小数のbit幅
input_num : 入力信号の数
structure : ネットワーク構造を示す.カンマ区切りで多段構造を表現することができる(後述)
output_num : 出力信号の数
例)
$ python script/main.py 16 2 2 2
> NN_NL_016_0002_0002_NL_016_0002_0002
> saved to generate.v
> None
これにより,generate.vの中に16bitの小数で動くNN_NL_016_0002_0002_NL_016_0002_0002というニューラルネットが構築されます.
これは下の図のようなニューラルネットを表します.
それぞれの意味は
input* : 入力
output* : 出力
w* : 入力に対する重み係数
b* : ニューラルネットのバイアス
例えば左上のニューラルネットワークが発火する条件は
if input1 * w1 + input2 * w3 + b1 > 0:
return 1
else:
return 0
となっています.
また,NN_NL_016_0002_0002_NL_016_0002_0002に渡される引数の順番ですが,
- input*
- w*
- b*
- output*
の順番です.
したがって,この場合を全部書き下すと
input1,input2,w1,w2,w3,w4,w5,w6,w7,w8,b1,b2,b3,b4,ouput1,output2
となっています.
これによりニューラルネットワークが推論された結果が,output1,output2に入ります.
また,このmain.pyは多段のニューラルネットワークを構築することも可能で,
$ python main.py 16 32 64,32,48 16
とすると,16bit幅の小数を扱うことができる,
層 | ニューラルネットのユニット数 |
---|---|
入力層 | 32 |
隠れ層1 | 64 |
隠れ層2 | 32 |
隠れ層3 | 48 |
出力層 | 16 |
というニューラルネットワークを構成することができます.
#小数表現
今回のニューラルネットワークは一般的に使われる浮動小数点に対応していません.
そのため,重み係数や,入力を代入するにはひと手間かかります.
小数の仕様は以下のようになっています.
width = 16の場合
1~8bit: 小数部 それぞれのbitが2^(-8+i-1)を表す.(C)
9~15bit: 整数部 それぞれのbitが2^(i-8-1)を表す.(N)
16bit: 負の数のフラグ.(F)
bit | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
意味 | F | N | N | N | N | N | N | N | C | C | C | C | C | C | C | C |
となっています.width/2までのbitが小数部,トップのbitが負の数のフラグ,それ以外が整数部となっています.
これだけ聞くとややこしいので,スクリプトを用意しました.
$ python script/convert_number.py width number
``
width: 小数のbit幅
number: 変換したい値
例:
$ python script/convert_number.py 16 5.5
16b'0000010110000000
ABS ERROR = 0.000000e+00
これにより,16bitの小数で5.5を表現したとき,16b'0000010110000000となることが分かります.
Verilogで構築する際にはこの値を入れれば大丈夫なことが分かります.
ここで,ABS ERRORは小数表現したときの誤差となります.10進数の小数を16bitの2進数で表したとき,どれくらい絶対誤差が生まれるかを10進法表現しています.
例:
$ python script/convert_number.py 16 -1.1
16b'1111111011100111
ABS ERROR = 2.343750e-03
-1.1を16bitの固定小数で表した場合,ABS ERROR = 2.343750e-03となっているので,誤差があることが分かります.そこで,32bitの固定小数で表すと,
例:
$ python script/convert_number.py 32 -1.1
32b'11111111111111101110011001100111
ABS ERROR = 9.155273e-06
ABS ERROR = 9.155273e-06となり,16bitで表現したときと比べ,誤差が減っていることが分かります.bit幅を大きくとると精度は上がりますが,回路規模が大きくなりFPGA上で動かなくなるので,バランスをとりながらチューニングしてください.
#終わりに
VerilogHDLとFPGAを始めて4カ月の拙作です.バグや間違い,拡張の方針等ありましたらご助言いただけると幸いです.