2012-03-06 5 views
1

나는 대학에서 프로젝트를위한 기계 학습을 보여주는 그래픽 응용 프로그램을 코딩하려고 노력해 왔으며 파이썬으로 개발 해왔다. 파이썬은 꽤 느린 언어이기 때문에 런타임 실행 속도를 높이고 Cython을 우연히 발견했습니다. 아직 C/C++에 익숙하지 않지만 가능한 한 많은 코드를 정적으로 입력하려고했습니다. 경고가 있어도 가독성/유연성이 떨어질 수 있지만 현재로서는이 점이 제게 큰 문제는 아닙니다.Cython으로 성능 향상 극대화

그러나 필자는 순수한 Python에 비해이 구현을 크게 개선 한 것을 발견하지 못했으며, 속도를 높이는 방법에 대한 제안이 있다면 궁금합니다. 얼마나 현실적인지 모르겠지만 10 배속 향상과 같은 것에 매우 만족할 것입니다.

나는 ̶h̶a̶v̶e̶n̶'̶t̶ 프로파일 내 코드 아직 내 코드를 프로파일 링 한 결과는 다음과 연결되어 있습니다.

아직 진행 중이므로 레이아웃은 좋지 않지만 몇 가지 간단한 기능 그룹화를 수행했습니다.

소스 코드는 here입니다. 코드의 가장 관련성이 높은 부분은 아래에 게시됩니다.

.

주어진 패드의 메모리를 통해 반복하는 :

cdef findBestApproximation(int padindex): 
    cdef double last_collision_x 
    cdef double last_collision_y 
    cdef double last_collision_i_angle 
    cdef double last_collision_i_speed 
    cdef double last_collision_f_angle 
    cdef double last_collision_f_speed 
    cdef double x_divergence 
    cdef double y_divergenve 
    cdef double f_angular_divergence 
    cdef double divergence 

    printData("FINDING APPROXIMATION FOR PAD %s...\n" % padindex) 
    pad = Pads.padlist[padindex] 
    memory = pad.memory 
    ball = Balls.ball 
    if not memory: 
     approximation = getPadMidpoint(padindex) 
     return approximation 

    collision_data = getCollisionData() 
    (last_collision_x, last_collision_y, last_collision_i_angle, 
    last_collision_i_speed, last_collision_f_angle, 
    last_collision_f_speed) = collision_data 

    best_approx = 0 
    strictness_coef = 1.03 

    for memory_tuple in memory: 
     (x_miss, y_miss, x_collision, y_collision, _, _, f_angle, _) = memory_tuple.getData() 
     (divergence, x_divergence, y_divergence, f_angular_divergence) = calculateDivergence(memory_tuple, collision_data) 

     divergence = x_divergence + y_divergence + f_angular_divergence 

     approximation = (divergence, x_miss, y_miss) 

     printData("\n\nPAD: %s" % padindex) 
     printData("\nLAST COLLISION (X) = %s, CONSIDERED CASE (X) = %s" % (last_collision_x, x_collision)) 
     printData("pos_x DIVERGENCE: %s" % x_divergence) 

     printData("\nLAST COLLISION (Y) = %s, CONSIDERED CASE (Y) = %s" % (last_collision_y, y_collision)) 
     printData("pos_y DIVERGENCE: %s" % y_divergence) 

     printData("\nLAST COLLISION (fAngle) = %s, CONSIDERED CASE (fAngle) = %s" % (last_collision_f_angle, f_angle)) 
     printData("FINAL ANGLE DIVERGENCE: %s" % f_angular_divergence) 

     printData("\nTOTAL DIVERGENCE: %s\n\n" % divergence) 

     if not best_approx: 
      best_approx = approximation 
     else: 
      (least_divergence, _, _) = best_approx 
      if divergence < least_divergence: 
       best_approx = approximation 

    (_, pos_x, pos_y) = best_approx 
    approximation = (pos_x, pos_y) 
    return approximation 

합니다.

계산 및 패드의 메모리에 저장된 특정 과거 사건에 대한 점수를 돌리는 :

