8月4日、Vinod Chuganiが「7 Approaches to Reduce Inference Latency in Your LLM Workflows」と題した記事を公開した。この記事では、本番環境でのLLM推論レイテンシを削減するための7つの実践的手法について詳しく紹介されている。
LLMを研究用プロトタイプから本番サービスへ移行する際、エンジニアが直面する最大の壁のひとつがレイテンシだ。チャットUIで応答が数秒以上かかれば、ユーザーは離脱する。コストも跳ね上がる。
まず押さえておきたい基礎として、LLMの生成処理には2つのフェーズがある。プロンプト全体を一括処理するプリフィルフェーズ(コンピュート律速)と、トークンを1つずつ順次生成するデコードフェーズ(メモリ帯域律速)だ。これらがそれぞれTTFT(Time to First Token)とTPOT(Time Per Output Token)という2つの指標に対応する。どの最適化手法がどちらに効くかを意識しながら読むと整理しやすい。
最も効果的な2手法:量子化と投機的デコーディング
量子化(Quantization)― まず最初に試すべき一手
量子化は、モデルの重みを16ビット浮動小数点(FP16/BF16)から8ビット(INT8)や4ビット(INT4)整数に変換することでメモリフットプリントを圧縮する手法だ。
700億パラメータのモデルをFP16で動かすには、ロードするだけで約140GBのVRAMが必要になる。4ビット量子化すればモデルがメモリを通過する速度がFP16比で4倍になり、デコードレイテンシ(TPOT)が直接改善される。
精度低下のリスクはあるが、AWQやGPTQといったモダンな手法を使えばその損失を最小限に抑えられる。インフラ変更なしで即効性が高いため、最初に試すべき施策と言える。
投機的デコーディング(Speculative Decoding)― 条件次第で2〜3倍の高速化
自己回帰生成の本質的な問題は、トークン#5を生成するにはトークン#4が必要、という逐次依存性にある。投機的デコーディングはこれを2つのモデルを組み合わせて回避する:
- ドラフトモデル(小型・高速、例:Llama-3-8B): 複数トークンを高速に予測
- ターゲットモデル(大型・高精度、例:Llama-3-70B): ドラフトの予測を並列で検証
# 注:以下は動作原理を示す疑似コードであり、実在のフレームワークAPIではない
# (元記事も "PSEUDOCODE -- illustrative only, not a real framework API" と明示している)
draft_tokens = draft_model.generate(prompt, n=5) # Near-instant
accepted = target_model.verify(draft_tokens) # Single parallel pass
# If draft is accurate, all 5 tokens are accepted
output_tokens.extend(accepted)
Hugging Faceではassistant_model=draft_modelを.generate()に渡すだけで実装できる。ドラフトモデルの予測精度が高い条件下(ドメインや出力パターンが安定しているケースなど)では、出力品質を落とさずに生成速度を2〜3倍に改善できると元記事では述べられている。ただしこの数値はドラフト精度に大きく依存するため、実際の改善幅はユースケースによって変わる点に注意が必要だ。
残る5手法:それぞれの役割
KVキャッシュ(Key-Value Caching)
Transformerの注意機構では、新しいトークンを生成するたびにすべての過去トークンとの関係を再計算する。KVキャッシュはこの計算結果をVRAMに保存し、次のトークン生成時の再計算を省略する。TPOTを直接削減できるが、生成が長くなるにつれてキャッシュサイズが増加するため、VRAMとのバランス管理が必要になる。
継続的バッチング(Continuous Batching)
静的バッチ処理では、100トークンで終わるリクエストが1,000トークン必要なリクエストの完了を待たされる。継続的バッチング(イテレーションレベルスケジューリングとも呼ばれる)は、トークン単位で完了したリクエストを即座に返却し、空いたGPUスロットに新しいリクエストを割り込ませる。サーバー全体のスループットと個別レイテンシを同時に改善する。
プルーニングと知識蒸留
プルーニングはモデルの重みを削除して構造そのものを小さくする。知識蒸留は大きな「教師モデル」の振る舞いを小さな「生徒モデル」に学習させる手法だ。たとえば感情分析や構造化データ抽出のような特定タスクに70Bモデルを使うのは過剰で、8Bモデルに蒸留することでモデルサイズに比例したレイテンシ削減が期待できる。元記事では具体的なミリ秒値は示されていないが、モデルを大幅に小型化できれば推論時間の大幅短縮につながるというのが趣旨だ。
最適化推論エンジンの採用
標準ライブラリのデフォルト.generate()関数は研究用途向けで、高スループット・低レイテンシの本番環境には不向きだ。vLLM、Text Generation Inference(TGI)、TensorRT-LLMといった専用フレームワークへの移行が推奨される。これらはPagedAttention(KVキャッシュの非連続メモリ管理)・継続的バッチング・最適化CUDAカーネルを自動的に組み込んでいる。
コンテキストとプロンプト管理
RAGパイプラインでは、ベクターDBから取得した大量のコンテキストをプロンプトに詰め込むことが多い。不要なトークンはすべてプリフィル計算時間を増やし、TTFTを悪化させる。
2つの対策がある。プロンプト圧縮(軽量NLPモデルで関連文のみ抽出してからLLMに渡す)とプロンプトキャッシュ(2,000語の静的システムプロンプトなどのプリフィル状態をキャッシュし、ユーザーのクエリ部分だけを再計算する)だ。
組み合わせてこそ効く
これらの施策は単体でも効果があるが、記事ではスタッキングが重要だと強調している。INT8量子化モデルをvLLMでサービングし、継続的バッチングと投機的デコーディングを組み合わせれば、最適化なしのベースラインとは別次元のアプリケーションになる。
各手法はインフラコスト・スループット上限・実装複雑度とのトレードオフを持つ。7つのアプローチがそれぞれ推論スタックの異なるレイヤー(重みレベルからプロンプトエンジニアリングまで)に対応しているため、体系的に検討することが最短ルートになる。
詳細は7 Approaches to Reduce Inference Latency in Your LLM Workflowsを参照していただきたい。