페이지

2022년 10월 2일 일요일

28.3 경사하강법 구현

 복잡한 형상의 함수라면 기울기가 가리키는 방향에 반드시 최댓값이 존재한다고는 볼 수 없습니다(마찬가지로 반대 방향에 최솟값이 존재한다고 볼 수도 없습니다). 그러나 국소적으로 보면 기울기는 함수의 출력을 가장 크게 하는 방향을 나타냅니다. 그래서 기울기 방향으로 일정거리만큼 이동하여 다시 기울기를 구하는 작업을 반복하면 점차 원하는 지점(최댓값 혹은 최솟값)에 접근하리라 기대할 수 있습니다. 이것이 경사하강법(gradient descent)입니다. 알맞은 지점에서 시작하면 (좋은 초긱값을 주면) 경사하강법은 우리 목적지까지 효율적으로 안내해줍니다.

그러면 경사하강법을 우리 문제에 적용해보죠. 여기에서 문제는 로젠브록 함수의 '최솟값'찾기 입니다. 따라서 기울기 방향에 마이너스를 곱한 방향으로 이동합니다. 코드는 다음과 같습니다.


이와 같이 반복 횟수를 iters로 설정합니다(iters는 iterations의 약자입니다). 또한 기울기에 곱하는 값을 미리 설정해두고 있는데, 앞의 예에서는 lr = 0.001로 설정했습니다(lr은 learning rate의 머리글자로, 학습률을 의미합니다).


앞 코드의 for문에서는 x0와 x1이라는 Variable 인스턴스를 반복 사용하여 미분값을 구합니다. 이때 x0 grad와 x1 grad에는 미분값이 계속 누적되기 때문에 새롭게 미분할 때는 지금까지 누적된 값을 초기화 해야 합니다. 그래서 역전파하기 전에 각 변수의 cleargrad메서드를 호출하여 미분값을 초기화한 것입니다.


코드를 실행해보면 (x0, x1)값이 갱신되는 과정을 볼 수 있습니다. 실제로 터미널에 다음과 같은 결과가 출력됩니다.


출발점(0.0, 2.0)에서 시작하여 위치가 계속 갱싢되는 모습을 볼수 있습니다. [그림 28-2]는 이 결과를 플롯한 모습입니다.


[그림 28-2]롤 보면 모적지인 별의 위치에 서서히 접근하고 있음을 알 수 있습니다. 다만 도중에 멈춘 것 같군요, 그래서 반복 횟수를 iters = 10000으로 늘려 다시 실행해봤습니ㅏㄷ. 그 겨롸가 [그림 28-3]입니다.


[그림 28-3] 에서는 목적지에 더욱 가까워졌습니다. 이때 (x0, x1) 값은 (0.99449622, 0.98900063) 입니다. 참고로 횟수를 더 늘려서. 예컨대 iters = 50000으로 설정해 실행하면 실재로 (1.0, 1.0)위치에 간신히 도착합니다.


이것으로 이번 댄계도 끝입니다. 이번 단계에서는 DeZero를 사용하여 경사하강법을 구현했고, 이를 이용해 로젠브록 합수의 최솟값 위치를 찾을 수 있었습니다. 그러나 50,000번이나 반복한다는 것은 너무 과해보입니다. 사실 경사하강법은 로젠브록 함수 같이 골짜기가 길게 뻗은 함수에는 잘 대응하지 못합니다. 그래서 다음 단계에서는 또 다른 최적화 기법을 소개하고 구현할 예정입니다.


댓글 없음: