カテゴリー「FPGA」の78件の記事

2020年3月 9日 (月)

LUT-Networkの蒸留とMobileNet風構成とセマンティックセグメンテーション

はじめに

従来のパーセプトロンモデルを使った学習ではなく、回路そのものを微分してFPGAを直接学習してしまおうという当サイトオリジナルのディープラーニングLUT-Networkですが、ここのところ深いネットを学習させるために蒸留(Knowledge Distillation)に取り組んでいました。

その一つの成果として、MNISTデータを使ったセマンティックセグメンテーション(もどき)を試してみたのでブログに記録しておきます。

 

まずは先に結果

まず先に最新の結果を記載いたします。MNISTベースの画像を入力して、それぞれの数字領域を色塗りするセマンティックセグメンテーション(もどき)を学習させてみました。

入力画像
Mnist_test_640x480

 

出力画像

上記の入力画像をもとに Verilog のRTLシミュレーションで得た結果画像が以下です。
Result

 

FPGAリソース

下記が実際にRTLを合成した場合のリソース量です。DNN部のみですが、畳み込みの為のラインバッファなどの制御回路のLUTも含んでいます。

Resource

以上のように、ZYBO Z7-20 のリソースを半分も使うことなく、また外部メモリを使うこともなく、上に記載のリソースのみでスループット1のDNN回路が出来上がりました。MobileNet風の接続の導入で配線がスリムになったことで合成時のルーティングなどでの問題もまったく発生していません。
一応、学習済みのソースをここに置いておきます。

ダウンロード - mnist_seg.zip

 

本回路はビデオ伝送路にラインバッファ分の遅延のみで、ビデオ信号の経路にフィルタとして挿入可能です。またLUT-NetはLUT1段で1層ですので非常に高クロックで合成可能で、例えば300MHz程度で合成も可能です。ピクセルクロック300MHzといえば4k画像30fpsに相当しますといえば想像しやすいのではないかと思います。

細かい部分はまだいろいろチューニング余地がありますが、まずはフレーム単位でメモリに溜めないと演算できないGPUに対してリソース量もリアルタイム性も非常に高いFPGAでのAIの可能性が少しだけ広がったのではないかと思います。

 

ネットワーク構成

ちなみにFPGAリソースこそ少ないですが、depthwise CNV と pointwise CNV で合わせて57層という結構深いネットになっています。
一応、出力させたネット構造のみテキストファイルで置いておきます。

ベースモデル:ダウンロード - training_model.txt
蒸留後のモデル:ダウンロード - lutnet_model.txt

 

MobileNet風の構成と蒸留(Distillation)の小規模実験

今回の進展にあたり、大きな変化となったのが MobileNet v1 風の考え方の取り込みと、蒸留(Distillation)という考え方です。
まず、セマンティックセグメンテーション風の色塗りをやる前に行った、普通のMNITのクラス分類で適用したネットワークの構成が以下です。

Mnist99_net

MobileNet v1 を参考に depthwise/pointwiseの畳み込み層を準備しています。その際にLUT-Net特有の改善としてdepthwise層の出力チャネルを入力チャネルより多くし、同じチャネルを処理するノードを複数割り当てています(今回は各4個づつ)。
全結線のノードと違い、深さ方向に各1個だと1チャネルの属性を十分捉えらてないため、異なる成分をとらえることが可能になるように多様性を持たせています。なお、多様化した結果、結局使われなかったノードは後の蒸留時に消滅しますのでここは安心して増やすことが可能です。

ちなみにこのMobileNet風の構成は蒸留することなくランダム結線のままでも比較的効率よく学習してくれる模様で、以下がその学習時のログです。

Mobile_lut_net_train_graph

63epoch目で 99.08% の認識率まで確認しています。
特徴的なのが、train と test でほとんど挙動に差がなく、LUT-Net の汎化性能に関してはパーセプトロン型のDNN同等以上の可能性も感じています。

 

蒸留の効果確認

ちなみに先の例では蒸留の有無にかかわらず99%超えてしまい、効果がよくわからないのでもう少し回路を小さくして実験しました。
その際の回路構成が下記です。
Mobile_lut_net_little

LUT 3k個程度の小さな回路ですが、飽和するまで回したところ

蒸留した場合:98.42%
ランダム結線:97.06%

となり、蒸留によって結線の最適化をした方で若干の改善が見られました。

 

まとめ

LUT-Netの開発もしばらく停滞していた感もありましたが、MobileNet構成の実験と、蒸留の可能性が見えてきたことで適用可能性が一気に増えてきたように思います。
特に全結線層を使えばバイナリネットであっても、比較的深い層も通常のDNN同様に学習できることが見え初めてきましたのでそこからLUT-Netに持ち込めるというのは大きな成果に思います。
またその際もすべて全結線層にするのではなく、depthwise層は初めからLUT-Netにしていますので比較的相性良く組み合わせる手が見えてきたと思っております。

引き続き、もっといろいろな応用ができればと思う次第です。
今回のセグメンテーションは、Pooling層無しで行っており、すべてのノードが100%演算している反面、フィルタの段数分(ラインバッファの範囲)でしか判別ができません。よって小さな範囲を見て判定できるアプリにしか使えませんが、それでも小さい範囲で認識が完結する欠陥検知や異物検知系の見分け補助とか、線画やモノクロ写真の色付けとか、がリアルタイムでできないものか、とか、いろいろとワクワクする応用例は思いつくわけです(実用になるかは別として)。

広い領域を見るにはU-Net的なことをする必要が出てきますが、その場合は一度中間結果をメモリに入れないといけないのと、PoolingするとLUT-Netの場合演算器の利用効率が下がるので、やるなら並列して1frame前の画像を通常型の演算器でやって、最新フレームの入力に追加チャネルとして入れるのがいいのかなと思っていたりもします。まだまだ先が長いですのでのんびり取り組んで行ければと思います。

 

 


追記(2020/03/13)

セマンティックセグメンテーションについて動画を作りましたので置いておきます。
全体の合成でも配線混雑やタイミング収束などで苦しむことは全くなく、あっさり合成出来きました。MobileNetの効果は大きいです。
1msの遅延で1000fpsがAI処理付きでカメラからOLEDに通り抜けており、OLEDが画面がまるでガラスのように向こう側が遅延なくAI重畳されて映し出されています。
AI眼鏡の可能性の提示と、電脳コイルの世界への入り口となること祈りつつ。

 

 

