- Home »

Обучение YOLOv7 на собственных данных
Натренировать собственный детектор объектов — это как собрать свою сборку Linux: с одной стороны, есть готовые решения, но с другой — хочется же покопаться в коде и сделать что-то идеально заточенное под свои задачи. YOLOv7 дает нам эту возможность, причем сравнительно безболезненно. Главное — понимать, что обучение нейросетей это не просто “скачал → запустил → профит”. Здесь нужен подходящий железный друг с хорошей GPU, правильно размеченные данные и немного терпения.
Сегодня разберем, как поднять training pipeline для YOLOv7 с нуля, пройдем все подводные камни подготовки данных, настроим окружение и получим работающую модель. Я покажу реальные команды, которые работают, а не теоретические выкладки из академических статей.
Как это работает: архитектура YOLOv7
YOLOv7 — это single-stage detector, который обрабатывает изображение за один проход через сеть. В отличие от двухэтапных детекторов типа R-CNN, YOLO не генерирует region proposals, а сразу предсказывает bounding boxes и классы объектов для каждой ячейки сетки, наложенной на изображение.
Основные компоненты архитектуры:
- Backbone — извлекает фичи из изображения (Extended Efficient Layer Aggregation Networks)
- Neck — агрегирует фичи с разных уровней (Path Aggregation Network)
- Head — финальные предсказания координат и классов
Что касается обучения, то YOLOv7 использует составную loss-функцию, которая учитывает:
- Локализацию объектов (coordinate loss)
- Confidence score (objectness loss)
- Классификацию (classification loss)
Подготовка окружения и железа
Для комфортной работы вам понадобится машина с GPU. Если своего железа нет, можно взять VPS с GPU или выделенный сервер — это будет гораздо быстрее, чем мучиться на CPU.
Рекомендуемые системные требования:
- GPU с минимум 8GB VRAM (GTX 3070/RTX 4060 и выше)
- RAM: 16GB+
- Свободного места: 50GB+ (зависит от размера датасета)
- CUDA 11.0+
Устанавливаем окружение:
# Клонируем официальный репозиторий
git clone https://github.com/WongKinYiu/yolov7.git
cd yolov7
# Создаем виртуальное окружение
python -m venv yolov7-env
source yolov7-env/bin/activate # Linux/Mac
# yolov7-env\Scripts\activate # Windows
# Устанавливаем зависимости
pip install -r requirements.txt
# Дополнительно установим несколько полезных пакетов
pip install tensorboard seaborn thop
Проверяем, что CUDA работает:
python -c "import torch; print(torch.cuda.is_available()); print(torch.cuda.device_count())"
Подготовка данных: размечаем правильно
Это самая важная часть всего процесса. Плохо размеченные данные = плохая модель, независимо от того, насколько крутая у вас архитектура.
YOLOv7 работает с данными в формате YOLO:
# Структура файла аннотации (.txt)
class_id center_x center_y width height
# Все координаты нормализованы относительно размера изображения (0-1)
# Пример для изображения 640x480 с объектом класса 0
0 0.5 0.3 0.2 0.4
Структура датасета должна быть следующей:
dataset/
├── train/
│ ├── images/
│ │ ├── img1.jpg
│ │ ├── img2.jpg
│ │ └── ...
│ └── labels/
│ ├── img1.txt
│ ├── img2.txt
│ └── ...
├── val/
│ ├── images/
│ └── labels/
└── test/
├── images/
└── labels/
Если у вас данные в другом формате, можно использовать конвертеры:
# Конвертер из COCO в YOLO формат
import json
from PIL import Image
import os
def coco_to_yolo(coco_json_path, images_dir, output_dir):
with open(coco_json_path, 'r') as f:
coco_data = json.load(f)
# Создаем маппинг category_id -> class_index
categories = {cat['id']: idx for idx, cat in enumerate(coco_data['categories'])}
# Группируем аннотации по изображениям
image_annotations = {}
for ann in coco_data['annotations']:
image_id = ann['image_id']
if image_id not in image_annotations:
image_annotations[image_id] = []
image_annotations[image_id].append(ann)
for img_info in coco_data['images']:
img_id = img_info['id']
img_name = img_info['file_name']
img_width = img_info['width']
img_height = img_info['height']
# Создаем YOLO аннотацию
yolo_annotations = []
if img_id in image_annotations:
for ann in image_annotations[img_id]:
x, y, w, h = ann['bbox']
class_id = categories[ann['category_id']]
# Конвертируем в YOLO формат
center_x = (x + w/2) / img_width
center_y = (y + h/2) / img_height
norm_width = w / img_width
norm_height = h / img_height
yolo_annotations.append(f"{class_id} {center_x} {center_y} {norm_width} {norm_height}")
# Сохраняем аннотацию
annotation_file = os.path.join(output_dir, img_name.replace('.jpg', '.txt'))
with open(annotation_file, 'w') as f:
f.write('\n'.join(yolo_annotations))
Настройка конфигурации
Создаем конфигурационный файл для нашего датасета:
# custom_dataset.yaml
train: ./dataset/train/images
val: ./dataset/val/images
test: ./dataset/test/images
# Количество классов
nc: 3
# Названия классов
names: ['person', 'car', 'bicycle']
Также можно настроить гиперпараметры обучения в файле data/hyp.scratch.custom.yaml
:
# Основные гиперпараметры
lr0: 0.01 # начальная скорость обучения
lrf: 0.1 # финальная скорость обучения (lr0 * lrf)
momentum: 0.937
weight_decay: 0.0005
warmup_epochs: 3.0
warmup_momentum: 0.8
warmup_bias_lr: 0.1
# Аугментации
hsv_h: 0.015 # изменение тона
hsv_s: 0.7 # изменение насыщенности
hsv_v: 0.4 # изменение яркости
degrees: 0.0 # поворот изображения
translate: 0.1 # сдвиг
scale: 0.5 # масштабирование
shear: 0.0 # сдвиг
perspective: 0.0 # перспектива
flipud: 0.0 # вертикальное отражение
fliplr: 0.5 # горизонтальное отражение
mosaic: 1.0 # мозаика
mixup: 0.0 # миксап
Запуск обучения
Теперь можно запустить обучение. Базовая команда выглядит так:
# Обучение с нуля
python train.py --workers 8 --device 0 --batch-size 16 --data custom_dataset.yaml --img 640 640 --cfg cfg/training/yolov7-custom.yaml --weights '' --name yolov7-custom --hyp data/hyp.scratch.custom.yaml
# Transfer learning (рекомендуется)
python train.py --workers 8 --device 0 --batch-size 16 --data custom_dataset.yaml --img 640 640 --cfg cfg/training/yolov7.yaml --weights yolov7.pt --name yolov7-custom --hyp data/hyp.scratch.custom.yaml --epochs 100
Разберем основные параметры:
--workers
— количество потоков для загрузки данных--device
— GPU устройство (0, 1, 2… или cpu)--batch-size
— размер батча (зависит от VRAM)--img
— размер входного изображения--weights
— предобученные веса (” для обучения с нуля)--epochs
— количество эпох обучения
Мониторинг процесса обучения
Для отслеживания прогресса обучения используем TensorBoard:
# Запускаем TensorBoard
tensorboard --logdir runs/train
# Или можно использовать встроенные графики
python -c "
import matplotlib.pyplot as plt
import pandas as pd
# Читаем результаты
results = pd.read_csv('runs/train/yolov7-custom/results.csv')
results.columns = results.columns.str.strip()
# Строим графики
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
axes[0,0].plot(results['epoch'], results['train/box_loss'], label='Box Loss')
axes[0,0].plot(results['epoch'], results['train/obj_loss'], label='Obj Loss')
axes[0,0].plot(results['epoch'], results['train/cls_loss'], label='Cls Loss')
axes[0,0].set_title('Training Losses')
axes[0,0].legend()
axes[0,1].plot(results['epoch'], results['val/box_loss'], label='Box Loss')
axes[0,1].plot(results['epoch'], results['val/obj_loss'], label='Obj Loss')
axes[0,1].plot(results['epoch'], results['val/cls_loss'], label='Cls Loss')
axes[0,1].set_title('Validation Losses')
axes[0,1].legend()
axes[1,0].plot(results['epoch'], results['metrics/precision'], label='Precision')
axes[1,0].plot(results['epoch'], results['metrics/recall'], label='Recall')
axes[1,0].set_title('Precision/Recall')
axes[1,0].legend()
axes[1,1].plot(results['epoch'], results['metrics/mAP_0.5'], label='mAP@0.5')
axes[1,1].plot(results['epoch'], results['metrics/mAP_0.5:0.95'], label='mAP@0.5:0.95')
axes[1,1].set_title('mAP Metrics')
axes[1,1].legend()
plt.tight_layout()
plt.savefig('training_progress.png')
plt.show()
"
Оптимизация и тонкая настройка
Если модель переобучается или плохо сходится, можно попробовать несколько трюков:
Проблема | Решение | Параметры |
---|---|---|
Переобучение | Увеличить регуляризацию | weight_decay: 0.001, dropout: 0.5 |
Медленная сходимость | Увеличить learning rate | lr0: 0.02, warmup_epochs: 5 |
Нестабильное обучение | Уменьшить batch size | batch-size: 8, накопление градиентов |
Плохая детекция мелких объектов | Увеличить размер изображения | –img 832 832 |
Для накопления градиентов при маленьком batch size:
# Эмуляция batch_size=64 с накоплением
python train.py --batch-size 16 --accumulate 4 --data custom_dataset.yaml --cfg cfg/training/yolov7.yaml --weights yolov7.pt
Тестирование и валидация
После обучения проверяем качество модели:
# Валидация на тестовом датасете
python test.py --data custom_dataset.yaml --img 640 --batch 32 --conf 0.001 --iou 0.65 --device 0 --weights runs/train/yolov7-custom/weights/best.pt --name yolov7-custom-test
# Инференс на отдельных изображениях
python detect.py --weights runs/train/yolov7-custom/weights/best.pt --conf 0.25 --img-size 640 --source /path/to/images --save-txt --save-conf
# Инференс на видео
python detect.py --weights runs/train/yolov7-custom/weights/best.pt --conf 0.25 --img-size 640 --source /path/to/video.mp4
# Инференс через веб-камеру
python detect.py --weights runs/train/yolov7-custom/weights/best.pt --conf 0.25 --img-size 640 --source 0
Сравнение с другими решениями
Модель | mAP@0.5 | Скорость (FPS) | Размер модели | Простота обучения |
---|---|---|---|---|
YOLOv7 | 52.5% | 120 | 37MB | Высокая |
YOLOv5 | 50.4% | 140 | 28MB | Высокая |
YOLOv8 | 53.9% | 100 | 44MB | Средняя |
EfficientDet | 50.4% | 60 | 52MB | Низкая |
YOLOv7 показывает отличный баланс между точностью и скоростью. Особенно хорошо подходит для real-time приложений.
Экспорт модели
Для использования в продакшене модель можно экспортировать в различные форматы:
# Экспорт в ONNX
python export.py --weights runs/train/yolov7-custom/weights/best.pt --grid --end2end --simplify --topk-all 100 --iou-thres 0.65 --conf-thres 0.35 --img-size 640 640 --max-wh 640
# Экспорт в TensorRT (если есть TensorRT)
python export.py --weights runs/train/yolov7-custom/weights/best.pt --grid --end2end --simplify --topk-all 100 --iou-thres 0.65 --conf-thres 0.35 --img-size 640 640 --max-wh 640 --device 0 --half
# Экспорт в TensorFlow Lite
python export.py --weights runs/train/yolov7-custom/weights/best.pt --img-size 640 640 --batch-size 1 --include tflite
Автоматизация и интеграция
Создаем скрипт для автоматической переподготовки модели при появлении новых данных:
#!/bin/bash
# auto_retrain.sh
# Проверяем наличие новых данных
if [ -f "new_data_flag" ]; then
echo "Найдены новые данные, запускаем переобучение..."
# Создаем бэкап текущей модели
cp runs/train/yolov7-custom/weights/best.pt backups/model_$(date +%Y%m%d_%H%M%S).pt
# Запускаем обучение
python train.py --workers 8 --device 0 --batch-size 16 \
--data custom_dataset.yaml --img 640 640 \
--cfg cfg/training/yolov7.yaml \
--weights backups/model_$(ls -t backups/ | head -1) \
--name yolov7-custom-retrain \
--hyp data/hyp.scratch.custom.yaml \
--epochs 50
# Тестируем новую модель
python test.py --data custom_dataset.yaml --img 640 --batch 32 \
--conf 0.001 --iou 0.65 --device 0 \
--weights runs/train/yolov7-custom-retrain/weights/best.pt \
--name yolov7-custom-test-new
# Если качество улучшилось, заменяем основную модель
NEW_MAP=$(grep "all" runs/test/yolov7-custom-test-new/results.csv | tail -1 | cut -d',' -f7)
OLD_MAP=$(grep "all" runs/test/yolov7-custom-test/results.csv | tail -1 | cut -d',' -f7)
if (( $(echo "$NEW_MAP > $OLD_MAP" | bc -l) )); then
echo "Новая модель лучше ($NEW_MAP vs $OLD_MAP), обновляем..."
cp runs/train/yolov7-custom-retrain/weights/best.pt production/model.pt
# Уведомляем об обновлении
curl -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
-d "chat_id=$CHAT_ID" \
-d "text=Модель обновлена! Новый mAP: $NEW_MAP"
fi
rm new_data_flag
fi
Нестандартные применения
YOLOv7 можно использовать не только для классической детекции объектов:
- Детекция текста — обучить на датасете с текстовыми регионами
- Медицинская диагностика — поиск патологий на рентгеновских снимках
- Контроль качества — детекция дефектов на производстве
- Анализ спутниковых снимков — поиск объектов на карте
- Аугментация данных — использование предсказаний для создания синтетических данных
Интересный трюк — использование YOLOv7 для создания attention maps:
# Модифицированный inference с визуализацией attention
import torch
import cv2
import numpy as np
from models.experimental import attempt_load
from utils.general import non_max_suppression
from utils.plots import plot_one_box
def visualize_attention(model, img, layer_name='model.24'):
"""Визуализация attention карт"""
activation = {}
def get_activation(name):
def hook(model, input, output):
activation[name] = output.detach()
return hook
# Регистрируем хук
model.model[24].register_forward_hook(get_activation(layer_name))
# Делаем inference
pred = model(img)[0]
# Получаем attention карту
attention = activation[layer_name]
attention = torch.mean(attention, dim=1, keepdim=True)
attention = torch.nn.functional.interpolate(attention, size=(640, 640), mode='bilinear')
return attention.cpu().numpy()
Производительность и оптимизация
Для ускорения inference в продакшене:
# Оптимизация модели с помощью TensorRT
import tensorrt as trt
import pycuda.driver as cuda
def build_engine(onnx_file_path, engine_file_path, precision='fp16'):
"""Конвертация ONNX в TensorRT engine"""
logger = trt.Logger(trt.Logger.WARNING)
builder = trt.Builder(logger)
network = builder.create_network(1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH))
parser = trt.OnnxParser(network, logger)
with open(onnx_file_path, 'rb') as model:
if not parser.parse(model.read()):
print('ERROR: Failed to parse the ONNX file.')
for error in range(parser.num_errors):
print(parser.get_error(error))
return None
config = builder.create_builder_config()
config.max_workspace_size = 1 << 30 # 1GB
if precision == 'fp16':
config.set_flag(trt.BuilderFlag.FP16)
elif precision == 'int8':
config.set_flag(trt.BuilderFlag.INT8)
engine = builder.build_engine(network, config)
with open(engine_file_path, "wb") as f:
f.write(engine.serialize())
return engine
Бенчмарки производительности на разном железе:
GPU | Precision | Batch Size | FPS | Latency (ms) |
---|---|---|---|---|
RTX 3080 | FP32 | 1 | 85 | 11.8 |
RTX 3080 | FP16 | 1 | 142 | 7.0 |
RTX 4090 | FP16 | 1 | 235 | 4.3 |
RTX 4090 | INT8 | 1 | 310 | 3.2 |
Отладка и решение проблем
Самые частые проблемы и их решения:
- CUDA out of memory — уменьшить batch size или размер изображения
- Loss не уменьшается — проверить качество аннотаций, уменьшить learning rate
- Плохая детекция — увеличить количество данных, использовать аугментации
- Модель не запускается — проверить совместимость версий PyTorch и CUDA
Скрипт для диагностики:
# debug_dataset.py
import os
import cv2
import numpy as np
from pathlib import Path
def validate_dataset(dataset_path):
"""Проверка датасета на корректность"""
issues = []
for split in ['train', 'val', 'test']:
img_dir = Path(dataset_path) / split / 'images'
lbl_dir = Path(dataset_path) / split / 'labels'
if not img_dir.exists():
issues.append(f"Отсутствует директория {img_dir}")
continue
img_files = list(img_dir.glob('*.jpg')) + list(img_dir.glob('*.png'))
for img_file in img_files:
# Проверяем изображение
img = cv2.imread(str(img_file))
if img is None:
issues.append(f"Не удается прочитать {img_file}")
continue
# Проверяем аннотацию
lbl_file = lbl_dir / f"{img_file.stem}.txt"
if not lbl_file.exists():
issues.append(f"Отсутствует аннотация для {img_file}")
continue
with open(lbl_file, 'r') as f:
lines = f.readlines()
for i, line in enumerate(lines):
parts = line.strip().split()
if len(parts) != 5:
issues.append(f"Неверный формат в {lbl_file}:{i+1}")
continue
try:
cls, x, y, w, h = map(float, parts)
if not (0 <= x <= 1 and 0 <= y <= 1 and 0 <= w <= 1 and 0 <= h <= 1):
issues.append(f"Неверные координаты в {lbl_file}:{i+1}")
except ValueError:
issues.append(f"Неверные числа в {lbl_file}:{i+1}")
return issues
# Запуск проверки
issues = validate_dataset('./dataset')
if issues:
print("Найдены проблемы:")
for issue in issues:
print(f"- {issue}")
else:
print("Датасет корректен!")
Заключение и рекомендации
YOLOv7 — это мощный и относительно простой в использовании фреймворк для обучения детекторов объектов. Главные преимущества:
- Хорошая документация и активное сообщество
- Быстрая скорость обучения и inference
- Гибкость в настройке под конкретные задачи
- Поддержка различных форматов экспорта
Рекомендации по использованию:
- Начинайте с transfer learning — это быстрее и эффективнее
- Тщательно подготавливайте данные — это 80% успеха
- Используйте аугментации для увеличения разнообразия данных
- Мониторьте процесс обучения через TensorBoard
- Тестируйте модель на реальных данных, а не только на валидационной выборке
YOLOv7 отлично подходит для задач реального времени, особенно если у вас есть хорошее GPU. Для серверных приложений рекомендую использовать VPS с GPU или выделенный сервер — это избавит от проблем с настройкой железа и даст стабильную производительность.
Помните: хорошая модель получается итеративно. Не ожидайте идеального результата с первого раза — экспериментируйте с гиперпараметрами, добавляйте данные, пробуйте разные подходы к аугментации. Удачи в ваших CV-проектах!
В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.
Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.