본문 바로가기
Python

파이썬 Scipy, 함수 최적화(Optimization) 방법과 코드 (Python)

by 무적물리 2020. 3. 21.

엔지니어링에서 최적화는 중요한 테크닉입니다. 예를 들면 캔의 특정 질량과 부피를 정해두고 캔의 반지름과 높이를 원하는 범위안에서 구한다고 생각해보면 최적의 캔의 반지름과 높이가 존재할 것입니다. 이렇게 목적 값을 타겟팅하여 독립변수를 찾는 것이 최적화 기법입니다.


실제로, 현업에서 관련한 업무를 수행하고 있습니다. 오늘 공유드릴 내용은 파이썬의 Scipy 패키지를 이용해서 간단하게 생성한 최적화 방법입니다. 물론, 비슷한 기능이 엑셀에도 '해찾기'라는 이름으로 존재합니다. 엑셀을 통한 해당 방법의 사용은 시간을 두고 천천히 포스팅하겠습니다.




Import Package

해당 패키지를 사용하시 위해서는 패키지를 설치하고 파이썬에서 호출해 주어야합니다. 패키지는 아래와 같이 호출해주면 됩니다. 필요한 패키지는 'Scipy'와 'Numpy' 입니다. 넘파이는 필수적인 패키지이니 잘 알아두면 좋습니다.



import numpy as np

from scipy.optimize import minimize


최적화 함수 선택

간단한 최적화 함수를 예제로 삼겠습니다. 함수는 최소가 1이 되는 함수입니다. f(x, y)=x²+y²+2 함수를 예제 함수로 삼고자합니다. 사실 최적화 알고리즘을 테스트하기 위한 Test Function은 위키백과에 많이 소개되어 있습니다. 구글에서 'Test Fuction'으로 검색하보면 가장 상단에 위키백과 링크가 있으니, 맘에 드는 것으로 사용하시면 되겠습니다.


- Test 함수 : f(x, y) = x²+y²+1

- 최적 변수 : x= 0, y= 0

- 최적 값 : f(0, 0) = 1 



def function(x):

    return x[0]**2 + x[1]**2 + 1


Scipy 최적화를 하기 위해서 변수는 리스트형으로 만들어주어야 합니다. 따라서 x=x[0], y=x[1]으로 변수 선언을 해주었습니다. 이후에 변수가 늘어났을 때에는 변수의 개수에 맞춰서 x[0]에서 x[n]까지 변수를 선언해주면 됩니다.


최적화 시작점 선언

민감도 기반 최적화는 알고리즘에 따라 최적점을 찾기 위해서 독립변수를 바꿔가며 반응값을 변화시킵니다. 최적화에 가장 중요한 요소 중 하나는 독립변수의 시작점을 설정하는 것입니다. 시작점이 최적점 근처에 위치한다면 빠르고 정확하게 최적점을 찾을 수 있고, 위치에 따라 Local Optimum에 빠지거나 시간이 오래 걸릴 수 있습니다.


위와 같은 간단한 함수 최적화 문제를 풀기 위해서는 시간이 오래 걸리던 짧게 걸리던 체감할 수 있을 정도의 차이는 아니지만, 함수가 시뮬레이션으로 대체된다면 이야기는 다릅니다. 적절한 시작점과 독립변수, 반응값의 범위를 정해주어야 빠르게 최적화가 가능합니다.


Init_Point = np.array([3., 1.])


예제이기 때문에 위와 같이 시작점을 적당히 'x=x[0]=3.0, y=x[1]=1.0' 으로 설정했습니다. 해당 포인트는 Numpy Array로 설정되어야합니다. 



최적화 알고리즘 선택

Scipy에서 제공하는 최적화 알고리즘은 다양합니다. 일단은 'CG'라고 하는 알고리즘을 선택하여 최적화 예제를 풀어보겠습니다. 다른 알고리즘의 특성을 파악해 적용하고 싶으신 분은 아래 사이트를 참고해 주십시오.




minimize 함수의 괄호 안의 앞에서 부터 차례대로 함수명, 시작점, 최적화 알고리즘, 옵션을 입력해줍니다. 여기서 xtol이란, Tolerance 를 뜻하며 최적화를 위한 독립변수의 Step Size를 뜻합니다. 스텝이 크면 함수 밖으로 튕겨져 나가며, 스텝이 너무 작으면 Local Optima에 빠지기 때문에 문제 공간의 크기에 따라서 적절히 Tolerance를 정해주어야 합니다.


Optimum = minimize(function, Init_Point, method='CG', options={'xtol': 1e-8, 'disp': True})

print(Optimum)


위와 같이 함수 function에 최적화를 적용해주고 최적값을 출력해주겠습니다. 출력 함수는 잘 아시는 바와 같이 print 함수입니다.


전체 최적화 코드

위에서 열거한 최적화 코드는 전체는 아래와 같습니다. 한번에 보시면 이해하기 편하실겁니다.


# 패키지 Import

import numpy as np

from scipy.optimize import minimize


# 함수선언

def function(x):

    return x[0]**2 + x[1]**2 + 1


# 시작점 설정

Init_Point = np.array([3., 1.])


# 최적화 알고리즘 적용

Optimum = minimize(function, Init_Point, method='CG', options={'xtol': 1e-8, 'disp': True})

print(Optimum)



최적화 결과

Running을 하면 아래와 같이 결과가 출력됩니다. 가장 위의 메세지대로 최적화가 성공적으로 종료되었습니다. 우리가 찾고자 하는 최적 변수는 (0, 0)이며, 최적화 알고리즘으로 도출된 최적 변수도 이와 같습니다. 또한, 이 때의 반응 값인 function 값은 1이된 것을 확인할 수 있습니다.


Optimization terminated successfully.

Current function value: 1.000000

Iterations: 1

Function evaluations: 12

Gradient evaluations: 3

fun: 1.0000000000000009

jac: array([5.96046448e-08, 2.98023224e-08])

message: 'Optimization terminated successfully.'

nfev: 12

nit: 1

njev: 3

status: 0

success: True

x: array([2.74227774e-08, 9.14092579e-09])


변수 범위 설정 예제

추가적으로 변수의 범위를 설정할 수 있는 예제를 최근에 작성하여 업데이트합니다. 위 코드를 기반으로하고 있지만 위 코드에서 살짝 변경이 되었으며 최적화 알고리즘도 변경된 예제입니다. 확인하시려면 아래글을 확인해주세요.



마무리

이와 같이 최적화 함수를 적절히 사용하면 빠른 시간내에 좋은 퍼포먼스를 낼 수 있습니다. 위 내용 참고하셔서 파이썬을 위한 최적화를 실습해보시면 좋겠습니다. 파이썬은 참으로 확장성이 넓은 언어라고 다시 한번 느낄 수 있었습니다.


댓글