12.1. Array API-Unterstützung (experimentell)#

Die Array API-Spezifikation definiert eine Standard-API für alle Array-Manipulationsbibliotheken mit einer NumPy-ähnlichen API. Scikit-learn verwendet angeheftete Kopien von array-api-compat und array-api-extra.

Die Unterstützung von Scikit-learn für den Array API-Standard erfordert, dass die Umgebungsvariable SCIPY_ARRAY_API vor dem Import von scipy und scikit-learn auf 1 gesetzt wird.

export SCIPY_ARRAY_API=1

Bitte beachten Sie, dass diese Umgebungsvariable für den temporären Gebrauch bestimmt ist. Weitere Details finden Sie in der Array API-Dokumentation von SciPy.

Einige Scikit-learn-Schätzer, die sich hauptsächlich auf NumPy (im Gegensatz zur Verwendung von Cython) verlassen, um die algorithmische Logik ihrer Methoden fit, predict oder transform zu implementieren, können so konfiguriert werden, dass sie beliebige Array API-kompatible Eingabedatenstrukturen akzeptieren und Operationen automatisch an den zugrunde liegenden Namespace weiterleiten, anstatt sich auf NumPy zu verlassen.

Zu diesem Zeitpunkt wird diese Unterstützung als experimentell betrachtet und muss explizit über die Konfiguration array_api_dispatch aktiviert werden. Details finden Sie weiter unten.

Hinweis

Derzeit sind nur array-api-strict, cupy und PyTorch dafür bekannt, mit Scikit-learn-Schätzern zu funktionieren.

Das folgende Video bietet einen Überblick über die Designprinzipien des Standards und wie er die Interoperabilität zwischen Array-Bibliotheken erleichtert.

12.1.1. Aktivieren der Array API-Unterstützung#

Die Konfiguration array_api_dispatch=True muss auf True gesetzt werden, um die Array API-Unterstützung zu aktivieren. Wir empfehlen, diese Konfiguration global zu setzen, um ein konsistentes Verhalten zu gewährleisten und eine versehentliche Vermischung von Array-Namespaces zu verhindern. Beachten Sie, dass wir in den folgenden Beispielen einen Context Manager (config_context) verwenden, um nicht jedes Code-Snippet mit False zurücksetzen zu müssen und somit den Rest der Dokumentation nicht zu beeinflussen.

Scikit-learn akzeptiert array-like Eingaben für alle metrics und einige Schätzer. Wenn array_api_dispatch=False ist, werden diese Eingaben mithilfe von numpy.asarray (oder numpy.array) in NumPy-Arrays konvertiert. Dies konvertiert zwar einige Array API-Eingaben erfolgreich (z. B. JAX-Arrays), aber wir empfehlen generell, array_api_dispatch=True zu setzen, wenn Array API-Eingaben verwendet werden. Dies liegt daran, dass NumPy-Konvertierungen oft fehlschlagen können, z. B. bei auf der GPU zugewiesenen Torch-Tensoren.

12.1.2. Beispielhafte Verwendung#

Der folgende Beispielcode zeigt, wie CuPy verwendet wird, um LinearDiscriminantAnalysis auf einer GPU auszuführen.

>>> from sklearn.datasets import make_classification
>>> from sklearn import config_context
>>> from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
>>> import cupy

>>> X_np, y_np = make_classification(random_state=0)
>>> X_cu = cupy.asarray(X_np)
>>> y_cu = cupy.asarray(y_np)
>>> X_cu.device
<CUDA Device 0>

>>> with config_context(array_api_dispatch=True):
...     lda = LinearDiscriminantAnalysis()
...     X_trans = lda.fit_transform(X_cu, y_cu)
>>> X_trans.device
<CUDA Device 0>

Nachdem das Modell trainiert wurde, sind die gefitteten Attribute, die Arrays sind, ebenfalls aus demselben Array API-Namespace wie die Trainingsdaten. Wenn beispielsweise der Array API-Namespace von CuPy für das Training verwendet wurde, befinden sich die gefitteten Attribute auf der GPU. Wir stellen ein experimentelles Hilfsprogramm _estimator_with_converted_arrays zur Verfügung, das die Attribute eines Schätzers von Array API in ein ndarray überträgt.

>>> from sklearn.utils._array_api import _estimator_with_converted_arrays
>>> cupy_to_ndarray = lambda array : array.get()
>>> lda_np = _estimator_with_converted_arrays(lda, cupy_to_ndarray)
>>> X_trans = lda_np.transform(X_np)
>>> type(X_trans)
<class 'numpy.ndarray'>

12.1.2.1. PyTorch-Unterstützung#

PyTorch-Tensoren können ebenfalls direkt übergeben werden.

>>> import torch
>>> X_torch = torch.asarray(X_np, device="cuda", dtype=torch.float32)
>>> y_torch = torch.asarray(y_np, device="cuda", dtype=torch.float32)

