FPGAボード(KV260)での推論 - takgto/utokyo-chipathon2023 GitHub Wiki
FPGA上でC++のソースコードをコンパイルして実行し、画像や映像に対して推論を行います。また、保存されている映像だけでなく、カメラで映している映像に対してリアルタイムで推論を行います。
この手順では、VSCode(Visual Studio Code)というエディタでFPGA上のテキストを編集します。FPGAとの接続方法は読み進めると出てきます。(Vimを使える人はVSCode不要です)
このアイコンのついているコードはVSCodeで編集するという意味です。
(コンソール)という表示はVSCodeのコンソールに入力するという意味です。
モデル変換で使用したMobaXtermを使用する場面もあります。
このアイコンのついているコマンドはMobaXtermのSSH接続したコンソールに一行ずつ入力してください。
SSHコンソールでも以下のコマンドを入力すると、エイリアス(ショートカットのようなもの)を使えるようになります。

source ./aliases(source ./init260.shでも同じです)
画像推論コードをビルド(コンパイル)します。 SSHコンソールに以下のコマンドを入力します。

cd ~/Vitis-AI/examples/VART/yolov3
(もしくはyolov3)
./make.sh yolov3_file_series.cppできる実行ファイルは拡張子無しのyolov3となります。
FPGAに接続したMobaXTermのSSHコンソールまたはVSCodeのターミナルに以下のコマンドを入力します。

xmutil listapps
xmutil unloadapp
xmutil loadapp kv260-benchmark-b4096上記を実行して、実行環境をロードしてください。
画像に対して推論を行います。FPGAに接続したMobaXTermのSSHコンソールまたはVSCodeのターミナルに以下のコマンドを入力します。

pwd
(カレントディレクトリは /home/root/Vitis-AI/examples/VART/yolov3 であることを確認)
ls images
(000000009615.jpg 000000012896.jpg 000000020904.jpg list.txt が表示されるはず)
ln -s /usr/share/vitis_ai_library/models/yolov3-416/yolov3-416.xmodel yolov3-416.xmodel
./yolov3 yolov3-416.xmodel ./images/000000020904.jpg上記 ls imagesで表示されるjpgイメージのひとつを2番目の引数として実行する。
すると、yolov3/imagesディレクトリに検出結果として000000020904_det.jpgが作られます。
VSCodeで、yolov3ディレクトリを開き、画像を開きます。
VSCodeのターミナルに以下のコマンドを入力すると、~/Vitis-AI/examples/VART/yolov3ディレクトリが開きます。

code ~/Vitis-AI/examples/VART/yolov3VSCodeまたはMobaXtermの左のファイル一覧で0_000000020904_det.jpgをクリックすると、推論結果の画像が表示されます。
000000020904_det.jpg

000000012896_det.jpg

000000009615_det.jpg

FPGAに接続したMobaXTermのSSHコンソールまたはVSCodeのターミナルに以下のコマンドを入力します。
** 注意 **
MobaXtermは貼り付けで行が折り返った時、同じ行に上書きしてしまいうまくいきません。以下のコマンドの2行目がうまくいかない時は手打ちでコマンドを入力してください。

cd ~/Vitis-AI/examples/VART/yolov3
./make.sh yolov3_video_series.cppmake.shの結果、yolov3(1つ上のカレントディレクトリの名前)が実行ファイルとしてできます。
動画推論を実行するため、次のコマンドをFPGAに接続したMobaXTermのSSHコンソールに入力します。

./yolov3 yolov3-416.xmodel ./video/adas.webm
ここで、次の4.精度検証を行う場合は動画が終了するまで動画を閉じないでください。他の場合、動画をアクティブにしてEscボタンまたはqボタンを押すと動画が閉じます。
精度は上記動画(adas.webm)の正解(Ground Truth)と、実際にyolov3で検出した結果とを比較してmAPという精度指標によって評価します。
精度検証を行うには、yolov3のコードの中に動画検出結果をファイルとして保存する機能が必要で、yolov3_video_series.cppには予めそのコードが埋め込まれています。実際にコンパイルした結果を走らせると、同じディレクトリに検出結果の情報が入ったdetection_log.txtというファイルが保存されます。まず、このファイルをWSL2に転送します。WSL2から次のコマンドをタイプします。
注:精度検証を行う場合は必ず動画を最後まで走らせてください。途中、ESCやqで抜けないでください

