c151470512b77a2bbbf984b290112917.jpg

Оптимизация вывода модели PyTorch на ЦП

Летающий как лев на Intel Xeon

Делиться

c151470512b77a2bbbf984b290112917

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

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

В этой статье мы предположим, что платформа, на которой выполняется вывод модели, представляет собой процессор Intel® Xeon® Scalable 4-го поколения, а именно, экземпляр Amazon EC2 c7i.xlarge (с 4 виртуальными процессорами Intel Xeon), работающий под управлением выделенного образа AMI Deep Learning Ubuntu (22.04) и сборки PyTorch 2.8.0 на CPU. Конечно, выбор платформы развертывания модели — одно из многих важных решений, принимаемых при проектировании решения для ИИ, наряду с выбором архитектуры модели, фреймворка разработки, ускорителя обучения, формата данных, стратегии развертывания и т. д. — каждое из которых должно приниматься с учетом связанных затрат и скорости выполнения. Выбор процессора для выполнения вывода модели может показаться неожиданным в эпоху, когда количество специализированных ускорителей вывода ИИ постоянно растет. Однако, как мы увидим, бывают случаи, когда лучшим (и самым дешевым) вариантом вполне может оказаться обычный CPU.

Мы представим модель классификации изображений и продемонстрируем некоторые возможности оптимизации вывода моделей ИИ на процессоре Intel® Xeon®. Развертывание модели ИИ обычно включает в себя полноценное решение сервера вывода, но для простоты мы ограничимся обсуждением только основного ядра модели. Для ознакомления с обслуживанием вывода моделей см. нашу предыдущую публикацию: «Аргументы в пользу централизованного обслуживания вывода моделей ИИ».

Цель этой публикации — продемонстрировать, что: 1) несколько простых методов оптимизации могут привести к значительному повышению производительности и 2) достижение таких результатов не требует специальных знаний в области анализаторов производительности (таких как Intel® VTune™ Profiler) или внутреннего устройства низкоуровневых вычислительных ядер. Важно отметить, что процесс оптимизации модели ИИ может значительно различаться в зависимости от архитектуры модели и среды выполнения. Оптимизация для обучения будет отличаться от оптимизации для вывода. Оптимизация модели трансформатора будет отличаться от оптимизации модели CNN. Оптимизация модели с 22 миллиардами параметров будет отличаться от оптимизации модели со 100 миллионами параметров. Оптимизация модели для работы на графическом процессоре будет отличаться от оптимизации для работы на центральном процессоре. Даже разные поколения одного семейства процессоров могут иметь разные вычислительные компоненты и, следовательно, разные методы оптимизации. Хотя основные шаги по оптимизации заданной модели в конкретном случае довольно стандартны, конкретный курс действий и конечный результат могут существенно различаться в зависимости от текущего проекта.

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

Почему процессор?

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

  1. Доступность : использование специализированных ускорителей ИИ, таких как графические процессоры, обычно требует специального развертывания и обслуживания или, в качестве альтернативы, доступа к таким экземплярам на облачной платформе. Процессоры же используются повсеместно. Разработка решения для работы на центральном процессоре обеспечивает гораздо большую гибкость и расширяет возможности развертывания.
  2. Доступность : даже если ваш алгоритм может получить доступ к ИИ-ускорителю, возникает вопрос доступности. ИИ-ускорители пользуются чрезвычайно высоким спросом, и даже если/когда вы сможете приобрести один из них, будь то локальный или облачный вариант, вы можете отдать предпочтение им для задач, требующих ещё больших ресурсов, таких как обучение моделей ИИ.
  3. Сокращение задержки : во многих ситуациях ваша модель ИИ является лишь одним из компонентов конвейера программных алгоритмов, работающих на стандартном процессоре. Хотя модель ИИ может работать значительно быстрее на ускорителе ИИ, учитывая время, необходимое для отправки запроса на вывод по сети, вполне возможно, что её запуск на том же процессоре будет быстрее.
  4. Недостаточное использование ускорителя : ИИ-ускорители, как правило, довольно дороги. Чтобы оправдать их стоимость, необходимо поддерживать их полную загрузку, минимизируя время простоя. В некоторых случаях нагрузка на процесс вывода не оправдает затраты на дорогостоящий ИИ-ускоритель.
  5. Архитектура модели : В наши дни мы склонны автоматически предполагать, что модели ИИ будут работать значительно лучше на ускорителях ИИ, чем на центральных процессорах. И хотя чаще всего это действительно так, ваша модель может включать слои, которые работают лучше на центральном процессоре. Например, последовательные алгоритмы, такие как подавление немаксимальных вычислений (NMS) и венгерский алгоритм сопоставления, как правило, работают лучше на центральном процессоре, чем на графическом процессоре, и часто перекладываются на центральный процессор, даже если графический процессор доступен (например, см. здесь). Если ваша модель содержит много таких слоёв, запуск её на центральном процессоре может быть не таким уж плохим вариантом.

Почему Intel Xeon?

Масштабируемые процессоры Intel® Xeon® оснащены встроенными ускорителями для матричных и сверточных операторов, которые часто встречаются в типичных рабочих нагрузках ИИ/МО. К ним относятся AVX-512 (представленный в Gen1), расширение VNNI (Gen2) и AMX (Gen4). Механизм AMX, в частности, включает специализированные аппаратные инструкции для выполнения моделей ИИ с использованием прецизионных типов данных bfloat16 и int8. Ускорители тесно интегрированы с оптимизированным программным стеком Intel, который включает oneDNN, OpenVINO и расширение Intel для PyTorch (IPEX). Эти библиотеки используют специализированные аппаратные возможности Intel® Xeon® для оптимизации выполнения моделей с минимальными изменениями кода.

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

Эксперимент по выводу

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

импорт torch, torchvision импорт времени def get_model(): model = torchvision.models.resnet50() model = model.eval() return model def get_input(batch_size): batch = torch.randn(batch_size, 3, 224, 224) return batch def get_inference_fn(model): def infer_fn(batch): with torch.inference_mode(): output = model(batch) return output return infer_fn def benchmark(infer_fn, batch): # разминка for _ in range(10): _ = infer_fn(batch) iters = 100 start = time.time() for _ in range(iters): _ = infer_fn(batch) end = time.time() return (end — start) / iters batch_size = 1 model = get_model() batch = get_input(batch_size) infer_fn = get_inference_fn(model) avg_time = benchmark(infer_fn, batch) print(f»nСреднее количество выборок в секунду: {(batch_size/avg_time):.2f}»)

Базовая производительность нашей игрушечной модели составляет 22,76 выборок в секунду (SPS).

Оптимизация вывода модели

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

Мы сосредоточимся на оптимизациях, не изменяющих архитектуру модели; такие методы оптимизации, как дистилляция и обрезка модели, выходят за рамки данной публикации. Также не рассматриваются методы оптимизации отдельных компонентов модели, например, путём реализации пользовательских операторов PyTorch.

В предыдущей публикации мы обсуждали оптимизацию моделей ИИ на процессорах Intel XEON в контексте учебных нагрузок. В этом разделе мы вернёмся к некоторым упомянутым там методам, на этот раз в контексте вывода моделей ИИ. Мы дополним их методами оптимизации, уникальными для настроек вывода, включая компиляцию модели для вывода, квантование INT8 и вывод с несколькими исполнителями.

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

Оптимизация 1: Пакетный вывод

Распространенным методом повышения эффективности использования ресурсов и сокращения среднего времени ответа на вывод является группировка входных выборок в пакеты. В реальных сценариях необходимо ограничивать размер пакета, чтобы соответствовать требованиям к времени ответа на уровне обслуживания, но в рамках нашего эксперимента мы игнорируем это требование. Экспериментируя с различными размерами пакетов, мы обнаружили, что пакет размером 8 обеспечивает пропускную способность 26,28 выборок в секунду, что на 15% выше базового значения.

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

Оптимизация 2: Формат памяти каналов-последних

По умолчанию в PyTorch четырёхмерные тензоры хранятся в формате NCHW, то есть четыре измерения представляют размер пакета, каналы, высоту и ширину соответственно. Однако формат channels-last или NHWC (то есть размер пакета, высота, ширина и каналы) обеспечивает более высокую производительность на процессоре. Настройка нашего скрипта вывода для применения оптимизации channels-last заключается в простой настройке формата памяти как модели, так и входных данных в torch.channels_last, как показано ниже:

