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

# ONNX Runtime GPU

> **Inférence ML multiplateforme, accélérée par le matériel — déployez n’importe quel modèle depuis n’importe quel framework**

ONNX Runtime (ORT) est le moteur d’inférence open source de Microsoft pour les modèles ONNX (Open Neural Network Exchange). Il fournit une inférence accélérée par le matériel sur les CPU, les GPU et les accélérateurs spécialisés via une API unifiée. Que votre modèle ait été entraîné dans PyTorch, TensorFlow, Scikit-learn ou XGBoost — si vous pouvez l’exporter au format ONNX, ORT peut l’exécuter plus rapidement.

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

***

## Pourquoi ONNX Runtime ?

| Fonctionnalité                   | ONNX Runtime      | TorchScript          | TensorFlow Serving |
| -------------------------------- | ----------------- | -------------------- | ------------------ |
| Indépendant du framework         | ✅                 | ❌ PyTorch uniquement | ❌ TF uniquement    |
| Accélération GPU                 | ✅ CUDA/TensorRT   | ✅                    | ✅                  |
| Quantification INT8/FP16         | ✅                 | Partiel              | Partiel            |
| Déploiement mobile/en périphérie | ✅                 | Limité               | Limité             |
| Fusion d’opérateurs              | ✅                 | Partiel              | ✅                  |
| Intégration facile               | ✅ Python/C++/Java | Python               | Python/gRPC        |

{% hint style="success" %}
**Avantage clé :** ONNX Runtime avec le fournisseur d’exécution CUDA offre généralement **un gain de vitesse de 1,5 à 3x** par rapport à l’inférence PyTorch native pour les modèles de vision par ordinateur et de NLP.
{% endhint %}

***

## Fournisseurs d’exécution pris en charge

ONNX Runtime prend en charge plusieurs backends matériels (fournisseurs d’exécution) :

| Fournisseur                 | Matériel      | Cas d’utilisation      |
| --------------------------- | ------------- | ---------------------- |
| `CUDAExecutionProvider`     | GPU NVIDIA    | Inférence GPU générale |
| `TensorrtExecutionProvider` | GPU NVIDIA    | Débit maximal          |
| `CPUExecutionProvider`      | CPU           | Secours / périphérie   |
| `ROCMExecutionProvider`     | GPU AMD       | Matériel AMD           |
| `CoreMLExecutionProvider`   | Apple Silicon | macOS/iOS              |
| `OpenVINOExecutionProvider` | Intel         | CPU/GPU Intel          |

***

## Prérequis

* Compte Clore.ai avec location de GPU
* Connaissances de base en Python
* Un modèle entraîné (PyTorch, TensorFlow ou ONNX déjà exporté)

***

## Étape 1 — Louer un GPU sur Clore.ai

1. Accédez à [clore.ai](https://clore.ai) → **Place de marché**
2. N’importe quel GPU NVIDIA fonctionne — d’une RTX 3070 pour les petits modèles à une A100 pour les grands transformeurs
3. **Pour les modèles de transformeurs :** RTX 4090 ou A100 recommandée
4. **Pour la vision par ordinateur :** Une RTX 3090 ou RTX 4090 suffit

***

## Étape 2 — Déployer votre conteneur

ONNX Runtime n’a pas de conteneur officiel précompilé, mais l’image de base NVIDIA CUDA est idéale :

**Image Docker :**

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

**Ports :**

```
22
```

**Variables d'environnement :**

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

{% hint style="info" %}
Sinon, utilisez `pytorch/pytorch:2.11.0-cuda12.8-cudnn9-runtime` qui inclut CUDA et un environnement Python prêt pour l’installation d’ORT.
{% endhint %}

***

## Étape 3 — Installer ONNX Runtime avec prise en charge GPU

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

# Mettre à jour les paquets
apt-get update && apt-get install -y \\
    python3-pip \\
    python3-dev \\
    wget \
    git \
    libgomp1

# Installer ONNX Runtime avec prise en charge CUDA
pip install onnxruntime-gpu

# Installer les paquets de support
pip install \\
    onnx \\
    numpy \
    Pillow \
    transformers \\
    torch \
    torchvision \\
    fastapi \
    uvicorn

# Vérifier l'installation
python3 << 'EOF'
import onnxruntime as ort
print(f"Version ORT : {ort.__version__}")
print(f"Fournisseurs disponibles : {ort.get_available_providers()}")
# Doit inclure : CUDAExecutionProvider, TensorrtExecutionProvider, CPUExecutionProvider
EOF
```

***

## Étape 4 — Exporter votre modèle au format ONNX

### Exportation d’un modèle PyTorch

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

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

# Créer une entrée factice (batch=1, image RGB 224x224)
dummy_input = torch.randn(1, 3, 224, 224)

# Exporter au format ONNX
torch.onnx.export(
    model,
    dummy_input,
    "resnet50.onnx",
    export_params=True,
    opset_version=17,              # Utiliser l’opset stable le plus récent
    do_constant_folding=True,      # Optimiser les opérateurs constants
    input_names=["input"],
    output_names=["output"],
    dynamic_axes={
        "input": {0: "batch_size"},    # Batch dynamique
        "output": {0: "batch_size"}
    }
)
print("Modèle exporté avec succès !")

# Vérifier le modèle exporté
onnx_model = onnx.load("resnet50.onnx")
onnx.checker.check_model(onnx_model)
print("Le modèle ONNX est valide !")
```

### Exportation HuggingFace Transformers

```bash
# Installer optimum pour l’export ONNX de HuggingFace
pip install optimum[exporters]

# Exporter BERT pour la classification de texte
optimum-cli export onnx \\
    --model bert-base-uncased \\
    --task text-classification \\
    ./bert_onnx/

# Exporter avec optimisation
optimum-cli export onnx \\
    --model microsoft/phi-2 \\
    --task text-generation \\
    --optimize O2 \\
    ./phi2_onnx/
```

### Exporter avec l’optimisation ORT

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

# Charger et optimiser
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
)
```

***

## Étape 5 — Exécuter l’inférence avec ONNX Runtime

### Inférence GPU de base

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

# Configurer la session avec les fournisseurs d’exécution GPU
# Les fournisseurs sont essayés dans l’ordre — CUDA d’abord, puis repli sur CPU
providers = [
    ("CUDAExecutionProvider", {
        "device_id": 0,
        "arena_extend_strategy": "kNextPowerOfTwo",
        "gpu_mem_limit": 4 * 1024 * 1024 * 1024,  # limite de 4 Go
        "cudnn_conv_algo_search": "EXHAUSTIVE",
        "do_copy_in_default_stream": True,
    }),
    "CPUExecutionProvider"
]

# Options de session pour les performances
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

# Charger le modèle
session = ort.InferenceSession(
    "resnet50.onnx",
    sess_options=opts,
    providers=providers
)

print(f"Exécution sur : {session.get_providers()}")

# Préparer l’entrée
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()

# Exécuter l’inférence
outputs = session.run(None, {"input": img_tensor})
probabilities = outputs[0][0]
top5_idx = probabilities.argsort()[-5:][::-1]
print("Top 5 prédictions :", top5_idx, probabilities[top5_idx])
```

### Inférence par lot pour le débit

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

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

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

# Mesurer les tailles de lot
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"Lot {batch_size:3d} : {throughput:7.1f} img/s, {latency:.1f} ms/lot")
```

***

## Étape 6 — Fournisseur d’exécution TensorRT (performances maximales)

Pour les GPU NVIDIA, TensorRT EP offre des performances encore meilleures :

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

# Configuration du fournisseur d’exécution TensorRT
tensorrt_provider_options = {
    "trt_max_workspace_size": 4 * 1024 * 1024 * 1024,  # 4 Go
    "trt_fp16_enable": True,          # Activer FP16 pour une inférence plus rapide
    "trt_int8_enable": False,
    "trt_engine_cache_enable": True,   # Mettre en cache les moteurs compilés
    "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("Fournisseur actif :", session.get_providers()[0])

# La première exécution compile le moteur TensorRT (peut prendre 1 à 3 minutes)
# Les exécutions suivantes utilisent le moteur en cache et sont très rapides
```

{% hint style="warning" %}
**Compilation du moteur TensorRT** se produit lors de la première inférence et peut prendre 1 à 5 minutes. Activez la mise en cache (`trt_engine_cache_enable: True`) afin que le moteur compilé soit réutilisé entre les sessions.
{% endhint %}

