我正在使用几种技术(NumPy、Weave和Cython)来执行 Python 性能基准测试。代码在数学上的基本作用是C = AB
,其中 A、B 和 C 是N x N
矩阵(注意:这是矩阵乘积,而不是逐元素乘法)。
我已经编写了 5 个不同的代码实现:
- 纯 Python(循环 2D Python 列表)
- NumPy(二维 NumPy 数组的点积)
- Weave inline(C++ 循环遍历 2D 数组)
- Cython(循环 2D Python 列表 + 静态类型)
- Cython-Numpy(循环 2D NumPy 数组 + 静态类型)
我的期望是实现 2 到 5 将比实现 1 快得多。但我的结果表明并非如此。这些是我相对于纯 Python 实现的标准化加速结果:
- python_list:1.00
- numpy_array:330.09
- weave_inline:30.72
- cython_list:2.80
- cython_array:0.14
我对 NumPy 的表现很满意,但是我对 Weave 的表现不那么热情,Cython 的表现让我哭了。我的整个代码分为两个文件。一切都是自动化的,您只需运行第一个文件即可查看所有结果。有人可以通过说明我可以做些什么来获得更好的结果来帮助我吗?
matmul.py:
import time
import numpy as np
from scipy import weave
from scipy.weave import converters
import pyximport
pyximport.install()
import cython_matmul as cml
def python_list_matmul(A, B):
C = np.zeros(A.shape, dtype=float).tolist()
A = A.tolist()
B = B.tolist()
for k in xrange(len(A)):
for i in xrange(len(A)):
for j in xrange(len(A)):
C[i][k] += A[i][j] * B[j][k]
return C
def numpy_array_matmul(A, B):
return np.dot(A, B)
def weave_inline_matmul(A, B):
code = """
int i, j, k;
for (k = 0; k < N; ++k)
{
for (i = 0; i < N; ++i)
{
for (j = 0; j < N; ++j)
{
C(i, k) += A(i, j) * B(j, k);
}
}
}
"""
C = np.zeros(A.shape, dtype=float)
weave.inline(code, ['A', 'B', 'C', 'N'], type_converters=converters.blitz, compiler='gcc')
return C
N = 100
A = np.random.rand(N, N)
B = np.random.rand(N, N)
function = []
function.append([python_list_matmul, 'python_list'])
function.append([numpy_array_matmul, 'numpy_array'])
function.append([weave_inline_matmul, 'weave_inline'])
function.append([cml.cython_list_matmul, 'cython_list'])
function.append([cml.cython_array_matmul, 'cython_array'])
t = []
for i in xrange(len(function)):
t1 = time.time()
C = function[i][0](A, B)
t2 = time.time()
t.append(t2 - t1)
print function[i][1] + ' \t: ' + '{:10.6f}'.format(t[0] / t[-1])
cython_matmul.pyx:
import numpy as np
cimport numpy as np
import cython
cimport cython
DTYPE = np.float
ctypedef np.float_t DTYPE_t
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
cpdef cython_list_matmul(A, B):
cdef int i, j, k
cdef int N = len(A)
A = A.tolist()
B = B.tolist()
C = np.zeros([N, N]).tolist()
for k in xrange(N):
for i in xrange(N):
for j in xrange(N):
C[i][k] += A[i][j] * B[j][k]
return C
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
cpdef cython_array_matmul(np.ndarray[DTYPE_t, ndim=2] A, np.ndarray[DTYPE_t, ndim=2] B):
cdef int i, j, k, N = A.shape[0]
cdef np.ndarray[DTYPE_t, ndim=2] C = np.zeros([N, N], dtype=DTYPE)
for k in xrange(N):
for i in xrange(N):
for j in xrange(N):
C[i][k] += A[i][j] * B[j][k]
return C