1. 程式人生 > >tf.identity && tf.control_dependencies

tf.identity && tf.control_dependencies

tf.identity && tf.control_dependencies

下面是關於這兩個函式用途的介紹:

tf.identity

tf.identity is useful when you want to explicitly transport tensor between devices (like, from GPU to a CPU). The op adds send/recv nodes to the graph, which make a copy when the devices of the input and the output are different.

換句話說,tf.identity是為了顯示地轉化Tensor的儲存裝置,例如可以在CPU以及GPU中轉化。經過tf.identity(x)相當於產生了一個x完整的copy。下面是這個函式實現的程式碼:

if context.executing_eagerly():
    input = ops.convert_to_tensor(input)
    in_device = input.device
    # TODO(ashankar): Does 'identity' need to invoke execution callbacks?
    context_device = context.context().device_name
    if
not context_device: context_device = "/job:localhost/replica:0/task:0/device:CPU:0" if context_device != in_device: return input._copy() # pylint: disable=protected-access return input else: return gen_array_ops.identity(input, name=name)

tf.control_dependencies

這個函式會在with程式碼快中,僅包含一個引數control_inputs

,也就是程式碼快中的op在執行之前首先需要執行這個引數中的op。如果with程式碼塊中沒有形成新的op,那麼這個管理器就相當於失效了。下面是TF官方關於這個引數的介紹。

  • control_inputs: A list of Operation or Tensor objects which must be executed or computed before running the operations defined in the context. Can also be None to clear the control dependencies. If eager execution is enabled, any callable object in the control_inputs list will be called.

一個例子

下面程式的功能是,做5次迴圈,每次迴圈給x加1,賦值給y,然後打印出來,所以我們預期達到的效果是輸出2,3,4,5,6。

x = tf.Variable(1.0)
y = 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,1,1,1,1 。可以看到,沒有達到我們預期的效果,y只被賦值了一次。

如果改成這樣:

x = tf.Variable(1.0)
y = 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())

這時候列印的是2,3,4,5,6

解釋:對於control_dependencies這個管理器,只有當裡面的操作是一個op時,才會生效,也就是先執行傳入的引數op,再執行裡面的op。而y=x僅僅是tensor的一個簡單賦值,不是定義的op,所以在圖中不會形成一個節點,這樣該管理器就失效了。tf.identity是返回一個一模一樣新的tensor的op,這會增加一個新節點到gragh中,這時control_dependencies就會生效,所以第二種情況的輸出符合預期。