COVID-19: Учебное пособие по созданию детектора маски для лица с помощью YOLOv3. * Для вывода могут использоваться как видеопотоки, так и изображения.

Эта статья призвана предложить полные инструкции (пошаговые) для тех, кто хочет обучить детектор объектов из семейства YOLO работе с пользовательскими данными. В связи с пандемией такая задача представляется весьма актуальной.

Для этого урока я собираюсь использовать YOLOv3, одну из наиболее часто используемых версий семейства YOLO, которая включает в себя современную систему обнаружения объектов для сценария в реальном времени, и она удивительно точна и быстро. Более новые версии, такие как YOLOv4, YOLOv5, могут достичь еще лучших результатов, и в своих следующих статьях я собираюсь также поэкспериментировать с этими архитектурами и поделиться с вами своими выводами.

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

Вы можете найти этот проект загруженным в моем репо на Github.

Окружающая среда 🌠

Для реализации этого проекта я использовал ресурсы Google Colab. Мои первые эксперименты с этапами предварительной обработки были проведены на моем ноутбуке, поскольку они не требовали больших вычислительных затрат, но модель была обучена на Colab с использованием GPU.

Набор данных 📚

Перво-наперво, чтобы построить детектор масок, нам нужны соответствующие данные. Кроме того, из-за природы YOLO нам нужны аннотированные данные с ограничивающими рамками. Один из вариантов - создать собственный набор данных, собирая изображения из Интернета или фотографируя друзей / знакомых и аннотируя их вручную с помощью специальных программ, таких как LabelImg. Однако обе идеи были бы исключительно утомительными и трудоемкими (особенно последнее). Другой вариант, который на сегодняшний день является наиболее жизнеспособным для моей цели, - использовать общедоступный набор данных. Я выбрал Набор данных Face Mask Detection от Kaggle и загрузил его прямо на свой Google Диск (вы можете узнать, как это сделать здесь). Загруженный набор данных состоит из двух папок:

  • изображения, состоящий из 853 файлов .png.
  • аннотации, состоящие из 853 соответствующих XML-аннотаций.

После загрузки набора данных нам нужно преобразовать файлы .xml в .txt и, точнее, нам нужно создать формат YOLO, чтобы обучить нашу модель. Пример показан ниже:

Чтобы создать файл .txt, нам нужно по 5 вещей из каждого файла .xml. Для каждого ‹object›… ‹/object› в файле .xml выберите класс (а именно the ‹name›… ‹/name› поле) и координаты ограничивающей рамки (а именно 4 атрибута в ‹bndbox›… ‹/bndbox›). Желаемый формат выглядит так:

<class_name> <x_center> <y_center> <width> <height>

Однако для этого я создал сценарий, который выбирает 5 вышеупомянутых атрибутов для каждого объекта в каждом файле .xml и создает соответствующие файлы .txt. (Примечание: в моем скрипте можно найти более подробные аналитические шаги, касающиеся подхода к преобразованию).

Например, с image1.jpg должен быть связан image1.txt, содержащий:

1 0.18359375 0.337431693989071 0.05859375 0.10109289617486339
0 0.4013671875 0.3333333333333333 0.080078125 0.12021857923497267
1 0.6689453125 0.3155737704918033 0.068359375 0.13934426229508196

И это точное преобразование указанного выше файла .xml в файл .txt. (Примечание. Крайне важно сгруппировать в одну папку изображения с соответствующими аннотациями .txt).

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

И тогда мы знаем, что пока у нас все хорошо, но давайте продолжим ...

Поезд-тестовый сплит ❇️

Чтобы обучить нашу модель и проверить ее на этапе обучения, мы должны разделить наши данные на два набора: обучающий и проверочный. Соотношение составляло 90–10% соответственно. Итак, я создал две новые папки и поместил 86 изображений с соответствующими аннотациями в test_folder, а остальные 767 изображений в train_folder.

Потерпите еще немного, нам нужны последние штрихи, и мы готовы обучать нашу модель 😅

Клонировать фреймворк даркнет ⬇️

Следующим шагом будет клонирование репозитория darknet, запустив:

!git clone https://github.com/AlexeyAB/darknet

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

!wget https://pjreddie.com/media/files/darknet53.conv.74

darknet53.conv.74 - это основа сети YOLOv3, которая изначально обучена для классификации в наборе данных ImageNet и играет роль экстрактора. Чтобы использовать это для обнаружения, дополнительные веса, которые присутствуют в сети YOLOv3, случайным образом инициализируются перед обучением. Но, конечно, они получат свои истинные ценности на этапе обучения.

Последний шаг 🚨

Нам нужно создать 5 файлов, чтобы завершить подготовку и начать обучение модели.

  1. face_mask.names: создайте файл _ .names, содержащий классы проблемы. В нашем случае исходный набор данных Kaggle имеет 3 категории: with_mask, without_mask и mask_weared_incorrect. Чтобы немного упростить задачу, я объединил две последние категории в одну. Таким образом, для нашей задачи у нас есть две категории: Хорошо и Плохо в зависимости от того, правильно ли кто-то носит маску.
1. Good
2. Bad

2. face_mask.data: создайте файл _ .data, который включает соответствующую информацию по нашей проблеме, и он будет использоваться из программы:

classes = 2
train = data/train.txt
valid  = data/test.txt
names = data/face_mask.names
backup = backup/

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

