tf.nn.embedding_lookup関数は何をしますか?


158
tf.nn.embedding_lookup(params, ids, partition_strategy='mod', name=None)

この機能の義務がわかりません。それはルックアップテーブルのようなものですか?それぞれのIDに対応するパラメーター(ID単位)を返すことはどちらですか。

たとえば、skip-gramモデルでを使用するとtf.nn.embedding_lookup(embeddings, train_inputs)、それぞれに対してtrain_input対応する埋め込みが見つかりますか?


「ルックアップテーブルのようなものですか?」tldr-はい。各x(id)に対して、関連するy(params)を与えます。
David Refaeli

回答:


147

embedding_lookup関数はparamsテンソルの行を取得します。この動作は、numpyの配列でインデックスを使用するのと似ています。例えば

matrix = np.random.random([1024, 64])  # 64-dimensional embeddings
ids = np.array([0, 5, 17, 33])
print matrix[ids]  # prints a matrix of shape [4, 64] 

params引数は、テンソルのリストにすることもできます。その場合ids、テンソル間で分散されます。例えば、3つのテンソルのリスト与えられ[2, 64]、デフォルトの動作は、彼らが表現するということですids[0, 3][1, 4][2, 5]

partition_strategyidsリスト間での配置方法を制御します。分割は、行列が大きすぎて1つに保持できない場合に、より大きなスケールの問題に役立ちます。


21
なぜ彼らはそれをこのように呼ぶのでしょうselect_rowsか?
Lenar Hoyt

12
@LenarHoytは、このルックアップのアイデアがWord Embeddingsに由来しているためです。「行」は、ベクトル空間への単語の表現(埋め込み)であり、それら自体で役立ちます。多くの場合、実際のネットワークよりも多くなります。
Lyndon White

2
tensorflowはどのように埋め込み構造を学習しますか?この機能はそのプロセスも管理しますか?
vgoklani 2017年

19
@vgoklaniは、いいえ、embedding_lookupIDに対応する埋め込みを取得する便利な(そして並列の)方法を提供しますidsparamsその成分(例えば、損失関数に、直接または間接的に、使用されるTF変数-テンソルは通常、トレーニングプロセスの一部として学習されTF変数であるtf.l2_loss(例えば、オプティマイザによって最適化されています)tf.train.AdamOptimizer)。
Shobhit 2017年

5
@RafałJózefowiczなぜ「デフォルトの動作は、IDを表すことです:[0、3]、[1、4]、[2、5]。」?説明してもらえますか?
Aerin 2017

219

はい、要点を理解するまで、この機能は理解するのが難しいです。

最も単純な形式では、に似ていtf.gatherます。でparams指定されたインデックスに従っての要素を返しますids

