如果 gr 是一个浮点数列表,如果你想用NumPy进行矢量化将是转换的第一步 gr 到一个NumPy数组 np.array() 。
gr
np.array()
接下来,我假设你有 new_gr 用零形状初始化 (height,width) 。在两个最里面的循环中执行的计算基本上代表 2D convolution 。所以,你可以使用 signal.convolve2d 适当的 kernel 。决定 kernel ,我们需要查看缩放因子并制作一个 3 x 3 从它们中取出内核并否定它们来模拟我们在每次迭代时所做的计算。因此,您将获得一个矢量化解决方案,其中两个最内层的循环被移除以获得更好的性能,如此 -
new_gr
(height,width)
2D convolution
signal.convolve2d
kernel
3 x 3
import numpy as np from scipy import signal # Get the scaling factors and negate them to get kernel kernel = -np.array([[0,1-2*t,0],[-1,1,0,],[t,0,0]]) # Initialize output array and run 2D convolution and set values into it out = np.zeros((height,width)) out[1:-1,1:-1] = signal.convolve2d(gr, kernel, mode='same')[1:-1,:-2]
的 验证输出和运行时测试 强>
定义功能:
def org_app(gr,t): new_gr = np.zeros((height,width)) for h in xrange(1, height-1): for w in xrange(1, width-1): new_gr[h][w] = gr[h][w] + gr[h][w-1] + gr[h-1][w] + t * gr[h+1][w-1]-2 * (gr[h][w-1] + t * gr[h-1][w]) return new_gr def proposed_app(gr,t): kernel = -np.array([[0,1-2*t,0],[-1,1,0,],[t,0,0]]) out = np.zeros((height,width)) out[1:-1,1:-1] = signal.convolve2d(gr, kernel, mode='same')[1:-1,:-2] return out
验证 -
In [244]: # Inputs ...: gr = np.random.rand(40,50) ...: height,width = gr.shape ...: t = 1 ...: In [245]: np.allclose(org_app(gr,t),proposed_app(gr,t)) Out[245]: True Timings - In [246]: # Inputs ...: gr = np.random.rand(400,500) ...: height,width = gr.shape ...: t = 1 ...: In [247]: %timeit org_app(gr,t) 1 loops, best of 3: 2.13 s per loop In [248]: %timeit proposed_app(gr,t) 10 loops, best of 3: 19.4 ms per loop
@Divakar,我尝试了几种变体 org_app 。完全矢量化的版本是:
org_app
def org_app4(gr,t): new_gr = np.zeros((height,width)) I = np.arange(1,height-1)[:,None] J = np.arange(1,width-1) new_gr[I,J] = gr[I,J] + gr[I,J-1] + gr[I-1,J] + t * gr[I+1,J-1]-2 * (gr[I,J-1] + t * gr[I-1,J]) return new_gr
虽然你的速度只有一半 proposed_app ,它的风格更接近原作。因此可以帮助理解嵌套循环如何被矢量化。
proposed_app
重要的一步是转换 I 进入一个列数组,这样就可以了 I,J 索引一个值块。
I
I,J