2016-07-06 10 views
13

input_xで表されるデータがあります。これは不明なサイズのテンソル(バッチで入力する必要があります)であり、各アイテムのサイズはnです。 input_xtf.nn.embedding_lookoutとなり、embedのサイズは[?, n, m]となりました。ここで、mは埋め込みサイズ、?は未知のバッチサイズを指します。Tensorflow - バッチデータを含む入力行列のmatmul

これは、ここで説明されています

input_x = tf.placeholder(tf.int32, [None, n], name="input_x") 
embed = tf.nn.embedding_lookup(W, input_x) 

私は今U、行列変数で(今埋め込む行列である)私の入力データの各サンプルを乗算しようとしている、と私は見えることはできませんそれをする方法を得るために。

私は最初にtf.matmulを使用して試しましたが、形状の不一致によるエラーが発生します。私は、(Iもtf.nn.math_ops.から機能を試し、結果は同じであった)Uの寸法を拡大しbatch_matmulを適用することによって、次のことを試みた:

U = tf.Variable(...)  
U1 = tf.expand_dims(U,0) 
h=tf.batch_matmul(embed, U1) 

実際のデータがあるときは、初期コンパイルを通過するが、適用され、私は次のエラーを取得する:

In[0].dim(0) and In[1].dim(0) must be the same: [64,58,128] vs [1,128,128]

なぜこれが起こっている私も知っている - 私はUの次元を複製し、それは今1ですが、minibatchサイズ、64」doesnのフィット。

テンソル行列入力で、その行列乗法を正しく(未知のバッチサイズのために)行うことはできますか?

+0

を与えるだろう。あなたは、2つの行列乗算の出力のサイズにスキャン関数にイニシャライザを追加する必要があります。U * x –

+0

現在、[tf.matmul](http://stackoverflow.com/a/43829731/1090562)は正しいですバッチ乗算を行う方法。 –

答えて

10

matmul operationは、行列(2Dテンソル)でのみ作用します。これを行うには2つの主なアプローチがあり、どちらもUが2Dテンソルであると仮定します。

  1. 次元テンソルにスライスembed、個別Uでそれらのそれぞれを乗算します。これはおそらく、このようなtf.scan()を使用して行うのが最も簡単です:

    h = tf.scan(lambda a, x: tf.matmul(x, U), embed) 
    
  2. 一方、効率が重要な場合、乗算のような単一matmulで行うことができますので、2Dテンソルであることをembedを再構築する方が良いかもしれこの:cUの列数がある

    embed = tf.reshape(embed, [-1, m]) 
    h = tf.matmul(embed, U) 
    h = tf.reshape(h, [-1, n, c]) 
    

    。最後の形状変更はhが3Dテンソルであることを確認します。0次元は元のx_inputembedのようなバッチに対応します。

+0

ありがとうございました!私は効率を気にします。どのくらい私はオプション1を避けるべきですか、またはテンソルフロー(GPUなどで)はそれを多少効率的に行いますか? オプション2については、このように行列構造の一部が失われます。私はこの操作をサポートしていないことに驚いています。それは一般的な操作ではありませんか? – yoki

+0

@yoki 2つのアプローチの結果は、オプション2の2回目の変更後に完全に一致するはずです。私は主にオプション1を含んでいました。 あなたがやっていることは、再発するネットワークの外では非常に一般的だとは思いません。 (これは 'scan'の主な用途の1つです) [batch_matmul'](https://www.tensorflow.org/versions/master/api_docs/python/math_ops.html#batch_matmul)操作があることに気付きましたあなたも使うことができますが、それを使うには 'U'マトリックスのコピーをたくさん作る必要があります。 – Styrke

+1

@yoki実際に私はそれについて考えているので、あなたがしようとしていることは、おそらく実際には違いはありません。 行列の乗算は連想的であるため、埋め込みルックアップを実行する前に 'W'に' U'を掛けて、まったく同じ結果を得て、その製品の埋め込みを調べます。私が知らないエキゾチックなことをしない限り、最も効果的なアプローチは、実際に両方を定義してからそれらを掛け合わせるのではなく、単に「WU」を表す単一の行列を定義することです。 – Styrke

4

@Strykeによって応答されるように、これを達成する2つの方法がある:

  1. tf.scanを再成形1.スキャン、および2はラムダ機能を必要とし、一般的に再帰的な操作のために使用されます。同じもののいくつかの例がここにあります:https://rdipietro.github.io/tensorflow-scan-examples/

  2. 私は個人的には直感的ですので、形を変えたいと思います。 3Dテンソルの各行列に2Dテンソルの行列を掛けようとすると、Cijl = Aijk * Bklのように簡単な形で行うことができます。

    A' = tf.reshape(Aijk,[i*j,k]) 
    C' = tf.matmul(A',Bkl) 
    C = tf.reshape(C',[i,j,l]) 
    
37

前の答えは廃止されました。現在ランク> 2とtf.matmul()サポートテンソル:また

The inputs must be matrices (or tensors of rank > 2, representing batches of matrices), with matching inner dimensions, possibly after transposition.

tf.batch_matmul()を除去し、tf.matmul()は、バッチ乗算を行うには正しい方法ですました。今、あなたは形状(batch_size, n, k)のテンソルを受け取ることになります

import tensorflow as tf 
batch_size, n, m, k = 10, 3, 5, 2 
A = tf.Variable(tf.random_normal(shape=(batch_size, n, m))) 
B = tf.Variable(tf.random_normal(shape=(batch_size, m, k))) 
tf.matmul(A, B) 

:主なアイデアは、次のコードから理解することができます。ここでは何が起こっているのですか?行列mxknxmbatch_sizeの行列のbatch_sizeがあるとします。それぞれのペアについて、nxm X mxkを計算すると、nxkという行列が得られます。それらのうちbatch_sizeがあります。このようなものでも有効である

お知らせ:

A = tf.Variable(tf.random_normal(shape=(a, b, n, m))) 
B = tf.Variable(tf.random_normal(shape=(a, b, m, k))) 
tf.matmul(A, B) 

とだけ一つのことを追加するためにあなたの形状​​

+1

質問のように、1つの行列に他の行列を掛けたい場合は、これを行う正しい方法は何ですか?あなたは、単一の行列batch_sizetimesを複製(タイル)する必要がありますか、それとも良い方法がありますか? – KarlSt

+1

@ KarlSt私の実験に基づいて、最初のN-2次元が一致しない場合、これは機能しません。明らかに、このコマンドのnumpyバージョンは放送をサポートしていますが、私はTFでそれを行う唯一の方法は、単一の行列batch_size時間をタイル化することだと思います。私はトランスポーズトリックを試してみました(行列が[batch_size、n、m]であり、2番目の行列が[1、m、k]であるように見えます)。私はそれがバグと呼ばれることは確かではありませんが、明らかに、これはそのような共通の操作以来、TFで実装されるべきです。 – sirgogo

+0

私はここでより良い方法を見つけました:https://groups.google.com/a/tensorflow.org/forum/#!topic/discuss/4tgsOSxwtkY 乗算に使用されていない2つの次元を、reshape、乗算2つの行列を作成し、再度形状を呼び出して目的の形状にします。これは、バッチ乗算を行うことと同じです。 – KarlSt

関連する問題