码迷,mamicode.com
首页 > Web开发 > 详细

Recurrent neural network language modeling toolkit 源码深入剖析系列(二)

时间:2015-03-31 09:14:26      阅读:229      评论:0      收藏:0      [点我收藏+]

标签:rnnlm

系列前言
参考文献:
  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?(点此阅读)

最近学习完系列神经网络语言模型后,最好的更为深刻的理解方式就是阅读源码,看一看究竟怎么实现的,认真的分析过源码,并且画出内部的数据结构图之后,才觉的了解的更透彻,甚至感觉自己能换一种语言重写这个开源工具。而且从阅读源码的过程中学到了很多实现技巧。当然自己的理解很多地方是比较狭隘的,可能有许多错误,而且某些地方是感觉那么回事,也没太仔细的思考,可能很多就没想清楚。而有些地方只有几行代码,却无奈的坐在那里想了一个下午╮(╯▽╰)╭,连吃饭、走路的时候也在想,我想这是快走火入魔了吧,哈哈。另外不知道对不对的起标题中的"深入"两个字啊,反正看上去高端点,就先这么标着吧。由于我在代码中注释很多,几乎是每行一注释,很多想仔细说的也在源码注释里面,所以内容主要以代码注释为主,外加对源码内部数据结构的图解。并且原谅我喜欢把参考内容放到最上面,养成习惯了,上面的8篇文章一开始读的话最好读第5篇,其他的内容都会在第5篇中大概的提到。另外为了懒得跑到另一篇文章去看图解,所以图解可能会反复出现在每篇文章中。

前言完了,上一篇是介绍成员变量的大概含义,这一篇是介绍一些成员函数的功能,仍然是大体了解一下个别函数的功能,在第三篇才正式写实现分析。这一篇稍短,里面大部分是代码,因为很多涉及变量相关的在上一篇注释过了,所以这篇就没注释那么详细。如下:



 //构造函数,这里进行很多变量的初始化    
CRnnLM()        //constructor initializes variables    
{    
    //这里的很多变量在前面都前一篇都有详细的介绍  
    //这里的初始值只要初始是为非0的可以留意一下  
    version=10;    
    filetype=TEXT;    
        
    use_lmprob=0;    
    lambda=0.75;    
    gradient_cutoff=15;    
    dynamic=0;    
        
    train_file[0]=0;    
    valid_file[0]=0;    
    test_file[0]=0;    
    rnnlm_file[0]=0;    
        
    alpha_set=0;    
    train_file_set=0;    
        
    alpha=0.1;    
    beta=0.0000001;    
    //beta=0.00000;    
    alpha_divide=0;    
    logp=0;    
    llogp=-100000000;    
    iter=0;    
        
    min_improvement=1.003;    
        
    train_words=0;    
    train_cur_pos=0;    
    vocab_max_size=100;    
    vocab_size=0;    
        
    vocab=(struct vocab_word *)calloc(vocab_max_size, sizeof(struct vocab_word));    
        
    layer1_size=30;    
        
    direct_size=0;    
    direct_order=0;    
        
    bptt=0;    
    bptt_block=10;    
    bptt_history=NULL;    
    bptt_hidden=NULL;    
    bptt_syn0=NULL;    
        
    gen=0;    
        
    independent=0;    
        
    neu0=NULL;    
    neu1=NULL;    
    neuc=NULL;    
    neu2=NULL;    
        
    syn0=NULL;    
    syn1=NULL;    
    sync=NULL;    
    syn_d=NULL;    
    syn_db=NULL;    
    //backup    
    neu0b=NULL;    
    neu1b=NULL;    
    neucb=NULL;    
    neu2b=NULL;    
        
    neu1b2=NULL;    
        
    syn0b=NULL;    
    syn1b=NULL;    
    syncb=NULL;    
    //    
        
    rand_seed=1;    
        
    class_size=100;    
    old_classes=0;    
        
    one_iter=0;    
    maxIter=0;    
        
    debug_mode=1;    
    srand(rand_seed);    
        
    //word映射为哈希的值小于100000000    
    vocab_hash_size=100000000;          
        
    //动态分配内存,calloc会自动将申请的内存初始化为0,但这里奇怪申请这么大空间,这里没对vocab_hash做检查    
    vocab_hash=(int *)calloc(vocab_hash_size, sizeof(int));    
}    
    
