尧图精选

Python基于CNN的人脸表情识别系统:毕设98分完整资源与实战指南

🕒 发布时间:2026/9/28 8:54:35 📁 来源:尧图网络
简介这份资源是面向计算机相关专业学生与项目实战学习者的深度学习毕业设计资料围绕Python与卷积神经网络实现人脸表情识别系统展开适合正在做大作业、毕业设计或需要完整项目练手的人群。压缩包共36个文件约446.05MB包含14个py脚本、5个ipynb笔记本、5个docx与1个pptx等覆盖模型训练、测试、数据处理、可视化及论文答辩材料另附数据集、预训练模型与Haar级联人脸检测文件。项目经导师指导并获评审98分源码均经本地编译调试可稳定运行难度适中。读者可据此掌握CNN、VGG、ResNet等多模型对比实验流程理解数据分离、表情映射与模型评估思路并直接参考论文与答辩PPT完成写作与汇报。目前已有76人学习适合需要完整方案与排错参考的学习者下载使用。1. 从一份 98 分毕设拆起这套 CNN 人脸表情识别资源到底能跑出什么如果你正在做计算机视觉方向的毕业设计或者想找一个能写进简历的完整 CNN 实战项目这套「Python 基于卷积神经网络的人脸表情识别系统」大概率能省掉你两周的摸索时间。它不是那种只丢一个train.py就跑路的半成品而是把源码、数据集、预训练模型、论文、答辩 PPT、参考文献、标注工具、可视化脚本全部打包在一起评审分 98 分源码经过本地编译调试拿到手就能跑。核心任务很明确输入一张人脸图片或一段视频模型输出 7 类表情生气、厌恶、恐惧、开心、悲伤、惊讶、中性的预测结果。技术栈是 Python PyTorch模型覆盖 CNN、VGG、ResNet 三条路线还带一个model_All_Compare.py做横向对比。适合谁正在做大作业或毕设的计算机相关专业学生以及需要完整项目实战练习的学习者。难度适中但前提是你得知道每个文件是干什么的、参数怎么调、坑在哪。2. 资源结构拆解从 model_CNN.py 到 haarcascade 的完整链路2.1 源码文件的分工与调用关系拿到压缩包先别急着跑花十分钟把目录结构理清楚后面能少踩一半的坑。这套资源的文件命名比较直白但有几个容易混淆的地方我提前标出来。核心模型文件分三组model_CNN.py/model_CNN_test.py基础 CNN 模型的定义与测试脚本结构最简单适合先跑通流程model_VGG.py/model_VGG_test.pyVGG 变体层数更深训练慢但精度通常更高model_ResNet.py/model_ResNet_test.pyResNet 残差结构解决深层网络退化问题model_All_Compare.py把上面三个模型的训练/评估结果拉到一起对比写论文时直接出图数据处理链路data_process.py原始数据预处理包括灰度化、归一化、尺寸统一data_separation.py划分训练集/验证集/测试集data_view.py数据可视化快速看样本分布和图像质量image_emotion_mapping.py表情标签与数值的映射关系改类别数时必看辅助工具haarcascade_frontalface_default.xmlOpenCV 的人脸检测器负责从整张图里框出人脸区域templates/Web 端模板文件说明这套系统带了一个简易的演示界面video example_dsh.mp4示例视频用来测试视频流表情识别Face-Annotation-Tool-master.zip人脸标注工具想自己扩数据集时用得上预训练模型和 Notebookmodel_resnet.pkl训练好的 ResNet 权重可以直接加载推理CNN_01.ipynb~CNN_03.ipynb、ResNet.ipynb、Facial-expressions.ipynbJupyter 版本适合边调边看中间结果ResNet_model_template.py、VGG_model_template.py模板文件改网络结构时从这里复制论文和答辩材料单独放小组论文目录下有 4 份不同作者的文档人脸面部表情识别答辩PPT.pptx是最终答辩用的版本手册.docx是操作说明。提示先确认dataset目录下的数据格式再决定跑哪个模型。FER2013 原始格式和图片文件夹格式的读取方式完全不同。2.2 环境配置与依赖安装这套代码基于 PyTorchPython 版本建议 3.7 以上。我一般会先建一个干净的虚拟环境避免和系统里的包打架。# 创建虚拟环境 python -m venv fer_env # 激活Windows fer_env\Scripts\activate # 激活Linux/Mac source fer_env/bin/activate # 安装核心依赖 pip install torch torchvision opencv-python numpy matplotlib pillow pandas scikit-learn如果你用的是 GPU 版本去 PyTorch 官网复制对应 CUDA 版本的安装命令别直接pip install torch否则默认装 CPU 版训练会慢到怀疑人生。# 验证环境是否正常 import torch import cv2 import numpy as np print(PyTorch version:, torch.__version__) print(CUDA available:, torch.cuda.is_available()) print(OpenCV version:, cv2.__version__) # 如果 CUDA available 是 False检查显卡驱动和 CUDA 版本是否匹配参数说明torch.cuda.is_available()返回False时先别急着改代码大概率是驱动或 CUDA 版本不匹配。opencv-python装完后如果cv2.imshow报错换成opencv-python-headless或者检查系统 GUI 依赖。2.3 数据准备与预处理流程数据集是 FER2013 格式dataset目录下应该有对应的图片或 CSV。先跑data_view.py看一眼数据长什么样。# data_view.py 核心逻辑示意 import os import cv2 import matplotlib.pyplot as plt data_dir dataset/train emotions os.listdir(data_dir) fig, axes plt.subplots(1, 7, figsize(14, 2)) for i, emotion in enumerate(emotions): img_path os.path.join(data_dir, emotion, os.listdir(os.path.join(data_dir, emotion))[0]) img cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) axes[i].imshow(img, cmapgray) axes[i].set_title(emotion) axes[i].axis(off) plt.show()这段代码做三件事遍历dataset/train下的表情类别文件夹每个类别取第一张图用灰度模式读入并展示。重点看两点——图像是否已经裁剪到人脸区域以及类别是否平衡。如果某个类别样本特别少训练时会出现严重偏斜后面调参要加class_weight。data_process.py负责统一尺寸和归一化常见做法是把图片缩到 48x48 灰度图像素值除以 255。data_separation.py按 8:1:1 或 7:2:1 划分数据集注意划分前要打乱顺序否则同一人的连续帧可能同时进训练集和测试集导致精度虚高。3. 模型训练与推理CNN、VGG、ResNet 三条路怎么选3.1 基础 CNN 模型的结构与训练参数model_CNN.py是最容易上手的入口。它的网络结构不复杂两到三层卷积 池化 全连接参数量小训练快适合先验证整条链路是否通畅。# model_CNN.py 网络定义核心片段 import torch.nn as nn import torch.nn.functional as F class CNN(nn.Module): def __init__(self, num_classes7): super(CNN, self).__init__() self.conv1 nn.Conv2d(1, 32, kernel_size3, padding1) self.conv2 nn.Conv2d(32, 64, kernel_size3, padding1) self.pool nn.MaxPool2d(2, 2) self.fc1 nn.Linear(64 * 12 * 12, 128) self.fc2 nn.Linear(128, num_classes) self.dropout nn.Dropout(0.5) def forward(self, x): x self.pool(F.relu(self.conv1(x))) x self.pool(F.relu(self.conv2(x))) x x.view(-1, 64 * 12 * 12) x F.relu(self.fc1(x)) x self.dropout(x) x self.fc2(x) return x参数说明num_classes7对应 7 类表情如果你只做 5 类改这个数字即可。Dropout(0.5)是防止过拟合的常规操作如果训练集很小可以调到 0.3。输入尺寸假设是 48x48经过两次池化变成 12x12全连接层的输入维度要跟着改。训练脚本里关注这几个参数# 训练循环关键参数 batch_size 64 learning_rate 0.001 epochs 50 optimizer torch.optim.Adam(model.parameters(), lrlearning_rate) criterion nn.CrossEntropyLoss()batch_size根据显存调8G 显存跑 64 没问题4G 就降到 32。learning_rate用 0.001 起步训练后期 loss 不降了再考虑降到 0.0001。epochs设 50 是保守值实际看验证集精度连续 5 轮不提升就可以早停。3.2 VGG 与 ResNet 的迁移学习策略VGG 和 ResNet 的代码结构类似但有两个关键区别一是网络更深二是通常用预训练权重做迁移学习。model_VGG.py和model_ResNet.py里如果写了pretrainedTrue第一次跑会自动下载权重网络不通畅的话会卡住。# ResNet 迁移学习示例 import torchvision.models as models class ResNetFER(nn.Module): def __init__(self, num_classes7): super(ResNetFER, self).__init__() self.backbone models.resnet18(pretrainedTrue) # 替换第一层卷积适配灰度图单通道输入 self.backbone.conv1 nn.Conv2d(1, 64, kernel_size7, stride2, padding3, biasFalse) # 替换最后的全连接层 self.backbone.fc nn.Linear(512, num_classes) def forward(self, x): return self.backbone(x)这里有个容易翻车的点ResNet 原始输入是 3 通道 RGB而 FER 数据通常是单通道灰度图。直接把conv1换成单通道后预训练权重里对应通道的参数会丢失需要重新训练。另一种做法是把灰度图复制成 3 通道保留预训练权重但计算量翻三倍。我一般选前者因为表情识别对颜色信息依赖不大。model_All_Compare.py会把三个模型的准确率、loss 曲线、混淆矩阵画在一起。跑之前确认三个模型都训练完了否则对比图里缺数据。3.3 推理与视频流表情识别训练完保存的model_resnet.pkl可以直接加载推理。单张图片的流程是读图 → 灰度化 → 人脸检测 → 裁剪 → 缩放 → 归一化 → 送入模型 → 取最大概率类别。import cv2 import torch import numpy as np from PIL import Image # 加载模型 model ResNetFER(num_classes7) model.load_state_dict(torch.load(model_resnet.pkl, map_locationcpu)) model.eval() # 人脸检测器 face_cascade cv2.CascadeClassifier(haarcascade_frontalface_default.xml) # 表情标签 emotion_labels [angry, disgust, fear, happy, sad, surprise, neutral] def predict_emotion(image_path): img cv2.imread(image_path) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces face_cascade.detectMultiScale(gray, scaleFactor1.1, minNeighbors5, minSize(30, 30)) for (x, y, w, h) in faces: roi gray[y:yh, x:xw] roi cv2.resize(roi, (48, 48)) roi roi.astype(float32) / 255.0 roi np.expand_dims(roi, axis0) roi np.expand_dims(roi, axis0) tensor torch.from_numpy(roi) with torch.no_grad(): output model(tensor) prob torch.nn.functional.softmax(output, dim1) pred torch.argmax(prob, dim1).item() cv2.rectangle(img, (x, y), (xw, yh), (0, 255, 0), 2) cv2.putText(img, emotion_labels[pred], (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2) cv2.imshow(Emotion, img) cv2.waitKey(0) cv2.destroyAllWindows() predict_emotion(test.jpg)参数说明scaleFactor1.1控制人脸检测的缩放步长值越小检测越细但越慢。minNeighbors5是检测框的邻域阈值调高会减少误检但可能漏检。minSize(30, 30)过滤太小的区域视频流里可以适当调大。视频流版本把cv2.imread换成cv2.VideoCapture逐帧处理即可。video example_dsh.mp4就是用来测这个的。注意视频流里每帧都做人脸检测会很卡常见做法是每隔几帧检测一次中间帧复用上一次的人脸框。4. 避坑与排查跑这套代码最容易翻车的五个地方4.1 路径写死导致 FileNotFoundError现象跑data_process.py或训练脚本时直接报FileNotFoundError提示找不到dataset/train或某个.pkl文件。原因源码里很多路径是相对路径而且作者本地目录结构和压缩包解压后的结构可能不一致。比如代码里写的是../dataset但你解压后dataset就在同级目录。解决全局搜一遍open(、pd.read_csv(、torch.load(、cv2.imread(把路径改成基于脚本所在目录的动态路径。我一般会在脚本开头加一行os.chdir(os.path.dirname(os.path.abspath(__file__)))一劳永逸。4.2 灰度图与三通道不匹配现象加载预训练 ResNet 时维度报错提示expected input[1, 3, 48, 48] to have 3 channels, but got 1 channel。原因torchvision.models.resnet18(pretrainedTrue)默认第一层接收 3 通道而 FER 数据是单通道灰度图。解决要么改conv1为单通道并接受预训练权重部分丢失要么在数据预处理时把灰度图np.stack成 3 通道。前者精度略降但训练快后者保留全部预训练信息但计算量增加。论文里建议用后者因为答辩时解释起来更顺。4.3 类别不平衡导致模型只预测多数类现象训练完发现模型对所有输入都输出happy或neutral混淆矩阵里其他类别几乎全错。原因FER2013 本身类别分布不均disgust和fear样本远少于happy。不加权的情况下模型会倾向于预测多数类来降低整体 loss。解决在CrossEntropyLoss里加weight参数按类别样本数倒数设置权重。或者用WeightedRandomSampler在数据加载时过采样少数类。跑完model_All_Compare.py看混淆矩阵如果某几类召回率特别低基本就是这个原因。4.4 训练 loss 震荡不收敛现象loss 曲线上下大幅震荡验证集精度忽高忽低始终上不去。原因学习率太大、batch_size 太小、或者数据没打乱。也有可能是data_separation.py划分时没设随机种子每次跑划分结果都不一样。解决先把学习率降到 0.0001 试一轮如果 loss 平滑下降说明之前太大。batch_size 尽量往大了调直到显存快满。在划分脚本里固定random.seed(42)和np.random.seed(42)保证每次划分一致。如果还震荡检查输入归一化是不是忘了做像素值 0-255 直接送进网络必炸。4.5 视频推理卡顿或人脸框闪烁现象跑video example_dsh.mp4时帧率极低或者人脸框在相邻帧之间跳来跳去。原因每帧都跑完整的人脸检测 表情分类计算量翻倍。另外detectMultiScale本身对光照和角度敏感相邻帧结果不稳定。解决人脸检测降频比如每 5 帧检测一次中间帧用上一次的框。表情分类可以每帧都跑因为输入已经裁剪成 48x48计算量很小。如果框还是闪加一个简单的 IOU 跟踪或者对检测框做滑动平均。haarcascade的参数minNeighbors调到 6 或 7 也能减少误检。5. 把项目变成论文和答辩的加分项几个实操技巧5.1 用 model_All_Compare.py 出对比图表论文里最需要的是「为什么选这个模型」的证据。model_All_Compare.py跑完会生成准确率对比柱状图、loss 曲线、混淆矩阵。我一般会把三个模型的训练日志都保留下来用 pandas 读进去自己画这样图表风格统一比脚本默认输出的好看。import pandas as pd import matplotlib.pyplot as plt # 假设三个模型的训练日志分别存成了 csv cnn_log pd.read_csv(logs/cnn_log.csv) vgg_log pd.read_csv(logs/vgg_log.csv) resnet_log pd.read_csv(logs/resnet_log.csv) plt.figure(figsize(10, 5)) plt.plot(cnn_log[val_acc], labelCNN) plt.plot(vgg_log[val_acc], labelVGG) plt.plot(resnet_log[val_acc], labelResNet) plt.xlabel(Epoch) plt.ylabel(Validation Accuracy) plt.legend() plt.title(Model Comparison on FER2013) plt.savefig(comparison.png, dpi300) plt.show()参数说明dpi300是论文插图的最低要求再低打印出来会糊。如果三个模型 epoch 数不一样截取相同 epoch 区间对比否则不公平。5.2 答辩 PPT 里必须放的三张图人脸面部表情识别答辩PPT.pptx已经有一版现成的但如果你想拿高分建议替换或补充三张图第一张是数据集的类别分布柱状图说明你意识到了不平衡问题第二张是三个模型的验证集精度对比曲线证明你做过选型第三张是混淆矩阵指出模型在哪些类别上容易混淆通常是 fear 和 surprise。这三张图一放评委基本不会在「工作量」上为难你。5.3 用 Face-Annotation-Tool 扩数据集的注意事项Face-Annotation-Tool-master.zip是标注工具想自己补数据时用。但注意两点一是标注格式要和现有image_emotion_mapping.py里的映射对齐否则训练时标签错乱二是新增数据要重新跑data_separation.py并且确保新数据和原数据分布一致别只补disgust补到过拟合。5.4 一个我踩过的坑pkl 文件跨版本加载model_resnet.pkl是用特定 PyTorch 版本保存的如果你本地版本差异太大torch.load会直接报错或者加载后精度暴跌。血泪经验是先看手册.docx里有没有写版本号没有的话试map_locationcpu加载还不行就重新训练。从那以后我每次拿到别人的 pkl 文件都强制走一遍「加载 → 推理一张测试图 → 对比预期输出」的验证流程确认没问题再往下做。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →