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

use*_*590 89 python numpy deep-learning tensorflow

我最近回顾了一个卷积文本分类的有趣实现.但是,我所评论的所有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)
Run Code Online (Sandbox Code Playgroud)

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

mrr*_*rry 127

有几种方法可以在TensorFlow中使用预先训练的嵌入.假设你有一个名为NumPy数组的嵌入embedding,包含vocab_size行和embedding_dim列,你想要创建一个W可以在调用中使用的张量tf.nn.embedding_lookup().

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

    W = tf.constant(embedding, name="W")
    
    Run Code Online (Sandbox Code Playgroud)

    这是最简单的方法,但它不具有内存效率,因为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})
    
    Run Code Online (Sandbox Code Playgroud)

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

  3. 如果嵌入是作为另一个TensorFlow模型的一部分进行训练的,则可以使用a 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")
    
    Run Code Online (Sandbox Code Playgroud)

  • 啊,你有几个选择.你*可以*使用TensorFlow`tf.decode_csv()`op将文本文件转换为张量,但这可能很昂贵(特别是,它要求你每列创建一个`Tensor`,然后连接数字一起).也许更容易的选择是使用[`pandas.read_csv()`](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html)和[`pandas.DataFrame.as_matrix ()`](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.as_matrix.html)将输入作为NumPy数组. (4认同)
  • 在调用`sess.run(embedding_init,...)`返回之后,应该对NumPy数组进行垃圾回收(假设你没有在程序中保留对它的引用).根据程序的结构,你可能想要"del embedding"(其中`embedding`是NumPy数组)来更早地释放数组. (3认同)

Liu*_*Jia 31

我使用此方法加载和共享嵌入.

W = tf.get_variable(name="W", shape=embedding.shape, initializer=tf.constant_initializer(embedding), trainable=False)
Run Code Online (Sandbox Code Playgroud)


Ten*_*ort 10

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

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

重用Pre-Trained Embedding, 的代码Universal 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)
Run Code Online (Sandbox Code Playgroud)

有关由 Google 开发和开源的 Pre-Trained Embeddings 的更多信息,请参阅TF Hub Link


小智 5

@mrry的答案是不正确的,因为它可以解释每个网络运行时嵌入权重的覆盖,因此如果您按照小批量方法训练网络,则会覆盖嵌入的权重.因此,根据我的观点,预训练嵌入的正确方法是:

embeddings = tf.get_variable("embeddings", shape=[dim1, dim2], initializer=tf.constant_initializer(np.array(embeddings_matrix))
Run Code Online (Sandbox Code Playgroud)

  • @TimZaman ..实际上,他缺少trainable = False参数,因此最终将微调他的嵌入过程. (4认同)
  • 另外,我认为Eugenio的推理是不正确的.你只需要在每个迷你批次中运行"embedding_init"操作,一切都会好的.也就是说,只需在训练开始时运行一次嵌入初始化. (4认同)

sad*_*med 5

如果您使用 Embedding 层,那么使用 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)

Run Code Online (Sandbox Code Playgroud)