2014-10-01 9 views
5

Ich muss ein Array schreiben, das zu groß ist, um in den Speicher einer binären Binärdatei zu passen. Dies kann mit dem Befehl matfile erreicht werden, der den wahlfreien Zugriff auf eine .mat-Datei auf der Disc ermöglicht.Vorzuordnen eines großen Arrays in einer MATLAB-Matdatei mit etwas anderem als Nullen

Ich versuche, das Array in dieser Datei vorzubelegen, und die von einem MathWorks blog empfohlene Ansatz ist

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

Dies funktioniert, aber lässt mich mit einer großen Reihe von Nullen - die riskant ist, wie einige Die echten Werte, mit denen ich sie füllen werde, können auch null sein. Für kleinere Arrays, tue ich in der Regel

smallarray = nan(20,20); 

Aber wenn ich diesen Ansatz für die große Array versuchen erhalte ich ein „out of memory“ Fehler; vermutlich produziert die nan() Funktion das große Array von NaN s zuerst im Speicher.

Wie kann ich ein großes Array mit etwas anderem als Nullen vorallokalisieren?

+1

Hmm, verwandte Frage Ich nehme an, ob es * Notwendigkeit * gibt, in diesem Fall vorzugeben. Der übliche Leistungsvorteil wird vermutlich trivial im Vergleich zu der Zeit sein, die benötigt wird, um Material auf Disc zu schreiben ... denke, es vermeidet, dass die Datei fragmentiert wird? – Flyto

Antwort

3

Ich fand, dass weder sclark81 noch Sam Roberts Antworten tatsächlich funktionieren, und ich bezweifle, dass das Konzept der Vorallokation auf gilt. Die unten angegebenen Ergebnisse wurden auf einer i7-3770-CPU bei 3,4 GHz mit 16,8 GB Hauptspeicher, auf dem Matlab R2013a unter Linux 3.16 läuft, erhalten.

Der Code

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

theoretisch 8 GB Speicher auf der Festplatte hat jedoch die resultierende Datei nimmt eine Größe von 4726 Bytes, und das Verfahren weniger als 0,01 Sekunden, initialisiert auf 0 „weist“. Ich kann die Größe 10- oder 100-fach vergrößern, und es ändert sich nicht viel. Seltsam. Btw., Die clear am Ende ist da, um sicherzustellen, dass die Datei von Matlab geschrieben und geschlossen wird.

Oft wollen wir NaN vorzubelegen Initialisierung statt 0 Dadurch wird die Weise

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

11 Sekunden, und Ergebnisse in einer Datei von 57 MB nimmt. Aber wie das OP darauf hingewiesen hat, macht dieser Ansatz keinen Sinn, da er zunächst die gesamte 8-GB-Matrix im Speicher erzeugt und dann ausschreibt, was den Zweck von vereitelt. Wenn die Matrix in den Speicher passt, gibt es zunächst keinen Grund, die Daten während der Verarbeitung in einer Datei zu speichern.

Sam Roberts vorgeschlagen ersten zuzuteilen/initialisieren, wie oben auf 0 und dann um die Werte ändern NaN:

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

Dies dauert 16 Sekunden, mit der gleichen resultierenden Dateigröße. Dies ist jedoch in keiner Weise besser als der oben beschriebene naive Ansatz, da in der dritten Zeile die gesamte Matrix in den Speicher eingelesen, mit dem skalaren NaN im Speicher multipliziert und dann wieder ausgeschrieben wird, was zu einem Spitzenspeicherverbrauch von 8 GB führt. (Dies ist nicht nur im Einklang mit der Semantik von matfile -Variablen im documentation erklärt, aber ich habe auch mit einem Speichernutzung Monitor überprüft.)

sclarke81 auf diese Weise statt zu vermeiden Erzeugung der Matrix im Speicher vorgeschlagen:

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

