Mais conteúdo relacionado Semelhante a 「ゼロから作るDeep learning」の畳み込みニューラルネットワークのハードウェア化 (20) 「ゼロから作るDeep learning」の畳み込みニューラルネットワークのハードウェア化4. 4
ニューラルネットワーク( 2 層 NN )
1
2
3
36
37
38
1
2
12
13
x1
x2
x3
x36
C
( ぼけ量)
バイアス値
バイアス値
1
2
3
4
y1
y2
y3
y4
入力層
中間層
出力層
「ニューラルネットワークを使用した HD から 4K2K
への解像度変換ボケ復元回路の実装」から引用
5. 5
ニューラルネットワークの推論をハードウェア化
● 2 層ニューラルネットワーク (NN) はハードウェア化したこと
あり
– ニューラルネットワークを使用した HD から 4K2K への解
像度変換ボケ復元回路の実装( 2015 年 3 月発表)
– http://www.tech.tsukuba.ac.jp/2014/report2014/report03
.pdf
– HD から 4K2K へボケを復元しながら超解像度変換
– 6x6 入力 NN は 1 クロック (148.5MHz) で 4 ピクセル出力
– NN 推論の乗算をシフト+加算で実行。 DSP を使用しない
– 重みを入れると VHDL を出力する自作 Ruby スクリプトで
NN の VHDL を生成
8. 8
解度変換ボケ復元用 FPGA 回路
「ニューラルネットワークを使用
した HD から 4K2K への解像度変
換ボケ復元回路の実装」から引用
AXI
Interconnect
HDMI
Input
Module
(Neural Network
x4 output)
AXI4
Master
Write
160MHz
HDMI
INPUT
HDMI
Output
Module
HDMI
OUTPUT0
DDR3
SDRAM
Controller
(MIG)
AXI4 Master
Read/Write
200MHz
512bits
MicroBlaze
(CPU)
AXI
Interconnect
Serial
InterfaceGPIO
ボケ量の
設定
HDMI
Output
Module
HDMI
OUTPUT1
HDMI
Output
Module
HDMI
OUTPUT2
HDMI
Output
Module
AXI4 Master
Read
64bits
160MHz
HDMI
OUTPUT3
64bits
or
128bits
64bits
or
128bits
DDR3 SDRAM
(DDR3-1600)
64bits
800MHz
AXI4 Master
Read
64bits
160MHz
AXI4 Master
Read
64bits
160MHz
AXI4 Master
Read
64bits
160MHz
HD
148.5MHz
HD
148.5MHz
HD
148.5MHz
HD
148.5MHz
HD
148.5MHz
FPGA
(XC7K325T-2FFG900)MicroBlaze回路
TB-FMCH-HDMI2
RX Board
TB-FMCH-HDMI2
TX Board
TB-FMCH-HDMI2
TX Board
TB-7K-325T-IMG
FMC
Connector
FMC
Connector
FMC
Connector
9. 9
HDMI Input Module ブロック図
RestoreBlur
データバス幅
変換回路
データバス幅
変換回路
y1
y2
y3
y4
axi4_master_inf
axi4_master_inf
RGB pixel
data
RGB pixel
data
128 bits
data
128 bits
data
AXI4
Interconnect
Video
Signals
制御回路
制御回路
HDMI Input Module
「ニューラルネットワークを使用
した HD から 4K2K への解像度変
換ボケ復元回路の実装」から引用
10. 10
RGB のニューラルネットワーク
Line Buffer(3)
Line Buffer(2)
Line Buffer(1)
Line Buffer(0)
Line Buffer(4)
解像度変換ボケ復元用
ニューラルネットワーク
(Red)
Ry1
Ry2
Ry3
Ry4
Line Buffer(3)
Line Buffer(2)
Line Buffer(1)
Line Buffer(0)
Line Buffer(4)
解像度変換ボケ復元用
ニューラルネットワーク
(Green)
Gy1
Gy2
Gy3
Gy4
Line Buffer(3)
Line Buffer(2)
Line Buffer(1)
Line Buffer(0)
Line Buffer(4)
解像度変換ボケ復元用
ニューラルネットワーク
(Blue)
By1
By2
By3
By4
Red Video Signals
Green Video Signals
Blue Video Signals
Video
Signals
y1
y2
y3
y4
Rx1~
Rx6
Rx7~
Rx12
Rx13~
Rx18
Rx19~
Rx24
Rx25~
Rx30
Rx31~
Rx36
Gx1~
Gx6
Gx7~
Gx12
Gx13~
Gx18
Gx19~
Gx24
Gx25~
Gx30
Gx31~
Gx36
Bx1~
Bx6
Bx7~
Bx12
Bx13~
Bx18
Bx19~
Bx24
Bx25~
Bx30
Bx31~
Bx36
「ニューラルネットワークを使用
した HD から 4K2K への解像度変
換ボケ復元回路の実装」から引用
12. 12
●「ゼロから作る Deep Learning 」
● とっても良い本
● Python ベース、 C に比べてコードが少なくて済む
● Python 入門から書かれている
● Python コードが公開されていて、 MIT ライセンスで商用 OK
● Python がとってもわかりやすい
●
PDF 版を買えば普通にコピペができる
● CONV 、 Afne 、 RELU 、 SoftMax などの各層に forward() と
backwar() の関数がある
● 各層を接続していけば、 forward() (推論)と backward() (損失関
数の勾配)が連結される
13. 13
●「ゼロから作る Deep Learning 」の目次
● 第 1 章 Python 入門
● 第 2 章 パーセプトロン
● 第 3 章 ニューラルネットワーク
● 第 4 章 ニューラルネットワークの学習
● 第 5 章 誤差逆伝搬法
●
第 6 章 学習に関するテクニック
● 第 7 章 畳み込みニューラルネットワーク
● 第 8 章 ディープラーニング
14. 14
本の全章をやってみました
● 本の全章を Jupyter
Notebook を使って記録し
ながらやってみました
●
http://marsee101.blog19.f
c2.com/blog-entry-3793.ht
ml
● から
● http://marsee101.blog19.f
c2.com/blog-entry-3801.ht
ml
●
大体分かりました
今では忘れてきています。
まずいです!!!
17. 17
2 層ニューラルネットワーク
● 第 5 章誤差逆伝搬法の 2 層ニューラルネットワークの Python コード
を改造してハードウェア化することにした
● MNIST の手書き数字認識用のニューラルネットワーク( 784 入力
( 28x28 )、 0 ~ 9 までの数字の 10 出力)
● 第 5 章誤差逆伝搬法の 2 層ニューラルネットワークの構成
– 全結合層(隠れ層 50 出力)
– ReLU
– 全結合層( 10 出力)
– Softmax
18. 18
ハードウェア化への第 1 歩(量子化)
● 第 5 章誤差逆伝搬法の 2 層ニューラルネットワークの Python コードを改造し
てハードウェア化
● 学習はそのまま浮動小数点演算で学習
●
推論のみ 重みとバイアス、層の出力を量子化
● 量子化方法( forward_int() )
– 量子化ビット分を掛け算( float 型)
– 四捨五入して int 型に変換し、小数点以下切り捨て
– 量子化ビット長で飽和演算
– float 型に変換
– 掛け算した分を割り算して戻す( float )
19. 19
重みとバイアスの量子化コード
MAGNIFICATION = 2 ** (9-1)
RANGE = 2 ** 4
class Affne:
def __fnft__(self, W, b):
self.W =W
self.b = b
self.x = None
self.orfgfnal_x_shape = None
# 重み バイアスパラメータの微分・
self.dW = None
self.db = None
self.bw=MAGNIFICATION
def forward_fnt(self, x):
# テンソル対応
self.orfgfnal_x_shape = x.shape
x = x.reshape(x.shape[0], -1)
self.x = x
self.W = np.array(self.W*self.bw+0.5, dtype=fnt)
self.b = np.array(self.b*self.bw+0.5, dtype=fnt)
for f fn range(self.W.shape[0]):
for j fn range(self.W.shape[1]):
ff (self.W[f][j] > self.bw-1):
self.W[f][j] = self.bw-1
elff (self.W[f][j] < -self.bw):
self.W[f][j] = -self.bw;
for f fn range(self.b.shape[0]):
ff (self.b[f] > self.bw-1):
self.b[f] = self.bw-1
elff (self.b[f] < -self.bw):
self.b[f] = -self.bw
self.W = np.array(self.W, dtype=float)
self.b = np.array(self.b, dtype=float)
self.W = self.W/self.bw
self.b = self.b/self.bw
out = np.dot(self.x, self.W) + self.b
「ゼロから作る Deep
Learning 」の
Python コードを変更
掛け算
INT に変換
飽和演算
掛け算した分を
割り算で戻す
FLOAT に変換
20. 20
出力の量子化
out = np.array(out*self.bw+0.5, dtype=fnt)
for f fn range(out.shape[0]):
for j fn range(out.shape[1]):
ff (out[f][j] > self.bw*RANGE-1):
out[f][j] = self.bw*RANGE-1
elff (out[f][j] < -self.bw*RANGE):
out[f][j] = -self.bw*RANGE
out = np.array(out, dtype=float)
out = out/self.bw
return out
掛け算
INT に変換
飽和演算
FLOAT に変換
掛け算した分を割
り算で戻す
●
重みは正規化されているので、 -1 ~ 1 、 9 ビットに量子化
●
出力は符号 1 ビット、整数部 4 ビット、小数部 9 ビットの計 13 ビットに
量子化
22. 22
Vivado HLS で実装するための準備
●
トレーニングによって生成された重みを C のヘッダファイルに変換
●
Python コードで実装した
●
第一層目の全結合層の重みとバイアス
– af1_weight.h
– af1_bias.h
●
第 2 層目の全結合層の重みとバイアス
– af2_weight.h
– af2_bias.h
●
ヘッダファイル内には浮動小数点数の配列と固定小数点数の配列
– const float af1_fweight[784][50];
– const ap_fxed<9, 1, AP_TRN_ZERO, AP_SAT> af1_weight[784][50];
27. 27
Vivado HLS で実装するための準備 2
● Vivado HLS のテストベンチで MNIST の手書き数字を使用する
– Python コードで MNIST データセットの一部データを抜き出し
て、 C ヘッダファイルの mnist_data.h を生成
28. 28
ニューラルネットワークの C ソースコード
●
af1_dot1: for(int col=0; col<50; col++){
●
dot1[col] = 0;
●
af1_dot2: for(int row=0; row<784; row++){
●
dot1[col] += buf[row]*af1_weight[row][col];
●
}
●
dot1[col] += af1_bias[col];
●
●
if(dot1[col] < 0) // ReLU
●
dot1[col] = 0;
●
}
●
●
af2_dot1: for(int col=0; col<10; col++){
●
dot2[col] = 0;
●
af2_dot2: for(int row=0; row<50; row++){
●
dot2[col] += dot1[row]*af2_weight[row][col];
●
}
●
dot2[col] += af2_bias[col];
●
out[col] = dot2[col];
●
}
●
最後の softmax 関数は無し
● 実装が難しいし、 10 出力
の max 値を検出するれば手
書き数字の判定はできる
● ap_fxed は Vivado HLS の
任意精度固定小数点データ
型
ap_ffxed<13, 5, AP_TRN_ZERO, AP_SAT> dot1[50];
ap_ffxed<13, 5, AP_TRN_ZERO, AP_SAT> dot2[10];
29. 29
Vivado HLS による NN の実装
● テストベンチ( mnist_data.h の 100 個の手書き数字を判定)
– ソフトウェアの精度 99% (浮動小数点演算)
– ハードウェアの精度 98% (固定小数点演算)
● ただし、人間での判定は容易であると思われる数字をミス
ソフトウェアとハードウェアがミス
ハードウェアだけがミス
30. 30
Vivado HLS による C コードの合成結果 (2017.1)
● 使用する Zynq は PYNQ ボードの xc7x020clg400-1
●
Latency は 2.79ms ( 100MHz クロック)
● リソース使用量は BRAM が 38 個、 DSP48E が 1 個
37. 37
プーリング( MAX 値)
● Max プーリング、 2x2 、ストライド 2
● 2x2 領域の最大値を出力に入れる
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
Max プーリング
画像
出力
6
42. 42
ハードウェア化への第 1 歩(量子化)
● 第 7 章畳み込みニューラルネットワークの畳み込みニューラルネットワークの
Python コードを改造してハードウェア化
● 学習はそのまま浮動小数点演算で学習
●
推論のみ 重みとバイアス、層の出力を量子化
● 量子化方法( forward_int() )
– 量子化ビット分を掛け算( float 型)
– 四捨五入して int 型に変換し、小数点以下切り捨て
– 量子化ビット長で飽和演算
– float 型に変換
– 掛け算した分を割り算で戻す( float )
45. 45
Vivado HLS で実装するための準備
●
トレーニングによって生成された重みを C のヘッダファイルに変換
●
Python コードで実装した
●
畳み込み層の重みとバイアス
– conv1_weight.h
– conv1_bias.h
●
最初の全結合層の重みとバイアス
– af1_weight.h
– af1_bias.h
●
二番目の全結合層の重みとバイアス
– af2_weight.h
– af2_bias.h
●
浮動小数点数の配列と固定小数点数の配列
– const float conv1_fweight[10][1][5][5];
– const ap_fxed<9, 1, AP_TRN_ZERO, AP_SAT> conv1_weight[10][1][5][5];
46. 46
畳み込みニューラルネットワークの C ソースコード
●
CONV1: for(int i=0; i<10; i++){ // カーネルの個
数
●
CONV2: for(int j=0; j<24; j++){
●
CONV3: for(int k=0; k<24; k++){
●
conv_out[i][j][k] = 0;
●
CONV4: for(int m=0; m<5; m++){
●
CONV5: for(int n=0; n<5; n++){
●
conv_out[i][j][k] += buf[j+m][k+n] *
conv1_weight[i][0][m][n];
●
}
●
}
●
conv_out[i][j][k] += conv1_bias[i];
●
●
if(conv_out[i][j][k]<0) // ReLU
●
conv_out[i][j][k] = 0;
●
}
●
}
●
}
●
POOL1: for(int i=0; i<10; i++){
●
POOL2: for(int j=0; j<24; j += 2){
●
POOL3: for(int k=0; k<24; k += 2){
●
POOL4: for(int m=0; m<2; m++){
●
POOL5: for(int n=0; n<2; n++){
●
if(m==0 && n==0){
●
pool_out[i][j/2][k/2] = conv_out[i][j]
[k];
●
} else if(pool_out[i][j/2][k/2] <
conv_out[i][j+m][k+n]){
●
pool_out[i][j/2][k/2] = conv_out[i]
[j+m][k+n];
●
}
●
}
●
}
●
}
●
}
●
}
47. 47
CNN の Vivado HLS による C シミュレーション
● 100 個の手書き数字のデータ (mnist_data.h) を使用して、何個間違う
かをカウント
● ソフトウェア ー 1 個、ハードウェア ー 3 個
● ソフトウェアに比べてハードウェアが間違いすぎか?
● 小数部分の桁が少ない全結合層のビット幅を 12 から 13 にしてみた
● ソフトウェア ー 1 個、ハードウェア ー 1 個
48. 48
CNN を合成( Vivado HLS )
●
使用する Zynq は PYNQ ボードの xc7x020clg400-1
●
Latency は 100 MHz クロックで、 17.2 ms
● リソース使用量を見ると BRAM_18K の使用が多い(重み、バイアス)
● チューニングをすると 6.91ms まで行った。 BRAM_18K が 59%
58. 58
手書き数字の 1 を判定
● 1 をピンクの四角枠に入れて r キーを押すと CNN の推論を行う
● result[1] が 72 で最大なので、結果 (max_id) は 1
59. 59
手書き数字の 5 を判定
● 5 をピンクの四角枠に入れて r キーを押すと CNN の推論を行う
● result[5] が b2 で最大なので、結果 (max_id) は 5
60. 60
Linux 上で手書き数字認識 CNN 制御用ア
プリケーションソフトを作成 1
●
PYNQ ボードの Debian 上で手書き数字 CNN
制御用アプリケーションソフトを作成した
●
FPGA に実装した固定小数点のハードウェア
と ARM Cortex-A9 650MHz の性能を比較し
た
●
gcc のオプティマイズオプション無しのとき
– ハードウェア処理時間ー 12.9ms
– ソフトウェア処理時間ー 60.8ms
– SW 処理時間 /HW 処理時間≒ 4.71 倍
61. 61
Linux 上で手書き数字認識 CNN 制御用ア
プリケーションソフトを作成 2
● Ubuntu 16.04 上で手書き数字 CNN 制御用ア
プリケーションソフトを作成した
● FPGA に実装した固定小数点のハードウェア
と ARM Cortex-A9 650MHz のの性能を比較
した
● gcc のオプティマイズオプション -O2 のとき
– ハードウェア処理時間ー 12.9ms
– ソフトウェア処理時間ー 6.13ms
– SW 処理時間 /HW 処理時間≒ 0.475 倍
62. 62
まとめ 1
●
「ゼロから作る Deep Learning 」を読んで勉強した
●
MNIST の 2 層ニューラルネットワークの量子化
●
量子化の結果を元に重みとバイアスを C のヘッダに変換
●
MNIST のデータの一部を C のヘッダに変換(テストベンチ用)
●
Vivado HLS の C コードで 2 層ニューラルネットワークを記述
●
Vivado HLS で合成
●
MNIST の畳み込みニューラルネットワークを量子化
●
量子化の結果を元に重みとバイアスを C のヘッダに変換
●
Vivado HLS の C コードで畳み込みニューラルネットワークを記述
●
Vivado HLS で合成
63. 63
まとめ 2
● 四角枠生成回路などの必要な IP を生成
● Vivado で回路を作って合成
● SDK でアプリケーションソフトを作ってテストー成功
● Linux 上でアプリケーションソフトを作ってテストー成功
● DNN に関する FPGA の部屋のすべての記事は下記の URL を参照
– Deep Neural Network
– http://marsee101.web.fc2.com/dnn.html
–