在 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 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)
有关由 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 将完成所有必需的处理?谢谢! 啊,你有几个选择。您可以使用 TensorFlowtf.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 中为未知单词添加新的嵌入(训练和预设测试)