日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

GhostNet网络详解

發(fā)布時(shí)間:2024/3/13 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 GhostNet网络详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1. GhostNet網(wǎng)絡(luò)

一張圖片經(jīng)過神經(jīng)網(wǎng)絡(luò)進(jìn)行特征提取后,能夠得到很多特征圖。

在特征圖中會有一些相似性很高,這就是神經(jīng)網(wǎng)絡(luò)中存在的特征圖冗雜的情況(如圖中扳手相連的兩幅特征圖)。

作者認(rèn)為可以對其中的一個(gè)特征圖進(jìn)行(Cheap Operations)簡單的線性運(yùn)算從而生成更多相似特征圖,從而可以使用更少的參數(shù)生成更多的特征圖,將相似的特征圖認(rèn)為是彼此的Ghost。

2. Ghost Module


作者用Ghost Module代替?zhèn)鹘y(tǒng)卷積,首先采用普通的1x1卷積對輸入圖片進(jìn)行通道數(shù)的壓縮,然后再進(jìn)行深度可分離卷積(逐層卷積)得到更多的特征圖,然后將不同的特征圖concat到一起,組合成新的output。

Ghost Module構(gòu)建代碼

class GhostModule(nn.Module):def __init__(self, inp, oup, kernel_size=1, ratio=2, dw_size=3, stride=1, relu=True):super(GhostModule, self).__init__()#ratio一般會指定成2,保證輸出特征層的通道數(shù)等于expself.oup = oupinit_channels = math.ceil(oup / ratio)new_channels = init_channels*(ratio-1)#利用1x1卷積對輸入進(jìn)來的特征圖進(jìn)行通道的濃縮,獲得特征通縮#跨通道的特征提取self.primary_conv = nn.Sequential(nn.Conv2d(inp, init_channels, kernel_size, stride, kernel_size//2, bias=False), #1x1卷積的輸入通道數(shù)為GhostModule的輸出通道數(shù)oup/2nn.BatchNorm2d(init_channels), #1x1卷積后進(jìn)行標(biāo)準(zhǔn)化nn.ReLU(inplace=True) if relu else nn.Sequential(), #ReLU激活函數(shù))#在獲得特征濃縮后,使用逐層卷積,獲得額外的特征圖#跨特征點(diǎn)的特征提取 一般會設(shè)定大于1的卷積核大小self.cheap_operation = nn.Sequential(nn.Conv2d(init_channels, new_channels, dw_size, 1, dw_size//2, groups=init_channels, bias=False), #groups參數(shù)的功能就是將普通卷積轉(zhuǎn)換成逐層卷據(jù)nn.BatchNorm2d(new_channels),nn.ReLU(inplace=True) if relu else nn.Sequential(),)def forward(self, x):x1 = self.primary_conv(x)x2 = self.cheap_operation(x1)#將1x1卷積后的結(jié)果和逐層卷積后的結(jié)果進(jìn)行堆疊out = torch.cat([x1,x2], dim=1)return out[:,:self.oup,:,:]

1x1卷積的輸入通道數(shù)為GhostModule的輸出通道數(shù)oup/2,因?yàn)樽罱K輸出特征層由1x1卷積后的結(jié)果和逐層卷積后的結(jié)果進(jìn)行堆疊組成的,進(jìn)行逐層卷積時(shí)特征層的通道數(shù)不變,如果要保證最終輸出特征層的通道數(shù)是一個(gè)固定值,那么就要使得1x1卷積后的結(jié)果的通道數(shù)為最終輸出特征層的1/2。

3. Ghost BottleNeck原理

Ghost BottleNeck是由Ghost Module組成的瓶頸結(jié)構(gòu)

Ghost BottleNeck整體架構(gòu)和Residual Block非常相似,也可以直接認(rèn)為是將Residual Block中的普通卷積操作替換成Ghost Module得到。

左圖中主干部分用用兩個(gè)Ghost Module(GM)串聯(lián)組成,其中第一個(gè)GM擴(kuò)大通道數(shù),第二個(gè)GM將通道數(shù)降低到與輸入通道數(shù)一致;殘差邊部分與ResNet一樣。由于S=1,因此不會對輸入特征層的高和寬進(jìn)行壓縮,其功能為加深網(wǎng)絡(luò)的深度。