>>> with config_context(array_api_dispatch=True):
...     lda = LinearDiscriminantAnalysis()
...     X_trans = lda.fit_transform(X_torch, y_torch)
>>> type(X_trans)
<class 'torch.Tensor'>
>>> X_trans.device.type
'cuda'

12.1.3. Unterstützung für Array API-kompatible Eingaben#

Schätzer und andere Werkzeuge in Scikit-learn, die Array API-kompatible Eingaben unterstützen.

12.1.3.1. Schätzer#

12.1.3.2. Meta-Schätzer#

Meta-Schätzer, die Array API-Eingaben akzeptieren, unter der Bedingung, dass der Basis-Schätzer dies ebenfalls tut.

12.1.3.3. Metriken#

12.1.3.4. Werkzeuge#

Die Abdeckung wird voraussichtlich im Laufe der Zeit zunehmen. Bitte verfolgen Sie das dedizierte Meta-Issue auf GitHub, um den Fortschritt zu verfolgen.

12.1.4. Behandlung von Eingabe- und Ausgabearray-Typen#

Schätzer und Bewertungsfunktionen können Eingabearrays aus verschiedenen Array-Bibliotheken und/oder Geräten akzeptieren. Wenn ein gemischter Satz von Eingabearrays übergeben wird, konvertiert Scikit-learn die Arrays nach Bedarf, um sie alle konsistent zu machen.

Für Schätzer gilt die Regel „alles folgt X – gemischte Array-Eingaben werden so konvertiert, dass sie alle der Array-Bibliothek und dem Gerät von X entsprechen. Für Bewertungsfunktionen gilt die Regel „alles folgt y_pred – gemischte Array-Eingaben werden so konvertiert, dass sie alle der Array-Bibliothek und dem Gerät von y_pred entsprechen.

Wenn eine Funktion oder Methode mit Array API-kompatiblen Eingaben aufgerufen wurde, besteht die Konvention darin, Arrays aus derselben Array-Bibliothek und auf demselben Gerät wie die Eingabedaten zurückzugeben.

12.1.4.1. Schätzer#

Wenn ein Schätzer mit einem Array API-kompatiblen X gefittet wird, werden alle anderen Array-Eingaben, einschließlich Konstruktorargumenten (z. B. y, sample_weight), konvertiert, um der Array-Bibliothek und dem Gerät von X zu entsprechen, falls sie dies nicht bereits tun. Dieses Verhalten ermöglicht den Wechsel von der Verarbeitung auf der CPU zur Verarbeitung auf der GPU zu jedem Zeitpunkt innerhalb einer Pipeline.

Dies ermöglicht Schätzern, gemischte Eingabetypen zu akzeptieren, wodurch X innerhalb einer Pipeline auf ein anderes Gerät verschoben werden kann, ohne y explizit zu verschieben. Beachten Sie, dass Scikit-learn-Pipelines die Transformation von y nicht zulassen (um Datenlecks zu vermeiden).

Betrachten Sie zum Beispiel eine Pipeline, bei der X und y beide auf der CPU beginnen und die folgenden drei Schritte durchlaufen:

  • TargetEncoder, der kategorisches X transformiert, aber auch y benötigt, was bedeutet, dass sowohl X als auch y sich auf der CPU befinden müssen.

  • FunctionTransformer(func=partial(torch.asarray, device="cuda")), der X auf die GPU verschiebt, um die Leistung im nächsten Schritt zu verbessern.

  • Ridge, dessen Leistung durch die Übergabe von Arrays auf einer GPU verbessert werden kann, da diese große Matrixoperationen sehr effizient verarbeiten können.

X enthält zunächst kategoriale Zeichenfolgendaten (muss also auf der CPU sein), die im TargetEncoder in numerische Werte kodiert werden. X wird dann explizit auf die GPU verschoben, um die Leistung von Ridge zu verbessern. y kann nicht von der Pipeline transformiert werden (erinnern Sie sich, dass Scikit-learn-Pipelines die Transformation von y nicht zulassen), aber da Ridge gemischte Eingabetypen akzeptieren kann, ist dies kein Problem und die Pipeline kann ausgeführt werden.

Die gefitteten Attribute eines mit einem Array API-kompatiblen X gefitteten Schätzers sind Arrays aus derselben Bibliothek wie die Eingabe und werden auf demselben Gerät gespeichert. Die Methoden predict und transform erwarten anschließend Eingaben aus derselben Array-Bibliothek und demselben Gerät wie die Daten, die an die fit-Methode übergeben wurden.

12.1.4.2. Bewertungsfunktionen#

Wenn ein Array API-kompatibles y_pred an eine Bewertungsfunktion übergeben wird, werden alle anderen Array-Eingaben (z. B. y_true, sample_weight) konvertiert, um der Array-Bibliothek und dem Gerät von y_pred zu entsprechen, falls sie dies nicht bereits tun. Dies ermöglicht Bewertungsfunktionen, gemischte Eingabetypen zu akzeptieren, wodurch sie innerhalb eines Meta-Schätzers (oder einer Funktion, die Schätzer akzeptiert) mit einer Pipeline verwendet werden können, die Eingabearrays zwischen Geräten verschiebt (z. B. von CPU zu GPU).

