Wie kann man eine Matrix "kopieren", ohne eine temporäre Matrix im Speicher zu erstellen, die einen Speicherüberlauf verursacht?


9

Durch Zuweisen einer Matrix zu einem viel größeren zugewiesenen Speicher dupliziert matlab sie irgendwie, während sie "kopiert" wird. Wenn die zu kopierende Matrix groß genug ist, kommt es zu einem Speicherüberlauf. Dies ist der Beispielcode:

main_mat=zeros(500,500,2000);
n=500;
slice_matrix=zeros(500,500,n);
for k=1:4
    parfor i=1:n
        slice_matrix(:,:,i)=gather(gpuArray(rand(500,500)));
    end
    main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)=slice_matrix; %This is where the memory will likely overflow
end

Jeder Weg, um nur die zu "zerschlagen" slice_matrix das main_matohne Overhead auf das zu ? Danke im Voraus.

BEARBEITEN:

Der Überlauf trat auf, wenn er main_matvorher zugewiesen wurde. Wenn main_matmit main_mat=zeros(500,500,1);(kleinere Größe) initialisiert wird , tritt der Überlauf nicht auf, er verlangsamt sich jedoch, da die Zuordnung nicht erfolgt, bevor die Matrix zugewiesen wird. Dies verringert die Leistung erheblich, wenn der Bereich kzunimmt.


1
Zu Ihren Schleifen: Es wird empfohlen, die äußere Schleife zu parforOptimierungszwecken auf eine Schleife zu setzen . Kopiert parforIhre Daten außerdem auf jeden einzelnen Worker. Unter der Annahme, dass 4 Worker Ihre Daten viermal im RAM duplizieren.
Adriaan

1
Was ist Ihr Hinweis darauf, dass Matlab den Speicher tatsächlich dupliziert? Verwenden Sie die memoryFunktion? Der Task-Manager? Ein Speicherfehler von Matlab? In welcher Codezeile passiert es?
Eliahu Aaron

Wie Sie sehen konnten, wo ich den Code kommentiert habe, tritt main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)das Problem des Speicherüberlaufs auf. Es wird überprüft, wenn ich das main_matzuvor zugewiesen habe . Es läuft über, wenn ich es nicht tue, wird es nicht überlaufen. Matlab gibt den Fehler "Nicht genügend Speicher" zurück.
Gregor Isack

Passt Ihre 500x500x2000 Matrix in den Speicher? Es ist ~ 4 GB. Unter stackoverflow.com/q/51987892/7328782 erfahren Sie, warum der Fehler " Nicht genügend Speicher" nur beim Schreiben in das Array auftreten kann.
Cris Luengo

Könnten Sie zum besseren Verständnis Ihres Problems ein h=h+slice_matrix(end)Vorher einfügen main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)=slice_matrix;(und h mit 0 initialisieren)? Ich vermute, dass diese neu hinzugefügte Zeile bereits Speicherprobleme verursacht.
Daniel

Antworten:


4

Das Hauptproblem ist, dass Zahlen mehr Platz als Nullen benötigen. main_mat=zeros(500,500,2000);benötigt wenig RAM, während main_mat = rand(500,500,2000);viel benötigt wird, egal ob Sie GPU oder parfor verwenden (in der Tat werden Sie durch parfor mehr RAM verwenden). Dies ist also keine unnatürliche Schwellung des Gedächtnisses. Nach Daniels Link unten scheint die Zuweisung von Nullen nur Zeiger auf den Speicher zu erzeugen, und der physische Speicher wird nur gefüllt, wenn Sie die Matrix für "Zahlen" verwenden. Dies wird vom Betriebssystem verwaltet. Und es wird für Windows, Mac und Linux erwartet, entweder Sie tun es mit Matlab oder anderen Sprachen wie C.


Im Moment verstehe ich MATLAB nicht mehr. Sobald ich die Befehle mit dem zerosgesamten virtuellen Speicher eingebe, wird dieser tatsächlich zugewiesen, aber es wird kein Speicher verwendet. whoszeigt für beide Matrizen die gleiche Größe, während mein Betriebssystem einen unterschiedlichen Speicherverbrauch zeigt. Ich habe meinen Kommentar gelöscht, weil Ihre Antwort definitiv nicht falsch ist.
Daniel

3
Ich habe etwas gefunden, das dies erklärt: stackoverflow.com/questions/51987892/…
Daniel

Gute Antwort! Vielen Dank.
JLev

@ Gregor: Ich denke, um dies zu bestätigen, versuchen Sie es onesstattdessen mit zeros, dies stellt sicher, dass der Speicher zum Zeitpunkt des Aufrufs der jeweiligen Funktion tatsächlich zugewiesen ist.
Daniel

Wenn ich alles richtig verstehe, lautet die Schlussfolgerung: Es gibt keine temporäre Kopie. Die Ausnahmen für nicht genügend Speicher entstehen, weil main_matWerte ungleich Null zugewiesen werden. Bisher wurde nur virtueller Speicher (Adressraum) zugewiesen, dieser wird jetzt dem physischen Speicher zugewiesen.
Daniel

1

Das Entfernen parforwird wahrscheinlich Ihr Problem beheben.

parforist dort nicht nützlich. MATLABsparfor keine Parallelität des gemeinsam genutzten Speichers (dh es werden keine neuen Threads gestartet), sondern eine Parallelität des verteilten Speichers (es werden neue Prozesse gestartet). Es ist so konzipiert, dass die Arbeit auf einen Satz oder Arbeitsknoten verteilt wird. Obwohl es auch innerhalb eines Knotens (oder eines einzelnen Desktop-Computers) funktioniert, um die Arbeit auf mehrere Kerne zu verteilen, ist es keine optimale Methode, um Parallelität innerhalb eines Knotens durchzuführen.

Dies bedeutet, dass jeder der von gestarteten Prozesse parforeine eigene Kopie haben mussslice_matrix , was die Ursache für die große Speichermenge ist, die von Ihrem Programm verwendet wird.

Weitere Informationenparforparfor und den Zeitpunkt finden Sie unter "Entscheiden, wann verwendet werden soll " in der MATLAB-Dokumentation .


1
Ist das Entfernen parfor der einzige Weg ? Die Verarbeitung funktioniert am besten, wenn ich sie so entworfen habe, da alles im Inneren parforCPU- und GPU-intensiv ist und somit die Leistung erheblich verbessert.
Gregor Isack

@ GregorIsack: Ich habe mich für Ihren Beispielcode entschieden und wusste nicht, dass Sie tatsächlich viel Arbeit im Internet geleistet haben parfor. Wenn ja, dann ist es wahrscheinlich nützlich. - Wenn dies nicht der Fall slice_matrixist gpuarray, wird es möglicherweise nicht in die Zuordnung kopiert.
Cris Luengo

Hmmm, auch wenn slice_matrixes kein ist gpuArray, bekomme ich immer noch ein Überlaufsymptom. Ich werde diese Frage offen lassen und sehen, ob es eine alternative Lösung gibt. Danke für die Antwort!
Gregor Isack

0

Ich gehe davon aus, dass Ihr Code nur ein Beispielcode ist und rand()einen benutzerdefinierten Code in Ihrer MVE darstellt. Es gibt also einige Hinweise und Tricks für die Speichernutzung in matlab.

Es gibt einen Ausschnitt aus den MathWorks-Schulungshandbüchern:

Wenn Sie in MATLAB eine Variable einer anderen zuweisen, wie dies beim Übergeben von Parametern an eine Funktion der Fall ist, erstellt MATLAB transparent einen Verweis auf diese Variable. MATLAB unterbricht die Referenz und erstellt nur dann eine Kopie dieser Variablen, wenn der Code einen oder mehrere der Werte ändert. Dieses Verhalten, das als " Copy-on-Write" oder " Lazy- Copying" bezeichnet wird, verschiebt die Kosten für das Kopieren großer Datenmengen, bis der Code einen Wert ändert. Wenn der Code keine Änderungen vornimmt, sind daher kein zusätzlicher Speicherplatz und keine zusätzliche Ausführungszeit zum Kopieren von Variablen erforderlich.

Als erstes müssen Sie die (Speicher-) Effizienz Ihres Codes überprüfen. Sogar der Code exzellenter Programmierer kann mit (ein wenig) Gehirnleistung weiter optimiert werden. Hier einige Hinweise zur Speichereffizienz

  • nutzt die Nativ Vektorisierung von Matlab, zum Beispiel sum(X,2), mean(X,2),std(X,[],2)
  • Stellen Sie sicher, dass matlab keine Matrizen erweitern muss (die implizite Erweiterung wurde kürzlich geändert). Es könnte effizienter sein, das zu verwendenbsxfun
  • Einsatz in-place-Operationen, zB x = 2*x+3stattx = 2*x+3
  • ...

Beachten Sie, dass das Optimum in Bezug auf die Speichernutzung nicht dasselbe ist, als ob Sie die Rechenzeit reduzieren möchten. Daher sollten Sie die Anzahl der Worker reduzieren oder die parfor-schleife nicht verwenden. (Da parforShared Memory nicht verwendet werden kann, gibt es bei Verwendung der Parallel Toolbox keine Funktion zum Kopieren beim Schreiben .

Wenn Sie sich Ihr Gedächtnis genauer ansehen möchten , was verfügbar ist und was von Matlab verwendet werden kann, lesen Sie feature('memstats'). Was ist für Sie interessant ist , ist die Virtual Memory , das ist

Gesamter und verfügbarer Speicher, der dem gesamten MATLAB-Prozess zugeordnet ist. Es ist durch die Prozessorarchitektur und das Betriebssystem begrenzt. oder verwenden Sie diesen Befehl [user,sys] = memory.

Schneller Seitenknoten : Matlab speichert Matrizen konsistent im Speicher. Für große Matrizen benötigen Sie einen großen Block freien Arbeitsspeichers. Dies ist auch der Grund, warum Sie Variablen zuweisen möchten, da Matlab durch dynamisches Ändern gezwungen wird, die gesamte Matrix jedes Mal an einen größeren Punkt im RAM zu kopieren, wenn sie aus dem aktuellen Punkt herauswächst.

Wenn Sie wirklich Speicherprobleme haben , möchten Sie vielleicht nur die Kunst der Datentypen kennenlernen - wie es in Sprachen niedrigerer Ebene erforderlich ist. main_mat=zeros(500,500,2000,'single');Zum Beispiel können Sie Ihre Speichernutzung halbieren, indem Sie direkt von Anfang an die Genauigkeit verwenden - übrigens funktioniert dies auch mit rand(...,'single')und nativeren Funktionen - obwohl einige der komplexeren Matlab-Funktionen die Eingabe vom Typ double erfordern, was Sie können wieder ausgestoßen.


0

Wenn ich das richtig verstehe, besteht Ihr Hauptproblem darin, dass parforkein Speicher freigegeben werden kann. Stellen Sie sich jeden Parfor Worker als fast separate Matlab-Instanz vor.

Grundsätzlich gibt es nur eine Problemumgehung, die ich kenne (die ich noch nie ausprobiert habe), nämlich "Shared Matrix" in Fileexchange: https://ch.mathworks.com/matlabcentral/fileexchange/28572-sharedmatrix

Weitere Lösungen: Wie andere vorgeschlagen haben: Parfor entfernen ist sicherlich eine Lösung, mehr RAM erhalten, große Arrays verwenden (die Festplatten verwenden, wenn der RAM voll ist, lesen Sie hier ), Operationen in kleinere Blöcke aufteilen, nicht zuletzt eine andere Alternative in Betracht ziehen als Matlab.


0

Sie können folgenden Code verwenden. Sie brauchen die Slice_Matrix eigentlich nicht

main_mat=zeros(500,500,2000);
n=500;
slice_matrix=zeros(500,500,n);
for k=1:4
   parfor i=1:n
       main_mat(:,:,1+(k-1)*n + i - 1) = gather(gpuArray(rand(500,500)));
   end
   %% now you don't need this main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)=slice_matrix; %This is where the memory will likely overflow
end

Das kann man nicht in einer Parfor-Schleife machen
Gregor Isack

Hast du das versucht?
Mayank1513

Es gibt einen Grund, warum ich das aus der Parfoor-Schleife verschoben habe. Ich habe nicht genau den gleichen Code ausprobiert, aber ich wusste, dass er aufgrund der Indizierung nicht funktionieren würde.
Gregor Isack
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.