基于深度学习的实时人脸表情分类系统,支持多种CNN架构(ResNet、VGG、MobileNet、EfficientNet等),提供模型训练、评估、优化(量化/剪枝/知识蒸馏)及Web演示功能。
本项目实现了一个完整的表情识别系统,能够识别5种基本表情:
- 😠 愤怒 (Anger)
- 😨 恐惧 (Fear)
- 😊 快乐 (Happy)
- 😢 悲伤 (Sad)
- 😲 惊讶 (Surprise)
- 多模型支持:自定义CNN、ResNet18/34/50、VGG16、MobileNetV2、EfficientNet-B0
- 迁移学习:支持ImageNet预训练权重,大幅提升训练效率
- 模型优化:支持动态量化、模型剪枝、知识蒸馏
- 数据清洗:自动检测并处理损坏、重复、低质量图片
- Web演示:基于Flask的可视化界面,支持图片上传和摄像头拍照
- 批量训练:一键训练多个模型并生成对比报告
emotion-recognition/
├── app.py # Flask Web服务入口
├── pyproject.toml # 项目依赖(uv 管理)
├── LICENSE # MIT 许可证
│
├── src/ # 核心代码
│ ├── config.py # 集中配置(路径、类别、输入尺寸、超参)
│ ├── model.py # 模型工厂(CNN + 迁移学习注册表、按模型的输入尺寸)
│ ├── transforms.py # 按模型构建预处理/增强管线
│ ├── inference.py # 自描述 checkpoint 的保存/加载与单图推理
│ ├── dataset.py # 数据集加载与清洗
│ ├── train.py # 单模型训练脚本
│ ├── train_multiple.py # 批量训练与对比
│ ├── evaluate.py # 模型评估工具
│ ├── optimize_distill.py # 模型优化(量化/剪枝/蒸馏)
│ ├── assets.py # 运行时资产注册表(YuNet/HSEmotion 下载与缓存)
│ ├── face/ # 人脸检测与裁剪(YuNet)
│ ├── engine/ # 可替换推理后端(onnxruntime,可扩展 RKNN/ncnn)
│ ├── runtime/ # 情绪核心运行时(单帧编排、时序平滑、Demo)
│ ├── logging_setup.py # 统一日志
│ └── utils.py # 工具函数(随机种子、数据划分、可视化)
│
├── templates/
│ └── index.html # Web演示前端页面
│
├── tests/ # pytest 测试
├── docs/ # 设计稿与实施计划
│
├── data/ # 数据目录(需自行准备)
│ ├── raw/ # 原始数据(anger/fear/happy/sad/surprise)
│ ├── train/ # 训练集(自动生成)
│ └── val/ # 验证集(自动生成)
│
├── models/ # 模型权重
│ ├── best_model_*.pth # 训练产物
│ ├── face/yunet.onnx # 人脸检测(自动下载)
│ └── emotion/*.onnx # 情绪模型(自动下载)
│
└── results/ # 训练结果(自动生成)
# 克隆项目
git clone <repository-url>
cd emotion-recognition
# 安装依赖(使用 uv)
uv sync将表情图片按类别放入 data/raw/ 目录:
data/raw/
├── anger/ # 愤怒表情图片
├── fear/ # 恐惧表情图片
├── happy/ # 快乐表情图片
├── sad/ # 悲伤表情图片
└── surprise/ # 惊讶表情图片
支持的图片格式:JPG、JPEG、PNG、BMP
uv run python -m src.utils这将自动清洗数据并按8:2比例划分为训练集和验证集。
训练单个模型:
# 默认 EfficientNet-B0;用命令行参数覆盖
uv run python -m src.train --model resnet18 --epochs 20 --batch-size 64 --lr 0.001
# 强制 CPU
uv run python -m src.train --model mobilenet --cpu可选模型:cnn, resnet18, resnet34, resnet50, vgg16, mobilenet, efficientnet。
训练已内置:类别加权损失、label smoothing、weight decay、随机种子、早停、CUDA 自动混合精度。
输入尺寸自动按模型选择:迁移学习骨干用 224×224(ImageNet 标准),自定义 CNN 用 48×48。
批量训练多个模型:
# 训练全部
uv run python -m src.train_multiple
# 仅训练指定模型
uv run python -m src.train_multiple --models resnet18 mobilenet efficientnet自动生成对比报告与图表。
# 评估 models/ 下所有模型并生成对比报告
uv run python -m src.evaluate --all
# 评估单个 checkpoint
uv run python -m src.evaluate --model-path models/best_model_resnet18.pth
# 预测单张图片
uv run python -m src.evaluate --model-path models/best_model_resnet18.pth --image path/to/img.jpgcheckpoint 自带模型类型等元信息,评估/部署时无需手动指定
model_type。
# 启动 Web(默认仅本机访问 127.0.0.1:5000,使用 waitress 生产服务器)
uv run python app.py
# 对外访问(waitress):FLASK_HOST=0.0.0.0 uv run python app.py
# 开发调试(仅限本机;调试器有 RCE 风险,代码会强制 127.0.0.1):
# FLASK_DEBUG=1 uv run python app.py访问 http://localhost:5000 查看 Web 界面。启动时会自动加载首个 best_model_*.pth。
硬件无关的实时人脸情绪推理闭环,可作陪伴机器人等嵌入式设备的感知核心。
# 开箱即用:自动下载 YuNet + HSEmotion 预训练模型(AffectNet 8 类,含 Neutral)
uv run python -m src.runtime.demo --camera 0
# 或对单张图片推理
uv run python -m src.runtime.demo --image face.jpg
# 预先下载全部运行时资产
uv run python -m src.assets
# 换用自训模型(如 Plan 1B 蒸馏量化产物)
uv run python -m src.runtime.demo --camera 0 \
--emotion-model models/emotion_int8.onnx \
--labels anger fear happy sad surprise --input-size 112链路:取帧 → YuNet 检测裁脸 → ONNX 情绪模型(onnxruntime)→ 时序平滑 → 情绪事件。
推理后端(src/engine/)可替换为 RKNN/ncnn 而不改动 runtime;设计见
docs/superpowers/specs/2026-06-11-embedded-emotion-core-design.md。
| 模型 | 参数量 | 预计准确率 | 训练速度 | 推荐场景 |
|---|---|---|---|---|
| Custom CNN | ~590万 | 60-70% | 中 | 学习CNN原理 |
| ResNet18 | ~1120万 | 75-85% | 快 | 推荐首选 |
| ResNet34 | ~2150万 | 78-88% | 中 | 更高准确率 |
| ResNet50 | ~2350万 | 80-90% | 慢 | 最高准确率 |
| VGG16 | ~1.38亿 | 75-85% | 很慢 | 经典架构学习 |
| MobileNetV2 | ~220万 | 70-80% | 最快 | 移动端部署 |
| EfficientNet-B0 | ~410万 | 78-88% | 快 | 最佳平衡 |
- 初学者/快速实验:MobileNet(训练最快)
- 实际项目首选:ResNet18 或 EfficientNet-B0
- 追求最高准确率:ResNet50
- 移动端部署:MobileNet + 量化
- 学习CNN原理:Custom CNN
将 FP32 模型的线性层转换为 INT8(eager 模式动态量化仅作用于 nn.Linear):
uv run python -m src.optimize_distill --mode quantize --model-path models/best_model_resnet18.pth全局非结构化 L1 剪枝(剪枝后建议微调以恢复准确率):
uv run python -m src.optimize_distill --mode prune --model-path models/best_model_resnet18.pth --amount 0.3将大模型的知识迁移到小模型:
uv run python -m src.optimize_distill --mode distill \
--teacher-path models/best_model_resnet50.pth --student resnet18 --epochs 15推荐组合:
- ResNet50 → ResNet18
- EfficientNet → MobileNet
- ResNet18 → MobileNet
GET /api/modelsPOST /api/load_model
Content-Type: application/json
{
"model_filename": "best_model_resnet18.pth"
}POST /api/predict
Content-Type: application/json
{
"image": "data:image/jpeg;base64,..."
}响应示例:
{
"predicted_class": "happy",
"predicted_class_zh": "快乐",
"emoji": "😊",
"confidence": 0.953,
"probabilities": {
"anger": {"zh": "愤怒", "emoji": "😠", "probability": 0.01},
"fear": {"zh": "恐惧", "emoji": "😨", "probability": 0.02},
"happy": {"zh": "快乐", "emoji": "😊", "probability": 0.953},
"sad": {"zh": "悲伤", "emoji": "😢", "probability": 0.01},
"surprise": {"zh": "惊讶", "emoji": "😲", "probability": 0.007}
}
}GET /api/status训练时默认启用以下增强:
- 随机水平翻转 (p=0.5)
- 随机旋转 (±10°)
- 颜色抖动 (亮度/对比度 ±0.2)
使用 ReduceLROnPlateau:当验证准确率不再提升时自动降低学习率。
- Dropout (Conv层: 0.25, FC层: 0.5)
- BatchNormalization
- 早停(保存最佳模型)
系统自动检测并处理以下问题:
- 损坏图片:无法打开或读取
- 格式错误:非标准图像格式
- 尺寸异常:过小(<32px)或过大(>2000px)
- 质量过低:全黑/全白或方差过小
- 重复图片:基于MD5哈希去重
问题文件会被移动到 data/quarantine/ 目录。
- Python 3.10+
- 8GB RAM
- 10GB 磁盘空间
- Python 3.10+
- 16GB RAM
- NVIDIA GPU (CUDA 11.0+)
- 20GB+ 磁盘空间
# 运行测试
uv run pytest -q
# 代码检查
uv run ruff check src app.py tests- GPU加速:如有NVIDIA GPU,确保安装CUDA版本的PyTorch
- 数据隐私:训练数据不会上传到任何服务器
- 模型文件:
.pth文件较大,已在.gitignore中排除 - 首次训练:预训练模型权重会自动从网络下载
欢迎提交Issue和Pull Request!
- Fork本仓库
- 创建特性分支 (
git checkout -b feature/AmazingFeature) - 提交更改 (
git commit -m 'Add some AmazingFeature') - 推送到分支 (
git push origin feature/AmazingFeature) - 开启Pull Request
本项目采用 MIT 许可证。详见 LICENSE 文件。
如有问题或建议,请通过以下方式联系:
- 提交 GitHub Issue
- 发送邮件至:Kerro99920@gmail.com
如果这个项目对你有帮助,请给个 ⭐ Star!