Python for循环每次迭代速度变慢

3

我正在尝试优化一些Python代码(加速一些矩阵运算),我的代码与此类似(我的真实数据集也类似于“gps”),

import numpy as np
gps = [np.random.rand(50,50) for i in xrange(1000)]
ips = np.zeros( (len(gps),len(gps)), dtype='float32')

for i in xrange(len(gps)):
  for j in xrange(0,i+1):
    ips[i,j]= f.innerProd(gps[i],gps[j])
    ips[j,i]= ips[i,j]
   print "Inner product matrix: %3.0f %% done (%d of %d)"%  \
               (((i+1)**2.)/(len(gps)**2.)*100, i, len(gps))

def innerProd(mat1,mat2):
    return float(np.sum(np.dot(np.dot(mat1,mat2),mat1)))

我想了解的是,为什么程序在开始迭代时运行速度很快,随着迭代的进行逐渐变慢?我知道这个问题可能有点天真,但我真的想更清楚地了解在尝试其他操作之前正在发生的事情。我已经在Fortran中实现了我的函数(在Fortran领域内留下任何for循环),并使用f2py创建了一个动态库以从Python调用该函数,这将是Python中的新代码..
import numpy as np
import myfortranInnProd as fip

gps = [np.random.rand(50,50) for i in xrange(1000)]
ips = np.zeros( (len(gps),len(gps)), dtype='float32')

ips = fip.innerProd(gps)

不幸的是,我惊讶地发现我的Fortran-Python版本运行速度比第一个版本慢1.5~2倍(值得一提的是,在Fortran实现中使用了MATMUL())。我已经搜索了一段时间,认为这种“减速”与内存带宽、内存分配或缓存有关,考虑到大数据集,但我不太确定真正发生了什么以及如何提高性能。我在小型英特尔原子电脑、2GB RAM和4核英特尔至强处理器、8GB(当然使用相应比例的数据集)上运行代码,并且“减速”的情况是相同的。

我只需要理解为什么会出现这种“减速”?如果我在C中实现该函数,是否有好处?还是尝试实现在GPU上运行?还有其他改进方法吗? 预先感谢。


我在profile模式下运行了这段代码,发现大部分时间都花在了np.dot函数上,你可以通过执行python -m profile filename.py来对任何文件进行性能分析。 - Dan D.
1
如果你将内部循环除以(i+1),它将花费相同的时间。因此它的行为就像应该的那样。 - jfs
2个回答

4

显而易见的是,每次完成外部循环的执行,内部循环的执行次数都会增加。当i为0时,内部循环只会执行一次,但当i为100时,它将被执行101次。这可能解释了你的观察结果,或者你是指内部循环本身的每次执行随着时间的推移变得更慢了吗?


你说得对,这很明显 :D.. 我本应该自己想出来的。不管怎样,有没有关于如何提高它的性能的想法?你认为C实现可以胜任吗?据我所知,numpy已经是低级别实现了,所以我不知道是否会有任何区别,你觉得呢?我相信我会尝试使用pycuda来实现它。 - Alex S

2

内部的for循环执行次数取决于外部for循环的索引i的值。由于每次内部循环完成时都会显示调试信息,所以随着i增加,它的显示越来越少。(注意百分比仍然按照规律增加。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接