Recurrent Neural Network Language Modeling Toolkit代码学习

来源:互联网 发布:php基础知识:blog 编辑:程序博客网 时间:2024/05/23 15:22

Recurrent Neural Network Language Modeling Toolkit  工具使用点击打开链接

本博客地址:http://blog.csdn.net/wangxinginnlp/article/details/38385471


按照训练的进度学习代码:

RNN训练过程(摘自Mikolov的博士论文):

1. Set time counter t = 0, initialize state of the neurons in the hidden layer s(t) to 1

2. Increase time counter t by 1
3. Present at the input layer w(t) the current word wt
4. Copy the state of the hidden layer s(t..1) to the input layer
5. Perform forward pass as described in the previous section to obtain s(t) and y(t)
6. Compute gradient of error e(t) in the output layer
7. Propagate error back through the neural network and change weights accordingly
8. If not all training examples were processed, go to step 2


trainNet()中的结构:

大循环: 1518-1679 每一轮循环都包括train set和valid set上循环,循环终止:1665-1670

在train set上的循环: 1535-1586 循环终止:1554

在valid set上的循环: 1620-1646 循环终止:1623


step1. 

learnVocabFromTrainFile() 统计训练文件中所有的单词信息,并对统计好的信息进行整理

涉及的数据结构:

vocab_word

ocab_hash *int

                    

涉及的函数:

addWordToVocab(char *word)

对于一个单词w,将其信息存入vocab_word结构的数组中,其结构下标为wp,然后取w的hash码(getWordHash),使该hash码的值为其在vocab_word结构

中的下标wp。[后面会对vocab_word进行sort,单词w的下标可能会发生改变,这个在searchVocab中会有体现]

searchVocab(char *word)

查找并返回单词w在vocab_word中的下标。取其hash码,在vocab_hash中查找,如果查不出则返回-1,否则找到的下标,取出vocab中该下标对应单词

与单词w进行对比,如果相同,则返回该下标,否则在vocab中逐个查找对比,对找到的下标在vocab_has中进行添加并返回;如果还是找不到,则返回-1。

sortVocab()

依据单词在训练集中出现的次数,对vocab_word进行重排序。


step2. 

initNet()

初始化神经网络结构(神经元和其连接)

