关于pytorch的出现nan如何解决

import numpy as np
from torch.nn import functional as F
import h5py
import matplotlib.pyplot as plt
import lr_utils
import torch
import torch.nn as nn
import matplotlib.gridspec as grid_spec
train_set_x_orig , train_set_y , test_set_x_orig , test_set_y , classes = lr_utils.load_dataset()
train_x_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0], -1).T
test_x_flatten = test_set_x_orig.reshape(test_set_x_orig.shape[0], -1).T
train_x = train_x_flatten / 255
train_y = train_set_y
test_x = test_x_flatten / 255
test_y = test_set_y
print(train_x.shape,train_y.shape)
train_x=torch.from_numpy(train_x).float()
train_y=torch.from_numpy(train_y).float()
test_x=torch.from_numpy(test_x).float()
#test_y=torch.from_numpy(test_y).float()
W1=torch.randn([5,12288],requires_grad=True).float()
b1=torch.ones([1,1],requires_grad=True).float()
W2=torch.randn([1,5],requires_grad=True).float()
b2=torch.ones([1,1],requires_grad=True).float()
optimizer = torch.optim.SGD([W1,W2,b1,b2], 0.001)
cast=[]
print(test_x)
for step in range(10000):
z1=W1@train_x+b1
A1=torch.relu(z1)
z2=W2@A1+b2
A2=torch.sigmoid(z2)
print(A2.shape)
loss=F.binary_cross_entropy(train_y,A2)
loss.backward()
optimizer.step()
optimizer.zero_grad()
if step%100==0:
cast.append(loss)
testZ1=W1@test_x+b1
testA1=torch.relu(testZ1)
testZ2=W2@testA1+b2
testA2=torch.sigmoid(testZ2)
print(testA2.shape,testA2)
testA2=testA2.detach().numpy()
def predict(testA2):
for i in range(50):
if testA2[:,i]>0.5:
testA2[:,i]=1
else:
testA2[:,i]=0
return testA2
testA2=predict(testA2)
print(testA2,test_y)
acc2=np.mean(testA2==test_y)
print(acc2)
在做识别猫猫吴恩达深度学习时使用pytorch出现testA2的值都是nan,出现了问题,不知道代码哪里有错误。

debug吧,应该是数据或者读取数据出的问题

pytorch训练模型时出现nan原因整合
常见原因-1
⼀般来说,出现NaN有以下⼏种情况:

相信很多⼈都遇到过训练⼀个deep model的过程中,loss突然变成了NaN。在这⾥对这个问题做⼀个总结:

1.如果在迭代的100轮以内,出现NaN,⼀般情况下的原因是因为你的学习率过⾼,需要降低学习率。可以不断降低学习率直⾄不出

现NaN为⽌,⼀般来说低于现有学习率1-10倍即可。

如果为了排除是不是学习率的原因,可以直接把学习率设置为0,然后观察loss是否出现Nan,如果还是出现就不是学习率的原因

2.如果当前的⽹络是类似于RNN的循环神经⽹络的话,出现NaN可能是因为梯度爆炸的原因,⼀个有效的⽅式是增加“gradient

clipping”(梯度截断来解决)

3.可能⽤0作为了除数;

4.可能0或者负数作为⾃然对数

5.需要计算loss的数组越界(尤其是⾃定义了⼀个新的⽹络,可能出现这种情况)

6.在某些涉及指数计算,可能最后算得值为INF(⽆穷)(⽐如不做其他处理的softmax中分⼦分母需要计算exp(x),值过⼤,最

后可能为INF/INF,得到NaN,此时你要确认你使⽤的softmax中在计算exp(x)做了相关处理(⽐如减去最⼤值等等))

1 梯度爆炸

原因:学习的过程中,梯度变得⾮常⼤,使得学习的过程偏离了正常的轨迹,使得学习过程难以继续

现象:观察每次迭代的loss值,会发现loss随着每轮迭代明显增长,并且代越来越⼤,最后loss值太⼤最终超过了浮点型表⽰的范围,所以变成了Nan。

解决⽅法:

1、降低学习率

2、梯度裁剪,设置gradient clipping,⽤于限制过⼤的diff

3、数据量纲不⼀致,也会导致梯度爆炸,数据归⼀化⽅法(减均值,除⽅差,或者加⼊normalization,例如BN、L2 norm等)

4、如果模型中有多个loss层,就需要找到梯度爆炸的层,然后降低该层的loss weight

2 学习率过⾼

原因:过⾼的学习率乘上所有的梯度使得所有参数变成⽆效的值。

现象:观察输出⽇志,会发现学习率变成nan

解决⽅法:设置合适的学习速率

3 损失函数有误, data underflow

原因:损失函数的计算可能导致NaN的出现,如交叉熵损失函数的计算可能出现log(0),所以就会出现loss为Nan的情况

当⽹络训练到达⼀定程度的时候,模型对分类的判断可能会产⽣0这样的数值,log(0)本⾝是没有问题的,-inf可以安全的参与绝⼤部分运算,除了(-inf * 0),会产⽣NaN。NaN的话,⼀旦参与reduce运算会让结果完蛋的

现象: 观测训练产⽣的loss时⼀开始并不能看到异常,loss也在逐步的下降,但是突然出现Nan

解决⽅法: 尝试重现该错误,在loss layer中加⼊⼀些输出以进⾏调试.

找到可能出现的错误的地⽅,增加⼀个bias

源代码

match wh / prior wh

g_wh = (matched[:, 2:] - matched[:, :2]) / priors[:, 2:]

g_wh = torch.log(g_wh) / variances[1]

return target for smooth_l1_loss

return torch.cat([g_cxcy, g_wh], 1) # [num_priors,4]

修改后

eps = 1e-5

match wh / prior wh

g_wh = (matched[:, 2:] - matched[:, :2]) / priors[:, 2:]

g_wh = torch.log(g_wh + eps) / variances[1]

return target for smooth_l1_loss

return torch.cat([g_cxcy, g_wh], 1) # [num_priors,4]

y_truth * log(y_predict)

when y_truth[i] is 0, it is likely that y_predict[i] would be 0

这样的表达式,要考虑对log中的变量进⾏clip. ⽐如

safe_log = tf.clip_by_value(some_tensor, 1e-10, 1e100)

bin_tensor * tf.log(safe_log)

4 输⼊数据有误

原因: 输⼊中就含有NaN 或者 trainingsample中出现了脏数据!脏数据的出现导致logits计算出了0,0传给 即nan。

现象:每当学习的过程中碰到这个错误的输⼊,就会变成NaN。观察loss的时候也许不能察觉任何异常,loss逐步的降低,但突然间就变成NaN了

解决⽅法:逐步去定位错误数据,然后删掉这部分数据.

通过设置batch_size = 1,shuffle = False,⼀步⼀步地将sample定位到了所有可能的脏数据,删掉

重整数据集,确保训练集和验证集⾥⾯没有损坏的图⽚。可以使⽤⼀个简单的⽹络去读取输⼊,如果有⼀个数据是错误的,这个⽹络的loss值也会出现Nan

5 Pooling层的步长⼤于核的尺⼨

如下例所⽰,当池化层中stride > kernel的时候会在y中产⽣NaN

6 设置远距离的Label会得到NAN

我的理解是,模型采⽤了交叉熵损失函数,当标签过于分散的时候,⽐⽅说标签为8000的数据,其概率分布值就会变成了⽐较⼩的数值,也就是会出现类似于log(0)这种情况,从⽽模型的loss为Nan.

1、 nan 和inf产⽣原因

NaN 是not a number,

INF是infinity的简写,意义是⽆穷⼤。⽐如求损失函数会⽤到log(x),如果 x 接近0,那么结果就是 inf。

从理论的⾓度上看,出现NaN和Inf,本质是梯度消失与梯度爆炸所导致的。

