6月8日、Neomind Labsが「Running Gemma 4 26B at 5 tokens/sec on a 13-year-old Xeon with no GPU」と題した記事を公開した。地下室に眠っていた300ドル以下の中古サーバーで、Googleの260億パラメータLLM「Gemma 4 26B」をGPUなしで毎秒5トークンという実用速度で動かすまでの、泥臭いデバッグの記録だ。
単なる「動いた」報告ではない。サイレントに計算をスキップし続けるバグを発見し、パッチを書き、マージリクエストを送るまでの一部始終が記されている点がこの記事の核心だ。
「GPUなし、300ドル以下、毎秒5トークン」という事実
| 項目 | 内容 |
|---|---|
| ハードウェア | 中古HP StoreVirtual(Xeon E5-2690 v2 × 2、Ivy Bridge世代、DDR3、GPUなし) |
| 命令セット | AVX1のみ(AVX2・FMA3なし) |
| モデル | Gemma 4 26B-A4B(MoE)、Q8_0量子化 |
| デコード速度 | 約5.2トークン/秒 |
| プロンプト評価 | 約16トークン/秒 |
| ハードウェアの調達コスト | 300ドル以下 |
毎秒5トークン前後は「読む速度(reading speed)」と表現されることがあり、会話として成立する実用水準だ。
Gemma 4はGoogleが2025年にリリースしたオープンウェイトLLMシリーズで、26B-A4BはMoE(Mixture of Experts)アーキテクチャを採用している。MoEは全パラメータのうち一部の「エキスパート」だけを各推論ステップで活性化する設計で、実効的な計算量を抑えながら大規模モデルの表現力を持つ。この構造が後述するバグの舞台になる。
きっかけ——「10年前のXeonで十分」という記事との出会い
きっかけはHacker Newsで話題になった記事「A 10 year old Xeon is all you need」だ。2016年製の単一XeonでGemma 4を動かした内容で、ik_llama.cpp(llama.cppのフォーク。CPU推論の最適化に特化しており、本家では対応していないアーキテクチャ向けカーネルを多数持つ)と約25のフラグを駆使している。
「自分もXeonを持っている」と試したが、起動時にビルドが失敗した。
原因はCPU世代の差にある。その記事のCPUはBroadwell(2015年製)。手元のE5-2690 v2はIvy Bridge(2013年製)。ik_llama.cppの高速カーネルはAVX2とFMA3を前提としているが、これらの命令セットが登場したのはHaswell(v3世代)の2014年以降だ。Ivy BridgeにはAVX2が存在しない。
バグの核心:サイレントに壊れていた前方パス
単にビルドエラーを直すだけでは終わらなかった。ビルドを通したあとも、モデルは流暢に見えるが意味不明な多言語ノイズを出力し続けた。タイ文字、韓国語、<unused>トークン、英語の断片が混在し、温度0でも決定論的に再現する。
診断のため生ロジット(最終softmax前の値)を計測すると、最初のトークンの平均ロジットが本来ゼロ近傍であるべきところ+16を示し、語彙の約80%が正のロジットを持っていた。ランダムな破損ではなく、「大きな定数で隠れ状態が毎レイヤー押しつぶされている」ことを示すパターンだ。
原因はコードの構造にあった。ik_llama.cppのコンピュートディスパッチャーは、GGML_USE_IQK_MULMATが無効なビルドではMOE_FUSED_UP_GATEとFUSED_UP_GATEのケースを持っていない。しかしグラフビルダーはこれらのopを無条件に生成し続ける。ディスパッチャーのswitchでケースが存在しないためデフォルトに落ち、エキスパートFFNの全テンソルが実質的に未計算のまま放置された。Gemma 4 26Bは30レイヤー×アクティブ8エキスパートという構造なので、1回の前方パスで約240テンソル分の計算が無音でスキップされていた。
修正内容:3コミット
パッチはPR #2138として公開されており、記事執筆時点ではレビュー待ちの状態だった(最新状況はPRページで確認できる)。変更の骨子は以下の3点だ。
コンパイル修正:
iqk_quantize.cppのscalar#elseブランチが実際にはAVX2ヘルパー(hsum_i32_8等)を参照していたため、ポータブルなscalarループに書き直した。非AVX2環境でビルド自体が通らない問題を解消する。ランタイムバグの修正:
ggml_moe_up_gateとggml_fused_up_gateにおいて、GGML_USE_IQK_MULMATが無効な場合、グラフビルダーが既存の計算パスを持つopを生成するよう変更。ggml_mul_mat_id(標準ggml実装)とggml_fused_mul_unaryの組み合わせで代替する。変更全体は#if !GGML_USE_IQK_MULMATガードの中にあり、AVX2ビルドへの影響はない。CIスタブ修正:非AVX2ハードウェアでテストスイート自体が動かないよう、スタブのシグネチャ不一致や
<cstdint>の欠落などを修正。
加えて、--run-time-repackフラグは量子化ウェイトをAVX2専用のインターリーブレイアウト(Q8_0_R8)に並べ替えるため、AVX1環境では同様の出力破壊を引き起こす別バグがある。このフラグは実行スクリプトから外すことで回避できる。
再現手順
同じハードウェアで試したい場合のレシピは単純だ。
- ハードウェア:Ivy Bridge世代のXeon(AVX1、AVX2なし)
- ビルド:上記ブランチから
GGML_USE_IQK_MULMATを無効にしてコンパイル - モデル:Gemma 4 26B-A4B、Q8_0
- 実行:通常のCPUフラグを使い、
--run-time-repackは外す
これだけで約5トークン/秒のデコード、GPUなしで動く。
有料APIが落ちたときのフォールバックや、トークン課金では割に合わないバッチ処理の代替手段として、古い企業向けサーバーを活用できる可能性を示す事例だ。ハードウェアの制約を「動かない理由」ではなく「デバッグの起点」として扱う姿勢が、この記事の読みどころだ。
詳細はRunning Gemma 4 26B at 5 tokens/sec on a 13-year-old Xeon with no GPUを参照していただきたい。