FC2カウンター FPGAの部屋 TensorFlow, Keras

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

FPGAの部屋

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

TensorFlow + Kerasを使ってみた22(Linux版とWindows版のVivado HLSでの違い)

TensorFlow + Kerasを使ってみた21(特徴マップ数が3個、5個、10個のMNIST用CNNをC/RTLコシムとIP化)”の続き。

前回は、特徴マップ数が 3 個、 5 個、10 個のMNIST用CNNをC/RTL 強調シミュレーションと、Export RTL を行って、結果を比較した。今回は、前回はLinux 版のVivado HLS 2017.4 の結果だったが、Windows版のVivado HLS 2017.4 の結果も比較した。また、Vivado HLS 2018.1 で特徴マップが 3 個の場合をやってみたので比較した。

Windows版のVivado HLS 2017.4 の特徴マップ 3 個、5 個、10 個のC コードの合成とExport RTLを行った。結果は下表に示す。

特徴マップが 3 個の場合のWindows版Vivado HLS 2018.1 の C コードの合成の結果を示す。
tensorflow_keras_111_180618.png

特徴マップが 3 個の場合のWindows版Vivado HLS 2018.1 の Export RTLの結果を示す。
tensorflow_keras_112_180618.png

Vivado HLSの特徴マップ 3 個、5 個、10 個のC コードの合成とExport RTLの結果を下表に示す。
tensorflow_keras_113_180618.png

Vivado HLS 2017.4 のLinux 版とWindows版のC コードの合成結果は同じだったが、Export RTLの結果は異なっている。これは、Vivado 2017.4 が Linux 版とWindows版で異なっているのかもしれない?
Vivado HLS 2018.1 のC コードの合成結果は、2017.4 の結果よりも FF と LUT のリソース使用量が少なった。Export RTLの結果は、FF は Vivado HLS 2018.1 の方がリソース使用量が少なかったが、LUT は Vivado HLS 2017.4 の方がリソース使用量が少なかった。
  1. 2018年06月18日 05:30 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた21(特徴マップ数が3個、5個、10個のMNIST用CNNをC/RTLコシムとIP化)

TensorFlow + Kerasを使ってみた20(特徴マップ3個のMNIST用CNNをVivado HLSで実装)”の続き。

前回は、MNIST 用のCNN で特徴マップ数が 3 個の場合をVivado HLS で実装した。今回は、特徴マップ数が 3 個、 5 個、10 個のMNIST用CNNをC/RTL 強調シミュレーションと、Export RTL を行う。

まずは、特徴マップ数が 3 個の時のMNIST 用CNN をC/RTL 強調シミュレーションと、Export RTL を行ってみよう。
最初に、テストベンチの mnist_conv_nn_hlss_tb.cpp の 「#define NUM_ITERATIONS 1000」をコメントアウトして、「#define NUM_ITERATIONS 2」のコメントアウトを削除した。これは、C/RTL 強調シミュレーションを行うにあたって、1000 個推論を実行するのは時間がかかりすぎると思ったからだ。波形を見るだけなので、少ない推論数でも十分なわけだ。
tensorflow_keras_104_180616.png

これで、C/RTL 強調シミュレーションを行ったところ、エラーだった。
tensorflow_keras_105_180616.png

次に、Export RTL を行った。なお、Vivado synthesis, place and route にチェックを入れてある。結果を示す。
tensorflow_keras_103_180616.png

LUT は 2794 個、FF は 3195 個、DSP は 62 個、BRAM 34 個、SRL 73 個使用している。
合成時のリソース使用量はBRAM_18K が 34 個、DSP48E が 62 個、FF が 5284 個、LUT が 9137 個だった。DSP と BRAM の個数は同じで、FF は約 60.5 % 、LUT は約 31.4 % になった(LUT はLUT とSRL をLUT として計算した)。


