小样本图像分类应优先选用参数少、收敛快的预训练模型(如efficientnet-b0),替换对应分类头(efficientnet改model.classifier[1],resnet改model.fc,vit改model.heads.head),并采用先全冻结骨干网络、再渐进解冻最后2个stage的微调策略,配合adamw优化器与强数据增强(含randomperspective和randaugment),可显著提升准确率。

直接用 torchvision.models 加 torch.nn.Linear 替换分类头,再冻结前几层,小样本下准确率通常能比从头训练高 15–30% —— 但前提是数据增强和学习率调得对,否则容易过拟合或收敛失败。
怎么选预训练模型和替换分类层?
别一上来就用 ResNet50;小样本(比如每类 EfficientNet_B0 或 ViT_B_16(后者需 torchvision>=0.13),参数少、收敛快。关键动作是替换最后的全连接层:
model = torchvision.models.efficientnet_b0(pretrained=True) model.classifier[1] = torch.nn.Linear(model.classifier[1].in_features, num_classes)
注意:EfficientNet 的分类头是 Sequential,要改 [1];ResNet 则直接改 model.fc;VisionTransformer 改 model.heads.head。漏掉这步,模型输出维度还是 1000,训练会报 RuntimeError: expected scalar type Float but found Long。
冻结哪几层?冻结后怎么微调?
冻结太狠(只训练最后 1 层),特征迁移不充分;全放开,小样本下极易过拟合。实测有效策略是:
- 先冻结全部 backbone:
for param in model.parameters(): param.requires_grad = False - 只训练新分类层,跑 5–10 轮
- 再解冻最后 2 个 stage(如
model.features[-2:]对应EfficientNet),学习率设为 backbone 的 1/10(例如分类层用1e-3,backbone 用1e-4) - 用
torch.optim.AdamW,别用SGD—— 小样本下 AdamW 的权重衰减更稳
小样本下必须配什么数据增强?
普通 RandomHorizontalFlip + ColorJitter 不够。真实场景中,以下组合缺一不可:
-
transforms.RandomRotation(degrees=15)(防角度偏移) -
transforms.RandomAffine(degrees=0, translate=(0.1, 0.1))(模拟位置扰动) -
transforms.RandomPerspective(distortion_scale=0.2, p=0.3)(应对拍摄畸变) - 必须加
transforms.AutoAugment()或transforms.RandAugment(num_ops=2, magnitude=9)—— 手写规则效果远不如自动策略
漏掉透视变换或 RandAugment,验证集准确率常卡在 60–70%,补上后普遍跳到 82–88%。另外,Resize(224) 前务必用 transforms.Resize(256) 再 CenterCrop(224),否则图像拉伸失真,特征提取失效。
为什么验证损失下降但测试准确率不涨?
这是小样本迁移最典型的陷阱:模型记住了训练集噪声,而非学到了判别特征。排查顺序是:
- 检查是否误把验证集路径当训练集加载(
Dataset初始化时路径写错) - 确认
model.eval()和torch.no_grad()在验证时已启用 —— 漏掉会导致 BatchNorm 统计量污染 - 验证集是否做了和训练集一致的增强?不能只做
Resize + ToTensor,必须复用同一transforms.Compose - 学习率太大(>1e-3)或 batch size 太小(torch.cuda.amp.autocast() 省显存
真正难的是平衡冻结粒度和增强强度 —— 同一组超参在猫狗二分类上有效,在工业零件缺陷识别上可能完全失效,得靠验证集 loss 曲线拐点手动干预,没法全自动。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











