Главная / Статьи / Оптимизация инференса LLM: предзаполнение, декодирование и корпоративные инструменты LLMOps

Оптимизация инференса LLM: предзаполнение, декодирование и корпоративные инструменты LLMOps

Проблемы заполнения предварительных данных и декодирования, непрерывная группировка данных, FlashAttention, квантизация, PagedAttention, спекулятивное декодирование, разбитое заполнение предварительных данных и децентрализованная обработка запросов.

1809 слов

Проектирование высокопроизводительных и экономичных решений для обслуживания LLM подразумевает учет реальных ограничений аппаратного обеспечения, а не простое оформление API в надежде на постоянную загрузку GPU.

В начальный период бюджеты корпораций на генеративный ИИ сосредотачивались на обучении и доработке моделей. Как только приложения покидают лабораторные условия, ситуация меняется: возникает постоянная нагрузка на GPU во время выполнения запросов, а задержки становятся непредсказуемыми.

Масштабирование вынуждает искать баланс между физическими и финансовыми ограничениями. Эффективные системы учитывают не только внешние слои обработки, но и то, как на самом деле происходит выполнение запросов в силиконовых чипах.

1. Два этапа, два узких места

Каждый запрос на выполнение модели делится на этапы предварительной обработки и декодирования. На каждом из этих этапов возникают свои ограничения аппаратного обеспечения.

Предварительная обработка (обычно связана с вычислительными ресурсами)

Prefill обрабатывает все токены запроса одновременно и параллельно формирует активации в формате ключ-значение. Довольно длинные запросы приводят к тому, что большие матричные умножения исчерпывают вычислительные ресурсы, поэтому этот этап ограничен вычислениями. Короткие запросы или маленькие пакеты данных могут изменить ситуацию: недостаточное количество арифметических операций не позволяет скрыть нагрузку на память, в результате чего Prefill ограничивается проблемами памяти. Время обработки Prefill — это первое ожидание пользователя.

Декодирование (обычно ограничено пропускной способностью памяти)

После ввода запроса токены поступают по одному. На каждом шаге полные веса модели и растущая история данных в формате ключ-значение загружаются из памяти с высокой пропускной способностью (HBM) в SRAM GPU. При небольших размерах пакетов эта процедура повторяется так часто, что GPU вынужден ждать из-за ограничений пропускной способности памяти, а не из-за недостатка вычислительных мощностей.

Одна нюанса определяет всю структуру дизайна. Увеличение размера пакетов позволяет распределить операцию загрузки весов между несколькими последовательностями, а процесс декодирования снова приближается к зависимости от вычислительных мощностей. Именно поэтому существует непрерывное формирование пакетов: оно переводит процесс декодирования в режим, при котором арифметические блоки остаются загруженными.

Уравнение задержки

Общая задержка запроса делится на этапы предзаполнения и декодирования:

T_total  =  TTFT  +  (N_tokens − 1) × TPOT
  • TTFT (время до первого токена) включает полное предзаполнение запроса и первый выходной токен — это то, что пользователь воспринимает как первоначальную реакцию системы.
  • TPOT (время на один выходной токен), или задержка между токенами, представляет собой постоянную стоимость каждого последующего шага декодирования.
  • N_tokens — это длина готового результата.

Фактор (N − 1) добавлен намеренно: первый токен уже находится внутри TTFT, поэтому только остальные умножаются на TPOT. Смешивание прямых вычислений предзаполнения с TTFT — распространенная ошибка. TTFT предназначен для работы с пользователем и обязан включать этот первый шаг декодирования.

2. Входные данные до того, как GPU обрабатывают трафик

Пиковый трафик исчерпает ресурсы GPU, если сначала не будет проведена очистка, оценка и фильтрация входных данных. Типичный путь: API-шлюз → многоуровневая семантическая кэш-система → при отсутствии данных — интеллектуальный маршрутизатор, который оценивает сложность задачи и направляет её в очередь для стандартных моделей или в очередь для передовых моделей.

