zoukankan      html  css  js  c++  java
  • Recurrent Neural Network Language Modeling Toolkit代码学习

    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的大小。

    i 0 1 2 3 4 5 6 7 8 9
    sqrt(vocab[i].cn/b)/dd 0.17 0.12 0.12 0.12 0.12 0.09 0.07 0.07 0.07 0.05
    df 0.17 0.29 0.41 0.53 0.65 0.74 0.81 0.88 0.95 1
    a(before) 0 0 0 1 1 1 2 2 2 2
    (a+1)/class_size 0.33 0.33 0.33 0.66 0.66 0.66 1 1 1 1
    class_index 0 0 0 1 1 2 2 2 2 2
    a(after) 0 0 1 1 1 2 2 2 2 2

    **影响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

  • 相关阅读:
    Linux 查看端口占用情况
    Linux 的 ls 和 ll 的使用方法:
    awk文本分析
    【Linux】/etc/passwd文件中字段解释
    vue学习笔记(八)---源码学习
    uniapp学习笔记(更新中)
    微信小程序学习
    哈希表的原理
    容器通常具备一些固定的方法
    字符串的方法
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/7347381.html
Copyright © 2011-2022 走看看