2011-11-22 2 views
2

다음 문제의 파이썬 순환 오버 헤드에 대한 도움이 필요합니다. 2D Numpy 배열에서 고전적인 동적 프로그래밍 알고리즘 인 픽셀 흐름 알고리즘을 계산하는 함수를 작성하고 있습니다. 그것은 필요 같이 적어도 한번 상기 어레이의 모든 요소를 ​​방문numpy로 동적 프로그래밍을 할 때 Python 루프 오버 헤드를 피할 수 있습니까?

1)

for x in range(xsize): 
    for y in range(ysize): 
     updateDistance(x,y) 

2) 잠재적 보이는 요소의 이웃의 값에 따라 소자의 경로를 따라 이

while len(workingList) > 0: 
    x,y = workingList.pop() 
    #if any neighbors of x,y need calculation, push x,y and neighbors on workingList 
    #else, calculate flow on pixels as a sum of flow on neighboring pixels 

은 불행히도, 난 updateDistance에 대한 호출이 pass 경우에도 # 1에 파이썬 루프 오버 헤드를 많이 받고있는 것으로 보인다. 나는이 알고리즘이 파이썬에서 루핑 오버 헤드를 피할 수있는 좋은 접근 방식이어야한다는 고전적인 충분한 알고리즘이라고 생각한다. 나는 # 1을 고칠 수 있다면 # 2의 루프에서 파열 될 것이라고 걱정한다.

2D numpy 배열의 요소를 신속하게 반복하고 해당 배열의 요소 체인을 잠재적으로 업데이트하는 방법에 대한 제안 사항이 있습니까?

편집 : # 2

의 자세한 내용을 비우기 내가 아마도 np.meshgrid 전화를 벡터화와 함께 첫 번째 루프를 벡터화 할 수있을 것 같다.

루프의 일부는 약간 복잡하지만 여기서는 단순화 된 버전입니다. 루프와 이웃 요소에 대한 색인 생성에 대해 걱정하고 있습니다.

#A is a 2d cost matrix 
workingList = [(x,y)] 
while len(workingList) > 0: 
    x,y = workingList.pop() 
    neighborsToCalculate = [] 
    for n in neighborsThatNeedCalculation(x,y): #indexes A to check neighbors of (x,y) 
     neighborsToCalculate.append(n) 
    if len(neighborstToCalculate) != 0: 
     workingList.append((x,y)) 
     workingList.extend(neighborsToCalculate) 
    else: 
     for xn,yn in neighbors(x,y): 
      A[x,y] += 1+A[xn,yn] 

이것은 일반적인 너비 우선 검색 문제입니다. 이것이 병렬화 될 수 있다면 좋을 것입니다. 그것은 경로를 따르기 때문에 아마도 현재 형태로는 될 수 없지만, 나는 제안을 기뻐할 것입니다.

+0

두 번째 루프에 대한 자세한 내용을 게시 할 수 있습니까? – Simon

+0

@Simon 예, 저는 그것을 좀 더 구체화 시켰습니다. – Rich

답변

3

알고리즘에서 파이썬 루프를 사용하면 numpy에서 속도 향상을 얻을 수 없습니다. 문제를 병렬 처리해야합니다.

이미지 처리에서, 병렬화는 모든 픽셀에 대해 동일한 기능, 즉 커널을 사용하는 것을 의미합니다. 대신 일을 NumPy와에서 :

for x in range(xsize): 
    for y in range(ysize): 
     img1[y, x] = img2[y, x] + img3[y, x] 

당신이 할 : 루프가 C에서 일어나는

img1 = img2 + img3 # add 2 images pixelwise 

그래서. 각 픽셀에 대해 길이를 알 수없는 이웃 목록을 가지고 있다는 사실은 이러한 방식으로 문제를 어렵게 만듭니다. 문제 (알고리즘에 대해 좀 더 구체적으로 설명 할 수 있을까요?)를 수정하거나 cython과 같은 다른 언어를 사용해야합니다.

편집는 :

당신은 당신의 알고리즘을 변경하지 않고 NumPy와 혜택을받지 않습니다. Numpy를 사용하면 선형 대수 연산을 수행 할 수 있습니다. 임의 조작을 수행 할 때이 라이브러리로 오버 플로우 루핑을 피할 수 없습니다.

이를 최적화하려면, 당신은 고려할 수 :

  • 을 알고리즘을 최적화 루핑 비용

  • 제거하는 (파이썬 확장 전문) 사이 썬과 같은 다른 언어로 전환 : 당신이 만약 선형 대수 연산 (이것은 neighborsThatNeedCalculation 함수에 따라 다름)을 사용하여 동일한 결과를 얻을 수 있지만 numpy를 사용할 수는 있지만 새로운 아키텍처를 찾아야합니다. MapReduce와 같은 병렬화 기술을 사용하여

  • 입니다. 파이썬을 사용하면 멀티 프로세싱 모듈에서 사용할 수있는 풀 (pool)을 사용할 수 있습니다. 다른 언어로 전환하면 속도가 향상됩니다. 파이썬에는 다른 병목 현상이 있기 때문입니다.경우

당신은 설정에 쉽게 뭔가 통합을 원하고, 당신은 당신이 당신의 알고리즘을 재 작업 할 수없는 경우, 난 강력 사이 썬을 제안 C와 같은 공연이 필요합니다.

+0

시간을내어 주셔서 감사합니다. 나는 초기 엄청난 스피드 업으로 cython으로 끝났다. – Rich

3

첫 번째 부분에서는 numpy.vectorize을 사용할 수 있지만 배열 작업을 사용하여 updateDistance 기능을 구현할 방법이없는 경우에만 사용해야합니다. 다음은 예입니다 : 이것은 당신이하려고하는 작업이있는 경우, 현실에서

import numpy as np  
updateDistance = np.vectorize(lambda x: x + 1) # my updateDistance increments 

, 단지 a + 1을한다. 그래서 우리는 사람의 배열을 가지고 updateDistance을 적용하는 경우 :

>>> a = np.ones((3,3)) 
>>> updateDistance(a) 
array([[ 2., 2., 2.], 
     [ 2., 2., 2.], 
     [ 2., 2., 2.]]) 

는 두 번째 부분에 관해서는, 나는 내가 더 나은 대안을 제안하기 위해 충분히 내용을 이해 생각하지 않습니다. 가장 가까운 이웃을 반복적으로 관찰해야하는 것처럼 들리므로, 적어도 if-else에서 문제를 개선 할 수 있다고 생각됩니다.


업데이트 : 첫 번째 부분에 대한 타이밍.

참고 : 이러한 타이밍은 환경을 정상화하려고 시도하지 않고 내 컴퓨터에서 수행되었습니다.

python -mtimeit 'import numpy as np' 'n = 100' 'a = np.ones((n, n))' 'b = np.zeros((n, n))' 'for x in range(n): ' ' for y in range(n):' '  b[x,y] = a[x,y] + 1' 

np.vectorize 시간이 생성된다 :

루프 회수가 생성되어 두 경우

python -mtimeit 'import numpy as np' 'n = 100' 'a = np.ones((n, n))' 'updateDistance = np.vectorize(lambda x: x + 1)' 'b = updateDistance(a)' 

, n = 100는 100 × 100 배열을 이끈다. 필요에 따라 100을 교 체하십시오. 마지막으로

Array size Loop version np.vectorize version np.vectorize speed up 
100 x 100  20.2 msec  2.6 msec    7.77x 
200 x 200  81.8 msec  10.4 msec    7.87x 
400 x 400  325 msec  42.6 msec    7.63x 

는, 당신이 할 수있는 간단하게 배열 작업을 사용으로 np.vectorize 예를 비교 : 내 컴퓨터에

python -mtimeit 'import numpy as np' 'n = 100' 'a = np.ones((n, n))' 'a += 1' 

, 이것은 다음을 생성합니다. 요약

Array size Array operation version Speed up over np.vectorize version 
100 x 100  23.6 usec     110.2x 
200 x 200  79.7 usec     130.5x 
400 x 400  286 usec     149.0x 

, 거기에 대신 루프로, np.vectorize 사용에 장점이 있지만, 가능하면, 배열 연산을 사용 updateDistance의 기능을 구현하기 위해 훨씬 더 큰 인센티브가 있습니다.

+0

감사합니다. 나는 많은 단계를 거쳐 현재 셀 이상을 업데이트 할 수있는 모든 요소에 걸쳐 연산을 벡터화하고 싶다. 귀하의 예제를 보면, 나는 람다 본문에서 고려중인 현재 x, y 좌표를 알고 'a'에 직접 업데이트해야합니다. 이것이 numpy의 합리적인 사용인가? – Rich

1

C- 확장/Cython 사용을 고려해야합니다. 파이썬 함께있을 경우, 하나 개의 주요 개선 교체에 의해 달성 될 수있다 :

for xn,yn in neighbors(x,y): 
     A[x,y] += 1+A[xn,yn] 

로 :

n = neighbors(x,y) 
A[x,y] += len(n)+sum(A[n]) 

neighbors 인덱스가 아닌 첨자를 반환해야합니다.

관련 문제