YOLOV4知识点分析(二)
YOLOV4知識點分析(二)
- 數據增強相關-mixup
論文名稱:mixup: BEYOND EMPIRICAL
RISK MINIMIZATION
論文地址:https://arxiv.org/abs/1710.09412
mixup由于非常有名,大家都應該知道,而且網上各種解答非常多,故這里就不重點說了。其核心操作是:兩張圖片采用比例混合,label也需要混合。
論文中提到的一些關鍵的Insight:
1 也考慮過三個或者三個以上的標簽做混合,但是效果幾乎和兩個一樣,而且增加了mixup過程的時間。2 當前的mixup使用了一個單一的loader獲取minibatch,對其隨機打亂后,mixup對同一個minibatch內的數據做混合。這樣的策略和在整個數據集隨機打亂效果是一樣的,而且還減少了IO的開銷。3 在同種標簽的數據中使用mixup不會造成結果的顯著增強
- 數據增強相關-cutmix和Mosaic
論文名稱:CutMix: Regularization
Strategy to Train Strong Classifiers with Localizable Features
論文地址:https://arxiv.org/abs/1905.04899
開源地址:https://github.com/clovaai/CutMix-PyTorch
mixup相當于是全圖融合,cutout僅僅對圖片進行增強,不改變label,而cutmix則是采用了cutout的局部融合思想,并且采用了mixup的混合label策略,看起來比較make sense。
cutmix和mixup的區別是,其混合位置是采用hard 0-1掩碼,而不是soft操作,相當于新合成的兩張圖是來自兩張圖片的hard結合,而不是Mixup的線性組合。但是其label還是和mixup一樣是線性組合。作者認為mixup的缺點是:Mixup samples suffer from the fact that they are locally ambiguous
and unnatural, and therefore confuses the model, especially for localization。
M是和原圖大小一樣的矩陣,只有0-1值,用于控制線性混合度,通過參數可以控制裁剪矩形大小,
偽代碼如下
而Mosaic增強是本文提出的,屬于cutmix的擴展,cutmix是兩張圖混合,而馬賽克增強是4張圖混合,好處非常明顯是一張圖相當于4張圖,等價于batch增加了,可以顯著減少訓練需要的batch size大小。
- 數據增強相關-Stylized-ImageNet
論文名稱:ImageNet-trained cnns
are biased towards texture; increasing shape bias improves accuracy and
robustness
本文非常有意思,得到的結論非常有意義,可以指導我們對于某些場景測試失敗的分析。本質上本文屬于數據增強論文,做的唯一一件事就是:對ImageNet數據集進行風格化。本文結論是:CNN訓練學習到的實際是紋理特征(texture bias)而不是形狀特征,這和人類的認知方式有所區別,如論文題目所言,存在紋理偏置。而本文引入風格化imagenet數據集,平衡紋理和形狀偏置,提高泛化能力。本文指出在ImageNet上訓練的CNN強烈的偏向于識別紋理而不是形狀,這和人的行為是極為不同的,存在紋理偏差,所以提出了Stylized-ImageNet數據,混合原始數據訓練就可以實現既關注紋理,也關注形狀(也就是論文標題提到的減少紋理偏向,增加形狀偏向)。從而不僅更適合人類的行為,更驚訝的是提升了目標檢測的精度,以及魯棒性,更加體現了基于形狀表示的優勢。文章從一只披著象皮的貓究竟會被識別為大象還是貓這個問題入手,揭示了神經網絡根據物體的texture進行識別而非我們以為的根據物體的形狀。作者準備了6份數據,分別是正常的圖片,灰色圖,只包含輪廓的,只包含邊緣的,只有紋理沒有形狀,紋理和形狀相互矛盾(大象的紋理,貓的形狀),對于第六份數據(紋理和形狀沖突的數據),作者采用Stylized-ImageNet隨機地將物體的紋理替換掉(也就是本文創新點),如下(c)所示:
采用了4個主流網絡,加上人類直觀評估。原圖其實是作者除了物體外,其余都是白色背景的數據集,目的是去除干擾。
對于前面5份數據,采用原圖和灰度圖,神經網絡都可以取得非常高的準確率,而對于只包含輪廓和只包含邊緣的圖片,神經網絡的預測準確率則顯著降低。更有意思的是,對于只包含紋理的圖片,神經網絡取得特別高的準確率。因而不難推斷出,神經網絡在識別中,主要是參考紋理信息而不是形狀信息。作者先構造數據集,然后再進行后面的深入實驗,IN就是指的ImageNet,SIN是指的風格化的ImageNet,如下所示
SIN的特點是保留shape,但是故意混淆掉紋理信息。
從上表的第一行可以看出,在原始圖片IN上訓練的模型不能適應去除紋理SIN的圖片(IN-SIN),而使用去除紋理的圖片進行訓練和測試效果會差于使用原始圖片進行訓練和測試(SIN-SIN),這說明紋理信息在圖像識別中確實起到了一定的作用,去除了紋理信息會提高模型識別的難度。最后,當我們使用去除紋理的圖片進行訓練而在原圖進行測試的時候(SIN-IN),效果比在去除紋理的圖片上面效果好(SIN-SIN)。
后面三行的實驗采用的是第一行resnet的網絡結構,其主要特征是限制模型的感受野,從而讓模型無法學習到空間的信息,其對應的感受野分別是33*33,17*17,9*9,對于訓練原始的圖片,其結果測試誤差跟沒有加上感受野限制的誤差差別不大,從而說明紋理信息起到主導作用(IN-IN),而對應去除掉紋理信息的圖片,其測試結果下降十分明顯(SIN-SIN),說明形狀信息起到主要的作用,證明了SIN的模型確實在學習形狀的信息而不是紋理的信息。這個實驗是要說明提出的SIN數據集由于強制抹掉了固定紋理,網絡訓練難度增大,在沒有限制感受野情況下可以學的蠻好,但是一旦限制了感受野就不行了,說明SIN模型學習到的不僅僅是紋理(因為紋理是局部的,如果依靠紋理來分類,那么準確率應該下降不了這么多),更多的是依靠shape分類,因為感受野外限制了,導致無法看到整個shape,并且通過更加限制感受野,SIN-SIN準確率下降更多可以發現。也就是說SIN數據集由于替換掉了紋理,迫使網絡學習shape和紋理,達到了本文目的。SIN上訓練的ResNet50展示出更強的形狀偏向,符合人類常理。增強形狀偏向也改變了表示,那么影響了CNN的性能和魯棒性了嗎?我們設置了兩個訓練方案:1 同時在SIN和IN上訓練2 同時在SIN和IN上訓練,在IN上微調。稱為Shape-ResNet。
作者把去掉紋理的數據和原圖一起放進去模型中進行訓練,最后用原圖進行finetune,發現這種方法可以提高模型的性能。Shape-ResNet超過了原始ResNet的準確率,說明SIN是有用的圖像增強。
總結:CNN識別強烈依賴于紋理,而不是全局的形狀,但是這是不好的,為了突出形狀bias,可以采用本文的SIN做法進行數據增強,SIN混合原始數據訓練就可以實現既關注紋理,也關注形狀,不僅符合人類直觀,也可以提高各種任務的準確率和魯邦性。所以本文其實是提出了一種新的數據增強策略。是不是很有意思的結論?
- 數據增強相關-label
smooth
論文題目:Rethinking the
inception architecture for computer vision
label smooth是一個非常有名的正則化手段,防止過擬合,基本上沒有人不知道,故不詳說了,核心就是對label進行soft操作,不要給0或者1的標簽,而是有一個偏移,相當于在原label上增加噪聲,讓模型的預測值不要過度集中于概率較高的類別,把一些概率放在概率較低的類別。
- 特征增強相關-DropBlock
論文題目:DropBlock: A
regularization method for convolutional networks
論文地址:https://arxiv.org/abs/1810.12890
開源代碼:https://github.com/miguelvr/dropblock
由于dropBlock其實是dropout在卷積層上的推廣,故很有必須先說明下dropout操作。dropout,訓練階段在每個mini-batch中,依概率P隨機屏蔽掉一部分神經元,只訓練保留下來的神經元對應的參數,屏蔽掉的神經元梯度為0,參數不參數與更新。而測試階段則又讓所有神經元都參與計算。dropout操作流程:參數是丟棄率p1)在訓練階段,每個mini-batch中,按照伯努利概率分布(采樣得到0或者1的向量,0表示丟棄)隨機的丟棄一部分神經元(即神經元置零)。用一個mask向量與該層神經元對應元素相乘,mask向量維度與輸入神經一致,元素為0或1。2)然后對神經元rescale操作,即每個神經元除以保留概率1-P,也即乘上1/(1-P)。3)反向傳播只對保留下來的神經元對應參數進行更新。4)測試階段,Dropout層不對神經元進行丟棄,保留所有神經元直接進行前向過程。
為啥要rescale呢?是為了保證訓練和測試分布盡量一致,或者輸出能量一致。可以試想,如果訓練階段隨機丟棄,那么其實dropout輸出的向量,有部分被屏蔽掉了,可以認為輸出變了,如果dropout大量應用,那么其實可以等價為進行模擬遮擋的數據增強,如果增強過度,導致訓練分布都改變了,那么測試時候肯定不好,引入rescale可以有效的緩解,保證訓練和測試時候,經過dropout后數據分布能量相似。
上面的截圖來自:https://www.pianshen.com/article/2769164511/
dropout方法多是作用在全連接層上,在卷積層應用dropout方法意義不大。文章認為是因為每個feature map的位置都有一個感受野范圍,僅僅對單個像素位置進行dropout并不能降低feature map學習的特征范圍,也就是說網絡仍可以通過該位置的相鄰位置元素去學習對應的語義信息,也就不會促使網絡去學習更加魯邦的特征。既然單獨的對每個位置進行dropout并不能提高網絡的泛化能力,那么很自然的,如果我們按照一塊一塊的去dropout,就自然可以促使網絡去學習更加魯邦的特征。思路很簡單,就是在feature
map上去一塊一塊的找,進行歸零操作,類似于dropout,叫做dropblock。
綠色陰影區域是語義特征,b圖是模擬dropout的做法,隨機丟棄一些位置的特征,但是作者指出這做法沒啥用,因為網絡還是可以推斷出來,?是本文做法。
dropblock有三個比較重要的參數,一個是block_size,用來控制進行歸零的block大小;一個是γ,用來控制每個卷積結果中,到底有多少個channel要進行dropblock;最后一個是keep_prob,作用和dropout里的參數一樣。
M大小和輸出特征圖大小一致,非0即1,為了保證訓練和測試能量一致,需要和dropout一樣,進行rescale。
上述是理論分析,在做實驗時候發現,block_size控制為7*7效果最好,對于所有的feature map都一樣,γ通過一個公式來控制,keep_prob則是一個線性衰減過程,從最初的1到設定的閾值(具體實現是dropout率從0增加到指定值為止),論文通過實驗表明這種方法效果最好。如果固定prob效果好像不好。實踐中,并沒有顯式的設置的值,而是根據keep_prob(具體實現是反的,是丟棄概率)來調整。DropBlock in ResNet-50
DropBlock加在哪?最佳的DropBlock配置是block_size=7,在group3和group4上都用。將DropBlock用在skip connection比直接用在卷積層后要好,具體咋用,可以看代碼。
class DropBlock2D(nn.Module):
r"""Randomly
zeroes 2D spatial blocks of the input tensor.
As described in the paper `DropBlock: A regularization method for
convolutional networks`_ , dropping whole blocks of feature map allows to
remove semantic information as
compared to regular dropout.
Args:
drop_prob (float): probability of an element to be dropped. block_size (int): size of the block to
drop
Shape:
-
Input:
(N, C, H, W)- Output:(N, C, H, W)… _DropBlock: A regularization method for
convolutional networks:
https://arxiv.org/abs/1810.12890“”"
def init(self, drop_prob, block_size):
super(DropBlock2D, self).init()self.drop_prob = drop_prob self.block_size = block_sizedef forward(self, x): # shape: (bsize, channels, height, width)
assert x.dim() == 4, \
“Expected input
with 4 dimensions (bsize, channels, height, width)”
if not self.training or self.drop_prob == 0.: return x else: # get gamma value
gamma = self._compute_gamma(x)
# sample mask mask = (torch.rand(x.shape[0], *x.shape[2:]) < gamma).float()# place mask on input device
mask = mask.to(x.device)
# compute block mask
block_mask = self._compute_block_mask(mask)
# apply block mask
out = x * block_mask[:, None, :, :]
# scale output
out = out * block_mask.numel() / block_mask.sum()
return outdef _compute_block_mask(self, mask):
比較巧妙的實現,用max pool來實現基于一點來得到全0區域 block_mask
= F.max_pool2d(input=mask[:, None, :, :],
kernel_size=(self.block_size, self.block_size), stride=(1, 1),
padding=self.block_size // 2)
if self.block_size % 2 == 0: block_mask =
block_mask[:, :, :-1, :-1]
block_mask = 1 - block_mask.squeeze(1)return block_maskdef _compute_gamma(self, x):
return self.drop_prob / (self.block_size ** 2)
聯合線性調度一起使用,如下所示:
總結
以上是生活随笔為你收集整理的YOLOV4知识点分析(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: YOLOV4知识点分析(一)
- 下一篇: 智能交通监控