Спекулятивное декодирование
- 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%