Как работает инференс LLM

Каждый вызов generate() у языковой модели запускает на одном GPU две совершенно разные по характеру фазы. Prefill обрабатывает промпт и упирается в вычисления. Decode генерирует токены по одному и упирается в память. Почти любая оптимизация инференса бьёт либо по одной фазе, либо по другой, поэтому сначала важно понять, какая из них стала узким местом.

Сначала текст превращается в числа. Токенизатор режет строку на токены, заменяет их целочисленными ID из словаря примерно на 50 тысяч позиций и достаёт из таблицы эмбеддингов вектор для каждого. Для модели со скрытой размерностью 4096 один токен становится вектором на 4096 чисел. Позиция токена чаще всего кодируется через RoPE, то есть поворотом векторов, а не отдельным позиционным вектором.

Дальше последовательность идёт через десятки слоёв трансформера, обычно от 32 до 80 с лишним. В каждом слое self-attention считает для каждого токена три проекции query, key и value, сопоставляет query каждого токена с key остальных и через softmax решает, сколько value попадёт в итог. Затем feed-forward сеть прогоняет вектор каждого токена через двухслойный MLP. Внимание перемешивает информацию между позициями, а FFN её преобразует.

В фазе prefill все токены считаются параллельно одним большим перемножением матриц, и загрузка GPU высокая. Ключевая метрика здесь Time to First Token. Заодно заполняется KV-кэш: тензоры K и V каждого слоя складываются в память для повторного использования.

В фазе decode модель выдаёт по токену за шаг и тянет из памяти все веса и весь кэш ради крохотного вычисления. Узкое место смещается на пропускную способность памяти, а метрикой становится Inter-Token Latency. Без KV-кэша генерация была бы квадратичной по сложности, с ним ускорение примерно пять раз и больше. Но кэш растёт линейно с длиной контекста: для модели на 13 млрд параметров это около 1 МБ на токен, а контекст на 4 тысячи токенов съедает уже 4 ГБ видеопамяти.

Поэтому длинный контекст стоит дорого и конкурирует за память с размером батча. Лечат это квантованием кэша, скользящим окном внимания, grouped-query attention и PagedAttention. А DeepSeek V4, вышедший в апреле 2025 года, пошёл дальше и перестроил само внимание так, чтобы кэш был меньше изначально: на контексте в миллион токенов V4-Pro требует около 10 процентов KV-кэша от уровня V3.2.

Отдельно стоит квантование весов. Модель на 7 млрд параметров в FP32 занимает 28 ГБ, в FP16 уже 14 ГБ, в INT8 всего 7 ГБ, а в INT4 всего 3,5 ГБ. Именно поэтому модели на 7 млрд запускаются на ноутбучных видеокартах, а GPTQ и AWQ держат потерю качества в пределах пары процентных пунктов. Переход с FP16 на INT8 часто режет задержку вдвое.

Сверху этого серверы инференса добавляют continuous batching, который перемежает токены разных запросов на одном шаге, и speculative decoding, где маленькая черновая модель предлагает токены, а большая проверяет их за один проход. Фреймворки вроде vLLM, TensorRT-LLM и TGI комбинируют эти техники, поэтому один GPU обслуживает десятки пользователей одновременно.

Вывод простой. Длинные промпты дороги по prefill, длинные ответы по decode, и они нагружают разные ресурсы. Когда вам говорят, что модель медленная, первый вопрос: она медленно стартует или медленно стримит. От ответа зависит, что именно оптимизировать.

Оригинал разбора от Avi Chawla: https://x.com/_avichawla/status/2071201619530956863

+1
0
+1
0
+1
0
+1
0
+1
0

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *