Развертывание обученной нейронной сети — это гораздо больше, чем просто перевод каждого оператора в ядро GPU. По своей сути, это сложная задача компиляции, которая имеет множество легитимных решений. Когда NVIDIA TensorRT создает инференс-движок, он принимает взаимосвязанные решения о трансформациях графа, слиянии операций, выборе реализаций, размещении памяти и квантовании. Этот процесс называется планированием (scheduling). Различные стратегии планирования могут сохранять семантику модели, но при этом приводить к совершенно разным показателям производительности. Именно поэтому планирование является центральным элементом оптимизации компиляторов глубокого обучения.
Однако ни одна стратегия планирования не является лучшей для каждой модели и среды развертывания. Трансформация, которая ускоряет одну сеть, может замедлить другую. Ядро, которое быстрее в изоляции, может плохо взаимодействовать со слиянием, layouts тензоров или трафиком памяти в других частях графа. Агрессивное планирование может улучшить производительность, но нарушить требования приложения к точности. Эти связанные, зависящие от модели эффекты часто проявляются только после построения и измерения полного движка, что делает выбор правильной стратегии все более сложной задачей для предсказания.
В этой статье, являющейся первой частью серии, мы развиваем более четкий способ рассуждения об оптимизации производительности. Мы исследуем вопросы: что делает один скомпилированный движок лучше другого? Почему индивидуально перспективные решения могут провалиться в сквозном тестировании? Как точность должна ограничивать оптимизацию производительности? Мы представляем Global Performance Tuner (Глобальный тюнер производительности) — функцию автоматической настройки производительности, выпущенную в TensorRT 11.1, и исследуем эти вопросы через интуитивный пример и математическую модель.

01Какую проблему решает Global Performance Tuner?
Следующая аналогия иллюстрирует мотивацию создания функции Global Performance Tuner в TensorRT. Представьте шеф-повара с одним отличным блюдом, которое нравилось трем постоянным клиентам на протяжении многих лет. Один любит острое, второй — кисло-сладкое, а третий предпочитаетExtra salt. Шеф-повар объединяет перец чили, сироп, лимон и соль в одном стандартном рецепте, который удовлетворяет всех троих. В один прекрасный день появляется новый четвертый клиент, который не переносит острое. Сохранение перца чили расстраивает новичка, а его удаление рискует потерять первого клиента.
Корневая причина дилеммы шеф-повара заключается в том, что метод добавления специй не масштабируется: количество взаимодействующих исключений растет вместе с базой клиентов, и изменение для одного клиента может ухудшить блюдо для другого. Масштабируемый подход сохраняет базовое блюдо, но делает специи настраиваемыми. Шеф-повар записывает подходящую комбинацию для каждого постоянного клиента. Для нового клиента с неизвестными предпочтениями шеф-повар предлагает бесплатные образцы с разными комбинациями, отвергает неподходящие варианты и оставляет тот, который клиенту нравится больше всего.

Если сопоставить эту аналогию с компиляцией глубокого обучения, то TensorRT — это шеф-повар, его общий конвейер — базовый рецепт, настраиваемые конфигурации компилятора — специи, а скомпилированный движок — готовое блюдо. Каждая модель ONNX — это клиент. Настройка производительности предлагает образцы, а сквозная производительность отражает удовлетворенность клиента.
Исторически оптимизация производительности TensorRT начиналась с внутренних моделей KPI. Инженеры изучали эти рабочие нагрузки, выявляли оптимизируемые паттерны и кодировали свои выводы в виде эвристик в стратегии планирования по умолчанию TensorRT. Каждая эвристика захватывает экспертные знания и позволяет пользователям автоматически получать выгоду от оптимизаций, обнаруженных на репрезентативных моделях.
По мере того как модели и среды развертывания становятся разнообразнее, этот подход приводит к проблеме масштабирования, аналогичной описанной в аналогии. Эвристика, вдохновленная одной внутренней моделью KPI, присоединяется к общей стратегии и может помочь знакомым паттернам, но вызвать регрессию для неизвестной внешней модели. Добавление еще одной проверки или исключения может защитить эту модель, но повторение этого процесса делает логику планирования все более сложной для расширения.
Проблема проявляется в трех связанных формах:
- Разрастание эвристик (Heuristic sprawl): Каждая новая эвристика, специфичная для модели, вводит еще одно правило, взаимодействия которого с существующими правилами необходимо понимать и поддерживать. По мере накопления этих правил код становится трудно поддерживаемым, и улучшения для одного семейства моделей могут непреднамеренно повлиять на другое.
- Переплетение производительности и точности: Ядра пониженной точности и другие агрессивные оптимизации могут улучшить производительность, внося численные различия, превышающие допустимый допуск приложения. Выбор более высокой точности может снизить этот риск, но пожертвовать производительностью. Следовательно, производительность и численная приемлемость не всегда могут быть оптимизированы независимо.
- Персонализация производительности: Решения по планированию, которые хорошо работают для одной модели или GPU, могут работать плохо для другой. Кодирование каждого успешного выбора в одну универсальную стратегию планирования затрудняет эффективную специализацию TensorRT для постоянно расширяющегося диапазона внешних моделей, аппаратных платформ и требований приложений.

