基于循环神经网络(RNN)的神经语言模型

这篇主要介绍神经语言模型的结构。与RNN相比,NLP应用中主要多了两个层:词向量层(embedding)和softmax层。下面对这两个层分别进行介绍。

一.词向量层(embedding)

  在神经网络的输入层,每一个单词用一个实数向量来表示,这个向量被成为“词向量”(Word embedding,也可以翻译成:词嵌入)。词向量可以形象的理解为将词汇表嵌入到一个固定维度的是实数空间里。将单词编号转化为词向量主要有两大作用。

  1.降低输入的维度。如果不使用词向量层,而直接将单词以One-hot vector的形式输入循环神经网络,那么输入的维度大小将与词汇表大小相同,通常在1000以上。而词向量的维度通常在200~1000之间,这将大大减少循环神经网络的参数数量和计算量。

  2.增加语义信息。简单的单词编号是不包含任何语义信息的。两个单词之间编号相近,并不意味着它们的含义有任何联系。而词向量层将稀疏的编号转化为稠密的向量表示,这使得词向量有可能包含更多丰富的信息。在自然语言应用中学习得到的词向量通常会将含义相似的词赋予取值相近的词向量值,使得上层的网络可以更容易的抓住相似单词之间的共性。举例来说,因为猫和狗都需要吃东西,因此在预测下文中出现单词“吃”的概率时,上文中出现“猫”和“狗”带来的影响可能是相似的。在这样的任务训练出来的词向量中,代表“猫”和“狗”的词向量取值很可能是相近的。

假设词向量的维度是emb_size,词汇表的大小为vocab_size,那么所有单词的词向量都可以放入一个大小为emb_size*vocab_size的矩阵内,在读取词向量时,可以调用tf.nn.embedding_lookup的方法。

embedding=tf.get_variable("embedding",[vocab_size,emb_size])
input_embedding=tf.nn.embedding_lookup(embedding,input_data)
#输出矩阵比输入矩阵多一个维度,新增的维度大小为emb_size,在语言模型中,一般input_data的维度为batch_size*num_steps,而输出的input_embedding的维度为batch_size*num_steps*emb_size

二.softmax层

softmax的主要作用是将循环神经网络的输出转化为一个单词表中每个单词的输出概率。为此需要两个步骤:

1.使用一个线性映射将循环神经网络的输出映射为一个维度与词汇表大小相同的向量。这一步的输出叫做logits。

#定义线性映射用到的参数。hidden_size是循环神经网络的隐藏状态维度,vocab_size是词汇表的大小。
weight=tf.get_variable("weight",[hidden_size,vocab_size])
bias=tf.get_variable("bias",[vocab_size])
#计算线性映射,output是RNN的输出,其维度为[batch_size*num_steps,hidden_size])
logits=tf.nn.bas_add(tf.matmul(output,weight),bias)

2.调用softmax方法将logits转化为和为1的概率,事实上,语言模型的每一步输出可以看做是一个分类问题:在vocab_size个可能的类别中决定这一步最可能输出的单词。

#prob的维度与logits的维度相同
probs=tf.nn.sotfmax(logits)

模型训练通常并不关心概率的具体取值,而更关心最终的log perplexity(对数复杂度),因此可以直接调用tf.nn.sparse_sotfmax_cross_entropy_with_logits方法直接从logits计算log perplexity作为损失函数:

#labels是一个大小为[batch_size*num_steps]的一维数组,它包含每个位置正确的单词编号。
#logits的维度为[batch_size*num_step,hidden_size]
#loss的维度与labels相同,代表每个位置上的log perplexity
loss=tf.nn.sparse_softmax_cross_entropy_with_logits(labels=tf.reshape(self.targets,[-1]),logits=logits)



你可能感兴趣的:(深度学习细节)