반응형

원본 링크



Facial Expression Recognition with Keras

케글(Kaggle)은 2013년에 얼굴 표정 인식 대회를 발표했다. 연구자들은 사람 얼굴로부터 7가지 다른 감정을 탐지하기 위한 모델을 만드려고 했다. 그러나 최근 연구는 근래에서 조차 놀라운 결과와는 거리가 멀다. 그렇기 때문에 이 주제는 여전히 만족스러운 주제이다.


Scarlett Johansson



Dataset

훈련과 평가 모두 Fec2013 데이터셋을 사용한다. 데이터셋의 압축된 버전은 92MB이고 압축되지 않은 버전은 295MB이다. 데이터셋에는 28,000개의 훈련 이미지와 3,000개의 테스트 이미지가 있다. 각 이미지는 48 X 48 픽셀로 저장되어있다. 순수 데이터셋은 이미지 픽셀(48 X 48 = 2304), 각 이미지의 감정, 사용 형태(훈련 또는 테스트)로 구성된다.

데이터 폴더에 데이터셋이 이미 로드되었다고 가정하면, 아래와 같이 데이터셋 컨텐츠를 읽을 수 있다.


with open("/data/fer2013.csv") as f:
    content = f.readlines()

    lines = np.array(content)

    num_of_instances = lines.size
    print("number of instances: ",num_of_instances)



Learning Procedure

최근 딥러닝은 컴퓨터 비젼 연구를 지배한다. 대학의 컴퓨터 비전 학회조차 거의 딥러닝 황동으로 변화되었다. 여기서 우리는 이 작업을 다루기 위해 CNN을 적용할 것이다. 그리고 텐서플로를 벡앤드(backend)로하여 케라스로 CNN을 구성할 것이다.

이미 데이터셋을 로드했기 때문에 훈련과 테스트 셋은 전용 변수로 저장될 수 있다.


x_train, y_train, x_test, y_test = [], [], [], []

for i in range(1,num_of_instances):
    try:
        emotion, img, usage = lines[i].split(",")

        val = img.split(" ")
        pixels = np.array(val, 'float32')

        emotion = keras.utils.to_categorical(emotion, num_classes)

        if 'Training' in usage:
            y_train.append(emotion)
            x_train.append(pixels)
        elif 'PublicTest' in usage:
            y_test.append(emotion)
            x_test.append(pixels)
    except:
        print("", end="")

이번에는 CNN을 구성한다.


model = Sequential()

#1st convolution layer
model.add(Conv2D(64, (5, 5), activation='relu', input_shape=(48,48,1)))
model.add(MaxPooling2D(pool_size=(5,5), strides=(2, 2)))

#2nd convolution layer
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(AveragePooling2D(pool_size=(3,3), strides=(2, 2)))

#3rd convolution layer
model.add(Conv2D(128, (3, 3), activation='relu'))
model.add(Conv2D(128, (3, 3), activation='relu'))
model.add(AveragePooling2D(pool_size=(3,3), strides=(2, 2)))

model.add(Flatten())

#fully connected neural networks
model.add(Dense(1024, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(1024, activation='relu'))
model.add(Dropout(0.2))

model.add(Dense(num_classes, activation='softmax'))

이제 네트워크를 훈련할 수 있다. 적은 시간에 훈련을 완료하기 위해 임의로 선택된 훈련셋 인스턴스로 학습을 구현하는 것을 선호한다. 이것이 train과 fit 제너레이터(generator)가 사용된 이유이다. 또한 손실(loss) 함수는 작업이 다중 분류(mulit class classification)이기 때문에 cross entropy가 된다.


gen = ImageDataGenerator()
train_generator = gen.flow(x_train, y_train, batch_size=batch_size)

model.compile(loss='categorical_crossentropy'
            , optimizer=keras.optimizers.Adam()
            , metrics=['accuracy'])

model.fit_generator(train_generator, steps_per_epoch=batch_size, epochs=epochs)

훈련(fit)이 끝났다. 이제는 네트워크를 평가할 수 있다.


train_score = model.evaluate(x_train, y_train, verbose=0)
print('Train loss:', train_score[0])
print('Train accuracy:', 100*train_score[1])

test_score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', test_score[0])
print('Test accuracy:', 100*test_score[1])

오퍼피팅에 빠지지 않은 아래 결과를 얻었다. 회차(epoch)가 증가하면 오버피팅이 발생했다.


Test loss: 2.27945706329
Test accuracy: 57.4254667071

Train loss: 0.223031098232
Train accuracy: 92.0512731201



Confusion Matrix

분명히 정확도(accuracy)는 다중 분류 문제에 대한 올바른 인상을 표현해서는 안된다. 이 모델의 Confusion matrix는 아래와 같다. 행(line)은 실제 값을, 열(column)은 상태 예측을 나타낸다. 테스트셋에 467개의 화난(angry) 인스턴스가 있고 우리는 214개의 화난 아이템을 올바르게 구분할 수 있다. 한편 혐오(disgust)로 9개를 구분하였지만 실제로는 화남(angry)이다.

Angry Disgust Fear Happy Sad Surprise Neutral
Angry 214 9 53 30 67 8 86
Disgust 10 24 9 2 6 0 5
Fear 45 2 208 29 89 45 78
Happy 24 0 40 696 37 18 80
Sad 65 3 83 56 285 10 151
Surprise 7 1 42 27 9 303 26
Neutral 45 2 68 65 88 8 331

기본적으로 scikit-learn은 이러한 confusion matrix를 만든다.


from sklearn.metrics import classification_report, confusion_matrix

pred_list = []; actual_list = []

for i in predictions:
    pred_list.append(np.argmax(i))

for i in y_test:
    actual_list.append(np.argmax(i))

confusion_matrix(actual_list, pred_list)



Face detection

훈련 셋에서 이미지는 이미 잘려서 얼굴 영역만이 집중된다. 이것은 필수는 아니지만 우리는 커스텀 테스팅 이미지의 얼굴을 탐지하고 신경망 모델에 단지 얼굴 영역만을 전달해야 한다.
이것은 극적으로 정확도를 증가시킬 것이다.

** 얼굴 탐지 솔루션에 대한 내용으로 다른 글에서 이미 나온 부분이라 생략한다.



Testing

커스텀 이미지의 얼굴 표현을 인식해 보자. 오직 오류 비율(error rates)만이 아무것도 표현하지 않기 때문이다.


img = image.load_img("/data/pablo.png", grayscale=True, target_size=(48, 48))

x = image.img_to_array(img)
x = np.expand_dims(x, axis = 0)

x /= 255

custom = model.predict(x)
emotion_analysis(custom[0])

x = np.array(x, 'float32')
x = x.reshape([48, 48]);

plt.gray()
plt.imshow(x)
plt.show()

감정은 0에서 6까지의 레이블된 수치형으로 저장된다. 케라스는 7가지 다른 표정 점수를 포함하는 출력 배열을 생성하며 우리는 막대 그래프로 각 예측을 시각화 할 수 있다.


def emotion_analysis(emotions):
    objects = ('angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral')
    y_pos = np.arange(len(objects))

    plt.bar(y_pos, emotions, align='center', alpha=0.5)
    plt.xticks(y_pos, objects)
    plt.ylabel('percentage')
    plt.title('emotion')

    plt.show()

유명한 넷플릭스 시리즈 Narcos를 봤다면 다음 사진은 익술할 것이다. 다음은 Pablo Escobar가 구금될 때 경찰서에서 붙잡힌 사진으로 우리가 만든 모델이 성공적으로 행복한 분위기의 Pablo를 인식할 수 있는 것 같다.


Pablo Escobar’s facial expression

두번째로 Godfather에서 Don Corleone 역할을 한 Marlon Brando의 장면을 테스트할 것이다. Corleone는 아들의 팔꿈치 시체를 보고 운다. Brando의 얼굴 표정 또한 모델일 인식하는 것처럼 보인다.


Marlon Brando’s facial expression

Hugh Jackman은 항상 화낭 모습으로 기억된다. 그렇기 때문에 이번에는 그를 테스트해 본다. 특히, X-man의 울버린인 Jackman의 사진을 골랐다. 결과는 매우 성공적이다.


Hugh Jackman’s facial expression

마지막으로, 미술 당국은 여전히 모나리자의 표정에 대해 서로 합의할 수 없다. 네트워크는 모나리자가 무표정(neutral mood)이라고 말한다.


Da Vinci’s Mona Lisa’s facial expression



Real time solution

우리는 비디오 스트리밍 또는 웹캠에서 표정분석을 할 수 잇다. 이 주제에 대해서는 Real Time Facial Expression Recognition on Streaming Data에서 다뤘고 그에 관한 데모는 아래와 같다.

Web cam

저자와 저자의 동료가 모든 표정을 지어본다. 보이는 것과 같이 이 구현은 매우 빠르게 동작한다.




Video streaming

Cambridge Analytica 스캔들 이후 마크 주커버그의 증언을 기억하자. 페이스북은 이 뉴스로 1340억을 잃었다. 이는 아래에 탐지된 것과 같이 맡크같은 누군가를 불행하게 만든다.




Conclusion

사람의 얼굴 표정을 인식하기 위한 CNN 모델을 구현했다. 모델은 테스트셋에서 57%의 정확도이다. 그것은 캐글 대회 우승자가 34%의 정확도를 갖기 때문에 수용할 수 있다.

전체 이미지 대신 탐지된 얼굴을 처리하는 것이 정확도를 증가시켰을 것이다. 이것은 소소한 기술이다. 네트워크를 실행하기 전에 수동으로 얼굴을 잘라냈다.

전체 프로젝트의 소스는 여기에서 찾을 수 있다.

이 글에서는 얼굴 표정 인식 작업에 대한 맞춤 설계를 포함하였고 auto-keras로 동일 작업에 대해 정확도를 57%에서 66%로 개선할 수 있다.




반응형

+ Recent posts