オンプレLLM/技術記録
前回の続きです。Ubuntu 24.04 / CUDA 13.0 / nvidia-driver-595-server、llama.cpp を -DGGML_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=86 でビルドし、104GB(4分割GGUF)を配置。構築作業そのものはAIエージェント主導で実働1日でした。
本題はチューニングです。同じバイナリ・同じ重みで、設定だけで3倍の幅がありました。
核心は --n-cpu-moe:層で切らず、役割で切る
llama.cppでGPUに載せる量を決める従来のオプションは -ngl N(上からN層をGPUへ)です。しかしMoEでこれをやると、各層には「共通部」と「専門家」が同居しているため、VRAMに貴重な専門家が中途半端に載り、共通部がCPUに残ります。
2025年8月(PR #15077・2025-08-04マージ)に入った --n-cpu-moe は、これを直交する軸で切ります。
-ngl 99 --n-cpu-moe 999 -t 16 -fa on -c 8192 --no-mmap
-ngl 99 で全層をGPUに指定しつつ、--n-cpu-moe 999 で専門家だけをCPU側へ引き剥がす。結果、VRAMには共通部だけが残り6.7GB、104GBの専門家はRAM常駐という配置になります。この1行があるかないかで、12GBのGPUで177Bが動くかどうかが決まりました。
罠1:最初の計測が、そもそも間違っていた
組み上げ直後の llama-bench は 5.36 tok/s を返しました。実際にはこれは無効値です。104GBがページキャッシュに載り切る前に測っていたため、計測中もディスクから読んでいたのです。
ウォームアップ後の同一条件は 16.66 tok/s。3.1倍の差があり、ここで「遅い」と判断して構成を変えていたら、正しい設定を捨てていました。以降、計測前に必ず free の buff/cache がモデルサイズを超えていることを確認する手順にしました。
罠2:KVキャッシュがモデルをページキャッシュから追い出す
常駐サービス化にあたり -c 16384 でコンテキストを取ったところ、4.8 tok/s しか出ませんでした。原因は容量です。モデル104GBに対しRAMは125GiB。ここにKVキャッシュが乗ると余白が消え、mmapされたモデルページが追い出され、毎トークンHDDを読みに行く状態になります。
対処は2つ組み合わせました。-c 8192 でコンテキストを削り、--no-mmap でモデルを匿名メモリに完全展開して、そもそも追い出されない状態にする。ページキャッシュに依存する構成を、依存しない構成に変えたわけです。
罠3:スレッドを倍にすると遅くなる(2×2で切り分ける)
当初 -t 32 --numa distribute と -t 16 を比べて「遅くなった」ことは分かりました。ただしこれでは、スレッド数とNUMA指定のどちらが効いたのか分かりません。片方ずつ動かした要因計画で測り直します。
- -t 16 --numa distribute:生成 16.79 / PP 131.0
- -t 16 --numa isolate:生成 16.83 / PP 136.1
- -t 32(NUMA指定なし):生成 13.74 / PP 135.6
- -t 32 --numa distribute:生成 13.83 / PP 135.9
結果は明確でした。効いているのはスレッド数だけで、-t 32 にすると生成が 18%落ちます。一方 NUMA指定は誤差の範囲(distributeとisolateで0.2%、指定の有無で0.7%)でした。
より重要なのは非対称性です。スレッドを倍にすると、生成は18%悪化するのに、プロンプト処理は4%改善します。同じ設定変更が逆方向に効くということは、2つの処理の律速要因が違うということです——生成はメモリ帯域律速(SMTでスレッドを増やしても帯域を奪い合うだけ)、プロンプト処理は演算律速(バッチで行列積を回すためスレッドが増えれば素直に効く)。
余ったVRAM 5.2GBを使い切る
ここまでで --n-cpu-moe 999(専門家を全部CPU)でしたが、VRAMは6.7GB/12GBしか使っていません。余りに専門家を数層ぶん戻せます。
- 999(=48層すべてCPU):生成 16.66 / PP 131.1
- 46(2層をGPUへ):生成 17.01 / PP 138.6
- 45(3層をGPUへ):生成 17.31 / PP 140.1
- 44(4層をGPUへ):VRAM不足で起動せず
ここから 1層あたりの専門家=約1.73GB、移設1層あたり0.73ms/token の短縮が求まります。さらに逆算すると、60.0ms/token の内訳が「専門家の読み出し43ms(72%)+その他17ms」と分解できます。この機体の性能は、7割がメモリ帯域で決まっているということです。
カタログ値では決まらない
3つの罠はいずれも、一般論としては逆が正しいものでした。スレッドは多いほうが速い、コンテキストは長いほうが良い、ベンチマークは動かせば数字が出る——この機体とこのモデルの組み合わせでだけ反転します。
AI駆動開発というと生成が注目されますが、実際に効いたのは条件を変えて測り直す作業を、何十回でも厭わず回せることでした。人間だけなら「こんなものだろう」で止まっていた3倍です。
次回は実用性編。ベンチマーク値と実運用値が2.5倍乖離するという、いちばん重要な話を書きます。
当社は、お手元の遊休ハードウェアを活用した「社内専用AI基盤」の構築を支援しています。
既存機材の適性診断は無料。買う前に、config.json とメモリ帯域から「動かせるモデルと速度」を計算してお示しします。
お問い合わせフォーム(「社内AI基盤 相談希望」とお書き添えください)/ info@flagship-ai.jp
シリーズ「レガシー to AI 実録」
- 総集編:1台のPCで22システム・24.6万行 ― AI開発3.5ヶ月の実測記録
- 実録①:20年もののJavaを、約1週間でフル刷新
- 実録②:既存コード0行変更で、基幹系に新しい入口を作る
- 実録③:1ヶ月級の構成検討を、プロトタイプ2日+実測で
- 実録⑥:同じ機体で速度が3倍、--n-cpu-moe と3つの罠
- 実録⑤:VRAM 12GBで177Bを動かす、MoE時代のモデル選定
- 実録⑥:同じ機体で速度が3倍、--n-cpu-moe と3つの罠(本記事)
- 実録⑦:ベンチ16.7・実運用6.6 ― 帯域律速の現実
※本記事の数値は2026年9月時点、Threadripper 1950X / DDR4-2400 4ch 128GB / RTX 3060 12GB / llama.cpp CUDAビルドでの自社実測です。構成により結果は異なります。