はじめに
計算機の世界で ××倍速い、とか、〇〇倍の効率を達成とか、よく聞くわけですが、いわゆる当社比で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 と比較してどうなんだろう、というところで駄文を書いてみた次第です。