Utilisation d'une incorporation de mots pré-entraînée (word2vec ou Glove) dans TensorFlow

95

J'ai récemment examiné une implémentation intéressante pour la classification de texte convolutif . Cependant, tout le code TensorFlow que j'ai examiné utilise des vecteurs d'incorporation aléatoires (non pré-entraînés) comme celui-ci:

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)

Est-ce que quelqu'un sait comment utiliser les résultats de Word2vec ou d'une incorporation de mots pré-entraînés GloVe au lieu d'un mot aléatoire?

user3147590
la source

Réponses:

130

Il existe plusieurs façons d'utiliser une intégration pré-entraînée dans TensorFlow. Supposons que vous ayez l'incorporation dans un tableau NumPy appelé embedding, avec des vocab_sizelignes et des embedding_dimcolonnes et que vous souhaitiez créer un tenseur Wpouvant être utilisé dans un appel à tf.nn.embedding_lookup().

  1. Créez simplement Wcomme un tf.constant()qui prend embeddingsa valeur:

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

    C'est l'approche la plus simple, mais elle n'est pas efficace en mémoire car la valeur de a tf.constant()est stockée plusieurs fois en mémoire. Puisqu'il embeddingpeut être très volumineux, vous ne devez utiliser cette approche que pour des exemples de jouets.

  2. Créez en Wtant que tf.Variableet initialisez-le à partir du tableau NumPy via un 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})

    Cela évite de stocker une copie de embeddingdans le graphique, mais cela nécessite suffisamment de mémoire pour conserver deux copies de la matrice en mémoire à la fois (une pour le tableau NumPy et une pour le tf.Variable). Notez que j'ai supposé que vous souhaitiez conserver la constante de matrice d'incorporation pendant l'entraînement, donc West créée avec trainable=False.

  3. Si l'incorporation a été formée dans le cadre d'un autre modèle TensorFlow, vous pouvez utiliser a tf.train.Saverpour charger la valeur à partir du fichier de point de contrôle de l'autre modèle. Cela signifie que la matrice d'intégration peut contourner complètement Python. Créez Wcomme dans l'option 2, puis procédez comme suit:

    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")
mrry
la source
Je crée W comme suit: W = np.loadtxt ("/ media / w2vTest.txt", dtype = 'string', delimiter = '') qui crée en tant que ligne: ['in' '0.070312 ...... «-0,0625»]. Il y a des problèmes ici! Dois-je considérer cela comme mon W après avoir supprimé «in» et converti les nombres de chaîne en float32? si tel est le cas, comment se connecter «in» à son vecteur respectif? OU je dois convertir des chiffres en float32 et laisser «in» tel quel; vous attendez-vous à ce que tensorflow fasse tout le traitement requis? Merci!
user3147590
4
Ah, vous avez quelques options ici. Vous pouvez utiliser l'opération TensorFlow tf.decode_csv()pour convertir le fichier texte en un tenseur, mais cela peut être coûteux (en particulier, cela vous oblige à en créer un Tensorpar colonne, puis à concaténer les numériques ensemble). Une alternative plus simple serait peut-être d'utiliser pandas.read_csv()et pandas.DataFrame.as_matrix()d'obtenir l'entrée sous forme de tableau NumPy.
mrry
3
Le tableau NumPy doit être récupéré après l'appel aux sess.run(embedding_init, ...)retours (en supposant que vous ne gardiez pas une référence à celui-ci dans votre programme). Selon la structure de votre programme, vous souhaiterez peut-être del embedding(où embeddingest le tableau NumPy) libérer le tableau plus tôt.
mrry
1
@mrry: pouvez-vous parler davantage de l'option 1 et plus précisément "elle n'est pas efficace en mémoire car la valeur d'un tf.constant () est stockée plusieurs fois en mémoire". Mémoire inefficace pour le GPU ou le CPU? Plus généralement, pourquoi tf.constant () doit-il avoir plusieurs copies en mémoire, alors que l'espace réservé tf.Variable () + alimentation de l'option 2 n'a pas ce problème?
Gabriel Parent
1
Si vous vous demandez également pourquoi «la valeur d'un tf.constant () est stockée plusieurs fois en mémoire», jetez un œil à cette réponse: stackoverflow.com/a/42450418/5841473
alyaxey
33

J'utilise cette méthode pour charger et partager l'intégration.

W = tf.get_variable(name="W", shape=embedding.shape, initializer=tf.constant_initializer(embedding), trainable=False)
LiuJia
la source
L'incorporation doit-elle être des colonnes ou des lignes dans la matrice numpy?
Greyshack
6

La réponse de @mrry n'est pas correcte car elle provoque l'écrasement des poids des plongements chaque fois que le réseau est exécuté, donc si vous suivez une approche de minibatch pour former votre réseau, vous écrasez les poids des plongements. Donc, de mon point de vue, la bonne façon de procéder aux incorporations pré-entraînées est:

embeddings = tf.get_variable("embeddings", shape=[dim1, dim2], initializer=tf.constant_initializer(np.array(embeddings_matrix))
Eugenio Martínez Cámara
la source
Copie exacte de la réponse de LiuJia.
TimZaman
4
@TimZaman .. En fait, il manque l'argument trainable = False et finira donc par affiner ses plongements dans le processus.
Shatu
4
De plus, je pense que le raisonnement d'Eugenio est incorrect. Vous n'avez simplement pas besoin d'exécuter l'opération "embedding_init" avec chaque mini-lot, et tout ira bien. Autrement dit, exécutez simplement l'initialisation d'intégration une seule fois au début de la formation.
Shatu
@Shatu comment puis-je m'assurer que l'initialisation de l'intégration est exécutée uniquement au début de la formation?
1
@ dust0x .. Si la taille des plongements est suffisamment petite, vous pouvez simplement les spécifier comme valeur initiale. S'ils sont assez volumineux, vous pouvez les transmettre dans feed_dict lorsque vous exécutez l'initialiseur pour toutes les variables. Faites-moi savoir si ce n'est pas assez clair et j'essaierai de publier un exemple de code pour les deux approches.
Shatu le
6

Réponse compatible 2.0 : il existe de nombreux intégrations pré-formées, développées par Google et Open Source.

Certains le sont Universal Sentence Encoder (USE), ELMO, BERT, etc. et il est très facile de les réutiliser dans votre code.

Le code pour réutiliser le Pre-Trained Embedding, Universal Sentence Encoderest indiqué ci-dessous:

  !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)

Pour plus d'informations sur les Embeddings pré-formés développés et open-source par Google, consultez TF Hub Link .

Prise en charge de Tensorflow
la source
5

Avec la version 2 de tensorflow, c'est assez facile si vous utilisez le calque Embedding

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
la source
3

J'étais également confronté à un problème d'intégration, j'ai donc écrit un tutoriel détaillé avec un jeu de données. Ici, je voudrais ajouter ce que j'ai essayé Vous pouvez également essayer cette méthode,

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]}))

Voici un exemple détaillé du didacticiel Ipython si vous voulez comprendre à partir de zéro, jetez un œil.

Aaditya Ura
la source