Головна / Статті / Спекулятивне декодування та ранній вихід: прискорене авторегресивне декодування

Спекулятивне декодування та ранній вихід: прискорене авторегресивне декодування

Процес проектування, потім перевірка, а також використання шарів, заснованих на рівні впевненості, зменшують затримку декодування, якщо це дозволяють обмеження щодо прийнятності та точності.

2856 слів

Чому оптимізація декодування знаходиться на критичному шляху

Процес інференсу LLM має етап попереднього заповнення, який виконується паралельно для всього запиту, та етап декодування, під час якого токени генеруються послідовно. Етап попереднього заповнення може перевантажити GPU; етап декодування зазвичай не може цього зробити, оскільки кожен новий токен залежить від попереднього. Саме ця послідовна залежність є причиною високої затримки у взаємодії, навіть коли кількість операцій типу FLOPs на папері здається достатньою.

Prefill phase:
  Input: [token_1, token_2, ..., token_512]  → all 512 tokens processed in parallel
  Matrix shape: [batch, 512, 4096]
  GPU utilization: high — large matrix, full Tensor Core throughput

Decode phase (one step):
  Input: [token_513]  → one token processed
  Matrix shape: [batch, 1, 4096]
  GPU utilization: low - tiny matrix, most CUDA cores idle

Структура уваги під час декодування

На кожному кроці декодування модель формує запити до поступово зростаючого кешу ключів/значень. Обсяг роботи на кожному кроці зростає з довжиною контексту, тоді як можливості батчування обмежуються показниками затримки для чату.

One attention head, decode step:

Query Q: [8, 1, 128]   →  8 × 128 = 1,024 elements
Keys  K: [8, 2048, 128] →  8 × 2048 × 128 = 2M elements
Values V: [8, 2048, 128] →  same

Matrix multiply (QKᵀ) per head:
  Shape: [8, 1, 128] × [8, 128, 2048] → [8, 1, 2048]
  FLOPs: 8 × 1 × 128 × 2048 ≈ 2.1M FLOPs per head

For 32 heads: ≈ 67M FLOPs per layer
For 32 layers: ≈ 2.1B FLOPs total per decode step

A100 peak at BF16: ~312 TFLOPS = 312 × 10¹² FLOPs/sec

Time to execute 2.1B FLOPs at 100% utilization:
  2.1 × 10⁹ / 312 × 10¹² ≈ 0.0067 ms

Actual observed decode latency per step: ~10–30ms

Effective compute utilization: < 0.1%

Спекулятивне декодування: спочатку чернетка, потім перевірка

Модель-проект меншого розміру пропонує кілька майбутніх токенів; цільова модель перевіряє їх під час одного паралельного кроку обробки, приймаючи префікс та знову вибираючи дані при першій відмові. Прийняті проекти збільшують кількість ефективних токенів на кожен складний крок обробки цільовою моделлю.

Without speculative decoding:
  Generate 5 tokens: 5 × 30ms = 150ms

With speculative decoding (K=4):
  Draft 4 tokens: 4 × 1.5ms = 6ms
  1 target verification pass: ~35ms  (slightly longer than decode,
                                       processes K+1=5 positions)
  Expected accepted tokens per round:
    (1 - 0.80^5) / (1 - 0.80) ≈ 3.36 tokens
  Time per round: 6ms + 35ms = 41ms
  Time per token: 41ms / 3.36 ≈ 12.2ms
Speedup: 30ms → 12.2ms ≈ 2.5×

Прискорення залежить від збігу між проектом та цільовою моделлю. Простий текст з низькою ентропією дозволяє використовувати довгі проекти; несподівані токени призводять до скорочення кількості прийнятих варіантів.

import torch
import torch.nn.functional as F

