这两天在学习残差网络(ResNet),其中的核心组件 —— 残差块(Residual block)的设计原理让我困惑了好久。在查阅了不少资料、向 ChatGPT 反复请教后,我有了一些直观的理解,整理如下。

一、残差(Residual)是什么?

简单来说,残差是 prediction 和 input 之间的差值。这个定义本身比较简单,但其原理却不那么容易理解。因为它涉及到转变我思考问题的方式。

具体来说,在引入这个概念之前,深度学习中的神经网络主要关注的是另一个差值 loss,也就是 prediction 和 truth 之间的差值。通过反向传播和梯度下降,神经网络总能从 loss 中学习,性能越来越好。这个思路比较直观:loss 就是误差,神经网络通过不断降低 loss 来提升自身的性能。那残差的含义是啥?百思不得其解。

除此之外,研究者还发现,增加神经网络的深度可以提升其性能。从直觉上来理解,这类似于脑容量变大和大脑皮层神经元变多后,学习能力会增强。

于是,神经网络越来越深,从最初的几层演变为几十层。一切都挺好且充满希望。直到……

二、残差要解决什么问题?

随着神经网络的层数继续增多,研究者发现神经网络的性能反而变差了。

主要原因是随着层数增多,梯度消失或爆炸(vanishing/exploding gradient)问题越来越常出现,使得神经网络越来越难以从 loss 这个差值中学到有用的知识,性能也因此下降。

换句话说,增加的层数帮了倒忙。

三、残差怎么解决这个问题?

设计者抱着一个朴素的愿望给添加的层设定了一个底线 —— “别添乱”。然后期望在守住这个底线的同时,它们学点有用的知识。

手段就是用残差块替代传统的层。

残差块内部分为残差连接(residual connection)和残差映射(residual mapping)。它俩的特征分别是:

  1. 残差连接:无参数且不学习,它的工作是把 input 原封不动地传递给下一层。
  2. 残差映射:有参数且能学习,它像传统的层一样从 loss 中努力地学点什么。

那它们是怎么守住“不添乱”这个底线呢?

靠的是残差映射的学习能力和残差连接的兜底。具体来说是这样:

  • 如果残差映射始终无法从 loss 中学到东西,即无论怎样 loss 都没有减小,那么残差映射最终会学习让自己啥都不干,只输出 0。这种情况下,整个残差块就靠残差连接一个单元干活了,相当于一个复读机 —— 把 input 原封不动地输出给下一层。
  • 如果在守住这个底线之后,残差映射还能学到一些知识,残差块就会提升神经网络的表现。

打个比方,继承家业后,二代一边沿用已有的经营方法(残差连接),另一边引入数字化和智能化(残差映射)谋发展。

  • 如果数字化和智能化开花结果,企业就上一个台阶 —— 残差映射学到了知识,提升了神经网络的表现。
  • 如果数字化和智能化探索无果,就止损守成 —— 残差映射没学到东西,不干了,让残差连接主导,保持住神经网络的表现。

四、效果如何?

研究者实践发现,残差块有效地改善了深层神经网络的学习过程,提升了它们的性能。这让构建更深度的神经网络(比如百层甚至千层)成为可能。

因此,残差块这个设计理念对后续深度神经网络的构建产生了深远的影响。

五、学习资料

  1. 残差设计者何恺明的学术报告:B 站油管(正片从 19:30 开始)。
  2. 《Dive into Deep Learning》的 8.6. Residual Networks (ResNet) and ResNeXt
  3. 《Practical Deep Learning for Coders》的 14.2 Building a Modern CNN: ResNet