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

Полную статью с исходным кодом читайте здесь —https://machinelearningprojects.net/emotion-detector-using-keras/

Давай сделаем это…

Шаг 1 — Импорт необходимых библиотек для Детектора эмоций.

from keras.preprocessing.image import ImageDataGenerator
from keras.layers import Dense,Dropout,Activation,Conv2D,MaxPooling2D,BatchNormalization,Flatten
from keras.models import Sequential
from keras.optimizers import rmsprop_v2
from keras.callbacks import EarlyStopping,ReduceLROnPlateau,ModelCheckpoint
from keras.models import load_model
import cv2
from PIL import Image
import numpy as np
import pandas as pd
import os
from keras.utils.np_utils import to_categorical
import seaborn as sns

Шаг 2 — Чтение всех изображений и сохранение их в кадре данных.

int2emotions = {0:'Angry',1:'Fear',2:'Happy',3:'Neutral',4:'Sad',5:'Surprise'}
emotions2int = {'Angry':0,'Fear':1,'Happy':2,'Neutral':3,'Sad':4,'Surprise':5}

dic = {'images':[], 'labels':[], 'purpose':[]}
    
for d in os.listdir('fer2013/'):
    print(d)
    for emotion in os.listdir(f'fer2013/{d}'):
        print(emotion)
        for i in os.listdir(f'fer2013/{d}/{emotion}'):
            img = cv2.imread(f'fer2013/{d}/{emotion}/{i}',0)
            img = img.reshape(48,48,1)
            
            dic['images'].append(img)
            dic['labels'].append(emotion)
            
            if d=='train':
                dic['purpose'].append('T')
            else:
                dic['purpose'].append('V')

df = pd.DataFrame(dic)
df.head()
  • Здесь мы просто читаем наши данные и сохраняем их в кадре данных pandas.
  • Изображения содержат изображения с формой 48X48X1.
  • Этикетки изображают эмоции этого изображения.
  • Цель имеет 2 значения T и V. T для обучения и V для проверки.

Шаг 3 — Извлечение данных обучения и данных проверки.

train_data = df[df['purpose']=='T']
val_data = df[df['purpose']=='V']
  • Создание 2 разных фреймов данных.
  • Первый для обучения и второй для проверки.

Проверьте голову обучающих данных.

train_data.head()

Проверьте заголовок данных проверки.

val_data.head()

Шаг 4 — Проверьте значения в столбце меток данных поезда.

train_data[‘labels’].value_counts()
  • Как мы видим на изображении ниже, метки очень несбалансированы в обучающих данных, поэтому мы сбалансируем их на следующем шаге.

Шаг 5 — Взять равные экземпляры всех классов.

happy_df = train_data[train_data['labels']=='Happy'].sample(n=3171)
neutral_df = train_data[train_data['labels']=='Neutral'].sample(n=3171)
sad_df = train_data[train_data['labels']=='Sad'].sample(n=3171)
fear_df = train_data[train_data['labels']=='Fear'].sample(n=3171)
angry_df = train_data[train_data['labels']=='Angry'].sample(n=3171)
surprise_df = train_data[train_data['labels']=='Surprise'].sample(n=3171)

train_data = pd.concat([happy_df,neutral_df,sad_df,fear_df,angry_df,surprise_df])

train_data = train_data.sample(frac=1)
train_data.reset_index(inplace=True)
train_data.drop('index',inplace=True,axis=1)

train_data.head()
  • Здесь мы берем 3171 экземпляр каждой эмоциональной рекламы, связывающейся с ними, чтобы сделать один окончательный кадр данных.

Шаг 6 — Снова проверка значений в столбце меток данных поезда.

train_data[‘labels’].value_counts()
  • Теперь снова проверяем подсчеты, и теперь мы видим, что все классы сбалансированы.

Построение столбца.

sns.countplot(train_data[‘labels’])

Шаг 7 — Объявление некоторых констант.

batch_size= 32
classes = 6
rows,columns=48,48

Шаг 8 — Получение данных для модели детектора эмоций в правильной форме.

train_labels = list(train_data['labels'].replace(emotions2int))
train_labels = to_categorical(train_labels)

val_labels = list(val_data['labels'].replace(emotions2int))
val_labels = to_categorical(val_labels)

train_data = list(train_data['images'])
train_data = np.array(train_data)

val_data = list(val_data['images'])
val_data = np.array(val_data)
  • Строка 1–2. Преобразование эмоций в целые числа, например Angry в 0, Fear в 1 и т. д., а затем преобразование этих чисел в горячее кодирование с помощью to_categorical. Это данные о поездах.
  • Строка 4–5 — Делаем то же самое, что и выше, для данных проверки.
  • Строка 7–8 — Преобразование столбца изображения в список, а затем в массив NumPy для целей обучения, потому что мы не будем использовать столбцы фрейма данных для целей обучения, поэтому мы преобразуем их в массивы.
  • Строка 10–11 — Делаем то же самое, что и выше, для данных проверки.

Проверка формы обучающих данных.

train_data.shape

Проверка формы данных проверки.

val_data.shape

Шаг 9 — Создание модели детектора эмоций.

model = Sequential()

# First Block
model.add(Conv2D(64,(3,3),activation='elu',input_shape=(rows,columns,1),kernel_initializer='he_normal',padding='same'))
model.add(BatchNormalization())
model.add(Conv2D(64,(3,3),activation='elu',input_shape=(rows,columns,1),kernel_initializer='he_normal',padding='same'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.2))

# Second Block
model.add(Conv2D(128,(3,3),activation='elu',kernel_initializer='he_normal',padding='same'))
model.add(BatchNormalization())
model.add(Conv2D(128,(3,3),activation='elu',kernel_initializer='he_normal',padding='same'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.2))

# Third Block
model.add(Conv2D(256,(3,3),activation='elu',kernel_initializer='he_normal',padding='same'))
model.add(BatchNormalization())
model.add(Conv2D(256,(3,3),activation='elu',kernel_initializer='he_normal',padding='same'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.2))

# Fourth Block
model.add(Conv2D(512,(3,3),activation='elu',kernel_initializer='he_normal',padding='same'))
model.add(BatchNormalization())
model.add(Conv2D(512,(3,3),activation='elu',kernel_initializer='he_normal',padding='same'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.2))

# Fifth Block
model.add(Flatten())
model.add(Dense(256,activation='elu',kernel_initializer='he_normal'))
model.add(BatchNormalization())
model.add(Dropout(0.5))

# Sixth Block
model.add(Dense(128,activation='elu',kernel_initializer='he_normal'))
model.add(BatchNormalization())
model.add(Dropout(0.5))

# Seventh Block
model.add(Dense(64,activation='elu',kernel_initializer='he_normal'))
model.add(BatchNormalization())
model.add(Dropout(0.5))

# Eighth Block
model.add(Dense(classes,activation='softmax',kernel_initializer='he_normal'))

print(model.summary())

  • Создание нашей модели сверточной нейронной сети.
  • Создание 4 блоков слоев Conv2DBatchNormalizationConv2DBatchNormalizationMaxPooling2DDropout.
  • Создание 3 блоков слоев Dense — Batch — Dropout и, наконец, создание 1 Dense слоя с 6 нейронами/узлами.

Шаг 10 — Объявление обратных вызовов.

checkpoint = ModelCheckpoint('model\\6_class_emotion_detector_V2.h5',
                             save_best_only=True,
                             mode='min',
                             monitor='val_loss',
                             verbose=1)

earlystopping = EarlyStopping(patience=10,
                             verbose=1,
                             min_delta=0,
                             monitor='val_loss',
                             restore_best_weights=True)


callbacks = [checkpoint, earlystopping]

model.compile(metrics=['accuracy'],
             optimizer='rmsprop',
             loss='categorical_crossentropy')

Шаг 11 — Обучение модели.

train_samples = 28273
validation_samples = 3534
batch_size = 64
epochs=30

history = model.fit(train_data,
                    train_labels,
                    epochs=epochs,
                    steps_per_epoch=train_samples//batch_size,
                    validation_data=(val_data,val_labels),
                    validation_steps=validation_samples//batch_size,
                    callbacks=callbacks)
  • Наконец обучение модели.

Шаг 12 — Живой прогноз.

import cv2
from keras.models import load_model
import numpy as np

int2emotions = {0:'Angry',1:'Fear',2:'Happy',3:'Neutral',4:'Sad',5:'Surprise'}
model = load_model('model\\6_class_emotion_detector_V2.h5')
cap = cv2.VideoCapture(0)

classifier = cv2.CascadeClassifier('Haarcascades\\haarcascade_frontalface_default.xml')

def detect_face(frame):
    faces=classifier.detectMultiScale(frame,1.3,4)
    if faces==():
        return frame
    for x,y,w,h in faces:
        cv2.rectangle(frame,(x,y),(x+w,y+h),(172,42,251),2)
        face = frame[y:y+h,x:x+w]
        face = cv2.cvtColor(face,cv2.COLOR_BGR2GRAY)
        face = cv2.resize(face,(48,48))
        face = face.reshape(1,48,48,1)
        cv2.putText(frame,text=int2emotions[np.argmax(model.predict(face))],
                    org=(x,y-15),fontFace=cv2.FONT_HERSHEY_SIMPLEX,fontScale=1,color=(106,40,243),thickness=2)
    return frame

while 1:
    ret,frame= cap.read()
    if ret==True:
        cv2.imshow('emotion_detector',detect_face(frame))
        if cv2.waitKey(1)==27:
            break
cap.release()
cv2.destroyAllWindows()

Дайте мне знать, если есть какие-либо вопросы относительно Детектора эмоций, связавшись со мной по электронной почте или LinkedIn.

Чтобы узнать больше о машинном обучении, глубоком обучении, компьютерном зрении, НЛП и проектах Flask, посетите мой блог — Проекты машинного обучения

Для дальнейшего объяснения кода и исходного кода посетите здесь — https://machinelearningprojects.net/emotion-detector-using-keras/

Итак, это все для этого блога, ребята, спасибо за то, что прочитали его, и я надеюсь, что вы возьмете что-то с собой после прочтения этого и до следующего раза 👋…

Прочитайте мой предыдущий пост: КЛАССИФИКАЦИЯ ПОРОД ОБЕЗЬЯН С ИСПОЛЬЗОВАНИЕМ ПЕРЕДАЧИ ОБУЧЕНИЯ