GPU 上的 tf.reduce_sum 结合占位符作为输入形状失败

Posted

技术标签:

【中文标题】GPU 上的 tf.reduce_sum 结合占位符作为输入形状失败【英文标题】:tf.reduce_sum on GPU fails in combination with placeholder as input shape 【发布时间】:2018-09-06 07:20:17 【问题描述】:

更新: 在 Tensorflow 1.14.0 中修复(可能更早,没有检查)

更新: 仍在 Tensorflow 1.7.0 中发生

更新: 我写了一个协作笔记本,在 google 的 gpu 硬件上重现了这个 bug:https://drive.google.com/file/d/13V87kSTyyFVMM7NoJNk9QTsCYS7FRbyz/view?usp=sharing

更新: 在这个问题的第一次修订中错误地指责tf.gather 之后,我现在将其缩小到tf.reduce_sum 并结合占位符作为形状:

tf.reduce_sum 为形状取决于占位符的大张量生成零(仅在 GPU 上)。

在向占位符batch_size(在我的例子中为>700000)提供一个大整数时运行以下代码:

import tensorflow as tf
import numpy as np

graph = tf.Graph()
with graph.as_default():
    batch_size = tf.placeholder(tf.int32,shape=[])
    ones_with_placeholder = tf.ones([batch_size,256,4])
    sum_out = tf.reduce_sum(ones_with_placeholder,axis=2)
    min_sum_out = tf.reduce_min(sum_out)

sess = tf.Session(graph=graph)

sum_result,min_sum_result = sess.run([sum_out,min_sum_out],feed_dict=batch_size: 1000000)
print("Min value in sum_out processed on host with numpy:", np.min(sum_result))
print("Min value in sum_out tensor processed in graph with tf:", min_sum_result)

显示以下错误结果:

Min value in sum_out processed on host with numpy: 0.0
Min value in sum_out tensor processed in graph with tf: 0.0

我原以为在轴 2 上应用 reduce_sum 应该会导致到处都是 4.0!

在 CPU 上运行这个精确的代码会导致正确的结果。同样使用 tf.ones 的固定形状运行它会在 CPU 和 GPU 上产生正确的结果:

ones_with_fixed_shape = tf.ones([1000000,256,4])
sum_out = tf.reduce_sum(ones_with_fixed_shape,axis=2)

GPU 上的占位符有什么问题?

【问题讨论】:

感谢您对我提出的答案的澄清评论。我认为,如果您将问题编辑为具有发生这种行为的确定性(非随机)情况,那将是非常有益的。这可能是一个错误,但需要一个具体的、易于重现的示例来验证是否是这种情况。 IMO 你能做的最好的事情就是编辑掉(现在不必要的)细节,更新标题并提供一个简洁的代码 sn-p 允许任何人简单地通过复制粘贴来重现问题。我相信你会找到问题的答案:) 似乎与数组的数据类型有关。我尝试了:ones_with_placeholder = tf.ones([batch_size,256,4], dtype=tf.int64) 并得到了预期的结果。如果未明确指定,则使用的默认类型是tf.float32。这可能是数字溢出问题吗? 是的,我能够使用您提供的代码复制问题。我很好奇这种行为的原因是什么!我编辑添加了几个import 语句,所以现在任何人都可以通过复制粘贴来尝试它。 通过一些实验,它确实可以在您的代码中输入多达 524,288 (2 ^ 19) 个,失败为 524,289,这将使占位符的最大 ok 大小为 2 ^ ( 19 + 10 (256 x 4) + 2 ( 对于 float32 ) = 2 ^ 31,这看起来像是可以存储在 int32 中的大小。 【参考方案1】:

基本问题是速度/准确性之间的权衡。尽管您的示例看起来微不足道,但将整个张量初始化为 1,但仍有 1.024B 个条目。注意 int32 可以表示范围内的整数 [-2,147,483,648 到 2,147,483,647] 不损失精度:

因此,如果我们累积所有条目并执行计算,我们预计会看到一些错误。这也解释了为什么较小的矩阵没有出现问题(较小的 Batch 大小)。

【讨论】:

不,这不是问题所在。如果你看一下sum_out,在第一维(取决于batch_size)的某个阈值之前它是正确的(都是4.0s),但是sum_out 的最后一个条目都是零。所以这不是精度损失,而是硬失败。至少如果你想像我一样计算块错误率......

以上是关于GPU 上的 tf.reduce_sum 结合占位符作为输入形状失败的主要内容,如果未能解决你的问题,请参考以下文章

tf.reduce_sum函数

tf.reduce_sum()函数

TFboy养成记 tf.cast,tf.argmax,tf.reduce_sum

几种模型评价指标实现代码

Tensorflow - tf常用函数使用(持续更新中)

tensorflow学习