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

Как работает индексация тензорного потока

У меня возникли проблемы с пониманием базовой концепции с тензорным потоком. Как работает индексирование для тензорных операций чтения/записи? Чтобы сделать это конкретным, как можно преобразовать следующие примеры numpy в tensorflow (используя тензоры для массивов, индексов и значений):

x = np.zeros((3, 4))
row_indices = np.array([1, 1, 2])
col_indices = np.array([0, 2, 3])
x[row_indices, col_indices] = 2
x

с выходом:

array([[ 0.,  0.,  0.,  0.],
       [ 2.,  0.,  2.,  0.],
       [ 0.,  0.,  0.,  2.]])

... и...

x[row_indices, col_indices] = np.array([5, 4, 3])
x

с выходом:

array([[ 0.,  0.,  0.,  0.],
       [ 5.,  0.,  4.,  0.],
       [ 0.,  0.,  0.,  3.]])

... и, наконец,...

y = x[row_indices, col_indices]
y

с выходом:

array([ 5.,  4.,  3.])
4b9b3361

Ответ 1

Там github issue # 206, чтобы поддержать это красиво, между тем вам придётся прибегать к подробным обходам

Первый пример можно сделать с помощью tf.select, который объединяет два одинаковых тензора, выбирая каждый элемент из одного или другого

tf.reset_default_graph()
row_indices = tf.constant([1, 1, 2])
col_indices = tf.constant([0, 2, 3])
x = tf.zeros((3, 4))
sess = tf.InteractiveSession()

# get list of ((row1, col1), (row2, col2), ..)
coords = tf.transpose(tf.pack([row_indices, col_indices]))

# get tensor with 1 at positions (row1, col1),...
binary_mask = tf.sparse_to_dense(coords, x.get_shape(), 1)

# convert 1/0 to True/False
binary_mask = tf.cast(binary_mask, tf.bool)

twos = 2*tf.ones(x.get_shape())

# make new x out of old values or 2, depending on mask 
x = tf.select(binary_mask, twos, x)

print x.eval()

дает

[[ 0.  0.  0.  0.]
 [ 2.  0.  2.  0.]
 [ 0.  0.  0.  2.]]

Второе можно сделать с помощью scatter_update, за исключением того, что scatter_update поддерживает только линейные индексы и работает с переменными. Таким образом, вы можете создать временную переменную и изменить ее форму. (чтобы избежать переменных, которые вы могли бы использовать dynamic_stitch, см. конец)

# get linear indices
linear_indices = row_indices*x.get_shape()[1]+col_indices

# turn 'x' into 1d variable since "scatter_update" supports linear indexing only
x_flat = tf.Variable(tf.reshape(x, [-1]))

# no automatic promotion, so make updates float32 to match x
updates = tf.constant([5, 4, 3], dtype=tf.float32)

sess.run(tf.initialize_all_variables())
sess.run(tf.scatter_update(x_flat, linear_indices,  updates))

# convert back into original shape
x = tf.reshape(x_flat, x.get_shape())

print x.eval()

дает

[[ 0.  0.  0.  0.]
 [ 5.  0.  4.  0.]
 [ 0.  0.  0.  3.]]

Наконец, третий пример уже поддерживается с помощью gather_nd, вы пишете

print tf.gather_nd(x, coords).eval()

Чтобы получить

[ 5.  4.  3.]

Изменить, 6 мая

Обновление x[cols,rows]=newvals может быть выполнено без использования переменных (которые занимают память между вызовами сеанса) с помощью select с sparse_to_dense, который принимает вектор разреженных значений или полагается на dynamic_stitch

sess = tf.InteractiveSession()
x = tf.zeros((3, 4))
row_indices = tf.constant([1, 1, 2])
col_indices = tf.constant([0, 2, 3])

# no automatic promotion, so specify float type
replacement_vals = tf.constant([5, 4, 3], dtype=tf.float32)

# convert to linear indexing in row-major form
linear_indices = row_indices*x.get_shape()[1]+col_indices
x_flat = tf.reshape(x, [-1])

# use dynamic stitch, it merges the array by taking value either
# from array1[index1] or array2[index2], if indices conflict,
# the later one is used 
unchanged_indices = tf.range(tf.size(x_flat))
changed_indices = linear_indices
x_flat = tf.dynamic_stitch([unchanged_indices, changed_indices],
                           [x_flat, replacement_vals])
x = tf.reshape(x_flat, x.get_shape())
print x.eval()