高位合成によるFPGA回路設計を読んで、MNISTを試してみた


はじめに

前々から、FPGAの高位合成や画像認識に興味はあったのですが、これはという書籍もなく、色々なサンプルに手を出しては、途中で挫折するということを繰り返していました。(主にpetalinuxのせいな気がする)
そんな中、これは!という書籍が発売されているのを知り、早速購入してみました。

帯に書いてあった"高位合成の初歩から丁寧に学べる待望の入門書"という売り文句は間違ってなく、大変勉強になったんですが・・・、Chapter5のVitis AIでDPUを実装し、MNISTを実行する、というところで散々ハマったので、その過程を書き記してみます。
私が回路・基板設計がメインのハードウェアエンジニアで、たまにHDLもかじったことがありますという程度のスキルレベルで、Linuxをいじったり、C++でコーディングするハードルが高いということもあり、これらの罠回避に難航したということもあるかもしれません。
ただ、MNISTを実行するだけのために、これだけの労力を費やさないとならないというのは、こういうハードルや罠の多さが、今ひとつ普及しない要因になってるんじゃ・・・とかも思ったりします。(クラウドだったら、Google Colabでサッと試せるし)

実行環境

項目 バージョン
OS Ubuntu 18.04 (Virtualbox)
ボード Ultra96v2
Vivado 2020.1
Vitis 2020.1
Petalinux 2020.1 (2019.2)
Vitis AI 1.2

罠1: Bootgenでエラー発生

5-3-2 DPU動作環境の構築で、VitisプラットフォームにDPUを組み込むところがあるんですが、森北出版さんから提供されているVitisカスタムプラットフォームを使っても、Bootgenでエラーが発生して、bootimageが生成できませんでした。エラーメッセージを見た感じ、各ファイルの格納場所の指定を変更する必要がありそう・・・というのは分かるんですが、どこでそれを変更するのかが分からん、と。

[WARNING]: [fsbl_config] a53_x64 | a53_x32 | r5_single | r5_dual is no more supported. Use 'destination_cpu' attribute for bootloader partition
[ERROR]  : Cannot read file - /home/tanaka/work/HLS_for_SW/Appendix/petalinux/boot/pmufw.elf
ERROR: [v++ 82-1008] Cannot generate bootimage


おそらくVitisプラットフォームの何処かで指定しているんだろうと思いつつも、見当がつかないので、Appendixを見ながら、Vitisプラットフォームを一から作ってみることにしました。で、一から作ってみたところ、bifファイルで指定することを把握。下記のように自分の環境に合わせ変更して、再ビルドすることで、Bootgen成功。
linux.bif
the_ROM_image:
{
       [fsbl_config] a53_x64
       [bootloader] /home/madrid/ultra96v2_work/petalinux/boot/zynqmp_fsbl.elf
       [pmufw_image] /home/madrid/ultra96v2_work/petalinux/boot/pmufw.elf
       [destination_device=pl] <bitstream>
       [destination_cpu=a53-0, exception_level=el-3, trustzone] /home/madrid/ultra96v2_work/petalinux/boot/bl31.elf
       [destination_cpu=a53-0, exception_level=el-2] /home/madrid/ultra96v2_work/petalinux/boot/u-boot.elf
}

罠2: MNISTの学習でエラー発生

5-4-2 MNISTの学習で、Keras形式のMNIST学習モデルを生成するスクリプトを実施したところ、Illegal instruction(core dumped)エラーが発生しました。どうもTensorflowをimportするところでエラーが発生しているっぽいんだけど、ググってみたら、以下のような情報を発見。


確かに、うちのPCのCPU Core-i7 3770だから、、、ダメっぽいですね。というか、もうこんなんどうしようもないやん、、、はい、PCを新調して解決しました。

注: TensorFlow 1.6 以降、バイナリは AVX 命令を使用するので、古い CPU では動作しないことがあります。

罠3: Petalinuxのバージョン間違えた

