如何在TensorFlow中改变变量的形状?

23

TensorFlow 教程 指出,在创建张量时,我们需要指定张量的形状。该形状自动成为张量的形状。它还指出,TensorFlow 提供了高级机制来重新塑造变量。我该怎么做?有任何代码示例吗?


1
现在行为已经改变了,如果将shape作为参数指定,形状不再自动变成变量的形状。请参见下面的答案。 - Mayou36
6个回答

20
tf.Variable类是创建变量的推荐方法,但它限制了您在创建变量后更改变量形状的能力。

如果您需要更改变量的形状,可以按照以下步骤操作(例如,对于32位浮点张量):

var = tf.Variable(tf.placeholder(tf.float32))
# ...
new_value = ...  # Tensor or numpy array.
change_shape_op = tf.assign(var, new_value, validate_shape=False)
# ...
sess.run(change_shape_op)  # Changes the shape of `var` to new_value's shape.

请注意,此功能不包含在公开文档的API中,因此可能会发生变化。如果您确实需要使用此功能,请告诉我们,我们可以研究一种支持它继续前进的方法。


1
这种方法的问题在于var.shape没有相应地更新。当存储检查点时,这种情况会持续存在,从而防止再次加载检查点,因为变量形状与权重形状不匹配。有没有一种方法可以强制更新var.shape?我应该创建一个GitHub问题吗? - Michael Gygli
我发现了这个讨论问题的线程:https://github.com/tensorflow/tensorflow/issues/10091#issuecomment-304301817。不过,我想知道是否有一种方法可以扩展现有网络的权重。 - Michael Gygli

5
请看 TensorFlow 文档中的 shapes-and-shaping,了解不同的形状变换。其中最常用的函数可能是 tf.reshape,它类似于 numpy 的等效函数。只要元素数量保持不变,就可以指定任何所需的形状。文档中提供了一些示例。

这不会改变变量的形状,而是返回一个张量,该张量具有变量的值,但具有新的形状。 - Mayou36

4

文档展示了重新调整形状的方法,包括:

  • reshape
  • squeeze(从张量形状中删除大小为1的维度)
  • expand_dims(添加大小为1的维度)

此外还有一些方法可以获取您的张量的shapesizerank。可能最常用的是reshape,以下是一个带有一些特殊情况(-1)的代码示例:

import tensorflow as tf

v1 = tf.Variable([
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12]
])
v2 = tf.reshape(v1, [2, 6])
v3 = tf.reshape(v1, [2, 2, -1])
v4 = tf.reshape(v1, [-1])
# v5 = tf.reshape(v1, [2, 4, -1]) will fail, because you can not find such an integer for -1
v6 = tf.reshape(v1, [1, 4, 1, 3, 1])
v6_shape = tf.shape(v6)
v6_squeezed = tf.squeeze(v6)
v6_squeezed_shape = tf.shape(v6_squeezed)

init = tf.initialize_all_variables()

sess = tf.Session()
sess.run(init)
a, b, c, d, e, f, g = sess.run([v2, v3, v4, v6, v6_shape, v6_squeezed, v6_squeezed_shape])
# print all variables to see what is there
print e # shape of v6
print g # shape of v6_squeezed

2
tf.Variable(tf.placeholder(tf.float32))

在TensorFlow 1.2.1中无效。

在Python Shell中:

import tensorflow as tf
tf.Variable(tf.placeholder(tf.float32))

您将获得以下内容:

ValueError: initial_value must have a shape specified: Tensor("Placeholder:0", dtype=float32)

更新:如果您添加 validate_shape=False,则不会出现错误。
tf.Variable(tf.placeholder(tf.float32), validate_shape=False)

如果tf.py_func符合您的要求:
def init():
    return numpy.random.rand(2,3)
a = tf.pyfun(init, [], tf.float32)

通过传递自己的初始化函数,您可以创建任何形状的变量。

另一种方法:

var = tf.get_varible('my-name', initializer=init, shape=(1,1))

你可以传递 tf.constant 或任何返回 numpy 数组的 init 函数。提供的形状将不会得到验证,输出的形状是你真实数据的形状。

1

tf.Variable:使用None参数进行shape定义

在1.14版本中增加了一个特性,允许指定未知形状。

如果shapeNone,则使用初始形状值。

如果指定了shape,则将其用作形状并允许有None

示例:

var = tf.Variable(array, shape=(None, 10))

这样可以后续使用与上述形状相匹配的形状分配值(例如,轴0中的任意形状)。

var.assign(new_value)


1
正如Mayou36所说,您现在可以在首次声明后更改变量形状。以下是一个可行的示例:
v = tf.Variable([1], shape=tf.TensorShape(None), dtype=tf.int32) 
tf.print(v)
v.assign([1, 1, 1])
tf.print(v)

并且这将输出:

[1]
[1 1 1]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接