8 Stimmen

Wie vermeidet man enormen zusätzlichen Speicherverbrauch bei der Verwendung von numpy vectorize?

Der folgende Code veranschaulicht mein Problem am besten:

Die Ausgabe auf der Konsole (NB, es dauert ~8 Minuten, um sogar den ersten Test auszuführen) zeigt, dass die 512x512x512x16-Bit-Array-Zuweisungen nicht mehr als erwartet verbrauchen (256 MByte für jeden), und wenn man sich "oben" ansieht, bleibt der Prozess im Allgemeinen wie erwartet unter 600 MByte.

ただし während die vektorisierte Version der Funktion aufgerufen wird, erweitert sich der Prozess zu enorm Größe (über 7 GByte!). Selbst die naheliegendste Erklärung, die mir dafür einfällt - dass vectorize die Ein- und Ausgaben intern in float64 konvertiert - könnte nur ein paar Gigabyte erklären, obwohl die vektorisierte Funktion eine int16 zurückgibt und das zurückgegebene Array sicherlich eine int16 ist. Gibt es eine Möglichkeit, dies zu vermeiden? Benutze/verstehe ich das otypes-Argument von vectorize falsch?

import numpy as np
import subprocess

def logmem():
    subprocess.call('cat /proc/meminfo | grep MemFree',shell=True)

def fn(x):
    return np.int16(x*x)

def test_plain(v):
    print "Explicit looping:"
    logmem()
    r=np.zeros(v.shape,dtype=np.int16)
    for z in xrange(v.shape[0]):
        for y in xrange(v.shape[1]):
            for x in xrange(v.shape[2]):
                r[z,y,x]=fn(x)
    print type(r[0,0,0])
    logmem()
    return r

vecfn=np.vectorize(fn,otypes=[np.int16])

def test_vectorize(v):
    print "Vectorize:"
    logmem()
    r=vecfn(v)
    print type(r[0,0,0])
    logmem()
    return r

logmem()    
s=(512,512,512)
v=np.ones(s,dtype=np.int16)
logmem()
test_plain(v)
test_vectorize(v)
v=None
logmem()

Ich verwende die jeweils aktuellen Versionen von Python/numpy auf einem amd64 Debian Squeeze System (Python 2.6.6, numpy 1.4.1).

3voto

DaveP Punkte 6644

Ein grundlegendes Problem der Vektorisierung ist, dass alle Zwischenwerte ebenfalls Vektoren sind. Dies ist zwar ein bequemer Weg, um eine anständige Geschwindigkeitssteigerung zu erreichen, kann aber sehr ineffizient sein, was die Speichernutzung angeht, und wird ständig den CPU-Cache belasten. Um dieses Problem zu überwinden, müssen Sie einen Ansatz verwenden, bei dem explizite Schleifen mit kompilierter Geschwindigkeit und nicht mit Python-Geschwindigkeit ausgeführt werden. Die beste Möglichkeit, dies zu tun, ist die Verwendung von cython , Fortran-Code umhüllt mit f2py o numexpr . Sie können einen Vergleich dieser Ansätze finden ici obwohl es hier mehr um Geschwindigkeit als um Speicherverbrauch geht.

2voto

HYRY Punkte 89513

Können Sie den Quellcode von vectorize() lesen. Es konvertiert den dtype des Arrays in ein Objekt und ruft np.frompyfunc() auf, um die ufunc aus Ihrer Python-Funktion zu erstellen. Die ufunc gibt ein Objekt-Array zurück und schließlich konvertiert vectorize() das Objekt-Array in ein int16-Array.

Es wird viel Speicher verwendet, wenn der D-Typ des Arrays Objekt ist.

Die Verwendung von Python-Funktionen zur elementweisen Berechnung ist langsam, auch wenn sie mit frompyfunc() in ufunc umgewandelt werden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X