# Детекция YOLOv9/v10

> **Современное обнаружение объектов в реальном времени — обучайте и разворачивайте последние модели YOLO на GPU**

YOLO (You Only Look Once) по-прежнему является эталоном для обнаружения объектов в реальном времени. YOLOv9 представил Программируемую Информацию Градиента (PGI) и Обобщенную Эффективную Сеть Агрегации Слоев (GELAN), в то время как YOLOv10 привнес обнаружение без NMS с двойным назначением меток. Обе версии обеспечивают первоклассный баланс точности и скорости на GPU NVIDIA.

* **YOLOv9 GitHub:** [WongKinYiu/yolov9](https://github.com/WongKinYiu/yolov9) — 8K+ ⭐
* **YOLOv10 GitHub:** [THU-MIG/yolov10](https://github.com/THU-MIG/yolov10) — 10K+ ⭐
* **Ultralytics (объединённый):** [ultralytics/ultralytics](https://github.com/ultralytics/ultralytics) — 32K+ ⭐

***

## YOLOv9 vs YOLOv10 vs YOLOv8 — Краткое сравнение

| Модель   | mAP50-95 | Скорость (A100) | Параметры | NMS       |
| -------- | -------- | --------------- | --------- | --------- |
| YOLOv8x  | 53.9     | 14.2ms          | 68.2M     | Требуется |
| YOLOv9e  | 55.6     | 16.8ms          | 57.3M     | Требуется |
| YOLOv10x | 54.4     | 10.7ms          | 29.5M     | **Без**   |
| YOLOv10b | 53.0     | 8.8ms           | 19.1M     | **Без**   |
| YOLOv10s | 46.8     | 4.2ms           | 7.2M      | **Без**   |

{% hint style="success" %}
**YOLOv10 работает без NMS** — без этапа постобработки подавления немаксимумов. Это позволяет развертывать модель end-to-end и особенно полезно для встраиваемых/edge-сценариев и развертывания с TensorRT.
{% endhint %}

***

## Сценарии использования

* **Безопасность и наблюдение** — обнаружение людей/транспортных средств/объектов в реальном времени
* **Автономные транспортные средства** — обнаружение пешеходов и препятствий
* **Контроль качества в производстве** — обнаружение дефектов на производственных линиях
* **Аналитика ритейла** — анализ потока клиентов и обнаружение товаров
* **Медицинская визуализация** — обнаружение аномалий на рентгенах и сканах
* **Спортивная аналитика** — отслеживание игроков и мяча
* **Сельское хозяйство** — обнаружение болезней культур и вредителей

***

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

* Аккаунт Clore.ai с арендой GPU
* Данные для обучения (для обучения кастомной модели) или использование предобученных весов COCO
* Базовые знания Python и командной строки

***

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

1. Перейдите на [clore.ai](https://clore.ai) → **Маркетплейс**
2. Выберите GPU в зависимости от задачи:
   * **Только инференс:** RTX 3080/3090 или RTX 4080 — отличное соотношение цена/производительность
   * **Обучение небольших моделей:** RTX 4090 24GB
   * **Обучение больших моделей (YOLOv9e/YOLOv10x):** A100 40/80GB

{% hint style="info" %}
**Для инференса в реальном времени** (видеопотоки) RTX 3090 или RTX 4090 дают 100–500 FPS в зависимости от варианта модели. Даже самая маленькая YOLOv10n работает на 4090 с TensorRT со скоростью 1000+ FPS.
{% endhint %}

***

## Шаг 2 — Разверните контейнер Ultralytics

Официальный Docker-образ Ultralytics поддерживает YOLOv8, YOLOv9 и YOLOv10 через единый API:

**Docker-образ:**

```
ultralytics/ultralytics:latest
```

**Порты:**

```
22
8000
```

**Переменные окружения:**

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

**Диск:** Минимум 20 ГБ (предобученные веса + ваш датасет)

***

## Шаг 3 — Подключитесь и проверьте

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

# Проверить GPU
nvidia-smi

# Проверить установку Ultralytics
python3 -c "import ultralytics; ultralytics.checks()"

# Должна отображаться информация о GPU, версии CUDA и доступности моделей
```

***

## Шаг 4 — Быстрый инференс с предобученными моделями

### Инференс YOLOv10 (без NMS)

```python
from ultralytics import YOLO
import cv2

# Загрузить модель YOLOv10 (автозагрузка, если отсутствует)
model = YOLO("yolov10x.pt")  # Варианты: n, s, m, b, l, x

# Выполнить инференс на изображении
results = model("https://ultralytics.com/images/bus.jpg")

# Показать результаты
for result in results:
    boxes = result.boxes
    print(f"Detected {len(boxes)} objects")
    for box in boxes:
        cls = int(box.cls[0])
        conf = float(box.conf[0])
        xyxy = box.xyxy[0].tolist()
        print(f"  {model.names[cls]}: {conf:.2f} at {[int(x) for x in xyxy]}")

# Сохранить аннотированное изображение
results[0].save("output.jpg")
```

### Инференс YOLOv9

```python
from ultralytics import YOLO

# Загрузить модель YOLOv9
model = YOLO("yolov9e.pt")  # Варианты: t, s, m, c, e

# Пакетный инференс для максимальной пропускной способности
results = model(
    source=[
        "image1.jpg",
        "image2.jpg",
        "image3.jpg",
    ],
    batch=8,        # Обрабатывать 8 изображений параллельно
    device="cuda",
    conf=0.25,      # Порог уверенности
    iou=0.45,       # Порог IoU для NMS (не нужен для v10)
    imgsz=640,
    half=True       # FP16 для ускорения в 2 раза
)
```

### Инференс потокового видео в реальном времени

```python
from ultralytics import YOLO
import cv2

model = YOLO("yolov10s.pt")

# Для веб-камеры (device=0) или видеофайла
cap = cv2.VideoCapture("input_video.mp4")

# Получить свойства видео
fps = cap.get(cv2.CAP_PROP_FPS)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

# Видео-писатель для вывода
out = cv2.VideoWriter(
    "output_video.mp4",
    cv2.VideoWriter_fourcc(*"mp4v"),
    fps,
    (width, height)
)

frame_count = 0
while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break
    
    results = model(frame, conf=0.25, verbose=False)
    annotated = results[0].plot()
    out.write(annotated)
    frame_count += 1
    
    if frame_count % 100 == 0:
        print(f"Processed {frame_count} frames")

cap.release()
out.release()
print("Готово! Вывод сохранён в output_video.mp4")
```

***

## Шаг 5 — Обучение собственной модели

### Подготовьте ваш набор данных

YOLO использует специфическую структуру каталогов и формат меток:

```
dataset/
├── images/
│   ├── train/          # Изображения для обучения (.jpg/.png)
│   ├── val/            # Изображения для валидации
│   └── test/           # Тестовые изображения (опционально)
└── labels/
    ├── train/          # Файлы меток (.txt)
    ├── val/
    └── test/
```

Каждый файл меток (с тем же именем, что и изображение, `.txt` расширение) содержит:

```
# class_id center_x center_y width height (все нормализованы 0-1)
0 0.512 0.334 0.256 0.412
1 0.123 0.654 0.089 0.123
```

### Создать конфигурацию датасета

```bash
cat > /workspace/custom_dataset.yaml << 'EOF'
# Конфигурация датасета
path: /workspace/dataset
train: images/train
val: images/val
test: images/test

# Количество классов
nc: 3

# Имена классов
names:
  0: person
  1: car
  2: bicycle
EOF
```

### Импорт из Roboflow (рекомендуется)

```python
# Установить Roboflow
pip install roboflow

from roboflow import Roboflow
rf = Roboflow(api_key="YOUR_API_KEY")
project = rf.workspace("your-workspace").project("your-project")
version = project.version(1)
dataset = version.download("yolov9")

# Датасет теперь находится в ./your-project-1/
```

### Обучение YOLOv10

```python
from ultralytics import YOLO

# Загрузить предобученную модель YOLOv10 (transfer learning)
model = YOLO("yolov10m.pt")  # Средний вариант — хороший баланс

results = model.train(
    data="/workspace/custom_dataset.yaml",
    epochs=100,
    imgsz=640,
    batch=16,               # Настройте под объем VRAM вашего GPU
    device="cuda",
    workers=8,
    project="/workspace/runs",
    name="yolov10_custom",
    patience=50,            # Ранняя остановка
    save=True,
    save_period=10,         # Сохранять чекпоинт каждые 10 эпох
    plots=True,
    val=True,
    augment=True,           # Аугментация данных
    degrees=10.0,
    flipud=0.0,
    fliplr=0.5,
    mosaic=1.0,
    mixup=0.1,
    copy_paste=0.1,
    lr0=0.01,
    lrf=0.01,
    momentum=0.937,
    weight_decay=0.0005,
    warmup_epochs=3.0,
    amp=True                # Автоматическая смешанная точность (FP16)
)

print(f"Обучение завершено! Лучший mAP: {results.results_dict['metrics/mAP50-95(B)']:.3f}")
```

### Обучение YOLOv9

```python
from ultralytics import YOLO

model = YOLO("yolov9e.pt")

results = model.train(
    data="/workspace/custom_dataset.yaml",
    epochs=100,
    imgsz=640,
    batch=8,               # v9e больше, требует меньшего батча
    device="cuda",
    workers=8,
    project="/workspace/runs",
    name="yolov9_custom",
    amp=True,
    optimizer="SGD",
    momentum=0.937,
    weight_decay=0.0005
)
```

{% hint style="info" %}
**Советы по обучению:**

* **Размер батча:** Начните с `batch=16` для RTX 4090, `batch=32` для A100 40GB
* **Размер изображения:** `imgsz=640` это стандарт; используйте 1280 для задач с высоким разрешением
* **Эпохи:** 100 эпох обычно для тонкой настройки, 300+ для обучения с нуля
* **AMP (смешанная точность):** Всегда включайте `amp=True` для ускорения в 1.5–2 раза
  {% endhint %}

***

## Шаг 6 — Экспорт в TensorRT для максимальной скорости

```python
from ultralytics import YOLO

# Загрузить обученную модель
model = YOLO("/workspace/runs/yolov10_custom/weights/best.pt")

# Экспорт в TensorRT (FP16 для лучшего баланса скорости и точности)
model.export(
    format="engine",        # TensorRT engine
    device="cuda",
    half=True,              # FP16
    dynamic=False,          # Статические формы для максимальной оптимизации TRT
    batch=1,                # Оптимизация под batch size 1 (реальное время)
    imgsz=640,
    workspace=4             # TRT workspace в ГБ
)
# Сохранено как: best.engine

# Загрузить и запустить TRT-движок
trt_model = YOLO("best.engine")
results = trt_model("image.jpg")
```

### Экспорт в ONNX

```python
# Экспорт в ONNX для гибкости развертывания
model.export(
    format="onnx",
    opset=17,
    half=True,              # FP16 веса
    dynamic=True,           # Динамический размер батча
    simplify=True
)
```

***

## Шаг 7 — Подать как REST API

```bash
pip install fastapi uvicorn python-multipart

cat > /workspace/yolo_api.py << 'EOF'
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import JSONResponse, FileResponse
from ultralytics import YOLO
from PIL import Image
import io
import uuid
import os

app = FastAPI(title="YOLOv10 Detection API")
model = YOLO("yolov10x.pt")

@app.get("/health")
async def health():
    return {"status": "ok", "model": "yolov10x", "device": "cuda"}

@app.post("/detect")
async def detect(
    file: UploadFile = File(...),
    conf: float = 0.25,
    iou: float = 0.45,
    return_image: bool = False
):
    # Прочитать загруженное изображение
    image_data = await file.read()
    img = Image.open(io.BytesIO(image_data)).convert("RGB")
    
    # Выполнить детекцию
    results = model(img, conf=conf, iou=iou, verbose=False)
    result = results[0]
    
    # Построить ответ
    detections = []
    for box in result.boxes:
        detections.append({
            "class": model.names[int(box.cls[0])],
            "confidence": round(float(box.conf[0]), 4),
            "bbox": [round(x, 2) for x in box.xyxy[0].tolist()],
            "class_id": int(box.cls[0])
        })
    
    response = {
        "count": len(detections),
        "detections": detections,
        "image_size": list(result.orig_shape)
    }
    
    if return_image:
        output_path = f"/tmp/{uuid.uuid4()}.jpg"
        result.save(filename=output_path)
        return FileResponse(output_path, media_type="image/jpeg")
    
    return JSONResponse(response)

@app.post("/detect/batch")
async def detect_batch(files: list[UploadFile] = File(...)):
    results = []
    for file in files:
        data = await file.read()
        img = Image.open(io.BytesIO(data)).convert("RGB")
        res = model(img, verbose=False)[0]
        results.append({
            "filename": file.filename,
            "count": len(res.boxes),
            "detections": [
                {"class": model.names[int(b.cls[0])], "conf": float(b.conf[0])}
                for b in res.boxes
            ]
        })
    return JSONResponse({"results": results})

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
EOF

python3 /workspace/yolo_api.py &

# Протестировать API
curl -X POST "http://localhost:8000/detect" \
    -F "file=@test_image.jpg" | python3 -m json.tool
```

***

## Шаг 8 — Валидировать и провести бенчмарк модели

```python
from ultralytics import YOLO

model = YOLO("yolov10x.pt")

# Валидация на датасете COCO
metrics = model.val(
    data="coco.yaml",
    imgsz=640,
    batch=32,
    device="cuda",
    half=True
)

print(f"mAP50:    {metrics.box.map50:.3f}")
print(f"mAP50-95: {metrics.box.map:.3f}")
print(f"Precision: {metrics.box.mp:.3f}")
print(f"Recall:    {metrics.box.mr:.3f}")

# Тест скорости
model.benchmark(
    format="engine",   # Сравнить несколько форматов экспорта
    imgsz=640,
    half=True,
    device="cuda"
)
```

***

## Скачать результаты

```bash
# С вашей локальной машины:
scp -P <ssh-port> root@<server-ip>:/workspace/runs/yolov10_custom/weights/best.pt ./
scp -P <ssh-port> root@<server-ip>:/workspace/output_video.mp4 ./

# Скачать весь прогон обучения
rsync -avz -e "ssh -p <ssh-port>" \
    root@<server-ip>:/workspace/runs/ \
    ./yolo_training_runs/
```

***

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

### Ошибка CUDA Out of Memory во время обучения

```python
# Уменьшите размер батча
model.train(data="data.yaml", batch=4, imgsz=640)

# Или включить gradient checkpointing
model.train(data="data.yaml", batch=8, imgsz=640, cache=False)
```

### Медленная скорость обучения

```python
# Включите кеширование (загружает датасет в RAM/GPU)
model.train(data="data.yaml", cache=True)  # Кеш в RAM
model.train(data="data.yaml", cache="disk")  # Кеш на диск

# Увеличьте число workers (внимание: слишком много может замедлить)
model.train(data="data.yaml", workers=8)
```

### Низкий mAP / Плохое обнаружение

```bash
# Убедитесь, что метки корректны (нормализованы, в пределах 0-1)
python3 -c "
from ultralytics.data.utils import check_det_dataset
check_det_dataset('custom_dataset.yaml')
"

# Визуализировать образцы обучения
python3 -c "
from ultralytics import YOLO
model = YOLO('yolov10m.pt')
model.train(data='data.yaml', epochs=1, batch=4, plots=True)
# Проверьте /workspace/runs/train/exp/train_batch*.jpg
"
```

***

## Справочные показатели производительности (GPU Clore.ai)

| Модель       | GPU      | Батч | FPS (инференс) | mAP50-95 |
| ------------ | -------- | ---- | -------------- | -------- |
| YOLOv10n     | RTX 3090 | 1    | 1,200          | 38.5     |
| YOLOv10s     | RTX 3090 | 1    | 780            | 46.8     |
| YOLOv10m     | RTX 4090 | 1    | 950            | 51.3     |
| YOLOv10x     | RTX 4090 | 1    | 380            | 54.4     |
| YOLOv9e      | A100 40G | 1    | 720            | 55.6     |
| YOLOv10x TRT | RTX 4090 | 1    | 920            | 54.2     |

***

## Дополнительные ресурсы

* [Документация Ultralytics](https://docs.ultralytics.com/)
* [Статья YOLOv9](https://arxiv.org/abs/2402.13616)
* [Статья YOLOv10](https://arxiv.org/abs/2405.14458)
* [Roboflow Universe](https://universe.roboflow.com/) — 100K+ публичных датасетов
* [Ultralytics HUB](https://hub.ultralytics.com/) — Облачная платформа для обучения
* [Датасет COCO](https://cocodataset.org/) — Стандартный эталонный датасет

***

*YOLOv9 и YOLOv10 на арендуемых GPU Clore.ai предоставляют доступный путь для обучения пользовательских моделей обнаружения объектов и развёртывания конвейеров инференса в реальном времени — без накладных расходов AWS SageMaker или Google Vertex AI.*

***

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

| Сценарий использования      | Рекомендуемый GPU | Примерная стоимость на Clore.ai |
| --------------------------- | ----------------- | ------------------------------- |
| Разработка/Тестирование     | RTX 3090 (24GB)   | \~$0.12/gpu/hr                  |
| Производственный инференс   | RTX 4090 (24GB)   | \~$0.70/gpu/hr                  |
| Обучение с большими батчами | A100 80GB         | \~$1.20/gpu/hr                  |

> 💡 Все примеры в этом руководстве можно развернуть на [Clore.ai](https://clore.ai/marketplace) GPU-серверах. Просматривайте доступные GPU и арендуйте по часам — без обязательств, с полным root-доступом.