右圖中主干部分的兩個(gè)GM之間加入了一個(gè)stride=2的Deepwise卷積,可以將特征圖高和寬進(jìn)行壓縮,使其大小降為輸入的1/2;在殘差邊部分,也會添加一個(gè)步長為2x2的深度可分離卷積和1x1的普通卷積,以保證Add操作可以對齊。由于S=2,因此會對輸入特征層的高和寬進(jìn)行壓縮,其功能為改變輸入特征層的形狀。

實(shí)際應(yīng)用中,為了進(jìn)一步提高效率,GhostModule中的所有常規(guī)卷積都用pointwise卷積代替。

Ghost BottleNeck構(gòu)建代碼

class GhostBottleneck(nn.Module):def __init__(self, in_chs, mid_chs, out_chs, dw_kernel_size=3, stride=1, act_layer=nn.ReLU, se_ratio=0.):super(GhostBottleneck, self).__init__()has_se = se_ratio is not None and se_ratio > 0.self.stride = stride#首先利用一個(gè)ghost模塊進(jìn)行特征提取#此時(shí)指定的通道數(shù)會比較大,可以看作是逆殘差結(jié)構(gòu),進(jìn)行通道數(shù)上升self.ghost1 = GhostModule(in_chs, mid_chs, relu=True)if self.stride > 1: #根據(jù)步長判斷是否使用深度可分離卷積對輸入特征圖進(jìn)行高和寬的壓縮#如果要進(jìn)行特征圖的高寬壓縮,則進(jìn)行逐層卷積self.conv_dw = nn.Conv2d(mid_chs, mid_chs, dw_kernel_size, stride=stride,padding=(dw_kernel_size-1)//2,groups=mid_chs, bias=False)self.bn_dw = nn.BatchNorm2d(mid_chs)if has_se: #判斷是否使用注意力機(jī)制模塊self.se = SqueezeExcite(mid_chs, se_ratio=se_ratio)else:self.se = None#再次利用一個(gè)ghost模塊進(jìn)行特征提取self.ghost2 = GhostModule(mid_chs, out_chs, relu=False)#判斷步長是否等1、輸入通道和輸出通道是否一樣if (in_chs == out_chs and self.stride == 1):self.shortcut = nn.Sequential()else: #如果不一樣則利用深度可分離卷積和1x1卷積調(diào)整通道數(shù),保證主干部分和殘差邊部分能夠進(jìn)行相加self.shortcut = nn.Sequential(nn.Conv2d(in_chs, in_chs, dw_kernel_size, stride=stride,padding=(dw_kernel_size-1)//2, groups=in_chs, bias=False),nn.BatchNorm2d(in_chs),nn.Conv2d(in_chs, out_chs, 1, stride=1, padding=0, bias=False),nn.BatchNorm2d(out_chs),)def forward(self, x): #前向傳播residual = xx = self.ghost1(x)if self.stride > 1:x = self.conv_dw(x)x = self.bn_dw(x)if self.se is not None:x = self.se(x)x = self.ghost2(x)x += self.shortcut(residual)return x

4. GhostNet的構(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í)候)

然后利用一個(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)行分類了。

