python 2.7 - examples - Cómo hacer la asignación de segmentos en Tensorflow
tensorflow gpu (3)
Encontré que Tensorflow proporciona scatter_update()
para asignar valores a la porción de un tensor en la dimensión 0. Por ejemplo, si el tensor T
es tridimensional, puedo asignar el valor v[1, :, :]
a T[i, :, :]
.
a = tf.Variable(tf.zeros([10,36,36]))
value = np.ones([1,36,36])
d = tf.scatter_update(a,[0],value)
with tf.Session() as sess:
sess.run(tf.initialize_all_variables())
print a.eval()
sess.run(d)
print a.eval()
Pero, ¿cómo asignar valores v[1,1,:]
a T[i,j,:]
?
a = tf.Variable(tf.zeros([10,36,36]))
value1 = np.random.randn(1,1,36)
e = tf.scatter_update(a,[0],value1) #Error
with tf.Session() as sess:
sess.run(tf.initialize_all_variables())
print a.eval()
sess.rum(e)
print a.eval()
¿Hay alguna otra función que proporcione TF o una forma sencilla de hacer esto?
Actualmente, puede realizar la asignación de segmentos para las variables en TensorFlow. No hay una función específica para él, pero puede seleccionar una porción y assign
una assign
:
my_var = my_var[4:8].assign(tf.zeros(4))
Primero, tenga en cuenta que (después de haber consultado la documentación ) parece que el valor de retorno de la assign
, incluso cuando se aplica a un sector, es siempre una referencia a toda la variable después de aplicar la actualización.
EDITAR: La información a continuación está en desuso, es imprecisa o siempre fue incorrecta. El hecho es que el valor devuelto de assign
es un tensor que se puede usar fácilmente y ya incorpora la dependencia a la asignación, por lo que simplemente evaluarlo o usarlo en otras operaciones garantizará que se ejecute sin la necesidad de un bloque explícito tf.control_dependencies
.
Tenga en cuenta, también, que esto solo agregará la asignación de operación al gráfico, pero no la ejecutará a menos que se ejecute explícitamente o se establezca como una dependencia de alguna otra operación. Una buena práctica es usarlo en un contexto tf.control_dependencies
:
with tf.control_dependencies([my_var[4:8].assign(tf.zeros(4))]):
my_var = tf.identity(my_var)
Puede leer más sobre esto en el número #4638 TensorFlow.
Creo que lo que necesita es el assign_slice_update
discutido en el ticket # 206 . Aún no está disponible, sin embargo.
ACTUALIZACIÓN: Esto ahora está implementado. Vea la respuesta de jdehesa: https://.com/a/43139565/6531137
Hasta que haya disponible assign_slice_update
(o scatter_nd()
), puede crear un bloque de la fila deseada que contenga los valores que no desea modificar junto con los valores que desea actualizar, de esta manera:
import tensorflow as tf
a = tf.Variable(tf.ones([10,36,36]))
i = 3
j = 5
# Gather values inside the a[i,...] block that are not on column j
idx_before = tf.concat(1, [tf.reshape(tf.tile(tf.Variable([i]), [j]), [-1, 1]), tf.reshape(tf.range(j), [-1, 1])])
values_before = tf.gather_nd(a, idx_before)
idx_after = tf.concat(1, [tf.reshape(tf.tile(tf.Variable([i]), [36-j-1]), [-1, 1]), tf.reshape(tf.range(j+1, 36), [-1, 1])])
values_after = tf.gather_nd(a, idx_after)
# Build a subset of tensor `a` with the values that should not be touched and the values to update
block = tf.concat(0, [values_before, 5*tf.ones([1, 36]), values_after])
d = tf.scatter_update(a, i, block)
with tf.Session() as sess:
sess.run(tf.initialize_all_variables())
sess.run(d)
print(a.eval()[3,4:7,:]) # Print a subset of the tensor to verify
El ejemplo genera un tensor de unos y realiza a[i,j,:] = 5
. La mayor parte de la complejidad radica en obtener los valores que no queremos modificar, a[i,~j,:]
(de lo contrario, scatter_update()
reemplazará esos valores).
Si desea ejecutar T[i,k,:] = a[1,1,:]
como pidió, debe reemplazar 5*tf.ones([1, 36])
en el ejemplo anterior por tf.gather_nd(a, [[1, 1]])
.
Otro enfoque sería crear una máscara para seleccionar tf.select()
los elementos deseados de ella y asignarlo de nuevo a la variable, como tal:
import tensorflow as tf
a = tf.Variable(tf.zeros([10,36,36]))
i = tf.Variable([3])
j = tf.Variable([5])
# Build a mask using indices to perform [i,j,:]
atleast_2d = lambda x: tf.reshape(x, [-1, 1])
indices = tf.concat(1, [atleast_2d(tf.tile(i, [36])), atleast_2d(tf.tile(j, [36])), atleast_2d(tf.range(36))])
mask = tf.cast(tf.sparse_to_dense(indices, [10, 36, 36], 1), tf.bool)
to_update = 5*tf.ones_like(a)
out = a.assign( tf.select(mask, to_update, a) )
with tf.Session() as sess:
sess.run(tf.initialize_all_variables())
sess.run(out)
print(a.eval()[2:5,5,:])
Es potencialmente menos eficiente en términos de memoria, ya que requiere el doble de memoria para manejar la variable a to_update
, pero puede modificar fácilmente este último ejemplo para obtener una operación de preservación de gradiente del nodo tf.select(...)
. También podría interesarle ver esta otra pregunta de : Asignación condicional de valores de tensor en TensorFlow .
Esas contorsiones poco elegantes deben reemplazarse por una llamada a la función TensorFlow adecuada a medida que esté disponible.
El tf.scatter_update
puede modificar el tensor en la primera dimensión. Como se indica en la documentación,
Índices: un tensor. Debe ser uno de los siguientes tipos: int32, int64. Un tensor de índices en la primera dimensión de la ref.
Puedes usar la función scatter_nd_update
para hacer lo que quieras. Como se muestra a continuación, que he probado.
a = tf.Variable(tf.zeros([10,36,36]))
value1 = np.random.randn(1,36)
e = tf.scatter_nd_update(a,[[0,1]],value1)
init= tf.global_variables_initializer()
sess.run(init)
print(a.eval())
sess.run(e)