***

## Étape 7 — Quantification INT8 pour une vitesse maximale

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

# Quantification dynamique INT8 (aucune donnée d’étalonnage requise)
quantize_dynamic(
    model_input="resnet50.onnx",
    model_output="resnet50_int8_dynamic.onnx",
    weight_type=QuantType.QInt8
)

# Quantification statique INT8 (nécessite des données d’étalonnage)
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):
        # Charger 100 images d’étalonnage
        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
)
```

***

## Étape 8 — Construire une API d’inférence

```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 d’inférence ONNX Runtime")

# Charger le modèle au démarrage
session = ort.InferenceSession(
    "resnet50.onnx",
    providers=["CUDAExecutionProvider", "CPUExecutionProvider"]
)

# Charger les étiquettes de classes 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 &

# Tester l'API
curl -X POST "http://localhost:8080/predict" \\
    -H "accept: application/json" \\
    -F "file=@test_image.jpg"
```

***

## Étape 9 — Surveiller l’utilisation du GPU

```bash
# Surveillance GPU en temps réel pendant l’inférence
watch -n 0.5 nvidia-smi

# Ou utilisez nvitop pour une meilleure interface
pip install nvitop
nvitop
```

***

## Benchmarks de performance

| Modèle    | GPU      | Fournisseur   | Débit (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         |

***

## Dépannage

### Fournisseur CUDA non disponible

```bash
# Vérifier que CUDA ORT est installé (et non la version CPU uniquement)
pip uninstall onnxruntime
pip install onnxruntime-gpu

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

### Erreurs de compilation TensorRT

```bash
# Vérifier la compatibilité de la version TensorRT
python3 -c "import tensorrt; print(tensorrt.__version__)"

# Utiliser plutôt CUDA EP
providers = ["CUDAExecutionProvider"]  # Ignorer TensorRT EP
```

### Erreurs de discordance de forme

```python
# Vérifier les formes d’entrée/sortie du modèle
for input in session.get_inputs():
    print(f"Entrée : {input.name}, forme : {input.shape}, type : {input.type}")

for output in session.get_outputs():
    print(f"Sortie : {output.name}, forme : {output.shape}, type : {output.type}")
```

***

## Avancé : pipeline multi-modèles

```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:
        # Étape 1 : détection d’objets
        boxes = self.detector.run(None, {"image": image})[0]
        
        results = []
        for box in boxes:
            # Recadrer la région détectée
            crop = self._crop(image, box)
            
            # Étape 2 : classifier chaque région
            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()
```

***

## Ressources supplémentaires

* [GitHub d’ONNX Runtime](https://github.com/microsoft/onnxruntime)
* [Documentation ONNX Runtime](https://onnxruntime.ai/docs/)
* [Optimum de Hugging Face](https://huggingface.co/docs/optimum/)
* [Zoo de modèles ONNX](https://github.com/onnx/models) — Modèles préexportés
* [Netron](https://netron.app/) — visualiseur de modèles ONNX
* [API Python d’ONNX Runtime](https://onnxruntime.ai/docs/api/python/)

***

*ONNX Runtime sur Clore.ai est le choix idéal pour les services d’inférence de production qui doivent servir des modèles issus de différents frameworks avec une efficacité GPU maximale.*

***

## Recommandations GPU Clore.ai

| Cas d’utilisation            | GPU recommandé   | Coût estimé sur Clore.ai                  |
| ---------------------------- | ---------------- | ----------------------------------------- |
| Développement/Test           | RTX 3090 (24 Go) | 0,07–0,21 $/gpu/h                         |
| Inférence de production      | RTX 4090 (24 Go) | 0,14–0,42 $/gpu/h                         |
| Déploiement à grande échelle | A100 80 Go       | [bare metal](https://clore.ai/bare-metal) |

> 💡 Tous les exemples de ce guide peuvent être déployés sur [Clore.ai](https://clore.ai/marketplace) des serveurs GPU. Parcourez les GPU disponibles et louez à l'heure — sans engagement, accès root complet.


---

# 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-fr/devops-gpu/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.
