使用 cython 加速 numpy 矩阵乘法

Speed-up numpy matrix multiplication using cython

我在算法中计算了数千次矩阵乘法。因此,我计算:

import numpy as np
import time


def mat_mul(mat1, mat2, mat3, mat4):
    return(np.dot(np.transpose(mat1),np.multiply(np.diag(mat2)[:,None], mat3))+mat4)

n = 2000
mat1 = np.random.rand(n,n)
mat2 = np.diag(np.random.rand(n))
mat3 = np.random.rand(n,n)
mat4 = np.random.rand(n,n)

t0=time.time()
cov_11=mat_mul(mat1, mat2, mat1, mat4)
t1=time.time()
print('time ',t1-t0, 's')

矩阵的大小: n = (2000,2000) 并且 mat2 只有沿其对角线的条目。剩余条目为零。

在我的机器上,我得到以下信息: time 0.3473696708679199 s

我怎样才能加快速度?

谢谢。

cython 不会加快它的速度,仅仅是因为 numpy 使用其他技巧来加快线程和 SIMD 之类的速度,任何试图仅使用 cython 实现此类功能的人最终都会获得更差的性能。

只有两种可能:

  1. 使用基于 gpu 的 numpy (cupy) 版本
  2. 如果您还没有使用最好的后端(如英特尔 MKL),请为 numpy 使用不同的更优化的后端

可以通过减少临时数组的数量并尽可能重用它们(即。多次)。事实上,虽然矩阵乘法通常是 heavily-optimized 通过 BLAS 实现,filling/copying(新分配的)数组增加了 non-negligible 开销。

实现如下:

def mat_mul_opt(mat1, mat2, mat3, mat4):
    tmp1 = np.empty((n,n))
    tmp2 = np.empty((n,n))
    vect = np.diag(mat2)[:,None]
    np.dot(np.transpose(mat1),np.multiply(vect, mat3, out=tmp1), out=tmp2)
    np.add(mat4, tmp2, out=tmp1)
    return tmp1

如果可以对输入矩阵进行变异,或者如果您可以 pre-allocate tmp1tmp2 在函数外一次(然后多次重复使用),则可以进一步优化代码).这是一个例子:

def mat_mul_opt2(mat1, mat2, mat3, mat4, tmp1, tmp2):
    vect = np.diag(mat2)[:,None]
    np.dot(np.transpose(mat1),np.multiply(vect, mat3, out=tmp1), out=tmp2)
    np.add(mat4, tmp2, out=tmp1)
    return tmp1

以下是我的 i5-9600KF 处理器(6 核)的性能结果:

mat_mul:                 103.6 ms
mat_mul_opt1:             96.7 ms
mat_mul_opt2:             83.5 ms
np.dot time only:         74.4 ms   (kind of practical lower-bound)
Optimal lower bound:      55   ms   (quite optimistic)