Training моделей детекции объектов: YOLOv8, YOLO11, RT-DETR
YOLOv8 — практический стандарт детекции для большинства production-задач. Но между «запустить yolo train» и получить [email protected] > 0.85 на реальных данных — дистанция в несколько итераций, каждая с конкретными решениями.
Конфигурация обучения и гиперпараметры
# yolov8_custom.yaml — конфиг для кастомного обучения
model: yolov8m.pt # m = medium, баланс скорость/точность
# Датасет
data: dataset.yaml
imgsz: 640 # 1280 для мелких объектов, но в 4x медленнее
batch: 16 # при VRAM 12GB; 32 при 24GB
epochs: 200
# Оптимизатор
optimizer: AdamW
lr0: 0.001
lrf: 0.01 # финальный LR = lr0 * lrf
momentum: 0.937
weight_decay: 0.0005
warmup_epochs: 3.0
# Аугментации (встроенные в YOLOv8)
mosaic: 1.0 # вкл mosaic до последних 10 эпох
mixup: 0.15
copy_paste: 0.1 # сегментация → копируем объекты на новый фон
degrees: 10.0
translate: 0.1
scale: 0.5
flipud: 0.0
fliplr: 0.5
hsv_h: 0.015
hsv_s: 0.7
hsv_v: 0.4
from ultralytics import YOLO
model = YOLO('yolov8m.pt')
results = model.train(
data='dataset/data.yaml',
imgsz=640,
batch=16,
epochs=200,
device='0', # GPU 0
project='runs/detect',
name='defect_v1',
save_period=10, # чекпоинт каждые 10 эпох
val=True,
plots=True, # confusion matrix, PR-curve
patience=50 # early stopping
)
Глубокий разбор: почему модель не обучается
Самая частая ситуация: loss падает, val mAP растёт до ~0.6 и стагнирует. Анализ confusion matrix показывает систематические FP одного класса. Три основные причины:
1. Аннотационные ошибки. Даже 5% неправильных bbox разрушают обучение мелких классов. Инструмент диагностики:
import numpy as np
from pathlib import Path
def audit_annotation_quality(labels_dir: str) -> dict:
"""
Проверяем аннотации на:
- bbox выходящие за границы (x+w > 1 в YOLO формате)
- микро-bbox (< 5px площадь при imgsz=640)
- дублирующиеся bbox (IoU > 0.9)
"""
issues = {'out_of_bounds': [], 'tiny_boxes': [], 'duplicates': []}
for label_path in Path(labels_dir).glob('*.txt'):
boxes = np.loadtxt(label_path, ndmin=2)
if boxes.shape[0] == 0:
continue
cls_ids, cx, cy, bw, bh = (boxes[:, i] for i in range(5))
# Out of bounds
oob = (cx - bw/2 < 0) | (cx + bw/2 > 1) | \
(cy - bh/2 < 0) | (cy + bh/2 > 1)
if oob.any():
issues['out_of_bounds'].append(str(label_path))
# Tiny boxes < 2% от изображения
tiny = (bw * bh) < 0.0004 # ~16x16px при 640
if tiny.any():
issues['tiny_boxes'].append(str(label_path))
return issues
2. Несбалансированный датасет без учёта spatial distribution. YOLOv8 anchor-free, но если объекты одного класса сосредоточены в одном углу изображения — модель выучит эту корреляцию.
3. Слишком агрессивный mosaic при мелких объектах. Mosaic уменьшает объекты в 2–4 раза. При исходных объектах 20–40px они становятся 5–10px — ниже порога детектируемости.
# Отключаем mosaic в последние 10 эпох + для мелких объектов
# через custom trainer
from ultralytics.models.yolo.detect import DetectionTrainer
class SmallObjectTrainer(DetectionTrainer):
def build_dataset(self, img_path, mode='train', batch=None):
dataset = super().build_dataset(img_path, mode, batch)
# Если средний размер bbox < 3% — снижаем mosaic
if mode == 'train':
dataset.mosaic = 0.5 # вместо 1.0
return dataset
RT-DETR: когда YOLO не хватает
RT-DETR (Real-Time DEtection TRansformer, Baidu 2023) — трансформерная детекция без NMS. Превосходит YOLOv8 на сценах с сильными окклюзиями и нестандартными соотношениями сторон объектов.
from ultralytics import RTDETR
model = RTDETR('rtdetr-l.pt')
model.train(
data='dataset/data.yaml',
imgsz=640,
batch=8, # RT-DETR тяжелее YOLOv8 по памяти
epochs=100,
device='0',
optimizer='AdamW',
lr0=0.0001,
warmup_epochs=2
)
Сравнение на задаче детекции мелких дефектов (объекты 15–40px):
| Модель | [email protected] | [email protected]:0.95 | Latency (RTX3080) | VRAM |
|---|---|---|---|---|
| YOLOv8n | 0.724 | 0.421 | 2.3ms | 2.1GB |
| YOLOv8m | 0.811 | 0.513 | 5.1ms | 5.8GB |
| YOLOv8l | 0.837 | 0.541 | 8.2ms | 8.1GB |
| RT-DETR-L | 0.869 | 0.574 | 9.8ms | 9.4GB |
| YOLO11l | 0.845 | 0.553 | 7.9ms | 7.8GB |
TensorRT для production
from ultralytics import YOLO
trained_model = YOLO('runs/detect/defect_v1/weights/best.pt')
trained_model.export(
format='engine', # TensorRT
device=0,
half=True, # FP16: ~2x speedup, minimal accuracy loss
dynamic=False, # fixed batch для максимальной оптимизации
imgsz=640,
batch=1, # или 8 при батч-инференсе
workspace=4 # GB для TensorRT optimizer
)
Сроки
| Задача | Срок |
|---|---|
| Fine-tuning YOLOv8 (готовые данные) | 1–2 недели |
| Полный цикл: данные → обучение → оптимизация | 4–7 недель |
| Кастомный detector (новая архитектура head) | 8–14 недель |