Настройка (tuning) предоставляет масштабируемое дополнение к эвристической оптимизации.
02Математическая теория производительности компиляторов глубокого обучения
В этом разделе мы разработаем абстрактную математическую модель производительности компиляторов глубокого обучения. Цель состоит в том, чтобы разделить два фундаментальных вопроса: какие исполняемые файлы может построить компилятор для модели и как компилятор выбирает один из этих вариантов для оптимальной производительности.
Концепция: Модель и пространство моделей
Пусть m представляет модель, а M представляет совокупность всех рассматриваемых моделей, называемую пространством моделей:
m ∈ MЗдесь модель — это абстрактное описание вычислений, которые необходимо скомпилировать. Ее конкретное представление может быть графом ONNX, сетью, созданной через API TensorRT, моделью PyTorch или другим представлением фронтенда, которое полностью специфицирует вычисления модели.
Концепция: Решение и пространство решений
При заданной модели m в качестве входных данных компилятор глубокого обучения создает исполняемый вывод для целевого оборудования, определяемый как решение. Одна и та же модель, как правило, может быть скомпилирована в разные решения при различных политиках планирования. Пусть s представляет одно такое решение, а S представляет совокупность возможных решений, называемую пространством решений:
s ∈ S = {s_0, s_1, s_2, …, s_n}Решение — это абстракция исполняемых вычислений на целевом оборудовании. Конкретно решение может быть движком TensorRT или кубином (cubin) сериализованной последовательности ядер GPU. Более абстрактно, это также может быть промежуточное представление (IR) компилятора, при условии, что представление однозначно определяет окончательный исполняемый файл в рамках оставшегося процесса компиляции.
Каждое решение также определяет функцию от входного домена модели к ее выходному кодомену:
s : X → Y
s(x) = yЗдесь (x, y) — пара входных-выходных данных для последовательности ядер GPU, которые реализуют нейронную сеть. На этом уровне абстракции модель описывает предполагаемые вычисления, а решение описывает один конкретный способ реализации этих вычислений на целевом оборудовании.
Принцип детерминизма
Утверждение: Когда как детерминированная программа, так и ее полная среда выполнения остаются фиксированными, программа имеет фиксированное время выполнения.
Этот принцип служит предположением моделирования для анализа производительности. При строгой интерпретации среда включает входные данные, целевое устройство, программный стек, частоту GPU, температуру, состояние питания, нагрузку на систему и другие условия выполнения, которые могут влиять на время выполнения. На практике не каждую переменную среды можно контролировать идеально, поэтому повторные измерения времени выполнения демонстрируют шум. Если это возмущение моделируется как независимый гауссовский шум, среднее значение повторных измерений является оценкой максимального правдоподобия среднего времени выполнения.
Как только среда выполнения зафиксирована на уровне, необходимом для абстракции, каждое решение может быть связано с одной характеристической величиной времени выполнения. Это позволяет представить время выполнения как математическую функцию.
Концепция: Функция времени выполнения
Функция времени выполнения T отображает каждое решение на его время выполнения на указанном целевом устройстве при фиксированной среде выполнения:
T : S → ℝ⁺
T(s_0) = t_0Среда рассматривается как фиксированная и поэтому опущена из нотации.
Концепция: Алгоритм построителя (Builder Algorithm)
Алгоритм построителя (также называемый планировщиком производительности) — это отображение из пространства моделей в степенное множество пространства решений. При заданной конкретной модели в качестве входных данных алгоритм построителя выводит пространство решений с заданным требованием к точности.
B: M → 2^S
max
B(m) = {s_1, s_2, …, s_n | max_{x ∈ X} || s(x) – y || ≤ ε} = SВ условии точности, показанном выше, пары входных-выходных данных (x, y) рассматриваются как эталонные значения, а ε представляет порог допуска точности. Эталонные данные, метрика сравнения и допуск рассматриваются как фиксированный контекст и поэтому подавлены из аргументов B.
В идеале алгоритм построителя должен генерировать достаточно богатый набор решений, чтобы содержать s*, оптимальное решение: самое быстрое допустимое решение в смоделированном пространстве решений.
s* ∈ B(m)Концепция: Алгоритм поиска (Searching Algorithm)
Алгоритм поиска (также называемый решателем пространства решений) — это отображение из степенного множества пространства решений в пространство решений. При заданном наборе кандидатов в качестве входных данных алгоритм поиска выберет одно решение из них в качестве вывода.
A: 2^S → S
A(S) = argmin_{s_i ∈ S} T(s_i), S ⊆ SОбратите внимание, что в реальном мире алгоритм поиска может выбрать субоптимальное решение из пространства решений. В TensorRT эта субоптимальность может возникать как минимум из двух источников:
- Эвристики, используемые во время поиска: Эвристика может удалять кандидатов до того, как они будут оценены как часть полного движка. Например, построитель может фильтровать определенные тактики свертки в соответствии с порогом размерности канала в определенном слое входной модели. Если отфильтрованная тактика должна была бы участвовать в самом быстром сквозном решении, алгоритм поиска больше не сможет обнаружить это оптимальное решение.
- Несоответствие между локальным профилированием и сквозным выполнением: Во время построения движка кандидаты ядер могут профилироваться индивидуально во время выбора тактики, однако производительность измеряется по всему движку при инференсе. Ядро, работающее изолированно, и то же ядро, работающее как часть большего графа, не имеют идентичной среды выполнения (например, техника адаптивного размера сетки, используемая в GPU NVIDIA Blackwell). Следовательно, сумма индивидуально измеренных времен выполнения ядер не обязательно равна сквозному времени выполнения.
В идеальном случае алгоритм построителя генерирует набор кандидатов, содержащий s*, а алгоритм поиска надежно выбирает его:
A(S) = s*Компилятор глубокого обучения, таким образом, может быть представлен кортежем алгоритмов (A, B), где B генерирует кандидаты, а A выбирает среди них. Однако на практике генерация кандидатов, отсечение, профилирование и выбор могут быть тесно связаны. Граница между A и B, следовательно, может не быть явной в архитектуре компилятора.
Пусть B* обозначает оптимальный алгоритм построителя среди семейства алгоритмов построителя, а A* обозначает оптимальный алгоритм поиска в семействе алгоритмов поиска. Идеальный компилятор реализовал бы кортеж (A*, B*). Для любой входной модели этот кортеж генерировал бы набор кандидатов, содержащий глобально оптимальное решение, а затем надежно обнаруживал бы его:
∀ A, B, ∀ m ∈ M, T(A*(B*(m))) ≤ T(A(B(m)))На уровне математической абстракции одной из возможных реализаций A* является алгоритм полного перебора — оценка каждого решения в наборе кандидатов и выбор того, у которого наименьшее время выполнения:
A*(S) = argmin_{s_i ∈ S} T(s_i)Хотя применение алгоритма полного перебора не всегда будет приемлемым, если бюджет времени построения ограничен, могут существовать компромиссы между временем построения и производительностью инференса. A* используется для обозначения алгоритмов поиска, которые обязательно вернут оптимальное решение при любой входной модели.
Построение B* является более фундаментальной проблемой. Даже идеальный алгоритм поиска не может выбрать решение, которое построитель никогда не делает достижимым. Вместо того чтобы ожидать построения B* за один шаг, можно прогрессивно аппроксимировать его, расширяя и улучшая маршруты построения, доступные компилятору.
03Моделирование Global Performance Tuner
В этом разделе мы моделируем компиляцию как последовательность проходов компилятора, а затем показываем, как настраиваемые маршруты построения обеспечивают основу для настройки производительности, учитывающей точность.
Моделирование компилятора глубокого обучения
Как и традиционный компилятор, компилятор глубокого обучения можно рассматривать как последовательность проходов, каждый из которых преобразует одно IR в другое. Как упоминалось ранее, IR имеет взаимно однозначное отображение на окончательный исполняемый двоичный файл; следовательно, IR можно считать решением. Для этой абстракции пусть f представляет самовзаимодействие IR из пространства решений в пространство решений:
f : S → S
f(s) = s’Алгоритм построителя компилятора глубокого обучения можно смоделировать как серию проходов для преобразования одного решения в другое:
B(m) = f_{k-1}(f_{k-2}(…(f_1(f_0(m))))) = f_{k-1} ∘ f_{k-2} ∘ … ∘ f_0 (m)
B = f_{k-1} ∘ f_{k-2} ∘ … ∘ f_1 ∘ f_0Алгоритм построителя B — это композиция функций, которая выглядит как маршрут, по которому проходит модель и преобразуется в