def get_model(channels_last=False): model = torchvision.models.resnet50() if channels_last: model= model.to(memory_format=torch.channels_last) model = model.eval() return model def get_input(batch_size, channels_last=False): batch = torch.randn(batch_size, 3, 224, 224) if channels_last: batch = batch.to(memory_format=torch.channels_last) return batch batch_size = 8 model = get_model(channels_last=True) batch = get_input(batch_size, channels_last=True) infer_fn = get_inference_fn(model) avg_time = benchmark(infer_fn, batch) print(f»nСреднее количество выборок в секунду: {(batch_size/avg_time):.2f}»)

Применение оптимизации памяти на уровне последних каналов приводит к дополнительному повышению пропускной способности на 25%.

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

Более подробную информацию об оптимизации формата памяти можно найти в документации PyTorch, а подробную информацию о том, как это реализовано внутри oneDNN, — в документации Intel.

Оптимизация 3: Автоматическая смешанная точность

Современные масштабируемые процессоры Intel® Xeon® (начиная с третьего поколения) поддерживают тип данных bfloat16 — 16-битную альтернативу стандартному float32. Мы можем воспользоваться этим преимуществом, применив автоматический пакет смешанной точности PyTorch, torch.amp, как показано ниже:

def get_inference_fn(model, enable_amp=False): def infer_fn(batch): with torch.inference_mode(), torch.amp.autocast( 'cpu', dtype=torch.bfloat16, enabled=enable_amp ): output = model(batch) return output return infer_fn batch_size = 8 model = get_model(channels_last=True) batch = get_input(batch_size, channels_last=True) infer_fn = get_inference_fn(model, enable_amp=True) avg_time = benchmark(infer_fn, batch) print(f»nСреднее количество выборок в секунду: {(batch_size/avg_time):.2f}»)

Результатом применения смешанной точности является пропускная способность 86,95 выборок в секунду, что в 2,6 раза больше предыдущего эксперимента и в 3,8 раза больше базового результата.

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

Оптимизация 4: Оптимизация выделения памяти

Типичные рабочие нагрузки ИИ/МО требуют выделения больших блоков памяти и доступа к ним. Существует ряд методов оптимизации, направленных на настройку распределения и использования памяти во время выполнения модели. Одним из распространённых шагов является замена системного распределителя памяти по умолчанию (ptmalloc) альтернативными библиотеками выделения памяти, такими как Jemalloc и TCMalloc, которые, как было показано, демонстрируют лучшую производительность при выполнении распространённых рабочих нагрузок ИИ/МО (например, см. здесь). Чтобы установить TCMalloc, выполните:

sudo apt-get install google-perftools

Мы программируем его использование через переменную среды LD_PRELOAD:

LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libtcmalloc.so.4 python main.py

Эта оптимизация приводит к еще одному значительному повышению производительности: 117,54 SPS, что на 35% выше, чем в нашем предыдущем эксперименте!!

Оптимизация 5: включение выделения больших страниц

По умолчанию ядро Linux выделяет память блоками по 4 КБ, обычно называемыми страницами. Сопоставлением адресов виртуальной и физической памяти управляет блок управления памятью (MMU) процессора, который использует небольшой аппаратный кэш, называемый буфером трансляции (TLB). TLB ограничен по количеству записей, которые он может хранить. При наличии большого количества небольших страниц (как в моделях больших нейронных сетей) количество промахов кэша TLB может быстро расти, увеличивая задержку и замедляя скорость работы программы. Распространенным способом решения этой проблемы является использование «огромных страниц» — блоков по 2 МБ (или 1 ГБ) на страницу. Это уменьшает количество требуемых записей TLB, повышая эффективность доступа к памяти и снижая задержку выделения памяти.

экспорт THP_MEM_ALLOC_ENABLE=1

В случае нашей модели влияние незначительно. Тем не менее, это важная оптимизация для многих рабочих нагрузок ИИ/МО.

Оптимизация 6: IPEX

Intel® Extension for PyTorch (IPEX) — это расширение библиотеки для PyTorch с новейшими оптимизациями производительности для оборудования Intel. Для установки выполните:

pip install intel_extension_for_pytorch

В приведенном ниже блоке кода мы демонстрируем базовое использование API ipex.optimize.

импортировать intel_extension_for_pytorch как ipex def get_model(channels_last=False, ipex_optimize=False): model = torchvision.models.resnet50() если channels_last: model= model.to(memory_format=torch.channels_last) model = model.eval() если ipex_optimize: model = ipex.optimize(model, dtype=torch.bfloat16) вернуть model