class GhostNet(nn.Module):def __init__(self, cfgs, num_classes=1000, width=1.0, dropout=0.2):super(GhostNet, self).__init__()# setting of inverted residual blocksself.cfgs = cfgsself.dropout = dropout# building first layer 對輸入圖片進(jìn)行第一個(gè)卷積標(biāo)準(zhǔn)化+激活函數(shù)output_channel = _make_divisible(16 * width, 4)#以應(yīng)用到y(tǒng)olov4為例 416,416,3 -> 208,208,16 壓縮高和寬,通道數(shù)擴(kuò)張self.conv_stem = nn.Conv2d(3, output_channel, 3, 2, 1, bias=False) #s=2,output_channel=16self.bn1 = nn.BatchNorm2d(output_channel)self.act1 = nn.ReLU(inplace=True)input_channel = output_channel# building inverted residual blocks 構(gòu)建瓶頸結(jié)構(gòu)stages = []block = GhostBottleneckfor cfg in self.cfgs: #對配置列表進(jìn)行循環(huán)layers = []for k, exp_size, c, se_ratio, s in cfg:output_channel = _make_divisible(c * width, 4)hidden_channel = _make_divisible(exp_size * width, 4)#根據(jù)cfg里面的內(nèi)容構(gòu)建瓶頸結(jié)構(gòu)layers.append(block(input_channel, hidden_channel, output_channel, k, s,se_ratio=se_ratio))#計(jì)算下一個(gè)瓶頸結(jié)構(gòu)的輸入input_channel = output_channelstages.append(nn.Sequential(*layers))#卷積標(biāo)準(zhǔn)化+激活函數(shù)output_channel = _make_divisible(exp_size * width, 4)stages.append(nn.Sequential(ConvBnAct(input_channel, output_channel, 1)))input_channel = output_channel#根據(jù)構(gòu)建好的block序列模型self.blocks = nn.Sequential(*stages) #構(gòu)建分類才能夠# building last several layersoutput_channel = 1280self.global_pool = nn.AdaptiveAvgPool2d((1, 1))self.conv_head = nn.Conv2d(input_channel, output_channel, 1, 1, 0, bias=True)self.act2 = nn.ReLU(inplace=True)self.classifier = nn.Linear(output_channel, num_classes)def forward(self, x):#第一個(gè)卷積標(biāo)注化+激活函數(shù)x = self.conv_stem(x)x = self.bn1(x)x = self.act1(x)#瓶頸結(jié)構(gòu)特征提取x = self.blocks(x)#構(gòu)建分類岑那個(gè)x = self.global_pool(x)x = self.conv_head(x)x = self.act2(x)x = x.view(x.size(0), -1)if self.dropout > 0.:x = F.dropout(x, p=self.dropout, training=self.training)x = self.classifier(x)return xdef ghostnet(**kwargs):"""Constructs a GhostNet model"""cfgs = [# k, t, c, SE, s# k代表卷積核大小,表示跨特征點(diǎn)的特征提取能力# t代表第一個(gè)ghost模塊的通道數(shù)大小,它的值一般比較大一點(diǎn)# c代表瓶頸結(jié)構(gòu)最終的輸出通道數(shù)# SE代表是否使用注意力機(jī)制,如果不為0就是用注意力機(jī)制# s代表步長,如果s=2就會對輸入特征層進(jìn)行高和寬的壓縮# stage1# 208,208,16 -> 208,208,16[[3, 16, 16, 0, 1]],# stage2# 208,208,16 -> 104,104,24[[3, 48, 24, 0, 2]],[[3, 72, 24, 0, 1]],# stage3# 104,104,24 -> 52,52,40[[5, 72, 40, 0.25, 2]],[[5, 120, 40, 0.25, 1]],# stage4# 52,52,40 -> 26,26,80 -> 26,26,112[[3, 240, 80, 0, 2]],[[3, 200, 80, 0, 1],[3, 184, 80, 0, 1],[3, 184, 80, 0, 1],[3, 480, 112, 0.25, 1],[3, 672, 112, 0.25, 1]],# stage5# 26,26,112 -> 13,13,160[[5, 672, 160, 0.25, 2]],[[5, 960, 160, 0, 1],[5, 960, 160, 0.25, 1],[5, 960, 160, 0, 1],[5, 960, 160, 0.25, 1]]]return GhostNet(cfgs, **kwargs)

5. 將GhostNet應(yīng)用到Y(jié)olov4上

需要利用主干特征提取網(wǎng)絡(luò)獲得的三個(gè)有效特征進(jìn)行加強(qiáng)特征金字塔的構(gòu)建

取出stage3、stage4、stage5的輸出:

class GhostNet(nn.Module):def __init__(self, pretrained=True):super(GhostNet, self).__init__()model = ghostnet()if pretrained:state_dict = torch.load("model_data/ghostnet_weights.pth")model.load_state_dict(state_dict)del model.global_pooldel model.conv_headdel model.act2del model.classifierdel model.blocks[9]self.model = modeldef forward(self, x):x = self.model.conv_stem(x)x = self.model.bn1(x)x = self.model.act1(x)feature_maps = []for idx, block in enumerate(self.model.blocks):x = block(x)if idx in [2,4,6,8]:feature_maps.append(x)return feature_maps[1:]

參考文獻(xiàn):
原作者解讀
Ghostnet網(wǎng)絡(luò)介紹與構(gòu)建

總結(jié)

以上是生活随笔為你收集整理的GhostNet网络详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。