> 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 d'inférence open-source de qualité production qui prend en charge pratiquement tous les principaux frameworks ML. Conçue pour un service à haut débit et faible latence, Triton gère PyTorch, TensorFlow, ONNX, TensorRT, OpenVINO, et plus encore — le tout depuis 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 de servir des modèles ML à grande échelle :

* **Multi-framework :** PyTorch, TensorFlow, TensorRT, ONNX, OpenVINO, backends personnalisés en Python
* **Exécution concurrente :** Plusieurs modèles, plusieurs instances par GPU
* **Regroupement dynamique (dynamic batching) :** Regroupe automatiquement les requêtes pour un meilleur débit
* **gRPC + HTTP :** Protocoles standards du secteur prêts à l'emploi
* **Métriques :** Point de terminaison de métriques compatible Prometheus
* **Répertoire de modèles :** Gestion des modèles basée sur le système de fichiers

**Ports utilisés :**

| Port | Protocole | Usage                |
| ---- | --------- | -------------------- |
| 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      | N'importe quelle NVIDIA avec CUDA 11+ | RTX 4090 / A100 |
| RAM      | 16 Go                                 | 32 Go           |
| Stockage | 20 Go                                 | 50 Go           |

{% hint style="info" %}
Triton prend aussi en charge l'inférence CPU uniquement pour les charges non-CUDA. Utilisez la `cpu-only` variante de l'image Docker pour des économies sur les tâches en lot 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 **Place de marché** et filtrez par VRAM ≥ 16 Go.
3. Sélectionnez un serveur et cliquez sur **Configurer**.
4. Définir 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éfinir les ports ouverts : `22` (SSH), `8000` (HTTP), `8001` (gRPC), `8002` (métriques).
6. Cliquez **Louez**.

{% hint style="warning" %}
Les images Docker Triton sont volumineuses (\~15–20 Go). Prévoyez 3–5 minutes pour le premier téléchargement au premier lancement. 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 répertoire de modèles

Triton charge les modèles à partir d'un **répertoire 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 (optionnelle)
│       └── model.pt
├── model_name_2/
│   ├── config.pbtxt
│   └── 1/
│       └── model.onnx
```

Chaque modèle nécessite :

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 en TorchScript

```python
import torch
import torchvision

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

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

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

### Configurer le répertoire de modèles

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

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

# Télécharger 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 en 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 conviennent pas aux backends standards (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 le CMD du Dockerfile, il démarre 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 une 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 la santé 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 une 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}")
```

***

## Monitoring avec Prometheus

Triton expose des 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 GPU
nv_gpu_utilization{gpu_uuid="..."}
# Mémoire GPU
nv_gpu_memory_used_bytes{gpu_uuid="..."}
```

***

## Configuration du regroupement 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 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 le tag tritonserver correspondant, ex. 23.10 pour CUDA 12.2
```

### Port non accessible

**Solution :** Vérifiez que les trois ports (8000, 8001, 8002) sont bien redirigés sur 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,10 $/h  | \~500 req/s      |
| RTX 4090  | 24 Go | \~0,35 $/h  | \~1500 req/s     |
| A100 40GB | 40 Go | \~0,80 $/h  | \~3000 req/s     |
| H100      | 80 Go | \~2,50 $/h  | \~8000 req/s     |

***

## Ressources utiles

* [Triton GitHub](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 de Triton](https://github.com/triton-inference-server/python_backend)
* [Analyseur de performance 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 (24GB) | \~$0.12/gpu/hr           |
| Inférence en production | RTX 4090 (24GB) | \~$0.70/gpu/hr           |
| Grands modèles (70B+)   | A100 80GB       | \~$1.20/gpu/hr           |

> 💡 Tous les exemples de ce guide peuvent être déployés sur [Clore.ai](https://clore.ai/marketplace) serveurs GPU. Parcourez les GPU disponibles et louez à l’heure — sans engagement, avec 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:

```
GET https://docs.clore.ai/guides/guides_v2-fr/mlops-et-deploiement/triton-inference-server.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