def speculative_decode(target_model, draft_model, input_ids,
                       max_new_tokens, K=4, temperature=1.0):
    """
    Conceptual speculative decoding loop.
    Real implementations handle KV cache management across both models.
    """
    generated = input_ids.clone()
    while generated.shape[1] - input_ids.shape[1] < max_new_tokens:
        # --- Draft phase ---
        draft_tokens = []
        draft_probs = []
        draft_input = generated.clone()
        for _ in range(K):
            with torch.no_grad():
                draft_logits = draft_model(draft_input).logits[:, -1, :]
            q = F.softmax(draft_logits / temperature, dim=-1)
            token = torch.multinomial(q, num_samples=1)
            draft_tokens.append(token)
            draft_probs.append(q)
            draft_input = torch.cat([draft_input, token], dim=1)
        # --- Verify phase: one target forward pass over all K+1 positions ---
        verify_input = torch.cat([generated] + draft_tokens, dim=1)
        with torch.no_grad():
            target_logits = target_model(verify_input).logits
        # target_logits[:, -K-1:, :] covers all K draft positions + bonus
        # --- Accept/reject ---
        accepted = 0
        for i in range(K):
            p = F.softmax(target_logits[:, -(K+1)+i, :] / temperature, dim=-1)
            q = draft_probs[i]
            token = draft_tokens[i]
            # Acceptance probability
            accept_prob = torch.min(
                torch.ones_like(p.gather(1, token)),
                p.gather(1, token) / (q.gather(1, token) + 1e-9)
            )
            if torch.rand(1) < accept_prob:
                generated = torch.cat([generated, token], dim=1)
                accepted += 1
            else:
                # Sample corrected token and stop this round
                corrected_dist = F.relu(p - q)
                corrected_dist = corrected_dist / corrected_dist.sum(dim=-1, keepdim=True)
                corrected_token = torch.multinomial(corrected_dist, num_samples=1)
                generated = torch.cat([generated, corrected_token], dim=1)
                break
        else:
            # All K accepted - take bonus token
            bonus_logits = target_logits[:, -1, :]
            p_bonus = F.softmax(bonus_logits / temperature, dim=-1)
            bonus_token = torch.multinomial(p_bonus, num_samples=1)
            generated = torch.cat([generated, bonus_token], dim=1)
    return generated

Якщо це можливо, обирайте проекти з однієї сім’ї – їх менші версії, отримані шляхом дистиляції чи квантування – та вимірюйте показник прийняття на своєму трафіку, а не на прикладах з публічних блогів.

Коли проекти відхиляються

Якщо розподіл токенів у проекті змінюється, показник прийняття різко падає, і ви оплачуєте витрати на обробку проекту з мінімальною користю. Постійно стежте за показником прийняття; у разі його зниження поверніться до звичайної декодування.

Ранній вихід: зупиняйте глибокі шари при впевненості

Деякі архітектури дозволяють виходити на проміжних рівнях, коли рівень впевненості високий, що дозволяє заощадити ресурси обчислень на „легких“ токенах.

Layer distribution of exits:Exit at layers 1–8  (very easy tokens like punctuation, articles):  15%
Exit at layers 9–16 (medium tokens, common continuations):           35%
Exit at layers 17–24 (harder tokens, named entities, numbers):       30%
Exit at layers 25–32 (full computation required):                    20%Weighted average layers executed:
  0.15 × 6 + 0.35 × 12 + 0.30 × 20 + 0.20 × 32
  = 0.90 + 4.20 + 6.00 + 6.40
  = 17.5 layers averageSpeedup vs always running 32 layers:
  32 / 17.5 ≈ 1.83×

Ретельно оцінюйте вплив на точність: ранній вихід жертвує якістю заради швидкості та схильний до похибок калібрування.

Спекулятивний розкодування проти раннього виходу

Спекулятивне розкодування змінює цикл пропозицій токенів за допомогою другої моделі; ранній вихід змінює глибину обробки всередині однієї моделі. Вони по-різному вирішують схожі проблеми та іноді можуть поєднуватися з квантуванням, безперервним батчингом та використанням кешу KV.

Combined stack example:

Target: 7B model, BF16, FlashAttention, PagedAttention
  → Model: ~14 GB, memory-efficient attention, paged KV cache

Draft: 70M model, INT4, FlashAttention
  → Model: ~35 MB, near-zero memory overhead

Speculative decode:
  → with K=4, α=0.80
  → ~2.5× token generation speedup on long outputs

Full stack speedup vs FP32 no-optimization baseline:
  - Quantization: 2–2.3× throughput
  - FlashAttention: 20–40% attention latency reduction
  - Speculative decoding: 2–2.5× decode speedup (on eligible requests)

Combined: 5–8× improvement in end-to-end tokens/second

Коли кожен з них корисний

Спекулятивне розкодування ефективне, коли рівень попередньої угоди високий та затримки обумовлені переважно цим етапом. Воно неефективне, коли попередні версії рідко збігаються або накладні витрати на їх створення перевищують отримані переваги. Ранній вихід корисний, коли багато токенів є легкими та дозволяє бюджет точності; він неефективний для складних токенів або при погано калібруваному рівні впевненості.

Погляд з точки зору продакшну

Надсилайте дані з показниками: частка прийнятих даних, середня довжина прийнятих даних, зміни у оцінці якості, рівень використання GPU та затримка p95. Оптимізації за допомогою флагів функцій. Зберігайте можливість повернення до стандартного режиму декодування. Пам’ятайте, що залишковим бутлекнеком може бути пропускна здатність пам’яті, мережа чи процес відображення на клієнті — а не лише кількість операцій FLOPs, тому проводьте аналіз перед тим, як застосовувати кожен з цих методів.

Заключні зауваження

Навантаження на обладнання під час заповнення та декодування впливає по-різному. Спекулятивне декодування та передчасний вихід є практичними засобами, якщо оцінювати їх за кривими прийнятності та точності. Розглядайте їх як функції для продакшну з панелями керування, а не як одноразові тести; так вони проявлять свою ефективність у реальних умовах роботи.

Сценарій для інтуїтивного розуміння

Уявіть собі модель обсягом 7 млрд параметрів, яка використовується для чату з відповідями довжиною 50–150 токенів. Попереднє заповнення системного запиту на 2 тис. токенів є обтяжливим, але відбувається рідко за один раз; кроки декодування є основною причиною затримок, які сприймає користувач. Зменшення кількості кроків декодування за допомогою спекулятивних прийняттів або зменшення обсягу роботи за крок через передчасний вихід позитивно впливає на сприйняття користувачами швидкості роботи.

Чек-лист операцій

  • Базові показники p95 та якості.
  • Додайте прототип моделі, розміщену в тому ж місці, щоб уникнути затримок мережі.
  • Записуйте гістограми прийняття.
  • Порівнюйте якість на наборах фактів у режимі A/B.
  • Стежте за балансом CPU/GPU під час роботи прототипів на різних пристроях.
  • Перевіряйте показники після кожної зміни токенізатора чи процедури налаштування.

Поширені проблеми

Використання випадкового, непов’язаного проекту; ігнорування впливу температури на рівень прийнятності; оголошення про перемогу на стендах для тестування продуктивності без перевірки якості; поєднання раннього завершення обробки з агресивною квантизацією до моменту появи галюцинацій. Кожна з цих проблем піддається вимірюванню — спочатку за допомогою інструментів.

Розширені рекомендації для команд платформи

Централізуйте оптимізацію процесу інференсу на рівні сервірування, щоб команди додатків не вигадували окремо методи вибору проектів. Розкривайте заголовки чи атрибути трекінгу, які показують, чи використовувалося спекулятивне або раннє завершення. Виставляйте рахунки за токени з позначками оптимізації, щоб відділ фінансів бачив результати. Практикуйте процедуру скасування змін. Документуйте, що спекулятивне декодування не усуває потреби у якісному пошуку інформації чи хороших запитах — воно лише здешевлює створення наступних токенів, коли модель вже знає, що хоче сказати.

Більше деталей про поєднання методів

Об’єднуйте безперервне групування з спекулятивними підходами обережно: довжина проєктів впливає на припущення планувальника. Поєднуйте це з політиками видалення даних з кешу KV, щоб довгі розмови не спричиняли надмірної навантаженості. Також поєднуйте з кешуванням запитів на етапі попереднього заповнення, щоб уникнути ситуації, коли ви “виправляєте декодування”, при цьому продовжуючи марнувати ресурси на попереднє заповнення. Цілісний підхід до реалізації кращий, ніж просте застосування окремих рішень у критичних частинах системи.

Часто ставлені запитання від практиків

Чи змінює спекулятивний підхід відповіді? При правильній реалізації він має відповідати цільовому розподілу; перевіряйте це за допомогою парних тестів. Чи змінює раннє завершення обробки відповіді? Так, за задумом, коли воно пропускає певні етапи — враховуйте цей ефект. Чи можна створювати проєкти на CPU? Іноді; необхідно це перевірити. Чи є це актуальним для малих моделей на пристрої? Часто менше, ніж для великих моделей. Порядок пріоритетів: спочатку виправте проблеми з групуванням та кешуванням, потім — спекулятивні підходи, а нарешті — раннє завершення, якщо це підтримується архітектурою.

