2013-08-16 284 views
3

3D矩阵中的数据是由层(从顶部到底部)生成的,我想将该数据与2D矩阵相乘,但不是采取每个需要拍摄的图层来自第1层的矢量,来自第2层的矢量等等。乘以3D矩阵和2D矩阵CUDA

目前我在做什么是对那些矢量从3D矩阵复制到一个二维矩阵TMPA然后用(使用CUBLAS),结果存储在繁殖tmpB终于逐行复制回到它在3D矩阵中对应的位置C。总体而言,我的整个应用程序运行速度至少比CPU版本快两倍,但在我看来,从设备到设备制作的这些内存拷贝(甚至是)对于性能来说并不是很好。

什么是更好的方式来做这种计算?我在考虑在乘数之前重新排列数据,以避免内存拷贝。

的3D矩阵Ç和2D矩阵已经在GPU的存储器中。

EDIT

设M,N,P是三维矩阵存储以行优先顺序上该设备的存储器中的线性阵列中的甲的尺寸。我的代码如下所示:

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; 
    } 
} 

希望这会有所帮助。

+0

您能描述一下数据如何存储在GPU内存中以及CUBLAS调用您用来执行此计算的内容吗?这并不是所有这些都清楚你实际上试图从文本中做什么(提示:方程式和短代码片段胜过千言万语) – talonmies

+0

通常情况下,cudaMemcpyD2D应该很快。你有没有分析应用程序,以确定时间花在哪里? –

+0

@RobertCrovella的确他们很快,但我想知道是否有更好的方法来避免这些内存拷贝。我会看看给出的答案,看看是否有帮助。 – BRabbit27

回答

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

+0

矩阵应该是'MXP'并且有N个(我正在使用行主要顺序,并且只是遵循[本指南](http://peterwittek.com/2013/06/cublas-matrix-c-style/))避免转换到列专业),3D阵列排列为MxNxP。 – BRabbit27

+0

我认为我的部分有一个错误,而不是乘以** AB **应该是** BA **(否则尺寸不一致)。混乱是因为使用cublas我不得不颠倒矩阵,以避免从行主变为列主顺序(如上面的指导中所述)。无论如何,我明白了你的观点,我会马上尝试,并带着结果/怀疑回来。谢谢 ! – BRabbit27

+0

我在想使用流,但我不知道“足够小”是什么意思。通常M约为3到10,P约为2e6 - 4e6,N可能在30 - 1800之间。我描述了应用程序,显然我没有使GPU饱和,你能否给出一些关于使用流的建议。谢谢。 – BRabbit27