Tensorflow NaN错误?
tensorflow
5
0

我正在使用TensorFlow,并且修改了教程示例以拍摄RGB图像。

该算法在新图像集上开箱即用,直到突然之间(仍然收敛,通常精度约为92%),由于ReluGrad收到非限定值的错误而崩溃。调试表明,直到突然之间,由于不明原因,该数字都没有异常发生,引发了错误。新增中

print "max W vales: %g %g %g %g"%(tf.reduce_max(tf.abs(W_conv1)).eval(),tf.reduce_max(tf.abs(W_conv2)).eval(),tf.reduce_max(tf.abs(W_fc1)).eval(),tf.reduce_max(tf.abs(W_fc2)).eval())
print "max b vales: %g %g %g %g"%(tf.reduce_max(tf.abs(b_conv1)).eval(),tf.reduce_max(tf.abs(b_conv2)).eval(),tf.reduce_max(tf.abs(b_fc1)).eval(),tf.reduce_max(tf.abs(b_fc2)).eval())

作为每个循环的调试代码,将产生以下输出:

Step 8600
max W vales: 0.759422 0.295087 0.344725 0.583884
max b vales: 0.110509 0.111748 0.115327 0.124324
Step 8601
max W vales: 0.75947 0.295084 0.344723 0.583893
max b vales: 0.110516 0.111753 0.115322 0.124332
Step 8602
max W vales: 0.759521 0.295101 0.34472 0.5839
max b vales: 0.110521 0.111747 0.115312 0.124365
Step 8603
max W vales: -3.40282e+38 -3.40282e+38 -3.40282e+38 -3.40282e+38
max b vales: -3.40282e+38 -3.40282e+38 -3.40282e+38 -3.40282e+38

由于我的值都不是很高,因此发生NaN的唯一方法是处理不正确的0/0,但是由于本教程代码没有进行任何除法或类似运算,因此我看不到其他解释,这是因为内部TF代码。

我对此一无所知。有什么建议么?该算法收敛良好,在我的验证集上的准确性稳步提高,在迭代8600时达到了92.5%。

参考资料:
Stack Overflow
收藏
评论
共 8 个回答
高赞 时间 活跃

我对长序列使用LSTM并得到了纳米梯度。这些答案都没有帮助我。但是我想出了三个自己的解决方案。我希望它们对从Google搜索来到这里的其他人有用。

  1. 渐变剪切对我没有帮助,因为渐变在一批更新中变成了Nan。在这种情况下,您可以使用以下几行将nans替换为零:

     opt = tf.train.AdamOptimizer(args.lr) grads = opt.compute_gradients(loss) grads2 = [(tf.where(tf.is_nan(grad), tf.zeros(grad.shape), grad), var) for grad, var in grads] opt_op = opt.apply_gradients(grads2) 

    如果要跟踪nans是否出现,可以使用以下代码:

     was_nan = tf.reduce_any(tf.convert_to_tensor([tf.reduce_any(tf.is_nan(g)) for g in grads])) 
  2. 用LayerNormBasicLSTMCell替换LSTMCell-具有层范数的LSTM单元格-类似于时间步之间的批处理范数。

  3. 如果您使用常规的循环状态丢失,则可以将其替换为“无内存丢失的循环丢失”。码:

     LayerNormBasicLSTMCell(neurons, dropout_keep_prob=0.8) 

    请注意,您也可以不使用图层归一化就单独打开辍学功能:

     LayerNormBasicLSTMCell(neurons, layer_norm=False, dropout_keep_prob=0.8) 
收藏
评论

如果y_conv是softmax的结果,例如y_conv = tf.nn.softmax(x) ,那么更好的解决方案是用log_softmax替换它:

y = tf.nn.log_softmax(x)
cross_entropy = -tf.reduce_sum(y_*y)
收藏
评论

无偏差的替代方案。

许多其他解决方案都使用裁剪来避免未定义的渐变。根据您的问题,削波会产生偏差,在所有情况下可能都不可接受。如以下代码所示,我们只需要处理不连续点-而不是它附近的区域。

具体答案

def cross_entropy(x, y, axis=-1):
  safe_y = tf.where(tf.equal(x, 0.), tf.ones_like(y), y)
  return -tf.reduce_sum(x * tf.log(safe_y), axis)

