2011-11-14 233 views
3

我試圖根據英文wikipedia轉儲中找到的前100K個單詞建立一個n-gram語言模型。我已經使用用Java編寫的修改過的XML解析器提取了純文本,但需要將其轉換爲vocab文件。解決執行Perl腳本時出現內存不足錯誤

爲了做到這一點,我找到了一個據說可以完成這項工作的perl腳本,但是缺少關於如何執行的說明。不用說,我是一個Perl的新手,這是我第一次遇到它的使用需求。

當我運行此腳本時,在使用4GB RAM和runnung Ubuntu 10.04和10.10的兩個獨立雙核心機器上的7.2GB文本文件上使用此腳本時,出現內存不足錯誤。

當我聯繫作者時,他說這個腳本在配備4GB RAM的MacBook Pro上運行良好,並且在使用perl 5.12的6.6GB文本文件上執行時,總內存使用量約爲78 MB。作者還說,該腳本逐行讀取輸入文件,並在內存中創建一個散列表。

的腳本是:

#! /usr/bin/perl 

use FindBin; 
use lib "$FindBin::Bin"; 

use strict; 
require 'english-utils.pl'; 

## Create a list of words and their frequencies from an input corpus document 
## (format: plain text, words separated by spaces, no sentence separators) 

## TODO should words with hyphens be expanded? (e.g. three-dimensional) 

my %dict; 
my $min_len = 3; 
my $min_freq = 1; 

while (<>) { 

    chomp($_); 
    my @words = split(" ", $_); 

    foreach my $word (@words) { 

     # Check validity against regexp and acceptable use of apostrophe 

     if ((length($word) >= $min_len) && ($word =~ /^[A-Z][A-Z\'-]+$/) 
     && (index($word,"'") < 0 || allow_apostrophe($word))) { 
      $dict{$word}++; 
     } 
    } 

} 

# Output words which occur with the $min_freq or more often 

foreach my $dictword (keys %dict) { 
    if ($dict{$dictword} >= $min_freq) { 
     print $dictword . "\t" . $dict{$dictword} . "\n"; 
    } 
} 

我通過mkvocab.pl corpus.txt

正在執行的命令行這個腳本中包括額外的腳本是一個簡單的正則表達式腳本來測試撇號的的位置,以及它們是否匹配英語語法規則。

我以爲內存泄漏是由於不同的版本,因爲我的機器上安裝了5.10。所以我升級到5.14,但錯誤仍然存​​在。根據free -m,我的系統上有大約1.5GB的可用內存。

由於我完全不熟悉語言的語法和結構,能否指出問題的原因以及問題存在的原因以及如何解決問題。

+0

你的輸入文件中是否有長行?如果你的輸入文件沒有換行符,你將在內存中保存大量數據。即使假設你的文字有重複,你的散列值可能會非常大。 – TLP

回答

7

加載7,2Gb文件轉換成散列可能是可能的,如果有一些重複用詞,例如the發生17,000次,等等。但它似乎相當多。

您的腳本假定文件中的行適當長。如果你的文件不包含換行符,你將把整個文件加載到$_的內存中,然後使用split加倍加載內存,然後在你的散列中添加更多內容。這會對任何系統造成壓力。

一個想法可能是使用空間" "作爲輸入記錄分隔符。它將大致執行你已經在使用split進行的操作,除了它將單獨留下其他空白字符,並且不會像過多地修剪多餘的空白字符。例如:

$/ = " "; 
while (<>) { 
    for my $word (split) { # avoid e.g. "foo\nbar" being considered one word 
     if (
       (length($word) >= $min_len) && 
       ($word =~ /^[A-Z][A-Z\'-]+$/) && 
       (index($word,"'") < 0 || allow_apostrophe($word)) 
     ) { 
      $dict{$word}++; 
     } 
    } 
} 

這將允許在一口大小的塊被讀取,甚至很長的行,假設你有話(而不是製表符,換行符)之間的空間。

+0

這解決了此問題。在7200 rpm驅動器的雙核筆記本電腦上,大約需要一個小時才能執行,而且不會出現內存問題。謝謝! – Jason

+0

@Jason不客氣。 – TLP

3

嘗試運行

dos2unix corpus.txt 

這可能是您正在閱讀的整個文件作爲一行...

+0

這可能是一種可能性,因爲輸出文本僅包含編輯器的尺寸... – Jason

相關問題