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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人工智能 > pytorch >内容正文

pytorch

【深度学习】真正的即插即用!盘点11种CNN网络设计中精巧通用的“小”插件...

發布時間:2025/3/12 pytorch 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【深度学习】真正的即插即用!盘点11种CNN网络设计中精巧通用的“小”插件... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

??作者丨皮特潘

編輯丨極市平臺

導讀

?

所謂“插件”,就是要能錦上添花,又容易植入、落地,即真正的即插即用。本文盤點的“插件”能夠提升CNN平移、旋轉、scale等變性能力或多尺度特征提取,感受野等能力,在很多SOTA網絡中都會看到它們的影子。

前言

本文盤點一些CNN網絡中設計比較精巧而又實用的“插件”。所謂“插件”,就是不改變網絡主體結構, 可以很容易嵌入到主流網絡當中,提高網絡提取特征的能力,能夠做到plug-and-play。網絡也有很多類似盤點工作,都宣稱所謂的即插即用、無痛漲點。不過根據筆者經驗和收集,發現很多插件都是不實用、不通用、甚至不work的,于是有了這一篇。

首先,我的認識是:既然是“插件”,就要是錦上添花的,又容易植入,容易落地的,真正的即插即用。本文盤點的“插件”,在很多SOTA網絡中會看到它們的影子。是值得推廣的良心“插件”,真正能做到plug-and-play??傊痪湓?#xff0c;就是能夠work的“插件”。很多“插件”都為提升CNN能力而推出的,例如平移、旋轉、scale等變性能力,多尺度特征提取能力,感受野等能力,感知空間位置能力等等。

入圍名單:STN、ASPP、Non-local、SE、CBAM、DCNv1&v2、CoordConv、Ghost、BlurPool、RFB、ASFF

1 STN

出自論文:Spatial Transformer Networks

論文鏈接:https://arxiv.org/pdf/1506.02025.pdf

核心解析

在OCR等任務中,你會經??吹剿纳碛?。對于CNN網絡,我們希望其具有對物體的姿態、位置等有一定的不變性。即在測試集上可以適應一定的姿態、位置的變化。不變性或等變性可以有效提高模型泛化能力。雖然CNN使用sliding-window卷積操作,在一定程度上具有平移不變性。但很多研究發現,下采樣會破壞網絡的平移不變性。所以可以認為網絡的不變性能力非常弱,更不用說旋轉、尺度、光照等不變性。一般我們利用數據增強來實現網絡的“不變性”。

本文提出STN模塊,顯式將空間變換植入到網絡當中,進而提高網絡的旋轉、平移、尺度等不變性??梢岳斫鉃椤皩R”操作。STN的結構如上圖所示,每一個STN模塊由Localisation net,Grid generator和Sampler三部分組成。Localisation net用于學習獲取空間變換的參數,就是上式中的六個參數。Grid generator用于坐標映射。Sampler用于像素的采集,是利用雙線性插值的方式進行。

STN的意義是能夠把原始的圖像糾正成為網絡想要的理想圖像,并且該過程為無監督的方式進行,也就是變換參數是自發學習獲取的,不需要標注信息。該模塊是一個獨立模塊,可以在CNN的任何位置插入。符合本次“插件”的盤點要求。

核心代碼:

class SpatialTransformer(nn.Module):def __init__(self, spatial_dims):super(SpatialTransformer, self).__init__()self._h, self._w = spatial_dims self.fc1 = nn.Linear(32*4*4, 1024) # 可根據自己的網絡參數具體設置self.fc2 = nn.Linear(1024, 6)def forward(self, x): batch_images = x #保存一份原始數據x = x.view(-1, 32*4*4)# 利用FC結構學習到6個參數x = self.fc1(x)x = self.fc2(x) x = x.view(-1, 2,3) # 2x3# 利用affine_grid生成采樣點affine_grid_points = F.affine_grid(x, torch.Size((x.size(0), self._in_ch, self._h, self._w)))# 將采樣點作用到原始數據上rois = F.grid_sample(batch_images, affine_grid_points)return rois, affine_grid_points

2 ASPP

插件全稱:atrous spatial pyramid pooling

