Всем привет!
Это было долго. Итак, позвольте мне начать с краткого обзора того, чем я занимался в это время. Я переехал в красивый город Боулдер, штат Колорадо, США, чтобы получить степень магистра наук в Университете Колорадо в Боулдере!
Я начал работать над проектом взаимодействия человека и робота в Лаборатории совместного искусственного интеллекта и робототехники в моем университете и за очень короткое время познакомился со множеством удивительных людей!
Хорошо, хватит, перейдем к текущей задаче. Это сообщение, надеюсь, ответит на вопрос -
Как распознать эмоции лица с помощью сверточной нейронной сети?
Прежде чем мы начнем с подробностей, давайте начнем с основ!
Что такое сверточная нейронная сеть?
Прямо сейчас все, что вам нужно знать, что сверточная нейронная сеть или CNN, как ее обычно называют, представляет собой набор из двух типов слоев:
- Скрытые слои / Часть извлечения объектов
- извилины
- объединение
2. Классификатор.
Хорошо, но что за свертка?
Свертка - это математическая операция, которая включает комбинацию двух функций для получения третьей функции. В CNN свертка выполняется для входных данных с использованием фильтра для создания карты характеристик.
Но вы тоже упомянули о том, что называется объединением?
Слой объединения добавляется после слоя свертки. Он выполняет непрерывное уменьшение размерности, то есть уменьшает количество параметров и вычислений, тем самым сокращая время обучения и контролируя переобучение. Один из таких методов объединения называется max-pooling, который принимает максимальное значение в каждом окне, что уменьшает размер карты функций, сохраняя при этом важную информацию.
Теперь давайте перейдем к последней вещи, которую нам нужно знать, прежде чем мы начнем грязные руки, - это Dropout, метод, при котором случайно выбранные нейроны игнорируются во время обучения. Они «выпадают» случайным образом. Это отличный метод, который используется для уменьшения переобучения нашей модели и получения хорошо обобщенных результатов.
Все еще не понимаете?
Не волнуйтесь, просто прочтите этот замечательный пост от Дафны Корнелисс, и вы все поймете.
Теперь приступим к кодированию!
Мы будем работать с набором данных Kaggle FER2013, который можно загрузить, щелкнув ссылку, и извлечь CSV-файл.
Я буду придерживаться построчного подхода, чтобы его было легче понять. Начнем с предварительной обработки. Вы можете выполнить форк репозитория для этого кода, если хотите продолжить.
Это довольно простой шаг, который включает в себя получение данных и их хранение в удобном для нас виде.
Строка 1–7 - Импорт библиотек и чтение файла CSV.
Строка 8–3 - Получение обучающих функций X
и меток y
из pixels
и emotion
столбцов CSV соответственно и преобразование их в многочисленные массивы. Мы также добавляем дополнительное измерение к нашему вектору признаков с помощью функции np.expand_dims()
, это делается для того, чтобы входные данные подходили для нашей CNN, которую мы разработаем позже. И функции, и метки сохраняются в виде файлов .npy
, которые будут использоваться позже.
После того, как мы выполним приведенный выше код, наш результат будет выглядеть примерно так:
Preprocessing Done Number of Features: 48 Number of Labels: 7 Number of examples in dataset:35887 X,y stored in fdataX.npy and flabels.npy respectively
Теперь приступим к разработке нашей модели. Я разделю процесс на несколько этапов, чтобы он не был слишком утомительным.
Строка 1–11 - Импорт необходимых библиотек для нашей CNN.
Строка 12-23 - Хорошо, здесь много всего происходит, сначала мы объявляем переменные, которые нам понадобятся для обучения нашей CNN. У нас разрешение 48x 48 пикселей, поэтому ширина и высота равны 48. Затем у нас есть 7 эмоций, которые мы прогнозируем, а именно (0 = гнев, 1 = отвращение, 2 = страх, 3 = счастье, 4 = грусть, 5 = сюрприз. , 6 = нейтральный), поэтому у нас есть 7 меток. Мы будем обрабатывать наши входные данные с размером пакета 64.
Затем мы загружаем функции и метки в x
и y
соответственно и стандартизированные x
путем вычитания средних значений и деления на стандартное отклонение.
Строка 24–35 - Первые четыре строки просто печатают изображения с использованием значений пикселей. После этого мы разделяем данные на набор для обучения и тестирования с помощью функции sklearn train_test_split()
и сохраняем тестовые функции и метки для использования в дальнейшем. Мы также выполняем еще одно деление наших обучающих данных, чтобы получить данные проверки, которые будут использоваться позже в коде.
Теперь перейдем к следующему фрагменту кода.
Этот шаг является наиболее важной частью всего процесса, поскольку мы проектируем CNN, через которую мы будем передавать наши функции для обучения модели и в конечном итоге тестировать ее с использованием тестовых функций. Мы использовали комбинацию нескольких различных функций для создания CNN, которые мы будем обсуждать одну за другой.
Sequential()
- Последовательная модель - это просто линейный стек слоев, в котором слои накладываются друг на друга по мере того, как мы продвигаемся от входного уровня к выходному слою. Подробнее об этом можно прочитать здесь.model.add(Conv2D())
- это сверточный 2D-слой, который выполняет операцию свертки, как описано в начале этого сообщения. Цитируя Документацию Keras: Этот слой создает ядро свертки, которое свертывается с входом слоя для создания тензора выходных данных. Здесь мы используем размер ядра 3x3 и выпрямленную линейную единицу (ReLU) в качестве нашей функции активации.model.add(BatchNormalization())
- Он выполняет операцию пакетной нормализации для входных данных следующего уровня, так что наши входные данные находятся в заданном масштабе, скажем, от 0 до 1, а не разбросаны повсюду.model.add(MaxPooling2D())
- Эта функция выполняет операцию объединения данных, как описано в начале сообщения. В этой модели мы берем окно объединения 2x2 с шагом 2x2. Если вы хотите узнать больше о MaxPooling, вы можете обратиться к Документации Keras или упомянутому выше сообщению.model.add(Dropout())
- Как объяснялось выше, Dropout - это метод, при котором случайно выбранные нейроны игнорируются во время обучения. Они «выпадают» случайным образом. Это снижает переоснащение.model.add(Flatten())
- Это просто сглаживает ввод от ND до 1D и не влияет на размер пакета.model.add(Dense())
- Согласно документации Keras,Dense
реализует операцию:output = activation(dot(input, kernel)
гдеactivation
- это функция поэлементной активации, переданная как аргументactivation
,kernel
- это матрица весов, созданная слоем. Проще говоря, это последний гвоздь в гробу, который использует особенности, полученные с помощью слоев, и отображает их на этикетке. Во время тестирования этот слой отвечает за создание окончательной метки для обрабатываемого изображения.
После выполнения функции model.summary()
результат будет выглядеть примерно так:
К следующему фрагменту!
Это довольно простой фрагмент кода, в котором сначала модель компилируется с categorical_crossentropy
в качестве функции потерь и с использованием Оптимизатора Адама. Мы используем точность в качестве метрики для проверки.
Затем мы настраиваем модель с фиксированным размером пакета (здесь 64), эпохами (здесь 100) и данными проверки, которые мы получили путем разделения данных обучения ранее. И, наконец, мы сохраняем модель для некоторых пользовательских тестов, о которых я расскажу позже.
После того, как мы запустим приведенный выше код (fertrain.py), мы получим результат, который будет выглядеть примерно так:
Train on 29068 samples, validate on 3230 samples Epoch 1/100 29068/29068 [==============================] — 34s 1ms/step — loss: 2.0047 — acc: 0.2124 — val_loss: 1.8123 — val_acc: 0.2817 Epoch 2/100 29068/29068 [==============================] — 31s 1ms/step — loss: 1.7918 — acc: 0.2692 — val_loss: 1.6796 — val_acc: 0.3195 Epoch 3/100 29068/29068 [==============================] — 31s 1ms/step — loss: 1.7021 — acc: 0.3148 — val_loss: 1.5516 — val_acc: 0.3957 . . . Epoch 100/100 29068/29068 [==============================] — 31s 1ms/step — loss: 0.3083 — acc: 0.9049 — val_loss: 1.3855 — val_acc: 0.6666 Saved model to disk
Мы видим, что точность проверки составила 66,6%, что на самом деле неплохо! Давайте сделаем шаг вперед и протестируем модель на данных тестирования, которые мы сохранили ранее, запустив файл fertest.py
. Мы получим такой вывод:
Loaded model from disk Accuracy on test set :66.3694622458
Это впечатляющий результат, потому что модель, победившая в конкурсе имела точность 71,1%, что означает, что этот результат ставит нас на 5-е место! Разве это не круто!
Теперь я также создал матрицу путаницы, чтобы выяснить, какие эмоции обычно путают друг с другом чаще, и это выглядело примерно так:
Посмотрите, как гнев и отвращение перепутали друг с другом, поскольку это очень похожие отрицательные эмоции. Нечто подобное произошло с Fear and Sadness.
Основываясь на этом результате, я делю эмоции на 3 категории (положительные, нейтральные и отрицательные) для своего следующего проекта, который предполагает предоставление роботу возможностей распознавания эмоций лица во время навигации!
Вы можете создать свою собственную матрицу путаницы, запустив программу confmatrix.py
из репозитория.
Чтобы было веселее, я протестировал модель на лицах актеров из популярного сериала F.R.I.E.N.D.S, и результаты были довольно хорошими!
Имейте в виду, это реальные предсказанные эмоции. Вы можете сделать то же самое со своим пользовательским тестовым изображением или использовать эту модель в своем собственном проекте, разветвив и клонировав репозиторий и запустив файл thefertestcustom.py
!
Я думаю, что на этом все закончилось очень хорошо. Как всегда, поездка была отличной.
Прощай!