MobileNet V3 论文翻译地址:
MobileNet V3 论文翻译
h_sigmoid复现:common.py
class h_sigmoid(nn.Module): def __init__(self, inplace=True): super(h_sigmoid, self).__init__() self.relu = nn.ReLU6(inplace=inplace) def forward(self, x): return self.relu(x + 3) / 6h_swish复现:
common.py
至此已经实现了h_swish公式内容。
class h_swish(nn.Module):
def __init__(self, inplace=True):
super(h_swish, self).__init__()
self.sigmoid = h_sigmoid(inplace=inplace)
def forward(self, x):
y = self.sigmoid(x)
return x * y
网络结构复现
主体结构:
NL:使用的非线性层
HS:h-swish
RE:ReLU
NBN:没有批处理规范化
SE: squeeze-and-excite
第一行的意思:使用了h-swish的非线性层的3x3 conv2d,stride=2, out channels=16。复现代码:
class Conv3BN(nn.Module):
"""
This equals to
def conv_3x3_bn(inp, oup, stride):
return nn.Sequential(
nn.Conv2d(inp, oup, 3, stride, 1, bias=False),
nn.BatchNorm2d(oup),
h_swish()
)
"""
def __init__(self, inp, oup, stride):
super(Conv3BN, self).__init__()
self.conv = nn.Conv2d(inp, oup, 3, stride, 1, bias=False)
self.bn = nn.BatchNorm2d(oup)
self.act = h_swish()
def forward(self, x):
return self.act(self.bn(self.conv(x)))
def fuseforward(self, x):
return self.act(self.conv(x))
squeeze-and-excite
MobileNet v3 中 引用的Squeeze-and-Excite是怎么回事
AdaptiveAvgPool2d Linear ReLU Linear h_sigmoid
对应的 *** 作:
-
Squeeze(Fsq)
用AdaptiveAvgPool2d将H × W × C H的feature map压缩为1 × 1 × C
-
Excitation(Fex)
得到Squeeze的1 × 1 × C 的feature map后,使用FC全连接层,对每个通道的重要性进行预测,得到不同channel的重要性大小。有两个全连接,一个降维,一个恢复维度。
-
Scale
最后将学习到的各个channel的激活值(sigmoid激活,值0~1)乘以之前的feature map的对应channel上。
class SELayer(nn.Module):
def __init__(self, channel, reduction=4):
super(SELayer, self).__init__()
#用1x1的卷积
self.avg_pool = nn.AdaptiveAvgPool2d(1) #Squeeze,将H × W × C H的feature map压缩为1 × 1 × C
self.fc = nn.Sequential(
nn.Linear(channel, channel // reduction),
nn.ReLU(inplace=True),
nn.Linear(channel // reduction, channel),
h_sigmoid() # h_sigmoid,修改了x
) # 使用FC全连接层,对每个通道的重要性进行预测,得到不同channel的重要性大小
def forward(self, x):
# b=1,c=16,_=64,16个数据组成一行,一共64排数据。
b, c, _, _ = x.size() #返回x张量行数、列数、深度.
# Squeeze
y = self.avg_pool(x).view(b, c) #池化后的1 × 1 × C feature map重塑为 b*c 的张量
# Excitation 预测并重塑为 b*c*1*1张量
y = self.fc(y).view(b, c, 1, 1)
# Scale
return x * y
滤波器4维张量:
[height,width,input_channels,output_channels] //滤波器张量 [卷积核高度,卷积核宽度,图像通道数,卷积核个数] //第三维input_channels为input张量的第四维。
图像4维张量张量:
[batch_size,height,width, channels] //图像张量 [个数,高度,宽度,通道数]InvertedResidual
InvertedResidual(论文中是bneck)是MobileNetv2中提出的,stride=1和stride=2在走向是有差异的。
stride=1的时候:
1、point-wise升维 2、depth-wise提取特征 3、通过Linear的point-wise降维。 4、input与结果 相加(残差结构)
第一层bneck是支持relu6的3x3卷积,第二个箭头所指的bneck是支持hswish的5x5卷积。
整体结构如下所示,
即先利用1x1卷积进行升维度,再进行下面的 *** 作,并具有残差边:
在输入1x1卷积进行升维度后,进行3x3深度可分离卷积:
注意力机制调整每个通道的权重:
1x1卷积:
class InvertedResidual(nn.Module):
def __init__(self, inp, oup, hidden_dim, kernel_size, stride, use_se, use_hs):
super(InvertedResidual, self).__init__()
assert stride in [1, 2]
self.identity = stride == 1 and inp == oup
# 如果输入通道等于 隐藏层的维数,来一个dw
if inp == hidden_dim:
self.conv = nn.Sequential(
# dw Depth-wise
nn.Conv2d(hidden_dim, hidden_dim, kernel_size, stride, (kernel_size - 1) // 2, groups=hidden_dim,
bias=False),
nn.BatchNorm2d(hidden_dim),
h_swish() if use_hs else nn.ReLU(inplace=True),
# Squeeze-and-Excite
SELayer(hidden_dim) if use_se else nn.Sequential(),
# pw-linear
nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup),
)
else:
self.conv = nn.Sequential(
# pw Point-wise 1x1
nn.Conv2d(inp, hidden_dim, 1, 1, 0, bias=False),
nn.BatchNorm2d(hidden_dim),
h_swish() if use_hs else nn.ReLU(inplace=True),
# dw Depth-wise
nn.Conv2d(hidden_dim, hidden_dim, kernel_size, stride, (kernel_size - 1) // 2, groups=hidden_dim,
bias=False),
nn.BatchNorm2d(hidden_dim),
# Squeeze-and-Excite
SELayer(hidden_dim) if use_se else nn.Sequential(),
h_swish() if use_hs else nn.ReLU(inplace=True),
# pw-linear
nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup),
)
def forward(self, x):
y = self.conv(x)
# stride=1时,输入加输出
if self.identity:
return x + y
else:
return y
yaml定义:
依次是传入上面函数的[ oup, hidden_dim(exp size), kernel_size, stride, use_se, use_hs ]
# YOLOv5 backbone
backbone:
# MobileNetV3-small
# [from, number, module, args]
[[-1, 1, Conv3BN, [16, 2]], # 0-p1/2
[-1, 1, InvertedResidual, [16, 16, 3, 2, 1, 0]], # 1-p2/4
[-1, 1, InvertedResidual, [24, 72, 3, 2, 0, 0]], # 2-p3/8
[-1, 1, InvertedResidual, [24, 88, 3, 1, 0, 0]], # 3-p3/8
[-1, 1, InvertedResidual, [40, 96, 5, 2, 1, 1]], # 4-p4/16
[-1, 1, InvertedResidual, [40, 240, 5, 1, 1, 1]], # 5-p4/16
[-1, 1, InvertedResidual, [40, 240, 5, 1, 1, 1]], # 6-p4/16
[-1, 1, InvertedResidual, [48, 120, 5, 1, 1, 1]], # 7-p4/16
[-1, 1, InvertedResidual, [48, 144, 5, 1, 1, 1]], # 8-p4/16
[-1, 1, InvertedResidual, [96, 288, 5, 2, 1, 1]], # 9-p5/32
[-1, 1, InvertedResidual, [96, 576, 5, 1, 1, 1]], # 10-p5/32
[-1, 1, InvertedResidual, [96, 576, 5, 1, 1, 1]], # 11-p5/32
]
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)