行主序矩阵X(4×3)与Q(2×3)调用cublasSgemm失败,求无需转置的乘法方案
首先得明确:cublas默认是列主序存储,但完全不需要把行主序矩阵转成列主序再计算——只要利用好transa/transb参数和维度调整,直接用原始内存就能搞定。
先理清楚你的矩阵维度问题:你说的X是4×3行主序,Q是2×3行主序,这两个矩阵直接相乘维度不匹配(4×3的列数是3,2×3的行数是2,不相等),所以你应该是想算X × Q^T(得到4×2的结果)或者**Q × XT**(得到2×4的结果)——我先以X×QT为例给你讲具体怎么调参数。
核心逻辑:行主序矩阵 ≈ 列主序的转置矩阵
行主序的M×N矩阵,在内存里的存储顺序,和列主序的N×M转置矩阵完全一致。比如你的X是4×3行主序,它的内存布局就等于列主序下XT(3×4)的布局;Q是2×3行主序,内存布局等于列主序下QT(3×2)的布局。
我们要算的行主序Y = X × Q^T,等价于列主序下的Y^T = Q × X^T(矩阵转置的乘法性质)。而要在cublas里用原始内存实现这个计算,只需要通过trans参数把列主序的转置矩阵“还原”成我们需要的原矩阵即可。
具体代码示例
假设你已经初始化了cublas句柄handle,矩阵X、Q、Y的设备内存都已分配好,alpha=1.0,beta=0.0(直接覆盖Y的初始值):
float alpha = 1.0f; float beta = 0.0f; cublasStatus_t status = cublasSgemm( handle, CUBLAS_OP_T, // 把Q对应的列主序矩阵(Q^T)转置成原矩阵Q(2×3) CUBLAS_OP_T, // 把X对应的列主序矩阵(X)转置成X^T(3×4) 2, // m:Y^T的行数 = Q的行数 = 2 4, // n:Y^T的列数 = X^T的列数 =4 3, // k:Q的列数 = X^T的行数 =3 &alpha, Q, // Q的设备内存地址(行主序2×3) 3, // lda:Q对应的列主序矩阵(Q^T)的行数 =3 X, // X的设备内存地址(行主序4×3) 4, // ldb:X对应的列主序矩阵(X)的行数 =4 &beta, Y, // Y的设备内存地址(行主序4×2) 2 // ldc:Y^T对应的列主序矩阵的行数 =2 );
参数说明(避免踩坑)
transa/transb:设为CUBLAS_OP_T就是告诉cublas,把传入的列主序矩阵(实际是我们的行主序矩阵)转置后再参与计算;如果是CUBLAS_OP_N就是不转置。lda/ldb/ldc:对应列主序矩阵的行数,也就是我们行主序矩阵的列数(因为行主序M×N对应列主序N×M,行数是N)。比如行主序Q是2×3,对应列主序Q^T是3×2,所以lda=3。m/n/k:对应列主序下结果矩阵Y^T的行数、列数,以及相乘的公共维度,一定要和trans参数对应上。
如果你想算Q × X^T,只需要调整一下参数:把m改成4,n改成2,trans参数和lda/ldb对应调整就行,原理完全一样。
之前你尝试把X当3×4、Q当3×2处理报错,大概率是lda/ldb或者m/n/k的参数没匹配对——比如把X当3×4列主序时,lda应该设为3,但如果对应的trans参数没设对,就会出现维度不匹配的错误。
内容的提问来源于stack exchange,提问作者zinsek

