第288篇 经典骨干网络——ResNet与EfficientNet深度解析

发布时间:2026/8/29 7:19:08
第288篇 经典骨干网络——ResNet与EfficientNet深度解析 CNN基础讲完了这篇深入聊两个最重要的骨干网络ResNet和EfficientNet。骨干网络Backbone是特征提取的核心几乎所有视觉模型都建立在它之上。目标检测用ResNet做backbone语义分割用ResNet或EfficientNet做backbone实例分割Mask R-CNN也是ResNet。选对backbone模型就成功了一半。面试中经常问到ResNet为什么能训练那么深EfficientNet比ResNet好在哪里怎么选择合适的backbone这些问题回答好了说明你对CNN的理解不是停留在表面。一、ResNet残差学习的革命ResNet是2015年何恺明等人提出的一举拿下ImageNet冠军。核心贡献是残差连接skip connection让网络深度从十几层跳到152层还能正常训练。为什么深层网络难训练不是过拟合的问题深层网络训练误差也高而是梯度消失/爆炸。反向传播时梯度要经过很多层连乘如果每层梯度小于1连乘后趋近于0。网络越深前面的层越难收到有效的梯度信号。残差连接怎么解决的把输入x直接加到输出上output F(x) x。反向传播时梯度可以沿着skip connection直接传回去不用经过F(x)的层层变换。即使F(x)的梯度很小加上x的梯度恒为1总梯度不会消失。# ResNet基本块 class BasicBlock(nn.Module): def __init__(self, in_ch, out_ch, stride1): super().__init__() self.conv1 nn.Conv2d(in_ch, out_ch, 3, stride, 1) self.bn1 nn.BatchNorm2d(out_ch) self.conv2 nn.Conv2d(out_ch, out_ch, 3, 1, 1) self.bn2 nn.BatchNorm2d(out_ch) # 维度不匹配时用1x1卷积调整 self.shortcut nn.Sequential() if stride ! 1 or in_ch ! out_ch: self.shortcut nn.Sequential( nn.Conv2d(in_ch, out_ch, 1, stride), nn.BatchNorm2d(out_ch) ) def forward(self, x): out F.relu(self.bn1(self.conv1(x))) out self.bn2(self.conv2(out)) out self.shortcut(x) # 残差连接 return F.relu(out)Bottleneck结构ResNet-50/101/152用的不是BasicBlock而是Bottleneck。1x1卷积降维→3x3卷积→1x1卷积升维。比如256→64→64→256。中间的3x3卷积在64通道上做计算量大幅减少。这种设计让深层网络在保持表达能力的同时计算效率更高。ResNet的变体ResNet-18/34用BasicBlockResNet-50/101/152用Bottleneck。ResNeXt引入分组卷积提升性能。Wide ResNet加宽通道数在某些场景下更快。二、EfficientNetNAS搜索出的最优解EfficientNet是2019年Google提出的。思路很新颖——用神经架构搜索NAS找到最优的网络结构然后研究如何系统地缩放网络。核心发现网络的深度、宽度、输入分辨率三个维度都要均衡缩放。只增加深度网络更深会遇到瓶颈梯度问题。只增加宽度通道更多对深层特征提升有限。只增加分辨率计算量爆炸。三者要一起调。Compound Scaling用一个复合系数φ统一控制三个维度。depthα^φwidthβ^φresolutionγ^φ。α、β、γ通过小规模实验搜索确定。EfficientNet-B0到B7φ从0到7性能逐步提升。# MBConv模块EfficientNet的基本单元 # 1x1扩展 → 3x3深度卷积 → SE注意力 → 1x1压缩 class MBConv(nn.Module): def __init__(self, in_ch, out_ch, expand_ratio4): super().__init__() mid_ch in_ch * expand_ratio self.conv nn.Sequential( nn.Conv2d(in_ch, mid_ch, 1), # 扩展 nn.BatchNorm2d(mid_ch), nn.SiLU(), nn.Conv2d(mid_ch, mid_ch, 3, 1, 1, groupsmid_ch), # 深度卷积 nn.BatchNorm2d(mid_ch), nn.SiLU(), SEBlock(mid_ch), # 注意力 nn.Conv2d(mid_ch, out_ch, 1), # 压缩 nn.BatchNorm2d(out_ch), )SE注意力模块Squeeze-and-Excitation全局平均池化→全连接→全连接→sigmoid得到每个通道的权重。用这个权重重新校准通道特征——重要的通道权重大不重要的权重小。SE模块的计算量很小但能稳定提升精度。EfficientNetV22021年的改进版。主要改进是训练速度——用渐进式学习减少训练时间。用Fused MBConv替代小尺寸的MBConv提升在小特征图上的效率。三、如何选择Backbone实际项目中怎么选backbone主要看三个因素精度需求、速度需求、部署平台。精度优先ResNet-101/152或者EfficientNet-B5/B6/B7。参数量大、精度高适合对精度要求高但对速度不敏感的场景。速度优先MobileNetV3、ShuffleNetV2、EfficientNet-B0/B1。参数量小、推理快适合边缘部署。平衡选择ResNet-50或者EfficientNet-B3。精度和速度都比较均衡是大多数项目的默认选择。# 不同backbone的参数量和计算量对比 backbones { ResNet-18: {params: 11.7M, flops: 1.8G}, ResNet-50: {params: 25.6M, flops: 4.1G}, ResNet-101: {params: 44.5M, flops: 7.8G}, EfficientNet-B0: {params: 5.3M, flops: 0.4G}, EfficientNet-B3: {params: 12M, flops: 1.8G}, EfficientNet-B5: {params: 30M, flops: 10G}, }还有一个重要考量预训练权重。ResNet的ImageNet预训练权重到处都有迁移学习很方便。EfficientNet的预训练权重也有但生态不如ResNet完善。如果用国产推理平台要确认算子是否被支持。四、面试高频追问QResNet的skip connection在推理时还有用吗A有。skip connection不是只在训练时起作用。推理时outputF(x)xF(x)学到的残差函数加上恒等映射x最终输出就是两者之和。skip connection在推理时就是简单的加法操作计算量可以忽略。QEfficientNet的NAS搜索成本高吗A很高。原始论文搜索一次要几千GPU小时。但搜索一次就够了——结构可以复用。对于大多数团队来说直接用官方提供的结构就好不需要自己搜索。Q深度可分离卷积为什么能减少计算量A标准3x3卷积的计算量9in_chout_chHW。深度可分离卷积拆成两步深度卷积每个通道单独卷积9in_chHW逐点卷积1x1卷积in_chout_chHW。总计算量大约是标准卷积的1/8到1/9。代价是表达能力有所下降但在轻量化场景下性价比很高。ResNet和EfficientNet是当前最主流的两个骨干网络。ResNet的残差学习、EfficientNet的复合缩放和NAS搜索这两个思路深刻影响了后续的CNN设计。下一篇我们聊YOLO系列目标检测。经典骨干网络是视觉模型的基础。ResNet残差学习原理、EfficientNet复合缩放与NAS搜索、Backbone选择策略这三个维度覆盖了骨干网络的核心知识。上一篇第287篇 CNN卷积神经网络下一篇聊YOLO系列。如果这篇文章对你有帮助欢迎点赞支持一下你的鼓励是我持续更新的动力