在V100上使用CUDA了解张量核的平铺
我有一个从NVidia大量借用的玩具代码。我将随机生成的矩阵替换为从文件中读取矩阵的函数 使用此玩具代码并将两个大小为在V100上使用CUDA了解张量核的平铺,cuda,Cuda,我有一个从NVidia大量借用的玩具代码。我将随机生成的矩阵替换为从文件中读取矩阵的函数 使用此玩具代码并将两个大小为[2000 x 10000]*[10000 x 3008]的矩阵相乘,效果非常好。输出与预期一致 当我尝试一个大得多的乘法[20000 x 10000]*[10000 x 30000]时,输出出现了可怕的错误,其中2/3的行是0 我确信这是我不理解代码行的结果: // blockDim.x must be a multple of warpSize // 128x4 means
[2000 x 10000]*[10000 x 3008]
的矩阵相乘,效果非常好。输出与预期一致
当我尝试一个大得多的乘法[20000 x 10000]*[10000 x 30000]
时,输出出现了可怕的错误,其中2/3的行是0
我确信这是我不理解代码行的结果:
// blockDim.x must be a multple of warpSize
// 128x4 means we have 16 warps and a block computes a 64x64 output tile
blockDim.x = 128;
blockDim.y = 4;
gridDim.x = (MATRIX_M + (WMMA_M * blockDim.x / 32 - 1)) / (WMMA_M * blockDim.x / 32);
gridDim.y = (MATRIX_N + WMMA_N * blockDim.y - 1) / (WMMA_N * blockDim.y);
即使这不是我错误的根源,我仍然应该理解它在做什么。我了解设置blockDim.*
每个扭曲有32个线程,128*4/32=16个扭曲
问题:有人能给我解释一下
gridDim.x
和gridDim.y
的值和计算背后的逻辑吗?张量核的正确使用似乎对使用gridDim.
的正确值非常敏感。几个介绍性要点:
- 首先,tensor核心能力是在warp级别访问的。博客文章指出,“我们将采用的策略是让一个warp负责输出矩阵的单个16×16部分”,因此输出矩阵维度将驱动用于计算结果的CUDA网格维度。(还可以根据输出矩阵大小确定网格大小。更具体地说,他们为每个输出点分配一个线程。这里我们分配一个32线程扭曲来负责输出矩阵的一个16x16平铺。)代码使用
(即多少行)和WMMA_M
(即多少列)定义单个扭曲级别tensor core操作将处理的内容。这些值为16,这决定了在每个扭曲的输出中使用16x16平铺的选择WMMA_N
- 与CUDA中经常出现的情况一样,块尺寸可以是任意的,但它们通常会影响网格大小(变量)。扭曲存在于块级别,块中扭曲的数量有效地决定了每个块将处理输出矩阵中的16x16块。在这种特殊情况下,代码选择的块尺寸为128(
)乘以4(blockDim.x
)。这恰好是4个“宽”扭曲乘以4个“高”扭曲,因此每个块在输出中处理一组4x4瓷砖,这意味着每个块负责64x64输出点。请注意,主机代码中的这些blockDim.y
和blockDim
变量在逻辑上与CUDA设备代码中的gridDim
和blockDim
内置变量相分离(尽管最终在数字上相同)gridDim
- 鉴于上述情况,典型BLAS GEMM操作的m、n和k参数在这里具有相同的含义。m是左侧输入矩阵的行数。n是右侧输入矩阵的列数。k是左矩阵的列数,必须与右矩阵的行数匹配。因此m,n定义了输出矩阵的维数。这些在代码中分别表示为
和矩阵M
矩阵N
gridDim.x
和gridDim.y
所需的算法
WMMA_M
(该扭曲的输出平铺宽度责任),我们就有足够的线程覆盖输出矩阵的宽度WMMA\N
(该扭曲的输出平铺高度责任),我们就有足够的线程覆盖输出矩阵的高度。请注意,在这种情况下,y维度中扭曲的“高度”绝对为1,因为代码要求块宽度维度为扭曲大小的整数倍。因此,任何扭曲都有一个恒定的threadIdx.y
组件穿过扭曲blockDim.x
(在主机代码中),按上述1中的比例缩放,以获得x中的总网格尺寸(块数)。此除法操作是通常的CUDA“向上取整”整数除法操作,用于将块数缩放为等于或大于所需的线程数,以说明矩阵大小不能被块大小均匀整除gridDim.x = (MATRIX_M + (WMMA_M * blockDim.x / 32 - 1)) / (WMMA_M * blockDim.x / 32);
^ ^ ^ ^
| | | divided by the block size scaled for the
| | | portion of the output matrix it covers.
| | rounded up
| the matrix size
The grid in blocks is
同样,y轴网尺寸也是如此。唯一真正的区别是x(扭曲宽度)中的32个线程负责16x16输出平铺,其中