> 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/mlops-et-deploiement/triton-inference-server.md).

# Serveur d'inférence Triton

**NVIDIA Triton Inference Server** est une plateforme de déploiement d'inférence open source de qualité production qui prend en charge pratiquement tous les principaux frameworks de ML. Conçu pour un service à haut débit et à faible latence, Triton gère PyTorch, TensorFlow, ONNX, TensorRT, OpenVINO, et plus encore — le tout à partir d'un seul processus serveur. Déployez-le sur le cloud GPU de Clore.ai pour une infrastructure d'inférence évolutive et rentable.

***

## Qu'est-ce que Triton Inference Server ?

Triton est la réponse de NVIDIA au défi du déploiement de modèles de ML à grande échelle :

* **Multi-framework :** PyTorch, TensorFlow, TensorRT, ONNX, OpenVINO, backends Python personnalisés
* **Exécution concurrente :** Plusieurs modèles, plusieurs instances par GPU
* **Batching dynamique :** Regroupe automatiquement les requêtes pour un débit plus élevé
* **gRPC + HTTP :** Protocoles standard du secteur prêts à l'emploi
* **Métriques :** Point de terminaison de métriques compatible Prometheus
* **Dépôt de modèles :** Gestion des modèles basée sur le système de fichiers

**Ports utilisés :**

| Port | Protocole | Objectif             |
| ---- | --------- | -------------------- |
| 8000 | HTTP      | API d'inférence REST |
| 8001 | gRPC      | API d'inférence gRPC |
| 8002 | HTTP      | Métriques Prometheus |

***

## Prérequis

| Exigence | Minimum                          | Recommandé      |
| -------- | -------------------------------- | --------------- |
| VRAM GPU | 8 Go                             | 16–24 Go        |
| GPU      | Toute carte NVIDIA avec CUDA 11+ | RTX 4090 / A100 |
| RAM      | 16 Go                            | 32 Go           |
| Stockage | 20 Go                            | 50 Go           |

{% hint style="info" %}
Triton prend également en charge l'inférence uniquement CPU pour les charges de travail non CUDA. Utilisez la `cpu-only` variante de l'image Docker pour réduire les coûts sur les tâches par lots qui ne nécessitent pas de GPU.
{% endhint %}

***

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

1. Connectez-vous à [clore.ai](https://clore.ai).
2. Cliquez sur **Place de marché** et filtrez par VRAM ≥ 16 Go.
3. Sélectionnez un serveur et cliquez sur **Configurer**.
4. Définissez l'image Docker : **`nvcr.io/nvidia/tritonserver:24.01-py3`**
   * (Remplacez `24.01` par la version la plus récente — consultez [le catalogue NGC](https://catalog.ngc.nvidia.com/orgs/nvidia/containers/tritonserver))
5. Définissez les ports ouverts : `22` (SSH), `8000` (HTTP), `8001` (gRPC), `8002` (métriques).
6. Cliquez sur **Louer**.

{% hint style="warning" %}
Les images Docker Triton sont volumineuses (\~15–20 Go). Prévoyez 3 à 5 minutes pour le premier téléchargement au lancement initial. Les démarrages suivants sont rapides.
{% endhint %}

***

## Étape 2 — Dockerfile personnalisé (avec SSH)

L'image officielle Triton n'inclut pas de serveur SSH. Utilisez ce Dockerfile :

```dockerfile
FROM nvcr.io/nvidia/tritonserver:24.01-py3

RUN apt-get update && apt-get install -y \
    openssh-server \
    wget curl \\
    && rm -rf /var/lib/apt/lists/*

# Configurer SSH
RUN mkdir /var/run/sshd && \
    echo 'root:clore123' | chpasswd && \\
    sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

# Installer la bibliothèque cliente Python
RUN pip install tritonclient[all] numpy Pillow

RUN mkdir -p /models

EXPOSE 22 8000 8001 8002

CMD service ssh start && \\
    tritonserver \\
        --model-repository=/models \\
        --log-verbose=0 \\
        --http-port=8000 \\
        --grpc-port=8001 \\
        --metrics-port=8002
```

***

## Étape 3 — Comprendre le dépôt de modèles

Triton charge les modèles depuis un **dépôt de modèles** — un répertoire avec une structure spécifique :

```
/models/
├── model_name_1/
│   ├── config.pbtxt          # Configuration du modèle
│   ├── 1/                    # Version 1
│   │   └── model.pt          # Fichier du modèle
│   └── 2/                    # Version 2 (facultatif)
│       └── model.pt
├── model_name_2/
│   ├── config.pbtxt
│   └── 1/
│       └── model.onnx
```

Chaque modèle a besoin de :

1. Un répertoire portant le nom du modèle
2. Un `config.pbtxt` fichier de configuration
3. Au moins un sous-répertoire de version (par ex., `1/`) contenant le fichier du modèle

***

## Étape 4 — Déployer un modèle PyTorch

### Exporter le modèle vers TorchScript

```python
import torch
import torchvision

# Charger un ResNet50 pré-entraîné
model = torchvision.models.resnet50(pretrained=True)
model.eval()

# Exporter vers TorchScript
example_input = torch.randn(1, 3, 224, 224)
traced_model = torch.jit.trace(model, example_input)

# Enregistrer
traced_model.save("/tmp/resnet50.pt")
print("Modèle exporté avec succès")
```

### Configurer le dépôt de modèles

```bash
# Connexion SSH à votre instance Clore.ai
ssh root@<clore-host> -p <port>

# Créer la structure de répertoires
mkdir -p /models/resnet50/1

# Importer le modèle
# (depuis votre machine locale)
scp -P <port> /tmp/resnet50.pt root@<clore-host>:/models/resnet50/1/model.pt
```

### Créer config.pbtxt

```bash
cat > /models/resnet50/config.pbtxt << 'EOF'
name: "resnet50"
platform: "pytorch_libtorch"
max_batch_size: 32

input [
  {
    name: "input__0"
    data_type: TYPE_FP32
    dims: [3, 224, 224]
  }
]

output [
  {
    name: "output__0"
    data_type: TYPE_FP32
    dims: [1000]
  }
]

dynamic_batching {
  preferred_batch_size: [8, 16, 32]
  max_queue_delay_microseconds: 100
}

instance_group [
  {
    count: 2
    kind: KIND_GPU
    gpus: [0]
  }
]
EOF
```

***

## Étape 5 — Déployer un modèle ONNX

### Exporter vers ONNX

```python
import torch
import torchvision
import torch.onnx

model = torchvision.models.resnet50(pretrained=True)
model.eval()

dummy_input = torch.randn(1, 3, 224, 224)

torch.onnx.export(
    model,
    dummy_input,
    "/tmp/resnet50.onnx",
    opset_version=13,
    input_names=["images"],
    output_names=["logits"],
    dynamic_axes={
        "images": {0: "batch_size"},
        "logits": {0: "batch_size"}
    }
)
```

### Configuration ONNX

```bash
mkdir -p /models/resnet50_onnx/1
scp -P <port> /tmp/resnet50.onnx root@<clore-host>:/models/resnet50_onnx/1/model.onnx

cat > /models/resnet50_onnx/config.pbtxt << 'EOF'
name: "resnet50_onnx"
platform: "onnxruntime_onnx"
max_batch_size: 32

input [
  {
    name: "images"
    data_type: TYPE_FP32
    dims: [3, 224, 224]
  }
]

output [
  {
    name: "logits"
    data_type: TYPE_FP32
    dims: [1000]
  }
]

dynamic_batching {
  preferred_batch_size: [8, 16, 32]
  max_queue_delay_microseconds: 100
}
EOF
```

***

## Étape 6 — Déployer un backend Python personnalisé

Pour les modèles qui ne rentrent pas dans les backends standard (prétraitement personnalisé, logique d'ensemble) :

```bash
mkdir -p /models/custom_model/1

cat > /models/custom_model/1/model.py << 'EOF'
import triton_python_backend_utils as pb_utils
import numpy as np
import torch

class TritonPythonModel:
    def initialize(self, args):
        self.model = torch.nn.Linear(10, 5).cuda()
        self.model.eval()
    
    def execute(self, requests):
        responses = []
        for request in requests:
            input_tensor = pb_utils.get_input_tensor_by_name(request, "INPUT")
            input_np = input_tensor.as_numpy()
            
            with torch.no_grad():
                inp = torch.from_numpy(input_np).float().cuda()
                out = self.model(inp).cpu().numpy()
            
            output_tensor = pb_utils.Tensor("OUTPUT", out.astype(np.float32))
            responses.append(pb_utils.InferenceResponse(output_tensors=[output_tensor]))
        
        return responses
    
    def finalize(self):
        pass
EOF

cat > /models/custom_model/config.pbtxt << 'EOF'
name: "custom_model"
backend: "python"
max_batch_size: 64

input [
  {
    name: "INPUT"
    data_type: TYPE_FP32
    dims: [10]
  }
]

output [
  {
    name: "OUTPUT"
    data_type: TYPE_FP32
    dims: [5]
  }
]
EOF
```

***

## Étape 7 — Démarrer Triton et tester

### Démarrer le serveur Triton

```bash
# Démarrer (si vous utilisez la commande CMD du Dockerfile, il se lance automatiquement)
tritonserver \\
    --model-repository=/models \\
    --http-port=8000 \\
    --grpc-port=8001 \\
    --metrics-port=8002 \\
    --log-verbose=0 &

# Attendre que le serveur soit prêt
sleep 5
curl -s http://localhost:8000/v2/health/ready
# Attendu : {"live": true}
```

### Vérifier les modèles disponibles

```bash
curl http://<clore-host>:<public-8000>/v2/models
```

### Exécuter l'inférence via HTTP

```python
import tritonclient.http as httpclient
import numpy as np

client = httpclient.InferenceServerClient(
    url="<clore-host>:<public-port-8000>",
    ssl=False
)

# Vérifier l'état du serveur
print("Serveur prêt :", client.is_server_ready())
print("Modèle prêt :", client.is_model_ready("resnet50_onnx"))

# Créer l'entrée
image = np.random.rand(1, 3, 224, 224).astype(np.float32)
input_tensor = httpclient.InferInput("images", image.shape, "FP32")
input_tensor.set_data_from_numpy(image)

# Exécuter l'inférence
outputs = [httpclient.InferRequestedOutput("logits")]
response = client.infer("resnet50_onnx", [input_tensor], outputs=outputs)

logits = response.as_numpy("logits")
predicted_class = np.argmax(logits[0])
print(f"Classe prédite : {predicted_class}")
```

### Exécuter l'inférence via gRPC

```python
import tritonclient.grpc as grpcclient
import numpy as np

client = grpcclient.InferenceServerClient(
    url="<clore-host>:<public-port-8001>"
)

image = np.random.rand(1, 3, 224, 224).astype(np.float32)
input_tensor = grpcclient.InferInput("images", image.shape, "FP32")
input_tensor.set_data_from_numpy(image)

outputs = [grpcclient.InferRequestedOutput("logits")]
response = client.infer("resnet50_onnx", [input_tensor], outputs=outputs)

logits = response.as_numpy("logits")
print(f"Forme de la sortie : {logits.shape}")
```

***

## Surveillance avec Prometheus

Triton expose les métriques sur le port 8002 :

```bash
curl http://<clore-host>:<public-port-8002>/metrics
```

Métriques clés :

```
# Débit d'inférence
nv_inference_request_success{model="resnet50_onnx", version="1"}
# Temps moyen d'inférence
nv_inference_compute_infer_duration_us{model="resnet50_onnx", version="1"}
# Utilisation du GPU
nv_gpu_utilization{gpu_uuid="..."}
# Mémoire GPU
nv_gpu_memory_used_bytes{gpu_uuid="..."}
```

***

## Configuration du batching dynamique

```protobuf
dynamic_batching {
  preferred_batch_size: [4, 8, 16, 32]
  max_queue_delay_microseconds: 5000
  preserve_ordering: true
  
  priority_levels: 3
  default_priority_level: 2
  default_queue_policy {
    timeout_action: REJECT
    default_timeout_microseconds: 10000
    allow_timeout_override: true
    max_queue_size: 100
  }
}
```

***

## Dépannage

### Échec du chargement du modèle

```
Échec du chargement du modèle : fichier du modèle introuvable
```

**Solution :** Vérifiez la structure des répertoires et les permissions :

```bash
ls -la /models/resnet50/1/
# Doit contenir model.pt (PyTorch) ou model.onnx (ONNX)
chmod -R 755 /models/
```

### Incompatibilité CUDA

**Solution :** Faites correspondre la version de l'image Triton à votre pilote CUDA :

```bash
nvidia-smi  # Notez la version CUDA
# Utilisez la balise tritonserver correspondante, par ex. 23.10 pour CUDA 12.2
```

### Port inaccessible

**Solution :** Vérifiez que les trois ports (8000, 8001, 8002) sont transférés dans Clore.ai. Testez chacun :

```bash
curl http://<host>:<port>/v2/health/live
```

### OOM lors du chargement du modèle

**Solution :** Réduisez le nombre d'instances ou utilisez des instances CPU pour certains modèles :

```protobuf
instance_group [
  {
    count: 1       # Réduire par rapport à la valeur par défaut
    kind: KIND_GPU
  }
]
```

***

## Estimation des coûts

| GPU        | VRAM  | Prix estimé                               | Débit (ResNet50) |
| ---------- | ----- | ----------------------------------------- | ---------------- |
| RTX 3080   | 10 Go | 0,05–0,19 $/h                             | \~500 req/sec    |
| RTX 4090   | 24 Go | 0,14–0,42 $/h                             | \~1500 req/sec   |
| A100 40 Go | 40 Go | [bare metal](https://clore.ai/bare-metal) | \~3000 req/sec   |
| H100       | 80 Go | \~1,04 $/h                                | \~8000 req/sec   |

***

## Ressources utiles

* [GitHub de Triton](https://github.com/triton-inference-server/server)
* [Registre de conteneurs NGC](https://catalog.ngc.nvidia.com/orgs/nvidia/containers/tritonserver)
* [Bibliothèques clientes Triton](https://github.com/triton-inference-server/client)
* [Référence de configuration des modèles Triton](https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/user_guide/model_configuration.html)
* [Backend Python Triton](https://github.com/triton-inference-server/python_backend)
* [Analyseur de performances Triton](https://github.com/triton-inference-server/client/blob/main/src/c%2B%2B/perf_analyzer/README.md)

***

## 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 en production | RTX 4090 (24 Go) | 0,14–0,42 $/gpu/h                         |
| Grands modèles (70B+)   | 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/mlops-et-deploiement/triton-inference-server.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.
