我是CuPy
CUDA/GPU 计算的新手。有人能解释一下为什么(x / y)[i]
比 更快吗x[i] / y[i]
?
当利用 GPU 加速计算时,是否有任何指导原则可以让我快速确定哪个操作更快?从而避免对每个操作进行基准测试。
# In VSCode Jupyter Notebook
import cupy as cp
from cupyx.profiler import benchmark
x = cp.arange(1_000_000)
y = (cp.arange(1_000_000) + 1) / 2
i = cp.random.randint(2, size=1_000_000) == 0
x, y, i
# Output:
(array([ 0, 1, 2, ..., 999997, 999998, 999999], shape=(1000000,), dtype=int32),
array([5.000000e-01, 1.000000e+00, 1.500000e+00, ..., 4.999990e+05,
4.999995e+05, 5.000000e+05], shape=(1000000,), dtype=float64),
array([ True, False, True, ..., True, False, True], shape=(1000000,), dtype=bool))
def test1(x, y, i):
return (x / y)[i]
def test2(x, y, i):
return x[i] / y[i]
print(benchmark(test1, (x, y, i)))
print(benchmark(test2, (x, y, i)))
# Output:
test1: CPU: 175.164 us +/- 61.250 (min: 125.200 / max: 765.100) us GPU-0: 186.001 us +/- 67.314 (min: 134.144 / max: 837.568) us
test2: CPU: 342.364 us +/- 130.840 (min: 223.000 / max: 1277.600) us GPU-0: 368.133 us +/- 136.911 (min: 225.504 / max: 1297.408) us
GPU(至少,也可能是 CPU)上的算术能力与字节检索能力的比率通常偏向于算术能力。因此,算法性能通常可以通过所需的内存操作数量来预测。实现的第一步
x[i]/y[i]
是创建x[i]
和y[i]
,这是纯内存操作 - 流压缩。然后发生降低级别的算术。在另一种实现中,首先发生更高级别的算术,然后将内存操作减少 50%。高端数据中心 GPU(例如A100)可能具有约 10 TF 的 FP64 吞吐量和约 2 TB/s 的内存带宽,因此该比率将是每读取或写入一个字节数据 5 FP64 FLOP。对于 8 字节 FP64 数量,即每读取或写入一个 FP64 数量 40 FLOP。(除法需要多个 FLOP。)
假设数组
i
由 50% 的 True 和 50% 的 false 组成。现在让我们计算所需的所有步骤。在
x[i]/y[i]
实现过程中,我们必须i
数组—1,000,000 次读取。x
使用它来读取和数组的一部分y
,但在 GPU 上,您无法读取单个元素。您每次以 32 字节为单位读取内存,因此实际上,如果 True/False 分布均匀,您最终可能会读取整个x
和y
数组 - 2,000,000 次读取i
在
(x/y)[i]
实现中:i
数组—1,000,000 次读取。x
和y
数组 - 2,000,000 次读取i
唯一的区别是流压缩操作的定位和所需的除法操作数量。流压缩基本上是一种纯内存绑定活动,因此区别在于访问内存的成本。第一种方法需要两倍的流压缩。
至少在 GPU 上,Flops 通常比读取/写入数据的“成本”要低得多。
True/False 的百分比比率
i
实际上不会影响 A100 的分析。与 FP32 相比,其他 GPU(如 T4)的 FP64 吞吐量相对较低。T4 的 内存带宽与 FP32 吞吐量的 ~8TF 之比为 320GB/s,但 FP64 吞吐量仅为 1/8TF 或 125GF。在 True 与 False 的比率较高时,这并不重要,但在 True 与 False 的比率较低时,对于 T4,除法成本可能是一个因素。切换到 FP32 数据类型可能会消除这种区别。换句话说,对于 FP64 操作,T4 不一定满足我在此处回答的初始前提:“GPU(至少,也可能是 CPU)上的算术能力与字节检索能力之比通常偏向于算术能力。”