Проблема: модель працює лише в середовищі фреймворку
Ви навчили 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+ успішних конвертацій. Замовте аналіз — і ми підберемо оптимальний план робіт. Зв'яжіться з нами для консультації та оцінки вашого проекту.







