【问题标题】:CUBLAS Sgemm confusing resultsCUBLAS Sgemm 令人困惑的结果
【发布时间】:2018-07-30 05:25:00
【问题描述】:

对于大小为 4x3 和 2x3 的两个矩阵 X 和 Q 记忆中的样子

x = [0 1 2 3 4 5 6 7 8 9 10 11]
q = [3 4 5 6 7 8]

我尝试使用 cublas 乘法 cublasSgemm,但无法获得预期的结果。

因为它们以行优先顺序存储,所以它们应该被解释为 3x4 和 3x2,所以对我来说似乎

cublasSgemm(cublas_handle,
    CUBLAS_OP_T, CUBLAS_OP_N,
    q_rows_num, x_rows_num, dim,
    &alpha, // 1
    q_device, q_rows_num,
    x, x_rows_num,
    &beta, // 0
    x_q_multiplication, q_rows_num);

在哪里

dim = 3
x_rows_num = 4
q_rows_num = 2

会起作用,但在那种情况下我会出错

** On entry to SGEMM  parameter number 8 had an illegal value

我也尝试过改组参数,但找不到任何可行的设置。

那么是否可以在不改变列优先顺序的情况下将它们相乘?

编辑:

所以我在这个工作示例中所做的更改得到了预期的结果:

#include <cublas_v2.h>

#include <iostream>
#include <cuda.h>
#include <cuda_runtime.h>

int main()
{
    int x_rows_num = 4;
    int q_rows_num = 2;
    int dim = 3;

int N = x_rows_num*dim;
int M = q_rows_num*dim;


float *x, *q, *x_q_multiplication;
cudaMallocManaged(&x, N*sizeof(float));
cudaMallocManaged(&q, M*sizeof(float));
cudaMallocManaged(&x_q_multiplication, q_rows_num*x_rows_num*dim);

for (int i = 0; i< N; i++) x[i] = i*1.0f;
for (int i = 0; i< M; i++) q[i] = (i + 3)*1.0f;

float *q_device;
cudaMallocManaged(&q_device, M*sizeof(float));
cudaMemcpy(q_device, q, M*sizeof(float), cudaMemcpyHostToDevice);

cublasHandle_t handle;
cublasCreate(&handle);

float alpha = 1.f;
float beta = 0.f;
cublasSgemm(handle,
    CUBLAS_OP_T, CUBLAS_OP_N,
    x_rows_num, q_rows_num, dim,
    &alpha, 
    x, dim, 
    q, dim,  
    &beta, 
    x_q_multiplication, x_rows_num);
cudaDeviceSynchronize();

for (int i = 0; i < q_rows_num*x_rows_num; i++) std::cout << x_q_multiplication[i] << " ";

cudaFree(x);
cudaFree(q);
cudaFree(x_q_multiplication);
return 0;
}

但我仍然不确定为什么 dim 成为主要维度

【问题讨论】:

  • cublasSgemm(cublas_handle, CUBLAS_OP_T, CUBLAS_OP_N, q_rows_num, x_rows_num, dim, &amp;alpha, q_device, dim, x, dim, &amp;beta, x_q_multiplication, q_rows_num); 工作,但我不知道为什么,我认为前导 dim 将始终是原始行数。
  • @RobertCrovella 关于您的第一条评论我在原始帖子中附上了示例,并更改了前导维度。关于您的第二条评论,我感到有些冒犯,因为正如您在原始示例(cublasSgemm 执行)中看到的那样,我想乘以 q^t * x 并且对 cublas 的解释是 2x3 * 3x4 矩阵乘法,但您似乎停止阅读在它之前。我还认为,很明显,预期结果只是以任何顺序乘法的结果。

标签: cuda blas cublas


【解决方案1】:

您最初的 CUBLAS 调用:

cublasSgemm(cublas_handle,
    CUBLAS_OP_T, CUBLAS_OP_N,
    q_rows_num, x_rows_num, dim,
    &alpha, // 1
    q_device, q_rows_num,
    x, x_rows_num,
    &beta, // 0
    x_q_multiplication, q_rows_num);

接近正确。您对主要尺寸应该是什么的解释是正确的。你错的是Op 说明符。如果两个矩阵都是行主要排序的,并且第一个数组需要按其(行主要)转置顺序读取,那么操作应该是:

#include <cublas_v2.h>

#include <cstring>
#include <iostream>
#include <cuda.h>
#include <cuda_runtime.h>

int main()
{
    int x_rows_num = 4;
    int q_rows_num = 2;
    int dim = 3;

    int N = x_rows_num*dim;
    int M = q_rows_num*dim;

    float x0[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
    float q0[6]  = {3, 4, 5, 6, 7, 8 };

    float *x, *q, *x_q_multiplication;
    cudaMallocManaged(&x, N*sizeof(float));
    cudaMallocManaged(&q, M*sizeof(float));
    cudaMallocManaged(&x_q_multiplication, q_rows_num*x_rows_num*dim);

    std::memcpy(x, x0,  N*sizeof(float));
    std::memcpy(q, q0,  M*sizeof(float));

    float *q_device;
    cudaMallocManaged(&q_device, M*sizeof(float));
    cudaMemcpy(q_device, q, M*sizeof(float), cudaMemcpyHostToDevice);

    cublasHandle_t handle;
    cublasCreate(&handle);

    float alpha = 1.f;
    float beta = 0.f;
    cublasSgemm(handle,
            CUBLAS_OP_N, CUBLAS_OP_T,
            q_rows_num, x_rows_num, dim,
            &alpha, // 1
            q_device, q_rows_num,
            x, x_rows_num,
            &beta, // 0
            x_q_multiplication, q_rows_num);

    cudaDeviceSynchronize();

    for (int i = 0; i < q_rows_num*x_rows_num; i++) std::cout << x_q_multiplication[i] << " "; std::cout << std::endl;

    cudaFree(x);
    cudaFree(q);
    cudaFree(x_q_multiplication);
    return 0;
}

这是为我做的:

$ nvcc -arch=sm_52 cublas_trans.cu -o cublas_trans -lcublas 
$ ./cublas_trans 
76 88 91 106 106 124 121 142 

我相信这是正确的答案。

顺便说一句,罗伯特·克罗维拉(Robert Crovella)现在删除的评论(您说您对此感到冒犯)是 100% 正确的。我怀疑他像我一样阅读了您最初的 CUBLAS 调用,解释了参数并得出结论,就像我所做的那样,正如 CUBLAS 本身所做的那样,您正在尝试将 3x4 矩阵和 3x2 矩阵相乘。这就是引发无效参数错误的原因。

【讨论】:

  • 我认为预期的结果会类似于 link 和我在封闭的 main 方法中得到的结果。另一件事也许我错了,在你的例子中我可以看到你想要乘以 Q*X。它们的共同维度是 3,因此假设我们必须将 Q 解释为由于列/行主要排序而转置,所以我认为 Q 应该被转置以使排序转换无效。
  • 您链接到的 alpha 不是您问题中描述的内容。您的问题中描述的是:pastebin.com/LZhL0064
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-11
相关资源
最近更新 更多