如何在GPU上使用tensorflow使用fp16进行卷积? (使用__half或Eigen::half的python API)。
我想在tensorflow上使用fp16测试模型,但遇到问题。实际上,我发现 tensorflow 中的fp16卷积似乎将fp32卷积的结果转换为fp16,这不是我所需要的。
我试图给tf.nn.conv2d提供fp16格式的fp16输入,并给tf.nn.conv2d提供fp32格式的fp16输入(tf.cast到fp32),然后tf.cast结果到fp16,他们给出了完全相同的结果。
但是我认为,在fp16中进行卷积与在fp32中进行卷积然后将其转换为fp16是不同的吗?
请帮助我,谢谢。
environment:
ubuntu 16.04
tensorflow 1.9.0
cuda 9.0
Tesla V100
import tensorflow as tf
import numpy as np
import os
def conv16_32(input, kernel): # fake fp16 convolution
input = tf.cast(input, tf.float16)
kernel = tf.cast(kernel, tf.float16)
input = tf.cast(input, tf.float32)
kernel = tf.cast(kernel, tf.float32)
out = tf.nn.conv2d(input, kernel, [1,1,1,1], padding='VALID')
out = tf.cast(out, tf.float16)
out = tf.cast(out, tf.float64)
return out
def conv16(input, kernel): # real fp16 convolution
input = tf.cast(input, tf.float16)
kernel = tf.cast(kernel, tf.float16)
out = tf.nn.conv2d(input, kernel, [1,1,1,1], padding='VALID')
out = tf.cast(out, tf.float64)
return out
x = np.random.rand(16, 32, 32, 16).astype('float64')
w = np.random.rand(3, 3, 16, 16).astype('float64')
x = tf.get_variable('input', dtype=tf.float64, initializer=x)
w = tf.get_variable('weight', dtype=tf.float64, initializer=w)
out_16 = conv16(x, w)
out_16_32 = conv16_32(x, w)
os.environ['CUDA_VISIBLE_DEVICES'] = '1'
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
sess = tf.Session(config = config)
sess.run(tf.global_variables_initializer())
sess.run(tf.local_variables_initializer())
print(sess.run(tf.reduce_max(out_16_32 - out_16)))
上面两个函数给出相同的结果,说最终的“打印”结果为零。
fp16卷积和fp32卷积的结果不应该相同(在我看来)。
如何在GPU上使用真实的fp16使用Tensorflow进行卷积? (使用__half或Eigen::half的python API)
最佳答案
我认为您正确使用了这些操作。在您的示例中,您可以检查卷积运算的确确实具有正确的类型。
conv2d_op_16 = out_16.op.inputs[0].op
print(conv2d_op_16.name, conv2d_op_16.type, conv2d_op_16.get_attr('T'))
# Conv2D Conv2D <dtype: 'float16'>
conv2d_op_16_32 = out_16_32.op.inputs[0].op.inputs[0].op
print(conv2d_op_16_32.name, conv2d_op_16_32.type, conv2d_op_16_32.get_attr('T'))
# Conv2D_1 Conv2D <dtype: 'float32'>
而且TensorFlow确实为fp16 for CPU和for GPU注册了内核,因此没有理由认为自己在做其他事情。我没有fp16的丰富经验,所以我不确定零差是否为“正常”,但
conv16
似乎没有任何方式使用fp16卷积以外的任何东西。