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

Posted

技术标签:

【中文标题】如何理解 TensorFlow 中的静态形状和动态形状?【英文标题】:How to understand static shape and dynamic shape in TensorFlow? 【发布时间】:2016-09-02 22:25:55 【问题描述】:

在TensorFlow FAQ 中,它说:

在 TensorFlow 中,张量同时具有静态(推断)形状和 动态(真实)形状。静态形状可以使用 tf.Tensor.get_shape() 方法:这个形状是从 用于创建张量的操作,可能是部分操作 完全的。如果静态形状未完全定义,则动态形状 可以通过评估 tf.shape(t) 来确定张量 t 的大小。

但我仍然不能完全理解静态形状和动态形状之间的关系。有没有例子表明它们之间的差异?谢谢。

【问题讨论】:

【参考方案1】:

有时张量的形状取决于在运行时计算的值。我们来看下面的例子,其中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) 返回来自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]

这是显示两者的示意图:

【讨论】:

我可以使用带有可学习层的动态形状吗?如果我使用较小的输入,权重会怎样? 通常需要静态知道可学习参数的形状,但输入可以具有可变的批量大小。【参考方案2】:

在上面的答案中定义得很好,投票赞成。我经历了更多的观察,所以我想分享一下。

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 的类型无效,它必须是张量/操作或字符串。

另一方面,动态形状需要通过 sess.run() 运行操作来获取形状

sess.run(tf.shape(c))

输出:数组([1, 3, 1, 1])

sess.run(c).shape

(1, 3, 1, 1) # 元组

希望它有助于澄清 tensorflow 概念。

【讨论】:

【参考方案3】:

Tensorflow 2.0 兼容答案:提及 mrry 在他的答案中指定的代码,在 Tensorflow Version 2.x (> 2.0) 中,为了社区的利益。

# 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]

【讨论】:

有没有办法在 tensorflow 2.0 和 tf.keras中有 inferred shapedynamic shape >

以上是关于如何理解 TensorFlow 中的静态形状和动态形状?的主要内容,如果未能解决你的问题,请参考以下文章

tensorflow学习笔记

如何将动态形状调整到另一个形状

tensorflow中张量(tensor)的属性——维数(阶)形状和数据类型

TensorFlow SparseCategoricalCrossentropy 是如何工作的?

如何修复Tensorflow中的“ValueError:操作数无法与形状(2592,)(4,)一起广播”?

TensorFlow-静态图和PyTorch-动态图区别