基于paddlepaddle实现MobileNets_v1复现
基于paddlepaddle实现Mobilenet_v2复现
一、介绍
Mobilenet_v3与Mobile_v2的不同点如下:
对原本的Inverted_residual_block添加了Squeeze-and-Excite结构来提高精度,Inverted_residual_block+Squeeze-and-Excite结构,如图一。
添加h-swish激活函数,提高了准确率,而h-swish和h-sigmoid相比于swish和sigmoid减少了计算量,比较如图二,h-swish计算公式如下: h-swish[x] = x.
R
e
L
U
6
(
x
+
3
)
6
\frac{ReLU6(x+3)}{6}
6ReLU6(x+3)?
引入了Efficient Last Stage,可以在不损失计算精度的基础上减小计算量,结构如图三。
图一
图二
图三
二、整体网络架构
Large网络架构如图
Small网络架构如图
其中,input为进入网络的特征矩阵的大小,Operator含有kernel_size的大小信息。exp_size为在BottleNet模块中增加后的通道数,out为输出通道数,SE为是否有Squeeze-and-Excite结构,NL为激活函数种类,RE为ReLU6,HS为h-swish,s为stride,NBN表示无BatchNorm结构。
三、论文复现
1、导入工具包
import paddle
from paddle.nn import Conv2D, BatchNorm2D, ReLU6, Hardsigmoid, Hardswish, \
AdaptiveAvgPool2D
import paddle.nn.functional as F
2、建立基础的代码运行块
class ConvBNLayer(paddle.nn.Layer):
def __init__(self, inchannels, outchannels, stride, kernelsize = 3, groups = 1, NL = "RE"):
super(ConvBNLayer, self).__init__()
self.NL = NL
padding = (kernelsize - 1) // 2
self.conv = Conv2D(
in_channels=inchannels,
out_channels=outchannels,
kernel_size=kernelsize,
stride=stride,
padding=padding,
groups=groups
)
self.bn = BatchNorm2D(outchannels)
self.relu = ReLU6()
self.Hsh = Hardswish()
def forward(self, inputs):
x = self.conv(inputs)
x = self.bn(x)
if self.NL == "RE":
x = self.relu(x)
if self.NL == "HS":
x = self.Hsh(x)
return x
3、建立无SE的结构
class Bc_Block(paddle.nn.Layer):
def __init__(self, inchannels, outchannels, kernel_size, exp_size, stride, NL):
super(Bc_Block, self).__init__()
self.stride = stride
self.layer0 = ConvBNLayer(
inchannels=inchannels,
outchannels=exp_size,
kernelsize=1,
stride=1,
NL=NL
)
self.layer1 = ConvBNLayer(
inchannels=exp_size,
outchannels=exp_size,
kernelsize=3,
stride=stride,
groups=exp_size,
NL=NL
)
self.conv0 = Conv2D(
in_channels=exp_size,
out_channels=outchannels,
kernel_size=1
)
self.bn0 = BatchNorm2D(outchannels)
self.conv1 = Conv2D(
in_channels=inchannels,
out_channels=outchannels,
kernel_size=1
)
self.bn1 = BatchNorm2D(outchannels)
def forward(self, inputs):
y = inputs
x = self.layer0(inputs)
x = self.layer1(x)
x = self.conv0(x)
x = self.bn0(x)
if self.stride == 2:
return x
if self.stride == 1:
y = self.conv1(inputs)
y = self.bn1(y)
return x+y
4、建立有SE的结构
class SE_Block(paddle.nn.Layer):
def __init__(self, inchannels, outchannels, kernel_size, exp_size, stride, NL):
super(SE_Block, self).__init__()
self.stride = stride
self.layer0 = ConvBNLayer(
inchannels=inchannels,
outchannels=exp_size,
kernelsize=1,
stride=1,
NL=NL
)
self.layer1 = ConvBNLayer(
inchannels=exp_size,
outchannels=exp_size,
kernelsize=3,
stride=stride,
groups=exp_size,
NL=NL
)
self.pooling = AdaptiveAvgPool2D(output_size=(1, 1))
self.linear0 = Conv2D(in_channels=exp_size, out_channels=int(exp_size*0.25), kernel_size=1)
self.linear1 = Conv2D(in_channels=int(exp_size*0.25), out_channels=exp_size, kernel_size=1)
self.relu = ReLU6()
self.Hs = Hardsigmoid()
self.conv0 = Conv2D(
in_channels=exp_size,
out_channels=outchannels,
kernel_size=1
)
self.bn0 = BatchNorm2D(outchannels)
self.conv1 = Conv2D(
in_channels=inchannels,
out_channels=outchannels,
kernel_size=1
)
self.bn1 = BatchNorm2D(outchannels)
def forward(self, inputs):
y = inputs
x = self.layer0(inputs)
x = self.layer1(x)
z = self.pooling(x)
z = self.linear0(z)
z = self.relu(z)
z = self.linear1(z)
z = self.Hs(z)
x = x*z
x = self.conv0(x)
x = self.bn0(x)
if self.stride == 2:
return x
if self.stride == 1:
y = self.conv1(inputs)
y = self.bn1(y)
return x+y
5、建立分类头
class Classifier_Head(paddle.nn.Layer):
def __init__(self, in_channels, hidden_channel, num_channel):
super(Classifier_Head, self).__init__()
self.pooling = AdaptiveAvgPool2D(output_size=(1, 1))
self.conv0 = Conv2D(
in_channels=in_channels,
out_channels=hidden_channel,
kernel_size=1
)
self.HS = Hardswish()
self.conv1 = Conv2D(
in_channels=hidden_channel,
out_channels=num_channel,
kernel_size=1
)
def forward(self, inputs):
x = self.pooling(inputs)
x = self.conv0(x)
x = self.HS(x)
x = self.conv1(x)
x = paddle.squeeze(x)
x = F.softmax(x)
return x
6、搭建MobileNetV3_Large架构
class MobileNetV3_Large(paddle.nn.Layer):
def __init__(self, num_channel):
super(MobileNetV3_Large, self).__init__()
block_setting=[
[3, 16, 16, False, "HS", 1],
[3, 64, 24, False, "RE", 2],
[3, 72, 24, False, "RE", 1],
[5, 72, 40, True, "RE", 2],
[5, 120, 40, True, "RE", 1],
[5, 120, 40, True, "RE", 1],
[3, 240, 80, False, "HS", 2],
[3, 200, 80, False, "HS", 1],
[3, 184, 80, False, "HS", 1],
[3, 184, 80, False, "HS", 1],
[3, 480, 112, True, "HS", 1],
[3, 672, 112, True, "HS", 1],
[5, 672, 160, True, "HS", 2],
[5, 960, 160, True, "HS", 1],
[2, 960, 160, True, "HS", 1]
]
self.feature = [
ConvBNLayer(
inchannels=3,
outchannels=16,
kernelsize=3,
stride=2,
NL="HS"
)
]
inchannels = 16
for k, exp_size, out, SE, NL, s in block_setting:
if SE:
self.feature.append(
SE_Block(
inchannels=inchannels,
outchannels=out,
kernel_size=k,
exp_size=exp_size,
stride=s,
NL=NL
)
)
inchannels=out
else:
self.feature.append(
Bc_Block(
inchannels=inchannels,
outchannels=out,
kernel_size=k,
exp_size=exp_size,
stride=s,
NL=NL
)
)
inchannels=out
self.feature.append(
ConvBNLayer(
inchannels=160,
outchannels=960,
kernelsize=1,
stride=1,
NL="HS"
)
)
self.head = Classifier_Head(
in_channels=960,
hidden_channel=1280,
num_channel=num_channel
)
def forward(self, x):
for layer in self.feature:
x = layer(x)
x = self.head(x)
return x
7、搭建MobileNetV3_Small架构
class MobileNetV3_Small(paddle.nn.Layer):
def __init__(self, num_channel):
super(MobileNetV3_Small, self).__init__()
block_setting=[
[3, 16, 16, True, "RE", 2],
[3, 72, 24, False, "RE", 2],
[3, 88, 24, False, "RE",1],
[5, 96, 40, True, "HS", 2],
[5, 240, 40, True, "HS", 1],
[5, 240, 40, True, "HS", 1],
[5, 120, 48, True, "HS", 1],
[5, 144, 48, True, "HS", 1],
[5, 288, 96, True, "HS", 2],
[5, 576, 96, True, "HS", 1],
[5, 576, 96, True, "HS", 1]
]
self.feature = [
ConvBNLayer(
inchannels=3,
outchannels=16,
kernelsize=3,
stride=2,
NL="HS"
)
]
inchannels = 16
for k, exp_size, out, SE, NL, s in block_setting:
if SE:
self.feature.append(
SE_Block(
inchannels=inchannels,
outchannels=out,
kernel_size=k,
exp_size=exp_size,
stride=s,
NL=NL
)
)
inchannels=out
else:
self.feature.append(
Bc_Block(
inchannels=inchannels,
outchannels=out,
kernel_size=k,
exp_size=exp_size,
stride=s,
NL=NL
)
)
inchannels=out
self.feature.append(
ConvBNLayer(
inchannels=96,
outchannels=576,
kernelsize=1,
stride=1,
NL="HS"
)
)
self.head = Classifier_Head(
in_channels=576,
hidden_channel=1024,
num_channel=num_channel
)
def forward(self, x):
for layer in self.feature:
x = layer(x)
x = self.head(x)
return x
四、查看网络结构
model = MobileNetV3_Small(num_channel=1000)
paddle.summary(model, (1, 3, 224, 224))
model = MobileNetV3_Large(num_channel=1000)
paddle.summary(model, (1, 3, 224, 224))
|