В данной статье разберём основные принципы детекции (обнаружения) объектов на изображении с помощью алгоритма YOLO, а также то, как на практике совмещают задачу классификации (например, полов/эмоций лица) с детекцией в единой модели.
Общий принцип работы YOLO
YOLO (You Only Look Once) — серия моделей одношаговой детекции объектов. Ключевой принцип:
1. Сетка (grid): Изображение мысленно делится на равномерную сетку (например, 13×13, 19×19 или другой размер в зависимости от архитектуры и масштаба).
2. Предсказание в каждой ячейке: Модель в каждой ячейке предсказывает ограничивающие рамки (bounding boxes) потенциальных объектов, их классы и степень уверенности (confidence).
3. Сжатие результатов: На выходе мы получаем совокупность предсказанных рамок и их классификацию. Далее применяются такие пост-обработки, как Non-Maximum Suppression (NMS), чтобы убрать дублирующие рамки.
Основная идея «одношаговости» в том, что детекция и классификация происходят одновременно за один прогон сети. Это даёт высокую скорость, что выгодно для приложений реального времени (камеры наблюдения, мобильные устройства, автопилоты и т.д.).
Детекция лиц с YOLO
Чтобы модель YOLO искала именно лица, в процессе обучения её настраивают (fine-tune) на датасет, где размечены рамки лиц. Примеры таких датасетов:
● WIDER FACE (один из самых популярных, содержит разнообразные сцены и ракурсы),
● FDDB (Face Detection Data Set and Benchmark),
● MAFA (Masked Face Detection Dataset) — содержит примеры с масками на лицах.
В результате сеть учится:
1. Искать лица в общем изображении,
2. Возвращать координаты bounding box для каждого найденного лица,
3. Классифицировать объект как «лицо» (если это однообъектный детектор) или определять дополнительную информацию (если учим на несколько классов, скажем, «лицо без маски» / «лицо в маске» и т. д.).
Расширение задачи: классификация пола, эмоций и т.п.
После того как YOLO определяет рамку лица, есть два сценария:
1. Две раздельные модели:
Сначала YOLO-детектор находит координаты лиц,
Затем по вырезанному (crop) лицу запускается отдельная свёрточная модель (CNN) для классификации пола, расы, эмоций и т.д.
2. Многозадачная (multi-task) YOLO-модель:
В рамках одного обучения детектор одновременно предсказывает bounding box и дополнительные категории (пол, эмоция).
Фактически, кроме класса «лицо» (или «нет лица»), сеть может иметь несколько выходных «голов» (output heads), отвечающих за дополнительные признаки.
Второй подход экономит вычислительные ресурсы (вместо запуска двух отдельных моделей), но требует более сложной разметки (например, у каждого лица должна быть метка пола/эмоции и т.д.).
Соединение детекции и классификации
Чтобы определить, например, пол/эмоции у каждого детектированного лица, есть два подхода:
Подход «Две стадии» (Two-stage)
1. Запускаем YOLO и получаем координаты лиц.
2. Для каждого лица делаем кроп (ROI — Region Of Interest) и подаём в отдельную сеть классификации (например, нашу модель из предыдущего раздела, которая распознаёт эмоции).
3. Объединяем результаты: у нас есть детекция (позиция лица) + класс (выражение лица, пол и т.д.).
Плюсы:
● Гибкость, можно менять классификатор независимо от детектора.
● Можно обучить классификатор на другом (более обширном) датасете лиц.
Минусы:
● Дополнительное время на прогон классификатора.
● Нужно хранить/обрабатывать кропы отдельно.
Подход «Одностадийная многозадачная сеть»
1. Модель детектирует «лицо» и одновременно предсказывает дополнительные атрибуты (пол, эмоция) в виде дополнительных выходных каналов.
2. Один проход сети выдаёт и bounding box, и нужный класс.
Плюсы:
● Быстро (одно прохождение сети).
● Удобно в реальном времени на видео.
Минусы:
● Усложнённая разметка (нужно размечать лица и атрибуты в одном датасете).
● Сеть требует хорошей настройки гиперпараметров: «бо́льшую» голову для детекции, «голову» для классификации.
Необходимая структура датасета детектора лиц, разметка и объёмы данных
Чтобы обучить детектор лиц (например, на базе YOLO), необходимо иметь качественно размеченный датасет. На практике структура датасета и формат аннотаций зависят от конкретных инструментов и фреймворка, но есть ряд общих принципов:
1. Структура датасета
Чаще всего датасет делится на три части:
1. Обучающая выборка (train) — основная масса изображений для обучения.
2. Валидационная выборка (val) — для настройки гиперпараметров и контроля качества во время обучения.
3. Тестовая выборка (test) — для итоговой независимой оценки точности модели.
Пример общей структуры каталогов:
face_dataset/
├── train/
│ ├── images/
│ │ ├── img_001.jpg
│ │ ├── img_002.jpg
│ │ └── …
│ └── labels/
│ ├── img_001.txt (или .xml, .json и т.д.)
│ ├── img_002.txt
│ └── …
├── val/
│ ├── images/
│ └── labels/
└── test/
├── images/
└── labels/
● В папке images хранятся изображения в стандартных форматах (JPEG, PNG).
● В папке labels — соответствующие файлы разметки: их формат зависит от того, как именно фреймворк читает аннотации (YOLO‑формат, Pascal VOC XML, COCO JSON и т.п.).
2. Форматы разметки
Главная задача при обучении детектора лиц — задать координаты bounding box (прямоугольника) для каждого лица на изображении. В зависимости от используемого фреймворка могут быть разные варианты:
1. YOLO-текстовый формат (Darknet/Yolov5/Yolov8 и др.)
На каждое изображение создаётся .txt‑файл с таким же именем, где каждая строка содержит:
<class_id> <x_center> <y_center> <width> <height>
Все координаты нормированы относительно размеров изображения (от 0 до 1).
Например, если у нас только один класс «лицо», то <class_id> = 0 (или другое число, если несколько классов).
2. Pascal VOC (XML)
На каждое изображение создаётся .xml, где записаны информация об изображении и bounding boxes в формате:
<annotation>
<object>
<name>face</name>
<bndbox>
<xmin>…</xmin>
<ymin>…</ymin>
<xmax>…</xmax>
<ymax>…</ymax>
</bndbox>
</object>
…
</annotation>
Часто используется во многих библиотеках (например, в mmdetection, some forks of YOLO).
3. COCO JSON
Единый .json‑файл, где для каждого изображения перечисляются аннотации в формате «segmentations», «bbox» (x, y, width, height) и др.
Популярно при работе с PyTorch/Detectron2, а также при организации больших датасетов.
Что важно:
● Если используется YOLO, нужно убедиться, что все необходимые классы (в данном случае «лицо») прописаны в конфигурационном файле.
● Для многообъектной детекции (не только лицо, но и «фон», «машина» и т.д.) все классы указываются в общей конфигурации, и каждому bounding box присваивается свой class_id.
3. Дополнительные элементы разметки (опционально)
1. Landmarks (точки на лице): Глаза, нос, рот и т.д. — это уже не bounding box, а ключевые точки (facial landmarks). Используется для более точного выравнивания лица или в задачах Face Alignment.
2. Атрибуты лица (эмоция, пол, наличие маски и т.д.): Если требуется совместить детекцию с классификацией, то для каждого bounding box могут быть указаны дополнительные атрибуты. В случае YOLO-многозадачных подходов (multi-head) может потребоваться собственный формат или расширение аннотаций (например, отдельные поля для эмоции).
4. Объёмы данных и разнообразие
1. Количество образцов. Для детекции лиц особенно важно иметь много разнообразных примеров:
Не существует «минимального» числа изображений, но для robust-детекции тысячи — это только начало. Для хорошего качества часто нужны десятки или даже сотни тысяч изображений.
Если проект небольшой, можно стартовать с нескольких тысяч (скажем, 2–5 тыс.), но модель может страдать от недообучения или плохо работать на нетипичных лицах.
2. Разнообразие:
Разные ракурсы (фронтальный, профиль, полупрофиль).
Разное освещение (природное, искусственное, ночные сцены).
Разные расстояния (крупные планы, дальние лица).
Разные этнические типы, возраст, пол.
Шумы (размытость, частичное перекрытие, очки, маски).
3. Распределение по train/val/test:
Обычно 70–80% данных идут на обучение, 10–20% на валидацию, и 10–20% на тест (проценты не жёсткие, зависят от размера датасета).
При наличии очень большого датасета можно выделять меньший тест/вал. Обязательно иметь независимый тестовый набор, не пересекающийся с train.
4. Использование готовых датасетов:
WIDER FACE: широко используемый набор с богатым разнообразием сцен; содержит более 32 тысяч изображений и ~394 тыс. размеченных лиц.
FDDB: один из первых общепризнанных датасетов.
MAFA (Masked Faces) или MaskFace: для случаев, когда часть лица закрыта (маски, шарфы).
CelebA: хоть и ориентирован на атрибуты лиц, включает в себе также координаты для лиц и landmark’и.
5. Ключевые рекомендации
1. Проверяйте качество разметки: даже небольшая ошибка (неточное определение границ) может существенно повлиять на итоговую точность детектора.
2. Соблюдайте единый формат: все аннотации должны быть в одной системе координат, корректно совпадать с размерами изображений.
3. Валидация на реальных данных: если модель будет работать на видеопотоке, полезно проверить датасет на видео-кадрах со схожими условиями съёмки.
4. Балансируйте сложные случаи: слишком много простых «лобовых» фото можгут сместить модель, и она хуже научится находить лица под углами или в слабом свете.
Импорт датасета WIDER FACE и обучение детектора лиц YOLO (PyTorch)
Ниже приведён конвейер для обучения детектора лиц на базе YOLOv5 (PyTorch), используя датасет WIDER FACE. Мы рассмотрим основные шаги:
1. Скачивание и подготовка данных WIDER FACE
2. Преобразование разметки в YOLO‑формат
3. Настройка конфигурации (файл dataset.yaml)
4. Запуск обучения через скрипты YOLOv5
Шаг 1. Клонирование YOLOv5 и установка зависимостей
# Клонируем репозиторий YOLOv5 (Ultralytics)
!git clone https://github.com/ultralytics/yolov5.git
%cd yolov5
# Устанавливаем зависимости
!pip install -r requirements.txt
Если вы запускаете это в локальном окружении, уберите ! и % и выполните команды в терминале/консоли.
Шаг 2. Скачивание датасета WIDER FACE
Датасет WIDER FACE доступен по ссылке:
● http://mmlab.ie.cuhk.edu.hk/projects/WIDERFace/
Там есть три основных архивa:
1. WIDER_train (изображения для тренировки)
2. WIDER_val (изображения для валидации)
3. WIDER_test (изображения для тестирования)
Также есть разметка (Annotations) в формате .mat или .txt:
● wider_face_split (разделение train/val/test),
● Annotations (bounding box координаты для каждого лица).
Допустим, вы скачали (или уже имеете) следующие папки:
WIDER_train/
WIDER_val/
wider_face_split/
Разархивировали их в какую-то директорию.
Шаг 3. Преобразование разметки в YOLO‑формат
WIDER FACE по умолчанию хранит bounding box’ы в виде текстовых файлов (каждое изображение — несколько строк с координатами x, y, w, h). Для YOLO нужно создать для каждого изображения .txt‑файл, где каждая строка имеет вид:
<class_id> <x_center_norm> <y_center_norm> <width_norm> <height_norm>
● class_id — в случае детекции только лиц обычно 0 (или 1, если у вас свой список классов).
● x_center_norm, y_center_norm — координаты центра bounding box, нормированные на ширину и высоту изображения (числа от 0 до 1).
● width_norm, height_norm — ширина и высота прямоугольника (также от 0 до 1).
Скрипт для конвертации:
import os
import cv2
# Папка с изображениями (train)
train_images_dir = «path/to/WIDER_train/images»
# Папка с аннотациями (txt-файлы WIDER FACE)
train_annot_dir = «path/to/wider_face_split/train/label.txt»
# Целевая папка, куда будем класть YOLO-нотацию
yolo_labels_dir = «path/to/WIDER_train/labels_yolo»
os.makedirs(yolo_labels_dir, exist_ok=True)
# Пробегаемся по аннотационным файлам WIDER FACE
# В WIDER FACE часто один txt-файл содержит несколько записей.
with open(train_annot_dir, ‘r’) as f:
lines = f.readlines()
current_img_path = None
n = 0
yolo_lines = []
for line in lines:
line = line.strip()
if line.endswith(‘.jpg’):
# Сохраняем предыдущие yolo_lines в файл (если были)
if current_img_path and len(yolo_lines) > 0:
# Сформируем имя .txt
base_name = os.path.splitext(os.path.basename(current_img_path))[0]
out_path = os.path.join(yolo_labels_dir, base_name + «.txt»)
with open(out_path, ‘w’) as out_f:
out_f.write(«\n».join(yolo_lines))
current_img_path = line
yolo_lines = [] # Очищаем список строк для нового изображения
else:
# парсим bounding box
box_info = line.split()
if len(box_info) >= 4:
x, y, w, h = map(float, box_info[:4])
img_full_path = os.path.join(train_images_dir, current_img_path)
# Получаем исходные размеры
img = cv2.imread(img_full_path)
H, W = img.shape[:2]
# YOLO: cx, cy, w_norm, h_norm
cx = x + w/2
cy = y + h/2
cx_norm = cx / W
cy_norm = cy / H
w_norm = w / W
h_norm = h / H
# Формируем строку «class_id cx cy w h»
# class_id = 0 (только лица)
yolo_line = f»0 {cx_norm:.6f} {cy_norm:.6f} {w_norm:.6f} {h_norm:.6f}»
yolo_lines.append(yolo_line)
# Не забудем сохранить для последнего изображения
if current_img_path and len(yolo_lines) > 0:
base_name = os.path.splitext(os.path.basename(current_img_path))[0]
out_path = os.path.join(yolo_labels_dir, base_name + «.txt»)
with open(out_path, ‘w’) as out_f:
out_f.write(«\n».join(yolo_lines))
Шаг 4. Создание dataset.yaml для YOLOv5
Файл dataset.yaml описывает структуру датасета для скриптов YOLOv5.
# dataset.yaml
train: /absolute/path/to/WIDER_train/images
val: /absolute/path/to/WIDER_val/images
# Если есть test, можно добавить, либо просто не указывать
# Один класс — «face»
names:
0: face
Шаг 5. Запуск обучения YOLOv5
Теперь, когда структура данных готова, мы можем запустить обучение.
%cd yolov5
!python train.py \
—data /absolute/path/to/dataset.yaml \
—cfg models/yolov5s.yaml \
—weights » \
—batch-size 16 \
—epochs 50 \
—img 640
Шаг 6. Проверка результата
После обучения в папке runs/train/expN/weights появится файл best.pt — это сохранённые лучшие веса модели по метрике mAP. Можно протестировать её:
!python detect.py \
—weights runs/train/expN/weights/best.pt \
—img 640 \
—conf 0.25 \
—source /absolute/path/to/test_image.jpg
В результате одна и та же модель может работать как универсальный детектор (любой объект, в том числе лицо), так и как специализированный детектор лиц (своя конфигурация и классы). Подходы на базе YOLO постепенно трансформируются и расширяются (версии YOLOv6, YOLOv7, YOLOv8 и т.д.), улучшая точность и производительность, а также предлагая новые методы для совмещения детекции с дополнительной классификацией (например, пол или эмоции) в рамках единой сети.
Таким образом, статья демонстрирует, что YOLO не просто «один из многих» методов детекции, а полноценная экосистема, которая даёт разработчикам мощный инструмент быстрого и точного обнаружения лиц в разнообразных сценариях компьютерного зрения.