Ultralytics YOLO27: Встать в лист ожидания.
Get Started
Обучи первую модель YOLO·Данные·Урок 4/10
Урокначинающий

Подготовь собственный датасет

Организуй изображения и метки в формате Ultralytics YOLO, преобразуй пиксельные рамки в нормализованные строки меток и найди повреждённые метки до обучения.

Из-за одной неправильно названной папки или ненормализованной метки обучение не завершится с ошибкой. Ultralytics пропустит повреждённые изображения и продолжит работу, поэтому модель обучится лишь на части данных и получится посредственной, а ты потеряешь полдня, пытаясь найти причину не там.

В этом уроке разбирается практическая часть подготовки датасета для детекции: папки, строки меток, преобразование и проверки. Ты будешь работать с реальным датасетом медицинских таблеток из 115 изображений, на котором обучаются модели в остальной части курса. Вопросы о том, что собирать и как размечать, рассматриваются в разделе Лучшие практики аннотирования.

Результат

Ты научишься организовывать датасет в формате Ultralytics YOLO, преобразовывать пиксельные рамки в нормализованные строки меток и находить отсутствующие или повреждённые метки по строке сканирования до начала обучения.

Ускоренное прохождение
Если ты уже освоился, вот краткая версия.
  1. Создай images/{train,val} и labels/{train,val} с совпадающими именами файлов.

  2. Запиши по одной строке class x_center y_center width height на объект; каждое значение должно быть от 0 до 1.

  3. Преобразуй пиксельные рамки, разделив координаты на ширину и высоту изображения.

  4. Наложи файл меток на изображение и проверь, что в строке сканирования указано 0 corrupt.

Практические занятия

Получи учебный датасет#

Диалоговое окно создания датасета в Ultralytics Platform: область для загрузки изображений, видео или датасетов YOLO, COCO и NDJSON, а также поля имени, URL, описания и типа задачи

Такая структура также подходит для загрузки ZIP-архива через диалог создания датасета в Ultralytics Platform, поэтому подготовленный здесь датасет можно загрузить без изменений. Скачай 92 обучающих и 23 валидационных кадра с таблетками в блистерных упаковках и распакуй их в my_dataset:

curl -L -o medical-pills.zip https://github.com/ultralytics/assets/releases/download/v0.0.0/medical-pills.zip
unzip -q medical-pills.zip -d my_dataset
my_dataset/
├── images/
│   ├── train/   Frame_0.jpg, Frame_100.jpg, ... (92 images)
│   └── val/     Frame_144.jpg, ... (23 images)
└── labels/
    ├── train/   Frame_0.txt, Frame_100.txt, ... (92 files)
    └── val/     Frame_144.txt, ... (23 files)

Манифеста нет. Ultralytics находит каждую метку, заменяя /images/ на /labels/ в пути к изображению, а расширение — на .txt, поэтому images/val/Frame_144.jpg читает labels/val/Frame_144.txt. Отсюда следуют два вывода:

  • Папки должны называться точно images и labels и находиться рядом.
  • Изображение с пустым или отсутствующим файлом меток считается фоновым: оно допустимо и полезно, чтобы научить модель тому, что не нужно обнаруживать, но только если это было задумано.

Разберём строку метки#

Файл меток YOLO для zidane.jpg, по одной строке на объект: индекс класса, затем нормализованные координаты центра x, центра y, ширины и высоты

Каждая строка соответствует одному объекту: целочисленный индекс класса, затем центр и размер ограничивающей рамки в долях от ширины и высоты изображения. Вот реальная строка из labels/train/Frame_0.txt:

0 0.330729 0.816204 0.103125 0.121296
  • 0: индекс класса 0, которому в YAML будет соответствовать имя pill.
  • 0.330729 0.816204: центр рамки расположен на 33% ширины и 82% высоты изображения.
  • 0.103125 0.121296: рамка занимает около 10% ширины и 12% высоты изображения.

Пример: преобразуем рамку из пикселей#

Инструменты разметки часто экспортируют координаты углов в пикселях (x1, y1, x2, y2). Раздели их на размер изображения. Левый человек на изображении bus.jpg размером 810×1080 из прошлого урока занимает область от (49, 398) до (240, 902):

ПолеФормулаЗначение
x_center(x1 + x2) / 2 / width(49 + 240) / 2 / 810 = 0.178395
y_center(y1 + y2) / 2 / height(398 + 902) / 2 / 1080 = 0.601852
width(x2 − x1) / width191 / 810 = 0.235802
height(y2 − y1) / height504 / 1080 = 0.466667

Большинство инструментов разметки, а также такие инструменты, как Roboflow, поддерживают прямой экспорт в формат YOLO. Для COCO JSON следуй руководству по обучению на COCO JSON; репозиторий JSON2YOLO описывает другие форматы. Для XML Pascal VOC достаточно короткого скрипта с приведённой выше формулой:

import xml.etree.ElementTree as ET
from pathlib import Path

CLASSES = ["person", "bus"]  # index = class id; must match names in data.yaml