実行環境のところに、2020.1 (2019.2)と書いたんですが、最初あまり考えず、元からインストールしてあった2019.2を使用していました。まあ、自分の思慮不足、不注意と言ってしまえば、それまでなんですが、ちょっとバージョンが違っただけでここまで挙動変わるのは・・・初心者には結構つらい。まさかPetalinuxのバージョンが問題になっているとは気づかず、様々なトラブルシューティングをする羽目に陥っていました。

ライブラリ入ってない問題

DPUのバイナリ作成も完了し、VARTのサンプルプログラムと合わせて、Ultra96v2ボードにコピーしてしてみたところ、複数のライブラリが入ってないというエラーが発生。下記は無理やり適当なバイナリをscpでもってきてrpmでインストールしてみたが、バージョンが古く動かなかった時のログ。

root@ultra96v2_base:~/MNIST# ./MNIST dpu_mnist_0.elf 
./MNIST: /usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.26' not found (required by /usr/lib/libxir.so.1)

dnf使えない問題

不足しているライブラリをインストールするために、dnfコマンドを使おうとしたが、リポジトリが登録されておらず使えない。どこのリポジトリをどうやって登録すればいいんだ??とハマったあげく、Xilinxから提供されている?リポジトリを登録したら、何とかライブラリをインストールできるように。

root@ultra96v2_base:/etc/yum.repos.d# dnf -v repolist
DNF version: 2.7.5
cachedir: /var/cache/dnf/aarch64/thud
petalinux_v2020.3-generic                                                      1.9 MB/s | 3.6 MB     00:01    
not found deltainfo for: petalinux_v2020.3-generic
not found updateinfo for: petalinux_v2020.3-generic
Xilinx-v2020.3: using metadata from Fri Apr  2 22:24:00 2021.
Last metadata expiration check: 0:00:05 ago on Fri Mar 18 16:58:24 2022.

Repo-id      : Xilinx-v2020.3
Repo-name    : petalinux_v2020.3-generic
Repo-revision: 1617402240
Repo-updated : Fri Apr  2 22:24:00 2021
Repo-pkgs    : 10215
Repo-size    : 3.7 G
Repo-baseurl : http://petalinux.xilinx.com/sswreleases/rel-v2020.3/generic/rpm/aarch64/
Repo-expire  : 172800 second(s) (last: Fri Mar 18 16:58:24 2022)
Repo-filename: /etc/yum.repos.d/CentOS-Base.repo
Total packages: 10215

DPUから応答がない問題

ようやくライブラリのインストールが終わって、VARTサンプルプログラムを実行したところ、execute_asyncした後、DPUから応答がない。エラーログでググっても、それらしい解決方法も見当たらないし、結構お手上げでした。ただ、この辺で、そもそもなんでライブラリのインストールが必要だったんだ?書籍ではそんな手順の記載はなかったし、どこかで何かの手順に問題があったんじゃ?と思い、改めて見直したところ、書籍ではpetalinux 2020.1を使用していることに気づく。もしかして、これが原因??と思い、petalinux 2020.1を入れて、改めてVitisプラットフォームの作成を行うことにしました。

root@ultra96v2_base:~/MNIST# ./MNIST dpu_mnist_0.elf 
WARNING: Logging before InitGoogleLogging() is written to STDERR
I0318 19:33:13.888545  2321 main.cc:195] create running for subgraph: mnist_0
out_dims : 1, 1, 1, 10
in_dims  : 1, 28, 28, 1
F0318 19:33:23.977075  2321 xrt_cu.cpp:165] Check failed: is_done cu timeout! core_idx 0  handle=0x55cd4e5760 ENV_PARAM(XLNX_DPU_TIMEOUT) 10000 state 1 ERT_CMD_STATE_COMPLETED 4 ms 10010  bo=4is_done 0 
*** Check failure stack trace: ***
Aborted
root@ultra96v2_base:~/MNIST#

罠4: U-Bootが正常に起動しない

