メインコンテンツまでスキップ

拡散 LLM:左から右に書かないモデルたち

上級

AILmanac でこれまで扱ってきたモデルはすべて、同じやり方でテキストを生成します。1 トークン、次のトークン、左から右へ、ひたすら。それをしないモデルの一族がいます。 マスクされた位置が並んだ白紙のキャンバスから始め、その全部を一度に予測し、 自信のあるものだけを残して、また繰り返す。40 番目の位置が 7 番目より先に 決まることもあります。

誰もが気にするのは数字のほうです。Inception の Mercury 2 — しかも推論モデル — は、報告では Blackwell GPU 上で 1,009 トークン/秒、エンドツーエンドの レイテンシ 1.7 秒で動き、推論を有効にした同等の競合よりおよそ 8〜14 倍速いと されています(The Decoder)。 Google の実験的な Gemini Diffusion はオーバーヘッドを除いて 1,479 トークン/秒でサンプリングし、Gemini 2.5 Flash の 272.4 と対比されています (Techmeme のまとめ)。

ところが、このアプローチをスケールで成立させた 8B のオープンウェイトモデル LLaDA の README は、サンプリングステップ数が応答長と等しいときに品質が 最大になると書いています。1 トークンあたり 1 回の順伝播。自己回帰モデルと まったく同じ、しかも KV キャッシュがないのでより遅い。

どちらの事実も本当です。このレッスンはその 2 つの橋渡しです。アルゴリズムが 実際に何をしているのか、どのノブが速度を買い、その代価は何か、初期の拡散 LLM を使い物にならなくしていた 2 つの構造的限界と、実際に出荷された修正、そして 本番に入れる前に知っておくべき 3 つの落とし穴(ストリーミング、長さの課金、 そして自己回帰モデルには存在しないジェイルブレイクの一種)です。

What you'll learn
  • マスク拡散生成を、キャンバス・ノイズ除去パス・コミット判断という言葉で説明でき、双方向アテンションが何を買い何を失うかを言える
  • steps ノブを正しく使う:順伝播 1 回あたりのトークン数を計算し、並列化を攻めすぎることが単に品質を落とすのではなく誤りになる条件付き独立性の失敗を説明できる
  • 今日呼び出せるあらゆる dLLM にブロック拡散が入っている理由を説明できる — それが KV キャッシュ、可変長出力、トークンストリーミングを取り戻したものだから
  • dLLM が本当に勝つ仕事を選べる:穴埋めと任意順の編集、レイテンシ律速の音声、境界のある判断 — 「すべてを、ただ速く」ではない
  • オープンな dLLM エンドポイントは境界ではアラインメントされていないものとして扱う。マスク穴埋めプロンプトは、自己回帰モデルの拒否では起こりえない形でアラインメントを迂回するため

仕組み — 頭の中で描くしかない 1 枚の図​

自己回帰(AR)モデルのループはこうです。プレフィックス全体を読み、1 つの位置 (次の位置)についての確率分布を出し、サンプリングし、末尾に足し、繰り返す。これを 安く保っているのが KV キャッシュです — それより前のトークンのキーとバリューは 一度計算したら変わりません。アテンションが因果的で、右側にはまだ何も存在しない からです。

マスク拡散 LLM はこれを反転させます。アテンションが双方向です。あらゆる位置が、 両方向のあらゆる位置を参照します。だから 1 回の順伝播で、モデルはすべての マスク位置についての分布を同時に出します。生成は答えをなぞる歩行ではなく、答え 全体の反復的な洗練になります。

Guided walkthrough1 of 5
  1. 生成長 L を決める。L 個の位置すべてを特別なマスクトークンで埋める。純粋なマスク dLLM(LLaDA、Dream)では L は最初の順伝播の前に固定され、モデルは進みながら系列を伸ばすことはできない。

最後の 1 行は覚えておく価値があります。AR モデルは順伝播 1 回あたり 1 トークンに 固定されています。拡散 LLM では自分で選べます。Google のオープンウェイト参入作 DiffusionGemma は、256 個のブロックを並列に洗練しながら順伝播 1 回あたり およそ 20 トークンを報告しており、これが H100 1 枚で約 1,500 出力トークン/秒に 到達する仕組みです(DiffusionGemma Technical Report)。

steps というノブ、そしてそれを回しすぎるのが「粗くなる」ではなく「間違う」理由​

