密集矩阵乘法优化在python中效果很小
我想知道为什么I和j上的循环优化反转(应该提供更好的数据局部性)不能与python中的以下代码一起工作:密集矩阵乘法优化在python中效果很小,python,optimization,matrix,Python,Optimization,Matrix,我想知道为什么I和j上的循环优化反转(应该提供更好的数据局部性)不能与python中的以下代码一起工作: import random import time def fillRand1D(size): return [random.uniform(-2.0, 2.0) for _ in range(size * size)] def mmNaive1D(A, B, size): C = [0] * size * size for i in range(size):
import random
import time
def fillRand1D(size):
return [random.uniform(-2.0, 2.0) for _ in range(size * size)]
def mmNaive1D(A, B, size):
C = [0] * size * size
for i in range(size):
for j in range(size):
for k in range(size):
C[i * size + j] += A[i * size + k] * B[k * size + j]
return C
def mmInvariant1D(A, B, size):
C = [0] * size * size
for i in range(size):
for j in range(size):
sigma = C[i * size + j]
for k in range(size):
sigma += A[i * size + k] * B[k * size + j]
C[i * size + j] = sigma
return C
def mmLoop1D(A, B, size):
C = [0] * size * size
for k in range(size):
for i in range(size):
for j in range(size):
C[i * size + j] += A[i * size + k] * B[k * size + j]
return C
def mmLoopInvariant1D(A, B, size):
C = [0] * size * size
for k in range(size):
for i in range(size):
Aik = A[i * size + k]
for j in range(size):
C[i * size + j] += Aik * B[k * size + j]
return C
def main():
matmul_func_1D = [mmNaive1D,mmInvariant1D,mmLoop1D,mmLoopInvariant1D]
size = 200
A_1D = fillRand1D(size)
B_1D = fillRand1D(size)
for f in matmul_func_1D:
A = A_1D[:] # copy !
B = B_1D[:]
start_time = time.time()
C = f(A_1D,B_1D,size)
# print(T)
print(f.__name__ + " in " + str(time.time() - start_time) + " s")
if __name__ == '__main__':
main()
python的结果如下:
mmNaive1D in 3.420367956161499 s
mmInvariant1D in 2.316128730773926 s
mmLoop1D in 3.4071271419525146 s
mmLoopInvariant1D in 2.5221548080444336 s
< C++ >相同的优化给出:
> Time [MM naive] 1.780587 s
> Time [MM invariant] 1.642554 s
> Time [MM loop IKJ] 0.304621 s
> Time [MM loop IKJ invariant] 0.276159 s
您的
A、B和C
矩阵是python列表,对于大维度来说速度非常慢。您可以将它们创建为numpy阵列,以尝试加快功能:
>>> import numpy as np
>>> A = np.random.uniform(-2., 2., (size,size))
>>> B = np.random.uniform(-2., 2., (size,size))
这将A
和B
矩阵定义为size x size
随机矩阵
代码的瓶颈是python循环。Python循环相当慢,您希望尽可能在代数运算中避免它们。在你的例子中,你想要实现的(如果我没有错的话)是C=A*B
where*是两个2D矩阵之间的点积。翻译成numpy:
>>> C = A.dot(B)
如果你计时:
>>> %timeit C = A.dot(B)
100 loops, best of 3: 7.91 ms per loop
只需7.91 ms
即可计算点积。我知道你想玩python,但是如果你想做数学演算,你越早去numpy,你的算法的速度就越好
回到您的算法,如果我在我的计算机上运行您的代码,优化确实有效,并实现了一定的加速:
mmNaive1D in 1.72708702087 s
mmInvariant1D in 1.64227509499 s
mmLoop1D in 1.57529997826 s
mmLoopInvariant1D in 1.26218104362 s
所以这对我来说很有效
编辑:在多次运行代码后,我得到了不同的结果:
mmNaive1D in 1.63492894173 s
mmInvariant1D in 1.1577808857 s
mmLoop1D in 1.67409181595 s
mmLoopInvariant1D in 1.32283711433 s
这次“优化”不起作用。我猜这是因为算法的瓶颈是python循环,而不是内存访问
EDIT2:一些更相关的结果执行每个算法的100次迭代以获得平均计时(花了一段时间哈哈):
即使100次迭代仍然不够相关(比如1.000.000次会更好,但需要花费很多时间),这表明作为100次运行时的平均值,“优化”并不是真正的优化。我真的不知道为什么,但可能是在python中添加一个新变量要比200次内存访问慢(可能后面有一些缓存)。python列表不是连续数组,因此优化在这里没有什么作用,我很抱歉。哦,谢谢,如果我使用的是连续的数组,我想它可能会工作。如果你需要能够指定连续性,Numpy是优化这类过程的好地方。。。当然,您可以只使用numpy.multiplyYes,但是对于python
for
循环进行的所有类型检查,您可能看不到数据局部性的优势。正如en_Knight所说,对于任何真正的数组计算,您最好使用numpy
,尽管我怀疑您只是在玩弄一些东西。确切地说,我只是想玩一下Python,我会尝试使用numpy,谢谢!谢谢伊伦戈的回答。事实上,我的问题是为什么数据局部性优化不起作用。正如我在评论中所说,我尝试将连续数组与numpy.ascontiguousarray一起使用,但没有成功。我想你是对的,瓶颈不是内存访问。我只是用每个函数100次迭代的平均时间进行了编辑。希望你感到好奇:P
mmNaive1D in 1.66692941904 s
mmInvariant1D in 1.15141540051 s
mmLoop1D in 1.58852998018 s
mmLoopInvariant1D in 1.28386260986 s