Как работает speculative decoding и MTP при инференсе LLM

Коротко: speculative decoding ускоряет генерацию не потому, что «угадывает токен и больше не прогоняет большую модель». Большая target-модель всё равно проверяет speculative-токены через все свои слои. Выигрыш возникает потому, что несколько позиций проверяются одним batched forward pass, а не несколькими последовательными decode-pass. На GPU это намного эффективнее: лучше переиспользуются прочитанные веса, растёт арифметическая интенсивность, уменьшается число последовательных запусков и синхронизаций.

MTP/NextN — один из способов дешёво построить такой speculative draft.


1. Почему обычный autoregressive decode медленный

Языковая модель генерирует текст авторегрессионно:

P(x1, x2, ..., xn)
=
P(x1) · P(x2 | x1) · P(x3 | x1,x2) · ...

Следующий токен зависит от всех предыдущих. После обработки prompt у нас есть контекст:

x1 x2 ... xt

Чтобы получить следующий токен, модель делает:

x1 ... xt
    ↓
все слои модели
    ↓
hidden state ht
    ↓
LM head
    ↓
logits
    ↓
sampling
    ↓
x(t+1)

После этого только что выбранный x(t+1) надо снова подать в модель:

x(t+1)
   ↓
все слои модели
   ↓
h(t+1)
   ↓
LM head
   ↓
x(t+2)

И так далее. Поэтому для генерации 1000 токенов нужны примерно 1000 последовательных decode steps.

Ключевое слово здесь — последовательных: GPU не может начать полноценный расчёт x(t+2), пока не известно, каким оказался x(t+1).


2. Почему prefill намного быстрее decode

Это хорошо видно практически на любой локальной LLM. Большая модель может показывать, например:

prompt processing: 1200–1500 tok/s
generation:          40–60 tok/s

Хотя через те же самые веса проходят те же Transformer/MoE-блоки.

Причина — в форме вычислений.

При decode одного токена слой во многом выполняет операции вида:

W @ h

где W — большая матрица весов, а h — один hidden vector.

При prompt processing одновременно обрабатывается много позиций:

W @ H

где H — матрица из множества hidden vectors.

GPU намного лучше загружен такой работой. Упрощённо:

decode:
прочитали огромную W
→ использовали её для одного vector

prefill:
прочитали огромную W
→ использовали её сразу для сотен/тысяч vectors

Для больших LLM decode часто ограничен не количеством доступных FLOPS, а:

  • bandwidth VRAM;
  • kernel-launch overhead;
  • синхронизациями;
  • меж-GPU коммуникацией;
  • слабой утилизацией вычислительных блоков при маленьком batch.

Именно в эту проблему и бьёт speculative decoding.


3. Главная идея speculative decoding

Пусть есть:

Target model T

— большая модель, результат которой мы хотим получить.

И есть дешёвый механизм:

Draft model D

который примерно угадывает, что скажет target.

Draft быстро предлагает несколько следующих токенов:

A B C D

После этого target не проверяет их по одному четырьмя последовательными decode-pass. Вместо этого target получает speculative prefix и оценивает сразу несколько позиций одним batched forward pass.

Если draft хорошо совпал с target, за один последовательный запуск большой модели можно продвинуть генерацию сразу на несколько токенов.

Это и есть speculative decoding.


4. Простейший пример

Допустим, уже подтверждённый контекст заканчивается так:

The capital of France is

Target-модель обычным способом определила следующий токен:

Paris

Draft после этого предполагает продолжение:

,
which
is

Получается speculative sequence:

The capital of France is Paris , which is

Target теперь может проверить несколько позиций одновременно. За один forward он получает распределения примерно такого вида:

после "... Paris"
→ P(","), P("."), ...

после "... Paris ,"
→ P("which"), P("and"), ...

после "... Paris , which"
→ P("is"), P("was"), ...

после "... Paris , which is"
→ P("the"), P("a"), ...

Если первые три draft-токена проходят проверку, target за один verification step продвинулся сразу на несколько токенов.


5. Как target может проверить несколько последовательных токенов одновременно

На первый взгляд здесь парадокс. Для вычисления C ведь нужен B, а для вычисления B нужен A. Почему их можно считать одним batch?

Потому что speculative sequence уже предложена draft-механизмом.

Target получает:

A B C

целиком. Causal mask обеспечивает правильную зависимость:

позиция A видит:
context

позиция B видит:
context + A

позиция C видит:
context + A + B

Но A не видит B/C, а B не видит C.

Именно так обычный Transformer обрабатывает prompt. Поэтому target способен вычислить hidden states всех speculative positions одним batched проходом, не нарушая причинность.


6. Считаются ли внутренние слои для speculative-токенов

Да. Это самое важное место во всей теме.

Для каждого проверяемого speculative token target-модель всё равно должна вычислить:

embedding
↓
layer 1
↓
layer 2
↓
...
↓
layer N
↓
final norm
↓
LM head
↓
logits

Speculative decoding не пропускает target layers.

Если target имеет 40 слоёв, speculative positions тоже проходят через эти 40 слоёв.

Но вместо нескольких последовательных вычислений:

W @ h1

пауза / sampling

W @ h2

пауза / sampling

W @ h3

получается вычисление ближе к:

W @ 

То есть маленький GEMM вместо серии GEMV/matvec. На современном GPU это принципиально другой режим эффективности.


7. Откуда конкретно берётся ускорение

7.1. Переиспользование весов

При обычном decode:

token 1:
прочитать веса → вычислить

token 2:
снова прочитать веса → вычислить

token 3:
снова прочитать веса → вычислить

При verification batch:

прочитать веса
→ применить сразу к нескольким positions

Весов модели могут быть десятки гигабайт. Поэтому уменьшение числа отдельных обходов весов очень важно.

7.2. Лучшая загрузка GPU

Matrix-vector multiplication при batch=1 обычно плохо использует огромную вычислительную мощность GPU. Matrix-matrix multiplication для нескольких positions утилизирует GPU лучше.

Speculative verification фактически превращает часть autoregressive decode в маленький prefill.

7.3. Меньше последовательных зависимостей

Обычный decode:

target
→ sampling
→ target
→ sampling
→ target
→ sampling

Speculative:

cheap draft
→ один target verification batch
→ сразу несколько новых tokens

Главная цель — уменьшить число serial target steps.

7.4. Меньше kernel launches и синхронизаций

Каждый отдельный decode-pass содержит множество GPU kernels и точек синхронизации. Если несколько позиций считаются одним graph, часть overhead амортизируется.


8. FLOPs могут вырасти, а latency уменьшиться

Это сначала кажется противоречием.

При speculative decoding target может выполнить больше арифметических операций, чем при обычной генерации. Причина — иногда target вычисляет speculative positions, которые потом будут отвергнуты.

Например draft предложил:

A B C D

а target принял только:

A

Вычисления для B C D частично оказались бесполезны.

Тем не менее wall-clock может уменьшиться:

больше параллельной работы
<
меньше последовательных шагов

Современный GPU имеет огромное количество ALU/Tensor Cores, которые при обычном batch=1 decode часто недогружены. Поэтому дополнительная арифметика может оказаться дешевле, чем дополнительный последовательный проход по весам.

Это один из ключевых выводов классической работы Leviathan, Kalman и Matias: speculative decoding может увеличить суммарное число арифметических операций, но снизить wall-clock благодаря параллельной проверке и сокращению memory traffic.


9. Что такое draft

Draft — это механизм, который дёшево предлагает continuation.

9.1. Маленькая отдельная модель

Классический вариант:

Target: 70B
Draft:   1B

Draft быстро генерирует x1 x2 x3 x4, target проверяет их batch-ом.

Чем сильнее draft совпадает с target и чем он дешевле, тем лучше.

9.2. MTP / NextN

Multi-Token Prediction — модель при обучении получает дополнительные головы/модули, предназначенные для предсказания будущих токенов.

Вместо отдельной полноценной маленькой LLM можно использовать небольшой обученный MTP-модуль, связанный с самой target-моделью.

В llama.cpp этот режим называется:

draft-mtp

Главная идея:

target hidden representation
+
token information
→ MTP module
→ cheap draft prediction

Детали конкретной архитектуры зависят от модели.

Важно понимать, что MTP — это не просто:

последний hidden state
→ ещё один обычный lm_head
→ магически токен через два

MTP специально обучен предсказывать будущие позиции и может использовать промежуточную информацию и предыдущие draft tokens.

9.3. EAGLE и похожие методы

Другой класс drafter-ов пытается предсказывать промежуточные feature/hidden representations target-модели, а не только token IDs.

Идея та же:

очень дёшево построить вероятное продолжение
→ batch verification target-моделью

9.4. N-gram speculation

Draft-модель вообще не обязательна.

