沈陽網(wǎng)站建設(shè)團(tuán)隊(duì)杭州seo網(wǎng)絡(luò)推廣
前言:Hello大家好,我是小哥談。GhostNet是一種針對(duì)計(jì)算機(jī)視覺任務(wù)的深度神經(jīng)網(wǎng)絡(luò)架構(gòu),它于2020年由中國科學(xué)院大學(xué)的研究人員提出。GhostNet的設(shè)計(jì)目標(biāo)是在保持高精度的同時(shí),減少模型的計(jì)算和存儲(chǔ)成本。GhostNet通過引入Ghost模塊來實(shí)現(xiàn)高效的網(wǎng)絡(luò)設(shè)計(jì),Ghost模塊是一種新穎的特征重用機(jī)制,它可以在網(wǎng)絡(luò)中引入更多的輕量級(jí)子網(wǎng)絡(luò),這些子網(wǎng)絡(luò)與主干網(wǎng)絡(luò)以并行的方式連接,通過共享卷積核來提高計(jì)算效率。GhostNet在ImageNet圖像分類任務(wù)上取得了較好的性能,并且在計(jì)算和存儲(chǔ)方面比一些流行的網(wǎng)絡(luò)模型如MobileNetV3和EfficientNet要更高效。因此,GhostNet被認(rèn)為是一種具有潛力的輕量級(jí)神經(jīng)網(wǎng)絡(luò)架構(gòu),在計(jì)算資源有限的設(shè)備上具有廣泛的應(yīng)用前景。🌈?
?前期回顧:
? ? ? ? ? ?YOLOv5算法改進(jìn)(1)— 如何去改進(jìn)YOLOv5算法
? ? ? ? ???YOLOv5算法改進(jìn)(2)— 添加SE注意力機(jī)制
? ? ? ? ? ?YOLOv5算法改進(jìn)(3)— 添加CBAM注意力機(jī)制
? ? ? ? ? ?YOLOv5算法改進(jìn)(4)— 添加CA注意力機(jī)制
? ? ? ? ? ?YOLOv5算法改進(jìn)(5)— 添加ECA注意力機(jī)制
? ? ? ? ? ?YOLOv5算法改進(jìn)(6)— 添加SOCA注意力機(jī)制
? ? ? ? ? ?YOLOv5算法改進(jìn)(7)— 添加SimAM注意力機(jī)制
? ? ? ? ? ?YOLOv5算法改進(jìn)(8)— 替換主干網(wǎng)絡(luò)之MobileNetV3
? ? ? ? ? ?YOLOv5算法改進(jìn)(9)— 替換主干網(wǎng)絡(luò)之ShuffleNetV2
? ? ? ? ? ? 目錄
🚀1.論文
🚀2.GhostNet網(wǎng)絡(luò)架構(gòu)及原理
💥💥2.1?Ghost?Module
💥💥2.2?Ghost Bottlenecks
💥???????💥2.3?Ghostnet的構(gòu)建
🚀3.YOLOv5結(jié)合Ghostnet
💥💥步驟1:在common.py中添加Ghostnet模塊
💥💥步驟2:在yolo.py文件中加入類名?
💥💥步驟3:創(chuàng)建自定義yaml文件?
💥💥步驟4:驗(yàn)證是否加入成功
💥💥步驟5:修改train.py中的'--cfg'默認(rèn)參數(shù)
🚀1.論文
GhostNet是2019年由華為諾亞方舟實(shí)驗(yàn)室發(fā)布的輕量級(jí)網(wǎng)絡(luò),速度和MobileNetV3相似,但是識(shí)別的準(zhǔn)確率比MobileNetV3高,在ImageNet ILSVRC-2012分類數(shù)據(jù)集的達(dá)到了75.7%的top-1精度。該論文提除了Ghost模塊,通過廉價(jià)操作生成更多的特征圖?;谝唤M原始的特征圖,作者應(yīng)用一系列線性變換,以很小的代價(jià)生成許多能從原始特征發(fā)掘所需信息的“Ghost”特征圖(Ghost feature maps)。Ghost模塊是一種即插即用的模塊,通過堆疊Ghost模塊得出Ghost bottleneck,進(jìn)而搭建輕量級(jí)神經(jīng)網(wǎng)絡(luò)——GhostNet。🍃
論文題目:《GhostNet: More Features from Cheap Operations》
論文地址:??https://arxiv.org/abs/1911.11907
代碼實(shí)現(xiàn):??https://github.com/huawei-noah/Efficient-AI-Backbones/releases/tag/GhostNetV2
🚀2.GhostNet網(wǎng)絡(luò)架構(gòu)及原理
💥???????💥???????2.1?Ghost?Module
通過上述的介紹,我們了解到了,GhostNet的核心思想就是使用一些計(jì)算量更低(Cheap Operations)的操作去生成這些冗余的特征圖。在論文中,作者設(shè)計(jì)了一個(gè)名為Ghost Module的模塊,他的功能是代替普通卷積。📚
Ghost Module將普通卷積分為兩部分:
首先,進(jìn)行一個(gè)普通的1x1卷積,這是一個(gè)少量卷積,比如正常使用32通道的卷積,這里就用16通道的卷積,這個(gè)1x1卷積的作用類似于特征整合,生成輸入特征層的特征濃縮。
然后,我們?cè)龠M(jìn)行深度可分離卷積,這個(gè)深度可分離卷積是逐層卷積,它也就是論文上面提到的Cheap Operations。它利用上一步獲得的特征濃縮生成Ghost特征圖。
因此,如果我們從整體上去看這個(gè)Ghost Module,它其實(shí)就是兩步簡單思想的匯總:
💞(1)利用1x1卷積獲得輸入特征的必要特征濃縮。
💞(2)利用深度可分離卷積獲得特征濃縮的相似特征圖(Ghost)。
Ghost-Module分成三個(gè)步驟:
🍀(1)先通過普通的conv生成一些特征圖。
🍀(2)對(duì)生成的特征圖進(jìn)行cheap操作生成冗余特征圖,這步使用的卷積是DW 卷積。
🍀(3)將conv生成的特征圖與cheap操作生成的特征圖進(jìn)行concat操作。
如下圖(b)所示,展示了Ghost模塊和普通卷積的過程。👇
💥???????💥2.2?Ghost Bottlenecks
實(shí)現(xiàn)了Ghost 模塊,接下來開始搭建 Ghost Bottlenecks。
Ghost Bottlenecks是由Ghost Module組成的瓶頸結(jié)構(gòu),其實(shí)本質(zhì)上就是用Ghost Module,來代替瓶頸結(jié)構(gòu)里面的普通卷積。
Ghost Bottlenecks可以分為兩個(gè)部分,分別是主干部分和殘差邊部分,包含Ghost Module的,我們稱它為主干部分。
Ghost Bottlenecks有兩個(gè)種類,如下圖所示,當(dāng)我們需要對(duì)特征層的寬高進(jìn)行壓縮的時(shí)候,我們會(huì)設(shè)置這個(gè)Ghost Bottlenecks的Stride=2,即步長為2。此時(shí)我們會(huì)Bottlenecks里面多添加一些卷積層,在主干部分里,我們會(huì)在兩個(gè)Ghost Module中添加一個(gè)步長為2x2的深度可分離卷積進(jìn)行特征層的寬高壓縮。在殘差邊部分,我們也會(huì)添加上一個(gè)步長為2x2的深度可分離卷積和1x1的普通卷積。🌹
接下來實(shí)現(xiàn)GhostNet。🔖
💥???????💥2.3?Ghostnet的構(gòu)建
GhostNet的參數(shù)結(jié)構(gòu)參考論文中的圖,如下圖:
可以看到,整個(gè)Ghostnet都是由Ghost Bottlenecks進(jìn)行組成的。
當(dāng)一張圖片輸入到Ghostnet當(dāng)中時(shí),我們首先進(jìn)行一個(gè)16通道的普通1x1卷積塊(卷積+標(biāo)準(zhǔn)化+激活函數(shù))。之后我們就開始Ghost Bottlenecks的堆疊了,利用Ghost Bottlenecks,我們最終獲得了一個(gè)7x7x160的特征層(當(dāng)輸入是224x224x3的時(shí)候)。然后我們會(huì)利用一個(gè)1x1的卷積塊進(jìn)行通道數(shù)的調(diào)整,此時(shí)我們可以獲得一個(gè)7x7x960的特征層。之后我們進(jìn)行一次全局平均池化,然后再利用一個(gè)1x1的卷積塊進(jìn)行通道數(shù)的調(diào)整,獲得一個(gè)1x1x1280的特征層。然后平鋪后進(jìn)行全連接就可以進(jìn)行分類了。🌿
🚀3.YOLOv5結(jié)合Ghostnet
💥💥步驟1:在common.py中添加Ghostnet模塊
將下面Ghostnet模塊的代碼復(fù)制粘貼到common.py文件的末尾。
class SeBlock(nn.Module):def __init__(self, in_channel, reduction=4):super().__init__()self.Squeeze = nn.AdaptiveAvgPool2d(1)self.Excitation = nn.Sequential()self.Excitation.add_module('FC1', nn.Conv2d(in_channel, in_channel // reduction, kernel_size=1)) # 1*1卷積與此效果相同self.Excitation.add_module('ReLU', nn.ReLU())self.Excitation.add_module('FC2', nn.Conv2d(in_channel // reduction, in_channel, kernel_size=1))self.Excitation.add_module('Sigmoid', nn.Sigmoid())def forward(self, x):y = self.Squeeze(x)ouput = self.Excitation(y)return x * (ouput.expand_as(x))class G_bneck(nn.Module):# Ghost Bottleneck https://github.com/huawei-noah/ghostnetdef __init__(self, c1, c2, midc, k=5, s=1, use_se = False): # ch_in, ch_mid, ch_out, kernel, stride, use_sesuper().__init__()assert s in [1, 2]c_ = midcself.conv = nn.Sequential(GhostConv(c1, c_, 1, 1), # ExpansionConv(c_, c_, 3, s=2, p=1, g=c_, act=False) if s == 2 else nn.Identity(), # dw# Squeeze-and-ExciteSeBlock(c_) if use_se else nn.Sequential(),GhostConv(c_, c2, 1, 1, act=False)) # Squeeze pw-linearself.shortcut = nn.Identity() if (c1 == c2 and s == 1) else \nn.Sequential(Conv(c1, c1, 3, s=s, p=1, g=c1, act=False), \Conv(c1, c2, 1, 1, act=False)) # 避免stride=2時(shí) 通道數(shù)改變的情況def forward(self, x):# print(self.conv(x).shape)# print(self.shortcut(x).shape)return self.conv(x) + self.shortcut(x)
具體如下圖所示:
💥💥步驟2:在yolo.py文件中加入類名?
首先在yolo.py文件中找到parse_model函數(shù)這一行,加入G_bneck模塊。
💥💥步驟3:創(chuàng)建自定義yaml文件?
在models文件夾中復(fù)制yolov5s.yaml,粘貼并重命名為yolov5s_Ghostnet.yaml。
然后根據(jù)Ghostnet的網(wǎng)絡(luò)架構(gòu)來修改配置文件。
yaml文件修改后的完整代碼如下:
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license# Parameters
nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple
anchors:- [10,13, 16,30, 33,23] # P3/8- [30,61, 62,45, 59,119] # P4/16- [116,90, 156,198, 373,326] # P5/32# Ghostnet backbone
backbone:# [from, number, module, args][[-1, 1, Conv, [16, 3, 2, 1]], # 0-P1/2 ch_out, kernel, stride, padding, groups[-1, 1, G_bneck, [16, 16, 3, 1]], # 1 ch_out, ch_mid, dw-kernel, stride[-1, 1, G_bneck, [24, 48, 3, 2]], # 2-P2/4[-1, 1, G_bneck, [24, 72, 3, 1]], # 3[-1, 1, G_bneck, [40, 72, 3, 2, True]], # 4-P3/8[-1, 1, G_bneck, [40, 120, 3, 1, True]], # 5[-1, 1, G_bneck, [80, 240, 3, 2]], # 6-P4/16[-1, 3, G_bneck, [80, 184, 3, 1]], # 7[-1, 1, G_bneck, [112, 480, 3, 1, True]],[-1, 1, G_bneck, [112, 480, 3, 1, True]],[-1, 1, G_bneck, [160, 672, 3, 2, True]], # 10-P5/32[-1, 1, G_bneck, [160, 960, 3, 1]], # 11[-1, 1, G_bneck, [160, 960, 3, 1, True]],[-1, 1, G_bneck, [160, 960, 3, 1]],[-1, 1, G_bneck, [160, 960, 3, 1, True]],[-1, 1, Conv, [960]],]# YOLOv5 v6.0 head
head:[[-1, 1, Conv, [480, 1, 1]],[-1, 1, nn.Upsample, [None, 2, 'nearest']],[[-1, 9], 1, Concat, [1]], # cat backbone P4[-1, 3, C3, [480, False]], # 19[-1, 1, Conv, [240, 1, 1]],[-1, 1, nn.Upsample, [None, 2, 'nearest']],[[-1, 5], 1, Concat, [1]], # cat backbone P3[-1, 3, C3, [240, False]], # 23 (P3/8-small)[-1, 1, Conv, [240, 3, 2]],[[-1, 20], 1, Concat, [1]], # cat head P4[-1, 3, C3, [480, False]], # 26 (P4/16-medium)[-1, 1, Conv, [480, 3, 2]],[[-1, 15], 1, Concat, [1]], # cat head P5[-1, 3, C3, [960, False]], # 29 (P5/32-large)[[23, 26, 29], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)]
💥💥步驟4:驗(yàn)證是否加入成功
在yolo.py文件里,配置我們剛才自定義的yolov5s_Ghostnet.yaml。
然后運(yùn)行yolo.py,得到結(jié)果。
這樣就算添加成功了。🎉🎉🎉??
💥💥步驟5:修改train.py中的'--cfg'默認(rèn)參數(shù)
在train.py文件中找到?parse_opt函數(shù),然后將第二行?'--cfg'?的default改為?'models/yolov5s_Ghostnet.yaml',然后就可以開始進(jìn)行訓(xùn)練了。🎈🎈🎈