cupy 索引很慢
cupy indexing is slow
我正在尝试对大小为 16000 的大型 cupy 数组执行操作。我发现诸如加法之类的数学运算相当快,但使用布尔掩码进行索引相对较慢。例如下面的代码:
import cupy as cp
arr = cp.random.normal(0, 1, 16000)
%timeit arr * 5
%timeit arr > 0.4
%timeit arr[arr > 0.4] = 0
给我输出:
28 µs ± 950 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
26.5 µs ± 1.61 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
104 µs ± 2.6 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
最终索引至少慢两倍的原因是什么?我认为乘法应该比设置数组元素慢。
Update:这对于 numpy 索引不是真的。将 cupy 数组更改为 numpy,我得到:
6.71 µs ± 373 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
4.42 µs ± 56.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
5.39 µs ± 29.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
在第 3 种情况下,cupy
通过一系列操作组合结果:cupy_greater
、cupy_copy
、inclusive_scan_kernel
、inclusive_scan_kernel
、add_scan_blocked_sum_kernel
、CUDA memcpy DtoH
(或许提供需要置零的元素个数)、CUDA memset
(或许将一个数组置零),最后是cupy_scatter_update_mask
(将零散布到它们正确的位置,也许)。
这是一个比 arr*5
复杂得多的序列,后者似乎 运行 是一个单一的 cupy_multiply
。你可以用 cupy
user-defined kernel:
做得更好
import cupy as cp
clamp_generic = cp.ElementwiseKernel(
'T x, T c',
'T y',
'y = (y > x)?c:y',
'clamp_generic')
arr = cp.random.normal(0, 1, 16000)
clamp_generic(0.4, 0, arr)
我正在尝试对大小为 16000 的大型 cupy 数组执行操作。我发现诸如加法之类的数学运算相当快,但使用布尔掩码进行索引相对较慢。例如下面的代码:
import cupy as cp
arr = cp.random.normal(0, 1, 16000)
%timeit arr * 5
%timeit arr > 0.4
%timeit arr[arr > 0.4] = 0
给我输出:
28 µs ± 950 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
26.5 µs ± 1.61 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
104 µs ± 2.6 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
最终索引至少慢两倍的原因是什么?我认为乘法应该比设置数组元素慢。
Update:这对于 numpy 索引不是真的。将 cupy 数组更改为 numpy,我得到:
6.71 µs ± 373 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
4.42 µs ± 56.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
5.39 µs ± 29.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
在第 3 种情况下,cupy
通过一系列操作组合结果:cupy_greater
、cupy_copy
、inclusive_scan_kernel
、inclusive_scan_kernel
、add_scan_blocked_sum_kernel
、CUDA memcpy DtoH
(或许提供需要置零的元素个数)、CUDA memset
(或许将一个数组置零),最后是cupy_scatter_update_mask
(将零散布到它们正确的位置,也许)。
这是一个比 arr*5
复杂得多的序列,后者似乎 运行 是一个单一的 cupy_multiply
。你可以用 cupy
user-defined kernel:
import cupy as cp
clamp_generic = cp.ElementwiseKernel(
'T x, T c',
'T y',
'y = (y > x)?c:y',
'clamp_generic')
arr = cp.random.normal(0, 1, 16000)
clamp_generic(0.4, 0, arr)