Если текущий текст похож на уже встречавшийся фрагмент prompt/context, можно предположить продолжение по n-gram совпадению.

Это особенно полезно для:

  • кода;
  • JSON;
  • копирования фрагментов;
  • repetitive structured output.

На момент августа 2026 года llama.cpp поддерживает несколько speculative backends, включая отдельную draft-модель, MTP, EAGLE-подобные механизмы и несколько n-gram вариантов.


10. MTP в Qwen3.6

Qwen3.6 обучен с Multi-Token Prediction. Для llama.cpp существуют отдельные GGUF-варианты с MTP-весами.

Типичный запуск выглядит так:

./llama-server \
  -hf unsloth/Qwen3.6-35B-A3B-MTP-GGUF:UD-Q4_K_XL \
  -ngl 99 \
  -c 8192 \
  -fa on \
  -np 1 \
  --spec-type draft-mtp \
  --spec-draft-n-max 2

Здесь:

--spec-type draft-mtp

выбирает MTP как drafter.

А:

--spec-draft-n-max 2

ограничивает максимальную длину speculative draft.

На момент августа 2026 года Unsloth указывает для Qwen3.6 MTP ограничение -np > 1: multi-slot serving пока не поддерживается в этой конфигурации. Это implementation detail и со временем может измениться.


11. Что означает --spec-draft-n-max 2

Это не означает:

модель теперь всегда выдаёт ровно два токена вместо одного.

Это означает:

drafter может построить speculative continuation максимум заданной длины.

Target после этого проверяет draft.

Реально за одну итерацию может быть принято:

0 draft tokens
1 draft token
2 draft tokens

а verification дополнительно даёт ещё один target token.

Поэтому при γ = 2 одна итерация в удачном случае способна продвинуть sequence до:

γ + 1 = 3 tokens

12. Почему появляется дополнительный +1 токен

Пусть draft предложил:

A B

Target batch verification вычисляет распределения:

P(A | context)
P(B | context,A)
P(next | context,A,B)

Если A и B accepted, logits для позиции после B уже вычислены. Из них можно сразу выбрать/сэмплировать C.

Получается:

A B C

То есть два draft tokens позволили target iteration выдать три новых токена.

В общем случае максимальное продвижение:

γ + 1

13. Verification при greedy decoding

При полностью детерминированном decoding всё просто. Например:

temperature = 0

Draft предлагает:

A B C

Target одновременно получает свои argmax для соответствующих позиций:

A B X

Сравниваем слева направо:

A == A  → accept
B == B  → accept
C != X  → reject

После первого несовпадения speculative suffix больше нельзя использовать.

Почему? Потому что все последующие draft tokens были построены при условии, что C правильный. Если target выбрал вместо него X, continuation должна считаться уже из:

... A B X

14. Verification при sampling

С sampling всё интереснее.

Допустим используются:

temperature > 0
top-k
top-p

Теперь target не обязан выбирать argmax.

Пусть target distribution:

p(x)

а draft distribution:

q(x)

Draft sampled токен x ~ q.

Нельзя просто требовать совпадения с target argmax. И нельзя просто принять токен потому, что он находится внутри target top-k или top-p.

Для сохранения точного target distribution используется speculative sampling.


15. Правило acceptance min(1, p/q)

Для предложенного draft token x вычисляется:

accept probability
=
min(1, p(x) / q(x))

где:

p(x) = вероятность target
q(x) = вероятность draft

после соответствующих sampling transforms.

Рассмотрим пример.

Draft:

q(C) = 0.70

Target:

p(C) = 0.10

Draft слишком любит C. Если каждый раз принимать C, output будет смещён в сторону draft-модели.

Поэтому:

P(accept C | draft proposed C)
=
0.10 / 0.70
≈ 0.143

Draft предлагает C в 70% случаев, но принимается он примерно в 14.3% этих случаев:

0.70 × 0.143
≈ 0.10

И итоговая масса соответствует target.


16. Что если target любит токен сильнее draft

Допустим:

q(A) = 0.20
p(A) = 0.60

Тогда:

p(A)/q(A) = 3

а:

min(1,3) = 1

Если draft предложил A, он всегда принимается.

Но drafter предлагает его слишком редко — только в 20% случаев вместо нужных target 60%. Оставшаяся probability mass восстанавливается через корректирующее распределение при rejection.


17. Что происходит при rejection

Если draft token отклонён, нельзя просто вызвать обычный target sampler из p. Иначе уже принятая/отклонённая масса исказит распределение.

Классический speculative sampling использует residual distribution:

p'(x)
=
normalize(max(0, p(x) - q(x)))

Из него выбирается correction token.

Это и обеспечивает ключевое свойство классического алгоритма:

итоговая последовательность имеет то же probability distribution, что и обычный sampling непосредственно из target-модели.

То есть speculative decoding может быть lossless относительно target sampling distribution.


18. Почему нельзя просто принимать всё, что входит в top-k

Представим target:

A = 60%
B = 25%
C = 10%
D =  5%

И все четыре входят в top-k.

Draft:

A = 10%
B = 10%
C = 70%
D = 10%

Если использовать правило:

draft token входит в target top-k
→ accept

то C будет приниматься очень часто. В результате output distribution начнёт походить на draft, хотя target хотел выбирать C только в 10% случаев.

Это уже другая модель генерации.


19. Почему top-p тоже не решает проблему

Допустим nucleus top-p=0.95 содержит:

A  40.00%
B  25.00%
C  10.00%
D   5.00%
...
Z   0.05%

Все эти токены находятся «внутри разрешённого nucleus».

Но вероятности A и Z отличаются в:

40 / 0.05 = 800 раз

Membership в top-p говорит только:

токен не отфильтрован.

Он ничего не говорит о том, как часто target должен его выбирать.

Поэтому простое inside top-p → accept создаёт statistical bias.


20. Можно ли намеренно использовать approximate acceptance

Да.

Можно построить более агрессивный алгоритм:

если draft token входит в top-N target
→ accept

или:

если p_target(x) > threshold
→ accept

или:

если rank_target(x) < R
→ accept

Это может повысить acceptance rate и ускорение.

Но тогда inference уже не гарантирует точное target distribution. Это approximate speculative decoding.

Для некоторых практических задач такой trade-off может быть приемлем. Но если цель — ускорить модель, не меняя её статистическое поведение, нужен корректный rejection/correction algorithm.


21. Где в этом softmax

Softmax никуда не исчезает.

Target всё равно должен получить logits для проверяемых позиций. Условно:

H =

logits = H @ W_vocab

После этого sampling pipeline формирует effective probability distributions.

При batch verification LM head тоже может считаться сразу для нескольких positions. То есть часть выигрыша batching распространяется и на output projection.

Но speculative decoding существует не ради экономии softmax.

Основная стоимость большой LLM лежит в прохождении model blocks и доступе к весам. Особенно это заметно у больших dense/MoE-моделей.


22. Нужно ли вычислять полный vocabulary для verification

Для классического exact sampling target должен иметь достаточно информации, чтобы сформировать нужное распределение p.

Для greedy decoding теоретически нужен только корректный argmax.

Для stochastic sampling и residual correction нужны target probabilities после sampler transforms.

Конкретные runtime могут оптимизировать отдельные операции, но концептуально verification требует target distribution для проверяемой позиции.

Поэтому speculative decoding — не «способ избежать output head».


23. Что происходит с KV-cache

Target verification вычисляет новые internal states для speculative positions.

В обычном Transformer это, в частности, K и V для новых позиций.

Если draft:

A B C

и все три приняты, то:

KV(A)
KV(B)
KV(C)

можно оставить в target KV-cache. Следующий decode продолжает непосредственно после C.


24. Что происходит с KV-cache при rejection

Пусть target принял:

A B

но отверг C.

Все состояния после первого rejected position больше недействительны.

Runtime должен:

  1. сохранить state принятого prefix;
  2. удалить/откатить speculative suffix;
  3. добавить correction token;
  4. продолжить decoding уже от корректного state.

Конкретная реализация может:

  • писать speculative states во временную ветку;
  • копировать sequence state;
  • откатывать KV positions;
  • использовать отдельные sequence IDs.

Но логически всегда происходит одно и то же:

accepted prefix
→ commit

rejected suffix
→ discard

25. А что с recurrent/hybrid моделями

Не все современные LLM являются обычными full-attention Transformers.

Hybrid-архитектуры могут сочетать:

attention
+
linear attention
+
recurrent state
+
MoE

Тогда кроме KV-cache существуют recurrent states.

Для speculative verification runtime должен корректно управлять и ими:

accepted speculative state
→ commit

rejected speculative state
→ rollback/discard

Это делает поддержку speculative decoding для hybrid-моделей сложнее, чем для классического Transformer.

Поэтому MTP требует не только наличия MTP-весов, но и поддержки конкретной архитектуры inference engine.


26. Почему MTP требует дополнительной VRAM

MTP может ускорить inference, но он не бесплатен по памяти.

Появляются дополнительные расходы:

MTP weights
+
draft context/state
+
temporary verification buffers
+
larger compute graph

Поэтому может возникнуть ситуация:

обычная модель:
130k context помещается

та же модель + MTP:
только 90–110k

Это нормальный trade-off:

скорость
vs
максимальный context

27. Почему verification batch требует больше compute memory

Обычный decode обрабатывает одну новую позицию. Speculative verification — несколько.

Внутренние activation tensors имеют дополнительное измерение по числу проверяемых positions.

Поэтому растут:

  • temporary CUDA buffers;
  • graph workspace;
  • intermediate activations;
  • иногда communication buffers при multi-GPU.

При очень плотном заполнении VRAM именно MTP может стать причиной того, что runtime вынужден отключить какую-то оптимизацию или уменьшить контекст.


28. Pipeline parallelism и OOM

На нескольких GPU inference engine может пытаться использовать pipeline/overlap между устройствами. Это иногда требует дополнительного workspace.

Поэтому возможен лог вида:

cudaMalloc failed: out of memory
failed to allocate compute buffers
retrying without pipeline parallelism

Если после этого появляется:

model loaded

это не обязательно означает, что часть модели ушла на CPU.

Это может означать:

weights + cache + MTP помещаются

но самый прожорливый compute schedule
не помещается

→ runtime выбрал менее memory-intensive schedule

Такой fallback может быть вполне рабочим.


29. Почему MTP особенно хорошо работает, когда target decode memory-bound

Рассмотрим условную большую модель.

Один decode token:

время = 20 ms

Это не означает, что ALU GPU были заняты на 100% все 20 ms. Большая часть ограничения может быть связана с чтением весов.

Verification двух speculative positions может занять, например:

26 ms

а не:

40 ms

Потому что веса читаются и используются более эффективно.

Если два speculative tokens приняты и дополнительно получается ещё один target token, условно:

3 output tokens / 26 ms
≈ 115 tok/s

вместо:

1 / 20 ms
= 50 tok/s

Это идеализированный пример.

На практике:

  • draft имеет стоимость;
  • часть tokens rejected;
  • verification batch становится тяжелее;
  • runtime overhead остаётся.

Поэтому реальный speedup обычно намного меньше теоретического максимума.


30. Acceptance rate — центральная метрика

Если drafter почти всегда угадывает target, speculative decoding великолепен. Если угадывает плохо — target выполняет много бесполезной работы.

Обозначим среднюю вероятность принять speculative token:

α

и максимальную длину draft:

γ

При упрощающем предположении независимой одинаковой acceptance probability ожидаемое число токенов, выдаваемых одной target iteration:

E[tokens]
=
1 + α + α² + ... + α^γ

или:

E[tokens]
=
(1 - α^(γ+1)) / (1 - α)

Пример:

α = 0.8
γ = 2

Тогда:

E = 1 + 0.8 + 0.64 = 2.44 tokens

То есть в идеализированной модели одна target verification iteration продвигает sequence в среднем примерно на 2.44 токена.


31. Почему это не означает 2.44× speedup

Потому что target verification batch сам становится тяжелее. И drafter тоже что-то стоит.

Для инженерной оценки удобно ввести:

T1 = latency обычного target decode одного token

Rγ = latency verification batch / T1

Cγ = полная latency построения draft / T1

Тогда грубая практическая оценка:

speedup
≈
E[tokens] / (Rγ + Cγ)

Например:

E  = 2.44
Rγ = 1.45
Cγ = 0.15

Получаем:

2.44 / 1.60 ≈ 1.53×

То есть обычные 45 tok/s могут превратиться примерно в 69 tok/s. В реальном runtime дополнительные overhead могут снизить результат.

Классическая теоретическая модель speculative decoding использует похожую идею: speedup определяется одновременно acceptance rate и относительной стоимостью drafter-а, а не одной только длиной draft.


32. Почему слишком большой draft может замедлить модель

Кажется логичным:

n-max = 2 хорошо
→ n-max = 8 должно быть ещё лучше

Но нет.

При увеличении γ потенциально можно принять больше tokens, но одновременно:

verification batch тяжелее
draft дороже
вероятность ошибки дальнего token выше
wasted speculative computation больше
memory/workspace больше

Поэтому существует оптимальная draft length.