3. face_mask.cfg: этот файл конфигурации должен быть адаптирован к нашей проблеме, а именно нам нужно скопировать yolov3.cfg, переименовать его в _.cfg и применить поправки. как описано ниже:

  • измените строку batch на batch = 64
  • измените подразделение строки на subdivisions = 16 (Примечание: в случае возникновения проблемы нехватки памяти увеличьте это значение до 32 или 64)
  • измените входные размеры на значения по умолчанию width = 416, height = 416. (Примечание: лично я начал с этого разрешения и обучил свою модель 4000 итераций, но для достижения более точных прогнозов я увеличил разрешение и продолжил процесс обучения еще на 3000 итераций ).
  • измените строку max_batches на (#classes * 2000), таким образом, 4000 итераций для нашей задачи (Примечание: если у вас только одна категория, вы не должны тренироваться ваша модель рассчитана всего на 2000 итераций. Рекомендуется, чтобы 4000 итераций были минимальным количеством итераций для модели).
  • измените шаг строки на 80% и 90% от max_batches. Для нашего случая 80/100 * 4000 = 3200, 90/100 * 4000 = 3600.
  • Используйте ctrl + F и найдите слово «yolo». Это приведет вас прямо к yolo_layers, где вы хотите сделать 2 вещи. Измените количество классов (для нашего случая classes = 2) и измените количество фильтров на две правые переменные над строкой [yolo]. Это изменение должно иметь вид filter = (classes + 5) * 3, а именно filter = (2 + 5) * 3 = 21 для нашей задачи. В нашем файле .cfg есть 3 слоя yolo_layers, поэтому вы должны сделать вышеупомянутые изменения 3 раза.

4. Файлы train.txt и test.txt: эти два файла включены в файл face_mask.data и указывают абсолютный путь для каждого изображения к модели. Например, фрагмент моего файла train.txt выглядит так:

/content/gdrive/MyDrive/face_mask_detection/mask_yolo_train/maksssksksss734.png
/content/gdrive/MyDrive/face_mask_detection/mask_yolo_train/maksssksksss735.png
/content/gdrive/MyDrive/face_mask_detection/mask_yolo_train/maksssksksss736.png
/content/gdrive/MyDrive/face_mask_detection/mask_yolo_train/maksssksksss737.png
/content/gdrive/MyDrive/face_mask_detection/mask_yolo_train/maksssksksss738.png
...

(Примечание: как я упоминал ранее, файлы .png должны находиться в той же папке с соответствующими аннотациями .txt)

Следовательно, наш проект имеет такую ​​структуру:

MyDrive
├──darknet
      ├──...
      ├──backup
      ├──...
      ├──cfg
            ├──face_mask.cfg
      ├──...
      ├──data
            ├──face_mask.data
            ├──face_mask.names
            ├──train.txt
            ├──test.txt
├──face_mask_detection
      ├──annotations       (contains original .xml files)
      ├──images            (contains the original .png images)
      ├──mask_yolo_test    (contains .png % .txt files for testing)
      ├──mask_yolo_train   (contains .png % .txt files for training)
      ├── show_bb.py
      └── xml_to_yolo.py

Пусть начнётся ... тренировка 📈

После того, как мы скомпилировали модель, нам нужно изменить соответствующие разрешения, как показано ниже:

!chmod +x ./darknet

и, наконец, мы можем начать обучение, запустив:

!./darknet detector train data/face_mask.data cfg/face_mask.cfg backup/face_mask_last.weights -dont_show -i 0 -map

Флаг -map будет информировать нас о ходе обучения путем распечатки важных показателей, таких как средняя потеря, точность, отзыв, средняя точность (AP), meanAveragePrecsion (mAP) и т. Д.

Однако индикатор mAP в консоли считается лучшим показателем, чем потеря, поэтому тренируйтесь, пока mAP увеличивается.

(Примечание: процесс обучения может занять много часов в зависимости от различных параметров ... это нормально. Для этого проекта, чтобы обучить мою модель до этого момента , Мне понадобилось около 15 часов. Но первые впечатления от модели я получил примерно за 7 часов, которые прошли 4000 шагов обучения).

Пришло время тестирования (и обсуждения) 🎉

И да… модель готова к демонстрации !!! Давайте попробуем несколько изображений, которых он никогда раньше не видел. Для этого нам нужно запустить:

!./darknet detector test data/face_mask.data cfg/face_mask.cfg backup/face_mask_best.weights

Вы заметили, что мы использовали face_mask_best.weights, а не face_mask_final.weights? К счастью, наша модель сохраняет лучшие веса (mAP. 5 87,16%) в папке резервного копирования на случай, если мы обучим его большему количеству эпох, чем должно быть (что может привести к переобучению).

Примеры, которые показаны ниже, были взяты из Pexels, представляют собой изображения с высоким разрешением, и невооруженным глазом я бы сказал, что они сильно отличаются от наборов данных для обучения / тестирования из разных точек, и поэтому они имеют разное распространение. Я выбрал такие картинки, чтобы увидеть, насколько хорошо модель обобщает.

В приведенных выше примерах модель точна и достаточно уверена в своих прогнозах. Примечательно то, что изображение справа не запутало модель с существованием маски на земном шаре. Это показывает, что прогнозы основаны не только на существовании маски, но и на окружающем ее контексте.

Эти два являются примерами, которые, очевидно, показывают, что изображенные люди не носят маски, и модели также довольно легко это различить.

В этих двух приведенных выше примерах мы можем проверить производительность модели в случаях, когда появляются обе категории. Вызывает восхищение тот факт, что модель даже распознает лица на размытом фоне. Я также заметил, что его предварительный прогноз, для которого он не так уверен (только 38% в чистой области), по сравнению с прогнозом сразу после него (100% в размытой области), может быть связан с качеством набора данных, который обучены, и поэтому кажется, что на него в определенной степени повлияли (по крайней мере, это не неточно).

Последний тест 🐵

Конечно, большим преимуществом YOLO является его скорость. По этой причине я также хочу показать вам, как это работает, когда на вход поступает видео:

!./darknet detector demo data/face_mask.data cfg/face_mask.cfg backup/face_mask_best.weights -dont_show vid1.mp4 -i 0 -out_filename res1.avi

Заключение 👏

Это было мое первое пошаговое руководство по созданию собственного детектора с использованием YOLOv3 на пользовательском наборе данных. Я надеюсь, что вы сочли полезным. Не стесняйтесь оставлять отзывы или задавать любые соответствующие вопросы.

Большое спасибо за уделенное время! До скорой встречи ... 😜