You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

cuBLAS矩阵乘法结果与NumPy不一致问题排查

问题

尝试使用cuBLAS执行矩阵乘法,并将结果与NumPy对比,但二者结果存在差异。

C++ cuBLAS代码

#include <iostream>
#include <vector>
#include <cublas_v2.h>
#include <cuda_runtime.h>

void printMatrix(const std::vector<double>& matrix, int rows, int cols) {
    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j) {
            std::cout << matrix[i * cols + j] << " ";
        }
        std::cout << std::endl;
    }
}

int main() {
    // Initialize cuBLAS
    cublasHandle_t handle;
    cublasCreate(&handle);

    // Matrix dimensions
    int m = 3;
    int n = 2;
    int k = 4;

    // Matrix A: shape (3, 4)
    std::vector<double> A = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0};

    // Matrix B: shape (4, 2)
    std::vector<double> B = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0};

    // Matrix C: shape (3, 2)
    std::vector<double> C(m * n, 0.0);

    // Allocate device memory
    double* d_A;
    double* d_B;
    double* d_C;
    cudaMalloc(&d_A, A.size() * sizeof(double));
    cudaMalloc(&d_B, B.size() * sizeof(double));
    cudaMalloc(&d_C, C.size() * sizeof(double));

    // Copy data from host to device
    cublasSetVector(A.size(), sizeof(double), A.data(), 1, d_A, 1);
    cublasSetVector(B.size(), sizeof(double), B.data(), 1, d_B, 1);

    // Perform matrix multiplication using cuBLAS
    double alpha = 1.0;
    double beta = 0.0;
    cublasDgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, m, n, k, &alpha, d_A, m, d_B, k, &beta, d_C, m);

    // Copy result from device to host
    cublasGetVector(C.size(), sizeof(double), d_C, 1, C.data(), 1);

    // Print the result
    std::cout << "Result matrix C:" << std::endl;
    printMatrix(C, m, n);

    // Verify the result
    std::vector<double> expected_C = {50.0, 60.0, 114.0, 140.0, 178.0, 220.0};
    bool success = true;
    for (int i = 0; i < m * n; ++i) {
        if (std::abs(C[i] - expected_C[i]) > 1e-6) {
            success = false;
            break;
        }
    }

    if (success) {
        std::cout << "Test passed!" << std::endl;
    } else {
        std::cout << "Test failed!" << std::endl;
    }

    // Free device memory
    cudaFree(d_A);
    cudaFree(d_B);
    cudaFree(d_C);

    // Destroy cuBLAS handle
    cublasDestroy(handle);

    return 0;
}

NumPy计算结果

>>> import numpy as np
>>> a = np.array(list(range(1, 13))).reshape(3, 4)
>>> b = np.array(list(range(1, 9))).reshape(4, 2)
>>> np.matmul(a, b)
array([[ 50,  60],
       [114, 140],
       [178, 220]])

cuBLAS输出结果

Result matrix C:
70 80 
90 158 
184 210 
Test failed!

问题原因与修复方案

核心原因

cuBLAS默认采用**列优先(Fortran风格)存储矩阵,而你的代码中矩阵A、B是按行优先(C风格)**初始化的,同时cublasDgemm的leading dimension(lda、ldb、ldc)参数设置错误,导致cuBLAS读取矩阵的方式与预期不符,计算出错误结果。

在cublasDgemm中,lda表示矩阵A的leading dimension:

  • 对于列优先存储的M×K矩阵,lda等于矩阵的行数M(每列有M个元素,下一列第一个元素与当前列第一个元素的间隔是M)。
  • 但你的矩阵A是行优先存储的3×4矩阵,此时对应的leading dimension应该是矩阵的列数K=4(每行有4个元素,下一行第一个元素与当前行第一个元素的间隔是4)。

同理,矩阵B是行优先的4×2矩阵,ldb应设为2;结果矩阵C是行优先的3×2矩阵,ldc应设为2。

修复代码

修改cublasDgemm的调用参数,调整lda、ldb、ldc的值:

// 修正后的矩阵乘法调用
cublasDgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, m, n, k, &alpha, d_A, k, d_B, n, &beta, d_C, n);

另一种修复思路

如果你想保持leading dimension参数为矩阵行数,也可以将矩阵转置后传递给cuBLAS,并设置转置操作参数:

// 转置矩阵操作,此时A和B按列优先读取对应原行优先矩阵的转置
cublasDgemm(handle, CUBLAS_OP_T, CUBLAS_OP_T, m, n, k, &alpha, d_A, m, d_B, k, &beta, d_C, m);

验证结果

修复后,cuBLAS的输出结果将与NumPy完全一致:

Result matrix C:
50 60 
114 140 
178 220 
Test passed!

内容的提问来源于stack exchange,提问作者musako

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 21:54:52