Подтвердить что ты не робот

Как назначить slice в Tensorflow

Я обнаружил, что Tensorflow предоставляет scatter_update() для присвоения значений срезу тензора в измерении 0. Например, если тензор T трехмерен, я могу присвоить значение v[1, :, :] 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()

Но как присвоить значения v[1,1,:] 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()

Есть ли какая-либо другая функция, которую обеспечивает TF, или простой способ сделать это?

4b9b3361

Ответ 1

Я считаю, что вам нужно assign_slice_update, описанное в билет # 206. Он пока недоступен.

UPDATE: теперь это реализовано. См. Ответ jdehesa: fooobar.com/questions/156922/...


До появления assign_slice_update (или scatter_nd()) вы можете создать блок нужной строки, содержащий значения, которые вы не хотите изменять вместе с требуемыми значениями для обновления, например:

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

Пример генерирует тензор единиц и выполняет a[i,j,:] = 5. Большая часть сложности заключается в получении значений, которые мы не хотим изменять, a[i,~j,:] (иначе scatter_update() заменит эти значения).

Если вы хотите выполнить T[i,k,:] = a[1,1,:] по вашему запросу, вам нужно заменить 5*tf.ones([1, 36]) в предыдущем примере на tf.gather_nd(a, [[1, 1]]).

Другим подходом было бы создать маску для tf.select() желаемых элементов из нее и присвоить ее переменной, как таковой:

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,:])

Он потенциально менее эффективен с точки зрения памяти, поскольку он требует в два раза больше памяти для обработки переменной a -like to_update, но вы можете легко изменить этот последний пример, чтобы получить операцию сохранения градиента от tf.select(...) node. Вам также может быть интересно посмотреть на этот другой вопрос StackOverflow: Условное назначение тензорных значений в TensorFlow.

Эти неэлегантные искажения должны быть заменены на вызов правильной функции TensorFlow по мере ее появления.

Ответ 2

В настоящее время вы можете назначать срезы для переменных в TensorFlow. Для него нет определенной именованной функции, но вы можете выбрать срез и вызвать для него assign:

my_var = my_var[4:8].assign(tf.zeros(4))

Во-первых, обратите внимание, что (после просмотра документации) кажется, что возвращаемое значение assign, даже когда применяется к срезу, всегда является ссылкой на всю переменную после применения обновления.

РЕДАКТИРОВАТЬ: приведенная ниже информация является устаревшей, неточной или всегда была неправильной. Дело в том, что возвращаемое значение assign является тензором, который может быть легко использован и уже включает в себя зависимость от присваивания, поэтому простая оценка этого или использование его в дальнейших операциях обеспечит его выполнение без необходимости явного блока tf.control_dependencies,


Также обратите внимание, что это только добавит операцию присваивания в граф, но не запустит его, если оно явно не выполнено или не установлено как зависимость какой-либо другой операции. Хорошей практикой является использование его в контексте tf.control_dependencies:

with tf.control_dependencies([my_var[4:8].assign(tf.zeros(4))]):
    my_var = tf.identity(my_var)

Вы можете прочитать больше об этом в выпуске TensorFlow № 4638.

Ответ 3

tf.scatter_update может модифицировать тензор в первом измерении. Как указано в документации,

индексы: Тензор. Должен быть одного из следующих типов: int32, int64. Тензор индексов в первом измерении исх.

Вы можете использовать функцию scatter_nd_update чтобы делать то, что вы хотите. Как показано ниже, который я протестировал.

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)