# MicroExpression_Classification **Repository Path**: sunmingqiyyds/MicroExpression_Classification ## Basic Information - **Project Name**: MicroExpression_Classification - **Description**: 基于ResNet50网络对casme2实现微表情分类模型的训练和安卓端部署 - **Primary Language**: Python - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2023-08-15 - **Last Updated**: 2023-08-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 0 项目简介 > 您是否有过以下困惑: 1. > 第一次约会中,内心小鹿乱撞,却摸不清他(她)对我的真实情感,是喜欢、犹豫还是......我应该怎么做,才能得到他(她)的真心呢? 1. > 青春期的孩子最为敏感,最为复杂,为人父母,管教过于温和怕起不到效果,过于激烈又会伤了孩子的自尊心,探寻他们内心深处的真实情感,才能对症下药。 > 现在,只需要fork本项目,安装一个微表情识别软件的手机,就能为你解决以上困惑,为你追求真爱,为你家庭和睦助上一臂之力。 - 任务:本次实验是一个图像多分类问题,利用ResNet50卷积神经网络实现微表情分类,再部署至手机端。 - 实践平台:百度AI实训平台-AI Studio、Python3.7+ Paddle2.2、Android Studio、安卓手机。 该项目是本人为完成学校课程而创建的,数据集不能公开,在此深表歉意。 但模型文件(MicroExpression.nb)文件有,文件在我的AI Studio[微表情](https://aistudio.baidu.com/aistudio/projectdetail/3425078?contributionType=1) 中,需要的朋友拿去手机端部署就ok,部署直接看[第五版块](#_5基于Paddle-Lite进行安卓部署)。 针对此项目还存在的改进空间,以及这类场景在飞桨框架下的实现,希望大家多交流观点,fork优化,相互关注,共同学习进步[个人主页](https://aistudio.baidu.com/aistudio/usercenter)。 # 1 数据集介绍 人类接触外界的过程通常伴随一系列复杂的心理活动,由此诱发情感,也称情绪。研究表明,情绪变化会在脸部产生表情,两者存在绝对的对应关系。 近年来,在人脸表情范畴下,新兴起一个细化的分支——微表情( Micro-Expression)。 * 猜猜左边这位大哥的微表情,看似一脸认真,其实他的标签是高兴哈哈哈哈哈 * 仔细观察右边这位小姐姐,眉头微微皱起,嘴角轻轻上扬,如此迷惑,其实她代表微表情的是压抑
由此可见,未经正规训练过的人很难识别微表情所代表的真实情感。 不同于传统的宏观表情,微表情具有如下特点: 1. 真实的情绪,复杂心理活动 1. 非自主控制,不自觉流露 1. 持续时间短,强度弱,不易察觉 其实,微表情研究在侦察讯问、安全司法、临床医学都有很好的应用前景,因此开发一套自动化设备,对微表情进行识别研究是很有必要的。 微表情来源于中科院提供的CASMEII数据库,这些样本主要包括七类:高兴、惊讶、恐惧、悲伤、厌恶、压抑和其他。 由于样本量较少,因此训练集、验证集、测试集按照6:2:2划分。 训练样本量| 2,464张 验证样本量| 822张 测试样本量| 826张 加载使用方式|自定义数据集 ## 1.1 数据标注 数据集分为train、valid、test三个文件夹,每个文件夹内包含7个分类文件夹,每个分类文件夹内是具体的样本图片。 ```python !unzip data/data128555/Classification2.zip ``` ```python import io import os from PIL import Image from config import get # 数据集根目录 DATA_ROOT = 'classification2' # 标签List LABEL_MAP = get('LABEL_MAP') # 标注生成函数 def generate_annotation(mode): # 建立标注文件 with open('{}/{}.txt'.format(DATA_ROOT, mode), 'w') as f: # 对应每个用途的数据文件夹,train/valid/test train_dir = '{}/{}'.format(DATA_ROOT, mode) # 遍历文件夹,获取里面的分类文件夹 for path in os.listdir(train_dir): # 标签对应的数字索引,实际标注的时候直接使用数字索引 label_index = LABEL_MAP.index(path) # 图像样本所在的路径 image_path = '{}/{}'.format(train_dir, path) # 遍历所有图像 for image in os.listdir(image_path): # 图像完整路径和名称 image_file = '{}/{}'.format(image_path, image) try: # 验证图片格式是否ok with open(image_file, 'rb') as f_img: image = Image.open(io.BytesIO(f_img.read())) image.load() if image.mode == 'RGB': f.write('{}\t{}\n'.format(image_file, label_index)) except: continue generate_annotation('train') # 生成训练集标注文件 generate_annotation('valid') # 生成验证集标注文件 generate_annotation('test') # 生成测试集标注文件 ``` ## 1.2 数据集定义 接下来我们使用标注好的文件进行数据集类的定义,方便后续模型训练使用。 ### 1.2.1 导入数据集的定义实现 ```python import paddle import numpy as np from config import get paddle.__version__ ``` ```python from dataset import MicroExpression ``` ### 1.2.2 实例化数据集类 根据所使用的数据集需求实例化数据集类,并查看总样本量。 ```python train_dataset = MicroExpression(mode='train') valid_dataset = MicroExpression(mode='valid') print('训练数据集:{}张;验证数据集:{}张'.format(len(train_dataset), len(valid_dataset))) ``` # 2 模型选择和开发 本次我们使用ResNet50网络来完成我们的案例实践。 ## 2.1 模型的介绍 以下项目对于ResNet50结构、功能有详细介绍,故在此不赘述,感兴趣的读者可以点击链接详细了解。 [https://aistudio.baidu.com/aistudio/projectdetail/3405244?contributionType=1](http://) ## 2.2 模型的选择 ```python network = paddle.vision.models.resnet50(num_classes=get('num_classes'), pretrained=True) ``` ``` model = paddle.Model(network) model.summary((-1, ) + tuple(get('image_shape'))) ``` # 3 模型训练和优化 其中关键API介绍如下: ##### CosineAnnealingDecay: [https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/optimizer/lr/CosineAnnealingDecay_cn.html#cosineannealingdecay](http://) ##### Momentum: [https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/optimizer/Momentum_cn.html#momentum](http://) ## 3.1 模型配置 ```python EPOCHS = get('epochs') BATCH_SIZE = get('batch_size') def create_optim(parameters): step_each_epoch = get('total_images') // get('batch_size') lr = paddle.optimizer.lr.CosineAnnealingDecay(learning_rate=get('LEARNING_RATE.params.lr'), T_max=step_each_epoch * EPOCHS) return paddle.optimizer.Momentum(learning_rate=lr, parameters=parameters, weight_decay=paddle.regularizer.L2Decay(get('OPTIMIZER.regularizer.factor'))) #正则化来提升精度 # 模型训练配置 model.prepare(create_optim(network.parameters()), # 优化器 paddle.nn.CrossEntropyLoss(), # 损失函数 paddle.metric.Accuracy(topk=(1, 5))) # 评估指标 # 训练可视化VisualDL工具的回调函数 visualdl = paddle.callbacks.VisualDL(log_dir='visualdl_log') ``` ## 3.2 模型的训练 ```python # 启动模型全流程训练 model.fit(train_dataset, # 训练数据集 valid_dataset, # 评估数据集 epochs=EPOCHS, # 总的训练轮次 batch_size=BATCH_SIZE, # 批次计算的样本量大小 shuffle=True, # 是否打乱样本集 verbose=1, # 日志展示格式 save_dir='./chk_points/', # 分阶段的训练模型存储路径 callbacks=[visualdl]) # 回调函数使用 ``` top1 表示预测的第一个答案就是正确答案的准确率 top5 表示预测里面前五个包含正确答案的准确率 预测可视化:
## 3.3 模型的保存 ```python model.save(get('model_save_dir')) ``` # 4 模型评估和测试 ## 4.1 测试数据集 ```python # 模型评估和测试 predict_dataset = MicroExpression(mode='test') print('测试数据集样本量:{}'.format(len(predict_dataset))) ``` ## 4.2 执行预测 ```python from paddle.static import InputSpec # 网络结构示例化 network = paddle.vision.models.resnet50(num_classes=get('num_classes')) # 模型封装 model_2 = paddle.Model(network, inputs=[InputSpec(shape=[-1] + get('image_shape'), dtype='float32', name='image')]) # 训练好的模型加载 model_2.load(get('model_save_dir')) # 模型配置 model_2.prepare() # 执行预测 result = model_2.predict(predict_dataset) ``` ```python from PIL import Image import matplotlib.pyplot as plt # 样本映射 LABEL_MAP = get('LABEL_MAP') def show_img(img, predict): plt.figure() plt.title('predict: {}'.format(LABEL_MAP[predict_label])) image_file, label = predict_dataset.data[idx] image = Image.open(image_file) plt.imshow(image) plt.show() # 随机取样本展示 indexs = [50,150 , 250, 350] for idx in indexs: predict_label = np.argmax(result[0][idx]) real_label = predict_dataset[idx][1] show_img(real_label,predict_label ) print('样本ID:{}, 真实标签:{}, 预测值:{}'.format(idx, LABEL_MAP[real_label], LABEL_MAP[predict_label])) ``` ## 4.3 模型的保存 ```python model_2.save('infer/MicroExpression', training=False) ``` # 5 基于Paddle-Lite进行安卓部署 ## 5.1 PaddleLite简介 Paddle-Lite 是飞桨推出的一套功能完善、易用性强且性能卓越的轻量化推理引擎。 轻量化体现在使用较少比特数用于表示神经网络的权重和激活,能够大大降低模型的体积,解决终端设备存储空间有限的问题,推理性能也整体优于其他框架。本部分以本案例的微表情数据集的ResNet50模型为例,介绍怎样使用Paddle-Lite,在移动端(基于华为麒麟985npu的安卓开发平台)对进行模型速度评估。 华为麒麟NPU部署参考链接: [https://paddlelite.paddlepaddle.org.cn/v2.10/demo_guides/huawei_kirin_npu.html](http://) 由下图可见,NPU上的运算速率是CPU的数倍:
说明:PaddleLite v2.10不支持鸿蒙系统下使用npu,若有需要,可按照上述链接改为EMUI系统。 ## 5.2 准备工作 文件:infer文件夹中的 .pdmodel .pdiparams 和下载到本地的image_classification_demo文件,下载链接如下: [https://github.com/PaddlePaddle/Paddle-Lite-Demo](http://) 工具:Android Studio、华为手机(开启USB调试模式)、USB数据线 Android Studio安装: [https://blog.csdn.net/qq_41976613/article/details/91432304](http://) 通过以下命令,将.pdmodel 和 .pdiparams两个模型文件生成Android Studio可执行的.nb文件。 ```python # 准备PaddleLite依赖 !pip install paddlelite==2.10 ``` ```python # 准备PaddleLite部署模型 #--valid_targets中参数(arm)用于传统手机,(huawei_kirin_npu,arm )用于华为带有npu处理器的手机 !paddle_lite_opt \ --model_file=infer/MicroExpression.pdmodel \ --param_file=infer/MicroExpression.pdiparams \ --optimize_out=./infer/ResNet \ --optimize_out_type=naive_buffer \ --valid_targets=huawei_kirin_npu,arm ``` ### 5.2.1 配置文件_电脑端 * 在下载的Paddle-Lite-Demo进入以下目录,按下列步骤配置文件 Paddle-Lite-Demo-master\Paddle-Lite-Demo-master\PaddleLite-android-demo\image_classification_demo\app\src\main\assets * 将待预测的图片放入ages文件夹 * 将数据标签文件放入labels文件夹 制作标签文件见 classfication2/train.txt **序号和类别的对应关系千万不能弄错了!** * 在models文件夹中放入自己的模型 创建子文件夹resnet_for_npu,将上述步骤生成的.nb文件下载到本地,并改名为model.nb ### 5.2.2 配置环境_手机端 1. 连续点击“版本号”以进入开发者模式 1. 开启USB调试按钮 1. USB配置选为PTP图片传输
## 5.3 完成部署 * 导入demo文件: 位置:Paddle-Lite-Demo-master\Paddle-Lite-Demo-master\PaddleLite-android-demo\image_classification_demo * 在strings.xml文件中修改三行字符:在 models/ labels/ images/ 后修改为上文添加文件的名称。 * 在Predictor.java文件中修改三行代码,改为如下内容: * 当Android Studio右上角设备信息为HUAWEI时,点击绿色三角形按钮下载至手机端: ## 5.4 效果展示 手机会自动出现以下画面
Open Gallery可在本地相册中添加图片预测, Take Photo可调用手机摄像头进行拍摄预测, Settings可进行硬件性能的相关设置。 说明:由于我没有再把鸿蒙系统改为EMUI系统,故默认使用CPU进行预测,从预测时间几百ms可以看出,符合上文中官方给出的推理时间。 # 6 小结 * 现在基于ResNet50的微表情图片分类、部署的任务大致完成了,接下来打算通过引入光流算法对微表情视频文件进行分类,尽请期待; * 感谢以上参考文档,为我提供解决问题的思路; * 这是我在飞桨平台上的处女作,欢迎大家给我点赞,点Fork, 当然,有不足之处也同样欢迎读者朋友们给我指正,谢谢。