出自論文:DeepLab: Semantic Image Segmentation with Deep Convolutional Nets, Atrous Conv

論文鏈接:https://arxiv.org/pdf/1606.00915.pdf

核心解析

本插件是帶有空洞卷積的空間金字塔池化模塊,主要是為了提高網絡的感受野,并引入多尺度信息而提出的。我們知道,對于語義分割網絡,通常面臨是分辨率較大的圖片,這就要求我們的網絡有足夠的感受野來覆蓋到目標物體。對于CNN網絡基本是靠卷積層的堆疊加上下采樣操作來獲取感受野的。本文的該模塊可以在不改變特征圖大小的同時控制感受野,這有利于提取多尺度信息。其中rate控制著感受野的大小,r越大感受野越大。

ASPP主要包含以下幾個部分:1. 一個全局平均池化層得到image-level特征,并進行1X1卷積,并雙線性插值到原始大小;2. 一個1X1卷積層,以及三個3X3的空洞卷積;3. 將5個不同尺度的特征在channel維度concat在一起,然后送入1X1的卷積進行融合輸出。

核心代碼

class ASPP(nn.Module):def __init__(self, in_channel=512, depth=256):super(ASPP,self).__init__()self.mean = nn.AdaptiveAvgPool2d((1, 1))self.conv = nn.Conv2d(in_channel, depth, 1, 1)self.atrous_block1 = nn.Conv2d(in_channel, depth, 1, 1)# 不同空洞率的卷積self.atrous_block6 = nn.Conv2d(in_channel, depth, 3, 1, padding=6, dilation=6)self.atrous_block12 = nn.Conv2d(in_channel, depth, 3, 1, padding=12, dilation=12)self.atrous_block18 = nn.Conv2d(in_channel, depth, 3, 1, padding=18, dilation=18)self.conv_1x1_output = nn.Conv2d(depth * 5, depth, 1, 1)def forward(self, x):size = x.shape[2:]# 池化分支image_features = self.mean(x)image_features = self.conv(image_features)image_features = F.upsample(image_features, size=size, mode='bilinear')# 不同空洞率的卷積atrous_block1 = self.atrous_block1(x)atrous_block6 = self.atrous_block6(x)atrous_block12 = self.atrous_block12(x)atrous_block18 = self.atrous_block18(x)# 匯合所有尺度的特征x = torch.cat([image_features, atrous_block1, atrous_block6,atrous_block12, atrous_block18], dim=1)# 利用1X1卷積融合特征輸出x = self.conv_1x1_output(x)return net

3 Non-local

出自論文:Non-local Neural Networks

論文鏈接:https://arxiv.org/abs/1711.07971

核心解析

Non-Local是一種attention機制,也是一個易于植入和集成的模塊。Local主要是針對感受野(receptive field)來說的,以CNN中的卷積操作和池化操作為例,它的感受野大小就是卷積核大小,而我們常用3X3的卷積層進行堆疊,它只考慮局部區域,都是local的運算。不同的是,non-local操作感受野可以很大,可以是全局區域,而不是一個局部區域。捕獲長距離依賴(long-range dependencies),即如何建立圖像上兩個有一定距離的像素之間的聯系,是一種注意力機制。所謂注意力機制就是利用網絡生成saliency map,注意力對應的是顯著性區域,是需要網絡重點關注的區域。

  • 首先分別對輸入的特征圖進行 1X1的卷積來壓縮通道數,得到,特征。

  • 通過reshape操作,轉化三個特征的維度,然后對進行矩陣乘操作,得到類似協方差矩陣, 這一步為了計算出特征中的自相關性,即得到每幀中每個像素對其他所有幀所有像素的關系。

  • 然后對自相關特征進行 Softmax 操作,得到0~1的weights,這里就是我們需要的 Self-attention系數。

  • 最后將 attention系數,對應乘回特征矩陣g上,與原輸入 feature map X 殘差相加輸出即可。

這里我們結合一個簡單例子理解一下,假設g為(我們暫時不考慮batch和channel維度):

