Matrix CUDA动态矩阵乘法

Matrix CUDA动态矩阵乘法,matrix,matrix-multiplication,cuda,Matrix,Matrix Multiplication,Cuda,我一直在尝试编写的简单程序的想法是从用户那里获取输入,以查看矩阵的乘法大小 我希望将输入x乘以x,目前我不希望将两个不同的大小相乘 你们建议我怎么做 很抱歉,我的问题不够清楚,我想修改这个内核,使它可以处理任何大小的矩阵(其中x和y是等价的,以保持简单)。而不是16的倍数 我不确定您是否需要我当前的代码,但以下是内核代码: // CUDA Kernel __global__ void matrixMul( float* C, float* A, float* B, int wA, int wB,

我一直在尝试编写的简单程序的想法是从用户那里获取输入,以查看矩阵的乘法大小

我希望将输入x乘以x,目前我不希望将两个不同的大小相乘

你们建议我怎么做

很抱歉,我的问题不够清楚,我想修改这个内核,使它可以处理任何大小的矩阵(其中x和y是等价的,以保持简单)。而不是16的倍数

我不确定您是否需要我当前的代码,但以下是内核代码:

// CUDA Kernel
__global__ void matrixMul( float* C, float* A, float* B, int wA, int wB,size_t block_size)
{
    int bx = blockIdx.x;
    int by = blockIdx.y;
    int tx = threadIdx.x;
    int ty = threadIdx.y;

    int aBegin = wA * block_size * by;
    int aEnd   = aBegin + wA - 1;
    int aStep  = block_size;

    int bBegin = block_size * bx;

    int bStep  = block_size * wB;
    float Csub=0;

    for (int a = aBegin, b = bBegin; a <= aEnd; a += aStep, b += bStep) 
    {
        extern __shared__ float As[];
        extern __shared__ float Bs[];
        extern __shared__ float smem[];

        smem[ty*block_size+tx] = A[a + wA * ty + tx];

        smem[block_size*block_size+ty*block_size+tx]  = B[b + wB * ty + tx];

        __syncthreads();

        for (int k = 0; k < block_size; ++k)
            Csub += smem[ty*block_size+k] * smem[block_size*block_size+k*block_size+tx] ;

        __syncthreads();
    }

    int c = wB * block_size * by + block_size * bx;
    C[c + wB * ty + tx] = Csub;


}
矩阵B,2x2填充至16x16:

5.000 0.000 9.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
7.000 4.000 8.000 7.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
所以我得到的C的结果是正确的:

35.000 20.000 40.000 35.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
 0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
 0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
 0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
 0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
 0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
 0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
 0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
 0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
 0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
 0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
 0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
 0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
 0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
 0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
 0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
但是,如果去掉零,则矩阵应为: A:

B:

C应为:

35.000 20.000
63.000 36.000

然而,这两个矩阵C是不一样的。

这不是一个非常清楚的问题,所以这个答案是基于您之前在几个非常类似的问题中提出的猜测

理解如何进行这类运算的一个很好的起点是回到起点,从第一原理出发思考矩阵乘法问题。您对计算两个矩阵的点积的代码感兴趣,C=AB。您的限制是,您使用的内核只能计算矩阵的乘积,这些矩阵是某些内部块大小的整数倍。那你能做什么呢

看待这个问题的一种方法是想象AB矩阵是相同的。矩阵乘法可以这样写:

由此产生的矩阵C可以由AB中八个子矩阵的乘积组合而成:

也许这不是很明显,这有助于解决这个问题,但是让我们考虑一个具体的例子:

  • 您有一个最佳矩阵乘法内核,它使用32的内部块大小,并且只有当矩阵是该块大小的整数倍时才正确
  • 你有一对1000x1000的方阵要乘
  • 这些第一个事实意味着您的内核只能正确地解决1024x1024产品或992x992产品,而不能解决所需的1000x1000操作

    如果您决定使用1024x1024产品,您可以使用块分解思想来表述如下问题:

    其中,Onn表示大小合适的零矩阵。现在有一对
    1024x1024
    矩阵,它们的乘积将导致

    即,左侧上部块是一个1000x1000矩阵,包含AB。这实际上是零填充,以获得正确的结果。在本例中,这意味着执行的计算比所需的多7%。than是否重要可能取决于具体的应用程序

    第二种方法是使用基本内核计算一个992x992产品,然后制定一个策略来处理计算的块分解版本中的其他七个产品,如下所示:

    其中A11和B11是992x992矩阵,Onn和以前一样是零矩阵。在第一次检查时,这看起来不是很有帮助,但值得记住的是,所有用于生成右侧矩阵的计算只包含计算矩阵乘积所需的总计算量的1.2%左右。当GPU进行主计算时,可以在主机CPU上轻松完成这些操作,然后将它们添加到GPU结果中以形成最终矩阵。因为CUDAAPI是异步的,所以大部分主机计算可以完全隐藏,并且实际上是免费的


    这个答案包含两种策略,可以在不改变当前内核代码的一行以上的情况下实现您所要求的功能。显然还有第三种方法,那就是更彻底地修改内核本身,但是如果解决方案不起作用,你应该先自己尝试一下,然后寻求帮助。

    你的问题是什么?你是在问如何从用户那里获得输入吗?如果我正确理解了你之前的问题,你真正的问题是如何修改这个内核代码(本身是CUDA SDK矩阵乘法示例的一个非常简单的修改版本),以便它可以用于任意大小的矩阵乘法,而不是内核块大小的整数倍。您能否编辑您的问题以反映这一点?目前还不清楚你到底在问什么。@Talonmes,你是对的。这正是我想要的Hi Dan,你找到上面实现的正确代码了吗?@JohnSmith我找到了,谢谢。但我认为它只限于16个街区。我只是看一下,看能不能改一下。谢谢你的解释。为了时间,我将使用填充解决方案。我很好奇你在哪里提出了“计算量增加7%”。我尝试了零填充,但结果不正确。我花了一些时间试图弄明白,但在填充过程中,它似乎位于0。请参阅我编辑的OP以获取更新。您在示例中执行零填充的方式是错误的。7%的数字来自2*1024^3和2*1000^3之间的差异,这是两种尺寸下点积的运算计数。您好Talonmes,谢谢您的回答。您提到该策略需要更改一行代码。所以这不是关于在矩阵中创建矩阵,而是有一个if语句来检查边界,对吗?鉴于Dan上面的代码,我该如何计算边界?谢谢
    7.000 4.000
    8.000 7.000
    
    35.000 20.000
    63.000 36.000