mobilenetv2网络模型
时间: 2025-01-01 17:23:09 浏览: 7
### MobilenetV2 网络模型架构特点
#### 架构概述
MobileNetV2 是一种高效的卷积神经网络,专为移动设备设计,在保持较高精度的同时显著减少了计算量和参数数量。该网络引入了倒残差结构(Inverted Residuals) 和线性瓶颈(Linear Bottlenecks),使得模型更加轻量化并提高了性能[^1]。
#### 关键组件解析
##### 倒残差结构 (Inverted Residual Blocks)
传统残差单元通常采用先降维后升维的方式处理数据流;然而,MobileNetV2 中的倒残差块则采取相反策略——即先通过逐点卷积大幅增加通道数目(通常是输入通道数目的六倍),接着执行深度可分离卷积操作来减少空间维度而不改变通道数,最后再次利用逐点卷积降低至目标输出尺寸。这种设计不仅有助于缓解信息损失问题,还能够有效提升表达能力[^3]。
##### 深度可分离卷积 (Depthwise Separable Convolutions)
为了进一步优化效率,MobileNetV2 广泛采用了深度可分离卷积技术替代常规二维卷积层。具体来说,这种方法将标准卷积分解成两个独立步骤:首先是针对每个单独输入通道的应用小型滤波器进行局部感受野内的特征映射变换(depthwise convolution);其次是跨所有这些新生成的地图施加全连接权重矩阵完成最终融合过程(pointwise convolution)[^2]。
##### 膨胀因子与宽度乘子
在网络定义过程中引入了一个被称为膨胀因子(t) 的超参数用于控制中间扩展层大小,默认设置下会将原始输入扩大6倍作为临时工作空间。此外还有一个宽度乘子(widt_multiplier),它允许灵活调整整个网络规模从而适应不同硬件条件下的资源约束需求。
#### 实现示例
下面给出一段基于 PyTorch 框架实现 MobileNetV2 主干部分的核心代码片段:
```python
import torch.nn as nn
class ConvBNReLU(nn.Sequential):
def __init__(self, inp, oup, stride=1):
super(ConvBNReLU, self).__init__(
nn.Conv2d(inp, oup, 3, stride, 1, bias=False),
nn.BatchNorm2d(oup),
nn.ReLU6(inplace=True)
)
def _make_divisible(v, divisor, min_value=None):
"""
This function is taken from the original tf repo.
It ensures that all layers have a channel number that is divisible by 8
"""
if min_value is None:
min_value = divisor
new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
# Make sure that round down does not go down by more than 10%.
if new_v < 0.9 * v:
new_v += divisor
return new_v
class InvertedResidual(nn.Module):
def __init__(self, inp, oup, stride, expand_ratio):
super(InvertedResidual, self).__init__()
hidden_dim = int(round(inp * expand_ratio))
self.use_res_connect = stride == 1 and inp == oup
layers = []
if expand_ratio != 1:
# pw
layers.append(
ConvBNReLU(inp, hidden_dim, kernel_size=1))
layers.extend([
# dw
ConvBNReLU(hidden_dim, hidden_dim,
stride=stride, groups=hidden_dim),
# pw-linear
nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup),
])
self.conv = nn.Sequential(*layers)
def forward(self, x):
if self.use_res_connect:
return x + self.conv(x)
else:
return self.conv(x)
class MobileNetV2(nn.Module):
def __init__(self, num_classes=1000, width_mult=1.):
super(MobileNetV2, self).__init__()
block = InvertedResidual
input_channel = _make_divisible(32 * width_mult, 8)
last_channel = _make_divisible(1280 * width_mult, 8) if width_mult > 1.0 else 1280
inverted_residual_setting = [
# t, c, n, s
[1, 16, 1, 1],
[6, 24, 2, 2],
[6, 32, 3, 2],
[6, 64, 4, 2],
[6, 96, 3, 1],
[6, 160, 3, 2],
[6, 320, 1, 1],
]
features = [ConvBNReLU(3, input_channel, stride=2)]
for t, c, n, s in inverted_residual_setting:
output_channel = _make_divisible(c * width_mult, 8)
for i in range(n):
stride = s if i == 0 else 1
features.append(block(input_channel, output_channel, stride, expand_ratio=t))
input_channel = output_channel
features.append(ConvBNReLU(input_channel, last_channel, kernel_size=1))
self.features = nn.Sequential(*features)
self.classifier = nn.Linear(last_channel, num_classes)
def forward(self, x):
x = self.features(x)
x = x.mean([2, 3]) # global average pooling
x = self.classifier(x)
return x
```
阅读全文