//析构函数,释放申请的空间    
~CRnnLM()       //destructor, deallocates memory    
{    
    int i;    
        
    if (neu0!=NULL) {    
        free(neu0);    
        free(neu1);    
        if (neuc!=NULL) free(neuc);    
        free(neu2);    
            
        free(syn0);    
        free(syn1);    
        if (sync!=NULL) free(sync);    
            
        if (syn_d!=NULL) free(syn_d);    
            
        if (syn_db!=NULL) free(syn_db);    
            
        //    
        free(neu0b);    
        free(neu1b);    
        if (neucb!=NULL) free(neucb);    
        free(neu2b);    
            
        free(neu1b2);    
            
        free(syn0b);    
        free(syn1b);    
        if (syncb!=NULL) free(syncb);    
        //    
            
        for (i=0; i<class_size; i++) free(class_words[i]);    
        free(class_max_cn);    
        free(class_cn);    
        free(class_words);    
            
        free(vocab);    
        free(vocab_hash);    
            
        if (bptt_history!=NULL) free(bptt_history);    
        if (bptt_hidden!=NULL) free(bptt_hidden);    
        if (bptt_syn0!=NULL) free(bptt_syn0);    
            
        //todo: free bptt variables too    
    }    
}                      
    
//返回值类型为real且范围在[min, max]的数    
real random(real min, real max);    
    
//设置训练数据的文件名    
void setTrainFile(char *str);    
    
//设置验证数据集的文件名    
void setValidFile(char *str);    
    
//设置测试集的文件名    
void setTestFile(char *str);    
    
//设置模型保存文件,即该文件用来存储模型的信息,以及各类参数    
void setRnnLMFile(char *str);    
    
    
//下面的函数没写注释,{}里面有语句,变量的含义可以看前篇    
//就不再一一注释了,这些参数都是从main主函数里面传来的,具体来说  
//这些参数就是来自shell命令里面的,这里可以看看我的一篇rnnlm toolkit命令参数介绍          
void setLMProbFile(char *str) {strcpy(lmprob_file, str);}    
    
void setFileType(int newt) {filetype=newt;}    
    
void setClassSize(int newSize) {class_size=newSize;}    
void setOldClasses(int newVal) {old_classes=newVal;}    
void setLambda(real newLambda) {lambda=newLambda;}    
void setGradientCutoff(real newGradient) {gradient_cutoff=newGradient;}    
void setDynamic(real newD) {dynamic=newD;}    
void setGen(real newGen) {gen=newGen;}    
void setIndependent(int newVal) {independent=newVal;}    
    
void setLearningRate(real newAlpha) {alpha=newAlpha;}    
void setRegularization(real newBeta) {beta=newBeta;}    
void setMinImprovement(real newMinImprovement) {min_improvement=newMinImprovement;}    
void setHiddenLayerSize(int newsize) {layer1_size=newsize;}    
void setCompressionLayerSize(int newsize) {layerc_size=newsize;}    
void setDirectSize(long long newsize) {direct_size=newsize;}    
void setDirectOrder(int newsize) {direct_order=newsize;}    
void setBPTT(int newval) {bptt=newval;}    
void setBPTTBlock(int newval) {bptt_block=newval;}    
void setRandSeed(int newSeed) {rand_seed=newSeed; srand(rand_seed);}    
void setDebugMode(int newDebug) {debug_mode=newDebug;}    
void setAntiKasparek(int newAnti) {anti_k=newAnti;}    
void setOneIter(int newOneIter) {one_iter=newOneIter;}    
void setMaxIter(int newMaxIter) {maxIter=newMaxIter;}    
    
//返回单词的哈希值    
int getWordHash(char *word);    
    
//从文件中读取一个单词到word    
void readWord(char *word, FILE *fin);    
    
//查找word,找到返回word在vocab中的索引,没找到返回-1    
int searchVocab(char *word);    
    
//读取当前文件指针所指的单词,并返回该单词在vocab中的索引    
int readWordIndex(FILE *fin);    
    