В результате получается 159,31 SPS, что означает прирост производительности еще на 36%.

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

Оптимизация 7: Компиляция модели

Ещё одна популярная оптимизация PyTorch — torch.compile. Эта функция JIT-компиляции, представленная в PyTorch 2.0, выполняет слияние ядер и другие оптимизации. В предыдущей публикации мы подробно рассмотрели компиляцию PyTorch, в том числе её многочисленные функции, элементы управления и ограничения. Здесь мы продемонстрируем её базовое использование:

def get_model(channels_last=False, ipex_optimize=False, compile=False): model = torchvision.models.resnet50() if channels_last: model= model.to(memory_format=torch.channels_last) model = model.eval() if ipex_optimize: model = ipex.optimize(model, dtype=torch.bfloat16) if compile: model = torch.compile(model) return model

Применение torch.compile к модели, оптимизированной для IPEX, обеспечивает производительность 144,5 SPS, что ниже, чем в нашем предыдущем эксперименте. В нашей модели IPEX и torch.compile плохо сочетаются. При применении только torch.compile производительность составляет 133,36 SPS.

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

Оптимизация 8: Автоматическая настройка среды с помощью torch.xeon.run_cpu

Существует ряд параметров среды, которые контролируют управление потоками и памятью и могут использоваться для дальнейшей тонкой настройки производительности выполнения рабочей нагрузки ИИ/МО. Вместо ручной настройки PyTorch предлагает скрипт torch.xeon.run_cpu, который делает это автоматически. В рамках подготовки к использованию этого скрипта мы устанавливаем библиотеки Intel для многопоточной обработки и многопроцессорной обработки, один TBB и Intel OpenMP. Мы также добавляем символическую ссылку на нашу установку TCMalloc.

# установка TBB sudo apt install -y libtbb12 # установка openMP pip install intel-openmp # ссылка на tcmalloc sudo ln -sf /usr/lib/x86_64-linux-gnu/libtcmalloc.so.4 /usr/lib/libtcmalloc.so

В случае нашей игрушечной модели использование torch.xeon.run_cpu увеличивает пропускную способность до 162,15 SPS — незначительное увеличение по сравнению с нашим предыдущим максимумом в 159,31 SPS.

Дополнительные сведения о функциях torch.xeon.run_cpu и переменных среды, которые он применяет, см. в документации PyTorch.

Оптимизация 9: Многопользовательский вывод

Другой популярный метод повышения эффективности использования ресурсов и масштабирования — загрузка нескольких экземпляров модели ИИ и их параллельное выполнение в отдельных процессах. Хотя этот метод чаще применяется на машинах с большим количеством процессоров (разделённых на несколько узлов NUMA), но не на нашем небольшом экземпляре с 4 виртуальными процессорами, мы включили его здесь для демонстрации. В приведённом ниже скрипте мы запускаем два экземпляра нашей модели параллельно:

python -m torch.backends.xeon.run_cpu —ninstances 2 main.py

В результате пропускная способность достигает 169,4 SPS — дополнительное скромное, но значимое увеличение на 4%.

Оптимизация 10: Квантование INT8

Квантование INT8 — ещё один распространённый метод ускорения вывода моделей ИИ. При квантовании INT8 типы данных с плавающей запятой для весов и активаций модели заменяются 8-битными целыми числами. Процессоры Intel Xeon оснащены специализированными ускорителями для обработки операций INT8 (например, см. здесь). Квантование INT8 может привести к значительному увеличению скорости и уменьшению объёма памяти. Важно отметить, что снижение разрядности может существенно повлиять на качество выходных данных модели. Существует множество различных подходов к квантованию INT8, некоторые из которых включают калибровку или переобучение. Также существует широкий спектр инструментов и библиотек для применения квантования. Полное обсуждение темы квантования выходит за рамки данной публикации.

Поскольку в этой статье нас интересует только потенциальное влияние на производительность, мы продемонстрируем одну схему квантования с использованием TorchAO, не рассматривая влияние на качество модели. В приведённом ниже блоке кода мы реализуем квантование экспорта PyTorch 2 с бэкендом X86 через Inductor. Квантование INT8 — ещё один распространённый метод ускорения вывода моделей ИИ. При квантовании INT8 типы данных с плавающей запятой для весов и активаций модели заменяются 8-битными целыми числами. Процессоры Intel Xeon оснащены специальными ускорителями для обработки операций INT8 (например, см. здесь). Квантование INT8 может привести к значительному повышению скорости и уменьшению объёма памяти.