Основные компоненты:

  • Многоуровневое семантическое кэширование: поиск точных соответствий ключ-значение плюс сравнение векторов по коэффициенту cos θ ≥ τ. Повторные запросы никогда не затрагивают модель; при этом снижаются как затраты, так и задержки.
  • Интеллектуальное маршрутизирование моделей: легкий классификатор отправляет данные для классификации/форматирования на малые модели, а сложные задачи или использование нескольких этапов обработки передаются на специализированные модели.
  • 3. Двигатель выполнения: непрерывная группировка задач и управление памятью

    После маршрутизации задачи попадают в двигатель выполнения. Статическая группировка задач тратит ресурсы впустую: вся группа ждет завершения самой длительной операции. В производственных системах используется непрерывная группировка задач (планирование на уровне итераций), что позволяет полностью использовать ресурсы и сразу освобождать место после завершения обработки последовательности.

    Непрерывная группировка задач связана не только с скоростью обработки. Она также позволяет перейти от режима ограничений, связанных с памятью, к режиму ограничений, связанных с вычислительными мощностями, благодаря чему GPU выполняет арифметические операции вместо ожидания данных с HBM.

    4. Прямое устранение узких мест на этапах обработки

    Кэширование, маршрутизация и группировка данных позволяют управлять трафиком. Следующие механизмы влияют на сами этапы обработки.

    Предзаполнение: FlashAttention

    Затраты на предзаполнение растут пропорционально квадрату длины вводного текста, когда классический метод внимания формирует полную матрицу оценок размером N×N в памяти HBM. FlashAttention — это ядро с учетом операций ввода-вывода, которое вычисляет точные значения внимания путем обработки данных по блокам через встроенную SRAM, тем самым снижая нагрузку на HBM без использования приближений в математических расчетах. Результаты вычислений точны, а время обработки длинных входных данных сокращается. Этот метод является стандартом в большинстве систем обслуживания и используется в сочетании с разбиением данных на части и дальнейшей обработкой.

    Квантизация

    Декодирование требует передачи весов из памяти HBM в SRAM. Квантизация уменьшает размер весов — от FP16 до FP8, INT8 или 4-битных форматов (AWQ, GPTQ) — что позволяет передавать на каждый токен меньше байтов. Это увеличивает эффективную пропускную способность и позволяет хранить больше последовательностей в памяти. Ожидается небольшое снижение точности, что необходимо подтвердить с помощью собственных тестов.

    Пагинированный кэш KV (PagedAttention)

    Исторические ключи/значения постепенно увеличивают объем данных, используясь по одному токену за раз, что приводит к значительному потреблению оперативной памяти. Фрагментация выделенных блоков памяти заставляет использовать больше ресурсов, чем необходимо. PagedAttention хранит данные KV в блоках фиксированного размера, подобно виртуальной памяти ОС, что устраняет фрагментацию и позволяет использовать более крупные группы данных на том же оборудовании. Сочетание этого метода с непрерывной обработкой данных способствует повышению уровня параллелизма.

    Спекулятивная декодировка

    Последовательная декодировка, ограниченная объемом памяти, приводит к простою процессора между операциями загрузки данных. Спекулятивная декодировка использует этот промежуток времени: небольшой модуль генерирует предполагаемую последовательность токенов, а основная сеть проверяет эту последовательность в одной операции. Принятые токены требуют примерно столько же времени на обработку, сколько один шаг работы крупной модели.

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

    5. Планирование обеих фаз: пошаговое предзаполнение и дезагрегация

    Для предзаполнения и декодирования требуется разный аппаратный ресурс. Использование одного пула GPU позволяет длительному процессу предзаполнения монополизировать вычислительные мощности, что увеличивает задержку между токенами во всех остальных запросах. Для решения этой проблемы предлагаются два взаимодополняющих решения.

    Пошаговое предзаполнение

    Вместо одного крупного этапа предварительной обработки разделите запрос на части и чередуйте их с шагами декодирования в одной группе обработки (Sarathi / Sarathi-Serve). Это снижает резкие пики нагрузки на соседние элементы и сочетает задачи, зависящие от вычислительных мощностей, и задачи, зависящие от объема памяти. Метод непрерывной группировки определяет, какие запросы будут обрабатываться вместе, тогда как метод разбиения на части определяет, как происходит выполнение объемной предварительной обработки без снижения скорости декодирования.

    Раздельная обработка

    Разбиение на части снижает взаимное влияние процессов; раздельная обработка устраняет его путем размещения разных этапов на разном оборудовании (DistServe, Splitwise). Предварительная обработка выполняется на пулах, оптимизированных для вычислений, а декодирование — на пулах, оптимизированных для пропускной способности; данные KV передаются через внутренние каналы связи. Каждый этап масштабируется с учетом особенностей архитектуры оборудования, где он выполняется.

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

    6. Системные последствия и компромиссы

    В производственных сценариях для повышения производительности приходится идти на увеличение операционных рисков и затрат на инфраструктуру. Цифры меняются в зависимости от аппаратного обеспечения, модели, объема трафика и настроек — оценивайте свою нагрузку самостоятельно, вместо того чтобы копировать усредненные показатели.

    Многоуровневое семантическое кэширование — точное хранение данных в формате KV плюс проверка сходства векторов. В таких случаях запросы обрабатываются без использования модели. Затраты: поиск векторов (от нескольких десятых до низких сотен миллисекунд); при слишком низком значении τ могут появляться устаревшие или неточные ответы.

    Интеллектуальное маршрутизирование — классификатор сложности направляет простые задачи на использование небольших моделей. Это снижает среднюю стоимость обработки токенов; неправильное маршрутизирование снижает качество ответов.

    Непрерывная группировка — объединение на уровне итераций в процессе генерации. Более высокая загрузка и пропускная способность при одновременной обработке; отдельные запросы могут ожидать своей очереди во время сборки. Статическая группировка по-прежнему подходит для задач с офлайн-обработкой.

    Квантизация — веса с меньшей точностью уменьшают объем передачи данных от HBM к SRAM. Возможна более высокая одновременная обработка на одной GPU; необходима проверка точности; поддержка ядер различается.

    Структурированные KV-элементы — фиксированные блоки устраняют фрагментацию. Возможны более крупные группы данных; требуется управление блоками и совместимое ядро для обработки внимания.

    Спекулятивная декодировка — небольшая часть модели предлагает вариант, а большая часть проверяет его совместно. Несколько токенов за один большой шаг; влияние второй модели и коэффициента принятия решений.

    Когда вам нужны точные показатели задержки или затрат, берите их из воспроизводимых тестов целевой нагрузки (опубликованных исследований работы системы или внутренних тестов нагрузки), а не из фиксированных маркетинговых процентов.

    7. Завершение цикла

    Переход от прототипа к продакшену подразумевает проектирование с учетом особенностей аппаратного обеспечения. Разделяйте операции предварительной загрузки и декодирования, отслеживайте, как размер пакетов влияет на выбор режима работы между операциями, зависящими от памяти и вычислений, кэшируйте предсказуемые запросы, направляйте простые задачи на маленькие модели и объединяйте токены с помощью непрерывной группировки. Затем преодолевайте трудности декодирования с помощью квантизации, структурированных хранилищ KV-данных и спекулятивного декодирования, а также снижайте влияние фазовых помех с помощью разбиения данных на части и их дезагрегации. Все эти методы позволяют справляться с пиковыми нагрузками без перегрузки GPU.

    Чек-лист планирования мощности

    Когда показатель TTFT растет, необходимо проверить распределение длин запросов, коэффициент успешных обращений к семантической кэш-системе, наличие технологии FlashAttention, а также то, продолжают ли длинные запросы занимать всю мощность GPU в виде одной большой операции предзаполнения. Когда при высокой конкурентности растет показатель TPOT, следует изучить фактический размер пакетов обработки, время пребывания данных в KV-памяти, уровень квантования и то, вернулась ли процедура декодирования к режиму, ограниченному объемом памяти.

    Практический еженедельный анализ включает три вопроса: сохраняем ли мы в кэше предсказуемые запросы? переносим ли мы простые задачи с использования передовых моделей? оптимизировали ли мы процесс декодирования так, чтобы GPU выполняли арифметические операции вместо ожидания данных из HBM? Положительные ответы обычно позволяют избежать необходимости покупки дополнительных серверов до того, как будет настроена вся система обслуживания.

    Разбиение на части должно входить в план развития только после того, как методы предзаполнения по блокам и непрерывная группировка уже доказали свою эффективность. Трафик между компонентами и дублирование весов представляют собой реальные затраты; их необходимо учитывать, когда пулы, адаптированные под конкретную фазу, явно превосходят по производительности общий фонд моделей в вашей схеме.

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

    Примечания оператора

    Семантическим кэшам необходимы периоды действия TTL и анализ параметра τ; слишком маленькое значение τ приводит к получению близких, но некорректных ответов. Маршрутизаторам требуются данные о сложности обработки с метками, иначе они могут отправлять сложные запросы к небольшим моделям. Для непрерывной группировки необходимы показатели задержек в очереди, чтобы «более высокая пропускная способность» не маскировала проблемы в интерактивной работе. Для спекулативного декодирования нужны панели управления для оценки предварительных результатов — если процесс одобрения сбоит, вы тратите деньги на вторую модель без улучшения скорости.

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

    Список литературы

    Основные статьи, лежащие в основе этих механизмов (номера принадлежат авторам, а не вам):

    1. Orca — распределенная система обслуживания трансформеров — Yu и др., OSDI 2022 (USENIX).
    2. PagedAttention — управление памятью — Kwon и др., SOSP 2023 (arXiv:2309.06180).
    3. GPTQ — квантизация после обучения — Frantar и др., 2022 (arXiv:2210.17323).
    4. AWQ — квантизация весов с учетом активаций — Lin и др., 2023 (arXiv:2306.00978).
    5. FlashAttention — точное обработка внимания с учетом объема данных — Dao и др., NeurIPS 2022 (arXiv:2205.14135).
    6. Speculative decoding — метод для ускорения работы трансформеров — Leviathan, Kalman, Matias, ICML 2023 (arXiv:2211.17192).
  • Sarathi / Sarathi-Serve с чанкованными предзаполнениями и декодированием путем использования piggybacking — Agrawal и др., 2023–2024 (arXiv:2308.16369).
  • DistServe с разделением процессов предзаполнения и декодирования — Zhong и др., OSDI 2024 (USENIX).
  • Разделение этапов в методе Splitwise для генеративного инференса — Patel и др., ISCA 2024 (arXiv:2311.18677).