Speculative decoding: как ускоряют генерацию LLM — это схема, где маленькая draft-модель предлагает несколько токенов вперёд, а большая target-модель проверяет их за один прямой проход. Подтверждённые токены попадают в вывод, отклонённые запускают обычную генерацию. Документация Transformers описывает это как assisted decoding и отмечает, что помощник заменяет десятки дорогих проходов основной модели.
Кто предлагает кандидатов и кто подтверждает
Роли в схеме разделены жёстко. Draft-модель (её называют assistant, помощник) генерирует последовательность кандидатов. Target-модель (основная) их проверяет. В документации Transformers на huggingface.co сказано: помощник предлагает кандидатов до того, как основная модель примет по ним решение, а основная модель проверяет эти кандидаты за один прямой проход. Помощник быстрый и дешёвый, и он способен заменить десятки более дорогих проходов основной модели.
Блог Hugging Face «Assisted Generation» описывает тот же контур как balancing act: помощник должен быстро выдавать кандидатов и при этом быть достаточно точным. Слабый помощник даёт расходы без выигрыша, слишком медленный помощник превращает ускорение в замедление. Документация NVIDIA Triton Inference Server формулирует это как набор техник для генерации более одного токена за итерацию прямого прохода, полезных там, где GPU недогружен из-за малого размера батча.
Роли можно зафиксировать таблицей.
| Элемент | Что делает | Что получает на выходе |
|---|---|---|
| Draft (assistant) | Предлагает кандидатов вперёд | Короткая последовательность токенов |
| Target (main) | Проверяет кандидатов одним проходом | Подтверждение или исправление |
| Цикл | Принимает подтверждённое, отбрасывает хвост | Новый префикс для следующего раунда |
Практический вывод: выбирая помощника, смотрите на его совместимость с основной моделью и на скорость его собственных проходов. Обе характеристики определяют, появится ли выигрыш вообще.
Несколько кандидатов за один прямой проход
Ключевая механика опирается на свойство прямого прохода: при отключённом кэше вход содержит всю последовательность, а выход содержит логиты следующего токена для всех позиций. Блог Hugging Face приводит проверку: если подать сгенерированную последовательность на вход и применить argmax к логитам, получится та же последовательность. Логиты на позиции N соответствуют распределению следующего токена при входе из первых N токенов.
Отсюда следует, что один проход target-модели может служить проверкой целой цепочки кандидатов. Документация NVIDIA Triton описывает это так: draft-токены коллективно валидируются обработкой через целевую LLM за один прямой проход. У схемы два допущения. Первое: обработка нескольких draft-токенов одновременно окажется такой же быстрой, как обработка одного токена. Второе: значительная часть draft-токенов будет успешно подтверждена за время полной генерации.
Если верно первое допущение, задержка не станет хуже стандартного подхода. Если верно второе, генерация продвигается в среднем более чем на один токен за проход. Оба допущения проверяемы на ваших запросах: первое — замером времени прохода при разной длине входа, второе — подсчётом доли принятых токенов.
Причинность: после первого несовпадения хвост недействителен
Принятие идёт слева направо. Блог Hugging Face формулирует правило прямо: после первого несовпадения все кандидаты аннулируются. Причина в авторегрессивной природе задачи — каждый следующий токен условлен предыдущими. Если помощник ошибся на позиции K, все кандидаты после K построены на неверной предпосылке.
Порядок действий в цикле, по описанию того же блога, такой. Помощник генерирует кандидатов жадным декодированием. Основная модель делает проход по кандидатам и получает логиты. Метод выбора токена (argmax для жадного поиска, multinomial для сэмплинга) даёт next_tokens. next_tokens сравниваются с кандидатами, и считается число совпадений с учётом причинности слева направо. По числу совпадений отрезается всё, что относится к неподтверждённым кандидатам: сохраняются совпавшие токены плюс первый расходящийся токен, который основная модель породила от валидной подпоследовательности.
Эвристика числа кандидатов в оригинальной реализации: стартовое значение 5, при полном совпадении всех токенов оно увеличивается на 2, в остальных случаях уменьшается на 1. Смысл в том, что разные участки вывода предсказуемы в разной степени.
Жадная проверка и вероятностный sampling
Жадный режим и сэмплинг различаются способом выбора токена из логитов. Блог Hugging Face называет два распространённых метода: выбор наиболее вероятного токена (greedy decoding) и выбор из распределения (multinomial sampling). В жадном режиме проверка сводится к argmax: кандидат либо совпадает с выбором основной модели, либо нет.
Сэмплинг усложняет картину. Блог отмечает, что извлечение выборки из распределения заставляет жадного помощника ошибаться чаще, и выигрыш по задержке падает. Управлять этим позволяет температура: при значениях около нуля сэмплинг приближается к жадному декодированию и благоприятствует помощнику, при значениях много больше единицы выборка становится хаотичной. Низкие температуры сохраняют большую часть выигрыша.
В коде Transformers режим задаётся параметром do_sample. Документация указывает: при do_sample=True происходит повторная выборка, если проверка токена не прошла. Жадный поиск и сэмплинг поддерживаются, батчевые входы — нет.
| Режим | Выбор токена | Поведение при несовпадении |
|---|---|---|
| Жадный поиск | argmax по логитам | Кандидат отклоняется, хвост отбрасывается |
| Сэмплинг | Выборка из распределения | Повторная выборка при провале проверки |
Сохранение распределения и ослабленные варианты
Стандартный speculative decoding сохраняет распределение целевой модели. Документация Transformers называет его lossless и указывает, что выходное распределение точно совпадает с распределением целевой модели. Первичная работа Google Research «Fast Inference from Transformers via Speculative Execution» формулирует это как ускорение точного декодирования без изменения распределения и сообщает об ускорении 2–3x на T5-XXL по сравнению со стандартной реализацией T5X при идентичных выходах.
Ослабленный вариант — static ensemble verification. Документация Transformers описывает его так: проверка идёт против смеси распределений целевой и draft-модели, что повышает долю принятия и ускоряет вывод с изменением распределения: результат соответствует указанной смеси. Рекомендуемое стартовое значение веса — 0.7. Этот режим требует логитов кандидатов от помощника и не поддерживается вместе с prompt lookup decoding.
Разница практическая: если выход должен воспроизводить поведение целевой модели, берите стандартную схему. Если допустимо смещение распределения ради более высокой доли принятия, static ensemble verification даёт рычаг, но требует собственной проверки на ваших задачах.
Совместимость токенизаторов и universal assisted decoding
Блог Hugging Face называет требование к помощнику: у него должен быть точно такой же токенизатор, как у основной модели. Без этого пришлось бы добавлять дорогие шаги декодирования и перекодирования, причём на CPU, что тянет за собой медленные передачи данных между устройствами. Быстрота помощника критична для выигрыша.
Universal assisted decoding снимает это ограничение. Документация Transformers описывает UAD как способ сделать speculative decoding возможным при разных токенизаторах основной и вспомогательной моделей: кандидаты перекодируются, а алгоритм вычисляет наибольшую общую подпоследовательность, чтобы продолжение оставалось выровненным. Включается передачей tokenizer, assistant_tokenizer и assistant_model в generate().
Документация перечисляет и другие варианты. Prompt lookup decoding обходится без модели-помощника: он ищет перекрывающиеся n-граммы в промпте и при отсутствии совпадения возвращается к обычному авторегрессивному декодированию; подходит для задач, привязанных к входу, — суммаризации и перевода. Self-speculative decoding использует промежуточные слои самой модели как помощника и работает для моделей, обученных отдавать early-exit логиты. Multi-token prediction задействует дополнительные предсказательные слои из чекпойнта основной модели и требует чекпойнтов, обученных с MTP-слоями.
От чего зависит выигрыш
Выигрыш определяется долей принятых токенов и накладными расходами драфтера. Блог Hugging Face формулирует это как баланс: качество кандидатов и скорость помощника тянут в разные стороны, а автоматически подобрать помощника нельзя. Там же приведены ориентиры: помощник должен быть минимум на порядок меньше основной модели, ускорение достигает 3x при INT8 и 2x в остальных случаях, когда модель помещается в память GPU; при выгрузке памяти можно увидеть до 10x. Эти числа относятся к конкретным условиям замера и требуют проверки на вашей конфигурации.
Google Developers Blog в материале о DFlash на TPU v5p разбирает другой фактор — последовательность драфтинга. Авторегрессивный помощник тратит K последовательных проходов на K кандидатов, и время на «угадывание» начинает съедать сэкономленное на проверке. Блочно-диффузионный подход порождает блок кандидатов за один проход. В замерах на TPU v5p с целевой моделью Llama-3.1-8B DFlash дал ускорение 2.29x против 1.30x у EAGLE-3. Там же отмечено, что стоимость проверки 1024 токенов почти совпадает со стоимостью проверки 16 токенов, а увеличение блока с 16 до 128 даёт меньше одного дополнительного принятого токена за шаг. Рост доли принятия на позицию оценивается как в 2–3 раза более ценный рычаг, чем расширение блока.
Документация NVIDIA Triton добавляет, что эффективность сильно зависит от задачи: предсказывать следующие токены в автодополнении кода проще, чем генерировать пересказ статьи. Блог Hugging Face относит к выигрышным задачам распознавание речи, перевод и суммаризацию.
Учебная трасса: таблица раундов и отрицательная проба
Ниже — учебный разбор жадной проверки на условных символах. Это ручная трасса для понимания порядка шагов. Модель не запускалась, ускорение не измерялось. Целевой поток: A B C D F.
Раунд 1. Текущий префикс пуст. Draft предлагает A B X Y. Target подтверждает A B, а на следующей позиции выбирает C. Принимаем A B, дописываем C, отбрасываем X и весь следующий хвост Y. Новый префикс — A B C.
Раунд 2. Префикс A B C. Draft предлагает D E. Target подтверждает D и выбирает F вместо E. Новый префикс — A B C D F.
| Раунд | Префикс до | Draft | Принято | Исправление target | Отброшено | Префикс после |
|---|---|---|---|---|---|---|
| 1 | пусто | A B X Y | A B | C | X Y | A B C |
| 2 | A B C | D E | D | F | E | A B C D F |
Ожидаемый результат: итоговый префикс A B C D F, где C и F — исправляющие токены target, а X, Y и E отброшены. Отрицательная проба: если после несовпадения на X продолжить принимать Y, получится неподтверждённый хвост. Правильный шаг — пересчитать продолжение от префикса A B C. Эта ошибка типична при ручной реализации цикла: сравнение кандидатов делается без учёта причинности, и в вывод просачиваются токены, построенные на неверной предпосылке.
Матрица решения для выбора стратегии.
| Ситуация | Первый шаг |
|---|---|
| Маленький совместимый draft, приемлемая доля принятия | Проверить на своих запросах |
| Медленный draft или низкая доля принятия | Сначала замерить накладные расходы |
| Чат без контроля inference | Искать поддержку у провайдера |
Один промпт декодер не включает: поддержка должна быть на стороне inference-стека. В коде Transformers помощник подключается параметром assistant_model в generate(), и тот же аргумент доступен в Pipeline API.
import os
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM-1.7B")
model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-1.7B", dtype="auto")
assistant_model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-135M", dtype="auto")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt")
outputs = model.generate(**inputs, assistant_model=assistant_model)
print(tokenizer.batch_decode(outputs, skip_special_tokens=True))
Это пример из документации Transformers. Замените идентификаторы чекпойнтов на свои и проверьте, что токенизаторы совместимы; при разных токенизаторах передайте tokenizer, assistant_tokenizer и assistant_model для universal assisted decoding.
Что относится к документации, к учебному примеру и к неизвестному
Разделение важно для честной оценки. К документации и первичным материалам относятся: определение assisted decoding и проверка кандидатов одним проходом, правило аннулирования хвоста после первого несовпадения, эвристика числа кандидатов, требование общего токенизатора, описание UAD, lossless-свойство стандартной схемы, поведение static ensemble verification, ориентиры ускорения из блога Hugging Face и результаты DFlash на TPU v5p из Google Developers Blog.
К учебному примеру относится трасса A B C D F с таблицей раундов и отрицательной пробой. Это условные символы для разбора порядка шагов. Значения не являются измерением редакции, не подтверждают лимиты продукта и не переносятся на реальные конфигурации.
К неизвестному относится всё, что зависит от вашего стека: фактическая доля принятия на ваших запросах, реальные накладные расходы вашего помощника, поведение конкретного inference-сервера и доступность функции у конкретного провайдера. Эти параметры измеряются на месте. Ориентиры из публикаций служат отправной точкой для собственного замера.
Частые вопросы
Что такое speculative decoding простыми словами?
Это схема ускорения генерации, где маленькая модель предлагает несколько токенов вперёд, а большая проверяет их за один проход. Подтверждённые токены принимаются, отклонённые запускают обычную генерацию. Документация Transformers описывает это как assisted decoding. Выигрыш появляется, когда помощник быстрый и часто угадывает.
Чем draft-модель отличается от target-модели?
Draft-модель предлагает кандидатов и работает быстро за счёт малого размера. Target-модель проверяет кандидатов и формирует итоговый вывод. Документация Transformers указывает, что помощник должен быть существенно меньше основной модели. Блог Hugging Face называет ориентир: минимум на порядок меньше.
Почему после первой ошибки отбрасывается весь хвост?
Каждый следующий токен условлен предыдущими, поэтому кандидаты после ошибки построены на неверной предпосылке. Блог Hugging Face формулирует правило: после первого несовпадения все кандидаты аннулируются. Цикл затем повторяется от исправленного префикса.
Сохраняет ли speculative decoding распределение модели?
Стандартная схема сохраняет распределение целевой модели, документация Transformers называет её lossless. Первичная работа Google Research описывает ускорение точного декодирования без изменения распределения. Ослабленный вариант static ensemble verification проверяет против смеси распределений и меняет итоговое распределение.
Нужен ли одинаковый токенизатор у draft и target?
Блог Hugging Face называет совпадение токенизаторов требованием для быстрой работы помощника. Universal assisted decoding снимает это ограничение: кандидаты перекодируются, а алгоритм вычисляет наибольшую общую подпоследовательность для выравнивания. Включается передачей tokenizer, assistant_tokenizer и assistant_model в generate().