Сценарій для кращого розуміння

Уявіть собі модель об’ємом 7 млрд параметрів, яка використовується для чату з відповідями довжиною 50–150 токенів. Попереднє заповнення системного запиту на 2 тис. токенів є обтяжливим, але відбувається рідко за один раз; кроки декодування є основною причиною затримки, яку відчуває користувач. Зменшення кількості кроків декодування за допомогою спекулятивних прийняттів рішень або зменшення обсягу роботи за крок через передчасний вихід позитивно впливає на сприйняття користувачами швидкості роботи.

Чек-лист для експлуатації

  • Базові показники p95 та якості.
  • Додайте модель-проект, розміщену в тому ж місці, щоб уникнути затримок мережі.
  • Записуйте гістограми прийняття рішень.
  • Порівнюйте якість на наборах фактів у режимі A/B.
  • Стежте за балансом CPU/GPU під час роботи моделей-проектів на різних пристроях.
  • Перевіряйте показники після кожної зміни токенізатора чи параметрів налаштувань.

Поширені проблеми

Використання випадкового, непов’язаного проекту; ігнорування впливу температури на рівень прийнятності; оголошення про перемогу на стендах для тестування продуктивності без перевірки якості; поєднання раннього завершення обробки з агресивною квантизацією до моменту появи галюцинацій. Кожна з цих проблем піддається вимірюванню — спочатку за допомогою інструментів.

Розширені рекомендації для команд платформи

Централізуйте оптимізацію процесу інференсу на рівні сервірування, щоб команди додатків не вигадували окремо методи вибору проектів. Розкривайте заголовки чи атрибути трекінгу, які показують, чи використовувалося спекулятивне або раннє завершення. Виставляйте рахунки за токени з позначками оптимізації, щоб відділ фінансів бачив результати. Практикуйте процедуру скасування змін. Документуйте, що спекулятивне декодування не усуває потреби у якісному пошуку інформації чи хороших запитах — воно лише здешевлює створення наступних токенів, коли модель вже знає, що хоче сказати.

Більше деталей про поєднання методів

Об’єднуйте безперервне групування з спекулятивними підходами обережно: довжина проєктів впливає на припущення планувальника. Поєднуйте це з політиками видалення даних з кешу KV, щоб довгі розмови не спричиняли надмірної навантаженості. Також поєднуйте з кешуванням запитів на етапі попереднього заповнення, щоб уникнути ситуації, коли ви “виправляєте декодування”, при цьому продовжуючи марнувати ресурси на попереднє заповнення. Цілісний підхід до реалізації кращий, ніж просте застосування окремих рішень у критичних частинах системи.

Часто ставлені запитання від практиків

Чи змінює спекулятивний підхід відповіді? При правильній реалізації він має відповідати цільовому розподілу; перевіряйте це за допомогою парних тестів. Чи змінює раннє завершення обробки відповіді? Так, за задумом, коли воно пропускає певні етапи — потрібно враховувати цей ефект. Чи можна створювати проєкти на CPU? Іноді; необхідно це перевірити. Чи є це актуальним для малих моделей на пристрої? Часто менше, ніж для великих моделей. Порядок пріоритетів: спочатку виправте проблеми з групуванням та кешуванням, потім — спекулятивні підходи, а нарешті — раннє завершення, якщо це підтримується архітектурою.

Числова інтуїція, яка справдила себе

Припустимо, що виконання цільового кроку коштує 10 мс, а проект пропонує 5 токенів із середнім рівнем прийняття 60% для 3 токенів. Ефективна вартість за кожен прийнятий токен є нижчою, ніж у звичайних кроків із одним токеном, навіть після додаткових витрат проекту, якщо рівень прийняття залишається високим. Якщо рівень прийняття знижується до приблизно 1 токену, схема втрачає ефективність. Саме через таку чутливість панелі керування є кращими за окремі приклади.

Протокол регресії якості

