比赛简介
共10类食物,数据集共5000个图片,尺寸大小不一,类别分别均衡。需要自己划分训练集和验证集,用于判分的测试集不可见。
比赛难度不大,主要难点在于如何减小过拟合,提高模型的泛化能力。代码已在我的github上开源,欢迎star。
涨点核心思想:
- cbam注意力
- auto_augment
- cutmix
- snapshot
- LabelSmooth
数据探索
由于数据集比较小,也比较简单,因此主要是统计了一下所有图像的尺寸分布,发现大多数图像的宽高在400~500,因此可以选择将图像输入尺寸调整到这个区间。
大尺寸的另一个好处是可以显著提高分类准确率。
训练策略
数据集划分
采用9:1的比例将数据集划分为训练集和验证集,时间和资源允许的情况下,可以进行10折交叉验证。
数据增强
数据集比较小,因此数据增强是提分的重点方向。除了torch自带的随机裁切和随机擦除以外,涨分的一大技巧是采用auto_augment。数据增强的代码如下:
train_transform = transforms.Compose([
transforms.Resize((size+32, size+32)),
transforms.RandomChoice([transforms.RandomCrop(size, padding=1, pad_if_needed=True, padding_mode='edge'),
transforms.RandomResizedCrop(size, scale=(resize_scale, 1.0), ratio=(0.8, 1.2))]),
transforms.RandomHorizontalFlip(),
auto_augment.AutoAugment(dataset='CIFAR'),
transforms.ToTensor(),
transforms.RandomErasing(p=erasing_prob),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
模型选择
采用efficientnet-b5,同时增加了cbam注意力模块,代码如下:
class ChannelAttention(nn.Module):
def __init__(self, in_planes, ratio=16):
super(ChannelAttention, self).__init__()
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.max_pool = nn.AdaptiveMaxPool2d(1)
self.fc1 = nn.Conv2d(in_planes, in_planes // 16, 1, bias=False)
self.relu1 = nn.ReLU()
self.fc2 = nn.Conv2d(in_planes // 16, in_planes, 1, bias=False)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
avg_out = self.fc2(self.relu1(self.fc1(self.avg_pool(x))))
max_out = self.fc2(self.relu1(self.fc1(self.max_pool(x))))
out = avg_out + max_out
return self.sigmoid(out)
class SpatialAttention(nn.Module):
def __init__(self, kernel_size=7):
super(SpatialAttention, self).__init__()
assert kernel_size in (3, 7), 'kernel size must be 3 or 7'
padding = 3 if kernel_size == 7 else 1
self.conv1 = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
avg_out = torch.mean(x, dim=1, keepdim=True)
max_out, _ = torch.max(x, dim=1, keepdim=True)
x = torch.cat([avg_out, max_out], dim=1)
x = self.conv1(x)
return self.sigmoid(x)
优化器和学习率衰减
优化器采用RAdam,学习率衰减策略采用torch1.4自带的学习率自动重启的余弦衰减。
optimizer = newoptim.RAdam(model.parameters(), lr=lr, weight_decay=weight_decay)
scheduler = optim.lr_scheduler.CosineAnnealingWarmRestarts(optimizer, T_0=epochs//snap_num)
训练方法
采用三阶段训练法,每一阶段基于快照集成思想获得5个模型快照,选择acc最高的模型作为当前阶段的训练结果。具体流程如下:
- Stage 1:图像输入尺寸为400,使用LabelSmooth和cutmix,采用带学习率自动重启的CosineAnnealingWarmRestarts方法,获得5个模型快照,选择val_acc最高的模型,作为Stage 1的训练结果。
- Stage 2:图像输入尺寸为500,适当调整随机裁切和随机擦除的参数,增加weight_decay,在Stage 1模型的基础上训练获得5个模型快照,选择val_acc最高的模型,作为Stage 2的训练结果。
- Stage 3:图像输入尺寸为500,关闭cutmix,损失函数采用CrossEntropyLoss,在Stage 2模型的基础上训练获得5个模型快照,选择val_acc最高的模型,作为最终的训练结果。
模型性能
单模型,验证集上acc为99.4%,提交到modelarts上,测试集的acc为99.2%。
由于是采用的单模型,因此如果加入模型融合的trick,应该还能够更进一步提高acc。