Dream 7B はこのノブを明示的に公開しています。diffusion_generate() は steps を 「拡散タイムステップ」として説明し、1 ステップあたり max_new_tokens / steps トークンが生成されるとし、ステップが少ないほど速いが粗くなるとはっきり書いています (DreamLM/Dream、Apache-2.0)。

では、なぜ常に少ないステップを使わないのか。それが持ち込む誤差がノイズではなく、 特定可能で名前のついたバグだからです。

1 回の順伝播が与えるのは、各マスクスロットについての周辺分布です。つまり、 まだ分からないすべてについて平均されたその位置でのトークンの確率です。同じ パスから 2 つのスロットをコミットすると、あなたは両者の周辺分布の積から サンプリングしていることになり、同時分布からではありません。両者のあいだの 依存関係は黙って捨てられます。Fast-dLLM の著者は根本原因をそのまま述べています。 真の同時分布に依存関係があるのに、マスク拡散モデルは周辺確率から独立にトークンを サンプリングするため、並列デコードのもとで生成品質が劣化する、と (Fast-dLLM, arXiv:2505.22618)。

直感的にはこうです。都市名を尋ねると、隣り合う 2 つのスロットがそれぞれ自分の 位置について「New」と「Delhi」を最尤トークンと評価することがあります。 「New York」も「New Delhi」もどちらもありえるからです。両方を 1 回のパスで コミットすると、どちらでもないものが出てきます。並列化しすぎたデコードの 失敗モードは、文章がぼやけることではなく、継ぎ目のところで自信たっぷりに 組み立てられたナンセンスです。

この分野を実用にした修正が信頼度を考慮した並列デコードです。マスクされた 各スロットについて信頼度(通常は softmax の最大確率)を計算し、しきい値を 超えたスロットだけをコミットし、1 つも超えなければループが前に進むように最も 高い 1 つだけをコミットする。ほぼ独立なトークンは一緒にデコードされ、互いに 依存するトークンは待たされます。Fast-dLLM は、LLaDA と Dream において各種 ベンチマークで最大 27.6 倍のスループット改善を、精度低下はごくわずかで 報告しています — 学習不要、デコードを変えるだけです。

これがこの研究領域全体の形です。並列性はタダ、独立性はタダではない、そして 仕事はどのトークンを安全に一緒にできるかを見分けるところにあります。

What you'll learn
  • 信頼度しきい値は、実際に筋道を立てて考えられる品質ダイヤルだ:しきい値を上げるとパスあたりのコミット数が減り、パス数が増え、遅くなり、AR の品質に近づく。Fast-dLLM v2 はしきい値 0.9 で GSM8K において 2.6 倍の高速化を精度低下ごくわずかで報告している — 「全部コミット」ではなく、そのあたりが出発点にすべき設定だ。

2 つの構造的な限界 — そして今日 dLLM を呼び出せる理由であるブロック拡散​

LLaDA 自身のリポジトリは、効率面の制約を婉曲表現なしに列挙しています。サンプリング 時のコンテキスト長が固定、KV キャッシュ非対応、そしてサンプリングステップが 応答長を下回ると性能が劣化する。著者はこれを意図的なものとして位置づけています — 最適化する前に、このアプローチの天井を見きわめたかったのだと (ML-GSAI/LLaDA、MIT、約 4k スター、Base と Instruct の重みに加えて LLaDA 1.5、LLaDA-MoE-7B-A1B、iLLaDA の各派生)。

これを積み上げると、純粋なマスク dLLM はプロダクトとしてほぼ使い物になりません。

  1. KV キャッシュがない。 双方向アテンションは、どのパスもどのトークンの文脈も 変えうることを意味するので、キャッシュされたキーとバリューは無効になります。 毎ステップ、系列全体を再計算します。
  2. 出力長が固定。 生成前に L を選ばなければなりません。小さすぎれば切り詰め、 大きすぎれば捨てる位置に計算を浪費します。
  3. レイテンシが AR より悪い。 1 と 2 が重なると、「並列」なモデルが置き換える はずの逐次モデルよりエンドツーエンドで遅くなりえます。

ブロック拡散は、純粋であることをやめることで 3 つすべてを解決します。ブロック 単位で生成し、前のブロックには自己回帰的に条件づけ、現在のブロックの内側で 拡散を回す。これが柔軟な系列長とブロック間の KV キャッシュをもたらします — ICLR 2025 の oral である BD3-LM の定式化です (arXiv:2503.09573、 kuleshov-group/bd3lms)。