Um beispielsweise die oben beschriebene Pipeline innerhalb von z. B. cross_validate oder GridSearchCV verwenden zu können, muss die intern aufgerufene Bewertungsfunktion gemischte Eingabetypen akzeptieren.

Der Ausgabetyp von Bewertungsfunktionen hängt von der Anzahl der Ausgabewerte ab. Wenn eine Bewertungsfunktion einen skalaren Wert zurückgibt, gibt sie einen Python-Skalar (typischerweise eine float-Instanz) anstelle eines Array-Skalars zurück. Für Bewertungsfunktionen, die Multiclass oder Multioutput unterstützen, wird ein Array aus derselben Array-Bibliothek und demselben Gerät wie y_pred zurückgegeben, wenn mehrere Werte ausgegeben werden müssen.

12.1.5. Gängige Schätzer-Prüfungen#

Fügen Sie das Tag array_api_support zur Tag-Menge eines Schätzers hinzu, um anzuzeigen, dass er die Array API unterstützt. Dies aktiviert spezielle Prüfungen als Teil der gängigen Tests, um zu überprüfen, ob die Ergebnisse der Schätzer bei Verwendung von reinem NumPy und Array API-Eingaben gleich sind.

Um diese Prüfungen durchzuführen, müssen Sie array-api-strict in Ihrer Testumgebung installieren. Dies ermöglicht Ihnen die Durchführung von Prüfungen ohne GPU. Um den vollständigen Satz von Prüfungen auszuführen, müssen Sie auch PyTorch, CuPy installieren und über eine GPU verfügen. Prüfungen, die nicht ausgeführt werden können oder fehlende Abhängigkeiten haben, werden automatisch übersprungen. Daher ist es wichtig, die Tests mit dem Flag -v auszuführen, um zu sehen, welche Prüfungen übersprungen werden.

pip install array-api-strict  # and other libraries as needed
pytest -k "array_api" -v

Die Ausführung der Scikit-learn-Tests gegen array-api-strict sollte helfen, die meisten Code-Probleme im Zusammenhang mit der Handhabung mehrerer Geräteeingaben durch die Verwendung von simulierten Nicht-CPU-Geräten aufzudecken. Dies ermöglicht eine schnelle iterative Entwicklung und Fehlersuche von Array API-bezogenem Code.

Um jedoch eine vollständige Handhabung von PyTorch- oder CuPy-Eingaben, die auf tatsächlichen GPU-Geräten zugewiesen sind, zu gewährleisten, ist es notwendig, die Tests gegen diese Bibliotheken und Hardware auszuführen. Dies kann entweder durch die Verwendung von Google Colab oder durch die Nutzung unserer CI-Infrastruktur bei Pull Requests (aus Kostengründen manuell von Maintainern ausgelöst) erreicht werden.

12.1.5.1. Hinweis zur MPS-Geräteunterstützung#

Unter macOS kann PyTorch die Metal Performance Shaders (MPS) verwenden, um auf Hardwarebeschleuniger (z. B. die interne GPU-Komponente der M1- oder M2-Chips) zuzugreifen. Die MPS-Geräteunterstützung für PyTorch ist jedoch zum Zeitpunkt der Erstellung dieses Dokuments unvollständig. Weitere Details finden Sie im folgenden GitHub-Issue:

Um die MPS-Unterstützung in PyTorch zu aktivieren, setzen Sie die Umgebungsvariable PYTORCH_ENABLE_MPS_FALLBACK=1, bevor Sie die Tests ausführen.

PYTORCH_ENABLE_MPS_FALLBACK=1 pytest -k "array_api" -v

Zum Zeitpunkt der Erstellung dieses Dokuments sollten alle Scikit-learn-Tests erfolgreich sein, jedoch ist die rechnerische Geschwindigkeit nicht unbedingt besser als bei der CPU.

12.1.5.2. Hinweis zur Geräteunterstützung für float64#

Bestimmte Operationen in Scikit-learn führen Operationen mit float64-Präzision durch, um Überläufe zu verhindern und Korrektheit zu gewährleisten (z. B. metrics.pairwise.euclidean_distances, preprocessing.StandardScaler). Bestimmte Kombinationen von Array-Namespaces und Geräten, wie z. B. PyTorch on MPS (siehe Hinweis zur MPS-Geräteunterstützung), unterstützen jedoch den Datentyp float64 nicht. In diesen Fällen wird Scikit-learn stattdessen auf die Verwendung des Datentyps float32 zurückgreifen. Dies kann zu einem anderen Verhalten führen (typischerweise numerisch instabile Ergebnisse) im Vergleich zur Nichtverwendung von Array API-Dispatching oder zur Verwendung eines Geräts mit float64-Unterstützung.