//将word添加到vocab中,并且返回刚添加word在vocab中的索引    
int addWordToVocab(char *word);    
    
//从train_file中读数据,相关数据会装入vocab,vocab_hash    
//这里假设vocab是空的    
void learnVocabFromTrainFile();     //train_file will be used to construct vocabulary    
    
//保存当前的权值,以及神经元信息值    
void saveWeights();         //saves current weights and unit activations    
    
//上面是暂存当前权值及神经元值,这里是从前面存下的数据中恢复    
void restoreWeights();      //restores current weights and unit activations from backup copy    
//void saveWeights2();      //allows 2. copy to be stored, useful for dynamic rescoring of nbest lists    
//void restoreWeights2();           
    
//保存隐层神经元的ac值    
void saveContext();    
    
//恢复隐层神经元的ac值    
void restoreContext();    
    
//保存隐层神经元的ac值    
void saveContext2();    
    
//恢复隐层神经元的ac值    
void restoreContext2();    
    
//初始化网络    
void initNet();    
    
//保存网络的所有信息到rnnlm_file    
void saveNet();    
    
//从文件流中读取一个字符使其ascii等于delim    
//随后文件指针指向delim的下一个    
void goToDelimiter(int delim, FILE *fi);    
    
//从rnnlm_file中读取网络的所有信息    
void restoreNet();    
    
//清除神经元的ac,er值    
void netFlush();    
    
//隐层神经元(论文中的状态层s(t))的ac值置1    
//s(t-1),即输入层layer1_size那部分的ac值置1    
//bptt+history清0    
void netReset();    //will erase just hidden layer state + bptt history + maxent history (called at end of sentences in the independent mode)    
    
//网络前向,计算概率分布    
void computeNet(int last_word, int word);    
    
//反传误差,更新网络权值    
void learnNet(int last_word, int word);    
    
////将隐层神经元的ac值复制到输出层后layer1_size那部分    
void copyHiddenLayerToInput();    
    
//训练网络    
void trainNet();    
void useLMProb(int use) {use_lmprob=use;}    
    
//测试网络    
void testNet();    
    
//这两个我还没看~    
void testNbest();    
void testGen();    
    
//矩阵和向量相乘  
//1.type == 0时,计算的是神经元ac值,相当于计算srcmatrix × srcvec, 其中srcmatrix是(to-from)×(to2-from2)的矩阵  
//  srcvec是(to2-from2)×1的列向量,得到的结果是(to-from)×1的列向量,该列向量的值存入dest中的ac值  
//2.type == 1, 计算神经元的er值,即(srcmatrix)^T × srcvec,T表示转置,转置后是(to2-from2)×(to-from),srcvec是(to-from)×1的列向量    
  
void matrixXvector(struct neuron *dest, struct neuron *srcvec, struct synapse *srcmatrix, int matrix_width, int from, int to, int from2, int to2, int type);    

  



  
//构造函数,这里进行很多变量的初始化    
CRnnLM()        //constructor initializes variables    
{    
    //这里的很多变量在前面都前一篇都有详细的介绍  
    //这里的初始值只要初始是为非0的可以留意一下  
    version=10;    
    filetype=TEXT;    
        
    use_lmprob=0;    
    lambda=0.75;    
    gradient_cutoff=15;    
    dynamic=0;    
        
    train_file[0]=0;    
    valid_file[0]=0;    
    test_file[0]=0;    
    rnnlm_file[0]=0;    
        
    alpha_set=0;    
    train_file_set=0;    
        
    alpha=0.1;    
    beta=0.0000001;    
    //beta=0.00000;    
    alpha_divide=0;    
    logp=0;    
    llogp=-100000000;    
    iter=0;    
        
    min_improvement=1.003;    
        
    train_words=0;    
    train_cur_pos=0;    
    vocab_max_size=100;    
    vocab_size=0;    
        
    vocab=(struct vocab_word *)calloc(vocab_max_size, sizeof(struct vocab_word));    
        
    layer1_size=30;    
        
    direct_size=0;    
    direct_order=0;    
        
    bptt=0;    
    bptt_block=10;    
    bptt_history=NULL;    
    bptt_hidden=NULL;    
    bptt_syn0=NULL;    
        
    gen=0;    
        
    independent=0;    
        
    neu0=NULL;    
    neu1=NULL;    
    neuc=NULL;    
    neu2=NULL;    
        
    syn0=NULL;    
    syn1=NULL;    
    sync=NULL;    
    syn_d=NULL;    
    syn_db=NULL;    
    //backup    
    neu0b=NULL;    
    neu1b=NULL;    
    neucb=NULL;    
    neu2b=NULL;    
        
    neu1b2=NULL;    
        
    syn0b=NULL;    
    syn1b=NULL;    
    syncb=NULL;    
    //    
        
    rand_seed=1;    
        
    class_size=100;    
    old_classes=0;    
        
    one_iter=0;    
    maxIter=0;    
        
    debug_mode=1;    
    srand(rand_seed);    
        
    //word映射为哈希的值小于100000000    
    vocab_hash_size=100000000;          
        
    //动态分配内存,calloc会自动将申请的内存初始化为0,但这里奇怪申请这么大空间,这里没对vocab_hash做检查    
    vocab_hash=(int *)calloc(vocab_hash_size, sizeof(int));    
}    
    
