加快矩阵

时间:2017-07-12 04:30:30

标签: python performance numpy scipy vectorization

我有一个3-d Numpy数组flow如下:

flow = np.random.uniform(low=-1.0, high=1.0, size=(720,1280,2))
# Suppose flow[0] are x-coordinates. flow[1] are y-coordinates.

需要计算每个x,y点的角度。以下是我实施它的方法:

def calcAngle(a):
    assert(len(a) == 2)
    (x, y) = a
    # angle_deg = 0
    angle_deg = np.angle(x + y * 1j, deg=True)
    return angle_deg

fangle = np.apply_along_axis(calcAngle, axis=2, arr=flow) 
# The above statement takes 14.0389318466 to execute

每个点的角度计算需要14.0389318466 seconds才能在我的Macbook Pro上执行。

有没有办法可以加快速度,可能是通过使用一些矩阵运算,而不是一次处理一个像素。

2 个答案:

答案 0 :(得分:4)

numpy.angle支持矢量化操作。因此,只需将第一和第二列切片输入到最终输出中,就像这样 -

fangle = np.angle(flow[...,0] + flow[...,1] * 1j, deg=True)

验证 -

In [9]: flow = np.random.uniform(low=-1.0, high=1.0, size=(720,1280,2))

In [17]: out1 = np.apply_along_axis(calcAngle, axis=2, arr=flow)

In [18]: out2 = np.angle(flow[...,0] + flow[...,1] * 1j, deg=True)

In [19]: np.allclose(out1, out2)
Out[19]: True

运行时测试 -

In [10]: %timeit np.apply_along_axis(calcAngle, axis=2, arr=flow)
1 loop, best of 3: 8.27 s per loop

In [11]: %timeit np.angle(flow[...,0] + flow[...,1] * 1j, deg=True)
10 loops, best of 3: 47.6 ms per loop

In [12]: 8270/47.6
Out[12]: 173.73949579831933

173x+ 加速!

答案 1 :(得分:4)

您可以使用numpy.arctan2()以弧度为单位获取角度,然后使用numpy.rad2deg()转换为度数:

fangle = np.rad2deg(np.arctan2(flow[:,:,1], flow[:,:,0]))

在我的电脑上,这比Divakar的版本快一点:

In [17]: %timeit np.angle(flow[...,0] + flow[...,1] * 1j, deg=True)
10 loops, best of 3: 44.5 ms per loop

In [18]: %timeit np.rad2deg(np.arctan2(flow[:,:,1], flow[:,:,0]))
10 loops, best of 3: 35.4 ms per loop

使用np.angle()的更有效方法是创建flow的复杂视图。如果flow是类型np.float64的数组(m, n, 2),那么flow.view(np.complex128)[:,:,0]将是np.complex128类型的数组,其形状为(m, n):< / p>

fangle = np.angle(flow.view(np.complex128)[:,:,0], deg=True)

这似乎比使用arctan2后跟rad2deg的速度更快(但差异远不及timeit的测量噪音):

In [47]: %timeit np.angle(flow.view(np.complex128)[:,:,0], deg=True)
10 loops, best of 3: 35 ms per loop

请注意,如果flow创建为某个其他数组的转置,或者使用大于1的步骤创建另一个数组的切片,则可能无效。