我想为我创建的自定义模型学习最优的weights
和exponents
:
weights = tf.Variable(tf.zeros([t.num_features, 1], dtype=tf.float64))exponents = tf.Variable(tf.ones([t.num_features, 1], dtype=tf.float64))# 运行正常:pred = tf.matmul(x, weights)# 不工作:x_to_exponent = tf.mul(tf.sign(x), tf.pow(tf.abs(x), tf.transpose(exponents)))pred = tf.matmul(x_to_exponent, weights)cost_function = tf.reduce_mean(tf.abs(pred-y_))optimizer = tf.train.GradientDescentOptimizer(t.LEARNING_RATE).minimize(cost_function)
问题在于,每当x
中出现负值零时,优化器就会将权重返回为NaN
。如果我简单地在x=0时加上0.0001,一切都会按预期运行。但我真的需要这样做吗?TensorFlow优化器不应该有处理这种情况的方法吗?
我注意到维基百科上没有显示任何激活函数,其中x被取到指数。为什么没有像下图所示的激活函数?
对于上图,我希望我的程序能学习到正确的指数是0.5。
回答:
这是TensorFlow的正确行为,因为在那里的梯度是无穷大(并且许多数学上应该是无穷大的计算最终会因为不确定的极限而变成NaN)。
如果你想解决这个问题,稍微泛化的梯度裁剪可能会有效。你可以通过Optimizer.compute_gradients
获取梯度,手动通过类似于
safe_grad = tf.clip_by_value(tf.select(tf.is_nan(grad), 0, grad), -lim, lim)
的方式对它们进行裁剪,然后将裁剪后的梯度传递给Optimizer.apply_gradients
。在接近奇点的地方,梯度可能非常大,因此需要裁剪以防止爆炸。
警告:没有保证这种方法一定会有效,特别是对于较深的网络,NaN可能会污染网络的大片区域。