Die Idee ist wahrscheinlich, dass nur ein skalares NaN im Speicher generiert und dann in jedes Element der On-Disk-Matrix kopiert wird. Das passiert jedoch nicht. In der Tat scheint diese Methode etwa 8,38 GB Speicher in der Spitze zu verbrauchen, 12% mehr als der naive Ansatz!

Jetzt mehr auf die Vorzüge der Vorbelegung mit . Wenn man nicht voreilt, sondern das Array zeilenweise mit NaNs füllt, dauert dies 27 Sekunden. Aber, wenn man weist ihn vorab auf 0 initialisiert und dann zeilenweise Überschreibungen von NaNs

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 

es dauert ewig: Der Prozess wurde nur etwa 3% fertig, als ich es nach 45 Minuten abgebrochen, auf etwa eine Extrapolation Tag der gesamten Laufzeit!

Das Verhalten von matlab.io.MatFile ist dunkel und mysteriös, und es scheint, dass im Moment nur ausgiebige Tests zu einem effektiven Weg führen, diese Einrichtung zu nutzen. Man kann jedoch zu dem Schluss kommen, dass die Vorabzuweisung eine schlechte Idee ist, wenn es um geht.

+0

@A Donda: schätzen Sie Ihre quantitativen Ergebnisse für die identifizierten Ansätze. MATLAB/RAM/OS-Grenzen sind bekannt, aber der HDD.IO ist der Mörder. Tage zu verbringen, nur um "NaN" vorzugeben, ist nichts als eine luxuriöse Verschwendung von Ressourcen. Wie in >>> http://stackoverflow.com/a/27083554/3666197 dargestellt, erfordern die 'matfile'/HDF5 und die echten BigDATA-Probleme eine viel vorsichtigere Datenmanipulationsstrategie als eine * Vorbelegung *. [n.b.Die Stärke des HDF5-Formats liegt in seiner Unterstützung für eine effiziente Implementierung von dynamischen Änderungen der Datenelemente in den BigDATA-Skalierungen, nicht für den * statischen * Inhalt. – user3666197

+0

Sehr interessant! In Bezug auf Ihr letztes Ergebnis ... Ich frage mich, ob die Umwandlung von 1 (ein Int) in Nan (ein Float) teilweise für die Verlangsamung verantwortlich sein könnte. Ich habe derzeit keine MATLAB-Installation, daher kann ich das nicht selbst überprüfen. Könnten Sie das letzte Experiment wiederholen, aber "mf.x" auf nan (oder einen Float wie 0.1) initialisieren? – GnomeDePlume

+0

... Ich versuche nur zu überprüfen, dass NaN ein Float in MATLAB ist. Entschuldigung, wenn das nicht stimmt. Zu sehr an Python/Numpy gewöhnt! – GnomeDePlume

0

Diese Methode funktioniert für mich. Beachten Sie, dass Sie den Bereich für den Matrixindex angeben müssen (X(1:10000,1:10000)), andernfalls setzen Sie einfach das einzelne Element auf 10000,10000 auf NaN.

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

Können Sie so etwas wie:

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

und dann

matObj.X = matObj.X + 1; 

oder

matObj.X = matObj.X * NaN; 

?

+0

Das ist ein guter Gedanke, und es funktioniert. Ich werde die andere Antwort akzeptieren, weil es weniger Schritte erfordert, aber danke. – Flyto

+0

Ich stimme zu - die andere Antwort ist besser. –

0

Dies kann durch Speicherzuordnung einer Binärdatei unter Verwendung von MappedTensor (Selbstzitation) durchgeführt werden.

% - 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; 

Sie können mit memmapfile einen ähnlichen Ansatz versuchen, aber memmapfile reserviert Speicherplatz für die gesamte Tensor, wenn auf eine zugeordneten Datei zu schreiben.

Sie können eine bestimmte Binärdatei vorab zuordnen und dann mit fsutil auf einem PC oder fallocate auf einem Mac- oder Linux-Rechner abbilden.

Verwandte Themen