加速 GPU vs CPU 用于矩阵运算
Speedup GPU vs CPU for matrix operations
我想知道有多少 GPU 计算可以帮助我加快模拟速度。
我的代码的关键部分是矩阵乘法。基本上,代码类似于以下 python 代码,其中包含 1000 阶矩阵和长 for 循环。
import numpy as np
m_size = 1000
sim_length = 50
a = np.random.rand(m_size, m_size)
b = np.random.rand(m_size, m_size)
for j in range(sim_length):
result = np.dot(a,b)
注意:我的矩阵很密集,大部分是随机的,for 循环是用 cython 编译的。
我天真的猜测有两个因素:
- 更多并行线程(当前为 1 阶线程,GPU 为 100 阶线程?)--> 100 阶加速? [Source 已经过时了,从 2011 年开始]
- 较低的处理器频率(当前为 3Ghz,GPU 通常为 2Ghz)--> 忽略
我认为这个观点太天真了,所以我错过了什么?
一般来说,GPU 在高度并行的简单任务(这就是它们的用途)上比 CPU 快得多,例如乘以大矩阵,但 GPU 计算存在一些问题:
- 在普通 RAM 和图形 RAM 之间传输数据需要时间
- loading/starting GPU 程序需要一些时间
所以虽然乘法本身可能快 100(或更多)倍,但您可能会体验到实际上小得多的加速甚至减速
与 CPU 相比,GPU "stupid" 存在更多问题,例如分支代码的大幅减速、必须手动处理缓存以及其他可以为 GPU 编写快速程序的问题具有挑战性。
矩阵乘法性能
如果你使用numpy
,你可能正在使用一个BLAS库作为计算后端,例如ATLAS、OpenBLAS、MKL等。当你使用最快的一个MKL时,你可以找到一个最近的性能基准,在最近的 Nvidia GPU K40m 和 Intel Xeon 12 核 E5-2697 v2 @ 2.70GHz 之间
https://developer.nvidia.com/cublas
其中 K40m 比 12 线程 E5-2697 快 6 倍。考虑到 MKL 在多核上的扩展性很好 CPU。 K40m 比 1 线程 E5-2697 快 72 倍。另请注意,1000-dim 几乎是充分利用 GPU 和 CPU 的下限。较小的矩阵大小通常会导致 GPU 性能下降更多。
如果您为 numpy
使用较慢的 BLAS 后端,请使用 GNU 许可的 ATLAS。然后,您可以在此处找到 MKL 和 ATLAS 之间的比较
https://software.intel.com/en-us/intel-mkl/benchmarks#DGEMM-ATLAS
其中 MKL 比 ATLAS 快 2~4 倍。
对于 Nvidia GPU,唯一广泛使用的后端是 CUDA 的 cuBLAS,因此性能不会像 ATLAS vs. MKL 那样有太大变化。
数据传输
正如@janbrohl所说,主机RAM和GPU设备内存之间的数据传输是影响整体性能的重要因素。这是数据传输速度的基准。
CUDA - how much slower is transferring over PCI-E?
给定矩阵大小,您实际上可以分别计算出计算和数据传输的绝对时间。这些可以帮助您更好地评估性能。
为了最大限度地提高 GPU 的性能,您可能需要重新设计程序以最小化数据传输,方法是将所有计算操作移至 GPU,而不仅仅是矩阵乘法。
使用 opencl api,我在 1280 核 HD7870(甚至不是主流桌面级 gpu)上尝试了 8k X 8k x 8k X 8k 乘法,它花了大约 0.99 秒,这意味着大约 5400 亿次加法和 5400 亿次乘法也意味着 1.1 Tflops(其广告中所说的峰值的 %40)。高端桌面级 CPU 只有 0.2 - 0.3 Tflops(峰值),不包括其集成的 GPU。因此,最好的 cpu 在性能和每瓦性能以及每美元性能方面甚至无法达到中低端 gpu。
性能的关键选项:
- 像 32x32 或 48x48 这样的补丁中的计算(每个计算单元都有一组线程,所以每个线程计算补丁的一部分或 column/row 的所有补丁的总和)
- 像 Strassen 的算法一样以指数方式更快。
- 流水线化读取、写入和计算操作,以便连续迭代有收获。
针对硬件差异进行优化
使用具有 1 到 4 选项的库
我想知道有多少 GPU 计算可以帮助我加快模拟速度。
我的代码的关键部分是矩阵乘法。基本上,代码类似于以下 python 代码,其中包含 1000 阶矩阵和长 for 循环。
import numpy as np
m_size = 1000
sim_length = 50
a = np.random.rand(m_size, m_size)
b = np.random.rand(m_size, m_size)
for j in range(sim_length):
result = np.dot(a,b)
注意:我的矩阵很密集,大部分是随机的,for 循环是用 cython 编译的。
我天真的猜测有两个因素:
- 更多并行线程(当前为 1 阶线程,GPU 为 100 阶线程?)--> 100 阶加速? [Source 已经过时了,从 2011 年开始]
- 较低的处理器频率(当前为 3Ghz,GPU 通常为 2Ghz)--> 忽略
我认为这个观点太天真了,所以我错过了什么?
一般来说,GPU 在高度并行的简单任务(这就是它们的用途)上比 CPU 快得多,例如乘以大矩阵,但 GPU 计算存在一些问题:
- 在普通 RAM 和图形 RAM 之间传输数据需要时间
- loading/starting GPU 程序需要一些时间
所以虽然乘法本身可能快 100(或更多)倍,但您可能会体验到实际上小得多的加速甚至减速
与 CPU 相比,GPU "stupid" 存在更多问题,例如分支代码的大幅减速、必须手动处理缓存以及其他可以为 GPU 编写快速程序的问题具有挑战性。
矩阵乘法性能
如果你使用numpy
,你可能正在使用一个BLAS库作为计算后端,例如ATLAS、OpenBLAS、MKL等。当你使用最快的一个MKL时,你可以找到一个最近的性能基准,在最近的 Nvidia GPU K40m 和 Intel Xeon 12 核 E5-2697 v2 @ 2.70GHz 之间
https://developer.nvidia.com/cublas
其中 K40m 比 12 线程 E5-2697 快 6 倍。考虑到 MKL 在多核上的扩展性很好 CPU。 K40m 比 1 线程 E5-2697 快 72 倍。另请注意,1000-dim 几乎是充分利用 GPU 和 CPU 的下限。较小的矩阵大小通常会导致 GPU 性能下降更多。
如果您为 numpy
使用较慢的 BLAS 后端,请使用 GNU 许可的 ATLAS。然后,您可以在此处找到 MKL 和 ATLAS 之间的比较
https://software.intel.com/en-us/intel-mkl/benchmarks#DGEMM-ATLAS
其中 MKL 比 ATLAS 快 2~4 倍。
对于 Nvidia GPU,唯一广泛使用的后端是 CUDA 的 cuBLAS,因此性能不会像 ATLAS vs. MKL 那样有太大变化。
数据传输
正如@janbrohl所说,主机RAM和GPU设备内存之间的数据传输是影响整体性能的重要因素。这是数据传输速度的基准。
CUDA - how much slower is transferring over PCI-E?
给定矩阵大小,您实际上可以分别计算出计算和数据传输的绝对时间。这些可以帮助您更好地评估性能。
为了最大限度地提高 GPU 的性能,您可能需要重新设计程序以最小化数据传输,方法是将所有计算操作移至 GPU,而不仅仅是矩阵乘法。
使用 opencl api,我在 1280 核 HD7870(甚至不是主流桌面级 gpu)上尝试了 8k X 8k x 8k X 8k 乘法,它花了大约 0.99 秒,这意味着大约 5400 亿次加法和 5400 亿次乘法也意味着 1.1 Tflops(其广告中所说的峰值的 %40)。高端桌面级 CPU 只有 0.2 - 0.3 Tflops(峰值),不包括其集成的 GPU。因此,最好的 cpu 在性能和每瓦性能以及每美元性能方面甚至无法达到中低端 gpu。
性能的关键选项:
- 像 32x32 或 48x48 这样的补丁中的计算(每个计算单元都有一组线程,所以每个线程计算补丁的一部分或 column/row 的所有补丁的总和)
- 像 Strassen 的算法一样以指数方式更快。
- 流水线化读取、写入和计算操作,以便连续迭代有收获。
针对硬件差异进行优化
使用具有 1 到 4 选项的库