tf.zeros() 的动态大小(用于具有 None 尺寸的占位符)

Dynamic size for tf.zeros() (for use with placeholders with None dimensions)

考虑以下代码:

x = tf.placeholder("float", shape=[42, 4])
y = tf.zeros([42, 4], "float")
xy_stacked = tf.concat(1, [x, y])

print(x.get_shape())
print(y.get_shape())
print(xy_stacked.get_shape())

这将按预期产生以下输出:

TensorShape([Dimension(42), Dimension(4)])
TensorShape([Dimension(42), Dimension(4)])
TensorShape([Dimension(42), Dimension(8)])

但是,如果占位符具有在 运行 时由传递给 feed_dict= 的值确定的动态维度,就像占位符经常做的那样:

x = tf.placeholder("float", shape=[None, 4])
y = tf.zeros([None, 4], "float")
xy_stacked = tf.concat(1, [x, y])

这将产生 tf.zeros([None, 4], "float") 的错误。显然 Dimension(None) 不允许 tf.zeros:

TypeError                                 Traceback (most recent call last)
<ipython-input-24-277eca38a392> in <module>()
      2 
      3 x = tf.placeholder("float", shape=[None, 4])
----> 4 y = tf.zeros([None, 4], "float")
      5 xy_stacked = tf.concat(1, [x, y])
      6 
[...]

/usr/local/lib/python3.4/dist-packages/numpy/core/_methods.py in _prod(a, axis, dtype, out, keepdims)
     33 
     34 def _prod(a, axis=None, dtype=None, out=None, keepdims=False):
---> 35     return umr_prod(a, axis, dtype, out, keepdims)
     36 
     37 def _any(a, axis=None, dtype=None, out=None, keepdims=False):

TypeError: unsupported operand type(s) for *: 'NoneType' and 'int'

我发现如果我将零张量的第一维设置为非 None,例如 1:

,它不会产生错误
x = tf.placeholder("float", shape=[None, 4])
y = tf.zeros([1, 4], "float")
xy_stacked = tf.concat(1, [x, y])

但是随后生成的 xy_stacked 张量 t运行 适合这个大小:

TensorShape([Dimension(None), Dimension(4)])
TensorShape([Dimension(1), Dimension(4)])
TensorShape([Dimension(1), Dimension(8)])

如何用零填充占位符张量,以便在此示例中得到形状为 TensorShape([Dimension(None), Dimension(8)]) 的张量?

到目前为止我发现的唯一 "solutions" 是以下内容之一:

x = tf.placeholder("float", shape=[None, 4])
y = 0 * x
xy_stacked = tf.concat(1, [x, y])

或者简单地将 y 声明为占位符并始终传递正确大小的零数组。

但这两个看起来都不是问题的干净解决方案,而且在比这个简单示例更复杂的应用程序中,这样的 hacks 很快就会失控。

我正在使用 tensorflow-0.6.0-py3

制作与另一个张量 相同 形状的零张量的推荐方法是使用 tf.zeros_like() op:

x = tf.placeholder(tf.float32, shape=[None, 4])
y = tf.zeros_like(x)

根据 Tensor.get_shape(),生成的张量 y 看起来具有 [None, None] 的形状,但在运行时它将扩展为与 x 相同的形状:

print y.get_shape()
# ==> TensorShape([Dimension(None), Dimension(None)])

sess = tf.Session()
y_result = sess.run(y, feed_dict={x: np.random.rand(4, 4)})

print y_result.shape
# ==> (4, 4)

返回 [None, None] 静态形状,因为形状推断尚未专门用于 tf.zeros_like()。我已经提交了一份 GitHub issue for that,它应该很快就会被修复。


编辑: 在您的评论中,您询问了如何处理零张量的形状基于但不同于[=39 的情况=] 原始张量。这也是可能的,使用 tf.shape() and tf.stack() to build the dimensions, and tf.fill() 产生零张量:

x = tf.placeholder(tf.float32, shape=[None, 4])

# Use tf.shape() to get the runtime size of `x` in the 0th dimension.
zeros_dims = tf.stack([tf.shape(x)[0], 7])

y = tf.fill(zeros_dims, 0.0)

sess = tf.Session()
y_result = sess.run(y, feed_dict={x: np.random.rand(4, 4)})
print y_result.shape
# ==> (4, 7)