Fast-dLLM v2(arXiv:2509.26328)は、チューニング された版がどんな姿になるかを示しており、その細部は知っておく価値があります。 あなたが観測するベンダーの挙動を説明してくれるからです。

  • ハイブリッドなアテンションマスク。 ブロックの内側ではブロック対角 (双方向)、ブロックどうしのあいだではブロック因果(左から右)。効くところには 双方向の文脈を、キャッシュが住むところには AR のセマンティクスを。
  • 2 段のキャッシュ。 完了したブロックを綺麗なプレフィックス文脈として保持する ブロックレベルのキャッシュに加えて、ブロック内デコードがまだ必要とする再計算の ためのサブブロックキャッシュ(DualCache)。
  • 学習時の相補マスキング。 各サンプルをマスク m と 1 − m の 2 つのビューに 複製するので、すべてのトークンがマスクの予測対象としても文脈としても教師される。
  • 報告された結果。 標準的な AR デコードに対して最大 2.5 倍;H100 でバッチ サイズ 64 のとき 1.8 倍;7B のベンチマーク平均スコアは Dream の 57.6 に対して 60.3、内訳には HumanEval 63.4 対 57.9、GSM8K 62.0 対 39.2 を含む。

そして学習コストが、この分野の見方を変える細部です。Fast-dLLM v2 は AR モデルからの ファインチューニングをおよそ 1B トークン — Dream の 580B より約 500 分の 1 で 行い、7B を A100 64 枚で約 12 時間で学習したと報告しています。

拡散は別種のモデルではなく、後付けできるデコードモードである​

DiffusionGemma はその点を見逃しようのない形で示します。ゼロから学習したものでは ありません。活性 3.8B / 総計 25.2B パラメータの mixture-of-experts モデルである Gemma 4 をファインチューニングして拡散モデルにしており、使ったのは出発点の AR モデルの総学習トークン予算の 10% 未満 — 教師ありノイズ除去ファインチューニング、 その後に強化学習とサンプラー蒸留です (arXiv:2608.00146、CC-BY-4.0 の重み)。

驚くべきなのは、変換を生き延びたものです。レポートは、ベースモデルの思考モード、 マルチモーダル入力、長いコンテキストが保たれ、さらに自己回帰的に生成する能力も 維持されており、劣化はわずかだと述べています。1 組の重み、2 つのデコードモード。

この結果が持ちこたえるなら、「拡散 LLM」は独立したプロダクトのカテゴリであることを やめ、サービング時の選択肢になります。同じ系列のモデルに、推論側の並列性ダイヤルが 付いているだけ、ということです。これは 1 秒あたりトークン数のどんな記録よりも はるかに重大な主張であり、プロバイダーがあなたの使っているモデルでフラグを立てて から学ぶのではなく、いま仕組みを学んでおくべき理由です。

拡散 LLM が本当に得意なこと​

速度は見出しであり、この主張のいちばん弱い部分です。速度は争われているからです — 専用の AR ハードウェアも毎秒数百トークンを出してきています (トークン速度 を参照)。持続する 優位は、アルゴリズムの形から導かれるもののほうです。

任意順の生成とネイティブな穴埋め。 どのスロットをコミットするか自分で選べる ので、系列の途中に穴を空けたまま、両側の完全な文脈を使ってモデルに埋めさせること ができます。Dream はこれを alg パラメータとして公開しています — origin (ランダム順)、maskgit_plus(top-1 信頼度)、topk_margin(top1 − top2 の マージン)、entropy — さらにそれらの戦略にランダム性を加える alg_temp も あります。コードの編集、テンプレートの補完、固定された JSON の骨組みへの フィールド埋めでは、AR モデルに 40 行目を変えるためファイル全体を出し直させる よりも構造的に相性が良いのです。

レイテンシ律速のインタラクション。 Inception の Mercury Voice は 128K コンテキストで170 ms 未満の初トークン到達時間を掲げ、執筆時点で入力/出力 100 万トークンあたり $0.20/$1.50 の価格です。音声はレイテンシそのものが プロダクトである最も明快なケースです。そのしきい値が効く理由は 全二重音声 AI のページで扱っています。

エンドツーエンドの推論ターンアラウンド。 Mercury 2 が報告する、推論を伴う 答え 1 件あたり 1.7 秒という数字は、スループットとは別の主張です — エージェント ループが毎ターン実際に体感する数字です。

