Конвертация модели в ONNX-формат

Проектируем и внедряем системы искусственного интеллекта: от прототипа до production-ready решения. Наша команда объединяет экспертизу в машинном обучении, дата-инжиниринге и MLOps, чтобы AI работал не в лаборатории, а в реальном бизнесе.
Показано 1 из 1 услугВсе 1566 услуг
Конвертация модели в ONNX-формат
Средняя
от 1 рабочего дня до 3 рабочих дней
Часто задаваемые вопросы
Направления AI-разработки
Этапы разработки AI-решения
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1218
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    853
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1047
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    825

Конвертация моделей в формат ONNX

ONNX (Open Neural Network Exchange) — открытый формат представления ML-моделей, не привязанный к конкретному фреймворку. Конвертированную модель запускают ONNX Runtime, TensorRT, OpenVINO, CoreML — на CPU, GPU, NPU, мобильных устройствах.

Конвертация HuggingFace модели через Optimum

# Установка
pip install optimum[onnxruntime]

# Экспорт через CLI
optimum-cli export onnx \
  --model bert-base-uncased \
  --task text-classification \
  --opset 17 \
  --device cuda \
  --fp16 \
  ./bert-onnx/
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")

# Использование идентично обычной HF модели
inputs = tokenizer("Great product!", return_tensors="pt")
outputs = model(**inputs)

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

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,)),    # input_ids
    torch.tensor([0, 16])               # offsets
)

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"},
    }
)

Оптимизация ONNX графа

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,            # 0=нет, 1=базовая, 2=расширенная, 99=все
    use_gpu=True,
    only_onnxruntime=False
)
optimized_model.save_model_to_file("bert_optimized.onnx")

Верификация корректности конвертации

import onnx
import onnxruntime as ort
import numpy as np

# Проверка валидности модели
model = onnx.load("bert_optimized.onnx")
onnx.checker.check_model(model)

# Сравнение вывода с оригинальной PyTorch моделью
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 — ONNX не поддерживает динамический control flow. Решение: унификация через masking или конвертация через TorchScript.

Custom operators: операторы без ONNX эквивалента. Решение: регистрация custom op или рефакторинг с использованием стандартных операций.

Dynamic shapes: некоторые операции требуют статических размерностей. Решение: правильное указание dynamic_axes или использование фиксированных размеров с padding.

Numerical precision: накопление ошибок в длинных цепочках операций при FP16. Решение: конвертация в FP32, затем квантизация отдельно.