您应该注释(即,静态类型)所有可能的变量。如果您愿意,以下是我的解决方案:# mydot.pyx
import numpy as np
cimport cython
def dot_1(a, b):
c = [[0 for j in range(len(b[i]))] for i in range(len(a))]
for i in range(len(c)):
for j in range(len(c[i])):
t = 0
for k in range(len(b)):
t += a[i][k] * b[k][j]
c[i][j] = t
return c
@cython.boundscheck(False) # turn off bounds-checking
@cython.wraparound(False) # turn off negative index wrapping
def dot_2(double[:, :] A, double[:, :] B):
cdef Py_ssize_t M = A.shape[0]
cdef Py_ssize_t Na = A.shape[1]
cdef Py_ssize_t Nb = B.shape[0]
cdef Py_ssize_t K = B.shape[1]
assert Na == Nb
result = np.empty((M, K), dtype='d')
cdef double[:, :] C = result
cdef double t
for m in range(M):
for k in range(K):
t = 0
for n in range(Na):
t += A[m, n] * B[n, k]
C[m, k] = t
return result
以及
^{pr2}$
当您运行cython annotate mydot.pyx时,Cython将生成一个HTML文件来注释Cython代码。在那里,黄色高亮显示越深,生成的C代码的开销(Python)就越多。您可以将这两个解决方案(特别是for循环)相互比较。在
运行python app.py也会给你更快的结果。当然,如果您提供的输入值小于某个阈值,那么您将看不到二者之间有意义的速度差异,因为您没有进行足够的迭代。但是,在某个阈值之后,速度差异应该是显著的,因为循环中的每个迭代对于您的版本来说都是昂贵的(参见较深的黄色线)。在
最后一点要说的是,正如这个问题下的每个人都建议的那样,当你提供具有更大维度的矩阵时,numpy的函数应该更高效——它们使用的是来自底层BLAS和LAPACK实现的分块(子)矩阵操作,而不是天真地逐个迭代索引。在
注:如果你想让dot_2不仅专门化doubleS,而且还想专门化其他有意义的算术类型,比如intS和{}S,那么应该检查Cython的fused types。在
编辑。因为我的回答后来被选为答案,所以我想举一个大尺寸输入的例子。如果不是上面的app.py,而是使用以下内容:# app.py
import pyximport
from numpy import array, random as rnd
from scipy import median
from timeit import repeat
pyximport.install()
from mydot import dot_1, dot_2
M = 100
N = 100
K = 1
a = rnd.randn(M, N)
b = rnd.randn(N, K)
dot_1_t = repeat('dot_1(a, b)', repeat=1000, number=1, globals=globals())
dot_2_t = repeat('dot_2(a, b)', repeat=1000, number=1, globals=globals())
print(f'dot_1 took {median(dot_1_t)*1000} ms.')
print(f'dot_2 took {median(dot_2_t)*1000} ms.')
计时应与以下内容类似:dot_1 took 5.218300502747297 ms.
dot_2 took 0.013017997844144702 ms.
本文探讨了如何使用Cython提高Python中计算两个矩阵点积的效率。通过对比不同方法,展示了静态类型和Cython优化如何显著减少执行时间。实验结果显示,Cython优化后的版本比原始Python代码快了多个数量级,尤其是在处理大型矩阵时。
中计算两个矩阵的点积的最快方法是什么...&spm=1001.2101.3001.5002&articleId=113677149&d=1&t=3&u=d6edd031bd4b43c9af34a011bc7d2331)
289

被折叠的 条评论
为什么被折叠?