cd /home/x-nics-kuroda/Vitis-AI2.5/adas-edge-eval/logs
scp [email protected]:/home/root/Vitis-AI/examples/VART/yolov3/detection_log.txt .次にmAPの計算をします。
cd /home/x-nics-kuroda/Vitis-AI2.5/adas-edge-eval
python3 eval/eval_log.py logs/detection_log.txtdetection_log.txtは名前を自由に変えて、そのファイルを上記コマンドで指定すれば問題ないです。
結果の要約
| IoU 0.5(主指標) | IoU 0.75(参考値) | |
|---|---|---|
| mAP2_frame | 62.84% | 38.96% |
| mAP2_display | 62.84% | 38.96% |
| loss(display − frame) | +0.00% | +0.00% |
コンソール出力の全文(クリックで開く)
ログ: logs/detection_log.txt
レコード数: 1616, 期待フレーム数: 1616
ログ検査: OK (1616 レコード, shown=1616)
IoU: 0.5 [主], 0.75 [参考]
=== mAP_frame (IoU=0.5) ===
mAP2 (car+person)/2 = 62.84%
bicycle: AP = 0.00%
car: AP = 88.04%
person: AP = 37.65%
mAP (3cls, ref) = 41.90%
=== mAP_display (IoU=0.5) ===
valid: 1616, inversions: 0, avg hold: 1.0 frames
mAP2 (car+person)/2 = 62.84%
bicycle: AP = 0.00%
car: AP = 88.04%
person: AP = 37.65%
mAP (3cls, ref) = 41.90%
=== mAP_frame (IoU=0.75) [ref] ===
mAP2 (car+person)/2 = 38.96%
bicycle: AP = 0.00%
car: AP = 67.38%
person: AP = 10.55%
mAP (3cls, ref) = 25.98%
=== mAP_display (IoU=0.75) [ref] ===
valid: 1616, inversions: 0, avg hold: 1.0 frames
mAP2 (car+person)/2 = 38.96%
bicycle: AP = 0.00%
car: AP = 67.38%
person: AP = 10.55%
mAP (3cls, ref) = 25.98%
=== summary (mAP2) ===
IoU=0.5 IoU=0.75 [ref]
mAP2_frame 62.84% 38.96%
mAP2_display 62.84% 38.96%
loss +0.00% +0.00%
棒グラフを保存しました: logs/detection_log_map.png
| 指標 | 意味 |
|---|---|
| mAP_frame | 各フレームの検出結果を、そのフレームの GT と照合した精度(モデル+前後処理の精度) |
| mAP_display | 実際に表示された検出結果を、間引き・逆行を反映して照合した精度(実検出器の精度) |
IoU は、検出結果の Bbox と GT の Bbox の重なり具合です。大きいほどよく重なっています。
表示しなかったフレームでは、直前に表示した結果が画面に残っているとみなして GT と照合します。
表示を間引いた場合(SHOW_EVERY=4)
GT のフレーム : 0 1 2 3 | 4 5 6 7 | 8 9 10 11 | 12 13 14 15 | ...
評価に使う結果 : 0 0 0 0 | 4 4 4 4 | 8 8 8 8 | 12 12 12 12 | ...
GT は毎フレーム変わりますが、評価に使う結果は、表示を飛ばしている間は変わりません。
※ この動画は、中身が 4 フレームに 1 回くらいしか切り替わらないため、SHOW_EVERY=4 の影響は小さめです。10 フレームに 1 回の表示では、10% 近く低下する場合もあります。
表示順が逆転した場合
表示の順番 : 0 | 4 | 12 | 8 (無効) | 16 | 20
GT のフレーム : 0 1 2 3 | 4 5 6 7 | 8 9 10 11 | 12 13 14 15 | 16 17 18 19 | 20 ...
評価に使う結果 : 0 0 0 0 | 4 4 4 4 | 4 4 4 4 | 12 12 12 12 | 16 16 16 16 | 20 ...
それまでに表示したフレームより前のフレーム(この例では 8)が後から表示された場合、その表示は無効になり、1 つ前に表示した結果(4)が評価に使われます。
実行後、次のような棒グラフがポップアップで表示されます。

