Press "Enter" to skip to content

如何用Keras识别人物面部表情?

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

2013年的时候,Kaggle曾组织过一次人脸表情识别大赛,参赛者要搭建一个模型,识别7种人类面部表情。虽然好几年过去了,期间也陆续出现了一些研究成果,但这依然是个很有趣的课题。在本文,我(作者Sefik Serengil——译者注)会展示如何用Keras识别人物面部表情。

数据集

我们的训练集和测试集还是使用 Kaggle 当年比赛用的数据集 Fec2013,点击这里可以获取。 该数据集压缩后大小为 92 M,未压缩版本大小为 295 M。数据集中包含 2 万 8 千张训练照片和 3 万张测试照片。每一张照片都存储为 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.sizeprint("number of instances: ",num_of_instances)

学习过程

最近几年,深度学习技术在计算机视觉研究占据了主要地位,即便是学术性的计算机视觉大会也紧密转为深度学习研讨会。在这里,我们会使用深度学习中的卷积神经网络完成本次任务。然后我们会利用 TensorFlow 的后端,使用 构建卷积神经网络。

我们已经将数据集下载到了本地,现在可以把训练集和测试集存储为专用变量了。

x_train, y_train, x_test, y_test = [], [], [], [] for i in range(1,num_of_instances): 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)

然后构造卷积神经网络架构:

model = Sequential() #第一个卷积层model.add(Conv2D(64, (5, 5), activation='relu', input_shape=(48,48,1)))model.add(MaxPooling2D(pool_size=(5,5), strides=(2, 2))) #第二个卷积层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))) #第三个卷积层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()) #全连接神经网络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'))

模型搭建完毕后,我们开始训练神经网络。为了能缩短训练时间,我比较喜欢随机选择训练集让模型学习,这也是在 Keras 中使用 fit_generator 的原因。同样,损失函数会是交叉熵,因为我们的任务是多类型分类问题。

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.27945706329Test accuracy: 57.4254667071 Train loss: 0.223031098232Train accuracy: 92.0512731201

最终搭建的面部表情识别模型准确率为57%。

用自定义照片测试模型

我们现在试着让模型识别我们自己找来的照片中的面部表情,因为单凭测试集中的错误率说明不了什么。

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打上标签。Keras会生成一个输出数组,包括这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()

如果你看过 NetFlix 出品的《毒枭》系列,你一定很熟悉这张照片。下面这张照片是大毒枭巴勃罗·埃斯科瓦尔被捕入狱时照的照片。用我们刚才搭建的模型对这张照片识别后,显示巴勃罗当时的心情非常不错。

接着我们用第二张照片,马龙·白兰度在《教父》中饰演的“老头子”考利昂看到儿子尸体时的画面。测试结果显示模型也能识别出考利昂痛苦悲伤的表情。

我还想测试一下发怒的表情,提到发怒,休·杰克曼演的“金刚狼”可是个典型,就是他了。我选了《X战警》中金刚狼暴怒的图片。测试结果显示非常成功。

最后,让模型挑战一个高难度的照片:蒙娜丽莎的微笑。至今艺术家们仍没有搞明白达芬奇的画作《蒙娜丽莎》中人物当时的心情。用我们的模型识别后,显示当时蒙娜丽莎的心情非常平和自然。

结语

在本文我们构建了一个卷积神经网络识别人类的面部表情。最终模型的准确率为 57%,这个结果还可以接受吧,因为当年 Kaggle 的那次比赛最高准确率才34%。如果对检测到的图像中的人脸进行处理,而非处理整个图像,能进一步提高准确率。因此我在运行神经模型前,对图像中的人脸做了些裁切工作。我计划下一步训练 Inception 中的预构建模型完成这个任务,到时候再和大家分享。

点击这里查看本项目代码。

Be First to Comment

发表评论

电子邮件地址不会被公开。 必填项已用*标注