rnnlm源码分析 六

本文深入剖析RNNLM(循环神经网络语言模型)的源码,涵盖从基本原理到扩展应用。通过一系列经典论文,探讨在大规模神经网络语言模型训练中的策略和挑战,以及如何解决长期依赖问题。了解神经概率语言模型的构建和学习过程,探究人工神经网络在语言建模中的可能性。
摘要由CSDN通过智能技术生成
               
系列前言
参考文献:
  1. RNNLM - Recurrent Neural Network  Language Modeling Toolkit(点此阅读)
  2. Recurrent neural network based language model(点此阅读)
  3. EXTENSIONS OF RECURRENT NEURAL NETWORK LANGUAGE MODEL(点此阅读)
  4. Strategies for Training Large Scale Neural Network  Language Models(点此阅读)
  5. STATISTICAL LANGUAGE MODELS BASED ON NEURAL  NETWORKS(点此阅读)
  6. A guide to recurrent neural networks and backpropagation(点此阅读)
  7. A Neural Probabilistic Language Model(点此阅读)
  8. Learning Long-Term Dependencies with Gradient Descent is Difficult(点此阅读)
  9. Can Artificial Neural Networks Learn 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 stability   if (neuc[a].ac<-50) neuc[a].ac=-50//for numerical stability   val=-neuc[a].ac;   neuc[a].ac=1/(1+fasterexp(val));  }    }     //1->2 class //输出层class_size部分ac值置0    for (b=vocab_size; b<layer2_size; b++) neu2[b].ac=0;     //计算压缩层到class层(输出层的一部分)    if (layerc_size>0) {  matrixXvector(neu2, neuc, sync, layerc_size, vocab_size, lay
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值