Перш ніж увімкнути його глобально, виконайте фіксовані запити у наборах завдань на перевірку фактів, програмування та відхилення. Порівняйте показники прийняття токенів, які є ідентичними, коли налаштовано спекулятивний режим для точного збігу розподілу. Дослідіть будь-які систематичні відхилення. Для раннього виявлення проблем відстежуйте показник успішності у завданнях із оцінкою та людські уподобання, якщо вони доступні.

Розміщення обладнання

Якщо це можливо, розміщуйте проєкти та цільові версії в одному вузлі. Використання проєктів на різних хостах створює затримки в мережі, які можуть скасувати досягнуті результати. Слідкуйте за об’ємом пам’яті: два моделі разом із кешем KV можуть спричинити її переповнення у пристрої, який раніше комфортно справлявся лише з однією моделлю.

Планування взаємодій

Сервери з безперервною обробкою пакетів мають враховувати змінні фактори, що впливають на обсяг даних. Погані алгоритми планування розділяють пакети, що знижує ефективність використання ресурсів. Координуйте дії з адміністраторами сервісу; не змінюйте параметри лише у коді додатку.

Чесність щодо залишкових вузьких місць

Навіть після покращення процесу декодування користувачі все ще можуть чекати на виклики інструментів, отримання даних чи обробку формату Markdown на стороні клієнта. Відстежуйте процес від початку до кінця. Оптимізація в неправильних місцях марнує час інженерів.

Підсумок

Послідовне декодування є структурним податком авторегресії. Спекулятивне декодування та передчасний вихід зменшують цей податок за певних умов. Впроваджуйте їх з такою ж дисципліною, як і будь-яку функцію для виробництва: метрики, прапорці, можливості скасування змін та чіткі власники обов’язків у команді платформи обслуговування.

Числова інтуїція, що працює

Припустимо, що виконання одного кроку коштує 10 мс, а проект пропонує 5 токенів із середнім рівнем прийняття 60% для 3 токенів. Ефективна вартість за кожен прийнятий токен є нижчою, ніж у класичних кроків з одним токеном, навіть після додаткових витрат на розробку проекту, якщо рівень прийняття залишається високим. Якщо рівень прийняття знижується до приблизно 1 токену, схема стає невигідною. Саме через цю чутливість панелі керування кращі за анекдоти.

Протокол регресії якості

Перш ніж увімкнути функцію глобально, протестуйте фіксовані запити у наборах для перевірки фактів, програмування та відмов. Порівняйте показники ідентичності токенів у разі налаштування спекулятивних алгоритмів для точного збігу розподілу. Дослідіть будь-які систематичні відхилення. Для прискореного завершення відстежуйте коефіцієнт успішності на задачах з оцінкою та людські уподобання, якщо вони доступні.

Розміщення обладнання

Якщо це можливо, розміщуйте проєкти та цільові версії на одному вузлі. Використання проєктів на різних хостах створює мережеву нестабільність, яка може скасувати досягнуті результати. Слідкуйте за об’ємом пам’яті: два моделі разом із кешем KV можуть спричинити переповнення пам’яті у пристрої, який раніше комфортно справлявся з однією моделлю.

Планування взаємодій

Сервери з безперервною обробкою пакетів мають враховувати змінний розмір спекулятивних даних. Погані механізми планування розділяють пакети, що знижує ефективність використання ресурсів. Координуйте дії з адміністраторами сервісу; не змінюйте параметри лише у коді додатку.

Чесність щодо залишкових вузьких місць

Після покращення процесу декодування користувачі все ще можуть чекати на виклики інструментів, отримання даних чи обробку Markdown на стороні клієнта. Необхідно відстежувати процес від початку до кінця. Оптимізація в неправильних місцях марнує час інженерів.

Короткий підсумок

Послідовне декодування є структурним тягарем авторегресії. Спекулятивне декодування та раннє завершення зменшують цей тягар за певних умов. Їх слід впроваджувати з такою ж дисципліною, як і будь-яку функцію в продакшені: з використанням метрик, прапорців, можливостей скасування змін та чіткого визначення відповідальних осіб у команді платформи обслуговування.

Числова інтуїція

Припустимо, що один крок обробки коштує 10 мс, а проект пропонує 5 токенів із середнім рівнем прийняття 60% для 3 токенів. Ефективна вартість за кожен прийнятий токен є нижчою, ніж у класичних кроків з одним токеном, навіть після додаткових витрат на обробку проекту, якщо рівень прийняття залишається високим. Якщо рівень прийняття знижується до приблизно 1 токену, така схема стає невигідною. Саме через цю чутливість панелі керування кращі за окремі приклади.

