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


95

我最近审查了卷积文本分类的一个有趣的实现。但是我检查过的所有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预训练词嵌入的结果,而不是随机的结果?

Answers:


130

您可以通过多种方式在TensorFlow中使用预训练的嵌入。假设你有一个与NumPy阵列称为嵌入embedding,用vocab_size行和embedding_dim列,要创建一个张量W,可以在一个呼叫中使用tf.nn.embedding_lookup()

  1. 只需创建W一个tf.constant()是需要embedding为它的价值:

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

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

  2. 创建W为a tf.Variable并通过NumPy数组对其进行初始化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})
    

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

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

    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吗?如果是这样,那么如何将“输入”连接到其各自的向量?或者我需要将数字转换为float32,然后按原样保留“ in”;期望tensorflow将完成所有必需的处理?谢谢!
user3147590 '02

4
啊,您这里有两个选择。您可以使用TensorFlow tf.decode_csv()op将文本文件转换为张量,但这可能会很昂贵(特别是,它需要您为Tensor每列创建一个,然后将数字列连接在一起)。也许更简单的选择是使用pandas.read_csv()并将pandas.DataFrame.as_matrix()输入作为NumPy数组获取。
mrry '16

3
在调用return之后,应该对NumPy数组进行垃圾回收sess.run(embedding_init, ...)(假设您没有在程序中保留对其的引用)。根据程序的结构,您可能希望del embeddingembeddingNumPy数组在哪里)更早地释放该数组。
mrry'3

1
@mrry:您可以详细谈谈选项1,更具体地说:“由于tf.constant()的值在内存中多次存储,因此内存使用效率不高”。GPU或CPU的内存效率低下?更一般而言,为什么tf.constant()必须在内存中具有多个副本,而选项2的tf.Variable()+填充占位符却没有此问题?
加百利(Gabriel)父母

1
如果您还想知道为什么“ tf.constant()的值在内存中多次存储”,请查看以下答案:stackoverflow.com/a/42450418/5841473
alyaxey

33

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

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

嵌入应该是numpy矩阵中的列还是行?
Greyshack

6

@mrry的答案不正确,因为它会导致覆盖每个运行网络的嵌入权重,因此,如果您采用小批量方法来训练网络,则将覆盖嵌入权重。因此,以我的观点,预训练嵌入的正确方法是:

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

刘佳答案的精确副本。
TimZaman '16

4
@TimZaman ..实际上,他缺少了trainable = False参数,因此最终会在此过程中微调其嵌入。
沙图

4
另外,我认为Eugenio的推理是不正确的。您只需要在每个迷你批处理中都不必运行“ embedding_init”操作,那么一切都会好起来的。也就是说,仅在训练开始时运行一次嵌入初始化。
Shatu

@Shatu如何确保仅在训练开始时才执行嵌入初始化?

1
@ dust0x ..如果嵌入的大小足够小,则只需将它们指定为初始值即可。如果它们很大,则可以在为所有变量运行初始化程序时将它们传递到feed_dict中。请让我知道是否还不够清楚,我将尝试为这两种方法发布一些示例代码。
Shatu

6

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)

有关更多信息,请参见TF Hub Link,它是Google开发和开放源代码的预培训嵌入。


5

在Tensorflow版本2中,如果您使用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)


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

如果您想从头开始理解,请看这里工作详细的Tutorial Ipython示例

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.