Она зависит от:

  • модели;
  • sampler settings;
  • языка;
  • типа текста;
  • текущего контекста;
  • GPU;
  • quantization;
  • batch kernels;
  • скорости drafter.

Оптимум надо измерять, а не угадывать.


33. Почему coding часто хорошо подходит speculative decoding

Код содержит много предсказуемых конструкций:

for item in items:
    ...
{
  "name": "...",
  "value": ...
}

Также coding-agent часто:

  • копирует имена функций;
  • повторяет пути файлов;
  • воспроизводит структуру JSON;
  • пишет boilerplate;
  • продолжает уже существующий код.

Поэтому MTP и особенно n-gram speculation могут иметь высокий acceptance.

В сложном reasoning-тексте token entropy выше, и дальний draft может угадываться хуже.


34. Agentic inference имеет ещё один важный фактор

Agent обычно генерирует не один ответ на 5000 токенов, а много коротких turns:

reason
→ tool call
→ tool output
→ reason
→ edit
→ test
→ reason
...

Поэтому для агента важны сразу две скорости:

prefill / context reuse
+
decode throughput

MTP ускоряет в первую очередь decode.

Он не решает автоматически проблему повторного prefill длинного контекста.

Если inference engine каждый agent step заново обрабатывает 100k prompt, хороший prefix/KV-cache reuse может быть важнее MTP.


35. Как измерять пользу MTP

Нельзя смотреть только на tok/s.

Полезно измерять:

1. baseline generation tok/s
2. generation tok/s с MTP
3. draft tokens generated
4. draft tokens accepted
5. acceptance rate
6. target verification batch size
7. VRAM usage
8. maximum stable context
9. prompt processing speed
10. end-to-end agent task time

Последний пункт особенно важен.

Например:

MTP:
+30% decode throughput

но:

-30% maximum context

может быть плохим trade-off для длинноконтекстного агента.


36. Пример компромисса на 24 ГБ VRAM

Допустим одна конфигурация позволяет:

Q4_K_M
+
MTP
+
90k context
+
60 tok/s

А более компактный quant:

IQ4_NL
+
MTP
+
132k context
+
примерно та же скорость

Первая конфигурация имеет немного более точные веса. Вторая даёт намного больше рабочего контекста.

Для coding-agent второй вариант может быть системно лучше, даже если standalone benchmark модели чуть хуже.

Это хороший пример того, почему локальный inference надо оптимизировать как всю систему, а не только как quant весов.


37. Greedy и stochastic speculative decoding — не одно и то же

Полезно разделять эти случаи.

Greedy

Target определяет:

argmax p(x)

Draft token либо совпадает, либо нет. Verification простая и детерминированная.

Sampling

Target имеет distribution p(x), draft — q(x).

Нужно probabilistic acceptance/rejection и residual correction.

Если реализация сделана корректно, результат имеет то же distribution, что target sampling без speculation.


38. Что происходит с temperature, top-k и top-p

Удобно мысленно считать, что sampling pipeline превращает исходные logits target в итоговое effective distribution:

raw logits
↓
penalties
↓
temperature
↓
top-k
↓
top-p
↓
другие filters
↓
normalize
↓
p(x)

Draft аналогично имеет q(x).

Speculative sampling работает уже с этими effective distributions.

Поэтому p/q относится не обязательно к «сырому softmax модели», а к distributions после соответствующего sampling policy.

Точная последовательность зависит от runtime.


39. Stateful samplers и grammar constraints усложняют картину

В реальных inference engines sampling может включать:

  • repetition penalties;
  • DRY;
  • grammar constraints;
  • JSON grammar;
  • token bans;
  • dynamic samplers.

Для строгой гарантии exactness состояние sampler-а должно обновляться и откатываться согласованно с accepted/rejected speculative branch.

Особенно тонки grammar-constrained режимы: локальная masking-логика и состояние грамматики должны корректно сочетаться с rollback.

Поэтому фраза:

speculative decoding всегда математически идентичен baseline

верна для алгоритма и sampler pipeline, которые действительно реализуют корректную target-distribution-preserving verification.


40. MTP и качество модели

При корректной target verification MTP используется только как proposal mechanism.

Он не должен самостоятельно определять финальный output.

Поэтому более слабый MTP drafter в нормальном lossless режиме приводит прежде всего к:

меньше acceptance
→ меньше speedup

а не к:

хуже качество target

Это важное преимущество speculative decoding: target всё равно является арбитром.


