Ist die Zukunft der python numerischen Berechnung?
Ende letzten Jahres machte Nvidia eine bedeutende Ankündigung über die Zukunft des pythonbasierten numerischen Computing. Ich wäre nicht überrascht, wenn du es verpasst hast. Immerhin scheint jede andere Ankündigung von jeder KI-Firma damals und heute Mega-entscheidend zu sein.
Diese Ankündigung führte die vor Cunumeric BibliothekAnwesend Ein Drop-In-Ersatz für die allgegenwärtige Numpy-Bibliothek, die oben auf dem gebaut wurde Legat Rahmen.
Wer sind Nvidia?
Die meisten Menschen werden Nvidia wahrscheinlich aus ihren ultraschnellen Chips kennen, die Laptop und Rechenzentren auf der ganzen Welt betreiben. Möglicherweise sind Sie auch mit Nvidias charismatischem, Lederjacke-liebender CEO Jensen Huang vertraut, der heutzutage auf der Bühne jeder KI-Konferenz auftaucht.
Was viele Menschen nicht wissen, ist, dass Nvidia auch progressive Gerätearchitekturen und zugehörige Software program entwirft und schafft. Eines der wertvollsten Produkte ist die Berechnen Sie einheitliche Gerätearchitektur (CUDA). CUDA ist die proprietäre parallel-Computerplattform und das Programmiermodell von Nvidia. Seit seiner Einführung im Jahr 2007 hat es sich zu einem umfassenden Ökosystem entwickelt, das Treiber, Laufzeit, Compiler, mathematische Bibliotheken, Debugging- und Profilerierungswerkzeuge und Containerbilder umfasst. Das Ergebnis ist eine ordentlich abgestimmte {Hardware}- und Software program-Schleife, die den NVIDIA-GPUs im Zentrum der modernen Hochleistungs- und KI-Workloads im Zentrum hält.
Was ist Legat?
Legate ist eine von Nvidia geführte Open-Supply-Laufzeitschicht, mit der Sie vertraute Python-Daten-Science-Bibliotheken (Numpy, Cunumeric, Pandas-APIs, spärliche lineare Algebra-Kernel,…) auf Multi-Core-CPUs, einzelne oder multi-gpu-Nodes und sogar Multi-Nod-Cluster durchführen können. Es übersetzt hochrangige Array-Operationen in ein Diagramm von feinkörnigen Aufgaben und Händen, die zum C ++ drapieren Legion Die Laufzeit, die die Aufgaben plant, die Daten verteilt und Kacheln zwischen CPUs, GPUs und Netzwerkverbindungen für Sie bewegt.
Kurz gesagt, Legate lässt die bekannten Python-Bibliotheken mit einzelnen Knoten clear auf Multi-GPU-Multi-Knoten-Maschinen skalieren.
Was ist Cunumeric?
Cunumeric ist ein Drop-In-Ersatz für Numpy, dessen Array-Operationen von Legates Activity Engine ausgeführt und auf einem oder vielen NVIDIA-GPUs beschleunigt werden (oder, wenn keine GPU vorhanden ist, in allen CPU-Kernen). In der Praxis installieren Sie es und müssen nur eine Importlinie ändern, um sie anstelle Ihres regulären Numpy -Code zu verwenden. Zum Beispiel …
# previous
import numpy as np
...
...
# new
import cupynumeric as np # the whole lot else stays the identical
...
...
… Und führen Sie Ihr Skript mit dem Befehl Legat auf dem Terminal aus.
Hinter den Kulissen konvertiert Cunumeric jeden Numpy -Anruf Sie beispielsweise NP.Sin, Np.Linalg.svd, Fancy Indexing, Rundfunk, Reduzierung usw. in Legataufgaben. Diese Aufgaben werden,
- Trennwand Ihre Arrays in Kacheln, die sich für den GPU -Speicher anpassen.
- Zeitplan Jede Kachel auf dem besten verfügbaren Gerät (GPU oder CPU).
- Überlappen Berechnen Sie mit Kommunikation, wenn die Workload mehrere GPUs oder Knoten umfasst.
- Verschütten Kacheln zu NVME/SSD automatisch, wenn Ihr Datensatz den GPU -RAM übernimmt.
Da die API von Cunumeric Numpys quick 1-für-1 spiegelt, kann der vorhandene wissenschaftliche oder datenwissenschaftliche Code von einem Laptop computer zu einem Multi-GPU-Cluster ohne Umschreiben skalieren.
Leistungsvorteile
Additionally, das alles scheint großartig, oder? Es ist jedoch nur sinnvoll, wenn es zu konkreten Leistungsverbesserungen gegenüber Numpy führt, und Nvidia macht einige starke Behauptungen, dass dies der Fall ist. Als Datenwissenschaftler, Ingenieure und Dateningenieure für maschinelles Lernen verwenden wir in der Regel viel Numpy, und wir können zu schätzen wissen, dass dies ein entscheidender Aspekt der von uns geschriebenen und aufrechterhaltenen Systeme sein kann.
Jetzt habe ich keine Gruppe von GPUs oder Supercomputer zum Testen, aber mein Desktop -PC verfügt über eine NVIDIA Geforce RTX 4070 GPU, und wir werden das verwenden, um einige der Ansprüche von Nvidia zu testen.
(base) tom@tpr-desktop:~$ nvidia-smi
Solar Jun 15 15:26:36 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 565.75 Driver Model: 566.24 CUDA Model: 12.7 |
|-----------------------------------------+------------------------+----------------------+
| GPU Title Persistence-M | Bus-Id Disp.A | Unstable Uncorr. ECC |
| Fan Temp Perf Pwr:Utilization/Cap | Reminiscence-Utilization | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA GeForce RTX 4070 Ti On | 00000000:01:00.0 On | N/A |
| 32% 29C P8 9W / 285W | 1345MiB / 12282MiB | 2% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Sort Course of identify GPU Reminiscence |
| ID ID Utilization |
|=========================================================================================|
| No operating processes discovered |
+-----------------------------------------------------------------------------------------+
Ich werde Cunumeric und Numpy auf meinem PC installieren, um Vergleichstests durchzuführen. Dies wird uns helfen, zu beurteilen, ob die Behauptungen von NVIDIA korrekt sind und die Leistungsunterschiede zwischen den beiden Bibliotheken verstehen.
Einrichtung einer Entwicklungsumgebung.
Wie immer greife ich gerne eine separate Entwicklungsumgebung ein, um meine Assessments durchzuführen. Auf diese Weise wird nichts, was ich in dieser Umgebung tue, eines meiner anderen Projekte beeinflusst. Zum Zeitpunkt des Schreibens ist Cunumeric nicht verfügbar, um unter Home windows zu installieren, daher werde ich stattdessen WSL2 Ubuntu für Home windows verwenden.
Ich werde Miniconda verwenden, um meine Umgebung einzurichten, aber ich kann gerne jedes Werkzeug verwenden, mit dem Sie sich wohl fühlen.
$ conda create cunumeric-env python=3.10 -c conda-forge
$ conda activate cunumeric-env
$ conda set up -c conda-forge -c legate cupynumeric
$ conda set up -c conda-forge ucx cuda-cudart cuda-version=12
Code Beispiel 1 – Eine einfache Matrixmultiplikation
Die Matrix -Multiplikation ist das Brot und die Butter von mathematischen Operationen, die so viele AI -Systeme untermauern. Daher ist es sinnvoll, diesen Vorgang zuerst auszuprobieren.
Beachten Sie, dass ich in all meinen Beispielen fünfmal in Folge die Numpy- und Cunumeric -Code -Snippets ausführen werde und die für jeweils benötigte Zeit durchschnittlich. Ich führe auch einen „Aufwärmschritt in der GPU vor, bevor der Timing ausgeführt wird, um Gemeinkosten wie Simply-in-Time (JIT) -Kompilation zu berücksichtigen.
import time
import gc
import argparse
import sys
def benchmark_numpy(n, runs):
"""Runs the matrix multiplication benchmark utilizing commonplace NumPy on the CPU."""
import numpy as np
print(f"--- NumPy (CPU) Benchmark ---")
print(f"Multiplying two {n}×{n} matrices ({runs} runs)n")
# 1. Generate knowledge ONCE earlier than the timing loop.
print(f"Producing two {n}x{n} random matrices on CPU...")
A = np.random.rand(n, n).astype(np.float32)
B = np.random.rand(n, n).astype(np.float32)
# 2. Carry out one untimed warm-up run.
print("Performing warm-up run...")
_ = np.matmul(A, B)
print("Heat-up full.n")
# 3. Carry out the timed runs.
instances = ()
for i in vary(runs):
begin = time.time()
# The operation being timed. The @ operator is a handy
# shorthand for np.matmul.
C = A @ B
finish = time.time()
period = finish - begin
instances.append(period)
print(f"Run {i+1}: time = {period:.4f}s")
del C # Clear up the outcome matrix
gc.acquire()
avg = sum(instances) / len(instances)
print(f"nNumPy common: {avg:.4f}sn")
return avg
def benchmark_cunumeric(n, runs):
"""Runs the matrix multiplication benchmark utilizing cuNumeric on the GPU."""
import cupynumeric as cn
import numpy as np # Import numpy for the canonical sync
print(f"--- cuNumeric (GPU) Benchmark ---")
print(f"Multiplying two {n}×{n} matrices ({runs} runs)n")
# 1. Generate knowledge ONCE on the GPU earlier than the timing loop.
print(f"Producing two {n}x{n} random matrices on GPU...")
A = cn.random.rand(n, n).astype(np.float32)
B = cn.random.rand(n, n).astype(np.float32)
# 2. Carry out a vital untimed warm-up run for JIT compilation.
print("Performing warm-up run...")
C_warmup = cn.matmul(A, B)
# One of the best apply for synchronization: power a replica again to the CPU.
_ = np.array(C_warmup)
print("Heat-up full.n")
# 3. Carry out the timed runs.
instances = ()
for i in vary(runs):
begin = time.time()
# Launch the operation on the GPU
C = A @ B
# Synchronize by changing the outcome to a host-side NumPy array.
np.array(C)
finish = time.time()
period = finish - begin
instances.append(period)
print(f"Run {i+1}: time = {period:.4f}s")
del C
gc.acquire()
avg = sum(instances) / len(instances)
print(f"ncuNumeric common: {avg:.4f}sn")
return avg
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Benchmark matrix multiplication on NumPy (CPU) vs. cuNumeric (GPU)."
)
parser.add_argument(
"-n", "--n", kind=int, default=3000, assist="Matrix dimension (n x n)"
)
parser.add_argument(
"-r", "--runs", kind=int, default=5, assist="Variety of timing runs"
)
parser.add_argument(
"--cunumeric", motion="store_true", assist="Run the cuNumeric (GPU) model"
)
args, unknown = parser.parse_known_args()
# The dispatcher logic
if args.cunumeric or "--cunumeric" in unknown:
benchmark_cunumeric(args.n, args.runs)
else:
benchmark_numpy(args.n, args.runs)
Das Ausführen der numpy Seite der Dinge verwendet die reguläre Python Beispiel1.py Befehlszeilensyntax. Für das Laufen mit Legat ist die Syntax komplexer. Die automatische Konfiguration von Legat von Legaten deaktiviert und starten Sie dann das Skript von Beispiel1.PY unter Legat mit einer CPU-, einer GPU- und Null -OpenMP -Threads mit dem Cunumeric Backend.
Hier ist die Ausgabe.
(cunumeric-env) tom@tpr-desktop:~$ python example1.py
--- NumPy (CPU) Benchmark ---
Multiplying two 3000×3000 matrices (5 runs)
Producing two 3000x3000 random matrices on CPU...
Performing warm-up run...
Heat-up full.
Run 1: time = 0.0976s
Run 2: time = 0.0987s
Run 3: time = 0.0957s
Run 4: time = 0.1063s
Run 5: time = 0.0989s
NumPy common: 0.0994s
(cunumeric-env) tom@tpr-desktop:~$ LEGATE_AUTO_CONFIG=0 legate --cpus 1 --gpus 1 --omps 0 example1.py --cunu
meric
(0 - 7f2e8fcc8480) 0.000000 {5}{module_config}: Module numa can't detect assets.
(0 - 7f2e8fcc8480) 0.000000 {4}{topology}: cannot open /sys/units/system/node/
(0 - 7f2e8fcc8480) 0.000049 {4}{threads}: reservation ('GPU ctxsync 0x55cd5fd34530') can't be happy
--- cuNumeric (GPU) Benchmark ---
Multiplying two 3000×3000 matrices (5 runs)
Producing two 3000x3000 random matrices on GPU...
Performing warm-up run...
Heat-up full.
Run 1: time = 0.0113s
Run 2: time = 0.0089s
Run 3: time = 0.0086s
Run 4: time = 0.0090s
Run 5: time = 0.0087s
cuNumeric common: 0.0093s
Nun, das ist ein beeindruckender Anfang. Cunumeric registriert eine 10 -fache Beschleunigung über Numpy.
Die Warnungen, die Legat ausgibt, können ignoriert werden. Diese sind informativ und zeigen, dass Legate keine Particulars über das CPU/Speicherlayout (NUMA) der Maschine oder genügend CPU -Kerne für die Verwaltung der GPU finden konnten.
Code Beispiel 2 – Logistische Regression
Die logistische Regression ist ein grundlegendes Instrument in der Datenwissenschaft, da sie eine einfache, interpretierbare Methode zum Modellieren und Vorhersagen binärer Ergebnisse bietet (Ja/Nein, Cross/Fail, Klicken/No-Click on). In diesem Beispiel werden wir messen, wie lange es dauert, einen einfachen binären Klassifikator für synthetische Daten zu trainieren. Für jeden der fünf Läufe erzeugt es zuerst N Proben mit D Merkmale (x) und ein entsprechender zufälliger 0/1 Label -Vektor (Y). Es initialisiert den Gewichtsvektor w zu Nullen und dann durchführen 500 Iterationen des Batch -Gradientenabstiegs: Berechnung der linearen Vorhersagen z = x.dot (w)das Sigmoid anwenden p = 1/(1+exp (-z))den Gradienten berechnen Grad = xtdot (p – y) / nund aktualisieren die Gewichte mit W -= 0,1 * Grad. Das Skript zeichnet die verstrichene Zeit für jeden Lauf auf, säubert den Speicher und druckt schließlich die durchschnittliche Trainingszeit.
import time
import gc
import argparse
import sys
# --- Reusable Coaching Operate ---
# By placing the coaching loop in its personal perform, we keep away from code duplication.
# The `np` argument permits us to move in both the numpy or cupynumeric module.
def train_logistic_regression(np, X, y, iters, alpha):
"""Performs a set variety of gradient descent iterations."""
# Guarantee w begins on the proper gadget (CPU or GPU)
w = np.zeros(X.form(1))
for _ in vary(iters):
z = X.dot(w)
p = 1.0 / (1.0 + np.exp(-z))
grad = X.T.dot(p - y) / X.form(0)
w -= alpha * grad
return w
def benchmark_numpy(n_samples, n_features, iters, alpha):
"""Runs the logistic regression benchmark utilizing commonplace NumPy on the CPU."""
import numpy as np
print(f"--- NumPy (CPU) Benchmark ---")
print(f"Coaching on {n_samples} samples, {n_features} options for {iters} iterationsn")
# 1. Generate knowledge ONCE earlier than the timing loop.
print("Producing random dataset on CPU...")
X = np.random.rand(n_samples, n_features)
y = (np.random.rand(n_samples) > 0.5).astype(np.float64)
# 2. Carry out one untimed warm-up run.
print("Performing warm-up run...")
_ = train_logistic_regression(np, X, y, iters, alpha)
print("Heat-up full.n")
# 3. Carry out the timed runs.
instances = ()
for i in vary(args.runs):
begin = time.time()
# The operation being timed
_ = train_logistic_regression(np, X, y, iters, alpha)
finish = time.time()
period = finish - begin
instances.append(period)
print(f"Run {i+1}: time = {period:.3f}s")
gc.acquire()
avg = sum(instances) / len(instances)
print(f"nNumPy common: {avg:.3f}sn")
return avg
def benchmark_cunumeric(n_samples, n_features, iters, alpha):
"""Runs the logistic regression benchmark utilizing cuNumeric on the GPU."""
import cupynumeric as cn
import numpy as np # Additionally import numpy for the canonical synchronization
print(f"--- cuNumeric (GPU) Benchmark ---")
print(f"Coaching on {n_samples} samples, {n_features} options for {iters} iterationsn")
# 1. Generate knowledge ONCE on the GPU earlier than the timing loop.
print("Producing random dataset on GPU...")
X = cn.random.rand(n_samples, n_features)
y = (cn.random.rand(n_samples) > 0.5).astype(np.float64)
# 2. Carry out a vital untimed warm-up run for JIT compilation.
print("Performing warm-up run...")
w_warmup = train_logistic_regression(cn, X, y, iters, alpha)
# One of the best apply for synchronization: power a replica again to the CPU.
_ = np.array(w_warmup)
print("Heat-up full.n")
# 3. Carry out the timed runs.
instances = ()
for i in vary(args.runs):
begin = time.time()
# Launch the operation on the GPU
w = train_logistic_regression(cn, X, y, iters, alpha)
# Synchronize by changing the ultimate outcome again to a NumPy array.
np.array(w)
finish = time.time()
period = finish - begin
instances.append(period)
print(f"Run {i+1}: time = {period:.3f}s")
del w
gc.acquire()
avg = sum(instances) / len(instances)
print(f"ncuNumeric common: {avg:.3f}sn")
return avg
if __name__ == "__main__":
# A extra sturdy argument parsing setup
parser = argparse.ArgumentParser(
description="Benchmark logistic regression on NumPy (CPU) vs. cuNumeric (GPU)."
)
# Hyperparameters for the mannequin
parser.add_argument(
"-n", "--n_samples", kind=int, default=2_000_000, assist="Variety of knowledge samples"
)
parser.add_argument(
"-d", "--n_features", kind=int, default=10, assist="Variety of options"
)
parser.add_argument(
"-i", "--iters", kind=int, default=500, assist="Variety of gradient descent iterations"
)
parser.add_argument(
"-a", "--alpha", kind=float, default=0.1, assist="Studying price"
)
# Benchmark management
parser.add_argument(
"-r", "--runs", kind=int, default=5, assist="Variety of timing runs"
)
parser.add_argument(
"--cunumeric", motion="store_true", assist="Run the cuNumeric (GPU) model"
)
args, unknown = parser.parse_known_args()
# Dispatcher logic
if args.cunumeric or "--cunumeric" in unknown:
benchmark_cunumeric(args.n_samples, args.n_features, args.iters, args.alpha)
else:
benchmark_numpy(args.n_samples, args.n_features, args.iters, args.alpha)
Und die Ausgänge.
(cunumeric-env) tom@tpr-desktop:~$ python example2.py
--- NumPy (CPU) Benchmark ---
Coaching on 2000000 samples, 10 options for 500 iterations
Producing random dataset on CPU...
Performing warm-up run...
Heat-up full.
Run 1: time = 12.292s
Run 2: time = 11.830s
Run 3: time = 11.903s
Run 4: time = 12.843s
Run 5: time = 11.964s
NumPy common: 12.166s
(cunumeric-env) tom@tpr-desktop:~$ LEGATE_AUTO_CONFIG=0 legate --cpus 1 --gpus 1 --omps 0 example2.py --cunu
meric
(0 - 7f04b535c480) 0.000000 {5}{module_config}: Module numa can't detect assets.
(0 - 7f04b535c480) 0.000000 {4}{topology}: cannot open /sys/units/system/node/
(0 - 7f04b535c480) 0.001149 {4}{threads}: reservation ('GPU ctxsync 0x55fb037cf140') can't be happy
--- cuNumeric (GPU) Benchmark ---
Coaching on 2000000 samples, 10 options for 500 iterations
Producing random dataset on GPU...
Performing warm-up run...
Heat-up full.
Run 1: time = 1.964s
Run 2: time = 1.957s
Run 3: time = 1.968s
Run 4: time = 1.955s
Run 5: time = 1.960s
cuNumeric common: 1.961s
Nicht ganz so beeindruckend wie unser erstes Beispiel, aber ein 5 -fach -bis -6 -fach -Geschwindigkeitsmesser eines bereits schnellen Numpy -Programms ist nicht zu schnüffeln.
Code Beispiel 3 – Lösung linearer Gleichungen
Dieses Skript unterteilt, wie lange es dauert, um ein dichtes 3000 × 3000 linearer Algebra -Gleichungssystem zu lösen. Dies ist ein grundlegender Betrieb in der linearen Algebra, die zur Lösung der Typgleichung verwendet wird Ax = b, Wo A ist ein riesiges Zahlenraster (in diesem Fall eine 3000 × 3000 -Matrix), und B ist eine Liste von Zahlen (ein Vektor).
Ziel ist es, die unbekannte Liste der Zahlen X zu finden, die die Gleichung wahr macht. Dies ist eine rechenintensive Aufgabe, die im Mittelpunkt vieler wissenschaftlicher Simulationen, technischer Probleme, Finanzmodelle und sogar einiger AI -Algorithmen steht.
import time
import gc
import argparse
import sys # Import sys to verify arguments
# Observe: The library imports (numpy and cupynumeric) are actually achieved *inside*
# their respective capabilities to maintain them separate and keep away from import errors.
def benchmark_numpy(n, runs):
"""Runs the linear clear up benchmark utilizing commonplace NumPy on the CPU."""
import numpy as np
print(f"--- NumPy (CPU) Benchmark ---")
print(f"Fixing {n}×{n} A x = b ({runs} runs)n")
# 1. Generate knowledge ONCE earlier than the timing loop.
print("Producing random system on CPU...")
A = np.random.randn(n, n).astype(np.float32)
b = np.random.randn(n).astype(np.float32)
# 2. Carry out one untimed warm-up run. That is good apply even for
# the CPU to make sure caches are heat and any one-time setup is completed.
print("Performing warm-up run...")
_ = np.linalg.clear up(A, b)
print("Heat-up full.n")
# 3. Carry out the timed runs.
instances = ()
for i in vary(runs):
begin = time.time()
# The operation being timed
x = np.linalg.clear up(A, b)
finish = time.time()
period = finish - begin
instances.append(period)
print(f"Run {i+1}: time = {period:.6f}s")
# Clear up the outcome to be protected with reminiscence
del x
gc.acquire()
avg = sum(instances) / len(instances)
print(f"nNumPy common: {avg:.6f}sn")
return avg
def benchmark_cunumeric(n, runs):
"""Runs the linear clear up benchmark utilizing cuNumeric on the GPU."""
import cupynumeric as cn
import numpy as np # Additionally import numpy for the canonical synchronization
print(f"--- cuNumeric (GPU) Benchmark ---")
print(f"Fixing {n}×{n} A x = b ({runs} runs)n")
# 1. Generate knowledge ONCE on the GPU earlier than the timing loop.
# This ensures we're not timing the information switch in our essential loop.
print("Producing random system on GPU...")
A = cn.random.randn(n, n).astype(np.float32)
b = cn.random.randn(n).astype(np.float32)
# 2. Carry out a vital untimed warm-up run. This handles JIT
# compilation and different one-time GPU setup prices.
print("Performing warm-up run...")
x_warmup = cn.linalg.clear up(A, b)
# One of the best apply for synchronization: power a replica again to the CPU.
_ = np.array(x_warmup)
print("Heat-up full.n")
# 3. Carry out the timed runs.
instances = ()
for i in vary(runs):
begin = time.time()
# Launch the operation on the GPU
x = cn.linalg.clear up(A, b)
# Synchronize by changing the outcome to a host-side NumPy array.
# That is assured to dam till the GPU has completed.
np.array(x)
finish = time.time()
period = finish - begin
instances.append(period)
print(f"Run {i+1}: time = {period:.6f}s")
# Clear up the GPU array outcome
del x
gc.acquire()
avg = sum(instances) / len(instances)
print(f"ncuNumeric common: {avg:.6f}sn")
return avg
if __name__ == "__main__":
# A extra sturdy argument parsing setup
parser = argparse.ArgumentParser(
description="Benchmark linear clear up on NumPy (CPU) vs. cuNumeric (GPU)."
)
parser.add_argument(
"-n", "--n", kind=int, default=3000, assist="Matrix dimension (n x n)"
)
parser.add_argument(
"-r", "--runs", kind=int, default=5, assist="Variety of timing runs"
)
# Use parse_known_args() to deal with potential further arguments from Legate
args, unknown = parser.parse_known_args()
# The dispatcher logic: verify if "--cunumeric" is within the command line
# This can be a easy and efficient strategy to change between modes.
if "--cunumeric" in sys.argv or "--cunumeric" in unknown:
benchmark_cunumeric(args.n, args.runs)
else:
benchmark_numpy(args.n, args.runs)
Die Ausgänge.
(cunumeric-env) tom@tpr-desktop:~$ python example4.py
--- NumPy (CPU) Benchmark ---
Fixing 3000×3000 A x = b (5 runs)
Producing random system on CPU...
Performing warm-up run...
Heat-up full.
Run 1: time = 0.133075s
Run 2: time = 0.126129s
Run 3: time = 0.135849s
Run 4: time = 0.137383s
Run 5: time = 0.138805s
NumPy common: 0.134248s
(cunumeric-env) tom@tpr-desktop:~$ LEGATE_AUTO_CONFIG=0 legate --cpus 1 --gpus 1 --omps 0 example4.py --cunumeric
(0 - 7f29f42ce480) 0.000000 {5}{module_config}: Module numa can't detect assets.
(0 - 7f29f42ce480) 0.000000 {4}{topology}: cannot open /sys/units/system/node/
(0 - 7f29f42ce480) 0.000053 {4}{threads}: reservation ('GPU ctxsync 0x562e88c28700') can't be happy
--- cuNumeric (GPU) Benchmark ---
Fixing 3000×3000 A x = b (5 runs)
Producing random system on GPU...
Performing warm-up run...
Heat-up full.
Run 1: time = 0.009685s
Run 2: time = 0.010043s
Run 3: time = 0.009966s
Run 4: time = 0.009739s
Run 5: time = 0.009383s
cuNumeric common: 0.009763s
Das ist ein enormes Ergebnis. Der Nvidia Cunumeric Run ist 100x schneller als der Numpy -Lauf.
Code Beispiel 4 – Sortieren
Sortierung ist ein so grundlegender Teil von allem, was beim Laptop passiert, und moderne Laptop sind so schnell, dass die meisten Entwickler nicht einmal darüber nachdenken. Aber lassen Sie uns sehen, wie viel Unterschied mit Cunumeric für diesen allgegenwärtigen Operation eingesetzt werden kann. Wir werden eine große (30.000.000) 1D -Array von Zahlen sortieren
# benchmark_sort.py
import time
import sys
import gc
# Array dimension
n = 30_000_000 # 30 million parts
def benchmark_numpy():
import numpy as np
print(f"Sorting an array of {n} parts with NumPy (5 runs)n")
instances = ()
for i in vary(5):
knowledge = np.random.randn(n).astype(np.float32)
begin = time.time()
_ = np.type(knowledge)
finish = time.time()
period = finish - begin
instances.append(period)
print(f"Run {i+1}: time = {period:.6f}s")
del knowledge
gc.acquire()
avg = sum(instances) / len(instances)
print(f"nNumPy common: {avg:.6f}sn")
def benchmark_cunumeric():
import cupynumeric as np
print(f"Sorting an array of {n} parts with cuNumeric (5 runs)n")
instances = ()
for i in vary(5):
knowledge = np.random.randn(n).astype(np.float32)
begin = time.time()
_ = np.type(knowledge)
# Pressure GPU sync
_ = np.linalg.norm(np.zeros(()))
finish = time.time()
period = finish - begin
instances.append(period)
print(f"Run {i+1}: time = {period:.6f}s")
del knowledge
gc.acquire()
_ = np.linalg.norm(np.zeros(()))
avg = sum(instances) / len(instances)
print(f"ncuNumeric common: {avg:.6f}sn")
if __name__ == "__main__":
if "--cunumeric" in sys.argv:
benchmark_cunumeric()
else:
benchmark_numpy()
Die Ausgänge.
(cunumeric-env) tom@tpr-desktop:~$ python example5.py
--- NumPy (CPU) Benchmark ---
Sorting an array of 30000000 parts (5 runs)
Creating random array on CPU...
Performing warm-up run...
Heat-up full.
Run 1: time = 0.588777s
Run 2: time = 0.586813s
Run 3: time = 0.586745s
Run 4: time = 0.586525s
Run 5: time = 0.583783s
NumPy common: 0.586529s
-----------------------------
(cunumeric-env) tom@tpr-desktop:~$ LEGATE_AUTO_CONFIG=0 legate --cpus 1 --gpus 1 --omps 0 example5.py --cunumeric
(0 - 7fd9e4615480) 0.000000 {5}{module_config}: Module numa can't detect assets.
(0 - 7fd9e4615480) 0.000000 {4}{topology}: cannot open /sys/units/system/node/
(0 - 7fd9e4615480) 0.000082 {4}{threads}: reservation ('GPU ctxsync 0x564489232fd0') can't be happy
--- cuNumeric (GPU) Benchmark ---
Sorting an array of 30000000 parts (5 runs)
Creating random array on GPU...
Performing warm-up run...
Heat-up full.
Run 1: time = 0.010857s
Run 2: time = 0.007927s
Run 3: time = 0.007921s
Run 4: time = 0.008240s
Run 5: time = 0.007810s
cuNumeric common: 0.008551s
-------------------------------
Noch eine äußerst beeindruckende Leistung von Cunumeric und Legate.
Zusammenfassung
Dieser Artikel wurde eingeführt Cunumericeine Nvidia-Bibliothek als Hochleistungs Drop-In Ersatz für Numpy. Das wichtigste Mitnehmen ist, dass Datenwissenschaftler ihren vorhandenen Python -Code zu NVIDIA -GPUs mit minimalem Aufwand beschleunigen können, häufig durch einfaches Ändern einer einzelnen Importlinie und das Ausführen des Skripts mit dem ‚Legat‘ Befehl.
Zwei Hauptkomponenten führen die Technologie mit:
- Legat: Eine Open-Supply-Laufzeitschicht von Nvidia, die automatisch hochrangige Python-Operationen in Aufgaben übersetzt. Es verwaltet clever verwaltet, diese Aufgaben über einzelne oder mehrere GPUs zu verteilen, Datenpartitionierung, Speicherverwaltung (bei Bedarf sogar auf Festplatten zu verschütten) und die Kommunikation optimieren.
- Cunumeric: Die benutzergerichtete Bibliothek, die die Numpy-API widerspiegelt. Wenn Sie einen Anruf wie np.matmul () tätigen, wandelt Cunumeric ihn in eine Aufgabe um, damit die Legate -Engine auf der GPU ausgeführt werden kann.
Ich konnte die Leistungsansprüche von NVIDIA validieren, indem ich vier Benchmark -Assessments auf meinem Desktop -PC (mit einem NVIDIA RTX 4070 TI GPU) durchführte, in dem Normal -Numpy auf der CPU gegen Cunumeric an der GPU verwiesen wurde.
Die Ergebnisse zeigen signifikante Leistungssteigerungen für Cunumeric:
- Matrix -Multiplikation: ~ 10x schneller als Numpy.
- Logistisches Regressionstraining: ~ 6x Schneller.
- Lösung linearer Gleichungen: Eine huge 100x+ Beschleunigung.
- Sortieren eines großen Arrays: Eine weitere enorme Verbesserung, die ungefähr läuft 70x Schneller.
Zusammenfassend zeigte ich, dass Cunumeric erfolgreich sein Versprechen liefert und die immense Rechenleistung von GPUs für die breitere Python -Datenwissenschaftsgemeinschaft zugänglich macht, ohne eine steile Lernkurve oder einen vollständigen Code -Umschreiben zu verlangen.
Weitere Informationen und Hyperlinks zu verwandten Ressourcen finden Sie in der ursprünglichen NVIDIA -Ankündigung zu Cunumeric Hier.
