ボトルネック:なぜローカルLLMは遅いのか
Llama-3-70BやMixtral 8x7Bモデルが1秒間にわずか2トークンという低速でテキストを出力するのを待つのは、非常にストレスが溜まるものです。たとえRTX 4090を使用していたとしても、計算上の制約は避けられません。問題はGPUが弱いことではなく、LLMが「自己回帰的(auto-regressive)」であることにあります。LLMはテキストを一度に1つずつ生成するため、たった一つの単語を出力するたびに、数十億のパラメータすべてをスキャンする必要があるのです。
その裏側で、推論は「メモリ帯域幅」の戦いとなっています。GPUは時間の95%を膨大なモデルの重みをVRAMから演算コアに移動させることに費やし、実際の計算にはわずか5%しか使っていません。70Bモデルで1トークンを生成するには、約40GBのデータ(4ビット量子化の場合)を読み取る必要があります。これを繰り返すことは、まさに効率性の悪夢と言えるでしょう。
解決策:「思考の速い」アシスタントによるデコーディング
投機的デコーディング(Speculative decoding)はこの状況を一変させます。巨大で低速な「ターゲットモデル」にすべての重労働を押し付けるのではなく、機敏で小さな「ドラフトモデル」を偵察役として雇います。
連携の仕組みは以下の通りです:
- 推測(投機):1Bや3Bパラメータのモデル(VRAMの隅に収まるサイズ)が、次の5〜8トークンを素早く予測します。小型なので非常に高速です。
- 監査(検証):70Bのターゲットモデルが、その予測されたテキスト全体を1回の並列パスで確認します。そして、「自分も同じことを言っただろうか?」と問いかけるのです。
もし偵察役が5語のうち4語を正解させれば、エキスパート(ターゲットモデル)はそれらを即座に採用します。これにより、巨大モデルを1回動かす「コスト」で4トークンを手に入れたことになります。偵察役が失敗した場合は、エキスパートが最初の間違いを修正し、処理を引き継ぎます。私のテストでは、平凡な偵察役であっても、出力の質を一切落とさずに、ほぼ「無料」で速度を向上させることができました。
環境のセットアップ
これを機能させるには、モデルが同じボキャブラリ(語彙)を共有している必要があります。Llama 3 70Bを実行しているなら、ドラフトにはLlama 3 8BやLlama-3-distilled 1Bモデルを使用してください。GemmaのドラフトをLlamaのターゲットに使うといった異なるファミリーの混在は、内部的な「言語」が異なるため、通常はうまく機能しません。
ここでは、2つの主要ツールに焦点を当てます。llama.cpp(GGUF形式とコンシューマー向けハードウェアの標準)と、vLLM(高速なAPIサーバー構築の定番)です。
ハードウェア要件
- OS:LinuxまたはmacOSを推奨します。Windowsユーザーは、より良いパフォーマンスを得るためにWSL2を使用すべきです。
- VRAM:両方のモデルを収める十分なスペースが必要です。70B Q4_K_Mモデル(約42GB)と8B Q4ドラフト(約5GB)の場合、48GBの構成(3090/4090の2枚刺し)が最適です。
Configuring llama.cpp for Speed
llama.cppでは、--draftフラグを使うことで簡単に投機的実行を行えます。開始前に、ターゲットとドラフトの両方がGGUF形式であることを確認してください。
# Llama-3-70Bを8Bドラフトで高速化する
./llama-cli -m models/llama-3-70b-q4.gguf \
--draft 5 \
-md models/llama-3-8b-q4.gguf \
-p "ニュースの見出しをスクレイピングするPythonスクリプトを書いてください。" \
-n 512 \
--n-gpu-layers 81
調整すべき主なパラメータ:
-md: 小型ドラフトモデルのパスを指定します。--draft 5: 偵察役に5トークン先まで予測させます。ドラフトモデルが優秀な場合は8を試してください。予測精度が低い場合は4に下げます。
両方のモデルをGPU上に置いてください。ターゲットがGPUにあるのにドラフトをCPUにオフロードすると、PCIeのレイテンシによって高速化のメリットが相殺されてしまいます。
Implementing vLLM for API Serving
vLLMは、Webインターフェースを構築する場合により適した選択肢です。投機的デコーディングを動的に処理し、Medusaのような高度なヘッドもサポートしています。
# 投機的実行を有効にしてvLLMサーバーを起動する
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Meta-Llama-3-70B-Instruct \
--tensor-parallel-size 2 \
--speculative-model meta-llama/Meta-Llama-3-8B-Instruct \
--num-speculative-tokens 5 \
--gpu-memory-utilization 0.95
ハイエンドなセットアップを使用している場合は、「Medusa」や「Eagle」ヘッドを検討してください。これらはモデル自体に組み込まれた特殊なコンポーネントで、別のドラフトモデルファイルを用意することなく2倍から3倍の高速化を実現できます。
成功の測定:採択率(Acceptance Rate)
実行を開始したら、体感速度だけでなく、生成終了時に表示される統計情報を確認してください。
- Tokens per Second (TPS): 最終的な成果です。3 TPSから7 TPSに向上していれば成功です。
- Acceptance Rate: 偵察役の推測のうち、エキスパートが採用した割合です。
一般的なチャットにおいて、採択率70〜80%が理想的です。もし40%を下回るようなら、偵察役はほぼ闇雲に推測している状態です。これは通常、ドラフトモデルが小さすぎるか、ターゲットと類似したデータで訓練されていない場合に起こります。
トラブルシューティングのヒント
速度が向上しない場合は、以下の3点を確認してください:
- VRAMの過負荷:OSがシステムRAMのスワップを開始すると、パフォーマンスはほぼゼロになります。必要に応じて、モデルをさらに量子化してください。
- トークナイザーの不一致:ドラフトとターゲットで異なるトークナイザーを使用している場合、エキスパートはすべての推測を拒絶します。必ず同じモデルファミリーを使用してください。
- 予測の深さ(Lookahead Depth):欲張りすぎないでください。
--draft 15に設定すれば速そうに見えますが、推測が外れるたびにエキスパートが再計算を強いられるため、標準的な推論よりも遅くなる可能性があります。
これらの設定をマスターすることで、遅いローカル環境を、商用APIに匹敵するレスポンスの良いアシスタントへと変えることができます。しかも、データはすべて自分の手元でプライベートに保たれたままです。

