Все статьи
Артемий Мазаев·· 9 мин чтения

Спекулятивный декодинг: ускоряем LLM в 2–3 раза 🏎️💨

Спекулятивный декодинг: почему декод простаивает GPU и как черновик с редактором ускоряют генерацию без потери качества — EAGLE, Medusa, MTP, vLLM.

Спекулятивный декодинг: ускоряем LLM в 2–3 раза 🏎️💨

Ну чё, малютки, ловите парадокс: у тебя простаивает дорогая видюха на 80 ГБ VRAM, генерируя текст медленнее, чем могла бы. GPU способен за один такт перемножить миллиарды чисел, а токены всё равно сыпятся по одному в час по чайной ложке. Спекулятивный декодинг — трюк, который эксплуатирует именно эту дыру: даёт мелкой модели угадывать за большую, а большой — проверять оптом. Итог — ускорение в 2–3 раза, и результат бит-в-бит совпадает с тем, что модель выдала бы сама.

🔥Суть за 10 секунд

Мелкая черновая модель быстро предлагает несколько токенов вперёд. Большая целевая модель проверяет их все за один проход — так же дёшево, как сгенерить один токен. Верные догадки принимаются, неверные — отбрасываются и переписываются целевой моделью. Итоговый текст математически идентичен тому, что дала бы одна целевая модель без всякого черновика.


Парадокс простаивающего GPU

Раскладка, которую я уже проговаривал в статье про KV-кэш: генерация токен за токеном — это memory-bound процесс. На каждом шаге GPU обязан перечитать из VRAM вообще все веса модели (и KV-кэш), чтобы вычислить один-единственный следующий токен. Арифметика при этом занимает жалкие доли времени — основное узкое место — это скорость шины памяти, а не мощность тензорных ядер.

Результат: на генерации GPU простаивает. Вычислительные блоки ждут, пока подъедут данные из памяти, а могли бы в это время посчитать в разы больше — были бы токены, на которых считать.

Спекулятивный декодинг подсовывает эти токены. Идея простая до неприличия: пусть маленькая быстрая модель набросает черновик на несколько шагов вперёд, а большая модель, вместо генерации по одному, проверит весь черновик разом — благо простаивающей вычислительной мощности для этого с избытком.


Черновик и редактор

Аналогия из редакции: черновик пишет стажёр — быстро, дёшево, местами ошибается. Главный редактор не переписывает всё с нуля — он читает черновик и вычёркивает только то, что неверно. Если стажёр угадал правильно — редактор экономит кучу времени. Если ошибся — редактор всё равно должен был прочитать текст, так что потерь почти нет.

В цифрах: черновая модель (draft) предлагает k токенов вперёд, целевая модель (target) проверяет все k за один проход и для каждой позиции решает — принять токен черновика или заменить своим. Смотри на гонке двух дорожек:

🏎️ Обычный декод vs спекулятивный
Цель — сгенерировать «Кот сидел на окне и смотрел на дождь». Серый — черновик мелкой модели (ещё не проверен), зелёный — подтверждено большой моделью, синий — бонусный токен «в подарок», красный — отклонено и переписано.
🐢 Обычный декод — 1 токен за проход GPU0 проходов GPU
···
···
···
···
···
···
···
···
🚀 Спекулятивный — пачками по 40 проходов GPU
···
0
Проходов GPU — обычный
0
Проходов GPU — спекулятивный
черновикпринятобонусотклонено
Шаг 0/6

Ключевое: обычный декод тратит один проход GPU на один токен. Спекулятивный тратит один проход GPU на проверку целой пачки, а сколько токенов из неё примут — вопрос отдельный. В худшем случае (черновик ошибся сразу) не проиграли почти ничего. В лучшем — за один проход получили сразу k+1 токен.

Раунд спекулятивного декодинга: черновик предлагает k токенов, целевая модель проверяет всех разом. Принятые токены остаются, на первом отказе — ресэмплинг, и раунд начинается заново с новой позиции.

Почему проверка почти бесплатна

Вот это и есть весь фокус, объясняющий, откуда берётся ускорение без потери качества. Проверка k черновых токенов — это forward pass целевой модели с последовательностью длины k, поданной параллельно. А раз декод memory-bound, время шага определяется не тем, сколько токенов считать, а тем, что веса читаются из VRAM один раз за проход — независимо, обрабатывается ли на этом проходе один токен или пять.

