Speculative Decoding
Speculative decodingとは、小さく高速な「ドラフト」モデルが数トークン先まで予測し、その後、大きなターゲットモデルが1回の並列フォワードパスでそれらを検証する推論最適化手法です。ターゲットモデルは、自身が生成したであろうものと一致するトークンを受け入れ、それ以外を棄却します。ユーザーは通常のデコーディングとまったく同じ出力を得ますが、その速度は2~4倍になります。
Speculative decodingとは、小さく高速な「ドラフト」モデルが数トークン先まで予測し、その後、大きなターゲットモデルが1回の並列フォワードパスでそれらを検証する推論最適化手法です。ターゲットモデルは、自身が生成したであろうものと一致するトークンを受け入れ、それ以外を棄却します。ユーザーは通常のデコーディングとまったく同じ出力を得ますが、その速度は2~4倍になります。
なぜ重要なのか
LLMの生成は逐次的な依存関係に縛られており、各トークンは1つ前のトークンを待たなければなりません。大きなモデルのボトルネックは生の計算能力ではなく、メモリ帯域幅、つまりトークンごとに1回、巨大な重みをGPUの計算ユニットへ移動させることにあります。Speculative decodingは、複数の推測トークンを1回のフォワードパスにまとめることで逐次の連鎖を断ち切り、高価な大モデルの呼び出し回数を劇的に減らします。Googleが2022年に初めて発表し、2024~2025年には主要な推論エンジン(vLLM、TensorRT-LLM、llama.cpp、together.ai)がすべてspeculative decodingを標準の最適化として搭載し、同じ出力品質を保ちながらサービング費用を30~70%削減しています。
仕組み
1. ドラフトモデルが提案する: 小さく安価なモデル(たとえば70Bターゲットの1Bパラメータ版)が、次のk個のトークンを自己回帰的に生成します。ドラフトモデルの重みは小さいため、これは高速です。
2. ターゲットモデルが検証する: ターゲットモデルが、k個のドラフトトークンに対して1回のフォワードパスを並列で実行し、各位置で自身が生成したであろうものを計算します。
3. 受け入れるか棄却するか: 最初のドラフトトークンから始めて、ターゲットモデルは自身のトップ候補(または確率に応じてサンプリングしたもの)が一致すればそれを受け入れ、一致しなくなるまで続けます。
4. 修正して続行する: 最初に一致しなかった箇所で、ターゲットのトークンがドラフトのものを置き換えます。プロセスはそこから再開します。
5. 正味の効果: ドラフトが平均して70%の確率で正しければ、ターゲットモデルはフォワードパスあたり約3倍多くのトークンを生成し、遅延がそれに比例して削減されます。
なぜロスレスなのか
正しく実装されたspeculative decodingは、通常のデコーディングとまったく同じ出力分布を生成します。これが成り立つのは、ターゲットモデルが検証者として機能するためです。ドラフトが提案するどのトークンもターゲットの受け入れテストを通過しなければならないため、最終的な系列はターゲットが単独で生成したであろうものと同一になります。品質のトレードオフはなく、得られるのは速度の向上だけです。
バリエーション
標準的なspeculative decoding(Google 2022): 1つのドラフトモデルと1つのターゲット。最初の定式化です。
Medusa: ターゲットモデル自体に複数の「ヘッド」を追加し、数トークン先を予測させることで、別途のドラフトモデルを不要にします。デプロイがよりシンプルになります。
EAGLE: ターゲットモデル自身の内部表現を使ってドラフトする、より正確なバリエーション。外部のドラフトよりも高い受け入れ率を達成します。
Tree speculative decoding: 複数の候補トークンツリーを並列でドラフトします。受け入れ確率は高まりますが、検証の計算量が増えます。
Self-speculative: ターゲットモデルの層をスキップして、同じ重みから安価な「ドラフト」を作ります。
最も効果的な場面
バッチサイズ1の推論: 単一ユーザーのインタラクティブなチャットはメモリ律速です。Speculative decodingはここで真価を発揮します。
長い出力: モデルが生成するトークンが多いほど、累積的な節約が積み上がります。
繰り返しの多い構造: 出力が予測しやすいパターン(コード、JSON)に従う場合、ドラフトの受け入れ率は非常に高くなります。
遊休ハードウェアの活用: メモリ待ちでアイドル状態になりがちなGPUで、推測が計算の空きを埋めます。
効果が小さい場面
大規模バッチのサービング: 高スループットのワークロードは、すでにメモリ律速ではなく計算律速です。推測はあまり節約にならず、オーバーヘッドだけを追加します。
非常に創造的/ランダムな出力: ドラフトの受け入れ率が低く、高速化が限られます。
極小モデル: 3Bターゲットに対する1Bドラフトは、ターゲットがすでに安価なため、あまり節約になりません。
短いプロンプトと短い回答: 推測のセットアップのオーバーヘッドが、得られる利益を上回ります。
トレードオフ
メモリ上に追加のモデル: ターゲットとドラフトの両方をサービングすることになります。self-speculativeを使わない限り、メモリのフットプリントが増えます。
実装の複雑さ: 検証ループ、棄却サンプリング、KVキャッシュのロールバックの管理は簡単ではありません。ライブラリを使いましょう。
受け入れ率への敏感さ: 相性の悪いドラフトは、棄却が支配的になると、かえって動作を遅くすることがあります。
コールドスタート: ドラフトが温まるまで、最初の数トークンは推測の恩恵を受けません。
よくある間違い
異なるファミリーのドラフトモデルを使う: Mistralターゲットに対するLlamaドラフトは、ほとんど受け入れられません。ドラフトはターゲットと整合している必要があります。
ドラフトが大きすぎる: 70Bターゲットに対する7Bドラフトは受け入れ率は高いものの、実行コストが高すぎます。ドラフトはターゲットのサイズの5~20%であるべきです。
KVキャッシュのロールバックを無視する: 棄却されたトークンは、ターゲットのKVキャッシュをロールバックしなければなりません。これを忘れると状態が壊れます。
すでに高速なモデルに適用する: Haiku/Flashクラスのモデルはメモリが軽量です。推測による節約は小さくなります。
エンドツーエンドで測定しない: リクエスト経路全体をベンチマークしましょう。素朴な1秒あたりトークン数の向上は、負荷がかかったときやネットワーク遅延が支配的なときに消えてしまうことがあります。
Sources: