0. 結論を先に
動きました。 Qwen3.8-Flash-Next 専用の推論エンジン Strata の派生、Strata-GLM を Linux と GPU 2 枚に対応させ、320B の GLM-5.3-Flash(unsloth の UD-IQ4_XS、約 157GB)を RTX 4060 Ti 16GB×2 + DDR4 128GB の自作 PC で動かしました。品質は GPU 1 枚のときと同じ(出力分布の差 KL 0.01〜0.03、同じ条件なら 2 回の実行でビット一致)。日本語知識(JamC-QA)は 64.66% で、Qwen3.8-Flash-Next と互角です。
でも、遅かった。 生成は約 4.4 tok/s、最初のトークンまで 15〜50 秒。同じ PC で動かした Qwen3.8-Flash-Next(GPU 1 枚)の 30〜37 tok/s と比べると、生成は約 1/7〜1/8、入力処理は約 1/10 です。
そこで止めずに、なぜ遅いのかを最後まで追いました。 やったことは次のとおりで、本文はこの順に書いてあります。
| やったこと | 分かったこと |
|---|---|
| Strata-GLM のソースを読み、Linux ビルドと 2 枚構成(層分割)に対応(自作パッチ 10 本、GitHub で公開) | 遅い PCIe 側の GPU には層を少なく置く(K=12)。2 枚の品質は 1 枚と同じ |
| プロンプトキャッシュ(snapshot)を 2 枚構成で使えるように拡張 | 続きのターンが 36 秒 → 2〜3 秒、32K の会話で 160 秒 → 2〜10 秒 |
| thinking を切れない問題をサーバー側で修正 | 公式テンプレートに enable_thinking がない。</think> を足して閉じる |
| エンジンログの集計で 1 トークンの時間を分解 | 7〜9 割が CPU のエキスパート計算。GPU は 35 ms しか働いていない |
| スレッド数・PCIe 分担・エキスパートのスキップを実測 | スレッドは 6 本で頭打ち。PCIe 分担は効かない。スキップは +62% だが品質が落ちる(KL 0.19) |
| MTP(投機デコード)をソースと運用ログで評価 | 連続トークンのエキスパートの重なりが 1/3 しかなく、効かない(0.85〜1.08 倍)。作者も不採用 |
| perf で CPU の律速を切り分け | UD-IQ4_XS の中身の 45% が IQ3_S で、その内積カーネルが 1 コア 4.4GB/s で計算律速。メモリ帯域でも GPU でもない |
| マザーボードを替えて PCIe を対称に | 入力処理は −20%。生成は変わらない(CPU 律速の裏付け) |
| 同じ PC で Flash-Next を立てて同じ手順で測定 | 7〜10 倍差。GPU の使用率が逆(GLM は GPU が待つ、Flash-Next は GPU が 98%) |
結論: この構成で GLM-5.3-Flash が遅いのは、157GB のモデルが RAM 128GB に収まらず、VRAM に 16% しか載らない分を CPU が計算するから。直せるもの(カーネル、CPU 交換)を全部積んでも 7〜10 tok/s で、Flash-Next には届きません。逆に言えば、Flash-Next と Strata の強みは「125B が 78GB に収まり、VRAM 16GB のキャッシュが効く大きさ」にある。この領域では、モデルの大きさそのものが設計です。
1 人で長い文書を読ませて質問を重ねる用途なら使えます(2 ターン目からは数秒)。複数人の共有、長い思考、コーディングエージェントには向きません。
1. なぜこれをやったか
当ラボでは DGX Spark と Ryzen AI Max+ 395(EVO-X2)がフル稼働で、GPU の余裕がありません。「16GB クラスの普及帯 GPU で、大きな MoE が実用になるか」を確かめたくて、まず Qwen3.8-Flash-Next(125B MoE)を Strata という推論エンジンで RTX 4060 Ti 16GB 1 枚で動かしました(別記事)。
Strata は「GPU 1 枚 + 大きな RAM」に特化した推論エンジンで、MoE のエキスパート重みを RAM に置き、GPU には使う分だけ流し込む作りです。llama.cpp のように汎用ではなく、対応モデルごとに専用の処理が書かれています。
GLM-5.3-Flash(Zhipu AI)は 320B の MoE で、アクティブ 18B。Strata 本家には GLM 対応がなく、有志のフォーク Strata-GLM(isichan-ai)が GPU 1 枚・Windows 前提で GLM-5.3-Flash を動かしていました。4 ビット級の量子化で 157GB。RAM 128GB、VRAM 16GB×2=32GB の自作 PC に載るか、載ったら使えるのか、を確かめたのがこの記事です。
2. 構成
| 項目 | 内容 |
|---|---|
| CPU | Ryzen 5 5600(6 コア 12 スレッド、Zen3、AVX2 のみ・VNNI なし) |
| RAM | DDR4-3200 128GB(デュアルチャネル。連続読みの実測上限 約 45GB/s) |
| GPU | RTX 4060 Ti 16GB × 2 |
| マザーボード / PCIe | 測定の大半は ASRock B550M Pro4。GPU0 がチップセット経由 Gen3 x4(実測 約 3GB/s)、GPU1 が CPU 直結 Gen4 x8(約 13GB/s)という非対称。最後に GIGABYTE X570 AORUS PRO に替えて両方 Gen4 x8(13.5GB/s)にし、違いを測った(§5-1) |
| OS | Ubuntu 22.04、CUDA 13.4(pip で導入、sudo 不要) |
| モデル | GLM-5.3-Flash、unsloth 公式 UD-IQ4_XS(5 ファイル、約 157GB) |
| エンジン | Strata-GLM(6feb85f)+ 自作パッチ 10 本(§3) |
RTX 4060 Ti は省電力設計で、負荷をかけないと PCIe のリンク速度が出ません。帯域を測るときは GPU に負荷をかけてから測る必要があります(最初に測ったとき、アイドルの値を見て「遅い」と誤解しました)。
3. Strata-GLM を Linux・GPU 2 枚で動かすまで
Strata-GLM は Windows・GPU 1 枚が前提で、そのままでは Linux でビルドできず、2 枚構成の引数(--layer-split)は GLM の処理に対応していませんでした。§0 の表の 1〜3 行目を詳しく書きます。手を入れたのは次の 3 か所です。
(1) Linux ビルド対応。Windows 固有の API 呼び出しとビルド設定の修正。CUDA ツールキットは pip の nvidia-cuda-nvcc 等で venv に入れ、シンボリックリンクでツールキットの形に組みました(sudo 不要、ビルド約 4 分)。
(2) GPU 2 枚への層の分割。層 0〜K-1 を GPU0、層 K〜44 と出力ヘッドを GPU1 に置き、層の間は RAM 上のピン留めバッファで受け渡します(GPU 間の直接転送=P2P は使いません。1 トークンあたり 82KB と小さい)。入力処理(一括処理の経路)では、各 GPU が自分の層のエキスパートを RAM から取り寄せるので、遅い PCIe につながった GPU には層を少なく置くのが正解でした。K=12(GPU0 に 12 層、GPU1 に 33 層)で、K=23(半々)より入力処理が約 10% 速くなります。
(3) cuBLAS のストリーム指定漏れの修正。2 枚で動かすと数値が揺れる原因になっていた、計算の順序の問題を直しました。
加えて、運用で必要になった 2 つ。
(4) プロンプトキャッシュを 2 枚構成で有効化(§6)。元のコードは 2 枚のとき自動でキャッシュを切っていました。
(5) thinking を無効にできない問題の修正。GLM-5.3-Flash の公式チャットテンプレートには enable_thinking がなく、無効を指定しても推論文が出ます。サーバー側でプロンプトの末尾に </think> を足して閉じる修正を入れました。
パッチ 10 本は GitHub で公開しました。 Strata-GLM のフォークに linux-2gpu ブランチとして置いてあり、clone してそのままビルドできます。作者が取り込みやすいよう、1 本ずつのパッチファイルも同梱しています。
- ブランチ: https://github.com/nabe2030/Strata-GLM/tree/linux-2gpu
- 使い方(ビルド手順、2 枚の起動例、K の決め方): README-LINUX-2GPU.ja.md(英語版 README-LINUX-2GPU.md)
- パッチ単体: patches/linux-2gpu/(6feb85f に順に当てる 0001〜0010)
ライセンスは元のまま MIT です。Strata-GLM の作者には Linux ビルドと cuBLAS の件を issue で報告済みで(#2、#3)、公開したブランチの場所も伝えています。
3-1. 2 枚で品質が落ちていないことの確認
速さを測る前に、2 枚に分けても計算結果が変わっていないことを確かめました。方法は トークン列を固定した比較(教師強制): 同じ入力と同じ出力トークン列を強制して、各位置でモデルが出す確率分布を 1 枚構成と 2 枚構成で取り、その差(KL ダイバージェンス)を見ます。自由生成で文章を見比べるより厳密で、1 トークンの違いで以後の文が分かれる問題も避けられます。
| 比較 | 平均 KL | top-1 一致 |
|---|---|---|
| 2 枚(K=12)vs 1 枚 | 0.008〜0.016 | 97〜100% |
| 2 枚、同じ条件で 2 回 | 0(ビット一致) | 100% |
| 1 枚どうしで GPU キャッシュの数だけ変えた場合(物差し) | 0.006〜0.014 | 95〜99% |
GPU のキャッシュ数を変えただけ(どのエキスパートを GPU で計算するかが変わる)でも KL 0.01 前後の差が出るので、2 枚に分けた差はその誤差の下限と同じ桁です。
4. 速さ — 何が決めているか
生成は約 4.4 tok/s。1 回の処理(1〜1.4 トークンを出す)に約 210 ms かかり、その 7〜9 割が CPU のエキスパート計算です。GPU が働いているのは 35 ms ほどしかありません。
中で何が起きているかを追うとこうなります。GLM-5.3-Flash は 45 層のうち 42 層が MoE で、各層で 128 個のエキスパートから 8 個を選びます。1 トークンで触るエキスパートは約 360 個、重みにして約 2GB。VRAM には全エキスパートの 11% しか載らないので、残り約 244 個(約 1.9GB)を毎トークン RAM から読んで CPU が計算します。DDR4 デュアルチャネルの実測上限は 45GB/s ですが、エンジンの実効は約 17GB/s。速さを決めているのはここです。
4-1. 試して効かなかったこと
| 試したこと | 結果 | 理由 |
|---|---|---|
| GPU を 2 枚にする(1 枚 → 2 枚) | 生成 3.1 → 4.4 tok/s(+40%) | VRAM が増えてキャッシュに載るエキスパートが増えた分だけ。2 倍にはならない |
| CPU スレッドを増やす(4 / 6 / 10 / 12) | 4.9 / 5.3 / 5.3 / 3.6 tok/s | 6 本で頭打ち。12 本は GPU 駆動や IO のスレッドが CPU を取れず逆に遅い |
RAM からの読みを PCIe 経由で GPU に回す(--pcie-frac) |
0〜+8%、0.5 では悪化 | 遅い PCIe の GPU0 に送ると GPU 側の時間が跳ね上がる |
| エキスパートのスキップ(重みの小さいものを計算しない) | +62%(8.6 tok/s) だが KL 0.19 | 誤差の下限の 4 倍以上、top-1 一致 80%。品質を落とすので不採用 |
| MTP(投機デコード) | 見込み 0.85〜1.08 倍 | §7 |
スレッド数が 6 で頭打ちになる理由は、最初は分かりませんでした。メモリ帯域が詰まっているなら、2 スレッドで 45GB/s に届く PC でエンジンが 17GB/s しか使えていないのはおかしい。計算がコアあたりで詰まっているなら、4 → 6 本で +50% 近く伸びるはずで、実測は +8%。候補は (a) 1 トークン内のタスクの粒度が粗く、6 本以上に分けても最後の待ちが残る、(b) エキスパートの重みが 4KB ページの mmap 上にあり TLB ミスとページ走査で連続読みの速さが出ない、(c) AVX2 のみの dequant+内積がコアあたりで頭打ち、の 3 つ。
4-2. perf で切り分けた結果 — 犯人は IQ3_S の内積カーネル
生成中に perf でサンプリングしたところ、CPU 時間の 42% が ggml_vec_dot_iq3_s_q8_K(IQ3_S 形式の内積)、16% が ggml_vec_dot_iq4_xs_q8_K(IQ4_XS の内積)、29% がワーカーのスピン待ちでした。
ここで気づいたのが、unsloth の UD-IQ4_XS は中身が 1 種類ではないこと。「UD(Unsloth Dynamic)」は層やテンソルごとに量子化を変えて容量を詰める方式で、このモデルではエキスパートのバイト数の約 45% が IQ3_S、約 55% が IQ4_XS でした。
2 つのカーネルを単独で測ると、性格がまったく違います。
| カーネル | 1 コアあたり | 6 コア | 12 スレッド(SMT) | データが L2 に収まる 1MiB のとき |
|---|---|---|---|---|
| IQ3_S の内積 | 4.4GB/s | 26GB/s | 26.5GB/s(増えない) | 同じ 4.4GB/s |
| IQ4_XS の内積 | 14GB/s | 42GB/s(4 コアで到達) | 40GB/s | — |
IQ3_S はデータが L2 キャッシュに収まっていても 4.4GB/s で、メモリではなく計算(ビットの展開とシャッフル)がコアあたりで頭打ち。物理コア数に比例するので 6 本で止まり、SMT の 12 スレッドにしても伸びない。一方 IQ4_XS は 4 コアで DDR4 の上限に届く、メモリ律速のカーネルです。TLB・ページ走査は否定(dTLB ミスは出ているが計算側が遅くて隠れている)、タスクの粒度による待ちは 1 トークンの 1 割程度でした。
「6 本で頭打ち」の正体は、IQ3_S 部分の計算が物理 6 コアで飽和していたことでした。
4-3. CPU を替えたら速くなるか
この結果で、CPU 交換の見立てが変わりました。
- Ryzen 9 5900X(12 コア、同じ DDR4)に替えると、生成は約 1.35〜1.45 倍(5.4 → 7.3〜7.8 tok/s)。IQ3_S 部分が物理コア数に比例して速くなるため。ただし IQ4_XS 部分はすでに DDR4 の天井にいるので、そこは伸びない。
- CPU を替えずにコードで直す手もある。IQ3_S の内積カーネルを IQ4_XS 並み(14GB/s/コア)にできれば、同じ CPU で +20〜25%。出力は変わらない(可逆)。
- DDR5 世代(Zen4/5)なら両方の天井が上がり、+50〜80% 級の見込み(実測なし)。
- もう一つ、量子化の選び方。この構成では「ファイルが小さい形式」より「CPU カーネルが速い形式」が効きます。IQ3_S を含まない量子化なら、同じ容量でも速い可能性があります(未検証)。
CPU 時間をゼロにしても GPU 側の約 40 ms が残るので、この構成の理論上限は約 25 tok/s です。
5. 入力処理 — 最初のトークンまでの待ちは、入力の長さに比例しない
| 入力トークン | GLM-5.3-Flash(2 枚) | Flash-Next(同じ PC、1 枚) |
|---|---|---|
| 560 | 42 秒 | 2.6 秒 |
| 4,400 | 40〜50 秒 | 4.4 秒 |
| 32,000 | 161〜185 秒 | 21 秒 |
| ShareGPT 200 問の中央値(平均 237 トークン) | 14.5 秒(p99 53 秒) | 1.5 秒(p99 3.3 秒) |
GLM は入力の長さにほぼ比例しません。Strata の一括処理(チャンク 4096 トークン単位で層ごとにまとめて処理する方式)は、チャンクごとに「使われたエキスパートを層ごとにまとめて GPU に流す」作りで、短い入力でもほぼ全エキスパートを流します。そのため、入力がどれだけ短くても十数秒〜50 秒の立ち上がりがかかります。4,400 トークンまではこの立ち上がりが時間の大半を占め、32K で初めて長さに比例する領域に入ります(約 200 tok/s。Flash-Next は約 1,480 tok/s)。
256 トークン未満の入力は 1 トークンずつの逐次処理の経路(立ち上がりなし、1 トークン約 0.15 秒)のほうが速いので、切り替えの閾値を 256 に置いています。
5-1. マザーボードを替えたら(GPU0 を Gen3 x4 → Gen4 x8 に)
測定の大半を行った ASRock B550M Pro4 では、GPU0 がチップセット経由の Gen3 x4 で、入力処理のときに GPU0 への転送待ちが出ていました。CPU 直結の x16 スロットが 2 本ある GIGABYTE X570 AORUS PRO に替えて、両方を Gen4 x8(実測 13.5GB/s、左右対称)にしたときの変化です。
| ASRock B550M Pro4(x4 + x8) | GIGABYTE X570 AORUS PRO(x8 + x8) | |
|---|---|---|
| 長文 4,147 トークンの入力処理(K=12) | 81 秒 | 65 秒(−20%) |
| うち GPU0 へのエキスパート転送 | 10.8 秒 | 4.2 秒 |
| 層の分け方 K による差 | K=8〜30 で 80〜92 秒(K が大きいほど遅い) | K=8〜23 で 64〜65 秒(差なし) |
| TTFT 初回 86 トークン | 21 秒 | 11〜13 秒 |
| TTFT 初回 32K | 161 秒 | 135〜146 秒 |
| 生成速度 | 5.4 tok/s | 5.5 tok/s(変わらず) |
| ShareGPT c=1 の生成中央値 / TTFT 中央値 | 4.40 tok/s / 14.5 秒 | 4.68 tok/s / 14.1 秒 |
転送待ちが消えた分だけ入力処理が縮み、K の選び方で悩む必要もなくなりました。一方で生成速度はまったく変わりません。生成を決めているのは CPU の計算だという、もう一つの裏付けです。
6. プロンプトキャッシュ — 2 ターン目から速くなる
最初の待ちが長いぶん、2 ターン目以降で前の計算を使い回せるかが実用性を決めます。Strata-GLM は GPU 1 枚のときだけ「直前のプロンプトの状態(snapshot)」を保持していて、2 枚では切っていました。各 GPU が持つ状態を順に保存・復元するように拡張したところ:
| 会話 | 1 回目 | 同じ入力の再送 | 続きのターン |
|---|---|---|---|
| 英語 4.4K トークン | 39.5 秒 | 0.2 秒 | 2.8 秒 |
| 英語 32K | 162 秒 | 0.3 秒 | 2.2〜2.8 秒 |
| 日本語 32K | 161 秒 | 0.3 秒 | 1.9〜9.8 秒 |
保存と復元はビット一致(再送の KL 0)。再開した続きと最初から全部読んだ場合の差は KL 0.03〜0.05 で、同じ入力を別の履歴の後に投げただけでも 0.04 の差が出るので、誤差の下限の桁です。
弱点は 割り込み。別の会話の要求が 1 本挟まると、元の会話は最初から読み直しになります(4.4K で 37 秒、32K で 160 秒)。OpenCode のようなハーネスは会話の途中にタイトル生成などの短い要求を挟むので、使い方によってはこの効果が消えます。会話ごとに状態を RAM に複数保持する拡張(案 B)は未実装です。
7. MTP は救いにならない
Strata の Qwen3.8-Flash-Next では MTP(モデル自身の nextn 層で次のトークンを下書きし、まとめて検証する投機デコード)が、Ryzen AI Max+ 395 の機体で 28 → 44 tok/s と 1.5 倍を出しています。GLM-5.3-Flash にも MTP 層(blk.45)があり、GGUF にも入っています。期待して調べましたが、ソースと運用ログから出た結論は 効かない見込み(0.85〜1.08 倍) でした。
理由は律速の場所です。MTP で k トークンをまとめて検証すると、CPU が読むエキスパートは k トークン分の和集合になります。GLM では連続するトークンが同じエキスパートを使う割合が約 3 分の 1 しかなく(運用ログ 188 要求の回帰)、まとめて検証する数を 1 トークン増やすごとに CPU の仕事が 0.67 トークン分増えます。律速が CPU なので、下書きが当たって稼いだ分と同じだけ CPU 時間が増え、償却できるのは GPU の 35 ms だけ。Strata-GLM の作者自身も GLM で MTP を測って「遅くなった」と記録し、採用していません。別のフォーク(lighttransport、CPU エキスパート構成)でも +7〜20% 止まりです。
Flash-Next で効くのは、VRAM に載る割合が高く、GPU 側の時間が償却の対象になるからです。「MTP が効くかはモデルではなく、重みがどこにあるかで決まる」というのが、この構成で分かったことです。
8. 4 軸の測定
当ラボの定型(①速度、②日本語知識、③コーディング、④マルチモーダル)で測りました。比較相手は、同じ Strata で動かした Qwen3.8-Flash-Next です。
8-1. ①速度(方式4: vllm bench serve、ShareGPT 200 問、c=1)
| GLM-5.3-Flash(2 枚、IQ4_XS、157GB) | Flash-Next(同じ PC、1 枚、IQ3_S、78GB、MTP あり) | Flash-Next(同上、MTP なし) | |
|---|---|---|---|
| 生成 tok/s(要求ごとの中央値) | 4.40 | 37.4(8.5 倍) | 30.4(6.9 倍) |
| 総スループット(入力+生成 / 所要) | 6.32 tok/s | 63.6 tok/s(10 倍) | 53.5 tok/s |
| TTFT 中央値 / p99 | 14.5 秒 / 53 秒 | 1.5 秒 / 3.3 秒 | 1.5 秒 / 3.2 秒 |
| 200 問の所要 | 3.9 時間 | 24 分 | 29 分 |
| GPU の使用率 | GPU0 16%、GPU1 69% | GPU1 98% | GPU1 99% |
| CPU の使用率 | 76% | 44% | 46% |
同じ PC で、GLM は GPU を 2 枚使って 4.4 tok/s、Flash-Next は 1 枚で 30〜37 tok/s。GPU の使用率が逆のことを言っています: Flash-Next は GPU が 98% 働いて GPU 律速、GLM は GPU が待っていて CPU 律速。モデルの大きさ(157GB は RAM に収まらず、78GB は収まる)、量子化(IQ4_XS 対 IQ3_S)、GPU の枚数が違うので「モデルそのものの差」ではありませんが、この PC で何が実用的かを決めるのは、重みがどこに置かれて、誰が計算するかだということは、この 2 つの数字で言えます。
MTP は Flash-Next を 1.2〜1.3 倍にしました。GLM では効かない見込み(§7)。
c は同時に投げる要求の数で、c=1 は 1 人で使う状況です。Strata は要求を 1 件ずつ処理するので、c=2 にしても総スループットは変わらず(6.3 → 6.7 tok/s)、2 本目は待つだけで所要が 2 倍になります。チームで共有する用途(c≧8)は対象外です。
なお vllm bench serve の報告値は Strata では使えません(ストリーミングの形式の違いで 80/200 件が空と数えられ、TTFT が 8 ms と出る)。上の値はサーバーログから再計算したものです。
8-2. ②日本語知識(JamC-QA)
JamC-QA は SB Intuitions が公開した、日本固有の知識を問う 4 択問題 2,309 問です。3-shot、思考なし、4 択一致判定で測りました。
| モデル | 正解率 |
|---|---|
| GLM-5.3-Flash(本構成) | 64.66%(1,493 / 2,309) |
| Qwen3.8-Flash-Next(Strata、300 問のみ) | 66.0% |
| Qwen3.8-Flash-Next(DGX Spark、SGLang、2,309 問) | 64.57% |
互角です。カテゴリ別では歴史(72%)・医療(73%)が高く、地理(54%)が低い。Flash-Next と同じ傾向でした。
気づいた点が 2 つ。(1) 回答トークン数の上限 8 で打ち切られた問が 102 問(4.4%)あり、中身は「答えの数字のあとに Wait, let me reconsider. と続けようとしたもの」。思考を切っても自己修正を始める癖があり、この 102 問の正解率は 50%(他は 65%)。(2) 4 つの選択肢のうち 4 番目を選ぶ回数が正解より 91 少ない偏りがありました。
1 問あたり 37 秒(ほぼ全部が入力処理の立ち上がり)で、2,309 問に約 24 時間かかりました。
8-3. ③コーディング(Aider Polyglot)— 打ち切り
Aider Polyglot は Exercism 由来の 225 題を 6 言語で解かせ、テストが落ちたらエラーを見せてもう 1 回直させるベンチマークです。
思考ありで測ると 1 題 90 分、32,768 トークンを思考で使い切る題もあり、225 題で 20 日かかる見込みになりました。思考なしに切り替えても 1 題 17 分(約 2 日)。75 題で打ち切りました。 打ち切り時点の参考値は pass_rate_1 14.7%、pass_rate_2 50.7%(思考なし、1 並列)。225 題の値ではなく、題の順序による言語の偏りもあるので、Flash-Next(DGX Spark、思考あり、pass_rate_2 56.9%)とは比べられません。
ここで分かったのは数字より、この速さではコーディングエージェントの用途に入らないことです。Aider は 1 題に数千〜数万トークンを生成します。4.4 tok/s では 1 題に十数分〜1 時間かかり、待てません。
8-4. ④マルチモーダル
GLM-5.3-Flash はテキスト専用なので対象外です。
9. 速くする余地は、構造的にどれだけあるか
「遅い」で終わらせず、直せるものと直せないものを分けて、直せるものを全部積んだらどこまで行くかを見積もります。
| 要因 | GLM-5.3-Flash(157GB) | Flash-Next(78GB) | 直せるか |
|---|---|---|---|
| モデルが RAM に収まるか | 収まらない。VRAM に 16%、残りを CPU が計算 | 収まる。VRAM のエキスパートキャッシュが効き GPU 律速 | 直せない(モデルの大きさ) |
| トークン間でエキスパートが重なる割合 | 約 1/3 → MTP が効かない | 高い → MTP で 1.2〜1.5 倍 | 直せない(モデルの性質) |
| CPU の内積カーネル(IQ3_S) | 1 コア 4.4GB/s で計算律速 | 関係ない(GPU 律速) | 直せる。+20〜25% |
| CPU のコア数 | 物理 6 コアで飽和 | 関係ない | Ryzen 9 5900X で 1.35〜1.45 倍 |
| 入力処理の立ち上がり | チャンクごとに全エキスパートを流す | 同じ設計だが量が少ない | マザーボードで −20%。残りはエンジンの設計 |
| GPU 側の時間 | 1 トークンあたり約 40 ms | — | CPU をゼロにしても残る上限(約 25 tok/s) |
直せるものを全部積む(カーネル改善 + 12 コア CPU)と、5.5 → 7〜10 tok/s が見込みです。Flash-Next の 30〜40 tok/s には届きません。根本は「RAM に収まらないモデルは、収まらない分を CPU が計算する」ことで、どれだけ CPU を速くしても、GPU で計算する Flash-Next と同じ土俵には乗りません。
逆に言うと、Flash-Next と Strata の強みはここにあります。125B のモデルが 78GB に収まり、RAM 128GB の PC で VRAM 16GB のキャッシュが効く大きさ。GPU の計算力でなく、「どこに重みを置けるか」が速さを決める領域では、モデルの大きさそのものが設計の一部です。
構造を変える手が一つだけあります。GLM を 2 ビット級の量子化(約 100GB)にして RAM に収めること。他のフォーク(project-maya)が「V100×2・RAM 30GB で 28〜40 tok/s」と言っている構成はこれで、VRAM 64GB が前提ではあるものの、RAM に収まるだけで CPU の仕事は大きく減ります。品質は落ちるので、KL で測って天秤にかける話になります。次にやるならこれです。
10. まとめ — この構成で GLM-5.3-Flash は使えるか
| 軸 | 結果 |
|---|---|
| 動くか | 動く。品質は 1 枚と同じ(KL 0.01 前後) |
| 速さ | 生成 4.4 tok/s、最初のトークンまで 15〜50 秒(キャッシュなし)、続きのターンは 2〜10 秒 |
| 日本語知識 | JamC-QA 64.66%、Flash-Next と互角 |
| コーディング | 遅すぎて測り切れない(75 題で打ち切り) |
| Flash-Next との比較(同じ PC) | 生成は 1/7〜1/8、入力処理は 1/10。知識は同等 |
向いている使い方: 1 人で、長い文書を読ませて質問を重ねる用途。最初の 1 回は待つが、2 ターン目からは数秒で返る。品質は 320B 相応。
向いていない使い方: 複数人での共有(直列処理)、長い思考を要する課題(32K トークンの思考に 2 時間)、コーディングエージェント。
何が足りないか: GPU でも VRAM でもメモリ帯域でもなく、RAM 上のエキスパートを CPU が計算する内積カーネルの速さでした。16GB×2 の GPU はモデルの 16% しか持てず、残り 84% を CPU が計算する。その中の IQ3_S 形式の部分が 1 コア 4.4GB/s で頭打ちになり、6 コアで飽和する。MTP でもエキスパートのスキップでも埋まりません。埋める手は §9 の 3 つ(カーネルの書き直し、コアの多い CPU、DDR5 世代)と、量子化を「ファイルの小ささ」でなく「CPU カーネルの速さ」で選ぶことです。
他のフォーク(project-maya の「V100×2 で 40 tok/s」など)の数字と並べると見劣りしますが、条件が違います。VRAM 64GB でモデルの 6〜7 割を載せ、2 ビット級の量子化で、受理率 97% の MTP の最良値です。16GB×2・4 ビット級・RAM 128GB という「VRAM に 16% しか載らない」領域の数字は、調べた範囲では他にありませんでした。この記事の数字は、その領域の現実です。
おわりに — 当ラボについて
筆者は NPO法人 IoTメディアラボラトリーで、IoT 研究とあわせて AI 分野の検証を担当しています。東京大学・本郷キャンパス 大学院工学系研究科の同名のラボで行っていた IoT 研究が独立し、研究機関として活動を続けている組織です。
私がやっていることは、本記事のようなローカル LLM の実機検証が中心です。新しいモデルが出るたびに手元のハードで動かし、速度・日本語知識・コーディング・マルチモーダルの 4 軸で測り、動かなければ原因を突き止めるところまでやります。ベンダーの公称値ではなく、実際に自分の機械で何が起きるかを知りたいからです。
そのぶん、計算資源はいくらあっても足りません。もっと GPU が欲しい(笑)。機材の提供、検証のご依頼、共同研究など、お声がけいただけると喜びます。
付録 A. 測定の方法と条件
- 品質: トークン列を固定した比較(教師強制)。48〜128 トークンの固定列で各位置のロジットを保存し、KL(基準‖条件)・top-1 一致・KL>0.1 の位置数で比較。誤差の下限は「同じ入力を別の履歴の後に処理」で 0.03〜0.05。
- 速度: 自前測定は 5 話題 × 200 トークン、貪欲、思考なし、ウォームアップ後。再現のばらつき ±5〜10%。方式4 は vllm bench serve(クライアントのみ docker)、ShareGPT_V3 200 問、seed 0、サーバーログから再計算。
- JamC-QA: sbintuitions/JamC-QA v1.0 test、3-shot、思考なし、max_tokens 8、temperature 0、1 並列。
- Aider Polyglot: 編集形式 whole、2 回まで試行、max_tokens 32768、1 並列。公式 Dockerfile 無改変。
- 本番設定: 2 枚、K=12、常駐 95GiB、VRAM 予約 3400MiB、ctx 262,144、チャンク 4096、pool-workers 10、PF_MIN 256、snapshot 有効、swap なし、エキスパートのスキップなし。
付録 B. 運用で引っかかったこと
- GPU の番号: CUDA の既定の順序では同型 GPU の順が曖昧になる。
CUDA_DEVICE_ORDER=PCI_BUS_IDを必ず付ける。 - swap: 常駐 95GiB をページ固定すると、swap が有効なら起動時に 3〜5GB が追い出され、定常でも出入りする。swap を切り、MemAvailable を監視(2.5GiB 未満で停止)するほうが安定した。
- VRAM の余裕は GPU1 で約 0.6GB。ctx 262,144 で動くが、他のプロセスが GPU を使うと落ちる。
- 起動に約 210 秒。起動直後はエキスパートを SSD から読むので最初の数要求は遅い。ウォームアップを 1 本流す。
- GPU 温度は最大 77℃(85℃ で自動停止する監視を置いた)。
- 一括処理の経路は短い入力(86 トークン)で非決定的(同条件で KL 0.007)。長い入力はビット一致。品質には影響しない大きさ。
付録 C. 公開物
すべて https://github.com/nabe2030/Strata-GLM の linux-2gpu ブランチにあります(MIT ライセンス)。
| 何 | 場所 | 中身 |
|---|---|---|
| 自作パッチ 10 本 | patches/linux-2gpu/ | Linux ビルド、GPU 2 枚の層分割、cuBLAS のストリーム指定、プロンプトキャッシュの 2 枚対応、thinking 無効の修正。調査用フック(環境変数で有効、既定は無効)を含む |
| 使い方 | README-LINUX-2GPU.ja.md | ビルド手順(sudo 不要)、2 枚の起動例、設定例、K の決め方、既知の制限 |
| 測定ツール | contrib/nabelab-tools/ | 教師強制による KL 比較(kl_test.py ほか)、PCIe とメモリ帯域の測定(pcie_bench.cu、bw.c)、内積カーネルのマイクロベンチ(mb.c)、MTP の効きの見積もり(union_stats.py、mtp_model.py)、vllm bench serve の値をサーバーログから再計算する道具(m4_recompute.py)、再開できる JamC-QA(jamcqa_resume.py)、温度とメモリの監視(memwatch.sh) |






