Нейросети и машинное обучение — перспективная отрасль IT, с каждым годом ML-технологии все глубже проникают в разные сферы, включая бизнес, медицину, науку. Понимая все это, я решил выбрать направление машинного обучения в качестве своей профессии. Меня зовут Артем Раздьяконов, я студент курса “Data Scientist PRO” в Skillbox.

Но сегодня хотел бы рассказать не о своей учебе, а о первом крупном проекте — системе распознавания эмоций. Сразу скажу, что это статья для таких же начинающих, как и я сам. Возможно, кто-то из новичков найдет что-то полезное для себя. Ну а если у профи будут советы — то я только рад. Задавайте в комментариях вопросы, постараюсь на все ответить. Ну а пока — поехали!

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

Процесс подготовки данных

На первом этапе я подготовил необходимый для нейросети набор данных. Он включал 9 папок, в каждой из которых находился мой снимок, демонстрирующий какую-либо эмоцию. Количество фотографий каждого класса составило около 6000 изображений, выборка сбалансированная. Кроме того, в архив test_kaggle входило 5000 снимков совершенно разных эмоций, то есть изображения не были маркированы каким-либо классом. Общее количество снимков для тренировки — 40000. Для валидации — 10000.

Немного расскажу о процессе подготовки изображений. Я выбрал такой сценарий работы: данные загружались из Google Drive в локальное хранилище блокнота Colab.  После этого создавался генератор с указанием валидационной выборки. Затем — параметры для аугментации данных. Поскольку данные изначально были отсортированы по папкам каждого класса, использовался метод flow_from_directory.

Выбор архитектуры моделей

Это один из важнейших этапов. Изначально я решил создать простую сверточную сеть с использованием EarlyStopping и ReduceLROnPlateau во избежание переобучения. Итоговая модель вышла на плато при значениях accuracy на валидации в ~0,45.

Отмечу, что старался максимально использовать существующие наработки. Помню, мой преподаватель, Алексей Мастов, говорил, что для классификации в боевых условиях проще всего использовать архитектуры из зоопарка моделей. Другими словами, велосипед в данном случае изобретать не обязательно; лучше взять готовые решения.

Архитектуру я выбирал при помощи статьи "Image Classification Using Pre-trained models". Решил выбрать три архитектуры: MobileNet V2, VGG19 и ResNet50. Главные критерии при выборе — небольшое время инференса и доступность.

Обучение модели

В случае использования этих трех архитектур обучение реализуется при помощи  transfer learning и fine-tuning. Первый касается лишь выходного слоя, который может меняться в соответствии с конкретной задачей. Второй же предполагает обучение либо всех, либо значительной части слоев модели.

Архитектура любой сверточной нейронной сети (а я в своей работе использую именно такую сеть) сконструирована так, чтобы она могла находить и “учить” важные признаки из данных с помощью конволюций или свёрток. Вот интересная ссылка на исследование группы ученых, где наглядно показано, что “видят” нейронные сети. Демонстрация реализована путём визуализации активаций их фильтров на разных слоях. Поначалу фильтры слоев обучаются различать границы или текстуры. По мере продвижения от слоя к слою появляются различия в паттернах, частях объектов, а на финишной прямой — видны и отдельные объекты.

Признаки, которые архитектуры вычленили из ImageNet, отличаются от потенциальных признаков нашего кейса. Так как, скажем, разница между классами «жираф» и «кружка» гораздо больше, чем между эмоциями «радость» и «нейтральное поведение». Дело том, что в первом случае различие между классами может быть заметно уже на этапе границ, а во втором — только на этапе отдельных объектов. У жирафа очень длинная шея и есть 4 ноги, а кружка просто имеет форму цилиндра с ручкой. В свою очередь весёлое и грустное лицо отличаются характерными мимическими признаками, которые проявляются в зависимости от настроения человека. Соответственно, нам необходимо заново обучить все слои, чтобы сеть определила новые признаки. 