たとえば(あなたが中にいると仮定してtf.InteractiveSession()

params = tf.constant([10,20,30,40])
ids = tf.constant([0,1,2,3])
print tf.nn.embedding_lookup(params,ids).eval()

[10 20 30 40]paramsの最初の要素(インデックス0)は、params 10の2番目の要素(インデックス1)はなので、が返されます20

同様に、

params = tf.constant([10,20,30,40])
ids = tf.constant([1,1,3])
print tf.nn.embedding_lookup(params,ids).eval()

戻り[20 20 40]ます。

しかしembedding_lookupそれだけではありません。params引数は可能リストテンソルのではなく、単一テンソル。

params1 = tf.constant([1,2])
params2 = tf.constant([10,20])
ids = tf.constant([2,0,2,1,2,3])
result = tf.nn.embedding_lookup([params1, params2], ids)

そのような場合、で指定されたインデックスは、デフォルトのパーティション戦略が「mod」でidsあるパーティション戦略に従ってテンソルの要素に対応します。

'mod'戦略では、インデックス0はリストの最初のテンソルの最初の要素に対応します。インデックス1 は、2番目のテンソルの最初の要素に対応します。インデックス2 は、3番目のテンソルの最初の要素に対応します。paramsがテンソルのリストであると仮定すると、単にindex は(i + 1)番目のテンソルの最初の要素に対応します。i0..(n-1)n

現在、nリストparamsにはnテンソルしか含まれていないため、インデックスはテンソルn + 1に対応できません。したがって、インデックスは最初のテンソルの2番目の要素にn対応します。同様に、インデックスは2番目のテンソルの2番目の要素に対応します。n+1

したがって、コードでは

params1 = tf.constant([1,2])
params2 = tf.constant([10,20])
ids = tf.constant([2,0,2,1,2,3])
result = tf.nn.embedding_lookup([params1, params2], ids)

インデックス0は最初のテンソルの最初の要素に対応します:1

インデックス1は2番目のテンソルの最初の要素に対応します:10

インデックス2は最初のテンソルの2番目の要素に対応します:2

インデックス3は2番目のテンソルの2番目の要素に対応します:20

したがって、結果は次のようになります。

[ 2  1  2 10  2 20]

8
注:を使用できますpartition_strategy='div'[10, 1, 10, 2, 10, 20]つまりid=1、最初のパラメーターの2番目の要素です。基本的に:( partition_strategy=modデフォルト) id%len(params):params内のparamのid//len(params)インデックス:上記のparam内の要素のインデックスpartition_strategy=*div*逆の方法
Mario Alemi

3
@ asher-sternは、「mod」戦略がデフォルトである理由を説明できますか?「div」戦略は標準のテンソルスライス(与えられたインデックスによる行の選択)により似ているようです。「div」の場合、パフォーマンスの問題はありますか?
svetlov.vsevolod 2017

46

はい、tf.nn.embedding_lookup()関数の目的は、埋め込み行列でルックアップを実行し、単語の埋め込み(または簡単に言えば、ベクトル表現)を返すことです。

単純な埋め込み行列(形状:)は次のvocabulary_size x embedding_dimensionようになります。(つまり、各単語は数値のベクトルで表されるため、word2vecという名前になります


埋め込みマトリックス

the 0.418 0.24968 -0.41242 0.1217 0.34527 -0.044457 -0.49688 -0.17862
like 0.36808 0.20834 -0.22319 0.046283 0.20098 0.27515 -0.77127 -0.76804
between 0.7503 0.71623 -0.27033 0.20059 -0.17008 0.68568 -0.061672 -0.054638
did 0.042523 -0.21172 0.044739 -0.19248 0.26224 0.0043991 -0.88195 0.55184
just 0.17698 0.065221 0.28548 -0.4243 0.7499 -0.14892 -0.66786 0.11788
national -1.1105 0.94945 -0.17078 0.93037 -0.2477 -0.70633 -0.8649 -0.56118
day 0.11626 0.53897 -0.39514 -0.26027 0.57706 -0.79198 -0.88374 0.30119
country -0.13531 0.15485 -0.07309 0.034013 -0.054457 -0.20541 -0.60086 -0.22407
under 0.13721 -0.295 -0.05916 -0.59235 0.02301 0.21884 -0.34254 -0.70213
such 0.61012 0.33512 -0.53499 0.36139 -0.39866 0.70627 -0.18699 -0.77246
second -0.29809 0.28069 0.087102 0.54455 0.70003 0.44778 -0.72565 0.62309 

Iは、マトリックス埋め込み上に分割してのみロード言葉vocab我々の語彙との対応するベクトルされるemb配列。

vocab = ['the','like','between','did','just','national','day','country','under','such','second']

emb = np.array([[0.418, 0.24968, -0.41242, 0.1217, 0.34527, -0.044457, -0.49688, -0.17862],
   [0.36808, 0.20834, -0.22319, 0.046283, 0.20098, 0.27515, -0.77127, -0.76804],
   [0.7503, 0.71623, -0.27033, 0.20059, -0.17008, 0.68568, -0.061672, -0.054638],
   [0.042523, -0.21172, 0.044739, -0.19248, 0.26224, 0.0043991, -0.88195, 0.55184],
   [0.17698, 0.065221, 0.28548, -0.4243, 0.7499, -0.14892, -0.66786, 0.11788],
   [-1.1105, 0.94945, -0.17078, 0.93037, -0.2477, -0.70633, -0.8649, -0.56118],
   [0.11626, 0.53897, -0.39514, -0.26027, 0.57706, -0.79198, -0.88374, 0.30119],
   [-0.13531, 0.15485, -0.07309, 0.034013, -0.054457, -0.20541, -0.60086, -0.22407],
   [ 0.13721, -0.295, -0.05916, -0.59235, 0.02301, 0.21884, -0.34254, -0.70213],
   [ 0.61012, 0.33512, -0.53499, 0.36139, -0.39866, 0.70627, -0.18699, -0.77246 ],
   [ -0.29809, 0.28069, 0.087102, 0.54455, 0.70003, 0.44778, -0.72565, 0.62309 ]])


emb.shape
# (11, 8)

TensorFlowにルックアップを埋め込む

次に、任意の入力文に対して埋め込みルックアップを実行する方法を確認します。

In [54]: from collections import OrderedDict

# embedding as TF tensor (for now constant; could be tf.Variable() during training)
In [55]: tf_embedding = tf.constant(emb, dtype=tf.float32)

# input for which we need the embedding
In [56]: input_str = "like the country"

# build index based on our `vocabulary`
In [57]: word_to_idx = OrderedDict({w:vocab.index(w) for w in input_str.split() if w in vocab})

# lookup in embedding matrix & return the vectors for the input words
In [58]: tf.nn.embedding_lookup(tf_embedding, list(word_to_idx.values())).eval()
Out[58]: 
array([[ 0.36807999,  0.20834   , -0.22318999,  0.046283  ,  0.20097999,
         0.27515   , -0.77126998, -0.76804   ],
       [ 0.41800001,  0.24968   , -0.41242   ,  0.1217    ,  0.34527001,
        -0.044457  , -0.49687999, -0.17862   ],
       [-0.13530999,  0.15485001, -0.07309   ,  0.034013  , -0.054457  ,
        -0.20541   , -0.60086   , -0.22407   ]], dtype=float32)

ボキャブラリ内の単語インデックスを使用して、元の埋め込み行列(単語を含む)から埋め込みを取得した方法を確認します。

通常、このような埋め込みルックアップは、最初のレイヤー(埋め込みレイヤーと呼ばれます)によって実行されます。最初のレイヤーは、これらの埋め込みをさらに処理するためにRNN / LSTM / GRUレイヤーに渡します。


サイドノート:通常、語彙には特別なunkトークンもあります。したがって、入力文のトークンがボキャブラリに存在しない場合、に対応するインデックスunkが埋め込み行列で検索されます。


PSこれembedding_dimensionは、アプリケーションに合わせて調整する必要があるハイパーパラメータですが、Word2VecGloVeなどの人気のあるモデル300は、各単語を表すために次元ベクトルを使用します。

ボーナスリーディング word2vecスキップグラムモデル


17

以下は、ルックアップを埋め込むプロセスを描いた画像です。

画像:埋め込みルックアッププロセス

簡潔に言うと、IDのリストで指定された埋め込みレイヤーの対応する行を取得し、それをテンソルとして提供します。それは次のプロセスによって達成されます。

  1. プレースホルダーを定義する lookup_ids = tf.placeholder([10])
  2. 埋め込みレイヤーを定義する embeddings = tf.Variable([100,10],...)
  3. テンソルフロー操作を定義する embed_lookup = tf.embedding_lookup(embeddings, lookup_ids)
  4. 実行して結果を得る lookup = session.run(embed_lookup, feed_dict={lookup_ids:[95,4,14]})

6

paramsテンソルが高次元の場合、IDは上部次元のみを参照します。多分それはほとんどの人にとって明白ですが、私はそれを理解するために次のコードを実行しなければなりません:

embeddings = tf.constant([[[1,1],[2,2],[3,3],[4,4]],[[11,11],[12,12],[13,13],[14,14]],
                          [[21,21],[22,22],[23,23],[24,24]]])
ids=tf.constant([0,2,1])
embed = tf.nn.embedding_lookup(embeddings, ids, partition_strategy='div')

with tf.Session() as session:
    result = session.run(embed)
    print (result)

「div」戦略を試すだけで、1つのテンソルに対しては、違いはありません。

出力は次のとおりです。

[[[ 1  1]
  [ 2  2]
  [ 3  3]
  [ 4  4]]

 [[21 21]
  [22 22]
  [23 23]
  [24 24]]

 [[11 11]
  [12 12]
  [13 13]
  [14 14]]]

3

それを見る別の方法は、テンソルを1次元配列にフラット化し、次にルックアップを実行していると仮定することです

(例)Tensor0 = [1,2,3]、Tensor1 = [4,5,6]、Tensor2 = [7,8,9]

平坦化されたテンソルは次のようになります[1,4,7,2,5,8,3,6,9]

ここで、[0,3,4,1,7]のルックアップを実行すると、[1,2,5,4,6]と表示されます。

(i、e)たとえば、ルックアップ値が7で、3つのテンソル(または3行のテンソル)がある場合、

7/3:(リマインダーは1、商は2)したがって、Tensor1の2番目の要素である6が表示されます。


2

私もこの機能に興味を持っていたので、2セントを差し上げます。

2Dの場合にそれを見る方法は、行列の乗算と同じです(他の次元に一般化するのは簡単です)。

N個のシンボルを持つ語彙を考えてみましょう。次に、シンボルxを次元Nx1のベクトルとして表すことができます(ワンホットエンコード)。

しかし、このシンボルをNx1のベクトルとしてではなく、yと呼ばれる次元Mx1のシンボルとして表現したいとします。

したがって、xyに変換するには、次元MxNの行列Eを使用して埋め込むことができます。

y = E x

これは、本質的にtf.nn.embedding_lookup(params、ids、...)が行っていることであり、idsは、ワンホットエンコードされたベクトルxの1の位置を表す1つの数値にすぎないというニュアンスがあります。


0

Asher Sternの答えに追加する と、大きな埋め込みテンソルの分割paramsとして解釈されます。これは、完全な埋め込みテンソルを表す単一のテンソル、または分割された埋め込みテンソルを表す最初の次元を除いてすべて同じ形状のXテンソルのリストにすることができます。

この関数tf.nn.embedding_lookupは、埋め込み(params)が大きくなることを考慮して記述されています。したがって、私たちは必要partition_strategyです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.