//析构函数,释放申请的空间    
~CRnnLM()       //destructor, deallocates memory    
{    
    int i;    
        
    if (neu0!=NULL) {    
        free(neu0);    
        free(neu1);    
        if (neuc!=NULL) free(neuc);    
        free(neu2);    
            
        free(syn0);    
        free(syn1);    
        if (sync!=NULL) free(sync);    
            
        if (syn_d!=NULL) free(syn_d);    
            
        if (syn_db!=NULL) free(syn_db);    
            
        //    
        free(neu0b);    
        free(neu1b);    
        if (neucb!=NULL) free(neucb);    
        free(neu2b);    
            
        free(neu1b2);    
            
        free(syn0b);    
        free(syn1b);    
        if (syncb!=NULL) free(syncb);    
        //    
            
        for (i=0; i<class_size; i++) free(class_words[i]);    
        free(class_max_cn);    
        free(class_cn);    
        free(class_words);    
            
        free(vocab);    
        free(vocab_hash);    
            
        if (bptt_history!=NULL) free(bptt_history);    
        if (bptt_hidden!=NULL) free(bptt_hidden);    
        if (bptt_syn0!=NULL) free(bptt_syn0);    
            
        //todo: free bptt variables too    
    }    
}                      
    
//返回值类型为real且范围在[min, max]的数    
real random(real min, real max);    
    
//设置训练数据的文件名    
void setTrainFile(char *str);    
    
//设置验证数据集的文件名    
void setValidFile(char *str);    
    
//设置测试集的文件名    
void setTestFile(char *str);    
    
//设置模型保存文件,即该文件用来存储模型的信息,以及各类参数    
void setRnnLMFile(char *str);    
    
    
//下面的函数没写注释,{}里面有语句,变量的含义可以看前篇    
//就不再一一注释了,这些参数都是从main主函数里面传来的,具体来说  
//这些参数就是来自shell命令里面的,这里可以看看我的一篇rnnlm toolkit命令参数介绍          
void setLMProbFile(char *str) {strcpy(lmprob_file, str);}    
    
void setFileType(int newt) {filetype=newt;}    
    
void setClassSize(int newSize) {class_size=newSize;}    
void setOldClasses(int newVal) {old_classes=newVal;}    
void setLambda(real newLambda) {lambda=newLambda;}    
void setGradientCutoff(real newGradient) {gradient_cutoff=newGradient;}    
void setDynamic(real newD) {dynamic=newD;}    
void setGen(real newGen) {gen=newGen;}    
void setIndependent(int newVal) {independent=newVal;}    
    
