1 ポイント 投稿者 GN⁺ 4 시간 전 | 1件のコメント | WhatsAppで共有
  • 2013年型のデュアルXeon E5-2690 v2とDDR3で構成されたサーバー上で、Gemma 4 26B-A4B Q8_0をCPUのみで動かし、デコード約5.2トークン/秒、プロンプト評価約16トークン/秒を達成
  • ik_llama.cppの高速パスはAVX2・FMA3を前提としているが、Ivy Bridge CPUはAVX1のみ対応のため、非AVX2ビルド向けのコンパイル修正と演算フォールバックが必要だった
  • グラフビルダーがMOE_FUSED_UP_GATEFUSED_UP_GATEを無条件に生成する一方、非AVX2ディスパッチャーには処理パスがなく、順伝播ごとに約240個のテンソルが計算されないままになり、支離滅裂な多言語出力につながっていた
  • Claudeがロジットの計測とコード解析でエラーを見つけ、融合演算を2回のggml_mul_mat_idggml_fused_mul_unaryに置き換えた。ユーザーは実験を実行し、正常な結果の基準を判定した
  • 古い企業向けサーバーも、有料API障害時のローカル代替手段や低速なバッチ作業に活用できるが、AVX2専用レイアウトを作る--run-time-repackは使ってはいけない

13年前のストレージサーバーの実行環境

  • 再利用したHP StoreVirtual機器は、2013年型のデュアルXeon E5-2690 v2とDDR3メモリを使用しており、GPUはない
    • Ivy Bridge世代のためAVX1のみ対応で、AVX2とFMA3には対応していない
    • もともとはディスクストレージ用に作られたもので、購入費用は300ドル未満
  • 実行モデルはGoogleのGemma 4 26B-A4Bで、260億パラメータを持つオープンウェイトの**混合エキスパート(MoE)**モデル
  • Q8_0量子化モデルで、デコードは約5.2トークン/秒、プロンプト評価は約16トークン/秒と測定された

出発点となった2016年型Xeonの事例

  • Hacker Newsで共有されたA 10 year old Xeon is all you needは、GPUなしで2016年型の単一Xeonと128GB DDR3上でGemma 4を実行した事例
  • その構成ではik_llama.cppと、約25個の細かな実行フラグを使用している
    • 投機的デコード
    • CPUを考慮したMoEルーティング
    • CPU向けFlash Attention
    • 実行時の重み再パッキング
  • 同じアプローチをIvy Bridgeサーバーに適用したが、起動段階で実行が停止した
    • 2016年型Broadwell CPUと異なり、E5-2690 v2にはAVX2とFMA3がない
    • これらの命令セットは2014年のHaswell、つまりIntelのv3世代から提供されており、高速カーネルはそれを前提に書かれていた

Claudeを使った診断とパッチ

  • 起動失敗の情報を受け取ったClaudeは、CPU命令セットの違いを原因として特定した
  • 以前に無料モデルで試みた未完成のアプローチを引き継ぎ、性能上重要なC++パスがAVX2以前のCPUで正しくフォールバックするよう修正した
  • 作業は単一のfix itリクエストで終わるものではなかった
    • 別の開発者が書いた性能重視のC++コードを読む
    • 特定のマイクロアーキテクチャでカーネルが有効でない理由を分析する
    • フォークの既存最適化を捨てずに、サポートされないパスを迂回する
  • ユーザーはC++カーネルのフォールバックを直接書く代わりに、実験を実行して出力を読み、次の質問を決め、正常な結果の基準を判定する役割を担った
  • 診断とパッチは、そのサーバー上で実行されたClaudeインスタンスが行った

