Соседняя глава про архитектуру сервинга описывает внешний контур: режимы онлайн/пакет/поток, маршрутизацию, бюджет задержек и автомасштабирование. Эта глава — про внутренности LLM-движка инференса: что происходит внутри одного узла, когда большая языковая модель реально генерирует ответ токен за токеном.
Наивный инференс LLM медленный и дорогой по фундаментальной причине: текст рождается авторегрессионно, и каждый новый токен требует отдельного прохода по всей модели. Ключ к оптимизации — увидеть, что фаза prefill упирается в вычисления и формирует TTFT, а фаза decode упирается в пропускную способность памяти и формирует скорость потока токенов (TPOT).
Дальше разбираем рычаги движка: KV-cache и PagedAttention, continuous batching из Orca, квантизацию весов и KV-cache (GPTQ, AWQ, FP8/INT8), спекулятивное декодирование, параллелизм и prefill-decode disaggregation, а также ёмкость и экономику стоимости за токен под SLO.
Практическая польза главы
Авторегрессия и две фазы
Ответ из сотен токенов — это сотни последовательных проходов по модели. Prefill обрабатывает весь промпт за один проход (compute-bound, задаёт TTFT), а decode генерирует по одному токену, читая на каждом шаге все веса и весь KV-cache (memory-bandwidth-bound, задаёт TPOT/inter-token latency). Разделение этих фаз — основа всех приёмов оптимизации.
KV-cache и PagedAttention
KV-cache хранит ключи и значения внимания, чтобы не пересчитывать его на каждом токене; он линейно растёт с контекстом и пакетом и доминирует в видеопамяти. Наивные движки теряют 60-80% памяти на фрагментацию. Kwon et al. (SOSP 2023) переносят идею страничной памяти ОС в внимание: блоки фиксированного размера на несмежной памяти убирают фрагментацию и дают рост throughput в 2-4x при той же задержке.
Батчинг и квантизация
Continuous (in-flight) батчинг из Orca (OSDI 2022) пересобирает пакет на каждой итерации и держит загрузку GPU высокой. Квантизация снижает память и ускоряет decode: weight-only GPTQ и AWQ сжимают веса до 3-4 бит, FP8/INT8 ускоряет обе фазы, квантизация KV-cache освобождает память под более крупные пакеты и длинные контексты — всё это ценой риска для качества, который нужно мерить на своих данных.
Спекулятивность, параллелизм, экономика
Спекулятивное декодирование (Leviathan et al., ICML 2023; Medusa/EAGLE) рождает несколько токенов за один тяжёлый проход при хорошем согласии draft- и target-модели. Tensor/pipeline/sequence parallelism и prefill-decode disaggregation масштабируют большие модели и разносят фазы по пулам. Итоговая метрика эксплуатации — стоимость за 1000 токенов под раздельные TTFT/TPOT-SLO.
Соседняя глава
Архитектура сервинга и инференса моделей
Там — общий контур сервинга (онлайн/пакет/поток, маршрутизация, автомасштабирование). Здесь — внутренности движка большой языковой модели (LLM).
Соседняя глава «Архитектура сервинга и инференса моделей» описывает внешний контур: режимы онлайн/пакет/поток, маршрутизацию, бюджет задержек и . Эта глава — про то, что происходит внутри одного узла, когда реально генерирует ответ. Мы не повторяем контур сервинга, а разбираем движок : KV-cache, батчинг, квантизацию, спекулятивное декодирование и параллелизм.
Наивный инференс медленный и дорогой по фундаментальной причине: текст генерируется авторегрессионно — токен за токеном, и каждый новый токен требует отдельного прохода по всей модели. Один ответ из сотен токенов — это сотни последовательных проходов, в каждом из которых GPU читает все веса модели ради нескольких операций на токен. Дальше всё крутится вокруг одного наблюдения: prefill и decode упираются в разные ресурсы, и оптимизировать их одним приёмом не получится.
Две фазы декодирования: prefill и decode
Prefill — обработка промпта
Все токены входного промпта проходят через сеть за один проход и заполняют параллельно. Это фаза с большим числом матричных умножений: она упирается в вычисления (compute-bound) и определяет TTFT.
Decode — генерация по токену
Каждый следующий токен считается отдельным проходом, который читает все накопленные веса и KV-cache. Здесь почти нет арифметики на байт прочитанной памяти, поэтому фаза упирается в (memory-bandwidth-bound) и определяет скорость потока токенов.
Где упирается инференс LLM
Один запрос проходит обе фазы, и каждая упирается в свой ресурс: prefill нагружает вычисления и формирует TTFT, decode читает память на каждый токен и формирует TPOT. Отсюда и расходятся дальнейшие приёмы оптимизации.
Метрики и компромисс задержка ↔ пропускная способность ↔ стоимость
Время до первого токена
TTFT
Time-to-first-token: задержка от прихода запроса до первого сгенерированного токена. Зависит в основном от длины промпта, прогрева и фазы prefill; именно её чувствует пользователь как «модель задумалась».
Задержка между токенами
TPOT / ITL
Time-per-output-token (он же inter-token latency — задержка между токенами): среднее время на каждый следующий токен в фазе decode. Определяет, насколько «плавно» льётся ответ при стриминге; обратная величина — скорость потока для одного запроса.
Пропускная способность
tokens/s
Суммарная скорость генерации токенов по всем запросам на узле. Растёт с размером пакета и высокой , но почти всегда конкурирует с задержкой отдельного запроса.
Полезная пропускная способность
goodput
Доля запросов, обслуженных в рамках по TTFT и TPOT. Высокий tokens/s бесполезен, если половина запросов нарушает SLO по задержке.
Эти метрики тянут в разные стороны: укрупнение пакета поднимает tokens/s и снижает стоимость за токен, но ухудшает TPOT и . Поэтому одну метрику оптимизировать бесполезно — выигрыш нужно мерить по задержке, пропускной способности и стоимости сразу, иначе улучшение по одной оси молча оплачивается другой.
KV-cache: главный потребитель памяти
Что это
KV-cache хранит ключи и значения внимания для всех уже обработанных токенов, чтобы при генерации каждого нового токена не пересчитывать внимание по всей последовательности заново. Без него decode деградировал бы до квадратичной стоимости.
Почему доминирует в памяти
Размер KV-cache линейно растёт с длиной контекста, числом слоёв и запросов в пакете. На длинных контекстах он легко превосходит сами веса модели и становится главным потребителем , ограничивая максимальный размер пакета.
Фрагментация
Наивные движки резервируют непрерывный буфер под максимальную длину каждого запроса. Реальные ответы короче, поэтому возникают внутренняя и внешняя фрагментация и зарезервированная, но неиспользуемая память — до 60–80% по измерениям авторов vLLM.
PagedAttention / vLLM
Kwon et al. (SOSP 2023) переносят идею страничной виртуальной памяти ОС в внимание: KV-cache хранится в небольших блоках фиксированного размера, отображаемых на несмежную физическую память. Это убирает почти всю фрагментацию, позволяет совместно использовать блоки между запросами и поднимает пропускную способность в 2–4 раза при той же задержке.
Батчинг: от статического к continuous
Статический пакет
Запросы собираются в фиксированный пакет и обрабатываются до общего завершения. Короткие ответы простаивают, ожидая самый длинный в пакете, а новые запросы ждут следующего окна — низкая загрузка и высокая хвостовая задержка.
Динамический пакет
Движок ждёт короткое окно и формирует пакет на лету, балансируя задержку и заполнение. Лучше статического, но всё ещё планирует на уровне целого запроса, поэтому «застревает» на самых длинных генерациях. Подробнее про окна — в соседней главе про сервинг.
Continuous / in-flight batching
Orca (OSDI 2022) предлагает планирование на уровне итерации: пакет пересобирается на каждом шаге декодирования. Завершившийся запрос немедленно покидает пакет, а новый занимает его место, не дожидаясь остальных. Selective batching применяет пакетирование только к тем операциям, где это корректно. Так загрузка GPU держится высокой даже при разной длине ответов.
Continuous (in-flight) батчинг — главный приём, поднимающий : пакет не простаивает в ожидании самого длинного ответа, а постоянно «дозаполняется» новыми запросами. Вместе с paged KV-cache это база современных движков (vLLM, TensorRT-LLM).
Квантизация: качество ↔ скорость ↔ память
| Метод | Что делает | Экономия памяти | Компромисс |
|---|---|---|---|
| GPTQ (weight-only) | Послойная квантизация весов до 3–4 бит на основе приближённой информации второго порядка | ≈4× меньше под веса (FP16 → INT4) | Почти без потери качества на 4 битах (на 3 битах деградация заметнее и лучше переносится очень крупными моделями); квантизует 175B-модель за ~4 GPU-часа |
| AWQ (weight-only) | 4-битная квантизация с защитой ~1% «значимых» каналов по статистике активаций | ≈4× меньше под веса | Лучшая устойчивость качества, чем у наивного round-to-nearest; >3× ускорение vs FP16 в TinyChat |
| FP8 / INT8 | Квантизация весов и/или активаций до 8 бит; FP8 нативно ускоряется на современных GPU | ≈2× меньше под веса; ускоряет и prefill, и decode | Минимальная потеря качества при аккуратной калибровке; требует поддержки железа |
| Квантизация KV-cache | Хранение ключей и значений в INT8/FP8 вместо FP16 | ≈2× меньше под KV-cache → больше пакет / длиннее контекст | Освобождает память под более крупные пакеты; риск деградации на очень длинных контекстах |
GPTQ (Frantar et al.) и AWQ (Lin et al.) — это weight-only квантизация: сжимаются только веса, что сильнее всего помогает memory-bandwidth-bound фазе decode. FP8/INT8 сжимают и активации, ускоряя обе фазы на железе с нативной поддержкой. Квантизация KV-cache освобождает память под более крупные пакеты и длинные контексты.
Спекулятивное декодирование
Идея Leviathan, Kalman, Matias (ICML 2023): маленькая быстрая draft-модель «угадывает» сразу несколько следующих токенов, а большая target-модель проверяет их все за один параллельный проход. Принятые токены сохраняются, первый отвергнутый и далее — пересчитываются. Выход математически идентичен обычному декодированию, но несколько токенов рождаются за один тяжёлый проход — авторы показывают ускорение в 2–3 раза на T5-XXL.
Medusa добавляет к модели несколько «голов», предсказывающих будущие токены без отдельной draft-модели; EAGLE предсказывает не токены, а признаки следующего шага, повышая процент принятия. Приём помогает, когда draft хорошо согласуется с target (предсказуемый текст, код); при низком проценте принятия накладные расходы могут свести выигрыш на нет или даже замедлить генерацию.
Параллелизм для больших моделей
Tensor parallelism
Каждый слой (матрицы внимания и MLP) разрезается между GPU, которые синхронно считают свою долю и обмениваются частичными результатами на каждом слое. Снижает задержку и память на GPU, но требует быстрого межсоединения NVLink и чувствителен к его пропускной способности.
Pipeline parallelism
Модель режется по слоям на стадии, разложенные по разным GPU; запросы текут по конвейеру. Дёшево по коммуникации, но создаёт «пузырь» простоя на краях конвейера, который сглаживают микропакетами.
Sequence parallelism
Длинная последовательность и связанный с ней KV-cache распределяются между устройствами вдоль оси токенов. Снимает ограничение памяти на сверхдлинных контекстах, дополняя tensor- и pipeline- .
Prefill–decode disaggregation
Compute-bound фаза prefill и memory-bandwidth-bound фаза decode разносятся на разные пулы GPU. Это убирает взаимные помехи (длинный prefill больше не «душит» поток decode у соседей) и позволяет масштабировать и тюнить фазы независимо.
Ёмкость и эксплуатация
Выбор размера пакета
Больше пакет — выше tokens/s и загрузка GPU, но хуже TPOT и риск нарушить целевой уровень сервиса (SLO). Размер пакета выбирают по кривой goodput: наибольший пакет, при котором TTFT и TPOT ещё укладываются в бюджет.
Автомасштабирование под целевой уровень сервиса (SLO)
ведут не по средней загрузке, а по нарушению TTFT/TPOT-SLO и глубине очереди. Прогрев тяжёлого -движка долгий, поэтому нужна заранее тёплая ёмкость — как описано в соседней главе про контур сервинга.
Экономика стоимости за токен
Главная единица экономики — стоимость за 1000 токенов: цена GPU-часа, делённая на устойчивый tokens/s в рамках SLO. Квантизация, непрерывное пакетирование (continuous batching) и disaggregation снижают её, повышая полезную утилизацию железа.
Ключевые компромиссы
- Крупный пакет и длинное окно поднимают tokens/s и снижают стоимость за токен, но ухудшают TTFT/TPOT и хвостовую задержку интерактивных запросов.
- Агрессивная квантизация (особенно ниже 4 бит и квантизация KV-cache на длинных контекстах) экономит память и ускоряет инференс ценой риска для качества — её нужно мерить на своих задачах, а не доверять усреднённым бенчмаркам.
- Спекулятивное декодирование ускоряет decode при хорошем согласии draft- и target-модели, но при низком проценте принятия добавляет накладные расходы и может замедлить генерацию.
- Тензорный параллелизм (tensor parallelism) снижает задержку, но требует дорогого быстрого интерконнекта; конвейерный параллелизм (pipeline parallelism) дёшев по связи, но добавляет «пузырь» простоя — выбор зависит от топологии узла.
Частые ошибки
Рекомендации
Источники и материалы
Карта источников: vLLM/PagedAttention держит объяснение KV-cache и блочной памяти; Orca — continuous batching; GPTQ/AWQ — квантизацию; speculative decoding paper — ускорение через черновую модель; TensorRT-LLM — практические реализации in-flight batching, paged KV-cache и FP8/INT8.
Связанные главы
- Архитектура сервинга и инференса моделей - Соседняя глава про общий контур сервинга: онлайн/пакет/поток, маршрутизация, бюджет задержек и автомасштабирование, в который встроен движок большой языковой модели (LLM).
- AI Engineering: обзор - Где оптимизация инференса стоит в жизненном цикле AI-приложения и как связана с оценкой качества и стоимостью.
- Архитектура системы GenAI с извлечением контекста (RAG) - Как длинные контексты извлечения (RAG) нагружают KV-cache и почему оптимизация инференса определяет задержку и цену ответа.
- История ускорителей NVIDIA - Почему пропускная способность памяти и поддержка FP8 на ускорителях напрямую определяют пределы инференса большой языковой модели (LLM).
