Python Cython中平方范数的快速计算
我想计算平方范数,它可以写成 W是一个矩阵,有V行。u是一个向量。我有两个numpy对象W和uPython Cython中平方范数的快速计算,python,python-3.x,performance,numpy,cython,Python,Python 3.x,Performance,Numpy,Cython,我想计算平方范数,它可以写成 W是一个矩阵,有V行。u是一个向量。我有两个numpy对象W和u import numpy as np import numpy.random as npr V = 10 W = npr.normal(size=(V, 3)) u = npr.normal(size=(1,3)) 如果我逐行计算,我可以这样做: res = np.zeros(V) for v in range(V): res[v] = (W[v] - u).dot((W[v] - u).
import numpy as np
import numpy.random as npr
V = 10
W = npr.normal(size=(V, 3))
u = npr.normal(size=(1,3))
如果我逐行计算,我可以这样做:
res = np.zeros(V)
for v in range(V):
res[v] = (W[v] - u).dot((W[v] - u).transpose())
但一旦V变大(比如5000),它可能会变慢,我需要一次又一次地重新计算它。
所以我尝试了矩阵乘法,但没有成功,因为它不是逐行乘法
((W - u).transpose()).dot(W - u)
如何快速计算Numpy中的平方范数
我计划使用Cython,所以循环中的逐行乘法能比Numpy快吗?我了解到Cython有,但如果我在内部使用Numpy对象,Cython似乎无法并行化for loop
(11月20日添加:可能我无法在prange
中使用Python对象,但我可以使用Numpy对象)。方法#1
你可以在NumPy中使用快速BLAS,而不需要任何循环,就像这样-
res = (W**2).sum(1) + (u**2).sum(1) -2*W.dot(u.ravel())
d = W -u
res = np.einsum('ij,ij->i',d,d)
对于u
-
res = np.einsum('ij,ij->i',W,W) + np.inner(u,u).ravel() -2*W.dot(u.ravel())
方法说明
使用(W[v]-u).dot((W[v]-u)
在每次迭代中,我们都在做内部点积。因为,我们对W
的所有行都这样做,这在利用广播时转换为((W-u)**2).sum(1)
现在,
因此,
sum_k((Xik-Yjk)**2) = sum_k(Xik**2) + sum_k(Yjk**2) - 2*sum_k(Xik*Yjk)
RHS上的最后一个术语基本上是矩阵乘法,我们正在利用np.dot
进近#2
或者,使用更多的np.einsum
,情况会是这样-
res = (W**2).sum(1) + (u**2).sum(1) -2*W.dot(u.ravel())
d = W -u
res = np.einsum('ij,ij->i',d,d)
如果我在Cython中使用np.dot(),它会比在纯Python中使用它慢吗?@user2978524如果你能在NumPy这里使用
np.dot
,我想你不会看到它对Cython有任何好处。我明白了,你是对的。你能告诉我你是如何得出第一个答案的(带np.dot的那个)?我对numpy总是很难理解,我不知道为什么你的答案会给出我想要的,这让我在将来也会陷入同样的问题。你知道有用的参考资料吗?@user2978524补充道。你也可以使用np.linalg.norm(W-u)
您是否在循环变量中添加了cdef int v
类型?如果没有,可能会导致速度减慢。但您在cython中的并行化是正确的;如果您在循环中接触任何python对象,则无法使用像prange
这样的OpenMP函数。无论如何,看起来您已经获得了一个更智能的python解决方案!@CodeSur在上面的geon中,我只展示了Python版本以便于复制,但我将在Cython中适当地定义变量!