「10年前のXeonで最新級のLLMを動かす」と聞くと、正直かなり無茶に見えます。
でも今回の元記事は、その“無茶”をちゃんと工夫で押し切る話で、かなり面白いです。私はこういう、性能の限界をソフトウェアでねじ伏せる系の話が大好きです。ロマンがあります。
舞台は、2016年製の Intel Xeon E5-2620 v4 を積んだ再生サーバー。
メモリはなんと 128GB DDR3。容量はあるけど、速度は今どきのRAMよりかなり遅い。しかも GPUなし。つまり、LLMを動かすにはかなり不利な条件です。
普通なら「じゃあ無理ですね」で終わりそうですが、この記事はそこで終わらない。
著者が狙っているのは、Gemma 4 をこの古いCPU機でできるだけ実用的に走らせることです。
この記事の核はここです。
LLMの推論は、実はCPUの演算能力だけでは決まりません。むしろ多くの場合、ボトルネックは memory bandwidth、つまり「重みデータをどれだけ速く運べるか」です。
これはいわゆる memory wall の問題です。
CPUの演算性能はどんどん上がっているのに、メモリの転送速度が追いつかない。結果、CPUは「計算する準備はできてるのに材料が来ない」という状態になるわけです。かなりもどかしい世界です。
元記事では、ふつうの黒箱ツールではなく、ik_llama.cpp が公開している細かなオプションを大量に使っています。
正直、フラグの羅列だけ見ると呪文です。でも、やっていることは筋が通っています。
このあたり、一般ユーザー向けにはかなりマニアックです。
ただ私は、こういう「便利なUIの裏で何が起きているか」を理解している記事はすごく価値があると思います。AIは派手に見えて、実際はかなり泥臭い最適化の積み重ねなんですよね。
この記事の重要ポイントのひとつが speculative decoding です。
これは、重い“本命モデル”の前に、小さくて軽い“下書きモデル”を走らせて、候補トークンを先回りで出す仕組みです。
要するに、「毎回ゼロから重い計算をする」のを避けるテクニックです。
特にCPUでは、計算そのものよりメモリ転送が高くつくので、軽い drafter を使う価値が大きい。著者はこの点をかなり強く押しています。
個人的にも、これはかなり“AI時代っぽい発明”だと思います。
CPUやGPUの素の力で殴るだけではなく、賢く予測して無駄な読み出しを減らす。まさにソフトウェアでハードウェアの弱点を補う発想です。
Gemma 4 26B-A4B は MoE(Mixture of Experts) 型のモデルです。
MoEは、たくさんある expert のうち、毎回その一部だけを使う方式です。
ここでポイントになるのが、CPUでMoEを回すときの cache thrashing です。
cache はCPU内部の超高速メモリですが、MoEは「たくさんある expert をあちこち参照する」ので、キャッシュがすぐ入れ替わってしまうことがあります。これが cache thrashing。要するに、CPUが毎回バタバタして落ち着かない状態です。
その対策として使われているのが cpu-moe です。
これは expert の選び方や並べ方をCPU向けに調整し、キャッシュに乗りやすくするためのものです。
さらに merge-up-gate-experts によって、expert 内の一部計算をまとめて実行し、メモリ往復を減らしています。
こういう「1回でもRAMとの往復を減らす」工夫は、DDR3環境では特に効くはずです。
CPUは16 thread ありますが、物理コアは8。
記事では -t 8 を使って、物理コア数に合わせています。
これは地味ですが、とても重要です。
LLM推論はメモリ待ちが多いので、スレッドを増やせば増やすほど速くなるとは限りません。むしろ、スレッドを増やしすぎると制御コストが増えて逆効果になることがあります。
ここはまさに「数字が大きいほど偉いわけではない」という、実務的で好きなポイントです。
古いマシンほど、無駄な盛り方より“ちょうどいい設定”が効くんですよね。
mlock と run-time-repack はかなり実戦的mlockこれはモデルのデータをRAMに固定し、OSに勝手にディスクへ退避させないようにする設定です。
もしLLMの重みがswapに行ったら、速度はほぼ終わります。ディスクはRAMより桁違いに遅いので、これはもう戦闘不能レベルです。
記事では、mlock が失敗する場合に ulimit -l の制限が足りない、と説明しています。
つまり、「メモリは足りてるのに、OSの安全設定が足を引っ張る」わけです。こういうの、本当にあるあるです。便利なはずのデフォルト設定が、性能追求の場面では足かせになるんですよね。
run-time-repackこれは読み込み前に重みの並びをCPU向けに再配置するものです。
要するに、RAMの中のデータ配置を「CPUが読みやすい形」に並べ替えるイメージです。
個人的には、この発想はかなり好きです。
データを速くするために、計算前に“置き方”を変える。ものすごく地味だけど、性能改善ってだいたいこういう地味な工夫の集合なんですよ。
no-kv-offload は「いないGPUを探さない」ためのフラグKV cache は、会話の文脈を覚えておく短期記憶みたいなものです。
通常、KV cache はGPUへ逃がして高速化することがあります。でもこの環境にはGPUがありません。
そこで --no-kv-offload を使い、最初からGPUを探しにいかないようにしています。
当たり前に見えますが、こういう「存在しないハードを探させない」ことも性能面では大切です。無駄な判定でつまずくことがあるからです。
記事の後半では -sm graph のようなグラフ分割の話も出てきます。
これは計算をどう分割して複数の処理資源に振るか、というかなり深い話です。
ただし、この記事の実行では
“Split mode 'graph' is not supported for Gemma4 external MTP”
という形で断られ、結局 layer 分割に切り替えられています。
ここはすごく現実的です。
最先端のモデルや推論エンジンは、理論上よさそうでも、実装が追いついていないことがある。AI界隈は特にこれが激しいです。
「最新モデルが出た → そのまま最速で動く」とは全然ならない。むしろ、まずどの機能がまだ対応していないかを探すところから始まる。かなり泥くさい世界です。
この元記事の魅力は、「古いマシンで無理やり動かした」こと自体ではありません。
本当に面白いのは、LLM推論がどれだけ“メモリ設計のゲーム”なのか を、実例で見せてくれるところです。
最新のLLMって、つい「巨大なGPUがあれば速いんでしょ」と思いがちです。
でも実際には、
みたいな、かなりシステム寄りの工夫が効いてきます。
私はこの手の話を見るたびに、AIは「魔法」ではなく「極端に複雑なシステム工学」なんだなと感じます。
そして、10年前のXeonでもここまでやれるなら、ソフトウェア最適化の余地はまだまだ大きい、というのがこの記事の一番のメッセージではないかと思います。