ONNX Runtime, OpenVINO и TVM: обзор инструментов для ускорения ML-моделей
В статье рассказываем о том, какие инструменты лучше использовать для инференса ML на CPU. А также сравниваем ONNX Runtime, OpenVINO и TVM.
Большинство вычислений при работе ML-моделей — матричные. Для работы с ними подходят Tensor и CUDA — специальные графические ядра, интегрированные в GPU. Это дает видеокартам преимущества перед CPU в машинном обучении. Однако они стоят дороже. Если нужно развернуть инференс на процессоре, есть компромисс — использовать инструменты для оптимизации.
По мотивам выступления Артема Земляка, инженера-программиста Smart Consulting, рассказываем о том, какие фреймворки лучше использовать для эффективного продакшена ML-сервисов.
Если вам интересна тема статьи, присоединяйтесь к нашему сообществу «MLечный путь» в Телеграме. Там мы вместе обсуждаем проблемы и лучшие практики организации production ML-сервисов, а также делимся собственным опытом. А ещё там раз в неделю выходят дайджесты по DataOps и MLOps.
Способы оптимизации
Скорость инференса зависит от используемых инструментов. Например, можно разворачивать модели только на базовых фреймворках — PyTorch, TensorFlow, PaddlePaddle, TFLite, TorchScript — и получать не самые лучшие результаты. Такие инструменты больше подходят для обучения и тестового инференса моделей, когда нет потребности в высокой скорости ML-сервиса. Для эффективной работы нужно использовать более мощные фреймворки. Например, ONNX Runtime, OpenVINO или TVM.
В зависимости от выбранного фреймворка могут быть разные способы оптимизации.
Первый способ — конвертация в ONNX Runtime, OpenVINO или TVM. В большинстве случаев это и последний шаг на пути к ускорению инференса. Посмотрите на график: если конвертировать модель ResNet18 из TensorFlow в OpenVINO, можно ускорить инференс примерно в 10 раз.
Второй способ — использование функций дополнительной оптимизации. В каждом фреймворке, в том числе базовом, есть свои инструменты для ускорения инференса. Яркий пример — динамическая квантизация. Она жертвует «излишней» точностью весов модели, округляет их. Тем самым ускоряет вычисления и инференс.
Также можно использовать базовые графовые оптимизации. Например, прунинг — уменьшение размера обученной сети без потери точности, путем удаления лишних параметров из слоев модели.
Третий способ — конвертировать модель в EDGE-версию базового фреймворка. У некоторых базовых фреймворков есть свои оптимизированные под «мобильное» (EDGE) железо версии — в них можно «экспортировать» модели.
PyTorch-модели можно конвертировать в TorchScript, а TensorFlow — в TensorFlow Lite.
Иногда это дает преимущество: если фреймворк адаптирован под EDGE, то, грубо говоря, он лучше справляется с инференсом на процессорах.
Больше информации о базовых фреймворках можно узнать из полной версии доклада.
Четвертый способ — гибридная оптимизация. Если скорости недостаточно, можно поэкспериментировать. Например, конвертировать PyTorch-модель в TorchScript и сделать квантизацию весов.
Но практика показывает, что лучший вариант — конвертировать в ONNX Runtime, OpenVINO или TVM, а после — использовать их методы дополнительной оптимизации. Но какой фреймворк выбрать?
Создавайте и используйте кластеры Managed Kubernetes
Вы можете добавить к ним графические процессоры — для этого выберите фиксированную конфигурацию ноды с GPU.
Бенчмарки эксперимента
Чтобы понять, какой фреймворк лучше использовать, команда из Smart Consulting провела эксперимент. Они проверили, сколько времени и памяти потребляет инференс разных моделей на ONNX Runtime, OpenVINO и TVM. И при каких методах дополнительной оптимизации эти параметры наилучшие.
Правила проведения эксперимента:
- Все рассматриваемые модели должны быть запущены в режиме инференса.
- В рамках одного бенчмарка — несколько циклов тестирования.
- Память и время вычисляются по 100 раз внутри каждого цикла.
- В итоговую таблицу записываются средние значения показателей.
ONNX Runtime
Это open source-движок для конвертации моделей из базовых фреймворков в ONNX-формат — высокопроизводительный инструмент для запуска инференсов.
В ONNX Runtime (ORT) есть дополнительная оптимизация — квантизация и базовые графовые оптимизации. Последнее всегда включено во время тестирования производительности.
Тест на производительность
модель | время, с | диск, ГБ | оптимизация | CPU |
LaBSE_en_ru | 0,165 | 0,501 | — | i7-11800H |
LaBSE_en_ru | 0,075 | 0,126 | Квантизация | i7-11800H |
LaBSE_ner_nerel | 0,263 | 0,499 | — | i7-11800H |
LaBSE_ner_nerel | 0,091 | 0,125 | Квантизация | i7-11800H |
paraphrase-mpnet-base-v2 | 0,166 | 1,086 | — | i7-11800H |
paraphrase-mpnet-base-v2 | 0,067 | 0,272 | Квантизация | i7-11800H |
HalfResNet34 | 1,47 | 0,038 | — | i7-11800H |
HalfResNet34 | 1,30 | 0,015 | Квантизация | i7-11800H |
BERT | 0,977 | 0,692 | — | i7-11800H |
BERT | 0,427 | 0,173 | Квантизация | i7-11800H |
ResNet18 | 1,10 | 0,046 | — | i7-11800H |
ResNet18 | 1,04 | 0,012 | Квантизация | i7-11800H |
По всем рассмотренным классам моделей — для распознавания образов, текста — квантизация в ORT, в среднем, сократила количество используемой памяти на 72,4%, а время работы в режиме инференса — на 42,1%.
Но хорошие ли это показатели? Для ответа на вопрос сравним ORT с PyTorch.
Сравнение с PyTorch
Параметры бенчмарка такие же: тестирование инференса на разных моделях, без квантизации и с ней.
В большинстве случаев видно, что даже без оптимизации ORT выигрывает PyTorch, который использует квантизацию.
Другая ситуация с количеством потребляемой памяти: ORT без квантизации потребляет не меньше, чем PyTorch. Зато с оптимизацией он показал лучшие результаты.
Преимущества ORT
Также ORT хорошо работает на процессорах без специальных инструкций AVX. Это хорошо, когда нужно запустить модель на слабом процессоре. С PyTorch ситуация другая: для эффективной работы нужно устанавливать дополнительные расширения. Рассмотрим пару кейсов.
Распознавание образов. Если нужно построить систему распознавания образов, но есть только слабый процессор и ограничения по времени инференса, можно воспользоваться ORT.
модель | время, с | диск, ГБ | оптимизация | CPU |
ResNet18 (ORT) | 4,69 | 0,046 | — | Xeon 8 CPU (без AVX) |
ResNet18 (PyTorch) | 32,1 | 0,044 | — | Xeon 8 CPU (без AVX) |
Инференс модели ResNet18 на ORT примерно в 7 раз быстрее, чем на PyTorch.
Распознавание голоса. То же самое и с моделями распознавания голоса. Для системы (например, небольшой социальной сети), которая должна обрабатывать большое количество голосовых сообщений, лучше подойдет ORT.
модель | время, с | диск, ГБ | оптимизация | CPU |
Voice_recognition (ORT) | 394 | — | Квантизация | Xeon 8CPU (без AVX) |
ResNet18 (PyTorch) | 5659 | — | — | Xeon 8CPU (без AVX) |
Инференс модели Voice_recognition на ORT примерно в 14 раз быстрее, чем на PyTorch.
Дополнительный тест
модель | время, с | диск, ГБ | оптимизация | CPU |
ResNet18 | 1,10 | 0,046 | — | i7-11800H |
BERT len=10 | 1,88 | 0,692 | — | i7-11800H |
BERT len=128 | 6,44 | 0,692 | — | i7-11800H |
BERT len=256 | 13,44 | 0,692 | — | i7-11800H |
SR | 1,6 | 0,0003 | — | i7-11800H |
OpenVINO
Это открытый ML-фреймворк для оптимизации и развертывания моделей глубокого обучения. В отличие от ORT OpenVINO не такой «гибкий»: инструмент умеет конвертировать только из ONNX. Из минусов — для работы нужны инструкции процессора (SSE4.2 и AVX). Без них OpenVINO либо не запустится, либо не будет просчитывать модель.
Тест на производительность
модель | время, с | диск, ГБ | оптимизация | CPU |
HalfResNet34 | 1,41 | 0,038 | — | i7-11800H |
ResNet18 | 0,66 | — | — | i7-11800H |
ResNet18 | 0,67 | — | — | i7-11800H |
ResNet18 | 1,81 | — | — | i7-11800H |
ResNet18 | 0,55 | — | — | i7-11800H |
SR | 1,19 | — | — | i7-11800H |
SR | 1,25 | — | — | i7-11800H |
SR | 3,11 | — | — | i7-11800H |
SR | 1,38 | — | — | i7-11800H |
Без оптимизации OpenVINO выдает хорошие результаты, как и ORT на некоторых моделях распознавания образов.
Динамические шейпы
Во время инференса на статических шейпах размеры и форма тензоров не меняются. Но есть ситуации, когда параметры тензора не известны заранее — например, когда меняется размер входных данных модели. Разработчики OpenVINO это учли и добавили динамические шейпы.
При тестировании OpenVINO скорость инференса проверяли как на статическом, так и динамическом шейпе.
Режимы инференса
В OpenVINO есть инструменты для дополнительной оптимизации. Среди них — квантизация и специальные режимы инференса:
- LATENCY — режим на сокращение задержек,
- THROUGHPUT — режим оптимизации RPM,
- ASYNC — асинхронный режим инференса.
Их можно комбинировать и добиваться хорошего времени инференса. Например, с помощью режимов можно ускорить модель BERT на 20-30%. Для этого нужно правильно подобрать комбинацию режимов в связке с динамическим или статическим шейпом.
модель | (DYNAMIC) время, с | (STATIC)время, с | диск, ГБ | оптимизация | CPU |
BERT len=10 | 2,22 | 2,16 | — | — | i7-11800H |
BERT len=10 | 2,22 | 2,08 | — | LATENCY | i7-11800H |
BERT len=10 | 2,16 | 2,24 | — | THROUGHPUT | i7-11800H |
BERT len=10 | 1,47 | 1,69 | — | THROUGHPUT + ASYNC | i7-11800H |
BERT len=128 | 6,47 | 6,06 | — | — | i7-11800H |
BERT len=128 | 6,95 | 6,37 | — | LATENCY | i7-11800H |
BERT len=128 | 8,9 | 13,2 | — | THROUGHPUT | i7-11800H |
BERT len=128 | 6,7 | 5,22 | — | THROUGHPUT + ASYNC | i7-11800H |
BERT len=256 | 13,5 | 10,4 | — | — | i7-11800H |
BERT len=256 | 13,6 | 10,4 | — | LATENCY | i7-11800H |
BERT len=256 | 18 | 26 | — | THROUGHPUT | i7-11800H |
BERT len=256 | 12,5 | 10,2 | — | THROUGHPUT + ASYNC | i7-11800H |
TVM
Это open source-оптимизатор ML, разработанный компанией Apache в 2018 году. Позволяет оптимизировать модели для эффективной работы на любом аппаратном сервере. По сути, это целая система для автоматического создания и оптимизации моделей. А также их конвертации в DLL- и so-форматы для запуска на Windows и Linux соответственно.
Как и ORT, инструмент может конвертировать модели из большого числа фреймворков и форматов. Среди них — ONNX, TorchScript, TensorFlow, TFLite, Keras, MXNet, Darknet, Caffe и Caffe 2, Coreml, Oneflow, PaddlePaddle.
Также в TVM много дополнительных оптимизаций. Некоторые из них еще «сырые»:
- Квантизация — может ускорить инференс в два раза, но пока плохо реализована и может сократить точность модели.
- Компилятор модели — использует три уровня оптимизации под определенный target.
- Auto TVM и Auto Scheduler — необходимы для автоматического тюнинга моделей и улучшения производительности.
Тест на производительность
модель | время, с | диск, ГБ | оптимизация | CPU |
ResNet18 | 1,09 | 0,046 | (opt_level=3) llvm -mcpu=skylake-avx512 | i7-11800H |
ResNet18 | 1,06 | — | (opt_level=3) llvm -mcpu=skylake-avx512 autoscheduler | i7-11800H |
ResNet18 | 0.74 | — | (opt_level=3) llvm -mcpu=skylake-avx512 quantize_dynamic | i7-11800H |
BERT len=10 | 2,5 | — | (opt_level=3) llvm -mcpu=skylake-avx512 | i7-11800H |
BERT len=128 | 8,29 | — | (opt_level=3) llvm -mcpu=skylake-avx512 FastMath | i7-11800H |
BERT len=256 | 23,33 | — | (opt_level=3) llvm -mcpu=skylake-avx512 | i7-11800H |
SR | 2,1 | — | (opt_level=3) llvm -mcpu=skylake-avx512 | i7-11800H |
Сложно сказать, насколько эффективны дополнительные оптимизации в TVM. Если у вас есть опыт использования, поделитесь им в комментариях.
Скорость без использования AVX
TVM хорошо работает на процессорах и без использования инструкций типа AVX. Но делает это немного хуже, чем ORT.
модель | время, с | диск, ГБ | оптимизация | CPU |
ResNet18 (TVM) | 6,37 | 0,046 | (opt_level=3) llvm | Xeon 8CPU (без AVX) |
ResNet18 (ORT) | 4,69 | — | (opt_level=3) llvm | Xeon 8CPU (без AVX) |
ResNet18 (PyTorch) | 32,1 | 0,044 | — | Xeon 8CPU (без AVX) |
Инференс модели ResNet18 на TVM примерно в 4 раза быстрее, чем на PyTorch. Однако это на 35% медленней инференса на ORT.
Сравнение инструментов
На протяжении всего эксперимента ONNX Runtime (ORT) был отправной точкой — неким примером для сравнений. Но заслуженный ли этот титул?
На примере нескольких моделей — ResNet18, SR и BERT — был проведен заключающий тест:
Эксперимент показал: TVM медленней соперников в два раза, а OpenVINO и ORT идут «впритык» — они оба хорошо подходят для оптимизации моделей обработки языка и компьютерного зрения.
В более крупном масштабе видно: OpenVINO, как и TVM, быстрее ORT. Хотя TVM сильно потерял в точности из-за использования квантизации.
«Топ-3» по скорости можно построить так: на первом месте — OpenVINO, на втором — ORT, на третьем — TVM.
Какой фреймворк выбрать?
Выбор фреймворка зависит от конкретной ситуации и предпочтений инженера.
Хотите поэкспериментировать с настройками — используйте TVM. Это перспективный проект. Но его методы для оптимизации еще «сырые»: можно выиграть в скорости инференса, но потерять в качестве модели.
Если нужно гибкое стабильное и «гибкое» решение — используйте ONNX Runtime.Много базовых фреймворков поддерживают конвертацию в ONNX-формат и обратно. Это особенно полезно, если в компании обучают нейросети, например, сразу на PyTorch, TensorFlow и PaddlePaddle. Итоговые модели можно конвертировать в один формат — без затрат времени на оптимизацию каждой из них по отдельности.
Хотите максимально ускорить инференс — используйте OpenVINO. Инструмент несильно опережает ONNX Runtime в производительности, но в работе с большим количеством моделей разница может быть существенной. Из минусов: в OpenVINO можно конвертировать модели только из ONNX. Это препятствует сценарию из прошлого пункта.
Какой фреймворк для оптимизации моделей используете вы? Подключайтесь к обсуждению в нашем чате.