CutMix數據增強學習

一、前言

    之前有一篇博客學習了mixup數據增強,對於提升模型的性能非常顯著。長江後浪推前浪,這一篇CutMix數據增強居然將其推在沙灘上。簡單回顧下mixup數據增強:從訓練樣本中隨機抽取兩個樣本進行簡單的隨機加權求和,同時樣本的標籤也對應加權求和,然後預測結果與加權求和之後的標籤求損失,在反向求導更新參數。

    CutMix的處理方式也比較簡單,同樣也是對一對圖片做操作,簡單講就是隨機生成一個裁剪框Box,裁剪掉A圖的相應位置,然後用B圖片相應位置的ROI放到A圖中被裁剪的區域形成新的樣本,計算損失時同樣採用加權求和的方式進行求解,最後作者對比了mixup、cutout和baseline,數據上看似乎也是小小地吊打的節奏。

  • Mixup:將隨機的兩張樣本按比例混合,分類的結果按比例分配;
  • Cutout:隨機的將樣本中的部分區域cut掉,並且填充0像素值,分類的結果不變;
  • CutMix:就是將一部分區域cut掉但不填充0像素而是隨機填充訓練集中的其他數據的區域像素值,分類結果按一定的比例分配

   爲什麼會這樣呢,論文的意思我姑且這樣描述,mixup是直接求和兩張圖,如同附身,鬼影一樣,模型很難學到準確的特徵圖響應分佈。而cutmix相當於換某個零件,模型更容易區分異類。

二、算法細節

   算法的核心過程在論文中這樣描述:

    M是一個與圖像尺寸一致的由0和1標記的掩碼矩陣,實際就是標記需要裁剪的區域和保留的區域,裁剪的區域值均爲0,其餘位置爲1,圖像A和B組合得到新樣本,最後兩個圖的標籤也對應求加權和(其實這個公式想要表達的是再求接損失時,二者的loss求加權和,這樣說更準確)。那麼問題來了這個裁剪區域的box是如何得到,加權的係數如何確定?

   權值同mixup一樣是採用bata分佈隨機得到,alpha的值爲論文中取值爲1,這樣加權係數[0-1]就服從beta分佈,實際上從論文的代碼實現上看,beta分佈真正的用途是爲了生成裁剪區域。論文這樣描述:

裁剪框box的左上角座標採集服從寬高(W和H)的均勻分佈,及隨其採點,box的寬高計算則需要用到beta分佈產生的加權係數納悶噠(😊懶得打公式了),這樣裁剪區box的面積與圖像面積之比爲1-納悶噠。這樣損失的加權和(公式(1))說採用的納悶噠就與面積比相對應。這裏我對代碼進行了簡答整理,以便更好地嵌入自己的框架:

代碼地址:https://github.com/clovaai/CutMix-PyTorch

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
 
def cutmix_data(x, y, alpha=1., use_cuda=True):
 
    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)
 
 
 
    size=x.size()
 
    bbx1, bby1, bbx2, bby2=rand_bbox(size,lam)
 
    x[:, :, bbx1:bbx2, bby1:bby2] = x[index, :, bbx1:bbx2, bby1:bby2]
 
    # adjust lambda to exactly match pixel ratio
 
    lam = 1 - ((bbx2 - bbx1) * (bby2 - bby1) / (x.size()[-1] *x.size()[-2]))
 
    y_a, y_b = y, y[index]
 
    return x, y_a, y_b, lam

嚴格的講,生成的box可能超出圖像邊界而被裁減,所以再代碼中最終的加權係數重新計算了一下:

lam = 1 - ((bbx2 - bbx1) * (bby2 - bby1) / (x.size()[-1] *x.size()[-2]))

訓練過程完整的使用代碼如下:

if mixType=='mixup':
 
    inputs, targets_a, targets_b, lam = mixup_data(inputs, targets, args.alpha, use_cuda)
 
elif mixType=='cutmix':
 
    inputs, targets_a, targets_b, lam = cutmix_data(inputs, targets, args.alpha, use_cuda)
 
 
 
optimizer.zero_grad()
 
inputs, targets_a, targets_b = Variable(inputs), Variable(targets_a), Variable(targets_b)
 
outputs = net(inputs)
loss = criterion(outputs, target_a) * lam + criterion(outputs, target_b) * (1. -lam)

我在最近工作中的私有數據集中進行了試驗,同樣的數據,其他參數一致,僅僅更換mixup爲cutmix,模型性能確有提升。對於困難樣本的效果有很好的提升。同時心中有一個疑問,如果在mini-batch中隨機採樣中,樣本對組合新數據時,圖像A和B在裁剪區域均爲背景區域,且背景區域幾乎相似,而非目標所在區域,這樣訓練強制模型擬合,是否合理,還是會引入噪聲樣?? 求大佬們解答一二。 

參考論文:

CutMix: Regularization Strategy to Train Strong Classifiers with Localizable Features

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章