g = torch.tensor([[1, 2],[3, 4]).view(-1, 1).float()

為:

theta = torch.tensor([2, 4, 6, 8]).view(-1, 1)

為:

phi = torch.tensor([7, 5, 3, 1]).view(1, -1)

那么,和矩陣相乘如下:

tensor([[14., 10., 6., 2.],[28., 20., 12., 4.],[42., 30., 18., 6.],[56., 40., 24., 8.]])

進過softmax(dim=-1)后如下,每一行代表著g里面的元素的重要程度,每一行前面的值比較大,因此希望多“注意”到g前面的元素,也就是1比較重要一點?;蛘哌@樣理解:注意力矩陣代表著g中每個元素和其他元素的依賴程度。

tensor([[9.8168e-01, 1.7980e-02, 3.2932e-04, 6.0317e-06],[9.9966e-01, 3.3535e-04, 1.1250e-07, 3.7739e-11],[9.9999e-01, 6.1442e-06, 3.7751e-11, 2.3195e-16],[1.0000e+00, 1.1254e-07, 1.2664e-14, 1.4252e-21]])

注意力作用上之后,整體值向原始g中的值都向1靠攏:

tensor([[1.0187, 1.0003],[1.0000, 1.0000]])

核心代碼

class NonLocal(nn.Module):def __init__(self, channel):super(NonLocalBlock, self).__init__()self.inter_channel = channel // 2self.conv_phi = nn.Conv2d(channel, self.inter_channel, 1, 1,0, False)self.conv_theta = nn.Conv2d(channel, self.inter_channel, 1, 1,0, False)self.conv_g = nn.Conv2d(channel, self.inter_channel, 1, 1, 0, False)self.softmax = nn.Softmax(dim=1)self.conv_mask = nn.Conv2d(self.inter_channel, channel, 1, 1, 0, False)def forward(self, x):# [N, C, H , W]b, c, h, w = x.size()# 獲取phi特征,維度為[N, C/2, H * W],注意是要保留batch和通道維度的,是在HW上進行的x_phi = self.conv_phi(x).view(b, c, -1)# 獲取theta特征,維度為[N, H * W, C/2]x_theta = self.conv_theta(x).view(b, c, -1).permute(0, 2, 1).contiguous()# 獲取g特征,維度為[N, H * W, C/2]x_g = self.conv_g(x).view(b, c, -1).permute(0, 2, 1).contiguous()# 對phi和theta進行矩陣乘,[N, H * W, H * W]mul_theta_phi = torch.matmul(x_theta, x_phi)# softmax拉到0~1之間mul_theta_phi = self.softmax(mul_theta_phi)# 與g特征進行矩陣乘運算,[N, H * W, C/2]mul_theta_phi_g = torch.matmul(mul_theta_phi, x_g)# [N, C/2, H, W]mul_theta_phi_g = mul_theta_phi_g.permute(0, 2, 1).contiguous().view(b, self.inter_channel, h, w)# 1X1卷積擴充通道數mask = self.conv_mask(mul_theta_phi_g)out = mask + x # 殘差連接return out

4 SE

出自論文:Squeeze-and-Excitation Networks

論文鏈接:https://arxiv.org/pdf/1709.01507.pdf

核心解析

本文是ImageNet最后一屆比賽的冠軍作品,你會在很多經典網絡結構中看到它的身影,例如Mobilenet v3。其實是一種通道注意力機制。由于特征壓縮和FC的存在,其捕獲的通道注意力特征是具有全局信息的。本文提出了一種新的結構單元——“Squeeze-and Excitation(SE)”模塊,可以自適應的調整各通道的特征響應值,對通道間的內部依賴關系進行建模。有以下幾個步驟:

  • Squeeze: 沿著空間維度進行特征壓縮,將每個二維的特征通道變成一個數,是具有全局的感受野。

  • Excitation: 每個特征通道生成一個權重,用來代表該特征通道的重要程度。

  • Reweight:將Excitation輸出的權重看做每個特征通道的重要性,通過相乘的方式作用于每一個通道上。

核心代碼

class SE_Block(nn.Module):def __init__(self, ch_in, reduction=16):super(SE_Block, self).__init__()self.avg_pool = nn.AdaptiveAvgPool2d(1) # 全局自適應池化self.fc = nn.Sequential(nn.Linear(ch_in, ch_in // reduction, bias=False),nn.ReLU(inplace=True),nn.Linear(ch_in // reduction, ch_in, bias=False),nn.Sigmoid())def forward(self, x):b, c, _, _ = x.size()y = self.avg_pool(x).view(b, c) # squeeze操作y = self.fc(y).view(b, c, 1, 1) # FC獲取通道注意力權重,是具有全局信息的return x * y.expand_as(x) # 注意力作用每一個通道上

5 CBAM

出自論文:CBAM: Convolutional Block Attention Module

論文鏈接:https://openaccess.thecvf.com/content_ECCV_2018/papers/Sanghyun_Woo_Convolutional_Block_Attention_ECCV_2018_paper.pdf

核心解析

SENet在feature map的通道上進行attention權重獲取,然后與原來的feature map相乘。這篇文章指出,該種attention方法法只關注了通道層面上哪些層會具有更強的反饋能力,但是在空間維度上并不能體現出attention。CBAM作為本文的亮點,將attention同時運用在channel和spatial兩個維度上, CBAM與SE Module一樣,可以嵌入在大部分的主流網絡中,在不顯著增加計算量和參數量的前提下能提升模型的特征提取能力。

通道注意力: 如上圖所示,輸入是一個 H×W×C 的特征F,我們先分別進兩個空間的全局平均池化和最大池化得到 兩個 1×1×C 的通道描述。再將它們分別送進一個兩層的神經網絡,第一層神經元個數為 C/r,激活函數為 Relu,第二層神經元個數為 C。注意,這個兩層的神經網絡是共享的。然后,再將得到的兩個特征相加后經過一個 Sigmoid 激活函數得到權重系數 Mc。最后,拿權重系數和 原來的特征 F 相乘即可得到縮放后的新特征。偽代碼:

def forward(self, x):# 利用FC獲取全局信息,和Non-local的矩陣相乘本質上式一樣的avg_out = self.fc2(self.relu1(self.fc1(self.avg_pool(x))))max_out = self.fc2(self.relu1(self.fc1(self.max_pool(x))))out = avg_out + max_outreturn self.sigmoid(out)

空間注意力: 與通道注意力相似,給定一個 H×W×C 的特征 F‘,我們先分別進行一個通道維度的平均池化和最大池化得到兩個 H×W×1 的通道描述,并將這兩個描述按照通道拼接在一起。然后,經過一個 7×7 的卷積層, 激活函數為 Sigmoid,得到權重系數 Ms。最后,拿權重系數和特征 F’ 相乘即可得到縮放后的新特征。偽代碼:

def forward(self, x):# 這里利用池化獲取全局信息avg_out = torch.mean(x, dim=1, keepdim=True)max_out, _ = torch.max(x, dim=1, keepdim=True)x = torch.cat([avg_out, max_out], dim=1)x = self.conv1(x)return self.sigmoid(x)

6 DCN v1&v2

插件全稱:Deformable Convolutional

出自論文

v1: [Deformable Convolutional Networks]

https://arxiv.org/pdf/1703.06211.pdf

v2: [Deformable ConvNets v2: More Deformable, Better Results]

https://arxiv.org/pdf/1811.11168.pdf

核心解析

變形卷積可以看作變形+卷積兩個部分,因此可以當作插件使用。在各大主流檢測網絡中,變形卷積真是漲點神器,網上解讀也非常之多。和傳統的固定窗口的卷積相比,變形卷積可以有效地對幾何圖形,因為它的“局部感受野”是可學習的,面向全圖的。這篇論文同時提出了deformable ROI pooling,這兩個方法都是增加額外偏移量的空間采樣位置,不需要額外的監督,是自監督的過程。

如上圖所示,a為不同的卷積,b為變形卷積,深色的點為卷積核實際采樣的位置,和“標準的”位置有一定的偏移。c和d為變形卷積的特殊形式,其中c為我們常見到的空洞卷積,d為具有學習旋轉特性的卷積,也具備提升感受野的能力。

變形卷積和STN過程非常類似,STN是利用網絡學習出空間變換的6個參數,對特征圖進行整體變換,旨在增加網絡對形變的提取能力。DCN是利用網絡學習數整圖offset,比STN的變形更“全面一點”。STN是仿射變換,DCN是任意變換。公式不貼了,可以直接看代碼實現過程。

變形卷積具有V1和V2兩個版本,其中V2是在V2的基礎上進行改進,除了采樣offset,還增加了采樣權重。V2認為3X3采樣點也應該具有不同的重要程度,因此該處理方法更具有靈活性和擬合能力。

核心代碼

def forward(self, x):# 學習出offset,包括x和y兩個方向,注意是每一個channel中的每一個像素都有一個x和y的offsetoffset = self.p_conv(x)if self.v2: # V2的時候還會額外學習一個權重系數,經過sigmoid拉到0和1之間m = torch.sigmoid(self.m_conv(x))# 利用offset對x進行插值,獲取偏移后的x_offsetx_offset = self.interpolate(x,offset)if self.v2: # V2的時候,將權重系數作用到特征圖上m = m.contiguous().permute(0, 2, 3, 1)m = m.unsqueeze(dim=1)m = torch.cat([m for _ in range(x_offset.size(1))], dim=1)x_offset *= mout = self.conv(x_offset) # offset作用后,在進行標準的卷積過程return out

7 CoordConv

出自論文:An intriguing failing of convolutional neural networks and the CoordConv solution

論文鏈接:https://arxiv.org/pdf/1807.03247.pdf

核心解析

在Solo語義分割算法和Yolov5中你可以看到它的身影。本文從幾個小實驗為出發點,探究了卷積網絡在坐標變換上的能力。就是它無法將空間表示轉換成笛卡爾空間中的坐標。如下圖所示,我們向一個網絡中輸入(i, j)坐標,要求它輸出一個64×64的圖像,并在坐標處畫一個正方形或者一個像素,然而網絡在測試集上卻無法完成。雖然這項任務是我們人類認為極其簡單的工作。分析原因是卷積作為一種局部的、共享權重的過濾器應用到輸入上時,它是不知道每個過濾器在哪,無法捕捉位置信息的。因此我們可以幫助卷積,讓它知道過濾器的位置。僅僅需要在輸入上添加兩個通道,一個是i坐標,另一個是j坐標。具體做法如上圖所示,送入濾波器之前增加兩個通道。這樣,網絡就具備了空間位置信息的能力,是不是很神奇?你可以隨機在分類、分割、檢測等任務中使用這種掛件。

如上面第一組圖片,傳統的CNN在根據坐標數值生成圖像的任務中,訓練集很好,測試集一團糟。第二組圖片增加了 CoordConv 之后可以輕松完成該任務,可見其增加了CNN空間感知的能力。

核心代碼

ins_feat = x # 當前實例特征tensor # 生成從-1到1的線性值 x_range = torch.linspace(-1, 1, ins_feat.shape[-1], device=ins_feat.device) y_range = torch.linspace(-1, 1, ins_feat.shape[-2], device=ins_feat.device) y, x = torch.meshgrid(y_range, x_range) # 生成二維坐標網格 y = y.expand([ins_feat.shape[0], 1, -1, -1]) # 擴充到和ins_feat相同維度 x = x.expand([ins_feat.shape[0], 1, -1, -1]) coord_feat = torch.cat([x, y], 1) # 位置特征 ins_feat = torch.cat([ins_feat, coord_feat], 1) # concatnate一起作為下一個卷積的輸入

8 Ghost

插件全稱:Ghost module

出自論文:GhostNet: More Features from Cheap Operations

論文鏈接:https://arxiv.org/pdf/1911.11907.pdf

核心解析

在ImageNet的分類任務上,GhostNet在相似計算量情況下Top-1正確率達75.7%,高于MobileNetV3的75.2%。其主要創新點就是提出了Ghost 模塊。在CNN模型中,特征圖是存在大量的冗余,當然這也是非常重要和有必要的。如下圖所示,其中標“小扳手”的特征圖都存在冗余的特征圖。那么能否降低卷積的通道數,然后利用某種變換生成冗余的特征圖?事實上這就是GhostNet的思路。

而本文就從特征圖冗余問題出發,提出一個僅通過少量計算(論文稱為cheap operations)就能生成大量特征圖的結構——Ghost Module。而cheap operations就是線性變換,論文中采用卷積操作實現。具體過程如下:

  • 使用比原始更少量卷積運算,比如正常用64個卷積核,這里就用32個,減少一半的計算量。

  • 利用深度分離卷積,從上面生成的特征圖中變換出冗余的特征。

  • 上面兩步獲取的特征圖concat起來輸出,送入后續的環節。

核心代碼

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__()self.oup = oupinit_channels = math.ceil(oup / ratio)new_channels = init_channels*(ratio-1)self.primary_conv = nn.Sequential(nn.Conv2d(inp, init_channels, kernel_size, stride, kernel_size//2, bias=False),nn.BatchNorm2d(init_channels),nn.ReLU(inplace=True) if relu else nn.Sequential(), )# cheap操作,注意利用了分組卷積進行通道分離self.cheap_operation = nn.Sequential(nn.Conv2d(init_channels, new_channels, dw_size, 1, dw_size//2, groups=init_channels, bias=False),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) # cheap變換操作out = torch.cat([x1,x2], dim=1) # 二者cat到一起return out[:,:self.oup,:,:]

9 BlurPool

出自論文:Making Convolutional Networks Shift-Invariant Again

論文鏈接:https://arxiv.org/abs/1904.11486

核心解析

我們都知道,基于滑動窗口的卷積操作是具有平移不變性的,因此也默認為CNN網絡具有平移不變性或等變性,事實上真的如此嗎?實踐發現,CNN網絡真的非常敏感,只要輸入圖片稍微改一個像素,或者平移一個像素,CNN的輸出就會發生巨大的變化,甚至預測錯誤。這可是非常不具有魯棒性的。一般情況下我們利用數據增強獲取所謂的不變性。本文研究發現,不變性的退化根本原因就在于下采樣,無論是Max Pool還是Average Pool,抑或是stride>1的卷積操作,只要是涉及步長大于1的下采樣,均會導致平移不變性的丟失。具體示例如下圖所示,僅僅平移一個像素,Max pool的結果就差距很大。

為了保持平移不變性,可以在下采樣之前進行低通濾波。傳統的max pool可以分解為兩部分,分別是stride = 1的max + 下采樣 。因此作者提出的MaxBlurPool = max + blur + 下采樣來替代原始的max pool。實驗發現,該操作雖然不能徹底解決平移不變性的丟失,但是可以很大程度上緩解。

核心代碼

class BlurPool(nn.Module):def __init__(self, channels, pad_type='reflect', filt_size=4, stride=2, pad_off=0):super(BlurPool, self).__init__()self.filt_size = filt_sizeself.pad_off = pad_offself.pad_sizes = [int(1.*(filt_size-1)/2), int(np.ceil(1.*(filt_size-1)/2)), int(1.*(filt_size-1)/2), int(np.ceil(1.*(filt_size-1)/2))]self.pad_sizes = [pad_size+pad_off for pad_size in self.pad_sizes]self.stride = strideself.off = int((self.stride-1)/2.)self.channels = channels# 定義一系列的高斯核if(self.filt_size==1):a = np.array([1.,])elif(self.filt_size==2):a = np.array([1., 1.])elif(self.filt_size==3):a = np.array([1., 2., 1.])elif(self.filt_size==4): a = np.array([1., 3., 3., 1.])elif(self.filt_size==5): a = np.array([1., 4., 6., 4., 1.])elif(self.filt_size==6): a = np.array([1., 5., 10., 10., 5., 1.])elif(self.filt_size==7): a = np.array([1., 6., 15., 20., 15., 6., 1.])filt = torch.Tensor(a[:,None]*a[None,:])filt = filt/torch.sum(filt) # 歸一化操作,保證特征經過blur后信息總量不變# 非grad操作的參數利用buffer存儲self.register_buffer('filt', filt[None,None,:,:].repeat((self.channels,1,1,1)))self.pad = get_pad_layer(pad_type)(self.pad_sizes)def forward(self, inp):if(self.filt_size==1):if(self.pad_off==0):return inp[:,:,::self.stride,::self.stride] else:return self.pad(inp)[:,:,::self.stride,::self.stride]else:# 利用固定參數的conv2d+stride實現blurpoolreturn F.conv2d(self.pad(inp), self.filt, stride=self.stride, groups=inp.shape[1])

10?RFB

插件全稱:Receptive Field Block

出自論文:Receptive Field Block Net for Accurate and Fast Object Detection

論文鏈接:https://arxiv.org/abs/1711.07767

核心解析

論文發現目標區域要盡量靠近感受野中心,這會有助于提升模型對小尺度空間位移的魯棒性。因此受人類視覺RF結構的啟發,本文提出了感受野模塊(RFB),加強了CNN模型學到的深層特征的能力,使檢測模型更加準確。RFB可以作為一種通用模塊嵌入到絕大多數網路當中。下圖可以看出其和inception、ASPP、DCN的區別,可以看作是inception+ASPP的結合。

具體實現如下圖,其實和ASPP類似,不過是使用了不同大小的卷積核作為空洞卷積的前置操作。

核心代碼

class RFB(nn.Module):def __init__(self, in_planes, out_planes, stride=1, scale = 0.1, visual = 1):super(RFB, self).__init__()self.scale = scaleself.out_channels = out_planesinter_planes = in_planes // 8# 分支0:1X1卷積+3X3卷積self.branch0 = nn.Sequential(conv_bn_relu(in_planes, 2*inter_planes, 1, stride),conv_bn_relu(2*inter_planes, 2*inter_planes, 3, 1, visual, visual, False))# 分支1:1X1卷積+3X3卷積+空洞卷積self.branch1 = nn.Sequential(conv_bn_relu(in_planes, inter_planes, 1, 1),conv_bn_relu(inter_planes, 2*inter_planes, (3,3), stride, (1,1)),conv_bn_relu(2*inter_planes, 2*inter_planes, 3, 1, visual+1,visual+1,False))# 分支2:1X1卷積+3X3卷積*3代替5X5卷積+空洞卷積self.branch2 = nn.Sequential(conv_bn_relu(in_planes, inter_planes, 1, 1),conv_bn_relu(inter_planes, (inter_planes//2)*3, 3, 1, 1),conv_bn_relu((inter_planes//2)*3, 2*inter_planes, 3, stride, 1),conv_bn_relu(2*inter_planes, 2*inter_planes, 3, 1, 2*visual+1, 2*visual+1,False) )self.ConvLinear = conv_bn_relu(6*inter_planes, out_planes, 1, 1, False)self.shortcut = conv_bn_relu(in_planes, out_planes, 1, stride, relu=False)self.relu = nn.ReLU(inplace=False)def forward(self,x):x0 = self.branch0(x)x1 = self.branch1(x)x2 = self.branch2(x)# 尺度融合out = torch.cat((x0,x1,x2),1)# 1X1卷積out = self.ConvLinear(out)short = self.shortcut(x)out = out*self.scale + shortout = self.relu(out)return out

11 ASFF

插件全稱:Adaptively Spatial Feature Fusion

出自論文:Adaptively Spatial Feature Fusion Learning Spatial Fusion for Single-Shot Object Detection

論文鏈接:https://arxiv.org/abs/1911.09516v1

核心解析

為了更加充分的利用高層語義特征和底層細粒度特征,很多網絡都會采用FPN的方式輸出多層特征,但是它們都多用concat或者element-wise這種融合方式,本論文認為這樣不能充分利用不同尺度的特征,所以提出了Adaptively Spatial Feature Fusion,即自適應特征融合方式。FPN輸出的特征圖經過下面兩部分的處理:

Feature Resizing:特征圖的尺度不同無法進行element-wise融合,因此需要進行resize。對于上采樣:首先利用1X1卷積進行通道壓縮,然后利用插值的方法上采樣特征圖。對于1/2的下采樣:利用stride=2的3X3卷積同時進行通道壓縮和特征圖縮小。對于1/4的下采樣:在stride=2的3X3的卷積之前插入tride=2的maxpooling。

Adaptive Fusion:特征圖自適應融合,公式如下

其中x n→l表示在(i,j)位置的特征向量,來自n特征圖,經過上述resize到l尺度。Alpha。Beta,gamma為空間注意力權重,經過softmax處理,如下:

代碼解析

class ASFF(nn.Module):def __init__(self, level, rfb=False):super(ASFF, self).__init__()self.level = level# 輸入的三個特征層的channels, 根據實際修改self.dim = [512, 256, 256]self.inter_dim = self.dim[self.level]# 每個層級三者輸出通道數需要一致if level==0:self.stride_level_1 = conv_bn_relu(self.dim[1], self.inter_dim, 3, 2)self.stride_level_2 = conv_bn_relu(self.dim[2], self.inter_dim, 3, 2)self.expand = conv_bn_relu(self.inter_dim, 1024, 3, 1)elif level==1:self.compress_level_0 = conv_bn_relu(self.dim[0], self.inter_dim, 1, 1)self.stride_level_2 = conv_bn_relu(self.dim[2], self.inter_dim, 3, 2)self.expand = conv_bn_relu(self.inter_dim, 512, 3, 1)elif level==2:self.compress_level_0 = conv_bn_relu(self.dim[0], self.inter_dim, 1, 1)if self.dim[1] != self.dim[2]:self.compress_level_1 = conv_bn_relu(self.dim[1], self.inter_dim, 1, 1)self.expand = add_conv(self.inter_dim, 256, 3, 1)compress_c = 8 if rfb else 16 self.weight_level_0 = conv_bn_relu(self.inter_dim, compress_c, 1, 1)self.weight_level_1 = conv_bn_relu(self.inter_dim, compress_c, 1, 1)self.weight_level_2 = conv_bn_relu(self.inter_dim, compress_c, 1, 1)self.weight_levels = nn.Conv2d(compress_c*3, 3, 1, 1, 0)# 尺度大小 level_0 < level_1 < level_2def forward(self, x_level_0, x_level_1, x_level_2):# Feature Resizing過程if self.level==0:level_0_resized = x_level_0level_1_resized = self.stride_level_1(x_level_1)level_2_downsampled_inter =F.max_pool2d(x_level_2, 3, stride=2, padding=1)level_2_resized = self.stride_level_2(level_2_downsampled_inter)elif self.level==1:level_0_compressed = self.compress_level_0(x_level_0)level_0_resized =F.interpolate(level_0_compressed, 2, mode='nearest')level_1_resized =x_level_1level_2_resized =self.stride_level_2(x_level_2)elif self.level==2:level_0_compressed = self.compress_level_0(x_level_0)level_0_resized =F.interpolate(level_0_compressed, 4, mode='nearest')if self.dim[1] != self.dim[2]:level_1_compressed = self.compress_level_1(x_level_1)level_1_resized = F.interpolate(level_1_compressed, 2, mode='nearest')else:level_1_resized =F.interpolate(x_level_1, 2, mode='nearest')level_2_resized =x_level_2# 融合權重也是來自于網絡學習level_0_weight_v = self.weight_level_0(level_0_resized)level_1_weight_v = self.weight_level_1(level_1_resized)level_2_weight_v = self.weight_level_2(level_2_resized)levels_weight_v = torch.cat((level_0_weight_v, level_1_weight_v,level_2_weight_v),1)levels_weight = self.weight_levels(levels_weight_v)levels_weight = F.softmax(levels_weight, dim=1) # alpha產生# 自適應融合fused_out_reduced = level_0_resized * levels_weight[:,0:1,:,:]+\level_1_resized * levels_weight[:,1:2,:,:]+\level_2_resized * levels_weight[:,2:,:,:]out = self.expand(fused_out_reduced)return out

結語

本文盤點了近年來比較精巧而又實用的CNN插件,希望大家活學活用,用在自己的實際項目中。

◎作者檔案

皮特潘,致力于AI落地而上下求索

往期精彩回顧適合初學者入門人工智能的路線及資料下載(圖文+視頻)機器學習入門系列下載中國大學慕課《機器學習》(黃海廣主講)機器學習及深度學習筆記等資料打印《統計學習方法》的代碼復現專輯 AI基礎下載機器學習交流qq群955171419,加入微信群請掃碼:

總結

以上是生活随笔為你收集整理的【深度学习】真正的即插即用!盘点11种CNN网络设计中精巧通用的“小”插件...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。