FC2カウンター FPGAの部屋 「ゼロから作るDeep Learning」の畳み込みニューラルネットワークのハードウェア化1

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

「ゼロから作るDeep Learning」の畳み込みニューラルネットワークのハードウェア化1

ゼロから作るDeep Learning」の7章 畳み込みニューラルネットワークをハードウェア化してFPGA に実装してみることにした。

学習はdeep-learning-from-scratch/ch05/ のtrain_neuralnet.py のコードをそのまま使用する。
このままでは浮動小数点数なので、指定されたビット長の固定小数点に量子化するメソッドをsimple_convnet_int.py、layers.py に追加してある。それが、simple_convnet_int.py、layers_int.py だ。
nn_fpga_ch7_1_170614.png

上の図のように Class Relu に def forward_int が追加されているのが分かると思う。つまり、固定小数点に量子化してforward 処理を実行するメソッドを追加したわけだ。ただし、Relu はforward と同じだ。今回は、更に、コードはforward と同じだが、メッセージを出力するforward_msg() を追加した。

今回の量子化は、全結合層 AF_*****と畳み込み層 COV_***** を分けた。
さらに、重みとバイアスの量子化ビットと出力の量子化ビットを分けてある。
forward_int() を書き換えてあるのは、class Affine と class Convolution のみだ。
重みやバイアスにAF_WB_MAG または COV_WB_MAG を掛けて、0.5 を加算して(四捨五入のため)integer に変換した後で、飽和演算を行う。すると小数点以下が切れてるので、量子化できることになる。そして、float に戻して、AF_WB_MAG または COV_WB_MAG で割っている。
その後、量子化の目安のため値のmax と min を表示しているが、今回は、DEBUG = 1 の時のみ表示する仕様にしている。
これは表示がうるさいときがあったからだ。
nn_fpga_ch7_2_170614.png
nn_fpga_ch7_3_170614.png

simple_convnet_int.py をjyputer Notebook で実行した結果を示す。この場合は、浮動小数点数での精度の値となっており、0.988 だった。
nn_fpga_ch7_4_170614.png
nn_fpga_ch7_5_170614.png

train_convnet.py の学習はそのまま使って、simple_convnet_int.py にも def loss_int や def predict_int、def accuracy_int を追加してあるので、固定小数点に量子化してforward 処理したときのaccuracy(精度)を確認することができる。
更に、DEBUG = 1 にすると、max値やmin値、配列の要素数などを観察することができる。
nn_fpga_ch7_6_170614.png

なお、量子化による演算を行った結果の精度は、0.986 だった。

最初に畳み込み層に入ってくる入力 x の配列は、(100, 1, 28, 28)だった。バッチ数が 100 個あるようだ。
重みの配列は(30, 1, 5, 5)だったつまり、30個の1チャネルの5x5 のカーネルということになる。
im2col()された col の配列は(57600, 25)だった。57600 = 24 x 24 x 100 バッチだ。24 は 28 ピクセルの画素を 5x5 にカーネル、ストライド1、パッド0で畳み込みしたときの出力ピクセルの幅と高さになる。
重みの配列は(30,)で、30個分の重みだ。これを30個の出力のすべての要素に足し算する。
畳み込み層の出力の配列は、(57600, 30)で、これをreshape すると、(100, 30, 24, 24)になる。これは、100バッチの30個の24x24 ということになる。
プーリング層の入力は、同様に、(100, 30, 24, 24)で、これを 2 x 2 のマス目で最大値を取りながら、(100, 30, 12, 12)に縮める。
(100, 30, 12, 12)が全結合層1層目の入力で、reshape を行って、(100, 4320)に変換し、(4320, 100)の重みとの内積を取って、(100,) にしている。その後は、全結合層のニューラルネットワークと同様なので、省略する。
100バッチ1回のログを示す。

(100, 1, 28, 28)
Conv col.shape = (57600, 25)
Conv col_W.shape = (25, 30)
Conv np.max(x) = 1.0
Conv np.min(x) = 0.0
(30, 1, 5, 5)
Conv np.max(self.W_int) = 0.50390625
Conv np.min(self.W_int) = -0.8046875
(30,)
Conv np.max(self.b_int) = -0.01171875
Conv np.min(self.b_int) = -0.37890625
Conv out.shape = (57600, 30)
Conv np.max(out) = 3.2695772065781057
Conv np.min(out) = -4.958961396710947
Conv np.max(out2) = 1.9921875
Conv np.min(out2) = -2.0
Conv out.reshape = (100, 30, 24, 24)
Pooling x.shape = (100, 30, 24, 24)
Pooling out.shape = (100, 30, 12, 12)
x shape =(100, 30, 12, 12)
np.max(self.W) = 0.7367957391676244
np.max(self.W) = 0.7367957391676244
np.max(self.b) = 0.13286493647098715
x reshape =(100, 4320)
np.max(x) = 1.9921875
np.min(x) = 0.0
(4320, 100)
np.max(self.W_int) = 0.73828125
np.min(self.W_int) = -0.78125
(100,)
np.max(self.b_int) = 0.1328125
np.min(self.b_int) = -0.0859375
(100, 100)
np.max(out) = 38.628021240234375
np.min(out) = -45.4913330078125
np.max(out2) = 31.96875
np.min(out2) = -32.0
x shape =(100, 100)
np.max(self.W) = 0.34009935565012406
np.max(self.W) = 0.34009935565012406
np.max(self.b) = 0.06031450057979193
x reshape =(100, 100)
np.max(x) = 31.96875
np.min(x) = 0.0
(100, 10)
np.max(self.W_int) = 0.33984375
np.min(self.W_int) = -0.5234375
(10,)
np.max(self.b_int) = 0.05859375
np.min(self.b_int) = -0.0703125
(100, 10)
np.max(out) = 33.219970703125
np.min(out) = -61.742919921875
np.max(out2) = 31.96875
np.min(out2) = -32.0

  1. 2017年06月14日 05:32 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog19.fc2.com/tb.php/3829-17564a86
この記事にトラックバックする(FC2ブログユーザー)