Python 加速矩阵计算(在子阵列上循环)[numpy]
我正试图为我的学生作业编写一个算法,它运行良好。但是,计算需要很长时间,特别是对于大型阵列。 这部分代码正在减慢所有程序的速度Python 加速矩阵计算(在子阵列上循环)[numpy],python,algorithm,performance,numpy,matrix,Python,Algorithm,Performance,Numpy,Matrix,我正试图为我的学生作业编写一个算法,它运行良好。但是,计算需要很长时间,特别是对于大型阵列。 这部分代码正在减慢所有程序的速度 Shapes: X.shape = mask.shape = logBN.shape = (500,500,1000), F.shape = (20,20), A.shape = (481,481), s2 -- scalar. 我应该如何更改此代码以使其更快 h = F.shape[0] w = F.shape[
Shapes: X.shape = mask.shape = logBN.shape = (500,500,1000),
F.shape = (20,20),
A.shape = (481,481),
s2 -- scalar.
我应该如何更改此代码以使其更快
h = F.shape[0]
w = F.shape[1]
q = np.zeros((A.shape[0], A.shape[1], X.shape[2]))
for i in range(A.shape[0]):
for j in range(A.shape[1]):
mask[:,:,:] = 0
mask[i:i + h,j:j + w,:] = 1
q[i,j,:] = ((logBN*(1 - mask)).sum(axis=(0,1)) +
(np.log(norm._pdf((X[i:i + h,j:j + w,:]-F[:,:,np.newaxis])/s2)/s2)).sum(axis=(0,1))
只是想弄清楚你的内心循环
mask[:,:,:] = 0
mask[i:i + h,j:j + w,:] = 1
q[i,j,:] = ((logBN*(1 - mask)).sum(axis=(0,1)) +
(np.log(norm._pdf((X[i:i + h,j:j + w,:]-F[:,:,np.newaxis])/s2)/s2)).sum(axis=(0,1))
看起来像
idx = (slice(i,i+h), slice(j,j_w), slice(None))
mask = np.zeros(X.shape)
mask(idx) = 1
mask = 1 - mask
# alt mask=np.ones(X.shape);mask[idx]=0
term1 = (logBN*mask).sum(axis=(0,1))
term2 = np.log(norm._pdf((X[idx] - F[...,None])/s2)/s2).sum(axis=(0,1))
q[i,j,:] = term1 + term2
因此,idx
和mask
在a
中定义子阵列。您正在阵列外部使用logBN
;和术语
。您正在对前2个dim上的值求和,因此term1
和term2
都具有形状X.shape[2]
,您将其保存在q
中
那个遮罩/窗口是20x20
作为第一个切入点,我将尝试一次计算所有
I
,j
的term2
。这看起来像是一个典型的滑动窗口问题。我还尝试将术语1
表示为一个减法-整个logBN
减去这个窗口。通过log
,exp
,power
的代数运算进行繁重的杂耍之后,一切都变成了这样-
# Params
m,n = F.shape[:2]
k1 = 1.0/(s2*np.sqrt(2*np.pi))
k2 = -0.5/s2**2
k3 = np.log(k1)*m*n
out = np.zeros((A.shape[0], A.shape[1], X.shape[2]))
for i in range(A.shape[0]):
for j in range(A.shape[1]):
mask[:] = 1
mask[i:i + h,j:j + w,:] = 0
XF = (X[i:i + h,j:j + w,:]-F[:,:,np.newaxis])
p1 = np.einsum('ijk,ijk->k',logBN,mask)
p2 = k2*np.einsum('ijk,ijk->k',XF,XF)
out[i,j,:] = p1 + p2
out += k3
使用的东西很少-
1] norm.pdf基本上是:norm.pdf(x)=exp(-x**2/2)/sqrt(2*pi)
。因此,我们可以内联实现并在脚本级别优化这些实现
2] 用标量除法效率不高,所以用倒数乘法代替了标量除法。因此,作为一种预处理,在进入循环之前存储它们的倒数。这还不完整-将所有变量(F、a、X)都放进去,这样人们就可以处理一些事情了。如果对数组进行迭代,通常最好将其转换为python列表,因为它非常慢-最快的是使用向量运算。@kabanus我不能确定它们是在程序工作期间生成的。我建议打印一次,将结果粘贴在这里。@Divakar我刚刚添加了信息:logBN——矩阵和s2——标量。这就是栅格!非常感谢。我想更改一个算法,但您使用
einsum
的解决方案的速度要快8倍。虽然我不明白为什么它比普通的numpy函数运行得更快。@Acapello相信我,我不得不仔细研究代数函数,因此在文章顶部有这样的评论。这是一次令人精疲力尽的会议!:)这是更快的,因为我们所做的操作要少得多。