
简介这份资源是面向高校学生与Python初学者的计算机视觉实战项目包聚焦Yolov5目标检测框架下的人脸识别与人脸表情识别两大任务可直接用于毕业设计、课程设计或技能进阶练习。压缩包共收录2000个文件以1929个txt标注与说明文件、39个Python源码、20个yaml配置、6个sh脚本及若干md、json文件为主整体约167.89MB涵盖数据配置、模型训练、推理导出等完整流程。项目源码经过严格测试可一键运行省去环境搭建与调试的重复劳动。目前已有372人学习关注说明其在同类毕设选题中具备一定参考价值。读者可从中获得Yolov5训练与推理脚本、人脸检测与表情分类的工程化实现思路、配置文件与依赖说明以及可复用的目录组织方式便于快速理解项目结构并在此基础上完成二次开发或论文撰写。1. 从一份能跑通的 YOLOv5 人脸表情识别源码说起毕业设计选题里人脸识别和人脸表情识别几乎是每年都被抢的方向但真正让人头疼的不是选题而是从零搭一套能跑通、能写进论文、还能应付答辩演示的代码。这份基于 YOLOv5 Python 的人脸识别、人脸表情识别项目源码解决的就是这个落地问题它把数据加载、模型训练、推理导出这几条链路都串好了目录里能看到train.py、export.py、dataloaders.py、general.py这些核心文件还有optimizer_config.json这种训练配置。适合谁正在做毕业设计、课程设计需要一份结构完整、能直接跑起来再改的工程的同学。下面我按自己拆包复现的顺序把这份源码怎么用、参数怎么调、哪里容易翻车讲清楚。2. YOLOv5 做表情识别的选型逻辑与工程结构2.1 为什么用 YOLOv5 而不是纯分类网络人脸表情识别本质上是分类任务很多人第一反应是 ResNet、VGG 这类分类骨干。但这份源码选了 YOLOv5原因在于它把检测和分类合在一条链路里先用检测头框出人脸区域再对框内区域做表情类别判断。这样做的好处是当一张图里有多张人脸时不需要额外写人脸检测逻辑YOLOv5 的检测输出直接就是后续分类的输入。从工程角度看YOLOv5 的仓库结构成熟dataloaders.py负责数据加载和增强general.py放通用工具函数train.py是训练入口export.py负责导出部署格式。这套结构对毕业设计很友好因为论文里要写的「数据集构建」「模型训练」「结果分析」三块都能在代码里找到对应位置不用自己从零设计模块划分。常见做法是把表情类别当成 YOLO 的类别标签比如 angry、happy、sad、neutral 等每张人脸框对应一个类别。这样训练时 YOLO 的损失函数会同时优化框的位置和类别概率。需要注意的是表情识别的类间差异比通用目标检测小得多所以数据增强策略和超参数要针对性调整不能直接套 COCO 那套配置。2.2 源码目录里每个文件的实际作用拆包后先别急着跑花十分钟把文件职责理清楚后面改代码会省很多事。下面这张表是我按实际调用关系整理的文件作用改动频率train.py训练主入口解析参数、构建模型、启动训练循环低主要改命令行参数dataloaders.py数据集加载、图像增强、batch 组装中换数据集时要改general.py通用工具含 NMS、坐标转换、日志等低一般不动export.py模型导出为 ONNX、TorchScript 等格式低部署时才用optimizer_config.json优化器超参数配置中调参时改README.md项目说明和基础用法低train.py里通常会暴露--data、--weights、--epochs、--batch-size、--img-size这些参数。--data指向数据集配置文件里面写清楚训练集、验证集路径和类别名。--weights可以加载预训练权重这对小数据集表情识别很关键因为从零训练容易过拟合。dataloaders.py是换数据集时最需要关注的文件。它里面定义了数据读取方式、标签格式解析、以及 mosaic、mixup 这类增强。表情识别的人脸区域通常比较规整mosaic 增强可能会把不同表情的人脸拼在一起导致标签语义混乱所以实际训练时我一般会把 mosaic 概率调低或者关掉。2.3 环境准备与依赖安装跑之前先把 Python 环境弄干净。建议用 conda 建独立环境避免和系统里的包冲突。Python 版本选 3.8 或 3.9太新的版本有些依赖轮子还没跟上。# 创建独立环境Python 3.8 兼容性最稳 conda create -n face_yolo python3.8 -y conda activate face_yolo # 安装 PyTorch根据自己 CUDA 版本选对应命令 # 这里以 CUDA 11.3 为例没有 GPU 就用 cpu 版本 pip install torch1.12.1cu113 torchvision0.13.1cu113 -f https://download.pytorch.org/whl/torch_stable.html # 安装项目其余依赖 pip install -r requirements.txt这段命令的逻辑是先隔离环境再装深度学习框架最后补项目依赖。torch和torchvision版本要匹配否则会出现ImportError或者算子不兼容。没有 GPU 的话把cu113换成cpu训练会慢很多但跑通流程没问题。装完用下面这行验证python -c import torch; print(torch.__version__, torch.cuda.is_available())输出里第二个值是True说明 GPU 可用。如果是False但你有显卡大概率是 CUDA 版本和驱动不匹配这时候别硬扛先换成 CPU 版本把流程跑通再回头解决 GPU 问题。提示requirements.txt里如果有版本号写死的包装不上时先看报错信息里的版本冲突不要盲目升级所有包。3. 数据集准备与训练参数配置3.1 表情数据集的目录结构与标签格式YOLOv5 要求的数据集格式是每张图对应一个.txt标签文件每行写类别索引 x_center y_center width height坐标都是归一化到 0 到 1 之间的值。表情识别的人脸框通常由人脸检测器先跑一遍得到再人工或自动标注表情类别。目录结构一般长这样datasets/ face_expression/ images/ train/ 0001.jpg 0002.jpg val/ 0100.jpg labels/ train/ 0001.txt 0002.txt val/ 0100.txt然后写一个数据集配置文件比如face_expression.yaml# 数据集根路径train.py 会基于这个路径拼接 path: ./datasets/face_expression train: images/train val: images/val # 类别数量和类别名顺序要和标签里的索引一致 nc: 5 names: [angry, happy, sad, neutral, surprise]这里nc是类别数names的顺序必须和标签文件里写的索引严格对应。我见过有人把happy写成索引 0但标签里 0 对应的是angry训练 loss 能降但预测全乱这种坑排查起来很费时间。标签生成可以用脚本批量处理核心逻辑是读人脸检测结果再按表情分类模型或人工标注给类别。如果数据集本身已经带了表情标签直接转换格式就行。3.2 训练命令与关键参数含义数据准备好之后训练命令本身不复杂但每个参数都影响结果。下面是一条我常用的训练命令python train.py \ --data face_expression.yaml \ --weights yolov5s.pt \ --epochs 100 \ --batch-size 16 \ --img-size 640 \ --optimizer Adam \ --lr0 0.001 \ --mosaic 0.0 \ --project runs/train \ --name exp_face逐项说明--data指向数据集配置--weights加载预训练权重表情识别数据量通常不大从预训练开始比从零训练收敛快很多--epochs 100是训练轮数小数据集 50 到 100 轮一般够用--batch-size 16受显存限制显存不够就降到 8--img-size 640是输入分辨率人脸区域小的话可以适当调大但显存占用也会涨。--optimizer Adam和--lr0 0.001是优化器和初始学习率。YOLOv5 默认用 SGD但表情识别这种细粒度分类任务Adam 收敛更稳。--mosaic 0.0是关掉 mosaic 增强前面说过表情识别里 mosaic 容易把不同表情的人脸拼一起标签语义会乱。训练过程中重点看两个指标box_loss和cls_loss。box_loss下降说明人脸框定位在变好cls_loss下降说明表情分类在变好。如果cls_loss震荡不降先检查标签类别是否和names对应再考虑调低学习率。3.3 优化器配置文件怎么改optimizer_config.json里通常放的是优化器的细粒度参数比如权重衰减、动量、学习率调度策略。不同版本的 YOLOv5 这个文件内容不一样打开后先看结构别直接覆盖。常见做法是只改自己需要的字段比如把weight_decay从默认值调小一点防止小数据集过拟合{ weight_decay: 0.0005, momentum: 0.937, lr0: 0.001, lrf: 0.01 }weight_decay是 L2 正则强度越大正则越强momentum影响优化器更新方向lr0是初始学习率lrf是最终学习率相对于初始学习率的比例用来做余弦退火。改完保存重新跑train.py就会生效。如果训练时发现 loss 突然变成 NaN先把学习率调小一个数量级再试。注意改配置文件前先备份一份原始文件调参调崩了能快速回退。4. 推理、导出与常见翻车点排查4.1 用训练好的权重做推理训练完成后权重默认存在runs/train/exp_face/weights/best.pt。推理可以用 YOLOv5 自带的detect.py也可以自己写脚本调用。自己写的好处是能把表情识别结果和业务逻辑接起来。import torch from models.common import DetectMultiBackend from utils.general import non_max_suppression, scale_boxes from utils.augmentations import letterbox import cv2 import numpy as np # 加载训练好的权重 device torch.device(cuda if torch.cuda.is_available() else cpu) model DetectMultiBackend(runs/train/exp_face/weights/best.pt, devicedevice) model.eval() # 读取图片并做预处理 img cv2.imread(test.jpg) img_resized letterbox(img, 640, stride32, autoTrue)[0] img_resized img_resized.transpose((2, 0, 1))[::-1] # BGR 转 RGB img_tensor torch.from_numpy(np.ascontiguousarray(img_resized)).float().to(device) / 255.0 img_tensor img_tensor.unsqueeze(0) # 前向推理 NMS 后处理 pred model(img_tensor) pred non_max_suppression(pred, conf_thres0.25, iou_thres0.45) # 解析结果 for det in pred: if det is not None and len(det): det[:, :4] scale_boxes(img_tensor.shape[2:], det[:, :4], img.shape).round() for *xyxy, conf, cls in det: label f{model.names[int(cls)]} {conf:.2f} print(label, xyxy)这段代码的逻辑是加载权重、预处理图片、前向推理、NMS 去重、坐标还原到原图尺寸。conf_thres0.25是置信度阈值低于这个值的框会被丢掉iou_thres0.45是 NMS 的 IoU 阈值控制重叠框的合并程度。表情识别里如果发现同一张脸被框了多次把iou_thres调低一点。letterbox做的是保持长宽比的缩放加填充这样不会让人脸变形。scale_boxes把归一化坐标还原回原图尺寸方便后续画框或裁剪。4.2 模型导出为 ONNX 的注意事项如果毕设要求部署演示或者要在没有 PyTorch 的环境里跑导出 ONNX 是常见选择。export.py就是干这个的python export.py \ --weights runs/train/exp_face/weights/best.pt \ --include onnx \ --img-size 640 640 \ --batch-size 1 \ --opset 12--include onnx指定导出格式--img-size要和训练时一致否则推理结果会偏--opset 12是 ONNX 算子集版本太低有些算子不支持太高某些推理引擎不兼容12 是比较稳的选择。导出后建议用onnxruntime跑一遍验证输出是否和 PyTorch 一致import onnxruntime as ort import numpy as np sess ort.InferenceSession(best.onnx) input_name sess.get_inputs()[0].name dummy np.random.randn(1, 3, 640, 640).astype(np.float32) out sess.run(None, {input_name: dummy}) print(out[0].shape)如果输出 shape 和预期不符先检查导出时的--img-size和--batch-size是否和推理时一致。4.3 避坑与常见问题排查现象一训练 loss 一直不降cls_loss 在某个值附近震荡。原因通常是标签类别索引和names顺序不一致或者标签文件里有空行、格式错误。解决方法是写个小脚本遍历标签文件统计每个类别索引出现的次数和names对照。另外检查标签坐标是否归一化有人直接把像素坐标写进去模型根本学不到东西。现象二推理时检测框位置整体偏移。原因是预处理和坐标还原不匹配。letterbox缩放后scale_boxes要用同样的缩放比例还原。如果自己改了预处理逻辑但没改还原逻辑框就会偏。解决方法是统一用 YOLOv5 自带的letterbox和scale_boxes不要自己手写缩放。现象三GPU 显存够但训练报 CUDA out of memory。不一定是显存真不够可能是--img-size或--batch-size设太大也可能是 dataloader 的 worker 数太多导致内存泄漏。先把--batch-size减半试再检查--workers参数设成 0 或 2 试试。如果还不行用nvidia-smi看是不是有其他进程占着显存。现象四导出 ONNX 后推理结果和 PyTorch 差很多。常见原因是导出时没设--dynamic或者 opset 版本和推理引擎不匹配。另外 YOLOv5 的 NMS 后处理如果没一起导出ONNX 输出的是原始预测需要自己写后处理。解决方法是先用固定输入尺寸导出验证一致后再考虑动态轴。现象五换了自己的数据集后验证集指标正常但实际图片预测很差。大概率是训练集和实际场景分布不一致比如训练集都是正面清晰人脸实际图片有侧脸、遮挡、光照变化。解决办法是在数据增强里加随机裁剪、亮度对比度扰动或者补充实际场景的样本。表情识别对光照和姿态很敏感这一点比通用目标检测更明显。5. 把这份源码改成能写进论文的进阶技巧5.1 用混淆矩阵和 PR 曲线补论文实验章节毕业设计论文里光有准确率不够答辩老师通常会问类别不平衡和误判分布。YOLOv5 训练完会在runs/train/exp_face/下生成混淆矩阵和 PR 曲线直接拿来用就行。如果找不到可以在验证脚本里手动调val.py加上--plots参数。混淆矩阵能看出哪些表情容易被混比如sad和neutral经常互相误判这本身就是论文里可以展开分析的点。PR 曲线则能说明在不同置信度阈值下各类别的查准率和查全率比单一准确率更有说服力。5.2 调整超参数提升小数据集表现表情识别公开数据集通常不大过拟合是常态。除了前面说的关掉 mosaic还可以做这几件事把--label-smoothing开到 0.1让模型不要对某一类过度自信把--dropout设成 0.2 左右在全连接层前加随机失活用--freeze冻结骨干网络前几层只训练检测头和分类头。我一般会先跑一组基线记录mAP0.5和各类别precision/recall然后每次只改一个参数对比指标变化。这样调参有据可查写论文时也能说清楚每个参数的作用。别一次改好几个参数不然指标涨了也不知道是谁的功劳跌了更不知道回退哪个。5.3 一个我踩过的坑验证集划分有次我图省事直接把训练集随机切了 20% 当验证集结果验证指标很高但答辩演示时换了几张新图就翻车。后来才发现同一个人的多张照片被分到了训练集和验证集模型其实是在「认人」而不是「认表情」。从那以后我每次划分数据集都强制按人物 ID 分组同一个人只出现在训练集或验证集其中一边。这个习惯让我后面几次实验的指标都更可信答辩时被问到泛化能力也能答得上来。如果你拿到的源码里已经分好了训练集和验证集先检查一下有没有同人跨集的情况。没有人物 ID 信息的话至少按图片拍摄时间或来源分组别用纯随机划分。希望这份拆解能帮你把这份源码真正跑起来、改明白顺利把毕业设计落地。本文还有配套的精品资源点击获取