1

我无法使用LingPipe POS 标记器来计算大型(~180MB)电子邮件语料库中最常用的词性。具体来说,它会消耗大量内存(至少 4GB),因此无论我为 JVM 提供多少内存,它都会因 OutOfMemoryError 而失败。在我放弃并尝试不同的标记库之前,我想我会问这里是否有人对 LingPipe 足够熟悉,知道我做错了什么。

我首先从文件 pos-en-general-brown.HiddenMarkovModel 中读取一个 HiddenMarkovModel 对象,该文件包含在 LingPipe 库中,它是样板 Java 序列化代码。然后我尝试像这样使用它:

HmmDecoder decoder = new HmmDecoder(hmm, new FastCache<String, double[]>(1000),
    new FastCache<String, double[]>(1000));

List<Email> emails = FileUtil.loadMLPosts(new File(args[1])); 
Multiset<String> rHelpTagCounts = countTagsInEmails(decoder, emails);

其中countTagsInEmails定义如下:

static TokenizerFactory TOKENIZER_FACTORY = IndoEuropeanTokenizerFactory.INSTANCE;

public static Multiset<String> countTagsInEmails(HmmDecoder decoder, List<Email> emails) {
    Multiset<String> tagCounts = HashMultiset.create();        
    for(Email email : emails) {
        char[] bodyChars = email.body.toCharArray();
        Tokenizer tokenizer = TOKENIZER_FACTORY.tokenizer(bodyChars, 0, bodyChars.length);
        List<String> bodyTokens = new ArrayList<>();
        tokenizer.tokenize(bodyTokens, new ArrayList<String>()); //Throw away the whitespaces list, we don't care
        Tagging<String> taggedTokens = decoder.tag(bodyTokens);
        tagCounts.addAll(taggedTokens.tags());
    }
    return tagCounts;
}

我认为 的细节FileUtil.loadMLPosts()并不重要;Email这只是从我的 180MB 电子邮件存档文件中创建一个对象列表,其中body每个对象的字段都是Email包含电子邮件正文的字符串。请注意,这Multiset是 Guava 的实现。

如果我在运行我的程序时观察 Java 的内存使用情况,它从 1GB 开始(已经惊人的高),然后随着标记的电子邮件的增多而稳步攀升。在某些时候,它会急剧跳跃,一次增加数百兆字节。在它完成对语料库的标记之前,它达到了 4GB(我给我的 JVM 的内存量)并崩溃了。

LingPipe 的 HmmDecoder 是否应该如此低效?还是我用错了?我注意到在 LingPipe 的(相当稀疏的)文档页面上给出的用于 POS 标记的示例总是显示解码器一次标记一个句子,所以将整个电子邮件正文传递给 是一个错误decoder.tag()吗?

4

0 回答 0