{"id":4842,"date":"2025-07-23T15:03:09","date_gmt":"2025-07-23T15:03:09","guid":{"rendered":"https:\/\/techtrendfeed.com\/?p=4842"},"modified":"2025-07-23T15:03:09","modified_gmt":"2025-07-23T15:03:09","slug":"numpy-api-on-a-gpu","status":"publish","type":"post","link":"https:\/\/techtrendfeed.com\/?p=4842","title":{"rendered":"NumPy API on a GPU?"},"content":{"rendered":"<p> <br \/>\n<\/p>\n<div>\n<h2 class=\"wp-block-heading\">Is  way forward for Python numerical computation?<\/h2>\n<p class=\"wp-block-paragraph\">Late final yr, NVIDIA made a big announcement relating to the way forward for Python-based numerical computing. I wouldn\u2019t be stunned for those who missed it. In spite of everything, each different announcement from each AI firm, then and now, appears mega-important.<\/p>\n<p class=\"wp-block-paragraph\">That announcement launched the <strong>cuNumeric <\/strong>library<strong>,<\/strong> a drop-in alternative for the ever-present NumPy library constructed on prime of the <strong>Legate<\/strong> framework.<\/p>\n<h3 class=\"wp-block-heading\">Who&#8217;re\u00a0Nvidia?<\/h3>\n<p class=\"wp-block-paragraph\">Most individuals will most likely know Nvidia from their ultra-fast chips that energy computer systems and information centres all around the world. You may additionally be accustomed to Nvidia\u2019s charismatic, leather-based jacket-loving CEO, Jensen Huang, who appears to pop up on the stage of each AI convention lately.<\/p>\n<p class=\"wp-block-paragraph\">What many individuals don\u2019t know is that Nvidia additionally designs and creates modern gadget architectures and related software program. One in all its most prized merchandise is the <strong>Compute Unified Gadget Structure<\/strong><span style=\"margin: 0px; padding: 0px;\"><strong>\u00a0<\/strong>(CUDA)<\/span>. CUDA<strong> <\/strong>is NVIDIA\u2019s proprietary parallel-computing platform and programming mannequin. Since its launch in 2007, it has developed right into a complete ecosystem comprising drivers, runtime, compilers, math libraries, debugging and profiling instruments, and container photos. The result&#8217;s a neatly tuned {hardware} and software program loop that retains NVIDIA GPUs on the centre of contemporary high-performance and AI workloads.<\/p>\n<h3 class=\"wp-block-heading\">What&#8217;s\u00a0Legate?<\/h3>\n<p class=\"wp-block-paragraph\">Legate is an NVIDIA-led open-source runtime layer that allows you to run acquainted Python data-science libraries (NumPy, cuNumeric, Pandas-style APIs, sparse linear-algebra kernels,\u00a0\u2026) on multi-core CPUs, single or multi-GPU nodes, and even multi-node clusters with out altering your Python code. It interprets high-level array operations right into a graph of fine-grained duties and arms that graph to the C++ <strong>Legion<\/strong> runtime, which schedules the duties, partitions the info, and strikes tiles between CPUs, GPUs and community hyperlinks for you.<\/p>\n<p class=\"wp-block-paragraph\">In a nutshell, Legate lets acquainted single-node Python libraries scale transparently to multi-GPU, multi-node machines.<\/p>\n<h3 class=\"wp-block-heading\">What&#8217;s cuNumeric?<\/h3>\n<p class=\"wp-block-paragraph\">cuNumeric is a drop-in alternative for NumPy whose array operations are executed by Legate\u2019s activity engine and accelerated on one or many NVIDIA GPUs (or, if no GPU is current, on all CPU cores). In apply, you put in it and wish solely change one import line to start out utilizing it instead of your common NumPy code. For instance \u2026<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\"># previous\nimport numpy as np\n...\n...\n\n# new\nimport cupynumeric as np     # every part else stays the identical\n...\n...<\/code><\/pre>\n<p class=\"wp-block-paragraph\">\u2026 and run your script on the terminal with the legate command. <\/p>\n<p class=\"wp-block-paragraph\">Behind the scenes, cuNumeric converts every NumPy name you make, for instance, np.sin, np.linalg.svd, fancy indexing, broadcasting, reductions, and so on, into Legate duties. These duties will,\u00a0<\/p>\n<ol class=\"wp-block-list\">\n<li class=\"wp-block-list-item\"><strong>Partition<\/strong> your arrays into tiles sized to suit GPU reminiscence.<\/li>\n<li class=\"wp-block-list-item\"><strong>Schedule<\/strong> every tile on the very best out there gadget (GPU or CPU).<\/li>\n<li class=\"wp-block-list-item\"><strong>Overlap<\/strong> compute with communication when the workload spans a number of GPUs or nodes.<\/li>\n<li class=\"wp-block-list-item\"><strong>Spill<\/strong> tiles to NVMe\/SSD robotically when your dataset outruns GPU RAM.<\/li>\n<\/ol>\n<p class=\"wp-block-paragraph\">As a result of the API of cuNumeric mirrors NumPy\u2019s almost 1-for-1, current scientific or data-science code can scale from a laptop computer to a multi-GPU cluster with no rewrite.<\/p>\n<h3 class=\"wp-block-heading\">Efficiency advantages<\/h3>\n<p class=\"wp-block-paragraph\">So, this all appears nice, proper? However it solely is sensible if it ends in tangible efficiency enhancements over utilizing NumPy, and Nvidia is making some sturdy claims that that is the case. As information scientists, machine studying engineers and information engineers sometimes use NumPy loads, we are able to respect that this generally is a essential facet of the techniques we write and preserve.<\/p>\n<p class=\"wp-block-paragraph\">Now, I don\u2019t have a cluster of GPUs or a supercomputer to check this on, however my desktop PC does have an Nvidia GeForce RTX 4070 GPU, and we\u2019re going to make use of that to check out a few of Nvidia\u2019s claims.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">(base) tom@tpr-desktop:~$ nvidia-smi\nSolar Jun 15 15:26:36 2025\n+-----------------------------------------------------------------------------------------+\n| NVIDIA-SMI 565.75                 Driver Model: 566.24         CUDA Model: 12.7     |\n|-----------------------------------------+------------------------+----------------------+\n| GPU  Title                 Persistence-M | Bus-Id          Disp.A | Risky Uncorr. ECC |\n| Fan  Temp   Perf          Pwr:Utilization\/Cap |           Reminiscence-Utilization | GPU-Util  Compute M. |\n|                                         |                        |               MIG M. |\n|=========================================+========================+======================|\n|   0  NVIDIA GeForce RTX 4070 Ti     On  |   00000000:01:00.0  On |                  N\/A |\n| 32%   29C    P8              9W \/  285W |    1345MiB \/  12282MiB |      2%      Default |\n|                                         |                        |                  N\/A |\n+-----------------------------------------+------------------------+----------------------+\n\n+-----------------------------------------------------------------------------------------+\n| Processes:                                                                              |\n|  GPU   GI   CI        PID   Kind   Course of title                              GPU Reminiscence |\n|        ID   ID                                                               Utilization      |\n|=========================================================================================|\n|  No working processes discovered                                                             |\n+-----------------------------------------------------------------------------------------+<\/code><\/pre>\n<p class=\"wp-block-paragraph\">I\u2019ll set up cuNumeric and NumPy on my PC to conduct comparative assessments. This may assist us assess whether or not Nvidia\u2019s claims are correct and perceive the efficiency variations between the 2 libraries.<\/p>\n<h2 class=\"wp-block-heading\">Establishing a growth surroundings.<\/h2>\n<p class=\"wp-block-paragraph\">As all the time, I wish to arrange a separate growth surroundings to run my assessments. That manner, nothing I do in that surroundings will have an effect on any of my different initiatives. On the time of writing, cuNumeric shouldn&#8217;t be out there to put in on Home windows, so I\u2019ll be utilizing WSL2 Ubuntu for Home windows as an alternative.<\/p>\n<p class=\"wp-block-paragraph\">I\u2019ll be utilizing Miniconda to arrange my surroundings, however be happy to make use of whichever software you\u2019re comfy with.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">$ conda create cunumeric-env python=3.10 -c conda-forge\n$ conda activate cunumeric-env\n$ conda set up -c conda-forge -c legate cupynumeric\n$ conda set up -c conda-forge ucx cuda-cudart cuda-version=12<\/code><\/pre>\n<h3 class=\"wp-block-heading\">Code instance 1\u200a\u2014\u200aA easy matrix multiplication<\/h3>\n<p class=\"wp-block-paragraph\">Matrix multiplication is the bread and butter of mathematical operations that underpin so many AI techniques, so it is sensible to strive that operation out first.<\/p>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><em>Be aware that in all my examples, I&#8217;ll run the NumPy and cuNumeric code snippets 5 instances in a row and common the time taken for every.<\/em> <em>I additionally carry out a \u201cwarm-up step on the GPU earlier than the timing run to keep in mind overheads akin to just-in-time (JIT) compilation.<\/em><\/p>\n<\/blockquote>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">import time\nimport gc\nimport argparse\nimport sys\n\ndef benchmark_numpy(n, runs):\n    \"\"\"Runs the matrix multiplication benchmark utilizing normal NumPy on the CPU.\"\"\"\n    import numpy as np\n    \n    print(f\"--- NumPy (CPU) Benchmark ---\")\n    print(f\"Multiplying two {n}\u00d7{n} matrices ({runs} runs)n\")\n\n    # 1. Generate information ONCE earlier than the timing loop.\n    print(f\"Producing two {n}x{n} random matrices on CPU...\")\n    A = np.random.rand(n, n).astype(np.float32)\n    B = np.random.rand(n, n).astype(np.float32)\n\n    # 2. Carry out one untimed warm-up run.\n    print(\"Performing warm-up run...\")\n    _ = np.matmul(A, B)\n    print(\"Heat-up full.n\")\n\n    # 3. Carry out the timed runs.\n    instances = []\n    for i in vary(runs):\n        begin = time.time()\n        # The operation being timed. The @ operator is a handy\n        # shorthand for np.matmul.\n        C = A @ B\n        finish = time.time()\n\n        length = finish - begin\n        instances.append(length)\n        print(f\"Run {i+1}: time = {length:.4f}s\")\n        del C # Clear up the consequence matrix\n        gc.gather()\n\n    avg = sum(instances) \/ len(instances)\n    print(f\"nNumPy common: {avg:.4f}sn\")\n    return avg\n\ndef benchmark_cunumeric(n, runs):\n    \"\"\"Runs the matrix multiplication benchmark utilizing cuNumeric on the GPU.\"\"\"\n    import cupynumeric as cn\n    import numpy as np # Import numpy for the canonical sync\n    \n    print(f\"--- cuNumeric (GPU) Benchmark ---\")\n    print(f\"Multiplying two {n}\u00d7{n} matrices ({runs} runs)n\")\n\n    # 1. Generate information ONCE on the GPU earlier than the timing loop.\n    print(f\"Producing two {n}x{n} random matrices on GPU...\")\n    A = cn.random.rand(n, n).astype(np.float32)\n    B = cn.random.rand(n, n).astype(np.float32)\n\n    # 2. Carry out a vital untimed warm-up run for JIT compilation.\n    print(\"Performing warm-up run...\")\n    C_warmup = cn.matmul(A, B)\n    # The very best apply for synchronization: power a replica again to the CPU.\n    _ = np.array(C_warmup)\n    print(\"Heat-up full.n\")\n\n    # 3. Carry out the timed runs.\n    instances = []\n    for i in vary(runs):\n        begin = time.time()\n        \n        # Launch the operation on the GPU\n        C = A @ B\n        \n        # Synchronize by changing the consequence to a host-side NumPy array.\n        np.array(C)\n\n        finish = time.time()\n\n        length = finish - begin\n        instances.append(length)\n        print(f\"Run {i+1}: time = {length:.4f}s\")\n        del C\n        gc.gather()\n\n    avg = sum(instances) \/ len(instances)\n    print(f\"ncuNumeric common: {avg:.4f}sn\")\n    return avg\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser(\n        description=\"Benchmark matrix multiplication on NumPy (CPU) vs. cuNumeric (GPU).\"\n    )\n    parser.add_argument(\n        \"-n\", \"--n\", sort=int, default=3000, assist=\"Matrix measurement (n x n)\"\n    )\n    parser.add_argument(\n        \"-r\", \"--runs\", sort=int, default=5, assist=\"Variety of timing runs\"\n    )\n    parser.add_argument(\n        \"--cunumeric\", motion=\"store_true\", assist=\"Run the cuNumeric (GPU) model\"\n    )\n    \n    args, unknown = parser.parse_known_args()\n\n    # The dispatcher logic\n    if args.cunumeric or \"--cunumeric\" in unknown:\n        benchmark_cunumeric(args.n, args.runs)\n    else:\n        benchmark_numpy(args.n, args.runs)<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Operating the NumPy facet of issues makes use of the common <strong>python example1.py <\/strong>command line syntax. For working utilizing Legate, the syntax is extra complicated. What it does is disable Legate\u2019s automated configuration after which launch the example1.py script below Legate with one CPU, one GPU, and 0 OpenMP threads utilizing the cuNumeric backend.<\/p>\n<p class=\"wp-block-paragraph\">Right here is the output.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">(cunumeric-env) tom@tpr-desktop:~$ python example1.py\n--- NumPy (CPU) Benchmark ---\nMultiplying two 3000\u00d73000 matrices (5 runs)\n\nProducing two 3000x3000 random matrices on CPU...\nPerforming warm-up run...\nHeat-up full.\n\nRun 1: time = 0.0976s\nRun 2: time = 0.0987s\nRun 3: time = 0.0957s\nRun 4: time = 0.1063s\nRun 5: time = 0.0989s\n\nNumPy common: 0.0994s\n\n(cunumeric-env) tom@tpr-desktop:~$ LEGATE_AUTO_CONFIG=0 legate --cpus 1 --gpus 1 --omps 0 example1.py --cunu\nmeric\n[0 - 7f2e8fcc8480]    0.000000 {5}{module_config}: Module numa cannot detect assets.\n[0 - 7f2e8fcc8480]    0.000000 {4}{topology}: cannot open \/sys\/units\/system\/node\/\n[0 - 7f2e8fcc8480]    0.000049 {4}{threads}: reservation ('GPU ctxsync 0x55cd5fd34530') can't be happy\n--- cuNumeric (GPU) Benchmark ---\nMultiplying two 3000\u00d73000 matrices (5 runs)\n\nProducing two 3000x3000 random matrices on GPU...\nPerforming warm-up run...\nHeat-up full.\n\nRun 1: time = 0.0113s\nRun 2: time = 0.0089s\nRun 3: time = 0.0086s\nRun 4: time = 0.0090s\nRun 5: time = 0.0087s\n\ncuNumeric common: 0.0093s<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Properly, that\u2019s a powerful begin. cuNumeric is registering a 10x speedup over NumPy.<\/p>\n<p class=\"wp-block-paragraph\">The warnings that Legate is outputting will be ignored. These are informational, indicating Legate couldn\u2019t discover particulars in regards to the machine\u2019s CPU\/reminiscence format (NUMA) or sufficient CPU cores to handle the GPU.<\/p>\n<h3 class=\"wp-block-heading\">Code instance 2\u200a\u2014\u200aLogistic regression<\/h3>\n<p class=\"wp-block-paragraph\">Logistic regression is a foundational software in information science as a result of it gives a easy, interpretable option to mannequin and predict binary outcomes (sure\/no, go\/fail, click on\/no-click). On this instance, we\u2019ll measure how lengthy it takes to coach a easy binary classifier on artificial information. For every of the 5 runs, it first generates <strong>N<\/strong> samples with <strong>D<\/strong> options (X), and a corresponding random 0\/1 label vector (Y). It initialises the load vector <code>w<\/code> to zeros, then performs <strong>500<\/strong> iterations of batch gradient descent: computing the linear predictions <strong>z = X.dot(w)<\/strong>, making use of the sigmoid <strong>p = 1\/(1+exp(\u2013z))<\/strong>, computing the gradient <strong>grad = X.T.dot(p \u2013 y) \/ N<\/strong>, and updating the weights with <strong>w -= 0.1 * grad<\/strong>. The script information the elapsed time for every run, cleans up reminiscence, and eventually prints the common coaching time.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">import time\nimport gc\nimport argparse\nimport sys\n\n# --- Reusable Coaching Operate ---\n# By placing the coaching loop in its personal perform, we keep away from code duplication.\n# The `np` argument permits us to go in both the numpy or cupynumeric module.\ndef train_logistic_regression(np, X, y, iters, alpha):\n    \"\"\"Performs a set variety of gradient descent iterations.\"\"\"\n    # Guarantee w begins on the right gadget (CPU or GPU)\n    w = np.zeros(X.form[1])\n    \n    for _ in vary(iters):\n        z = X.dot(w)\n        p = 1.0 \/ (1.0 + np.exp(-z))\n        grad = X.T.dot(p - y) \/ X.form[0]\n        w -= alpha * grad\n    \n    return w\n\ndef benchmark_numpy(n_samples, n_features, iters, alpha):\n    \"\"\"Runs the logistic regression benchmark utilizing normal NumPy on the CPU.\"\"\"\n    import numpy as np\n    \n    print(f\"--- NumPy (CPU) Benchmark ---\")\n    print(f\"Coaching on {n_samples} samples, {n_features} options for {iters} iterationsn\")\n\n    # 1. Generate information ONCE earlier than the timing loop.\n    print(\"Producing random dataset on CPU...\")\n    X = np.random.rand(n_samples, n_features)\n    y = (np.random.rand(n_samples) &gt; 0.5).astype(np.float64)\n\n    # 2. Carry out one untimed warm-up run.\n    print(\"Performing warm-up run...\")\n    _ = train_logistic_regression(np, X, y, iters, alpha)\n    print(\"Heat-up full.n\")\n\n    # 3. Carry out the timed runs.\n    instances = []\n    for i in vary(args.runs):\n        begin = time.time()\n        # The operation being timed\n        _ = train_logistic_regression(np, X, y, iters, alpha)\n        finish = time.time()\n\n        length = finish - begin\n        instances.append(length)\n        print(f\"Run {i+1}: time = {length:.3f}s\")\n        gc.gather()\n\n    avg = sum(instances) \/ len(instances)\n    print(f\"nNumPy common: {avg:.3f}sn\")\n    return avg\n\ndef benchmark_cunumeric(n_samples, n_features, iters, alpha):\n    \"\"\"Runs the logistic regression benchmark utilizing cuNumeric on the GPU.\"\"\"\n    import cupynumeric as cn\n    import numpy as np # Additionally import numpy for the canonical synchronization\n    \n    print(f\"--- cuNumeric (GPU) Benchmark ---\")\n    print(f\"Coaching on {n_samples} samples, {n_features} options for {iters} iterationsn\")\n\n    # 1. Generate information ONCE on the GPU earlier than the timing loop.\n    print(\"Producing random dataset on GPU...\")\n    X = cn.random.rand(n_samples, n_features)\n    y = (cn.random.rand(n_samples) &gt; 0.5).astype(np.float64)\n\n    # 2. Carry out a vital untimed warm-up run for JIT compilation.\n    print(\"Performing warm-up run...\")\n    w_warmup = train_logistic_regression(cn, X, y, iters, alpha)\n    # The very best apply for synchronization: power a replica again to the CPU.\n    _ = np.array(w_warmup)\n    print(\"Heat-up full.n\")\n\n    # 3. Carry out the timed runs.\n    instances = []\n    for i in vary(args.runs):\n        begin = time.time()\n        \n        # Launch the operation on the GPU\n        w = train_logistic_regression(cn, X, y, iters, alpha)\n        \n        # Synchronize by changing the ultimate consequence again to a NumPy array.\n        np.array(w)\n\n        finish = time.time()\n\n        length = finish - begin\n        instances.append(length)\n        print(f\"Run {i+1}: time = {length:.3f}s\")\n        del w\n        gc.gather()\n\n    avg = sum(instances) \/ len(instances)\n    print(f\"ncuNumeric common: {avg:.3f}sn\")\n    return avg\n\nif __name__ == \"__main__\":\n    # A extra sturdy argument parsing setup\n    parser = argparse.ArgumentParser(\n        description=\"Benchmark logistic regression on NumPy (CPU) vs. cuNumeric (GPU).\"\n    )\n    # Hyperparameters for the mannequin\n    parser.add_argument(\n        \"-n\", \"--n_samples\", sort=int, default=2_000_000, assist=\"Variety of information samples\"\n    )\n    parser.add_argument(\n        \"-d\", \"--n_features\", sort=int, default=10, assist=\"Variety of options\"\n    )\n    parser.add_argument(\n        \"-i\", \"--iters\", sort=int, default=500, assist=\"Variety of gradient descent iterations\"\n    )\n    parser.add_argument(\n        \"-a\", \"--alpha\", sort=float, default=0.1, assist=\"Studying charge\"\n    )\n    # Benchmark management\n    parser.add_argument(\n        \"-r\", \"--runs\", sort=int, default=5, assist=\"Variety of timing runs\"\n    )\n    parser.add_argument(\n        \"--cunumeric\", motion=\"store_true\", assist=\"Run the cuNumeric (GPU) model\"\n    )\n    \n    args, unknown = parser.parse_known_args()\n\n    # Dispatcher logic\n    if args.cunumeric or \"--cunumeric\" in unknown:\n        benchmark_cunumeric(args.n_samples, args.n_features, args.iters, args.alpha)\n    else:\n        benchmark_numpy(args.n_samples, args.n_features, args.iters, args.alpha)<\/code><\/pre>\n<p class=\"wp-block-paragraph\">And the outputs.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">(cunumeric-env) tom@tpr-desktop:~$ python example2.py\n--- NumPy (CPU) Benchmark ---\nCoaching on 2000000 samples, 10 options for 500 iterations\n\nProducing random dataset on CPU...\nPerforming warm-up run...\nHeat-up full.\n\nRun 1: time = 12.292s\nRun 2: time = 11.830s\nRun 3: time = 11.903s\nRun 4: time = 12.843s\nRun 5: time = 11.964s\n\nNumPy common: 12.166s\n\n(cunumeric-env) tom@tpr-desktop:~$ LEGATE_AUTO_CONFIG=0 legate --cpus 1 --gpus 1 --omps 0 example2.py --cunu\nmeric\n[0 - 7f04b535c480]    0.000000 {5}{module_config}: Module numa cannot detect assets.\n[0 - 7f04b535c480]    0.000000 {4}{topology}: cannot open \/sys\/units\/system\/node\/\n[0 - 7f04b535c480]    0.001149 {4}{threads}: reservation ('GPU ctxsync 0x55fb037cf140') can't be happy\n--- cuNumeric (GPU) Benchmark ---\nCoaching on 2000000 samples, 10 options for 500 iterations\n\nProducing random dataset on GPU...\nPerforming warm-up run...\nHeat-up full.\n\nRun 1: time = 1.964s\nRun 2: time = 1.957s\nRun 3: time = 1.968s\nRun 4: time = 1.955s\nRun 5: time = 1.960s\n\ncuNumeric common: 1.961s<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Not fairly as spectacular as our first instance, however a 5x to 6x speedup on an already quick NumPy program is to not be sniffed at.<\/p>\n<h3 class=\"wp-block-heading\">Code instance 3\u200a\u2014\u200afixing linear equations<\/h3>\n<p class=\"wp-block-paragraph\">This script benchmarks how lengthy it takes to resolve a dense 3000\u00d73000 linear algebra equation system. It is a basic operation in linear algebra used to resolve the equation of sort <strong>Ax = b, <\/strong>the place<strong> <\/strong>A is a huge grid of numbers (a 3000\u00d73000 matrix on this case), and b is an inventory of numbers (a vector).\u00a0<\/p>\n<p class=\"wp-block-paragraph\">The objective is to seek out the unknown listing of numbers x that makes the equation true. It is a computationally intensive activity that&#8217;s on the coronary heart of many scientific simulations, engineering issues, monetary fashions, and even some AI algorithms.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">import time\nimport gc\nimport argparse\nimport sys # Import sys to verify arguments\n\n# Be aware: The library imports (numpy and cupynumeric) at the moment are carried out *inside*\n# their respective features to maintain them separate and keep away from import errors.\n\ndef benchmark_numpy(n, runs):\n    \"\"\"Runs the linear clear up benchmark utilizing normal NumPy on the CPU.\"\"\"\n    import numpy as np\n\n    print(f\"--- NumPy (CPU) Benchmark ---\")\n    print(f\"Fixing {n}\u00d7{n} A x = b ({runs} runs)n\")\n\n    # 1. Generate information ONCE earlier than the timing loop.\n    print(\"Producing random system on CPU...\")\n    A = np.random.randn(n, n).astype(np.float32)\n    b = np.random.randn(n).astype(np.float32)\n\n    # 2. Carry out one untimed warm-up run. That is good apply even for\n    # the CPU to make sure caches are heat and any one-time setup is completed.\n    print(\"Performing warm-up run...\")\n    _ = np.linalg.clear up(A, b)\n    print(\"Heat-up full.n\")\n\n    # 3. Carry out the timed runs.\n    instances = []\n    for i in vary(runs):\n        begin = time.time()\n        # The operation being timed\n        x = np.linalg.clear up(A, b)\n        finish = time.time()\n\n        length = finish - begin\n        instances.append(length)\n        print(f\"Run {i+1}: time = {length:.6f}s\")\n        # Clear up the consequence to be secure with reminiscence\n        del x\n        gc.gather()\n\n    avg = sum(instances) \/ len(instances)\n    print(f\"nNumPy common: {avg:.6f}sn\")\n    return avg\n\ndef benchmark_cunumeric(n, runs):\n    \"\"\"Runs the linear clear up benchmark utilizing cuNumeric on the GPU.\"\"\"\n    import cupynumeric as cn\n    import numpy as np # Additionally import numpy for the canonical synchronization\n\n    print(f\"--- cuNumeric (GPU) Benchmark ---\")\n    print(f\"Fixing {n}\u00d7{n} A x = b ({runs} runs)n\")\n\n    # 1. Generate information ONCE on the GPU earlier than the timing loop.\n    # This ensures we're not timing the info switch in our important loop.\n    print(\"Producing random system on GPU...\")\n    A = cn.random.randn(n, n).astype(np.float32)\n    b = cn.random.randn(n).astype(np.float32)\n\n    # 2. Carry out a vital untimed warm-up run. This handles JIT\n    # compilation and different one-time GPU setup prices.\n    print(\"Performing warm-up run...\")\n    x_warmup = cn.linalg.clear up(A, b)\n    # The very best apply for synchronization: power a replica again to the CPU.\n    _ = np.array(x_warmup)\n    print(\"Heat-up full.n\")\n\n    # 3. Carry out the timed runs.\n    instances = []\n    for i in vary(runs):\n        begin = time.time()\n\n        # Launch the operation on the GPU\n        x = cn.linalg.clear up(A, b)\n\n        # Synchronize by changing the consequence to a host-side NumPy array.\n        # That is assured to dam till the GPU has completed.\n        np.array(x)\n\n        finish = time.time()\n\n        length = finish - begin\n        instances.append(length)\n        print(f\"Run {i+1}: time = {length:.6f}s\")\n        # Clear up the GPU array consequence\n        del x\n        gc.gather()\n\n    avg = sum(instances) \/ len(instances)\n    print(f\"ncuNumeric common: {avg:.6f}sn\")\n    return avg\n\nif __name__ == \"__main__\":\n    # A extra sturdy argument parsing setup\n    parser = argparse.ArgumentParser(\n        description=\"Benchmark linear clear up on NumPy (CPU) vs. cuNumeric (GPU).\"\n    )\n    parser.add_argument(\n        \"-n\", \"--n\", sort=int, default=3000, assist=\"Matrix measurement (n x n)\"\n    )\n    parser.add_argument(\n        \"-r\", \"--runs\", sort=int, default=5, assist=\"Variety of timing runs\"\n    )\n\n    # Use parse_known_args() to deal with potential additional arguments from Legate\n    args, unknown = parser.parse_known_args()\n\n    # The dispatcher logic: verify if \"--cunumeric\" is within the command line\n    # It is a easy and efficient option to swap between modes.\n    if \"--cunumeric\" in sys.argv or \"--cunumeric\" in unknown:\n        benchmark_cunumeric(args.n, args.runs)\n    else:\n        benchmark_numpy(args.n, args.runs)<\/code><\/pre>\n<p class=\"wp-block-paragraph\">The outputs.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">(cunumeric-env) tom@tpr-desktop:~$ python example4.py\n--- NumPy (CPU) Benchmark ---\nFixing 3000\u00d73000 A x = b (5 runs)\n\nProducing random system on CPU...\nPerforming warm-up run...\nHeat-up full.\n\nRun 1: time = 0.133075s\nRun 2: time = 0.126129s\nRun 3: time = 0.135849s\nRun 4: time = 0.137383s\nRun 5: time = 0.138805s\n\nNumPy common: 0.134248s\n\n(cunumeric-env) tom@tpr-desktop:~$ LEGATE_AUTO_CONFIG=0 legate --cpus 1 --gpus 1 --omps 0 example4.py --cunumeric\n[0 - 7f29f42ce480]    0.000000 {5}{module_config}: Module numa cannot detect assets.\n[0 - 7f29f42ce480]    0.000000 {4}{topology}: cannot open \/sys\/units\/system\/node\/\n[0 - 7f29f42ce480]    0.000053 {4}{threads}: reservation ('GPU ctxsync 0x562e88c28700') can't be happy\n--- cuNumeric (GPU) Benchmark ---\nFixing 3000\u00d73000 A x = b (5 runs)\n\nProducing random system on GPU...\nPerforming warm-up run...\nHeat-up full.\n\nRun 1: time = 0.009685s\nRun 2: time = 0.010043s\nRun 3: time = 0.009966s\nRun 4: time = 0.009739s\nRun 5: time = 0.009383s\n\ncuNumeric common: 0.009763s<\/code><\/pre>\n<p class=\"wp-block-paragraph\">That may be a large consequence. The Nvidia cuNumeric run is 100x quicker than the NumPy run.<\/p>\n<h3 class=\"wp-block-heading\">Code instance 4\u200a\u2014\u200aSorting<\/h3>\n<p class=\"wp-block-paragraph\">Sorting is such a basic a part of every part that occurs in computing, and trendy computer systems are so quick that almost all builders don\u2019t even give it some thought. However let\u2019s see how a lot of a distinction utilizing cuNumeric could make to this ubiquitous operation. We\u2019ll kind a big (30,000,000) 1D array of numbers<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\"># benchmark_sort.py\nimport time\nimport sys\nimport gc\n\n# Array measurement\nn = 30_000_000 # 30 million parts\n\ndef benchmark_numpy():\n    import numpy as np\n    print(f\"Sorting an array of {n} parts with NumPy (5 runs)n\")\n\n    instances = []\n    for i in vary(5):\n        information = np.random.randn(n).astype(np.float32)\n        begin = time.time()\n        _ = np.kind(information)\n        finish = time.time()\n\n        length = finish - begin\n        instances.append(length)\n        print(f\"Run {i+1}: time = {length:.6f}s\")\n        del information\n        gc.gather()\n\n    avg = sum(instances) \/ len(instances)\n    print(f\"nNumPy common: {avg:.6f}sn\")\n\ndef benchmark_cunumeric():\n    import cupynumeric as np\n    print(f\"Sorting an array of {n} parts with cuNumeric (5 runs)n\")\n\n    instances = []\n    for i in vary(5):\n        information = np.random.randn(n).astype(np.float32)\n        begin = time.time()\n        _ = np.kind(information)\n        # Drive GPU sync\n        _ = np.linalg.norm(np.zeros(()))\n        finish = time.time()\n\n        length = finish - begin\n        instances.append(length)\n        print(f\"Run {i+1}: time = {length:.6f}s\")\n        del information\n        gc.gather()\n        _ = np.linalg.norm(np.zeros(()))\n\n    avg = sum(instances) \/ len(instances)\n    print(f\"ncuNumeric common: {avg:.6f}sn\")\n\nif __name__ == \"__main__\":\n    if \"--cunumeric\" in sys.argv:\n        benchmark_cunumeric()\n    else:\n        benchmark_numpy()<\/code><\/pre>\n<p class=\"wp-block-paragraph\">The outputs.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">(cunumeric-env) tom@tpr-desktop:~$ python example5.py\n--- NumPy (CPU) Benchmark ---\nSorting an array of 30000000 parts (5 runs)\n\nCreating random array on CPU...\nPerforming warm-up run...\nHeat-up full.\n\nRun 1: time = 0.588777s\nRun 2: time = 0.586813s\nRun 3: time = 0.586745s\nRun 4: time = 0.586525s\nRun 5: time = 0.583783s\n\nNumPy common: 0.586529s\n-----------------------------\n\n(cunumeric-env) tom@tpr-desktop:~$ LEGATE_AUTO_CONFIG=0 legate --cpus 1 --gpus 1 --omps 0 example5.py --cunumeric\n[0 - 7fd9e4615480]    0.000000 {5}{module_config}: Module numa cannot detect assets.\n[0 - 7fd9e4615480]    0.000000 {4}{topology}: cannot open \/sys\/units\/system\/node\/\n[0 - 7fd9e4615480]    0.000082 {4}{threads}: reservation ('GPU ctxsync 0x564489232fd0') can't be happy\n--- cuNumeric (GPU) Benchmark ---\nSorting an array of 30000000 parts (5 runs)\n\nCreating random array on GPU...\nPerforming warm-up run...\nHeat-up full.\n\nRun 1: time = 0.010857s\nRun 2: time = 0.007927s\nRun 3: time = 0.007921s\nRun 4: time = 0.008240s\nRun 5: time = 0.007810s\n\ncuNumeric common: 0.008551s\n-------------------------------<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Yet one more vastly spectacular efficiency from cuNumeric and Legate.<\/p>\n<h2 class=\"wp-block-heading\">Abstract<\/h2>\n<p class=\"wp-block-paragraph\">This text launched <strong>cuNumeric<\/strong>, an NVIDIA library designed as a high-performance, <strong>drop-in<\/strong> alternative for <strong>NumPy<\/strong>. The important thing takeaway is that information scientists can speed up their current Python code on NVIDIA GPUs with minimal effort, usually by merely altering a single import line and working the script with the<strong> \u2018legate\u2019 <\/strong>command.<\/p>\n<p class=\"wp-block-paragraph\">Two important elements energy the expertise:<\/p>\n<ol class=\"wp-block-list\">\n<li class=\"wp-block-list-item\"><strong>Legate:<\/strong> An open-source runtime layer from NVIDIA that robotically interprets high-level Python operations into duties. It intelligently manages distributing these duties throughout single or a number of GPUs, dealing with information partitioning, reminiscence administration (even spilling to disk if wanted), and optimising communication.<\/li>\n<li class=\"wp-block-list-item\"><strong>cuNumeric:<\/strong> The user-facing library that mirrors the NumPy API. Once you make a name like np.matmul(), cuNumeric converts it right into a activity for the Legate engine to execute on the GPU.<\/li>\n<\/ol>\n<p class=\"wp-block-paragraph\">I used to be in a position to validate Nvidia\u2019s efficiency claims by working 4 benchmark assessments on my desktop PC (with an NVIDIA RTX 4070 Ti GPU), evaluating normal NumPy on the CPU in opposition to cuNumeric on the GPU.<\/p>\n<p class=\"wp-block-paragraph\">The outcomes display vital efficiency features for cuNumeric:<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\"><strong>Matrix Multiplication:<\/strong> <strong>~10x<\/strong> quicker than NumPy.<\/li>\n<li class=\"wp-block-list-item\"><strong>Logistic Regression Coaching:<\/strong> <strong>~6x<\/strong> quicker.<\/li>\n<li class=\"wp-block-list-item\"><strong>Fixing Linear Equations:<\/strong> A large <strong>100x+<\/strong> speedup.<\/li>\n<li class=\"wp-block-list-item\"><strong>Sorting a Massive Array:<\/strong> One other big enchancment, working roughly <strong>70x<\/strong> quicker.<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">In conclusion, I confirmed that cuNumeric efficiently delivers on its promise, making the immense computational energy of GPUs accessible to the broader Python information science group with out requiring a steep studying curve or a whole code rewrite.<\/p>\n<p class=\"wp-block-paragraph\">For extra info and hyperlinks to associated assets, take a look at the unique Nvidia announcement on cuNumeric <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/developer.nvidia.com\/blog\/nvidia-announces-availability-for-cunumeric-public-alpha\/\">right here<\/a>.<\/p>\n<\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>Is way forward for Python numerical computation? Late final yr, NVIDIA made a big announcement relating to the way forward for Python-based numerical computing. I wouldn\u2019t be stunned for those who missed it. In spite of everything, each different announcement from each AI firm, then and now, appears mega-important. That announcement launched the cuNumeric library, [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":4844,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[55],"tags":[664,2536,4219],"class_list":["post-4842","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-machine-learning","tag-api","tag-gpu","tag-numpy"],"_links":{"self":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts\/4842","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4842"}],"version-history":[{"count":1,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts\/4842\/revisions"}],"predecessor-version":[{"id":4843,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts\/4842\/revisions\/4843"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/media\/4844"}],"wp:attachment":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4842"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4842"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4842"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}<!-- This website is optimized by Airlift. Learn more: https://airlift.net. Template:. Learn more: https://airlift.net. Template: 69d9690a190636c2e0989534. Config Timestamp: 2026-04-10 21:18:02 UTC, Cached Timestamp: 2026-08-05 14:20:07 UTC -->