Beschleunigen Sie mit Rust und LLVM 100-mal Numpy, Scikit und Pandas: Interview mit Entwickler Weld

Hallo Habr! Ich präsentiere Ihnen die Übersetzung des Artikels "Interview mit Welds Hauptverantwortlichem: Beschleunigung von Numpy, Scikit und Pandas um das 100-fache mit Rust und LLVM" .

Nachdem ich einige Wochen mit Data Science-Tools in Python und R gearbeitet hatte, begann ich mich zu fragen, ob es eine Intermediate Representation (IR) wie CUDA gibt, die in verschiedenen Sprachen verwendet werden kann. Es muss etwas Besseres geben als die Neuimplementierung und Optimierung derselben Methoden in jeder Sprache. Darüber hinaus wäre es schön, eine gemeinsame Laufzeit zu haben, um das gesamte Programm zu optimieren, und nicht jede Funktion einzeln.

Nachdem ich mehrere Tage lang verschiedene Projekte recherchiert und getestet hatte, fand ich Weld(Sie können den wissenschaftlichen Artikel lesen ).

Zu meiner Überraschung ist einer der Autoren Weld Matei Zaharia (Matei Zaharia), der Schöpfer von Spark.

Also kontaktierte ich Shoumik Palkar , Welds Hauptverantwortlichen, und interviewte ihn. Showmick ist ein Doktorand am Institut für Informatik der Stanford University, wo er auf Anraten von Matey Zakharia eintrat.

Weld ist noch nicht industriell einsetzbar, aber sehr vielversprechend. Wenn Sie sich für die Zukunft der Datenwissenschaft und insbesondere von Rust interessieren, werden Sie dieses Interview lieben.

Werbung des Autors des Originalartikels
image
«Not a Monad Tutorial», Weld . !

, mail@fcarrone.com @unbalancedparen.

Wofür wurde Weld entwickelt, welche Probleme löst es?


Ziel von Weld ist es, die Produktivität von Anwendungen zu steigern, die APIs auf hoher Ebene wie NumPy und Pandas verwenden. Das Hauptproblem, das er löst, sind funktionsübergreifende und bibliotheksübergreifende Optimierungen, die heute von anderen Bibliotheken nicht bereitgestellt werden. Insbesondere haben viele weit verbreitete Bibliotheken moderne Implementierungen von Algorithmen für einzelne Funktionen (z. B. den in Pandas von C implementierten Fast-Join-Algorithmus oder die schnelle Matrixmultiplikation in NumPy), bieten jedoch nicht die Möglichkeit, die Kombination dieser Funktionen zu optimieren. Verhindern Sie beispielsweise unnötige Speicherscans, wenn Sie eine Matrixmultiplikation gefolgt von einer Aggregation durchführen.

Weld bietet eine gemeinsame Laufzeitumgebung, mit der Bibliotheken Berechnungen in einer gemeinsamen Zwischendarstellung (IR) ausdrücken können. Diese IR kann dann mit dem Compiler-Optimierer optimiert und dann im laufenden Betrieb (JIT) mit Optimierungen wie Schleifenzusammenführung, Vektorisierung usw. in parallelen Maschinencode kompiliert werden. Das IR von Weld ist anfangs parallel, sodass die darin ausgedrückten Programme immer trivial parallelisiert werden können.

Wir haben auch ein neues Projekt namens Split Annotations, das in Weld integriert wird und die Barriere für die Aufnahme solcher Optimierungen in vorhandene Bibliotheken verringern soll.

Wäre es nicht einfacher, Numpy, Pandas und Scikit zu optimieren? Wie viel schneller ist es?


Weld bietet eine Optimierung der Funktionskombination in diesen Bibliotheken, während die Optimierung der Bibliotheken die Aufrufe nur einzelner Funktionen beschleunigen kann. Tatsächlich sind viele dieser Bibliotheken bereits für jede einzelne Funktion sehr gut optimiert, bieten jedoch eine Leistung unterhalb der Grenzen moderner Geräte, da sie keine Parallelität verwenden oder die Speicherhierarchie nicht effizient nutzen.

