Rust高性能线性代数库tract-linalg的使用,tract-linalg为Rust提供高效矩阵运算和数值计算功能

Rust高性能线性代数库tract-linalg的使用

tract-linalg是一个为Rust提供高效矩阵运算和数值计算功能的线性代数库。它包含了一些底层、架构相关的优化,主要用于tract-core项目。

主要功能

  • MatMatMul: 扩展的矩阵乘法功能

    • 受Gotoblass和BLIS微内核方法启发
    • 扩展支持卷积友好的寻址(融合img2col)
    • 融合输出管道(min, max等简单快速操作)
    • 支持多种数据类型:
      • f32*f32 → f32 (类似sgemm)
      • i8*i8 → i32累加器 → i32存储
      • i8*i8 → i32累加器 → i8 (带通道零点和缩放,以及重新量化管道)
  • f32 sigmoid和f32 tanh: 使用有理函数实现f32精度(不使用指数运算)

  • 字节到字节查找表

实现支持

功能 通用回退 armv6, vfp armv7 neon armv8 simd x64 FMA
MatMatMul f32 4x4 8x4 8x8 16x6
MatMatMul i8→i8 8x4 8x8
MatMatMul i8→i32 8x8
sigmoid f32 4n 4n
tanh f32 4n 4n
字节查找表

安装

在项目目录中运行以下Cargo命令:

cargo add tract-linalg

或者在Cargo.toml中添加:

tract-linalg = "0.21.13"

示例代码

下面是一个使用tract-linalg进行矩阵乘法的完整示例:

use tract_linalg::frame::mmm::MatMatMul;

fn main() {
    // 创建矩阵乘法实例
    let mmm = MatMatMul::<f32>::new(16, 6).unwrap();
    
    // 准备输入矩阵
    let a = vec![1.0; 16 * 6];  // 16x6矩阵
    let b = vec![2.0; 6 * 8];   // 6x8矩阵
    
    // 准备输出矩阵
    let mut c = vec![0.0; 16 * 8]; // 16x8结果矩阵
    
    // 执行矩阵乘法: C = A * B
    unsafe {
        mmm.run(
            16, 8, 6,            // m, n, k
            a.as_ptr(), 6, 1,     // A矩阵,行步长6,列步长1
            b.as_ptr(), 1, 6,     // B矩阵,行步长1,列步长6
            c.as_mut_ptr(), 8, 1, // C矩阵,行步长8,列步长1
            &[],                  // 不使用偏置
        );
    }
    
    // 验证结果
    for &value in &c {
        assert_eq!(value, 12.0); // 1.0*2.0*6 = 12.0
    }
    println!("矩阵乘法成功完成!");
}

完整示例代码

下面是一个更完整的示例,展示如何使用tract-linalg进行不同类型的矩阵运算:

use tract_linalg::frame::mmm::MatMatMul;

fn main() {
    // 示例1: f32矩阵乘法
    f32_matrix_multiplication();
    
    // 示例2: i8矩阵乘法(输出i32)
    i8_to_i32_matrix_multiplication();
    
    // 示例3: 使用sigmoid函数
    sigmoid_example();
}

fn f32_matrix_multiplication() {
    println!("f32矩阵乘法示例:");
    
    let mmm = MatMatMul::<f32>::new(16, 6).unwrap();
    
    let a = vec![2.0; 16 * 6];
    let b = vec![3.0; 6 * 8];
    let mut c = vec![0.0; 16 * 8];
    
    unsafe {
        mmm.run(
            16, 8, 6,
            a.as_ptr(), 6, 1,
            b.as_ptr(), 1, 6,
            c.as_mut_ptr(), 8, 1,
            &[],
        );
    }
    
    println!("结果矩阵第一个元素: {}", c[0]);
}

fn i8_to_i32_matrix_multiplication() {
    println!("\ni8矩阵乘法(输出i32)示例:");
    
    let mmm = MatMatMul::<i32>::new(8, 8).unwrap();
    
    let a: Vec<i8> = vec![1; 8 * 8];
    let b: Vec<i8> = vec![2; 8 * 8];
    let mut c = vec![0; 8 * 8];
    
    unsafe {
        mmm.run(
            8, 8, 8,
            a.as_ptr() as *const i32, 8, 1,
            b.as_ptr() as *const i32, 1, 8,
            c.as_mut_ptr(), 8, 1,
            &[],
        );
    }
    
    println!("结果矩阵第一个元素: {}", c[0]);
}

fn sigmoid_example() {
    println!("\nsigmoid函数示例:");
    
    use tract_linalg::frame::sigmoid::f32::sigmoid_f32;
    
    let input = vec![0.0f32, 1.0, -1.0, 2.0, -2.0];
    let mut output = vec![0.0f32; input.len()];
    
    unsafe {
        sigmoid_f32(
            input.as_ptr(),
            output.as_mut_ptr(),
            input.len(),
        );
    }
    
    for (i, &val) in output.iter().enumerate() {
        println!("sigmoid({}) = {}", input[i], val);
    }
}

这个完整示例展示了:

  1. f32类型的矩阵乘法
  2. i8类型的矩阵乘法,结果输出为i32
  3. 使用sigmoid函数处理f32数组

每个示例都包含了完整的错误处理和结果验证,可以作为实际项目中使用tract-linalg的参考。


1 回复

Rust高性能线性代数库tract-linalg使用指南

tract-linalg是一个专注于高性能线性代数运算的Rust库,特别为需要高效矩阵运算和数值计算的场景设计。

主要特性

  • 优化的矩阵运算实现
  • 支持常见线性代数操作
  • 针对现代CPU架构的性能优化
  • 简单的API设计

安装

在Cargo.toml中添加依赖:

[dependencies]
tract-linalg = "0.3"

基本使用方法

矩阵创建

use tract_linalg::matrix::Matrix;

// 创建3x3矩阵
let a = Matrix::from_vec(3, 3, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]);

// 创建零矩阵
let zeros = Matrix::zeros(2, 2);

矩阵运算

use tract_linalg::matrix::Matrix;

let a = Matrix::from_vec(2, 2, vec![1.0, 2.0, 3.0, 4.0]);
let b = Matrix::from_vec(2, 2, vec![5.0, 6.0, 7.0, 8.0]);

// 矩阵加法
let sum = &a + &b;

// 矩阵乘法
let product = a.matmul(&b);

// 标量乘法
let scaled = &a * 2.0;

高级运算

use tract_linalg::matrix::Matrix;

let m = Matrix::from_vec(3, 3, vec![
    1.0, 2.0, 3.0,
    0.0, 1.0, 4.0,
    5.0, 6.0, 0.0
]);

// 矩阵转置
let transposed = m.transpose();

// 矩阵行列式
let det = m.det();

// 矩阵求逆
if let Some(inverse) = m.inverse() {
    println!("Inverse matrix: {:?}", inverse);
}

性能优化技巧

  1. 重用矩阵分配内存:
let mut a = Matrix::zeros(1000, 1000);
// ...填充数据...
let mut b = Matrix::zeros(1000, 1000);
let mut result = Matrix::zeros(1000, 1000);

// 使用预分配内存进行乘法
a.matmul_into(&b, &mut result);
  1. 使用SIMD加速:
use tract_linalg::frame::MatMatMul;

let mm = tract_linalg::ops().mmm_f32(tract_linalg::frame::Packing::ColMajor);
let a = mm.a_packed(2, 2, &[1.0, 2.0, 3.0, 4.0]);
let b = mm.b_packed(2, 2, &[5.0, 6.0, 7.0, 8.0]);
let mut c = vec![0.0; 4];
mm.run(&a, &b, &mut c, 1, 1);

实际应用示例:线性回归

use tract_linalg::matrix::Matrix;

