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

Основная проблема заключается в том, что сложно преобразовать искривление 43 лицевых мышц в эмоции. Для людей это легко, потому что у нас есть годы практики, но компьютеры видят мир как сетку чисел, которые представляют значения пикселей. Мы можем смотреть на изображение лица человека и легко различать улыбку и хмурый взгляд, но для модели машинного обучения это гораздо более сложная задача. Чтобы решить эту проблему, мы собираемся использовать глубокую сверточную нейронную сеть, реализованную в среде машинного обучения под названием Keras. Давайте начнем!

Что такое сверточная нейронная сеть?

Сверточная нейронная сеть извлекает признаки из 2D-данных и присваивает им веса, что в конечном итоге приводит к предсказанию. Например, если бы мы хотели обучить CNN распознавать рукописные числа, у нас был бы набор данных из изображений чисел размером 100x100 пикселей. CNN распознает кривые и прямые линии на участках размером 10x10 пикселей, и после обнаружения этих особенностей модель узнает, что комбинации определенных кривых и линий указывают на определенные числа. Особенно пышное число, такое как 8, будет отличаться от прямого числа, такого как 1 или 7. В случае обнаружения эмоций лица восходящие изгибы улыбки будут ассоциироваться со счастьем.

Почему глубокое обучение?

В настоящее время исследователи используют расстояние между лицевыми ориентирами для обнаружения эмоций. Лицо представлено как положение носа, глаз, рта, щек и других областей, а затем вычисляются расстояния между этими точками. Затем устанавливаются пороговые значения для обнаружения эмоции. Если лицо на изображении улыбается, щеки располагаются ближе к глазам, рот растягивается, а глаза прищуриваются. Этот подход работает в контролируемых настройках, но что, если вы можете видеть только половину лица на изображении? Что делать, если лицо немного повернуто? Чтобы получить точные ориентиры лица, вам придется искусственно преобразовать изображение, чтобы лицо было по центру и смотрело прямо в камеру. Благодаря подходу глубокого обучения модель может научиться быть гибкой и обнаруживать черты лиц независимо от того, как они ориентированы. Все, что вам нужно, это данные.

Сбор данных

Данная модель обучалась с использованием наборов изображений Cohn-Kanade, JAFFE и FER-2013. Изображения помечены эмоциями: счастье, грусть, отвращение, злость, удивление, страх и нейтраль, и чтобы нормализовать изображения и подготовить их к обучению модели, я преобразовал все их в оттенки серого, обрезал и масштабировал до 192x192 пикселей, и нормализованная интенсивность пикселей до значений от 0 до 1. Затем я преобразовал изображения в множество массивов, которые будут использоваться при обучении. Поскольку в категориях гнева и отвращения не было достаточно изображений, я объединил их в одну группу, в результате чего получилось 6 категорий.

Построение модели

Keras - это платформа для глубокого обучения, построенная на Google TensorFlow. Это упрощает создание и тестирование моделей, позволяя просто складывать слои. То, что потребовало бы сотни строк кода в TensorFlow или тысячи в Python, заняло около 30 с Keras.

model = Sequential()
model.add(Conv2D(32, (5, 5), padding='same', activation='relu', input_shape=(1, 192, 192)))
model.add(Conv2D(32, (5, 5), padding='same', activation='relu'))
model.add(Conv2D(32, (5, 5), padding='same', activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
 
model.add(Conv2D(64, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(64, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(64, (3, 3), padding='same', activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(128, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(128, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(128, (3, 3), padding='same', activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(.5))
model.add(Dense(6, activation='softmax'))

Давайте разберемся, что здесь происходит.

Conv2D

Первый сверточный слой видит изображение 192x192 пикселей и просматривает части изображения 5x5 пикселей. Он имеет 32 фильтра, то есть есть 32 различных шаблона, которые слой будет искать в части 5x5 пикселей. Шаблоны определяются по мере того, как модель учится на данных, но обычно они выглядят следующим образом:

У каждого шаблона есть вес, и эти веса также корректируются по мере обучения модели. Поскольку части изображения 5x5 имеют 32 различных представления, этот слой имеет размер 188x188x32. Вы заметите, что это не соответствует исходному размеру изображения (192x192). Это связано с тем, что части 5x5 создаются с помощью скользящего окна, перемещающегося по изображению на один пиксель за раз.

MaxPooling2D

Это слой подвыборки, который принимает максимальное значение окна 2x2. Это предотвращает переоснащение модели, что важно, когда необходимо предсказать эмоции на изображениях, которых она никогда раньше не видела. Каждый срез сверточного слоя 188x188 объединяется, в результате чего получается слой с размерами 94x94x32.

Сглаживание, плотность и выпадение

Последний объединенный слой выравнивается и используется в другом слое с функцией активации softmax. Это слой, который производит классификацию эмоций, поэтому это вектор 1x6. Наибольшее значение этого вектора соответствует одной из шести эмоций: счастливой, грустной, испуганной, сердитой, удивленной или нейтральной. Исключение используется для предотвращения переобучения модели данным. Значение отсева 0,5 означает, что в каждом цикле обучения половина «нейронов» не учитывается, поэтому модель сможет лучше обобщать новые изображения.

Обучение

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

Тестирование

После 15 эпох обучения (модель просмотрела все 40 000 изображений 15 раз), модель смогла угадать правильную эмоцию в 60% случаев. Этот тест проводился на изображениях, которых модель никогда раньше не видела.

Заключение

Я надеюсь, что это руководство сделало глубокое обучение менее модным словом и более осязаемым понятием для использования в вашем бизнесе. Если вы хотите пойти глубже (каламбур непреднамерен), ознакомьтесь с новым курсом Эндрю Нг по глубокому обучению. Не стесняйтесь форкнуть код на моем гитхабе, где есть обученные модели для использования в CoreML для iOS и TensorFlow Lite для Android.