cdef calculateDivergence(memory_tuple, collision_data): 
    cdef double pos_x_dif 
    cdef double pos_y_dif 
    cdef double i_angle_dif 
    cdef double i_speed_dif 
    cdef double f_angle_dif 
    cdef double f_speed_dif 

    cdef double max_x_difference 
    cdef double max_y_difference 
    cdef double max_angular_difference 

    cdef double x_divergence 
    cdef double y_divergence 
    cdef double f_angular_divergence 
    cdef double total_divergence 

    (last_collision_x, last_collision_y, last_collision_i_angle, 
    last_collision_i_speed, last_collision_f_angle, 
    last_collision_f_speed) = collision_data 

    (x_miss, y_miss, x_collision, y_collision, 
    i_angle, i_speed, f_angle, f_speed  ) = memory_tuple.getData() 

    pos_x_dif = abs(x_collision - last_collision_x) 
    pos_y_dif = abs(y_collision - last_collision_y) 
    i_angle_dif = getAngleDifference(i_angle, last_collision_i_angle) 
    i_speed_dif = abs(i_speed - last_collision_i_speed) 
    f_angle_dif = getAngleDifference(f_angle, last_collision_f_angle) 
    f_speed_dif = abs(f_speed - last_collision_f_speed) 

    max_x_difference  = window_width 
    max_y_difference  = window_height 
    max_angular_difference = 180 

    x_divergence   = 100 * pos_x_dif /max_x_difference 
    y_divergence   = 100 * pos_y_dif /max_y_difference 
    f_angular_divergence = 100 * f_angle_dif/max_angular_difference 

    #Apply weights. 
    x_divergence   *= WeightData.current_weight 
    y_divergence   *= WeightData.current_weight 
    f_angular_divergence *= (1 - WeightData.current_weight) 

    total_divergence = x_divergence + y_divergence + f_angular_divergence 

    divergence_data = (total_divergence, x_divergence, y_divergence, f_angular_divergence) 
    return divergence_data 

편집 : 코드를 프로파일 링의 Here's 결과. DrawSettingsMenu()는 최악의 경우이지만 무시할 수 있습니다 (기본적으로 설정 메뉴가 표시되지 않음). 모든 "초기화 ..."기능도 무시할 수 있습니다.

+3

내 첫 제안은 코드가 느린 곳에서 테스트하고 추측하지는 않습니다. 그래서 당신은 X 함수가 "합계"에서 Y 시간이 걸린다는 것을 알고 있습니다. – EKS

+2

파이썬 코드에서 작동하는'pypy'를 사용해보십시오. 모든 파이썬에서 작동하지는 않지만, 응용 프로그램에서 작동하는 경우, 여러분은 황금합니다. –

+0

이것이 CodeReview – PlasmaHH

답변

5

먼저 코드를 프로파일 링하고 최적화해야 할 부분을 확인해야합니다. 그런 다음 알고리즘을 최대한 부드럽게 최적화해야합니다. Python에서 너무 느린 함수를 확인하면 Cython을 사용하여 정적으로 시도 할 수 있지만 C로 작성하고 Cython에서 호출하면 성능이 향상됩니다. 그러나 코드를 최적화하기 전에 코드가 올바르게 작동하는지 확인하십시오. 그렇지 않으면 시간이 많이 걸릴 것입니다.

+0

응답 해 주셔서 감사합니다. 지금 코드를 프로파일 링했습니다. – Tagc

2

더 빨리 만들고 싶다면 PyPy 또는 Unladen Swallow과 같은 파이썬 구현을 시도해 볼 수 있습니다. 이전 버전의 Python을 사용하는 경우 Psyco을 살펴볼 수도 있습니다.

+0

감사합니다. 그래도 파이썬 3.2를 지원합니까? – Tagc

+0

아직까지는 PyPy 팀이 이미 지원을 계획하고 있습니다. – tstenner

+0

그들이 며칠 이내에 완료 될 수 있다면, 그것은 꽤 굉장 하겠지만 나는 그 행운을 얻지 못할 것이라고 생각합니다. : p – Tagc