Usar una inserción de palabras previamente entrenadas (word2vec o Glove) en TensorFlow

95

Recientemente revisé una implementación interesante para la clasificación de texto convolucional . Sin embargo, todo el código de TensorFlow que he revisado utiliza vectores de incrustación aleatorios (no entrenados previamente) como los siguientes:

with tf.device('/cpu:0'), tf.name_scope("embedding"):
    W = tf.Variable(
        tf.random_uniform([vocab_size, embedding_size], -1.0, 1.0),
        name="W")
    self.embedded_chars = tf.nn.embedding_lookup(W, self.input_x)
    self.embedded_chars_expanded = tf.expand_dims(self.embedded_chars, -1)

¿Alguien sabe cómo utilizar los resultados de Word2vec o una incrustación de palabras previamente entrenadas de GloVe en lugar de una incrustación aleatoria?

usuario3147590
fuente

Respuestas:

130

Hay algunas formas en las que puedes usar una inserción previamente entrenada en TensorFlow. Digamos que tiene la incrustación en una matriz NumPy llamada embedding, con vocab_sizefilas y embedding_dimcolumnas y desea crear un tensor Wque se pueda usar en una llamada a tf.nn.embedding_lookup().

  1. Simplemente crea Wcomo un valor tf.constant()que tiene embedding:

    W = tf.constant(embedding, name="W")

    Este es el enfoque más fácil, pero no es eficiente en la memoria porque el valor de a tf.constant()se almacena varias veces en la memoria. Dado que embeddingpuede ser muy grande, solo debe usar este enfoque para ejemplos de juguetes.

  2. Cree Wcomo a tf.Variablee inicialícelo desde la matriz NumPy a través de tf.placeholder():

    W = tf.Variable(tf.constant(0.0, shape=[vocab_size, embedding_dim]),
                    trainable=False, name="W")
    
    embedding_placeholder = tf.placeholder(tf.float32, [vocab_size, embedding_dim])
    embedding_init = W.assign(embedding_placeholder)
    
    # ...
    sess = tf.Session()
    
    sess.run(embedding_init, feed_dict={embedding_placeholder: embedding})
    

    Esto evita almacenar una copia de embeddingen el gráfico, pero requiere suficiente memoria para mantener dos copias de la matriz en la memoria a la vez (una para la matriz NumPy y otra para la tf.Variable). Tenga en cuenta que asumí que desea mantener constante la matriz de incrustación durante el entrenamiento, por lo que Wse crea con trainable=False.

  3. Si la incorporación se entrenó como parte de otro modelo de TensorFlow, puede usar a tf.train.Saverpara cargar el valor del archivo de punto de control del otro modelo. Esto significa que la matriz de incrustación puede omitir Python por completo. Cree Wcomo en la opción 2, luego haga lo siguiente:

    W = tf.Variable(...)
    
    embedding_saver = tf.train.Saver({"name_of_variable_in_other_model": W})
    
    # ...
    sess = tf.Session()
    embedding_saver.restore(sess, "checkpoint_filename.ckpt")
    
señor
fuente
Creo W de la siguiente manera: W = np.loadtxt ("/ media / w2vTest.txt", dtype = 'string', delimiter = '') que crea como una fila: ['in' '0.070312 ...... '-0.0625']. ¡Hay problemas aquí! ¿Debo considerar esto como mi W después de eliminar 'in' y convertir números de string a float32? si este es el caso, entonces, ¿cómo conectar 'in' a su vector respectivo? O necesito convertir las cifras a float32 y luego dejar 'en' como está; ¿Espera que tensorflow haga todo el procesamiento requerido? ¡Gracias!
user3147590
4
Ah, tienes un par de opciones aquí. Usted podría utilizar el TensorFlow tf.decode_csv()op para convertir el archivo de texto en un tensor, pero esto puede ser costoso (en particular, se requiere la creación de uno Tensorpor columna, y luego concatenar los numéricos juntos). Quizás una alternativa más fácil sería usar pandas.read_csv()y pandas.DataFrame.as_matrix()obtener la entrada como una matriz NumPy.
mrry
3
La matriz NumPy debe recolectarse como basura después de la llamada a los sess.run(embedding_init, ...)retornos (asumiendo que no mantiene una referencia a ella en su programa). Dependiendo de la estructura de su programa, es posible que desee del embedding(dónde embeddingestá la matriz NumPy) liberar la matriz antes.
mrry
1
@mrry: ¿puede hablar más sobre la opción 1 y más específicamente "no es eficiente en la memoria porque el valor de un tf.constant () se almacena varias veces en la memoria". ¿Memoria ineficiente para la GPU o la CPU? De manera más general, ¿por qué tf.constant () tiene que tener varias copias en la memoria, mientras que tf.Variable () + marcador de posición de alimentación de la opción 2 no tiene este problema?
Gabriel Parent
1
Si también se pregunta por qué "el valor de un tf.constant () se almacena varias veces en la memoria", eche un vistazo a esta respuesta: stackoverflow.com/a/42450418/5841473
alyaxey
33

Utilizo este método para cargar y compartir incrustaciones.

W = tf.get_variable(name="W", shape=embedding.shape, initializer=tf.constant_initializer(embedding), trainable=False)
LiuJia
fuente
¿Debería la incrustación ser columnas o filas en la matriz numpy?
Greyshack
6

La respuesta de @mrry no es correcta porque provoca la sobrescritura de los pesos de las incrustaciones cada vez que se ejecuta la red, por lo que si está siguiendo un enfoque de minibatch para entrenar su red, está sobrescribiendo los pesos de las incrustaciones. Entonces, desde mi punto de vista, la forma correcta de realizar incrustaciones previamente entrenadas es:

embeddings = tf.get_variable("embeddings", shape=[dim1, dim2], initializer=tf.constant_initializer(np.array(embeddings_matrix))
Eugenio Martínez Cámara
fuente
Duplicado exacto de la respuesta de LiuJia.
TimZaman
4
@TimZaman .. De hecho, le falta el argumento trainable = False y, por lo tanto, terminará ajustando sus incrustaciones en el proceso.
Shatu
4
Además, creo que el razonamiento de Eugenio es incorrecto. Simplemente no tiene que ejecutar la operación "embedding_init" con cada mini-lote, y todo estará bien. Es decir, ejecute la inicialización de incrustación solo una vez al comienzo del entrenamiento.
Shatu
@Shatu, ¿cómo me aseguro de que la inicialización de incrustación se ejecute solo al comienzo del entrenamiento?
1
@ dust0x .. Si el tamaño de las incrustaciones es lo suficientemente pequeño, puede especificarlas como valor inicial. Si son bastante grandes, puede pasarlos en feed_dict cuando ejecute el inicializador para todas las variables. Avíseme si no está lo suficientemente claro e intentaré publicar un código de muestra para ambos enfoques.
Shatu
6

Respuesta compatible con 2.0 : hay muchas incrustaciones previamente entrenadas, que son desarrolladas por Google y que han sido de código abierto.

Algunos de ellos lo son Universal Sentence Encoder (USE), ELMO, BERT, etc. y es muy fácil reutilizarlos en su código.

El código para reutilizar Pre-Trained Embedding, Universal Sentence Encoderse muestra a continuación:

  !pip install "tensorflow_hub>=0.6.0"
  !pip install "tensorflow>=2.0.0"

  import tensorflow as tf
  import tensorflow_hub as hub

  module_url = "https://tfhub.dev/google/universal-sentence-encoder/4"
  embed = hub.KerasLayer(module_url)
  embeddings = embed(["A long sentence.", "single-word",
                      "http://example.com"])
  print(embeddings.shape)  #(3,128)

Para obtener más información sobre las incrustaciones preformadas desarrolladas y de código abierto por Google, consulte TF Hub Link .

Soporte de Tensorflow
fuente
5

Con la versión 2 de tensorflow, es bastante fácil si usa la capa de incrustación

X=tf.keras.layers.Embedding(input_dim=vocab_size,
                            output_dim=300,
                            input_length=Length_of_input_sequences,
                            embeddings_initializer=matrix_of_pretrained_weights
                            )(ur_inp)
Fei Yan
fuente
3

También estaba enfrentando un problema de incrustación, así que escribí un tutorial detallado con un conjunto de datos. Aquí me gustaría agregar lo que probé.También puedes probar este método,

import tensorflow as tf

tf.reset_default_graph()

input_x=tf.placeholder(tf.int32,shape=[None,None])

#you have to edit shape according to your embedding size


Word_embedding = tf.get_variable(name="W", shape=[400000,100], initializer=tf.constant_initializer(np.array(word_embedding)), trainable=False)
embedding_loopup= tf.nn.embedding_lookup(Word_embedding,input_x)

with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        for ii in final_:
            print(sess.run(embedding_loopup,feed_dict={input_x:[ii]}))

Aquí hay un ejemplo detallado de trabajo de Tutorial Ipython si desea comprender desde cero, eche un vistazo.

Aaditya Ura
fuente