散文ではなく境界のある答え。 Inception の Mercury Decide は、選択肢、スコア、 あるいは校正済み確率付きの yes/no を、テキストとして書き出すのではなくモデルから 読み出して返します — 最大で毎秒 14 件の判断と報告されており、これが「全ケースで 走らせて、怪しいものだけエスカレーションする」を手頃にします。このカテゴリと その注意点は System One 決定モデル で詳しく扱っています。そこでは拡散のバックボーンは実装の詳細であって、本題では ありません。

価格への圧力。 Mercury 2.5 は現在、260K コンテキストで入力/出力 100 万 トークンあたり $0.04/$0.15(プロモーション、定価 $0.20/$0.75 から)、キャッシュ 済み入力は 100 万あたり $0.004 を掲示しています。プロモ価格は一時的なものとして 扱い、請求額は定価で見積もってください。

本番投入の前に知っておく 3 つの落とし穴​

Watch out
  • tok/s はベンダーが選んだ並列度で測られている。あなたの品質基準はもっと多いステップを必要とするかもしれず、その分だけ高速化は失われる。自分のプロンプトで、自分の精度しきい値のもとでベンチマークすること。
  • 出力は左から右に確定していくわけではない。単調なのはブロック境界だけで、ブロックの内側ではスロットがまだマスクされていたり書き換わったりする。「トークン N はもう変わらない」と前提する UI やパーサーはすべて間違っている。
  • 純粋なマスク dLLM は、あなたが前もって選んだ長さを計算し、その分を課金する。ブロック拡散はそれをブロック単位の粒度に落とすだけで、なくすわけではない。

3 つ目は箇条書き以上の扱いに値します。これはセキュリティ上の性質であり、自己回帰 モデルには対応物が存在しないからです。

AR モデルのアラインメントには構造的な利点があります。拒否が最初に起こるのです。 モデルが断ると決めれば、それ以降のすべてのトークンは「それはお手伝いできません」に 条件づけられます。拡散 LLM にはそういう瞬間がありません。拒否が生成の残りを 引き継ぐ左から右の時点が存在せず、マスクされたスロットはすでにキャンバスに 載っているものと整合するように埋められていきます。

DIJA(「The Devil behind the mask」、ICLR 2026、 arXiv:2507.11097、 ZichenWen1/DIJA)はそれを攻撃に変えます。 敵対的プロンプトは有害な意図をアンマスクされたトークンに置き、文脈的に 整合するようモデルに補完させるためのマスク区間を残します。報告された結果は、 Dream-Instruct に対してキーワードベースの攻撃成功率が最大 100%、 JailbreakBench での評価器ベース ASR で最強の既存ベースラインを最大 78.5%、 StrongREJECT スコアで 37.7 ポイント上回り、しかも有害な内容の書き換えや 難読化を一切必要としないというものです。著者の結論は、既存のアラインメント 機構は文脈を考慮したマスク入力プロンプトから dLLM を守らない、というものです。 逐次モデルのように推論の途中で安全でない生成をフィルタすることが、モデルには できないからです。

後続研究(arXiv:2602.00388)は、絵柄は 両面的だと論じています — 拡散はある設定では安全性の恵みをもたらし、それが 文脈のもとで崩れる — これはどちらかを仮定するのではなく測るべき理由になります。

実務上の持ち帰り:オープンウェイトの dLLM を公開するなら、その指示チューニングを ガードレールとして扱わないこと。リクエストとレスポンスの両方について、ベース モデルに対してするのとまったく同じように、境界でフィルタと分類を行ってください。 ローカルおよびハイブリッドエージェントのセキュリティ のページで境界パターンを扱っています。

10 分で試してみる​

Guided walkthrough1 of 4
  1. Inception は Mercury を OpenAI 互換 API で提供しており、モデルは OpenRouter にも掲載されている(例:openrouter.ai/inception/mercury-2)。既存の OpenAI SDK のスクリプトをそこに向け、モデル文字列を変えるだけ — リクエストの形に拡散固有のものは何もない。

OpenAI SDK でホスティング版の拡散 LLM を呼ぶ(変わるのはモデル文字列だけ)

# Inception serves an OpenAI-compatible API; OpenRouter also lists the models.
# Check the provider's model list for the current slug before you hard-code one.

curl https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
  "model": "inception/mercury-2",
  "messages": [
    {"role": "user", "content": "Rewrite this function to stream its output, and explain the two failure modes you introduced."}
  ],
  "stream": true
}'

# What to watch for, beyond the content:
#  - time to first token vs time to last token (the diffusion win is usually in the gap)
#  - whether the stream arrives in chunks that look like BLOCKS rather than words