Beispielsweise sind viele NumPy-Funktionen für mehrdimensionale Arrays (ndarray) in der C-Sprache auf niedriger Ebene implementiert, aber ein Aufruf jeder Funktion erfordert einen vollständigen Scan der Eingabedaten. Wenn diese Arrays nicht in die CPU-Caches passen, kann der größte Teil der Ausführungszeit damit verbracht werden, Daten aus dem Hauptspeicher zu laden, anstatt Berechnungen durchzuführen. Weld kann einzelne Funktionsaufrufe anzeigen und Optimierungen durchführen, z. B. das Kombinieren von Schleifen, in denen Daten in Caches oder CPU-Registern gespeichert werden. Solche Optimierungen können die Leistung in Mehrkernsystemen um mehr als eine Größenordnung verbessern, da sie eine bessere Skalierbarkeit bieten.

Bild

Die Integration von Weld-Prototypen mit Spark (oben links), NumPy (oben rechts) und TensorFlow (unten links) zeigt eine bis zu 30-fache Verbesserung gegenüber Implementierungen ihrer eigenen Infrastruktur, ohne den Benutzeranwendungscode zu ändern. Die bibliotheksübergreifende Optimierung von Pandas und NumPy (unten rechts) kann die Leistung um zwei Größenordnungen verbessern.

Was ist Baloo?


Baloo ist eine Bibliothek, die eine Teilmenge der Pandas-API mithilfe von Weld implementiert. Es wurde von Radu Jica, einem Master in CWI (Centrum Wiskunde & Informatica, Amsterdam), entwickelt. Das Ziel von Baloo ist es, die oben genannten Optimierungstypen auf Pandas anzuwenden, um die Single-Thread-Leistung zu verbessern, die Speichernutzung zu reduzieren und die Parallelität sicherzustellen.

Unterstützt Weld / Baloo externe Vorgänge (wie z. B. Dask) zur Verarbeitung von Daten, die nicht in den Speicher passen?


Weld und Baloo unterstützen derzeit keine externen Operationen (Out-of-Core, externer Speicher), obwohl wir uns über eine OpenSource-Entwicklung in diese Richtung freuen werden!

Warum haben Sie sich für Rust und LLVM entschieden, um Weld zu implementieren? Bist du sofort nach Rust gekommen?


Wir haben uns für Rust entschieden, weil:

  • Es hat eine minimale Laufzeit (tatsächlich überprüft es einfach die Grenzen von Arrays) und ist einfach in andere Sprachen wie Java und Python einzubetten
  • Es enthält funktionale Programmierparadigmen wie Pattern Matching, die das Schreiben von Code erleichtern, um beispielsweise den Pattern Matching Compiler zu optimieren
  • ( Rust crates), .

Wir haben uns für LLVM entschieden, da es sich um ein Open-Source-Kompilierungsframework handelt, das weit verbreitet ist und unterstützt wird. Wir generieren LLVM direkt anstelle von C / C ++, sodass wir den C-Compiler nicht benötigen. Dies reduziert auch die Kompilierungszeit, da wir keinen C / C ++ - Code analysieren.

Rust war nicht die erste Sprache, in der Weld implementiert wurde. Die erste Implementierung war Scala, die aufgrund ihrer algebraischen Datentypen und des Vorhandenseins eines so leistungsstarken Features wie Pattern Matching ausgewählt wurde. Dies vereinfachte das Schreiben des Optimierers, der der Hauptteil des Compilers ist. Unser ursprünglicher Optimierer wurde wie Catalyst erstellt, ein erweiterbarer Optimierer in Spark SQL.

Wir haben uns von Scala entfernt, weil es zu schwierig war, die JVM-basierte Sprache in andere Laufzeiten und Sprachen einzubetten.

Weld CPU GPU, RAPIDS, data science Python GPU?


Der Hauptunterschied zwischen Weld und Systemen wie RAPIDS besteht darin, dass Anwendungen mit unterschiedlichen Kerneln (Funktionen in CUDA-Begriffen) durch spontanes Kompilieren optimiert werden sollen und nicht die Implementierung einzelner Funktionen optimiert werden soll. Beispielsweise kompiliert das Weld-GPU-Backend einen einzelnen CUDA-Kernel, der für die endgültige Anwendung optimiert ist, anstatt separate Kernel aufzurufen.

