2017-12-20 7 views
0

Ich versuche joblib zu verwenden, um eine benutzerdefinierte zufällige Waldimplementierungszug parallel zu machen.Untersuchen der Joblib Verlangsamung

Die Aufgabe ist peinlich parallel, also nahm ich an, dass eine Beschleunigung mit joblib nicht zu schwer sein sollte.

Hier ist ein Beispielcode:

class RandomForest(object): 
    def __init__(self, settings, data): 
     self.forest = [None] * settings.n_trees 
     self.parallel = Parallel(n_jobs=settings.njobs, backend="threading") 

    def fit(self, data, train_ids_current_minibatch, settings, param, cache): 
     self.forest = self.parallel(
      delayed(_parallel_build_trees_batch)(
       i_t, data, train_ids_current_minibatch, settings, param, cache) 
      for i_t, tree in enumerate(self.forest)) 

    def partial_fit(self, data, train_ids_current_minibatch, settings, param, cache): 
     self.forest = self.parallel(
      delayed(_parallel_build_trees_partial)(
       tree, i_t, data, train_ids_current_minibatch, settings, param, cache) 
      for i_t, tree in enumerate(self.forest)) 

jedoch die Ausbildung ist viel langsamer, wenn mehrere Jobs verwenden, sowohl im Batch- und inkrementellen Fall. Die Daten- und Cache-Argumente sind Dicts, die (große) numpige Arrays enthalten, also frage ich mich, ob das der Grund ist.

Ich habe versucht, die gleiche Codierung mit multiprocessing.Pool und die Ergebnisse sind noch schlimmer, da nicht die threading Backend von Joblib, nehme ich an, weil die Fit-Funktionen verwenden stark numpy/scipy Code.

Irgendwelche Ideen zum Debuggen/Reparieren der Verlangsamung?

+0

hat mein Beitrag Ihre Frage beantworten? – hansaplast

Antwort

1

Ihre Analyse scheint mir korrekt zu sein: Die Verlangsamung wird verursacht durch data und cache große Objekte. Jetzt haben Sie in einer Multiprocessing-Umgebung keinen gemeinsamen Speicher, also müssen Sie diese Objekte irgendwie teilen. Python unterstützt dies über shared objects: Es gibt einen "Hauptprozess", der das Objekt wirklich hält. Aber dann müssen die anderen Prozesse alle Aktualisierungen über irgendeinen Mechanismus senden (AFAIK wird das Objekt gebeizt und dann über eine Pipe oder eine Warteschlange gesendet), was es verlangsamt.

Ich sehe einige Möglichkeiten für Sie:

  • Code umwandeln, so dass es Partitionen verwendet: Ich mit zufälligem Wald nicht vertraut bin. Ich nehme an, jeder Prozess hat data als einen anfänglichen Datensatz und dann versuchen Sie, ein "Optimum" zu finden. Wenn Sie Prozess 1 drücken könnten, um alle "Typ A" -Optimale zu finden, und Prozess 2, um alle "Typ B" -Optimale zu finden, und dann jeden Prozess z. ihre Ergebnisse auf der Festplatte in der Datei schreiben rf_process_x.txt dann brauchen Sie keinen Shared-Memory-Zustand
  • Code umwandeln, so dass es Warteschlangen (siehe letztes Beispiel auf this page) verwendet: Falls die Partitionierung nicht funktioniert, dann vielleicht könnten Sie:
    1. n worker-Prozesse
    2. jeder Prozess baut seinen data Satz für sich selbst starten (so im gemeinsam genutzten Speicher ist es nicht)
    3. im Hauptprozess Sie „Jobs“ in die task_queue setzen, zB Finde zufällige Gesamtstruktur mit diesem spezifischen Parametersatz. Der Worker erhält den Job von der task_queue, berechnet ihn und setzt sein Ergebnis auf eine result_queue. Dies ist nur dann schnell, wenn die Aufgaben und Ergebnisse langsam sind, da diese Objekte gebeizt und über eine Pipe vom übergeordneten Prozess zum Arbeitsprozess gesendet werden müssen.
  • Verwendung joblibs memmapping: Joblibs supports das Objekt auf die Platte Dumping und dann jede geben Objekt einen Memory-Mapped Zugriff auf diese Datei
  • , wenn Ihr Betrieb ist nicht CPU gebunden (tut schwere Festplatte oder Netzwerkbetrieb) Sie könnten zu Multithreading wechseln. Auf diese Weise haben Sie wirklich einen gemeinsamen Speicher.Aber soweit ich sehen kann, Sie sind cpu gebunden und wird in die „GIL lock“ Ausgabe laufen (in CPython nur ein Thread läuft zur gleichen Zeit)
  • Sie andere Möglichkeiten zur Beschleunigung der Zufalls Wald finden kann, z.B this SO answer erwähnt ein paar