def entropy(x, axis=-1):
  return cross_entropy(x, x, axis)

但是行得通吗?

x = tf.constant([0.1, 0.2, 0., 0.7])
e = entropy(x)
# ==> 0.80181855
g = tf.gradients(e, x)[0]
# ==> array([1.30258512,  0.60943794, 0., -0.64332503], dtype=float32)  Yay! No NaN.

(注意:删除了dup cross-post 。)

一般食谱

使用内部tf.where来确保函数没有渐近线。也就是说,更改对inf生成功能的输入,以使无法创建inf。然后使用第二个tf.where始终选择有效的代码路径。也就是说,按照“正常”的方式实施数学条件,即“单纯”的实施方式。

在Python代码中,配方为:

代替这个:

tf.where(x_ok, f(x), safe_f(x))

做这个:

safe_x = tf.where(x_ok, x, safe_x)
tf.where(x_ok, f(safe_x), safe_f(x))

假设您要计算:

f(x) = { 1/x, x!=0
       { 0,   x=0

天真的实现会导致梯度的NaN,即

def f(x):
  x_ok = tf.not_equal(x, 0.)
  f = lambda x: 1. / x
  safe_f = tf.zeros_like
  return tf.where(x_ok, f(x), safe_f(x))

它行得通吗?

x = tf.constant([-1., 0, 1])
tf.gradients(f(x), x)[0].eval()
# ==> array([ -1.,  nan,  -1.], dtype=float32)
#  ...bah! We have a NaN at the asymptote despite not having
# an asymptote in the non-differentiated result.

使用tf.where时避免NaN梯度的基本模式是两次调用tf.where 。最里面的tf.where确保结果f(x)始终是有限的。最外层的tf.where确保选择了正确的结果。对于正在运行的示例,技巧如下所示:

def safe_f(x):
  x_ok = tf.not_equal(x, 0.)
  f = lambda x: 1. / x
  safe_f = tf.zeros_like
  safe_x = tf.where(x_ok, x, tf.ones_like(x))
  return tf.where(x_ok, f(safe_x), safe_f(x))

但是行得通吗?

x = tf.constant([-1., 0, 1])
tf.gradients(safe_f(x), x)[0].eval()
# ==> array([-1.,  0., -1.], dtype=float32)
# ...yay! double-where trick worked. Notice that the gradient
# is now a constant at the asymptote (as opposed to being NaN).
收藏
评论

实际上,事实证明这是愚蠢的。我发布此消息是为了防止其他人遇到类似错误。

cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))

实际上是计算交叉熵的一种可怕方法。在某些样本中,某些类可以在一段时间后确定地排除在外,导致该样本的y_conv = 0。这通常不是问题,因为您对此不感兴趣,但是通过在其中写入cross_entropy的方式,该特定样本/类的结果为0 * log(0)。因此,NaN。

替换为

cross_entropy = -tf.reduce_sum(y_*tf.log(tf.clip_by_value(y_conv,1e-10,1.0)))

解决了我所有的问题。

收藏
评论

2.0兼容答案 :用于从中迁移@ user1111929的答案的代码

Tensorflow 1.xTensorflow 2.x ,如下所示:

Tensorflow 1.x

cross_entropy = -tf.reduce_sum(y_*tf.log(tf.clip_by_value(y_conv,1e-10,1.0)))

Tensorflow 2.x

cross_entropy = -tf.compat.v2.reduce_sum(y_*tf.log(tf.compat.v2.clip_by_value(y_conv,1e-10,1.0)))

要么

cross_entropy = -tf.compat.v2.math.reduce_sum(y_*tf.log(tf.compat.v1.clip_by_value(y_conv,1e-10,1.0)))

收藏
评论

实际上,削波不是一个好主意,因为它将在达到阈值时阻止渐变向后传播。相反,我们可以向softmax输出添加一点常数。

cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv + 1e-10))
收藏
评论

有时候你使用tf.sqrt()函数不添加小恒1e-10在里面,这诱导nan问题。

收藏
评论

您正在尝试使用标准公式来计算交叉熵 。当x=0 ,不仅该值不确定,而且数值上也不稳定。

最好使用tf.nn.softmax_cross_entropy_with_logits,或者如果您真的想使用手工制作的公式, 则将tf.clip_by_value的零值减少到日志中的很小的值。

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号