3

3D 矩阵中的数据是由层(从上到下)生成的,我想将该数据与 2D 矩阵B相乘,但不是取每一层,我需要从第 1 层取一个向量,从第 2 层取一个向量和很快。

目前我正在做的是将这些向量从 3D 矩阵复制到 2D 矩阵tmpA然后与B相乘(使用 CUBLAS)并将结果存储在tmpB中,最后逐行复制到它在 3D 矩阵C中对应的位置。

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

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

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

编辑

令 M、N、P 为 3D 矩阵A的维度,该矩阵 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;
  }
}

希望这可以帮助。

4

1 回答 1

4

你不需要做内存拷贝!BLAS 和 LAPACK API 的创建方式可以让您指定起点、步长、前导维度的长度等。

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

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

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 相同的循环中创建和销毁流。这增加了开销。

于 2013-08-16T19:26:45.723 回答