需要注意的是:(其中layer1_size为隐藏层节点的个数

输入层的节点个数 layer0_size=vocab_size+layer1_size; 

输出层的节点个数:layer2_size=vocab_size+class_size;

涉及的数据结构:

neuron


注意:最后需要对vocab中的class_index进行赋值,并索引class_word, class_cn。

478-490: 对vocab的class_index进行赋值。

举例:假设经过sort后大小为10的vocab词频依次为100,50,50,50,50,30,20,20,20,10,class_size设为3.

479: b = 400

480: dd = sqrt(100/400) +sqrt(50/400)*3 +sqrt(30/400) +sqrt(20/400)*3 +sqrt(10/400) ~ 2/99 = 3

481-490:循环中各个变量的变化,在给class_index赋值时候,主要比较df和(a+1)/class_size的大小。

i0123456789sqrt(vocab[i].cn/b)/dd0.170.120.120.120.120.090.070.070.070.05df0.170.290.410.530.650.740.810.880.951a(before)0001112222(a+1)/class_size0.330.330.330.660.660.661111class_index0001122222a(after)0011122222

**影响vocab中元素class_index赋值的是其元素的总体频率情况。


505-514: 对class_index赋值后,将vocab元素像串羊肉串(有多少个类就有多少根串)分别串起来.

class_cn记录每个class的元素个数;class_words负责把这些元素串起来,class_words最终指向的内容为单词在vocab中的下标。这么做的目的是为了

在输出层更快速地进行归一化(for faster search when normalizing probability at output layer)。


step3.

computeNet(last_word, word)

使用last_wor和加密过的history信息对下一个可能出现的单词word概率进行预测。

                                                                                   

图1. 模型结构

具体进行步骤:

1109: 计算 s(t-1)与矩阵W

1111-1114: 计算w(t)与矩阵U

1116-1122: 激活s(t)

1138-1144: 计算s(t)与矩阵X,将C向量计算出来。

1169-1178: 对输出层的classes向量C进行softmax(最后输出层由y(t)向量与classes向量组成)。

1185-1194: 计算s(t)与矩阵V,将y(t)向量计算出来。

值得注意的是:计算y(t)的时候,并非所有的单词的概率都计算出来。仅计算与单词t-1相同类的单词概率。与单词t-1类别相同的单词的起止下标:

起:class_words[vocab[word].class_index][0]

止: class_words[vocab[word].class_index][0]+class_cn[vocab[word].class_index]

[**为什么要对单词分类,如何对单词进行分类?这两个问题在其博士论文中有讲解,参见其博士论文37页中的3.4.2节 Factorization of the Output 

Layer。 最后P(w_t+1 | s(t)) = P(c_i|s(t))* P(w_i|c_i, s(t)) w_i是w_t+1在vocab中的位置,c_i是w_t+1的类别]

1222-1235: 对输出层的y(t)向量进行softmax。

涉及的函数:

matrixXvector(struct neuron *dest, struct neuron *srcvec, struct synapse *srcmatrix, int matrix_width, int from, int to, int from2, int to2, int type)

根据srcvec向量和srcmatrix矩阵的值和其他相关信息,计算出dest向量的值。注意最后一个参数:0 表示计算节点的激活值;1表示计算节点的“残差”。


step4.

learnNet(last_word, word)

根据上一步中y(t)与word信息,计算出各个节点的“残差”(neu[i].er),然后由此更新连接矩阵的权重。

1247-1261:分别计算出word部分和class部分的残差。[word部分仍然只计算同类word的残差]

1354-1364: 根据输出层y(t)的“残差”和矩阵V,计算出是s(t)关于y(t)部分“残差”,并更新矩阵V。

1366-1376: 根据输出层C的“残差”和矩阵X,计算出是s(t)关于C部分“残差”,并更新矩阵X。

1390-1395: 根据s(t)“残差”信息和矩阵U,计算出W(t)的“残差”,并更新矩阵U。

1396-1400: 根据s(t)“残差”信息和矩阵W,计算出s(t-1)的“残差”,并更新矩阵W。

至此,该递归神经结构中的所有连接权重(即矩阵 U W V X)全部更新完毕。


step5.

copyHiddenLayerToInput()

将s(t)向量中的激活值(ac)拷贝到s(t-1)。 注意:仅拷贝激活值(ac),残差(er)不拷贝


step6.

netReset()

如果模型设置为independent sentences mode(句子与句子之间独立?)并且遇到句子开始符号'</s>'(在learnVocabFromTrainFile() 中readWord函数处理

文件,使每个句子以‘</s>’开头),对模型中的节点信息[不是矩阵信息]进行重置。

968-972: 将s(t)中的激活值全部置1,并将s(t)向量中的激活值(ac)拷贝到s(t-1)。


在train set上进行训练时候有两部值得注意:

1554: train set上的迭代终止条件:train set上的语料全部学习了一遍。

1556: P(w|context)的概率 P(w_t+1 | s(t)) = P(c_i|s(t))* P(w_i|c_i, s(t)) w_i是w_t+1在vocab中的位置,c_i是w_t+1的类别


至此,在train set上循环完成一轮

=================================================================================================================


step7.

netFlush()

将所有的激活值和“残差”置0


**在valid set上没有learnNet步骤,不用调节参数

在valid set上循环完后,计算几个概率值:

1650:valid log probability

1651:PPL net

1655:valid entropy


step8.

saveNet()

保存模型的参数和模型的其他信息。



引用:

1. Mikolov的博士论文 :Statistical language models based on neural networks

8 0
原创粉丝点击