Ich habe diese Haskell-Funktion, die mehr als 50% aller Zuweisungen meines Programms verursacht, wodurch 60% meiner Laufzeit vom GC belegt werden . Ich laufe mit einem kleinen Stack (-K10K
), also gibt es keinen Stack-Überlauf, aber kann ich diese Funktion schneller machen, mit weniger Zuweisung?Optimiere eine Listenfunktion, die zu viel Müll erzeugt (kein Stack-Überlauf)
Ziel ist es, das Produkt einer Matrix durch einen Vektor zu berechnen. Ich kann hmatrix
zum Beispiel nicht verwenden, weil dies Teil einer größeren Funktion ist, die das ad
Automatic Differentiation-Paket verwendet, also muss ich Listen von Num
verwenden. Zur Laufzeit nehme ich an, dass die Verwendung des Numeric.AD
Moduls bedeutet, dass meine Typen Scalar Double
sein müssen.
listMProd :: (Num a) => [a] -> [a] -> [a]
listMProd mdt vdt = go mdt vdt 0
where
go [] _ s = [s]
go ls [] s = s : go ls vdt 0
go (y:ys) (x:xs) ix = go ys xs (y*x+ix)
Grundsätzlich wir Schleife durch die Matrix, Multiplizieren und Addieren eines Akkumulators, bis wir das Ende des Vektors erreicht, um das Ergebnis zu speichern, dann den Vektor fort wieder neu zu starten. Ich habe einen quickcheck
Test, der bestätigt, dass ich das gleiche Ergebnis als das Matrix-/Vektorprodukt in der hmatrix erhalte.
Ich habe versucht mit foldl
, foldr
, etc. Nichts, was ich ausprobiert habe macht die Funktion schneller (und einige Dinge wie foldr
verursachen ein Leck im Raum).
mit Profillauf sagt mir, oben auf der Tatsache, dass diese Funktion ist, wo die meiste Zeit und Zuteilung wird ausgegeben, dass es eine Menge Cells
erstellt werden, Cells
ein Datentyp aus dem ad
Paket zu sein.
Ein einfacher Test auszuführen:
import Numeric.AD
main = do
let m :: [Double] = replicate 400 0.2
v :: [Double] = replicate 4 0.1
mycost v m = sum $ listMProd m v
mygrads = gradientDescent (mycost (map auto v)) (map auto m)
print $ mygrads !! 1000
Das auf meinem Rechner sagt mir GC ist besetzt 47% der Zeit.
Irgendwelche Ideen?
Weitere Informationen! Wie läuft dieses Programm? Wo ist dein Testkabel? Welche konkreten Typen verwendest du? Was sind die Flags und die Version auf Ihrem Haskell-Compiler? –
Einige Informationen hinzugefügt. Diese Funktion wird über die Ad-Grad-Funktion aufgerufen, die ihre eigenen Typen (Instanzen von Num) verwendet. Profiling zeigt Zuweisungen von "Zellen". –
Einige halb informierte Vorschläge: Haben Sie erwogen, einen veränderlichen Zustand mit 'ST' zu verwenden? Und [Stream-Fusion] (https://hackage.haskell.org/package/stream-fusion-0.1.2.5/docs/Data-List-Stream.html)/[Conduit] (https: //hackage.haskell. org/Paket/Conduit)/[Pipes] (https://hackage.haskell.org/package/pipes)? Vielleicht (?) Könnte es sich sogar lohnen, Ihre Vektorliste in etwas anderes zu verwandeln, z. ein [ungeboxter Vektor] (http://lambda.jstolarek.com/2013/04/haskell-as-fast-as-c-a-case-study/)? Ich habe keine Erfahrung mit irgendeiner dieser Techniken, aber vielleicht können die Verbindungen Ihnen weiter helfen. –