?? 介紹
SE-Net 是 ImageNet 2017(ImageNet 收官賽)的冠軍模型,是由WMW團隊發(fā)布。具有復雜度低,參數少和計算量小的優(yōu)點。且SENet 思路很簡單,很容易擴展到已有網絡結構如 Inception 和 ResNet 中。
?? SE-Net注意力模塊
已經有很多工作在空間維度上來提升網絡的性能,如 Inception 等,而 SENet 將關注點放在了特征通道之間的關系上。其具體策略為:通過學習的方式來自動獲取到每個特征通道的重要程度,然后依照這個重要程度去提升有用的特征并抑制對當前任務用處不大的特征,這又叫做“特征重標定”策略。具體的 SE 模塊如下圖所示:
給定一個輸入
x
x
x ,其特征通道數為
c
1
c_1
c1?,通過一系列卷積等一般變換
F
t
r
F_{tr}
Ftr? 后得到一個特征通道數為
c
2
c_2
c2? 的特征。與傳統(tǒng)的卷積神經網絡不同,我們需要通過下面三個操作來重標定前面得到的特征。
- 首先是 Squeeze 操作,我們順著空間維度來進行特征壓縮,將一個通道中整個空間特征編碼為一個全局特征,這個實數某種程度上具有全局的感受野,并且輸出的通道數和輸入的特征通道數相等,例如將形狀為 (1, 32, 32, 10) 的 feature map 壓縮成 (1, 1, 1, 10)。此操作通常采用采用
global average pooling
來實現。 - 得到了全局描述特征后,我們進行 Excitation 操作來抓取特征通道之間的關系,它是一個類似于循環(huán)神經網絡中門的機制:
這里采用包含兩個全連接層的 bottleneck 結構,即中間小兩頭大的結構:其中第一個全連接層起到降維的作用,并通過 ReLU 激活,第二個全連接層用來將其恢復至原始的維度。進行 Excitation 操作的最終目的是為每個特征通道生成權重,即學習到的各個通道的激活值(sigmoid 激活,值在 0~1 之間)。 - 最后是一個 Scale 的操作,我們將 Excitation 的輸出的權重看做是經過特征選擇后的每個特征通道的重要性,然后通過乘法逐通道加權到先前的特征上,完成在通道維度上的對原始特征的重標定,從而使得模型對各個通道的特征更有辨別能力,這類似于attention機制。
?? SE-Net注意力模塊應用分析
SE模塊的靈活性在于它可以直接應用現有的網絡結構中。以 Inception 和 ResNet 為例,我們只需要在 Inception 模塊或 Residual 模塊后添加一個 SE 模塊即可。具體如下圖所示:
上圖分別是將 SE 模塊嵌入到 Inception 結構與 ResNet 中的示例,方框旁邊的維度信息代表該層的輸出,
r
r
r 表示 Excitation 操作中的降維系數。
?? SE-Net注意力模塊效果對比
SE 模塊很容易嵌入到其它網絡中,為了驗證 SE 模塊的作用,在其它流行網絡如 ResNet 和 Inception 中引入 SE 模塊,測試其在 ImageNet 上的效果,如下表所示:
首先看一下網絡的深度對 SE 的影響。上表分別展示了 ResNet-50、ResNet-101、ResNet-152 和嵌入 SE 模型的結果。第一欄 Original 是原作者實現的結果,為了進行公平的比較,重新進行了實驗得到 Our re-implementation 的結果。最后一欄 SE-module 是指嵌入了 SE 模塊的結果,它的訓練參數和第二欄 Our re-implementation 一致。括號中的紅色數值是指相對于 Our re-implementation 的精度提升的幅值。
從上表可以看出,SE-ResNets 在各種深度上都遠遠超過了其對應的沒有SE的結構版本的精度,這說明無論網絡的深度如何,SE模塊都能夠給網絡帶來性能上的增益。值得一提的是,SE-ResNet-50 可以達到和ResNet-101 一樣的精度;更甚,SE-ResNet-101 遠遠地超過了更深的ResNet-152。
上圖展示了ResNet-50 和 ResNet-152 以及它們對應的嵌入SE模塊的網絡在ImageNet上的訓練過程,可以明顯地看出加入了SE模塊的網絡收斂到更低的錯誤率上。
?? YOLOv5中插入SE-Net注意力模塊
1. 增加 SEAttention.yaml 文件
# Parameters
nc: 80 # number of classes
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # 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
# YOLOv5 v6.0 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, 6, 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, SPPF, [1024, 5]], # 9
]
# YOLOv5 v6.0 head
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]], # 13
[-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]], # 17 (P3/8-small)
[-1, 1, Conv, [256, 3, 2]],
[[-1, 14], 1, Concat, [1]], # cat head P4
[-1, 3, C3, [512, False]], # 20 (P4/16-medium)
[-1, 1, Conv, [512, 3, 2]],
[[-1, 10], 1, Concat, [1]], # cat head P5
[-1, 3, C3, [1024, False]], # 23 (P5/32-large)
[-1, 1, SEAttention, [1024]],
[[17, 20, 24], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
]
2. common.py配置
在./models/common.py
文件中增加以下模塊文章來源:http://www.zghlxwxcb.cn/news/detail-423640.html
import numpy as np
import torch
from torch import nn
from torch.nn import init
# https://arxiv.org/abs/1709.01507
class SEAttention(nn.Module):
def __init__(self, channel=512,reduction=16):
super().__init__()
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.fc = nn.Sequential(
nn.Linear(channel, channel // reduction, bias=False),
nn.ReLU(inplace=True),
nn.Linear(channel // reduction, channel, bias=False),
nn.Sigmoid()
)
def init_weights(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
init.kaiming_normal_(m.weight, mode='fan_out')
if m.bias is not None:
init.constant_(m.bias, 0)
elif isinstance(m, nn.BatchNorm2d):
init.constant_(m.weight, 1)
init.constant_(m.bias, 0)
elif isinstance(m, nn.Linear):
init.normal_(m.weight, std=0.001)
if m.bias is not None:
init.constant_(m.bias, 0)
def forward(self, x):
b, c, _, _ = x.size()
y = self.avg_pool(x).view(b, c)
y = self.fc(y).view(b, c, 1, 1)
return x * y.expand_as(x)
3. yolo.py配置
找到models/yolo.py
文件中parse_model()
函數的for i, (f, n, m, args) in enumerate(d['backbone'] + d['head'])
(258行上下)并其循環(huán)內添加如下代碼。文章來源地址http://www.zghlxwxcb.cn/news/detail-423640.html
elif m is SEAttention:
c1, c2 = ch[f], args[0]
if c2 != no:
c2 = make_divisible(c2 * gw, 8)
4. 訓練模型
python train.py --cfg yolov5_SEAttention.yaml
到了這里,關于YOLO算法改進指南【中階改進篇】:1.添加SE-Net注意力機制的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!