2016-08-26 17 views
11

Znalazłem, że Tensorflow zapewnia scatter_update(), aby przypisać wartości do plastra tensora w wymiarze 0. Na przykład, jeśli tensor T ma trzy wymiary, mogę przypisać wartość v[1,:,:] do T[i,:,:].Jak wykonać przypisanie przekroju w Tensorflow

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() 

Ale jak przypisać wartości v[1,1,:] do 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() 

Czy istnieje jakaś inna funkcja, którą zapewnia TF lub prosty sposób na zrobienie tego?

Odpowiedz

6

Wierzę, że to, czego potrzebujesz, to assign_slice_update omówione w ticket #206. Nie jest jeszcze dostępna.

AKTUALIZACJA: To jest teraz zaimplementowane. Zobacz jdehesa za odpowiedź: https://stackoverflow.com/a/43139565/6531137


Do assign_slice_update (lub scatter_nd()) jest dostępny, można zbudować blok żądanego wiersza zawierającego wartości, których nie chcesz zmodyfikować wraz z pożądanymi wartościami zaktualizować, jak sposób:

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 

Przykład generowania tensora jedynek i wykonuje a[i,j,:] = 5. Większość złożoności polega na uzyskaniu wartości, których nie chcemy modyfikować, a[i,~j,:] (w przeciwnym razie scatter_update() zastąpi te wartości).

Jeśli chcesz wykonać polecenie T[i,k,:] = a[1,1,:] na żądanie, musisz zastąpić 5*tf.ones([1, 36]) w poprzednim przykładzie przez tf.gather_nd(a, [[1, 1]]).

Innym podejściem byłoby utworzenie maski tf.select() odpowiednich elementów z nią i przypisać go do zmiennych, w następujący sposób:

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

jest potencjalnie mniej skuteczne w zakresie pamięci od wymaga dwukrotnie pamięć do obsługi zmiennej a-like to_update, ale można łatwo zmodyfikować ten ostatni przykład, aby uzyskać operację zachowywania gradientu z węzła tf.select(...). Możesz być także zainteresowany patrząc na to inne pytanie StackOverflow: Conditional assignment of tensor values in TensorFlow.

Te nieeleganckie zakłócenia należy zastąpić wywołaniem odpowiedniej funkcji TensorFlow, gdy stanie się ona dostępna.

+0

Dzięki za szczegółowy przykład! Jak powiedziałeś, obecny sposób jest nieco nieelegancki. Mam nadzieję, że funkcja 'assign_slice_update' będzie dostępna wkrótce. – user270700

+0

tf.select został zastąpiony przez tf.where w tensorflow 1. –

14

Obecnie można wykonać przypisanie przekroju dla zmiennych w TensorFlow. Nie ma określonego funkcja o nazwie dla niego, ale można wybrać kawałek i nazywają assign na nim:

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

Uwaga jednak, że to będzie tylko dodać op przypisania do wykresu, ale nie będzie go uruchomić, chyba że jest jawnie wykonywane lub ustawione jako zależność innej operacji. Dobrą praktyką jest użycie go w kontekście tf.control_dependencies:

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

Możesz przeczytać więcej na ten temat w TensorFlow emisji #4638 (skąd skopiowano przykłady).

+1

To powinno być teraz zaakceptowaną odpowiedzią. – user1735003