乘以3D矩阵和2D矩阵CUDA

时间:2013-08-16 14:47:52

标签: cuda gpgpu

3D矩阵中的数据是由图层(从上到下)生成的,我希望将这些数据与2D矩阵 B 相乘,但不需要采用每个图层我需要采用矢量来自第1层,第2层的向量,依此类推。

目前我正在做的是将这些矢量从3D矩阵复制到2D矩阵 tmpA 然后乘以 B (使用CUBLAS)并将结果存储在< strong> tmpB 最终逐行复制回到3D矩阵 C 中对应的位置。

总的来说,我的整个应用程序的运行速度至少是CPU版本的两倍,但在我看来,从设备到设备的那些内存副本(甚至)在性能上都不是很好。

进行此计算的更好方法是什么?我在考虑在乘法之前重新排列数据,以避免内存副本。

3D矩阵 A C 以及2D矩阵 B 已经存在于GPU的内存中。

修改

设M,N,P是设备内存中线性阵列中以行主要顺序存储的3D矩阵 A 的尺寸。我的代码如下所示:

cudaMalloc((void**)&d_tmpIn, sizeof(float)*M*P);
cudaMalloc((void**)&d_tmpOut, sizeof(float)*M*P);
cudaMalloc((void**)&d_C, sizeof(float)*M*N*P);

for (int iN = 0; iN < N; iN++)
{
  dst = d_tmpIn;
  for (int iM = 0; iM < M; iM++)
  {
    cudaMemcpy(dst, &(d_A[iN*P+0+iM*N*P]), sizeof(float)*P, cudaMemcpyD2D);
    dst += P;
  }

  cublasDgemm(cublasHandle, CUBLAS_OP_N, CUBLAS_OP_N, P, M, M, &alpha, d_tmpIn, P, d_B, M, &beta, d_tmpOut, P);

  src = d_tmpOut;
  for (int iM = 0; iM < M; iM++)
  {
    cudaMemcpy(&(d_C[iN*P+0+iM*N*P]), src, sizeof(float)*P, cudaMemcpyD2D);
    src += P;
  }
}

希望这有帮助。

1 个答案:

答案 0 :(得分:4)

您不需要做内存复制! BLAS和LAPACK API的创建方式使您可以指定起点,步幅长度,前导尺寸的长度等。

这样你可以按原样使用3D数组A和C,但是使用正确的参数调用cublasDgemm。

在您的情况下(如果我正确理解代码),看起来每个矩阵应该是P X M并且您有N个。但看起来3D阵列的排列方式为PxNxM。因此,如果不为d_tmpInd_tmpOut分配内存,您可以执行以下操作:A的行数为P。列数为M。但是,应将前导维度(lda)称为N * PC也是如此。

int lda = N * P;
int ldc = N * P;
for (int iN = 0; iN < N; iN++)
{
  double *d_tmpIn = d_A + iN * P;
  double *d_tmpOut = d_C + iN * P;
  cublasSetStream(streams[iN]); // Optional
  cublasDgemm(cublasHandle, CUBLAS_OP_N, CUBLAS_OP_N,
              P, M, M, &alpha, d_tmpIn, lda, d_B, M, &beta, d_tmpOut, ldc);

}

您还可以创建iN流并在单独的流中运行每个cublas。请注意,只有当M和P足够小时(即GPU尚未计算饱和)时,这才有用。

编辑如果您计划继续使用流,请尝试在程序开头创建一次并重新使用它们。不要在与Dgemm相同的循环中创建和销毁流。这增加了开销。