1. 项目概述
最近在实验室用PyTorch实现了一个人脸识别系统,效果还不错。这个项目主要基于VGG-16模型,通过迁移学习的方式在自定义数据集上进行了训练。整个过程从数据准备到模型部署大概花了两周时间,期间踩了不少坑,也积累了一些实战经验。
人脸识别作为计算机视觉的基础应用,在安防、金融、零售等领域都有广泛应用。相比传统方法,基于深度学习的人脸识别准确率更高,鲁棒性更好。PyTorch作为当前最流行的深度学习框架之一,其动态计算图和丰富的预训练模型库,使得实现这样的人脸识别系统变得相对简单。
2. 环境配置与数据准备
2.1 PyTorch环境搭建
我使用的是Python 3.8和PyTorch 1.12.1版本,搭配CUDA 11.6进行GPU加速。环境配置建议使用conda创建虚拟环境:
bash复制conda create -n face_rec python=3.8
conda activate face_rec
conda install pytorch torchvision torchaudio cudatoolkit=11.6 -c pytorch
注意:CUDA版本需要与显卡驱动兼容。我用的RTX 3060显卡,驱动版本510.47.03,实测CUDA 11.6运行稳定。
2.2 数据集准备
我使用了两个数据集:
- LFW(Labeled Faces in the Wild):包含13,000+人脸图像
- 自建数据集:采集了实验室20个人的照片,每人约50张不同角度和光照条件的图像
数据预处理流程:
- 使用OpenCV的Haar级联检测器进行人脸检测和裁剪
- 统一resize到224×224像素
- 应用随机水平翻转、颜色抖动等数据增强
- 按8:1:1划分训练集、验证集和测试集
python复制import cv2
from torchvision import transforms
transform = transforms.Compose([
transforms.ToPILImage(),
transforms.Resize((224, 224)),
transforms.RandomHorizontalFlip(),
transforms.ColorJitter(brightness=0.2, contrast=0.2),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
3. 模型构建与训练
3.1 VGG-16模型改造
使用预训练的VGG-16作为基础模型,替换最后的全连接层:
python复制import torch.nn as nn
from torchvision import models
class FaceNet(nn.Module):
def __init__(self, num_classes=20):
super(FaceNet, self).__init__()
self.base = models.vgg16(pretrained=True)
in_features = self.base.classifier[6].in_features
self.base.classifier[6] = nn.Linear(in_features, num_classes)
def forward(self, x):
return self.base(x)
3.2 训练策略
训练参数配置:
- 优化器:Adam,初始学习率0.001
- 损失函数:交叉熵损失
- Batch size:32
- Epochs:50
- 学习率调度:每10个epoch衰减为原来的0.1
python复制from torch.optim import Adam
from torch.optim.lr_scheduler import StepLR
model = FaceNet().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = Adam(model.parameters(), lr=0.001)
scheduler = StepLR(optimizer, step_size=10, gamma=0.1)
for epoch in range(50):
model.train()
for images, labels in train_loader:
# 训练代码...
pass
scheduler.step()
3.3 训练结果
经过50个epoch的训练,模型在测试集上达到了98.2%的准确率。训练过程中的损失和准确率曲线如下:
| Epoch | Train Loss | Val Acc |
|---|---|---|
| 10 | 0.152 | 92.3% |
| 20 | 0.078 | 95.6% |
| 30 | 0.042 | 97.1% |
| 40 | 0.025 | 97.8% |
| 50 | 0.018 | 98.2% |
4. 模型优化与部署
4.1 模型量化
为了提升推理速度,我对模型进行了动态量化:
python复制import torch.quantization
quantized_model = torch.quantization.quantize_dynamic(
model, {nn.Linear}, dtype=torch.qint8
)
torch.save(quantized_model.state_dict(), 'face_rec_quantized.pth')
量化后模型大小从528MB减小到132MB,推理速度提升约2.3倍。
4.2 部署方案
我尝试了三种部署方式:
- Flask Web API
- ONNX Runtime
- LibTorch C++接口
其中Flask方案最适合快速验证:
python复制from flask import Flask, request, jsonify
import cv2
import torch
app = Flask(__name__)
model = load_model()
transform = get_transform()
@app.route('/predict', methods=['POST'])
def predict():
file = request.files['image']
img = cv2.imdecode(np.frombuffer(file.read(), np.uint8), cv2.IMREAD_COLOR)
img = transform(img).unsqueeze(0)
with torch.no_grad():
output = model(img)
pred = output.argmax().item()
return jsonify({'class_id': pred})
5. 常见问题与解决方案
5.1 过拟合问题
在初期训练中,模型在训练集上准确率很高(99%+),但在验证集上只有85%左右。解决方法:
- 增加数据增强(添加随机旋转、遮挡)
- 在FC层添加Dropout(p=0.5)
- 使用早停策略(patience=5)
5.2 类别不平衡
自建数据集中某些人的样本较少。解决方法:
- 对少数类样本进行过采样
- 在损失函数中使用类别权重:
python复制class_counts = [50, 50, ..., 20] # 每个类别的样本数
weights = 1. / torch.tensor(class_counts, dtype=torch.float)
criterion = nn.CrossEntropyLoss(weight=weights.to(device))
5.3 实时识别延迟
在树莓派上测试时发现延迟严重(>1s)。优化方法:
- 改用MobileNetV3作为backbone
- 输入尺寸减小到112×112
- 使用TensorRT加速
优化后延迟降低到约200ms,满足实时性要求。
6. 扩展应用
基于这个人脸识别系统,可以扩展多个应用场景:
- 智能考勤系统:结合Redis存储考勤记录,支持API查询
- 门禁系统:使用行空板K10作为硬件载体
- 人脸检索:通过特征向量计算相似度
例如实现一个简单的考勤API:
python复制import redis
from datetime import datetime
r = redis.Redis()
def record_attendance(user_id):
now = datetime.now()
date_str = now.strftime("%Y-%m-%d")
time_str = now.strftime("%H:%M:%S")
r.hset(f"attendance:{date_str}", user_id, time_str)
这个项目从理论到实践走通了整个人脸识别流程,后续可以考虑加入活体检测、口罩识别等功能。PyTorch的灵活性和丰富的模型库让深度学习实验变得高效有趣。
