MLOps

Inference Optimization

Ускорение инференса

актуальноТекущий рабочий стандарт

Направления: Глубокое обучение · Оптимизация

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

Ключевые тезисы

  • и квантизация до 8 бит дают кратное ускорение при падении метрики в доли процента.
  • Компиляция (, ONNX Runtime, torch.compile) сливает операции и убирает накладные расходы интерпретатора.
  • Узкое место чаще в пропускной способности памяти, а не в арифметике — отсюда важность арифметической интенсивности.

Какую задачу решает

Обучение занимает часы один раз, работает круглосуточно. Поэтому экономика сервиса определяется не тем, сколько стоило обучить модель, а тем, сколько стоит каждый её вызов — и вот здесь оптимизация окупается немедленно.

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

Понимать при этом надо, во что вы упираетесь. Большинство слоёв в ограничены не арифметикой, а скоростью чтения весов из памяти: процессор ждёт данные. Оптимизация арифметики такому слою не поможет, а уменьшение размера весов — поможет вдвое.

Почему ускорение арифметики не помогло

Слой перемножает весов на одного запроса. Весов сто миллионов, то есть 400 МБ в float32; операций — те же сто миллионов. получается меньше единицы: на каждый прочитанный байт приходится доля операции. Карта, умеющая триллионы операций в секунду, простаивает — она ждёт, пока веса приедут из памяти. Значит, ускорять надо не счёт, а чтение: квантизация до 8 бит уменьшает объём вчетверо и даёт почти четырёхкратное ускорение. работает по той же причине с другой стороны: веса читаются один раз на весь , и интенсивность растёт пропорционально его размеру.

Подробный разбор

5 подтем — объяснения, формулы, примеры и интерактивные графики.

ТипБитПамять относительно fp32Типичная потеря качества
float3232
bfloat16 / float16160,5×почти нет
int880,25×доли процента
int440,125×заметная, нужна проверка
  • Посттренировочная квантизация: готовая модель переводится в int8 по калибровочной выборке. Быстро, обычно достаточно.
  • Квантизация с обучением: модель дообучается с учётом округления. Дороже, но спасает там, где первая просела.
  • Только веса: остаются в fp16. Стандарт для языковых моделей — там узкое место именно веса.
На практике

Проверять надо на своих данных, а не на бенчмарке. Падение метрики от распределено неравномерно: чаще всего страдают редкие классы и хвост распределения — ровно то, что в среднем не видно.

У современных ускорителей арифметика на порядок дешевле памяти: карта успевает сделать сотни операций за время, пока читает один байт. Значит, слой с низкой интенсивностью упирается в память, и ускорять в нём счёт бессмысленно.

ОперацияИнтенсивностьВо что упирается
× ( 1)< 1в память
× матрица (большой )десятки-сотнив арифметику
поэлементные (, сложение)≈ 0,1в память
на длинном контекстенизкаяв память

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

В обычном режиме каждая операция — отдельный вызов ядра: прочитать тензор из памяти, посчитать, записать обратно. Цепочка «» делает три прохода по памяти там, где хватило бы одного.

  • Слияние: несколько операций превращаются в одно ядро, промежуточный результат не покидает регистры.
  • Постоянное свёртывание: то, что известно заранее, считается один раз при компиляции.
  • Подбор реализаций: под конкретное железо и конкретные формы выбирается лучший алгоритм.
ИнструментГде применяют
torch.compilePyTorch, минимальные изменения кода
Runtimeпереносимость между языками и платформами
максимум на NVIDIA, ценой привязки
OpenVINO на CPU Intel
На практике

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

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

  • Сервер ждёт до N миллисекунд или до заполнения — что наступит раньше.
  • отдельного запроса растёт на величину окна ожидания.
  • Пропускная способность растёт в разы — то есть стоимость запроса падает в разы.
Как выбрать окно ожидания

Бюджет — 100 мс, сама модель считает 20 мс на батче из 32. в 10 мс съедает десятую часть бюджета и при нагрузке в тысячу запросов в секунду успевает набрать почти всегда. Окно в 50 мс наберёт батч гарантированно, но при низкой нагрузке будет добавлять полсотни миллисекунд к каждому запросу впустую. Практическое правило: окно порядка времени счёта одного батча, и обязательно измерить задержку под реальной нагрузкой, а не под равномерной.

  • Дистилляция: маленькая модель учится повторять выходы большой. Даёт кратное сокращение, но требует обучения и данных.
  • Обрезка (pruning): удаление незначимых весов. Структурная обрезка реально ускоряет, неструктурная чаще только экономит память.
  • Каскад: дешёвая модель отвечает на простые случаи, дорогая подключается на сложных. Часто окупается лучше всего.
На практике

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

Где применяется

  • Сервис под нагрузкойВтрое меньше при той же пропускной способности.
  • на устройствеМодель, не влезавшая в память телефона, влезает после .
  • Генерация ограничена памятью — даёт почти линейное ускорение.
  • Пакетная обработкаНочной прогон по миллионам записей: важна пропускная способность, а не .

Плюсы, минусы и альтернативы

Плюсы

  • Кратное ускорение при падении качества в доли процента.
  • Меньше памяти — больше модель влезает на ту же карту.
  • Прямая экономия: меньше ускорителей на ту же нагрузку.

Минусы

  • иногда бьёт по качеству непредсказуемо — нужна проверка на реальных данных.
  • Скомпилированный теряет гибкость: динамические формы поддерживаются хуже.
  • увеличивает задержку отдельного запроса ради общей пропускной способности.
  • Каждый инструмент привязан к своему железу и версиям — обновление становится рискованным.

Брать, если

  • Сервис под нагрузкой, и счёт за ускорители заметен.
  • Модель не влезает по памяти или не укладывается в бюджет .

Не брать, если

  • Нагрузка мала: сложность эксплуатации не окупится.
  • Качество на пределе допустимого — съест остаток.

Чем заменяют

Видеолекции

Записи университетских курсов, где эта тема звучит. Ссылка открывает запись с той секунды, где о ней говорят, — искать по трёхчасовой лекции не нужно.

Проверить себя

Тема встречается в тесте по направлениям — ошибки приведут обратно на эту страницу.

Следующий шагПроверить себя: Генеративный ИИ и LLMТема встречается в этом тесте 1 раз. Ошибка приведёт обратно на эту страницу — с объяснением, что именно не сошлось.Перейти →

Глава «MLOps» последний раз правилась . Нашли ошибку — напишите.