赞
踩
:温馨提示:文末有 CSDN 平台官方提供的学长 QQ 名片 :)
面部表情识别是计算机视觉领域的一个重要研究方向, 它在人机交互、心理健康评估、安全监控等领域具有广泛的应用。近年来,随着深度学习技术的快速发展, 面部表情识别的准确性和实时性得到了显著提升。本项目以 MobileNetV2 为基础模型构建面向面部表情识别的卷积神经网络, 完成模型的训练、验证和测试,面部表情识别准确率达到 85%以上。并利用 Flask + Bootstrap 框架搭建交互式分析平台,方便用户进行表情的识别。
B站视频详情及代码下载:基于深度学习的面部表情分类识别系统_哔哩哔哩_bilibili
基于深度学习的面部表情分类识别系统
利用 opencv 读取面部表情图像数据,并转换为 numpy 数组,图片为灰度图:
- def prepare_data(ori_data):
- """
- 像素数组转成 numpy array
- """
- image_array = np.zeros(shape=(ori_data.shape[0], img_size, img_size))
- image_label = np.array(list(map(int, ori_data['emotion'])))
-
- for i, row in ori_data.iterrows():
- image = np.fromstring(row['pixels'], dtype=int, sep=' ')
- image = np.reshape(image, (img_size, img_size))
- image_array[i] = image
-
- return image_array, image_label
读取的数据集,可视化部分样例数据:
数据集共包含:生气(Angry)、厌恶(Disgust)、恐惧(Fear)、开心(Happy)、悲伤(Sad)、惊讶(Surprise)和中性(Neutral)七种类型,其样本数量分布如下:
可以看出,样本类别极具不均衡,如不处理样本均衡问题,将影响模型的训练,样本少的类别会得不到充分的学习。
通过对样本进行采样,并切分出训练集、验证集和测试集:
- class_data = [data[data['emotion'] == i] for i in range(7)]
-
- # 对每个类别进行过采样,以匹配平均类别数量
- oversampled_data = [resample(class_df, replace=True, n_samples=int(average_class_count), random_state=42) for class_df in class_data]
- # 将过采样后的数据合并为一个平衡的数据集
- balanced_data = pd.concat(oversampled_data)
- # 重置索引并直接在原数据框上进行修改
- balanced_data.reset_index(drop=True, inplace=True)
-
- # 准备数据,将特征和标签分离
- all_x, all_y = prepare_data(balanced_data)
- # 重塑特征数据,以匹配输入形状
- all_x = all_x.reshape((all_x.shape[0], img_size, img_size, 1))
- # 将标签转换为独热编码格式
- all_y = to_categorical(all_y)
-
- # 将数据分为训练集和临时集,其中20%用于测试
- x_train, x_temp, y_train, y_temp = train_test_split(all_x, all_y, test_size=0.2)
- # 将临时集进一步分为验证集和测试集,各占50%
- x_val, x_test, y_val, y_test = train_test_split(x_temp, y_temp, test_size=0.5)
-
- print('训练集:{},验证集:{},测试集:{}'.format(x_train.shape[0], x_val.shape[0], x_test.shape[0]))
可以看出,七种类型的样本数量已基本均衡,有利于神经网络的训练。
MobileNetV2 是一种轻量级的深度神经网络模型,由Google在2018年发布,旨在用于移动和边缘设备上的高效图像识别任务。它是MobileNetV1的改进版,继承了其轻量级和高效的特点,并在多个方面进行了优化。以下是MobileNetV2模型的主要特点和结构:
主要特点:
深度可分离卷积(Depthwise Separable Convolution): MobileNetV2依然采用了深度可分离卷积来减少模型参数和计算量。这种卷积将标准的卷积分解为两个步骤:深度卷积(depthwise convolution)和逐点卷积(pointwise convolution)。
线性瓶颈(Linear Bottlenecks): 在MobileNetV2中,作者引入了线性瓶颈的概念,即在网络的最后几层使用了线性激活函数(ReLU6)而不是传统的ReLU,这有助于减少信息的损失。
倒残差结构(Inverted Residuals): MobileNetV2采用了倒残差结构,即先通过一个逐点卷积扩展维度,然后进行深度卷积,最后再用逐点卷积减少维度。这种结构有助于提高网络的表达能力。
轻量级: 由于采用了上述结构,MobileNetV2在保持精度的同时大大减少了模型的参数数量和计算量,使其非常适合在资源受限的设备上运行。
以 MobileNetV2 为 base 模型,加载利用 ImageNet 大规模数据集预训练的 MobileNetV2 模型权重,构建
- base_model = tf.keras.applications.MobileNetV2(
- weights='./pretrained_models/mobilenet_v2_weights_tf_dim_ordering_tf_kernels_1.0_96_no_top.h5',
- include_top=False,
- input_shape=(96,96,3)
- )
-
- # Inputlayer
- input = tf.keras.layers.Input(name='0_Input',
- shape=(img_size, img_size, 1))
-
- # Preprocessing stage
- x = tf.keras.layers.Resizing(name='1_Preprocessing_1',height = 96, width = 96)(input)
- x = tf.keras.layers.Rescaling(name='1_Preprocessing_2',
- scale = 1/127.0, offset=-1)(x)
- x = tf.keras.layers.RandomRotation(name='1_Preprocessing_3',
- factor=0.20,
- seed=100)(x)
- x = tf.keras.layers.RandomFlip(name='1_Preprocessing_4',
- mode="horizontal",
- seed=100)(x)
-
- ......
-
- # Feature extracting stage
- x = base_model(x)
- x = tf.keras.layers.Flatten(name='3_Classification_1')(x)
-
- # Classification stage
- x = tf.keras.layers.Dense(name='3_Classification_2',
- units=256,
- kernel_regularizer=tf.keras.regularizers.l2(l2=regularization_rate),
- kernel_initializer = 'he_uniform',
- activation='relu')(x)
-
- ......
-
- # Prediction stage
- predictions = tf.keras.layers.Dense(name='4_Prediction',
- units = 7,
- kernel_initializer = 'zeros',
- activation=tf.nn.softmax)(x)
-
- model = Model(inputs=input, outputs=predictions)
-
- model.compile(optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate),
- loss='categorical_crossentropy',
- metrics=['acc'])
- model.summary()
利用切分的训练集进行模型的训练,验证集进行模型的验证评估,并保存 val_acc 最高的模型权重:
- checkpoint = ModelCheckpoint('save_models/best_model.h5', monitor='val_acc', verbose=1, mode='max',save_best_only=True)
- early = EarlyStopping(monitor="val_acc", mode="max",restore_best_weights=True, patience=5)
- lrp_reducer = ReduceLROnPlateau(monitor='val_loss', factor=lrp_factor, patience=lrp_patience, verbose=1)
-
- callbacks_list = [checkpoint, early, lrp_reducer]
-
- history = model.fit(
- x_train, y_train,
- batch_size=batch_size,
- epochs=epochs,
- steps_per_epoch=x_train.shape[0] // batch_size,
- verbose=1,
- callbacks=callbacks_list,
- validation_data=(x_val, y_val),
- validation_steps=x_val.shape[0]//batch_size
- )
模型预测测试集的 AUC 得分,并绘制 ROC 曲线:
- # 获取疾病标签名称列表
- labels = list(emotions.values())
-
- # 创建一个范围,表示 x 轴上每个标签的位置
- x = np.arange(len(labels))
- # 设置柱状图的宽度
- width = 0.80
- fig, ax = plt.subplots(figsize=(20, 8), dpi=120)
- rects = ax.bar(x, cate_auc, width, color='#EEC900')
- ax.set_ylabel('AUC Score', fontsize=20)
- ax.set_xlabel('标签', fontsize=20)
- ax.set_title('不同类别模型预测 AUC Score 分布', fontsize=30)
- ax.set_xticks(x, labels, fontsize=20)
- ax.bar_label(rects, padding=3, fontsize=16)
- fig.tight_layout()
- plt.show()
- from matplotlib.colors import LogNorm
- import seaborn as sns
-
- true_labels = np.argmax(y_test, axis=1)
- predictions = np.argmax(pred_test, axis=1)
- conf_matrix = confusion_matrix(true_labels, predictions)
-
- plt.figure(figsize=(10, 8))
- sns.heatmap(conf_matrix, annot=True, cmap='GnBu', fmt='g', xticklabels=[emotions[i] for i in range(len(conf_matrix))], yticklabels=[emotions[i] for i in range(len(conf_matrix))], norm=LogNorm())
-
- plt.title('Confusion Matrix')
- plt.xlabel('Predicted Label')
- plt.ylabel('True Label')
- plt.show()
利用 Flask + Bootstrap 框架搭建响应式布局的交互分析 web 系统,利用 keras load_model 加载训练好的性能最佳的模型,提供标准化 rest api,提供面部表情的在线识别功能。
通过上传待测试面部表情图片,提交预测后,后端调用模型进行表情预测,预测结果返回给前端进行渲染可视化,展示预测的标签类别,及各类标签预测的概率分布。
本项目以 MobileNetV2 为基础模型构建面向面部表情识别的卷积神经网络, 完成模型的训练、验证和测试,面部表情识别准确率达到 85%以上。并利用 Flask + Bootstrap 框架搭建交互式分析平台,方便用户进行表情的识别。
欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。技术交流、源码获取认准下方 CSDN 官方提供的学长 QQ 名片 :)
精彩专栏推荐订阅:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。