MobileNetV1原理
MobileNet V1是一种轻量级的卷积神经网络,能够在保持较高准确率的情况下具有较少的参数量和计算时间。它是由Google的研究人员在2017年提出的,并成为当时最流行的轻量级模型之一。
MobileNet V1的核心思想是通过深度分离卷积来减少模型的参数量和计算时间。与标准卷积不同,深度分离卷积将空间卷积和通道卷积分为两个独立的卷积层,这使得网络更加高效。具体来说,在深度分离卷积中,首先使用一个空间卷积,然后使用一个通道卷积来提取特征。这与标准卷积相比可以减少参数数量并加速运算。
MobileNet V1的网络结构如下:
MobileNet V1由序列卷积和1x1卷积两个部分组成。序列卷积包括13个深度可分离卷积层,每个层都包括一个3x3的卷积和一个批量归一化层(BN层),并且在卷积之后使用了ReLU6激活函数。最后,1x1卷积层用于生成最终的特征向量,并使用全局平均池化来缩小特征图的大小。在最后一层之后,使用一个全连接层来进行分类。MobileNet V1可以根据需要使用不同的输入分辨率,其超参数取决于输入分辨率和需要的精度。
为什么要设计MobileNet:
Mobilenetv1是一种轻量级的深度神经网络模型,设计的目的是在保持较高的精度的同时减小模型的大小和计算量,使其适合于移动设备的推理任务。在过去,大部分深度神经网络模型都是基于卷积神经网络(CNN)进行设计的,这些模型往往非常庞大(比如VGG16/VGG19),因此不能直接应用于手机或其他嵌入式设备上。同时,运行这些大型模型所需要的计算资源也很昂贵。
为了解决这个问题,Google Brain团队提出了Mobilenetv1。Mobilenetv1是基于深度可分离卷积(depthwise separable convolution)的设计,它将标准的卷积层分成深度卷积层和逐点卷积层两个部分,用较少的参数和计算量达到了相当不错的准确率。具体来说,深度卷积层用于在每个通道上执行空间卷积,而逐点卷积层(Pointwise Convolution)用于在不同通道之间执行线性变换。这种设计可以减少计算量和模型大小,并使得Mobilenetv1在移动设备上能够运行得更快。
除此之外,Mobilenetv1还使用了其他一些技巧来进一步缩小模型。例如,通过扩张系数(expansion factor)来控制输出通道数和输入通道数之间的关系,从而精细控制模型的大小和复杂度;通过残差连接(Residual Connection)来提高信息流动,从而提高模型的准确性和训练速度。
综合来说,Mobilenetv1是一种非常出色的深度神经网络模型,它在保持较高精确度的同时,大大减小了模型大小和计算量,使得它更容易嵌入到移动和嵌入式设备中。
MobileNetV1的主要特点如下:
轻量级:MobileNetv1的模型参数量非常少,只有4.2M,比起其他深度神经网络模型如VGG16、ResNet等模型,模型大小大大减小,更适合移动设备等资源受限环境下进行应用。
深度可分离卷积:MobileNetv1主要使用了深度可分离卷积,即将标准卷积分解成一个深度卷积和一个逐点卷积两个部分,分离后分别进行卷积操作,可以大大减少计算量和参数数量,从而实现轻量化的目的。
使用卷积核大小为1x1的卷积层和全局平均池化层:MobileNetv1使用了大量的1x1卷积层和全局平均池化层来代替传统的卷积层,可以减少特征图的空间尺寸,从而减少计算量和参数数量。
加入线性层和ReLU6激活函数:为了减少梯度消失的现象,MobileNetv1在每个深度可分离卷积结构后加入一个线性层和ReLU6激活函数,同时提高模型的非线性能力。
高性能:MobileNetv1在性能表现方面也做得很好,准确率达到了当时的state-of-the-art水平,同时模型具有高效率的特点,能够在较短的时间内完成较为复杂的任务。
MobileNetV1的创新点:
Depthwise Separable Convolution(深度可分离卷积)
MobileNetV1使用Depthwise Separable Convolution代替了传统的卷积操作。Depthwise Separable Convolution分为两个步骤,首先进行深度卷积,然后进行点卷积。深度卷积可以在每个输入通道上进行滤波操作,而点卷积使用1×1卷积来对每个通道进行线性组合。这样可以减少运算量以及减小模型的大小,同时也可以提高模型的精度和鲁棒性。
2. Width Multiplier(宽度乘法参数)
MobileNetV1引入了width multiplier的概念,可以通过调整宽度乘数来控制模型的大小和计算量。宽度乘数是作用于每一层的通道数目,可以取0到1的任意值。当宽度乘数为1时,模型与原始模型一致,而当宽度乘数小于1时,模型会变得更轻巧。
3. Global Depthwise Pooling(全局深度池化)
MobileNetV1使用Global Depthwise Pooling代替了全连接层。全局深度池化是在每个通道上进行求和操作,并将结果作为输出。这样可以有效地减少模型的参数量和计算量,提高模型的速度和精度。
总的来说,MobileNetV1在模型轻量化方面具有显著的创新,可以在计算资源有限的设备上进行高效的推理操作,成为了移动设备上的高效神经网络模型。
MobileNetV1源码(torch版)
数据集运行代码时自动下载,如果网络比较慢,可以自行点击我分享的链接下载cifar数据集。
链接:https://pan.baidu.com/s/1kfF4WxfpXr4a-GnEugh3AA?pwd=kd9a%C2%A0#list/path=%2F
提取码:kd9a
# -*- coding: utf-8 -*-
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
from torchvision.datasets import CIFAR10
from torchvision.transforms import transforms
from torch.autograd import Variable
class DepthwiseSeparableConv(nn.Module):
def __init__(self, in_channels, out_channels):
super(DepthwiseSeparableConv, self).__init__()
self.depthwise_conv = nn.Conv2d(in_channels, in_channels, kernel_size=3, padding=1, groups=in_channels)
self.pointwise_conv = nn.Conv2d(in_channels, out_channels, kernel_size=1)
self.relu = nn.ReLU(inplace=True)
def forward(self, x):
x = self.depthwise_conv(x)
x = self.pointwise_conv(x)
x = self.relu(x)
return x
class MobileNetV1(nn.Module):
def __init__(self, num_classes=1000):
super(MobileNetV1, self).__init__()
self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=2, padding=1)
self.relu = nn.ReLU(inplace=True)
self.dw_separable_conv1 = DepthwiseSeparableConv(32, 64)
self.dw_separable_conv2 = DepthwiseSeparableConv(64, 128)
self.dw_separable_conv3 = DepthwiseSeparableConv(128, 128)
self.dw_separable_conv4 = DepthwiseSeparableConv(128, 256)
self.dw_separable_conv5 = DepthwiseSeparableConv(256, 256)
self.dw_separable_conv6 = DepthwiseSeparableConv(256, 512)
self.dw_separable_conv7 = DepthwiseSeparableConv(512, 512)
self.dw_separable_conv8 = DepthwiseSeparableConv(512, 512)
self.dw_separable_conv9 = DepthwiseSeparableConv(512, 512)
self.dw_separable_conv10 = DepthwiseSeparableConv(512, 512)
self.dw_separable_conv11 = DepthwiseSeparableConv(512, 512)
self.dw_separable_conv12 = DepthwiseSeparableConv(512, 1024)
self.dw_separable_conv13 = DepthwiseSeparableConv(1024, 1024)
self.avg_pool = nn.AdaptiveAvgPool2d((1, 1))
self.fc = nn.Linear(1024, num_classes)
def forward(self, x):
x = self.conv1(x)
x = self.relu(x)
x = self.dw_separable_conv1(x)
x = self.dw_separable_conv2(x)
x = self.dw_separable_conv3(x)
x = self.dw_separable_conv4(x)
x = self.dw_separable_conv5(x)
x = self.dw_separable_conv6(x)
x = self.dw_separable_conv7(x)
x = self.dw_separable_conv8(x)
x = self.dw_separable_conv9(x)
x = self.dw_separable_conv10(x)
x = self.dw_separable_conv11(x)
x = self.dw_separable_conv12(x)
x = self.dw_separable_conv13(x)
x = self.avg_pool(x)
x = torch.flatten(x, 1)
x = self.fc(x)
return x
def main():
train_data = CIFAR10('cifar',train=True,transform = transforms.ToTensor())
data = DataLoader(train_data,batch_size=128,shuffle=True)
device = torch.device("cuda")
net = MobileNetV1(num_classes=10).to(device)
print(net)
cross = nn.CrossEntropyLoss().to(device)
optimizer = torch.optim.Adam(net.parameters(),0.001)
for epoch in range(10):
for img,label in data:
img = Variable(img).to(device)
label = Variable(label).to(device)
output = net.forward(img)
loss = cross(output,label)
loss.backward()
optimizer.zero_grad()
optimizer.step()
pre = torch.argmax(output,1)
num = (pre == label).sum().item()
acc = num / img.shape[0]
print("epoch:",epoch + 1)
print("loss:",loss.item())
print("acc:",acc)
pass
if __name__ == '__main__':
main()
上述代码中,我使用的是CIFAR-10数据集,通过训练MobileNet V1对图像进行分类。在训练过程中,我使用Adam优化器和交叉熵损失函数,并在训练后使用验证集评估模型的性能。
其中,模型中使用了Depthwise Separable Convolution,它包含一层深度卷积和一层1x1卷积。深度卷积用于处理输入数据的不同通道,1x1卷积用于将不同通道的特征图合并成更多的通道。这个操作可以有效地减少参数数量和计算量,并提高模型的性能。
另外,模型还使用了AdaptiveAvgPool2d,该层可以自适应地将输入特征图的大小调整为任意大小,并对每个子区域进行平均池化操作。这可以使模型对输入图像的尺寸具有更强的鲁棒性。
通过MobileNet V1,我们可以在保持较高精度的同时具有较少的参数量和计算时间,在计算资源受限的情况下尤其有用。
训练10个epoch的效果