如何在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 CPUfor GPU注册了内核,因此没有理由认为自己在做其他事情。我没有fp16的丰富经验,所以我不确定零差是否为“正常”,但conv16似乎没有任何方式使用fp16卷积以外的任何东西。

09-06 19:46