Ryuz's tech blog

FPGAなどの技術ブログ

FPGAを始めるときの壁

FPGAをはじめてみたい

FPGAという何やら面白いものがあるらしくて、使うとすごい計算やいろいろなデバイス制御ができるらしい。」

と、興味を持って頂ける方はそれなりにいらっしゃるのではないでしょうか?

早速なんらかのHDLなる言語を勉強し、例えば SystemVerilog を少し勉強すれば下記のようなプログラムを書くことが出来ます。

入力ポート a,b から入ってくるデータをクロックサイクル毎に加算してc に出力するロジックのソースです。

module add  (
               input    logic           reset,
               input    logic           clk,

               input    logic   [31:0]  a,
               input    logic   [31:0]  b,
               output   logic   [31:0]  c
            );

    always_ff @( posedge clk ) begin
        if ( reset ) begin
            c <= 0;
        end 
        else begin
            c <= a + b;
        end
    end

endmodule

すばらしい! これであなた専用の加算エンジンができあがりです。 このエンジンは 300MHz で動かせば 300MOPs の演算能力を持ち、10個並べれば 3GOPs、10000個並べれば 3TOPs です。

と、ここまではプログラミング言語を教科書通り勉強すればたどり着くのですが、

で、「ここにどうやってデータ入れればいいの?」

という、最初にして最大の壁がやってきます。

  • 例えば PCIe経由でPCのCPU上で動くプログラムからデータを送り込む
  • 例えば USB経由でPCのCPU上で動くプログラムからデータを送り込む
  • 例えば LAN経由でPCのCPU上で動くプログラムからデータを送り込む
  • 例えば HDMI の入力や出力に繋いで2つの画像を合成する回路として使う

などなど、いくらでも思いつくわけですが、

などなど、周辺回路を何とかしないといけないわけです(実は最後の奴が一番楽じゃないかとすら思う筆者ですが)。

ここでメーカーが用意してくれてるものやOSSなど「今あるサンプルを使って何とかする」という流れになるのは当然なのですが、しばし、やりたい計算とインターフェースの仕様が整合しない(逆もしかりで、インターフェースの性能を活かせる演算器にすべき部分もある)ので、折角書いた演算器の性能が出ずに、CPUで計算した方が速いなんてことになることもしばしばです。

また、性能が出ても「こんなに大変じゃ、やってられない」と工数当たりの利得が得られないケースもありますし、「引き継げない」「メンテできない」と言った理由でビジネスの選択肢から外されるケースもあるでしょう。

極論ですが、現状この壁がFPGAの最大の壁で、息をするようにこの壁が乗り越えられるレベル に達すると、もう何でもできるFPGAマスターになっている気がします。

FPGAを勉強するにはFPGAが出来ないといけない、という、「缶詰の中の缶切り」状態になりかねません。

逆に、既にこの壁を乗り越えてしまった人には、もう壁でなくなっているので、この壁を何とかしようとする動機が薄れる気がします。乗り越えたら乗り越えたで振り返らずに折角できるようになったやりたかったことをやりたいのが人と言うものです。なので初心者の壁がいつまでも高いままそこに居座っている気もしています。

対CPU データ交換は Zynq が一番答えに近い?

この問題は、「何をする為にどんな方法で何とデータ交換するか?」によって解が違うので、一概に一発で解決できるソリューションはあまりない気はします。古くは RS-232C で UART 通信するロジックをせっせと書いたり、EZ-USB のようなものを使ったり、あれこれやっていたのですが、なかなか銀の弾丸にはなり得ませんでした。 Alveo などの解もあるのかもしれませんが、趣味で使うにはなかなか高価です。

そんななかで、対 CPU 通信に関していえば Zynq は(というか LinuxFPGA Manager は)、比較的再利用性の高い CPU と FPGA 間の接続環境な気はします。

例えば PYNQ

例えば私は使ったことないのですが、PYNQ などは、データ転送の性能はともかくとして、非常に多くの環境に同じインターフェースを提供し、多くの Python ユーザーに対して、冒頭の課題に対するひとまずの解決を提供しています(もちろん性能出そうとすると、いろいろ周辺回路の準備も必要なのですが)。

ACRi さんのブログ記事「PYNQ を使って Python で手軽に FPGA を活用 (1)(2)(3)(4)(5)」 などもとても興味深い記事でした。

Python 使う方々に向けて、「次にC言語覚えるより Verilog 覚える方が楽しいですよー」と、勧誘するのにとてもよさそうなツールに思えました。

やはり u-dma-buf が至高?

そうは言っても Rust や C/C++ でせっせと低レイヤーを叩いている筆者としては、もう少し直接的にアクセスがしたくなるわけです。 Zynq を使う上では、さしあたっては root 権限で /dev/mem を叩く方法があるわけですが、それだとメモリマップドI/Oにアクセスできるだけでやはりいろいろと性能を引き出すには難しい部分があります。

そうなってくると ikwzm氏の u-dma-buf などが神ソフトになってくるわけです。

他には同氏の uiomem だったり、Linux の UIO だったり、このあたりが Zynq 等の SoC の載ってる 色んなボード環境で共通的に使える というのが非常にありがたいわけです。

FPGA と CPU の間のデータのやり取りで、ある程度エコシステムと呼べるような、流用性の高いOSSなどのソフトウェア資産の走りとも言えるもので、私の中ではとても有難い物でした。

なお、筆者も調子に乗って Rust の本来あるべきメモリ安全性を棚に上げて unsafe だらけのこんなクレートを作ったりしています(苦笑)。 /dev/mem を叩く類の操作は、「PL をちょっと試してみる」という、ユニットテストを書くのに近い部分があるので、unsafe 多用でも便利な方が嬉しいケースもあるので、まあお許しください。なお C++版はこちらに記事にしていたりもします。

それでもデバイスドライバを書くのが最善ではある?

それでもやはり、最後は、自分でデバイスドライバを書くのが最善という事にはなってくるのかなと思います。

/dev/mem を叩くのに始まる汎用ドライバの利用は、どうしてもユーザーアプリが終了した場合の、PL の後始末に責任を持ってくれません。

