社区计算机视觉课程文档

ResNet(残差网络)

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

ResNet(残差网络)

拥有更多层的神经网络被认为更有效,因为增加更多层可以提高模型性能。

随着网络变得更深,提取的特征可以进一步丰富,例如 VGG16 和 VGG19 中所示。

一个问题出现了:“学习网络是否像堆叠更多层一样容易?”梯度消失问题是回答这个问题的障碍,通过归一化初始化和中间归一化层解决了这个问题。

然而,一个新的问题出现了:退化问题。随着神经网络变得更深,准确率饱和并迅速下降。一项比较浅层和深层普通网络的实验表明,深层模型表现出更高的训练和测试误差,这表明有效训练更深层架构存在根本性挑战。这种退化并非由于过拟合,而是因为当网络变得更深时,训练误差增加了。添加的层并没有近似恒等函数。

Degradation-error

ResNet 的残差连接释放了极致深度的潜力,与之前的架构相比,准确率大幅提升。

ResNet 架构

  • 一个残差块。来源:ResNet 论文 residual

ResNet 引入了一种称为残差学习的概念,它允许网络学习残差(即学习到的表示与输入之间的差异),而不是试图直接将输入映射到输出。这是通过跳跃连接(或快捷连接)实现的。

让我们分解一下

1. 基本构建块:残差块

在典型的神经网络层中,我们的目标是学习映射 F(x),其中 x 是输入,F 是网络应用的变换。如果没有残差学习,层的变换是:y = F(x)。在 ResNet 中,网络不是直接学习 F(x),而是被设计为学习残差 R(x),其中:R(x) = F(x) − x。因此,残差块中的变换写为:y = F(x) + x。

这里,x 是残差块的输入,F(x) 是块堆叠层(通常是卷积、批归一化和 ReLU)的输出。恒等映射 x 通过跳跃连接直接添加到 F(x) 的输出中。因此,该块正在学习残差 R(x) = F(x),最终输出是 F(x) + x。与原始映射相比,这种残差函数更容易优化。如果最优变换接近恒等(即不需要变换),网络可以很容易地将 F(x) ≈ 0 以便直接通过输入。

  • ResNet 的构建块如图片所示,来源 ResNet 论文。

resnet_building_block

2. 学习残差和梯度流

ResNets 对非常深的网络效果良好的主要原因是在反向传播过程中改善了梯度流。让我们从数学上分析反向传播。假设您有残差块 y = F(x) + x。在通过链式法则计算梯度时,我们计算损失 𝐿 对输入 x 的导数。对于标准块(没有残差),梯度为

∂x/∂L = ∂F(x)/∂L * ∂F(x)/∂x

然而,对于残差块,其中 y = F(x) + x,梯度变为

∂L/∂x = ∂L/∂F(x) * ∂F(x)/∂x + ∂L/∂F(x) ⋅1

请注意,现在我们在梯度计算中多了一个项 1。这意味着每层的梯度都有一个直接路径返回到较早的层,从而改善了梯度流并减少了梯度消失的可能性。梯度更容易流过网络,从而允许更深的网络在没有退化的情况下进行训练。

3. 为什么现在可以实现更深的网络:

ResNet 使训练数百甚至数千层网络成为可能。以下是更深网络从中受益的原因:

  • 恒等快捷连接:快捷连接执行恒等映射,其输出被添加到堆叠层的输出中。恒等快捷连接既不增加额外参数也不增加计算复杂性,这些连接绕过层,为信息流创建直接路径,并使神经网络能够学习残差函数 (F)。
  • 更好的梯度流:如前所述,残差有助于梯度在反向传播过程中更好地传播,解决了超深网络中的梯度消失问题。
  • 更容易优化:通过学习残差,网络本质上是将学习过程分解为更容易的增量步骤。对于网络来说,学习残差 R(x) = F(x) − x 比直接学习 F(x) 更容易,尤其是在非常深的网络中。

总结:

我们可以得出结论:ResNet 网络 -> 普通网络 + 快捷连接!

对于操作 (F(x) + x),(F(x)) 和 (x) 应该具有相同的维度。ResNet 采用两种技术来实现这一点:

  • 零填充快捷连接:添加零值通道,在不引入额外可学习参数的情况下保持维度。
  • 投影快捷连接:在必要时使用 1x1 卷积调整维度,这涉及一些额外的可学习参数。

在 ResNet 50、101 和 152 等更深层的 ResNet 架构中,采用了一种专门的“瓶颈构建块”来管理参数复杂性并保持效率,同时实现更深层次的学习。

ResNet 代码

在 ImageNet 上预训练的深度残差网络

您可以在下面看到如何使用 transformers 库加载预训练的带有图像分类头的 ResNet。

from transformers import ResNetForImageClassification

model = ResNetForImageClassification.from_pretrained("microsoft/resnet-50")

model.eval()

所有预训练模型都期望输入图像以类似方式归一化,即形状为 (3 x H x W) 的 3 通道 RGB 图像的小批量,其中 H 和 W 预期至少为 224。图像必须加载到 [0, 1] 范围,然后使用 mean = [0.485, 0.456, 0.406] 和 std = [0.229, 0.224, 0.225] 进行归一化。

这是一个示例执行。此示例可在 Hugging Face 文档中找到。

from transformers import AutoFeatureExtractor, ResNetForImageClassification
import torch
from datasets import load_dataset

dataset = load_dataset("huggingface/cats-image")
image = dataset["test"]["image"][0]

feature_extractor = AutoFeatureExtractor.from_pretrained("microsoft/resnet-50")
model = ResNetForImageClassification.from_pretrained("microsoft/resnet-50")

inputs = feature_extractor(image, return_tensors="pt")

with torch.no_grad():
    logits = model(**inputs).logits

# model predicts one of the 1000 ImageNet classes
predicted_label = logits.argmax(-1).item()
print(model.config.id2label[predicted_label])

参考文献

< > 在 GitHub 上更新