有时张量的形状取决于在运行时计算的值。我们来看下面的例子,其中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]
这是显示两者的示意图: