相信我,我们可以更快乐,因为童真只是一种态度!
——宫崎骏
全文字数:2507字
阅读时间:10分钟
前言
由于在公众号上文本字数太长可能会影响阅读体验,因此过于长的文章,我会使用"[L1]"来进行分段。这个系列将主要借鉴《Tensorflow实战Google学习框架》这本书,主要介绍实现语言模型的一些前期准备,后期会出更详细的文章。
实战语言模型系列:
a
Embedding 层
在介绍完了如何处理数据以及如何构造样本之后,就可以构建我们的神经网络语言模型了,下面是使用LSTM构建的语言模型的大体结构:
▲使用循环神经网络实现自然语言模型的示意图
那可以看出上面着重写出来的两层:
那接下来介绍embedding层。embedding层也称为词向量层或者是词嵌入层。那大家肯定知道在自然语言中词的表示方法类型有两种:
下面来简单说一说这两种表示方式,理解了这两种词的表示方式能够更好的了解为什么需要词向量层。
▍ 独热one-hot表示方式
这种方式是目前最常用的词的表示方法,这种方法把每个词表示为一个很长的词向量,这个很长向量的维度就是词项(不重复的词)字典中的个数,也就是我们在前面构造ptb数据集时候构造的字典。回忆我们在构造字典的时候把每个词按照词频进行排序,然后每一行代表一个词。one-hot表示方式说的就是词汇表中的单词都用一个词汇表那么长的向量表示,只有在词汇表中对应单词的位置为1,其余的所有位置都是0,通过这样稀疏的向量来表示这个单词。这种方式的缺点和优点点都很明显:
其实one-hot仅仅是将词符号化,后来就出现了词的分布表示。
▍ 词的分布表示
Harris在1954年提出的分布假说为词的分布表示提供了理论基础,假说的基本内容说的是"上下文相似的词,其语义也相似"。后来Firth在1957年对分布假说进行了进一步的阐述和明确:"词的语义由上下文决定"。
到目前为止,基于分布假说的词表示方法,根据建模的不同,主要分成:
虽然这些分布表示的方法不同,但是这些分布表示都是基于分布假说的,他们的核心思想也都有两部分组成:
我们使用神经网络能够很高效方便的描述出分布假说的核心思想的两个部分。而恰巧我们的语言模型具有能够捕捉上下文信息的能力,那么构建上下文与目标词之间的关系,最自然的一种思路就是使用语言模型。所以早期的词向量仅仅是神经网络训练语言模型的副产品。将one-hot转换成词向量主要有两大作用:
说了这么多词向量,而且上面也说了词向量是由语言模型训练的,所以对于大家熟悉的word2vec中的CBOW以及skip-gram仅仅是训练语言模型的一种方式。有人会说那和我们的embedding层有什么关系呢?其实对于我们现在的任务来说,embedding层和word2vec(实质上也就是一个两层的神经网络)的作用和效果一样,因为他们都是使用语言模型训练出来的。那你可能有疑问,因为很多时候,我们看到没有训练语言模型的时候仍然使用embedding层,那这就和使用语言模型训练词向量有点矛盾,其实这也是embedding层和word2vec的区别所在,embedding层是根据我们的任务所定,训练与我们任务有关系的词向量,和我们训练的任务有很大的关系,但是使用word2vec的话,仅仅是使用语言模型训练出来的词向量,表示的是一个词的向量空间,使用Word2vec的话,往往和我们的任务有很大的距离。
假设词向量的维度是EMB_SIZE,词汇表的大小为VOCAB_SIZE,那么所有单词的词向量可以放入一个大小为VOCAB_SIZE * EMB_SIZE。在读取词向量的时候,tensorflow给我们提供了一个tf.nn.embedding_lookup方法,那下面看看如何在使用tensorflow实现embedding层:
import tensorflow as tf
#这里仅仅使用get_variable声明了一个名字叫做"embedding"的词向量矩阵
embedding = tf.get_variable("embedding",[VOCAB_SIZE,EMB_SIZE])
input_embedding = tf.nn.embedding_lookup(embedding,input_data)
这样一看觉得还是很难理解,下面我通过一个简单的例子来演示一下:
import tensorflow as tf
#词汇表为4
VOCAB_SIZE = 4
#将维度到2
EMB_SIZE = 2
#随机生成一个词向量矩阵
embedding = tf.get_variable(
name = "embedding",
shape =(VOCAB_SIZE,EMB_SIZE),
initializer=tf.truncated_normal_initializer(stddev = 0.1) )
input_data = [0,1]
input_embedding = tf.nn.embedding_lookup(embedding,input_data)
with tf.Session() as sess:
#初始化变量
sess.run(tf.global_variables_initializer())
# 打印出随机初始化的词向量矩阵
print("embedding layer:"+ str(sess.run(embedding)) )
print("embedding layer output:" + str(sess.run(input_embedding)))
▲embedding层的过程