2016-01-19 11 views
82
tf.nn.embedding_lookup(params, ids, partition_strategy='mod', name=None) 

Ich kann die Pflicht dieser Funktion nicht verstehen. Ist es wie eine Nachschlagetabelle? Was bedeutet, die Parameter für jede ID (in ids) zurückzugeben?Was macht die Funktion tf.nn.embedding_lookup?

Zum Beispiel, in der skip-gram Modell, wenn wir tf.nn.embedding_lookup(embeddings, train_inputs) verwenden, dann für jedes train_input findet es die entsprechende Einbettung?

Antwort

96

embedding_lookup Funktion ruft Zeilen des params Tensors ab. Das Verhalten ähnelt der Indizierung mit Arrays in numpy. Z.B.

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 Argument kann auch eine Liste von Tensoren, in dem Fall der ids wird unter den Tensoren verteilt werden. Bei einer Liste von 3 Tensoren [2, 64] lautet das Standardverhalten beispielsweise, dass sie ids: [0, 3], [1, 4], [2, 5] darstellen.

partition_strategy steuert die Art und Weise, wie die ids auf die Liste verteilt sind. Die Partitionierung ist nützlich für Probleme größeren Maßstabs, wenn die Matrix zu groß sein könnte, um sie in einem Stück zu halten.

+11

Warum würden sie es so nennen und nicht 'select_rows'? –

+8

@LenarHoyt, weil diese Idee einer Suche von Word Embeddings stammt. und die "Zeilen" sind die Repräsentationen (Einbettungen) der Wörter, in einen Vektorraum - und sind in sich selbst nützlich. Oft mehr als das eigentliche Netzwerk. –

+2

Wie lernt Tensorflow die Einbettungsstruktur? Wird dieser Prozess auch von dieser Funktion verwaltet? – vgoklani

139

Ja, diese Funktion ist schwer zu verstehen, bis Sie den Punkt bekommen.

In seiner einfachsten Form ähnelt es tf.gather. Sie gibt die Elemente params gemäß den von ids angegebenen Indizes zurück.

Zum Beispiel (unter der Annahme Sie sind innerhalb tf.InteractiveSession())

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

würde [10 20 30 40] zurückkehren, weil das erste Element (Index 0) von params ist 10, das zweite Element von params (Index 1) 20 ist, usw.

.

Ähnlich

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

würde [20 20 40] zurückzukehren.

Aber embedding_lookup ist mehr als das. Das params Argument kann eine Liste von Tensoren sein, anstatt eines einzelnen Tensors.

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) 

In einem solchen Fall werden die Indizes in ids angegeben, entsprechen den Elementen von Tensoren gemäß einer Partitionierungsstrategie, wo die Standard-Partitionsstrategie ‚mod‘ ist.

In der 'mod'-Strategie entspricht Index 0 dem ersten Element des ersten Tensors in der Liste. Index 1 entspricht dem ersten Element des zweiten Tensors. Index 2 entspricht dem ersten Element des dritten Tensors und so weiter.Einfach Index i entspricht das erste Element des (i + 1) -te Tensor, für alle Indizes 0..(n-1), params unter der Annahme, eine Liste von n Tensoren ist. Jetzt

, Index n kann nicht auf Tensor entsprechen n + 1, weil die Liste params nur n Tensoren enthält. So Index n entspricht das zweite Element des ersten Tensor. In ähnlicher Weise Index n+1 entspricht das zweite Element des zweiten tensor usw.

also im Code

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) 

Index 0 mit dem ersten Elemente des ersten Tensor: 1 entspricht

index 1 entspricht das erste Element des zweiten Tensor: 10

Index 2 entspricht das zweite Element des ersten Tensor: 2

Index 3 entspricht das zweite Element des zweiten Tensor: 20

Somit würde das Ergebnis sein:

[ 2 1 2 10 2 20] 
+4

eine Anmerkung: Sie können 'partition_strategy = 'div'' verwenden und würden' [10, 1, 10, 2, 10, 20] 'erhalten, d. H.' Id = 1' ist das zweite Element des ersten Parameters. Grundsätzlich gilt: 'partition_strategy = mod' (default) ' id% len (params) ': Index des param in params ' ID // len (params) ': Index des Elements in der obigen param ' partition_strategy = * div * 'andersrum –

+2

@ asher-stern könntest du erklären, warum" mod "strategie standardmäßig ist? scheint, dass die "div" -Strategie dem Standard-Tensor-Slicing ähnlicher ist (select-rows nach gegebenen Indizes). Gibt es im Fall von "div" einige Leistungsprobleme? – svetlovva

0

Hinzufügen zu Asher Sterns Antwort, params als Partitionierungs eines interpretiert großer Einbettungstensor. Es kann mit Ausnahme der ersten Dimension ein einzelner Tensor darstellt, die vollständige Einbettung Tensor, oder eine Liste von X Tensoren alles gleichen Form, darstellt sharded Einbettung Tensoren.

Die Funktion tf.nn.embedding_lookup in Anbetracht der Tatsache, dass geschrieben wird (params) Einbetten wird groß sein. Deshalb brauchen wir partition_strategy.

2

Ein anderer Weg, um es zu betrachten ist, vorausgesetzt, dass Sie die Tensoren zu eindimensionaler Array abflachen und dann führen Sie eine Lookup

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

Der abgeflachte Tensor ist wie folgt [1,4,7,2,5,8,3,6,9]

Nun, wenn Sie eine Suche nach [0,3,4,1,7] tun es yeild wird [1,2,5,4,6]

(i, e) wenn Lookup-Wert 7 für Beispiel und haben wir 3 Tensoren (oder einen Tensor mit 3 Reihen) dann,

7/3: (Erinnerung 1 ist, wird Quotient 2), so 2. Element Tensor1, die 6

1

Wenn die params gezeigt wird Tensor ist in hohen Dimensionen, die IDs beziehen sich nur auf die obere Dimension. Vielleicht ist es offensichtlich für die meisten Menschen, aber ich muss den folgenden Code ausführen zu verstehen, dass:

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) 

einfach die ‚div‘ Strategie versucht und für einen Tensor, macht es keinen Unterschied.Hier

ist die Ausgabe:

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

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

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

Ja, der Zweck der tf.nn.embedding_lookup() Funktion ist ein lookup in der Einbettungsmatrix und gibt die Einbettungen auszuführen (oder in einfachen Worten, die Vektordarstellung) von Wörter.

Eine einfache Einbettungsmatrix (vocabulary_size x embedding_dimension) würde wie folgt aussehen. (Dh jedes Wort wird von einem Vektor von Zahlen dargestellt werden, daher der Name word2vec)


Embedding Matrix

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 

gespalten I die oben Einbettungs Matrix und geladen nur die Worte in vocab wird unser Vokabular sein und die entsprechenden Vektoren in emb Array.

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) 

Embedding Lookup in TensorFlow

Jetzt werden wir sehen, wie wir Einbettung Lookup für einigen beliebigen Eingabesatz durchführen können.

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) 

Beobachten Sie, wie wir das Einbettungen von unserer ursprünglichen Einbettungsmatrix (mit Worten) bekamen mit dem Indizes Worten in unserem Wortschatz.

Normalerweise wird eine solche Einbettungssuche von der ersten Schicht (Einbettungsschicht) durchgeführt, die diese Einbettungen dann zur weiteren Verarbeitung an RNN/LSTM-Schichten weiterleitet.


Side Hinweis: Normalerweise ist der Wortschatz wird auch ein spezielles unk Token. Wenn also ein Token aus unserem Eingabesatz nicht in unserem Vokabular vorhanden ist, wird der Index, der unk entspricht, in der Einbettungsmatrix nachgeschlagen.


P.S. Beachten Sie, dass embedding_dimension ist ein Hyper, die man für ihre Anwendung abzustimmen hat, aber beliebte Modelle wie Word2Vec und GloVe verwendet 300 Dimension Vektor für jedes Wort darstellt.

Bonus Leseword2vec skip-gram model

1

Da ich auch von dieser Funktion war fasziniert, werde ich meine zwei Cent geben.

Die Art, wie ich es im 2D-Fall sehe, ist genauso wie eine Matrix-Multiplikation (es ist einfach, sie auf andere Dimensionen zu verallgemeinern).

Betrachten Sie ein Vokabular mit N Symbolen. Dann können Sie ein Symbol x als einen Vektor der Dimensionen Nx1 darstellen, ein-hot-encoded.

Aber Sie wollen eine Darstellung dieses Symbol nicht als einen Vektor von N × 1, aber wie man mit den Maßen Mx1-, genannt y.

So x in y, zu transformieren Sie verwenden können, und Einbettungsmatrix E mit Abmessungen MxN:

y = Ex.

Dies ist im Wesentlichen, was tf.nn.embedding_lookup (params, ids, ...) tut, mit der Nuance, dass ids nur eine einzige Zahl, die die Position der 1 in der One-hot-codierten darstellt Vektor x.