💾 Почему проверка почти бесплатна
Декод — memory-bound: время шага определяется чтением весов из VRAM, а не арифметикой (подробно — в статье про KV-кэш). GPU читает веса один раз за проход независимо от того, для скольких токенов считает.
Чтение весов из VRAM (тяжёлая часть)
1 проход по весам
Токенов получено за этот проход
1 токен
1×
Токенов на 1 чтение весов
~1.0×
Время прохода относительно обычного
Так работает обычный автогрессивный декод: один проход весов — один токен на выходе. Вся пропускная способность VRAM потрачена на то, чтобы вычислить единственное число.

То есть проверить черновик из 5 токенов стоит примерно как сгенерить 1 токен обычным способом. Если целевая модель согласилась хотя бы с парой из пяти — уже в выигрыше. Именно поэтому у спекулятивного декодинга почти нет минусов: цена входа — один лишний проход весов, а выигрыш растёт с каждым принятым токеном черновика.

А как проверять сразу k токенов, если декод авторегрессивный?

Хитрость в том, что позиции 2..k уже известны заранее — их предложил черновик. Целевая модель не должна ждать вывода предыдущего шага, чтобы узнать вход следующего: вся последовательность подаётся сразу, с маской внимания, которая не даёт токену видеть будущее (та же causal-маска, что и при обучении). Технически это тот же трюк, которым тренируют трансформеры — teacher forcing, только тут учитель — черновик, а не размеченные данные.


Математика гарантии: почему это не аппроксимация

Самый частый вопрос: если часть токенов пишет мелкая слабая модель, разве качество не проседает? Ответ — нет, и это доказуемо. Приём называется speculative sampling, и вот его суть без формул:

1Черновик предложил токен с вероятностью q(x) по своему распределению
2Целевая модель знает свою вероятность p(x) для того же токена
3Токен принимается с вероятностью min(1, p(x)/q(x)) — чем увереннее в нём целевая модель относительно черновика, тем выше шанс принять
4При отказе — токен ресэмплится не из p(x) напрямую, а из скорректированного остатка max(0, p(x) − q(x)), нормализованного заново

Шаг 4 — не техническая деталь, а сердце доказательства: он гарантирует, что после исправления итоговое распределение токена математически равно p(x) — тому самому, что выдала бы целевая модель, если бы генерировала сама с нуля, без всякого черновика. Это не «почти то же самое» и не размен качества на скорость — это точная выборка из того же распределения, только более быстрым путём.

⚠️⚠️ Одно уточнение: только при жадном или температурном сэмплинге

Гарантия строгая при обычном сэмплировании (в том числе greedy — жадный выбор самого вероятного токена, это частный случай с температурой → 0). При экзотических стратегиях (beam search, некоторые виды контроля разнообразия) эквивалентность нужно доказывать отдельно — большинство движков включают спекуляцию только там, где она гарантированно бесплатна по качеству.


Сколько реально выигрываем

Выигрыш зависит от трёх вещей: как часто черновик угадывает (acceptance rate, α), сколько токенов он предлагает за раз (k), и насколько он сам дешевле целевой модели. Формула ожидаемого числа принятых токенов за раунд — (1 − α^(k+1)) / (1 − α), классика из оригинальной статьи Leviathan et al. Покрути сам:

🧮 Калькулятор ускорения
Три параметра решают всё: насколько черновик похож на оригинал, сколько токенов угадывать за раз, и насколько драфт-модель дешевле целевой.
Acceptance rate (α)75%
Как часто большая модель соглашается с черновиком — зависит от сложности текста и температуры
Длина черновика (k)4 токенов
Сколько токенов вперёд угадывает черновая модель за один раунд
Цена черновика10% от большой модели
Насколько черновая модель легче целевой — EAGLE почти бесплатен, отдельная 7B-модель дороже
×2.2
Ожидаемое ускорение
3.1
Токенов за раунд
Sweet spot: высокий acceptance rate и дешёвый черновик — почти вся стоимость раунда уходит на одну проверку большой моделью.

Общее наблюдение: высокий acceptance rate решает всё. Он падает на творческих задачах с высокой температурой (там много правдоподобных продолжений, черновику сложнее угадать точный токен) и растёт на предсказуемых текстах — код, повторяющиеся структуры, автодополнение. Отсюда практика: спекулятивный декодинг даёт наибольший буст именно на кодогенерации и структурированном выводе, а на «напиши стих в свободном стиле» выигрыш скромнее.


Зоопарк методов: кто предлагает черновик

Все методы решают одну задачу — где взять дешёвый и точный черновик — но по-разному:

МетодКак устроенОсобенность
Отдельная draft-модельМеньшая модель того же семейства (например, Llama 1B рядом с Llama 70B)Просто внедрить, но нужен отдельный набор весов в VRAM и совпадающий токенизатор
Prompt lookup / n-gramЧерновик ищется прямо в промпте по совпадению n-грамм, без отдельной моделиБесплатно по VRAM, отлично работает на задачах вроде «перепиши этот файл», где вывод повторяет вход
MedusaНесколько дополнительных «голов» поверх той же целевой модели, каждая предсказывает свою позицию вперёдНе нужна отдельная модель — головы дообучаются поверх готовой
EAGLE / EAGLE-2 / EAGLE-3Лёгкий блок предсказывает не токены, а следующие скрытые состояния целевой модели, из них уже сэмплится токенЗаметно точнее n-gram и Medusa за счёт доступа к внутреннему представлению целевой модели
MTP (Multi-Token Prediction)Черновые головы встроены и обучены вместе с самой моделью с нуляТак устроены DeepSeek-V3 и Kimi K2.5 — про их архитектуру я писал в разборе MoE

Тренд последних двух лет — от «поставь рядом отдельную маленькую модель» к «встрой дешёвый черновик прямо в архитектуру». EAGLE и MTP выигрывают именно потому, что черновик работает не вслепую по тексту, а видит внутренности целевой модели.


Подвохи

На больших батчах выигрыш тает. Спекуляция отбивает простаивающую вычислительную мощность GPU. При батче 1 (твой локальный чат) её навалом — грех не воспользоваться. А вот на сервере с батчем 64+ GPU и так уже занят вычислениями под завязку, свободных тактов для проверки черновика не остаётся — декод из memory-bound потихоньку переходит в compute-bound, и спекуляция может даже замедлить throughput вместо ускорения. Поэтому провайдеры включают её адаптивно: для интерактивных запросов с маленьким батчем — да, для батчевой обработки — часто нет.

VRAM на черновик. Отдельная draft-модель — это лишние веса и лишний KV-кэш в памяти, конкурирующие с основной моделью за то самое место, о котором я писал в статье про квантизацию. EAGLE и MTP этой проблемы почти лишены — черновой блок на порядки легче отдельной модели.

Токенизаторы должны совпадать. Черновая и целевая модель обязаны говорить на одном словаре токенов — иначе сверять предсказания токен-в-токен невозможно. На практике это ограничивает выбор draft-модели родственными моделями того же семейства.


Как включить у себя

vLLM — отдельная draft-модель или бесплатный n-gram, флагом при запуске:

# С отдельной draft-моделью
vllm serve meta-llama/Llama-3.1-70B \
  --speculative-config '{"model": "meta-llama/Llama-3.2-1B", "num_speculative_tokens": 5}'

# Без отдельной модели — prompt lookup по n-граммам
vllm serve Qwen/Qwen3-8B \
  --speculative-config '{"method": "ngram", "num_speculative_tokens": 5, "prompt_lookup_max": 4}'

llama.cpp — вторая модель через -md, длина черновика через --draft-max:

llama-server -m target-70b-q4.gguf -md draft-1b-q4.gguf \
  --draft-max 5 --draft-min 1

SGLang — EAGLE встроен нативно, включается флагом:

python -m sglang.launch_server \
  --model-path meta-llama/Llama-3.1-70B \
  --speculative-algorithm EAGLE \
  --speculative-num-steps 5 --speculative-eagle-topk 8
С чего начать

Если модель поддерживает нативный MTP или для неё есть готовый EAGLE-чекпоинт — бери его, выигрыш стабильно выше. Если нет — начни с prompt lookup на n-граммах: он бесплатен по VRAM и уже даёт заметный буст на задачах с повторяющимся выводом (рефакторинг кода, правки по инструкции). Отдельную draft-модель имеет смысл поднимать, только когда точность важнее экономии памяти.


TL;DR

1Зачем: декод memory-bound — GPU простаивает, читая веса ради одного токена за раз
2Как: черновик предлагает k токенов, целевая модель проверяет всех за один проход — так же дёшево, как сгенерить один
3Гарантия: speculative sampling математически даёт то же распределение, что и генерация целевой моделью напрямую — не аппроксимация
4Выигрыш: зависит от acceptance rate, длины черновика и его цены — растёт на предсказуемых текстах вроде кода
5Подвох: на больших батчах простаивающей мощности нет, выигрыш тает — включай адаптивно

Спекулятивный декодинг — редкий случай в ML, где ускорение достаётся буквально бесплатно: не разменял точность на скорость, а просто нашёл дыру в том, как железо тратит время. В следующий раз, когда локальная модель вдруг застрочит подозрительно быстро — знай, рядом крутится черновик. 🫡