Часть.2 Перевод: Фреймворк Darknet. Обучение Yolo v4
Внимание! Это руководство предназначено для людей, имеющих базовые познания в YOLO. В рамках проекта Beyond Robotics, с 1 по 15 июля будет выходить ряд видеоуроков, посвященных этому фреймворку.
Как тренировать нейросеть на нескольких видеокартах?
- Начните тренировать нейросеть на 1 видеокарте на 1000 итераций:
darknet.exe detector train cfg/coco.data cfg/yolov4.cfg yolov4.conv.137
- Далее, остановите обучение, используя частично тренированную модель
/backup/yolov4_1000.weights
(до 4 видеокарт):darknet.exe detector train cfg/coco.data cfg/yolov4.cfg /backup/yolov4_1000.weights -gpus 0,1,2,3
Если выходит “Nan”, то для некоторых датасетов наилучшим решением будет понизить скорость обучения. Для связки из 4 видеокарт установите значениеlearning_rate = 0,00065
(i.e. learning_rate = 0.00261 / GPUs). В этом случае также увеличьте в 4 раза значениеburn_in =
в cfg-файле. Таким образом, стоит использовать значениеburn_in = 4000
вместо1000
.
Как обучить свою нейросеть?
(Обучение старой версии Yolo v2 yolov2-voc.cfg, yolov2-tiny-voc.cfg, yolo-voc.cfg, yolo-voc.2.0.cfg
, … click by the link)
Обучение Yolo v4 (and v3):
- Для обучения
cfg/yolov4-custom.cfg
загрузите предтренировочный файл весов (162 MB): yolov4.conv.137 (зеркало yolov4.conv.137) - Создайте файл
yolo-obj.cfg
с таким же содержанием, как вyolov4-custom.cfg
(или скопируйтеyolov4-custom.cfg
вyolo-obj.cfg
)
- Измените параметр
batch
наbatch=64
- Измените параметр
subdivisions
наsubdivisions=16
- Задайте параметру
max_batches
значение, равноеclasses*2000
. При этом значениеmax_batches
должно быть не менее, чем общее количество изображений тренировочного датасета и не менее6000
). Например, следует установитьmax_batches=6000
если вы тренируете нейросеть на распознавание 3-х объектов - Задайте параметру
steps
два числа, которые будут равны 80% и 90% от параметраmax_batches
, например,steps=4800,5400
, приmax_batches = 6000
- Установите размер сети по параметрам width=416 height=416 или равный любому числу, кратному 32:
- Измените параметр classes=80 на ваше количество объектов в каждом из 3 [yolo]-слоев:
- Измените [
filters=255
] значение параметраfilters
, которое рассчитывается по формуле filters=(количество объектов + 5)x3 в трех сверточных [convolutional
] слоях перед каждым [yolo] слоем.
NOTE
Помните, что менять значение нужно только в последнем сверточном[convolutional
] слое, перед каждым [yolo
] слоем.
- darknet/yolov3.cfg at 0039fd26786ab5f71d5af725fc18b3f521e7acfd · AlexeyAB/darknet · GitHub
- darknet/yolov3.cfg at 0039fd26786ab5f71d5af725fc18b3f521e7acfd · AlexeyAB/darknet · GitHub
- darknet/yolov3.cfg at 0039fd26786ab5f71d5af725fc18b3f521e7acfd · AlexeyAB/darknet · GitHub
- При использовании [
Gaussian_yolo
] слоев, измените значение параметра [filters=57
], которое рассчитывается по формулеfilters=(classes + 9)x3
в трех сверточных [convolutional
] слоях перед каждым [Gaussian_yolo
] слоем- darknet/Gaussian_yolov3_BDD.cfg at 6e5bdf1282ad6b06ed0e962c3f5be67cf63d96dc · AlexeyAB/darknet · GitHub
- darknet/Gaussian_yolov3_BDD.cfg at 6e5bdf1282ad6b06ed0e962c3f5be67cf63d96dc · AlexeyAB/darknet · GitHub
- darknet/Gaussian_yolov3_BDD.cfg at 6e5bdf1282ad6b06ed0e962c3f5be67cf63d96dc · AlexeyAB/darknet · GitHub
Таким образом, если параметр classes=1
, тогда параметр filters=18
. Если classes=2
, тогда установите параметр filters=21
.
NOTE
Не пишите в cfg-файле [файле конфигурации]: формулу filters=(classes + 5)x3)
(В целом параметр filters
зависит от значений параметров classes
, coords и masks, например, filters=(classes + coords + 1)*<number of mask>
, где mask
индексы отметок (anchors
). Если параметр mask
отсутствует, тогда filters=(classes + coords + 1)*num)
Например, для распознавания двух объектов, yolo-obj.cfg
должен отличаться от yolov4-custom.cfg
в следующих строках каждого из трех [yolo]-слоев:
[convolutional
]
filters=21
[region
]
classes=2
- Создайте файл
obj.names
в путиbuild\darknet\x64\data\
, с названиями объектов, которые хотите распознать. При этом название каждого объекта должно быть расположено в новой строке. - Создайте файл
obj.data
в путиbuild\darknet\x64\data\
, со следующим содержанием (гдеclasses =
число объектов):
classes = 2
train = data/train.txt
valid = data/test.txt
names = data/obj.names
backup = backup/
- Поместите изображение ваших объектов в формате (.jpg) в пути
build\darknet\x64\data\obj\
Необходимо проставить отметки на каждый объект на изображении (label
) из вашего датасета. Используйте GUI для того, чтобы создать маркировочные рамки объектов и файлы аннотаций для Yolo v2 & v3 - Создайте
.txt
-файл для каждого файла в формате.jpg
в том же пути и с тем же названием, но с расширением.txt
. Далее поместите в файл следующие данные: номер и координаты объекта на изображении, указанные с новой строчки для каждого объекта:<object-class> <x_center> <y_center> <width> <height>
Где:
<object-class> - целое число объектов от 0 до(classes-1)
-
<x_center> <y_center> <width> <height>
- дробные значения ширины и высоты относительно изображения, они принимают значения в диапазоне(0.0 до 1.0)
Например: <x> = <absolute_x> / <image_width>
или <height> = <absolute_height> / <image_height>
Внимание: <x_center> <y_center>
- центр прямоугольника (не левый верхний угол!) Например, для img1.jpg
создаётся изображение img1.txt
, содержащее:
1 0.716797 0.395833 0.216406 0.147222
0 0.687109 0.379167 0.255469 0.158333
1 0.420312 0.395833 0.140625 0.166667
- Создайте файл
train.txt
в путиbuild\darknet\x64\data\
, который будет содержать в себе названия всех файлов c вашими изображениями, при этом каждое название должно быть прописано с новой строки, относительно пути darknet.exe. Например:data/obj/img1.jpg``data/obj/img2.jpg``data/obj/img3.jpg
- Загрузите предварительно натренированный файл весов для сверхточных слоев и поместите его в пути
build\darknet\x64
- для
yolov4.cfg, yolov4-custom.cfg
(162 MB): yolov4.conv.137 (зеркало Google диска yolov4.conv.137 ) - для
yolov4-tiny.cfg, yolov4-tiny-3l.cfg, yolov4-tiny-custom.cfg
(19 MB): yolov4-tiny.conv.29 - для
csresnext50-panet-spp.cfg
(133 MB): csresnext50-panet-spp.conv.112 - для
yolov3.cfg, yolov3-spp.cfg
(154 MB): darknet53.conv.74 - для
yolov3-tiny-prn.cfg , yolov3-tiny.cfg
(6 MB): yolov3-tiny.conv.11 - для
enet-coco.cfg (EfficientNetB0-Yolov3)
(14 MB): enetb0-coco.conv.132
- Начинайте обучение с использования командной строки:
darknet.exe detector train data/obj.data yolo-obj.cfg yolov4.conv.137
Для обучения на ОС Linux используйте команду:./darknet detector train data/obj.data yolo-obj.cfg yolov4.conv.137
(воспользуйтесь./darknet вместо darknet.exe
)
- файл
yolo-obj_last.weights
будет сохранен вbuild\darknet\x64\backup\
на каждые 1000 итераций - файл
yolo-obj_xxxx.weights
будет сохранен вbuild\darknet\x64\backup\
на каждые 1000 итераций - чтобы отключить использование
Loss-Window darknet.exe detector train data/obj.data yolo-obj.cfg yolov4.conv.137 -dont_show
, если обучение нейросети проходит на компьютере без монитора, например в облаке Amazon EC2 - чтобы увидеть график параметров mAP & Loss во время обучения на удаленном сервере без графического интерфейса (GUI), воспользуйтесь командой
darknet.exe detector train data/obj.data yolo-obj.cfg yolov4.conv.137 -dont_show -mjpeg_port 8090 -map
, далее откройте URL-адресhttp://ip-address:8090
в браузерах Chrome/Firefox
8.1. Для обучения с параметром mAP (mean average precisions/средняя точность), который вычисляется каждые 4 эпохи,установите valid=valid.txt
или train.txt
в файле obj.data
и запустите: darknet.exe detector train data/obj.data yolo-obj.cfg yolov4.conv.137 -map
После завершения обучения, вы получите файл весов, yolo-obj_final.weights
который будет находиться в пути build\darknet\x64\backup\
Через каждые 100 итераций, вы можете приостановить обучение и в дальнейшем начать с того же момента, где остановили обучение. Например, после 2000 итераций вы можете приостановить обучение, а позже начать его, используя: darknet.exe detector train data/obj.data yolo-obj.cfg backup\yolo-obj_2000.weights
( в исходном репозитории файл весов сохраняется только через каждые 10 000 итераций if(iterations > 1000)
)
Результат может быть получен ранее, чем через 45000 итераций.
NOTE
- Если во время обучения вы видите nan значения у поля
avg
(потери), значит обучение идет неправильно, а если nan расположен в каких-либо других строках – вы все делаете верно.
- Если вы изменяете параметр
width=
orheight=
in cfg-file, новая высота и ширина должны быть делителем числа 32.
После обучения нейросети используйте следующую команду для обучения: darknet.exe detector test data/obj.data yolo-obj.cfg yolo-obj_8000.weights
если появляется ошибка Out of memory
, тогда в.cfg-файле увеличьте параметр subdivisions=16
, 32
или 64
: link
Как обучать tiny-yolo?
Проделайте те же шаги, что и для модели full yolo model, как было описано выше в руководстве, за исключением следующего:
- Скачайте файл с первыми 29 сверточными слоями yolov4-tiny: https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v4_pre/yolov4-tiny.conv.29 (Или загрузите этот файл с файла весов yolov4-tiny.weights. При этом используйте команду:
darknet.exe partial cfg/yolov4-tiny-custom.cfg yolov4-tiny.weights yolov4-tiny.conv.29 29
- Создайте свою модель l
yolov4-tiny-obj.cfg
на основеcfg/yolov4-tiny-custom.cfg вместо yolov4.cfg
- Начинайте обучение:
darknet.exe detector train data/obj.data yolov4-tiny-obj.cfg yolov4-tiny.conv.29
Для обучения Yolo на основе других моделей (DenseNet201-Yolo or ResNet50-Yolo), вы можете скачать и установить предварительно обученный файл весов, как показано здесь.
Если вы хотите обучить вашу модель, не основываясь на других моделях, есть возможность запустить обучение нейронной сети без предварительно натренированных весов. Тогда случайные весы будут автоматически созданы в начале обучения.
Когда останавливать обучение модели?
Обычно достаточно провести по 2000 итераций для каждого класса (объекта), но не меньше, чем количество тренировочных изображений, и не менее 6000 итераций в сумме. Однако чтобы иметь лучшее понимание о том, когда пора остановить обучение, следует придерживаться следующей инструкции:
- Во время обучения, вы можете увидеть различные индикаторы ошибок. Остановиться следует тогда, когда индикатор 0.XXXXXXX avg перестанет заметно уменьшаться:Region Avg IOU: 0.798363, Class: 0.893232, Obj: 0.700808, No Obj: 0.004567, Avg Recall: 1.000000, count: 8 Region Avg IOU: 0.800677, Class: 0.892181, Obj: 0.701590, No Obj: 0.004574, Avg Recall: 1.000000, count: 89002: 0.211667, 0.60730 avg, 0.001000 rate, 3.868000 seconds, 576128 images Loaded: 0.000000 seconds
- 9002 - порядковое число итерации
- 0.60730 avg - средняя ошибка (чем меньше, тем лучше)Когда становится понятно, что средняя ошибка 0.xxxxxx avg перестает уменьшаться, несмотря на большое количество итераций, то необходимо остановить обучение. В конце средняя ошибка может иметь значение от 0.05 (для небольшой модели и простого датасета) до 3.0 (для большой модели и сложного датасета). Или если Вы начали обучение с флагом -map тогда Вы увидите mAP-индикатор Last accuracy [email protected] = 18.50% в консоле – этот индикатор намного лучше индикатора Loss, поэтому обучение должно продолжаться, пока mAP увеличивается.
- Когда обучение остановлено, необходимо взять несколько последних файлов весов из директории
darknet\build\darknet\x64\backup
и выбрать лучший из них:К примеру, несмотря на то, что Вы остановили тренировку после 9000 итераций, наиболее точная модель могла быть получена после 7000 или 8000 итераций. Это может произойти из-за переобучения модели.Переобучение – ситуация в которой модель будет работать только на данных из тренировочного датасета.Поэтому важно получить веса из точки ранней остановки (Early Stopping Point):
Чтобы получить файл весов с Early Stopping Point (см. график):
2.1. В первую очередь, в файле obj.data
необходимо прописать путь к тестовому датасету valid = valid.txt
(формат valid.txt
как в train.txt
), и если у вас нет тестовых изображений, просто скопируйте data\train.txt в data\valid.txt
.
2.2 Если обучение прекратилось после 9000 итераций, для проверки ранее обученных файлов весов, воспользуйтесь следующей командой:
(Если вы используете другой GitHub репозиторий, воспользуйтесь darknet.exe detector recall...
вместо darknet.exe detector map...
)
darknet.exe detector map data/obj.data yolo-obj.cfg backup\yolo-obj_7000.weights
darknet.exe detector map data/obj.data yolo-obj.cfg backup\yolo-obj_8000.weights
darknet.exe detector map data/obj.data yolo-obj.cfg backup\yolo-obj_9000.weights
Сравните последние строки вывода для каждого файла весов (7000, 8000, 9000): Выберете файл весов с наибольшим показателем mAP
(mean average precision – средняя точность) или IoU
(intersect over union — пересечение по объединению).
Например, если наибольший показатель mAP получен в файле yolo-obj_8000.weights
- тогда следует использовать именно эти весы.
Или производите обучение с -map флагом:
darknet.exe detector train data/obj.data yolo-obj.cfg yolov4.conv.137 -map
Таким образом, вы увидите график mAP (red-line) поверх графика ошибок. Показатель mAP будет рассчитан для 4 эпох, используя valid=valid.txt
файл, который указан в файле obj.data
(1 Epoch = images_in_train_txt / batch итераций
).
(чтобы изменить максимальное значение по оси x, измените параметр max_batches =
на 2000*classes
, например . max_batches = 6000
для 3 классов)
Пример распознавания объектов на обученных весах: darknet.exe detector test data/obj.data yolo-obj.cfg yolo-obj_8000.weights
IoU (intersection over union – пересечение по объединению) – среднее значение IoU объектов и распознавание для определенного порога = 0.24
mAP (mean average precision) – среднее значение average precisions для каждого класса, где average precision – это среднее значение 11 точек на кривой PR для всех возможных порогов (каждая вероятность распознавания объекта) для одинакового класса (Precision-Recall с точки зрения PascalVOC, где Precision рассчитывается как : TP/(TP+FP), а Recall как TP/(TP+FN) ), страница-11
По умолчанию,mAP-- метрика точности в PascalVOC competition, то же самое, что и метрика AP50 в MS COCO competition. C точки зрения Wiki Pascal, индикаторы Precision and Recall имеют немного другое значение в PascalVOC competition, но значение IoU всегда остается неизменным.
Использование собственной модели
Пример использования собственно обученной модели: darknet.exe detector test data/obj.data yolo-obj.cfg yolo-obj_8000.weights
Как улучшить распознавание объектов?
- Что сделать до обучения модели?
-
Установить параметр random=1 в .cfg-файле – это увеличит точность через обучение Yolo для разных разрешений изображений. link
-
Увеличьте разрешение сети в .cfg-файле (height=608, width=608 или любое другое значение, кратное 32) – это увеличит точность.
-
Убедитесь, что каждый объект, который должен распознаваться моделью обязательно промаркирован в датасете – ни один объект не должен быть пропущен. В большинстве случаев проблемы возникают из-за неправильной обработки датасета. Всегда проверяйте датасет, используя: link
-
*“У меня очень большое значение ошибки и очень маленький mAP. Что делать?”*Запустить тренировку с флагом -show_imgs в конце команды. Правильно ли расположены рамки на объектах? Если нет, то проблема в датасете.
-
Для каждого объекта, который вы хотите распознавать должен быть хотя бы 1 похожий объект в тренировочном датасете с примерно одинаковыми формой, положением в пространстве, относительным размером, углом поворота, наклоном и освещением. Поэтому желательно, чтобы тренировочный датасет состоял из изображений с объектами на разном расстоянии от камеры, разным углом поворота, разным освещением, положением в пространстве и разным задним планом. В идеале необходимо собрать по 2000 изображений каждого объекта и обучать минимум 2000*(кол-во классов) итераций.
-
Желательно включать в датасет изображения с объектами, которые не нужно распознавать, не рисуя на них маркировочную рамку (что приведет к созданию пустого .txt файла). Старайтесь включить в датасет ровно столько же изображений без маркировки, сколько присутствует изображений с маркировкой.
-
Как лучше рисовать маркировочную рамку: отметить только видимую часть объекта, или отмечать и видимую часть и огороженную часть, или отмечать объект чуть большей рамкой, чем сам объект? Тут следует исходить из того, как бы вам самим хотелось, чтобы определялся объект.
-
Для обучения модели с большим количеством объектов в каждом изображении добавьте параметр max=200 или выше в последний [
yolo
]-слой или [region
]-слой в вашcfg-файл
(глобальный максимум количества объектов, которым может быть определен YoloV3 равен0,0615234375*(width*height)
гдеwidth
иheight
это параметры из [net
] секции вcfg-файле
) -
Для обучения на распознавание мелких объектов (размеры меньше чем 16x16 после того, как размер изображения изменен на 416 x 416) - установите
layers = 23
вместо -
Для обучения на распознавание как больших, так и маленьких объектов, используйте модифицированные модели
-
Если вы обучаете модель на распознавание зеркальных объектов как отдельных классов (правая/левая рука, левый/правый поворот на улице), то для отключения увеличения флип-данных добавьте
flip=0
: link -
Общее правило: тренировочный датасет должен включать в себя:Относительные размеры искомых объектов:
train_network_width * train_obj_width / train_image_width ~= detection_network_width * detection_obj_width / detection_image_width
train_network_height * train_obj_height / train_image_height ~= detection_network_height * detection_obj_height / detection_image_height
То есть, на каждый объект из тестового датасета должен быть минимум один объект в тренировочном датасете с таким же class_id
и с примерно равными относительными размерами: object width in percent from Training dataset ~= object width in percent from Test dataset
Таким образом, если объекты занимают 80-90% всей площади изображения в тренировочном сете, то обученная модель не сможет определять объекты, занимающие 1-10% изображения.
Для ускорения обучения (с уменьшением точности распознавания) установите параметр stopbackward=1
для слоя 136 в файле cfg
. каждый model of object, side, illumination, scale, each 30 grad угол поворота и наклона соответствующей нейросети. Так, чем более разнообразные объекты вы хотите распознавать, тем более сложная модель нейросети должна быть использована.
Чтобы сделать маркировочные рамки более точными, добавьте три параметра ignore_thresh = .9 iou_normalizer=0.5 iou_loss=giou
к каждому [yolo
] слою и начинайте обучение, это увеличит параметр [email protected]
, но уменьшит [email protected]
.
После тренировки для распознавания:
Увеличьте network-resolution
, устанавливая следующие параметры в.cfg файле (height=608 и width=608
) или (height=832 и width=832
) или (любой множитель 32) – это увеличивает точность и позволяет распознавать мелкие объекты: link
Нет необходимости тренировать нейросеть снова, просто используйте .weights- файл
, натренированный для разрешения 416 x 416
Для получения наивысшей точности, необходимо производить обучение с большим разрешением, 608x608 и 832x832.
NOTE
Eсли появляется ошибка Out of memory
, в файле .cfg
необходимо увеличить параметр subdivisions=16, 32 или 64
Как маркировать объекты на фотографиях, рисовать маркировочные рамки и создавать аннотации? Здесь вы можете ознакомиться с репозиторием GUI-software для маркировки объектов на фотографиях и создания файлов аннотации для Yolo v2 - v4.
Например: train.txt, obj.names, obj.data, yolo-obj.cfg, air1-6.txt, bird1-4.txt
для 2 классов объектов (air, bird
) и train_obj.cmd
с примером, как обучать сет изображений с помощью Yolo v2 - v4
Различные инструменты для маркировки объектов на изображении:
- на C++
- на Python
- на Python
- на C++
- на JavaScript
- на C++
- на C#
- DL-Annotator для Windows ($30)
- v7labs - самый большой облачный инструмент ($1.5 в час)
Как использовать Yolo как библиотеки DLL и SO
- На ОС Linux
- Использовать
build.sh
или: - Построить darknet, используя
cmake
или - Установить LIBSO=1 в Makefile и сделать
make
- Использовать
- На ОС Windows
- Использовать
build.ps1
или: - Построить darknet, используя
cmake
или - Создать решение
build\darknet\yolo_cpp_dll.sln
или ``build\darknet\yolo_cpp_dll_no_gpu.sln` Существует 2 вида API:
- Использовать
-
C API
- Примеры на Python с использованием C API:
- C++ API
- Чтобы скомпилировать Yolo как C++ DLL-файл
yolo_cpp_dll.dll
откройте решениеbuild\darknet\yolo_cpp_dll.sln
, установитеx64
иRelease
, и выполните следующие действия:Build -> Build yolo_cpp_dll
- У вас должен быть установлен CUDA 10.2
- Для использования cuDNN do: (right click on project) → properties → C/C++ → Preprocessor → Preprocessor Definitions, и добавьте в начало строки: CUDNN;
- Для использования Yolo как DLL-файл на C++ консольном приложенииоткройте решения
build\darknet\yolo_console_dll.sln
, установитеx64
иRelease
, выполните следующие команды:Build -> Build yolo_console_dll
- Вы можете запустить консольное приложение через проводник Windows Explorer build\darknet\x64\yolo_console_dll.exe, для этого используйте следующую команду:
yolo_console_dll.exe data/coco.names yolov4.cfg yolov4.weights test.mp4
- После запуска консольного приложения и ввода названия файла изображения, вы увидите следующую информацию для каждого объекта:
<obj_id> <left_x> <top_y> <width> <height> <probability>
- Для использования удобного графического интерфейса OpenCV-GUI, необходимо раскомментировать следующую строку
//#define OPENCV в yolo_console_dll.cpp-файле
: link - Ознакомиться с простым примером кода по распознаванию объектов можно по ссылке
yolo_cpp_dll.dll-API
: linkstruct bbox_t {
unsigned int x, y, w, h; // (x,y) - top-left corner, (w, h) - width & height of bounded box
float prob; // confidence - probability that the object was found correctly
unsigned int obj_id; // class of object - from range [0, classes-1]
unsigned int track_id; // tracking id for video (0 - untracked, 1 - inf - tracked object)
unsigned int frames_counter;// counter of frames on which the object was detected };
class Detector {
public:
` Detector(std::string cfg_filename, std::string weight_filename, int gpu_id = 0);
~Detector();`
`std::vector<bbox_t> detect(std::string image_filename, float thresh = 0.2, bool use_mean = false);`
`std::vector<bbox_t> detect(image_t img, float thresh = 0.2, bool use_mean = false);`
` static image_t load_image(std::string image_filename);`
`static void free_image(image_t m);`
#ifdef OPENCV
std::vector<bbox_t> detect(cv::Mat mat, float thresh = 0.2, bool use_mean = false);
std::shared_ptr<image_t> mat_to_image_resize(cv::Mat mat) const;
#endif
};`
Фонд «Beyond Curriculum» публикует цикл материалов в рамках проекта «Beyond Robotics» при поддержке государственно-частного партнёрства «Шеврон» и Посольства США в Казахстане.