2013-05-14 11 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 

Проблема заключается в том, что после некоторого числа итераций, вещи начинают получать постепенно медленнее, пока одна итерация не требуется несколько раз больше чем первоначально.

Участок замедления enter image description here

использование процессора с помощью процесса Python является стабильным по всему 17-18% всего времени.

Я использую:

  • Python 2.7.4 32-разрядной версии;
  • Numpy 1.7.1 с MKL;
  • Windows 8.
+0

Я не думаю, что я вижу это поведение с помощью питона-2.7.4 под Linux. –

+9

Возможно, это связано с денормальными номерами: http://stackoverflow.com/a/9314926/226621 –

+4

В моем тестовом прогоне, как только он начал замедляться, я прервал его и сделал 'print numpy.amin (numpy.abs (numpy.abs) y [y! = 0])) 'и получил' 4.9406564584124654e-324', поэтому я считаю, что денормальные числа - ваш ответ. Я не знаю, как очистить денормалы до нуля изнутри Python, кроме создания расширения 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