Usando uma incorporação de palavras pré-treinada (word2vec ou Glove) no TensorFlow

95

Recentemente, revisei uma implementação interessante para classificação de texto convolucional . No entanto, todo o código do TensorFlow que analisei usa vetores de incorporação aleatórios (não pré-treinados) como o seguinte:

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)

Alguém sabe como usar os resultados do Word2vec ou da incorporação de palavras pré-treinadas do GloVe em vez de uma palavra aleatória?

user3147590
fonte

Respostas:

130

Existem algumas maneiras de usar uma incorporação pré-treinada no TensorFlow. Digamos que você tenha o embedding em um array NumPy chamado embedding, com vocab_sizelinhas e embedding_dimcolunas e deseja criar um tensor Wque pode ser usado em uma chamada para tf.nn.embedding_lookup().

  1. Basta criar Wcomo um tf.constant()que tem embeddingcomo valor:

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

    Essa é a abordagem mais fácil, mas não é eficiente em termos de memória porque o valor de a tf.constant()é armazenado várias vezes na memória. Como embeddingpode ser muito grande, você só deve usar essa abordagem para exemplos de brinquedos.

  2. Crie Wcomo um tf.Variablee inicialize-o a partir da matriz NumPy através de um 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})

    Isso evita armazenar uma cópia de embeddingno gráfico, mas requer memória suficiente para manter duas cópias da matriz na memória de uma vez (uma para a matriz NumPy e outra para tf.Variable). Observe que presumi que você deseja manter a matriz de incorporação constante durante o treinamento, portanto, Wé criada com trainable=False.

  3. Se a incorporação foi treinada como parte de outro modelo do TensorFlow, você pode usar um tf.train.Saverpara carregar o valor do arquivo de ponto de verificação do outro modelo. Isso significa que a matriz de incorporação pode ignorar o Python por completo. Crie Wcomo na opção 2 e faça o seguinte:

    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")
senhor
fonte
Eu crio W da seguinte maneira: W = np.loadtxt ("/ media / w2vTest.txt", dtype = 'string', delimitador = '') que cria como uma linha: ['in' '0,070312 ...... '-0,0625']. Existem problemas aqui! devo considerar isso como meu W depois de remover 'in' e converter números de string para float32? se for esse o caso, como conectar 'in' ao seu respectivo vetor? OU preciso converter os números para float32 e deixar 'in' como está; esperando que o tensorflow faça todo o processamento necessário? Obrigado!
user3147590
4
Ah, você tem algumas opções aqui. Você poderia usar o TensorFlow tf.decode_csv()op para converter o arquivo de texto em um tensor, mas isso pode ser caro (em particular, requer que você crie um Tensorpor coluna e, em seguida, concatene os numéricos juntos). Talvez uma alternativa mais fácil seja usar pandas.read_csv()e pandas.DataFrame.as_matrix()obter a entrada como um array NumPy.
março
3
O array NumPy deve ser coletado como lixo após a chamada para sess.run(embedding_init, ...)retorna (assumindo que você não mantenha uma referência a ele em seu programa). Dependendo da estrutura do seu programa, você pode desejar del embedding(onde embeddingestá o array NumPy) liberar o array mais cedo.
mrry
1
@mrry: você pode falar mais sobre a opção 1 e mais especificamente "não é eficiente em termos de memória porque o valor de um tf.constant () é armazenado várias vezes na memória". Memória ineficiente para a GPU ou CPU? De maneira mais geral, por que tf.constant () precisa ter várias cópias na memória, enquanto tf.Variable () + marcador de alimentação da opção 2 não tem esse problema?
Gabriel Parent
1
Se você também quer saber por que "o valor de um tf.constant () é armazenado várias vezes na memória", dê uma olhada nesta resposta: stackoverflow.com/a/42450418/5841473
alyaxey
33

Eu uso esse método para carregar e compartilhar a incorporação.

W = tf.get_variable(name="W", shape=embedding.shape, initializer=tf.constant_initializer(embedding), trainable=False)
LiuJia
fonte
A incorporação deve ser colunas ou linhas na matriz numpy?
Greyshack
6

A resposta de @mrry não está certa porque provoca a sobregravação dos pesos de embeddings de cada rede executada, portanto, se você está seguindo uma abordagem de minibatch para treinar sua rede, está sobrescrevendo os pesos dos embeddings. Então, no meu ponto de vista, a maneira certa de fazer embeddings pré-treinados é:

embeddings = tf.get_variable("embeddings", shape=[dim1, dim2], initializer=tf.constant_initializer(np.array(embeddings_matrix))
Eugenio Martínez Cámara
fonte
Duplicata exata da resposta de LiuJia.
TimZaman
4
@TimZaman .. Na verdade, ele está perdendo o argumento treinável = Falso e, portanto, acabará ajustando seus embeddings no processo.
Shatu
4
Além disso, acho que o raciocínio de Eugenio está incorreto. Você simplesmente não precisa executar a operação "embedding_init" com cada minilote e tudo ficará bem. Ou seja, apenas execute a inicialização de incorporação apenas uma vez no início do treinamento.
Shatu
@Shatu, como posso garantir que a inicialização de incorporação seja executada apenas no início do treinamento?
1
@ dust0x .. Se o tamanho dos embeddings for pequeno o suficiente, você pode apenas especificá-los como o valor inicial. Se eles forem muito grandes, você pode passá-los no feed_dict ao executar o inicializador para todas as variáveis. Avise-me se não estiver claro o suficiente e tentarei postar alguns códigos de amostra para ambas as abordagens.
Shatu
6

2.0 Resposta compatível : Existem muitos Embeddings Pré-Treinados, que são desenvolvidos pelo Google e que foram de fonte aberta.

Alguns deles são Universal Sentence Encoder (USE), ELMO, BERT, etc. e é muito fácil reutilizá-los em seu código.

Código de reutilizar a Pre-Trained Embedding, Universal Sentence Encoderé mostrado abaixo:

  !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 obter mais informações sobre os Embeddings pré-treinados desenvolvidos e disponibilizados pelo Google, consulte TF Hub Link .

Suporte Tensorflow
fonte
5

Com tensorflow versão 2 é muito fácil se você usar a camada de incorporação

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
fonte
3

Eu também estava enfrentando problemas de incorporação, então escrevi um tutorial detalhado com conjunto de dados. Aqui, gostaria de acrescentar o que experimentei. Você também pode tentar 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]}))

Aqui está trabalhando um exemplo detalhado do Tutorial Ipython, se você quiser entender do zero, dê uma olhada.

Aaditya Ura
fonte