По мотивам диссертации на степень магистра робототехники я решил написать трилогию статей. За этим стоит стремление поделиться открытиями и знаниями, которые я приобрел в этом волшебном путешествии. Эти три статьи в основном будут иметь форму пошаговых руководств по кодированию, в которых теоретически будут объяснены многие технические решения, которые были сделаны.

Прежде чем приступить к реализации, давайте немного поговорим о поле Распознавания мимики (FER):

FER - это область научных исследований, которая занимается техниками и методами, которые пытаются идентифицировать / делать выводы об эмоциональных состояниях по выражению лица. В человеческом общении мимика играет решающую роль в выводе эмоций, которые потенциально могут помочь в понимании намерений других. Согласно различным опросам [1, 2], вербальные компоненты передают только одну треть межличностного общения, а невербальные компоненты передают две трети. Большинство сообщений, связанных с отношениями и чувствами, содержится в выражениях лица. Таким образом, выражение лица играет жизненно важную роль во всем процессе обмена информацией. Выражения и эмоции неразрывно связаны. Экман и Фризен в [3] инициировали первую волну базовой теории эмоций, вдохновленной исследованиями эмоционального выражения. Они использовали неподвижные фотографии прототипов эмоциональных выражений лица и задокументировали некоторую степень универсальности в распознавании и порождении ограниченного набора «базовых» эмоций (счастье 😀, удивление 😮, страх 😨, отвращение 🤮, печаль 😭 и гнев 😡).

Эти 6 категорий также будут использоваться для нашей задачи, а CK + 48 [4] - это выбранный набор данных, который поможет нам обучить и оценить нашу модель. Вся реализация проходила в Google Colab с использованием ускорения графического процессора. Итак, без лишних слов, давайте перейдем к нашей задаче ...

Предварительная обработка данных ✂️

A) Перво-наперво, давайте импортируем необходимые библиотеки, как показано ниже.

Сразу после сохранения набора данных на Google Диске вам необходимо смонтировать диск и перейти в каталог, содержащий ваш набор данных.

Следующим шагом будет загрузка наших данных в память, поэтому я создал две вспомогательные функции, чтобы упростить задачу. Ниже вы можете увидеть их строки документации, которые описывают их функции (чтобы избежать огромных фрагментов кода в статье). Конечно, вы можете найти полный код в моей учетной записи GitHub.

А вот так выглядит наше распределение данных.

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

Б) Набор данных, который я использовал, включает 927 изображений формы 48x48x3. После этого мы случайным образом разбили набор данных на обучающий (70%), проверочный (15%) и тестовый (15%) наборы (обычно говоря, это считается хорошим практическим правилом для разделения наших данных).

Ориентировочный отпечаток раскола показан ниже.

X_train has shape: (648, 48, 48, 3) y_train has shape: (648, 6)  X_valid has shape: (139, 48, 48, 3) y_valid has shape: (139, 6)  X_test has shape: (140, 48, 48, 3) y_test has shape: (140, 6)
X_train + X_valid + X_test = 927 samples in total

Примечание. Очень важно, чтобы наш набор для проверки и тестирования был взят из одного и того же дистрибутива. Доктор Эндрю Нг в этом видео замечательно (и легко усваивается) объясняет причину. Дело в том, что наши данные поступают из одного и того же распределения (поскольку они создаются в рамках лабораторных ограничений), но в значительной степени неравное количество выборок среди некоторых классов в сочетании с относительно небольшим объемом данных может нанести ущерб эффективности модели. В идеале мы должны каким-то образом контролировать ~ 140 образцов для X_valid и X_test, выделив ~ 23 разных примера из каждой категории.

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

Примечание. Не все параметры класса ImageDataGenerator актуальны. Мы должны быть осторожны с этим. Например, переворот по вертикали не имеет значения для нашей задачи и предположительно может нанести ущерб точности модели.

Некоторые примеры аугментации, примененной к обучающим выборкам, показаны ниже.

Создание и настройка модели 🚀

Я создал функцию build_model, которая загружает модель EfficientNetB0, предварительно обученную в ImageNet (без ее исходного классификатора), и добавляет еще 3 слоя вверху, как вы можете видеть ниже. Идея выбрать всего 3 слоя (а не что-то более сложное) пришла из официальной документации Keras, в которой показано, как настроить EfficientNet на классификации изображений. Кроме того, эта функция компилирует модель с оптимизатором Адама, категориальной функцией кросс-энтропийных потерь и точностью в качестве метрики.

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