41. Почему иногда говорят о деградации качества от speculative decoding

Причин может быть несколько:

  1. Реализация использует approximate acceptance.
  2. Есть bug в cache/state rollback.
  3. Sampler state обрабатывается неидентично baseline.
  4. Используются разные temperature/top-p pipelines.
  5. Grammar/constraints взаимодействуют со speculation.
  6. Floating-point/batching differences меняют пограничные решения.
  7. Конкретный backend имеет implementation issue.

Поэтому для production agent полезно сравнивать MTP ON/OFF на одинаковом наборе задач.


42. Distribution-preserving не всегда означает байт-в-байт тот же текст

Даже если алгоритм сохраняет одно и то же distribution, stochastic sampling не обязательно даёт один и тот же конкретный текст при разных random-number consumption patterns.

«Distribution-preserving» означает:

вероятностный закон output тот же

а не обязательно:

при любой реализации и том же seed
получим байт-в-байт тот же sample

Чтобы требовать идентичный sample при фиксированном seed, runtime должен ещё и синхронизировать RNG semantics.

Для greedy decoding проверять идентичность проще.


43. Почему MTP может быть выгоднее отдельной draft-модели

Отдельный drafter требует:

дополнительные weights
дополнительный KV cache
дополнительные model passes

MTP head/module может быть намного компактнее и использовать representations самой target-модели.

Это потенциально уменьшает draft cost.

С другой стороны, MTP требует, чтобы сама модель была обучена с соответствующими heads/modules и чтобы runtime их поддерживал.


44. Почему обычный GGUF нельзя превратить в MTP одним флагом

MTP — это не только runtime algorithm.

Нужны обученные параметры.

Поэтому обычно существуют отдельно:

Model-GGUF

и:

Model-MTP-GGUF

Если MTP weights не сохранены в файле, inference engine не может «изобрести» их флагом:

--spec-type draft-mtp

Флаг включает использование уже существующего drafter-а, но не создаёт его.


45. Можно ли одновременно использовать MTP и n-gram speculation

Да, если runtime это поддерживает.

Например:

ngram
→ отлично угадывает повторение существующего кода

MTP
→ угадывает новое продолжение

Это комплементарные механизмы.

Современный llama.cpp позволяет комбинировать несколько speculative implementations. Такой подход особенно интересен для coding-agent.


46. Почему speculative decoding не ускоряет prompt processing так же заметно

Prompt и так считается batch-ом.

Если у нас prompt на 50k токенов, inference engine уже может обрабатывать его крупными chunks.

Главная проблема speculative decoding — именно:

batch = 1 autoregressive generation

Поэтому основной gain ожидается в generation throughput.


47. Как выглядит одна полная speculative iteration

Есть подтверждённый prefix:

P

Шаг 1. Draft

Drafter строит:

d1
d2
...
dγ

авторегрессионно или своим специализированным способом.

Шаг 2. Target verification

Target одним batch считает distributions:

p1(x) = T(P)
p2(x) = T(P+d1)
p3(x) = T(P+d1+d2)
...
pγ+1(x)

Шаг 3. Acceptance

Draft tokens проверяются слева направо.

Пока проходят — commit.

На первом rejection — stop.

Шаг 4. Correction / extra target token

Если произошёл rejection:

sample correction from residual distribution

Если все draft tokens accepted:

sample extra token from pγ+1

Шаг 5. Cache commit

Accepted target states сохраняются. Rejected suffix удаляется.

Шаг 6. Следующая итерация

Процесс повторяется.


48. Почему проверять надо слева направо

Пусть draft:

A B C

И target считает:

A ✓
B ✗

Тогда проверка C уже не имеет смысла как continuation.

Draft C был предложен при prefix:

... A B

Но правильный prefix после correction будет:

... A X

Это другая conditional distribution.

Поэтому speculative acceptance всегда имеет структуру:

accepted prefix
+
first correction

а не произвольный набор принятых tokens внутри draft.


49. Какой theoretical maximum

При draft length γ одна target iteration может выдать максимум:

γ + 1

токенов.

Но speedup почти никогда не достигает γ+1.

Для этого одновременно нужно:

acceptance ≈ 100%
draft cost ≈ 0
verification batch latency ≈ single-token latency
overhead ≈ 0

В реальном железе все четыре условия нарушаются.

Поэтому n-max=4 не означает .


50. Что значит реальный результат 45 → 60 tok/s

Это:

