Del*_*aIV 9 python performance numpy dot-product numba
我有以下代码:
import numpy as np
from numba import jit
Nx = 15
Ny = 1000
v = np.ones((Nx,Ny))
v = np.reshape(v,(Nx*Ny))
A = np.random.rand(Nx*Ny,Nx*Ny,5)
B = np.random.rand(Nx*Ny,Nx*Ny,5)
C = np.random.rand(Nx*Ny,5)
@jit(nopython=True)
def dotplus(B, v, C):
return np.dot(B, v) + C
k = 2
D = dotplus(B[:,:,k], v, C[:,k])
Run Code Online (Sandbox Code Playgroud)
我收到以下警告,我猜它指的是数组B[:,:,k]
和v
:
NumbaPerformanceWarning: np.dot() is faster on contiguous arrays, called on (array(float64, 2d, A), array(float64, 1d, C))
return np.dot(B, v0) + C
Run Code Online (Sandbox Code Playgroud)
有没有办法让两个数组连续,这样Numba就可以加速代码?
PS,如果您想知道 的含义k
,请注意这只是 MRE。在实际代码中,在循环内针对不同的值(因此,和的不同切片)dotplus
多次调用。循环更新 的值,但和不改变。for
k
B
C
for
v
B
C
Fir*_*ger 11
缺陷是正确的。B[..., k]
返回一个np.view()
into B
,但实际上并不复制任何数据。在内存中,视图的两个相邻元素的距离为B.strides[1]
,其计算结果为B.shape[-1]*B.itemsize
且大于B.itemsize
。因此,您的数组不是连续的。
最好的优化是将dotplus
循环矢量化并写入
D = np.tensordot(B, v, axes=(1, 0)) + C
Run Code Online (Sandbox Code Playgroud)
第二个最佳优化是重构,让批量维度成为数组的第一个维度。这可以在上述矢量化的基础上完成,并且通常是可取的。它看起来像
A = np.random.rand(5, Nx*Ny,Nx*Ny)
# rather than
A = np.random.rand(Nx*Ny,Nx*Ny,5)
Run Code Online (Sandbox Code Playgroud)
如果您无法重构代码,则需要开始分析。您可以通过以下方式轻松临时交换轴
B = np.moveaxis(B, -1, 0)
some_op(B[k, ...], ...)
B = np.moveaxis(B, 0, -1)
Run Code Online (Sandbox Code Playgroud)
与 max9111 的评论相反,这不会给你带来任何好处,np.ascontiguousarray()
因为在这两种情况下都必须复制数据。也就是说,副本O(Nx*Ny*k)
+缓冲区分配。直接矩阵向量乘法是O(Nx*Ny)
,但是你必须先收集元素,这非常昂贵。这取决于您的特定架构和具体问题,因此分析是最佳选择。
归档时间: |
|
查看次数: |
7148 次 |
最近记录: |