2019年12月29日 (日)

LUT-Networkの蒸留(Distillation)について

今日は、Networkの蒸留(Distillation)について考察してみたいと思います。

LUT-Networkに限らないのですが、その課題に学習時のGPUのメモリの不足と、学習時間の問題があります。


例えばMobileNetという軽量なネットワークがあります。これは畳み込み層をpointwiseとdepthwiseに分けて行うことで係数の数を大幅に削減しています。
軽量にすると学習時も計算量も減るように思ってしまいますが、実際には処理を分割したことで層が増えてしまい、逆にGPUの消費メモリが増え、学習時のメモリへの読み書きも増えてしまいます。

この延長で、超SparseであるLUT-Netは大規模な学習が非常に困難です。そこで、大規模な学習がしやすいネットワークで学習してから、メモリに収まる範囲で少しづつLUT-Networkに写し取っていくというというアイデアを考えています。
これを蒸留(Distillation)と呼ぶそうです。

現在、取り組もうとしている流れが以下の図です。

 

Distillation

 

まず、一般的な畳み込み(Convotution)ネットワークの畳み込み層をバイナリ化する場合、ReLUなどのActivation層を2値化を行うBinary-Activation層に置き換えることになります。この時、2値化の手前で BatchNormalizationを行うのが効果的です。

BatchNormalizationは通常 Inferrence時には単なるスケーリングのみとなります。スケーリングのみであるため、2値化と組み合わせる場合、2値化の閾値自体をずらしてやればスケーリングも不要となります。

しかしながら、ここで前提として計算の中間結果が非バイナリであることが求められます。GPUを用いる場合、GPU内の内部演算が一時的に多ビットになることは特にデメリットはありません。しかしながらFPGA化する場合、そのままリソース規模に効いてくるのでこれは致命的です。
また、画素サイズ分のスケーリング係数が発生するので規模の点でも非常に厳しくなります。

そこで、LUT-Networkでは、当初より BatchNormalizationとBinary-Activationを畳み込み処理に取り込んでいます。これは工夫したというより、こうするしかLUT-Net は成立しないので、特に気にすることなく当初からこうしていたわけですが、LUT-Netの特徴の一つでもあります。
一般的な畳み込み(Convotution)は、効率化のためにGPUなどで一括で計算されますが、処理量やメモリを増やして良ければ、Loweringを行い、im2col と col2im の処理に挟まれる形でDenseAffine計算に分解することができます。

Loweringを行うと、学習時のメモリ消費や計算時間は増えますが、畳み込みの中にDenseAffine以外の処理が入れ込めます。

今回考えているのは、従来のネットワークに、LUT-Networkで行っているこれらの仕組みのみを適用して学習させ、学習後に蒸留して取り込もうというアイデアです。

蒸留は、今のところ

  • 元のDenseAffineの重み順で結線すると効果的
  • 元のDenseAffineの結線数が少ないと模倣しやすい(おそらくMobileNetは効果的)

などが、見えており、もうひと頑張りといったところです。

なお、今回は蒸留を目的に従来のネットワークを変形して学習させようとしていますが、おそらくこの変形は蒸留することなくそのままFPGAにしても効果的ではないかと考えています。

 

DenseAffine + BatchNormalization + Binary-Activation はInferrence時に XNOR-Net のような構造にできるので、そのままHLSなどで合成すれば効果的にFPGA化できる可能性があります。

 

先日の記事で、他のバイナリネットワークに対するLUT-Networkのリソース規模の大雑把な比較を行っていますが、その際に前提としてLUT-Networkに対して行っている上記のような技法を適用しているのを前提としていた部分がありました。

またXNOR-Netについてはかなり概算が入っていたので、実際にいくつか合成実験も行ってみました。
私自身XNOR-Netは試したことがないので理解不十分かもしれませんが、理解の範囲で実験しています。


Xnornet_20191229212001

思っていたよりXNORネットはFPGA化において高効率に思います。

一方で全結線という点ではNに対してO(N log N)で規模増大する可能性を有しているのと、従来のパーセプトロンモデル以上のことはできない(単段ではXORが解けない)など、LUT-Netに比べて非効率な部分はあるかと思いますが、如何せん、PyTorchなどの既存のプラットフォームで学習できる可能性がある点で、手が付けやすいのは事実かと思います。

LUT-Net が一般的なネットと遠いので、なかなか蒸留できる接点を作っていくのが難しいのですが、FPGA化時の高効率化のためのポイントを押さえていけば、その中間的なところも組み立てていけそうな気もしますし、それ自体もいろいろと面白い検討ができそうな気がしています。

2019年12月15日 (日)

FPGAでのDNN(Deep Neural Network)の整理(LUT-Netまとめ)

はじめに

 現在DNN(Deep Neural Network)の実装において、FPGAの活用はしばし議論の対象になっています。もちろんDNN分野全体からするとニッチな部類に入るとは考えますが、FPGAベンダーはここに非常に力を入れており、作成したネットワークのデプロイ先としてFPGAが選択しやすくなるような各種のソリューションが用意され始めており、日々進化しています。
 ここでのFPGAのメリットは、低消費電力であったり、コストであったりします。DNNの実行にはクラウドであっても電力というランニングコストは馬鹿になりませんし、エッジコンピューティング、特にバッテリー駆動のモバイル分野においては電力は極めて重要です。またイニシャルコストの重要性はどちらも同じでしょう。

 ここでFPGAベンダーはこぞって、「GPUと同じように開発できます」をキャッチフレーズに、GPUを使って研究開発をしている多くのAI技術者を取り込むソリューションの開発に力を入れています。学習(Training)自体はまだまだGPUの力を借りることが必須ですので、仕上がったネットワークを推論(Inference)専用に最適化してデプロイするときにGPUと同じように扱えるメリットは非常に大きいのです。

 一方で、これではFPGAにGPUと同じ計算を少し効率的にやらせているに過ぎないことになります。FPGAの面白さは「GPUと同じことが効率よくできる」だけではなく、「FPGAでないとできない」ことができることにあると私は考えます。
 ここ1年程、そのような観点でFPGAでのDNNに取り組んできましたので、ここで少し整理しておきたいと思います。


