2017-04-21 35 views
10

Próbuję zdefiniować niestandardowe op w tensorflow, w którym w pewnym momencie muszę zbudować macierz (z), która zawierałaby sumy wszystkich kombinacji par rzędów dwóch macierzy (x i y). Ogólnie numery wierszy x i y są dynamiczne.Oceń wszystkie kombinacje par rzędów dwóch tensorów w tensorflow

W numpy jest dość prosta:

import numpy as np 
from itertools import product 

rows_x = 4 
rows_y = 2 
dim = 2 

x = np.arange(dim*rows_x).reshape(rows_x, dim) 
y = np.arange(dim*rows_y).reshape(rows_y, dim) 

print('x:\n{},\ny:\n{}\n'.format(x, y)) 

z = np.zeros((rows_x*rows_y, dim)) 
print('for loop:') 
for i, (x_id, y_id) in enumerate(product(range(rows_x), range(rows_y))): 
    print('row {}: {} + {}'.format(i, x[x_id, ], y[y_id, ])) 
    z[i, ] = x[x_id, ] + y[y_id, ] 

print('\nz:\n{}'.format(z)) 

powraca:

x: 
[[0 1] 
[2 3] 
[4 5] 
[6 7]], 
y: 
[[0 1] 
[2 3]] 

for loop: 
row 0: [0 1] + [0 1] 
row 1: [0 1] + [2 3] 
row 2: [2 3] + [0 1] 
row 3: [2 3] + [2 3] 
row 4: [4 5] + [0 1] 
row 5: [4 5] + [2 3] 
row 6: [6 7] + [0 1] 
row 7: [6 7] + [2 3] 

z: 
[[ 0. 2.] 
[ 2. 4.] 
[ 2. 4.] 
[ 4. 6.] 
[ 4. 6.] 
[ 6. 8.] 
[ 6. 8.] 
[ 8. 10.]] 

Ja jednak nie mam pojęcia jak zaimplementować coś podobnego w tensorflow.

Przeważnie przechodziłam przez SO i tensorflow API w nadziei znalezienia funkcji, która dawałaby kombinacje elementów dwóch tensorów lub funkcję, która dawałaby permutacje elementów tensora, ale bez skutku.

Wszelkie sugestie są mile widziane.

Odpowiedz

9

Można po prostu użyć zdolności nadawania tensorflow.

import tensorflow as tf 

x = tf.constant([[0, 1],[2, 3],[4, 5],[6, 7]], dtype=tf.float32) 
y = tf.constant([[0, 1],[2, 3]], dtype=tf.float32) 

x_ = tf.expand_dims(x, 0) 
y_ = tf.expand_dims(y, 1) 
z = tf.reshape(tf.add(x_, y_), [-1, 2]) 

sess = tf.Session() 
sess.run(z) 
+3

To magia ... Tak więc, żeby to naprawić: najpierw rozszerzasz 'x' i' y', tak, że 'x_' ma kształt [1, 4, 2], a' y_' ma kształt [3, 1, 2]. A następnie, zdolność nadawania tf.add "określa" jak wypełnić wymiary na [3, 4, 2] (co jest kształtem 'tf.add (x_, y_)'), a na końcu , 'tf.reshape' zapewnia, że ​​mamy 2 kolumny w' z'. "Odkrycie" jest kluczową częścią, i jak czytam [tutaj] (https://www.tensorflow.org/performance/xla/broadcasting): ... – ponadto

+0

... "Gdy są dwie kompatybilne tablice napotkany, kształt wyniku ma maksymalną wartość spośród dwóch danych wejściowych dla każdego indeksu wymiarów. ", a następnie:" Powstaje specjalny przypadek, który jest również obsługiwany, gdzie każda z tablic wejściowych ma zdegenerowany wymiar przy innym indeksie. W przypadku, wynik jest "operacją zewnętrzną" .To subtelne. Dziękuję za tę odpowiedź! – ponadto

1

Wariant 1

Określenie z jako zmienna i uaktualnia swoje rzędy:

import tensorflow as tf 
from itertools import product 


x = tf.constant([[0, 1],[2, 3],[4, 5],[6, 7]],dtype=tf.float32) 
y = tf.constant([[0, 1],[2, 3]],dtype=tf.float32) 

rows_x,dim=x.get_shape() 
rows_y=y.get_shape()[0] 

z=tf.Variable(initial_value=tf.zeros([rows_x*rows_y,dim]),dtype=tf.float32) 
for i, (x_id, y_id) in enumerate(product(range(rows_x), range(rows_y))): 
    z=tf.scatter_update(z,i,x[x_id]+y[y_id]) 

with tf.Session() as sess: 
    tf.global_variables_initializer().run() 
    z_val=sess.run(z) 
    print(z_val) 

ten drukuje

[[ 0. 2.] 
[ 2. 4.] 
[ 2. 4.] 
[ 4. 6.] 
[ 4. 6.] 
[ 6. 8.] 
[ 6. 8.] 
[ 8. 10.]] 

opcja 2

Tworzenie z rzut listowych:

import tensorflow as tf 
from itertools import product 


x = tf.constant([[0, 1],[2, 3],[4, 5],[6, 7]],dtype=tf.float32) 
y = tf.constant([[0, 1],[2, 3]],dtype=tf.float32) 

rows_x,dim=x.get_shape().as_list() 
rows_y=y.get_shape().as_list()[0] 


z=[x[x_id]+y[y_id] for x_id in range(rows_x) for y_id in range(rows_y)] 
z=tf.reshape(z,(rows_x*rows_y,dim)) 

with tf.Session() as sess: 
    z_val=sess.run(z) 
    print(z_val) 

Porównanie: Drugie rozwiązanie jest około dwa razy szybciej (tylko pomiar budowę z w obu rozwiązaniach). W szczególności czasy są następujące: pierwsze rozwiązanie: 0,211 sekundy, drugie rozwiązanie: 0,137 sekundy.

+0

Czas budowy jest zwykle nieprawidłową miarą wydajności, ponieważ zdarza się tylko raz; nikt nie dba o różnicę <1s czasu startowego. Byłbym o wiele bardziej zainteresowany wiedząc, czy istnieje różnica czasu wydajności wywnioskowania. – Multihunter