次に、特徴マップ数が 5 個の時のMNIST 用CNN をC/RTL 強調シミュレーションと、Export RTL を行ってみよう。
同様に、テストベンチの mnist_conv_nn_hlss_tb.cpp の 「#define NUM_ITERATIONS 1000」をコメントアウトして、「#define NUM_ITERATIONS 2」のコメントアウトを削除した。
C/RTL 強調シミュレーションを実行したところ、同様にエラーだった。
tensorflow_keras_106_180616.png

Export RTL を行った。なお、Vivado synthesis, place and route にチェックを入れてある。結果を示す。
tensorflow_keras_107_180617.png

LUT は 3605 個、FF は 3811 個、DSP は 93 個、BRAM 66 個、SRL 63 個使用している。
合成時のリソース使用量はBRAM_18K が 66 個、DSP48E が 93 個、FF が 6215 個、LUT が 11144 個だった。DSP と BRAM の個数は同じで、FF は約 61.3 % 、LUT は約 32.9 % になった(LUT はLUT とSRL をLUT として計算した)。


最後に、特徴マップ数が 5 個の時のMNIST 用CNN をC/RTL 強調シミュレーションと、Export RTL を行ってみよう。
同様に、テストベンチの mnist_conv_nn_hlss_tb.cpp の 「#define NUM_ITERATIONS 1000」をコメントアウトして、「#define NUM_ITERATIONS 2」のコメントアウトを削除した。
C/RTL 強調シミュレーションを実行したところ、同様にエラーだった。
tensorflow_keras_109_180617.png

Export RTL を行った。なお、Vivado synthesis, place and route にチェックを入れてある。結果を示す。
tensorflow_keras_108_180617.png

LUT は 5708 個、FF は 5681 個、DSP は 175 個、BRAM 130 個、SRL 73 個使用している。
合成時のリソース使用量はBRAM_18K が 130 個、DSP48E が 175 個、FF が 9005 個、LUT が 16391 個だった。DSP と BRAM の個数は同じで、FF は約 63.1 % 、LUT は約 35.3 % になった(LUT はLUT とSRL をLUT として計算した)。

Export RTL 時の特徴マップ数によるリソース使用量の違いを表に追加した。
tensorflow_keras_110_180617.png
  1. 2018年06月17日 05:36 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた20(特徴マップ3個のMNIST用CNNをVivado HLSで実装)

TensorFlow + Kerasを使ってみた19(特徴マップ3個と2個のMNIST用CNNをテスト)”の続き。

前回は、MNIST 用のCNN で特徴マップが 3 個と 2 個の時について学習を行ったところ、3 個の場合の精度が 98.54 % で使い物になるようだった。特徴マップが 2 個の場合は、98.02 % で少し低くなっていた。今回は、MNIST 用のCNN で特徴マップが 3 個の場合をVivado HLS で実装してみよう。

まずは、畳み込み層と全結合層の重みとバイアスをKeras からC のヘッダファイルとして取得した。
そして、MNIST のデータの1000 個分をC のヘッダファイルとして出力した mnist_data.h を使用する。
これらのヘッダファイルの取得方法は、”TensorFlow + Kerasを使ってみた18(特徴マップ5個のMNIST用CNNをVivado HLSで実装)”をご覧あれ。。。

Vivado HLS 2017.4 の mnist_conv_nn5_hlss_org を作成した。
各層の演算精度が書いてある mnist_conv_nn5_hlss.h を示す。ここの値を変更すると演算精度を変更することができる。
tensorflow_keras_99_180615.png

幾度と無く mnist_conv_nn5_hlss.h のパラメータを変更して、C シミュレーションを行った結果、「特徴マップが 5 個の時」のパラメータの中で、 CONV_BIT_LENGTH を 10 から 11 ビットに変更したところ、ハードウェア化する固定小数点演算の精度が改善した。これで行くことにする。

C シミュレーションを行った。結果を示す。
tensorflow_keras_98_180615.png

