NumPy 广播以提高点积性能
NumPy broadcasting to improve dot-product performance
这是一个相当简单的操作,但在我的实际代码中重复了数百万次,如果可能的话,我想提高它的性能。
import numpy as np
# Initial data array
xx = np.random.uniform(0., 1., (3, 14, 1))
# Coefficients used to modify 'xx'
a, b, c = np.random.uniform(0., 1., 3)
# Operation on 'xx' to obtain the final array 'yy'
yy = xx[0] * a * b + xx[1] * b + xx[2] * c
最后一行是我想改进的。基本上,xx
中的每一项都乘以一个因子(由 a, b, c
系数给出),然后将所有项相加得到最终的 yy
数组,其形状为 (14, 1)
vs 初始 xx
数组 (3, 14, 1)
.
的形状
是否可以通过 numpy 广播来做到这一点?
我们可以使用广播乘法,然后对第一个备选方案沿第一个轴求和。
作为第二个,我们也可以用np.dot
引入matrix-multiplication。因此,给我们另外两种方法。这是问题中提供的示例的时间 -
# Original one
In [81]: %timeit xx[0] * a * b + xx[1] * b + xx[2] * c
100000 loops, best of 3: 5.04 µs per loop
# Proposed alternative #1
In [82]: %timeit (xx *np.array([a*b,b,c])[:,None,None]).sum(0)
100000 loops, best of 3: 4.44 µs per loop
# Proposed alternative #2
In [83]: %timeit np.array([a*b,b,c]).dot(xx[...,0])[:,None]
1000000 loops, best of 3: 1.51 µs per loop
这与 Divakar 的回答相似。交换 xx
的第一个和第三个轴并进行点积。
import numpy as np
# Initial data array
xx = np.random.uniform(0., 1., (3, 14, 1))
# Coefficients used to modify 'xx'
a, b, c = np.random.uniform(0., 1., 3)
def op():
yy = xx[0] * a * b + xx[1] * b + xx[2] * c
return yy
def tai():
d = np.array([a*b, b, c])
return np.swapaxes(np.swapaxes(xx, 0, 2).dot(d), 0, 1)
def Divakar():
# improvement given by Divakar
np.array([a*b,b,c]).dot(xx.swapaxes(0,1))
%timeit op()
7.21 µs ± 222 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit tai()
4.06 µs ± 140 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit Divakar()
3 µs ± 105 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
这是一个相当简单的操作,但在我的实际代码中重复了数百万次,如果可能的话,我想提高它的性能。
import numpy as np
# Initial data array
xx = np.random.uniform(0., 1., (3, 14, 1))
# Coefficients used to modify 'xx'
a, b, c = np.random.uniform(0., 1., 3)
# Operation on 'xx' to obtain the final array 'yy'
yy = xx[0] * a * b + xx[1] * b + xx[2] * c
最后一行是我想改进的。基本上,xx
中的每一项都乘以一个因子(由 a, b, c
系数给出),然后将所有项相加得到最终的 yy
数组,其形状为 (14, 1)
vs 初始 xx
数组 (3, 14, 1)
.
是否可以通过 numpy 广播来做到这一点?
我们可以使用广播乘法,然后对第一个备选方案沿第一个轴求和。
作为第二个,我们也可以用np.dot
引入matrix-multiplication。因此,给我们另外两种方法。这是问题中提供的示例的时间 -
# Original one
In [81]: %timeit xx[0] * a * b + xx[1] * b + xx[2] * c
100000 loops, best of 3: 5.04 µs per loop
# Proposed alternative #1
In [82]: %timeit (xx *np.array([a*b,b,c])[:,None,None]).sum(0)
100000 loops, best of 3: 4.44 µs per loop
# Proposed alternative #2
In [83]: %timeit np.array([a*b,b,c]).dot(xx[...,0])[:,None]
1000000 loops, best of 3: 1.51 µs per loop
这与 Divakar 的回答相似。交换 xx
的第一个和第三个轴并进行点积。
import numpy as np
# Initial data array
xx = np.random.uniform(0., 1., (3, 14, 1))
# Coefficients used to modify 'xx'
a, b, c = np.random.uniform(0., 1., 3)
def op():
yy = xx[0] * a * b + xx[1] * b + xx[2] * c
return yy
def tai():
d = np.array([a*b, b, c])
return np.swapaxes(np.swapaxes(xx, 0, 2).dot(d), 0, 1)
def Divakar():
# improvement given by Divakar
np.array([a*b,b,c]).dot(xx.swapaxes(0,1))
%timeit op()
7.21 µs ± 222 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit tai()
4.06 µs ± 140 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit Divakar()
3 µs ± 105 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)