非AVX2ビルドで壊れていた演算パス

  • Gemma 4 MoE推論に使用したik_llama.cppllama.cppのフォークで、基本的にAVX2を最小条件と仮定している
  • ビルド時にGGML_USE_IQK_MULMATを無効にすると、大半の高速パスが除外され、通常のスカラー/SSE演算へフォールバックする
    • 一般的なQ8_0行列乗算では、このフォールバックが機能する
    • ただし2つのグラフ演算にはフォールバックが適用されていなかった
  • Gemma 4のMoEフィードフォワードネットワークは次の演算を生成する
    • MOE_FUSED_UP_GATE: エキスパートごとのgate・up行列乗算とSwiGLUを結合した演算
    • FUSED_UP_GATE: 非MoE層で使う密な演算バージョン
  • コンピュートディスパッチャーの2つの演算はGGML_USE_IQK_MULMAT条件で保護されていたが、グラフビルダーは条件なしで演算を生成していた
    • 非AVX2ビルドのディスパッチャーには、該当enumを処理するcaseがなかった
    • 演算がデフォルト分岐に流れ、すべてのエキスパート・フィードフォワードネットワークの出力先テンソルが静かに計算されないままになった
  • Gemma 4 26Bは30層でトークンごとにアクティブなエキスパートを8個使うため、順伝播ごとに、メモリバッファに残っていた値を含むテンソル約240個を消費することになった

支離滅裂な出力に現れた手がかり

  • エラー出力は流暢に見えるものの、意味のない多言語文字列だった
    • 26万2,000語彙全体にトークンIDが均等に散らばっていた
    • タイ語、日本語、<unused>センチネル、英語の断片などが同程度の頻度で生成された
  • 温度0では出力は決定的で、単一スレッドとマルチスレッドの実行結果もバイト単位で同一であり、NaNは発生しなかった
  • 層ごとに大きな定数が隠れ状態を押し上げ、最終softmaxが平坦になる形を示していた
  • Claudeはサンプリング前の生ロジットを計測し、上位5トークン、範囲、平均、NaN数を出力した
    • 最初の予測トークンの平均ロジットは0付近ではなく**+16**だった
    • 語彙全体の約80%が正のロジットを持っていた
  • ランダムな破損と異なりバイアスが一定だったため、隠れ状態の大きな部分が、小さな正の浮動小数点値が残った初期化されていないメモリを使っていると範囲を絞り込んだ

3段階で構成された修正

  • パッチはフォークのmain上に3つのコミットで構成されている
  • 非AVX2コンパイル修正

    • iqk_quantize.cppquantize_row_q8_0_x4quantize_row_q8_1_x4_Tにあるスカラー#else分岐が、実際にはhsum_i32_8などのAVX2ヘルパーを参照していた
    • その分岐を移植可能なスカラーループとして書き直した
    • ggml.cggml-quants.cに漏れ出していた一部のIQK呼び出しに、#if GGML_USE_IQK_MULMAT保護条件を追加した
    • iqk_cpu_ops.cppが単独でコンパイルされるよう、不足していたincludeを追加した
    • この修正がないと、フォーク自体が非AVX2ハードウェアでビルドできない
  • 実行時グラフフォールバック

    • ディスパッチャーを直す代わりに、グラフビルダーがそのビルドですでに計算パスを持つ演算を生成するよう変更した
    • ggml_moe_up_gateGGML_USE_IQK_MULMATが無効なとき、結合されたup_gate_exps重みを処理する
    • テンソル形状は[n_embd, 2*n_ff, n_experts]で、前半がgate、後半がup
    • 2つのggml_view_3dスライスに分離する
    • 各スライスにggml_mul_mat_idを実行する
    • ggml_fused_mul_unary(gate, up, SILU)で2つの結果を結合する
    • gateとupの重みがすでに分離されている場合は、スライスなしで2回のggml_mul_mat_idと融合乗算・単項演算を使う
    • 非MoE層で使うggml_fused_up_gateにも同じフォールバックを適用する
    • mul_mat_idは基本のggml実装を使い、fused_mul_unaryはSILUと乗算を一度に処理するため、すべての構成演算には非IQK実装がすでに存在する
    • 変更全体は#if !GGML_USE_IQK_MULMATの後ろにあるため、AVX2ビルドの結果は従来とビット単位で同一
  • CIスタブの整備

    • IQKソースの#elseスタブがiqk_mul_mat.hと異なっており、非AVX2ハードウェアではci/run.shもビルドできなかった
    • <cstdint> includeが欠けていた
    • 一部のスタブは不要な先頭パラメータを持っていたり、sinksパラメータが抜けていたりするなど、シグネチャが異なっていた
    • 一部の関数はスタブ自体がなく、リンク段階で未定義参照が発生した
    • スタブをヘッダーに合わせることで、非AVX2環境でもテストスイートの実行が可能になった

