Как ускорить доступ к многомерным массивам в scipy.weave? - PullRequest
2 голосов
/ 25 июля 2010

Я создаю свой код c на python, чтобы ускорить цикл:

from scipy import weave
from numpy import *

#1) create the array
a=zeros((200,300,400),int)
for i in range(200):
    for j in range(300):
        for k in range(400):    
            a[i,j,k]=i*300*400+j*400+k
#2) test on c code to access the array
code="""
for(int i=0;i<200;++i){
for(int j=0;j<300;++j){
for(int k=0;k<400;++k){
printf("%ld,",a[i*300*400+j*400+k]);    
}
printf("\\n");
}
printf("\\n\\n");
}
"""
test =weave.inline(code, ['a'])

Работает все хорошо, но все еще дорого, когда массив большой. Кто-то предложил мне использовать a.strides вместо отвратительного "a [i * 300 * 400 + j * 400 + k]" Я не могу понять документ о .strides.

Любые идеи

Заранее спасибо

Ответы [ 4 ]

4 голосов
/ 25 июля 2010

Вы можете заменить 3 цикла for на

grid=np.ogrid[0:200,0:300,0:400]
a=grid[0]*300*400+grid[1]*400+grid[2]

Следующее предполагает, что это может привести к ускорению ~ 68x (или лучше? См. Ниже):

% python -mtimeit -s"import test" "test.m1()"
100 loops, best of 3: 17.5 msec per loop
% python -mtimeit -s"import test" "test.m2()"
1000 loops, best of 3: 247 usec per loop

test.py:

import numpy as np

n1,n2,n3=20,30,40
def m1():
    a=np.zeros((n1,n2,n3),int)
    for i in range(n1):
        for j in range(n2):
            for k in range(n3):    
                a[i,j,k]=i*300*400+j*400+k
    return a

def m2():    
    grid=np.ogrid[0:n1,0:n2,0:n3]
    b=grid[0]*300*400+grid[1]*400+grid[2]
    return b 

if __name__=='__main__':
    assert(np.all(m1()==m2()))

При n1, n2, n3 = 200 300 400,

python -mtimeit -s"import test" "test.m2()"

на моей машине потребовалось 182 мс, а

python -mtimeit -s"import test" "test.m1()"

еще предстоитотделка.

1 голос
/ 29 июля 2010

Проблема в том, что вы печатаете 2,4 миллиона номеров на экране в вашем C-коде.Это, конечно, займет некоторое время, потому что числа должны быть преобразованы в строки, а затем выведены на экран.Вам действительно нужно распечатать их все на экране?Какова ваша конечная цель здесь?

Для сравнения я попытался просто установить другой массив в качестве каждого из элементов в.Этот процесс занял около 0,05 секунд при плетении.Я перестал синхронизировать печать всех элементов на экране примерно через 30 секунд.

0 голосов
/ 20 февраля 2013

Я действительно надеюсь, что вы не запустили цикл со всеми операторами печати, как уже отмечал Джастин.Кроме того:

from scipy import weave
n1, n2, n3 = 200, 300, 400

def m1():
    a = np.zeros((n1,n2,n3), int)
    for i in xrange(n1):
        for j in xrange(n2):
            for k in xrange(n3):
                a[i,j,k] = i*300*400 + j*400 + k
    return a

def m2():    
    grid = np.ogrid[0:n1,0:n2,0:n3]
    b = grid[0]*300*400 + grid[1]*400 + grid[2]
    return b 

def m3():
    a = np.zeros((n1,n2,n3), int)
    code = """
    int rows = Na[0];
    int cols = Na[1];
    int depth = Na[2];
    int val = 0;      
    for (int i=0; i<rows; i++) {
        for (int j=0; j<cols; j++) {
            for (int k=0; k<depth; k++) {
                val = (i*cols + j)*depth + k;
                a[val] = val;
            }
        }
    }"""
    weave.inline(code, ['a'])
    return a

%timeit m1()
%timeit m2()
%timeit m3()
np.all(m1() == m2())
np.all(m2() == m3())

Дает мне:

1 loops, best of 3: 19.6 s per loop
1 loops, best of 3: 248 ms per loop
10 loops, best of 3: 144 ms per loop

Что кажется довольно разумным.Если вы хотите еще больше ускорить его, вы, вероятно, захотите начать использовать свой графический процессор, который идеально подходит для подобных операций.

В этом особом случае вы можете даже:

def m4():
    a = np.zeros((n1,n2,n3), int)
    code = """
    int rows = Na[0];
    int cols = Na[1];
    int depth = Na[2];
    for (int i=0; i<rows*cols*depth; i++) {
        a[i] = i;
    }"""
    weave.inline(code, ['a'])
    return a

Но это уже не намного лучше, поскольку np.zeros() уже занимает большую часть времени:

%timeit np.zeros((n1,n2,n3), int)
10 loops, best of 3: 113 ms per loop
0 голосов
/ 28 апреля 2012

Нет способа ускорить доступ к многомерному массиву в C. Вы должны вычислить индекс массива и вы должны разыменовать его, это так просто, как это получается.

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