1. 项目概述
作为一名长期奋战在计算机视觉一线的算法工程师,我深知图像分类任务在深度学习领域的基础性和重要性。今天,我将以food-11食物分类项目为例,带大家完整走一遍从零搭建分类模型的全流程。这个项目虽然看似简单,但包含了数据预处理、模型设计、训练优化等核心环节,是理解深度学习图像处理的绝佳案例。
在工业界实践中,我们经常遇到类似food-11这样的小规模数据集场景。这类项目的特点是:数据量有限(通常每个类别只有几十到几百张图片)、类别间差异可能不明显(比如不同种类的面食)、但业务需求又要求较高的准确率。经过多次实战,我总结出了一套针对小规模数据集的解决方案,今天就将这些经验毫无保留地分享给大家。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据准备与预处理
2.1 数据集结构解析
food-11数据集采用典型的分类数据集结构,包含三个子集:
code复制food-11/
├── training/
│ ├── labeled/ # 带标注的训练数据
│ └── unlabeled/ # 无标注数据(可用于半监督学习)
├── validation/ # 验证集
└── testing/ # 测试集
每个类别文件夹以两位数编号命名(00-10),这种结构在实际项目中非常常见。我建议在开始编码前,先用tree命令或文件管理器直观查看数据集结构,这能帮助我们更好地设计数据读取逻辑。
2.2 数据读取实现
数据读取是深度学习项目中最容易被忽视但极其重要的环节。一个健壮的数据读取管道应该具备以下特性:
- 内存高效(特别是处理大型数据集时)
- 支持多种图像格式
- 具备基本的数据校验功能
以下是改进后的数据读取实现:
python复制def read_file(path, img_size=224):
"""
读取分类数据集
:param path: 数据集根路径
:param img_size: 统一调整的图像尺寸
:return: 图像数据(numpy数组)和标签
"""
X, Y = [], []
class_dirs = sorted([d for d in os.listdir(path) if os.path.isdir(os.path.join(path, d))])
for class_idx, class_dir in enumerate(tqdm(class_dirs)):
class_path = os.path.join(path, class_dir)
img_files = [f for f in os.listdir(class_path)
if f.lower().endswith(('.png', '.jpg', '.jpeg'))]
for img_file in img_files:
try:
img_path = os.path.join(class_path, img_file)
img = Image.open(img_path).convert('RGB') # 确保转为RGB格式
img = img.resize((img_size, img_size))
X.append(np.array(img))
Y.append(class_idx)
except Exception as e:
print(f"Error loading {img_path}: {str(e)}")
continue
return np.array(X), np.array(Y)
这个实现有以下改进:
- 自动过滤非图像文件
- 强制转换为RGB格式(避免某些灰度图像导致维度问题)
- 添加了异常处理
- 使用列表存储再转换,比预分配数组更灵活
2.3 数据增强策略
对于小数据集,数据增强是提升模型泛化能力的关键。在food分类任务中,我们需要考虑食物图像的特殊性:
-
几何变换:
- 随机旋转(-30°到30°):模拟不同拍摄角度
- 随机水平翻转:适用于对称性较强的食物
- 随机裁剪:模拟局部特写
-
颜色变换:
- 亮度/对比度调整:模拟不同光照条件
- 色相/饱和度微调:考虑食物颜色的多样性
python复制from torchvision import transforms
train_transform = transforms.Compose([
transforms.ToPILImage(),
transforms.RandomResizedCrop(224, scale=(0.8, 1.0)),
transforms.RandomRotation(30),
transforms.RandomHorizontalFlip(p=0.5),
transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2),
transforms.ToTensor(),
t
