【发布时间】:2020-12-03 02:53:20
【问题描述】:
我正在将我的 CPU 代码传输到 GPU。 在优化它时,我发现了一个有争议的性能行为:
考虑计算向量的 L2 范数的简单任务。对于具有大量元素的向量,我的性能按预期扩展,但是对于少量(256)它不是:
import cupy as cp
a=cp.random.rand(256)
%timeit cp.linalg.norm(a)
32.3 µs ± 159 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
现在,让我们将其与矩阵向量点积进行比较:
b=cp.random.rand(256,256)
%timeit cp.dot(a,b)
8.36 µs ± 80.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
您可以看到矩阵向量乘积的速度出乎意料地快了 4 倍。为什么会这样?
我开始研究这个玩具问题。首先,我创建了我的自定义缩减内核:
l2norm = cp.ReductionKernel('T x','T y', 'x * x','a + b', 'y = sqrt(a)', '0', 'l2norm')
使用这个内核,我的执行时间约为 17 微秒,比使用 linalg.norm 时快两倍,但仍然比矩阵向量点积差两倍。我相信这个内核已经优化得很好,所以 C++ Thurst 实现不会做得更好。
我还尝试使用cp.sqrt(a.dot(a)) 计算范数。我发现这是非常低效的,因为向量向量点积a.dot(a) 比矩阵向量积a.dot(b) 花费的时间更长!!!
我确实理解,对于这个小问题,性能受到带宽限制,因此大部分时间可以用于创建数组、复制/获取数据,而不是算术。但即使在这种情况下,我也希望 L2 范数比矩阵向量乘积快一点,因为它只需要 O(N) 次操作和获取,结果是一个数字。在矩阵向量积的情况下,我什至不预先分配结果,我执行 N^2 次操作并从内存中获取 O(N^2) 个数字。
对于大量元素(>1000 个元素),性能按预期扩展。
Ubuntu 18.05、anaconda 发行版、python 3.8.3、cupy 8.2.、nvcc 11.0
【问题讨论】:
标签: python linear-algebra benchmarking cupy