梯度消失是指导数值特别⼩,导致其连乘项接近⽆穷⼩,可能是由输⼈数据的值域太⼩(导致权重 W 的导数特别⼩)或者是神经⽹络层输出数据落在在激活函数的饱和区(导致激活函数的导数特别⼩)

梯度爆炸是指导数值特别⼤,导致其连乘项特别⼤,致使 W 在更新后超出了值域的表⽰范围。可能是输⼈数据没有进⾏归⼀化(数据量纲太⼤致使 W 的梯度值变⼤),只要连乘项的导数⼀直⼤于1,就会使得靠近输⼊层的 W 更新幅度特别⼤。连乘项是指链式求导法则中毎⼀层的导数,很明显梯度消失与梯度爆炸都受连乘项的影响(也就是⽹络梯度的影响)。

从数据的⾓度上看,训练中产⽣的 nan 、 inf ,本质上可以分为输⼈数据和值域的问题。输⼊数据有缺失,模型前向传播过程中值域超出界限。

梯度消失不会导致模型出现 nan 和 inf ,只会导致模型 loss 不会下降,精度⽆法在训练过程中提升。⽽梯度爆炸则有可能导致模型在训练过程中出现 inf 。

对于输⼊数据有缺陷,需要⽤均值进⾏ nan 值填充,对于图像数据通常不会出现。

绝⼤部分情况是值域的问题,值过⼤或过⼩。这出现在模型的前向传播中,模型中的系列运⾏使得数据超出值域范围,如交⼜熵中的 log 函数, log (1e-10), mse loss 中的 math.pow ( x .2)取平⽅;激活函数中的 relu 函数,没有上届限制;模型的权重过⼤。

解决⽅案:本质就是调整输⼊数据在模型运算过程中的值域

1、模型权重加⼊正则化,约束参数的⼤⼩

2、模型中加⼊ BatchNormalization ,归⼀化数据

3、使⽤带上限的激活函数,例如relu6函数

pytorch 下使⽤ torch . nn .ReLU6,函数原型为 min ( max (0, x ),6),也就是把 relu 函数的最⼤值限制为6。 也就是对输出做了限制4、在 losse 函数运算前进⾏值域修正

tf可以使⽤ clip_by_value 函数,在 loss 函数的 log , exp 前调整 y_pred 的值域,避第 -logl(0)产⽣的⽆穷⼤

pytorch 可以使⽤ torch.clip ( input , min=None , max = None ) 或 torch.clamp ( input , min=None, max = None )进⾏值域限制import torch.nn as nn

outputs = model(data)

loss= loss_fn(outputs, target)

optimizer.zero_grad()

loss.backward()

#nn.utils.clip_grad_value(model.parameters(),clip_value=2)

nn.utils.clip_grad_norm_(model.parameters(), max_norm=20, norm_type=2)

optimizer.step()

5、进⾏梯度減枝

对超出值域范围的梯度进⾏约束,避免梯度持续⼤于1,造成梯度爆炸。(没办法规避梯度消失)

pytorch 使⽤ nn.utils.clip_grad_value(parameters, clip_value).将所有的参数剪裁到[-clip_value , clip_value]。如 clip_value =1, [100,0.1]=>[1,0.1],该操作会改变梯度的⽅向

使⽤ nn.utils.clip_grad_norm_ 按照范数⼤⼩进⾏归⼀化,当参数的范数( norm_type=2 范数)⼤于最⼤值时,则会将其归约到最⼤值。该⽅法可以保证梯度的⽅向是完全⼀致的,可能会导致梯度值被缩放到特别⼩(如[100,0.1]=>[1,0.0001])。

6、使⽤ ResNet 或 DenseNet 结构

将深层的样度值通过跳跃连接传递到浅层中

在训练早期,模型参数可能不是很合适,会出现梯度消失和爆炸的情况,特别是有lstm,rnn这类⽹络的情况。nan 是not a number ,inf是⽆穷⼤。⽐如求损失函数会⽤到log,如果输⼊接近0,那么结果就是inf。

如有帮助请采纳谢谢

大概率是哪块除数为0了