Важно отметить, что снижение битовой точности может существенно повлиять на качество выходных данных модели. Существует множество различных подходов к квантованию INT8, некоторые из которых включают калибровку или переобучение. Также существует широкий спектр инструментов и библиотек для применения квантования. Полное обсуждение темы квантования выходит за рамки данной публикации. Поскольку в данной публикации нас интересует только потенциальное влияние на производительность, мы продемонстрируем одну схему квантования с использованием TorchAO, не рассматривая влияние на качество модели. В приведённом ниже блоке кода мы реализуем квантование экспорта PyTorch 2 с бэкендом X86 через Inductor. Подробности см. в документации:

из torchao.quantization.pt2e.quantize_pt2e импортировать prepare_pt2e, convert_pt2e импортировать torchao.quantization.pt2e.quantizer.x86_inductor_quantizer как xiq def quantize_model(model): x = torch.randn(4, 3, 224, 224).contiguous( memory_format=torch.channels_last) example_inputs = (x,) batch_dim = torch.export.Dim(«batch») с torch.no_grad(): exported_model = torch.export.export( model, example_inputs, dynamic_shapes=((batch_dim, torch.export.Dim.STATIC, torch.export.Dim.STATIC, torch.export.Dim.STATIC), ) ).module() quantizer = xiq.X86InductorQuantizer() quantizer.set_global(xiq.get_default_x86_inductor_quantization_config()) prepared_model = prepare_pt2e(exported_model, quantizer) prepared_model(*example_inputs) converter_model = convert_pt2e(prepared_model) optimized_model = torch.compile(converted_model) return optimized_model batch_size = 8 model = get_model(channels_last=True) model = quantize_model(model) batch = get_input(batch_size, channels_last=True) infer_fn = get_inference_fn(model, enable_amp=True) avg_time = benchmark(infer_fn, batch) print(f»nСреднее количество выборок в секунду: {(batch_size/avg_time):.2f}»)

В результате пропускная способность составляет 172,67 SPS.

Более подробную информацию о квантовании в PyTorch можно найти здесь.

Оптимизация 11: Компиляция и выполнение графа с помощью ONNX

Существует ряд сторонних библиотек, специализирующихся на компиляции моделей PyTorch в графовые представления и их оптимизации для производительности выполнения на целевых устройствах вывода. Одна из самых популярных библиотек для этой цели — Open Neural Network Exchange (ONNX). ONNX выполняет предварительную компиляцию моделей искусственного интеллекта/машинного обучения и выполняет их с помощью специальной библиотеки времени выполнения.

Хотя поддержка компиляции ONNX включена в PyTorch, для выполнения модели ONNX нам требуется следующая библиотека:

pip install onnxruntime

В приведенном ниже блоке кода мы демонстрируем компиляцию ONNX и выполнение модели:

def export_to_onnx(model, onnx_path=»resnet50.onnx»): dummy_input = torch.randn(4, 3, 224, 224) batch = torch.export.Dim(«batch») torch.onnx.export( model, dummy_input, onnx_path, input_names=[«input»], output_names=[«output»], dynamic_shapes=((batch, torch.export.Dim.STATIC, torch.export.Dim.STATIC, torch.export.Dim.STATIC), ), dynamo=True ) return onnx_path def onnx_infer_fn(onnx_path): import onnxruntime as ort sess = ort.InferenceSession( onnx_path, providers=[«CPUExecutionProvider»] ) input_name = sess.get_inputs()[0].name def infer_fn(batch): result = sess.run(None, {input_name: batch}) return result return infer_fn batch_size = 8 model = get_model() onnx_path = export_to_onnx(model) batch = get_input(batch_size).numpy() infer_fn = onnx_infer_fn(onnx_path) avg_time = benchmark(infer_fn, batch) print(f»nСреднее количество выборок в секунду: {(batch_size/avg_time):.2f}»)

Результирующая производительность составила 44,92 выборки в секунду, что значительно ниже, чем в наших предыдущих экспериментах. В случае нашей экспериментальной модели среда выполнения ONNX не даёт никаких преимуществ.

Оптимизация 12: Компиляция и выполнение графа с помощью OpenVINO

OpenVINO — ещё один набор инструментов с открытым исходным кодом, предназначенный для развёртывания высокопроизводительных решений ИИ. OpenVINO высоко оптимизирован для выполнения моделей на оборудовании Intel, например, благодаря полному использованию инструкций Intel AMX. Распространённый способ применения OpenVINO в PyTorch — сначала преобразовать модель в формат ONNX:

из openvino import Core def compile_openvino_model(onnx_path): core = Core() model = core.read_model(onnx_path) скомпилированный = core.compile_model(model, «CPU») return скомпилированный def openvino_infer_fn(compiled_model): def infer_fn(batch): result = compiled_model([batch])[0] return result return infer_fn batch_size = 8 model = get_model() onnx_path = export_to_onnx(model) ovm = compile_openvino_model(onnx_path) batch = get_input(batch_size).numpy() infer_fn = openvino_infer_fn(ovm) avg_time = benchmark(infer_fn, batch) print(f»nСреднее количество выборок в секунду: {(batch_size/avg_time):.2f}»)

Результатом этой оптимизации стала производительность 297,33 SPS, что почти в два раза выше, чем в нашем предыдущем лучшем эксперименте!!

Более подробную информацию об OpenVINO можно найти в официальной документации.

Оптимизация 13: Квантование INT8 в OpenVINO с NNCF

В качестве заключительной оптимизации мы возвращаемся к квантованию INT8, на этот раз в рамках компиляции OpenVINO. Как и прежде, существует ряд методов квантования, направленных на минимизацию влияния на качество производительности. Здесь мы демонстрируем базовый алгоритм с использованием библиотеки NNCF, описанной здесь.

class RandomDataset(torch.utils.data.Dataset): def __len__(self): return 10000 def __getitem__(self, idx): return torch.randn(3, 224, 224) def nncf_quantize(onnx_path): import nncf core = Core() onnx_model = core.read_model(onnx_path) calibration_loader = torch.utils.data.DataLoader(RandomDataset()) input_name = onnx_model.inputs[0].get_any_name() transform_fn = lambda data_item: {input_name: data_item.numpy()} calibration_dataset = nncf.Dataset(calibration_loader, transform_fn) quantized_model = nncf.quantize(onnx_model, calibration_dataset) return core.compile_model(quantized_model, «CPU») batch_size = 8 model = get_model() onnx_path = export_to_onnx(model) q_model = nncf_quantize(onnx_path) batch = get_input(batch_size).numpy() infer_fn = openvino_infer_fn(q_model) avg_time = benchmark(infer_fn, batch) print(f»nСреднее количество выборок в секунду: {(batch_size/avg_time):.2f}»)

В результате производительность составляет 482,46(!!) операций в секунду, что является еще одним существенным улучшением и превышает показатели нашего базового эксперимента более чем в 18 раз.

Результаты

Результаты наших экспериментов суммированы в таблице ниже:

d1c3ded98fd0f4f84ff8b78c9bc0ad61

В случае нашей экспериментальной модели продемонстрированные нами этапы оптимизации привели к значительному повышению производительности. Важно отметить, что влияние каждой оптимизации может значительно варьироваться в зависимости от особенностей модели. Вы можете обнаружить, что некоторые из этих методов не применимы к вашей модели или не приводят к повышению производительности. Например, при повторном применении той же последовательности оптимизаций к модели Vision Transformer (ViT) результирующий прирост производительности составляет 8,41 раза — всё ещё значительный, но меньше, чем 18,36 раза в нашем эксперименте. Подробности см. в приложении к этой публикации.

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

Краткое содержание

Эта публикация продолжает серию статей, посвящённых важной теме анализа и оптимизации производительности выполнения моделей ИИ/МО. В этой публикации мы сосредоточились на выводе моделей на процессорах Intel® Xeon®. Учитывая повсеместность и распространённость процессоров, возможность надёжного и производительного выполнения моделей на них может быть чрезвычайно привлекательной. Как мы показали, применяя ряд относительно простых методов, мы можем добиться значительного повышения производительности моделей, что существенно скажется на стоимости и задержке вывода.

Не стесняйтесь обращаться к нам с комментариями, вопросами или исправлениями.

Приложение: Оптимизация Vision Transformer

