2011-02-05 3 views
12

Python 3에서 Sugarscape 에이전트 시뮬레이션 모델의 작은 부분을 복제하려고합니다. 코드 성능이 NetLogo보다 3 배 느립니다. 내 코드에 문제가 있거나 파이썬의 고유 한 제한이 될 수 있습니까?에이전트 기반 시뮬레이션 : 성능 문제 : Python vs NetLogo & Repast

분명히 이것은 코드의 일부분 일 뿐이지 만 파이썬이 런타임의 3 분의 2를 소비하는 곳입니다. 내가이 조각에 표시 할 수 정말 비효율적 뭔가 쓴 경우 나는 희망 :

; -- The SugarScape growth and motion procedures. -- 
to M ; Motion rule (page 25) 
    locals [ps p v d] 
    set ps (patches at-points neighborhood) with [count turtles-here = 0] 
    if (count ps > 0) [ 
     set v psugar-of max-one-of ps [psugar]    ; v is max sugar w/in vision 
     set ps ps with [psugar = v]       ; ps is legal sites w/ v sugar 
     set d distance min-one-of ps [distance myself]  ; d is min dist from me to ps agents 
     set p random-one-of ps with [distance myself = d] ; p is one of the min dist patches 
     if (psugar >= v and includeMyPatch?) [set p patch-here] 
     setxy pxcor-of p pycor-of p       ; jump to p 
     set sugar sugar + psugar-of p      ; consume its sugar 
     ask p [setpsugar 0]         ; .. setting its sugar to 0 
    ] 
    set sugar sugar - metabolism ; eat sugar (metabolism) 
    set age age + 1 
end 

내 컴퓨터에서 :

UP = (0, -1) 
RIGHT = (1, 0) 
DOWN = (0, 1) 
LEFT = (-1, 0) 
all_directions = [UP, DOWN, RIGHT, LEFT] 
# point is just a tuple (x, y) 
def look_around(self): 
    max_sugar_point = self.point 
    max_sugar = self.world.sugar_map[self.point].level 
    min_range = 0 

    random.shuffle(self.all_directions) 
    for r in range(1, self.vision+1): 
     for d in self.all_directions: 
      p = ((self.point[0] + r * d[0]) % self.world.surface.length, 
       (self.point[1] + r * d[1]) % self.world.surface.height) 
      if self.world.occupied(p): # checks if p is in a lookup table (dict) 
       continue 
      if self.world.sugar_map[p].level > max_sugar: 
       max_sugar = self.world.sugar_map[p].level 
       max_sugar_point = p 
    if max_sugar_point is not self.point: 
     self.move(max_sugar_point) 

대략 동등한 code in NetLogo (이 단편은 위의 파이썬 기능보다 조금 더 않습니다) , 파이썬 코드는 1000 단계를 실행하는 데 15.5 초가 걸립니다. 동일한 랩톱에서 브라우저 내부에서 Java로 실행되는 NetLogo 시뮬레이션은 6 초 이내에 1000 단계를 완료합니다.

EDIT : 자바 구현을 사용하여 Repast를 확인했습니다. 5.4 초에 NetLogo와 거의 같습니다. Java와 Python 사이의 Recent comparisons은 Java에 아무런 이점이 없다는 것을 암시하기 때문에 비난할만한 코드일까요?

편집 : MASON은 Repast보다 더 빠르다고 생각합니다. 그러나 아직까지는 결국 Java가 실행됩니다.

답변

11

이것은 대단한 속도 향상을 제공하지는 않지만 전역 변수 나 속성에 액세스하는 것보다 지역 변수가 파이썬에서 상당히 빠릅니다. 그래서 당신은 이런 식으로, 지역 주민에 내부 루프에서 사용되는 일부 값을 할당 시도 할 수 :

