当前位置: 首页 > news >正文

fp16训练神经网络时出现nan问题

问题总结:nan 问题

现象

在训练过程中,训练损失(Train Loss)和测试损失(Test Loss)的值变为 nan(Not a Number)。这通常意味着训练过程中出现了数值计算错误或不稳定,导致无法计算出有效的损失值。同时,训练准确率和测试准确率(Train AccuracyTest Accuracy)保持在接近随机猜测的水平(例如 9.87% 或 10%)。

在你的训练过程中,nan 错误使得模型无法正常学习,导致:

  • 训练损失和测试损失 变为 nan
  • 训练准确率测试准确率 固定在随机值附近,未能有效提升。

原因

  1. 梯度爆炸或梯度消失

    • FP16 精度训练中,由于计算精度较低,梯度可能会在反向传播过程中变得过小(梯度消失)或过大(梯度爆炸)。这会导致在训练时出现 nan,特别是在使用深层网络时,数值的误差可能在多次计算后积累。
  2. 学习率过大

    • FP16 精度下,数值的范围更加有限。如果学习率设置过大,梯度更新的步长可能会过大,从而导致数值溢出或计算不稳定,最终导致 nan
  3. 损失函数中的无效值

    • 某些损失函数(如对数损失函数)可能会在计算过程中遇到无效值(例如对零或负数取对数),导致 nan
  4. FP16 特有的数值问题

    • FP16 精度会导致数据在表示过程中有较大的精度损失,尤其是在处理小数时。网络中的某些操作(如权重更新)可能会由于精度不足而导致计算出错。

解决方法

  1. 使用 GradScaler 和 Loss Scaling

    • 通过使用 torch.cuda.amp.GradScaler,可以动态地对损失进行缩放,从而避免梯度过小或过大,保持梯度稳定。Loss Scaling 是在 FP16 精度训练中防止梯度消失或爆炸的有效方法。
    scaler = GradScaler()
    scaler.scale(loss).backward()  # 梯度反向传播
    scaler.step(optimizer)  # 更新优化器
    scaler.update()  # 更新缩放因子
    
  2. 降低学习率

    • 减小学习率有助于减缓训练过程中梯度更新的步伐,避免梯度过大导致溢出或计算不稳定。通常,可以将学习率从 0.001 降到 0.0001 或更小,以保证训练稳定。
  3. 梯度裁剪

    • 如果问题是梯度爆炸,可以使用 梯度裁剪(Gradient Clipping)来限制梯度的最大值,避免梯度过大导致的数值溢出:
    torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
    
  4. 检查数据和损失函数

    • 确保输入数据没有异常值(如 NaN、无穷大或负值)。可以在数据预处理阶段进行规范化,确保数据在合理范围内。
    • 确保损失函数在计算时不会产生无效值。对于使用 对数损失 的函数,需要确保输入值大于零。
    print(f"Data max: {data.max()}, Data min: {data.min()}")
    
  5. FP16 转回 FP32

    • 如果依然无法解决问题,可以尝试退回到 FP32 精度训练,虽然会增加内存占用和计算时间,但可以避免由于 FP16 精度导致的数值问题。

总结

  • 现象:训练损失和测试损失为 nan,训练准确率和测试准确率固定在接近随机值。

  • 原因

    • 梯度爆炸或消失。
    • 学习率过大。
    • 损失函数计算中的无效值。
    • FP16 精度训练中的数值问题。
  • 解决方法

    • 使用 GradScalerLoss Scaling 来稳定梯度计算。
    • 降低学习率,避免梯度更新过大。
    • 使用梯度裁剪(如果出现梯度爆炸)。
    • 确保数据没有无效值,避免损失函数中的计算错误。
    • 在极端情况下,使用 FP32 代替 FP16

通过这些方法,你可以有效地避免训练过程中出现 nan 的问题,确保训练稳定进行。


根据你提供的结果,nan 问题出现在 训练 过程中,而非 推理(Inference)过程中。这从以下几个方面可以推测出来:

1. 训练过程的损失和准确率

  • 你在训练的 Train LossTest Loss 中看到的是 nan,这通常发生在训练过程中,由于反向传播计算梯度时数值不稳定导致。
  • 训练的准确率 Train Accuracy 也在持续提高,而测试准确率 Test Accuracy 达到接近随机猜测的水平(接近 10%),这说明在训练过程中,模型能够有效学习,但在梯度更新时遇到数值问题,导致损失变为 nan

2. 推理过程

  • 在推理过程中,通常不涉及梯度计算(即不进行反向传播)。因此,nan 结果一般不会出现在推理过程中。推理过程中发生 nan 的情况通常较少,除非输入数据本身有问题(如 nan、无穷大等),但这在训练过程中很少出现。

3. 推理与训练的区别

  • 训练:会涉及 前向传播损失计算反向传播梯度更新。在这些步骤中,数值计算(如梯度计算)会受到精度的影响,特别是 FP16 精度训练时,容易因为梯度过小或过大出现数值溢出,导致 nan
  • 推理:仅涉及 前向传播输出计算,没有梯度计算,因此更不容易出现 nan。如果出现 nan,通常是因为模型在训练时出现了不稳定,导致某些权重或激活值在推理时变为 nan

结论:

nan 问题出现在训练过程中,特别是在 FP16 精度训练中,由于梯度计算和损失更新时可能会出现数值不稳定,导致损失变为 nan。解决这个问题的常见方法是使用 Loss Scaling,通过 GradScaler 稳定梯度计算,避免梯度过小或过大。

推理过程一般不会直接导致 nan,除非是训练过程中有问题的模型参数导致推理时出现问题。

http://www.hskmm.com/?act=detail&tid=27558

相关文章:

  • 第十篇
  • 504 品酒大会!!!!!!
  • 整体理解pai0-具身智能-01 - jack
  • 【数据结构】可撤销并查集 - Slayer
  • 皮卡鱼源码导读
  • 高斯消元学习笔记
  • newDay07
  • 10月9日
  • 从开放重定向到XSS:漏洞升级实战
  • 余弦日记
  • 【题解】P11459 [USACO24DEC] Its Mooin Time P
  • 创建一个springboot项目,mybatis连接嵌入式数据库H2,实现增删改查功能
  • 基于众包的产品质量比较与推荐算法研究
  • 10/9
  • 2025.10.9
  • 线程池总结
  • 合并两个有序链表
  • 深入解析:一款相机是只有桶形畸变 和 枕形畸变的一种,还是两个都有?
  • 数据结构-链表
  • 重组抗体技术:从原理到应用,解锁高效可控的新一代抗体研发
  • P13690 [CEOI 2025] boardgames
  • CSS
  • 关于jinja2的ssti模版注入的学习+过滤
  • WPF Epplus export 10M+ items in excel with multiple sheets batch by batch
  • [EGOI 2023] Guessing Game
  • CF2152G Query Jungle
  • [ROI 2018] Addition without carry
  • [THUPC 2025 决赛] Im Here
  • 解码Linux基础命令
  • 基于 C++ 的高雷诺数湍流直接数值模拟求解器设计与性能优化 - 实践