趋近智
训练大型神经网络 (neural network),特别是多层Transformer模型,有时会造成数值不稳定。一个常见的问题是“梯度爆炸”现象,即在反向传播 (backpropagation)时,梯度的数值变得过大。这可能导致模型参数 (parameter)进行巨大的更新,可能引发发散(即损失值飙升至无穷大或NaN——非数字)或阻止收敛的震荡。这种不稳定在多层网络中,或在使用某些激活函数 (activation function)或初始化方案时,可能尤其常见,即便使用了层归一化 (normalization)等方法。由于低精度格式的数值范围有限,在混合精度训练(第20章讨论)中,这种情况也可能加剧。
梯度裁剪是一种直接而有效的方法,它通过限制梯度的大小来缓解这个问题,在优化器使用梯度更新模型权重 (weight)之前进行操作。主要思路不是改变梯度更新的方向,而是当梯度大小超过预设阈值时,限制其大小。
对于大型语言模型来说,最常用的方法是按梯度的L2范数(欧几里得范数)进行裁剪。这种做法将所有模型参数 (parameter)的全部梯度(或有时是每个参数组的梯度)视为一个向量 (vector),计算其L2范数,如果范数超过给定阈值 ,则重新缩放该向量。
从数学上讲,令 代表所有梯度串联在一起的向量。L2范数计算如下:
裁剪操作则应用如下:
如果范数 小于或等于阈值 ,梯度保持不变。如果范数大于 ,梯度向量 会被按 的比例缩小,从而确保其新范数恰好为 。这在限制梯度大小的同时,保持了梯度更新的方向。
在PyTorch中,这通常使用 torch.nn.utils.clip_grad_norm_ 函数实现。它在反向传播 (backpropagation)(计算梯度)之后、优化器步骤(根据梯度更新权重 (weight))之前应用。
import torch
from torch.nn.utils import clip_grad_norm_
# 假设模型、损失、优化器已定义
# ... 在训练循环内部 ...
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, targets)
loss.backward() # 计算梯度
# 定义最大梯度范数阈值
max_grad_norm = 1.0
# 裁剪梯度
total_norm = clip_grad_norm_(
model.parameters(),
max_norm=max_grad_norm,
norm_type=2.0
)
# 可选:如果需要,在裁剪前记录梯度范数
# print(f"裁剪前的梯度范数: {total_norm}")
optimizer.step() # 使用(可能已裁剪的)梯度更新权重
# ... 训练循环的其余部分 ...
在此代码段中,clip_grad_norm_ 计算传递给它的参数(model.parameters())的所有梯度的总L2范数。如果此范数超过 max_norm(我们的阈值 ),它会通过重新缩放 原地 修改梯度。该函数返回裁剪前的原始总范数,这有助于观察训练过程。设置 norm_type=2.0 明确指定了L2范数。
另一种方法是按值裁剪,尽管在训练大型Transformer模型时不如常用。这种方法独立地裁剪每个梯度分量 ,如果它落在指定范围 之外。
这意味着任何大于 的梯度分量都被设为 ,任何小于 的分量都被设为 。与范数裁剪不同,这种方法可以改变总梯度向量 (vector)的 方向,因为不同分量可能被不同程度地裁剪或根本不裁剪。
在PyTorch中,这可以使用 torch.nn.utils.clip_grad_value_ 完成:
import torch
from torch.nn.utils import clip_grad_value_
# ... 在训练循环内部,在 loss.backward() 之后 ...
# 为每个梯度分量定义最大绝对值
clip_value = 0.5
# 按值裁剪梯度
clip_grad_value_(model.parameters(), clip_value=clip_value)
optimizer.step()
# ... 训练循环的其余部分 ...
尽管更简单,但与范数裁剪相比,按值裁剪在深度学习 (deep learning)优化中通常被认为理论依据较少,因为它不将梯度视为一个统一的方向向量。对于大多数大型语言模型训练情况,clip_grad_norm_ 是更受推荐的方法。
max_norm 或 clip_value)是一个超参数 (parameter) (hyperparameter),通常需要凭经验调整。在大型语言模型训练中,max_norm 的一个常见起始值是 1.0。
clip_grad_norm_ 在裁剪 发生前 返回的值)有助于确定这个选择。如果范数频繁达到阈值,你可能要考虑学习率是否过高,或者阈值是否可以略微提高。如果范数很少接近阈值,它可能没有产生太大影响。下图说明了按范数裁剪的效果。位于圆圈外部(代表范数阈值 )的梯度向量 (vector)会沿径向按比例缩小,趋向于圆周边界,同时保持其原始方向。
梯度向量 和 原始范数大于阈值 。按范数裁剪将它们按比例缩小(蓝色虚线箭头),使其位于由 定义的边界上,而 已经在阈值内,保持不变。
通过防止过大的更新,梯度裁剪显著提升了成功训练大型语言模型所需的稳定性,使AdamW等优化器和精心设计的学习率调度能有效应对复杂的损失曲面。
这部分内容有帮助吗?
© 2026 ApX Machine LearningAI伦理与透明度•