フォールバックの性能コストと再パッキングの不具合

  • フォールバックは1つの融合カーネルの代わりに2回のmul_mat_idを実行するため、追加コストが発生する
  • このCPUはすでにメモリ帯域幅の制約を受けており、元の融合カーネルもAVX2専用だったため、この環境で諦める既存の実行パスはなかった
  • 最終性能は26B-A4B MoEで、デコード約5.2トークン/秒、プロンプト評価約16トークン/秒
  • --run-time-repackは起動時に量子化重みをAVX2専用のインターリーブ形式であるQ8_0_R8へ再配置する
    • AVX1環境で出力を再び破損させる別のバグ
    • 現在のパッチはこれを修正せず、実行スクリプトからこのフラグを削除している

原因を絞り込んだ過程

  • 命令セットの不一致は簡単に確認できたが、ディスパッチャーがエラーなしでデフォルト分岐に流れる問題は見つけにくかった
  • コードレビューによって複数の候補を除外した
    • RMSNormヘルパーは正しく見えた
    • ggml_vec_dot_q8_0_q8_0のAVX1フォールバックも正しく見えた
    • 単一スレッドの結果がビット単位で同一だったため、スレッド処理のエラーを除外した
  • ロジット平均が+16に固定され、ロングテールのトークン群が似た値を持つことから、残差ストリームの大きな部分が初期化されていないと判断した
  • ディスパッチャーで#if GGML_USE_IQK_MULMATを検索した後、約1分で欠落していた2つの演算パスを見つけた

再現条件と活用範囲

  • AVX2以前の機器での再現条件は次のとおり
    • ハードウェア: デュアルXeon E5-2690 v2、Ivy Bridge、AVX1、DDR3、GPUなし
    • ビルド: パッチブランチのik_llama.cppGGML_USE_IQK_MULMATなしでコンパイル
    • モデル: Gemma 4 26B-A4B Q8_0
    • 実行: 一般的なik_llama.cpp CPUフラグを使うが、--run-time-repackは除外
  • 正確な変更はikawrakow/ik_llama.cpp PR #2138で確認できる
    • 執筆時点ではまだオープンで、管理者レビュー待ちの状態のため、ブランチから直接実行する必要がある
    • 同じ機器で発生したバグはPRスレッドに報告できる
  • 古い企業向けサーバーにローカルモデルを保持しておけば、有料APIが停止したときの代替手段として使ったり、トークン単価が見合わない低速なバッチ作業を処理したりできる
  • サブスクリプションサービスを利用することよりも、見慣れないコードと古いシステムを自分で掘り下げる能力を重視しており、これは15年前のRailsアプリケーションや担当者が去ったデータベースを保守する作業にも同じように当てはまる

