Asignar op en TensorFlow: ¿cuál es el valor de retorno?

Estaba intentando construir un gráfico de autoincremento en TensorFlow. Pensé que la assign podría ser adecuada para eso, pero no encontré documentación para ello.

Asumí que esta operación devuelve su valor, como en los lenguajes tipo C, y escribí el siguiente código:

 import tensorflow as tf counter = tf.Variable(0, name="counter") one = tf.constant(1) ten = tf.constant(10) new_counter = tf.add(counter, one) assign = tf.assign(counter, new_counter) result = tf.add(assign, ten) init_op = tf.initialize_all_variables() with tf.Session() as sess: sess.run(init_op) for _ in range(3): print sess.run(result) 

y este código funciona.

La pregunta es: ¿es este el comportamiento esperado? ¿Por qué no se documenta la operación de asignación aquí: https://www.tensorflow.org/versions/0.6.0/api_docs/index.html

¿Es una operación no recomendada?

El operador tf.assign() es el mecanismo subyacente que implementa el método Variable.assign() . Toma un tensor mutable (con tf.*_ref Tipo de tf.*_ref ) y un nuevo valor, y devuelve un tensor mutable que se ha actualizado con el nuevo valor. El valor de retorno se proporciona para facilitar la ordenación de una asignación antes de una lectura posterior, pero esta función no está bien documentada. Esperemos que un ejemplo ilustre:

 v = tf.Variable(0) new_v = v.assign(10) output = v + 5 # `v` is evaluated before or after the assignment. sess.run(v.initializer) result, _ = sess.run([output, new_v.op]) print result # ==> 10 or 15, depending on the order of execution. 

 v = tf.Variable(0) new_v = v.assign(10) output = new_v + 5 # `new_v` is evaluated after the assignment. sess.run(v.initializer) result = sess.run([output]) print result # ==> 15 

En su ejemplo de código, las dependencias de flujo de datos imponen el orden de ejecución [read counter] -> new_counter = tf.add(...) -> tf.assign(...) -> [read output of assign] -> result = tf.add(...) , lo que significa que la semántica es inequívoca. Sin embargo , los pasos de lectura-modificación-escritura para actualizar el contador son algo ineficientes y pueden tener un comportamiento inesperado cuando hay varios pasos que se ejecutan simultáneamente. Por ejemplo, varios subprocesos que acceden a la misma variable podrían observar que el contador se mueve hacia atrás (en el caso de que un valor más antiguo se haya vuelto a escribir después de un valor más nuevo).

Le recomendaría que utilice Variable.assign_add() para actualizar el contador, de la siguiente manera:

 counter = tf.Variable(0, name="counter") one = tf.constant(1) ten = tf.constant(10) # assign_add ensures that the counter always moves forward. updated_counter = counter.assign_add(one, use_locking=True) result = tf.add(updated_counter, ten) # ... 

tf.assign() está bien documentado en las últimas versiones y se usa con frecuencia en los proyectos.

Esta operación genera “ref” después de que se realiza la asignación. Esto hace que sea más fácil encadenar las operaciones que necesitan usar el valor de restablecimiento.

En palabras más fáciles, toma tu tensor original y un nuevo tensor. Actualiza el valor original de su tensor con un nuevo valor y devuelve la referencia de su tensor original.