1000 個のMNIST のデータのうちでハードウェアの固定小数点演算ではエラーが 15 個、ソフトウェアの浮動小数点演算ではエラーが 16 個だった。
よって、ハードウェアの固定小数点演算での精度は、98.5 % となった。
ソフトウェアの浮動小数点演算での精度は、98.4 % となった。

C コードの合成を行った。結果を示す。
tensorflow_keras_100_180615.png
tensorflow_keras_101_180615.png

Latency は min が 101701 クロックで、max は 102133 クロックだった。100 MHz 動作だと約 1.02 ms だった。fpsにすると約 979 fps となった。
リソース使用量はBRAM_18K が 34 個、DSP48E が 62 個、FF が 5284 個、LUT が 9137 個だった。

特徴マップ数が 10 個の場合と 5 個の場合と 3 個の場合のリソース使用量を表にした。
tensorflow_keras_102_180615.png

この表を見ると、特に BRAM_18K の減りが激しいようだ。BRAM_18K の特徴マップ数が 10 個の時を基準とした時の 3 個の時のパーセンテージは 26.15 % だったが、DSP48E は 35.43 % で、FF は 58.68 % 、 LUT は 55.74 % だった。

なお、あくまで C コードの合成でのリソース使用量の見積もりであることに注意してほしい。
特に、パラメータ数が多いテンプレートを使っていると C コードの合成時のレポートと実際にExport RTL した時のVivado での概算とのリソース使用量の違いが多い気がする。
  1. 2018年06月15日 05:33 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた19(特徴マップ3個と2個のMNIST用CNNをテスト)

TensorFlow + Kerasを使ってみた18(特徴マップ5個のMNIST用CNNをVivado HLSで実装)”の続き。

特徴マップ5個のMNIST 用 CNN がうまく行ったようなので、特徴マップ 3 個と 2 個のMNIST 用CNN をKeras で学習させてみることにした。

まずは、Keras でSequentialモデルを作って学習する。以前使用していたCNN から畳み込み層の特徴マップの数を 5 個から 3 個に変更した。他のコードは変えていない。
tensorflow_keras_90_180614.png
tensorflow_keras_91_180614.png
tensorflow_keras_92_180614.png
tensorflow_keras_93_180614.png

Epoch 10 まで学習して val_acc: 0.9854 だった。やはり、特徴マップが多いものよりも精度は少し落ちている。ちなみに特徴マップが 10 個の時は、Epoch 12 で val_acc: 0.9898 、特徴マップが 5 個の時は、Epoch 10 まで学習して val_acc: 0.9864 だった。
学習も特徴マップが 10 個の時や 5 個の時よりも、3 個の時の方がより過学習になっていないようだ。


次に、Keras でSequentialモデルを作って学習する。以前使用していたCNN から畳み込み層の特徴マップの数を 5 個から 2 個に変更した。他のコードは変えていない。
tensorflow_keras_94_180614.png
tensorflow_keras_95_180614.png
tensorflow_keras_96_180614.png
tensorflow_keras_97_180614.png

Epoch 10 の時の精度が 0.9802 であまり上がらない。特徴マップ 2 個を使うという選択肢は厳しいようだ。
  1. 2018年06月14日 05:19 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた18(特徴マップ5個のMNIST用CNNをVivado HLSで実装)

TensorFlow + Kerasを使ってみた17(特徴マップを10個から5個へ)”の続き。

前回は、今までは畳み込み層で 10 個の特徴マップを使用していたが、5 個ではどうだろうということでやってみたところ、98.64 % の精度が確保できた。今回は、特徴マップ5 個のMNIST 用 CNN を使用して、Vivado HLS で実装してみた。

まずは、畳み込み層と全結合層の重みとバイアスをKeras からC のヘッダファイルとして取得した。
TensorFlow + Kerasを使ってみた9(畳み込み層の重みをC のヘッダに変換)
TensorFlow + Kerasを使ってみた10(バイアスをC のヘッダに変換)
TensorFlow + Kerasを使ってみた11(全結合層の重みをC のヘッダに変換)"

