> 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-de/gpu-devops/onnx-runtime.md).

# ONNX Runtime GPU

> **Plattformübergreifende, hardwarebeschleunigte ML-Inferenz — stellen Sie jedes Modell aus jedem Framework bereit**

ONNX Runtime (ORT) ist Microsofts Open-Source-Inferenz-Engine für ONNX-Modelle (Open Neural Network Exchange). Sie bietet hardwarebeschleunigte Inferenz über CPUs, GPUs und spezialisierte Beschleuniger hinweg über eine einheitliche API. Ganz gleich, ob Ihr Modell in PyTorch, TensorFlow, Scikit-learn oder XGBoost trainiert wurde — wenn Sie es in das ONNX-Format exportieren können, kann ORT es schneller ausführen.

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

***

## Warum ONNX Runtime?

| Funktion                       | ONNX Runtime      | TorchScript   | TensorFlow Serving |
| ------------------------------ | ----------------- | ------------- | ------------------ |
| Framework-agnostisch           | ✅                 | ❌ Nur PyTorch | ❌ Nur TF           |
| GPU-Beschleunigung             | ✅ CUDA/TensorRT   | ✅             | ✅                  |
| INT8/FP16-Quantisierung        | ✅                 | Teilweise     | Teilweise          |
| Bereitstellung für Mobile/Edge | ✅                 | Begrenzt      | Begrenzt           |
| Operator-Fusion                | ✅                 | Teilweise     | ✅                  |
| Einfache Integration           | ✅ Python/C++/Java | Python        | Python/gRPC        |

{% hint style="success" %}
**Hauptvorteil:** ONNX Runtime mit CUDA-Execution Provider liefert typischerweise **1,5–3-fache Beschleunigung** gegenüber der nativen PyTorch-Inferenz für Computer-Vision- und NLP-Modelle.
{% endhint %}

***

## Unterstützte Execution Provider

ONNX Runtime unterstützt mehrere Hardware-Backends (Execution Provider):

| Provider                    | Hardware      | Anwendungsfall          |
| --------------------------- | ------------- | ----------------------- |
| `CUDAExecutionProvider`     | NVIDIA-GPUs   | Allgemeine GPU-Inferenz |
| `TensorrtExecutionProvider` | NVIDIA-GPUs   | Maximaler Durchsatz     |
| `CPUExecutionProvider`      | CPU           | Fallback / Edge         |
| `ROCMExecutionProvider`     | AMD-GPUs      | AMD-Hardware            |
| `CoreMLExecutionProvider`   | Apple Silicon | macOS/iOS               |
| `OpenVINOExecutionProvider` | Intel         | Intel-CPUs/GPUs         |

***

## Voraussetzungen

* Clore.ai-Konto mit GPU-Miete
* Grundlegende Python-Kenntnisse
* Ein trainiertes Modell (PyTorch, TensorFlow oder vorab exportiertes ONNX)

***

## Schritt 1 — Miete eine GPU auf Clore.ai

1. Gehe zu [clore.ai](https://clore.ai) → **Marktplatz**
2. Jede NVIDIA-GPU funktioniert — von der RTX 3070 für kleine Modelle bis zur A100 für große Transformer
3. **Für Transformer-Modelle:** RTX 4090 oder A100 empfohlen
4. **Für Computer Vision:** RTX 3090 oder RTX 4090 reicht aus

***

## Schritt 2 — Stellen Sie Ihren Container bereit

ONNX Runtime hat keinen offiziellen vorgefertigten Container, aber das NVIDIA-CUDA-Base-Image ist ideal:

**Docker-Image:**

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

**Ports:**

```
22
```

**Umgebungsvariablen:**

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

{% hint style="info" %}
Alternativ verwenden Sie `pytorch/pytorch:2.11.0-cuda12.8-cudnn9-runtime` das CUDA und eine Python-Umgebung enthält, die für die ORT-Installation bereit ist.
{% endhint %}

***

## Schritt 3 — Installieren Sie ONNX Runtime mit GPU-Unterstützung

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

# Pakete aktualisieren
apt-get update && apt-get install -y \\
    python3-pip \\
    python3-dev \
    wget \
    git \
    libgomp1

# ONNX Runtime mit CUDA-Unterstützung installieren
pip install onnxruntime-gpu

# Unterstützende Pakete installieren
pip install \
    onnx \
    numpy \\
    Pillow \\
    transformers \
    torch \
    torchvision \
    fastapi \
    uvicorn

# Installation überprüfen
python3 << 'EOF'
import onnxruntime as ort
print(f"ORT-Version: {ort.__version__}")
print(f"Verfügbare Provider: {ort.get_available_providers()}")
# Sollte enthalten: CUDAExecutionProvider, TensorrtExecutionProvider, CPUExecutionProvider
EOF
```

***

## Schritt 4 — Exportieren Sie Ihr Modell nach ONNX

### PyTorch-Modellexport

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

# Beispiel: ResNet50 exportieren
model = torch.hub.load('pytorch/vision:v0.10.0', 'resnet50', pretrained=True)
model.eval()

# Dummy-Input erstellen (batch=1, RGB-Bild 224x224)
dummy_input = torch.randn(1, 3, 224, 224)

# Nach ONNX exportieren
torch.onnx.export(
    model,
    dummy_input,
    "resnet50.onnx",
    export_params=True,
    opset_version=17,              # Neueste stabile Opset verwenden
    do_constant_folding=True,      # Konstante Operationen optimieren
    input_names=["input"],
    output_names=["output"],
    dynamic_axes={
        "input": {0: "batch_size"},    # Dynamischer Batch
        "output": {0: "batch_size"}
    }
)
print("Modell erfolgreich exportiert!")

# Das exportierte Modell überprüfen
onnx_model = onnx.load("resnet50.onnx")
onnx.checker.check_model(onnx_model)
print("ONNX-Modell ist gültig!")
```

### Export mit HuggingFace Transformers

```bash
# Optimum für den HuggingFace-ONNX-Export installieren
pip install optimum[exporters]

# BERT für Textklassifizierung exportieren
optimum-cli export onnx \
    --model bert-base-uncased \
    --task text-classification \
    ./bert_onnx/

# Mit Optimierung exportieren
optimum-cli export onnx \
    --model microsoft/phi-2 \
    --task text-generation \
    --optimize O2 \
    ./phi2_onnx/
```

### Export mit ORT-Optimierung

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

# Laden und optimieren
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
)
```

***

## Schritt 5 — Führen Sie die Inferenz mit ONNX Runtime aus

### Grundlegende GPU-Inferenz

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

# Sitzung mit GPU-Execution-Providern konfigurieren
# Die Provider werden in Reihenfolge ausprobiert — zuerst CUDA, dann CPU-Fallback
providers = [
    ("CUDAExecutionProvider", {
        "device_id": 0,
        "arena_extend_strategy": "kNextPowerOfTwo",
        "gpu_mem_limit": 4 * 1024 * 1024 * 1024,  # 4GB-Grenze
        "cudnn_conv_algo_search": "EXHAUSTIVE",
        "do_copy_in_default_stream": True,
    }),
    "CPUExecutionProvider"
]

# Leistungsoptionen für die Sitzung
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

# Modell laden
session = ort.InferenceSession(
    "resnet50.onnx",
    sess_options=opts,
    providers=providers
)

print(f"Ausführung auf: {session.get_providers()}")

# Eingabe vorbereiten
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()

# Inferenz ausführen
outputs = session.run(None, {"input": img_tensor})
probabilities = outputs[0][0]
top5_idx = probabilities.argsort()[-5:][::-1]
print("Top-5-Vorhersagen:", top5_idx, probabilities[top5_idx])
```

### Batch-Inferenz für höheren Durchsatz

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

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

# GPU aufwärmen
dummy = np.random.randn(1, 3, 224, 224).astype(np.float32)
for _ in range(10):
    session.run(None, {"input": dummy})

# Batch-Größen benchmarken
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  # ms
    
    print(f"Batch {batch_size:3d}: {throughput:7.1f} img/sec, {latency:.1f}ms/batch")
```

***

## Schritt 6 — TensorRT-Execution-Provider (Maximale Leistung)

Für NVIDIA-GPUs bietet TensorRT EP eine noch bessere Leistung:

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

# Konfiguration des TensorRT-Execution-Providers
tensorrt_provider_options = {
    "trt_max_workspace_size": 4 * 1024 * 1024 * 1024,  # 4GB
    "trt_fp16_enable": True,          # FP16 für schnellere Inferenz aktivieren
    "trt_int8_enable": False,
    "trt_engine_cache_enable": True,   # Kompilierte Engines cachen
    "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("Aktiver Provider:", session.get_providers()[0])

# Der erste Durchlauf kompiliert die TensorRT-Engine (kann 1–3 Minuten dauern)
# Nachfolgende Durchläufe verwenden die zwischengespeicherte Engine und sind sehr schnell
```

