CNN图像分类的小技巧(1): mixup数据增强

1. mixup

论文连接
mixup是一种data augmentation方法,可以用来提升模型的泛化能力和对对抗样本(adversarial examples,指的是训练样本分布外的样本)的鲁棒性。mixup带来的好处还有:

  1. 降低模型对噪声样本的记忆以降低噪声样本多模型的影响。
  2. 对GANs网络训练的稳定性有所帮助

2. mixup被提出的动机

大多数深度神经网络模型的训练旨在最小化模型在训练集上的平均误差是遵循经验风险最小化(Empirical Risk Minimizatiom)原则的。经验风险最小化表达的意思是: 因为我们不可能知道真实的数据分布情况(我的理解:现实情况数据量太大,可能性太多),所以我们无法通过最小化模型的真实风险(最小化模型在真实数据集上的平均误差或者说损失函数)来训练模型,所以我们只能最小化模型在选定训练集上的经验风险(最小化模型在训练集上的平均误差或者说损失函数)。 这就导致了基于ERM(Empirical Rish Minimization)训练的模型展现出一些意想不到的行为:

  1. 对训练样本的记忆:样本中存在的噪声样本会影响模型的性能
  2. 对训练样本分布外的样本的敏感性:在面对对抗样本(adversarial examples)时性能很差

所以当测试数据集的分布稍微不同于训练数据集时模型不能提供很好的泛化能力,对训练数据过拟合。Mixup的提出就是想要减轻这些现象, 但是在讲到mixup之前我们要看一下另外一个概念:领域风险最小化(Vicinal Risk minimization).

VRM(Vicinal Risk Minimization)原则跟ERM原则在思想上类似,核心不同点在于训练样本的构建。在ERM每一个原训练样本基础上,VRM需要人根据先验知识为每一个原样本描述一个领域,领域是由相似但又不同于原训练样本的样本组成的集合, 最后额外的样本从每一个原样本的领域中抽取出来来扩充整个训练样本集,这就是我们所说的data augumentation。在图像分类中领域的构建可以通过翻转, 旋转,缩放原样本。经过扩充的训练集可以提高模型的泛化能力, 但是如何通过data augmentation扩充数据集,和使用什么样的data augmentation方法是原训练集相关的和需要先验知识的。而且我们以上所提到的data augmentation方法所产生的新的样本都跟原样本属于同一个类别,并没有建模不同类别样本间的临近关系。 所以mixup作为一种简单的和数据集不相关的data augmentation方法在这种情况下被提出了。 Mixup足够简单,通过对相本和标签进行线性插值就可以得到新的训练样本,简单的几行代码不会对模型的训练带来太多额外的负担,但是可以很好的提高模型的泛化能力。

3. mixup的实现

基于mixup的虚拟样本的构建很简单:

Screen Shot 2021-01-17 at 11.53.35 PM.png

其中 λ ∈ [0,1]。其中λ ~Beta(a,a), a 属于(0, ∞)。在这里我们需要注意的是用mixup是不仅要线性插值样本X,也需要线性插值标签Y。一个简单Pytorch代码例子来自官方源码:

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=args.lr, momentum=0.9,
                      weight_decay=args.decay)

def mixup_data(x, y, alpha=1.0, use_cuda=True):
    '''Returns mixed inputs, pairs of targets, and lambda'''
    if alpha > 0:
        lam = np.random.beta(alpha, alpha)
    else:
        lam = 1

    batch_size = x.size()[0]
    if use_cuda:
        index = torch.randperm(batch_size).cuda()
    else:
        index = torch.randperm(batch_size)

    mixed_x = lam * x + (1 - lam) * x[index, :]
    y_a, y_b = y, y[index]
    return mixed_x, y_a, y_b, lam


def mixup_criterion(criterion, pred, y_a, y_b, lam):
    return lam * criterion(pred, y_a) + (1 - lam) * criterion(pred, y_b)


def train(epoch):
    print('\nEpoch: %d' % epoch)
    net.train()
    train_loss = 0
    reg_loss = 0
    correct = 0
    total = 0
    for batch_idx, (inputs, targets) in enumerate(trainloader):
        if use_cuda:
            inputs, targets = inputs.cuda(), targets.cuda()

        inputs, targets_a, targets_b, lam = mixup_data(inputs, targets,
                                                       args.alpha, use_cuda)
        inputs, targets_a, targets_b = map(Variable, (inputs,
                                                      targets_a, targets_b))
        outputs = net(inputs)
        loss = mixup_criterion(criterion, outputs, targets_a, targets_b, lam)
        train_loss += loss.data[0]
        _, predicted = torch.max(outputs.data, 1)
        total += targets.size(0)
        correct += (lam * predicted.eq(targets_a.data).cpu().sum().float()
                    + (1 - lam) * predicted.eq(targets_b.data).cpu().sum().float())

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

4. mixup为什么有效

基于作者的表述,我自己的理解是: mixup会鼓励模型对训练样本有一个线性的理解,意味着对一个样本的判断不会那么绝对,这样可以减小过拟合。最后模型所形成的决策边界会很平滑使得模型在面对不确定的东西时不是非黑即白。 因为要构建模型对样本线性的理解,这使得噪声样本相比于真实样本来说对模型的影响很有限。因为噪声样本不能帮助模型对样本产生线性的理解,同时模型更容易在真实样本中学到这种线性的理解。对样本线性的理解会扩展模型的认知范围,因为模型需要去理解样本线性所带来的细微的差别,大的认知范围使得模型有潜力对训练集样本分布范围外的样本做出判断,进一步提升模型的泛化能力。

5. 注意事项

  1. 三个或以上的样本进行mixup并不会带来更多的收益。
  2. 模型容量越大或者训练时间越长mixup带来的收益越多。

你可能感兴趣的:(CNN图像分类的小技巧(1): mixup数据增强)