« LUT-NetのFPGAリソースについて | トップページ | LUT-Networkの蒸留(Distillation)について »

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

 

« LUT-NetのFPGAリソースについて | トップページ | LUT-Networkの蒸留(Distillation)について »

FPGA」カテゴリの記事

Deep Learning」カテゴリの記事

コメント

この記事へのコメントは終了しました。