Tensorflowでバッチ内積を行う方法は?


10

回答:


9

ネイティブ.dot_productメソッドはありません。ただし、2つのベクトル間の内積は、要素ごとに乗算合計されるため、次の例は機能します。

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]] }
    ) )

出力は次のとおりです。

[[ 20.]
 [ 92.]]

それは私の問題を解決しました、thx!
HenrySky 2016年

1
tf.mulはtf.multiplyになりました。github.com/tensorflow/tensorflow/issues/7032
Rahul Jha

1
TF開発者がAPIを変更することほど好きなものはないようです
Emre

6

チェックする価値のあるもう1つのオプションは[tf.einsum][1]、本質的にEinstein Notationの簡易バージョンです。

ニールとダンカーの例に続いて:

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]] }
    ) )

の最初の引数einsumは、乗算および合計される軸を表す方程式です。方程式の基本的なルールは次のとおりです。

  1. 入力テンソルは、次元ラベルのコンマ区切りの文字列で記述されます
  2. 繰り返されるラベルは、対応する次元が乗算されることを示します
  3. 出力テンソルは、対応する入力(または積)を表す次元ラベルの別の文字列によって記述されます
  4. 出力文字列にないラベルは合計されます

この場合、ij,ij->iは、入力が同じ形状の2つの行列に(i,j)なり、出力が形状のベクトルになることを意味します(i,)

慣れてきたらeinsum、他の多くの操作を一般化することがわかります。

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

残念ながら、einsum手動の乗算と削減と比較すると、かなり大きなパフォーマンスヒットがかかります。パフォーマンスが重要な場合は、ニールのソリューションを使用することをお勧めします。


3

tf.tensordotの対角線をとっても、軸を例えば

[[1], [1]]

私はニール・スレーターの例を採用しました:

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]] }
    ) )

これも今与える:

[ 20.  92.]

ただし、これは大きな行列には最適ではない可能性があります(ここの説明を参照


1
進歩の行進:-)、これがどのAPIバージョンに追加されたかわかりませんか?短い例で回答を拡張することをお勧めします(おそらく私のものに基づいていますが、それはを必要としないので、もっと単純なはずですreduce_sum
Neil Slater

例を追加しました!実際、tf.diag_partを使用しない場合は、非対角ドット積も得られるので、おそらく答えはより速くなります。どのAPIバージョンtf.tensordotが導入されたのか本当にわかりませんが、numpyでも利用できるので、それはずっと前のことかもしれません。
dumkar

これは、要素ごとの乗算と合計よりもはるかに多くのメモリを必要としないでしょうか?
kbrose 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.