{% hint style="warning" %}
**TensorRT-Engine-Kompilierung** erfolgt bei der ersten Inferenz und kann 1–5 Minuten dauern. Aktivieren Sie das Caching (`trt_engine_cache_enable: True`) damit die kompilierte Engine über Sitzungen hinweg wiederverwendet wird.
{% endhint %}

***

## Schritt 7 — INT8-Quantisierung für maximale Geschwindigkeit

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

# Dynamische INT8-Quantisierung (keine Kalibrierdaten erforderlich)
quantize_dynamic(
    model_input="resnet50.onnx",
    model_output="resnet50_int8_dynamic.onnx",
    weight_type=QuantType.QInt8
)

# Statische INT8-Quantisierung (erfordert Kalibrierdaten)
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 Kalibrierbilder laden
        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
)
```

***

## Schritt 8 — Erstellen Sie eine Inference-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="ONNX Runtime Inference API")

# Modell beim Start laden
session = ort.InferenceSession(
    "resnet50.onnx",
    providers=["CUDAExecutionProvider", "CPUExecutionProvider"]
)

# ImageNet-Klassenlabels laden
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 testen
curl -X POST "http://localhost:8080/predict" \
    -H "accept: application/json" \
    -F "file=@test_image.jpg"
```

***

## Schritt 9 — GPU-Auslastung überwachen

```bash
# Echtzeit-GPU-Überwachung während der Inferenz
watch -n 0.5 nvidia-smi

# Oder nvitop für eine bessere Oberfläche verwenden
pip install nvitop
nvitop
```

***

## Leistungsbenchmarks

| Modell    | GPU      | Provider      | Durchsatz (Inf./s) |
| --------- | -------- | ------------- | ------------------ |
| 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              |

***

## Fehlerbehebung

### CUDA-Provider nicht verfügbar

```bash
# Prüfen, ob CUDA-ORT installiert ist (nicht nur CPU-Version)
pip uninstall onnxruntime
pip install onnxruntime-gpu

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

### TensorRT-Kompilierfehler

```bash
# TensorRT-Versionskompatibilität prüfen
python3 -c "import tensorrt; print(tensorrt.__version__)"

# Stattdessen CUDA EP verwenden
providers = ["CUDAExecutionProvider"]  # TensorRT EP überspringen
```

### Shape-Mismatch-Fehler

```python
# Eingabe-/Ausgabeformen des Modells prüfen
for input in session.get_inputs():
    print(f"Eingabe: {input.name}, Shape: {input.shape}, Typ: {input.type}")

for output in session.get_outputs():
    print(f"Ausgabe: {output.name}, Shape: {output.shape}, Typ: {output.type}")
```

***

## Fortgeschritten: Multi-Modell-Pipeline

```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:
        # Phase 1: Objekterkennung
        boxes = self.detector.run(None, {"image": image})[0]
        
        results = []
        for box in boxes:
            # Erkannten Bereich zuschneiden
            crop = self._crop(image, box)
            
            # Phase 2: Jeden Bereich klassifizieren
            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()
```

***

## Zusätzliche Ressourcen

* [ONNX Runtime GitHub](https://github.com/microsoft/onnxruntime)
* [ONNX Runtime-Dokumentation](https://onnxruntime.ai/docs/)
* [Hugging Face Optimum](https://huggingface.co/docs/optimum/)
* [ONNX-Modellzoo](https://github.com/onnx/models) — Vorexportierte Modelle
* [Netron](https://netron.app/) — ONNX-Modellvisualisierer
* [ONNX Runtime Python-API](https://onnxruntime.ai/docs/api/python/)

***

*ONNX Runtime auf Clore.ai ist die ideale Wahl für Produktions-Inferenzdienste, die Modelle aus verschiedenen Frameworks mit maximaler GPU-Effizienz bereitstellen müssen.*

***

## GPU-Empfehlungen für Clore.ai

| Anwendungsfall                   | Empfohlene GPU   | Geschätzte Kosten bei Clore.ai            |
| -------------------------------- | ---------------- | ----------------------------------------- |
| Entwicklung/Testen               | RTX 3090 (24 GB) | 0,07–0,21 $/GPU/Stunde                    |
| Produktions-Inferenz             | RTX 4090 (24 GB) | 0,14–0,42 $/GPU/Stunde                    |
| Bereitstellung im großen Maßstab | A100 80GB        | [Bare Metal](https://clore.ai/bare-metal) |

> 💡 Alle Beispiele in diesem Leitfaden können bereitgestellt werden auf [Clore.ai](https://clore.ai/marketplace) GPU-Servern. Durchsuchen Sie verfügbare GPUs und mieten Sie stundenweise — keine Verpflichtungen, voller Root-Zugriff.


---

# 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-de/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.
