1. 项目概述:半监督学习在食品图像分类中的应用
食品图像分类是计算机视觉领域的一个重要应用场景,随着移动互联网和外卖平台的普及,对食品图像的自动识别需求日益增长。传统监督学习方法需要大量标注数据,而食品图像标注成本高、周期长。半监督学习(Semi-Supervised Learning)能够有效利用少量标注数据和大量未标注数据,显著降低标注成本。
PyTorch作为当前主流的深度学习框架,其动态计算图和丰富的模型库为半监督学习提供了强大支持。本项目将基于PyTorch实现一个半监督食品图像分类系统,重点解决以下问题:
- 如何有效利用少量标注样本
- 如何处理食品图像中的类内差异大、类间相似度高的问题
- 如何设计适合食品图像特征的半监督学习策略
2. 核心算法与模型设计
2.1 半监督学习基础框架
半监督学习的核心思想是通过对未标注数据的合理利用,提升模型性能。在食品图像分类中,我们采用基于一致性正则化(Consistency Regularization)的方法,其基本流程如下:
- 对有标注数据使用标准交叉熵损失
- 对无标注数据施加扰动后要求预测保持一致
- 结合两种损失进行联合优化
数学表达为:
L = L_supervised + λL_unsupervised其中λ是平衡系数,控制无监督损失的权重。
2.2 模型架构选择
针对食品图像特点,我们采用ResNet-50作为基础特征提取器,并进行以下改进:
- 输入层调整:将原始ImageNet预训练模型的输入尺寸从224×224调整为320×320,以保留更多食品细节
- 注意力机制:在最后两个残差块后添加CBAM注意力模块,增强对关键区域(如食材纹理)的关注
- 分类头设计:使用两个全连接层,中间加入Dropout(p=0.5)防止过拟合
提示:食品图像通常包含多个食材,全局和局部特征都重要,因此注意力机制特别适用
2.3 数据增强策略
半监督学习的效果高度依赖数据增强策略。针对食品图像,我们设计了一套组合增强方法:
| 增强类型 | 具体操作 | 参数范围 | 适用场景 |
|---|---|---|---|
| 几何变换 | 随机旋转 | ±30度 | 所有食品 |
| 颜色变换 | HSV调整 | H±0.1, S±0.2, V±0.2 | 光照变化大的场景 |
| 局部遮挡 | RandomErasing | 比例0.02-0.2 | 模拟部分遮挡 |
| 混合增强 | CutMix | α=1.0 | 增强类间关系学习 |
3. 实现细节与PyTorch代码解析
3.1 环境配置
推荐使用以下环境配置:
conda create -n foodssl python=3.8 conda install pytorch==1.10.0 torchvision==0.11.0 cudatoolkit=11.3 -c pytorch pip install albumentations==1.1.0 pytorch-lightning==1.5.03.2 一致性正则化实现
核心代码实现一致性损失:
import torch import torch.nn.functional as F def consistency_loss(logits_w, logits_s, threshold=0.95): # 计算弱增强和强增强预测的差异 probs_w = torch.softmax(logits_w.detach(), dim=-1) probs_s = torch.softmax(logits_s, dim=-1) # 只对高置信度样本计算损失 max_probs, _ = torch.max(probs_w, dim=-1) mask = (max_probs > threshold).float() # 计算MSE损失 loss = F.mse_loss(probs_s, probs_w, reduction='none') loss = (loss.mean(dim=1) * mask).mean() return loss3.3 训练流程设计
训练过程分为三个阶段:
- 预热阶段(前10%迭代):仅使用有标注数据训练
- 半监督阶段:逐步增加无标注数据权重
- 微调阶段(最后5%迭代):降低学习率,仅使用有标注数据
关键训练参数配置:
optimizer = torch.optim.SGD(model.parameters(), lr=0.03, momentum=0.9, weight_decay=5e-4) scheduler = torch.optim.lr_scheduler.CosineAnnealingLR( optimizer, T_max=200, eta_min=1e-4)4. 实验设计与性能优化
4.1 数据集构建
我们使用Food-101数据集作为基础,构建半监督实验环境:
- 有标注数据:每类随机选取100张(共101类,10,100张)
- 无标注数据:使用剩余图像(约90,000张)
- 测试集:官方提供的25,250张图像
数据处理流程:
from torchvision import transforms train_transform = transforms.Compose([ transforms.RandomResizedCrop(320), transforms.RandomHorizontalFlip(), transforms.ColorJitter(0.4, 0.4, 0.4), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ])4.2 性能对比实验
在不同标注比例下的准确率对比:
| 标注比例 | 纯监督 | 半监督(本文) | 提升幅度 |
|---|---|---|---|
| 10% | 58.2% | 72.5% | +14.3% |
| 20% | 65.7% | 78.1% | +12.4% |
| 50% | 76.3% | 83.9% | +7.6% |
4.3 消融实验
验证各组件贡献:
| 方法 | 准确率 | 说明 |
|---|---|---|
| Baseline | 68.2% | 标准ResNet-50 |
| +一致性正则 | 73.5% | 增加无监督损失 |
| +注意力机制 | 75.1% | 添加CBAM模块 |
| +混合增强 | 78.3% | 使用CutMix策略 |
5. 实际应用与部署建议
5.1 模型轻量化
为满足移动端部署需求,可采用以下优化策略:
- 知识蒸馏:使用训练好的大模型指导小模型训练
- 量化压缩:将FP32模型转为INT8,减少75%存储占用
- 模型剪枝:移除不重要的卷积核
量化示例代码:
model_fp32 = torch.load('food_model.pth') model_int8 = torch.quantization.quantize_dynamic( model_fp32, # 原始模型 {torch.nn.Linear}, # 要量化的模块 dtype=torch.qint8) # 量化类型5.2 部署方案
针对不同场景的部署建议:
云端部署:
- 使用TorchScript导出模型
- 搭配FastAPI提供REST服务
- 建议GPU:T4或A10G
移动端部署:
- 转换为ONNX格式
- 使用TensorRT或CoreML优化
- 建议使用量化后模型
边缘设备:
- 使用PyTorch Mobile
- 考虑Jetson Nano等嵌入式设备
6. 常见问题与解决方案
6.1 训练不稳定问题
症状:损失值剧烈波动或出现NaN 可能原因及解决:
- 学习率过高 → 降低初始学习率(如从0.1调到0.03)
- 无监督权重过大 → 逐步增加λ值(线性或余弦调度)
- 数据增强过强 → 调整增强参数,特别是颜色变换幅度
6.2 类别不平衡处理
食品数据集中常见某些类别样本过少:
- 对有标注数据使用类别平衡采样器
- 对无标注数据预测结果进行温度缩放(Temperature Scaling)
- 在损失函数中加入类别权重
实现示例:
from torch.utils.data import WeightedRandomSampler class_counts = [...] # 每个类别的样本数 weights = 1. / torch.tensor(class_counts, dtype=torch.float) samples_weights = weights[labels] sampler = WeightedRandomSampler( weights=samples_weights, num_samples=len(samples_weights), replacement=True)6.3 模型过拟合对策
当有标注数据很少时容易过拟合:
- 使用更强的正则化(Dropout=0.5,Weight Decay=5e-4)
- 采用早停策略(patience=10)
- 使用标签平滑(Label Smoothing=0.1)
标签平滑实现:
criterion = torch.nn.CrossEntropyLoss(label_smoothing=0.1)在实际应用中,我们发现食品图像分类的难点往往不在于模型本身,而在于数据的质量和多样性。建议定期收集真实场景下的食品图像,持续更新训练数据。对于新类别的加入,可以采用迁移学习策略,仅微调最后几层网络,既能快速适应新类别,又能保持原有类别的识别能力。