残差连接与层归一化通俗易懂的详解
残差连接Residual Connection和层归一化Layer Normalization是深度神经网络尤其是Transformer架构中用于提升模型训练稳定性、加速收敛并防止梯度消失/爆炸的两项关键技术。它们通常协同工作共同构成了Transformer中每个子层如自注意力层、前馈神经网络层的核心结构单元。为了清晰地展示其核心作用与实现下表对比了这两种技术特性残差连接 (Residual Connection)层归一化 (Layer Normalization)核心目的解决深度网络中的梯度消失/爆炸问题使网络能够轻松学习恒等映射从而允许构建极深的网络。稳定每一层神经网络输入的分布减少内部协变量偏移加速模型训练收敛。核心思想“跳跃连接”。不直接让网络层拟合目标函数H(x)而是改为拟合残差函数F(x) H(x) - x。最终的输出为x F(x)。对单一样本在某一层所有神经元的激活值进行标准化均值为0方差为1然后进行缩放和平移。在Transformer中的位置通常应用于每个子层如自注意力、前馈网络周围。输入x直接“跳跃”到该子层的输出之后进行相加。通常应用于残差相加之后。即LayerNorm(x Sublayer(x))。这种顺序称为“后归一化”Post-LN。通俗比喻如同在一条主路旁修建一条辅路新网络层。如果辅路修得好车流可以更快如果修得不好车流仍可顺畅地走主路不至于堵死。这降低了修建新路的风险。如同老师批改试卷时不是看绝对分数而是根据全班同学的平均分和分数分布来调整“标准化”每位同学的得分使得每次考试的难度差异不会对评价单个学生造成过大影响。残差连接Residual Connection详解1. 用途与解决的问题在非常深的神经网络中信号梯度在前向传播和反向传播时需要经过许多层。传统的堆叠层是让每一层直接学习一个复杂的映射H(x)。当网络很深时这个映射可能变得极其复杂且难以优化容易导致梯度在反向传播时变得极小消失或极大爆炸使得底层网络的参数几乎无法更新。残差连接的提出将一个棘手的学习目标H(x)转换成了一个相对更容易学习的目标。它允许网络层学习输入与输出之间的残差即差异部分。2. 实现原理对于一个基础的网络层或一组层F其输入为x传统的输出是F(x)。引入残差连接后该模块的输出变为输出 x F(x)这里的x就是“跳跃连接”过来的原始输入。F(x)是网络层需要学习的残差映射。3. 为什么有效恒等映射的便捷性如果当前层是多余的即最优的H(x)就是x那么网络只需简单地将F(x)的参数学习为接近0即可轻松实现输出 ≈ x。这比让一个非线性层直接学习恒等函数要容易得多。梯度回传的捷径在反向传播时梯度不仅通过F(x)的路径回传还会通过跳跃连接直接回传给上一层。这条“捷径”确保了梯度即使经过很深的网络也不容易消失因为总有一条梯度为1的直连路径存在。4. 在Transformer中的具体应用在Transformer的编码器和解码器层中每个子层自注意力子层、前馈神经网络子层都被一个残差连接所包裹然后紧接着进行层归一化。以编码器的自注意力子层为例# 伪代码示意 def encoder_sublayer(x): # 1. 自注意力计算 attention_output SelfAttention(x) # 2. 残差连接将原始输入 x 与自注意力输出相加 residual_output x attention_output # 残差连接在此发生 # 3. 层归一化 normalized_output LayerNorm(residual_output) return normalized_output层归一化Layer Normalization详解1. 用途与解决的问题在训练深度网络时每一层输入的分布会随着前一层参数的更新而不断变化这种现象称为“内部协变量偏移”Internal Covariate Shift。这会导致训练过程需要不断适应新的数据分布从而变得缓慢且不稳定。批归一化Batch Normalization通过对一个批次Batch内所有样本的同一特征进行归一化来解决这个问题但在序列长度可变如NLP任务或批次较小时效果不佳。层归一化提供了另一种思路针对单个样本对其在该层所有神经元或隐藏单元的激活值进行归一化。这使得它对批次大小不敏感非常适合Transformer这类处理变长序列的模型。2. 实现原理对于一个输入向量h代表某一层某个样本的所有神经元输出其维度为[d_model]例如512或768。层归一化的计算步骤如下计算均值和方差统计该样本在该层所有d_model个维度上的均值μ和方差σ²。μ (1/d_model) * Σ_{i1}^{d_model} h_iσ² (1/d_model) * Σ_{i1}^{d_model} (h_i - μ)²归一化使用计算出的均值和方差对h进行标准化得到均值为0、方差为1的向量。ĥ_i (h_i - μ) / sqrt(σ² ε)其中ε是一个极小的数如1e-5防止除以零。缩放与平移引入两个可学习的参数向量γ和β维度均为[d_model]对归一化后的结果进行缩放和平移。这一步至关重要它使模型有能力恢复归一化可能破坏掉的特征表示能力。output_i γ_i * ĥ_i β_i3. 为什么有效稳定训练通过将每层的输入稳定在相似的分布零均值、单位方差附近减少了内部协变量偏移使得可以使用更大的学习率并加速模型收敛。缓解梯度问题归一化操作在一定程度上也有助于缓解梯度消失或爆炸问题。适用于序列模型其计算独立于批次内其他样本因此完美适配变长序列和不同批次大小的训练场景。4. 在Transformer中的具体应用如前所述在标准的Transformer架构中层归一化被应用于残差相加之后。这种设计使得归一化操作的输入包含了原始输入和子层输出有助于稳定整个子层的输出分布。以下是一个简化的PyTorch风格代码示例展示了一个完整的Transformer子层如前馈网络如何结合残差连接和层归一化import torch import torch.nn as nn class TransformerSublayerWithResidualAndLN(nn.Module): def __init__(self, d_model, d_ff): super().__init__() # 示例子层一个简单的前馈网络 self.ffn nn.Sequential( nn.Linear(d_model, d_ff), nn.ReLU(), nn.Linear(d_ff, d_model) ) # 层归一化层 self.layer_norm nn.LayerNorm(d_model) def forward(self, x): # 保存原始输入用于残差连接 residual x # 前馈网络计算 sublayer_output self.ffn(x) # 残差连接原始输入 子层输出 residual_output residual sublayer_output # 残差连接 # 层归一化 output self.layer_norm(residual_output) # 层归一化 return output # 使用示例 d_model 512 d_ff 2048 batch_size 2 seq_len 10 model TransformerSublayerWithResidualAndLN(d_model, d_ff) input_tensor torch.randn(batch_size, seq_len, d_model) output_tensor model(input_tensor) print(f输入形状: {input_tensor.shape}) print(f输出形状: {output_tensor.shape}) # 应与输入形状一致总结残差连接通过引入“跳跃捷径”确保了信息尤其是梯度在深度网络中的顺畅流动使得训练超深网络成为可能层归一化则通过标准化每个样本层内的激活值稳定了训练过程并加速收敛。在Transformer中这两者以前文所述的顺序紧密结合构成了其强大且可稳定训练的深层架构的基石为后续BERT、GPT等大型语言模型的成功奠定了基础。参考来源Transformer架构详细解析从自注意力机制Self-Attention、词嵌入Embedding、多层编码Encoder-解码Decoder结构、输出层Linear-Softmax等模块解析用通俗易懂的语言了解 Transformer【大模型基础】Transformer架构精讲从原理到应用助你掌握大模型技术深度学习最强模型挑战一篇文章让你理解什么是Transformer模型从原理到代码的详细讲解好书推荐《ChatGPT原理与架构大模型的预训练、迁移和中间件编程 》【大模型】LLM 基础面试题合集 - LLM最全八股和答案二