【问题标题】:Difference between tf.assign and assignment operator (=)tf.assign 和赋值运算符 (=) 的区别
【发布时间】:2017-08-20 06:53:22
【问题描述】:

我试图了解 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。

第三,我使用 both 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. 在使用 (=) 的第二个 sn-p 中,当我有 sess.run(a) 时,我似乎正在运行分配操作。那么“a = a+1”是否会在内部创建像assign_op = tf.assign(a, a+1) 这样的赋值操作?会话运行的操作真的只是assign_op吗?但是当我运行 a.eval() 时,它不会继续增加 a,因此看起来 eval 正在评估一个“静态”变量。

  2. 我不确定如何解释第三个 sn-p。为什么两个 eval 递增 a,而第二个 sn-p 中的两个 eval 不递增?

谢谢。

【问题讨论】:

    标签: tensorflow


    【解决方案1】:

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

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

    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 对象,而不是变量a 增加1。

    当您运行sess.run 时,您将通过add 运算符获取结果,而不会对原始a 变量产生副作用。

    另一方面,tf.assign 会产生更新会话下图状态的副作用。

    【讨论】:

      【解决方案2】:

      这里的主要混淆是执行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)
      

      考虑到这一点:

      在使用 (=) 的第二个 sn-p 中,当我有 sess.run(a) 时,我似乎正在运行一个分配操作。那么“a = a+1”是否会在内部创建像 assign_op = tf.assign(a, a+1) 这样的赋值操作? [...]

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

      我不知道如何解释第三个 sn-p。为什么两个 eval 增加 a,而第二个 sn-p 中的两个 eval 不增加?

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

      【讨论】:

      • 感谢您的解释!
      • 想了一会儿,有一个后续问题。 :) 在第二个 sn-p 中,“a = a + 1”将 add_op 分配给变量“a”,因此后续评估不会重复更改“a”值。但是,如果我运行 sess.run(a) 然后 a.eval(),那么 a.eval() 中 tf.add 中的“a”的值是多少?当它打印'2'时,'a'值应该仍然是1。但是'a'不是已经变成了add_op吗?如果是这样,add_op 第一次返回值 2,那么 sess.run(a) 之后的 a.eval() 应该打印 3?谢谢!
      • 尝试重命名变量并重构代码,以免重新分配 python 变量。这个借口应该说得够清楚了。同样,在第二个 sn-p 上没有 TF 变量赋值,所有直到加法的操作都是纯的。因此,结果总是一样的。
      【解决方案3】:

      对于 sn-p 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()
      

      这个sn-p 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
      

      have a look at tensorboard's computational graph

      注意点:

      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' 这是张量类型的对象。

      对于片段 2see computational graph, you'll get the idea (注意这里没有赋值操作的节点)

      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()
      

      sn-p 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
      

      对于片段 3Computational graph

      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()
      

      sn-p 3 的o/p:

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

      现在,如果您查看此 sn-p 的计算图,它看起来与 sn-p 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.Variable(1, name="Var_name_a")... 所以 5+1= 6 被分配给原始“a”,而这个原始“a”被分配给新的“a”。

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

      check the graph here

      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()
      

      上面sn-p的o/p:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-04-20
        • 2014-10-26
        • 1970-01-01
        • 2010-12-17
        • 1970-01-01
        相关资源
        最近更新 更多