Dream 7B での steps スイープ — 自分の品質の崖を見つける

import time, torch
from transformers import AutoModel, AutoTokenizer

NAME = "Dream-org/Dream-v0-Instruct-7B"
tok = AutoTokenizer.from_pretrained(NAME, trust_remote_code=True)
model = AutoModel.from_pretrained(
  NAME, torch_dtype=torch.bfloat16, trust_remote_code=True
).to("cuda").eval()

PROMPT = "List the five largest cities in Germany with their populations."
MAX_NEW = 256

# steps == MAX_NEW is the authors' best-quality setting: one token per
# forward pass. Each halving doubles tokens-per-pass and doubles the
# number of independence assumptions you are making.
for steps in [256, 128, 64, 32, 16]:
  inputs = tok.apply_chat_template(
      [{"role": "user", "content": PROMPT}],
      return_tensors="pt", return_dict=True, add_generation_prompt=True,
  ).to("cuda")

  t0 = time.perf_counter()
  out = model.diffusion_generate(
      inputs.input_ids,
      attention_mask=inputs.attention_mask,
      max_new_tokens=MAX_NEW,
      steps=steps,
      temperature=0.0,
      alg="entropy",          # commit the lowest-entropy slots first
      alg_temp=0.0,
  )
  dt = time.perf_counter() - t0
  text = tok.decode(out[0][len(inputs.input_ids[0]):], skip_special_tokens=True)

  print(f"--- steps={steps}  tokens/pass={MAX_NEW/steps:.0f}  {dt:.2f}s ---")
  print(text.strip()[:400])

# Read the OUTPUTS, not just the timings. The numbers and the city names are
# the multi-token units that break first when too many slots are committed
# from one pass. That corruption is the conditional-independence bug, visible.

これが自分に関係あるかどうかの判断​

Key takeaways
  • 拡散 LLM の速度はたった 1 つの比率から来る — 生成長をノイズ除去ステップ数で割ったもの、つまり順伝播 1 回あたりにコミットされるトークン数だ。AR モデルは 1 に固定されている。それ以外はすべてこのダイヤルの帰結である。
  • 並列化しすぎたデコードは粗いのではなく誤っている:相関のあるスロットを 1 回のパスからコミットすると、同時分布ではなく周辺分布の積からサンプリングすることになる。信頼度しきい値によるデコードがその修正であり、Fast-dLLM は最大 27.6 倍のスループットを精度低下ごくわずかで報告している。
  • 純粋なマスク拡散には KV キャッシュがなく、出力長が固定だ。ブロック拡散(ブロック間は AR、ブロック内は拡散)がキャッシュ、可変長、ストリーミングを取り戻したものであり、今日呼び出せる dLLM がすべてブロックモデルである理由だ。
  • DiffusionGemma は自己回帰型の Gemma 4 MoE を、元の学習トークン予算の 10% 未満で拡散モデルに変換しつつ、思考モード、マルチモーダル性、AR 生成を保った。拡散はモデルの別種というより、デコードモードに見えてきている。
  • 穴埋めと任意順の編集、200 ms 未満の音声ターン、高速で境界のある判断、エンドツーエンドのターンレイテンシのために選ぶこと — そしてそのアラインメントは効かないと仮定すること。マスク穴埋めプロンプトは、アラインメント済みのオープン dLLM に対して最大 100% の ASR に達するからだ。
Enter キーまたはスペースキーでカードを裏返します。左右の矢印キーでカードを移動できます。用語を表示しました。
1 / 11

Check yourself

0/5
  1. マスク拡散 LLM に、256 トークンの答えを 32 回のノイズ除去ステップで求めたとする。これは何を意味するか?
  2. 純粋なマスク拡散 LLM が従来型の KV キャッシュを使えないのはなぜか?
  3. ブロック拡散(BD3-LM)は純粋なマスク拡散に対して何を変えるか?
  4. DiffusionGemma の最も重大な報告結果は次のどれか?
  5. オープンウェイトで指示チューニング済みの dLLM を信頼できないユーザーに公開している。dLLM 固有のリスクは何か?

下地の機構にまだ馴染みがない場合は、LLM とは何か と トークンとコンテキスト が、このページが 出発点として離れていく自己回帰のベースラインを扱っています。 トークン速度 は、同じレイテンシの 問題に反対側から攻めるハードウェアとソフトウェアの乗数を扱っています。

出典とさらに読む​

次のステップ​