这是一个基于(或跟进)另一个问题Faster implementation of ReLU derivative的问题。
本着一种提出最快的计算导数的方式的精神,我写了一些解决方案,其中一种是:
In [35]: np.random.seed(0)
In [36]: X = np.random.randn(3072,10000)
# computing ReLU derivative
In [42]: np.ceil(np.clip(X, 0, 1))
在以other solutions of Divakar为基准进行测试时,我发现上述方法的运行速度非常慢( 30倍)。以下是时间安排(从最快到最慢)
In [43]: %timeit -n100 ne.evaluate('X>=0').view('i1')
10.6 ms ± 203 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [44]: %timeit -n100 (X>=0).view('i1')
13.6 ms ± 77.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [45]: %timeit -n100 ne.evaluate('(X>=0)+0')
22.1 ms ± 16.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# the super slowest one
In [46]: %timeit -n100 np.ceil(np.clip(X, 0, 1))
317 ms ± 2.14 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
什么是导致这种缓慢的因素?瓶颈在哪里?
答案 0 :(得分:2)
首先,您只是在执行一种更复杂的操作序列。对于每个输入,您的ceil / clip物件都会执行以下操作:
(这分为两个阶段,一个阶段完成所有裁剪,一个阶段完成所有天花板。)
您正在针对对每个输入执行以下操作的选项进行计时:
> =更快也就不足为奇了。
第二,您的ceil / clip东西正在写入的字节数是> =的16倍。 > =会为每个输入元素生成一个输出字节(view
是一个视图,因此那里没有数据副本),而您的ceil / clip东西会生成一个中间类型数组和一个输出数组,均为dtype float64。
第三,分支预测变量在随机数组上的clip
时间不好。不知道每次将采取哪个分支。更可预测的数组通过clip
的速度更快:
In [21]: %timeit X.clip(0, 1)
1 loop, best of 5: 211 ms per loop
In [22]: A = np.full_like(X, 0.5)
In [23]: %timeit A.clip(0, 1)
10 loops, best of 5: 86.6 ms per loop
最后,至少在我测试过的机器和NumPy构建上,numpy.ceil
令人惊讶地慢:
In [24]: %timeit np.ceil(X)
10 loops, best of 5: 166 ms per loop
我不确定它是否正在实现软件ceil
实施或执行何种操作。在不同的版本上,这可能会有所不同。