Протокол регресії якості

Перш ніж увімкнути його глобально, протестуйте фіксовані запити у наборах для перевірки фактів, програмування та відмов. Порівнюйте показники ідентичності токенів, коли налаштовано спекулятивний режим для точного збігу розподілу. Досліджуйте будь-які систематичні відхилення. Для раннього завершення відстежуйте коефіцієнт успішності у завданнях з оцінкою та людські уподобання, якщо вони доступні.

Розміщення обладнання

Якщо це можливо, розміщуйте проєктний та цільовий моделі на одному вузлі. Використання проєктних моделей на різних хостах створює затримки в мережі, які можуть скасувати досягнуті результати. Слідкуйте за пам’яттю: дві моделі разом із кешем KV можуть вичерпати обмеження пам’яті пристрою, який раніше комфортно підтримував лише одну модель.

Планування взаємодій

Сервери з безперервною обробкою пакетів мають враховувати змінні розміри спекулятивних експансій. Погані планувальники розділяють пакети, що знижує ефективність використання. Координуйте дії з адміністраторами сервісу; не змінюйте параметри лише в коді додатку.

Чесність щодо залишкових вузьких місць

Після покращення процесу декодування користувачі все ще можуть чекати на виклики інструментів, отримання даних чи обробку Markdown на стороні клієнта. Необхідно відстежувати процес від початку до кінця. Оптимізація в неправильних місцях марнує час інженерів.

Підсумок

Секвенційне декодування є структурним тягарем авторегресії. Спекулятивне декодування та ранній вихід з процесу зменшують цей тягар за певних умов. Їх слід впроваджувати з такою ж дисципліною, як і будь-яку функцію в продакшені: з використанням метрик, прапорців, можливостей скасування змін та чіткого визначення відповідальних осіб у команді платформи обслуговування.

Числова інтуїція

Припустимо, що один крок обробки коштує 10 мс, а проект пропонує 5 токенів із середнім рівнем прийняття 60% для 3 токенів. Ефективна вартість за кожен прийнятий токен є нижчою, ніж у класичних кроків з одним токеном, навіть після додаткових витрат на обробку проекту, якщо рівень прийняття залишається високим. Якщо рівень прийняття знижується до приблизно 1 токену, така схема стає невигідною. Саме через цю чутливість панелі керування кращі за окремі приклади.

Протокол регресії якості

Перш ніж увімкнути функцію глобально, протестуйте встановлені запити у наборах для перевірки фактів, програмування та відмов. Порівнюйте показники ідентичності токенів, коли налаштовано спекулятивний режим для точного збігу розподілу. Досліджуйте будь-які систематичні відхилення. Для передчасного завершення відстежуйте коефіцієнт успішності у завданнях з оцінкою та людські уподобання, якщо вони доступні.

Розміщення обладнання

Якщо це можливо, розміщуйте проєктний та цільовий моделі на одному вузлі. Використання проєктних моделей на різних хостах створює затримки в мережі, які можуть скасувати досягнуті результати. Слідкуйте за об’ємом пам’яті: дві моделі разом із кешем KV можуть вичерпати обмеження пам’яті пристрою, який раніше комфортно підтримував одну модель.

Планування взаємодій

Сервери з безперервною обробкою пакетів мають враховувати змінний розмір спекулятивних даних. Погані механізми планування розбивають пакети, що знижує ефективність використання ресурсів. Координуйте дії з адміністраторами сервісу; не змінюйте параметри лише в коді додатку.

Чесність щодо залишкових вузьких місць

Після покращення процесу декодування користувачі все ще можуть чекати на виклики інструментів, отримання даних чи обробку Markdown на стороні клієнта. Необхідно відстежувати процес від початку до кінця. Оптимізація у неправильних місцях марнує час інженерів.

Короткий підсумок

Послідовне декодування є структурним тягарем авторегресії. Спекулятивне декодування та ранній вихід з процесу зменшують цей тягар за певних умов. Їх слід впроваджувати з такою ж дисципліною, як і будь-яку функцію в продакшені: з використанням метрик, флагів, можливостей відкату та чітких відповідальних осіб у команді платформи обслуговування.