小さな言語モデルを FPGA で速く動かす、という計画の現在地。 なぜ CPU では遅いのか、FPGA に移すと何が変わるのか、そして昨日それを初めて実測できた話。
やりたいのは 「量子化した小さめの推論モデルを、FPGA で作った自作の演算回路で動かす」ことです。 GPU を買えば速いのは分かっていて、目的は自分で作ることのほうにあります。
ただ、ここまでの調査と実測で、当初の見立てが2回ひっくり返りました。 この資料は、いま何が分かっていて、次に何をするのかを図で共有するためのものです。
ここで大事なのは PL は最初から空っぽ だということです。DSP が 220 個載っていますが、 配線されていないので何もしません。何をする回路にするかを設計して、 ビットストリーム(回路の設計図を焼いたファイル)を作って流し込む、という手順を踏みます。
そして PL は勝手に DDR にアクセスできません。HP ポートという門が用意されていて、 そこを通る回路を自分で組んで初めてメモリに手が届きます。 ADRFT1 で行き詰まったのは、まさにこの門が塞がれていたからでした。
実例として、昨日作った回路が実際にどれだけ使ったかを載せます。
| 資源 | 使用 | 全体 | 割合 | 役割 |
|---|---|---|---|---|
| LUT | 4,360 | 53,200 | 8.2% | 制御・判定・アドレス計算など何でも |
| フリップフロップ | 6,199 | 106,400 | 5.8% | 値を1クロック覚える |
| Block RAM | 11.5 | 140 | 8.2% | まとまったデータの一時置き場 |
| DSP | 0 | 220 | 0.0% | 掛け算専用。今回は計算をしていないので未使用 |
DSP がちょうど 0 なのが分かりやすいと思います。あの回路はデータを運ぶだけで計算をしないので、 掛け算器を1個も使っていません。LUT は何でも屋、DSP は掛け算専門、という分業になっています。
掛け算は LUT でも作れますが、まともな幅の掛け算器を LUT で組むと数百個を食って遅くなります。 だから最初から焼き込んである専用回路が用意されている、というわけです。 このチップの DSP は 25ビット × 18ビットの符号付き掛け算器に 48 ビットの累算器が付いたもので、 INT8 を扱うにはかなり大きすぎます。
重みが +1 / 0 / −1 の三値になると、掛け算は「足す・何もしない・引く」の3択に変わります。 これは掛け算ではないので DSP ではなく LUT で作ります。 つまり三値の道に進むと、効いてくる予算は DSP の 220 個ではなく LUT の 53,200 個のほうです。 ざっと見積もって必要なのは 1,000〜1,500 個程度なので、LUT も余ります。 結局、足りないのは帯域だけ、という結論は変わりません。
これが、この計画で最初にひっくり返った見立てです。 当初は「DSP が何百個も空いているから速くなるはず」と考えていました。実際には DSP はまったく足りていて、足りないのはメモリからの道幅のほうでした。
速くしたければ、重み1個あたりのバイト数を減らすのが一番効きます。 INT8(1バイト/重み)を三値化(約0.2バイト/重み)にすれば、同じ道幅で 5 倍の重みを流せます。 しかも三値なら掛け算が足し算・引き算で済むので、DSP すら要らなくなります。 BitNet b1.58 のようなモデルがこのボードに向いている理由がここにあります。
「PL は同じことを 74% でやります」というのは、こういう意味でした。 同じメモリに対して、CPU は3割しか引き出せないが、PL は7割強を引き出せる。 ハードウェアで直接メモリを叩く回路のほうが、汎用 CPU よりずっと効率よくメモリを使えるということです。
1.54 GB/s という測定値そのものは正しいのですが、その解釈が違いました。 これは DDR の 2.1 GB/s に対する 74% ではなく、PL 側の「道幅」0.80 GB/s に対する 96%です。 AXI の経路は 64 ビット幅=1クロックあたり 8 バイトしか運べないので、 100 MHz では 8 × 100,000,000 = 0.80 GB/s が上限になります。 読みの 0.77 も書きの 0.77 も、DDR ではなくこちらの天井に当たっていました。
読み専用の回路に作り替えて測り直した結果、PL が DDR から読み出せる本当の上限は 1.97 GB/s(DDR の 93.6%)でした。CPU の 33% に対して 2.8 倍で、 「PL のほうが DDR を引き出せる」という結論はむしろ強まっています。 ただし HP ポートを2本使うことが条件で、1本では 53.7% までしか届きません。 詳細は 「二つの天井」へ。
そして ADRFT1 では、CPU が 13% しか引き出せていませんでした。 あのボードで「遅い」と感じていたものの正体は、DDR の性能ではなく CPU がその性能を引き出せていなかったことだったわけです。 「ファブリックに移す価値がある」という仮説が実測で裏付けられたというのは、この差を指しています。
「何もしない回路をわざわざ作った」のには理由があります。 演算器を先に作り込んでしまうと、遅かったときに「回路が下手なのか、道が細いのか」が切り分けられません。 先に道の太さだけを確定させておけば、次に作る演算回路は「その道を食い切れるだけの規模」に設計すればよく、 過剰にも過少にもなりません。
転送後に元データと結果を1バイトずつ照合して完全一致を確認しています。 速いが壊れている、では意味がないので。
これは地味に見えて、この計画で一番大きな成果かもしれません。 ADRFT1 では最後までこの一周が作れませんでした。 FPGA を書き換えるのに専用の器材(3万円以上)が必要で、しかも失敗すると復旧できない、という状態だったからです。 引き出しから出てきた PYNQ-Z1 では、初日にこれが回りました。
ちなみに、KV260($199、性能は PYNQ-Z1 のおよそ 10 倍)への移行を検討していましたが、 PYNQ-Z1 が思ったより使えることが分かったので、判断は保留でよさそうです。 三値化した 135M クラスのモデルなら 512MB のメモリに収まるので、このボードで一度最後まで通せる可能性があります。
| 段階 | やること | 何が分かるか |
|---|---|---|
| 済 | 読み専用の帯域を測る | 2026-09-08 に実施。1.97 GB/s(DDR の 93.6%)。 予想どおり読み専用のほうが出たが、理由は想定と違った—— 伸びしろは書き戻しの分ではなく道幅にあった。 → 「二つの天井」 |
| 次 | INT8 の掛け算器を並べる | 道の太さに合わせた規模で作る。220個は要らない。 確定した設計値は 142.86 MHz で 14 個(全体の 6%) |
| 本命 | 三値(BitNet b1.58)化 | 重み1個あたり 1.0 → 0.2 バイト。同じ道で 5 倍流せる。 1.97 GB/s なら毎秒 9.8 G 個の重み相当 |
見込みとしては、三値化まで進めば 135M クラスで CPU の 10〜20 倍、 毎秒 30 トークン前後は狙えるはずです。ただしこれは今回測った帯域からの試算で、 実際に動かしてみるまでは分かりません。