Проблема: модель работает только в окружении фреймворка
Вы обучили 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:
-
Установите пакеты и выполните экспорт:
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+ успешных конвертаций. Закажите анализ — и мы подберём оптимальный план работ. Свяжитесь с нами для консультации и оценки вашего проекта.