Linux のプロセスが落ちると、確実にデストラクタを読んでくれる保証がないので、「DMA を起動したままアプリが落ちる」と言うような危険な状態に陥ることを回避できません。

一方で、ちゃんとデバイスドライバを作れば、Linux はプロセス終了時に開いているファイルはすべて閉じてくれますので、安全な後始末を保証する事も可能になります。

なにより、ドライバのオープン中はプロセスが存命中であることを保証できるので、ユーザープロセス側のメモリにPLからアクセスする という事も可能になります。Linuxデバイスドライバ内では ユーザープロセスの論理空間にアクセスするためのページテーブルを作ってもらうようなシステム関数にアクセスできますので、ある意味何でもありですので、「メモリコピーを減らして最高パフォーマンスを出す」にはこの方法が必要になる気がします。

おわりに

またしても何のソリューションも示していない駄文になってしまいましたが、この「FPGA の勉強を始めたときの壁」に対しては私も何らかのアプローチが出来ないものかとは常々思っている次第です。

  • PLへの bitstream のロード/アンロード
  • UIO とか u-dma-buf とかのロード/アンロード
  • メモリマップドI/O への高速な読み書き
  • カーネル空間で確保したメモリへの読み書き
  • ユーザー空間のメモリへの読み書き
  • PL側のDMAや、CPUからのアクセスを受け付けるインターフェイス回路

などなど、このあたりのソフトウェア資産を使いやすく整備していく必要がある気はしています。

Zynq などの登場で、「FPGAボードとCPUの接続形態がボード毎に一点物で終わる」という事態がだいぶ回避されて使いまわしが効くようになってきているので、今後ますます資産が増えていく事を期待する次第です。

余談

なお、今回はあくまで 対CPU の話でして、私のような「カメラやディスプレイの動作タイミングに合わせて、その間で動くAI認識エンジン作って遊ぼう」みたいな、CPU 置いてけぼりの世界でコンピューティングを楽しんでいる人間には実はあまり関係なかった話ではあります。

そういった別ルートから RTL を覚えて、ある程度使えるようになってからCPUとのやり取りを始めた、という経歴なので、ある意味チートコースでこの壁を乗り越えてきた人間だったりもします。

一方で、現在の IoT 全盛期に CPUと繋がってインターネットと繋がって、多彩なIT処理と有機的に繋がっていくことは既に必須事項になっているので、今からFPGA を始める方には、その価値を引き出すための最初のハードルがとても高くなっているのではないかと言う気もしています。

FPGAプログラミングは、極めて低レイヤーで、リアルの世界に対するインタラクションを行う部分で非常に強みを発揮しますので、まさにリアルとバーチャルを繋ぎ合わせて新しいコンピューティングを生み出してくれる可能性のある領域です。 是非是非、新しい方にどんどん参入してもらえるように、いろいろな壁を取り払っていきたいものです。

そして何より、冒頭のような 3GOPs のエンジンを作ったとして、それをちゃんと 3GOPs で働かせるための計算機アーキテクチャとは何ぞや? という本質の部分で思い悩める領域に入ってきていただきたいと思うわけです。

壁は高くとも、乗り越えると本当に楽しい領域です。より多くの方と一緒に FPGA を楽しめればと思います。

続・計算機の効率(x86の加算器を推定してみる)

はじめに

つい最近、x86 CPU が割と長らく整数乗算をスループット1で処理していなかったことに気が付いてこんなブログを書きました。

ついでなので、工夫や構成でトランジスタ数の変わる乗算は置いておいて、比較的変化の少ない加算器で専用計算機との比較をしてみようと思い、ChatGPT さんにいろいろ聞きながら適当な表を作ってみました。なので間違いがあれば「ハルシネーション って事にしておこう」という、逃げ道を作って、適当な調査で見積もりを進めていきます。

ここでは 加算のみを行う専用計算機 との比較を題材にしてみようと思います。

「加算のみの専用計算機ってなんやねん?」となるわけですが、まあ、「DIS-SWで二進数で値を入れると、二進数で加算結果が点灯する装置」とか、「同期の取れたデジタルビデオ信号を2つ入れると合成した画像を出力する」とか、まあ何でもいいんですが、そのものずばり加算器しかないものを考えます。

当初真面目に全加算器のトランジスタ数を数えようかとも思いましたが、こちらで、64bit加算器が約1,000個との記述を見かけたので、エイヤで、

という事にして見積もります。フェルミ推定的な事がしたいだけなので、目をつぶってください(苦笑)。

x86 とかの効率を推定してみる

で、Z80とかも混ざってますが、ざっくりトランジスタ数と、レジスタ to レジスタでの add 命令のサイクル数と、スーパースカラの way 数と、で専用計算機との効率差を計算したのが次の表です。 (対メモリとするともう1~2桁悪化しかねませんが、キャッシュミスとか言い出すと見積もり不能になるのでレジスタ間演算にしておきます)。

プロセッサ 全体Tr数 bit cycle way 加算器Tr数(推定) 効率
8080 6,000 8 4 1 125 1/192
Z80 8,200 8 4 1 125 1/262
8086 29,000 16 3 1 250 1/348
80186 55,000 16 3 1 250 1/660
80286 134,000 16 2 1 250 1/1072
80386 275,000 32 2 1 500 1/1100
80486 1,200,000 32 1 1 500 1/2400
Pentium 3,100,000 32 1 2 500 1/3100
Pentium Pro 5,500,000 32 1 3 500 1/3666
Pentium II 7,500,000 32 1 3 500 1/5000
Pentium III 9,500,000 32 1 3 500 1/6333
Pentium 4 42,000,000 32 1 3 500 1/28000

例えば 8086 なら 「16bit の加算器が 250個のトランジスタで出来てるものとして、これが全力でadd命令を実行しても 3サイクルに一回しか仕事をしてくれないので、投入している全体の29,000個のトランジスタを専用計算機につぎ込んだ場合に比べて、250 / 3 / 29,000 = 1/348 の効率しかないよね。」という感じの乱暴な計算をしています。 クロック周波数は無視して、あくまでその世代のトランジスタを目的の計算をするのに効率的に稼働させてるかだけを見ています。

世代が進むと効率はどんどん悪くなり、最後は 1/28000 という見積りになってしまいました(まあ後半浮動小数点ユニットも入ってくるので一概に比較してはいけないのかもですが)。

