NumPy中更快的矩阵乘法

2022-02-26 07:23:39

NumPy中的矩阵乘法速度相当快,无需优化。然而,如果每秒钟都很重要,就有可能显著提高性能(即使没有GPU)。

下面是一些小技巧的集合,可以帮助进行大型(~4000x4000)矩阵乘法。我用它们将深层神经网络的推理时间从24秒缩短到不到一秒。事实上,在一个例子中,我在CPU上优化的代码比使用GPU的Tensorflow运行得更快(1秒vs 7秒)。

第一步是衡量一切。在Linux上,是Python的时代。time()提供高分辨率计时器。时间信息将有助于指导你的工作。

在神经网络中,大部分时间都花在大型矩阵乘法上。

与缓慢的矩阵乘法相比,极其复杂的元素操作(如Sigmoid链)可能会对性能产生不可忽视的影响。在测量算法中每一步的性能之前,你不知道什么会影响性能。

确保阵列的数据类型为numpy。float32,而不是默认的numpy。64。我已经看到这有四倍或更多的改善。

(尝试进一步缩减到numpy.float16可能很有诱惑力,但这会适得其反,因为CPU和BLAS库本机无法以这种精度工作。)

BLAS是一个高性能矩阵库。尽管NumPy使用BLAS,但我';我注意到直接调用BLAS可以提高性能。也许这仅仅是因为直接调用BLAS会迫使您调整数据,以便与BLAS一起使用。

一个简单的检查方法是查看您的CPU使用情况(例如,使用top)。如果你的矩阵乘法使用的是单核,那么你可能使用的是慢BLAS。通过使用多核BLAS库(如OpenBLAS或英特尔MKL),您可以获得2倍以上的性能改进。

检查矩阵中的值是否存储在主列中(顺序=';F';)或行主顺序(顺序=';C';)。

你可以通过检查菜单来检查订单。矩阵的flags属性(注意C_连续和F_连续标志)。

>;a=np。数组([[1,2],[3,4]])>;a、 flagsC_contracting:TrueF_contracting:FalseOWNDATA:TrueWRITEABLE:TrueALIGNED:TrueWRITEBACKIFCOPY:FalseUPDATEIFCOPY:False

您可以通过复制矩阵来更改顺序(numpy.copy(…,order=';F';)或者通过转置。

更改矩阵的顺序可以提高性能(BLAS通常更适合列主顺序)。

提示:C和F代表C和Fortran编程语言中使用的顺序。BLAS更喜欢F,因为BLAS是用Fortran编写的。

在包含LSTMs的递归神经网络中,每次迭代都将前一次迭代的输入和输出状态结合起来。

i、 例如,矩阵M可以分解为M_x和M_h,而不是matmul(M,concatenate(x[i],h))。

这意味着temp=matmul(M_x,x[:])可以在单个大批量中预计算,然后迭代计算变成temp[i]+matmul(M_h,h)。

例如,可以利用稀疏向量v作为矩阵M[:,v>;0.001]列的过滤器。

大型矩阵可以通过计算奇异值分解(SVD)来近似。计算SVD的速度太慢,无法在线完成。然而,如果你的一个矩阵是常数,那么“预计算”可以得到回报。

U、 s,V=numpy。利纳格。svd(A)#非常慢,所以要预计算!秩=len(s)/3#压缩系数为3y=matmul(V[:秩,:],x)y*=s[:秩]y=matmul(U[:,:秩],y)

提示:预先计算并复制视图V[:rank,:],s[:rank],以及U[:,:rank]和don';别忘了把SVD降到32。

将单个2000x2000矩阵乘法减少到100x2000,然后再进行2000x100乘法(例如),可以产生很大的不同!

我';我们发现,将矩阵的秩减少三分之一或更多,对RNN的精度影响可以忽略不计,但会显著提高性能。