前回の経緯
YOLOv3で、DPUの処理が始まるとリブートする問題が発生。Ultra96v2のエラッタのPMIC電流制限にかかっていると思われ、次のいずれかで回避できないか?と考え、ひとまず簡単にできそうな、DPUの規模 or 周波数を落として、どうなるかを試してみました。
- Infinion USB005を購入して、PMICのFWを更新
- 誰かに更新してもらう(他力本願)
- PMICの電流制限に引っかからない程度に、DPUの規模と周波数を落とす。<==これを試してみた
- PGOODの回路を改造
DPUの規模変更
DPUのConfiguration
Ultra96v2に搭載されているZynq Ultrascale+ MPSoCでは、B512~B4096と8種類のconfigurationに対応している。各DPUのConfigurationについて、ユーザーガイドから抜粋した。B2304で、PP=8, ICP=12, OCP=12となっているので、B512, B800あたりにすれば大きく消費電流は減りそうです。
DPUCZDX8G Architecture |
Pixel Parallelism (PP) |
Input Channel Parallelism (ICP) |
Output Channel Parallelism (OCP) |
Peak Ops (operations/per clock) |
---|---|---|---|---|
B512 | 4 | 8 | 8 | 512 |
B800 | 4 | 10 | 10 | 800 |
B1024 | 8 | 8 | 8 | 1024 |
B1152 | 4 | 12 | 12 | 1150 |
B1600 | 8 | 10 | 10 | 1600 |
B2304 | 8 | 12 | 12 | 2304 |
B3136 | 8 | 14 | 14 | 3136 |
B4096 | 8 | 16 | 16 | 4096 |
DPUの実装
各DPUを実装した場合の、Ultra96v2のリソース使用率を以下にまとめておきます。ユーザーガイドを見れば、ビルドせずとも、リソース使用率は分かるんですが、一応、Vitisでビルドした際の使用率になります。LUTとREGはユーザーガイドのResource Useとズレはありますが、BRAMとDSPは全くの同値です。(まあ、当たり前か)
DPU以外は、最低限のAXI interconnect, AXI interrupt Controller, Clocking wizard, Processor System Resetしか実装しておらず、Platformのリソース使用は殆どなく、DPUが大半を占めています。にもかかわらず、B2304だとLUT/BRAM/DSPが結構な使用率になっているので、他の回路の実装が必要なユースケースだと、B1600あたりが限界な気もしますね。
Name | LUT | LUTAsMem | REG | BRAM | DSP | |
---|---|---|---|---|---|---|
Ultra96v2 | Platform | 2089 [ 2.96%] |
147 [ 0.51%] |
2564 [ 1.82%] |
0 [ 0.00%] |
0 [ 0.00%] |
User Budget | 68471 [100.00%] |
28653 [100.00%] |
138556 [100.00%] |
216 [100.00%] |
360 [100.00%] |
|
DPUCZDX8G | B512 | 27644 [ 40.37%] |
1887 [ 6.59%] |
35036 [ 25.29%] |
73 [ 33.80%] |
78 [ 21.67%] |
B800 | 30403 [ 44.40%] |
2227 [ 7.77%] |
42257 [ 30.50%] |
91 [ 42.13%] |
117 [ 32.50%] |
|
B1152 | 33227 [ 48.53%] |
2568 [ 8.96%] |
49060 [ 35.41%] |
123 [ 56.94%] |
164 [ 45.56%] |
|
B1600 | 38891 [ 56.80%] |
2845 [ 9.93%] |
62636 [ 45.21%] |
127 [ 58.80%] |
232 [ 64.44%] |
|
B2304 | 42823 [ 62.54%] |
3298 [ 11.51%] |
73622 [ 53.14%] |
167 [ 77.31%] |
326 [ 90.56%] |
DPUの変更手順
簡単に記しておきます。
- dpu_config.vhの変更
//`define B4096
`define B1600
- DPUの再ビルド
再ビルドして生成された、BOOT.BIN, image.ub, dpu.xclbinに置き換える。
make KERNEL=DPU DEVICE=ULTRA96V2
- YOLOv3モデルの再コンパイル
再ビルド後に生成されたhwhファイルにて、モデルのコンパイルを再実行。
YOLOv3の実行
B2304ではリブートしてしまったんですが、B1600に変更したところ、正常に動作することを確認できました。やはりPMICの電流制限にひっかかってリブートしているってことで間違いなさそう。
root@ultra96v2_v2020_1:~/YOLOv3# ./YOLOv3 dpu_yolov3_b1600.elf
WARNING: Logging before InitGoogleLogging() is written to STDERR
I0325 19:58:46.659310 635 main.cc:14] create running for subgraph: yolov3_b1600
conv2d_58_Conv2D_60
conv2d_66_Conv2D_70
conv2d_74_Conv2D_79
in_dims : 1, 416, 416, 3
out_dims0 : 1, 13, 13, 255
out_dims1 : 1, 26, 26, 255
out_dims2 : 1, 52, 52, 255
Infering COCO_train2014_000000000078.jpg...
Infering COCO_train2014_000000000036.jpg...
Infering COCO_train2014_000000000077.jpg...
Infering COCO_train2014_000000000071.jpg...
Infering COCO_train2014_000000000025.jpg...
Infering COCO_train2014_000000003259.jpg...
Infering COCO_train2014_000000000072.jpg...
Infering COCO_train2014_000000000030.jpg...
Infering COCO_train2014_000000000064.jpg...
Infering COCO_train2014_000000000009.jpg...
Infering COCO_train2014_000000000034.jpg...
Elapsed Time per frame: 293368[us]
B512, B800, B1152でも問題なく動作したので、各DPUで実行した場合の時間もまとめてみました。上に記載した、Peak Opsと大よそ反比例に近いような実行時間になっていますが、Peak Opsの割合ほど、実行時間が短縮されていないのは、データの転送時間などのオーバーヘッドが存在する分かな?もっと小さいモデルで、オーバーヘッドが支配的な場合だと、より顕著に見えてきそう。
また、参考までにUltra96v2のCPUで、YOLOv3を実行した場合の時間も確認してみましたが、約146秒となりました。CPUで処理した場合の詳細な実装内容までは確認していないので、同じ土俵での比較になっているか?までは分かりませんが、これだけ差があるというのは劇的ですね。ただ、モデルの量子化によって、32bit浮動小数点から8bit固定小数点に変更されている分、精度がどこまで維持できているかも気になる。
CPU/DPU | 周波数[MHz] | 時間[ms] |
---|---|---|
DPU B512 | 200/400 | 725 |
DPU B800 | 200/400 | 511 |
DPU B1152 | 200/400 | 367 |
DPU B1600 | 200/400 | 293 |
DPU B2304 | 200/400 | リブート |
CPU | - | 146093 |
DPUとCPUの実行結果比較
CPUとDPUで推論精度がどの程度異なるか?が気になったので、ひとまず一つの画像で比較してみました。(正確には、mAPなどで性能評価しないと分からないと思う。Xilinxとかでやってそうだけど、、、どこかにないんだろうか。)
- DPUの場合、スコアが低いオブジェクトの検出ができていない?一部のbook, bicycle, kerboardなどが検出できていない。
- スコアが高いオブジェクトも、矩形領域が結構違うものもある。
mAPを評価してみたら、結構差が出そうで興味深いです。(実際、どうやったらいいか分からないが)
モデルを量子化する際のパラメータとかで、性能が変わってきたり、とかあるんだろうか?
CPUでYOLOv3を実行(補足)
ちょっと記事の本題とは逸れるのですが、手順を簡単に記載しておきます。
Darknetのソースコードを取得
git clone https://github.com/pjreddie/darknet
ビルド実行
cd darknet
make
ただし、petalinuxにgcc, g++が入っていなかったので、ビルド前にdnfでgccとg++をインストールが必要だった。
dnf install gcc
dnf install g++
また、gcc, g++をインストール後もPATHが通ってなかったので、下記のシンボリックリンクを作成
cd /usr/bin
ln -s aarch64-xilinx-linux-gcc gcc
ln -s aarch64-xilinx-linux-g++ g++
下記にて、YOLOv3を実行
./darknet detect cfg/yolov3.cfg yolov3.weights COCO_train2014_000000003259.jpg