Что касается фазы обучения, я использовал 3 очень полезных обратных вызова:

  • ModelCheckPoint: сохраняет веса модели, с которой достигнута наилучшая точность проверки.
  • EarlyStopping: если точность проверки не повышается в течение 15 последовательных эпох, обучение будет прервано (этот обратный вызов предотвращает переобучение)
  • ReduceLROnPlateaue: это планировщик, который снижает скорость обучения (вдвое) каждый раз, когда точность проверки падает.

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

Примечание. Что касается размера партии, я экспериментировал с диапазоном значений. Для пакетов размером 16 и 32 время обучения увеличилось (и это имеет значение, особенно когда набор данных значительно велик), в то время как точность проверки не была даже выше по сравнению с пакетом из 64 образцов. С другой стороны, пакет из 128 образцов, конечно, ускорил процедуру обучения, однако не только проверка не была лучше, но и наблюдались значительные колебания кривых обучения (что, возможно, могло помешать сходимости модель).

Примечание. При создании этой модели я понял две очень важные вещи: (1) D, несмотря на то, что в большинстве случаев Пиксельная нормализация применяется к входным изображениям, EfficientNet все равно делает это со своими слоями Rescale, и, таким образом, дальнейшее попиксельное деление со значением 255 может повредить производительности модели. (2) D. Несмотря на то, что модель принимает в качестве входных тензоров формы (224, 224, 3), я понял, что лучшая производительность достигается при изменении входного слоя для получения тензоров формы (48, 48, 3) вместо масштабирования набора данных до 224x224. Единственным релевантным источником, который мне удалось найти, был Адриан Роузброк в одной из его статей на pyimagesearch.com.

Кривые обучения 📈 📉

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

Модель, кажется, вполне соответствует новым данным с довольно небольшим пробелом в обобщении. Точность обучения и проверки составляет примерно 98-99%. Однако веса лучшей версии модели будут загружены автоматически.

Окончательная оценка 🔮

Наконец, мы собираемся протестировать нашу модель на образцах, которые она больше не видела. Этот набор является тестовым набором, взятым из нашего исходного набора данных. Модель достигла точности 96,43% ,, а прогнозы отображаются в виде матрицы неточностей, чтобы мы могли тщательно проверить ошибочные классификации модели.

Как вы можете видеть из этой матрицы, класс «печаль» по сути является причиной проблемы. Однако это абсолютно разумно из-за небольшого количества доступных примеров. Кроме того, не забывайте, что даже для человека выражения лица, выражающие грусть, страх, отвращение или гнев, могут в любом случае сбивать с толку, и это может стать очевидным, если вы проверите расширенные образцы выражений лица выше и попытаетесь предсказать класс каждое выражение по своему усмотрению. Вы поймете, что эта задача связана с трудностями даже для людей.

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

Заключение 🏆

В этой статье мы увидели, как создать классификатор выражений лица, который может предсказывать эмоции. Для этого набора данных (CK + 48) достижение точности 96,43% близко к современным характеристикам, а в В следующей статье этой трилогии мы собираемся применить технику визуализации (GradCam), которая выявляет области изображения, которые играют решающую роль для модели, чтобы делать выводы, применяя тепловые карты к исходным изображениям. Такие методы очень важны для подходов к глубокому обучению, поскольку они способствуют объяснимости и интерпретируемости модели. Итак, на нашей следующей встрече мы увидим, как мы можем интерпретировать неточности нашей модели и как мы можем ее улучшить.

Большое вам спасибо за ваше время! (Полный проект можно найти здесь).

использованная литература

[1] Альберт Мехрабиан. Общение без слов. Теория коммуникации, стр. 193–200, 2008.

[2] Катрин Каулард, Дуглас Каннингем, Генрих Х. Бюлтхофф и Кристиан Уоллрэйвен. База данных выражений лица mpi - проверенная база данных эмоциональных и разговорных выражений лица. PloS one, 7 (3), 2012.

[3] Пол Экман, Э. Ричард Соренсон и Уоллес В. Фризен. Панкультурные элементы в выражениях эмоций на лице. Science, 164 (3875): 86–88, 1969.

[4] Патрик Люси, Джеффри Ф. Кон, Такео Канаде, Джейсон Сараги, Зара Амбадар и Иэн Мэтьюз. Расширенный набор данных cohn-kanade (ck +): полный набор данных для единицы действия и выражения эмоции. В 2010 г. конференция компьютерного общества IEee по компьютерному зрению и распознаванию образов - семинары, страницы 94–101. IEEE, 2010 г.