Idea


두 개의 이미지를 박스 형태로 자르고(Cut) 합쳐서(Mix) 새로운 이미지를 만드는데, 이 때, ground truth label 역시 같은 비율로 합쳐서 새로운 (Image, Label) 훈련데이터를 생성한다.

Code


두 (image, label) pair를 섞는 비율 $λ$은 대칭적인 $β$-분포로부터 샘플링한다.

https://github.com/clovaai/CutMix-PyTorch/blob/master/train.py#L220

for i, (input, target) inenumerate(train_loader):
# measure data loading time
        data_time.update(time.time() - end)

input =input.cuda()
        target = target.cuda()

        r = np.random.rand(1)
        if args.beta > 0 and r < args.cutmix_prob:
# generate mixed sample
            lam = np.random.beta(args.beta, args.beta)
            rand_index = torch.randperm(input.size()[0]).cuda()
            target_a = target
            target_b = target[rand_index]
            bbx1, bby1, bbx2, bby2 = rand_bbox(input.size(), lam)
input[:, :, bbx1:bbx2, bby1:bby2] =input[rand_index, :, bbx1:bbx2, bby1:bby2]
# adjust lambda to exactly match pixel ratio
            lam = 1 - ((bbx2 - bbx1) * (bby2 - bby1) / (input.size()[-1] *input.size()[-2]))
# compute output
            output = model(input)
            loss = criterion(output, target_a) * lam + criterion(output, target_b) * (1. - lam)
        else:
# compute output
            output = model(input)
            loss = criterion(output, target)

https://github.com/clovaai/CutMix-PyTorch/blob/master/train.py#L279

def rand_bbox(size, lam):
    W = size[2]
    H = size[3]
    cut_rat = np.sqrt(1. - lam)
    cut_w = np.int(W * cut_rat)
    cut_h = np.int(H * cut_rat)

# uniform
    cx = np.random.randint(W)
    cy = np.random.randint(H)

    bbx1 = np.clip(cx - cut_w // 2, 0, W)
    bby1 = np.clip(cy - cut_h // 2, 0, H)
    bbx2 = np.clip(cx + cut_w // 2, 0, W)
    bby2 = np.clip(cy + cut_h // 2, 0, H)

    return bbx1, bby1, bbx2, bby2

Experiments


논문에서 CIFAR-100에 대해서 PyramidNet에 대해 실험하였으며, 정확한 설정은 https://github.com/clovaai/CutMix-PyTorch#train-examples 에서 확인 가능하다. 기존 Baseline model에 CutMix를 적용할 경우, Top-1 error가 16.45%에서 14.23%로 약 2%의 성능향상을 보인다.