标签:rnnlm
#ifdef USE_BLAS extern "C" { #include <cblas.h> } #endif
real CRnnLM::random(real min, real max) { return rand()/(real)RAND_MAX*(max-min)+min; }这里RAND_MAX是VC中stdlib.h中宏定义的一个字符常量,#define RAND_MAX 0x7FFF,其值为32767,通常在产生随机小数时可以使用RAND_MAX。里面的rand()返回值在[0, RAND_MAX],[]表示闭区间,即能取到边界值。这样return返回值范围在[min, max]。如果我们返回[min, max)之间数,可以用下面语句:
//设置训练数据的文件名 void CRnnLM::setTrainFile(char *str) { strcpy(train_file, str); } //设置验证数据集的文件名 void CRnnLM::setValidFile(char *str) { strcpy(valid_file, str); } //设置测试集的文件名 void CRnnLM::setTestFile(char *str) { strcpy(test_file, str); } //设置模型保存文件,即该文件用来存储模型的信息,以及各类参数 void CRnnLM::setRnnLMFile(char *str) {
void CRnnLM::readWord(char *word, FILE *fin) { int a=0, ch; //feof(FILE *stream)当到达文件末尾时返回一个非0数 while (!feof(fin)) { //从流中读取一个字符到ch ch=fgetc(fin); //ascii为13表示回车,\r,即回到一行的开头 //注意\r与\n不同,后者是换行 // \r\n主要是在文本文件中出现的 if (ch==13) continue; if ((ch==' ') || (ch=='\t') || (ch=='\n')) { if (a>0) { //将'\n'送回到字符流中,下次读取时还会读取到,这里标记一个句子的结束 if (ch=='\n') ungetc(ch, fin); break; } //如果a=0的情况就遇到换行,即上一个句子的结束,这里把句子的结束标记为</s>单独作为一个word if (ch=='\n') { strcpy(word, (char *)"</s>"); return; } else continue; } word[a]=ch; a++; //过长的单词会被截断,过长的结果word[99] = '\0' if (a>=MAX_STRING) { //printf("Too long word found!\n"); //truncate too long words a--; } } //字符串结尾用'\0',其ascii码为0 word[a]=0; }
//返回单词的哈希值 int CRnnLM::getWordHash(char *word) { unsigned int hash, a; hash=0; //单词哈希值的计算方式 for (a=0; a<strlen(word); a++) hash=hash*237+word[a]; //vocab_hash_size在CRnnLm的构造函数初始化为1亿即100000000 hash=hash%vocab_hash_size; return hash; }
<span style="line-height: 36px;">int CRnnLM::searchVocab(char *word) { int a; unsigned int hash; hash=getWordHash(word); //第一层查找,vocab_hash[hash]==-1表示当前word不在vocab中 if (vocab_hash[hash]==-1) return -1; //第二层查找,这里确认当前word并未被其他word给冲突掉 if (!strcmp(word, vocab[vocab_hash[hash]].word)) return vocab_hash[hash]; //第三层查找,走到了这里,说明当前word与其他word的哈希值有冲突,直接线性查找 for (a=0; a<vocab_size; a++) { if (!strcmp(word, vocab[a].word)) { //这里把查找到的当前词的哈希值覆盖,这样vocab_hash总是保持最近查找词的hash值 //越是频繁查找的词,通过这种方式即便冲突了,下次也会在O(1)的时间内查找到! vocab_hash[hash]=a; return a; } } //没找到,即该词不在vocab内,即out-of-vocabulary return -1; }</span>
int CRnnLM::readWordIndex(FILE *fin) { char word[MAX_STRING]; readWord(word, fin); if (feof(fin)) return -1; return searchVocab(word); }
int CRnnLM::addWordToVocab(char *word) { unsigned int hash; strcpy(vocab[vocab_size].word, word); vocab[vocab_size].cn=0; vocab_size++; //vocab是动态管理的,当数组内存快不够了,再扩大数组内存,每次增加100个单位,每个单位是vocab_word类型 if (vocab_size+2>=vocab_max_size) { vocab_max_size+=100; //realloc是用来扩大或缩小内存的,扩大时原来的内容不变,系统直接 //在后面找空闲内存,如果没找到,则会把前面的数据重新移动到一个够大的地方 //即realloc可能会导致数据的移动,这算自己顺便看源码边复习一些c的知识吧 vocab=(struct vocab_word *)realloc(vocab, vocab_max_size * sizeof(struct vocab_word)); } //将word的哈希值作为vocab_hash的下标,下标所对应的整型值为vocab中对该word的索引 hash=getWordHash(word); vocab_hash[hash]=vocab_size-1; return vocab_size-1; }
void CRnnLM::sortVocab() { int a, b, max; vocab_word swap; //注意这里下标是从1开始,并未把vocab[0]考虑进来 //实际上vocab[0]是存放的</s>,从后面的learnVocabFromTrainFile()可以看到 for (a=1; a<vocab_size; a++) { max=a; for (b=a+1; b<vocab_size; b++) if (vocab[max].cn<vocab[b].cn) max=b; swap=vocab[max]; vocab[max]=vocab[a]; vocab[a]=swap; } }
void CRnnLM::learnVocabFromTrainFile() { char word[MAX_STRING]; FILE *fin; int a, i, train_wcn; //这里对vocab_hash的初始化说明不在vocab中的word,其vocab_hash[getWordHash(word)]为-1 for (a=0; a<vocab_hash_size; a++) vocab_hash[a]=-1; //以二进制模式读取文件 //关于二进制和文本文件的区别,可以参考这篇博文:http://www.cnblogs.com/flying-roc/articles/1798817.html //当train_file是文本文件存储时,即句子结尾是\r\n,前面readWord()函数有一个条件语句if处理掉了\r //如果train_file是二进制存储时,句子结尾只有\n,所以对于字符组成的文件来说两者差别不大 fin=fopen(train_file, "rb"); vocab_size=0; //也就是vocab[0]是存放的</s> addWordToVocab((char *)"</s>"); //记录train_file中tokens数量 train_wcn=0; while (1) { readWord(word, fin); if (feof(fin)) break; train_wcn++; //vocab存放的word不会重复,重复的word让其词频加1 i=searchVocab(word); if (i==-1) { a=addWordToVocab(word); vocab[a].cn=1; } else vocab[i].cn++; } //注意这里在读入train_file后,会将vocab排序,后面会看到对词语分类有帮助 sortVocab(); //select vocabulary size /*a=0; while (a<vocab_size) { a++; if (vocab[a].cn==0) break; } vocab_size=a;*/ if (debug_mode>0) { printf("Vocab size: %d\n", vocab_size); printf("Words in train file: %d\n", train_wcn); } //train_words表示训练文件中的词数 train_words=train_wcn; fclose(fin); }由于本篇长度差不多了,下一篇继续函数实现的分析
Recurrent neural network language modeling toolkit 源码剖析(三)
标签:rnnlm
原文地址:http://blog.csdn.net/a635661820/article/details/44779413