Wie mache ich das innere Produkt im Tensorflow?
-
16-10-2019 - |
Frage
Ich habe zwei Tensor a:[batch_size, dim]
b:[batch_size, dim]
. Ich möchte für jedes Paar in der Charge innere Produkte machen und generieren c:[batch_size, 1]
, wo c[i,0]=a[i,:].T*b[i,:]
. Wie?
Lösung
Es gibt keinen Einheimischen .dot_product
Methode. Ein Punktprodukt zwischen zwei Vektoren ist jedoch nur ein elementanter Multiplikum, sodass das folgende Beispiel funktioniert:
import tensorflow as tf
# Arbitrarity, we'll use placeholders and allow batch size to vary,
# but fix vector dimensions.
# You can change this as you see fit
a = tf.placeholder(tf.float32, shape=(None, 3))
b = tf.placeholder(tf.float32, shape=(None, 3))
c = tf.reduce_sum( tf.multiply( a, b ), 1, keep_dims=True )
with tf.Session() as session:
print( c.eval(
feed_dict={ a: [[1,2,3],[4,5,6]], b: [[2,3,4],[5,6,7]] }
) )
Die Ausgabe ist:
[[ 20.]
[ 92.]]
Andere Tipps
Eine weitere Option, die es wert ist, überprüft zu werden, ist [tf.einsum][1]
- Es ist im Wesentlichen eine vereinfachte Version von Einstein Notation.
Nachfolger mit den Beispielen von Neil und Dumkar:
import tensorflow as tf
a = tf.placeholder(tf.float32, shape=(None, 3))
b = tf.placeholder(tf.float32, shape=(None, 3))
c = tf.einsum('ij,ij->i', a, b)
with tf.Session() as session:
print( c.eval(
feed_dict={ a: [[1,2,3],[4,5,6]], b: [[2,3,4],[5,6,7]] }
) )
Das erste Argument an einsum
ist eine Gleichung, die die Achsen darstellt, die multipliziert und summiert werden. Die Grundregeln für eine Gleichung sind:
- Eingangstensoren werden durch eine von Kommas getrennte Reihe von Dimensionsmarken beschrieben
- Wiederholte Etiketten zeigen, dass die entsprechenden Abmessungen multipliziert werden
- Der Ausgangstensor wird durch eine andere Reihe von Dimensionsmarken beschrieben, die entsprechende Eingänge (oder Produkte) darstellen,
- Etiketten, die in der Ausgangszeichenfolge fehlen
In unserem Fall, ij,ij->i
bedeutet, dass unsere Eingaben 2 Matrizen gleicher Form betragen werden (i,j)
, und unsere Ausgabe wird ein Formvektor sein (i,)
.
Sobald Sie den Dreh raus haben, werden Sie das finden einsum
verallgemeinert eine große Anzahl anderer Operationen:
X = [[1, 2]]
Y = [[3, 4], [5, 6]]
einsum('ab->ba', X) == [[1],[2]] # transpose
einsum('ab->a', X) == [3] # sum over last dimension
einsum('ab->', X) == 3 # sum over both dimensions
einsum('ab,bc->ac', X, Y) == [[13,16]] # matrix multiply
einsum('ab,bc->abc', X, Y) == [[[3,4],[10,12]]] # multiply and broadcast
Leider, einsum
Ernimmt einen ziemlich kräftigen Leistungsakt im Vergleich zu einer manuellen Multiplikum+Reduzierung. Wo die Leistung kritisch ist, würde ich auf jeden Fall empfehlen, bei Neils Lösung zu bleiben.
Einnahme der Diagonale von tf.tenSudot Tut auch das, was Sie wollen, wenn Sie die Achse auf z. B. einstellen
[[1], [1]]
Ich habe das Beispiel von Neil Slater angepasst:
import tensorflow as tf
# Arbitrarity, we'll use placeholders and allow batch size to vary,
# but fix vector dimensions.
# You can change this as you see fit
a = tf.placeholder(tf.float32, shape=(None, 3))
b = tf.placeholder(tf.float32, shape=(None, 3))
c = tf.diag_part(tf.tensordot( a, b, axes=[[1],[1]]))
with tf.Session() as session:
print( c.eval(
feed_dict={ a: [[1,2,3],[4,5,6]], b: [[2,3,4],[5,6,7]] }
) )
was jetzt auch gibt:
[ 20. 92.]
Dies könnte jedoch für große Matrizen suboptimal sein (siehe Diskussion hier)