numpy - memory leak

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
Iriskinn
User
Beiträge: 7
Registriert: Donnerstag 29. Oktober 2020, 18:12

Hi,

in meinem Projekt benutze ich numpy und cv2 und habe ein volgendes Problem mit dem Speicherplatz:

Code: Alles auswählen

def observation(self, frame):
        data = copy(frame)
        frame = np.zeros(self.observation_space.low.shape)
        return frame.reshape(self.observation_space.low.shape)
diese Funktion fuehrt zu dem Speicherleck, wenn ich aber zweite zeile durch

Code: Alles auswählen

frame = cv2.resize(frame, (self.width, self.height), interpolation=cv2.INTER_AREA)
ersetze, funktioniert alles problemlos.
Ich weiss, dass diese Operationen nicht dasselbe machen, ich glaube aber, dass die beide gleich mit dem Speicher arbeiten (erzeigen ein neues Objekt und geben ihn zurueck).
Kann jemand erklaeren, warum das passiert und woran der Unterschied liegt?
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Iriskinn: Warum denkst Du das da das Speicherleck sitzt? Und ist das wirklich Code der da so in Deinem Programm steht? Falls ja, *warum*! Das Argument wird nur verwendet um eine Kopie davon zu erstellen, mit der dann aber überhaupt nichts gemacht wird. Mit `np.zeros()` wird ein Array erstellt und dann wird das mit `reshape()` auf genau die gleichen Dimensionen gebracht, die es sowieso schon hatte, was ein sinnfreier Schritt ist.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Iriskinn
User
Beiträge: 7
Registriert: Donnerstag 29. Oktober 2020, 18:12

@__blackjack__ Im ersten Fall braucht das Program mehr als 12 GB, im zweiten - weniger als 3 GB, deswegen glaube ich, dass es am Speicherleck liegt. Code steht wirklich in dem Program. Warum ich diese komische Sachen schreibe? Weil ich den Unterschied zwischen diesen zwei Versionen moeglichst klein machen will.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Die Programme brauchen halt so viel Speicher wie sie brauchen. Ohne dass wir beide Programme komplett kennen, ohne zu wissen, welche Dimensionen die Arrays haben, kann man dazu nichts sagen.
Iriskinn
User
Beiträge: 7
Registriert: Donnerstag 29. Oktober 2020, 18:12

Sirius3 hat geschrieben: Donnerstag 29. Oktober 2020, 19:27 Ohne dass wir beide Programme komplett kennen, ohne zu wissen, welche Dimensionen die Arrays haben, kann man dazu nichts sagen.
Beide Programme unterscheiden sich voneinander um 1 Zeile, die Dimensionen in beiden Faellen sind gleich -> ein Programm brauch 3 GB, zweites Programm brauch 12 GB.
Aber natuerclih hast du Recht, man muss das Programm (und Dimensionen, und wahrscheinlich noch die Mondphase) komplett kennen, um etwas sagen zu koennen.
Da ich das alles nicht geschrieben habe, muss ich solche hilfreiche Antworten bekommen:
Sirius3 hat geschrieben: Donnerstag 29. Oktober 2020, 19:27 Die Programme brauchen halt so viel Speicher wie sie brauchen.
einfachTobi
User
Beiträge: 491
Registriert: Mittwoch 13. November 2019, 08:38

Mit so einer Einstellung kommst du sicherlich weit bei Leuten, die dir kostenlos in ihrer Freizeit helfen wollen. Ich wills trotzdem mal versuchen:
Auf die Punkte von __blackjack__ bist du gar nicht eingegangen. Deine Funktion macht einfach unnütze Dinge. Beispielsweise wird `frame` kopiert und die Kopie namens `data` dann nicht verwendet. Wozu? Es ist nicht ersichtlich, was die Funktion bezwecken soll. Willst du nur die `shape` des Arrays ändern oder ein neues Array gleicher Dimension erstellen?
Denn Sirius hat Recht mit seiner Aussage: Ein Array braucht so viel Platz wie es braucht und ohne zu wissen was im Code passiert und zu wissen wie groß die Arrays sind, lässt sich halt nichts sagen. Da lässt sich nichts dran rütteln. Beide Programme unterscheiden sich im Minimum in 4 Zeilen, nämlich deiner Funktion `observation` und der Nutzung von `cv2.resize`.
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

@Iriskinn: Anhand der Dimensionen lässt sich der Speicherverbrauch recht gut ermitteln. Ich sehe nicht, warum man deshalb patzig werden sollte.
__blackjack__ hat doch oben bereits geschrieben, dass dein Programm so keinen Sinn macht. Warum gehst du also so vor? Werkzeuge muss man verstehen um sie korrekt einsetzen zu können - und beurteilen zu können ob es ein Speicherleck gibt.
Iriskinn
User
Beiträge: 7
Registriert: Donnerstag 29. Oktober 2020, 18:12

Stimmt, ich habe meine Frage nicht genug anschaulich formatiert. Ich korrigiere das:

Code: Alles auswählen

# erste Version (mit dem Speicherleck)
def observation(self, frame):
        data = copy(frame)
        frame = np.zeros(self.observation_space.low.shape)
        return frame.reshape(self.observation_space.low.shape)

Code: Alles auswählen

# zweite Version (ohne Speicherleck)
def observation(self, frame):
        data = copy(frame)
        frame = cv2.resize(frame, (self.width, self.height), interpolation=cv2.INTER_AREA)
        return frame.reshape(self.observation_space.low.shape)
So, jetzt sieht man sicher, dass nur eine Zeile sich unterscheidet.
EinArray braucht so viel Platz wie es braucht
Genau das verstehe ich nicht: sowohl np.zeros() als auch cv2.resize() erzeugen ein Array der Groesse (nicht shape) self.observation_space.low.shape. Warum fuehrt das im ersten Fall zu einem unvergleichbar groesserem Speicherverbrauh als im zweiten Fall?
Willst du nur die `shape` des Arrays ändern oder ein neues Array gleicher Dimension erstellen?
Ich will ein neues Array mit shape=self.observation_space.low.shape erstellen.
Auf die Punkte von __blackjack__ bist du gar nicht eingegangen. Deine Funktion macht einfach unnütze Dinge. Beispielsweise wird `frame` kopiert und die Kopie namens `data` dann nicht verwendet.
Wie ich schon geantwortet habe, ich wollte den Unterschied zwischen Versionen moeglichst klein machen. `data` wird nicht verwendet - ich weiss, das passiert aber in beiden Versionen => das Problem liegt nicht daran, warum besprechen wir das?
Wozu?
Ich will + ich kann.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Du denkst vielleicht, es liegt an dieser einen Zeile. Da es nicht an dieser einen Zeile liegen kann, brauchen wir das gesamte Programm.
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Mal eine ganz dumme Frage: Wie viele Bytes belegt denn *ein* Element vom `resize()`\ten `frame`? Bei dem `zeros()`-`frame` sind es 8 Bytes pro Element.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Natürlich, Bilder sind ja meist nur 8 bit. Da reicht schon ein kleines Bild mit einer Auflösung von 33000 x 33000 Pixeln.
Iriskinn
User
Beiträge: 7
Registriert: Donnerstag 29. Oktober 2020, 18:12

Das ist die Version, die funktinoiert: https://www.kaggle.com/kuto0633/gfootba ... nvironment Ihr wisst, welche Zeile zu ersetzen ist)

Ich fuehre das in Google Colab (wenn es eine Rolle spielen kann)
Iriskinn
User
Beiträge: 7
Registriert: Donnerstag 29. Oktober 2020, 18:12

__blackjack__ hat geschrieben: Freitag 30. Oktober 2020, 13:51 Mal eine ganz dumme Frage: Wie viele Bytes belegt denn *ein* Element vom `resize()`\ten `frame`? Bei dem `zeros()`-`frame` sind es 8 Bytes pro Element.
Du hast Recht, getsizeof() zeigt, dass die Groessen von Objekten sich unterscheiden. np.zeros() ist ~10 Mal groesser als cv2.resize().
Iriskinn
User
Beiträge: 7
Registriert: Donnerstag 29. Oktober 2020, 18:12

Vielen Dank fuer ihre Hilfe, das Problem wurde geloest: man muss

Code: Alles auswählen

frame = np.zeros(self.shape[channel_order], dtype.int8)
statt

Code: Alles auswählen

frame = np.zeros(self.shape[channel_order])
benutzen.
Also das war wirklich kein Speicherleck, sondern nur Missbrauch wegen dem Datentyp.
Antworten