Home » Обучение YOLOv7 на собственных данных
Обучение YOLOv7 на собственных данных

Обучение 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-проектах!


В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.

Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.

Leave a reply

Your email address will not be published. Required fields are marked