#ifdef USE_BLAS
extern "C" {
#include <cblas.h>
}
#endifreal 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 源码剖析(三)
原文:http://blog.csdn.net/a635661820/article/details/44779413