论文传送门:https://arxiv.org/pdf/1704.04861.pdf
MobileNet V1的目的:对图片进行特征提取,依据特征进行分类。
MobileNet V1的优点:轻量。
MobileNet V1的方法:使用深度可分离卷积(Depthwise Separable Convolution),减少模型参数量。深度可分离卷积由深度卷积(Depthwise Convolution)和逐点卷积(Pointwise Convolution)共同完成。
MobileNet V1的结构:主要由两部分构成:
①特征提取部分:由1个标准卷积块和13个深度可分离卷积块构成;
②分类部分:AvgPool+FC+Softmax。
import torch
import torch.nn as nn
def standard_conv_block(in_channel, out_channel, strid=1): # 定义Strandard convolutional layer with batchnorm and ReLU
return nn.Sequential(
nn.Conv2d(in_channel, out_channel, 3, strid, 1, bias=False), # conv
nn.BatchNorm2d(out_channel), # bn
nn.ReLU() # relu
)
def depthwise_separable_conv_block(in_channel, out_channel,
strid=1): # 定义Depthwise Separable convolutions with Depthwise and Pointwise layers followed by batchnorm and ReLU
return nn.Sequential(
nn.Conv2d(in_channel, in_channel, 3, strid, 1, groups=in_channel, bias=False),
# conv,使用与输入通道数相同组数的分组卷积实现Depthwise Convolution
nn.BatchNorm2d(in_channel), # bn
nn.ReLU(), # relu
nn.Conv2d(in_channel, out_channel, 1, 1, 0, bias=False), # 1x1conv,Pointwise Convolution
nn.BatchNorm2d(out_channel), # bn
nn.ReLU() # relu
)
class MobileNetV1(nn.Module): # 定义MobileNet结构
def __init__(self, num_classes=1000): # 初始化方法
super(MobileNetV1, self).__init__() # 继承初始化方法
self.num_classes = num_classes # 类别数量
self.feature = nn.Sequential( # 特征提取部分
standard_conv_block(3, 32, strid=2), # standard conv block,(n,3,224,224)-->(n,32,112,112)
depthwise_separable_conv_block(32, 64), # depthwise separable conv block,(n,32,112,112)-->(n,64,112,112)
depthwise_separable_conv_block(64, 128, strid=2),
# depthwise separable conv block,(n,64,112,112)-->(n,128,56,56)
depthwise_separable_conv_block(128, 128), # depthwise separable conv block,(n,128,56,56)-->(n,128,56,56)
depthwise_separable_conv_block(128, 256, strid=2),
# depthwise separable conv block,(n,128,56,56)-->(n,256,28,28)
depthwise_separable_conv_block(256, 256), # depthwise separable conv block,(n,256,28,28)-->(n,256,28,28)
depthwise_separable_conv_block(256, 512, strid=2),
# depthwise separable conv block,(n,256,28,28)-->(n,512,14,14)
depthwise_separable_conv_block(512, 512), # depthwise separable conv block,(n,512,14,14)-->(n,512,14,14)
depthwise_separable_conv_block(512, 512), # depthwise separable conv block,(n,512,14,14)-->(n,512,14,14)
depthwise_separable_conv_block(512, 512), # depthwise separable conv block,(n,512,14,14)-->(n,512,14,14)
depthwise_separable_conv_block(512, 512), # depthwise separable conv block,(n,512,14,14)-->(n,512,14,14)
depthwise_separable_conv_block(512, 512), # depthwise separable conv block,(n,512,14,14)-->(n,512,14,14)
depthwise_separable_conv_block(512, 1024, strid=2),
# depthwise separable conv block,(n,512,14,14)-->(n,1024,7,7)
depthwise_separable_conv_block(1024, 1024), # depthwise separable conv block,(n,1024,7,7)-->(n,1024,7,7)
nn.AdaptiveAvgPool2d(1) # avgpool,为方便后续转为特征向量,这里将avgpool放入特征提取部分,(n,1024,7,7)-->(n,1024,1,1)
)
self.fc = nn.Sequential( # 分类部分
nn.Linear(1024, self.num_classes), # linear,(n,1024)-->(n,num_classes)
nn.Softmax(dim=1) # softmax
)
def forward(self, x): # 前传函数
x = self.feature(x) # 特征提取,获得特征层,(n,1024,1,1)
x = torch.flatten(x, 1) # 将三维特征层压缩至一维特征向量,(n,1024,1,1)-->(n,1024)
return self.fc(x) # 分类,输出类别概率,(n,num_classes)