一、SENet
論文地址:Squeeze-and-Excitation Networks [CVPR2017]
Caffe代碼地址:SENet-Caffe
Pytorch代碼地址:SENet-Pytorch
1. 設(shè)計(jì)原理
??論文中提到,在SENet提出之前,大部分工作專注于研究特征圖的空間編碼質(zhì)量(可以理解為每個(gè)通道的特征圖的特征提取質(zhì)量),即只關(guān)注每個(gè)通道中特征圖的表達(dá)能力,而沒(méi)有關(guān)注不同通道的特征圖的融合(如果一個(gè)特征圖的維度為 C × H × W C×H×W C×H×W的話,SENet之前的工作只關(guān)注了 H H H和 W W W維度,而沒(méi)有關(guān)注 C C C維度,不同通道的特征圖融合還是通過(guò)卷積相加的方式完成)。
??SENet關(guān)注了通道關(guān)系,提出了Squeeze-and-Excitation模塊,通過(guò)顯式地模擬通道之間的相互依賴關(guān)系,自適應(yīng)地重新校準(zhǔn)通道的特征響應(yīng)(普通卷積過(guò)程的通道關(guān)系本質(zhì)上是隱式的和局部的(除了最頂層的通道關(guān)系,因?yàn)樽铐攲拥耐ǖ琅c任務(wù)相關(guān),比如分割網(wǎng)絡(luò)的最頂層通道數(shù)為分割類別數(shù),而中間層的通道數(shù)通常是經(jīng)驗(yàn)所得))。
2. SE Block
??SE Block的結(jié)構(gòu)如圖1所示,首先通過(guò)卷積操作
F
t
r
F_{tr}
Ftr?將輸入特征圖
X
∈
R
H
′
×
W
′
×
C
′
X\in R^{H'\times W'\times C'}
X∈RH′×W′×C′映射到特征圖
U
∈
R
H
×
W
×
C
U\in R^{H\times W\times C}
U∈RH×W×C,在這個(gè)過(guò)程中,用
V
=
[
v
1
,
v
2
,
.
.
.
,
v
C
]
V=[v_{1},v_{2},...,v_{C}]
V=[v1?,v2?,...,vC?]表示卷積核的集合,輸出可表示為
U
=
[
u
1
,
u
2
,
.
.
.
,
u
C
]
U=[u_{1},u_{2},...,u_{C}]
U=[u1?,u2?,...,uC?],則:
u
c
=
v
c
?
X
=
∑
s
=
1
C
′
v
c
s
?
x
s
u_c=v_{c}*X=\sum_{s=1}^{C'}v_{c}^s*x^s
uc?=vc??X=s=1∑C′?vcs??xs
??這里 ? * ? 表示卷積操作, u c ∈ R H × W u_{c}\in R^{H\times W} uc?∈RH×W, v c = [ v c 1 , v c 2 , . . . , v c C ′ ] v_{c}=[v_{c}^1,v_{c}^2,...,v_{c}^{C'}] vc?=[vc1?,vc2?,...,vcC′?], X = [ x 1 , x 2 , . . . , x C ′ ] X=[x^{1},x^{2},...,x^{C'}] X=[x1,x2,...,xC′], v c s v_{c}^s vcs?是一個(gè)二維卷積核,表示 v c v_{c} vc?的單個(gè)通道作用于 X X X的相應(yīng)通道上。
2.1 Squeeze:Global Information Embedding
??為了考慮輸出特征圖中每個(gè)通道的信息,論文通過(guò)全局平均池化的方式,將全局空間信息壓縮到一個(gè)通道描述符 z c z_{c} zc?中:
z c = F s q ( u c ) = 1 H × W ∑ i = 1 H ∑ j = 1 W u c ( i , j ) z_{c}=F_{sq}(u_{c})=\frac{1}{H\times W}\sum_{i=1}^{H}\sum_{j=1}^{W}u_{c}(i,j) zc?=Fsq?(uc?)=H×W1?i=1∑H?j=1∑W?uc?(i,j)
2.2 Excitation:Adaptive Recalibration
??為了完全捕獲通道依賴關(guān)系,論文選擇使用一種簡(jiǎn)單的帶有Sigmoid激活的門控機(jī)制:
s = F e x ( z , W ) = σ ( g ( z , W ) ) = σ ( W 2 δ ( W 1 z ) ) s=F_{ex}(z,W)=\sigma (g(z,W))=\sigma (W_{2}\delta (W_{1}z)) s=Fex?(z,W)=σ(g(z,W))=σ(W2?δ(W1?z))
??其中, δ \delta δ為ReLU函數(shù), W 1 ∈ R C r × C W_{1}\in R^{\frac{C}{r}\times C} W1?∈RrC?×C, W 2 ∈ R C × C r W_{2}\in R^{C\times\frac{C}{r}} W2?∈RC×rC?。
??通過(guò)s重新縮放U,得到SE Block最后的輸出:
x ˉ c = F s c a l e ( u c , s c ) = s c u c \bar{x}_{c}=F_{scale}(u_{c},s_{c})=s_{c}u_{c} xˉc?=Fscale?(uc?,sc?)=sc?uc?
3. SE-Inception and SE-ResNet
??圖2為原文設(shè)計(jì)的SE-Inception模塊和SE-ResNet模塊,這是一個(gè)即插即用模塊。為了解決通道之間的依賴關(guān)系,作者使用全局平均池化操作來(lái)壓縮全局空間信息,這就是Sequeeze操作。為了利用在Sequeeze操作中聚合的信息,作者通過(guò)FC-ReLU-FC-Sigmoid操作來(lái)完全捕獲通道依賴性,這就是Excitation操作。
class SELayer(nn.Module):
def __init__(self, channel, reduction=16):
super(SELayer, self).__init__()
self.avg_pool = nn.AdaptiveAvgPool2d(1) #全局平均池化,輸入BCHW -> 輸出 B*C*1*1
self.fc = nn.Sequential(
nn.Linear(channel, channel // reduction, bias=False), #可以看到channel得被reduction整除,否則可能出問(wèn)題
nn.ReLU(inplace=True),
nn.Linear(channel // reduction, channel, bias=False),
nn.Sigmoid()
)
def forward(self, x):
b, c, _, _ = x.size()
y = self.avg_pool(x).view(b, c) #得到B*C*1*1,然后轉(zhuǎn)成B*C,才能送入到FC層中。
y = self.fc(y).view(b, c, 1, 1) #得到B*C的向量,C個(gè)值就表示C個(gè)通道的權(quán)重。把B*C變?yōu)锽*C*1*1是為了與四維的x運(yùn)算。
return x * y.expand_as(x) #先把B*C*1*1變成B*C*H*W大小,其中每個(gè)通道上的H*W個(gè)值都相等。*表示對(duì)應(yīng)位置相乘。
二、YOLOv5中添加SENet
1.修改common.py
??在models/common.py
中添加下列代碼
class SElayer(nn.Module):
def __init__(self, c1, c2, ratio=16):
super(SElayer, self).__init__()
#c*1*1
self.avgpool = nn.AdaptiveAvgPool2d(1)
self.l1 = nn.Linear(c1, c1 // ratio, bias=False)
self.relu = nn.ReLU(inplace=True)
self.l2 = nn.Linear(c1 // ratio, c1, bias=False)
self.sig = nn.Sigmoid()
def forward(self, x):
b, c, _, _ = x.size()
y = self.avgpool(x).view(b, c)
y = self.l1(y)
y = self.relu(y)
y = self.l2(y)
y = self.sig(y)
y = y.view(b, c, 1, 1)
return x * y.expand_as(x)
2.修改yolo.py
??在models/yolo.py
中的parse_model
函數(shù)中添加SElayer模塊
if m in [Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, DWConv, MixConv2d, Focus, CrossConv, BottleneckCSP,
C3, C3TR, ASPP, SElayer]:
c1, c2 = ch[f], args[0]
if c2 != no:
c2 = make_divisible(c2 * gw, 8)
args = [c1, c2, *args[1:]]
3.修改yolov5s.yaml
??在Backbone的倒數(shù)第二層添加SElayer,修改后的yolov5s.yaml
如下所示:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-455132.html
# parameters
nc: 20 # number of classes
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple
# anchors
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
# YOLOv5 backbone
backbone:
# [from, number, module, args]
[[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[-1, 3, C3, [128]],
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[-1, 9, C3, [256]],
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[-1, 9, C3, [512]],
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
[-1, 3, C3, [1024]],
[-1, 1, SElayer, [1024]],
[-1, 1, SPPF, [512, 512]], # 10
]
head:
[[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 6], 1, Concat, [1]], # cat backbone P4
[-1, 3, C3, [512, False]], # 14
[-1, 1, Conv, [256, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 4], 1, Concat, [1]], # cat backbone P3
[-1, 3, C3, [256, False]], # 18 (P3/8-small)
[-1, 1, Conv, [256, 3, 2]],
[[-1, 15], 1, Concat, [1]], # cat head P4
[-1, 3, C3, [512, False]], # 21 (P4/16-medium)
[-1, 1, Conv, [512, 3, 2]],
[[-1, 11], 1, Concat, [1]], # cat head P5
[-1, 3, C3, [1024, False]], # 24 (P5/32-large)
[[18, 21, 24], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
]
參考文章
SE-ResNet的實(shí)現(xiàn)
YOLOv5-6.1添加注意力機(jī)制(SE、CBAM、ECA、CA)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-455132.html
到了這里,關(guān)于YOLOv5中添加SE模塊詳解——原理+代碼的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!