それでもまあ、専用計算機に比べて汎用機が千倍~数万倍非効率と言われる話とはそう乖離してない気はします。

ご承知の通り、この頃はシングルコアのままどんどん周波数を上げるのにトランジスタが使われていた時代で、パイプラインはどんどん深くなり、Pentium4Prescott でついに限界を迎えて、この後、マルチコア/メニイコアの方向に進んでいく事になります。

この後は MMX命令(SIMD)なども出てきてますます比較が難しくなるので、ざっくりシングルコア時代で覗いてみるのはわかりやすくて良い気がします。

じゃあFPGAはどうなのか?

ということで、FPGA に話を持っていくわけですが、まあ Pentium とかと比べるなら Spartan3 ぐらいの LUT4 時代が適当なのかなとも思います。

Xilinx の場合 LUT4(6T の SRAM として、これが16bitとマルチプレクサ ) の後ろに加算用のキャリーチェーンがいて、FFが居るわけですが、データシートとか見てみると何となく見積もりやすそうです。

適当に ChatGPT に聞きながら 1bit 分で300トランジスタぐらいじゃないかと大雑把に試算して 8bit 加算器分で 2400 トランジスタぐらいという事にします。で、FPGAの配線スイッチの比率は 70~90% ぐらいはあるらしいので、まあそこも含めて 10000トランジスタぐらいとして、8bit 加算器の125 で換算するとまあ、専用計算機(ASIC)の 1/100 ぐらいの効率でしょうか?

後は、なんか加算に関しては LUT6 だと逆に見積もり悪化しそうな気がしますが、FPGAの場合、ベンダーが効率を下げる改変をするわけがないと思うので、きっと加算以外のCLBの使われ方の方が多いのでしょう、多分。

おわりに

超適当な見積もりですが、FPGAは ASIC の 1/100 の効率で、CPU はそのさらに 1/100 の効率 とか、普段あまり根拠なく言ってる戯言のオーダーとだいたい合ってるような気はするわけです。

この後、CPU はマルチコア化していき、SIMD演算器が入り、GPGPUアクセラレートしたりといろんな方向に進化していきますし、Xilinx FPGA もどんどん高度なDSPをハードマクロで持つようになり、MPSoC や ACAP で CPUが入ったり、GPU が入ったり、AI-Engine が入ったり、もうなんかどう見積もっていいかカタログだけでは難しい世界になっているわけですが。

ただし、専用計算機と比較するとこれだけ差があるわけですから、決まった演算に関しては専用計算エンジンを抱き込みたいという気持ちは確かによくわかるわけで、どう混ぜていくか? が問われる中で、FPGA はとてもバランスの良い潤滑油な気がするのですよね。

FPGAユーザー増えると嬉しいです。

おまけ

汎用計算機の本質として「プログラム次第でどんな計算でもできますよ」というのは、「足し算しかできないけど効率1万倍」よりもしばし高い価値と見なされるわけですが、価値を決めているのは人間であって、「どちらがより人間社会に役立つか」という事なのかなとは思います。

現在「AIしか計算できないけど効率1万倍」というのが脚光を浴びているのは結局AIがここに来て社会的な価値を見出されたからに他ならないわけで。今後の計算機の歴史がどうなるのかは興味津々です。

CPUが苦手でFPGAが得意な処理についての妄想

CPUが苦手でFPGAが得意な処理にどんなのがあるか考えたときに、案外 LUT-Network はそれに近いかもしれないと思う。

ここで手元にある KV260 を考えてみると 117,120個 のLUTがある。

LUT-Network で行われる動作としては

  1. ランダムに結線されている別のノードの 6つのノードの結果を取得してくる
  2. その値をアドレスに 64bit のテーブルを引き結果とする

という、FPGA のLUTの動作ほぼそのままだ。この時テーブルの内容の情報エントロピーが十分高ければ(要するにランダムに近ければ)、CPUに備わった命令で計算するよりテーブル引きする方が早いという状況になる。

そうすると

  1. 1bit取得するためだけにキャッシュラインサイズだけ周辺を巻き込んだランダムアクセスが6回起こる
  2. 6回で取ってきた値をシフトしてORして入力値にする
  3. 64bit のテーブルをロードしてくる
  4. 入力値分シフトしてAND取って1bitを得る

というのが CPU で出来る最速の方法と思われる。

117,120個 のLUTがあるとテーブルサイズは 1Mバイト程度になってくるので L2キャッシュには収まるがL1キャッシュだと厳しくなってくる。 メニイコアのCPUやGPUを持ってくればL1に収まるかもしれないがそれにしてもコアを挟んでデータ交換しなければならないので load/store のコストは軽くはならない。

軽く10サイクルはかかると思われるので、500MHz でFPGAと同じ速度を出そうとしたら、仮にデータ交換のコストがゼロでも 5GHz で動く117,120コアのCPU/GPUを持ち出さないといけない計算になる。

要するに FPGA の LUT の数と同じコア数で10倍周波数の CPU を揃えてすら無いと同じことをするのが難しいという話になる。

GOWIN とかの Tang Nano 4K とかでも LUT4 になるとはいえ 4,608 LUT あるので、やりようによっては 1000コアのCPUに勝てるかもしれない(笑)。 (逆説的だが RTLシミュレータが遅いのもいろいろと納得がいくのである)

まあ、逆もしかりで、某CPU が最も得意である、「x86命令のエミュレーション」みたいなので勝負するとFPGAはぼろ負けするわけですが。

(それ以前の問題として、x86 とか ARM とかの命令セットエミュレータFPGAでロジック実装したら、なんかいろいろ怒られそうな予感)

計算機の効率というものについて素人が駄文を書いてみる

はじめに

計算機の世界で ××倍速い、とか、〇〇倍の効率を達成とか、よく聞くわけですが、いわゆる当社比で2つを比べる場合ならともかく、そうでない場合はいろいろと比較が難しいように感じております。

特に FPGA をやっていると、ASICと比べると 10~100倍効率が悪いとかよく言われるわけですが、書き換え可能で何でも実行できる汎用プロセッサと、専用エンジンを比べても仕方ない部分もあり、どういう条件下で何を比べているのかとかがとても重要だとは思うわけです。

