AIエッジコンテスト(実装コンテスト)のチュートリアル【7: 高位合成(失敗編)】


タイトルからしてネタバレですが、とりあえず失敗してみましょう。ソフトウェア技術者がなぜハードウェア設計につまずくかがわかると思います。
(この連載、いつになったら終わるんだろう。。。)

準備

1 環境

  • OS: Ubuntu 16.04 LTS (or 18.04 LTS), win10版はできますがサポート外です
  • Vivado 2019.1 を /tools/Xilinx/Vivado/2019.1 にインストール (他のバージョン、特にVivado 2019.2はサポート外です!!)

2 Board Definition File (BDF) を設定
搭載されているFPGAに合わせて予め色々設定がされているので、初心者の方は設定しておくことをお勧めします。Ultra96のメーカ(AvNet)からBoard Definition Fileをクローンして所定のディレクトリに置きます。

$ git clone git://github.com/Avnet/bdf
$ sudo cp -R bdf/* /tools/Xilinx/Vivado/2019.1/data/boards/board_files/

3 今回のソースコードを準備
コンテストチュートリアルのリポジトリに置いています。Vivado HLS(高位合成ツール)でプロジェクト作成後にコピーするので、予めcloneしておいてください。

テストベンチ、パラメータは前回と同じものを使います。
+ testbench_input.txt
+ testbench_output.txt
+ weight_l0.txt
+ bias_l0.txt

以降、管理者権限で実行します。

Vivado HLSの起動と初期設定

Vivado HLSのパスを通してから起動します。.bashrcに書いておけばパスは最初から通ります。

# source /tools/Xilinx/Vivado/2019.1/settings64.sh
# Vivado_hls &

Vivado HLSが起動するのでNew Projectを選択→New Project ウインドウで

  • Project name: HW_conv_l0_1 (好みの名前でよいですが。。)
  • Location: (home directory)/xilinx/HLS_proj/

としてNext, 次のAdd/Remove Files C-based source files,C-based testbench filesは共にNextをクリック。
Solution Configurationで Part Selection ->「...」をクリックし

BoardsUltra96v2 Evaluation Platformを選択しOK -> Finish.

Ultra96V2 Evaluation Platformが表示されない場合はBDFが適切な場所に置かれてないと思います。設定を確認してください。

プロジェクト設定が終わるとGUIが起動してコードが書ける状態になります。次に、ソース一式をプロジェクトに読み込みます。HLS設計の鉄則は予め合成対象コードをソフトウェアで確実に動作するように検証しておくことです。つまり、Vivado HLSで一からソフトコードを書くことはないはずです!

まずクローンしたサンプルコードをプロジェクトのディレクトリ直下に作ったsrcに置きましょう。

# cd (home directory)/xilinx/HLS_proj/HW_conv_l0_1
# mkdir src
# cp (コンテストのリポジトリをクローンした場所)/Inference_HLS_1/* ./src
  • HW_kernel.cpp
  • HW_main.cpp

に加えて、テストベンチ・パラメータ

  • testbench_input.txt
  • testbench_output.txt
  • weight_l0.txt
  • bias_l0.txt

一式をコピーします。

メイン画面で Source -> 右クリック -> Add Files... を選択しソースファイルを置いたsrcからtestbench_input.txt, testbench_output.txt, weight_l0.txt, bias_l0.txt, HW_kernel.cpp, HW_main.cpp を読み込みます。

こうなります↓

Project -> Project Settings ... をクリックして Simulation -> Add Files ... をクリックし、HW_main.cppを読み込み、 Options -> Optimizing Compile を選択
Synthesis -> Top Function -> Browse をクリックして kernel (HW_kernel.cpp) を選択しOKをクリック
SimulationとSynthesisを設定したらOKをクリックしてProject Settingsを閉じる.

Vivado HLSツールのお約束として、検証(C-Simulation)のメイン関数(今回はHW_main.cpp)を別に読み込む必要があったので、設定しています。

シミュレーションの実行

ソフトウェア検証と同じことをしていますが、一応、Vivado HLSでもやってみましょう。Run C SimulationをクリックしてOKをクリックください。シミュレーションが実行されてUbuntuで実行した場合と同じ結果になるはずです。


↑こんな感じにログが出力される。

今回はお試しですが、回路設計時にはこれを繰り返してソフトの検証を行ってください。

ハードウェア合成

まずはHW_main.cppHW_kernel.cppのプリプロセッサの定義をアンコメントします

HW_main.cppとHW_kernel.cppの該当箇所
//#define HLS 

HW_main.cppとHW_kernel.cppの該当箇所
 #define HLS

これで高位合成記述を対象に合成が行われます。
いよいよ高位合成です!メニューのC Synthesisをクリックして高位合成を行いましょう。

しばらくするとVivado HLS Console にFinished C Cynthesisが表示されて合成が終わります。レポートを見て合成結果を見てみましょう。どれどれ、Latencyってのがデータを送って処理が終わるまでの時間だから‥

?????


ちょっとびっくりしましたが、Detailをクリックすると詳細が表示されます。どうやらLoop1〜Loop3が?(わかりませーん)だから性能が見積もれない、ということです。
これはデータの読み出しにwhile()文を使っている→ループ回数が不明だからですね。データ出力転送は固定回数のfor()文で記述しましたから665859サイクル(クロック)なので、もし100MHz(10nsクロック周期)の場合は6658590ns、つまり6.8ms間隔で処理が終わるということです。

肝心の畳み込みは、、
え、2227967424サイクル??てことは100MHz(10ns)で22,279,674,240nsですか、、つまり約22秒??遅い。。。


次にハードウェアの消費量を見ましょう。えーと、Utilization Estimatesを見ると、利用可能なFPGAのリソース量(Utilization(%))に対する今回の高位合成による見積もりが見れます。BRAM18K(FPGAの内部メモリブロック数)が496%!!!!ひーっ、実装できないじゃないですか。。
原因はDetail -> Memoryをクリックすると分かります。BRAM18K数はメモリ量を18Kb(単位はビット)で割れば算出できるので

(入力バッファsrc_img)= 416 x 416 x 3 x 32bit(float) / (18 x 1024) 〜 920 (端数は繰り上がる)
(出力バッファdst_img)= 102 x 102 x 64 x 32bit / (18/1024) 〜 1181 (端数は繰り上がる)

入出力バッファをなんとか削ればよいということですね。その割には他のハードウェア資源(DSPブロック,LUT)の利用率は1%程度です。。この割合がアンバランスということはFPGAメーカーが意図している回路が設計できていないということですね。

つまりどういうことだ

ソフトウェアでよく書いている作法をそのまま高位合成しても

  • とりあえず合成できる
  • 性能が全く出ない。そもそも性能が見積もれないことが多い。。
  • ハードウェア量が爆発してしまう。。特に内臓メモリ(BRAM)数。

ハードウェアを意識したコードの修正(リファクタリング)が必要です。次回はリファクタリングしてみましょう。