TensorFlow筆記——(2) tf.group(), tf.tuple 和 tf.identity()

引言
最近在讀別人寫的代碼的時候看到下面的代碼。

update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS, first_clone_scope)
......
update_op = tf.group(*update_ops) 
1
2
3
不太明白這個group()函數的作用是什麼,於是上網進行了一番學習,在此記錄一下,也分享出來供新手參考。

理解
其實上網學習了之後,我才後知後覺的發現這個函數的作用也可以由它的名字猜測出來。group是分組的意思,其實該函數就是把update_ops(list)中的操作作爲一個組,把這些操作和成爲一個操作。除了group函數之外,tuple函數也有類似的功能,但是有一點細微的差別。
1. 首先是接受參數的形式不同。
group的參數是一個一個operation,而不是一個列表。這也是引言中的update_ops列表前需要加*的原因。
2. 返回值不同。
tf.group()返回的是op,tf.tuple()返回的是list of tensor。
如果還是不太理解的話可以看後面的例子,和下面的英文的api,英文的內容比較簡單,我就不翻譯了。
* 可以發現,如果我們有很多 tensor 或 op想要一起run,tf.group() 與 tf.tuple()兩個函數就是一個很好的幫手了。*

# TODO(touts): Accept "inputs" as a list.
def group(*inputs, **kwargs):
  """Create an op that groups multiple operations.

  When this op finishes, all ops in `inputs` have finished. This op has no
  output.

  See also @{tf.tuple$tuple} and
  @{tf.control_dependencies$control_dependencies}.

  Args:
    *inputs: Zero or more tensors to group.
    name: A name for this operation (optional).

  Returns:
    An Operation that executes all its inputs.

  Raises:
    ValueError: If an unknown keyword argument is provided.
  """
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def tuple(tensors, name=None, control_inputs=None)
Group tensors together.

This creates a tuple of tensors with the same values as the tensors argument, 
except that the value of each tensor is only returned after the values of all 
tensors have been computed.

control_inputs contains additional ops that have to finish before this op 
finishes, but whose outputs are not returned.

This can be used as a "join" mechanism for parallel computations: all the
argument tensors can be computed in parallel, but the values of any tensor
returned by tuple are only available after all the parallel computations 
are done.

See also group and with_dependencies.

Args:
tensors: A list of Tensors or IndexedSlices, some entries can be None.
name: (optional) A name to use as a name_scope for the operation.
control_inputs: List of additional ops to finish before returning.
Returns:
Same as tensors.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
例子1
w = tf.Variable(1)
mul = tf.multiply(w, 2)
add = tf.add(w, 2)
group = tf.group(mul, add)
tuple = tf.tuple([mul, add])
# sess.run(group)和sess.run(tuple)都會求Tensor(add)
#Tensor(mul)的值。區別是,tf.group()返回的是`op`
#tf.tuple()返回的是list of tensor。
#這樣就會導致,sess.run(tuple)的時候,會返回 Tensor(mul),Tensor(add)的值.
#而 sess.run(group)不會
1
2
3
4
5
6
7
8
9
10
tf.identity()
在學習tf.group()的時候,看到很多文章都是將tf.identity()和tf.group()放在一起辨析,就一起學習了。字面上來理解identity是恆等的意思,其實這就是一個賦值操作。在一般的情況下,我們使用賦值操作符=來進行賦值,例如y=x,表示將x的值賦值給y。但是在TensorFlow某些特殊的情況下是不支持這麼做的,原因是TensorFlow中的計算都是基於計算圖中的,計算圖的每個節點都是一個operation對象,所有以上的賦值操作也需要用一個賦值操作來表示,才能在計算圖中進行計算(賦值)。所以需要寫成y=tf.identity(x)。

例子2
下面程序要做的是,5次循環,每次循環給x加1,賦值給y,然後打印出來

x = tf.Variable(0.0)
#返回一個op,表示給變量x加1的操作
x_plus_1 = tf.assign_add(x, 1)

#control_dependencies的意義是,在執行with包含的內容(在這裏就是 y = x)前
#先執行control_dependencies中的內容(在這裏就是 x_plus_1)
with tf.control_dependencies([x_plus_1]):
    y = x
init = tf.initialize_all_variables()

with tf.Session() as session:
    init.run()
    for i in xrange(5):
        print(y.eval())#相當於sess.run(y),由於control_dependencies的所以執行print前都會先執行x_plus_1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
這個打印的是

0,0,0,0,0 
1
也就是說沒有達到我們預期的效果。
如果改成這樣:

x = tf.Variable(0.0)
x_plus_1 = tf.assign_add(x, 1)

with tf.control_dependencies([x_plus_1]):
    y = tf.identity(x)#修改部分
init = tf.initialize_all_variables()

with tf.Session() as session:
    init.run()
    for i in xrange(5):
        print(y.eval())
This works: it prints 1, 2, 3, 4, 5. 
1
2
3
4
5
6
7
8
9
10
11
12
這時候打印的是

1,2,3,4,5
1
可以看到,tf.identity的左右的是將普通的賦值語句變成一個操作。
但是第一種寫法爲什麼不work呢?
可以這樣解釋,雖然tf.control_dependencies參數中的op列表會在with包含的操作op執行之前先執行,但是y=x這個語句並不是一個op,而是一個tensor,所以執行y=x時,並不會執行tf.control_dependencies參數中的操作op。
所以可以將 y=x 修改爲 y=tf.identity(x),此時這個語句就是一個操作op,要先執行tf.control_dependencies參數中的op列表,再執行y=tf.identity(x)操作,最終輸出結果爲1.0 2.0 3.0 4.0 5.0,最終變量x的結果也爲5.0。

例子3
其實明白了上面例子爲什麼不能work之後,和group()函數的作用後。我們還有另一種改寫方法。

import tensorflow as tf  
x = tf.Variable(0.0)  
x_plus = tf.assign_add(x, 1)  
with tf.control_dependencies([x_plus]):#只有當內部爲操作時以來纔會生效  
    #y = tf.identity(x)#將該語句變爲操作  
    y = x  
    update = tf.group(y)#將該語句變爲操作  
init = tf.global_variables_initializer()  
with tf.Session() as session:  
    init.run()  
    for i in range(5):  
        session.run(update)  
        print(y.eval())  
    print(x.eval())#5  
————————————————
版權聲明:本文爲CSDN博主「Lavi_qq_2910138025」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/liuweiyuxiang/article/details/79953259

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章