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

# Triton Inference Server

**Сервер инференса NVIDIA Triton** — это платформа с открытым исходным кодом для инференса промышленного уровня, поддерживающая практически все основные ML-фреймворки. Triton, созданный для обслуживания с высокой пропускной способностью и низкой задержкой, работает с PyTorch, TensorFlow, ONNX, TensorRT, OpenVINO и другими — все из одного серверного процесса. Разверните его в GPU-облаке Clore.ai для масштабируемой и экономичной инфраструктуры инференса.

***

## Что такое Triton Inference Server?

Triton — это ответ NVIDIA на задачу масштабного обслуживания ML-моделей:

* **Мультифреймворк:** PyTorch, TensorFlow, TensorRT, ONNX, OpenVINO, пользовательские Python backend'ы
* **Параллельное выполнение:** Несколько моделей, несколько экземпляров на GPU
* **Динамическое пакетирование:** Автоматически объединяет запросы в пакеты для большей пропускной способности
* **gRPC + HTTP:** Стандартные промышленные протоколы из коробки
* **Метрики:** Конечная точка метрик, совместимая с Prometheus
* **Репозиторий моделей:** Управление моделями на основе файловой системы

**Используемые порты:**

| Порт | Протокол | Назначение             |
| ---- | -------- | ---------------------- |
| 8000 | HTTP     | REST API для инференса |
| 8001 | gRPC     | gRPC API для инференса |
| 8002 | HTTP     | Метрики Prometheus     |

***

## Требования

| Требование | Минимум                 | Рекомендуется   |
| ---------- | ----------------------- | --------------- |
| VRAM GPU   | 8 ГБ                    | 16–24 ГБ        |
| GPU        | Любая NVIDIA с CUDA 11+ | RTX 4090 / A100 |
| ОЗУ        | 16 ГБ                   | 32 ГБ           |
| Хранилище  | 20 ГБ                   | 50 ГБ           |

{% hint style="info" %}
Triton также поддерживает инференс только на CPU для задач без CUDA. Используйте `вариант только для CPU` образа Docker для экономии средств на пакетных заданиях, которым не требуется GPU.
{% endhint %}

***

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

1. Войдите в [маркетплейсе clore.ai](https://clore.ai).
2. Нажмите **Маркетплейс** и отфильтруйте по VRAM ≥ 16 ГБ.
3. Выберите сервер и нажмите **Настроить**.
4. Установите Docker-образ: **`nvcr.io/nvidia/tritonserver:24.01-py3`**
   * (Замените `24.01` на последнюю версию — проверьте [каталог NGC](https://catalog.ngc.nvidia.com/orgs/nvidia/containers/tritonserver))
5. Откройте порты: `22` (SSH), `8000` (HTTP), `8001` (gRPC), `8002` (метрики).
6. Нажмите **Аренда**.

{% hint style="warning" %}
Образы Triton Docker большие (\~15–20 ГБ). При первом запуске дайте 3–5 минут на начальную загрузку. Последующие запуски будут быстрыми.
{% endhint %}

***

## Шаг 2 — Пользовательский Dockerfile (с SSH)

Официальный образ Triton не включает SSH-сервер. Используйте этот 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/*

# Настройка SSH
RUN mkdir /var/run/sshd && \\
    echo 'root:clore123' | chpasswd && \\
    sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

# Установите клиентскую библиотеку 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
```

***

## Шаг 3 — Поймите структуру репозитория моделей

Triton загружает модели из **репозитория моделей** — каталога со специальной структурой:

```
/models/
├── model_name_1/
│   ├── config.pbtxt          # Конфигурация модели
│   ├── 1/                    # Версия 1
│   │   └── model.pt          # Файл модели
│   └── 2/                    # Версия 2 (необязательно)
│       └── model.pt
├── model_name_2/
│   ├── config.pbtxt
│   └── 1/
│       └── model.onnx
```

Каждой модели требуется:

1. Каталог с именем модели
2. Один `config.pbtxt` файл конфигурации
3. Как минимум один подкаталог версии (например, `1/`) с файлом модели

***

## Шаг 4 — Разверните модель PyTorch

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

```python
import torch
import torchvision

# Загрузить предварительно обученную ResNet50
model = torchvision.models.resnet50(pretrained=True)
model.eval()

# Экспортировать в TorchScript
example_input = torch.randn(1, 3, 224, 224)
traced_model = torch.jit.trace(model, example_input)

# Сохранить
traced_model.save("/tmp/resnet50.pt")
print("Модель успешно экспортирована")
```

### Настройка репозитория моделей

```bash
# Подключитесь по SSH к вашему экземпляру Clore.ai
ssh root@<clore-host> -p <port>

# Создайте структуру каталогов
mkdir -p /models/resnet50/1

# Загрузите модель
# (с вашего локального компьютера)
scp -P <port> /tmp/resnet50.pt root@<clore-host>:/models/resnet50/1/model.pt
```

### Создайте 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
```

***

## Шаг 5 — Разверните модель ONNX

### Экспорт в 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"}
    }
)
```

### Конфигурация 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
```

***

## Шаг 6 — Разверните пользовательский Python backend

Для моделей, которые не подходят для стандартных backend'ов (пользовательская предварительная обработка, логика ансамбля):

```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
```

***

## Шаг 7 — Запустите Triton и проверьте

### Запустить Triton Server

```bash
# Запуск (если используется CMD из Dockerfile, он стартует автоматически)
tritonserver \\
    --model-repository=/models \\
    --http-port=8000 \\
    --grpc-port=8001 \\
    --metrics-port=8002 \\
    --log-verbose=0 &

# Подождите, пока сервер будет готов
sleep 5
curl -s http://localhost:8000/v2/health/ready
# Ожидается: {"live": true}
```

### Проверить доступные модели

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

### Выполнить инференс через HTTP

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

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

# Проверка состояния сервера
print("Сервер готов:", client.is_server_ready())
print("Модель готова:", client.is_model_ready("resnet50_onnx"))

# Создать входные данные
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)

# Запуск инференции
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"Предсказанный класс: {predicted_class}")
```

### Выполнить инференс через 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"Форма выхода: {logits.shape}")
```

***

## Мониторинг с помощью Prometheus

Triton предоставляет метрики на порту 8002:

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

Основные метрики:

```
# Пропускная способность инференса
nv_inference_request_success{model="resnet50_onnx", version="1"}
# Среднее время инференса
nv_inference_compute_infer_duration_us{model="resnet50_onnx", version="1"}
# Использование GPU
nv_gpu_utilization{gpu_uuid="..."}
# Память GPU
nv_gpu_memory_used_bytes{gpu_uuid="..."}
```

***

## Конфигурация динамической пакетной обработки

```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
  }
}
```

***

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

### Сбой загрузки модели

```
Не удалось загрузить модель: не удалось найти файл модели
```

**Решение:** Проверьте структуру каталогов и права доступа:

```bash
ls -la /models/resnet50/1/
# Должен содержать model.pt (PyTorch) или model.onnx (ONNX)
chmod -R 755 /models/
```

### Несовместимость CUDA

**Решение:** Сопоставьте версию образа Triton с вашим драйвером CUDA:

```bash
nvidia-smi  # Обратите внимание на версию CUDA
# Используйте соответствующий тег tritonserver, например 23.10 для CUDA 12.2
```

### Порт недоступен

**Решение:** Проверьте, что все три порта (8000, 8001, 8002) проброшены в Clore.ai. Проверьте каждый:

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

### OOM во время загрузки модели

**Решение:** Уменьшите число экземпляров или используйте CPU-экземпляры для некоторых моделей:

```protobuf
instance_group [
  {
    count: 1       # Уменьшить по сравнению со значением по умолчанию
    kind: KIND_GPU
  }
]
```

***

## Оценка стоимости

| GPU        | VRAM  | Оценочная цена                              | Пропускная способность (ResNet50) |
| ---------- | ----- | ------------------------------------------- | --------------------------------- |
| RTX 3080   | 10 ГБ | $0.05–0.19/ч                                | \~500 req/sec                     |
| RTX 4090   | 24 ГБ | $0.14–0.42/ч                                | \~1500 req/sec                    |
| A100 40 ГБ | 40 ГБ | [голое железо](https://clore.ai/bare-metal) | \~3000 req/sec                    |
| H100       | 80 ГБ | \~$1.04/hr                                  | \~8000 req/sec                    |

***

## Полезные ресурсы

* [Triton на GitHub](https://github.com/triton-inference-server/server)
* [Реестр контейнеров NGC](https://catalog.ngc.nvidia.com/orgs/nvidia/containers/tritonserver)
* [Клиентские библиотеки Triton](https://github.com/triton-inference-server/client)
* [Справочник по конфигурации моделей Triton](https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/user_guide/model_configuration.html)
* [Python backend Triton](https://github.com/triton-inference-server/python_backend)
* [Анализатор производительности Triton](https://github.com/triton-inference-server/client/blob/main/src/c%2B%2B/perf_analyzer/README.md)

***

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

| Сценарий использования  | Рекомендуемый GPU | Оценочная стоимость на Clore.ai             |
| ----------------------- | ----------------- | ------------------------------------------- |
| Разработка/тестирование | RTX 3090 (24 ГБ)  | $0.07–0.21/гпу/ч                            |
| Промышленный инференс   | RTX 4090 (24 ГБ)  | $0.14–0.42/гпу/ч                            |
| Крупные модели (70B+)   | 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/mlops-i-razvertyvanie/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.
