これまで
前回、交換した RAM の無罪を多層検証で証明した。健全になった RAM は、副産物として一つの実験を解禁した。
壊れていた頃、モデルを VRAM から溢れさせてシステム RAM に落とす操作——spill——は封印されていた。故障が集中していたのがちょうど 50GB 帯で、spill でそこを踏むと即クラッシュだったからだ。今なら安全に測れる。ずっと気になっていた「spill するとどれくらい遅くなるのか」を、初めてデータで詰める。
spill とは何か
LLM 推論は、モデルの重みを GPU の VRAM に置いて回すのが基本だ。速いのは VRAM の帯域が桁違いに広いから。だがモデルが VRAM に収まらないと、あぶれた層をシステム RAM に置き、その分を CPU で計算する。これが spill(CPU オフロード)。
遅くなるのは誰でも知っている。知りたかったのは「どれくらい」と「どう」の部分だ。線形に遅くなるのか、それとも別の形なのか。
num_gpu スイープ
qwen3:32b(全 64 層)で、GPU に載せる層数(num_gpu)を振りながら生成速度を測る。tok/s は ollama の応答に含まれる eval_count(生成トークン数)と eval_duration(生成時間)から正確に出せる。
| num_gpu | CPU 上の重み | 生成 tok/s | VRAM 使用 |
|---|---|---|---|
| 0 | ~20 GB | 2.99 | 2 MiB |
| 16 | ~15 GB | 3.76 | 5.9 GB |
| 32 | ~10 GB | 5.43 | 10.5 GB |
| 48 | ~5 GB | 9.64 | 15.1 GB |
| 64 | 0 | 49.61 | 19.9 GB |
| 999 | 0 | 63.78 | 20.2 GB |
(num_gpu:999 は全層 + 出力層まで GPU に載せた場合)
崖
数字を眺めてほしい。num_gpu を 0 から 48 まで上げても、tok/s は 3.0 → 9.6 と這うようにしか伸びない。GPU に半分以上の層を載せても、まだこの程度だ。
ところが 48 → 64 で 9.6 → 49.6 tok/s、約 5 倍のジャンプが起きる。比例カーブではない。崖だ。
なぜこうなるのか。1 トークン生成するには、モデルの全層を順に通す必要がある。GPU 上の層は速く、CPU 上の層は遅い。1 トークンの時間はざっくり:
1 トークンの時間 ≈ (CPU 上の層数 × CPU の 1 層あたり時間) + (GPU 上の層数 × GPU の 1 層あたり時間)CPU の 1 層は GPU より桁違いに遅いので、CPU に残った層が全体を支配する。1 層でも CPU に残っていれば、そこが律速になる。 だから GPU に載せきる直前まで遅いまま、載せきった瞬間に律速が外れて一気に速くなる。これが崖の正体だ。
法則:tok/s ≈ RAM 帯域 ÷ 溢れ GB
もう一歩踏み込める。生成では各トークンで重みを 1 回読むだけ。だから CPU 側は純粋に RAM 帯域律速だ。スイープの各点を「tok/s × CPU 上の GB」で見ると、値が ~50〜60 に収まる(溢れが小さい点ほど下振れするのは、GPU 側の固定時間が相対的に効いてくるから。係数を決めているのは純 CPU の点だ):
num_gpu 48: 9.64 tok/s × ~5 GB ≈ 48num_gpu 32: 5.43 tok/s × ~10 GB ≈ 54num_gpu 16: 3.76 tok/s × ~15 GB ≈ 56num_gpu 0: 2.99 tok/s × ~20 GB ≈ 60つまり tok/s ≈ 実効 RAM 帯域 ÷ (CPU に溢れた GB)。係数の ~60 GB/s が、このマシンの DDR5-5600 dual-channel の実効帯域だ(理論値 89.6 GB/s の 7 割弱。妥当な実効値)。GPU 上の層は相対的にタダなので、速度を殺すのは溢れた分だけ——総モデルサイズではない。ここが直感に反する。
実用限界のモデルサイズ
速度が溢れ量だけで決まるなら、動かせるモデルの上限も逆算できる。VRAM の実効を 28GB(KV キャッシュ等の余白を引く)として、モデルサイズ ≈ 28GB + 許容できる溢れ量:
| 体感 | 許容 tok/s | 溢れ上限 | 積めるモデル(Q4 目安) |
|---|---|---|---|
| サクサク | 10 | ~6 GB | ~34 GB(32B Q6 / 49B Q4) |
| 実用 | 5 | ~12 GB | ~40 GB(70B Q4 がギリ) |
| 我慢 | 3 | ~20 GB | ~48 GB(70B Q5) |
| バッチのみ | 1 | ~50 GB | ~78 GB(容量限界) |
中途半端な spill が一番損だ、というのがこの表の含意でもある。少し溢れた瞬間に崖の下へ落ちる。
70B で答え合わせ
理屈が正しいか、実物で確かめる。llama3.3:70b(Q4, 42GB)をロードした。42GB は 32GB の VRAM に収まらないので、ollama は自動で GPU 73% / CPU 27% に配置——~12GB がシステム RAM へ spill する。
法則の予測は 60 ÷ 12 ≈ 5 tok/s。実測は 4.93 tok/s。ドンピシャだった。
しかもこれは、このマシンで一番重いメモリ配置だ。42GB を VRAM と RAM にまたがせて展開する——前回書いた通り、壊れていた頃なら即死していた構図。それが今は、遅いとはいえ普通に 70B を回せる。
例外:MoE
この法則が崩れる唯一のケースが MoE(Mixture of Experts)だ。MoE は 1 トークンで全パラメータを読まず、アクティブな一部の expert しか読まない。だから見かけのサイズが巨大でも、実際に毎トークン読む量=溢れコストは小さい。デカいモデルを spill で回したいなら MoE 一択、というのが今回のデータからの示唆だ。
まとめ
- 速度はモデルの総サイズでなく「VRAM から溢れた分」で決まる。
tok/s ≈ 実効 RAM 帯域 ÷ 溢れ GB。このマシンでは実効帯域 ~60 GB/s(DDR5-5600 dual-channel)。 - だから性能は「崖」になる。 半分 spill しても半分速度にはならない。GPU に載せきるかどうかの、ほぼ二値の勝負だ。
- 実用限界は VRAM 実効 + 許容 spill。 32GB VRAM + DDR5-5600 なら 70B Q4(~40GB)が実用ライン、実測 ~5 tok/s。じっくり用途なら十分使える。
- それを超えたいなら MoE。 アクティブ分しか読まないので溢れコストが低い。
- そして何より——この実験自体が、RAM が直った証明でもあった。このマシンで一番重いメモリ配置を、落とさずに測りきれたのだから。