| 項目 | 意味 |
|---|---|
| レコード数 | 検出を行ったフレーム(画像)の数。adas.webm は 1616 フレームから成ります。 |
| NINFER | 推論に用いたスレッドの数。series 版はスレッドを使わないので 1 です。 |
| SHOW_EVERY | 何フレームに 1 回表示するか。FPS を上げるために表示枚数を減らすことがあります。SHOW_EVERY=4 なら 4 フレームに 1 回表示します。 |
| CAP | スレッド版で、Read → Infer → Show の間に挟むキューに何枚まで溜められるか。 |
- mAP2 は car と person の AP の平均です。
- bicycle は高さ 12 ピクセル前後と非常に小さいため、今回は評価対象にしていません。
この棒グラフは課題の提出物の 1 つです。スクリーンショットを保存して提出してください。
report.py は、複数の検出ログをまとめて評価し、1 つの表にして比較するためのスクリプトです。モデル、入力サイズ、表示の間引き方などを変えて実行した結果を並べて比べられます。
リポジトリのトップディレクトリで実行します。
# ログを並べて指定する
python3 eval/report.py logs/det_log_series_tiny_show1.txt logs/det_log_series_tiny_show10.txt
# 名前のパターンでまとめて指定する
python3 eval/report.py logs/det_log_series_*.txt
# 表を Excel ファイルにも保存する
python3 eval/report.py logs/det_log_series_*.txt --xlsx report.xlsxログは 1 つずつ IoU 0.5 と 0.75 の 2 通りで評価するので、ログの数が多いと時間がかかります。
| オプション | 意味 |
|---|---|
logfiles(必須) |
評価する検出ログ(複数指定できます) |
--xlsx ファイル名 |
表を Excel ファイル(.xlsx)にも保存します |
--tsv ファイル名 |
表をタブ区切りのテキストにも保存します |
--config、--gt-dir
|
設定ファイルと GT の場所。通常は指定不要です |
detection_log.txt は実行のたびに上書きされます。条件を変えて実行したら、条件が分かる名前に変えて logs/ に保存してください。
mv detection_log.txt logs/det_log_series_tiny_show1.txt # series 版、tiny モデル、毎フレーム表示
mv detection_log.txt logs/det_log_series_tiny_show10.txt # series 版、tiny モデル、10 枚に 1 枚表示モデル名、入力サイズ、FPS、SHOW_EVERY などはログの先頭行に記録されているので、表には自動で入ります。
SE(SHOW EVERY)=1,10,2と変化させた場合の例:
model input SE FPS [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] inv
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
dpu_yolov3-tiny_best 416x416 1 6.9 63.5 11.5 0.2 0.0 0.0 0.0 31.9 5.7 +0.0 +0.0 0
dpu_yolov3-tiny_best 416x416 10 30.3 59.5 10.5 0.4 0.0 0.0 0.0 29.9 5.2 -1.3 -0.3 0
dpu_yolov3-tiny_best 416x416 2 11.4 63.6 11.5 0.2 0.0 0.0 0.0 31.9 5.8 +0.0 +0.0 0
| 列 | 意味 |
|---|---|
| model、input | 使ったモデルと入力サイズ |
| SE | SHOW_EVERY(何フレームに 1 回表示したか) |
| FPS | 1 秒あたりに処理したフレーム数 |
| car、person、bicycle | クラスごとの AP(mAP_display の値)。@.50 は IoU 0.5(主指標)、@.75 は IoU 0.75(参考値) |
| mAP2 | car と person の AP の平均 |
| loss | mAP_display − mAP_frame(IoU 0.5)。表示の間引きや逆転によって失われた精度で、マイナスが大きいほど損失が大きい |
| inv | 表示順が逆転して無効になった回数 |
※ 上の例では、SE を 1 → 10 にすると FPS は 6.9 → 30.3 と大きく上がる一方、[email protected] は 63.5 → 59.5 に下がり、loss は −1.3 になっています。表示を間引くと速くなるかわりに、表示されている検出結果が古くなり、精度が下がることが分かります。
ここから本格的に高速化を行います。そのためにはFPGA上にあるソースコード等のファイルを編集する必要があります。
ファイルを編集するにはVSCodeでSSHをし、FPGAに接続しましょう。私はVim使いになるんだ!という人は以下の手順は踏まなくても大丈夫です。
タスクバーまたはスタートメニューからVSCode(Visual Studio Code)を立ち上げます。

VSCodeの左下の青いマーク
をクリックして、以下のような画面を出します。

ホストに接続する、を押します。ここで、「KV260」という選択肢があれば選択します。
KV260がない場合、または、KV260を選択しても接続できなかった場合は1番下のSSHホストを構成する...を押します。 SSH構成ファイルがいくつか出てくるので、1番上のものを選択します。SSH構成ファイルに以下のように追加します。既にKV260がある場合は違う部分を修正してください。

Host kv260
HostName 192.168.1.100
User root保存したらさっきと同じように、左下の青色矢印からホストに接続するを押し、kv260を選びます。
「KV260」を選択後、OSの選択が出てきたらLinuxを、パスワードを要求されたらパスワード(root)を入力してください。
上記の作業でVSCodeでFPGA上のテキストを編集することができます。
VSCodeの右下側にターミナルを表示します。ターミナルが表示されていない場合は左上のメニューバー、または、メニューバーの・・・にある「ターミナル」を選択してターミナルのウインドウを表示します。
例えば、yolov3ディレクトリを開きたい時はVSCodeターミナルに以下のコマンドを入力します。
(ターミナル)
code ~/Vitis-AI/examples/VART/yolov3(1) 動画の読み込み
(2) AIモデルのセットアップと実行
(3)出力処理
上記の処理は全て、先程コンパイルしたファイルyolov3_video_subject1.cppで行っています。
その中身をVSCodeで開いて見てみましょう。このページで説明しています。
ここまでは保存されているビデオ画像を解析してきましたが、USBカメラを接続すると、カメラ映像をリアルタイムで解析できます。
入力画像をUSBカメラからに変更する方法はここをクリック。