3. MobileNetV3回顾

聊到MobileNetV3,我得先说说自己的感受。当年我在做一款实时视频分析App时,模型体积和推理速度卡得死死的。试过MobileNetV1,精度差点意思;试过V2,结构又有点复杂。直到V3出来,我才觉得——嗯,这才是移动端部署该有的样子。

MobileNetV3其实不是凭空冒出来的。它把V1的深度可分离卷积、V2的线性瓶颈和倒残差结构,再加上SE模块和h-swish激活函数,揉在一起做了个「缝合怪」。但你别小看这个缝合,它缝合得很有水平。

核心思路:用NAS(神经架构搜索)找到最优结构,再用NetAdapt算法微调每一层的通道数。说白了,就是让机器帮我们设计网络,然后人工再调一调。

3.1 深度可分离卷积:轻量化的基石

深度可分离卷积,我习惯叫它「拆开干活」。标准卷积是一次性完成空间和通道的混合,而深度可分离卷积把它拆成两步:

  1. 深度卷积(Depthwise Conv):每个通道单独做空间卷积
  2. 逐点卷积(Pointwise Conv):用1x1卷积混合通道信息

你想想看,标准卷积的计算量是:K × K × C_in × C_out × H × W。而深度可分离卷积是:K × K × C_in × H × W + C_in × C_out × H × W。比例大约是:

计算量比 = (K² × C_in + C_in × C_out) / (K² × C_in × C_out)
         = 1/C_out + 1/K²

当K=3时,计算量直接降到原来的1/8到1/9。我在项目中实测过,替换标准卷积后,模型推理速度提升了将近7倍,精度只掉了不到1%。

我的经验:深度可分离卷积在通道数较少时效果不明显。建议在通道数大于64的层使用,收益才大。

3.2 SE模块:注意力机制的精简版

SE模块全称是Squeeze-and-Excitation,说白了就是让网络学会「关注什么、忽略什么」。它分两步:

  • Squeeze(压缩):全局平均池化,把每个通道压缩成一个数值
  • Excitation(激励):两个全连接层,学习通道间的依赖关系,输出0~1的权重

MobileNetV3用的SE模块做了精简:把两个全连接层的中间维度设为输入通道数的1/4。我刚开始觉得这玩意儿会增加计算量,后来发现——其实它只增加了2%~3%的FLOPs,但能提升3%~5%的精度。这笔账,划算。

# 伪代码,展示SE模块的核心逻辑
def se_block(x, reduction=4):
    # x shape: [B, C, H, W]
    # Squeeze
    squeezed = global_avg_pool(x)  # [B, C, 1, 1]
    # Excitation
    fc1 = linear(squeezed, C // reduction)  # 降维
    fc1 = relu(fc1)
    fc2 = linear(fc1, C)  # 恢复维度
    scale = sigmoid(fc2)  # 0~1权重
    # Scale
    return x * scale

避坑指南:我曾经在某个项目中把SE模块加到了所有层,结果模型反而过拟合了。建议只在深度较大的层(比如stride=1的bottleneck)使用SE,浅层加SE收益不大。

3.3 h-swish激活函数:又快又好

swish激活函数大家都知道:f(x) = x × sigmoid(x)。效果好,但sigmoid计算太慢,尤其在移动端。h-swish就是swish的「硬核版本」:

h-swish(x) = x × ReLU6(x + 3) / 6

为什么叫「硬」?因为它用ReLU6代替了sigmoid。ReLU6计算起来就是一次比较和一次乘法,比sigmoid的指数运算快太多了。我在骁龙855上测过,h-swish比swish快了将近3倍。

不过要注意,h-swish只在较深的层使用。MobileNetV3的设计是:前1/3的层用ReLU,中间1/3用h-swish,最后1/3也用h-swish。为什么?因为浅层特征图尺寸大,h-swish的ReLU6操作会带来额外的内存开销。

关键对比:

激活函数 计算量 精度 移动端速度
ReLU 低 一般 快
swish 高 高 慢
h-swish 中 接近swish 快

3.4 三者的协同工作

这三个组件不是孤立的。我画了张图,帮你理清它们的关系:

MobileNetV3 核心组件协同图 输入特征图 深度可分离卷积 (空间+通道分离) SE模块 (通道注意力) h-swish激活 (硬版本swish) 输出特征图 深度可分离卷积负责空间特征提取,SE模块调整通道权重,h-swish提供非线性

你看这张图,流程很清晰:输入先经过深度可分离卷积提取空间特征,然后分两路——一路走SE模块做通道注意力,另一路走h-swish做非线性变换。最后合并输出。这就是MobileNetV3中一个bottleneck block的典型结构。

我个人觉得,MobileNetV3最聪明的地方不是某个单一创新,而是把这三个组件组合得恰到好处。深度可分离卷积省计算量,SE模块补精度,h-swish保速度。三者缺一不可。

实战建议:如果你要在自己的模型里用这些组件,我建议先从深度可分离卷积开始替换,效果最明显。SE模块加在中间层就好,别贪多。h-swish只在最后几层用,前面用ReLU就够了。

好了,MobileNetV3的核心组件就这些。下一章我们会动手搭建一个完整的MobileNetV3网络,到时候你会看到这些组件是怎么拼在一起的。

可可精品资料库