tf.assign 和赋值运算符 (=) 之间的区别



我试图了解tf.assign 和赋值运算符(=(之间的区别。我有三组代码

首先,使用简单的 tf.assign

import tensorflow as tf
with tf.Graph().as_default():
a = tf.Variable(1, name="a")
assign_op = tf.assign(a, tf.add(a,1))
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print sess.run(assign_op)
print a.eval()
print a.eval()

输出预期为

2
2
2

二、使用赋值运算符

import tensorflow as tf
with tf.Graph().as_default():
a = tf.Variable(1, name="a")
a = a + 1
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print sess.run(a)
print a.eval()
print a.eval()

结果仍然是 2、2、2。

第三,我同时使用 tf.assign 和赋值运算符

import tensorflow as tf
with tf.Graph().as_default():
a = tf.Variable(1, name="a")
a = tf.assign(a, tf.add(a,1))
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print sess.run(a)
print a.eval()
print a.eval()

现在,输出变为 2、3、4。

我的问题是

  1. 在使用 (=( 的第二个代码段中,当我有 sess.run(a( 时,似乎我正在运行一个赋值操作。那么"a = a+1"是否在内部创建了一个像assign_op = tf.assign(a, a+1(这样的赋值操作?会话运行的操作真的只是assign_op吗?但是当我运行 a.eval(( 时,它不会继续递增 a,因此看起来 eval 正在评估一个"静态"变量。

  2. 我不确定如何解释第三个片段。为什么两个 eval 递增 a,而第二个代码段中的两个 eval 不增加?

谢谢。

这里的主要混淆是,执行a = a + 1会将 Python 变量a重新分配给加法运算的结果张量a + 1。 另一方面,tf.assign是用于设置 TensorFlow 变量值的操作。

a = tf.Variable(1, name="a")
a = a + 1

这相当于:

a = tf.add(tf.Variable(1, name="a"), 1)

考虑到这一点:

在使用 (=( 的第二个代码段中,当我有 sess.run(a( 时,似乎我正在运行一个赋值操作。那么"a = a+1"是否在内部创建了一个像assign_op = tf.assign(a, a+1(这样的赋值操作?[...]

它可能看起来如此,但不是真的。如上所述,这只会重新分配 Python 变量。如果没有tf.assign或任何其他更改变量的操作,它将保持值 1。每次评估a时,程序将始终计算a + 1 => 1 + 1

我不确定如何解释第三个片段。为什么两个 eval 递增 a,而第二个代码段中的两个 eval 不增加?

这是因为在第三个代码段中的赋值张量上调用eval()也会触发变量赋值(请注意,这与对当前会话执行session.run(a)没有太大区别(。

首先,anwser并不是很精确。IMO,python对象和tf对象之间没有区别。它们都是由python GC管理的内存对象。

如果将第二个a更改为b,并打印出变量,

In [2]: g = tf.Graph()
In [3]: with g.as_default():
...:     a = tf.Variable(1, name='a')
...:     b = a + 1
...:
In [4]: print(a)
<tf.Variable 'a:0' shape=() dtype=int32_ref>
In [5]: print(b)
Tensor("add:0", shape=(), dtype=int32)
In [6]: id(a)
Out[6]: 140253111576208
In [7]: id(b)
Out[7]: 140252306449616

ab不会引用内存中的同一对象。

绘制计算图或内存图

一线,

# a = tf.Varaible(...
a -> var(a)

二线,

# b = a + 1
b -> add - var(a)
|
-- 1

现在,如果将其替换回b = a + 1a = a + 1,则分配操作后的a指向tf.add对象,而不是递增 1 的变量a

当你运行sess.run时,你正在通过该add运算符获取结果,对原始a变量没有副作用。

另一方面,tf.assign将具有更新会话下图形状态的副作用。

对于片段 1

with tf.Graph().as_default():
a = tf.Variable(1, name="a_var")
assign_op = tf.assign(a, tf.add(a,1,name='ADD'))
b = tf.Variable(112)
b = b.assign(a)  
print(a)
print(b)
print(assign_op)  
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())    
print (sess.run(a))      
print ("assign_op : ",sess.run(assign_op))    
print("         b :- ",b.eval())
print (sess.run(a))
print (sess.run(a))    
print ("assign_op : ",sess.run(assign_op))
print (sess.run(a))  
print (sess.run(a))     
writer = tf.summary.FileWriter("/tmp/log", sess.graph)
writer.close()

此代码段 1 的 O/P:

<tf.Variable 'a_var:0' shape=() dtype=int32_ref>
Tensor("Assign_1:0", shape=(), dtype=int32_ref)
Tensor("Assign:0", shape=(), dtype=int32_ref)
1
assign_op :  2
b :-  2
2
2
assign_op :  3
3
3

看看TensorBoard的计算图

注意事项:

  1. 计算第一个变量"A",因此得到 O/P : 1
  2. next sess.run(assign_op(, executes => assign_op = tf.assign(a, tf.add(a,1,name='ADD'((,它具有更新变量 'a'(=2( 并创建 'assign_op' 的效果,这是对象的张量类型。

对于片段 2:请参阅计算图,你会明白 (请注意,没有用于赋值操作的节点(

with tf.Graph().as_default():
a = tf.Variable(1, name="Var_a")
just_a = a + 1  
print(a)
print(just_a)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print (sess.run(a))  
print (sess.run(a))   
print ("just_a : ",sess.run(just_a))    
print (sess.run(a))
print (sess.run(a))
print ("just_a : ",sess.run(just_a)) 
print (sess.run(a))  
print (sess.run(a)) 
writer = tf.summary.FileWriter("/tmp/log", sess.graph)
writer.close()

代码段 2 的 O/P:

enter code here
<tf.Variable 'Var_a:0' shape=() dtype=int32_ref>
Tensor("add:0", shape=(), dtype=int32)
1
1
just_a :  2
1
1
just_a :  2
1
1

对于代码段 3:计算图

with tf.Graph().as_default():
a = tf.Variable(1, name="Var_name_a")
a = tf.assign(a, tf.add(a,5))
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())    
print (sess.run(a))  
print (sess.run(a))
print ("        a : ",sess.run(a))
print (sess.run(a))
print (sess.run(a))
print ("         a : ",sess.run(a))
print (sess.run(a))  
print (sess.run(a))        
writer = tf.summary.FileWriter("/tmp/log", sess.graph)
writer.close()

代码段 3 的 O/P:

enter code here
6
11
a :  16
21
26
a :  31
36
41

现在,如果您查看此代码段的计算图,它看起来与代码段 1 的计算图相似/精确。但这里的问题是代码 a = tf.assign(a, tf.add(a,5((,不仅更新变量 'a',还再次创建另一个张量 'a'。

现在刚刚创建的"A"将被使用

print (sess.run(a))

这个 'a' 将是 a = tf.assign(a, tf.add(a,5((

来自 tf.add(a,5( 的"a"只不过是 'a'(=1( => a = tf。变量(1, 名称="Var_name_a"(...所以 5+1=6 被分配给原来的"a",这个原来的"a"被分配给新的"a"。

我还有一个例子一次解释这个概念

在此处查看图表

enter code here
with tf.Graph().as_default():
w = tf.Variable(10,name="VAR_W") #initial val = 2
init_op = tf.global_variables_initializer()
# Launch the graph in a session.
with tf.Session() as sess:
# Run the variable initializer.
sess.run(init_op)
print(w.eval())
print(w) #type of 'w' before assign operation
#CASE:1
w = w.assign(w + 50)#adding 100 to var w
print(w.eval())      
print(w) #type of 'w' after assign operation
# now if u try  =>  w = w.assign(w + 50), u will get error bcoz newly 
created 'w' is considered here which don't have assign attribute
#CASE:2    
w = tf.assign(w, w + 100) #adding 100 to var w
print(w.eval())  
#CASE:3    
w = tf.assign(w, w + 300) #adding 100 to var w
print(w.eval())    
writer = tf.summary.FileWriter("/tmp/log", sess.graph)
writer.close()

上面代码段的 o/p:

10
<tf.Variable 'VAR_W:0' shape=() dtype=int32_ref>
60
Tensor("Assign:0", shape=(), dtype=int32_ref)
210
660

最新更新