lp6m’s blog

いろいろかきます

第5回AIエッジコンテストに参加した感想

経産省主催の第5回AIエッジコンテストにチームVerticalBeachとして参加しました。開発したリポジトリの整理などは後ほど行う予定です。
参加した感想を忘れないうちに所感を残しておこうと思います。
詳細な技術情報は提出した以下のレポートに記載しています。
drive.google.com

コンテスト概要

  • 車載動画に対する人物・車のトラッキング処理
  • Ultra96v2またはRISCVボード上に実装
  • ラッキング処理の何らかの処理をRISCVコアを使用することが必須条件
  • 速度処理賞の入賞条件: 評価指標MOTA>0.6
  • イデア賞の入賞条件: 評価指標MOTA>0.3

終結

物体検出はそこそこできているが、物体追跡が甘い。MOTA=0.2807344
1フレームあたりの速度:52.30ms (18fps程度は出そう?)
上が物体検出結果、下が物体追跡結果です。
youtu.be

前回の第4回AIエッジコンテストでは、自分のチーム含め処理速度入賞者の全員がXilinx DPUを使っていて、ほとんどDPUコンテストと化していた。
それを受けてか今回はRISCVコアをFPGA上に実装することが必須条件であり、実装ハードルが高いことは最初からわかっていた。
コンテストの開催期間は4ヶ月で、RISCVの実装経験もなかったのでできるだけ既存の実装を使って、とにかく何が何でも提出する、ということを目標にした。

題材自体はHW実装なしの第3回AIエッジコンテストと同じで、第3回の入賞者レポートを見る限り、MOTA>0.6という精度指標をエッジデバイスでリアルタイム性能を出しながら満たすのは非常に厳しいと思った。
前回のコンテストでXilinx DPUとVitis-AIを使用した経験があったので、物体検出(DPU)+物体追跡(RISCV)の組み合わせで実装することにした。(DNNモデルを動かすためのRISCV追加命令の実装!とかは確実に間に合わなそうだったので)

10月・11月

DPUで動作する物体検出モデルを選定する必要があるが、tinyYOLOv3が動作することは知っていたので、精度が向上したtinyYOLOv4を使用してみることにした。
DarknetからCaffeに変換するスクリプトを修正することで、DPUにオフロードされるsubgraphが1個にできた。経験もあったので特に難しいことはなかった。
前回コンテストではAvnetが用意してくれたHW環境をそのまま使っていたので、HW側の設計はほとんどせず、ただDPUを触っていただけだった。
今回はDPUだけでなくRISCVを搭載する必要があったので、自分でHW環境をビルドする必要があった。前回何も理解していなかったVitisフローを勉強した。 DPUとvector addカーネルの両方を乗せることができた。
Ultra96v2のWIFIを動かすために無駄な時間を食ってしまったが、結局最終的なHW環境ではWIFIは使用せずにUSB-LANを使用することにした。
qiita.com

12月

11/30にコンテスト主催側からRISCVのリファレンス環境が公開された。VexRiscvというRISCV実装が使用されていた。公開されるまではRocketChipを使うかVexRISCVを使うか、あるいはRISC-VとChiselで学ぶ はじめてのCPU自作を使うか迷っていた。
RocketChipはFPGAでは動作周波数が低いことや、リファレンス環境を流用できることからVexRiscvを使用することにした。
GitHub - SpinalHDL/VexRiscv: A FPGA friendly 32 bit RISC-V CPU implementation
リファレンス環境はベアメタルでの動作確認のみだったので、Petalinuxから実行できるか実験した。
qiita.com

ただ、このリファレンス環境には問題があることがわかった。RISCVコアのリセットがGPIO経由で行われていたが、命令バス・データバスのリセットは別で接続されていたので、2回目のリセット以降正常に計算が行われないことがわかった。
RISCVコアのリセットをpl_resetn0に接続して、PS側から制御する方法を学んだ。
lp6m.hatenablog.com

次に、リファレンス実装のRISCVの命令セットはrv32imで、浮動小数点演算が行えないので困った。VexRiscvではプラグインを追加する形でFPUを載せられるので、追加した。
ただ、リファレンス実装ではRISCVコアの命令バス・データバスをAXIバスに接続するために独自モジュールを使っていて、FPUを乗せると命令バスとデータバスのポート数が変わるために独自モジュールが使えなくなり頭を抱えた。
よく見てみるとVexRiscv自体に命令バス・データバスをAXI化する機能があったのでこれを使うことで問題は解決した。(なぜリファレンス実装は独自モジュールを使っていたのか・・)
手順は今後公開する予定です。

年末年始にFPUが動いて嬉しかった。


1月

FPUを搭載したRISCV向けにクロスコンパイルする手法を調べた。cross-ngを使ってクロスコンパイルができることがわかった。RISCVとPSコア間のデータの入出力を実現するのに少しだけリンカスクリプトの勉強をした。
11月に勉強したVitisフローを使ってRISCVとDPUを両方搭載したHW環境を作ることができた。
チームメイトが物体追跡アルゴリズムの勉強・実装調査をしてくれていたので物体追跡はByteTrackを使用することにした。
ByteTrackはReIDモデルを使用しない単純なアルゴリズムにもかかわらずSOTAを実現しているので、何もわかっていないけど期待感だけあった。
GitHub - ifzhang/ByteTrack: ByteTrack: Multi-Object Tracking by Associating Every Detection Box
ByteTrackをそのまま適用したが、MOTAスコアは0.17程度で0.60には遥か遠く希望を失った。
今回物体追跡アルゴリズムについては自分は担当していないので詳しいことはわかっていないが、コンテストのテスト動画のフレームレートが5fpsで、1フレームごとにバウンディングボックスの移動量が非常に大きいのでカルマンフィルタによるバウンディングボックスの位置推定が非常に厳しいようだった。
DPUでの物体検出結果をチームメイトに渡して、チームメイトにはそれをもとにByteTrackの改善をしてもらっていた。チームメイトが開発してくれていたC++製のByteTrackがUltra96のARMコア上で動作することを確認した。
Ultra96のPetalinuxでインストールされていたOpenCVがmp4を開けなかったり(aviに変換して解決)、cv::VideoCaptureがメモリリークを起こしたりしていて(1動画ずつ処理して回避)、厳しかった。

2月

2月に入ってもまだRISCVコアで何を動作させるか決まっていなかった。ByteTrackで使用されているハンガリアン法のアルゴリズムが簡単にRISCV向けにクロスコンパイルできそうということで、これをRISCVで動作させることにした。クロスコンパイルするとRISCVのデータメモリが当初の大きさだと足りないことがわかって、Vitisフローを1からやり直してデータメモリを大きくした。厳しかった。
すべてARMコアで動作させていたByteTrackのソースを改変してDPUとRISCVを使用するようにした。
物体検出と物体追跡処理のマルチスレッド化を実装して、
チームメイトはギリギリまでByteTrackの改善をしてくれて、最終的に評価値は0.2807344まで改善した!感謝。
レポートを書いたり実機評価をして、提出締め切りギリギリに提出した。


提出者が少なかったせいか提出期限が伸びたので、YOLOv4tinyの入力画像サイズを大きくするなどしたが、MOTAが改善することはなかった。

とりあえず提出するという当初の目標は達成できたが、ほとんどVitisフローとVexRiscvの実装方法の勉強に費やしてしまっていた。前回のコンテストもVitis-AIについて学んでいただけだった・・
RISCVの実装・命令の拡張にチャレンジするという余裕は全くなかった・・
上には厳しい気持ちになったとたくさん書いたが、こういった実装コンテストのおかげで色々学べるのはやっぱり楽しかった。
HLSでDNNモデルをHW実装するコンテストがあれば、(少なくとも自分は)VivadoやVitisの使い方を学ぶ時間は少なくてすむので、HW実装に注力できて面白そうだと思った。