Tensorflow NaN bug?

use*_*929 58 nan tensorflow

我正在使用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())
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

由于我的值都不是很高,NaN可能发生的唯一方法是处理不当的0/0,但由于本教程代码没有进行任何划分或类似的操作,我看到没有其他解释,因为这来自于内部TF代码.

我对如何处理这件事毫无头绪.有什么建议?该算法很好地收敛,它在我的验证集上的准确性稳步攀升,在迭代8600时刚达到92.5%.

use*_*929 130

实际上,事实证明它是愚蠢的.我发布这个以防万一其他人会遇到类似的错误.

cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
Run Code Online (Sandbox Code Playgroud)

实际上是一种计算交叉熵的可怕方法.在一些样本中,某些类可以在一段时间后确定地排除,导致该样本的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)))
Run Code Online (Sandbox Code Playgroud)

解决了我所有的问题.

  • 很高兴你解决了!另外需要注意的是,如果你有的话,你可能会发现[convolutional.py](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/models/image/mnist/convolutional.py)是一个更好的起点处理实际数据.它在文件顶部用NUM_CHANNELS参数化,如果你将它从1切换到3,你最好使用RGB数据.我已经开始使用它来分类一些缩小到"mnist size"(28x28)的较大RGB数据集,并且它工作得相当不错.关键是使用tf.nn.softmax_cross_entropy_with_logits (12认同)
  • 为什么不只是[`tf.nn.softmax_cross_entropy_with_logits(labels = y_,logits = y)`](https://www.tensorflow.org/api_docs/python/tf/nn/softmax_cross_entropy_with_logits)(通常不需要手动剪辑日志) ),而不是你的`y_*tf.log(tf.clip_by_value(y_conv,1e-10,1.0))`?这在[初学者教程](https://www.tensorflow.org/get_started/mnist/beginners#training)中提到过. (4认同)

小智 26

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

cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv + 1e-10))
Run Code Online (Sandbox Code Playgroud)

  • 这正是我在网络中所做的事情,但是我在计算以下内容时仍然会得到NaN:`tf.log(1e-10 + 1 - 1)`.如果我打印出数据并在Excel中计算相同的值,我会得到正确的-23值. (2认同)

jvd*_*lon 20

无偏见的替代方案.

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

具体答案

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)
Run Code Online (Sandbox Code Playgroud)

但它有效吗?

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.
Run Code Online (Sandbox Code Playgroud)

(注意:删除dup cross-post.)

一般食谱

使用内部tf.where来确保函数没有渐近线.也就是说,改变inf生成函数的输入,使得不能创建inf.然后使用秒tf.where来始终选择有效的代码路径.也就是说,按照"正常"的方式实现数学条件,即"天真"实现.

在Python代码中,配方是:

而不是这个:

tf.where(x_ok, f(x), safe_f(x))
Run Code Online (Sandbox Code Playgroud)

做这个:

safe_x = tf.where(x_ok, x, safe_x)
tf.where(x_ok, f(safe_x), safe_f(x))
Run Code Online (Sandbox Code Playgroud)

假设你想要计算:

f(x) = { 1/x, x!=0
       { 0,   x=0
Run Code Online (Sandbox Code Playgroud)

天真的实现会在渐变中产生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))
Run Code Online (Sandbox Code Playgroud)

它有用吗?

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.
Run Code Online (Sandbox Code Playgroud)

使用时避免NaN梯度的基本模式tf.where是调用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))
Run Code Online (Sandbox Code Playgroud)

但它有效吗?

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).
Run Code Online (Sandbox Code Playgroud)


小智 13

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

y = tf.nn.log_softmax(x)
cross_entropy = -tf.reduce_sum(y_*y)
Run Code Online (Sandbox Code Playgroud)