Чтобы продемонстрировать, как влияние обсуждаемых нами оптимизаций времени выполнения зависит от деталей модели ИИ/МО, мы повторно провели наш эксперимент на модели Vision Transformer (ViT) из популярной библиотеки timm:

из timm.models.vision_transformer импорт VisionTransformer def get_model(channels_last=False, ipex_optimize=False, compile=False): model = VisionTransformer() если channels_last: model= model.to(memory_format=torch.channels_last) model = model.eval() если ipex_optimize: model = ipex.optimize(model, dtype=torch.bfloat16) если компилировать: model = torch.compile(model) вернуть модель

Одним из изменений в этом эксперименте стало применение компиляции OpenVINO непосредственно к модели PyTorch, а не к промежуточной модели ONNX. Это было связано с тем, что компиляция OpenVINO на модели ViT ONNX не удалась. Изменённая последовательность квантования NNCF и компиляции OpenVINO показана ниже:

import openvino as ov import nncf batch_size = 8 model = get_model() calibration_loader = torch.utils.data.DataLoader(RandomDataset()) calibration_dataset = nncf.Dataset(calibration_loader) # квантизация модели PyTorch model = nncf.quantize(model, calibration_dataset) ovm = ov.convert_model(model, example_input=torch.randn(1, 3, 224, 224)) ovm = ov.compile_model(ovm) batch = get_input(batch_size).numpy() infer_fn = openvino_infer_fn(ovm) avg_time = benchmark(infer_fn, batch) print(f»nСреднее количество выборок в секунду: {(batch_size/avg_time):.2f}»)

В таблице ниже приведены результаты оптимизаций, обсуждаемых в этой статье, применительно к модели ViT:

91f83f78a2d7781078c443f56a7a34d4

Источник: towardsdatascience.com

✅ Найденные теги: PyTorch, Вывод, Модель, новости, Оптимизация, ЦП

ОСТАВЬТЕ СВОЙ КОММЕНТАРИЙ

Каталог бесплатных опенсорс-решений, которые можно развернуть локально и забыть о подписках

галерея

Кадр из фильма с мужчиной в форме, текст: "Вы ведь включали сегодня [ценз], верно?"
Интерфейс браузера с текстом о Google Veo 3.1 и ссылками на источники.
Wi-Fi передатчик с антенной на фоне поля, радиус действия 1 км.
Скриншот интерфейса Windows с виджетами и обоями в синих тонах.
Интерфейс программы текст-в-речь, библиотека аудио и транскрипция на экране.
ideipro logotyp
Абстрактная иллюстрация с абстрактными фигурами и силуэтом человека в центре.
Роботы-врачи в китайской больнице ИИ, лечение пациентов, футуристическая медицина.
ideipro logotyp
Image Not Found
А что если реальная опасность, исходящая от ИИ, заключается не в дипфейках, а в ежедневных слухах?

А что если реальная опасность, исходящая от ИИ, заключается не в дипфейках, а в ежедневных слухах?

Луис Розенберг, Unanimous AI Создано автором с помощью ChatGPT Большинство людей не осознают той серьезной угрозы, которую ИИ вскоре будет представлять для свободы воли человека . Часто повторяют, что «ИИ — это всего лишь инструмент», и, как…

Мар 5, 2026
Мультяшный мальчик в красной рубашке и голубой шапке, сидит среди других детей.

Ожирение назвали главным фактором риска развития диабета у американских подростков. Повлияли также мужской пол и более молодой возраст

Повлияли также мужской пол и более молодой возраст Когортный анализ данных почти двух тысяч американских подростков в возрасте…

Мар 5, 2026
Молот перед логотипом технологической компании с цветными квадратами.

Microsoft заблокировала слово «Микрослоп» на своём Discord-сервере и ввела ограничения

Изображение, созданное нейросетьюПохоже, Microsoft не очень нравится, когда её инвестиции в искусственный интеллект и активное…

Мар 5, 2026
Четыре символа: золото, стилизованная эмблема, каменное кольцо и змей, кусающий свой хвост.

Есть здесь люди, которые искренне считают, что установив макс, они увеличили суверенитет страны?

«В виртуальных дискуссиях уже давно затрагивают тему мессенджера MAX, представляя его как просто еще одну платформу для коммуникации….

Мар 5, 2026

Впишите свой почтовый адрес и мы будем присылать вам на почту самые свежие новости в числе самых первых