void setLearningRate(real newAlpha) {alpha=newAlpha;}    
void setRegularization(real newBeta) {beta=newBeta;}    
void setMinImprovement(real newMinImprovement) {min_improvement=newMinImprovement;}    
void setHiddenLayerSize(int newsize) {layer1_size=newsize;}    
void setCompressionLayerSize(int newsize) {layerc_size=newsize;}    
void setDirectSize(long long newsize) {direct_size=newsize;}    
void setDirectOrder(int newsize) {direct_order=newsize;}    
void setBPTT(int newval) {bptt=newval;}    
void setBPTTBlock(int newval) {bptt_block=newval;}    
void setRandSeed(int newSeed) {rand_seed=newSeed; srand(rand_seed);}    
void setDebugMode(int newDebug) {debug_mode=newDebug;}    
void setAntiKasparek(int newAnti) {anti_k=newAnti;}    
void setOneIter(int newOneIter) {one_iter=newOneIter;}    
void setMaxIter(int newMaxIter) {maxIter=newMaxIter;}    
    
//返回单词的哈希值    
int getWordHash(char *word);    
    
//从文件中读取一个单词到word    
void readWord(char *word, FILE *fin);    
    
//查找word,找到返回word在vocab中的索引,没找到返回-1    
int searchVocab(char *word);    
    
//读取当前文件指针所指的单词,并返回该单词在vocab中的索引    
int readWordIndex(FILE *fin);    
    
//将word添加到vocab中,并且返回刚添加word在vocab中的索引    
int addWordToVocab(char *word);    
    
//从train_file中读数据,相关数据会装入vocab,vocab_hash    
//这里假设vocab是空的    
void learnVocabFromTrainFile();     //train_file will be used to construct vocabulary    
    
//保存当前的权值,以及神经元信息值    
void saveWeights();         //saves current weights and unit activations    
    
//上面是暂存当前权值及神经元值,这里是从前面存下的数据中恢复    
void restoreWeights();      //restores current weights and unit activations from backup copy    
//void saveWeights2();      //allows 2. copy to be stored, useful for dynamic rescoring of nbest lists    
//void restoreWeights2();           
    
//保存隐层神经元的ac值    
void saveContext();    
    
//恢复隐层神经元的ac值    
void restoreContext();    
    
//保存隐层神经元的ac值    
void saveContext2();    
    
//恢复隐层神经元的ac值    
void restoreContext2();    
    
//初始化网络    
void initNet();    
    
//保存网络的所有信息到rnnlm_file    
void saveNet();    
    
//从文件流中读取一个字符使其ascii等于delim    
//随后文件指针指向delim的下一个    
void goToDelimiter(int delim, FILE *fi);    
    
//从rnnlm_file中读取网络的所有信息    
void restoreNet();    
    
//清除神经元的ac,er值    
void netFlush();    
    
//隐层神经元(论文中的状态层s(t))的ac值置1    
//s(t-1),即输入层layer1_size那部分的ac值置1    
//bptt+history清0    
void netReset();    //will erase just hidden layer state + bptt history + maxent history (called at end of sentences in the independent mode)    
    
//网络前向,计算概率分布    
void computeNet(int last_word, int word);    
    
//反传误差,更新网络权值    
void learnNet(int last_word, int word);    
    
////将隐层神经元的ac值复制到输出层后layer1_size那部分    
void copyHiddenLayerToInput();    
    
//训练网络    
void trainNet();    
void useLMProb(int use) {use_lmprob=use;}    
    
//测试网络    
void testNet();    
    
//这两个我还没看~    
void testNbest();    
void testGen();    
    
//矩阵和向量相乘  
//1.type == 0时,计算的是神经元ac值,相当于计算srcmatrix × srcvec, 其中srcmatrix是(to-from)×(to2-from2)的矩阵  
//  srcvec是(to2-from2)×1的列向量,得到的结果是(to-from)×1的列向量,该列向量的值存入dest中的ac值  
//2.type == 1, 计算神经元的er值,即(srcmatrix)^T × srcvec,T表示转置,转置后是(to2-from2)×(to-from),srcvec是(to-from)×1的列向量    
  
void matrixXvector(struct neuron *dest, struct neuron *srcvec, struct synapse *srcmatrix, int matrix_width, int from, int to, int from2, int to2, int type);    

  

Recurrent neural network language modeling toolkit 源码深入剖析系列(二)

标签:rnnlm

原文地址:http://blog.csdn.net/a635661820/article/details/44756545

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!