専用計算機

そもそもの話として、デジタル同期回路 でという条件下で話を進める場合、トランジスタ数 × 周波数 以上の計算性能は出ないし、その時の電力効率も製造プロセスで決まっているわけですから、「如何に特定の計算をしてる時に遊んでるトランジスタをゼロに近づけられる高効率な計算回路(アーキテクチャ)が作れるか?」という問題になってしまう気がします。

このとき神様が設計した限界的な回路の性能を理論限界を効率 1.0 として定義してみる事にします。 そうすると、例えば特定のビデオコーデックエンジンだとか、プログラマブルシェーダー以前のハードパイプラインのグラフィックスエンジンだとか、行列計算における TPU だとか Tensor Core だとかは、その計算しかできない かわりに、ある程度 1.0 に迫る領域の性能が期待されてくるわけですし、ものによっては0.5~0.9 ぐらいのそれに近い効率を出してるんじゃないかというようなものもあるように思います。

それに対して、多分、FPGA とかはASIC化時に理論限界を達成できる回路を焼いても、効率 0.01 以下とかでしょうし、CPU 実行なんかだと 0.000001 以下とかまで落ちるものも平気で出てくるんじゃないかと思います(もちろんアルゴリズムによりますが)。 なので、専用エンジンをCPUでエミュレーションすると計算に数日かかるなんてのはまあよくある話ではあるかと思っています。

それほどまでに専用計算機は高い性能を出せる反面、作るのは大変ですし、出来てしまうともうそこからはもう先が伸びないことが理論的に分かってるわけですから、逆に言うとその領域に達した計算機は 面白みのない物 に変貌してしまうとも言えると思います。

なので、グラフィックスなり、ビデオコーデックなり、次々新しい規格(アルゴリズム)が出てきて、バージョンアップを繰り返すことで市場を保っていたとも言える気がしています。

昨今、この分野が思いっきり AI専用計算機 の話題で占められてるのは言うまでも無いわけですが。

汎用機の汎用って何だろう?

専用機では、だいたい理論性能付近に達したところでそこから先の競争は、ある意味頭打ちした中での限界領域での凌ぎ合いになってしまうわけですが、今度は逆に、汎用性を考えるとこれはこれでまた難しい話になりそうです。

効率と汎用性のバランスを追求するアプローチとして、さしあたって

  • 汎用機に対して特定アプリで専用機に迫る機能を追加していく(アクセラレータ)
  • 専用機になるべくその性能を落とさないように汎用性を持たせていく

の2つを考えたとき、前者は CPU にハードウェア乗除算器つけたり、浮動小数点コプロ付けたり、SIMD演算器つけたりするような話で、後者はGPUのシェーダーがだんだんプログラマブルシェーダーになってきたような話だったりになるのかなと思います。

昨今の AI 専用エンジンは、概ね後者のような気がしていて、ひとまず MLP(Multi Layer Perceptron)だけなら 高速な行列乗算が出来ればOK だったところから CNN を皮切りに Transformer やらなんやら、細かい制御の必要なネットワークがあれこれ入ってきても、なるべく性能落さないように柔軟に対応できるように進化してきているようには思います。 これらも、単にパラメータが入れ替えられるだけで決まったネットしか計算できないようなものから、将来未知のネットが出てきてもある程度対応できそうなアーキまで幅広いので、単に FLOPS や OPs だけでは優劣が付かない気はしています(ソフト互換性とか、プログラミング容易性とか別の軸を置いておくにしても)。

少し x86 の歴史を調べてみた

ここで、AI エンジンとは逆に、汎用機側の底上げについて x86 という、とても長く生き残っているアーキテクチャを少し見てみようと思い立って調べてみました。

初期の x86 はそれなりに基礎的なマイコンで、8087 のような面白いコプロもあるわけですが、そっちは一旦置いておいて、今回は本流の MUL命令で使う整数乗算器について調べてみました。

少なくとも私が若いころ(80386ぐらい?)は、乗算と言えば何十サイクルもかかる重たい命令の一つだったはずで、これに1サイクルで乗算が出来るある意味専用計算機ユニットが搭載されたのはいつごろかと調べてみると、どうやら Core アーキテクチャになってからのようです(Pentium4 でも スループット3、レイテンシ14でした)。 私の記憶では、486の頃にキャッシュメモリが、初代Pentium で UパイプとVパイプのスーパースカラが導入されていたと思いますので、結構後半になって乗算器にリソース投資がなされたことになります。

32bit 乗算器とは言えそれなりのハードウェア規模となります。一方で当時のプログラムの中で MUL や IMUL が出てくる頻度はそれほど多いものではなく、その他の命令を実行している間には丸々遊んでしまいますので、むやみに搭載しても もったいない ということにしかならないわけです。

計算機において、アムダールの方法しかり、ボトルネックになっている個所に投資するのは定石です。

このとき、まずキャッシュがあり、乗算以外の命令も1命令1サイクルで実行できる状態になっていることは、前提条件として恐らく重要です。

加えて、マルチメディア処理のように、例えばベクトル乗算や行列乗算を頻繁に使うアプリケーションの台頭も重要かと思います。例えば行列乗算のように、非常に繰り返し回数の多い for ループの中に乗算がある という状況がうまれてきたわけです。

そこに分岐予測やスーパースカラ機構で、乗算の裏に、for 文のカウンタの計算や分岐処理が隠れて初めて、乗算がボトルネックになるわけです。

そしてこうなってくると、SIMD の採用も非常に効果を出し始め、まさにマルチメディア演算の為の命令セットとしての MMX が生れて SSE、AVX と繋がって進化してきたのではないかと想像します。

この時、大量のデータ供給するメモリ周りどうするんだ というのに一旦目をつぶってしまえば、理屈の上では肝心のCPU部分の効率を据え置いて、SIMDをだけどんどんリッチにしていく事で、特定のアプリに関してのみ効率を専用計算機に近づけていく ということが出来るわけです。理屈の上では。

