> For the complete documentation index, see [llms.txt](https://docs.clore.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.clore.ai/guides/guides_v2-ru/gpu-devops/onnx-runtime.md).

# ONNX Runtime GPU

> **Кроссплатформенный ML-инференс с аппаратным ускорением — развёртывайте любую модель из любого фреймворка**

ONNX Runtime (ORT) — это open-source движок инференса Microsoft для моделей ONNX (Open Neural Network Exchange). Он обеспечивает аппаратно ускоренный инференс на CPU, GPU и специализированных ускорителях через единый API. Независимо от того, была ли ваша модель обучена в PyTorch, TensorFlow, Scikit-learn или XGBoost — если вы можете экспортировать её в формат ONNX, ORT сможет запускать её быстрее.

**GitHub:** [microsoft/onnxruntime](https://github.com/microsoft/onnxruntime) — 14K+ ⭐

***

## Почему ONNX Runtime?

| Функция                                     | ONNX Runtime      | TorchScript      | TensorFlow Serving |
| ------------------------------------------- | ----------------- | ---------------- | ------------------ |
| Независимо от фреймворка                    | ✅                 | ❌ Только PyTorch | ❌ Только TF        |
| Ускорение на GPU                            | ✅ CUDA/TensorRT   | ✅                | ✅                  |
| Квантование INT8/FP16                       | ✅                 | Частично         | Частично           |
| Развёртывание на мобильных/edge-устройствах | ✅                 | Ограниченная     | Ограниченная       |
| Слияние операторов                          | ✅                 | Частично         | ✅                  |
| Лёгкая интеграция                           | ✅ Python/C++/Java | Python           | Python/gRPC        |

{% hint style="success" %}
**Ключевое преимущество:** ONNX Runtime с провайдером выполнения CUDA обычно обеспечивает **ускорение в 1,5–3 раза** по сравнению с нативным инференсом PyTorch для моделей компьютерного зрения и NLP.
{% endhint %}

***

## Поддерживаемые провайдеры выполнения

ONNX Runtime поддерживает несколько аппаратных бэкендов (Execution Providers):

| Провайдер                   | Оборудование  | Сценарий использования              |
| --------------------------- | ------------- | ----------------------------------- |
| `CUDAExecutionProvider`     | GPU NVIDIA    | Универсальный вывод на GPU          |
| `TensorrtExecutionProvider` | GPU NVIDIA    | Максимальная пропускная способность |
| `CPUExecutionProvider`      | CPU           | Резервный вариант / edge            |
| `ROCMExecutionProvider`     | GPU AMD       | Оборудование AMD                    |
| `CoreMLExecutionProvider`   | Apple Silicon | macOS/iOS                           |
| `OpenVINOExecutionProvider` | Intel         | CPU/GPU Intel                       |

***

## Предварительные требования

* Аккаунт Clore.ai с арендой GPU
* Базовые знания Python
* Обученная модель (PyTorch, TensorFlow или заранее экспортированный ONNX)

***

## Шаг 1 — Арендуйте GPU на Clore.ai

1. Перейдите на [маркетплейсе clore.ai](https://clore.ai) → **Маркетплейс**
2. Подойдёт любая NVIDIA GPU — от RTX 3070 для небольших моделей до A100 для больших трансформеров
3. **Для моделей-трансформеров:** Рекомендуется RTX 4090 или A100
4. **Для компьютерного зрения:** Достаточно RTX 3090 или RTX 4090

***

## Шаг 2 — Разверните свой контейнер

У ONNX Runtime нет официального заранее собранного контейнера, но базовый образ NVIDIA CUDA идеально подходит:

**Docker-образ:**

```
nvcr.io/nvidia/cuda:12.8.1-cudnn-devel-ubuntu22.04
```

**Порты:**

```
22
```

**Переменные среды:**

```
NVIDIA_VISIBLE_DEVICES=all
NVIDIA_DRIVER_CAPABILITIES=compute,utility
```

{% hint style="info" %}
В качестве альтернативы используйте `pytorch/pytorch:2.11.0-cuda12.8-cudnn9-runtime` который включает CUDA и Python-окружение, готовое к установке ORT.
{% endhint %}

***

## Шаг 3 — Установите ONNX Runtime с поддержкой GPU

```bash
ssh root@<server-ip> -p <ssh-port>

# Обновить пакеты
apt-get update && apt-get install -y \
    python3-pip \
    python3-dev \\
    wget \\
    git \\
    libgomp1

# Установить ONNX Runtime с поддержкой CUDA
pip install onnxruntime-gpu

# Установить вспомогательные пакеты
pip install \
    onnx \\
    numpy \\
    Pillow \\
    transformers \
    torch \\
    torchvision \\
    fastapi \\
    uvicorn

# Проверьте установку
python3 << 'EOF'
import onnxruntime as ort
print(f"Версия ORT: {ort.__version__}")
print(f"Доступные провайдеры: {ort.get_available_providers()}")
# Должны включать: CUDAExecutionProvider, TensorrtExecutionProvider, CPUExecutionProvider
EOF
```

***

## Шаг 4 — Экспортируйте свою модель в ONNX

### Экспорт модели PyTorch

```python
import torch
import torch.nn as nn
import onnx

# Пример: экспорт ResNet50
model = torch.hub.load('pytorch/vision:v0.10.0', 'resnet50', pretrained=True)
model.eval()

# Создать фиктивный вход (batch=1, RGB-изображение 224x224)
dummy_input = torch.randn(1, 3, 224, 224)

# Экспортировать в ONNX
torch.onnx.export(
    model,
    dummy_input,
    "resnet50.onnx",
    export_params=True,
    opset_version=17,              # Использовать последний стабильный opset
    do_constant_folding=True,      # Оптимизировать константные операции
    input_names=["input"],
    output_names=["output"],
    dynamic_axes={
        "input": {0: "batch_size"},    # Динамический batch
        "output": {0: "batch_size"}
    }
)
print("Модель успешно экспортирована!")

# Проверить экспортированную модель
onnx_model = onnx.load("resnet50.onnx")
onnx.checker.check_model(onnx_model)
print("Модель ONNX корректна!")
```

### Экспорт Transformers из HuggingFace

```bash
# Установить optimum для экспорта HuggingFace ONNX
pip install optimum[exporters]

# Экспортировать BERT для классификации текста
optimum-cli export onnx \\
    --model bert-base-uncased \\
    --task text-classification \\
    ./bert_onnx/

# Экспорт с оптимизацией
optimum-cli export onnx \\
    --model microsoft/phi-2 \\
    --task text-generation \\
    --optimize O2 \\
    ./phi2_onnx/
```

### Экспорт с оптимизацией ORT

```python
from optimum.onnxruntime import ORTModelForSequenceClassification
from optimum.onnxruntime.configuration import OptimizationConfig, ORTConfig
from optimum.onnxruntime import ORTOptimizer

# Загрузить и оптимизировать
model = ORTModelForSequenceClassification.from_pretrained(
    "distilbert-base-uncased-finetuned-sst-2-english",
    export=True
)

optimizer = ORTOptimizer.from_pretrained(model)
optimization_config = OptimizationConfig(
    optimization_level=2,
    optimize_for_gpu=True,
    fp16=True
)

optimizer.optimize(
    save_dir="./distilbert_optimized",
    optimization_config=optimization_config
)
```

***

## Шаг 5 — Выполните инференс с ONNX Runtime

### Базовый GPU-инференс

```python
import onnxruntime as ort
import numpy as np
from PIL import Image
import torchvision.transforms as transforms

# Настроить сессию с провайдерами выполнения для GPU
# Провайдеры пробуются по порядку — сначала CUDA, затем резервный CPU
providers = [
    ("CUDAExecutionProvider", {
        "device_id": 0,
        "arena_extend_strategy": "kNextPowerOfTwo",
        "gpu_mem_limit": 4 * 1024 * 1024 * 1024,  # Лимит 4 ГБ
        "cudnn_conv_algo_search": "EXHAUSTIVE",
        "do_copy_in_default_stream": True,
    }),
    "CPUExecutionProvider"
]

# Настройки сессии для производительности
opts = ort.SessionOptions()
opts.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
opts.intra_op_num_threads = 8
opts.execution_mode = ort.ExecutionMode.ORT_PARALLEL

# Загрузить модель
session = ort.InferenceSession(
    "resnet50.onnx",
    sess_options=opts,
    providers=providers
)

print(f"Запуск на: {session.get_providers()}")

# Подготовить входные данные
transform = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])

img = Image.open("test_image.jpg").convert("RGB")
img_tensor = transform(img).unsqueeze(0).numpy()

# Выполнить инференс
outputs = session.run(None, {"input": img_tensor})
probabilities = outputs[0][0]
top5_idx = probabilities.argsort()[-5:][::-1]
print("Топ-5 предсказаний:", top5_idx, probabilities[top5_idx])
```

### Пакетный инференс для повышения пропускной способности

```python
import onnxruntime as ort
import numpy as np
import time

session = ort.InferenceSession(
    "resnet50.onnx",
    providers=["CUDAExecutionProvider"]
)

# Разогреть GPU
dummy = np.random.randn(1, 3, 224, 224).astype(np.float32)
for _ in range(10):
    session.run(None, {"input": dummy})

# Замерить производительность для разных размеров батча
for batch_size in [1, 4, 8, 16, 32, 64]:
    inputs = np.random.randn(batch_size, 3, 224, 224).astype(np.float32)
    
    start = time.time()
    n_iter = 100
    for _ in range(n_iter):
        session.run(None, {"input": inputs})
    elapsed = time.time() - start
    
    throughput = (batch_size * n_iter) / elapsed
    latency = (elapsed / n_iter) * 1000  # мс
    
    print(f"Пакет {batch_size:3d}: {throughput:7.1f} img/сек, {latency:.1f} мс/пакет")
```

***

## Шаг 6 — Execution Provider TensorRT (максимальная производительность)

Для NVIDIA GPU провайдер TensorRT EP обеспечивает ещё более высокую производительность:

```python
import onnxruntime as ort
import numpy as np

# Конфигурация провайдера выполнения TensorRT
tensorrt_provider_options = {
    "trt_max_workspace_size": 4 * 1024 * 1024 * 1024,  # 4 ГБ
    "trt_fp16_enable": True,          # Включить FP16 для более быстрого инференса
    "trt_int8_enable": False,
    "trt_engine_cache_enable": True,   # Кэшировать скомпилированные движки
    "trt_engine_cache_path": "/tmp/trt_cache",
    "trt_max_partition_iterations": 1000,
    "trt_min_subgraph_size": 1,
    "trt_timing_cache_enable": True,
}

providers = [
    ("TensorrtExecutionProvider", tensorrt_provider_options),
    ("CUDAExecutionProvider", {"device_id": 0}),
    "CPUExecutionProvider"
]

session = ort.InferenceSession("resnet50.onnx", providers=providers)
print("Активный провайдер:", session.get_providers()[0])

# Первый запуск компилирует движок TensorRT (может занять 1–3 минуты)
# Последующие запуски используют кэшированный движок и работают очень быстро
```

{% hint style="warning" %}
**Компиляция движка TensorRT** происходит при первом инференсе и может занять 1–5 минут. Включите кэширование (`trt_engine_cache_enable: True`) чтобы скомпилированный движок переиспользовался между сессиями.
{% endhint %}

***

## Шаг 7 — Квантование INT8 для максимальной скорости

```python
from onnxruntime.quantization import quantize_dynamic, quantize_static, QuantType
import onnxruntime as ort
import numpy as np

# Динамическое квантование INT8 (не нужны данные для калибровки)
quantize_dynamic(
    model_input="resnet50.onnx",
    model_output="resnet50_int8_dynamic.onnx",
    weight_type=QuantType.QInt8
)

# Статическое квантование INT8 (требуются данные для калибровки)
from onnxruntime.quantization import CalibrationDataReader

class ImageCalibrationReader(CalibrationDataReader):
    def __init__(self, data_dir, input_name="input"):
        self.data_dir = data_dir
        self.input_name = input_name
        self.images = self._load_images()
        self.idx = 0
    
    def _load_images(self):
        # Загрузить 100 калибровочных изображений
        import glob, torchvision.transforms as T
        from PIL import Image
        transform = T.Compose([T.Resize(256), T.CenterCrop(224), T.ToTensor()])
        images = []
        for path in glob.glob(f"{self.data_dir}/*.jpg")[:100]:
            img = Image.open(path).convert("RGB")
            images.append(transform(img).numpy())
        return images
    
    def get_next(self):
        if self.idx >= len(self.images):
            return None
        data = {self.input_name: self.images[self.idx:self.idx+1]}
        self.idx += 1
        return data

from onnxruntime.quantization import quantize_static, QuantFormat
quantize_static(
    model_input="resnet50.onnx",
    model_output="resnet50_int8_static.onnx",
    calibration_data_reader=ImageCalibrationReader("/data/calibration_images"),
    quant_format=QuantFormat.QDQ,
    weight_type=QuantType.QInt8
)
```

***

## Шаг 8 — Создайте API для инференса

```bash
cat > /workspace/onnx_api.py << 'EOF'
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import JSONResponse
import onnxruntime as ort
import numpy as np
from PIL import Image
import io
import torchvision.transforms as transforms
import json

app = FastAPI(title="API инференса ONNX Runtime")

# Загрузить модель при запуске
session = ort.InferenceSession(
    "resnet50.onnx",
    providers=["CUDAExecutionProvider", "CPUExecutionProvider"]
)

# Загрузить метки классов ImageNet
with open("imagenet_classes.json") as f:
    classes = json.load(f)

transform = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])

@app.get("/health")
async def health():
    return {"status": "ok", "providers": session.get_providers()}

@app.post("/predict")
async def predict(file: UploadFile = File(...), topk: int = 5):
    image_data = await file.read()
    img = Image.open(io.BytesIO(image_data)).convert("RGB")
    tensor = transform(img).unsqueeze(0).numpy()
    
    outputs = session.run(None, {"input": tensor})[0][0]
    top_indices = outputs.argsort()[-topk:][::-1]
    
    results = [
        {"label": classes[str(i)], "score": float(outputs[i])}
        for i in top_indices
    ]
    return JSONResponse({"predictions": results})

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8080)
EOF

python3 /workspace/onnx_api.py &

# Проверить API
curl -X POST "http://localhost:8080/predict" \\
    -H "accept: application/json" \\
    -F "file=@test_image.jpg"
```

***

## Шаг 9 — Мониторинг использования GPU

```bash
# Мониторинг GPU в реальном времени во время инференса
watch -n 0.5 nvidia-smi

# Или используйте nvitop для более удобного интерфейса
pip install nvitop
nvitop
```

***

## Тесты производительности

| Модель    | GPU      | Провайдер     | Пропускная способность (инф/сек) |
| --------- | -------- | ------------- | -------------------------------- |
| ResNet50  | RTX 4090 | CUDA          | \~4,200                          |
| ResNet50  | RTX 4090 | TensorRT FP16 | \~8,500                          |
| BERT Base | RTX 4090 | CUDA          | \~380                            |
| BERT Base | RTX 4090 | TensorRT FP16 | \~720                            |
| YOLOv8n   | RTX 3090 | CUDA          | \~1,800                          |
| YOLOv8x   | A100     | TensorRT FP16 | \~920                            |

***

## Устранение неполадок

### Провайдер CUDA недоступен

```bash
# Проверьте, что установлен CUDA-ORT (а не только CPU-версия)
pip uninstall onnxruntime
pip install onnxruntime-gpu

python3 -c "import onnxruntime as ort; print(ort.get_available_providers())"
```

### Ошибки компиляции TensorRT

```bash
# Проверьте совместимость версии TensorRT
python3 -c "import tensorrt; print(tensorrt.__version__)"

# Используйте вместо этого CUDA EP
providers = ["CUDAExecutionProvider"]  # Пропустить TensorRT EP
```

### Ошибки несоответствия форм

```python
# Проверьте формы входа/выхода модели
for input in session.get_inputs():
    print(f"Вход: {input.name}, shape: {input.shape}, type: {input.type}")

for output in session.get_outputs():
    print(f"Выход: {output.name}, shape: {output.shape}, type: {output.type}")
```

***

## Продвинутый уровень: многомодельный конвейер

```python
import onnxruntime as ort
import numpy as np

class MultiModelPipeline:
    def __init__(self):
        providers = ["CUDAExecutionProvider"]
        self.detector = ort.InferenceSession("detector.onnx", providers=providers)
        self.classifier = ort.InferenceSession("classifier.onnx", providers=providers)
    
    def run(self, image: np.ndarray) -> list:
        # Этап 1: обнаружение объектов
        boxes = self.detector.run(None, {"image": image})[0]
        
        results = []
        for box in boxes:
            # Обрезать обнаруженную область
            crop = self._crop(image, box)
            
            # Этап 2: классифицировать каждую область
            label = self.classifier.run(None, {"input": crop})[0]
            results.append({"box": box.tolist(), "label": int(label.argmax())})
        
        return results
    
    def _crop(self, image, box):
        x1, y1, x2, y2 = box.astype(int)
        return image[:, :, y1:y2, x1:x2]

pipeline = MultiModelPipeline()
```

***

## Дополнительные ресурсы

* [GitHub ONNX Runtime](https://github.com/microsoft/onnxruntime)
* [Документация ONNX Runtime](https://onnxruntime.ai/docs/)
* [Hugging Face Optimum](https://huggingface.co/docs/optimum/)
* [Зоопарк моделей ONNX](https://github.com/onnx/models) — Предварительно экспортированные модели
* [Netron](https://netron.app/) — Визуализатор моделей ONNX
* [Python API для ONNX Runtime](https://onnxruntime.ai/docs/api/python/)

***

*ONNX Runtime на Clore.ai — идеальный выбор для производственных сервисов инференса, которым необходимо обслуживать модели из разных фреймворков с максимальной эффективностью GPU.*

***

## Рекомендации по GPU для Clore.ai

| Сценарий использования           | Рекомендуемый GPU | Оценочная стоимость на Clore.ai             |
| -------------------------------- | ----------------- | ------------------------------------------- |
| Разработка/тестирование          | RTX 3090 (24 ГБ)  | $0.07–0.21/гпу/ч                            |
| Промышленный инференс            | RTX 4090 (24 ГБ)  | $0.14–0.42/гпу/ч                            |
| Развертывание в крупном масштабе | A100 80 ГБ        | [голое железо](https://clore.ai/bare-metal) |

> 💡 Все примеры в этом руководстве можно развернуть на [Clore.ai](https://clore.ai/marketplace) GPU-серверах. Просматривайте доступные GPU и арендуйте по часам — без обязательств, с полным root-доступом.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.clore.ai/guides/guides_v2-ru/gpu-devops/onnx-runtime.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
