EnglishРусский Map

Спекулятивное декодирование

title
Спекулятивное декодирование
type
concept
summary
Предсказание нескольких токенов за прямой проход и пакетная проверка: четыре варианта в llama.cpp (draft-модель, MTP, EAGLE3, ngram-mod).
tags
llm, inference, llama-cpp, local-models
created
2026-05-13
updated
2026-07-29
lang
ru
translation_of
speculative-decoding
source_updated
2026-07-29
translated
2026-09-01
translator
lllm/antigravity/gemini-3.7-flash-medium

Спекулятивное декодирование - это метод, при котором дёшево генерируется несколько токенов-кандидатов, а затем проверяется за один пакетный прямой проход основной модели. Если кандидаты приняты, вы получаете сразу несколько токенов по цене одного прямого прохода; если отклонены - происходит откат к стандартной последовательной генерации. Основные различия заключаются в способе генерации кандидатов - и по состоянию на 2026 год llama.cpp поддерживает четыре механизма с разным балансом между памятью и качеством.

Арифметика здесь простая: генерация чернового токена должна быть существенно дешевле прогона основной модели, а доля принятых токенов - достаточно высокой, чтобы пакетная верификация окупалась. И то и другое зависит от задачи: строго структурированный вывод (код, перевод, математика) даёт куда больший процент подтверждения, чем творческий текст.

Четыре варианта в llama.cpp

Draft-модель (--spec-type draft). Для генерации черновых токенов берётся небольшая родственная модель из того же семейства - с тем же токенизатором, словарём и похожим стилем. Основная модель затем проверяет их пакетом. Это классическая реализация. Здесь критически важно соотношение размеров: черновая модель должна быть как минимум в ~3 раза меньше по числу активных параметров, иначе накладные расходы съедят всё ускорение. Пример от Вячеслава: одна Gemma-4 31B UD-Q4_K_XL выдаёт 62 t/s; Gemma-4 31B с Gemma-4 E2B в роли черновой модели - 97 t/s (около 55% принятых черновых токенов на коде). Стоит указывать --parallel 1, чтобы избежать четырёхкратного резервирования памяти при автоматическом параллелизме.

По умолчанию --draft-p-min равен 0.75: токен принимается, только если и черновая, и основная модель уверены в нём более чем на 75%. Технически здесь допускается дрейф вывода: может пройти токен, который сама основная модель не выбрала бы, но считает приемлемым. Точная проверка без потерь (lossless) не является поведением по умолчанию для draft-модели.

MTP - Multi-Token Prediction (--spec-type mtp). Дополнительные головы предсказания, обучаемые вместе с моделью, которые прогнозируют сразу несколько следующих токенов из одного скрытого состояния (hidden state). Никакой отдельной draft-модели и отдельных весов: головы уже встроены в GGUF. Впервые появился в DeepSeek V3/R1; llama.cpp PR #22673 добавил поддержку для Qwen 3.6 и Gemma 4.

Типичная конфигурация - MTP с --spec-draft-n-max 2-3. Замеры janvitos на RTX 4070 Super 12GB (reddit-qwen3-6-mtp-12gb): 80+ t/s на коде при 92-95% принятых токенов. Зависимость от контекста здесь ниже, чем у отдельной draft-модели, так как головы обучались вместе с основными весами. Верификация по умолчанию точная (exact) - MTP не допускает дрейфа вывода, свойственного draft-моделям.

EAGLE3 (--spec-type eagle3). Лёгкая авторегрессионная голова, подключаемая к существующим весам: без отдельной draft-модели и без обученных вместе с моделью голов MTP. Она считывает скрытое состояние основной модели и предсказывает по нему следующие несколько токенов. Работает с моделями, которые изначально не проектировались под спекулятивное декодирование. llama.cpp PR #18039. Проверка по умолчанию точная.

ngram-mod (--spec-type ngram-mod). Черновик строится чисто математически на основе предыдущих токенов из того же контекста - без модели и без голов. Отлично подходит, когда вывод дословно воспроизводит большие куски входных данных: точечная правка файла с выводом остального текста без изменений, замена имени переменной по всему блоку, перегенерация кода с одной правкой. llama.cpp PR #19164. Идеальный вариант для автономных кодинг-агентов: в цикле "прочитать файл -> изменить -> вывести изменённый файл" ngram-mod берёт на себя почти весь повторный вывод практически бесплатно.