def voc_to_yolo(xml_file: Path, out_dir: Path) -> None:
    root = ET.parse(xml_file).getroot()
    w, h = int(root.find("size/width").text), int(root.find("size/height").text)
    lines = []
    for obj in root.iter("object"):
        name = obj.find("name").text
        if name not in CLASSES:
            continue
        box = obj.find("bndbox")
        x1, y1, x2, y2 = (float(box.find(k).text) for k in ("xmin", "ymin", "xmax", "ymax"))
        xc, yc, bw, bh = (x1 + x2) / 2 / w, (y1 + y2) / 2 / h, (x2 - x1) / w, (y2 - y1) / h
        lines.append(f"{CLASSES.index(name)} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}")
    out_dir.mkdir(parents=True, exist_ok=True)
    (out_dir / f"{xml_file.stem}.txt").write_text("\n".join(lines) + "\n")

voc_to_yolo(Path("bus.xml"), Path("labels"))
print(Path("labels/bus.txt").read_text())

Если запустить скрипт на bus.xml с рамками человека и автобуса из прошлого урока, он выведет разобранный пример и результат для автобуса:

0 0.178395 0.601852 0.235802 0.466667
1 0.495679 0.454167 0.991358 0.482407

Проверь перед обучением#

Наложи несколько файлов меток на соответствующие изображения. Смещение класса, перепутанные местами x и y или рамки вокруг теней сразу заметны визуально, но не видны по метрикам:

from ultralytics.data.utils import visualize_image_annotations

visualize_image_annotations(
    "my_dataset/images/train/Frame_0.jpg",
    "my_dataset/labels/train/Frame_0.txt",
    {0: "pill"},
)

Затем проверь все файлы с помощью Ultralytics. При первом чтении датасета система сканирует метки и построчно определяет, можно ли использовать каждое изображение:

Результат отображается в строке сканирования: 23 images, 0 backgrounds, 0 corrupt — так выглядит исправный датасет. Любой другой результат указывает на одну из ошибок ниже.

Избегай этих ошибок#

Забыли нормализацию

Симптом: ignoring corrupt image/label: non-normalized or out of bounds coordinates [634. 881. 198. 163.] и ненулевое количество corrupt. Причина: вместо долей используются значения пикселей. Решение: раздели координаты на ширину и высоту изображения. Любое значение метки больше 1 означает, что координаты рамки не были нормализованы.

Папка меток названа неправильно

Симптом: yolo val сканирует 0 images, 23 backgrounds и выдаёт предупреждение No labels found, а обучение останавливается с ошибкой ValueError: train: No labels found — в данном случае потому, что папка меток называлась annotations. Решение: назови папки точно images и labels, используя совпадающие имена файлов.

Индексы классов начинаются с 1

Симптом: Label class 1 exceeds dataset class count 1. Possible class labels are 0-0. Причина: инструмент экспорта присвоил классам номера начиная с 1. Решение: индексы классов YOLO начинаются с 0; вычти 1 в скрипте преобразования или исправь настройку экспорта.

Углы и центры

Если рамки смещены на половину размера рамки вниз и вправо, значит, ты записал x1 y1 w h вместо x_center y_center w h. Проверка одного файла выявит это за секунды; никакая проверка сканированием этого не сделает.

Подробности о систематических проверках всего датасета см. в разделе Контроль качества датасета. Удобно брать за образец структуру встроенных датасетов, таких как coco8, coco128 и african-wildlife; полный список приведён в обзоре датасетов. Тренер добавляет к твоим меткам аугментацию данных, поэтому предварительная очистка данных улучшит каждую эпоху.

Попробовать

Скачай датасет с таблетками в my_dataset. Подготовь результаты трёх проверок: количество изображений и меток в каждой выборке; вывод скрипта, который печатает значения меток за пределами диапазона 0–1 (он не должен ничего вывести); и файл меток, наложенный на изображение с помощью visualize_image_annotations. Если у тебя есть собственные размеченные изображения, преобразуй 10 из них в такую же структуру и наложи одну метку на изображение.

Критерии готовности
Урок считается завершённым, если выполнены все условия ниже.
  • В my_dataset есть images/train, images/val, labels/train и labels/val с совпадающими именами файлов и количеством файлов.

  • Скрипт проверки не находит значений меток за пределами диапазона 0–1.

  • Ты наложил как минимум один файл меток на изображение, и рамки правильно охватывают таблетки.

Показать решение
for s in train val; do
  echo "$s: $(ls my_dataset/images/$s | wc -l) images, $(ls my_dataset/labels/$s | wc -l) labels"
done
# train: 92 images, 92 labels
# val:   23 images, 23 labels
from pathlib import Path

for txt in Path("my_dataset/labels").rglob("*.txt"):
    for line in txt.read_text().splitlines():
        values = [float(v) for v in line.split()[1:]]
        if any(v < 0 or v > 1 for v in values):
            print(txt, line)

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

Что дальше

Папки готовы. Теперь создай единственный YAML-файл, который укажет Ultralytics их расположение и значения классов.

Войди, чтобы сохранять прогресс