1件のコメント

 
GN⁺ 4 시간 전
Hacker Newsのコメント
  • 2027年半ばまでには、2,000億超のMixture of Experts(MoE)モデルを一般消費者向けハードウェアで動かせるようになると予想している
    16GB MacでQwen3.6-35B-A3Bをローカル実行し、毎秒7~9トークン出ている: https://github.com/deepanwadhwa/samosa-chat
    16GB RAMのMacBook AirでGPT-4級モデルがこの速度でローカル実行できていることになる

    • それまで待つ必要すらないかもしれない。Prismが数日前に公開した3値重みモデル Bonsai 27Bは約7GBしかなく、M4 MaxノートPCで毎秒44トークン超を出す: https://huggingface.co/prism-ml/Ternary-Bonsai-27B-mlx-2bit
      すでに大半の2,000億超モデルのアクティブパラメータ数に近いレンジなので、Prismがその気になればそうしたモデルを出せるはず。ただしHRMのような再帰ニューラルネットワークはそこまで多くのパラメータを必要としないため、本当にその規模が必要かは議論の余地がある: https://huggingface.co/sapientinc/HRM-Text-1B
    • 毎秒7~9トークンは、まともな速度とは言いがたい。専門家ではないがローカルで試した限り、毎秒12~16トークンを下回るともどかしかった
    • 予想自体にはおおむね同意するが、時期はもう少し遅れるかもしれない。こうした成果を出すには、今のようにパラメータ当たりのビット数を減らすのとはまったく別の圧縮が必要なので、その段階では従来のパラメータ数という指標自体が意味を失っている可能性がある
      例えば各層に256ビットのシードを1つだけ持たせ、それをノイズ関数に入れて16K個の実際の重みを生成すれば、重み1個あたりの保存サイズを1ビット未満まで下げられる
    • Ornith 35BをPiで動かして毎秒50トークン超出ている。Piが検索と取得もサポートしていると知ってからは、検索用に大規模モデルを探す必要がなくなった
      今月と来月にゲームチェンジャー級の新モデルが続々出そうで楽しみだ。Ornithはぜひ試す価値がある
    • 毎秒9トークンでは厳しいのではないかと思う。Claudeのセッションで1日もたたずに100万トークン使うことも珍しくなく、実運用には遅すぎるように見える
  • 聞きたくない人もいるだろうが、推論プロバイダーのトークン単価はローカル実行の電気代より安いと思う
    単純化のため出力生成だけで計算すると、毎秒5トークンは1時間あたり18,000トークンで、プロバイダーの費用は約0.005ドル。サーバーが推論中に約500Wを使い、電力料金が1kWhあたり0.3ドルのドイツを前提にすると、同じ量をローカル生成するのに0.15ドルかかり、30倍高い
    プライバシーが気になるならローカル実行には依然として価値があるが、推論プロバイダーよりはるかに非効率だという点は認識しておくべきだ。新しいGPUが推論効率を高めるにつれて、この差はさらに大きくなるだろう
    最初は18万トークンと誤計算していたが、実際には18,000トークンなので、電気をほぼ無料で使えない限り競争は難しい。プロバイダー側も小型モデルにまだH200/H100を使っているだろうが、GB300や来年のRuby GPUに切り替われば推論コストは30分の1まで下がり、ローカルモデルの主な価値はプライバシー保護になりそうだ

    • 自宅でQwen 27Bを動かすと、作業中は約400W消費し、生成は毎秒約40トークン、さらに重要なプロンプト処理は毎秒約1,000トークンだ
      1時間で360万入力トークンを処理するか、144,000トークンを生成し、電気代は約0.15ドル。Sonnetで同じ量を処理すると入力は7.2ドル、生成は1.4ドルなので、クラウドは生成で10倍、処理ではほぼ50倍高い
    • アメリカでは1kWhあたり0.30ドルにはまったく近くない。需要の少ない時間帯ならその半分だし、バッテリーに1,000ドル投資して、最安時間帯の0.11ドルの電力を蓄えることもできる
      推論プロバイダーは巨額の負債を抱えて市場シェア争いをしているので、価格は確実に上がるだろう
    • 太陽光とバッテリーで動くオフグリッドのセルフホストLLMサーバーを作れたら素晴らしいと思う。Low Tech Magazineのように日照が足りないときはオフラインになり、友人グループ・通り・サークルなど、地域コミュニティが日常的に使うのに必要な規模で構築する形だ
      AIをコミュニティが直接コントロールできるほど民主化すれば、データセンター問題も解決できるし、検閲やアラインメントの水準もコミュニティが民主的に決められる。Geohotzの一部の投稿に近い構想だ
      オープンソースモデルは、まもなく中古ハードウェアで安価に提供できるほど高性能かつ高効率になるだろう。小さなコミュニティごとに技術に明るい人が1人いて、数百ドルの初期費用を集めれば、その後は電気代なしでほぼ無料運用できる
      https://solar.lowtechmagazine.com/
    • 効率も重要だが、電気が安い人や効率的な機材を持っている人も多い。AMD Strix Haloホームサーバーなら100Wしか使わずにGemma4-26Bをおよそ毎秒70トークンで提供できる
    • もっと費用がかかるかどうかは気にしない。ローカルで動かすのはお金を節約するためではなく、自由とプライバシーを得るためであり、選択肢が存在することで長期的にはコストも下がる
      ローカルという代替手段がなければ、クラウドモデルの価格ははるかに高くなっているはずだ
  • この世代のデュアル Xeon は負荷がかかると 300W 以上を消費する可能性が高い。米国の平均的な電気料金では 1 日 1.35 ドルで、夏場に室内を冷房する必要があるならさらにかかる
    プロンプト処理時間を無視し、24 時間回し続けても 1 日あたり約 40 万トークンなので、出力 100 万トークンあたり約 0.30 ドルになる。偶然にも現在の OpenRouter におけるこのモデルの価格と同じだが、OpenRouter の生成速度は 8 倍速い
    データを家の外に出さないようにするなど、ローカル LLM を試す理由は多いが、金銭的に得をするのは難しい。自宅のローカル推論機材にずっと多くの金を投じた立場からすると、面白くはあっても節約手段ではないと思う

    • 実際の住宅に住んでいる人なら妥当な計算だと思う。私は賃貸住宅に住んでいて電気代を直接払っていないので、大家が苦情を言い始める時点が費用対効果の境界だ
    • ほとんどの人は金を節約するためにモデルをローカルで動かすのではなく、プライバシーをばらまかないためにそうしているのだと思う
    • 暗号資産に似ている。電気代のせいで、大多数にとっては自分で採掘するより 購入したほうが安い
    • 家で暖房をつける寒い季節なら、排熱も使えるので経済性はさらに良くなる
  • GPU なしで デュアル Xeon と DDR4 256GB 上で複数モデルを動かした結果をまとめている
    https://gist.github.com/hparadiz/f3596d00a62d8ebb2dadcc46ee5822c7

    • NUMA の性能低下をなくすために CPU を 1 基だけ使ってみたのか気になる。使えるメモリは半分になるだろうが、性能差がどれくらい出るのか知りたい
    • 遅い RAM が大量にあれば、小型モデルでもかなり速く動くようだ。この機材で より大きなモデルがどう動くのか気になる
  • かなり遅い部類だ。13 年前の CPUでも毎秒 8〜12 トークン出ていて、コンテキストサイズや他の設定によって変わりうる
    https://news.ycombinator.com/item?id=48354801

    • Xeon E3-1270 V2 3.50GHz と古い Nvidia Quadro K2200 4GB でも毎秒 8〜9 トークン出る。Ollama で gemma4:e2b と gemma4:12b-it-qat を動かしている
    • 元記事は Q8 量子化を使っていて、こちらは Q4 を使っている違いがあるのではないか?
  • 元記事の筆者です。元のコメントが何らかの理由で通報処理されたようだ。修正は上流プロジェクトの PR #2138 として開いてある: https://github.com/ikawrakow/ik_llama.cpp/pull/2138

  • この StoreVirtual 機材には、ソフトウェアをインストールするのに使えそうなポートがないように見える。USB ポートくらいしかないが、シリアルコンソール経由でインストールするのだろうか

  • 同じ構成で 2013 Mac Pro 上で Gemma 4 26B を動かしており、毎秒約 5 トークン出ている。デュアル GPU はここでは役に立たないが、一部の作業には十分実用的だ

  • 地下室の構成を実際に見たが、本当にすごい。次は 3D プリンターも紹介してほしい

  • やや関連のある動画として、Pentium 4 で LLM を動かし、NetburstGPTというあだ名を付けていた。もちろん非常に遅い
    https://www.youtube.com/watch?v=ILV-eu90te8