最近我尝试使用float16训练TF中的CNN。令我惊讶的是,即使TF声称支持它一段时间,它仍以各种方式被打破。例如,无论网络如何,float16优化都会在第二步中导致NaN丢失。
import tensorflow as tf
import numpy as np
slim = tf.contrib.slim
dtype = tf.float16
shape = (4, 16, 16, 3)
inpt = tf.placeholder(dtype, shape, name='input')
net = slim.conv2d(inpt, 16, [3, 3], scope='conv',
weights_initializer=tf.zeros_initializer(),
# normalizer_fn=slim.batch_norm
)
loss = tf.reduce_mean(net)
opt = tf.train.AdamOptimizer(1e-3)
train_op = slim.learning.create_train_op(loss, opt)
val = np.zeros(shape)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for i in range(2):
print(sess.run(train_op, feed_dict={inpt: val}))
据我所知,这显然是一个错误:我在零输入上应用零卷积,我应该得到零梯度,不会改变零损失。它只是不能分歧。如果dtype是float32就行了。在CPU和GPU版本上都会发生NaN损失。
然而,我被解雇了GH问题,一个随机的家伙关闭了这个问题,说它是预期的行为:https://github.com/tensorflow/tensorflow/issues/7226
如果你用BN取消注释该线,它将在图形构建时间中断,因为BN假设移动平均线(和beta,gamma)总是float32并且不能正确地投射它们。这个问题也已关闭,显然被忽略了:https://github.com/tensorflow/tensorflow/issues/7164
我觉得我正在与ISP的第一线IT支持人员交谈。
当这样一个简单的“网络”失败时,有人可以解释我应该如何用float16训练吗?现在报告错误的推荐方法是什么?
答案 0 :(得分:13)
看起来你需要一个略大的epsilon以避免在AdamOptimizer中零时刻的数值不稳定(默认值为1e-8)。这适用于我的float16:
opt = tf.train.AdamOptimizer(1e-3, epsilon=1e-4)
请求基于dtype设置epsilon是合理的(并且可能是这样的请求,或者更好的是拉取请求,将在GitHub上遇到更积极的响应)。请注意,GradientDescentOptimizer没有此类问题。