为什么以下示例中的python广播比简单循环慢?
我有一个向量数组,并计算他们的差异与第一个的差异.
使用 python广播时,计算速度明显慢于通过简单循环进行计算.为什么? import numpy as np def norm_loop(M,v): n = M.shape[0] d = np.zeros(n) for i in range(n): d[i] = np.sum((M[i] - v)**2) return d def norm_bcast(M,v): n = M.shape[0] d = np.zeros(n) d = np.sum((M - v)**2,axis=1) return d M = np.random.random_sample((1000,10000)) v = M[0] %timeit norm_loop(M,v) – > 25.9毫秒 %timeit norm_bcast(M,v) – > 38.5毫秒 我有Python 3.6.3和Numpy 1.14.2 要在google colab中运行示例: 解决方法
内存访问.
首先,广播版本可以简化为 def norm_bcast(M,v): return np.sum((M - v)**2,axis=1) 这仍然比循环版本略慢. 正如我所说,它归结为内存访问. 在广播版本中,从v中减去M的每个元素.到处理M的最后一行时,处理第一行的结果已经从高速缓存中逐出,因此对于第二步,这些差异再次被加载到高速缓冲存储器中.平方.最后,它们被加载并第三次处理以进行求和.由于M非常大,因此在每一步都清除部分缓存以编写所有数据. 在循环版本中,每一行都在一个较小的步骤中完全处理,从而减少了缓存未命中和整体更快的代码. 最后,通过使用einsum可以通过一些数组操作来避免这种情况. def norm_einsum(M,v): tmp = M-v return np.einsum('ij,ij->i',tmp,tmp) 这将它减少到整个数组上的两个操作 – 减法和调用einsum,它执行平方和求和. %timeit norm_bcast(M,v) 30.1 ms ± 116 μs per loop (mean ± std. dev. of 7 runs,10 loops each) %timeit norm_loop(M,v) 25.1 ms ± 37.3 μs per loop (mean ± std. dev. of 7 runs,10 loops each) %timeit norm_einsum(M,v) 21.7 ms ± 65.3 μs per loop (mean ± std. dev. of 7 runs,10 loops each) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |