この記事ではDNNDK on Vitis AI on Ultra96v2をベースに,Vitis-AI v1.4/Vitis 2020.2を用いてUltra96v2向けのプラットフォームを作成し、YOLOv3-tinyを動作させます。手順書のようであまり解説はありません。
Setup
- Host: Ubuntu 18.04
- Vitis 2020.2 Unified Software Platform
- petalinux 2020.2
- Vitis-AI v1.4
Xilinx統合環境インストーラをダウンロード
Petalinuxはこのインストーラを使用してダウンロードしたインストーラを起動して、インストールできた。
# Vitisを選択して/tools/Xilinxにインストール、再度起動してPetalinuxダウンロード
sudo ./Xilinx_Unified_2020.2_1118_1232_Lin64.bin
# Petalinuxインストール
sudo chmod +x /tools/Xilinx/PetaLinux/2020.2/bin/petalinux-v2020.2-final-installer.run
mkdir ~/petalinux_2020.2/
/tools/Xilinx/PetaLinux/2020.2/bin/petalinux-v2020.2-final-installer.run --dir ~/petalinux_2020.2/
# 2020.2有効化
source /tools/Xilinx/Vivado/2020.2/settings64.sh
source /tools/Xilinx/Vitis/2020.2/settings64.sh
source ~/petalinux_2020.2/settings.sh
便宜上、作業を行うディレクトリをBUILD_HOMEと名前を付けておきます。
必要なものをダウンロードします。
mkdir ultra96_vai1_4 #適当な名前
export BUILD_HOME="$PWD"
#Vitis-AI
git clone https://github.com/Xilinx/Vitis-AI
cd Vitis-AI
git checkout refs/tags/v1.4
export VITIS_AI_HOME="$PWD"
Avnet Vitis platforms
Avnetが用意してくれているハードウェアプラットフォームです。
cd $BUILD_HOME
mkdir Avnet
cd Avnet
git clone https://github.com/Avnet/bdf
git clone -b 2020p2_u96v2_sbc_base_20210426_105325 https://github.com/Avnet/hdl
git clone -b 2020p2_u96v2_sbc_base_20210426_105325 https://github.com/Avnet/petalinux
git clone -b 2020p2_u96v2_sbc_base_20210426_105325 https://github.com/Avnet/vitis
ビルド済みのものをAvnetのコミュニティからダウンロードすることもできます。
Ultra96のページからVitis PetaLinux Platform -> Ultra96-V2 – Vitis Platform 2020+ (Sharepoint site) -> 2020.2/Vitis_Platform/u96v2_sbc_vitis_2020_2.tar.gz
をダウンロードできます。
今回は1からやってみたかったので自分でビルドしました。ビルド前にAvnet/petalinux
に以下の修正を適用する必要がありました。Avnet/
以下のgitのtagチェックの修正と、petalinuxでFailed to add user layers
になってしまう問題の回避をしています。(なぜconfigure_petalinux_project()でキャッシュを無効にしないとだめなのかはよくわかっていません)
diff --git a/scripts/common.sh b/scripts/common.sh
index 72d2256..cca75da 100755
--- a/scripts/common.sh
+++ b/scripts/common.sh
@@ -124,11 +124,11 @@ check_git_tag()
# Verify the hdl repository is checked out with the correct ${TAG_STRING} tag
cd ${HDL_FOLDER}
echo -e "\nVerifying the hdl repository is checked out with the correct ${TAG_STRING} tag.\n"
- if [ ${TAG_STRING} = $(git status head | head -n1 | cut -d ' ' -f4) ]
+ if [ ${TAG_STRING} = $(git status head | head -n1 | cut -d ' ' -f2) ]
then
echo -e "\nReported hdl tag matches ${TAG_STRING}. Check petalinux tag next...\n"
else
- echo -e "\nReported hdl tag is $(git status head | head -n1 | cut -d ' ' -f4).\n"
+ echo -e "\nReported hdl tag is $(git status head | head -n1 | cut -d ' ' -f2).\n"
echo -e "\nThis does not match requested ${TAG_STRING}. Exiting now.\n"
exit
fi
@@ -136,11 +136,11 @@ check_git_tag()
# Verify the petalinux repository is checked out with the correct ${TAG_STRING} tag
cd ${PETALINUX_FOLDER}
echo -e "\nVerifying the petalinux repository is checked out with the correct ${TAG_STRING} tag.\n"
- if [ ${TAG_STRING} = $(git status head | head -n1 | cut -d ' ' -f4) ]
+ if [ ${TAG_STRING} = $(git status head | head -n1 | cut -d ' ' -f2) ]
then
echo -e "\nReported petalinux tag matches ${TAG_STRING}. Build will continue...\n"
else
- echo -e "\nReported petalinux tag is $(git status head | head -n1 | cut -d ' ' -f4).\n"
+ echo -e "\nReported petalinux tag is $(git status head | head -n1 | cut -d ' ' -f2).\n"
echo -e "\nThis does not match ${TAG_STRING}. Exiting now.\n"
exit
fi
@@ -339,10 +339,10 @@ configure_petalinux_project()
git clone -b ${META_AVNET_BRANCH} ${META_AVNET_URL} project-spec/meta-avnet
fi
- if [ "$KEEP_CACHE" = "true" ]
- then
- configure_cache_path
- fi
+ # if [ "$KEEP_CACHE" = "true" ]
+ # then
+ # configure_cache_path
+ # fi
if [ "$KEEP_WORK" = "true" ]
then
diff --git a/scripts/make_u96v2_sbc_base.sh b/scripts/make_u96v2_sbc_base.sh
index 8e50ab5..315ba2a 100755
--- a/scripts/make_u96v2_sbc_base.sh
+++ b/scripts/make_u96v2_sbc_base.sh
@@ -71,7 +71,7 @@ DEBUG="no"
#NO_BIT_OPTION can be set to 'yes' to generate a BOOT.BIN without bitstream
NO_BIT_OPTION='yes'
-source ${MAIN_SCRIPT_FOLDER}/common.sh
+. ${MAIN_SCRIPT_FOLDER}/common.sh
適用後は以下のようにしてビルドできます。2時間くらいかかりました。
cd $BUILD_HOME/Avnet/vitis
make u96v2_sbc
ダウンロードまたはビルドが完了すれば、Vitisフローで必要になる環境変数を設定しておきます。
export SDX_PLATFORM=$BUILD_HOME/Avnet/vitis/platform_repo/u96v2_sbc_base/u96v2_sbc_base.xpfm
Build the Hardware Project
Vitis-AIリポジトリにある、DPU-TRDを元に作成します。
参考記事と同様、Vitis-AIリポジトリからコピーして修正し、ビルドを行います。
ここでの手順はVitis-AI/dsa/DPU-TRD/prj/Vitis/README.md
を参考にしています。
Vitis-AI v1.1の時とはDPU-TRDの位置が変更されていました。また、READMEにもあるように、新たに$EDGE_COMMON_SW
を設定しておく必要があります。
cd $BUILD_HOME
mkdir ultra96v2_vitis_flow_tutorial_1 #適当な名前
cd ultra96v2_vitis_flow_tutorial_1
cp -r $VITIS_AI_HOME/dsa/DPU-TRD ./DPU-TRD-ULTRA96V2
export TRD_HOME=$BUILD_HOME/ultra96v2_vitis_flow_tutorial_1/DPU-TRD-ULTRA96V2
export EDGE_COMMON_SW=$BUILD_HOME/Avnet/petalinux/projects/u96v2_sbc_base_2020_2/images/linux
Ultra96v2向けに、以下の2つの設定ファイルを編集します。
-
$TRD_HOME/prj/Vitis/dpu_conf.vh
: DPUの構成を小さいものに変更
26c26
< `define B4096
---
> `define B1600
-
$TRD_HOME/prj/Vitis/config_file/prj_config
: Vivado(HWプラットフォーム)構成に合わせて修正
< freqHz=300000000:DPUCZDX8G_1.aclk
< freqHz=600000000:DPUCZDX8G_1.ap_clk_2
< freqHz=300000000:DPUCZDX8G_2.aclk
< freqHz=600000000:DPUCZDX8G_2.ap_clk_2
---
> id=0:DPUCZDX8G_1.aclk
> id=1:DPUCZDX8G_1.ap_clk_2
30,32d27
< sp=DPUCZDX8G_2.M_AXI_GP0:HPC0
< sp=DPUCZDX8G_2.M_AXI_HP0:HP2
< sp=DPUCZDX8G_2.M_AXI_HP2:HP3
35c30
< nk=DPUCZDX8G:2
---
> nk=DPUCZDX8G:1
修正が完了したら、ビルドします。
cd $TRD_HOME/prj/Vitis/
make KERNEL=DPU DEVICE=ULTRA96V2
ハードウェアのビルドはそれなりに時間がかかるので、待ちます。
完了すると、以下に必要なものができあがっています。
tree binary_container_1/sd_card
binary_container_1/sd_card
├── BOOT.BIN
├── Image
├── arch.json
├── boot.scr
├── dpu.xclbin
├── image.ub
├── init.sh
├── platform_desc.txt
├── rootfs.tar.gz
└── u96v2_sbc_base.hwh
Compile the Models from the Xilinx Model Zoo
Vitis-AIコンテナをビルドします。CPUしか使わない場合はdocker pull xilinx/vitis-ai:1.4.916
でセットアップできます。
cd $VITIS_AI_HOME/setup/docker
./docker_build_gpu.sh
XilinxがAI-Model-Zooで公開しているモデルのうち、いくつかのモデルはUltra96での性能が公開されています:
https://github.com/Xilinx/Vitis-AI/tree/master/models/AI-Model-Zoo#performance-on-ultra96
AI-Model-Zooにはtiny-yolov3モデルが存在するのですが、なぜかUltra96での性能が公開されていません。しかも、このtiny_yolov3_vmss
はクラスカテゴリが['KELLOGS,CHOCOLATE,CANDLE,SHAMPOO,BULB,PLIERS,DETERGENT,KOOLAID,LIPSTICK,BOX']となっていて、データセットも見つかりません・・
そこで、今回はVitis-AI v1.1で動作させたことのあるtiny_yolov3によるface mask検出を動作させてみようと思います。
Real-time tiny-YOLOv3 face mask detection on Ultra96v2
tiny-yolov3
の学習方法については元記事で紹介しています。学習済みのモデル・重みはGitHubで公開しています。元記事でも記述の通り、オリジナルのyolov3-tiny.cfgから変更を加えています。(darknetからcaffeへの変換の失敗を防ぐためmaxpoolのサイズを1箇所変更)
量子化に必要なデータセットはYOLOv3-face-mask-detectionからダウンロードします。
モデルのコンパイルはVitis-AI dockerコンテナ環境で行います。
cd $VITIS_AI_HOME
mkdir yolov3_tiny_model #ここにモデルとデータセット(mask.zip)を配置
cd yolov3_tiny_model
unzip mask.zip
cd $BUILD_HOME
./Vitis-AI/docker_run.sh xilinx/vitis-ai-gpu:1.4.916
#以下dockerコンテナ内で作業
conda activate vitis-ai-caffe
cd /workspace/Vitis-AI/yolov3_tiny_model
Darknet2Caffe
DarknetからCaffeに変換するスクリプトがXilinxから提供されています。
python3 ../models/AI-Model-Zoo/caffe-xilinx/scripts/convert.py yolov3-tiny_mask.cfg yolov3-tiny_mask_60000.weights yolov3_tiny_mask.prototxt yolov3_tiny_mask.caffemodel
Quantization
Vitis-AI Quantizer
を使用してモデルの量子化を行います。量子化のためのprototxtを作成します。
cp yolov3_tiny_mask.prototxt for_quantize.prototxt
量子化のスケールを最適化するために、実際に推論で使用する画像を使用してキャリブレーションを行います。
for_quantize.prototxt
の1〜6行目を削除し、以下のようにキャリブレーション画像へのパスを設定します。
diff yolov3_tiny_mask.prototxt for_quantize.prototxt
1,6c1,18
< name: "Darkent2Caffe"
< input: "data"
< input_dim: 1
< input_dim: 3
< input_dim: 224
< input_dim: 224
---
> layer {
> name: "data"
> type: "ImageData"
> top: "data"
> top: "label"
> include {
> phase: TRAIN
> }
> image_data_param {
> source: "./quant.txt"
> batch_size: 16
> }
> transform_param {
> mirror: false
> yolo_width: 416
> yolo_height: 416
> }
> }
画像ファイルリストをquant.txt
として作成します。以下のPythonコードで作成しました。
import os
import glob
calib_images = glob.glob('./mask/*.jpg')
for calib_image in calib_images:
print(os.path.abspath(calib_image), 0)
python3 gen_quantize_list.py > quant.txt
vai_q_caffe quantize \
-model ./for_quantize.prototxt \
-weights ./yolov3_tiny_mask.caffemodel \
--keep_fixed_neuron \
-calib_iter 100 \
-gpu 0
量子化が完了すると、以下のようにファイルが生成されます。
...
I1105 12:47:51.496042 7397 vai_q.cpp:368] Deploy Done!
--------------------------------------------------
Output Quantized Train&Test Model: "./quantize_results/quantize_train_test.prototxt"
Output Quantized Train&Test Weights: "./quantize_results/quantize_train_test.caffemodel"
Output Deploy Weights: "./quantize_results/deploy.caffemodel"
Output Deploy Model: "./quantize_results/deploy.prototxt"
Compilation
次に、DPU向けにモデルのコンパイルを行います。
ここで、DPUの構成に応じてコンパイルをする必要があり、Step1で生成されたarch.json
を使用します。
ちなみに、Vitis-AI v1.2まではDPU情報を表記したhwh
ファイルからdlet
を用いてdcf
を生成していましたが、dlet
はv1.3以降docker環境に存在しないようです。
cp /workspace/ultra96v2_vitis_flow_tutorial_1/DPU-TRD-ULTRA96V2/prj/Vitis/binary_container_1/sd_card/arch.json ./
vai_c_caffe \
-a arch.json \
-p ./quantize_results/deploy.prototxt \
-c ./quantize_results/deploy.caffemodel \
-o ./compiled \
-n yolov3_tiny_mask
**************************************************
* VITIS_AI Compilation - Xilinx Inc.
**************************************************
[INFO] Namespace(batchsize=1, inputs_shape=None, layout='NCHW', model_files=['./quantize_results/deploy.caffemodel'], model_type='caffe', named_inputs_shape=None, out_filename='/tmp/yolov3_tiny_mask_org.xmodel', proto='./quantize_results/deploy.prototxt')
[INFO] caffe model: /workspace/Vitis-AI/yolov3_tiny_model/quantize_results/deploy.caffemodel
[INFO] caffe model: /workspace/Vitis-AI/yolov3_tiny_model/quantize_results/deploy.prototxt
[INFO] parse raw model :100%|██████████████████████████████████████████████████████████████████| 48/48 [00:01<00:00, 38.79it/s]
[INFO] infer shape (NCHW) :100%|██████████████████████████████████████████████████████████████████| 48/48 [00:00<00:00, 2231.09it/s]
[INFO] infer shape (NHWC) :100%|██████████████████████████████████████████████████████████████████| 48/48 [00:00<00:00, 3651.45it/s]
[INFO] perform level-1 opt :100%|██████████████████████████████████████████████████████████████████| 3/3 [00:00<00:00, 1443.49it/s]
[INFO] generate xmodel :100%|██████████████████████████████████████████████████████████████████| 48/48 [00:00<00:00, 647.94it/s]
[INFO] dump xmodel: /tmp/yolov3_tiny_mask_org.xmodel
[UNILOG][INFO] Compile mode: dpu
[UNILOG][INFO] Debug mode: function
[UNILOG][INFO] Target architecture: DPUCVDX8G_ISA0_B1600_01000020F6014404
[UNILOG][INFO] Graph name: deploy, with op num: 100
[UNILOG][INFO] Begin to compile...
[UNILOG][WARNING] xir::Op{name = layer11-maxpool, type = pool-fix}'s input and output is unchanged, so it will be removed.
[UNILOG][INFO] Total device subgraph number 4, DPU subgraph number 1
[UNILOG][INFO] Compile done.
[UNILOG][INFO] The meta json is saved to "/workspace/Vitis-AI/yolov3_tiny_model/./compiled/meta.json"
[UNILOG][INFO] The compiled xmodel is saved to "/workspace/Vitis-AI/yolov3_tiny_model/./compiled/yolov3_tiny_mask.xmodel"
[UNILOG][INFO] The compiled xmodel's md5sum is 5476c1153bfe24bc2665ca081d449edb, and has been saved to "/workspace/Vitis-AI/yolov3_tiny_model/./compiled/md5sum.txt"
DPU subgraph number 1
となっているので理想的にDPUにオフロードされていそうです。
netron
を使用してコンパイルしたモデルyolov3_tiny_mask.xmodel
を確認できました。
prototxt
今回使用するXilinxの評価アプリケーションはモデルの情報をprototxtファイルから読み込みます。
AI-Model-Zooにあるtiny-yolov3を参考に以下のprototxtファイルを./compiled/tiny-yolov3.prototxt
として保存しました。
model {
name: "yolov3_tiny_mask"
kernel {
name: "yolov3_tiny_mask_0"
mean: 0.0
mean: 0.0
mean: 0.0
scale: 0.00390625
scale: 0.00390625
scale: 0.00390625
}
model_type : YOLOv3
yolo_v3_param {
num_classes: 3
anchorCnt: 3
layer_name: "15"
layer_name: "22"
conf_threshold: 0.3
nms_threshold: 0.45
biases: 10
biases: 14
biases: 23
biases: 27
biases: 37
biases: 58
biases: 81
biases: 82
biases: 135
biases: 169
biases: 344
biases: 319
test_mAP: false
}
}
Compile the AI Applications
クロスコンパイル環境を整えてyolov3の評価アプリケーションをホスト上でビルドします。
本手順はVitis-AIドキュメントのstep1-setup-cross-compiler
に沿っています。
この作業はdockerコンテナではなくホスト環境で行います。
Vitis2020.2を使用しているので./host_cross_compiler_setup_2020.2.sh
を実行する
cd $VITIS_AI_HOME/setup/mpsoc
./host_cross_compiler_setup_2020.2.sh
unset LD_LIBRARY_PATH
source /home/`$USER`/petalinux_sdk_2020.2/environment-setup-aarch64-xilinx-linux
クロスコンパイル環境が整ったのでアプリケーションをビルドします。
yolov3含め多数モデル向けの評価アプリケーションが公開されています。
cd $VITIS_AI_HOME/demo/Vitis-AI-Library/samples/yolov3
sh build.sh
test_jpeg_yolov3, test_accuracy_yolov3_mt, test_performance_yolov3, test_video_yolov3
の4つの実行ファイルが生成されています。
Create the SD card
これまでに作成したものを集めてきて、Ultra96v2で使用するSDカードを作成します。
Gpartedなどを使用して第一パーティションをFAT, 第二パーティションをext4でフォーマットします。
(それぞれBOOT, rootfs
とラベルを付けました。)
- ブートに必要なもの
cd $TRD_HOME/prj/Vitis/binary_container_1/sd_card
cp dpu.xclbin /media/lp6m/BOOT/
cp BOOT.BIN /media/lp6m/BOOT/
cp image.ub /media/lp6m/BOOT/
cp boot.scr /media/lp6m/BOOT/
cp Image /media/lp6m/BOOT/
sudo tar xvf rootfs.tar.gz -C /media/lp6m/rootfs/
- VART(Vitis-AI-Runtime)
cd $VITIS_AI_HOME/setup/mpsoc
sudo cp -r VART /media/lp6m/rootfs/home/root/
- yolov3 model, application, test image (video)
cd $VITIS_AI_HOME/yolov3_tiny_model
sudo cp -r compiled /media/lp6m/rootfs/home/root/yolov3_tiny_mask
sudo cp -r mask /media/lp6m/rootfs/home/root
cd $VITIS_AI_HOME/demo/Vitis-AI-Library/samples
sudo cp -r yolov3 /media/lp6m/rootfs/home/root/yolov3_app
sync
sync
が完了してからSDを取り外します。
- SDカード
- Ultra96V2
- 電源
Execute the AI applications on hardware
SDカード、電源、HDMIアダプタ、キーボード、マウス、Webカメラなどを繋いで本体を起動します。
参考:Ultra96-V2 で開発を行う際に必要なもの & あるといいもの
以降の作業はUltra96上で行います。
Wifiの設定
ターミナルを開いて、/home/root/wpa_supplicant.conf
を編集してSSIDとパスワードを設定します。
./wifi.sh
ifconfig -a
これでネットワークにつながるので、sshもできるようになります。(パスワードはroot)
VART(Vitis-AI Runtime)の実機へのインストール
VART(Vitis-AI Runtime)の実機へのインストールを参考にします。
無事起動したらVARTを実機側にもインストールします。
cd /home/root/VART
./target_vart_setup_2020.2.sh
dexplorerでDPU情報確認
dexplorer
でDPUのバージョンや有効になっている機能をチェックすることができます。
/usr/lib/
にカーネルイメージdpu.xclbin
をコピーする必要があります。
cp /mnt/sd-mmcblk0p1/dpu.xclbin /usr/lib/
dexplorer -w
[DPU IP Spec]
IP Timestamp : 2021-06-07 19:15:00
DPU Core Count : 1
[DPU Core Configuration List]
DPU Core : #0
DPU Enabled : Yes
DPU Arch : B1600
DPU Target Version : v1.4.1
DPU Freqency : 150 MHz
Ram Usage : Low
DepthwiseConv : Enabled
DepthwiseConv+Relu6 : Enabled
Conv+Leakyrelu : Enabled
Conv+Relu6 : Enabled
Channel Augmentation : Enabled
Average Pool : Enabled
Test Performance
評価アプリケーションは/usr/share/vitis_ai_library/models
内のモデルを対象に実行するので、コンパイルしたモデルをコピーします。
mkdir /usr/share/vitis_ai_library/models
cp -r yolov3_tiny_mask /usr/share/vitis_ai_library/models/
パフォーマンス計測には画像が1枚以上必要なので、画像リストimage.list
を作成します。
cd ~/yolov3_app
echo "/home/root/mask/Mask_0.jpg" > image.list
./test_performance_yolov3 yolov3_tiny_mask image.list
WARNING: Logging before InitGoogleLogging() is written to STDERR
I1105 19:42:33.142753 1657 benchmark.hpp:184] writing report to <STDOUT>
I1105 19:42:33.143976 1657 benchmark.hpp:211] waiting for 0/30 seconds, 1 threads running
I1105 19:42:43.144228 1657 benchmark.hpp:211] waiting for 10/30 seconds, 1 threads running
I1105 19:42:53.144506 1657 benchmark.hpp:211] waiting for 20/30 seconds, 1 threads running
I1105 19:43:03.144932 1657 benchmark.hpp:219] waiting for threads terminated
FPS=28.2217
E2E_MEAN=35403.1
DPU_MEAN=32646.8
画像サイズ416x416のyolov3-tiny
はUltra96v2上(DPU1600, 150Mhz)で28FPSが達成されることがわかりました。 グラフ全体をDPUにオフロードできたため、End-to-Endの時間のうちほとんどの時間がDPUの時間を占めています。
Image Test
./test_jpeg_yolov3 yolov3_tiny_mask ../mask/Mask_74.jpg
I1105 20:43:09.306178 1530 demo.hpp:1183] batch: 0 image: ../mask/Mask_74.jpg
I1105 20:43:09.306447 1530 process_result.hpp:44] RESULT: 0 1701.7 1393.09 2543.82 2229.84 0.983498
I1105 20:43:09.306952 1530 process_result.hpp:44] RESULT: 0 581.677 742.82 1237.53 1579.57 0.777177
I1105 20:43:09.307421 1530 process_result.hpp:44] RESULT: 2 3082.35 219.546 4175.43 1562.61 0.990156
残念ながら評価アプリケーションはbboxを描画してくれないようなので適当に手元で描画した結果はこのようになりました。
今回は精度評価などは行なっていませんがある程度認識できているように思います。
Video Test
最近のニュース番組を使うと良い感じになります。
export DISPLAY=:0.0
xrandr --output DP-1 --mode 640x480
./test_vido_yolov3 yolov3_tiny_mask youtube.mp4
解像度を変更してから実行したのですが動画の評価を実行中は画面のちらつきがものすごくひどくなってしまいました。
まとめ
とりあえずVitis-AI v1.4 / Vitis 2020.2のフローを追うことができた。