Почему итеративное умножение массива элементов уменьшено в 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.

Ответ 1

Как отметил @Alok, это, по-видимому, вызвано денормальными номерами, влияющими на производительность. Я запустил его в своей 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