使用 CUDA 进行矩阵乘法:2D 块与 1D 块

Posted

技术标签:

【中文标题】使用 CUDA 进行矩阵乘法:2D 块与 1D 块【英文标题】:Matrix multiplication with CUDA: 2D blocks vs 1D blocks 【发布时间】:2015-03-09 18:15:25 【问题描述】:

我目前正在做一个家庭作业,我必须实现几个矩阵乘法内核,尝试几个网格和块维度并对结果进行基准测试。

我的第一个内核使用 1D 线程块(其中每个线程块负责计算一个 1×n 子矩阵,每个线程负责计算该子矩阵中的一个元素),我的第二个内核是 2D 块(其中每个线程块负责计算一个方形子矩阵,每个线程负责计算该子矩阵中的一个元素)。他们都在使用全局内存。

我使用大小为 4096*4096 的矩阵启动了几项测试,对于 1D 内核,每个块的线程范围从 64 到 1024,对于 2D 内核,从 8*8 到 32*32。我希望两个内核都能获得相同的性能,但不知何故,2D 内核似乎总是稍微快一些。

这是否可以通过使用 2D 线程块在同一个“区域”中发生更多内存访问以及利用某种缓存机制这一事实来解释?

【问题讨论】:

是的,如果您使用的是缓存内存访问。 【参考方案1】:

是的,使用 2D 块可以减少每个块访问的不同矩阵元素的数量。这个简单的计算应该很清楚:

Calculation of A*B=C 
Matrix size: 4096*4096

Block size: 1024x1
Number of different elements read from Matrix A: 1 row = 4096 elements
Number of different elements read from Matrix B: 1024 columnes = 4096*1024
Sum: 4193280

Block size: 32x32
Number of different elements read from Matrix A: 32 rows = 32*1024
Number of different elements read from Matrix B: 32 columnes = 32*1024
Sum: 65536

要在结果矩阵中计算 C(i,j),您必须从矩阵 A 中读取第 i 行,从矩阵 B 中读取第 j 列。

因此,如果要计算结果矩阵的第一行,则必须读取第一行的 N 次(假设矩阵为 NxN),并且矩阵 B 中的每一列都读取一次。

4x1 Block

            v v v v
>0 1 2 3    0 1 2 3     x x x x
 4 5 6 7    4 5 6 7     - - - -
 8 9 A B    8 9 A B     - - - -
 C D E F    C D E F     - - - -

2x2 Block

            v v  
>0 1 2 3    0 1 2 3     x x - -
>4 5 6 7    4 5 6 7     x x - -
 8 9 A B    8 9 A B     - - - -
 C D E F    C D E F     - - - -

箭头指向计算x 指示的元素所需的行和列。

【讨论】:

或许您可以进一步解释一下您的“简单计算”? @op,但请注意,在您描述的实现中,您并没有直接重用值。如果您使用缓存方法(fermi 默认使用只读缓存或在开普勒中启用缓存),则好处是值在缓存中的概率更高,因为您在更高的位置重用值。

以上是关于使用 CUDA 进行矩阵乘法:2D 块与 1D 块的主要内容,如果未能解决你的问题,请参考以下文章

使用 Numba 进行矩阵乘法时出现 CUDA 内存不足错误

[CUDA]CUDA编程实战四——矩阵乘法

某些 CUDA 计算因块尺寸较大(< 1024)而失败

使用 2D std::vector 对 SYCL 进行矩阵乘法

大型矩阵的 CUDA 矩阵乘法中断

CUDA 矩阵乘法优化