AI

Optimizer_SGD

boals 2024. 8. 29. 15:53

:: Optimizer란? ::

저번 포스트에서 '딥러닝 학습의 최종 목표는 loss값을 최소화하는 (가중치를 찾는)것이다.'라고 하였다. 여기서 loss function을 주로 산이라고 비유를 많이 하는데, optimizer는 산을 타고 '내려오는' 방법이라고 비유할 수 있다. loss function의 최솟값을 찾아 가는 '과정'인 것이다.

 

optimizer를 설명할 때 가장 많이 나오는 이미지가 아래 이미지이다. 이번 포스트에서는 그 중에서도 SGD와 Momentum에 대해서 알아보자.


:: 경사하강법(Gradient Descent) ::

SGD(Stochastic Gradient Descent)에 대해서 알아보기 전에, 경사하강법에 대해서 알아보자.

 

나는 개인적으로 경사하강법이라는 이름보다는 Gradient Descent라는 영어 이름이 경사하강법의 개념을 이해하는 데에 더 직관적이라고 생각하는데, Gradient가 미분값을 의미하고 Descent가 밑으로 내려오는 것을 말하기 때문이다.(경사하강법의 중요 키워드는 '미분'이라고 생각하는데 경사 하강법이라는 말을 듣고 미분값을 떠오르긴 쉽지 않지 않은가?

 

다시 경사 하강법의 정의를 정리하자면, 현재 θ값에 해당하는 loss function J(θ)의 미분값 구한 뒤, 기울기(미분값)이 작아지는 방향으로 진행하는 과정을 반복하여 loss function의 최솟값을 구하는 과정이다.

 

경사하강법을 식으로 나타내면 다음과 같이 나타낼 수 있다.

 

여기서 주목해야 하는 부분은 값이 갱신되는 과정에서 미분값 앞에 마이너스(-)가 추가되었다는 점이다.

수학에서 그래프를 생각해보면 양의 부호는 오른쪽, 음의 부호는 왼쪽을 의미한다. 간단하게, 부호가 방향을 말한다는 것이다.

따라서 마이너스(-)가 추가된 것은 방향을 바꾼다는 것을 의미한다.

왼쪽 그림을 참고해서 설명을 추가하면,

미분값이 0보다 큰 경우 즉, 양의 부호를 띄는 경우 원래는 오른쪽을 향하고 있지만 왼쪽을 향하도록 수정해주고

미분값이 0보다 작은 경우 즉, 음의 부호를 띄는 경우 원래는 왼쪽을 향하고 있지만 오른쪽을 향하도록 수정한다는 것을 의미한다는 것이다.

 

아래 그림은 경사하강법에 대하여 설명하는 유튜브 강의 캡쳐본이다.

 

 

 

 

 

 

 

 

 

 

 

중간에 데이터가 날아가서 다시 쓴다.......... 한 시간동안 썼는데............ :(

슬퍼....너무 슬퍼....

 

위의 식과 조금 달라 보이기도 하지만 동일한 내용을 말하고 있다는 것을 알 수 있다.

위의 식에서는 alpha가, 캡쳐본의 eat(에타라고 하는 그리스 문자라고 한다...) learning rate(학습률)을 의미한다는 것을 알아두자! 

앞에서 loss function을 산에 비유하고 optimizer를 산을 내려오는 방법에 비유했다. 마찬가지로 learning rate를 산을 태려올 때의 보폭으로 비유할 수 있다. learning rate가 크다면 큰 걸음으로 내려오고, learning rate가 작다면 작은 걸음으로 내려오는 것이다. 다만 여기서 주목할 점은, learning rate가 너무 큰 경우 최솟값을 경유하지 못하고 뛰어넘을 수 있다는 점이다. (우리가 구덩이를 만나면 폴짝 뛰어서 넘는 경우를 상상하면 이해가 쉬울 것 같다!)

 

경사하강법 코드로 구현하기

theta = rand(vector)
# initial value는 무작위로

while True :
    theta_grad = evaluate_gradiant(J, data, theta)
    # theta에 해당하는 J의 미분값 구하기

    theta = theta - alpha * theta_grad
    # theta를 갱신

    if (norm(theta_grad) <= beta) : 
        break
    # theta_grad : J의 기울기
    # thetal_grad의 크기가 beta보다 작으면
	# -> 0에 가까워지면
    # 무한루프를 종료

동일한 코드를 class를 이용해서 구현한 코드가 있어서 추가해보자면,

import numpy as np

class SGD :
	def __init__(self, lr = 0.01) :
    	self.lr = lr

	def update(self, params, grads) :
    	for key in params.keys() :
        	params[key] -= self.lr * grads[key]

parameter가 딕셔너리 구조로 이루어져 있다는 점도 반영하고 있는 것을 확인할 수 있다.

 

class의 이름이 Gradient Descent가 아니라 SGD라 당황했을 수 있다. 본격적으로 SGD로 넘어가기 전에 Gradient의 문제점을 알아보자

 

Gradient Descent의 문제점 : 대부분의 문제점이 '미분'만을 이용한다는 점에서 비롯된다

 

1) 최적화를 통해 찾은 값이 최솟값(Global minimum)이라고 확신할 수 없다.

 

위의 식을 보면 미분값이 0일 경우 loss function값이 갱신되지 않고 유지된다.

미분값이 0이 되는 유형을 크게 나누어 보면,

1> 최솟값(global minimum) 2> 극솟값(local minimum) 3> 안장점(saddle point)이 있다.

하지만, Gradient Descent의 조건이 미분값 = 0 밖에 없기 때문에 우리가 얻은 값이 최솟값이라고 확신할 수 없는 것이다.

 

- 안장점을 처음 보는 경우도 있을 것 같아서 설명을 간단하게 추가하겠다.

사실 나는 안장점이라는 한국어보다는 saddle point라는 영어로 많이 접했다.

saddle point는 오른쪽 그림처럼 다변수 함수에서 x축으로는 최솟값을 가지는 반면, y축으로는 최댓값을 가지는 경우를 말한다. 

 

2) 미분 불가능한 함수에는 적용이 불가능하다

 