def look_around(self): 
    max_sugar_point = self.point 
    max_sugar = self.world.sugar_map[self.point].level 
    min_range = 0 

    selfx = self.point[0] 
    selfy = self.point[1] 
    wlength = self.world.surface.length 
    wheight = self.world.surface.height 
    occupied = self.world.occupied 
    sugar_map = self.world.sugar_map 
    all_directions = self.all_directions 

    random.shuffle(all_directions) 
    for r in range(1, self.vision+1): 
     for dx,dy in all_directions: 
      p = ((selfx + r * dx) % wlength, 
       (selfy + r * dy) % wheight) 
      if occupied(p): # checks if p is in a lookup table (dict) 
       continue 
      if sugar_map[p].level > max_sugar: 
       max_sugar = sugar_map[p].level 
       max_sugar_point = p 
    if max_sugar_point is not self.point: 
     self.move(max_sugar_point) 

기능 파이썬에서 호출도 (자바에 비해) 상대적으로 높은 오버 헤드를 가지고, 당신은 더 최적화하기 위해 시도 할 수 있도록 occupied 함수를 직접 사전 검색으로 바꿉니다.

또한 psyco을 살펴 봐야합니다. 파이썬을위한 just-in-time 컴파일러로 어떤 경우에는 속도를 크게 향상시킬 수 있습니다. 그러나 아직 파이썬 3.x를 지원하지 않으므로 파이썬의 구버전을 사용해야 할 것입니다.

+1

니스. 실행 시간은 15.5에서 11.4 초 (~ 26 %)로 감소했습니다. 도대체 파이썬이 적어도 인터프리터에 -O 옵션을 지정할 때, 그 물건을 최적화하지 않는 이유는 무엇입니까 ??? – max

+1

'점령'기능을 없애고 10.4 초로 떨어졌습니다. – max

+1

@ max : 숙련 된 속도 향상으로 다시 쓰는 것에 대해 감사드립니다. – Curious2learn

4

neighborhood이 NetLogo에서 구현되는 방식이 사용자가 가지고있는 이중 루프와 다른 것 같아요. 특히, 나는 그들이

n = [ [0,1],[0,-1],[1,0],[-1,0]....] 

같은 동네 벡터를 미리 계산 생각 (당신은 비전 = 1, 2에 대해 다른 하나를 필요 ... 것) 한 후, 중첩 루프 대신 n을 통해 하나 개의 루프를 사용하여 네가하는 것처럼. 이것은 곱셈의 필요성을 제거합니다.

나는 이것이 3 배의 속도 향상을 얻지 못할 것이라고 생각합니다.

+0

가장 높은 설탕 점 사이에 무작위 포인트가 필요합니다. 내 접근 방식에서는 루프 앞의 방향에 대해 '셔플'을 한 번만 수행합니다. NetLogo에서는 모든 최상의 포인트를 추적하여 목록에서 무작위로 선택합니다 (파이썬에서 시도했지만 약간 느려졌습니다). 당신의 접근 방식에서, 나는 여러 최고의 포인트를 다시 추적하거나 인접 벡터 각각을 섞는 (셔플 대신 하나씩) 시도해야 할 것입니다. 나는 시도 할 것이다. – max

+0

또한 토러스에서 랩핑을 확인해야하기 때문에 각 점에 대해 이웃을 미리 계산하거나 '%'연산을 계속 사용해야합니다. 전자는 몇 퍼센트 더 빠르며 후자는 훨씬 느립니다. – max

+0

netLogo에서 랩 어라운드 월드 비헤이비어를 더 빠르게 가져 오는 방법은 x 및 y 방향의 양 끝에 여분의 인덱스가있는 질 낮은 배열로 모델링하는 것입니다. 이웃 거리가 1 인 경우, 배열 인덱스는 0에서 width + 1, 0에서 height + 1까지 실행됩니다. 계산은 세계를 나타내는 인덱스의 하위 집합 내에서만 수행해야하며 각 차원의 양쪽 끝에있는 여분의 인덱스에 대한 패치 값은 다른 끝의 세계에서 복사 할 수 있습니다. 이렇게하면 세계 내부의 netLogo 패치에 해당하는 각 파이썬에 대한 % 계산을 피할 수 있습니다. –

3

이 질문은 오래된 질문이지만 NumPy를 사용하여 작업 속도를 높이는 것이 좋습니다. 논픽 티 (1, 2, 3 또는 N 차원 그리드) 동 질 데이터 객체 (모든 정수 또는 모든 수레 등)가 논리적으로 구성되는 곳은 Numpy로 표현되고 액세스 될 때 오버 헤드가 적습니다. 배열.

http://numpy.org