如何理解TensorFlow中的静态形状和动态形状?

How to understand static shape and dynamic shape in TensorFlow?

TensorFlow FAQ中说:

In TensorFlow, a tensor has both a static (inferred) shape and a dynamic (true) shape. The static shape can be read using the tf.Tensor.get_shape() method: this shape is inferred from the operations that were used to create the tensor, and may be partially complete. If the static shape is not fully defined, the dynamic shape of a Tensor t can be determined by evaluating tf.shape(t).

但是我还是不能完全理解静态形状和动态形状之间的关系。有什么例子可以说明它们的区别吗?谢谢

有时张量的形状取决于在运行时计算的值。让我们来看下面的例子,其中 x 被定义为具有四个元素的 tf.placeholder() 向量:

x = tf.placeholder(tf.int32, shape=[4])
print x.get_shape()
# ==> '(4,)'

x.get_shape()的值是x的静态形状,而(4,)表示它是一个长度为4的向量。现在让我们应用tf.unique() 选择 x

y, _ = tf.unique(x)
print y.get_shape()
# ==> '(?,)'

(?,)表示y是一个未知长度的向量。为什么不为人知? tf.unique(x) returns 来自 x 的唯一值和 x 的值是未知的,因为它是 tf.placeholder(),所以直到你喂它。让我们看看如果您提供两个不同的值会发生什么:

sess = tf.Session()
print sess.run(y, feed_dict={x: [0, 1, 2, 3]}).shape
# ==> '(4,)'
print sess.run(y, feed_dict={x: [0, 0, 0, 0]}).shape
# ==> '(1,)'

希望这能说明张量可以具有不同的静态和动态形状。动态形状始终是完全定义的——它没有 ? 维度——但静态形状可以不那么具体。这就是允许 TensorFlow 支持 tf.unique()tf.dynamic_partition() 等操作的原因,它们可以具有可变大小的输出,并用于高级应用程序。

最后,tf.shape() op 可用于获取张量的动态形状并将其用于 TensorFlow 计算:

z = tf.shape(y)
print sess.run(z, feed_dict={x: [0, 1, 2, 3]})
# ==> [4]
print sess.run(z, feed_dict={x: [0, 0, 0, 0]})
# ==> [1]

这是显示两者的示意图:

上面的回答定义的很好,投了赞成票。我还有一些观察,所以我想分享一下。

tf.Tensor.get_shape(),可用于使用创建它的操作来推断输出,这意味着我们可以在不使用 sess.run()(运行 操作)的情况下推断它,顾名思义,静态形状。 例如,

c=tf.random_uniform([1,3,1,1])

是一个 tf.Tensor,我们想在代码中的任何一步都知道它的形状,在 运行 生成图形之前,所以我们可以使用

c.get_shape()

tf.Tensor.get_shape无法动态的原因(sess.run())是因为输出类型 TensorShape 而不是 tf.tensor,输出 TensorShape 限制 sess.run().

的使用

sess.run(c.get_shape())

如果我们这样做,我们会收到一个错误,指出 TensorShape 的类型无效,它必须是 Tensor/operation 或字符串。

另一方面,动态形状需要通过sess.run()运算运行得到形状

sess.run(tf.shape(c))

Output: array([1, 3, 1, 1])

or

sess.run(c).shape

(1, 3, 1, 1) # tuple

希望它有助于阐明 tensorflow 概念。

Tensorflow 2.0 Compatible Answer:在Tensorflow Version 2.x (> 2.0)中提到mrry在他的答案中指定的代码,因为社区的利益。

# Installing the Tensorflow Version 2.1
!pip install tensorflow==2.1

# If we don't Disable the Eager Execution, usage of Placeholder results in RunTimeError

tf.compat.v1.disable_eager_execution()

x = tf.compat.v1.placeholder(tf.int32, shape=[4])
print(x.get_shape())

# ==> 4

y, _ = tf.unique(x)
print(y.get_shape())

# ==> (None,)

sess = tf.compat.v1.Session()
print(sess.run(y, feed_dict={x: [0, 1, 2, 3]}).shape)
# ==> '(4,)'
print(sess.run(y, feed_dict={x: [0, 0, 0, 0]}).shape)
# ==> '(1,)'

z = tf.shape(y)
print(sess.run(z, feed_dict={x: [0, 1, 2, 3]}))
# ==> [4]
print(sess.run(z, feed_dict={x: [0, 0, 0, 0]}))
# ==> [1]