如何给 TensorFlow 变量赋值?

88

我正在尝试在Python中为TensorFlow变量分配新值。

import tensorflow as tf
import numpy as np

x = tf.Variable(0)
init = tf.initialize_all_variables()
sess = tf.InteractiveSession()
sess.run(init)

print(x.eval())

x.assign(1)
print(x.eval())

但我得到的输出是

0
0

所以价值并没有改变,我错过了什么?

8个回答

135
在TF1中,语句x.assign(1)并不会直接将值1赋给x,而是创建了一个tf.Operation对象,你需要显式地运行它以更新变量。可以使用Operation.run()Session.run()来运行该操作:
assign_op = x.assign(1)
sess.run(assign_op)  # or `assign_op.op.run()`
print(x.eval())
# ==> 1

(实际上,它返回一个tf.Tensor,对应于变量的更新值,以便更轻松地进行链式赋值。)

但是,在TF2中,x.assign(1)现在会急切地赋值:

x.assign(1)
print(x.numpy())
# ==> 1

assign_op.run() 会报错:AttributeError: 'Tensor' object has no attribute 'run'。但是 sess.run(assign_op) 运行得非常好。 - abora
在这个例子中,在执行assign操作 / 可变张量之前,Variable x 存储在内存中的数据是否被覆盖,还是创建了一个新的张量来存储更新后的值? - dannygoldstein
3
assign() 的当前实现会覆盖已有的数值。 - mrry
1
有没有一种方法可以为Variable分配一个新值,而不在图形中创建任何其他操作?似乎每个变量已经为其创建了一个Assign操作,但调用my_var.assign()tf.assign()会创建一个新的操作,而不是使用现有的操作。 - Nathan
我不确定这是否与此相关,但您可以将张量参数(如数学运算)赋给assign。通过这种方式创建一个计数器,在每次评估分配操作时更新该计数器:op = t.assign(tf.add(t, 1)) - Eliel Van Hojman

43

您还可以为tf.Variable分配新值,而不必向图形中添加操作:tf.Variable.load(value, session)。该函数还可以在从图形外部分配值时节省添加占位符,并且在图形完成后很有用。

import tensorflow as tf
x = tf.Variable(0)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
print(sess.run(x))  # Prints 0.
x.load(1, sess)
print(sess.run(x))  # Prints 1.

更新:由于TF2中急切执行是默认的,而且图形不再在用户界面API中暴露,因此此方法已被弃用。


2
注意:你不能加载具有与变量初始值形状不同的数组! - Rajarshee Mitra
1
Variable.load(来自tensorflow.python.ops.variables)已被弃用,并将在未来版本中删除。 更新说明: 请使用Variable.assign,其在2.X中具有等效行为。不确定如何在Tensorflow 2.0中更改变量的值而不向图形添加操作。 - João Abrantes

15

首先,您可以通过将值直接传递给变量/常量来为它们分配值,就像使用占位符一样。因此,这样做是完全合法的:

import tensorflow as tf
x = tf.Variable(0)
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print sess.run(x, feed_dict={x: 3})

关于您对tf.assign() 运算符的疑惑。在TF中,只有在会话内运行时才会执行任何操作。因此,您总是需要像这样做:op_name = tf.some_function_that_create_op(params),然后在会话内运行sess.run(op_name)。以assign为例,您需要这样做:

import tensorflow as tf
x = tf.Variable(0)
y = tf.assign(x, 1)
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print sess.run(x)
    print sess.run(y)
    print sess.run(x)

@RobinDinse,是的。在上面的例子中,您的标准输出为0、1、1。 - Rajarshee Mitra
4
请注意,通过feed_dict传递变量的值并不会永久地将该值分配给变量,而仅在该次运行调用中有效。 - Robin Dinse
@RobinDinse,我如何永久分配该值?如果可以的话,请查看我的问题:https://stackoverflow.com/questions/53141762/tensorflow-how-to-assign-an-updated-numpy?noredirect=1#comment93177616_53141762 - volperossa

4
此外,需要注意的是,如果您正在使用your_tensor.assign(),则无需显式调用tf.global_variables_initializer,因为赋值操作会在后台自动执行初始化。
例如:
In [212]: w = tf.Variable(12)
In [213]: w_new = w.assign(34)

In [214]: with tf.Session() as sess:
     ...:     sess.run(w_new)
     ...:     print(w_new.eval())

# output
34 

然而,这并不会初始化所有的变量,而只会初始化在执行 assign 的变量。


1
我在这里回答了一个类似的问题。我查找了很多地方,但问题总是相同的。基本上,我不想给权重赋值,只想改变权重。以上答案的简短版本如下: tf.keras.backend.set_value(tf_var, numpy_weights)

0

这里是完整的工作示例:

import numpy as np
import tensorflow as tf

w= tf.Variable(0, dtype=tf.float32) #good practice to set the type of the variable
cost = 10 + 5*w + w*w
train = tf.train.GradientDescentOptimizer(0.01).minimize(cost)

init = tf.global_variables_initializer()
session = tf.Session()
session.run(init)

print(session.run(w))

session.run(train)
print(session.run(w)) # runs one step of gradient descent

for i in range(10000):
  session.run(train)

print(session.run(w))

请注意输出将为:

0.0
-0.049999997
-2.499994

这意味着在最开始时,变量为0,如定义的一样,然后经过一步梯度下降后,变量为-0.049999997,在进行了10,000个步骤后,我们达到了-2.499994(基于我们的成本函数)。

注意:您最初使用了交互式会话。当需要在同一脚本中运行多个不同会话时,交互式会话非常有用。但是,出于简单起见,我使用了非交互式会话。


0
请使用最新的TensorFlow即时执行模式。
import tensorflow as tf
tf.enable_eager_execution()
my_int_variable = tf.get_variable("my_int_variable", [1, 2, 3])
print(my_int_variable)

-10

有一个更简单的方法:

x = tf.Variable(0)
x = x + 1
print x.eval()

3
O.P. 正在研究 tf.assign 的用法,而不是加法。 - vega

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