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 файлов, чтобы завершить подготовку и начать обучение модели.
- 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 на пользовательском наборе данных. Я надеюсь, что вы сочли полезным. Не стесняйтесь оставлять отзывы или задавать любые соответствующие вопросы.
Большое спасибо за уделенное время! До скорой встречи ... 😜