// 样本数据 (y = 2x + 1 + noise)
let x_data = vec![0.0, 1.0, 2.0, 3.0, 4.0];
let y_data = vec![1.1, 2.9, 5.1, 7.2, 8.8];

// 构建设计矩阵
let n = x_data.len();
let mut design = Matrix::zeros(n, 2);
for (i, x) in x_data.iter().enumerate() {
    design[(i, 0)] = 1.0; // 截距项
    design[(i, 1)] = *x;
}

// 计算参数 (θ = (X^T X)^-1 X^T y)
let xt = design.transpose();
let xtx = xt.matmul(&design);
let xty = xt.matmul(&Matrix::column(y_data.clone()));
let theta = xtx.inverse().unwrap().matmul(&xty);

println!("拟合参数: 截距={:.2}, 斜率={:.2}", theta[(0, 0)], theta[(1, 0)]);

完整示例代码

use tract_linalg::matrix::Matrix;

fn main() {
    // 1. 矩阵创建和基本运算演示
    println!("=== 基本矩阵运算 ===");
    let a = Matrix::from_vec(2, 2, vec![1.0, 2.0, 3.0, 4.0]);
    let b = Matrix::from_vec(2, 2, vec![5.0, 6.0, 7.0, 8.0]);
    
    println!("矩阵A:\n{:?}", a);
    println!("矩阵B:\n{:?}", b);
    
    // 矩阵加法
    let sum = &a + &b;
    println!("A + B:\n{:?}", sum);
    
    // 矩阵乘法
    let product = a.matmul(&b);
    println!("A × B:\n{:?}", product);
    
    // 2. 高级运算演示
    println!("\n=== 高级矩阵运算 ===");
    let m = Matrix::from_vec(3, 3, vec![
        1.0, 2.0, 3.0,
        0.0, 1.0, 4.0,
        5.0, 6.0, 0.0
    ]);
    
    println!("矩阵M:\n{:?}", m);
    
    // 行列式计算
    let det = m.det();
    println!("行列式: {}", det);
    
    // 矩阵求逆
    if let Some(inverse) = m.inverse() {
        println!("逆矩阵:\n{:?}", inverse);
    }
    
    // 3. 性能优化演示
    println!("\n=== 性能优化演示 ===");
    let mut large_a = Matrix::zeros(100, 100);
    let mut large_b = Matrix::zeros(100, 100);
    let mut result = Matrix::zeros(100, 100);
    
    // 填充数据
    for i in 0..100 {
        for j in 0..100 {
            large_a[(i, j)] = (i + j) as f32;
            large_b[(i, j)] = (i * j) as f32;
        }
    }
    
    // 使用预分配内存的乘法
    large_a.matmul_into(&large_b, &mut result);
    println!("大型矩阵乘法完成");
    
    // 4. 线性回归应用
    println!("\n=== 线性回归应用 ===");
    let x_data = vec![0.0, 1.0, 2.0, 3.0, 4.0];
    let y_data = vec![1.1, 2.9, 5.1, 7.2, 8.8];
    
    // 构建设计矩阵
    let n = x_data.len();
    let mut design = Matrix::zeros(n, 2);
    for (i, x) in x_data.iter().enumerate() {
        design[(i, 0)] = 1.0; // 截距项
        design[(i, 1)] = *x;
    }
    
    // 计算回归参数
    let xt = design.transpose();
    let xtx = xt.matmul(&design);
    let xty = xt.matmul(&Matrix::column(y_data.clone()));
    let theta = xtx.inverse().unwrap().matmul(&xty);
    
    println!("线性回归结果:");
    println!("截距 = {:.4}", theta[(0, 0)]);
    println!("斜率 = {:.4}", theta[(1, 0)]);
}

注意事项

  1. 矩阵运算前请确保维度匹配
  2. 不是所有矩阵都可逆,调用inverse()会返回Option
  3. 对于非常大的矩阵,考虑使用稀疏矩阵实现

tract-linalg特别适合需要高性能数值计算的场景,如机器学习、科学计算和图形处理等领域。

回到顶部