2014-10-01 28 views
5

我需要寫一個數組,該數組對於.mat二進制文件來說太大而不適合內存。這可以通過matfile命令來完成,該命令允許隨機訪問光盤上的.mat文件。在MATLAB matfile中預先分配一個非零的大數組

我想預先分配該文件中的數組,並通過MathWorks blog推薦的方式是

matObj = matfile('myBigData.mat','Writable',true); 
matObj.X(10000,10000) = 0; 

這工作,但給我留下了一個大陣零 - 這是有風險的,因爲一些我將用它填充的真正價值也可能爲零。對於較小的陣列,我通常會這樣做

smallarray = nan(20,20); 

但是,如果我嘗試這種方法爲大數組,我得到一個「內存不足」的錯誤;大概nan()函數首先在內存中生成大量的NaN

如何預先分配一個大於零的數組?

+1

嗯,相關的問題我想是否有任何*需要*預先分配在這種情況下。通常的性能優勢大概會比寫入光盤所花費的時間微不足道。猜猜它能避免文件被分割? – Flyto 2014-10-01 11:01:50

回答

3

我發現sclarke81和Sam Robert的答案都沒有效果,我懷疑預分配的概念適用於matfile。以下報告的結果是在i7-3770 CPU @ 3.4 GHz,16.8 GB主存儲器上運行,在Linux 3.16上運行Matlab R2013a。

代碼

mf = matfile(fn, 'Writable', true); 
mf.x(5000, 200000) = 0; 
clear mf 

理論上「分配」 8 GB的磁盤存儲器,初始化爲0。然而,所得到的文件的大小爲4726個字節,並且這一過程需要小於0.01秒。我可以將尺寸增加10倍或100倍,沒有太大的變化。奇怪。順便提一下,clear最後是確保文件是由Matlab編寫和關閉的。

我們經常要預分配初始化爲NaN,而不是0這樣做的收到方式

mf = matfile(fn, 'Writable', true); 
mf.x = nan(5000, 200000); 
clear mf 

需要11秒,結果在57 MB的文件。但正如OP指出的那樣,這種方法沒有任何意義,因爲它首先在內存中生成8 GB的整個矩陣,然後將其寫出,這違背了matfile的目的。如果矩陣適合內存,那麼在處理數據時首先沒有理由將數據保存在文件中。

薩姆羅伯茨提議第一分配/初始化爲0如上述,然後改變數值爲NaN:

mf = matfile(fn, 'Writable', true); 
mf.x(5000, 200000) = 0; 
mf.x = mf.x * nan; 
clear mf 

這需要16秒,用相同的生成的文件大小。但是,這並不比上面的簡單方法更好,因爲在第三行,整個矩陣被讀入內存,乘以內存中的標量NaN,然後​​再次寫出,導致峯值內存消耗爲8 GB。 (這不僅與matfile - 變量語義一致,在documentation解釋,但我也有一個內存佔用監視器檢查。)

sclarke81建議,而不是避免產生矩陣的記憶是這樣的:

mf = matfile(fn, 'Writable', true); 
mf.x(1 : 5000, 1 : 200000) = nan; 
clear mf 

這個想法可能是在內存中只生成一個標量NaN,然後​​複製到磁盤矩陣的每個元素中。但是,那不是什麼情況。事實上,這種方法似乎在高峯期消耗大約8.38 GB的內存,比天真的方法高出12%!

現在更多關於與matfile預分配的優點。如果不預先分配,但用NaN逐行填充陣列

mf = matfile(fn, 'Writable', true); 
for i = 1 : 5000 
    mf.x(i, 1 : 200000) = nan(1, 200000); 
end 
clear mf 

這需要27秒。 ,如果一個預先分配初始化爲0和NaN的,然後按行改寫

mf = matfile(fn, 'Writable', true); 
mf.x(5000, 200000) = 0; 
for i = 1 : 5000 
    mf.x(i, 1 : 200000) = nan(1, 200000); 
end 
clear mf 

它需要年齡:當我在45分鐘後中止它,外推至一個過程只有約3%完成總運行時間爲

matlab.io.MatFile的行爲是黑暗而神祕的,看來目前只有廣泛的測試才能導致使用這種設施的有效方法。但是,有人可能會得出結論:預分配對於matfile來說是個壞主意。

+0

@A Donda:欣賞您所確定方法的定量結果。已知的MATLAB/RAM/OS限制,但HDD.IO是殺手。僅僅在預先分配'NaN'上花費的時間不過是奢侈的資源浪費。正如>>> http://stackoverflow.com/a/27083554/3666197中提到的那樣,'matfile'/HDF5和真正的BigDATA問題需要一種比*預分配*更爲謹慎的數據操縱策略。 [注:HDF5格式的優勢在於它支持高效地實現BigDATA尺度數據元素的動態變化,而不是*靜態*內容] – user3666197 2014-12-04 17:39:01

+0

非常有趣!關於你最後的發現......我想知道從1(一個int)到nan(一個浮點數)的轉換是否可能是減速的部分原因。我目前沒有安裝MATLAB,所以不能自己檢查。你可以重複上一個實驗,但將'mf.x'初始化爲nan(或者像0.1這樣的float)嗎? – GnomeDePlume 2014-12-05 15:21:42

+0

...我只是試圖檢查NaN是否是MATLAB中的一個浮點數。道歉,如果這是不正確的。太習慣Python/Numpy! – GnomeDePlume 2014-12-05 15:28:53

0

此方法適用於我。請注意,您必須指定矩陣索引的範圍(X(1:10000,1:10000)),否則您只需將單個元素設置爲10000,10000NaN

matObj = matfile('myBigData.mat','Writable',true); 
matObj.X(1:10000,1:10000) = NaN; 
0

你可以這樣做:

matObj = matfile('myBigData.mat','Writable',true); 
matObj.X(10000,10000) = 0; 

然後

matObj.X = matObj.X + 1; 

​​

+0

這是一個很好的想法,它的工作原理。我會接受其他答案,因爲它涉及的步驟較少,但謝謝。 – Flyto 2014-10-01 15:17:12

+0

我同意 - 其他答案更好。 – 2014-10-01 15:46:55

0

這可以通過使用MappedTensor(自引)的內存映射二進制文件來執行。

% - Create and map a large 'double' tensor to a temporary file on disk 
mt = MappedTensor(100, 100, 100); 

% - % Write 'nan' to every element of 'mt', without allocating entire tensor 
mt(:) = nan; 

您可以嘗試類似的做法與memmapfile,但memmapfile寫入映射文件時,整個張量分配空間。

您可以使用PC上的fsutil或mac或linux機器上的fallocate預先分配並映射特定的二進制文件。

相關問題