そして、MNIST のデータの1000 個分をC のヘッダファイルとして出力した mnist_data.h を使用する。
TensorFlow + Kerasを使ってみた12(MNISTのデータの一部をC のヘッダに変換)

そうして、作成したVivado HLS 2017.4 の mnist_conv_nn5_hlss_org を作成した。
Keras で重みやバイアス、各層の出力の最大値、最小値をみたところ、畳み込み層の整数部のビット数を 1 ビット増やして、4 ビットとすることにした。総ビット数は 10 ビットで変更無しなので、小数部が 1 ビット減って 6 ビットとした。
各層の演算精度が書いてある mnist_conv_nn5_hlss.h を示す。ここの値を変更すると演算精度を変更することができる。
tensorflow_keras_89_180613.png

C シミュレーションを行った。結果を示す。
tensorflow_keras_86_180612.png

1000 個のMNIST のデータのうちでハードウェアの固定小数点演算ではエラーが 7 個、ソフトウェアの浮動小数点演算ではエラーが 9 個だった。
よって、ハードウェアの固定小数点演算での精度は、99.3 % となった。
ソフトウェアの浮動小数点演算での精度は、99.1 % となった。
だいぶ精度が良いが、10000 個のテストデータの内の最初の 1000 個のデータで評価しているので、他のところのデータの精度が悪かったのか?

C コードの合成を行った。結果を示す。
tensorflow_keras_87_180613.png
tensorflow_keras_88_180613.png

Latency は min が 130646 クロックで、max は 131366 クロックだった。100 MHz 動作だと約 1.31 ms となる。fpsにすると約 763 fps となる。
前回の特徴マップが 10 個の飽和演算なしの時の Latency の max は 204376 クロックだったので、 204376 / 131366 x 100 ≒ 155.58 % の性能ということになる。
リソース使用量はBRAM_18K が 66 個、DSP48E が 93 個、FF が 6215 個、LUT が 11144 個だった。
前回の特徴マップが 10 個の飽和演算なしの時のリソース使用量は、BRAM_18K が 130 個、DSP48E が 175 個、FF が 9005 個、LUT が 16391 個だったので、BRAM_18K については、半分以下のリソース使用量となった。
  1. 2018年06月13日 04:46 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた17(特徴マップを10個から5個へ)

TensorFlow + Kerasを使ってみた16(C コードの合成、ビット幅の削減)”の続き。

前回は、各層の演算のビット幅をチェックしたが、ビット幅を小さくしても、思ったようにリソース使用量が少なくならなかった。今回は、IP のレイテンシとリソース使用量に効くのはなんと言っても、畳み込み層の特徴マップの数じゃないか?と思う。今までは畳み込み層で 10 個の特徴マップを使用していたが、5 個ではどうだろうということでやってみた。

まずは、Keras でSequentialモデルを作って学習する。以前使用していたCNN から畳み込み層の特徴マップの数を 10 個から 5 個に変更した。他のコードは変えていない。
tensorflow_keras_82_180612.png
tensorflow_keras_83_180612.png
tensorflow_keras_84_180612.png
tensorflow_keras_85_180612.png

Epoch 10 まで学習したが val_acc: 0.9864 なので、良さそうだ。ちなみに特徴マップが 10 個の時は、Epoch 12 で val_acc: 0.9898 だった。
演算のビット幅を落として精度が落ちるならば、特徴マップを減らして、演算のビット幅をあまり落とさないほう精度的には同じで、よりリソース使用量が小さくなるのではないか?と思っている。つまり、精度を考えた特徴マップの数と演算のビット幅の最適化を図っていきたい。
学習も特徴マップが 10 個の時よりも、5 個の時の方がより過学習になっていないようだ。
  1. 2018年06月12日 05:29 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた16(C コードの合成、ビット幅の削減)

