MCPcopy Index your code
hub / github.com/Lyn-liyuan/ndarray-cuda-matmul

github.com/Lyn-liyuan/ndarray-cuda-matmul @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
64 symbols 178 edges 7 files 9 documented · 14%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Ndarray CUDA Matrix Operations

Welcome to the Ndarray CUDA Matrix Operations library, a high-performance computing solution designed to accelerate matrix operations using Nvidia's CUDA technology with Rust's ndarray data structure. This library leverages the powerful cuBLAS library to perform efficient matrix multiplications on compatible Nvidia GPUs.

For ideas and methods of creating this library, please refer to:

Improving ndrray matrix computing performance with CUDA

Features

  • Seamless integration with Rust's ndarray crate.
  • High-performance matrix operations utilizing CUDA.
  • Support for one-dimensional and two-dimensional arrays.
  • Automatic memory management between host and device.
  • Simple and intuitive API mirroring that of ndarray.

Prerequisites

To use this library, you will need: - g++ 7 or above - rustc 1.77.2 - cuda 10 or above

Usage

First, ensure that you have initialized the CUDA environment by calling init_cublas() before any matrix operations, and call destory_cublas() to clean up resources upon completion:

extern crate ndarray_cuda_matmul;

use ndarray_cuda_matmul::{init_cublas, destory_cublas};

fn main() {
    // Initialize cublas context
    init_cublas();

    // Your matrix operations here

    // Clean up cublas context
    destory_cublas();
}

To perform matrix multiplication, use the cuda_dot method provided by the trait CudaDot implemented for ndarray’s ArrayBase:

use ndarray::Array;
use ndarray_cuda_matmul::CudaDot;

let a = Array::from_shape_vec((m, k), vec![...]).unwrap();
let b = Array::from_shape_vec((k, n), vec![...]).unwrap();

let result = a.cuda_dot(&b);

Here m, n, and k represent the dimensions of the matrices, and vec![...] should be replaced with your actual data.

Using the method of first copying the matrix into GPU memory, here's a code example

let a = array![[1.0_f32, 2.0_f32, 3.0_f32], [4.0_f32, 5.0_f32, 6.0_f32]];
let b = array![[1.0_f32, 2.0_f32], [3.0_f32, 4.0_f32], [5.0_f32, 6.0_f32]];
let c = array![[1.0f32,1.0f32],[1.0f32,1.0f32]];
init_cublas();
let out = a.to_device().dot(&b.to_device()).dot(&c.to_device()).to_host();
destory_cublas();

Matrix-scalar multiplication code example:

    init_cublas();
    let out = a
        .to_device()
        .dot(&b.to_device())
        .dot(&c.to_device())
        .mul_scalar(2.0_f32)
        .to_host();
    destory_cublas();

Matrix inversion code example:

let a = array![[1.0_f32, 2.0_f32, 3.0_f32, 4.0_f32],
                [2.0_f32, 3.0_f32, 1.0_f32, 2.0_f32],
                [1.0_f32, 1.0_f32, 1.0_f32, -1.0_f32],
                [1.0_f32, 0.0_f32, -2.0_f32, -6.0_f32],
            ];

init_cublas();
let out = a.to_device().inv().to_host();
destory_cublas();

Using run macro can simplify the code and write it like a mathematical expression. The following is an example of using run macro.

fn least_squares_method()
{
    let x = array![[1f32, 1f32], [1f32, 2f32], [1f32, 3f32], [1f32, 4f32]];
    let y = array![[6f32], [5f32], [7f32], [10f32]];
    let bate_hat = run!(x,y => {
        let x_t = x.t();
        x_t.dot(x).inv().dot(&x_t).dot(y)
    }).to_host();
    println!("{:?}",bate_hat);
}

The example code implements the least squares method using the code that is most similar to the mathematical expression.

$$(X^TX)^{-1}X^Ty$$

V.S.

x_t.dot(x).inv().dot(&x_t).dot(y)

Safety and Error Handling

This library uses unsafe code to interface with CUDA functions. It includes error handling that checks the status of each CUDA and cuBLAS call, ensuring that any errors are handled gracefully and reported appropriately.

Performance

The performance test was conducted using the following code, comparing the dot method provided by ndarray-linalg

fn dot_with_ndarry() {
    let a = Array::from_elem((H_SIZE, H_SIZE), 1.0_f32);
    let b = Array::from_elem((H_SIZE, V_SIZE), 1.0_f32);
    let start = Instant::now();
    for _ in 0..100 {
        let _ = a.dot(&b);
    }
    println!("ndarray dot elapsed: {:.2?}", start.elapsed());
}

fn dot_with_cuda() {
    let a = Array::from_elem((H_SIZE, H_SIZE), 1.0_f32);
    let b = Array::from_elem((H_SIZE, V_SIZE), 1.0_f32);
    let start = Instant::now();
    for _ in 0..100 {
        let _ = a.cuda_dot(&b);
    }
    println!("matmul elapsed: {:.2?}", start.elapsed());
}

Comparing result:

Rows columns run times ndarra-linalg cuda_dot
64 64 100 2.27ms 9.89ms
128 80 100 11.37ms 10.66ms
768 128 100 438.01ms 57.86ms
2048 1000 100 22800ms 323.30ms

Contribution

Contributions to this library are welcome! Whether it's through reporting issues, proposing new features, improving documentation, or submitting pull requests, all forms of contribution are encouraged.

License

This library is distributed under the MIT license.

Extension points exported contracts — how you extend this code

CudaDot (Interface)
A trait that defines a CUDA-based dot product between arrays. [4 implementers]
src/lib.rs
MatDot (Interface)
(no doc) [4 implementers]
src/lib.rs
ToDevice (Interface)
(no doc) [4 implementers]
src/lib.rs
MatT (Interface)
(no doc) [2 implementers]
src/lib.rs
ToHost (Interface)
(no doc) [2 implementers]
src/lib.rs

Core symbols most depended-on inside this repo

shape
called by 25
src/lib.rs
to_device
called by 16
src/lib.rs
to_host
called by 11
src/lib.rs
dot
called by 10
src/lib.rs
init_cublas
called by 8
src/lib.rs
destory_cublas
called by 8
src/lib.rs
cuda_dot
called by 6
src/lib.rs
matmul
called by 4
src/lib.rs

Shape

Function 47
Method 9
Interface 6
Class 2

Languages

Rust83%
C++17%

Modules by API surface

src/lib.rs43 symbols
src/common.h11 symbols
examples/MultipleLinearRegression/src/main.rs4 symbols
examples/pca/src/main.rs3 symbols
examples/pca/build.rs1 symbols
examples/MultipleLinearRegression/build.rs1 symbols
build.rs1 symbols

For agents

$ claude mcp add ndarray-cuda-matmul \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page