在 TensorFlow 中使用预训练的词嵌入(word2vec 或 Glove)

Posted

技术标签:

【中文标题】在 TensorFlow 中使用预训练的词嵌入(word2vec 或 Glove)【英文标题】:Using a pre-trained word embedding (word2vec or Glove) in TensorFlow 【发布时间】:2016-06-11 18:59:26 【问题描述】:

我最近查看了convolutional text classification 的一个有趣的实现。然而,我查看过的所有 TensorFlow 代码都使用随机(未预训练)嵌入向量,如下所示:

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)

有人知道如何使用 Word2vec 或 GloVe 预训练词嵌入的结果而不是随机的吗?

【问题讨论】:

【参考方案1】:

使用 tensorflow 版本 2,如果您使用嵌入层,这将非常容易

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)

【讨论】:

【参考方案2】:

2.0 兼容答案:有许多预训练嵌入,由 Google 开发并已开源。

其中一些是Universal Sentence Encoder (USE), ELMO, BERT 等。在您的代码中重用它们非常容易。

重用Pre-Trained EmbeddingUniversal Sentence Encoder的代码如下所示:

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

有关由 Google 开发和开源的预训练嵌入的更多信息,请参阅 TF Hub Link。

【讨论】:

【参考方案3】:

我也面临嵌入问题,所以我用数据集写了详细的教程。 这里我想补充一下我试过的你也可以试试这个方法,

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

这里有详细的教程Ipython example如果你想从头开始理解,看看。

【讨论】:

【参考方案4】:

您可以通过多种方式在 TensorFlow 中使用预训练嵌入。假设您在一个名为 embedding 的 NumPy 数组中进行了嵌入,其中包含 vocab_size 行和 embedding_dim 列,并且您想要创建一个张量 W 可用于对 tf.nn.embedding_lookup() 的调用。

    只需将W 创建为以embedding 为值的tf.constant()

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

    这是最简单的方法,但内存效率不高,因为tf.constant() 的值在内存中存储了多次。由于embedding 可能非常大,因此您应该只将这种方法用于玩具示例。

    W 创建为tf.Variable 并通过tf.placeholder() 从NumPy 数组中对其进行初始化:

    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)
    

    这避免了在图中存储embedding 的副本,但它确实需要足够的内存来一次在内存中保存矩阵的两个副本(一个用于 NumPy 数组,一个用于tf.Variable)。请注意,我假设您希望在训练期间保持嵌入矩阵不变,因此 W 是使用 trainable=False 创建的。

    如果嵌入是作为另一个 TensorFlow 模型的一部分进行训练的,您可以使用 tf.train.Saver 从另一个模型的检查点文件加载值。这意味着嵌入矩阵可以完全绕过 Python。按照选项 2 创建 W,然后执行以下操作:

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

【讨论】:

我按如下方式创建 W:W = np.loadtxt("/media/w2vTest.txt",dtype ='string',delimiter = ' ') 创建为一行:['in' '0.070312......'-0.0625']。这里有问题!在删除'in'并将数字从字符串转换为float32之后,我应该将其视为我的W吗?如果是这种情况,那么如何将“in”连接到其各自的向量?或者我需要将数字转换为 float32,然后保持原样;期望 tensorflow 将完成所有必需的处理?谢谢! 啊,你有几个选择。您可以使用 TensorFlow tf.decode_csv() 操作将文本文件转换为张量,但这可能会很昂贵(特别是,它需要您为每列创建一个 Tensor,然后将数字的一起)。也许更简单的替代方法是使用 pandas.read_csv()pandas.DataFrame.as_matrix() 将输入作为 NumPy 数组。 NumPy 数组应该在对sess.run(embedding_init, ...) 的调用返回后进行垃圾回收(假设您没有在程序中保留对它的引用)。根据程序的结构,您可能希望del embedding(其中embedding 是 NumPy 数组)提前释放数组。 @mrry:你能多谈谈选项 1,更具体地说“它不是内存效率的,因为 tf.constant() 的值多次存储在内存中”。 GPU或CPU的内存效率低下?更一般的,为什么tf.constant()在内存中要多份,而选项2的tf.Variable()+feeding占位符就没有这个问题? 如果您还想知道为什么“tf.constant() 的值会在内存中多次存储”,请查看以下答案:***.com/a/42450418/5841473【参考方案5】:

我使用这种方法来加载和共享嵌入。

W = tf.get_variable(name="W", shape=embedding.shape, initializer=tf.constant_initializer(embedding), trainable=False)

【讨论】:

嵌入应该是numpy矩阵中的列还是行?【参考方案6】:

@mrry 的答案是不正确的,因为它会引发每次运行网络时覆盖嵌入权重,因此如果您采用小批量方法来训练网络,那么您就是在覆盖嵌入权重。因此,在我看来,预训练嵌入的正确方法是:

embeddings = tf.get_variable("embeddings", shape=[dim1, dim2], initializer=tf.constant_initializer(np.array(embeddings_matrix))

【讨论】:

刘佳的回答一模一样。 @TimZaman .. 事实上,他缺少 trainable=False 参数,因此最终会在此过程中微调他的嵌入。 另外,我认为 Eugenio 的推理是不正确的。您只是不必对每个小批量运行“embedding_init”操作,一切都会好起来的。也就是说,只在训练开始时运行一次嵌入初始化。 @Shatu 如何确保嵌入初始化仅在训练开始时运行? @dust0x .. 如果嵌入的大小足够小,您可以将它们指定为初始值。如果它们很大,您可以在为所有变量运行初始化程序时将它们传递到 feed_dict 中。如果还不够清楚,请告诉我,我会尝试为这两种方法发布一些示例代码。

以上是关于在 TensorFlow 中使用预训练的词嵌入(word2vec 或 Glove)的主要内容,如果未能解决你的问题,请参考以下文章

Tensorflow:如何将预训练模型已经嵌入的数据输入到 LSTM 模型中?

如何在 Tensorflow 中为未知单词添加新的嵌入(训练和预设测试)

使用 TensorFlow 的训练和预测出了啥问题?

动手学pytorch-词嵌入预训练模型Glove

如何在Tensorflow中添加未知单词的新嵌入(训练和预设测试)

仅从训练数据或整个数据中构建词汇表?