とはいえ、実際問題仮に特定のアプリでそれが出来たとしても、結局のところ、SIMD演算器が丸々遊んでしまうような演算種別しか使わないアルゴリズムでは、まあ、何の再利用も出来ないハードウェアリソースがそこに居座ってしまう事になるわけで、汎用と専用の間で悩ましい問題は据え置かれるわけですが。

FPGA の場合どうなのか

では同じく汎用計算機の筈の FPGA の場合どうなのか考えてみます。

FPGA にもハードマクロの乗算器(DSP)とかは、いろいろ入っているのでそれらをもちだすとまあ、CPUと同じ話になっていくわけですが、一旦 LUT による汎用ロジックだけ考えます。

折角 x86 の MUL 命令を引き合いにだしたので、試しに KV260用に 32bit 乗算器を DSP を使わないオプションで合成してみたところ 553 個のLUT で構成できました。 深さはそれなりにあると思いますが、途中の FF を有効にすればレイテンシは増えますが、スループットは1のままある程度の周波数まで上がると思われます。

なおこれによると、32bit乗算器の組み合わせ回路はASICだと10,000ゲートぐらいだそうです。この時 LUT には 18ゲート分ぐらいの計算が詰め込めていることになります(まあしばしASICの数ゲートしかLUTに入らないことも多いわけですが)。

なお、ChatGPT が言うには LUT6 の規模は 700~1,000ゲート程度ではないかと推測しているので、乗算器の場合は FPGA は ASIC の 1/50 倍ぐらいの効率ではないかと思います。その他配線リソースとかも出てはきますが、まあせいぜい100倍差ぐらいなのでは無いかとは思います。

逆に言えばこの100倍を許容できれば、ありとあらゆるデジタル同期回路に置いて汎用性が手に入るのがFPGAなわけです。

これは乱暴に言うと 100個ぐらいの特性の違うアプリがあって、それぞれ回路をダウンロードして実行するという事をする環境であれば元が取れる可能性もあるよいう話にもなり得るのかなと言う気もしています。 パソコンであれば、SSDの中に入っている *.exe の数は凄い数があるわけで、そこまでいかなくともある程度多様性のあるアプリに対して非ノイマン型でのメリットが適用できればペイしてくるのでは無いかと言う期待は持っていたりします。

結局、CPUが仮に専用計算機に対して 1万分の1の効率しか持っていなくても、「専用機を1万台用意するより、1個のCPUで1万種類のアプリが実行できる方が嬉しい」と言うところがCPUの価値であり、FPGAはもっとここに踏み込むべきだとは思ってみる次第です。

おわりに

今日は適当に書き始めてしまったので自分でも何を書いているんだか途中からわからなくなってしまった部分はありますが、どこに汎用性を残して、どこを専用化するのか、というのは非常に難しい問題だとは感じます。

一方で、今自分が取り扱ってるアプリが、理論限界の 1.0 に対してどれぐらいなのか? あとどれぐらい伸びしろがあって、どこが制約しているのか。を正しく理解しておくことは大事だと思います。

既に 1.0 に迫っているものにたいしては、物量自体を増やさないと、それ以上は望めないですし、逆に 0.000001 のような領域にいるアプリであれば、プログラミングを工夫するだけでも改善するかもですし、GPUなりNPUなりFPGAなり、持ってくる計算機のアーキテクチャを変えることで劇的な改善が望める場合もあり得るわけです。 そう言ったときに、とりあえず元の効率がとても低ければ、比較的何にもで処方箋となりえるのがFPGAでは無かろうかとは思っております。

普段は、「FPGAじゃないとできない事」にフォーカスする私ですが、今日は、汎用プロセッサとして CPU や ASIC と比較してどうなんだろう、というところで駄文を書いてみた次第です。

計算機科学から見たリアルタイム・ハイスピードビジョン

はじめに

先日、下記のくだりを X で呟いたところ、思いのほかのプチバズり状態となり驚きました。

内容自体はもちろん私が最初に発見したわけではなく、少なくとも東京大学石川グループ研究室さんなどでは遥か昔から主張しておられた内容かと存じています(なお、ツイートで「100ピクセル動くなら探索範囲は 201x201 では?」というツッコミはその通りの私のポカですw)。

とはいえ、恥ずかしながら、私は高速度カメラとかを扱いつつも、しばらくこの分野で非常に有名な石川研究室さんを知らないまま開発をやっておりましたので、モグリと言われてもまあ仕方がないかなと思っております。

一方で、私の名前が入っている特許とか論文とか眺めて頂くと、リアルタイム・ハイスピードビジョン的な事もいろいろやっていた人間というのはなんとなくわかって頂けるのではないかと思います。

そこで転職したのを機に、少し 公知の内容技術一般論 で語れる範囲で少し触れてみたいと思います (なお、LUT-Network は過去も今もお仕事とは無関係な私の趣味の産物なので、こっちは自由に語ります)。

私の方はあくまで 計算機科学 に軸足を置いて、リアルタイムコンピューティングの観点から画像処理応用でこの領域に踏み込んでおりますので、少し違った視点からお話しできる点もあるのではないかと思います。

ダイナミクスに対して十分なサンプリングレートにすると起こること

まずはツイート含めて一般論(というか先人の成果)の復習です。

上の動き探索の例などがまあいい例と思いますが、例えば OpenCVcv::matchTemplateなどで SADやSSDなどである意味力業で行う探索において、上の理屈は非常によく当てはまります。

また、X に書いている通り、移動量が1ピクセル以下程度になってくると、例えば OpenCVオプティカルフロー とか、例えば Lucas-Kanade法 などを使うものなどが 画像ピラミッドなど作らずにそのまま機能するようになっていく事が想像頂けるのではないかと思います。 マッチングによる探索が微分という計算に変わる瞬間で、これは時間方向に十分情報密度が出てきて、時間方向に十分連続性をもった信号として取り扱えるようになったために起こる現象です。

現実世界では、自動車でも、ドローンでも、固定監視カメラでも、何でもよいですが、「車は急に止まれない」という話の通り、撮像対象やカメラ自身に起こりうる最大の加速度に対して起こりうる変化量を限定して考えることが出来るケースは多々ありますので、「一定制約下で移動量が1ピクセル以下になるまでフレームレートを上げれば別のアルゴリズムが適用できる」などということは十分に実用的に設定可能な条件です。

また、ここで、「移動量が1ピクセル以下」と書いたのは例でしかなく、実際には 予測不可能な変化量 が一定範囲に収まるようにすることが重要です。

(しばしデモでは誰にでもわかるように速さを見せびらかす構成になるのですが、本来見るべきは予測できない変化に対する応答性です。これは技術有識者がデモ見るときに見ているポイントの違いです。石川研究室の動画も当然のごとく両者に考慮した構成になってるものが多く、さすがだなと思います)。

物体追跡の場合は、物体はニュートン力学に従って、物理モデルでを作って予測することができますので、予期できない外乱加速度 の最大値がわかれば、カメラに求められる性能が逆算可能になります。

また、この際のモデルの更新もサンプリングレートを上げていくと容易になります。⊿t が小さくなりますので、早い話、テイラー展開したときに1次の項しか計算しないなどの簡略化を行っても十分高い精度が出たりします。

多くの場合、ここで運動方程式を、状態空間モデルにして計算していくと思いますが、この計算が簡単になるわけです。

なお、画像処理の場合、照明変動とか、ノイズとか、ローリングシャッターかグローバルシャッターかといういろいろな要因も入ってきますし、ストロボ照明のようなもの制御なども混ぜてアクティブセンシングを始めるといろいろ複雑化したりとかはあるのですが、まあ、こういった世界観があるわけです。

計算機として決まったサンプリングレートでの入力と計算と出力をするという事

ここで話を計算機に持っていくと、計算機には

  • 決まったらレートで必ず入力すること
  • 決まった時間内で必ず計算を終わらせること
  • 決まったらレートで必ず出力すること
  • 上記の一連のレイレンシも可能な限り短くしたい

などが求められてきます。

既存のPC(パソコン)などではこれが案外難しいです。 入力データの帯域自体は 画像サイズ×フレームレートでしかありませんので、昨今の高速なインターフェースを用いれば理屈上は可能でしょう。

しかし、一般的なPCでは、例えば USBカメラは同じUSBチャネル上に居る別のデバイスに帯域を取られることもありますし、画像入力が終わった後もCPUは別の仕事をしているかもしれません。急にネットワーク負荷がかかるなど様々な要因で「PCの動作が急に一瞬遅くなった」などは誰でも経験しているところです。ゲームなどでのフレームレートもしばし変動するのを御存じの方も多いでしょう。

CPU を占有できる場合でも、データ依存で計算時間が揺らぐことはしばしあり、これらはリアルタイムOSなどを用いて最悪実行時間保証を考えていくような分野になります。その場合は入力完了の割り込みに対する不感時間や最悪実行時間などシステム設計を吟味することになり、外部にもさまざま仕組みを持ったハードウェアを準備することになります。

出力にもしばし課題があります。例えば、ディスプレイの 60Hz の周期などは、カメラ撮影とは同期していませんので、「カメラ画像をディスプレイに表示する」という簡単な話であっても、PCの場合は内部のフレームバッファに一度バッファリングされ、同じフレームが2回出たり、フレームが1枚スキップされたりと言ったことが簡単に起こります。

このような問題に対して、非ノイマン型のプロセッサである FPGA は極めて有効であり、例えば以前に書いた下記のブログに繋がってきたりするわけです。

ryuz.hatenablog.com

(なお、余談ですが筆者はRTOS分野でもいろいろやっております)

イメージセンサの話(余談)

高速度撮影をすると、シャッター速度が短くなるので、「絵が暗くなって使い物にならないのではないか?」とおっしゃる方も良くおられます。

それはその通りで、短時間露光画像の1枚だけを見ると、S/N比が極めて悪くなります。基本的に暗い画像になるので、アナログゲインをあげるなどするわけですが、ノイズも一緒に増幅されるのでザラザラした画像になります。

しかしながら情報量として何か欠落しているかと言うと決してそんなことはありません。

例えばシャッター速度 1/1000秒(1ms) で 100枚 撮影した画像を加算すると、シャッター速度 1/10(100ms) で撮影したのと同じことになります。

加えて、この時、1枚づつは画素飽和(白飛び)が起こりにくいですので、ダイナミックレンジは逆に広がります。ダイナミックレンジが広がって白飛びしにくいので強い照明を焚くことも可能です。

また動きについても 100ms だとブレブレになる画像も少なくとも動きブラーは殆ど発生しません。代わりにショットノイズなどのノイズ成分強く表れてくるわけですが、これも過去のフレームをうまく使う事でノイズ除去の可能性が出てきます。

このあたりのノイズの仕組みなどイメージセンサの中の構造を勉強するといろいろな事が分かってきて面白いのですが、まあその話は今日は一旦置いておいておきます。

何が言いたいかと言うと、「データ帯域が増える」というのを甘受する代わりに、情報自体を小分けにして受け取ってるだけだという事です。 (もっと身もふたもない事を言うと、人間の目もイメージセンサも飛んでくる光子を確率的に光電変換して認識しているだけで、積分すると確率的な揺らぎがなだらかになってるだけだけなのですよね。光子の単位でセンシングできるSPADセンサーが最強ではないかと思う次第です)

また、データ帯域の観点でも、同じデータ帯域でも画像サイズを 1/4(縦横半分)、1/16 (縦横1/4)と小さくしてよければ同じ帯域で、4倍、16倍とフレームレートを上げることが出来ます。

これは、1/2ピクセルとか、1/4ピクセルとかのサブピクセル精度で計測精度が出れば、許容できることを意味します。このあたりが先に上げた「微分で扱える」部分と関連してきます。

リアルタイムに計算するという事とAIと

リアルタイムに計算するという事は、これまでの入力データに最新の入力データを加えて、素早く今できる最善の出力を行う事です。

これは計算に必要な情報が揃った端から出力を更新していく事に他なりません。この時出力には予測と言う名の推論が含まれていても良く、とにもかくにも今できる 最善の出力 を刻々と変化するリアルな時間の中で行い続ける事です。

ここまでの条件を今の GPGPU などの AI の環境で行う事が難しいというのはなんとなく想像していただけるのではなないかと思います。

ですので、これを何とかする AI を作れないかと言うのが、前回の下記の記事で紹介している LUT-Network であったりするわけです。

