Recurrent neural network language modeling toolkit 源码走读(

Strategies for Training Large Scale Neural Network Language Models(点此阅读)

这篇主要介绍一个网络前向计算的函数,内容量也挺大的。在此之前,解释一下rnn的输出层分解,和从神经网络的角度去看最大熵模型。先看一下原论文中最"标准"的rnn结构,这个结构是最原始的,后面会有系列的扩展,,详见参考文献的第3篇。

上图是最原始的循环神经网络的结构,关于它的前向计算和学习算法我在rnnlm原理以及bptt数学推导这篇文章有详细的写过。简要在写一下。上面这个网络的输出层有|V|维,在整个前向计算完毕后,我们得到的结果就是预测词的概率分布,即yt = P(wt+1 | wt,st-1), wt+1是要预测的词.

这是我从前篇文章截图来的,由于网络输出层部分计算量很大,特别是当|V|很大时,计算量会更大。于是Mikolov提出了将输出层分解,并不是在所有单词上计算概率的分布,而是在某一类单词中计算概率分布,这样就会大大降低计算量。于是有了如下图:

现在的计算预测词的概率分布变成了如下:

其中,yV'(t)表示在V中的部分词语,至于这个部分是哪一部分,得看怎么把这些单词分类了,ci表示类别, wt+1表示期望词。这样在前向计算概率分布时,就先计算在期望词的类别的概率分布,然后在当前预测词所在类别的词语上计算概率分布,这个待会会在源代码中看到。

void CRnnLM::computeNet(int last_word, int word){//last_word表示当前输入层所在的词//word表示要预测的词int a, b, c;real val;double sum; //sum is used for normalization: it's better to have larger precision as many numbers are summed together here//将last_word对应的神经元ac值为1,也可以看做是对该词的1-of-V的编码if (last_word!=-1) neu0[last_word].ac=1;//下面计算输入到隐层的部分for (a=0; a<layer1_size; a++) neu1[a].ac=0;for (a=0; a<layerc_size; a++) neuc[a].ac=0;//这里计算的是s(t-1)与syn0的乘积matrixXvector(neu1, neu0, syn0, layer0_size, 0, layer1_size, layer0_size-layer1_size, layer0_size, 0);//这里计算将last_word编码后的向量(大小是vocab_size,分量只有一个为1,其余为0)与syn0的乘积for (b=0; b<layer1_size; b++) {a=last_word;if (a!=-1) neu1[b].ac += neu0[a].ac * syn0[a+b*layer0_size].weight;}//这里计算将上面隐层所得到的输入(ac值)经过sigmoid函数的映射结果for (a=0; a<layer1_size; a++) {//为数值稳定,将ac值大小限制在[-50,50]//论文中有提到模型的参数小一些泛化的结果好一些if (neu1[a].ac>50) neu1[a].ac=50;if (neu1[a].ac<-50) neu1[a].ac=-50;val=-neu1[a].ac;//fasterexp函数在fasexp.h中实现,应该比math.h中的exp快吧neu1[a].ac=1/(1+fasterexp(val));//sigmoid函数即1/(1+e^(-x))}if (layerc_size>0) {//计算隐层到压缩层的结果matrixXvector(neuc, neu1, syn1, layer1_size, 0, layerc_size, 0, layer1_size, 0);//和上面类似,这里计算的是压缩层for (a=0; a<layerc_size; a++) {if (neuc[a].ac>50) neuc[a].ac=50; //for numerical stabilityif (neuc[a].ac<-50) neuc[a].ac=-50; //for numerical stabilityval=-neuc[a].ac;neuc[a].ac=1/(1+fasterexp(val));}}//1->2 class//输出层class_size部分ac值置0for (b=vocab_size; b<layer2_size; b++) neu2[b].ac=0;//计算压缩层到class层(输出层的一部分)if (layerc_size>0) {matrixXvector(neu2, neuc, sync, layerc_size, vocab_size, layer2_size, 0, layerc_size, 0);}else{//无压缩层,直接计算隐层到输出层matrixXvector(neu2, neu1, syn1, layer1_size, vocab_size, layer2_size, 0, layer1_size, 0);}

另外一个要说明的是最大熵模型,rnn结合了最大熵模型,直观的看上去是输入层与输出层连接了起来(虽然作者总是这么说,但我总觉的不能叫输入层和输出层连接起来,中间有过渡)。我们先看一下从神经网络的视角去看一个最大熵模型,这个神经网络就是没有隐层而已,其他和三层结构的一样,并且学习算法也是一样的。如下图:

分明是比谁记的都清楚,比谁都更加在意,

Recurrent neural network language modeling toolkit 源码走读(

相关文章:

你感兴趣的文章:

标签云: