当你在构建一个需要兼顾精度与效率的计算机视觉模型时,EfficientNet系列无疑会出现在你的候选名单中。这个由Google Research团队提出的模型家族,通过巧妙的复合缩放方法,在ImageNet数据集上实现了当时最佳的精度-效率平衡。但真正让EfficientNet脱颖而出的,是它那套可扩展的参数体系——width_coefficient和depth_coefficient。
EfficientNet的核心创新在于提出了**复合缩放(Compound Scaling)**方法。传统做法往往单独调整网络深度、宽度或输入分辨率,而EfficientNet则发现这三者之间存在微妙的平衡关系。
MBConv模块是EfficientNet的基础构建块,它包含以下几个关键组件:
复合缩放公式可以表示为:
code复制depth = α^φ
width = β^φ
resolution = γ^φ
其中α·β²·γ²≈2,φ是用户定义的缩放系数。
提示:当φ=1时,我们得到基准模型EfficientNet-B0;随着φ增大,模型规模按比例扩展。
宽度系数直接影响网络中每一层的通道数。在EfficientNet实现中,这个系数会与基础通道数相乘:
python复制def round_filters(filters, width_coefficient):
if not width_coefficient:
return filters
divisor = 8 # 常见设定
filters *= width_coefficient
new_filters = max(divisor, int(filters + divisor / 2) // divisor * divisor)
return new_filters
观察B0到B7的宽度系数变化:
| 模型变体 | 宽度系数 | 基础第一层通道 | 实际第一层通道 |
|---|---|---|---|
| B0 | 1.0 | 32 | 32 |
| B1 | 1.0 | 32 | 32 |
| B2 | 1.1 | 32 | 40 |
| B3 | 1.2 | 32 | 40 |
| B4 | 1.4 | 32 | 48 |
| B5 | 1.6 | 32 | 56 |
| B6 | 1.8 | 32 | 64 |
| B7 | 2.0 | 32 | 64 |
注:通道数会四舍五入到最接近的8的倍数,这是硬件友好的设计
深度系数控制着MBConv模块的重复次数。与宽度系数不同,它对网络结构的影响更为宏观:
python复制def round_repeats(repeats, depth_coefficient):
return int(math.ceil(depth_coefficient * repeats))
EfficientNet-B0中各阶段的MBConv重复次数为[1,2,2,3,3,4,1],当应用深度系数时:
实际应用中发现:深度系数不宜过大,否则容易导致梯度消失问题。EfficientNet通过渐进式增加深度和宽度,避免了这一陷阱。
当你需要为特定任务调整EfficientNet时,可以遵循以下步骤:
python复制# 示例:自定义缩放
def custom_scaling(base_model, width=1.2, depth=1.2):
# 克隆基础模型配置
config = base_model.config.copy()
# 应用宽度系数
for block in config.blocks:
block.input_filters = round_filters(block.input_filters, width)
block.output_filters = round_filters(block.output_filters, width)
# 应用深度系数
for block in config.blocks:
block.num_repeat = round_repeats(block.num_repeat, depth)
return EfficientNet(config)
注意:同时调整宽度和深度时,建议保持φ的平衡,避免单一维度过度增长。
在长期使用EfficientNet的过程中,我总结了一些实用经验:
内存不足时的解决方案:
训练小技巧:
一个真实案例:
在部署到移动设备时,发现B3模型推理速度不达标。通过以下调整实现了加速: