2016-09-21 4 views
3

메모리 (행 주요 순서) :numpy는 어떻게 다차원 방송을 구현 했습니까?

[[A(0,0), A(0,1)] 
[A(1,0), A(1,1)]] 

has this memory layout: 
[A(0,0), A(0,1), A(1,0), A(1,1)] 

나는 다음과 같은 경우에이 같은 알고리즘의 일을 생각한다.

[[0, 1, 2, 3]   [[1] 
        x 
[4, 5, 6, 7]]   [10]] 

    A (2 by 4)   B (2 by 1) 

Iterate 0th dimensions of A and B simultaneously { 
    Iterate last dimension of A{ 
     multiply; 
    } 
} 

방송 치수가 0 번째 치수 :

방송 치수는 지난 차원이다

[[0, 1, 2, 3] 
        x [[1,10,100,1000]] 
[4, 5, 6, 7]] 

    A (2 by 4)    B (1 by 4) 

Iterate 0th dimension of A{ 
    Iterate 1st dimensions of A and B simultaneously{ 
     multiply; 
    } 
} 

질문 :

  1. 어떻게 최고 곱셈의 어떤 순서로 알고 NumPy와 않습니다 . (순서대로 메모리가 사방에 메모리를 읽는 것보다 더 나은 독서.하지만 어떻게 NumPy와 그림 않았다고?)

  2. 배열이있는 경우에 할 NumPy와 것입니다 무엇
  3. 두 개 이상의 차원

  4. 할 NumPy와 것입니다 무엇
  5. 방송 차원이 마지막 차원이 아닌 경우? 무슨 일이 일어나고 있는지의

2 추측 :

#include <iostream> 
int main(void){ 
    const int nA = 12; 
    const int nB = 3; 
    int A[nA]; 
    int B[nB]; 
    for(int i = 0; i != nA; ++i) A[i] = i+1; 
    for(int i = 0; i != nB; ++i) B[i] = i+1; 
    //dimension 
    int dA[] = {2,3,2}; 
    int dB[] = {1,3,1}; 

    int* pA = A; 
    int* pB = B; 
    int* pA_end = A + nA; 
    //is it possible to make the compiler 
    //generate the iA and sA? 
    int iB = 0; 
    int iB_max = 2; 
    int sB[] = {1,0}; 

    while(pA != pA_end){ 
     std::cout << "*pA, *pB: " << *pA << ", " << *pB <<std::endl; 
     std::cout << "iB: " << iB <<std::endl; 
     *(pA) *= *(pB); 
     ++pA; 
     pB += sB[iB]; 
     ++iB; 
     if (iB == iB_max) {iB = 0; pB = B;} 
    } 

    for(pA = A; pA != pA_end; ++pA){ 
     std::cout << *(pA) << ", "; 
    } 
    std::cout << std::endl;  
} 
+0

2 추측이 잘못된 것 같다 ffered 외부 루프는

cython가 빠르고, 간단 c 반복으로이 변환 빠른입니다. numpy는 다중 색인을 사용하는 것 같습니다. – rxu

답변

3

정말 방송 세부 사항을 얻으려면 당신은 배열 형태와 진보를 이해할 필요가있다. 그러나 많은 작업이 nditer을 사용하여 c 코드로 구현되었습니다. http://docs.scipy.org/doc/numpy/reference/arrays.nditer.html에서 읽을 수 있습니다. np.nditer을 사용하면 Python 수준에서 도구에 액세스 할 수 있지만 실제 가치는 cython 또는 사용자 코드 c과 함께 사용하면됩니다.

np.lib.stride_tricks에는 스트라이드와 함께 놀 수있는 기능이 있습니다. 그 기능 중 하나는 배열이 함께 방송되는 방식을 시각화하는 데 도움이됩니다. 실제로 작업은 nditer으로 수행하지만,이 기능은 작업을 이해하는 데 도움이 될 수 효과적으로 2 배열 1의 모양에 맞게 복제 된

In [629]: np.lib.stride_tricks.broadcast_arrays(np.arange(6).reshape(2,3), 
            np.array([[1],[2]])) 
Out[629]: 
[array([[0, 1, 2], 
     [3, 4, 5]]), 
array([[1, 1, 1], 
     [2, 2, 2]])] 

참고. 그러나 복제는 실제 복제본이 아닌 스트라이핑 트릭으로 수행됩니다.

In [631]: A,B=np.lib.stride_tricks.broadcast_arrays(np.arange(6).reshape(2,3), 
             np.array([[1],[2]])) 
