前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TF入门04-TF实现Word2Vec

TF入门04-TF实现Word2Vec

作者头像
公众号-不为谁写的歌
发布2020-07-23 17:51:16
1K0
发布2020-07-23 17:51:16
举报
文章被收录于专栏:桃花源记桃花源记

Word2Vec是一组用来产生词嵌入的模型,包括两种主要的模型:skip-gram和CBOW。

Skip-gram vs CBOW 算法层面上, 两种模型很相似,CBOW模型是从两边预测中心词,skip-gram模型是中心词预测两边。比如,对于“The quick brown fox jumps”,CBOW模型从上下文"the, “quick”, “fox”, 和"jumps"预测中心词“brown”,skip-gram模型从“brown”预测上下文"the, “quick”, “fox”, 和"jumps"。 统计层面上,CBOW模型通过将上下文看做一个样本组成,将分布信息做了平滑处理。大多数情况下,cbow模型适用于小型数据集;skip-gram模型将每个上下文-中心词对看做一个样本,用在大型数据集上表现更好。

在本文中,我们使用skip-gram模型来构建word2vec。为了得到词嵌入向量,我们需要构建一个单隐藏层的神经网络,然后用来执行特定任务来完成训练;但是训练得到的模型并不是我们需要的。我们只关注隐藏层的权重,这些权重就是词嵌入向量。

上面的特定任务是指给定中心词预测上下文。对于句子中的某个词,在词的上下文中随机选择一个词;网络模型可以输出整个词典中每个词是中心词上下文的概率。

Softmax、Negative Sampling & Noise Contrastive Estimation(NCE)

为了得到某个词的所有可能上下文词的概率分布,我们使用softmax来实现。softmax函数根据输入xix_ixi​输出一个概率值pip_ipi​。在这里xix_ixi​表示中心词的一个可能的上下文: softmax(xi)=exp(xi)∑jexp(xj) softmax(x_i) = \frac{exp(x_i)}{\sum_j exp(x_j)} softmax(xi​)=∑j​exp(xj​)exp(xi​)​ 但是,softmax用于归一化的分母的计算需要遍历整个词典,通常情况下词典长度在百万级别,而且指数的计算也比较耗时,这就导致了softmax的计算量进一步加大

为了规避这个计算瓶颈,我们可以使用分层softmax(hierarchical softmax)和基于采样的softmax。论文Distributed Representations of Words and Phrases and their Compositionality 指出训练skip-gram模型,和分层softmax方法相比,使用negative sampling的方法训练速度更快,得到的词向量更好。

Negative Sampling(负采样)是基于采样方法的一种。基于采样的方法也包括重要性采样(importance sampling)和目标采样(target sampling)。负采样方法是NCE的简化版:负采样对噪声样本(负样本)的采样数量k以及噪声数据服从的分布Q做了假定,kQ(w)=1

负采样方法用于学习词嵌入表示,并不能保证其梯度值和softmax函数梯度值相近;而NCE方法随着负样本采样数的增加其提取值也愈来愈逼近于softmax的梯度值。Mnih and Teh(2012)表明使用25个噪声样本的计算结果与softmax的计算值差距不大,而且运算速度能加快45倍。因此,我们使用NCE来实现word2vec。

基于采样的方法,无论是负采样还是NCE方法,只适用于训练阶段;在应用阶段还需要执行softmax来得到正则化的概率结果。

数据介绍

2006年3月3日的维基百科文本的100MB数据text8。

100MB数据训练得到的词嵌入虽然表现不太好,但是从中也能看到一些有趣的现象。使用空格切分数据后,文本包括17005207个词。为了得到更好的词嵌入,需要使用更大的数据集。

Overview

使用TensorFlow实现模型,需要景观两个阶段:定义计算图以及图的运行。

阶段一:图定义

  1. 导入数据(tf.data 、placeholders)
  2. 定义权重
  3. 定义模型
  4. 定义损失函数loss
  5. 定义优化器

阶段二:执行运算图

  1. 变量初始化
  2. 初始化迭代器/向模型传送数据
  3. 执行前向计算
  4. 计算cost
  5. 梯度计算来调整模型参数

