Array mit Form und Datentyp kann nicht zugeordnet werden

105

Ich habe ein Problem mit der Zuweisung großer Arrays in numpy unter Ubuntu 18, während ich unter MacOS nicht mit demselben Problem konfrontiert bin.

Ich versuche, Speicher für ein numpy Array mit Form (156816, 36, 53806) mit zuzuweisen

np.zeros((156816, 36, 53806), dtype='uint8')

und während ich einen Fehler unter Ubuntu OS bekomme

>>> import numpy as np
>>> np.zeros((156816, 36, 53806), dtype='uint8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
numpy.core._exceptions.MemoryError: Unable to allocate array with shape (156816, 36, 53806) and data type uint8

Ich bekomme es nicht unter MacOS:

>>> import numpy as np 
>>> np.zeros((156816, 36, 53806), dtype='uint8')
array([[[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]],

       [[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]],

       [[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]],

       ...,

       [[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]],

       [[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]],

       [[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]]], dtype=uint8)

Ich habe irgendwo gelesen, dass np.zerosnicht wirklich der gesamte für das Array benötigte Speicher zugewiesen werden sollte, sondern nur für die Nicht-Null-Elemente. Obwohl der Ubuntu-Computer 64 GB Speicher hat, hat mein MacBook Pro nur 16 GB.

Versionen:

Ubuntu
os -> ubuntu mate 18
python -> 3.6.8
numpy -> 1.17.0

mac
os -> 10.14.6
python -> 3.6.4
numpy -> 1.17.0

PS: Auch bei Google Colab fehlgeschlagen

Martin Brisiak
quelle
1
Laufen andere Prozesse im Speicher?
BlueRine S
Nein, ich habe es versucht topund free -mdiese Befehle waren 60 GB Mem frei und mehr
Martin Brisiak
Hmmm. seltsam. Das sollte nicht so viel Speicherplatz beanspruchen. Wie viel Speicher hat es auf Macos belegt?
BlueRine S
1
Unwahrscheinlich, aber Sie führen zufällig keinen 32-Bit-Python-Interpreter in Ubuntu aus, oder?
Jdehesa
1
np.zeroserstellt keine sparseMatrix. Es kann zu Verzögerungen beim Ausfüllen der Nullen kommen. Aber siehe stackoverflow.com/q/27464039
hpaulj

Antworten:

107

Dies ist wahrscheinlich auf den Überlastungsmodus Ihres Systems zurückzuführen .

Im Standardmodus 0,

Heuristisches Overcommit-Handling. Offensichtliche Überbeanspruchungen des Adressraums werden abgelehnt. Wird für ein typisches System verwendet. Es stellt sicher, dass eine ernsthafte wilde Zuweisung fehlschlägt, während Overcommit die Swap-Nutzung reduziert. root darf in diesem Modus etwas mehr Speicher zuweisen. Dies ist die Standardeinstellung.

Die genaue verwendete Heuristik wird hier nicht gut erklärt, aber dies wird mehr unter Linux über Commit-Heuristik und auf dieser Seite diskutiert .

Sie können Ihren aktuellen Overcommit-Modus überprüfen, indem Sie ausführen

$ cat /proc/sys/vm/overcommit_memory
0

In diesem Fall weisen Sie zu

>>> 156816 * 36 * 53806 / 1024.0**3
282.8939827680588

~ 282 GB, und der Kernel sagt offensichtlich, dass ich auf keinen Fall so viele physische Seiten dafür festlegen kann, und er lehnt die Zuweisung ab.

Wenn Sie (als Root) ausführen:

$ echo 1 > /proc/sys/vm/overcommit_memory

Dadurch wird der Modus "Immer überbeanspruchen" aktiviert, und Sie werden feststellen, dass das System es Ihnen tatsächlich ermöglicht, die Zuordnung unabhängig von ihrer Größe vorzunehmen (mindestens innerhalb der 64-Bit-Speicheradressierung).

Ich habe dies selbst auf einem Computer mit 32 GB RAM getestet. Im Overcommit-Modus habe 0ich auch einen bekommen MemoryError, aber nachdem ich ihn wieder geändert 1habe, funktioniert er:

>>> import numpy as np
>>> a = np.zeros((156816, 36, 53806), dtype='uint8')
>>> a.nbytes
303755101056

Sie können dann an eine beliebige Stelle innerhalb des Arrays schreiben, und das System weist physische Seiten nur zu, wenn Sie explizit auf diese Seite schreiben. Sie können dies also mit Vorsicht für spärliche Arrays verwenden.

Leguananaut
quelle
2
Dies ist speziell eine Funktion des Linux-Kernels, sodass es unter MacOS nicht unbedingt eine direkte Entsprechung gibt, obwohl möglicherweise etwas Ähnliches. Ich denke nicht, dass es auf Macs so einfach ist, die Kerneleinstellungen zu ändern.
Iguananaut
1
@Iguananaut Was ist die genaue Bedeutung der Warnung "mit Sorgfalt"? dh. Was ist der schlimmste Fall, in dem auf einem Ubuntu 18-Server mit GTX 1080-GPU etwas schief geht?
mLstudent33
1
@ mLstudent33 Zum einen hat dies nichts mit Ihrer GPU zu tun, die über einen eigenen Speicher verfügt. Ich meine, Sie können immer noch Ihren Speicher füllen - jedes Mal, wenn Sie auf eine Seite im Speicher schreiben, muss diese Seite (normalerweise 4 KB) in den physischen Speicher übernommen werden. Das schlimmste Szenario ist also, dass Ihnen der Speicher ausgeht.
Iguananaut
1
Wird diese Änderung sofort wirksam oder müssen wir unsere Shell oder die Maschine selbst neu starten?
Dumbledad
2
Es wird sofort wirksam, bleibt aber ohne zusätzliche Maßnahmen nicht über den Neustart hinaus bestehen. Suchen Sie nach anderen Fragen, wie Sie die /proc/sysEinstellungen in Ihrer Distribution am besten beibehalten können.
Iguananaut
45

Ich hatte das gleiche Problem bei Windows und bin auf diese Lösung gestoßen. Wenn also jemand unter Windows auf dieses Problem stößt , besteht die Lösung für mich darin, die Auslagerungsdatei zu vergrößern, da dies auch für mich ein Problem mit einer Überlastung des Speichers war.

Windows 8

  1. Auf der Tastatur Drücken Sie die Windows-Taste + X und klicken Sie dann im Popup-Menü auf System
  2. Tippen oder klicken Sie auf Erweiterte Systemeinstellungen. Möglicherweise werden Sie nach einem Administratorkennwort gefragt oder müssen Ihre Auswahl bestätigen
  3. Tippen oder klicken Sie auf der Registerkarte Erweitert unter Leistung auf Einstellungen.
  4. Tippen oder klicken Sie auf die Registerkarte Erweitert, und tippen oder klicken Sie dann unter Virtueller Speicher auf Ändern
  5. Deaktivieren Sie das Kontrollkästchen Größe der Auslagerungsdatei für alle Laufwerke automatisch verwalten.
  6. Tippen oder klicken Sie unter Laufwerk [Datenträgerbezeichnung] auf das Laufwerk, das die Auslagerungsdatei enthält, die Sie ändern möchten
  7. Tippen oder klicken Sie auf Benutzerdefinierte Größe, geben Sie eine neue Größe in Megabyte in das Feld Anfangsgröße (MB) oder Maximale Größe (MB) ein, tippen oder klicken Sie auf Festlegen und tippen oder klicken Sie dann auf OK
  8. Starten Sie Ihr System neu

Windows 10

  1. Drücken Sie die Windows-Taste
  2. Geben Sie SystemPropertiesAdvanced ein
  3. Klicken Sie auf Als Administrator ausführen
  4. Klicken Sie auf Einstellungen
  5. Wählen Sie die Registerkarte Erweitert
  6. Wählen Sie Ändern ...
  7. Deaktivieren Sie das Kontrollkästchen Größe der Auslagerungsdatei für alle Laufwerke automatisch verwalten
  8. Wählen Sie dann Benutzerdefinierte Größe und geben Sie die entsprechende Größe ein
  9. Drücken Sie Festlegen, dann OK und verlassen Sie das Dialogfeld Virtueller Speicher, Leistungsoptionen und Systemeigenschaften
  10. Starten Sie Ihr System neu

Hinweis: Ich hatte in diesem Beispiel nicht genügend Speicher auf meinem System für die ~ 282 GB, aber für meinen speziellen Fall hat dies funktioniert.

BEARBEITEN

Von hier aus die empfohlenen Empfehlungen für die Größe der Auslagerungsdatei:

Es gibt eine Formel zur Berechnung der richtigen Auslagerungsgröße. Die anfängliche Größe beträgt eineinhalb (1,5) x die Größe des gesamten Systemspeichers. Die maximale Größe beträgt drei (3) x die ursprüngliche Größe. Angenommen, Sie haben 4 GB (1 GB = 1.024 MB x 4 = 4.096 MB) Speicher. Die anfängliche Größe wäre 1,5 x 4.096 = 6.144 MB und die maximale Größe wäre 3 x 6.144 = 18.432 MB.

Einige Dinge, die Sie von hier aus beachten sollten :

Dies berücksichtigt jedoch nicht andere wichtige Faktoren und Systemeinstellungen, die möglicherweise nur für Ihren Computer gelten. Lassen Sie Windows erneut auswählen, was verwendet werden soll, anstatt sich auf eine beliebige Formel zu verlassen, die auf einem anderen Computer funktioniert.

Ebenfalls:

Durch Erhöhen der Auslagerungsdateigröße können Instabilitäten und Abstürze unter Windows vermieden werden. Die Lese- / Schreibzeiten einer Festplatte sind jedoch viel langsamer als wenn sich die Daten in Ihrem Computerspeicher befinden würden. Wenn Sie eine größere Auslagerungsdatei haben, wird Ihre Festplatte zusätzlich belastet, und alles andere läuft langsamer. Die Größe der Auslagerungsdatei sollte nur bei Fehlern aufgrund von Speichermangel und nur als vorübergehende Korrektur erhöht werden. Eine bessere Lösung besteht darin, dem Computer mehr Speicher hinzuzufügen.

rekursiv bis
quelle
Welche benutzerdefinierten Größeneinstellungen (Anfangsgröße + maximale Größe) haben Sie derzeit? Ich bin mir nicht sicher, wie viel ich für mich selbst
zuweisen soll
1
@Azizbro Ich bin jetzt zum Standard zurückgekehrt, habe aber nur die Werte angepasst, bis der Fehler aufgrund von Speichermangel verschwunden ist.
Wiederholung bis
23

Ich bin auch unter Windows auf dieses Problem gestoßen. Die Lösung für mich war, von einer 32-Bit- auf eine 64-Bit-Version von Python zu wechseln . In der Tat kann eine 32-Bit-Software wie eine 32-Bit-CPU maximal 4 GB RAM (2 ^ 32) adressieren. Wenn Sie also mehr als 4 GB RAM haben, kann eine 32-Bit-Version dies nicht nutzen.

Mit einer 64-Bit-Version von Python (die auf der Download-Seite mit x86-64 bezeichnete ) verschwand das Problem.

Sie können überprüfen, welche Version Sie haben, indem Sie den Interpreter eingeben. Ich habe jetzt mit einer 64-Bit-Version : Python 3.7.5rc1 (tags/v3.7.5rc1:4082f600a5, Oct 1 2019, 20:28:14) [MSC v.1916 64 bit (AMD64)], wobei [MSC v.1916 64-Bit (AMD64)] "64-Bit-Python" bedeutet.

Hinweis : Zum Zeitpunkt dieses Schreibens (Mai 2020) ist matplotlibauf python39 nicht verfügbar. Ich empfehle daher, python37 mit 64 Bit zu installieren.

Quellen:

Kotchwane
quelle
Vielen Dank. Mit der letzten stabilen 64-Bit-Python-Version (3.8.3) kann ich auch matplotlib installieren.
Federico Tomasi
1
Wie gebe ich einen Dolmetscher ein?
Shayan
Mein Problem wurde auch gelöst. Pycharm verwenden. Die deinstallierte 32-Bit-Version, die neu installierte 64-Bit-Version und der Projektinterpreter wurden in die neue 64-Bit-Python geändert.
Jason Goal
3

In meinem Fall wurde durch Hinzufügen eines dtype-Attributs der dtype des Arrays in einen kleineren Typ geändert (von float64 auf uint8), wodurch die Arraygröße so weit verringert wurde, dass MemoryError in Windows (64 Bit) nicht ausgelöst wurde.

von

mask = np.zeros(edges.shape)

zu

mask = np.zeros(edges.shape,dtype='uint8')
Pragya Agrawal
quelle
1

Ändern Sie den Datentyp in einen anderen, der weniger Speicher benötigt. Für mich ändere ich den Datentyp in numpy.uint8:

data['label'] = data['label'].astype(np.uint8)
Mingming Qiu
quelle