Ускорение циклов над массивом Numpy - PullRequest
4 голосов
/ 12 мая 2011

В моем коде у меня есть цикл for, который индексирует многомерный массив Numpy и выполняет некоторые операции с использованием подмассива, получаемого на каждой итерации.Это выглядит так:

for sub in Arr:
  #do stuff using sub

Теперь все, что делается с использованием sub, полностью векторизовано, поэтому оно должно быть эффективным.С другой стороны, этот цикл повторяется около ~10^5 раз и является узким местом.Как вы думаете, я получу улучшение, перенеся эту часть на C. Я несколько неохотно делаю это, потому что do stuff using sub использует приемы вещания, нарезки, умного индексирования, которые было бы утомительно писать на простом C. Я также приветствуюмысли и предложения о том, как работать с широковещанием, секцией, умным индексированием при разгрузке вычислений до C.

Ответы [ 3 ]

6 голосов
/ 12 мая 2011

Если вы не можете «векторизовать» всю операцию и циклы действительно являются узким местом, тогда я настоятельно рекомендую использовать Cython.Я в последнее время балуюсь этим, и с ним легко работать, и у него неплохой интерфейс с numpy.Для чего-то вроде интегратора Ланжевена я видел ускорение в 115 раз по сравнению с приличной реализацией в numpy.См. Документацию здесь:

http://docs.cython.org/src/tutorial/numpy.html

, и я также рекомендую посмотреть на следующую бумагу

Вы можете увидеть удовлетворительное ускорение, просто набраввходной массив и счетчик циклов, но если вы хотите использовать весь потенциал Cython, вам придется жестко закодировать эквивалентную трансляцию.

2 голосов
/ 19 мая 2011

Сан, вы можете взглянуть на scipy.weave. Вы можете использовать scipy.weave.blitz, чтобы прозрачно перевести ваше выражение в C++ код и запустить его. Он будет обрабатывать срезы автоматически и избавляться от временных, но вы утверждаете, что тело вашей петли for не создает временных, поэтому ваш пробег может варьироваться.

Однако, если вы хотите заменить весь цикл for на что-то более эффективное, вы можете использовать scipy.inline. Недостатком является то, что вы должны написать C++ код. Это не должно быть слишком сложно, потому что вы можете использовать синтаксис Blitz++, который очень близок к выражениям с массивными массивами. Нарезка поддерживается напрямую, а трансляция - нет.

Есть два обходных пути:

  1. - использовать api numpy-C и использовать многомерные итераторы. Они прозрачно управляют вещанием. Однако вы вызываете среду выполнения Numpy, так что это может привести к некоторым накладным расходам. Другой вариант и, возможно, более простой вариант - использовать обычную матричную запись для вещания. Широковещательные операции могут быть записаны как внешние продукты с вектором всех единиц. Хорошо, что Blitz++ на самом деле не создаст эти временные широковещательные массивы в памяти, а выяснит, как обернуть его в эквивалентный цикл.

  2. Для второго варианта взгляните на http://www.oonumerics.org/blitz/docs/blitz_3.html#SEC88 для индексных заполнителей. Пока ваша матрица имеет менее 11 измерений, вы в порядке. Эта ссылка показывает, как их можно использовать для формирования внешних продуктов http://www.oonumerics.org/blitz/docs/blitz_3.html#SEC99 (поиск внешних продуктов для перехода к соответствующей части документа).

1 голос
/ 17 мая 2011

Помимо использования Cython, вы можете написать часть (-ы) бутылочного горлышка на Фортране.Затем используйте f2py, чтобы скомпилировать его в файл Python .pyd.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...