3) 모든 데이터 샘플에 대하여 미분을 계산하고, 계산한 미분을 통해 다시 새롭게 parameter를 계산해야 한다.

parameter가 많은 경우, 계산량이 매우 많아진다는 단점이 있다.

 

-> 3) 문제 해결 : SGD

 

4) 

-> 4) 문제 보완 : Momentum

 

진동 현상과 관련된 내용을 처음에 완전히 이해하지 못했는데 강의에서 자세히 설명해주셔서 이해한 내용을 바탕으로 적어보겠다!!


진동 현상 문제에서 가장 중요한 점은, 등위선과 미분값은 항상 수직이라는 것!


x와 y의 변화율 차이가 클수록 지그재그가 심해지기 때문에 극단적인 예로

f(x, y) = (1/20)x^2 + y^2인 경우를 보겠다!!

f(x, y)의 등위선들을 간단히 그리면 오른쪽 그림과 같을 것이다.

천천히 선을 그어보자

1) 랜덤으로 시작

2) 접선(미분값)(연두색)과 수직인 등위선(청록색) 긋기

다시 한 번 말하지만, 포인트는 등위선과 미분값(접선이라고 생각)이 수직이라는 것!! 

3), 4), 5), 6) 반복

하면 왼쪽과 같이 선이 그어지고, 지그재그 모양인 것을 확인 할 수 있다.

 

누가봐도 효율적인 움직임은 아닌 것 같다.

 

 

 

 


::SGD(Stochastic Gradient Descent, 확률적 경사 하강법)::

Gradient Descent가 모든 학습 데이터에 대한 계산을 진행했다면, SGD는 '무작위로 선택된 부분 집합'에 대하여 미분을 계산하는 방식이다. 

 

설문조사를 할 때 전체 인원에 대한 조사를 실시하지 않고 표본을 추출하여 조사를 하는 것과 유사하다고 볼 수 있다.

 

가장 일반적으로 minibatch를 이용하는데, 최적화 크기는 데이터와 하드웨어(메모리)에 의존한다.

 

minibatch의 크기가 작을수록 미분 추정이 안정화되고, 

minibatch의 크기가 클수록 효율성이 낮아지고 비용이 두 배로 증가한다.

이때, minibatch의 크기가 커질수록 diminishing returns 문제가 발생한다. (특정 시점 이후로 minibatch의 크기를 증가시키면 계산량이 증가하는 데에 비해 성능이 향상되지 않고 오히려 비용이 증가하는 문제가 발생함.)

 

따라서 모델에 가장 적합한 minibatch의 크기를 선택하는 것이 중요하다고 한다.

 

방식은 Gradient Descent와 동일하게 데이터를 샘플링한다는 차이만 있기 때문에 위에 구현한 Gradient Descent의 코드의 이름이 SGD였던 것이다..!!

 

참고링크

https://www.youtube.com/watch?v=5fwD1p9ymx8&t=2372s

https://www.youtube.com/watch?v=Bxyj5p1CAeg&t=1s