TensorFlow + Kerasを使ってみた15(飽和演算と通常の演算)”の続き。

前回は、畳み込み層に”Vivado HLS の任意精度固定小数点データ型の飽和演算”でテストした演算後の値を飽和演算し、また全結合層では内積の演算に飽和演算を用いる実装と、今まで通りにすべての演算に飽和演算を用いない場合について検証した。今回は、その飽和演算ありと飽和演算なしの2つの実装を合成して、リソース使用量を比較して見た後で、演算のビット幅を小さくして、C シミュレーション結果とC コードの合成結果を見ていこう。

最初に飽和演算なしの実装(mnist_conv_nn10_hlss_k_org)のC コードの合成結果を見る。
tensorflow_keras_73_180610.png
tensorflow_keras_74_180610.png

Latency は min が 202936 クロックで、 max が 204376 クロックだった。これは、100 MHz クロックを使用すると max の場合では、約 2.04 ms となった。
リソース使用量は、BRAM_18K が 130 個、DSP48E が 175 個、FF が 9005 個、LUT が 16391 個だった。

次に、飽和演算あり(mnist_conv_nn10_hlss_k)の実装のC コードの合成結果を見る。
tensorflow_keras_75_180610.png
tensorflow_keras_76_180610.png

こちらのLatency の min は 217336 クロックで max は 218776 クロックだった。100 MHz クロックだと max で 2.19 ms となった。飽和演算なしと比較すると、max 値で 217336 / 204376 ≒ 1.063 倍だった。
リソース使用量は、BRAM_18K が 130 個、DSP48E が 175 個は飽和演算なしと変化がないが、FF の 9168 個と LUT の 19109 個は飽和演算なしよりもリソース使用量が多かった。

次に演算のビット幅を縮小してみよう。
次に示す演算のビット幅でCNN の演算を行った。

#define INPUT_CHANNELS 1
#define INPUT_BIT_LENGTH 9
#define INPUT_INTEGER_LEN 1

#define CONV_BIT_LENGTH 8
#define CONV_INTEGER_LEN 3
#define CONV_CHANNELS 10
#define CONV_MID_BIT_LENGTH 13
#define CONV_MID_BIT_INTGER_LEN 3

#define AFFINE_BIT_LENGTH 11
#define AFFINE_INTEGER_LEN 5

#define OUTPUT_BIT_LENGTH 12
#define OUTPUT_INTEGER_LEN 7


演算のビット幅を 2 ビット減らしてみた。ただし整数部のビット幅はいじっていないので、飽和演算あり、飽和演算なしで同様のエラーになるはずである。
飽和演算ありと飽和演算なしの実装の C シミュレーション結果を示す。
tensorflow_keras_77_180610.png

飽和演算ありと飽和演算なしどちらも、HW_ERROR_COUNT = 23, SW_ERROR_COUNT = 15 だった。
エラー内容を示す。なおこのエラー内容も、飽和演算ありと飽和演算なしで同一だった。