Именно поэтому я решил тренировать все слои моделей. Тренировка проводилась на базе GPU. Три модели показали следующие значения Accuracy на валидации: VGG19 0.51, ResNet50 0.49 и MobileNet V2 0.46 (кстати, дополнительную информацию о моделях можно получить при сканировании QR-кода).  

Я выбрал VGG19 для работы, изучив инференс. Получилось 58-66 мс на 1 кадр против максимально допустимых 33 мс. Для того чтобы ускорить процесс, доведя результат до нормы, я применил пакет TensorRT с собственным "инференс-движком", который относительно недавно был встроен непосредственно в библиотеку TensorFlow. После подобной модификации модели скорость инференса приблизилась к значениям 5-10 мс на 1 кадр.

Ну а потом дело за малым — нужно сформировать файл для отправки на Kagglе, после чего — скачать архив с тестовыми изображениями, прогнать их все через модель, получить предсказания и отформатировать их. Да, есть важный нюанс — форматировать требуется в алфавитном порядке. Так, индекс «0» соответствует названию эмоции, которая идёт раньше всех. Итоговый файл .csv должен был включать строчки вида «название фотографии», эмоция. 

Детектируем эмоцию в кадре

Для того, чтобы решить эту задачу, нужно сначала научить нейросеть находить лицо. Проблема в том, что в кадр попадает вовсе не обрезанное изображение, вроде тех что содержались в базе для обучения. Для этого я решил применить детектор из OpenCV. После детекции лица результат отправляется на вход в сеть, а затем над bounding box выводится классифицированная эмоция.

Что в итоге?

С использованием разработанной модели классификации эмоций была создана система детектирования 9 состояний. Для удобства я создал как чисто скриптовую версию, так и версию с исполняемым файлом. Для этого я использовал пакет auto-py-to-exe.

Да, в скрипте я контролирую то, каким образом прописан путь к моделям. Это нужно для того, чтобы корректно отработал auto-py-to-exe в процессе создания исполнения файла, а также на тот случай, если кто-то решит запустить сам скрипт у себя на ПК.

Познакомиться с проектом, скачать его и потестировать возможности можно по ссылке. Ну а вот ссылка на курс “Data Scientist PRO” в Skillbox.

Комментарии (4)


  1. IgorPie
    10.12.2021 03:44
    +3

    Что-то содержательности не хватает. Про использование GPU написали, а откуда взяли датасет и разметку - не написали.

    Сканировать QR код? С ходу не понимаю чем, т.к. читаю с телефона. Эх, а были времена, когда картинки были кликабельны.


  1. LastNormal
    10.12.2021 08:31

    Выбор на тензор вместо пайторча просто из-за вкуса? Или какие то специфические фичи?


  1. bBars
    10.12.2021 18:07
    +2

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

    Возьмём такую-то библиотеку. Поразмышляем над тем, сделать ли X самому или взять готовое. — Пфф, зачем городить велосипед, если есть готовое? Берём готовое. Берём предобученую модель, но ещё с ней что-то сделаем, вот у меня есть фоточки (зачем брать обученную, если задача какая-то другая?). Я картинки по папкам распихал, натравил на них нейросеть. Вот моя первая нейросеть!

    Где вот эти проблемы и решения: как разбить задачу на подзадачи "найти лицо" и "определить эмоцию". Где это всё происходит? Как правильно спроектировать? Вот тут у нас N входов, вот тут нам нужен один такой-то слой для выполнения такой-то функции, вот тут ещё такой-то, вот тут нам нужна функция активации такая-то, потому что вот то-то — где эти все размышления (и объяснения)? Почему разработчик не касается этих вопросов?

    Статьи, которые я нахожу, делятся на "Давайте изучим терминологию и матаппарат", "Первая нейросеть XOR" и "Моделируем процесс сворачивания белка с помощью X, конволюции свёртки хостинг фистинг". Неужели нет доступных статей, которые начинаются с слов "вы поняли почти всё, что сказано про матаппарат, скоро поймёте и остальное, давайте сделаем кое-что посерьёзнее XOR, расчехляйте свой vim, погнали"?


  1. MegaMANGO
    11.12.2021 03:37

    Норм. Под чаёк заходит