Ryuz's tech blog

FPGAなどの技術ブログ

LUT-NetworkによるFPGAでの手書き数字(MNIST)のセマンティックセグメンテーション再整理

はじめに

私のTwitter のトップにも置いているこの動画ですが、かなり昔 C++ ベースでハイパーパラメーターや構造を何度も変えてリコンパイルしながら少しづつ試行錯誤してネットを育てるという事をやってしまったので、容易に再現環境が作れずにおりました。

セマンティックセグメンテーション

BinaryBrain ver4で、Python対応もだいぶ進んで、(作者にとっては)多少いろんなネット構造がある程度柔軟に扱えるようにもなってきましたので次のステップに行く前に整理してみました。

とは言え学習時間が結構かかるのですよね。

アプローチ

通常であれば、セマンティックセグメンテーションと言えば、U-Net みたいな構造でつくるかと思います。

当サイトとしても最終的には、以前から構想だけは持っているCNNの1frame前をIIRフィルタ的に使う使い方で、U-Net 的な効果を出したいと考えてはいるのですが、なかなかそこまで難しい学習ができるプラットフォームも作れていないので、Pooling層を使わずに 3x3 畳み込み層を 29直列することで、「数字1個分ぐらいはスコープに入る画像フィルタを学習してしまおう」というアプローチになっています。結構力業です。

その際に、LUT回路を微分した DifferentiableLUT モデルを MobileNet 風に、Pointwise(LUT 2層)-Depthwise(LUT 1層)-Pointwise(LUT 2層) として効率化を図ります。そうすると29直列で、145層のLUT層ができるのですが、残念ながらこれの直接学習は深すぎてうまくいきませんでした。

そこで、BinaryDenseAffine 層を用いた29層を先に学習させておいて、それを補助層として使いながらLUT層を学習させていくというアプローチをとっています。

ネットワークの概要

ネットワークの構造としてはこんな感じです。

f:id:Ryuz88:20210710095420p:plain
ネットワーク構造

f:id:Ryuz88:20210710095508p:plain
ネットワーク構造の表

表の Dense (BinaryDenseAffine) の方は、FP32 のパラメータですので、結構な規模なのですが、LUTの方は純粋に 6入力1出力のLUT素子の個数でカウントしています。

学習の進め方

こんな感じで学習させています。

  1. まずDenseなネットワークを学習させる
  2. 1層だけLUTにしてそこだけ学習させる
  3. LUT化した層以降を再度追加学習させる
  4. 2に戻って次の層をLUT化する

という地道なことをやってます。とても長いです。

工夫の余地はいくらでも残っていそうですが、工夫して効果を確認しようとすると、その「とても長い」を何度も繰り返して比較することになるので挫折しています(笑)。

学習結果

まずこちらがDenseでの学習結果です。今回はデータにネガポジ反転も混ぜましたが、さすが全結合の畳み込みだけあって綺麗に数字の部分も出していますし、分類もそれなりに数字に応じた部分が発火するようになっているようです。

f:id:Ryuz88:20210710095924p:plain
Denseでの学習結果

次に、これをLUTに写し取った結果です。

f:id:Ryuz88:20210710100135p:plain
DifferentiableLUTに写し取った結果

さすがだいぶ劣化しちゃいました。 とは言え、当サイトではまだ、LUT-Network の有り余る処理帯域を使って時間方向の変調の手が残っていますので、もう少し引き上げができるかとは思います。

実際、デモの動画でも実は1枚1枚はそれほど精度高くないのですが、1000fps で動いている関係上、60fps の民生カメラで撮影すると16枚程度が1フレームに重ね合わされてしまい、結果的に綺麗に映っているかと思います。人間の眼も同じくで、残像効果がありますので、映像と変わらない見栄えが得られます。

Verilogでシミュレーションしてみた

Verilog化してシミュレーションしてみた結果です。ちなみにここでも Verilator 大活躍でした。コンパイルは長いのですが画像生成まで含めると xsim などと比べると圧倒的に速いです。

f:id:Ryuz88:20210710100802p:plain
Verilogシミュレーション結果

なお色の意味は電子工作をしている人なら脳内変換できる抵抗のカラーコードになっております。

FPGA 用に合成してみた

まだ動かすところまで行ってないのですが、ニューラルネットの部分だけUltra96V2(Xilinx XCZU3EG)用に合成してみました。

3x3の畳み込みの為のラインバッファや、結果クラスのデコードなどいくつか周辺回路を含んでいるので理論値より少し多いですが、この後カメラ制御や表示制御などの周辺回路を入れてもを辛うじて収まりそうな規模にはなってきました。

f:id:Ryuz88:20210710100949p:plain
合成結果

おわりに

今回のサンプルコードはまだdevelopブランチですがこちらに置いております。

もう少し、このままでも学習のさせ方で精度アップが狙えそうな気もしておりますが、早めに整理して次のステップに時間割いた方がよいような気もしています。