id = 18, max_id_ref = 3, max_id_sw = 8
id = 115, max_id_ref = 4, max_id_sw = 9
id = 151, max_id_ref = 9, max_id_hw = 8
id = 184, max_id_ref = 8, max_id_hw = 3
id = 217, max_id_ref = 6, max_id_hw = 5
id = 247, max_id_ref = 4, max_id_sw = 2
id = 321, max_id_ref = 2, max_id_sw = 7
id = 324, max_id_ref = 0, max_id_hw = 6
id = 340, max_id_ref = 5, max_id_hw = 3
id = 340, max_id_ref = 5, max_id_sw = 3
id = 406, max_id_ref = 5, max_id_hw = 9
id = 445, max_id_ref = 6, max_id_sw = 0
id = 448, max_id_ref = 9, max_id_hw = 8
id = 449, max_id_ref = 3, max_id_sw = 5
id = 508, max_id_ref = 6, max_id_hw = 5
id = 547, max_id_ref = 2, max_id_hw = 3
id = 551, max_id_ref = 7, max_id_hw = 3
id = 582, max_id_ref = 8, max_id_hw = 2
id = 582, max_id_ref = 8, max_id_sw = 2
id = 619, max_id_ref = 1, max_id_hw = 8
id = 619, max_id_ref = 1, max_id_sw = 8
id = 625, max_id_ref = 6, max_id_hw = 4
id = 655, max_id_ref = 8, max_id_hw = 3
id = 658, max_id_ref = 7, max_id_hw = 4
id = 659, max_id_ref = 2, max_id_hw = 1
id = 659, max_id_ref = 2, max_id_sw = 1
id = 674, max_id_ref = 5, max_id_hw = 3
id = 684, max_id_ref = 7, max_id_hw = 3
id = 684, max_id_ref = 7, max_id_sw = 3
id = 685, max_id_ref = 8, max_id_hw = 2
id = 723, max_id_ref = 0, max_id_hw = 4
id = 738, max_id_ref = 2, max_id_hw = 8
id = 813, max_id_ref = 9, max_id_sw = 8
id = 846, max_id_ref = 7, max_id_hw = 9
id = 870, max_id_ref = 6, max_id_hw = 5
id = 883, max_id_ref = 3, max_id_sw = 5
id = 947, max_id_ref = 8, max_id_sw = 9
id = 965, max_id_ref = 6, max_id_sw = 0
HW_ERROR_COUNT = 23, SW_ERROR_COUNT = 15


次に、演算ビット幅を縮小したままC コードの合成を行った。
まずは、飽和演算なしからC コードの合成結果を示す。
tensorflow_keras_78_180611.png
tensorflow_keras_79_180611.png

Latency は min が 202936 クロックで、 max が 204376 クロックだった。これは、100 MHz クロックを使用すると max の場合では、約 2.04 ms となる。これはビット幅を変更する前と同じだった。
リソース使用量は、BRAM_18K が 130 個、DSP48E が 175 個、FF が 9005 個、LUT が 16391 個だった。これはビット幅を変更する前からすると、FF が約 88.2 % 、LUT が約 91.4 % に減少している。

次に飽和演算ありの C コードの合成結果を示す。
tensorflow_keras_80_180611.png
tensorflow_keras_81_180611.png

Latency の min は 217336 クロックで max は 218776 クロックだった。100 MHz クロックだと max で 2.19 ms となった。やはり、こちらもビット幅を変更する前と同一だった。
リソース使用量は、BRAM_18K が 130 個、DSP48E が 175 個は飽和演算なしと変化がないが、FF の 8107 個と LUT の 17641 個だった。これはビット幅を変更する前からすると、FF が約 88.4 % 、LUT が約 92.3 % に減少している。

ビット幅を縮小しても思ったよりリソース使用量の縮小がなかったので、以前の下に示す演算ビット幅で行こうと思う。

#define INPUT_CHANNELS 1
#define INPUT_BIT_LENGTH 9
#define INPUT_INTEGER_LEN 1

#define CONV_BIT_LENGTH 10
#define CONV_INTEGER_LEN 3
#define CONV_CHANNELS 10
#define CONV_MID_BIT_LENGTH 16
#define CONV_MID_BIT_INTGER_LEN 3

#define AFFINE_BIT_LENGTH 13
#define AFFINE_INTEGER_LEN 5

#define OUTPUT_BIT_LENGTH 12
#define OUTPUT_INTEGER_LEN 7


また、飽和演算ありと飽和演算なしだが、現在の整数ビット幅を維持できれば、飽和演算ありと飽和演算なしとエラー数も変化がないので、リソース使用量の少ない飽和演算なしで行くことにする。
  1. 2018年06月11日 05:04 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0
»