# 支援デコーディング

Assisted decodingは、メインモデルがトークンを確定する前に、ヘルパーが候補トークンを提案できるようにすることで、テキスト生成を高速化します。メインモデルは、1回のフォワードパスで候補トークンを検証します。ヘルパーは高速かつ低コストであり、メインモデルによるより高コストなフォワードパスを数十回分置き換えることができます。

このガイドでは、Transformersにおける支援デコーディング（assisted decoding）の手法について説明します。

## 投機的デコーディング

[Speculative decoding](https://hf.co/papers/2211.17192)では、より小さなアシスタントモデルが候補トークンをドラフトします。メインモデルはこれらトークンを1回のパスで検証します。検証されたトークンは最終出力に含まれ、拒否されたトークンは標準的なサンプリングをトリガーします。メインモデルが高コストなフォワードパスをより少ない回数で実行できるため、生成が高速化されます。

この手法は、アシスタントモデルがメインモデルよりもはるかに小さく、同じトークナイザーを使用する場合に最も効果的です。Speculative decodingは貪欲探索とサンプリングをサポートしますが、バッチ入力には対応していません。

`assistant_model` を [generate()](/docs/transformers/main/ja/main_classes/text_generation#transformers.GenerationMixin.generate) に渡します。トークンの検証に失敗した場合に再サンプリングを行うには、`do_sample=True` を設定します。

```py
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM-1.7B")
model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-1.7B", dtype="auto")
assistant_model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-135M", dtype="auto")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt")

outputs = model.generate(**inputs, assistant_model=assistant_model)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
'Hugging Face is an open-source company that provides a platform for developers to build and deploy machine'
```

`assistant_model` 引数は、[Pipeline](/docs/transformers/main/ja/main_classes/pipelines#transformers.Pipeline) API でも利用できます。

```python
import torch
from transformers import pipeline

pipeline = pipeline(
    "text-generation",
    model="meta-llama/Llama-3.1-8B",
    assistant_model="meta-llama/Llama-3.2-1B",
    dtype="auto"
)
pipeline("Hugging Face is an open-source company, ", max_new_tokens=50, do_sample=False)
```

ランダム性を制御するために`temperature`を設定します。温度を下げると、レイテンシが改善されることがよくあります。

```py
from transformers import AutoModelForCausalLM, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM-1.7B")
model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-1.7B", dtype="auto")
assistant_model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-135M", dtype="auto")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt")

outputs = model.generate(**inputs, assistant_model=assistant_model, do_sample=True, temperature=0.5)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
'Hugging Face is an open-source company that is dedicated to creating a better world through technology.'
```

## プロンプト検索デコーディング

Prompt lookup decodingにはアシスタントモデルは不要です。プロンプト内の重複するn-gramを検出することで、候補トークンを提案します。一致が見つからない場合は、通常の自己回帰デコーディングにフォールバックします。要約や翻訳などの入力に依存するタスクでは、候補トークンが原文の局所的なパターンを反映することが多いため、この手法が適しています。

`prompt_lookup_num_tokens` を [generate()](/docs/transformers/main/ja/main_classes/text_generation#transformers.GenerationMixin.generate) に渡します。これにより、アルゴリズムが繰り返しパターンを検出した際に、プロンプトの前方から何トークン分のコピーを試みるかが設定されます。

```py
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM-1.7B")
model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-1.7B", dtype="auto")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt")

outputs = model.generate(**inputs, prompt_lookup_num_tokens=5)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
'Hugging Face is an open-source company that provides a platform for developers to build and deploy machine learning models. It offers a variety of tools'
```

```py
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM-1.7B")
model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-1.7B", dtype="auto")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt")

outputs = model.generate(**inputs, prompt_lookup_num_tokens=5, do_sample=True, temperature=0.5)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
'Hugging Face is an open-source company that provides a platform for developers to build and deploy machine learning models. It offers a variety of tools'
```

## セルフ推測デコーディング

Self-speculative decodingでは、モデルの中間層をアシスタントとして用いて候補トークンを提案します。提案が一致した場合、モデルは早期に終了し、残りの層がトークンを検証または修正します。

すべてが1つのモデルであるため、重みとキャッシュが共有され、追加のメモリオーバーヘッドなしに速度が向上します。この手法は、中間層からの早期終了ロジットをサポートするように学習されたモデルでのみ機能します。

`assistant_early_exit` を [generate()](/docs/transformers/main/ja/main_classes/text_generation#transformers.GenerationMixin.generate) に渡して、終了レイヤーを設定します。

```py
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("facebook/layerskip-llama3.2-1B")
model = AutoModelForCausalLM.from_pretrained("facebook/layerskip-llama3.2-1B", dtype="auto")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt")

outputs = model.generate(**inputs, assistant_early_exit=4, do_sample=False, max_new_tokens=20)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
```

## マルチトークン予測（MTP）レイヤー

Multi-token prediction (MTP) レイヤーは、メインモデル自身のチェックポイントから由来する追加の予測レイヤーを用いて候補トークンを生成します。MTP レイヤーは、メインモデルの埋め込みと出力ヘッドを再利用します。各 MTP レイヤーは 1 つのトークンを生成するため、ステップごとの候補数はチェックポイントの MTP レイヤー数と一致します。メインモデルは、1 回のフォワードパスでこれらの生成結果を検証します。

MTPは、[DeepSeek-V3](https://huggingface.co/deepseek-ai/DeepSeek-V3)や[GLM-4.5](https://huggingface.co/zai-org/GLM-4.5)のようにMTPレイヤーで学習されたチェックポイントでのみ動作します。これらのチェックポイントにはMTPの重みが含まれており、`config.json`内の設定では`num_nextn_predict_layers`として`num_mtp_layers`が設定されています。

`use_mtp=True` を [generate()](/docs/transformers/main/ja/main_classes/text_generation#transformers.GenerationMixin.generate) に渡します。この引数は、モデルに MTP レイヤーがない場合にエラーを発生させます。投機的デコーディングと同様に、MTP は貪欲探索とサンプリングをサポートしますが、バッチ入力はサポートされていません。

ここでは、MTPとは、DeepSeek-V3やGLM-4.5のように、ターゲットのチェックポイントに含まれる予測レイヤーを指します。Gemma 4は、MTPデコーディングのために別のアシスタントチェックポイントを使用します。`assistant_model`として渡してください（[Multi-token prediction drafter](#multi-token-prediction-drafter)を参照）。

`text-generation` パイプラインと [generate()](/docs/transformers/main/ja/main_classes/text_generation#transformers.GenerationMixin.generate) は、どちらも `use_mtp=True` を受け付けます。

```py
from transformers import pipeline

pipe = pipeline(
    "text-generation",
    model="zai-org/GLM-4.5-Air",
    device_map="auto",
)

outputs = pipe(
    "Hugging Face is an open-source company",
    use_mtp=True,
    do_sample=False,
    max_new_tokens=50,
    add_special_tokens=True,
    return_full_text=True,
)

[output["generated_text"] for output in outputs]
```

代わりに、次のように推論することもできます。

```py
from transformers import AutoModelForCausalLM, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("zai-org/GLM-4.5-Air")
model = AutoModelForCausalLM.from_pretrained("zai-org/GLM-4.5-Air", device_map="auto")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(model.device)

outputs = model.generate(**inputs, use_mtp=True, do_sample=False, max_new_tokens=50)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
```

## マルチトークン予測ドラフター

MTPドラフターは、別のチェックポイントから読み込まれる軽量なアシスタントモデルです。ターゲットモデルが検証するための候補トークンを提案します。ドラフターは、ターゲットモデルの入力埋め込みを使用し、そのKVキャッシュにアテンションを向けます。ターゲットモデルの隠れ状態から開始し、自己回帰的にトークンをドラフトします。次の各トークンについて、投影された隠れ状態をドラフターにフィードバックします。ターゲットモデルは、speculative deocdingと同様に、1回のフォワードパスでドラフトされたトークンを検証します。

ターゲットのチェックポイントの一部であり、出力ヘッドを共有するMTPレイヤーとは異なり、MTPドラフターは独立したアシスタントモデルです。ターゲットのインプット埋め込みとKVキャッシュを使用して、トークンを提案します。

```py
from transformers import AutoProcessor, AutoModelForCausalLM

processor = AutoProcessor.from_pretrained("google/gemma-4-E4B-it")
target_model = AutoModelForCausalLM.from_pretrained(
    "google/gemma-4-E4B-it",
    dtype="auto",
    device_map="auto",

)

assistant_model = AutoModelForCausalLM.from_pretrained(
    "google/gemma-4-E4B-it-assistant",
    dtype="auto",
    device_map="auto",
)

messages = [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Write a short joke about saving RAM."},
]

inputs = processor.apply_chat_template(
    messages,
    tokenize=True,
    return_dict=True,
    return_tensors="pt",
    add_generation_prompt=True,
    enable_thinking=False
).to(target_model.device)
input_len = inputs["input_ids"].shape[-1]

outputs = target_model.generate(
    **inputs,
    assistant_model=assistant_model,
    max_new_tokens=256,
)
response = processor.decode(outputs[0][input_len:], skip_special_tokens=False)

processor.parse_response(response)
```

## 汎用的な支援デコーディング

Universal assisted decoding (UAD)は、メインモデルとアシスタントモデルのトークナイザーが異なる場合でも、speculative decodingを可能にします。これにより、任意の小型アシスタントモデルをメインモデルと組み合わせることができます。候補トークンは再エンコードされ、アルゴリズムが最長共通部分列を計算することで、継続部分が整列した状態に保たれます。

UADを有効にするには、`tokenizer`、`assistant_tokenizer`、`assistant_model`を[generate()](/docs/transformers/main/ja/main_classes/text_generation#transformers.GenerationMixin.generate)に渡してください。

```py
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

assistant_tokenizer = AutoTokenizer.from_pretrained("double7/vicuna-68m")
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-9b")
model = AutoModelForCausalLM.from_pretrained("google/gemma-2-9b", dtype="auto")
assistant_model = AutoModelForCausalLM.from_pretrained("double7/vicuna-68m", dtype="auto")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt")

outputs = model.generate(**inputs, assistant_model=assistant_model, tokenizer=tokenizer, assistant_tokenizer=assistant_tokenizer)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
'Hugging Face is an open-source company that is dedicated to creating a better world through technology.'
```

### 静的アンサンブル検証

標準的な推測デコーディングは*ロスレス*です。出力分布がターゲットモデルと完全に一致することを保証します。[静的アンサンブル検証](https://arxiv.org/abs/2604.07622)では、ターゲット分布とドラフト分布の混合分布に対して検証を行うことでこの制約を緩和し、出力分布が正確なターゲット分布ではなく混合分布になるというコストを払って、受入率を向上させます（推論が高速化されます）。推奨される初期値は`0.7`です。

```python
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM-1.7B")
model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-1.7B", dtype="auto")
assistant_model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-135M", dtype="auto")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt")

outputs = model.generate(**inputs, assistant_model=assistant_model, assistant_ensemble_weight=0.7, do_sample=True)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
```

これにはアシスタントモデルからの候補ロジットが必要であり、プロンプト検索デコーディングではサポートされていません。

## リソース

- テキスト生成のレイテンシとアシスト生成に関する詳細な背景については、[Assisted Generation: a new direction toward low-latency text generation](https://huggingface.co/blog/assisted-generation)ブログ記事をご覧ください。