Darüber hinaus ist Weld IR hardwareunabhängig, sodass es sowohl für die GPU als auch für die CPU sowie für nicht standardmäßige Geräte wie Vektorprozessoren verwendet werden kann.
Natürlich überschneidet sich Weld im Wesentlichen mit anderen Projekten auf demselben Gebiet, einschließlich RAPIDS, und wird unter deren Einfluss erstellt.

Laufzeitumgebungen wie Bohrium (implementiert Lazy Computing in NumPy) und Numba (Python-Bibliothek, JIT-Code-Compiler) teilen die übergeordneten Ziele von Weld. Und Optimierungssysteme wie Spark SQL beeinflussen das Schweißdesign direkt.

Hat Weld neben der Optimierung von Data Science-Bibliotheken noch andere Verwendungszwecke?


Einer der aufregendsten Aspekte von Weld IR ist, dass es Daten-Parallelität nativ unterstützt. Dies bedeutet, dass die Schleifenparallelisierung im Schweiß-IR immer sicher ist. Dies macht Weld IR attraktiv für neue Gerätetypen.

Beispielsweise verwendeten NEC-Mitarbeiter Weld, um Python-Workloads auf einem benutzerdefinierten Vektorprozessor mit hoher Bandbreite auszuführen und einem vorhandenen Weld-IR einfach ein neues Backend hinzuzufügen.

IR kann auch verwendet werden, um eine Schicht physischer Operationen in einer Datenbank zu implementieren. Wir planen, Funktionen hinzuzufügen, mit denen wir auch eine Teilmenge von Python in Weld-Code kompilieren können.

Sind Bibliotheken für den Einsatz in realen Projekten bereit? Und wenn nicht, wann können Sie mit einem Endergebnis rechnen?


Viele der Beispiele und Benchmarks, an denen wir diese Bibliotheken getestet haben, stammen aus der tatsächlichen Arbeitslast. Daher möchten wir, dass Benutzer die aktuelle Version in ihren Anwendungen ausprobieren und ihr Feedback hinterlassen. Und das Beste war, dass sie ihre eigenen Patches vorgeschlagen haben.

Im Allgemeinen kann derzeit nicht gesagt werden, dass in realen Anwendungen alles sofort funktioniert.

Unsere nächsten Releases in den nächsten Monaten werden sich ausschließlich auf die Benutzerfreundlichkeit und Zuverlässigkeit von Python-Bibliotheken konzentrieren. Unser Ziel ist es, Bibliotheken so gut zu machen, dass sie in reale Projekte einbezogen werden können. Und auch die Möglichkeit, Nicht-Weld-Bibliotheksversionen an Orten zu verwenden, an denen noch keine Unterstützung hinzugefügt wurde.

Wie ich in der ersten Frage festgestellt habe, sollte das Split-Annotations-Projekt ( Quellcode und akademischer Artikel ) diesen Übergang vereinfachen.

Geteilte Annotationen ist ein System, mit dem Sie dem vorhandenen Code Annotationen hinzufügen können, um zu bestimmen, wie dieser geteilt, transformiert und parallelisiert werden soll. Es bietet die Optimierung, die wir in Weld für am effektivsten halten (Speichern von Datenblöcken in CPU-Caches zwischen Funktionsaufrufen, anstatt den gesamten Datensatz zu scannen). Split-Annotationen sind jedoch viel einfacher zu integrieren als Weld, da sie vorhandenen Bibliothekscode verwenden, ohne sich auf den IR-Compiler zu verlassen. Es erleichtert auch die Wartung und das Debuggen, was wiederum die Zuverlässigkeit verbessert.

Bibliotheken, die noch keine vollständige Schweißunterstützung bieten, können geteilte Anmerkungen verwenden. Auf diese Weise können wir die Schweißunterstützung basierend auf dem Feedback der Benutzer schrittweise hinzufügen und gleichzeitig neue Optimierungen einbeziehen.

All Articles