usar neural network medium learning guide funciona example como python tensorflow nlp deep-learning word-embedding tensor natural-language-processing

neural - tensorflow python



¿Qué hace la función tf.nn.embedding_lookup? (8)

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

No puedo entender el deber de esta función. ¿Es como una tabla de búsqueda? ¿Qué significa devolver los parámetros correspondientes a cada id (en ids)?

Por ejemplo, en el modelo de skip-gram si utilizamos tf.nn.embedding_lookup(embeddings, train_inputs) , ¿para cada train_input encuentra la incrustación correspondiente?


Además de la respuesta de Asher Stern, params se interpreta como una partición de un gran tensor de inserción. Puede ser un solo tensor que represente el tensor de incrustación completo, o una lista de tensores X todos de la misma forma, excepto la primera dimensión, que representa los tensores de incrustación fragmentados.

La función tf.nn.embedding_lookup está escrita considerando el hecho de que la incrustación (params) será grande. Por lo tanto, necesitamos la partition_strategy .


Aquí hay una imagen que representa el proceso de incrustación de búsqueda.



De forma concisa, obtiene las filas correspondientes de una capa de incrustación, especificada por una lista de ID y la proporciona como tensor. Se logra a través del siguiente proceso.

  1. Definir un marcador de posición lookup_ids = tf.placeholder([10])
  2. Definir una capa de embeddings = tf.Variable([100,10],...)
  3. Defina la operación de embed_lookup = tf.embedding_lookup(embeddings, lookup_ids)
  4. Obtenga los resultados ejecutando lookup = session.run(embed_lookup, feed_dict={lookup_ids:[95,4,14]})

Como también estaba intrigada por esta función, daré mis dos centavos.

La forma en que lo veo en el caso 2D es solo como una multiplicación matricial (es fácil generalizar a otras dimensiones).

Considere un vocabulario con N símbolos. Luego, puede representar un símbolo x como un vector de dimensiones Nx1, codificado en caliente.

Pero desea una representación de este símbolo no como un vector de Nx1, sino como uno con dimensiones Mx1, llamado y .

Entonces, para transformar x en y , puede usar e incrustar la matriz E , con dimensiones MxN:

y = E x .

Esto es esencialmente lo que está haciendo tf.nn.embedding_lookup (params, ids, ...), con el matiz de que los identificadores son solo un número que representa la posición del 1 en el vector x codificado en caliente.


Cuando el tensor de parámetros está en dimensiones altas, los identificadores solo se refieren a la dimensión superior. Tal vez sea obvio para la mayoría de las personas, pero tengo que ejecutar el siguiente código para entender eso:

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)

Simplemente probando la estrategia ''div'' y para un tensor, no hay diferencia.

Aquí está la salida:

[[[ 1 1] [ 2 2] [ 3 3] [ 4 4]] [[21 21] [22 22] [23 23] [24 24]] [[11 11] [12 12] [13 13] [14 14]]]


Otra forma de verlo es, suponga que aplana los tensores a una matriz unidimensional, y luego está realizando una búsqueda

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

El tensor aplanado será el siguiente [1,4,7,2,5,8,3,6,9]

Ahora, cuando realices una búsqueda de [0,3,4,1,7], aparecerá [1,2,5,4,6]

(i, e) si el valor de búsqueda es 7, por ejemplo, y tenemos 3 tensores (o un tensor con 3 filas), entonces,

7/3: (el recordatorio es 1, el cociente es 2) Entonces se mostrará el segundo elemento del Tensor1, que es 6


Sí, el propósito de la función tf.nn.embedding_lookup() es realizar una búsqueda en la matriz de incrustación y devolver las incrustaciones (o en términos simples la representación vectorial) de las palabras.

Una matriz de incrustación simple (de forma: vocabulary_size x embedding_dimension ) se vería a continuación. (es decir, cada palabra estará representada por un vector de números; de ahí el nombre word2vec )

Matriz de incrustación

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

Dividí la matriz de incrustación anterior y cargué solo las palabras en vocab que serán nuestro vocabulario y los vectores correspondientes en la matriz de incrustación.

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)

Búsqueda de incrustación en TensorFlow

Ahora veremos cómo podemos realizar búsquedas de incrustación para alguna oración de entrada arbitraria.

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)

Observe cómo obtuvimos las incrustaciones de nuestra matriz de incrustación original (con palabras) utilizando los índices de palabras en nuestro vocabulario.

Por lo general, dicha búsqueda de incrustación es realizada por la primera capa (llamada capa de incrustación ) que luego pasa estas incrustaciones a las capas RNN / LSTM / GRU para su posterior procesamiento.

Nota al margen: por lo general, el vocabulario también tendrá un token especial de unk . Entonces, si un token de nuestra oración de entrada no está presente en nuestro vocabulario, entonces el índice correspondiente a unk buscará en la matriz de incrustación.

PD Tenga en cuenta que embedding_dimension es un hiperparámetro que uno tiene que ajustar para su aplicación, pero los modelos populares como Word2Vec y GloVe usan un vector de 300 dimensiones para representar cada palabra.

Modelo de omisión de word2vec de lectura adicional


Sí, esta función es difícil de entender, hasta que entienda el punto.

En su forma más simple, es similar a tf.gather . Devuelve los elementos de los params acuerdo con los índices especificados por los ids .

Por ejemplo (suponiendo que está dentro de tf.InteractiveSession() )

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

devolvería [10 20 30 40] , porque el primer elemento (índice 0) de los parámetros es 10 , el segundo elemento de los parámetros (índice 1) es 20 , etc.

Similar,

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

volvería [20 20 40] .

Pero embedding_lookup es más que eso. El argumento params puede ser una lista de tensores, en lugar de un solo 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)

En tal caso, los índices, especificados en ids , corresponden a elementos de tensores de acuerdo con una estrategia de partición , donde la estrategia de partición predeterminada es ''mod''.

En la estrategia ''mod'', el índice 0 corresponde al primer elemento del primer tensor de la lista. El índice 1 corresponde al primer elemento del segundo tensor. El índice 2 corresponde al primer elemento del tercer tensor, y así sucesivamente. Simplemente el índice i corresponde al primer elemento del tensor (i + 1) th, para todos los índices 0..(n-1) , suponiendo que params es una lista de n tensores.

Ahora, el índice n no puede corresponder al tensor n + 1, porque los params la lista contienen solo n tensores. Entonces el índice n corresponde al segundo elemento del primer tensor. Del mismo modo, el índice n+1 corresponde al segundo elemento del segundo tensor, etc.

Entonces, en el código

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)

El índice 0 corresponde al primer elemento del primer tensor: 1

El índice 1 corresponde al primer elemento del segundo tensor: 10

El índice 2 corresponde al segundo elemento del primer tensor: 2

El índice 3 corresponde al segundo elemento del segundo tensor: 20

Por lo tanto, el resultado sería:

[ 2 1 2 10 2 20]


embedding_lookup función embedding_lookup recupera filas del tensor de params . El comportamiento es similar al uso de indexación con matrices en numpy. P.ej

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 argumento params también puede ser una lista de tensores, en cuyo caso los ids se distribuirán entre los tensores. Por ejemplo, dada una lista de 3 tensores [2, 64] , el comportamiento predeterminado es que representarán ids : [0, 3] , [1, 4] , [2, 5] .

partition_strategy controla la forma en que se distribuyen los ids entre la lista. La partición es útil para problemas de mayor escala cuando la matriz puede ser demasiado grande para mantenerla en una sola pieza.