2013-05-14 64 views
12

下面的代码重现我在遇到算法我目前正在实施的问题:为什么迭代元素数组乘法在numpy中减速?

import numpy.random as rand 
import time 

x = rand.normal(size=(300,50000)) 
y = rand.normal(size=(300,50000)) 

for i in range(1000): 
    t0 = time.time() 
    y *= x 
    print "%.4f" % (time.time()-t0) 
    y /= y.max() #to prevent overflows 

的问题是,在一些数量的迭代,事情开始变得逐渐变慢,直到一个迭代需要多次多时间比最初。

放缓 由Python过程enter image description here

CPU占用率的曲线是稳定在17%-18%的全部时间。

我使用:

  • 的Python 2.7.4的32位版本;
  • Numpy 1.7.1 with MKL;
  • Windows 8的
+0

我不认为我看到Linux下的python-2.7.4此行为。 –

+9

这可能是由于denormal数字:http://stackoverflow.com/a/9314926/226621 –

+4

在我的测试运行中,只要它开始放缓,我打断它,并打印numpy.amin(numpy.abs( y [y!= 0]))'并且得到了'4.9406564584124654e-324',所以我认为反常数是你的答案。我不知道如何从Python内部刷新denormals为零,除了创建一个C扩展,虽然... –

回答

3

由于@Alok指出,这似乎是由denormal numbers影响性能的情况下造成的。我在我的OSX系统上运行它并确认了这个问题。我不知道在numpy中刷新非规范化为零的方法。我会尝试在算法中避开这个问题,避免使用非常小的数字:你是否真的需要划分y直到达到1.e-324的水平?

如果您避免低数字例如通过添加下面的行放在循环:

y += 1e-100 

那么你就会有一定的时间每次迭代(因为额外的操作虽然慢)。另一个解决方法是使用更高精度的算术,例如

x = rand.normal(size=(300,50000)).astype('longdouble') 
y = rand.normal(size=(300,50000)).astype('longdouble') 

这会使您的每一步都更加昂贵,但每一步都需要大致相同的时间。

请参见下面的比较在我的系统: enter image description here

+0

_>你真的需要分裂y直到下降到1.e-324水平吗?是的,否则这些值在大约400次迭代时溢出。我在算法中尝试了“添加小常量”解决方案(问题中给出的代码只是一个简单的测试代码),它解决了放慢问题。感谢大家的帮助! (特别是@Alok和@tiago) – Ottokar

相关问题