1

我正在开发一个机器学习应用程序,我的特征存储在巨大的文本文件中。目前我实现数据输入读取的方式,这是一种缓慢实用的方式。基本上,文本文件的每一行都代表一个稀疏格式的特征向量。例如,以下示例包含三个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;
4

3 回答 3

1
  1. 您绝对应该减少内存分配的数量。经典的方法是在每次分配时将向量加倍,以便获得对数的分配调用次数,而不是线性的。

  2. 由于您的行模式似乎是恒定的,因此无需手动对其进行标记,sscanf()在每个加载的行上使用一个来直接扫描该行的单词。

  3. 您的行缓冲区似乎非常大,这可能会导致堆栈爆炸,使缓存局部性变差。

于 2013-04-18T08:43:53.723 回答
0

可能当您调用 realloc 时,您正在执行系统调用。系统调用是一项昂贵的操作,涉及上下文交换和从用户空间到内核空间的切换,反之亦然。

似乎您正在为您获得的每一对令牌进行 realloc 调用。这是很多电话。您不关心之前将 1MByte 分配给文件指向的缓冲区。为什么你对 word 指向的缓冲区如此保守?

于 2013-04-18T08:00:58.670 回答
0

我发现在 Linux(Fedora)上 realloc() 非常有效,并且不会减慢速度,尤其是。在 Windows 上,由于内存的结构,它可能是灾难性的。

我对“长度未知的行”问题的解决方案是编写一个函数,该函数多次调用 fgets(),将结果连接起来,直到检测到换行符。该函数接受 &maxlinelength 作为参数,如果任何对 fgets() 的调用会导致连接的字符串超过 maxlinelength,则调整 maxlinelength。这样,新内存只会在找到最长的行之前重新分配。同样,如果 maxlinelength 已调整,您只需要为 WORD 重新分配()

于 2013-04-18T09:18:45.903 回答