In [632]: A.shape 
Out[632]: (2, 3) 
In [633]: A.strides 
Out[633]: (12, 4) 
In [634]: B.shape 
Out[634]: (2, 3) 
In [635]: B.strides 
Out[635]: (4, 0)   

그것은 복사하지 않고 복제를 수행이 (4,0) 진보를합니다.

=================

여기가 방송 중에 무엇이다, 파이썬 수준 nditer 사용.

In [1]: A=np.arange(6).reshape(2,3) 
In [2]: B=np.array([[1],[2]]) 

평원 nditer 한 번 http://docs.scipy.org/doc/numpy/reference/arrays.nditer.html#using-an-external-loop

In [5]: it =np.nditer((A,B)) 
In [6]: for a,b in it: 
    ...:  print(a,b) 

0 1 
1 1 
2 1 
3 2 
4 2 
5 2 

에서 요소를 한 세트를 공급하지만에 extenal_loop을 켤 때, 여기 덩어리, 브로드 캐스트 배열의 각각의 행에 반복 처리 :

In [7]: it =np.nditer((A,B), flags=['external_loop']) 
In [8]: for a,b in it: 
    ...:  print(a,b) 

[0 1 2] [1 1 1] 
[3 4 5] [2 2 2] 

더 복잡한 방송을 사용하면 external_loop은 여전히 ​​1 차원 배열을 생성하여 간단하게 만들 수 있습니다.,210 스타일 반복 :

In [13]: A1=np.arange(24).reshape(3,2,4) 
In [18]: it =np.nditer((A1,np.arange(3)[:,None,None]), flags=['external_loop']) 
In [19]: while not it.finished: 
    ...:  print(it[:]) 
    ...:  it.iternext() 
    ...:  
(array([0, 1, 2, 3, 4, 5, 6, 7]), array([0, 0, 0, 0, 0, 0, 0, 0])) 
(array([ 8, 9, 10, 11, 12, 13, 14, 15]), array([1, 1, 1, 1, 1, 1, 1, 1])) 
(array([16, 17, 18, 19, 20, 21, 22, 23]), array([2, 2, 2, 2, 2, 2, 2, 2])) 

참고 A1는 (3,2,4) 동안, nditer 루프 수율 2 * 4 길이 요소 3 단계 (제 1 축).

다른 검색 결과 : cython/nditer 첫 번째 방법은 속도 개선 효과가별로 없지만 두 번째 방법은 많은 도움이되었습니다. c 또는 cython의 경우 external_loop의 경우 간단히 낮은 수준 반복을 수행합니다.

===============

I는 (1) 및 제 3 축에 방송하는 경우가 반복자 2 * 3 단계 (효과적으로 첫번째 2 축 평탄화 걸리고, 급송 3) :

In [20]: it =np.nditer((A1,np.arange(2)[None,:,None]), flags=['external_loop']) 
In [21]: while not it.finished: 
    ...:  print(it[:]) 
    ...:  it.iternext() 
    ...:  
(array([0, 1, 2, 3]), array([0, 0, 0, 0])) 
(array([4, 5, 6, 7]), array([1, 1, 1, 1])) 
(array([ 8, 9, 10, 11]), array([0, 0, 0, 0])) 
(array([12, 13, 14, 15]), array([1, 1, 1, 1])) 
(array([16, 17, 18, 19]), array([0, 0, 0, 0])) 
(array([20, 21, 22, 23]), array([1, 1, 1, 1])) 

그러나 buffered와 함께, 그것은 2 개 1D 배열 나에게 먹이를 한 번 반복 할 : 그 BU를 보여

In [22]: it =np.nditer((A1,np.arange(2)[None,:,None]), flags=['external_loop','buffered']) 
In [23]: while not it.finished: 
    ...:  print(it[:]) 
    ...:  it.iternext() 
    ...:  
(array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]), 
array([0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1])) 

Does Cython offer any reasonably easy and efficient way to iterate Numpy arrays as if they were flat? 어떤 속도 테스트가 있습니다

for xarr in it: 
    x = xarr 
    size = x.shape[0] 
    for i in range(size): 
     x[i] = x[i]+1.0 
+0

'np.lib.stride_tricks.broadcast_arrays' 철자가 더 좋습니다 [https://docs.scipy.org/doc/numpy/reference/generated/numpy.broadcast_arrays.html] – Eric

+3

전체' stride_tricks.py' 파일은 더 깊이 파고 드는 것이 좋습니다. – hpaulj

+0

나는 nditer C 코드를 읽으려고하지만, 아직 이해하지는 못했다. nditer가 성능을 희생합니까? niter는 중첩 루프를 가변 스트라이드가있는 단일 루프로 취급합니까? – rxu

관련 문제