04Три принципа работы тюнера
Global Performance Tuner, представленный в TensorRT 11.1, опирается на три основных принципа, которые отличают его от традиционных методов оптимизации:
- Настройка, учитывающая точность (Accuracy-aware tuning): Тюнер не просто ищет максимальную скорость. Он строго проверяет каждое сгенерированное решение на соответствие заданному порогу точности (ε). Если решение дает слишком большую ошибку по сравнению с эталонной моделью, оно отбрасывается, независимо от того, насколько оно быстро.
- Настраиваемые маршруты построения (Customizable build routes): Пользователи могут определять собственные последовательности проходов компиляции. Это позволяет обойти ограничения эвристик по умолчанию и исследовать пространство решений, которое стандартный планировщик мог бы проигнорировать.
- Большое пространство решений (Large solution space): За счет комбинирования различных маршрутов и тактик, тюнер создает значительно более широкое пространство кандидатов, чем это возможно при ручном выборе параметров. Это увеличивает вероятность нахождения глобального оптимума.

05Что это значит на практике
Для разработчиков, работающих с нейросетями в России и СНГ, внедрение Global Performance Tuner означает переход от ручного тунинга параметров к системному исследованию пространства решений. Раньше, чтобы ускорить модель, инженеру приходилось гадать: "А что если мы отключим слияние для этого слоя?" или "Что если мы используем FP16 вместо INT8?". Это был процесс проб и ошибок, требующий огромных вычислительных ресурсов и времени.
С Global Performance Tuner процесс становится детерминированным и воспроизводимым. Вы задаете цель (максимальная скорость при допустимой потере точности) и предоставляете тюнеру набор правил (маршрутов). Алгоритм сам находит оптимальный компромисс. Это особенно важно для edge-устройств, где ресурсы ограничены, а требования к задержке критичны. Например, при развертывании модели компьютерного зрения на роботизированной платформе, вы можете задать маршрут, который приоритизирует низкую задержку, и другой маршрут, который приоритизирует точность распознавания мелких объектов. Тюнер выберет лучший движок для каждого сценария использования.
Важно отметить, что этот инструмент не заменяет понимание архитектуры модели. Он требует от инженера четкого определения метрик точности и понимания того, какие оптимизации допустимы для конкретного приложения. Однако он берет на себя рутинную работу по профилированию и сравнению сотен вариантов, позволяя команде сосредоточиться на архитектуре и логике, а не на микро-оптимизациях компилятора.
В следующей части серии мы подробнее рассмотрим алгоритмическую и архитектурную дизайн-модель Global Performance Tuner, а также лучшие практики его использования для достижения максимальной производительности в реальных проектах.
Источник: NVIDIA Developer ↗