ryuz.hatenablog.com

おわりに

リアルタイムビジョンを語り始めるといくらでも書くことはあるのですが、キリがなくなりそうなので今日はこのぐらいにしておきます(後日また加筆するかもしれませんが)

なお、私が連名になっている論文を見て頂ければわかるように、早稲田大学池永研究室 と連携させて頂いておりました。

先生とは転職後も個人的にはお付き合いさせて頂いており、LUT-Network を研究テーマに考えてくださっている学生さんもいらっしゃるようですので、今後、FPGA上でリアルタイム保証のできる LUT-Network がこの分野でもう少し面白い成果が生れてくるかもしれません。

計算機の観点から見てもリアルタイムビジョンの世界はとても興味深いものですの、この分野に興味を持ってくれる方が増えるととても嬉しく思う次第です。

余談

なお最後に余談ですが、タイトルのうち、リアルタイムビジョン と ハイスピードビジョン はそれぞれ異なるもので、高速度カメラの画像を処理するだけなら 十分バッファを持ったキャプチャカードで GPGPU で処理すればいいのですが、「固定時間(それも低レイテンシ)でリアルタイムフィードバックしなさい 」という話になると途端に難易度が上がります。

両方を複合して、「リアルタイムかつハイスピードで、しかもフィードバックによって現実世界に起こる作用まで考えて新しいアルゴリズムと計算機アーキテクチャを考えなさい」となると、非常に新規性の高い研究が生まれやすいフィールドが出来るわけです。 テーマに困っている学生さん、FPGA覚えるだけで周りに差が付けられますよw と誘惑してみます。

LUT-Network を振り返る

はじめに

BinaryBrain の最初のコミット日を調べてみると 2018年8月1日でした。

github.com

LUT-Network という名前のネットワークとその学習環境である BinaryBrain の開発を始めてから 6 年以上が経ったことになります。

世の中の AI が LLMなどで盛り上がるなか、作った本人もなかなか置いてけぼり感を感じながら時間だけ過ぎ去っていった感じはあったのですが、最近になって CQ出版様の Interface誌付録の別冊付録 FPGAマガジン No.3や、別冊付録GOWIN Vol.4 に記事にさせて頂いたりしたこともあり、少し引き合いを頂いたりもしております。有難い限りです。

ということで、今更ながら少し掘り返してみたいと思います。

そもそも何を狙ったものだったのか?

今更ですが当方のライフワークは リアルタイムコンピューティング にあります。 その時点で、「ノンリアルタイムOSの上で動いている AI のフレームワークGPGPU を使って実行」というようなものの相性の悪さが想像していただけると嬉しいのですが、ピンとくる方には来るでしょうし、そうでない方もいらっしゃるでしょう。

リアルタイムコンピューティングでは、フィードバック系での時間保証であったり、そのデータが「いつのものか?」が誤差なく正確であることに重要性があったり、「変化(時間方向への微分)」を正確に測ることが大事だったり、他のアクチュエータと正確に同期していることに価値があったり、まあ様々ですが、計算している間に嫌でも経過していく時間 というものをアルゴリズム要素に加えていこうという試みです。

早い話が、計算において、それに伴う時刻や時間経過が確定的に取り扱えないと困る人たち向けの計算機を考える分野なわけです。

ここで FPGA というのはとても便利なデバイスでして、アルゴリズムをコーディングする段階で、Verilog の always文とかでサイクル毎の処理を記述していくので、いつのデータを計算して、いつ結果を出すか完全に把握できるわけです。さらには PLL を弄って周波数調整したり、クロックの位相ずらしたり、I/Oにある遅延タップを弄ったり、と、ナノ秒超えてピコ秒までソフトウェアで扱えてしまいます。

もちろんいつ来るかわからないデータを待つとか、処理時間の読めないDRAMへのアクセスと同期するとか、不確定要素を持ち込むことはいくらでもできるわけですが、逆に言うとそれさえしなければとても高いリアルタイム性が得られるわけです。

で、まあ、そういう世界でいろいろな事をやっていたわけですが、世の中が AI 一色になってくると無視も出来ないので、AI 的なことやれないかとあれこれ考えるわけですが、DRAM 等を使わずになるべく低レイテンシでサイクル単位で処理時間を固定しようとすると FPGA 内で処理フローを閉じる必要があるわけです。

で、特に画像処理をカメラピクセルクロックで1クロック1データのスループットを保証する世界であれこれやっていた私にとってどういう制約になってくるかと言うと、例えば 100入力100出力のパーセプトロンを1層作ろうとするとDSP(積和乗算器)を 10000個 固定的に並べないといけないという事になるわけです。 まあ、高価なFPGA なら何層かぐらいは入るわけですが、まともに考えると趣味でやるには非現実的な規模になってきてしまうわけです。

とはいえ、そこで諦めるのももったいないので、今ある目の前の お安い FPGAボードに入りきる深層学習の理論限界ってどこよ? という、これまたとりとめのない事を考え始めて LUT-Network が爆誕したわけです。

何が嬉しいのか

大雑把に

  1. 演算のレイテンシが固定
  2. バイス限界の動作周波数が狙える
  3. 回路規模(消費リソース)が読める

となってきます。

まず一つ目ですが、FPGAロジックなので、当然、「XXサイクル後に結果が出る」というのは確定です。例えば 10層のMLP を 500MHz で動かせば、常に 20ns の固定遅延で入力に対する結果が出続けて、揺らぎはナノ秒レベルになります。

これは 非常に時間制約のあるフィードバック信号処理系に AIを突っ込める という可能性の提示に他なりません。

次に周波数ですが、これはまあ副産物みたいなものですが、FPGA の最小演算単位である LUT 1 段で1層出来てしまいますので、1クロックで1層づつ計算させれば配線遅延以外周波数を制約する要素が何もないわけです。

そして最後の回路規模については、学習用のネットワークを作る段階で規模が見えているというか、むしろ 先にデバイスが決まってからそれを学習させている 感じなので、たいへん見積もり性が良いわけです。

今信号処理につかってるFPGAの隙間リソースに「ちょこっとAI」を入れて、出来高払いで精度を見てみよう。みたいなお気楽な事も出来ちゃうわけです。

