我正在使用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)
解决了我所有的问题.
小智 26
实际上,剪切不是一个好主意,因为它会阻止渐变在达到阈值时向后传播.相反,我们可以为softmax输出添加一点常量.
cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv + 1e-10))
Run Code Online (Sandbox Code Playgroud)
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)
| 归档时间: |
|
| 查看次数: |
54437 次 |
| 最近记录: |