前言
- 文章来源:CSDN@LawsonAbs
- 系统环境:torch 1.9.1
- 遇到
nan
的主要排查顺序:(1)先检查主要代码有没有写错?(2)接着看会不会再log,exp()的时候出现计算问题?(3)梯度大小设置是否合理?
20230327更新
这两天写的一个损失函数又报nan了。如下图所示:
这个nan大概是在20epoch之后才出现,这大抵能说明:我的代码是写的没问题,可能是随着训练的过程,导致某些地方可能出现了问题。众所周知,最有可能出现问题的则是:softmax 和 log 函数两处,那么我看看我的对应处代码,发现如下:
这里我为了防止除0得到无穷大,所以加了一个self.eps,理论上不会得到inf了。同理,在计算log值的时候,也是用到了self.eps。但是为啥还有问题呢?于是我看了看我的eps值为1e-10
。然后执行一下上面这个操作,竟然发现sim的值为inf!
这说明eps取值太小,导致没有什么作用!故修改即可。
总结便是:eps
取值过小没有作用,导致最后防止除0操作时失败!
1. 场景1
前几天在写一段代码的时候,遇到了nan
错误,但是一直么有找到问题所在。我的代码主要是将一个 batch
中的entity对应的 embedding
送到自定义的2层BertModel中。
原因
- 送入到BertModel中仅传入了 hidden_states,没有传入attention_mask。但是后来搞定这个bug之后还是有nan值的村子。
- 于是按行debug,发现问题在于送入到BertEncoder中的 hidden_states 中有nan的存在。
我们可以用下面这行代码检查tensor中是否有nan 值。
torch.any(torch.isnan(entity_bank))
这个entity_bank
便是一个待检测的向量。于是对应解决这个nan值的生成即可。
但奇怪的是,使用下图中注释的一行就会有nan 的问题,但是用第二行代码则没有这个问题。
2. 场景2
最近在写一个自定义的损失函数,形式如下:
其中的L1 是正样本的损失,L2是负样本的损失。
原因
训练过程中再次出现nan,后来发现原因是:上式中的 log(*)
中的值可能存在0,我是先对0求了log,然后过滤掉了inf值,但是事实证明这么做是不行的。最好的方式是:
eps=1e-7
log(x+eps)
从而避免nan值的产生。
3. 场景3
nan最近真的是粘上我了 ┭┮﹏┭┮
短短几天,碰到了3次nan报错,而且每次都不一样。今天(2021/12/18)这次碰到的情况是模型训练到了一定的epoch时就开始出现nan
。如下所示:
因为已经到了第50epoch,所以我就怀疑是梯度的问题了。如果是脏数据的问题,那么应该在一个epoch之内就会报错。从网上查阅资料,感觉像是因为梯度爆炸导致的nan错,于是我调整了一个动态学习率,就没有再报这个错了。
如果是自己手写的loss,那么一定要保证最后得到的loss是一个均值,要么是除以batch_size
,要么是除以样本条数
,因为这个系数在求导的时候,就会被带到其中作为梯度的系数,这样就会把梯度降下来。
4. 场景4
因为代码bug导致的nan。
我在使用 R-Drop 的时候,需要使用KL散度求两个 predict logit
间的距离,pytorch中的 kl_div 函数有个参数说明如下:
这个参数:表示传入的 target
是否是在log
空间下(即是否由log处理过),推荐传入固定的分布结果,(如softmax
)避免由log导致的数值问题。
5. 场景5
还有一种常见的nan报错是 除零导致的错。如下所述:
背景:同一个entity可以对应多个mention,但是我想取这个entity的表示,就可以通过取各个mention表示的平均来获取。最后除以这个mention的个数即可。
于是我这么写了代码:
cur_entity_emb = torch.mm(cur_entity2mention,x) / torch.sum(cur_entity2mention,dim=1).unsqueeze_(1).expand(-1,808) # 拿到整个entity的表示
得到的这个 cur_entity_emb
中存在nan,那么罪魁祸首应该就是后面的这个 torch.sum()
存在问题,果不其然,查了一下的确是这个的问题。
6. 场景6
还是之前那个损失函数(如下图所示)
实现过后,代码在epoch 35 - epoch 40 之间总会报一个nan错,但是epoch 不固定,看看具体的报错信息:
发现这些报错信息下,都有一个常见的情况,那就是 NA acc 的准确率已经到了0.98-0.99 了,那这个跟报错有关系吗?于是我尝试将负样本损失单独训练,果不其然,在仅使用 loss_neg 下训练模型,发现不到10 step 损失就报nan !震惊,原来问题出现在负样本的损失上!
经仔细发现,原来是我负样本的损失在一定epoch的学习下就变成了0,显然这是不大可能的啊,针对情况改代码就可以了吧。