Wie mache ich ein Batch-Innenprodukt in Tensorflow?

10

Ich habe zwei Tensoren a:[batch_size, dim] b:[batch_size, dim]. Ich möchte inneres Produkt für jedes Paar in der Charge machen c:[batch_size, 1], wo erzeugen c[i,0]=a[i,:].T*b[i,:]. Wie?

HenrySky
quelle

Antworten:

9

Es gibt keine native .dot_productMethode. Ein Punktprodukt zwischen zwei Vektoren wird jedoch nur elementweise multipliziert, 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.]]
Neil Slater
quelle
Es hat mein Problem gelöst, danke!
HenrySky
1
tf.mul ist jetzt tf.multiply. github.com/tensorflow/tensorflow/issues/7032
Rahul Jha
1
Es gibt anscheinend nichts, was TF-Entwickler mehr lieben, als die API zu ändern ...
Emre
6

Eine weitere Option, die es wert ist, überprüft zu werden, ist [tf.einsum][1]- es handelt sich im Wesentlichen um eine vereinfachte Version der Einstein-Notation .

Nach 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 dafür einsumist eine Gleichung, die die zu multiplizierenden und zu summierenden Achsen darstellt. Die Grundregeln für eine Gleichung sind:

  1. Eingangstensoren werden durch eine durch Kommas getrennte Folge von Bemaßungsbezeichnungen beschrieben
  2. Wiederholte Beschriftungen zeigen an, dass die entsprechenden Abmessungen multipliziert werden
  3. Der Ausgangstensor wird durch eine andere Folge von Dimensionsbezeichnungen beschrieben, die entsprechende Eingaben (oder Produkte) darstellen.
  4. Beschriftungen, die in der Ausgabezeichenfolge fehlen, werden summiert

In unserem Fall ij,ij->ibedeutet dies, dass unsere Eingaben 2 Matrizen gleicher Form (i,j)sind und unsere Ausgabe ein Formvektor ist (i,).

Sobald Sie den Dreh raus haben, werden Sie feststellen, dass dies einsumeine Vielzahl anderer Operationen verallgemeinert:

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 ist einsumdie Leistung im Vergleich zu einer manuellen Multiplikation + Reduzierung ziemlich stark. Wenn die Leistung entscheidend ist, würde ich definitiv empfehlen, an Neils Lösung festzuhalten.

wynn
quelle
3

Wenn Sie die Diagonale von tf.tensordot nehmen, tun Sie auch, was Sie wollen, wenn Sie die Achse auf z

[[1], [1]]

Ich habe Neil Slaters Beispiel 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 kann jedoch für große Matrizen suboptimal sein (siehe Diskussion hier ).

Dumkar
quelle
1
Der Marsch des Fortschritts :-), ich bin nicht sicher, in welcher API-Version dies hinzugefügt wurde? Ich schlage vor, Ihre Antwort mit einem kurzen Beispiel zu erweitern (vielleicht basierend auf meinem, aber es sollte einfacher sein, da es das nicht braucht reduce_sum)
Neil Slater
Ich habe das Beispiel hinzugefügt! Tatsächlich gibt es auch nicht diagonale Punktprodukte, wenn Sie tf.diag_part nicht verwenden, sodass Ihre Antwort wahrscheinlich schneller sein wird. Ich bin mir nicht sicher, in welcher API-Version tf.tensordot eingeführt wurde, aber es könnte lange her sein, dass es auch in numpy verfügbar ist.
Dumkar
Würde dies nicht viel mehr Speicher benötigen als das elementweise Multiplizieren und Summieren?
Kbrose