ResNet 是深度学习、卷积神经网络、计算机视觉和人工智能模型结构中非常经典的一个术语全称是 Residual Network通常翻译为“残差网络”。它用来描述一种通过“残差连接”训练深层神经网络的结构。换句话说ResNet 是在回答神经网络变得很深之后怎样让信息和梯度更顺畅地传递从而避免训练困难。如果说普通卷积神经网络是把一层一层计算结果顺序传下去那么 ResNet 的关键思想是不仅让网络学习新的变换还允许输入信息直接跨层传递。这样网络不必每一层都从零学习完整映射而是学习“在原有信息基础上需要补充或修正什么”。因此ResNet 常用于图像分类、目标检测、图像分割、特征提取、医学影像分析、迁移学习和各种视觉模型中是理解深层卷积神经网络和残差学习的重要基础概念。一、基本概念什么是 ResNetResNet 是一种以残差块为核心构建的深层卷积神经网络。普通神经网络通常按顺序计算输入 x → 卷积层 → 激活函数 → 卷积层 → 输出如果网络层数较少这种结构通常可以正常训练。但当网络变得很深时训练会变得困难。即使理论上更深的网络表达能力更强实际训练中也可能出现训练误差不降反升的问题。ResNet 的核心做法是在若干层卷积计算之外额外增加一条“捷径连接”或“跳跃连接”让输入 x 可以直接加到后面的输出上。一个基本残差块可以写为其中• x 表示输入特征• F(x) 表示若干卷积层学习到的残差映射• y 表示残差块输出• 表示逐元素相加从通俗角度看普通网络让每个模块直接学习“最终应该输出什么”。ResNet 让模块学习“相对于输入还需要改什么”。这就是“残差”的含义。例如如果某个模块输入已经足够好那么这个模块只需要学习接近 0 的残差此时输出近似为也就是说网络可以比较容易地保留原有信息而不必强迫每一层都做复杂变换。二、为什么需要 ResNetResNet 之所以重要是因为深度神经网络在变深时会遇到训练困难。直观上看网络越深应该越强。因为更深的网络可以组合更多层特征从边缘、纹理到局部结构再到高级语义逐步形成更复杂的表达能力。但是实际训练中并不是简单地“层数越多越好”。当网络很深时可能出现• 梯度传播困难• 参数更新不稳定• 训练误差下降缓慢• 深层网络反而比浅层网络表现差• 信息在多层变换中逐渐丢失这类问题常被称为深层网络的退化问题。这里的“退化”不是指过拟合而是指更深的网络在训练集上也没有比浅层网络更好甚至训练误差更高。这说明问题不只是泛化能力而是优化本身变难了。ResNet 的残差连接可以缓解这个问题。它让信息可以跨过若干层直接传递也让梯度在反向传播时有更短的路径回到前面层。从通俗角度看普通深层网络像一条很长的传话链每一层都要重新加工信息传到后面可能变形或变弱。ResNet 则给信息开了一条“直达通道”让重要信息可以直接传过去。因此ResNet 的核心价值是• 让深层网络更容易训练• 缓解深层网络退化问题• 改善梯度传播• 允许网络学习残差而不是完整映射• 支持构建更深的卷积神经网络三、残差学习的核心思想ResNet 的关键不是简单“多连一条线”而是残差学习。假设一个网络模块原本希望学习某个目标映射普通网络会直接学习ResNet 则把这个目标改写为因此其中• H(x) 表示理想的目标映射• x 表示输入• F(x) 表示残差映射• H(x) − x 表示目标输出与输入之间的差异也就是说ResNet 让网络学习的不是完整目标 H(x)而是输入与目标之间的差值 F(x)。从通俗角度看如果输入已经接近目标网络只需要学习很小的修正。例如• 原始输入已经比较接近正确特征• 残差分支只补充需要改变的部分• 最终输出原始输入 修正量这类似于修改文章。普通网络像是要求每一层都重新写一篇文章。ResNet 更像是要求每一层只标出“需要改哪里”。如果不需要修改就让原文直接通过。因此残差学习降低了深层网络的优化难度。四、残差块ResNet 的基本单元ResNet 不是只在整个网络末尾加一次残差连接而是把网络拆成许多残差块。一个典型残差块包含两部分• 主分支若干卷积层、归一化层批量归一化BN和激活函数• 捷径分支把输入直接传到输出处图 1ResNet 的残差连接与残差块在数学上可以写为其中• F(x; W) 表示主分支中的卷积变换• W 表示主分支中的可学习参数• x 表示捷径分支传来的输入• y 表示相加后的输出如果输入和输出形状相同可以直接相加。如果输入和输出形状不同例如通道数变化或空间尺寸变化就需要在捷径分支中使用 1 × 1 卷积进行匹配其中• W_s 表示捷径分支上的投影变换• W_s x 用来调整 x 的通道数或空间尺寸从通俗角度看如果输入和输出“尺寸一样”可以直接走捷径。如果尺寸不一样就需要先通过 1 × 1 卷积把它们调整到可相加的形状。五、残差连接为什么有用残差连接有用主要体现在两个方面• 前向传播中保留信息• 反向传播中改善梯度流动1、前向传播信息更容易保留在普通网络中输入信息必须经过层层变换。如果某些层没有学好信息可能被破坏。在 ResNet 中输入 x 可以通过捷径分支直接传到输出如果主分支暂时没有学到有用变换至少 x 仍然可以保留下来。从通俗角度看残差连接让网络可以“保底”。即使某些层暂时学得不好也不至于完全阻断信息。2、反向传播梯度更容易传回前面层训练神经网络需要通过反向传播更新参数。如果网络很深梯度可能在层层传递中变得很小。残差连接为梯度提供了更直接的路径。从数学直觉上看如果那么 y 对 x 的变化不仅来自 F(x)还包含一条直接路径。这使得梯度可以更顺畅地传回前面的层。从通俗角度看普通深层网络像必须经过很多关卡才能传回反馈。ResNet 增加了捷径通道让反馈可以更快回到前面层。因此ResNet 能够训练非常深的网络例如几十层、上百层甚至更深的变体。六、ResNet 的整体结构ResNet 的整体结构通常由多个残差块堆叠而成。图 2ResNet 的整体结构与常见版本一个典型 ResNet 可以概括为输入图像↓初始卷积层↓多个残差阶段↓全局平均池化↓全连接层↓分类输出其中多个残差阶段通常会逐步降低空间分辨率、增加通道数。例如224 × 224 × 3↓112 × 112 × 64↓56 × 56 × 64↓28 × 28 × 128↓14 × 14 × 256↓7 × 7 × 512↓类别预测从通俗角度看ResNet 前面层学习边缘、纹理等低级特征中间层学习局部结构后面层学习对象部件和高级语义。残差块贯穿这些阶段使深层特征学习更加稳定。常见 ResNet 版本包括• ResNet-18• ResNet-34• ResNet-50• ResNet-101• ResNet-152数字通常表示网络大致层数。例如ResNet-50 表示约 50 层的 ResNet 结构。需要注意不同版本中的残差块设计可能不同。较浅的 ResNet 常使用 basic block较深的 ResNet 常使用 bottleneck block。七、Basic Block 与 Bottleneck BlockResNet 中常见两类残差块• Basic Block• Bottleneck Block1、Basic BlockBasic Block 通常用于较浅的 ResNet例如 ResNet-18、ResNet-34。它的主分支通常包含两个 3 × 3 卷积3 × 3 卷积 → BN → ReLU → 3 × 3 卷积 → BN然后与捷径分支相加再经过 ReLU。从通俗角度看Basic Block 结构直接适合较浅网络。2、Bottleneck BlockBottleneck Block 通常用于较深的 ResNet例如 ResNet-50、ResNet-101、ResNet-152。它的主分支通常包含1 × 1 卷积 → 3 × 3 卷积 → 1 × 1 卷积其中• 第一个 1 × 1 卷积用于降维• 中间 3 × 3 卷积用于空间特征提取• 最后一个 1 × 1 卷积用于升维从通俗角度看Bottleneck Block 像是先把通道压缩再做主要计算最后恢复通道数。这样可以减少计算量使更深的网络更容易训练。可以概括为• Basic Block结构简单常用于 ResNet-18 / 34• Bottleneck Block先降维再升维常用于 ResNet-50 / 101 / 152八、ResNet 的常见应用场景ResNet 最初主要用于图像分类但后来被广泛用作计算机视觉基础骨干网络。1、图像分类ResNet 可以直接用于图像分类任务。例如输入图片 → ResNet → 类别概率它可以判断图像属于猫、狗、汽车、飞机等类别。由于 ResNet 能训练较深网络因此可以提取更强的图像特征。2、目标检测在目标检测中ResNet 常作为 backbone用于提取图像特征。例如输入图像 → ResNet 特征提取 → 检测头 → 边界框 类别目标检测模型通常不会只用 ResNet 的最终分类输出而是使用其中间特征图。3、图像分割在语义分割、医学图像分割中ResNet 也常作为编码器。例如输入图像 → ResNet 编码器 → 解码器 → 像素级预测这类结构可以利用 ResNet 提取语义特征再通过解码器恢复空间分辨率。4、迁移学习ResNet 常用于迁移学习。先使用在大规模图像数据上预训练好的 ResNet再把它迁移到自己的任务中。例如• 冻结前面层只训练分类头• 微调整个网络• 使用 ResNet 提取图像特征从通俗角度看预训练 ResNet 像一个已经学过大量图像知识的视觉特征提取器。在新任务中它不必从零开始学习边缘、纹理和形状。九、ResNet 的优势、局限与使用注意事项1、ResNet 的主要优势ResNet 最大的优势是让深层网络更容易训练。它通过残差连接改善信息和梯度传播缓解深层网络退化问题。其次ResNet 是非常通用的视觉骨干网络。它可以用于分类、检测、分割、检索、医学影像等任务。再次ResNet 适合迁移学习。许多深度学习框架都提供预训练 ResNet可以直接用于特征提取或微调。从通俗角度看ResNet 的优势在于它让网络可以“加深而不容易学坏”。2、ResNet 的主要局限ResNet 也有局限。首先ResNet 仍然主要依赖卷积结构。它擅长局部空间特征提取但对全局长距离关系的直接建模能力不如注意力机制灵活。其次深层 ResNet 计算量仍然较大。例如 ResNet-101、ResNet-152 在训练和推理时都需要较多计算资源。再次ResNet 并不自动解决数据不足或标注质量差的问题。如果数据量太少、噪声太多模型仍然可能过拟合或学习到错误模式。此外ResNet 的残差连接要求相加特征形状匹配。如果通道数或空间尺寸变化需要用投影捷径进行调整。3、使用 ResNet 时需要注意的问题使用 ResNet 时需要注意• 残差相加要求特征形状一致• 通道数变化时可使用 1 × 1 卷积匹配• ResNet-18 / 34 常用 Basic Block• ResNet-50 / 101 / 152 常用 Bottleneck Block• 迁移学习时可先冻结 backbone• 小数据任务要注意过拟合• 分类任务常接全局平均池化和全连接层• 检测、分割任务常取中间特征图• 输入图像预处理要与预训练模型保持一致从实践角度看ResNet 是非常可靠的视觉基础模型但是否选择更深版本需要结合数据规模、任务难度和计算资源判断。十、Python 示例下面给出几个简单示例用来帮助理解 ResNet 的基本使用。示例 1一个简化残差块import torchimport torch.nn as nn # 基本残差块两个卷积层 BatchNorm ReLU加上残差连接class BasicResidualBlock(nn.Module): def __init__(self, channels): super().__init__() # 主路径Conv → BN → ReLU → Conv → BN self.conv_block nn.Sequential( nn.Conv2d(channels, channels, kernel_size3, padding1, biasFalse), nn.BatchNorm2d(channels), nn.ReLU(inplaceTrue), nn.Conv2d(channels, channels, kernel_size3, padding1, biasFalse), nn.BatchNorm2d(channels) ) self.relu nn.ReLU(inplaceTrue) def forward(self, x): # 残差分支计算 residual self.conv_block(x) # 捷径连接恒等映射后相加 out residual x # 相加后激活 out self.relu(out) return out # 测试残差块block BasicResidualBlock(channels64) # 输入2个样本64通道32x32特征图x torch.randn(2, 64, 32, 32) y block(x) print(输入形状, x.shape) # (2,64,32,32)print(输出形状, y.shape) # (2,64,32,32)这个例子中• 输入和输出形状相同• 主分支学习 F(x)• 捷径分支直接传递 x• 输出为 F(x) x示例 2通道数变化时的投影捷径import torchimport torch.nn as nn # 投影残差块当输入输出通道数或尺寸不同时用 1x1 卷积调整捷径分支class ProjectionResidualBlock(nn.Module): def __init__(self, in_channels, out_channels, stride1): super().__init__() # 主路径两个 3x3 卷积第一个可能带 stride 下采样 self.conv_block nn.Sequential( nn.Conv2d(in_channels, out_channels, kernel_size3, stridestride, padding1, biasFalse), nn.BatchNorm2d(out_channels), nn.ReLU(inplaceTrue), nn.Conv2d(out_channels, out_channels, kernel_size3, padding1, biasFalse), nn.BatchNorm2d(out_channels) ) # 捷径分支1x1 卷积调整通道和空间尺寸 self.shortcut nn.Sequential( nn.Conv2d(in_channels, out_channels, kernel_size1, stridestride, biasFalse), nn.BatchNorm2d(out_channels) ) self.relu nn.ReLU(inplaceTrue) def forward(self, x): residual self.conv_block(x) # 主路径输出 shortcut self.shortcut(x) # 捷径调整后的输出 out residual shortcut # 相加 out self.relu(out) return out # 测试从 64 通道到 128 通道步长 2 使空间尺寸减半32→16block ProjectionResidualBlock(in_channels64, out_channels128, stride2) x torch.randn(2, 64, 32, 32) # 输入形状 (2,64,32,32)y block(x) print(输入形状, x.shape) # (2,64,32,32)print(输出形状, y.shape) # (2,128,16,16)这个例子中• 主分支把通道数从 64 变为 128• stride2 让空间尺寸从 32 × 32 变为 16 × 16• 捷径分支也必须使用 1 × 1 卷积同步调整形状这样两个分支才能相加示例 3使用 torchvision 中的 ResNetimport torchimport torch.nn as nnfrom torchvision.models import resnet18 # 创建预训练的 ResNet-18 模型不使用预训练权重即随机初始化model resnet18(weightsNone) # 修改最后一层全连接层将其输出维度从原本的 1000ImageNet改为 10model.fc nn.Linear(model.fc.in_features, 10) # 模拟一批输入4 张 RGB 图像尺寸 224x224ResNet 默认输入尺寸x torch.randn(4, 3, 224, 224) # 前向传播得到 10 类 logitslogits model(x) print(输出 logits 形状, logits.shape) # torch.Size([4, 10])这个例子中• ResNet-18 接收图像 batch• 最后全连接层输出 10 个类别分数• logits 形状为 batch size × num_classes示例 4使用 ResNet 作为特征提取器import torch # PyTorch 主库import torch.nn as nn # 神经网络模块from torchvision.models import resnet18 # 导入 ResNet-18 模型 # 加载 ResNet-18不使用预训练权重随机初始化model resnet18(weightsNone) # 移除最后的全连接层保留卷积特征提取部分输出形状 [batch, 512, 1, 1]feature_extractor nn.Sequential( *list(model.children())[:-1] # 取除最后一层外的所有层) # 模拟一批输入4 张 RGB 图像尺寸 224x224x torch.randn(4, 3, 224, 224) # 提取特征features feature_extractor(x) print(特征形状, features.shape) # 输出 torch.Size([4, 512, 1, 1])这个例子中• ResNet 被用作图像特征提取器• 输出特征可以用于分类、检索或下游任务 小结ResNet 是一种以残差连接为核心的深层卷积神经网络。它让网络学习输入与目标之间的“修正量”而不是每层都重新学习完整映射。残差连接改善了信息和梯度传播使更深的网络更容易训练。对初学者而言可以把 ResNet 理解为一种给深层网络加入“捷径通道”的结构让模型既能加深又不容易在训练中退化。“点赞有美意赞赏是鼓励”