DNNをFPGAに実装する2つのアプローチ

 下記は、私の考えるDNNをFPGAに実装する際の2つのアプローチのイメージ図です。
 「GPUと同じように使う」のが右側、当サイトの主張する「FPGAらしく使う」のが左側です。
 ネットワークの探索や試行錯誤、学習自体はGPU上で行い、それをFPGAにインプリメントするという流れは同じです。
 ただし、おそらく左のアプローチは学習フェーズで右側以上にFPGAを意識しておく必要があり、より高い次元でのシステム最適化スキルが必要となります。開発も辛うじてHSLが使える程度で、本格的にやるとRTLがまだまだ必要な領域になります。

Dnnfpga

 

GPUのように使うという事

 先に図の右側のソフトウェア的なアプローチ、すなわち「GPU的に使う」場合のアプローチについて述べます。

 この場合、まずソフトウェアでのネットワーク記述ありきの状態で、これをFPGAを使ってどうアクセラレートするかという話になります。
 ですので使い方としてとてもGPUと似てきます。
 しかしながらGPUが汎用計算機であり、INT1からFP64まですべてに対応したエンジンが固定数だけ搭載されているのに対して、FPGAでは本当に必要な演算のみを必要な個数だけ構成することができます。特にINT8以下の領域などを狙った実装などではGPUに対して優位性が出しやすくなってきます。

 その一方で、システムのデータフロー自体はソフトウェア的であり、電力やコスト以外でFPGAならではの効果を付与するのは難しくなってきます。

 

FPGAらしさを活かす試み

 次に先の図の左側のハードウェア的なアプローチ、すなわちFPGAをFPGAらしく、得られたネットワークを計算する専用の回路、すなわちネットワーク構造そのものを計算構造としてインプリメントしてしまおうという試みについてです。

 こうなると既存のソフトウェアのデータフローはいったん置いておいて、「ニューラルネットワークを計算する計算機アーキテクチャをゼロベースで新規に考える」というところが出発点になりますので、大変な反面、とてもたくさん新しいことに取り組む余地が生まれてくると考えています。

 最大の利点は、低遅延やリアルタイム性だと考えます。入力に対して「計算」以上のことは何も行わずに出力に直結可能ですので、理屈上最短の遅延で結果を出力することができますし、計算以外ではメモリ転送用の回路などのリソースも不要になります。一方で、メモリを介さないため演算器は常にカメラやLCDなど外部機器と同期して計算できることも求められます。
 メモリと異なり、計算が追い付かない場合にカメラに対してready信号を下げて「ちょっと待ってくれ」といってもカメラは待ってくれません。このような計算機の外にあるデバイスとの連携しながら計算することこそがエッジコンピューティングの醍醐味であり、FPGAの得意とする領域と考えます。実際にFPGAが得意とする画像処理の中にはこのような仕組みの中で実装されているものも多数あります。今後ロボティクスなどとの融合でも一層重要になると考えます。その枠組みにそのままDNNを入れてしまうというのは「FPGAらしさ」を活かすための第一歩の取り組みかと考えています。

 

 

FPGAらしさを活かす為のテクニック

 ここでFPGAらしさを活かすのに有効な取り組みを考えてみたいと思います。これらは現在取り組み中のBinaryBrainにて順次実験中の内容です。

 FPGAに搭載されているリソースの量は決まっており、上げられる周波数もあらかじめ決まっていますので、時間当たりに割り当てできる回路リソースの上限はどのような手法をとっても大きくは変わりません。そうした「FPGAらしい使い方」を目指す中で、スループットを1サイクル1データを維持したいといったエッジコンピューティングならではの要件も出てきます。
 そこで、DMAなどの演算に使わない回路リソースを減らしたり、FPGAのリソースを有効利用できる演算方式を使った学習を行ったり、演算器を休まず稼働させるアーキテクチャを考えたりして、更なる付加価値性能を引き出すテクニックを考えていくことになります。

 

量子化(Quantization)

 量子化はあらゆる場面で役立ちます。単純に演算bit数が半分になれば回路規模は半分になりますので量子化の効果は大きいです。この方法をデータが1bitになるまで適用したものがバイナリネットワークとなります。そしてネットワークのバイナリ化はFPGAの性能を引き出すうえでは最もパワフルな手法の一つであります。
 DNNで最も演算量が多いのは乗算となりますが、重み(Weight)と活性化(Activation)のどちらか一方をバイナリ化すれば乗算が加算に置き換わり、両方をバイナリ化するとXNOR演算に置き換わります。

 しかしここで注意点があります。FPGAの場合、乗算は乗算器マクロを使うのに対して、加算やXNORは通常LUTを使うのでリソースバランス的に必ずしもメリットがないケースもあります。ハードウェアマクロとして持つ乗算機は数は変わらないので使わないともったいないという話にもなります。
 また、XNOR-Netなど乗算部をXNORに置き換えたものであっても、そのあとの加算(bitカウンティング)は複数bitで行う必要があるという点があります。例えば256個の接続がある場合、Binary Activation を行うまでの加算は最終的に8bitの出力が求められます。ソフトウェア的には積和演算のループでよいのですが、計算構造として空間展開すると特に加算部分がやや大きな加算器ツリーを構成することになってくるのでここは注意点です。

Sparse化/枝刈り(Pruning)

 私は、ニューラルネットワークのSparse化がGPUに比べてFPGAに特に効果が高い手法ではないかなと考えております。N個の入力にM個の出力を行う全線接続層(fully connected layer)を考えた場合、N×M の積和演算が発生し、バイナリ化しても内部では log2(N)のbit数の計算が求められます。
 したがって、接続数Nを減少させることができれば計算量は減少します。もともとDropoutなどの技法が通用する背景には学習させるときに必要な自由度確保のための接続数と、最後に本当に必要な接続数の乖離にあると思われますので、学習後に枝刈りが成立するのはある程度自然なことなのかと思います。
 接続数を抑えるという観点で MobileNet などのアプローチも有効である可能性は高いと思われます。

 しかしながら、ソフトウェア的アプローチを行う場合、しばしば「行列乗算のアクセラレータを作ってこれを共有演算器として使う」という事が行われます。その場合演算の対象が枝刈りなどで疎行列(Sparse Matrix)になったからと言って特別な仕組みを入れない限り「係数を0にしてそのまま計算した方が速い」ということになります。
 この点についてネットワーク構造をそのまま回路構造に反映させる手法においては、コストゼロでSparse化の恩恵に預かることができます。

 また、枝刈りとは異なるアプローチで、初めからSparse化して学習させるという点でFPFAでのSparse化の究極形が当サイトの主張するLUT-Networkだと考えております。LUT-Networkでは接続数を4や6などに固定して学習させることでFPGAのLUT構造そのものに学習結果を対応付けさせるので高効率にインプリメントが可能です(究極的には2に固定してゲートレベルの回路を学習で生成する可能性も秘めています)。

 

パーセプトロンよりFPGAに適したモデルの適用

 これもLUT-Network で主張するところであり、LUTで計算可能な範囲を効率するモデルとしてStochastic-LUTという構造を提案しています。パーセプトロンのモデルが複数層無いとXORが解けないのは有名な話ですがLUTは1層でXORが解けます。ですのでLUTの表現能力を活かせる学習の為にはパーセプトロンのモデルでは不足するわけです。
 Stochastic-LUTでは、各入力を0/1ではなく「1である確率」として扱い、LUTの値も「テーブルに1が格納されている確率」とし、「出力が1になる確率」を求める演算となります。一定条件下でこの演算はStochastic演算としてそのままバイナリ回路を学習できますし、そうでない場合でも演算モデル自体がLUTを汎用に学習させるのに使えることが見えてきました。
 このようにStochastic演算を考えていた時に見つけた計算モデルですが、計算式としては N次元の線形補間であり、バイリニア→トリリニア→ を4次や6次に拡張したモデルと等価です。
 多次元を絵にするのは難しいので簡単のために2入力LUTとして、XORを学習した場合を図にすると以下のようになります。
Stochastic_lut_xor
 ルックアップテーブル値で保持する内部の状態はXORも表現可能であり、これはそのまま誤差逆伝搬により学習され様々な形に変形可能です。

 つまるところDNNは、なにも積和演算器を中心としたCPU/GPUに合わせて学習する必然性はなく、微分可能な演算式であれば様々なモデルが学習可能です。FPGAなどを考える場合、先入観にとらわれずに、そのアーキテクチャゲートレベルで見たもっとも演算効率の良いモデルで学習するということは十分成り立つ話なのです。このような考え方は、そのデバイスのリソースの有効利用をして性能向上を図るうえで十分に効果的だと考えています。

オーバーサンプリングによるバイナリ変調(Oversampling Binary Modulation)

 当サイトの主張する第二の技術としてバイナリ変調に触れておきます。バイナリ化は回路削減に大きな効果がありますが、認識精度を低下させる要因でもあります。
 XNOR-Netなど、初段のいくつかの層は多値で扱うというアプローチも多いようですが、当サイトではフルバイナリに挑戦しています。

 一般に、回路効率を上げる方法として「係数を変えて回路を再利用する」というのがよくあるソフトウェア的なアプローチです。汎用的な行列演算エンジンを作っておいて、そこに次々と新しい係数+データのセットを投入することで1つの演算器を何度も再利用し、計算効率を上げます。
 ここでハードウェア的なアプローチとして「係数を変えずに回路を再利用する」というテクニックでアプローチしているのがバイナリ変調です。回路は同一のバイナリネットワークのまま、そこに投入するデータの方をオーバーサンプリングして複数の認識結果を得て再統合することで認識率を上げます。リアルタイムでのデータ水増し(Dynamic data augmentation)ともいえるかと思います。
 このテクニックはリアルタイム性の増加ともとても相性が良く、bit数を増やすという空間方向の演算拡張に対して、時間軸にデータを拡張しています。

 CNNが空間方向の係数の再利用であれば、この方法は時間方向の係数の再利用と言えるかと思います。

 

蒸留(Knowledge Distillation)

 これはまだまだこれからの取り組みなのですが、蒸留の技術は非常に重要だと考えます。というのもバイナリネットワークは深いネットワークを学習するのがまだまだ難しいからです。これはネットワークの構造的な問題と、学習時の演算リソースの両方の問題があります。
 そういった中で、一旦、従来型の方式で学習した結果を参考にFPGA向きの回路に結果を反映させていくという手法は今後重要になると考えます。

 蒸留については現在、全線接続されたバイナリネットで学習して、全線接続層を複数のSparse層に蒸留して写し取る実験を行っているところです。成果が出ればまたブログに書きたいと思います。

