我正在开发一个机器学习应用程序,我的功能存储在大文本文件中。目前我已经实现了数据输入读取的方式,这是缓慢实用的方法。基本上,文本文件的每一行代表稀疏格式的特征向量。例如,以下示例包含index:value
方式的三个功能。
1:0.34 2:0.67 6:0.99 12:2.1 28:2.1
2:0.12 22:0.27 26:9.8 69:1.8
3:0.24 4:67.0 7:1.9 13:8.1 18:1.7 32:3.4
以下是我现在的阅读方式。由于我之前不知道特征字符串的长度,我只是读了一个适当大的长度,其上限是每个字符串的长度。有一次,我已经从文件中读取了这一行,我只是使用strtok_r
函数将字符串拆分为键值对,然后进一步处理它以存储为稀疏数组。关于如何提高速度的任何想法都受到高度赞赏。
FILE *fp = fopen(feature_file, "r");
int fvec_length = 0;
char line[1000000];
size_t ln;
char *pair, *single, *brkt, *brkb;
SVECTOR **fvecs = (SVECTOR **)malloc(n_fvecs*sizeof(SVECTOR *));
if(!fvecs) die("Memory Error.");
int j = 0;
while( fgets(line,1000000,fp) ) {
ln = strlen(line) - 1;
if (line[ln] == '\n')
line[ln] = '\0';
fvec_length = 0;
for(pair = strtok_r(line, " ", &brkt); pair; pair = strtok_r(NULL, " ", &brkt)){
fvec_length++;
words = (WORD *) realloc(words, fvec_length*sizeof(WORD));
if(!words) die("Memory error.");
j = 0;
for (single = strtok_r(pair, ":", &brkb); single; single = strtok_r(NULL, ":", &brkb)){
if(j == 0){
words[fvec_length-1].wnum = atoi(single);
}
else{
words[fvec_length-1].weight = atof(single);
}
j++;
}
}
fvec_length++;
words = (WORD *) realloc(words, fvec_length*sizeof(WORD));
if(!words) die("Memory error.");
words[fvec_length-1].wnum = 0;
words[fvec_length-1].weight = 0.0;
fvecs[i] = create_svector(words,"",1);
free(words);
words = NULL;
}
fclose(fp);
return fvecs;
答案 0 :(得分:1)
您绝对应该减少内存分配的数量。经典方法是在每次分配时将向量加倍,以便获得对数的分配调用而不是线性。
由于您的线条图案似乎不变,因此无需手动对其进行标记,在每条加载的线条上使用单个sscanf()
直接扫描到该线条的字词。
您的行缓冲区似乎非常大,这可能会因为炸毁堆栈而花费成本,从而使缓存局部性恶化。
答案 1 :(得分:0)
正在调用realloc时,您正在进行系统调用。系统调用是一项昂贵的操作,涉及上下文交换以及从用户到内核空间的切换,反之亦然。
您似乎正在为您获得的每对令牌执行realloc调用。这是很多电话。您以前不关心将1MByte分配给文件指向的缓冲区。你为什么对字所指出的缓冲区这么保守?
答案 2 :(得分:0)
我发现在Linux(Fedora)上,realloc()非常有效,并且不会减慢速度,特别是。在Windows上,由于内存的结构,它可能是灾难性的。
我对“未知长度行”问题的解决方案是编写一个函数,该函数对fgets()进行多次调用,将结果连接起来,直到检测到换行符。该函数接受& maxlinelength作为参数,如果对fgets()的任何调用将导致连接字符串超过maxlinelength,则调整maxlinelength。这样,只有找到最长的行才会重新分配新内存。同样,如果调整了maxlinelength,你只需要为WORD重新调用()