【魔改YOLOv5-6.x(上)】结合轻量化网络Shufflenetv2、Mobilenetv3和Ghostnet
文章目錄
- 前言
- 一、Shufflenetv2
- 論文簡介
- 模型概述
- 加入YOLOv5
- 二、Mobilenetv3
- 論文簡介
- 模型概述
- 深度可分離卷積
- 逆殘差結構
- SE通道注意力
- h-swish激活函數
- 加入YOLOv5
- 三、Ghostnet
- 論文簡介
- 模型概述
- 加入YOLOv5
- References
前言
本文使用的YOLOv5版本為v6.1,對YOLOv5-6.x網絡結構還不熟悉的同學們,可以移步至:【YOLOv5-6.x】網絡模型&源碼解析
另外,本文所使用的實驗環境為1個GTX 1080 GPU,數據集為VOC2007,超參數為hyp.scratch-low.yaml,訓練200個epoch,其他參數均為源碼中默認設置的數值。
YOLOv5中修改網絡結構的一般步驟:
- models/common.py:在common.py文件中,加入要修改的模塊代碼
- models/yolo.py:在yolo.py文件內的parse_model函數里添加新模塊的名稱
- models/new_model.yaml:在models文件夾下新建模塊對應的.yaml文件
?
一、Shufflenetv2
[Cite]Ma, Ningning, et al. “Shufflenet v2: Practical guidelines for efficient cnn architecture design.” Proceedings of the European conference on computer vision (ECCV). 2018.
論文地址
論文代碼
論文簡介
曠視輕量化卷積神經網絡Shufflenetv2,通過大量實驗提出四條輕量化網絡設計準則,對輸入輸出通道、分組卷積組數、網絡碎片化程度、逐元素操作對不同硬件上的速度和內存訪問量MAC(Memory Access Cost)的影響進行了詳細分析:
- 準則一:輸入輸出通道數相同時,內存訪問量MAC最小
- Mobilenetv2就不滿足,采用了擬殘差結構,輸入輸出通道數不相等
- 準則二:分組數過大的分組卷積會增加MAC
- Shufflenetv1就不滿足,采用了分組卷積(GConv)
- 準則三:碎片化操作(多通路,把網絡搞的很寬)對并行加速不友好
- Inception系列的網絡
- 準則四:逐元素操作(Element-wise,例如ReLU、Shortcut-add等)帶來的內存和耗時不可忽略
- Shufflenetv1就不滿足,采用了add操作
針對以上四條準則,作者提出了Shufflenetv2模型,通過Channel Split替代分組卷積,滿足四條設計準則,達到了速度和精度的最優權衡。
?
模型概述
Shufflenetv2有兩個結構:basic unit和unit from spatial down sampling(2×)
- basic unit:輸入輸出通道數不變,大小也不變
- unit from spatial down sample :輸出通道數擴大一倍,大小縮小一倍(降采樣)
Shufflenetv2整體哲學要緊緊向論文中提出的輕量化四大準則靠攏,基本除了準則四之外,都有效的避免了。
為了解決GConv(Group Convolution)導致的不同group之間沒有信息交流,只在同一個group內進行特征提取的問題,Shufflenetv2設計了Channel Shuffle操作進行通道重排,跨group信息交流
class ShuffleBlock(nn.Module):def __init__(self, groups=2):super(ShuffleBlock, self).__init__()self.groups = groupsdef forward(self, x):'''Channel shuffle: [N,C,H,W] -> [N,g,C/g,H,W] -> [N,C/g,g,H,W] -> [N,C,H,W]'''N, C, H, W = x.size()g = self.groupsreturn x.view(N, g, C//g, H, W).permute(0, 2, 1, 3, 4).reshape(N, C, H, W)?
加入YOLOv5
- common.py文件修改:直接在最下面加入如下代碼
-
yolo.py文件修改:在yolo.py的parse_model函數中,加入conv_bn_relu_maxpool, Shuffle_Block兩個模塊(如下圖紅框所示)
-
新建yaml文件:在model文件下新建yolov5-shufflenetv2.yaml文件,復制以下代碼即可
?
二、Mobilenetv3
[Cite]Howard, Andrew, et al. “Searching for mobilenetv3.” Proceedings of the IEEE/CVF International Conference on Computer Vision. 2019.
論文地址
論文代碼
論文簡介
MobileNetV3,是谷歌在2019年3月21日提出的輕量化網絡架構,在前兩個版本的基礎上,加入神經網絡架構搜索(NAS)和h-swish激活函數,并引入SE通道注意力機制,性能和速度都表現優異,受到學術界和工業界的追捧。
主要特點:
?
模型概述
深度可分離卷積
Mobilenetv1提出了深度可分離卷積,就是將普通卷積拆分成為一個深度卷積(Depthwise Convolutional Filters)和一個逐點卷積(Pointwise Convolution):
- Depthwise Convolutional Filters:將卷積核拆分成為單通道形式,在不改變輸入特征圖像深度的情況下,對每一通道進行卷積操作,這樣就得到了和輸入特征圖通道數一致的輸出特征圖,這樣就會有一個問題,通道數太少,特征圖的維度太少,能獲取到足夠的有效信息嗎?
- Pointwise Convolution:逐點卷積就是1×1卷積,主要作用就是對特征圖進行升維和降維,在深度卷積的過程中,假設得到了8×8×3的輸出特征圖,我們用256個1×1×3的卷積核對輸入特征圖進行卷積操作,輸出的特征圖和標準的卷積操作一樣都是8×8×256了
?
逆殘差結構
深度卷積本身沒有改變通道的能力,來的是多少通道輸出就是多少通道,如果來的通道很少的話,DW深度卷積只能在低維度上工作,這樣效果并不會很好,所以我們要“擴張”通道。
既然我們已經知道PW逐點卷積也就是1×1卷積可以用來升維和降維,那就可以在DW深度卷積之前使用PW卷積進行升維(升維倍數為t,t=6),再在一個更高維的空間中進行卷積操作來提取特征,這樣不管輸入通道數是多少,經過第一個PW逐點卷積升維之后,深度卷積都是在相對的更高6倍維度上進行工作。
Inverted residuals:為了像Resnet一樣復用特征,引入了shortcut結構,采用了 1×1 -> 3 ×3 -> 1 × 1 的模式,但是不同點是:
- ResNet 先降維 (0.25倍)、卷積、再升維
- Mobilenetv2 則是 先升維 (6倍)、卷積、再降維
?
SE通道注意力
SE通道注意力出自論文:《Squeeze-and-excitation networks.》,主要是探討了卷積神經網絡中信息特征的構造問題,而作者提出了一種稱為“Squeeze-Excitation(SE)”的組件:
- SE組件的作用是:可以通過顯示地建模通道之間的相互依存關系來增強通道級的特征響應(說白了就是學習一組權重,將這組權重賦予到每一個通道來進一步改善特征表示),使得重要特征得到加強,非重要特征得到弱化
- 具體來說,就是通過學習的方式來自動獲取到每個特征通道的重要程度,然后依照這個重要程度去提升有用的特征并抑制對當前任務用處不大的特征
?
h-swish激活函數
近似操作模擬swish和relu,公式如下:
h _ s w i s h ( x ) = x ? R e L U 6 ( x + 3 ) 6 h\_swish(x)=x*\frac{ReLU6(x+3)}{6} h_swish(x)=x?6ReLU6(x+3)?、 h _ s i g m o i d ( x ) = R e L U 6 ( x + 3 ) 6 h\_sigmoid(x)=\frac{ReLU6(x+3)}{6} h_sigmoid(x)=6ReLU6(x+3)?
class h_sigmoid(nn.Module):def __init__(self, inplace=True):super(h_sigmoid, self).__init__()self.relu = nn.ReLU6(inplace=inplace)def forward(self, x):return self.relu(x + 3) / 6class h_swish(nn.Module):def __init__(self, inplace=True):super(h_swish, self).__init__()self.sigmoid = h_sigmoid(inplace=inplace)def forward(self, x):return x * self.sigmoid(x)?
加入YOLOv5
- common.py文件修改:直接在最下面加入如下代碼
-
yolo.py文件修改:在yolo.py的parse_model函數中,加入h_sigmoid, h_swish, SELayer, conv_bn_hswish, MobileNet_Block五個模塊
-
新建yaml文件:在model文件下新建yolov5-mobilenetv3-small.yaml文件,復制以下代碼即可
?
三、Ghostnet
Han, Kai, et al. “Ghostnet: More features from cheap operations.” Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition. 2020.
論文地址
論文代碼
論文簡介
Ghostnet出自華為諾亞方舟實驗室,作者發現在傳統的深度學習網絡中存在著大量冗余,但是對模型的精度至關重要的特征圖。這些特征圖是由卷積操作得到,又輸入到下一個卷積層進行運算,這個過程包含大量的網絡參數,消耗了大量的計算資源。
作者考慮到這些feature map層中的冗余信息可能是一個成功模型的重要組成部分,正是因為這些冗余信息才能保證輸入數據的全面理解,所以作者在設計輕量化模型的時候并沒有試圖去除這些冗余feature map,而是嘗試使用更低成本的計算量來獲取這些冗余feature map。
?
模型概述
Ghost卷積部分將傳統卷積操作分為兩部分:
- 第一步,使用少量卷積核進行卷積操作(比如正常用64個,這里就用32個,從而減少一半計算量)
- 第二步,使用3×3或5×5的卷積核進行逐通道卷積操作(Cheap operations)
最終將第一部分作為一份恒等映射(Identity),與第二步的結果進行Concat操作
GhostBottleneck部分有兩種結構:
- stride=1,不進行下采樣時,直接進行兩個Ghost卷積操作
- stride=2,進行下采樣時,多出來一個步長為2的深度卷積操作
?
加入YOLOv5
在最新版本的YOLOv5-6.1源碼中,作者已經加入了Ghost模塊,并在models/hub/文件夾下,給出了yolov5s-ghost.yaml文件,因此直接使用即可。
class GhostConv(nn.Module):# Ghost Convolution https://github.com/huawei-noah/ghostnetdef __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groupssuper().__init__()c_ = c2 // 2 # hidden channelsself.cv1 = Conv(c1, c_, k, s, None, g, act) # 先進行一半卷積 減少計算量self.cv2 = Conv(c_, c_, 5, 1, None, c_, act) # 再進行逐特征圖卷積def forward(self, x):y = self.cv1(x)return torch.cat([y, self.cv2(y)], 1) # 最后將兩部分進行concatclass GhostBottleneck(nn.Module):# Ghost Bottleneck https://github.com/huawei-noah/ghostnetdef __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stridesuper().__init__()c_ = c2 // 2self.conv = nn.Sequential(GhostConv(c1, c_, 1, 1), # pw# dw 當stride=2時 才開啟DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(),GhostConv(c_, c2, 1, 1, act=False)) # pw-linearself.shortcut = nn.Sequential(DWConv(c1, c1, k, s, act=False),Conv(c1, c2, 1, 1, act=False)) if s == 2 else nn.Identity()def forward(self, x):return self.conv(x) + self.shortcut(x) # Add(Element-Wise操作)class C3Ghost(C3):# C3 module with GhostBottleneck()def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):super().__init__(c1, c2, n, shortcut, g, e) # 引入C3(父類)的屬性c_ = int(c2 * e) # hidden channelsself.m = nn.Sequential(*(GhostBottleneck(c_, c_) for _ in range(n)))?
References
【精讀AI論文】曠視輕量化網絡ShuffleNet V2-算法精講
輕量級神經網絡“巡禮”(一)—— ShuffleNetV2
輕量級神經網絡“巡禮”(二)—— MobileNet,從V1到V3
Yolov5更換backbone,與模型壓縮(剪枝,量化,蒸餾)
目標檢測 YOLOv5 自定義網絡結構
總結
以上是生活随笔為你收集整理的【魔改YOLOv5-6.x(上)】结合轻量化网络Shufflenetv2、Mobilenetv3和Ghostnet的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 文件格式转换软件有哪些?值得推荐的几款软
- 下一篇: 打造轻量级自动化测试框架WebZ