(2020/03/11追記:ある程度蒸留が効果を出し始めました

ストキャスティック演算(Stochastic Operation)

 量子化されたネットに、バイナリ変調のような時間軸拡張されたデータを扱う場合、これはとても面白い考え方だと思っております。
 実際量子化されたデータを確率的に扱うと、確率共鳴のように本来切り捨てられたはずの量子化単位以下の情報が浮かび上がってきます。これらに対する演算を確率値を確率値のまま扱うことができれば幅が広がりそうです。バイナリに関する扱いであれば、ストキャスティック演算は実装上は乗算機が単なるANDゲートになるなど非常に効率的です。
 実際、MNISTの学習ぐらいならそこそこまでうまくいくようです。まだまだ課題が多いのですが、リアルタイムイな処理系の中に信号処理として入れ込む場合、連続時間の中で様々な角度で信号を見ていくことができる例だと思っています。

 

おわりに

 今回、少しFPGAで行うDNN全般の視点からLUT-Netの位置づけを見直してみました。
 こうしてみると、LUT-Netに限定する必要なく、FPGAでDNNをやる場合に重要になる技術がある程度整理して見えてきますし、FPGAでDNNをやる新しいメリットを探索する場合の手掛かりになる部分も見えてくるのではないかと思います。

 「FPGAでDNNをやろう!」といったときに、「VitisやSDxでDNNをFPGA化して終わり」ではなく、もっともっとFPGAらしい面白い使い方を探索してみる余地があるのではないかと思っております。
 AIの時代もFPGAが活躍して、くれると嬉しいなと思います。計算機アーキテクチャを考えるということは引き続きとても楽しいことであってほしいと思います。

 LUT-Netの方も、まだまだ取り組み途中で、やることはたくさん残っていますが、引き続き、無理のない範囲で楽しくやっていきたいと思います。引き続きよろしくお願いいたします。

 

2019年12月 8日 (日)

LUT-NetのFPGAリソースについて

久しく作業が止まっていましたが、今日はLUT-Netと従来のネットワークとのFPGA化したときのリソース規模の違いを俯瞰しておきたいと思います。

あらかじめ断っておきますが、ここで行う比較は認識率が異なるので公平な比較ではありません。通常のNN(Neural Network)は、まずやりたいことができる認識率を確保して、その後に、「それをいかにして速く小さくインプリメントするか?」が命題となります。

一方で、LUT-Net は初めからFPGA内で使えるリソースとハードリアルタイムな時間要件を先に決めてから、「そのリソース範囲でどこまで認識率が上がるか?」というアプローチをとっています。したがってそもそも土台が違うので一概に比較できません。

しかしながら、LUT-Net がどういうオーダーでリソース追求型のネットワークであるかの規模間を可視化するうえで役立つと考えますので、このような比較を載せておきます。

まず、先にLUT-Netでの畳み込みによる32x32サイズの画像分類に用いているネットワークの概算が下記です。

Lutnet

トータルとして、LUT数 153k, BRAM21個 のみですので、既存のFPGAに入れ込むことが可能です。
特徴として、スループットが1であり、1cycle毎に1認識の結果を出力可能です。つまり画像処理において、FPGAの動作周波数=カメラピクセルクロックとすれば、リアルタイムにすべての画素一の認識が完了します。VGA程度であれば1000fps(1kHz)動作も可能であり、認識処理のリアルタイム活用が可能です。

 

次に、この1cycle毎に1認識の性能を、通常の INT8 の CNN などで、同じ構造のネットワークを組んだらどうなるかの試算です。


Cnn

基本的にConv(畳み込み)もFC(全結合層)も、行列演算ですので、N×M個の乗算機が必要になります。そしてそれらを積算するのに接続数に比例する加算器が必要となります。ですので、計算上は、現存するどんなFPGAにも入りきれない、超巨大なリソース規模になります。

 

 

次にXNOR-Netの場合です。XNOR-Netは接続も重みもバイナリなので、リソースを大きく削減してくれます。

Xnornet

しかしながら、基本的に 乗算機がXOR演算となり、各種演算が INT8 から 1bit 化しただけなので、オーダー的には各演算が 1/8 になった程度の効果しか得られません。

 

もちろんスループット1なんて考えなければこんなことにはならないわけですが、それでもFPGAを使うメリットとしてはこの領域が必要な信号処理は多いわけで、そういったケースにAI的な適用ができれば非常に面白いのではないかと思う次第です。

 

2019年9月 2日 (月)

MNIST認識のリアルタイム動作環境更新

先日MNIST環境強化したのですがTwitterに書き込んでそのままだったので今更ながら更新しておきます。

今回は

  • Data Augmentation により、若干のスケール/回転/併進/ネガポジ耐性を付与
  • 数字部分かを判定する2クラス分類器を追加し、判定できない箇所の判定を抑制
  • LPF(ローパスフィルタ)として、1-TAPのIIRを追加(exponential smoothingが可能)

の3点が変更点となります。

 

Mnist_ar

 

これがシミュレーションの結果です。上半分が入力データで、下半分が検出結果を重畳したものです。

色は抵抗のカラーコードでして

黒:0 茶:1 赤:2 橙:3 黄:4 緑:5 青:6 紫:7 灰:8 白:9 となっています。

Sim_result

 

合成後の回路規模です。システム全体の規模となります。

Fpga_result

こんな感じでモノクロ反転した文字も認識しています。

おかげで、手で書いた文字もまあまあ行けました。

 Photo_20190902215501

 

ローパスフィルタは下の図のような感じです。入力と出力の間には遅延素子はなく、あくまで過去のデータも加えて結果を作るというだけで、本質的な点でリアルタイムが可能なデータパスであることが重要です。

なお、1000fps駆動なのでフレーム間の連続性も高く、過去の結果も活用することで認識精度の向上が可能です。

ただし画像の場合は音声などの1次元のデータと異なり、1タップのフィルタを組むのに画像1フレーム分のメモリが必要なところが課題です。

Iir

で、シミュレーションだと、数%程度認識率が上がるのですが、90%越えたあたりで数%変わっても見た目は良くわからないですね。

Lpf

この実物が見たい方は是非ICCE BERLIN 2019にお越しください(私は行けませんが)。

 

なお、現在はさらにDVI出力も付与しております。

Dsc_1204

 

余談ですが、認識結果ではなく画像の方にLPFを掛けると1000fpsの画像を60fpsのモニタに出すときに美しく出来ます。

OLEDなどの1000fpsの表示装置だと人間の目がLPFの役目を果たしてくれるのですが、LCDモニタの場合、そのまま間引いて表示すると露光時間不足でザラザラになってしまうので。

Lpf_dvi

ただしこれもメモリを消費するので、使い方は限定的ですね。

 

ちなみに今、これらの学習を行う BinaryBrain の Python 対応を developブランチで進めております。

まだまだ掛かりそうですが、頑張ります。

 

<追記 2019/09/06>

そういえば最新のリソース状況とかUPできていなかったので追加しておきます。

あくまで合成まで確認できているネットの中での認識率です。ソフトのみの実験とかだともう少しいけてます。

Lutnetwork_resource

2019年4月 9日 (火)

LUT-Networkの最新資料更新

FPGAXでお話のお時間を頂いて資料を作ってからある程度開発が進展してきました。

Twitter上中心に、多くの方からご支援いただけたことをまことに感謝しております。
特に marsee101さんには、FPGAの部屋にてBinaryBrainの記事を記載いただきました。この場をお借りして厚く御礼申し上げます。

さて、肝心の BinaryBrain Version3 ですがGPGPU(CUDA)に対応したことで計算速度が増加したのもありますが、前回書いた確率的LUTが極めて効率的に動き始めたというのが、もっとも大きな成果かと思います。

このようなオリジナルの素子の実験がやりやすくなったこともVer3の改善点です。

更新版の資料を

https://www.slideshare.net/ryuz88/lutnetwork-revision2

にアップロードいたしました。

また、今回はTOEIC300点台の私が、無謀にもgoogle翻訳頼みで英語版を作成するという暴挙にも出ております。(^^;

今回の更新は、アルゴリズムレベルというか、ニューロン(パーセプトロン)のモデル自体を生物の脳の模倣から電脳(電子計算機)の模倣にシフトしたという点で、ディープラーニングのあり方にもっと根本的な議論を投げかけることが出来たのでは無いかと思っています。

これが凄いことなのかどうかは私もAI分野の知識が浅いので測りかねていますので、有識者のご意見をお待ちする次第です。

いずれにせよ、LUTを使ったリアルタイム機械学習認識が高速高精度に行える道がだいぶ開けてきたのはそのとおりなので、新しい計算機の応用の道が増えれば嬉しくは思います。

LUT-NetworkはもちろんFPGA用なのですが、例えば6入力LUTの64bitテーブルは64bitCPU(ARMとか)のint型にパッキングできますし、4入力(16bit)なら16bitCPUでも1命令でテーブル引きできます。
ARMのNEONなどでさらに並列化も出来るかもしれず、組み込みAI分野にもっと手広く応用できる可能性も感じております。

これらは、TensorFlowなどの既存のDLのプラットフォームを使って、その範囲で試行錯誤していたのではたどり着けなかった成果かとは思っているので、最終形が仮にTensorFlowで実現可能であったとしても、BinaryBrain作ってよかったなと思っている次第です。

まだまだ、実用的なネットのインプリが出来ていないという点で先は長いですし、価値のあるものになるかは未知数なのですが、ちょっとした思い付きからここまで来れたのは本当に多くの方に支えられてのことだなと思います。

引き続き頑張りたいと思います。

 

<追記>
海外の方で同じようなアイデアを思いついた方々が出始めたようです。
LUTNet: Rethinking Inference in FPGA Soft Logic
教えてくださった方々有難うございます。

マイナーな分野なんで、いろいろ心配だったのですが、同じようなことを考える人が居るのは嬉しいことです。
FPGA特化なので人口少ないですが、AIの主戦場分野は本当に切磋琢磨の世界なのだろうなと思います。

<さらに追記>

 FaceBookで「Activation無しで線形性が出せるのか?」という話が少し盛り上がったので転記しておきます。
 もともと隣の入力に逆伝播している時点で線形性のある式ではなくなっているとは思っていますが、私の考えとして、特に2入力LUTの場合、「AND/OR/NOR/XOR/etc.. ないろんなゲートが確率的に重なり合って存在している状態」を想像してもらうと良いんじゃないかなと考えました。

ゲートごとにも距離があるので、答えをテーブルで数値に置き換えて、最適にするために選択するゲートの確率比率が連続的に変動していくと。で、それを6bitテーブルなどに拡張していってもちゃんと機能しているということです。

もともとボルツマンマシンのモデル自体確率モデルですし、そこからやり直したほうがいいのかもしれません。

今はまだ、「テーブルを確率変数に置き換えて立式したもので学習に成功した」という結果論でとまっているのでまだまだこれからですね。
今のAIは「説明できないけどうまく行っている」は沢山あるので、順番が逆になる(理論が後から着いてくる)のはそれほどおかしなことでもないのかもしれません。

 

2019年3月31日 (日)

祝! LUT-NetworkのLUTモデルの逆伝播学習動作

 前回メモで書いた内容がどうやら動作したようなので、速報レベルで記事を書いておきます。

 

Lut_copy_1

上記はMNISTデータをFP32にて、入力値がそれぞれバイナリの1になる確率として計算した後に、実際にバイナリモデルにテーブルコピーを行って動作確認したものです。

まずは原理検証ということで、FP32精度で軽く accuracy 0.8379 まで学習した後、バイナリのLUTモデルにコピーして x15(4bit精度) のPWM変調で accuracy 0.8084 が確認できました。コピー先のモデルは普通にFPGAのLUTをバイナリで模擬しているモデルなので、ちゃんと機能していることが確認できます。

アナログ値を例えばPWM変調などを掛けてバイナリにすると、もとの値に応じて確率的に1と0になります。このときの1になる確率から各テーブルの引かれる確率にして、最終的な結果が1になる確率を求める素子を構成し、この組み合わせを誤差逆伝播で学習させることで直接LUTテーブルを求めています。

ソースコードは

https://github.com/ryuz/BinaryBrain/blob/ver3_develop/include/bb/StochasticLut6.h

を参照下さい、Forward と Backward を見ていただければよいかと思います。

6入力LUTのモデルであり、重みとして W のパラメータが64個のテーブルに相当します。

Forwardでは、64個あるテーブルのそれぞれの参照される確率を求めた後に、テーブルの内容を2値化したものを元に、出力が1になる確率を求めるという他愛の無い計算で、Backwardではその微分を計算しています。

やっていることはシンプルなのですが、「テーブル引き」というモデルをそのまま数式にしてしまったところが新しいかと思いますし、テーブル引き時点で従来のいわゆるパーセプトロンとはかなり異なるモデルであることがご理解いただけるかと思います。

これがうまく行けば、極めて効率的にLUT-Networkの学習が可能になります。
また、学習過程では、「バイナリ値が1になる確率」という形で、FP32値を forward でも伝播させますので、回帰問題も効率的に学習できます(FPGAポーティング後の予測でオーバーサンプリング必要なのは従来どおりです)。

今回作った素子モデルは別にバイナリである必要もなくて

  • N入力に対して、2^N個の重み係数を持つ
  • forwardもbackwardも乗算と加算のみ
  • 単独でXORが解ける素子
  • 重みをfoward時に二値化するとFPGAに出来る

Nが小さい(疎行列)ことだけ重要で、ひょっとすると2値化せずに普通のDLの素子として使っても情報密度は従来のパーセプトロンのモデルより高いかも知れません。


従来のパーセプトロンを組み合わせて作ったμMLPよりも、早く高密度に学習しているような気がします。このあたりもおいおい追加検証が必要になりそうです。

現在CNNも実験中ですが、順調に学習が進行しています。

実行中の画面のスナップショットを以下に張っておきます。

 

Lut_cnn2

このアイデアはまだCUDA化していないので重たいですね。ただまだ2epoc目で92%まで来ています。その後、95%をあっさり超えました。保存したパラメータでLUTのモデルで実行したところちゃんと accuracy : 0.9441 の結果も得られました。

このモデルはメモリアクセスが少なくて、乗算が非常に多いので、CUDAにとても向いていると思います。

そもそも論として、FPGAに限らずに、ワーキングセットが小さく出来ればキャッシュのヒット率その他、計算機の効率が上げやすいという方向なので、ワーキングセットを小さくして代わりにfpsを上げて認識性能を出していくという試みは、いろいろと面白いのではないかと思います。

 

(2019/04/01追記)
 DNNの学習だけではなく、もっと手広く使えそうな気がしてきたのでTwitterに書いたことも転記しておきます。

 今回のモデルの計算グラフが下記です。6入力LUTを書くとテーブルが64個となり書くのが大変なので、2入力LUT(テーブルサイズ4)で書いてみました。
 実際にはこれの6入力版をパーセプトロン素子の代わりに使ってLUTネットワークの学習に成功しているわけです。もはやニューラルネットと呼んでよいのか微妙になってきましたが、複数のパーセプトロン素子でも等価なものが作れるのでぎりぎり許してください。

2lut_model

 各テーブル(W0~W3)が引かれる確率を求めているため、構造的にWを掛け算する前に、入力同士の乗算が発生しているのが特徴かと思います。また各テーブル値は回路化すると0か1しか取らないので、forward時は2値化して、backward時はそのまま使っています。FPGA化しないなら2値化自体不要と思います。
 通常のパーセプトロンのモデルは入力同士が最終段の加算部でのみ結合するので、単素子の逆伝搬ではお互い干渉しません。今回のモデルはクロスバー的には乗算で絡まっていて激しく干渉するのですがちゃんと動いていて自分が一番信じられないですが、CNNの例のとおり学習に関しては効率的に動作しているようです。
 このモデルは出力と他の入力値の両方の影響を受けるのでXORが学習できてしまいます。接続数が増えると破綻するので疎結合でしか利用できませんが、逆に言えば1段で全結合という手を取らなければ回避できます。生物の脳をモデルにしてたら思い付きようがないモデルと思っていまして、FPGAをモデルにしたからこその成果と思います。

 で、今回のモデルはもともとがデジタル論理素子の直接学習なので、あらゆるデジタル電気回路を記述可能です。するとこれを逆に使うことで、デジタル回路をネットに置き換えて逆伝播を行うことが可能と思われます。
 つまり、今回のモデルを使えばあらゆるone-way functionの逆解を求めるのに特別な知識なしにGPU回すだけの状態に変換可能な気がします。初期値依存なので実用的なパフォーマンスが出るか不明ですが、いわゆる暗号解読などの分野にDLの計算環境を活用できる可能性があります。
 例えば、デジタル乗算器の回路をLUT-Networkに写し取って、テーブル固定して、素因数分解したい値を教師にして、逆伝搬を繰り返せば素因数分解が出来ることになります。
 素因数分解などは、まだ、十分研究されている分野ですが、それ以外の複雑な系に関して、片方向の演算が定義できれば、簡単に逆計算がGPUを活用して探索できます。
 このモデルの入力同士で逆伝播に相互干渉するというのは、一種の自己参照ループと思っていまして、OPアンプのフィードバックとか想像してもらうと分かりやすいかと思いますが、解が存在すればそこに向かって系が収束していきます。フラットなグラフで最適化したいたら自己参照ループがうまく解けないケースが多いのですが、今回はDNNのテクニックで非常にうまく微分値が反映できています。
 かつて、チューリングらが、エニグマの暗号解読に自己参照ループを活用したチューリングボンベという非チューリングマシンを使って挑んだ話は有名ですが、こういったアプローチが、NP問題とか数学的にも解かれていない領域に対してあたらしい切り口が出来れば非常に面白いと思う次第です。

 幸いBinaryBrainはこういう実験もやれそうな構造に作っているので、どこかで挑戦してみたいと思います。

 

2019年3月17日 (日)

LUT-Networkの為の学習方法アイデアメモ

 先日、LUT-Networkでの回帰をやってみましたが、もともと観測すると1か0に確定するだけで、その確率を扱っているだけなので、多値が扱えないなんて事はまったく無いと思っています。

 で、今日急にお風呂の中でLUT-Networkの学習を効率化できるかもしれないアルゴリズム思いついたのでTwitterには書きましたが、ここにもメモしておきます。

 入力も出力も確率変数としてテーブル引きモデル書けそうな気がします。

 6つの入力がそれぞれある確率分布をもった一般的な確率変数の場合、テーブル引き後の出力の確率分布を求めるのは困難です。しかし、バイナリ化を前提とすると、0か1しかないわけですから、1になる確率だけをスカラ変数として扱えばよく、単精度浮動小数などの多値で管理すればよい筈です。ここまでは普通のネットでも同じ考え方の筈です。
(もちろん0になる確率は 「 1 -(0になる確率)」 です)

というのを前提に入出力も64個あるテーブルも、観測するまで0か1が確定せず、その確率分布だけ分かってる変数として扱えば、LUTのモデルもそのまま立式できそうな気がしてきました。

その場合、64個あるテーブルのそれぞれが引かれる確率が求まるはずで、、出力が 1 になる確率もそこから一意に求める式が立つはずです。で、式が立てば微分できるはずです

 
6入力LUTを仮定して入力の確率変数を x0 ~ x5 とすると

テーブル0 を引く確率  (1-X0) * (1-x1) * ....  (1 - X5)
テーブル1 を引く確率   X0      * (1-x1) * ....  (1 - X5)
...
テーブル63を引く確率   X0 * X1* ...  X5

のように64個ある各テーブルの引かれる確率が求まります。
その後、各テーブルの1になる確率を掛けて総和を取れば出力が1になる確率が求まります。

 LUT一個分にしては、ちょっと大きな式になりますが、今のμMLP方式より小さくなるはずですし、微分できるから当然逆伝播も記述できるはずです。

 課題としては、LUTを最後、確率変数ではなく、0か1に固定しないといけないため、学習時点では誤差が最小化するように正則化を書けながら進めないと多分うまく行かないだろうと点です。ただこれはバイナリネット全般に言えることで、今、BatchNormalizationなどがバイナリネットにおいて非常に重要な位置にあるのと本質的には同じなので、なんとかなりそうな気もしています。

 これがうまく行くと forward 演算で 0/1 にバイナライズしながら入力を変調して何度も実行して確率的に計算している箇所を多値を使って一気に高速化できる可能性が出てくる気がしてきます。

 上記計算は、多分CUDAとかの1SMに収まる程度と思いますし、今開発中の BinaryBrain で実験するにはもってこいだったりもします。

  まだアイデアレベルですが、まだまだ実験できるには時間がかかりそうですし、先に公開したもの勝ちな部分もあるので、実験に先立って書いておきます。

 余談ですが、BinaryBrainのねらい目は、TensorFlow や Chainer や Torch や Caffe なんかの汎用的なプラットフォームが取りこぼしていそうな、FPGA向けバイナリネットに限定した特殊計算のプラットフォームです。
  Spartan/Artix/Cyclone クラスや、場合によっては Lattice とかMicrosemi (Actel)も候補で、お気軽にAIっぽいことをやれるレンジを狙いたいなと思っています。

 バイナリ系は学習の計算もメモリ配置も特殊なので汎用の学習プラットフォームに同じポリシーで共存し難い部分がありまして、ましてや特化してGPUで高速学習をチューニングとかあまりな筈です。PC用のGPUを1日程度ぶん回して廉価FPGA 1個規模ぐらいが学習できるぐらいがレンジとして狙っているところです。


2019年3月10日 (日)

バイナリLUT-Networkで回帰問題をやってみる

バイナリネットワークをやっていると課題の一つに「普通にやると回帰問題が解けない」というのがあるかと思います。
バイナリネットはバイナリを入れてバイナリを出力しますので、そのままでは多値的なものが扱えません。例えば二乗誤差が最小になるようにフィッティングしたい場合、ターゲットが0.5だと0でも1でも誤差が変わらず最小化される余地がありません。
 一方で、バイナリであっても1になる確率というものは、もっとアナログ的な値を持っており、確率的な動作は可能です。
 信号処理の世界にはバイナリ変調という考え方があります。
 例えば下記のサイトのような⊿Σ変調は有名ですし、現在のオーディオは1bitDACが主流です。
 
 ということで私もアイデアだけは前からもっており、先日のFPGAXでも下記のアイデアを書かせていただきました。
 Photo
 
 
 現在、BinaryBrain Version3 を作ろうとしているのですが、その過程でちょっと試してみましたので、紹介しておきます。
 
Binary_regression
 
 バイナリでもオーバーサンプリングすることで、多値になるので2乗誤差が計算できますし、結果もちゃんと収束傾向にあるようで、そこそこのフィッティングはするようです。
 回路の利用の仕方が変わるだけで、回路自体は肥大化することはありません。従来多値を空間方向のリソースで計算していたのを、時間方向に転嫁しているわけです。
 
 条件は十分揃えられてないのであまり比較にならない部分もあるのですが、通常のFP32でのDenseAffineとバイナリ疎結合の LUT-Network でそれぞれ scikit-learn の diabetes のデータを 0.0-1.0 で正規化して損失関数は二乗誤差として解かせてみました。バイナリは255倍のオーバーサンプリングです。 
 255倍のオーバーサンプリングですので、8bit程度の精度で出力できているはずです。
 
 なお、こちらのサイトなどを参考にさせていただいてます。私のものはバイナリ計算に都合がいいようにレンジを補正しているので、サイトの損失値とは比較できない点はお気をつけください。バイナリとの比較もあって、FP32の方は活性化もSigmoidにして素のSGDでフィッティングしています。
 なお、まだプラットフォームの開発とデバッグの真っ最中なので、いろいろと不具合を孕んでいる可能性がある点はご了承ください。特に定量性はあまり無いと思います。ただ可能性としては面白い特性が出てきたので、速報レベルのネタ記事です。
 
 
(2019/03/12追記)
 個人的にはなかなか面白い特性の発見だったのですが、タイミング的に Edge TPU の衝撃に埋まってしまった感じがあるのと、TPUに乗り遅れて悔しい(笑)ので、少し、専用LSIについて追記してみます。
 FPGAを計算機とだけ見てしまうと、CPU/GPUよりもFPGAが向いている計算領域があったとして、最初はFPGAで性能が出るわけですが、ここで専用LSIが出てきてしまうとFPGAは負けてしまいますので、どうしてもボリュームゾーンではプロトタイプフェーズでしか出番が無いという宿命を背負っているわけです。専用計算機と汎用機の中間ぐらいにいるのでやむなしかと思います。
 一方で、LUT-Networkに関して言えば、唯一この規則の例外でして、LUT-Network用の専用LSIを作ったとしたらそれはFPGAそのものに他ならないわけです。
 このネットワークに関しては専用LSIに後からフィールドを奪われる心配が無い上に、FPGAが持つ本来の性能としての演算器を外部I/Oと直結できるというメリットや、バイナリ故の、空間を圧縮して時間方向に処理を増やす方向でのアプローチでリアルタイム性を高めるられるという可能性が残っています。
 今回、バイナリでも回帰が出来そうだという話は、I/O直結でリアルタイムな信号処理を行う分野に、ある程度高度なAI処理を適用できる可能性がでてきたという意味を含んでいると考えており、まだまだFPGAにも組み込みAI分野で生き残る可能性があるのではという希望とともに、もうちょっと頑張ってみようと思っている次第です。
 
 ちなみに上記のいいとこ取りしたのがAIコア入りのFPGAのようにも思える部分はあるのですが、既存のAIコアは、RTLのロジックの中に組み込むというよりは、GPU的な高性能ノイマン型が入っているイメージが強く「リアルタイム」とは少し違うような気がしています。
 本当の意味で、データフロープロセッシングをリアルタイム信号処理のデータフロー内にワンパスで入れ込もうとすると、量子化とスパース化を論理限界まで攻めてみる必要があるように思っています。
 この分野、まだ誰も論理限界を示せていないのではないかとは思う次第です。

2019年2月 2日 (土)

fpgax発表資料(2019/02/02) LUT-Network

今回、下記の勉強会で発表する機会を頂きました。
 
 
 内容はともかくとして、折角資料を作りましたので、Webでも公開したいと思います。
 なお、実際の
 Slide Share にアップロードしております。
 
 Web公開用は発表用と完全に同一ではありませんが、内容は同じものです。
 Slide Share は、後からの資料の更新は出来ないようなので、内容に致命的なミスがあった場合、URLを変えて再アップロードする可能性がありますのでご了承ください。
 
 PDF版も下記に置いておきます。
 
(本記事は、発表終了後に自動公開を設定しております。不備があればすみません。)

より以前の記事一覧