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 zurückzugeben, die jeder id (in ids) entsprechen?
Wenn wir beispielsweise im skip-gram
-Modell tf.nn.embedding_lookup(embeddings, train_inputs)
verwenden, wird für jeden train_input
die entsprechende Einbettung gefunden.
Die embedding_lookup
-Funktion ruft Zeilen des params
-Tensors ab. Das Verhalten ähnelt dem Verwenden der Indexierung 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]
Das Argument params
kann auch eine Liste von Tensoren sein. In diesem Fall wird die Variable ids
unter den Tensoren verteilt. Wenn Sie beispielsweise eine Liste von 3 Tensoren [2, 64]
angeben, wird standardmäßig ids
angezeigt: [0, 3]
, [1, 4]
, [2, 5]
.
partition_strategy
steuert, wie die ids
auf die Liste verteilt wird. Die Partitionierung ist für größere Probleme nützlich, wenn die Matrix zu groß ist, um sie in einem Stück zu halten.
Ja, diese Funktion ist schwer zu verstehen, bis Sie den Punkt verstanden haben.
In seiner einfachsten Form ähnelt es tf.gather
. Es gibt die Elemente von params
gemäß den durch ids
angegebenen Indizes zurück.
Zum Beispiel (vorausgesetzt, Sie befinden sich in 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ückgeben, da das erste Element (Index 0) der Parameter 10
ist, das zweite Element der Parameter (Index 1) 20
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ückgeben.
Aber embedding_lookup
ist mehr als das. Das params
-Argument kann eine Liste von Tensoren sein und nicht ein einzelner Tensor.
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 entsprechen die in ids
angegebenen Indizes Elementen von Tensoren gemäß einer Partitionsstrategie , wobei die Standardpartitionsstrategie 'mod' ist.
In der 'mod'-Strategie entspricht der Index 0 dem ersten Element des ersten Tensors in der Liste. Index 1 entspricht dem first - Element des second tensor. Index 2 entspricht dem first - Element des dritten Tensors und so weiter. Der Index i
entspricht einfach dem ersten Element des (i + 1) -ten Tensors. Für alle Indizes 0..(n-1)
wird angenommen, dass Parameter eine Liste von n
-Tensoren sind.
Index n
kann nun nicht dem Tensor n + 1 entsprechen, da die Liste params
nur n
Tensoren enthält. Der Index n
entspricht also dem second - Element des ersten Tensors. In ähnlicher Weise entspricht der Index n+1
dem zweiten Element des zweiten Tensors 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 entspricht dem ersten Element des ersten Tensors: 1
index 1 entspricht dem ersten Element des zweiten Tensors: 10
index 2 entspricht dem zweiten Element des ersten Tensors: 2
index 3 entspricht dem zweiten Element des zweiten Tensors: 20
Das Ergebnis wäre also:
[ 2 1 2 10 2 20]
Ja, der Zweck von tf.nn.embedding_lookup()
- Funktion besteht darin, ein Lookup in der Einbettungsmatrix auszuführen und die Einbettungen (oder in einfachen Worten die Vektordarstellung) von zurückzugeben Wörter.
Eine einfache Einbettungsmatrix (von Shape: vocabulary_size x embedding_dimension
) würde wie folgt aussehen. (d. h. jedes Wort wird durch einen Vektor von Zahlen dargestellt, daher der Name Word2vec)
Einbettungsmatrix
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
Ich teile die obige Einbettungsmatrix und lade nur die Wörter in vocab
, die unser Vokabular sind, und die entsprechenden Vektoren im 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)
Nachschlagen in TensorFlow
Jetzt werden wir sehen, wie wir Embedding Lookup für einen beliebigen Eingabesatz ausfü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 embeddings aus unserer ursprünglichen Einbettungsmatrix (mit Wörtern) mithilfe der Wortindizes in unserem Vokabular erhalten.
Normalerweise wird eine solche Einbettung von der ersten Schicht (mit dem Namen Einbettungsebene) durchgeführt, die diese Einbettungen dann zur weiteren Verarbeitung an RNN/LSTM/GRU-Schichten weiterleitet.
Randnotiz: Normalerweise hat das Vokabular auch ein spezielles unk
-Token. Wenn also kein Token aus unserem Eingabesatz in unserem Vokabular vorhanden ist, wird der Index, der unk
entspricht, in der Einbettungsmatrix nachgeschlagen.
P.S. Beachten Sie, dass embedding_dimension
ein Hyperparameter ist, den Sie für ihre Anwendung einstellen müssen, aber gängige Modelle wie Word2Vec und GloVe verwenden den 300
-Dimensionsvektor zur Darstellung jedes Words.
Bonus ReadingWord2vec-Überspringmodell
Hier ist ein Bild, das den Prozess des Einbettens der Suche darstellt.
Kurz gesagt, er erhält die entsprechenden Zeilen einer Einbettungsebene, die durch eine Liste von IDs angegeben wird, und stellt diese als Tensor bereit. Dies wird durch den folgenden Prozess erreicht.
lookup_ids = tf.placeholder([10])
embeddings = tf.Variable([100,10],...)
embed_lookup = tf.embedding_lookup(embeddings, lookup_ids)
lookup = session.run(embed_lookup, feed_dict={lookup_ids:[95,4,14]})
ausführen.Wenn der Params-Tensor hoch dimensioniert ist, bezieht sich die IDs nur auf die obere Dimension. Für die meisten Leute ist es offensichtlich, aber ich muss den folgenden Code ausführen, um das zu verstehen:
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)
Nur die 'div'-Strategie zu versuchen 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]]]
Eine andere Sichtweise besteht darin, anzunehmen, dass Sie die Tensoren zu einem eindimensionalen Array ausflachen und dann eine Suche durchführen
(zB) Tensor0 = [1,2,3], Tensor1 = [4,5,6], Tensor2 = [7,8,9]
Der abgeflachte Tensor wird wie folgt aussehen: [1,4,7,2,5,8,3,6,9]
Wenn Sie nun nach [0,3,4,1,7] suchen, werden Sie [1,2,5,4,6]
(i, e) wenn der Suchwert beispielsweise 7 ist und wir 3 Tensoren (oder einen Tensor mit 3 Reihen) haben, dann
7/3: (Erinnerung ist 1, Quotient ist 2) Also wird das zweite Element von Tensor1 angezeigt, welches 6 ist
Da ich auch von dieser Funktion fasziniert war, gebe ich meine zwei Cent.
Wie ich es im 2D-Fall sehe, ist dies nur eine Matrixmultiplikation (es ist leicht, 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, der nur einen Hot-Code enthält.
Sie möchten jedoch eine Darstellung dieses Symbols nicht als Vektor von Nx1, sondern als eine mit Dimensionen Mx1, genannt y.
Um x in y umzuwandeln, können Sie die Matrix E mit den Dimensionen MxN verwenden und einbetten:
y = Ex.
Dies ist im Wesentlichen das, was tf.nn.embedding_lookup (params, ids, ...) tut, mit der Nuance, dass ids nur eine Zahl sind, die die Position der 1 im ein-heiß-codierten Vektor darstelltx.
Zur Antwort von Asher Stern hinzugefügt params
ist interpretiert als Partitionierung eines großen Einbettungstensors. Es kann ein einzelner Tensor sein, der den vollständigen Einbettungstensor darstellt oder eine Liste von X-Tensoren, die alle dieselbe Form haben, mit Ausnahme der ersten Dimension, Scherben eingebettete Tensoren darstellen.
Die Funktion tf.nn.embedding_lookup
wird unter Berücksichtigung der Tatsache geschrieben, dass die Einbettung (Params) groß ist. Deshalb brauchen wir partition_strategy
.