cuda中的矩阵乘法

sma*_*ato 5 cuda

说我想将两个矩阵相乘,50 乘 50。我有 2 种方法来安排线程和块。

a) 一个线程来计算结果矩阵的每个元素。所以我在线程中有一个循环乘以一行和一列。

b) 一个线程来做每次乘法。结果矩阵的每个元素需要 50 个线程。乘法完成后,我可以使用二进制归约来求和结果。

我不确定该走哪条路,所以我选择了 b。这并不理想。事实上它很慢。知道为什么吗?我的猜测是线程太多并且它们大部分时间都在等待资源,这是真的吗?

Jon*_*rsi 5

与高性能计算中的许多事情一样,理解性能的关键是理解内存的使用。

如果您使用一个线程 do 进行一次乘法运算,那么对于该线程,您必须从内存中提取两条数据,将它们相乘,然后进行一些对数的加法运算。这是一个多、一个加和一个位的三个内存访问 - 算术强度非常低。好消息是这样的任务有很多线程,每个线程只需要一点点内存/寄存器,有利于占用;但是内存访问工作比很差。

简单的单线程做点积方法也有同样的问题——每次乘法都需要两次内存访问才能加载。好消息是,对于整个点积,只有一个全局内存存储,并且您避免了不能扩展且需要大量同步的二进制缩减;不利的一面是现在线程更少了,至少您的 (b) 方法对您有用。

现在您知道应该有某种方法可以在每次内存访问中执行更多操作;对于方 NxN 矩阵,有 N^3 个工作要做乘法,但只有 3xN^2 个元素 - 所以你应该能够找到一种方法来进行每 2 次内存访问超过 1 次计算。

CUDA SDK 中采用的方法是最好的方法 - 矩阵被分解为瓦片,并使用您的 (b) 方法 - 每个输出元素一个线程 - 被使用。但关键在于线程的排列方式。通过将整个小的子矩阵从慢速全局内存中提取到共享内存中,并从那里进行计算,可以进行多次乘法并添加您从内存中读取的每个数字。这种方法是许多应用程序中最成功的方法,因为获取数据——无论是通过网络,还是从 CPU 的主内存,或 GPU 的片外访问——通常比处理数据花费的时间长得多。

NVidia 的 CUDA 页面(尤其是http://developer.nvidia.com/object/cuda_training.html)中有一些文档很好地描述了他们的 SDK 示例。