petalinux 2020.1でVitisプラットフォームを再作成し、DPUを組み込むところまで終わって、ようやくUltra96v2に書き込んでみたところ、U-bootが正常に起動しませんでした。これだ!と考えた原因をつぶしこんでみたら、そもそもBootせず、状況がより悪化するという事態に、若干心が折れそうになったんですが・・・、全く同じ現象が発生し、解決方法まで書いてくれている方を発見(本当に助かりました)。
Bootパーティションに、boot.scrも追加でコピーしたら、正常に起動するようになりました。

  • BOOT.BIN
  • image.ub
  • dpu.xclbin
  • boot.scr <--これを追加

Release 2020.1   Mar 25 2022  -  16:03:34
NOTICE:  ATF running on XCZU3EG/silicon v4/RTL5.1 at 0xfffea000
NOTICE:  BL31: v2.2(release):xilinx_rebase_v2.2_2020.1
NOTICE:  BL31: Built : 15:43:28, Mar 25 2022


U-Boot 2020.01 (Mar 25 2022 - 15:59:59 +0000)

Model: Avnet Ultra96 Rev1
Board: Xilinx ZynqMP
DRAM:  2 GiB
PMUFW:  v1.1
EL Level:       EL2
Chip ID:        zu3eg
NAND:  0 MiB
MMC:   mmc@ff160000: 0, mmc@ff170000: 1
In:    serial@ff010000
Out:   serial@ff010000
Err:   serial@ff010000
Bootmode: SD_MODE
Reset reason:   EXTERNAL
Net:   No ethernet found.
Hit any key to stop autoboot:  0
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
## Executing script at 20000000
Wrong image format for "source" command
SCRIPT FAILED: continuing...
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
Card did not respond to voltage select!
Warning: SPI speed fallback to 100 kHz
unrecognized JEDEC id bytes: ff, ff, ff
Failed to initialize SPI flash at 0:0 (error -2)
SCRIPT FAILED: continuing...


no devices available
SCRIPT FAILED: continuing...
starting USB...
Bus dwc3@fe300000: Register 2000440 NbrPorts 2
Starting the controller
USB XHCI 1.00
scanning bus dwc3@fe300000 for devices... 4 USB Device(s) found
       scanning usb for storage devices... 0 Storage Device(s) found

Device 0: unknown device

Device 1: unknown device
scanning bus for devices...

Device 0: unknown device
No ethernet found.
missing environment variable: pxeuuid
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/00000000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/0000000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/000000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/00000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/0000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/00
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/0
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/default-arm-zynqmp-zynqmp
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/default-arm-zynqmp
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/default-arm
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/default
No ethernet found.
Config file not found
No ethernet found.
No ethernet found.

MNISTの実行

罠4の回避後、MNISTが動作することをようやく確認できました。MNISTのサンプルを試してみるだけで、2~3週間かかったので、うまく動いたときの感動は、Google colabでのMNISTとは雲泥の差ですよ、良い意味でも悪い意味でも。
次は、YOLOv3を試してみようと思いますが、また新たな罠にハマらないことを願うばかりです。

root@ultra96v2_v2020_1:~/MNIST# ./MNIST dpu_mnist_0.elf 
WARNING: Logging before InitGoogleLogging() is written to STDERR
I0325 16:33:50.311563   741 main.cc:203] create running for subgraph: mnist_0
out_dims : 1, 1, 1, 10
in_dims  : 1, 28, 28, 1
Image : one_9819.jpg, label = 1
Image : five_6491.jpg, label = 5
Image : eight_9150.jpg, label = 8
Image : nine_9386.jpg, label = 9
Image : six_8240.jpg, label = 6
Image : two_1256.jpg, label = 2
Image : three_9925.jpg, label = 3
Image : zero_9095.jpg, label = 0
Image : four_8500.jpg, label = 4
Image : seven_9262.jpg, label = 7
Elapsed Time per frame: 532[us]
root@ultra96v2_v2020_1:~/MNIST#