#线性代数 #OpenCL #科学计算 #GPU #GPU加速 #计算 #内核

oscirs_linalg

科学计算用的GPU加速线性代数库

7个不稳定版本 (3个破坏性更新)

0.4.0-alpha2023年8月13日
0.3.0 2023年8月10日
0.2.0 2023年6月8日
0.1.1 2023年6月5日

#1637 in 算法

Download history 48/week @ 2024-04-01

84 每月下载量
用于 oscirs

Apache-2.0

31KB
571

oscirs_linalg

crates.io

Rust的线性代数库

描述

此库允许进行简单的线性代数相关计算,并通过OpenCL 3.0支持GPU并行化。

此库依赖于opencl3库,该库提供了OpenCL 3.0宏的Rust实现。

使用

oscirs_linalg主要依赖于Matrix结构。您可以使用32位浮点向量创建一个矩阵,除了行数和列数的乘积等于向量的长度外。构造函数new_matrix在成功返回矩阵之前会检查这一点。数据向量是按行主序排列的。以下是一个示例代码。

use oscirs_linalg::matrix::Matrix;

let data: Vec<f32> = vec![2.0; 6];
let n_rows: usize = 2;
let n_cols: usize = 3;

let mat: Matrix = Matrix::new(data, n_rows, n_cols)
    .expect("Failed to create mat");

矩阵可以使用典型的算术运算符相加,就像整数或浮点数一样。矩阵也可以取负值或与浮点数相加/相减。当操作需要维度检查时,您应使用?运算符或expect()来处理错误。

let data_2: Vec<f32> = vec![3.0; 6];
let n_rows_2: usize = 2;
let n_cols_2: usize = 3;

let mat_2: Matrix = Matrix::new(data_2, n_rows_2, n_cols_2)
    .expect("Failed to create mat_2");

let result: Matrix = (&mat + &mat_2)
    .expect("Failed to add mat and mat_2");

assert_eq!(result.get_data(), vec![5.0; 6]);

可以使用嵌套方括号索引矩阵,分别使用row()col()方法分别索引行/列。

assert_eq!(result[[1, 1]], 5.0);

GPU加速

虽然可以使用A * B语法进行矩阵乘法,但这是一个基于单线程CPU的操作。对于大型矩阵,这很快就会变得低效。oscirs_linalg通过OpenCL支持基于GPU的并行矩阵乘法。

要开始并行化,首先通过init()函数初始化Calculator结构。请确保将其声明为可变的,因为它将在内部动态存储矩阵。

use oscirs_linalg::calculator::Calculator;

let mut calc: Calculator = Calculator::init()
    .expect("Failed to initialize Calculator");

在进行任何操作之前,矩阵必须存储在计算器的内存中。方法 store_matrix() 返回一个内存索引,该索引将用于在乘法操作中引用该矩阵。

let a_vec: Vec<f32> = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
let b_vec: Vec<f32> = vec![2.0, 1.0, 2.0, 3.0, 2.0, 1.0];

let a_mat: Matrix = Matrix::new(a_vec, 2, 3)
    .expect("Failed to create Matrix A");
let b_mat: Matrix = Matrix::new(b_vec, 3, 2)
    .expect("Failed to create Matrix B");

let a_idx: usize = calc.store_matrix(a_mat)
    .expect("Failed to store Matrix A in calculator memory");
let b_idx: usize = calc.store_matrix(b_mat)
    .expect("Failed to store Matrix B in calculator memory");

一旦两个矩阵都存储在计算器的内存中,您就可以在 Calculator 上调用 mat_mul() 方法来乘以两个矩阵。 mat_mul() 的参数是要乘的矩阵的内存索引。

let (c_mat, _c_idx) = calc.mat_mul(a_idx, b_idx)
    .expect("Failed to mulitply Matrix A and Matrix B");

assert_eq!(c_mat.get_data(), vec![12.0, 10.0, 30.0, 25.0], "Matrix C data not as expected");
assert_eq!(c_mat.get_rows(), 2, "Matrix C row dimension not as expected");
assert_eq!(c_mat.get_cols(), 2, "Matrix C col dimension not as expected");

mat_mul() 返回一个包含结果矩阵及其在内存中索引的元组。结果矩阵始终存储在计算器的内存中,以便后续计算可以更快地进行,且内存移动更少。

自定义OpenCL内核

oscirs_linalg 还支持使用 Calculator 提供的内存管理工具使用您自己的 OpenCL 内核。这有点复杂,涉及一些不安全的函数,但在 tests 文件夹下的 linalg_tests.rs 中提供了一个示例。它需要创建一个自定义闭包,该闭包从输入矩阵计算输出矩阵的维度和工作大小,一旦完成,就可以轻松地多次执行您的自定义内核。

依赖项

~1.3–1.8MB
~39K SLoC