Часть.2 Перевод: Фреймворк Darknet. Обучение Yolo v4

Внимание! Это руководство предназначено для людей, имеющих базовые познания в YOLO. В рамках проекта Beyond Robotics, с 1 по 15 июля будет выходить ряд видеоуроков, посвященных этому фреймворку.

Как тренировать нейросеть на нескольких видеокартах?

  1. Начните тренировать нейросеть на 1 видеокарте на 1000 итераций: darknet.exe detector train cfg/coco.data cfg/yolov4.cfg yolov4.conv.137
  2. Далее, остановите обучение, используя частично тренированную модель /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):

  1. Для обучения cfg/yolov4-custom.cfg загрузите предтренировочный файл весов (162 MB): yolov4.conv.137 (зеркало yolov4.conv.137)
  2. Создайте файл yolo-obj.cfg с таким же содержанием, как в yolov4-custom.cfg (или скопируйте yolov4-custom.cfg в yolo-obj.cfg)

NOTE

Помните, что менять значение нужно только в последнем сверточном[convolutional] слое, перед каждым [yolo] слоем.


Таким образом, если параметр 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

  1. Создайте файл obj.names в пути build\darknet\x64\data\, с названиями объектов, которые хотите распознать. При этом название каждого объекта должно быть расположено в новой строке.
  2. Создайте файл obj.data в пути build\darknet\x64\data\, со следующим содержанием (где classes = число объектов):

classes = 2

train = data/train.txt

valid = data/test.txt

names = data/obj.names

backup = backup/

  1. Поместите изображение ваших объектов в формате (.jpg) в пути build\darknet\x64\data\obj\ Необходимо проставить отметки на каждый объект на изображении (label) из вашего датасета. Используйте GUI для того, чтобы создать маркировочные рамки объектов и файлы аннотаций для Yolo v2 & v3

  2. Создайте .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

  1. Создайте файл train.txt в пути build\darknet\x64\data\, который будет содержать в себе названия всех файлов c вашими изображениями, при этом каждое название должно быть прописано с новой строки, относительно пути darknet.exe. Например: data/obj/img1.jpg

    data/obj/img2.jpg

    data/obj/img3.jpg

  2. Загрузите предварительно натренированный файл весов для сверхточных слоев и поместите его в пути build\darknet\x64

  3. Начинайте обучение с использования командной строки: 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= or height= 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 итераций в сумме. Однако чтобы иметь лучшее понимание о том, когда пора остановить обучение, следует придерживаться следующей инструкции:

  1. Во время обучения, вы можете увидеть различные индикаторы ошибок. Остановиться следует тогда, когда индикатор 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: 8

    9002: 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 увеличивается.

  2. Когда обучение остановлено, необходимо взять несколько последних файлов весов из директории darknet\build\darknet\x64\backup и выбрать лучший из них:

    К примеру, несмотря на то, что Вы остановили тренировку после 9000 итераций, наиболее точная модель могла быть получена после 7000 или 8000 итераций. Это может произойти из-за переобучения модели.

    Переобучение -- ситуация в которой модель будет работать только на данных из тренировочного датасета.

    Поэтому важно получить веса из точки ранней остановки (Early Stopping Point):


    68747470733a2f2f6873746f2e6f72672f66696c65732f3564632f3761652f3766612f35646337616537666164396434653365623361343834633538626663316666352e706e67.png


    Чтобы получить файл весов с 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 классов)

68747470733a2f2f6873746f2e6f72672f776562742f79642f766c2f61672f7964766c616775746f66327a636e6a6f64737467726f656e3861632e6a706567.jpg

Пример распознавания объектов на обученных весах: 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 всегда остается неизменным.

68747470733a2f2f6873746f2e6f72672f66696c65732f6361382f3836362f6437362f63613838363664373666623834303232383934306462663434326137663036612e6a7067.jpg

Использование собственной модели

Пример использования собственно обученной модели: darknet.exe detector test data/obj.data yolo-obj.cfg yolo-obj_8000.weights

Untitled design.jpg

Как улучшить распознавание объектов?

  1. Что сделать до обучения модели?

    • Установить параметр 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 вместо

  • Для обучения на распознавание как больших, так и маленьких объектов, используйте модифицированные модели

  • Полная модель: 5 yolo слоев

  • Если вы обучаете модель на распознавание зеркальных объектов как отдельных классов (правая/левая рука, левый/правый поворот на улице), то для отключения увеличения флип-данных добавьте 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

Различные инструменты для маркировки объектов на изображении:

Как использовать Yolo как библиотеки DLL и SO


  1. Чтобы скомпилировать 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;
  2. Для использования 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: link struct 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
         };`
      
         <br>
      

Фонд «Beyond Curriculum» публикует цикл материалов в рамках проекта «Beyond Robotics» при поддержке государственно-частного партнёрства «Шеврон» и Посольства США в Казахстане.