1. 批次与梯度配置
| 参数 | 类型 | 说明 | 注意事项 |
|---|---|---|---|
per_device_train_batch_size=4 | int | 每个GPU每次处理的样本数 | 显存占用直接由此决定,16GB显卡通常支持4-8 |
gradient_accumulation_steps=4 | int | 梯度累积步数 | 实际有效批量=4×4=16,需同步调整学习率 |
dataloader_drop_last=True | bool | 丢弃末批不完整数据 | 避免最后一个小批量影响训练稳定性 |
2. 精度与显存优化
| 参数 | 类型 | 说明 | 硬件要求 |
|---|---|---|---|
bf16=True | bool | 启用BF16混合精度 | 需Ampere架构以上GPU(如A100/3090) |
fp16=True | bool | FP16混合精度 | 旧方案,BF16优先 |
gradient_checkpointing=True | bool | 梯度检查点 |
显存不足时可启用 |
3. 训练过程控制
| 参数 | 类型 | 说明 | 计算公式 |
|---|---|---|---|
num_train_epochs=2 | int | 训练总轮次 | 总步数=样本数/(batch_size×accum_steps)×epochs |
learning_rate=1e-4 | float | 初始学习率 | 有效批量16时可能需要增大到2e-4 |
logging_steps=10 | int | 日志记录间隔 | 指参数更新次数(非原始步数) |
save_steps=100 | int | 模型保存间隔 | 每100次参数更新保存一次 |
4. 系统与日志
| 参数 | 类型 | 说明 | 使用场景 |
|---|---|---|---|
save_on_each_node=True | bool | 多节点保存策略 | 单机训练可忽略 |
report_to="none" | str | 禁用外部日志 | 不记录到WandB/TensorBoard |
概念说明
batch计算逻辑
单步处理(物理批量):
每次前向传播(Forward Pass)处理的样本数 =per_device_train_batch_size= 4。
(显存占用仅由该值决定,与累积步数无关。)梯度累积:
进行 4次 前向-反向传播(每次处理4个样本),但不立即更新参数,而是累加梯度。参数更新:
累积4次后,用 16个样本的平均梯度 更新一次模型参数。等效性与显存优化
配置
显存占用(近似)
实际批量
参数更新频率
batch_size=16高(直接处理16)
16
每1步更新
batch_size=4, accum=4低(仅处理4)
16
每4步更新
显存优势:
梯度累积允许用batch_size=4的显存开销,达到batch_size=16的训练效果。计算代价:
需运行4次前向-反向传播才更新一次参数,训练时间可能延长(但显存不足时的唯一选择)。
Gradient Checkpointing(梯度检查点)的工作机制
当
gradient_checkpointing=True时,深度学习框架(如 PyTorch、DeepSpeed)会 自动丢弃部分中间激活值,并在反向传播时 临时重新计算 这些丢弃的激活值,以节省显存。以下是详细解释:1. 是否会自动丢弃节点?
会自动丢弃部分激活值,但丢弃的节点选择遵循特定策略:
默认策略:通常按 均匀分段 丢弃(如每隔
N层保留一个检查点)。可自定义:某些框架(如 PyTorch)允许手动指定哪些层需要缓存。
2. 具体工作流程
(1) 前向传播(Forward Pass)
计算并丢弃:
框架仅保留部分层的激活值(如每隔
k层存一次),其余层的激活值 计算后立即丢弃。检查点(Checkpoint):
被保留的激活值会缓存在显存中,用于后续反向传播。
(2) 反向传播(Backward Pass)
从检查点重建:
当需要计算某一层的梯度时,框架会 从最近的检查点重新运行前向计算,临时恢复被丢弃的激活值。
计算梯度后丢弃:
一旦完成当前层的梯度计算,临时重建的激活值会再次被丢弃。
3. 显存与计算权衡
行为
显存占用
计算开销
不启用检查点
高(存储所有激活值)
低(无重计算)
启用检查点(True)
低(部分存储)
高(需重计算)
显存节省:通常减少 30%~50%(取决于模型结构和检查点间隔)。
计算代价:增加约 20%~40% 的训练时间。
4. 关键注意事项
检查点间隔:
间隔越小(如每层都存),显存占用越高,但计算越快。
间隔越大(如每10层存一次),显存占用越低,但计算越慢。
框架差异:
PyTorch:需手动指定检查点位置(如
checkpoint_sequential)。HuggingFace/DeepSpeed:自动选择检查点策略。
与混合精度兼容:
检查点的激活值可以是 FP16/BF16,进一步减少显存。
5. 总结
gradient_checkpointing=True会自动丢弃部分激活值,并在反向传播时按需重算。显存节省:适合大模型或有限显存场景(如 16GB 显卡训练 10B+ 模型)。
计算代价:以时间换空间,训练速度会变慢。
如果需要更细粒度的控制(如自定义检查点位置),可以手动实现(如 PyTorch 的
torch.utils.checkpoint)。
混合精度训练注意事项
BF16优势:
比FP16更稳定的数值范围(不易溢出/下溢)
无需梯度缩放(GradScaler)
常见问题解决方案
-
OOM错误:
-
启用
gradient_checkpointing -
减少
per_device_train_batch_size
-
-
训练不稳定:
-
检查BF16支持性
-
尝试
max_grad_norm=1.0限制梯度爆炸
-
-
日志不显示:
-
设置
report_to="tensorboard"或"wandb"或"SwanLab"
-
梯度裁剪:
梯度裁剪是一种在训练深度学习模型时,用来防止梯度爆炸的非常重要的技术。它通过直接干预反向传播计算出的梯度值,来确保训练过程的稳定性。
核心思想与工作原理
梯度裁剪的核心思想非常简单:当梯度的范数(可以理解为“长度”或“幅度”)超过某个我们设定的阈值时,就按比例将这个巨大的梯度向量缩小,使其范数等于这个阈值。
关键点在于: 它不是简单粗暴地截断单个梯度值,而是等比例地缩小整个梯度向量。这样做有一个巨大的好处:它保留了梯度原始的方向,只改变了其大小。在优化中,梯度的方向(指向损失函数下降最快的方向)比其大小更重要。
工作流程如下:
前向传播 & 计算损失:输入数据通过网络,计算出损失值。
反向传播:通过反向传播算法,计算出所有模型参数(权重)的梯度。所有这些梯度共同组成了一个很长的向量 g。
计算梯度范数:计算这个梯度向量 g 的范数(通常是L2范数)。
norm_g = sqrt(sum([g_i² for g_i in g]))比较与裁剪:
如果
norm_g <= max_norm(你设定的阈值,如1.0),则什么都不做,直接使用原始梯度 g。如果
norm_g > max_norm,则说明梯度爆炸了。这时我们需要按比例缩小整个梯度向量:
clipping_ratio = max_norm / (norm_g + 1e-6)(加上一个极小值防止除零错误)
然后执行:g_clipped = g * clipping_ratio
现在,新梯度g_clipped的范数就恰好是max_norm了。参数更新:优化器(如SGD、Adam)使用裁剪后的梯度
g_clipped来更新模型参数。为什么需要梯度裁剪?(解决梯度爆炸)
在深度神经网络(尤其是RNN、LSTM、Transformer)中,梯度爆炸是一个常见问题。其原因通常是网络层数过深,梯度在反向传播过程中需要连续乘以许多权重矩阵(可能大于1),导致梯度值呈指数级增长。
梯度爆炸会带来灾难性后果:
模型不稳定:损失函数值剧烈震荡,无法收敛。
NaN(非数值):过大的梯度会导致参数更新步长巨大,使得模型参数变成无穷大或NaN,训练彻底失败。
性能下降:即使没有完全失败,不稳定的更新也会阻止模型找到好的解。
梯度裁剪就像一个安全阀,当梯度压力过大时,它就释放一些压力,确保系统不会崩溃。
5998

被折叠的 条评论
为什么被折叠?