まだ発展余地はあるのか?

LUT-Network のネット規模はデバイスサイズで制約されます。また、高いリアルタイム性を求められる決まった時間内にできる計算量もたかが知れています。 結局ここが一つの限界点ではあるのですが、リアルタイム処理においてはまだ 過去の計算結果を使って動的計画法的に性能を上げていく という道筋は残っています。 特にハイサンプリングレートの世界ではシンプルな計算で過去から現在を予測しやすいケースがあります(なにしろ周期が早いので、その分世の中があまり変化しないので予測が容易になる)。過去からの情報も使いつつ最新のデータを使ってあくまで最新の出力に最善を尽くす というのは、例えばカルマンフィルタの考え方なんかはほぼこれですし、深層学習で言えば RNN などがこれにあたるかと思います。(結局、状態空間モデルの取り扱いを如何にAIで知的にするかという話に終始して来るのかな?)

とはいえ RNN はなかなか扱いが難しく、いろいろやったあと手が止まっていたりしますが(汗)。

おわりに

まあ、そんな LUT-Network なわけです。世間の「AIでできること」の期待値が LLM の登場であがりすぎて、AI と言うと超知的な事ができることを期待されがちなので、なかなか「AI できます」と言うのが憚られるようになってはいるのですが、それでも「ちょこっとAI」みたいなところに需要があるといいなと思う今日この頃です。

結局、「凄いAI」も「チープなAI」も、ルールベースで攻めるととても大変なタスクを人間に変わって何とかしてくれるという点では共通ですので、かならずしも ChatGPT みたいな凄いものでなくても、機械学習の使いどころはあるのではないかとは思っている次第です。

どこかでまた日の目が見れるといいなと思う次第です。

おまけ

見返してみると 私が最初に fpgax にお邪魔させて頂いた時のサブタイトルや導入が、リアルタイムコンピューティングの話ですね。

きっと聞いてた人は何のことやらだっただろうなと、今更ながら(汗)

speakerdeck.com

パソコンとIoTとを考えてみる

はじめに

一言で「ソフトウェア開発」と言っても非常に手広いと思います。 特に、当サイトでは常々「FPGA はソフトウェアだ」と言っておりますとおり、ソフトウェアの範疇は非常に広いです。

一方で、「ソフトウェア開発」といったときに、やはりパソコンやサーバーやスマホで動くアプロケーションのプログラミングが真っ先に頭に浮かぶ人が大半なのもまた事実かと思います。

ここで少し、パソコンで出来る部分と、パソコンで出来ない部分を考えながら、IoT を考えてみたいと思います。

パソコンのアーキテクチャ

一般的な今時のパソコンのブロック図として、たとえばここから図を引用させてもらいます。

いわゆる CPU には、DDR5-SDRAM や PCIe のインターフェースが出ており、チップセットLSI を通じて、USB であったり、Ether であったり、パソコン に一般的に装備される各種インターフェースを備えています。

逆に言うと、パソコンではこれらのインターフェースでしかパソコン外のものとのやり取りが出来ません。

PC に繋がる周辺機器

例えば Web カメラ

今、私のパソコンに繋がっていた Web カメラを、多分中身はこんな感じじゃないかなと適当に想像しながらお絵描きしたのが下記です。

Webカメラ想像図

この中では様々なデバイスとのインターフェースや、画像処理アルゴリズムや、USBのプロトコルスタックが入っていることが想像されます。 これは、パソコンにUSB しかついていないので、なんとかして イメージセンサを USB に接続できるところまでカメラ側で処理しないといけないのでこうなってるわけです。 中には十分ソフト屋がいろんなアルゴリズム改善の範疇にできるものが含まれていますが、パソコンとUSBを介して切り離されていますので、一般的なパソコン用のプログラマには弄れない領域になってしまっています。

例えばロボット

例えばLANケーブルを介して、制御できるロボットがあったとしましょう。

私は制御は詳しくないので、かなりテキトーですが、例えば下記みたいなものがあると想像されます。

サーボモーターの想像図

制御はPIDに限らず様々なアルゴリズムがあるかと思いますし、ソフトウェアプログラマが腕を発揮できる領域だとは思いますが、残念ながら、パソコンにはサーボに直接つながるようなインターフェースはないので、例えば Ether 経由でさまざまなプロトコルで制御するような場合、こういった構成になってしまい。やはりパソコンの外のプログラムになってしまいます。

パソコンの外のアルゴリズムはハードウェアになりがち

そして、しばし、これらのパソコンに接続されるデバイスはハードウェアになりがちです。

アルゴリズムが専用ASIC化されて固定される場合もしばしばですし、中に入っているマイコンで実行されるコードですら、結局、「一度リリースしたら容易に変更できない」というハードウェアになりがちです。

また、パソコンにプログラミングしているソフトウェアプログラマの多くの方々も、自分の手が出せない部分は「ハードウェア」として取り扱ってしまいがちです。

このような個別の機器をパソコンにつなげば済むものもありますが、パソコンをハブにしてしまうとデバイス同士の連携や同期は困難ですので、やれることに限界が出てくると考えています。

「ソフトウェア」の範疇を広げたい

筆者は「ソフトウェア」の範疇を可能な限り広げて考える事で、プログラムで支配できる領域を拡張したいと常々思っています。

そういった考え方に置いて多くの IoT デバイスは、このパソコンの制約を取り払ってくれます。

その中でも特に FPGA は群を抜いて何でもできるデバイスだと思っています。 なぜなら、あらゆる制約を生み出している、インターフェースI/O そのものをソフトウェアプログラミングできてしまうデバイスだからです。

例えば、イメージセンサのシャッタータイミングと、ストロボ照明と、サーボモーターを一括して動かして、特殊なセンシングを行うようなアルゴリズムを研究したいと言ったとき、そのようなインターフェースがFPGAならプログラムできてしまうわけです。 パソコンで出来ないことを加えるだけで、そうでない人に一歩差をつけた研究開発が可能になります。

パソコンで出来る事とできないことを整理してみる事で、新しい世界も見えてくるのでは無いでしょうか? FPGAユーザーが増えてくれると嬉しいなと思う、今日この頃です。