60 / 45 = 1.333...

то есть примерно:

+33% throughput

Latency на output token:

без MTP:
1000 / 45 ≈ 22.2 ms/token

с MTP:
1000 / 60 ≈ 16.7 ms/token

Экономия:

≈ 5.5 ms на output token

Это уже существенный результат для agentic workload. Если агент за задачу генерирует десятки тысяч токенов, wall-clock выигрыш накапливается.


51. Что оптимизировать на практике

1. Найти baseline

Измерить:

MTP OFF
generation tok/s
VRAM
max context

2. Включить небольшой draft

Например:

--spec-draft-n-max 2

3. Измерить acceptance

Если она высокая — увеличивать draft потенциально имеет смысл.

4. Попробовать 3/4

Смотреть не только на acceptance, но на итоговый wall-clock.

5. Следить за VRAM

Больший speculative batch может уменьшить максимальный context.

6. Проверить качество

Особенно:

tool calling
JSON
coding
длинные agent trajectories

52. Что важнее: acceptance rate или tok/s

tok/s.

Acceptance rate — диагностическая метрика.

Например:

Configuration A:
acceptance = 90%
60 tok/s

Configuration B:
acceptance = 75%
70 tok/s

Вторая быстрее.

Почему? Возможно, её drafter дешевле или verification batch лучше ложится на GPU.

Поэтому цель:

максимальный end-to-end throughput

а acceptance помогает понять, почему он такой.


53. Для агента лучше смотреть вообще не на tok/s

Финальная метрика:

seconds per successfully completed task

Потому что конфигурация может быть быстрее в tokens/sec, но:

  • сильнее квантована;
  • иметь меньше context;
  • делать больше agent steps;
  • чаще ошибаться в tools;
  • чаще переписывать код.

Например:

Model A:
70 tok/s
20 agent steps

Model B:
55 tok/s
10 agent steps

Model B может завершить задачу быстрее.


54. Ментальная модель, которую стоит запомнить

Неправильная:

MTP угадал два токена
→ большая модель их не считает
→ поэтому быстрее

Правильная:

MTP дёшево угадал continuation
↓
target всё равно полностью считает эти позиции
↓
но считает их одновременно batch-ом
↓
GPU делает больше работы за один serial target step
↓
если guesses часто принимаются,
число serial target steps на output token уменьшается

То есть speculative decoding — это прежде всего:

обмен дополнительной параллельной арифметики на уменьшение последовательности вычислений и memory traffic.


55. Самый важный парадокс speculative decoding

Можно сформулировать совсем коротко:

FLOPs ↑
serial target calls ↓
memory efficiency ↑
GPU utilization ↑
wall-clock ↓

Именно поэтому технология работает.

Она не пытается сделать большую модель математически дешевле. Она пытается заставить современное железо эффективнее выполнить почти те же вычисления.


56. Итог

Speculative decoding состоит из четырёх идей:

  1. Дешёвый drafter предлагает несколько будущих токенов.
  2. Target проверяет их одним batched forward pass.
  3. Acceptance algorithm оставляет только корректный speculative prefix.
  4. Cache/state management коммитит accepted states и откатывает rejected suffix.

MTP — один из наиболее удобных drafter-ов, потому что он обучен вместе с target-моделью и может быть существенно дешевле отдельной draft LLM.

Главный источник ускорения — не softmax и не пропуск слоёв. Он здесь:

несколько sequential target decodes
            ↓
один batched target verification

Для memory-bound autoregressive inference это может дать большой выигрыш даже при том, что общее количество арифметических операций возрастает.

А в stochastic sampling математическое правило min(1,p/q) нужно не ради «оценки качества токена», а ради более строгой цели:

использовать предложения drafter-а, не превращая drafter в скрытый источник bias и сохраняя distribution target-модели.


Литература и реализация

Для дальнейшего чтения:

  • Yaniv Leviathan, Matan Kalman, Yossi Matias — Fast Inference from Transformers via Speculative Decoding, ICML 2023.
  • llama.cpp — docs/speculative.md.
  • llama.cpp — common/speculative.cpp.
  • llama.cpp — examples/speculative/speculative.cpp.
  • Unsloth — model card Qwen3.6-35B-A3B-MTP-GGUF.
  • Qwen3.6 model card — архитектура и описание Multi-Token Prediction.

CLI-опции и ограничения speculative backends активно меняются, поэтому команды запуска перед использованием стоит сверять с текущей документацией llama.cpp.