前言
在使用ultralytics库的YOLO模型时,比如YOLOv8进行目标检测模型训练,遇到一个非常奇怪的问题:训练过程中的验证损失(loss)出现了NaN,而验证的评价指标如mAP50却能正常计算(有时mAP都也为0)。经过排查发现,这个问题和我的显卡(1660 Super)有关。本文记录了找到问题原因并解决的过程,供遇到类似问题的读者参考。
训练时在控制台打印的结果显示,训练集有正常显示loss,到验证时出现指标为0:
这时如果查看训练结果中的results.csv文件,出现下面的结果记录,显示val上的loss均为nan:
epoch, train/box_loss, train/cls_loss, train/dfl_loss, metrics/precision(B), metrics/recall(B), metrics/mAP50(B), metrics/mAP50-95(B), val/box_loss, val/cls_loss, val/dfl_loss, lr/pg0, lr/pg1, lr/pg2
1, 1.0528, 4.0179, 1.0164, 0.50566, 0.42115, 0.4226, 0.31671, nan, nan, nan, 0.0033291, 0.0033291, 0.0033291
2, 0.975, 2.3274, 0.99149, 0.87422, 0.84204, 0.9524, 0.73884, nan, nan, nan, 0.0066075, 0.0066075, 0.0066075
3, 0.99872, 1.7083, 1.0006, 0.86385, 0.92221, 0.97791, 0.75714, nan, nan, nan, 0.0098308, 0.0098308, 0.0098308
4, 0.98629, 1.4711, 1.0027, 0.9398, 0.96121, 0.98227, 0.74803, nan, nan, nan, 0.0097525, 0.0097525, 0.0097525
5, 0.95163, 1.1908, 0.98319, 0.93729, 0.97754, 0.98343, 0.77948, nan, nan, nan, 0.00967, 0.00967, 0.00967
6, 0.91768, 0.97527, 0.96595, 0.94316, 0.98203, 0.98379, 0.78054, nan, nan, nan, 0.0095875, 0.0095875, 0.0095875
7, 0.89667, 0.83439, 0.95954, 0.96266, 0.9745, 0.98683, 0.77252, nan, nan, nan, 0.009505, 0.009505, 0.009505
8, 0.88253, 0.76853, 0.95979, 0.93883, 0.98245, 0.98682, 0.7814, nan, nan, nan, 0.0094225, 0.0094225, 0.0094225
9, 0.87479, 0.70413, 0.95082, 0.943, 0.97676, 0.98672, 0.77541, nan, nan, nan, 0.00934, 0.00934, 0.00934
10, 0.8639, 0.67849, 0.95247, 0.96784, 0.97556, 0.98666, 0.78711, nan, nan, nan, 0.0092575, 0.0092575, 0.0092575
如果按照这个情况,等训练结束不出意外会得到下面的损失曲线:
损失曲线的box_loss、cls_loss、dfl_loss均为空,显然有猫腻!
问题描述
在YOLOv8模型训练的过程中,验证集的损失项出现了NaN值,导致模型训练无法有效进行。NaN(Not a Number)值通常表明某些计算过程出错,可能是数据、配置或硬件兼容性引起的。
NaN值在训练过程中出现通常可能是由以下几个原因引起的:
- 数据集问题:验证集数据不完整或格式错误。
- 学习率过高:过大的学习率会导致模型参数波动过大,可能引发NaN。
- 硬件兼容性问题:某些显卡在训练过程中不完全兼容特定的训练设置或计算模式。
这里我试过排查学习率的问题,从打印的结果看开始时学习率很低,关键我运行在另一台电脑上(RTX4090显卡),同样的代码、环境,没有复现这个问题。结合显卡类型和模型训练的反馈信息,我重点排查了硬件兼容性问题。
解决方案
在查阅资料后,发现16系列显卡,如1660 Super显卡在启用AMP(Automatic Mixed Precision, 自动混合精度)时容易引发NaN问题。混合精度训练会将一部分计算精度降低以加速训练,但可能会在不完全支持的显卡上导致损失计算异常。针对这一情况,以下是具体的解决步骤。
1. 禁用AMP功能
在YOLOv8的配置文件和代码中,将AMP功能关闭,以避免精度导致的计算问题。
(1)修改配置文件:
打开YOLOv8的训练代码,在调用YOLO训练时,指定AMP设置,修改为False
:
# 加载预训练的YOLOv8模型并开始训练
model = YOLO(model_path, task='detect')
results2 = model.train(
data=data_path, # 指定训练数据的配置文件路径
device=device, # 自动选择进行训练
workers=workers, # 指定使用的工作进程数量
imgsz=imgsz, # 指定输入图像的大小
epochs=epochs, # 指定训练的epoch数
batch=batch, # 指定每个批次的大小
name=train_name, # 指定训练任务的名称
amp=False
)
也就是增加一个参数设置,如下图所示:
(2)修改验证器代码:
打开ultralytics/engine/validator.py
文件,注释掉强制使用FP16精度的代码行:
# self.args.half = self.device.type != 'cpu' # 注释掉以防止验证过程中强制使用FP16
这个代码的位置大概就是下面的样子,跟你的ultralytics这个库的版本有关系,代码可能有些差别:
2. 验证配置变更
完成上述修改后,重新运行YOLOv8的训练代码,并观察验证集损失是否仍然为NaN。我的训练日志显示,NaN问题已成功解决,验证损失能够正常显示数值。
这时再看results.png可以发现,它val的loss重新有值了:
从数值上看,loss也是有值的:
3. 结果分析
在禁用AMP后,YOLOv8的训练过程变得稳定,验证集损失再未出现NaN的问题。通过分析,我总结出在某些显卡(如GTX 16系列)上,AMP功能可能导致精度计算问题,特别是在YOLOv8这类对计算精度敏感的模型中。关闭AMP后,可以牺牲少量训练速度来获得更稳定的结果。
总结
遇到类似问题的读者可以参考以下调试步骤:
- 检查数据集是否完整,排除格式错误。
- 调整学习率,以避免梯度爆炸。
- 根据硬件配置调整AMP设置,特别是对于GTX 16系列显卡用户,建议禁用AMP。
希望这篇记录能帮助到和我一样使用1660 Super显卡且遇到NaN问题的用户。禁用AMP是一个有效的解决方案,可以提升YOLOv8的训练稳定性,确保模型能正常训练并获得有效结果。