Когда выигрывает каждый вариант

Вариант Лучше всего для Хуже всего для Примечания
Draft-модель Dense-моделей, смешанных нагрузок Маленьких моделей, где не сходится соотношение размеров Есть дрейф вывода; не побитово точная
MTP Моделей с готовыми головами MTP (DeepSeek, Qwen 3.6, Gemma 4) Моделей без таких голов (большинство старых) Точная верификация
EAGLE3 Существующих моделей без голов MTP Vision / нетекстового вывода Точная верификация
ngram-mod Задач с обилием правок, кода с повторами Генерации в свободной форме Бесплатен; использует только контекст

Зависимость от длины контекста

Наблюдение по результатам замеров MTP на длинном контексте (Still-Notice8155, reddit-qwen3-6-mtp-12gb): MTP экономит примерно постоянное время на токен независимо от длины контекста, тогда как затраты на attention растут с контекстом линейно. Поэтому относительная выгода MTP увеличивается по мере заполнения контекста. На Qwen3.6-35B-A3B при контексте 125K: без MTP получается ~3 t/s, а в связке MTP + turboquant - 13.6 t/s (ускорение в 4.5 раза). При контексте 5K та же конфигурация быстрее всего в 1.8 раза. Это отличается от поведения большинства других оптимизаций: выигрыш от MTP максимален именно там, где базовый инференс работает медленнее всего.

Доля принятых токенов зависит от задачи

MTP на Qwen3.6 по девяти типам задач (mtp-bench.py от janvitos):

Задача Доля принятых
code_python 0.947
code_cpp 0.925
stepwise_math 0.826
qa_factual 0.826
translation 0.812
summarize 0.800
long_code_review 0.790
explain_concept 0.750
creative_short 0.694

Этот разброс отражает предсказуемость распределения токенов в ответе. Код с устоявшимися паттернами даёт ~95% подтверждений, а свободный текст опускается до ~69%. Это распределение сохраняется для всего семейства методов спекулятивного декодирования: задачи, на которых хорошо работает MTP, точно так же подходят для draft-моделей и вариантов с EAGLE3.

Проблемы и ограничения

  • Vision в MTP не работает по состоянию на середину 2026 года. Текущее состояние описано в issue #22867 и обсуждении PR #22673 в llama.cpp. Для мультимодальных задач лучше использовать draft-модель.
  • Память под draft-модель не бесплатна. Флаг --parallel 1 вдвое уменьшает резервирование KV-кэша по сравнению со значением по умолчанию --parallel 4; этот гигабайт памяти может стать решающим для того, чтобы модель поместилась в GPU.
  • Вывод reasoning-моделей при спекулятивном декодировании требует флага --chat-template-kwargs '{"preserve_thinking": true}', чтобы цепочка рассуждений (thinking trace) не обрезалась. Головы MTP в Qwen 3.6 обучались именно с таким расчётом.

Ссылки

  • reddit-qwen3-6-mtp-12gb - тред на Reddit с практическими замерами, откуда взяты приведённые выше эмпирические цифры
  • habr-local-llm-quantization-deep-dive - обзорная статья Вячеслава, в которой описаны все четыре варианта
  • moe-cpu-offload - ещё один практический инструмент, который в сочетании со спекулятивным декодированием позволяет запускать модели класса 35B на потребительских картах с 12 GB VRAM
  • local-llm-16gb-vram-tests - в этой статье с тестами спекулятивное декодирование отключено; указанные там скорости получены при последовательной генерации
  • llama-cpp - место реализации
  • deltafin - n-gram-спекуляция за пределами llama.cpp, работающая без потерь (lossless) и включённая по умолчанию, поскольку для прогретого токена узким местом становится resident I/O, а не вычисления
  • neutrino-1-8b - верификатор на 8B и drafter на 0.6B в одном формате и одном процессе с накладными расходами по весу всего 8.46%