阶段一:图定义

1. 创建dataset,生成样本

skip-gram模型的输入为(中心词,上下文词)pair对。数据传送到模型之前,需要将字符串类型转换成indices表示,如果“computer”是词典中第100个单词,那么对象下标为99。

每一个样本数据是一个标量,BATCH_SIZE个输入样本的构成tensor的shape 为[BATCH_SIZE],输出样本的shape为[BATCH_sIZE, 1].

2.定义权重

在embedding矩阵中每一行表示一个词的向量表示。如果词向量长度为EMBED_SIZE,embedding矩阵的shape为[VOCAB_SIZE, EMBED_SIZE]

3. Inference

为了从embed_matrix中得到对应输入的词向量表示,我们可以使用tf.nn.embedding_lookup来实现:

这个函数相当于一个查表操作,根据输入ids在params找到对应的向量。

如果输入是one_hot表示,向量乘以矩阵可以很快地找到one_hot非零值对应的向量(one_hot中非零值为第4个,相乘后结果就是矩阵的第4行);使用相乘方法,由于one_hot表示有很多0值进而会产生许多不必要的计算;使用tf.nn.lookup就可以节省这些不必要的计算。

为了得到中心词的embedding表示,

代码语言:javascript
复制
embed = tf.nn.embedding_lookup(embed_matrix, center_words, name='embed')
4. 定义损失函数

​ TensorFlow已经为我们实现了NCE损失函数:

代码语言:javascript
复制
tf.nn.nce_loss(
    weights,
    biases,
    labels,
    inputs,
    num_sampled,
    num_classes,
    num_true=1,
    sampled_values=None,
    remove_accidental_hits=False,
    partition_strategy='mod',
    name='nce_loss'
)

为了计算NCE loss,需要定义计算loss的隐藏层权重weights和偏置biases。在训练过程中这些参数会自动更新、优化。在采样之后,最终结果的计算过程如下:

代码语言:javascript
复制
tf.matmul(embed, tf.transpose(nce_weight)) + nce_bias

这项计算包含在tf.nn_nce_loss的计算过程中。

代码语言:javascript
复制
nce_weight = tf.get_variable('nce_weight', shape=[VOCAB_SIZE, EMBED_SIZE], initializer=tf.truncated_normal_initializer(stddev=1.0 / (EMBED_SIZE ** 0.5)))
nce_bias = tf.get_variable('nce_bias', initializer=tf.zeros([VOCAB_SIZE]))

损失函数定义如下:

代码语言:javascript
复制
loss = tf.reduce_mean(tf.nn.nce_loss(weights=nce_weight,
                              biases=nce_bias,
                              labels=target_words,
                              inputs=embed,
                              num_sampled=NUM_SAMPLED,
                              num_classes=VOCAB_SIZE))
5. 定义优化器
代码语言:javascript
复制
optimizer = tf.train.GradientDescentOptimizer(LEARNING_RATE).minimize(loss)

阶段二:图的执行

创建一个会话来执行优化op。

代码语言:javascript
复制
with tf.Session() as sess:
    # 迭代器初始化
    sess.run(iterator.initializer)
    # 变量初始化
    sess.run(tf.global_variables_initializer())

    writer = tf.summary.FileWriter('graphs/word2vec_simple', sess.graph)

    for index in range(NUM_TRAIN_STEPS):
        try:
            # 执行优化,计算loss
            loss_batch, _ = sess.run([loss, optimizer])
        except tf.errors.OutOfRangeError:
            sess.run(iterator.initializer)
    writer.close()

完整代码地址:ClickMe

Reference

Stanford CS 20: Tensorflow for Deep Learning Research

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-05-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Softmax、Negative Sampling & Noise Contrastive Estimation(NCE)
  • 数据介绍
  • Overview
    • 阶段一:图定义
      • 1. 创建dataset,生成样本
      • 2.定义权重
      • 3. Inference
      • 4. 定义损失函数
      • 5. 定义优化器
    • 阶段二:图的执行
      • Reference
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档