Deep learning/모델 구현

9. 학습 관련 기술들 (1) - 매개변수 갱신(SGD,모멘텀,AdaGrad,Adam)

jwjwvison 2021. 4. 23. 00:19

이 포스팅은 밑바닥부터 시작하는 딥러닝을 공부하고 정리한것 입니다.


이번 장에서는 신경망 학습의 핵심 개념들을 공부한다. 이번 장에서 다룰 주제는 가중치 매개변수의 최적값을 탐색하는 최적화 방법, 가중치 매개변수 초깃값, 하이퍼파라미터 설정 방법 등, 모두가 신경망 학습에서 중요한 주제이다. 오버피팅의 대응책인 가중치 감소와 드롭아웃 등의 정규화 방법도 간략하게 설명하고 구현해본다. 마지막으로 최근 많은 연구에서 사용하는 배치 정규화도 짧게 알아본다. 이번 장에서 배우는 기법을 이용하면 신경망(딥러닝) 학습의 효율과 정확도를 높일 수 있다.

 

1. 매개변수 갱신

 신경망 학습의 목적은 손실 함수의 값을 가능한 한 낮추는 매개변수를 찾는 것이였다. 이는 곧 매개변수의 최적값을 찾는 문제이며, 이러한 문제를 푸는 것을 최적화(optimization)라 한다. 우리는 지금까지 최적의 매개변수 값을 찾는 단서로 매개변수의 기울기(미분)을 이용했다. 매개변수의 기울기를 구해 반복해서 구해 점점 최적의 값에 다가갔다. 이것이 확률적 경사 하강법(SGD)이란 단순한 방법이다.

 

 (1) SGD

 SGD는 수식으로 다음과 같이 쓸 수 있다.

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 * grad[key]

 optimizer는 최적화를 행하는 자라는 뜻의 단어이다. 이 코드에서는 SGD가 그 역할을 한다. 매개변수 갱신은 optimizer가 책임지고 수행하니 우리는 optimizer에 매개변수와 기울기 정보만 넘겨주면 된다.

 

<단점>

 SGD는 단순하고 구현도 쉽지만, 문제에 따라서는 비효율적일 때가 있다.

 SGD는 위 그림과 같이 심하게 굽어진 움직임을 보여준다. 즉 SGD의 단점은 비등방성 함수( 뱡향에 따라 성질, 즉 여기에서는 기울기가 달라지는 함수)에서는 탐색 경로가 비효율적 이다. 또한 SGD가 지그재그로 탐색하는 근본 원인은 기울어진 방향이 본래의 최솟값과 다른 방향을 가리켜서라는 점도 생각해볼 필요가 있다.

 

(2) 모멘텀

 모멘텀(Momentum) 기법의 수식으로는 다음과 같이 쓸 수 있다.

 v는 속도, 기울기 방향으로 힘을 받아 물체가 가속된다는 물리 법칙을 나타낸다. av항은 물체가 아무런 힘을 받지 않을 때 서서히 하강시키는 역할을 한다 (a는 0.9 등의 값으로 설정한다.

class Momentum:
    def __init__ (self,lr=0.01,momentum=0.9):
        self.lr=lr
        self.momentum=momentum
        self.v=None
        
    def update(self,params,grads):
        if self.v is None:
            self.v={}
            for key,val in params.items():
                self.v[key] = np.zeros_like(val)
                
        for key in params.keys():
            self.v[key]= self.momentum * self.v[key] - self.lr*grads[key]
            params[key] += self.v[key]

 그림에서 보듯 모멘텀의 갱신 경로를 공이 그릇 바닥을 구르듯 움진인다. SGD와 비교하면 지그재그 정도가 덜한 것을 알 수 있다. 이는 x축의 힘은 아주 작지만 방향은 변하지 않아서 한 방향으로 일정하게 가속하기 때문이다. 거꾸로 y축의 힘은 크지만 위아래로 번갈아 받아서 상충하여 y축 방향의 속도는 안정적이지 않는다. 전체적으로는 SGD보다 x축방향으로 빠르게 다가가 지그재그 움직임이 줄어든다.

 

(3) AdaGrad

 신경망 학습에서는 학습률(수식에서는 n로 표기) 값이 중요하다. 이 값이 너무 작으면 학습 시간이 너무 길어지고, 반대로 너무 크면 발산하여 학습이 제대로 이뤄지지 않는다.

 이 학습률을 정하는 효과적 기술로 학습률 감소(learning rate decay)가 있다. 이는 학습을 진행하면서 학습률을 점차 줄여가는 방법이다. 처음에는 크게 학습하다가 조금씩 작게 학습한다는 이야기이다.

 

 AdaGrad는 개별 매개변수에 적응적으로 학습률을 조정하면서 학습을 진행한다.

 

 h는 기존 기울기 값을 제곱하여 계속 더해준다. 그리고 매개변수를 갱신할 때 1/h^(1/2)를 곱해 학습률을 조정한다. 매개변수의 원소 중에서 많이 움직인(크게 갱신된) 원소는 학습률이 낮아진다는 뜻인데, 다시 말해 학습률 감소가 매개변수의 원소마다 다르게 적용됨을 뜻한다.

class AdaGrad:
    def __init__ (self,lr=0.01):
        self.lr=lr
        self.h=None
        
    def update(self,param,grads):
        if self.h is None:
            self.h={}
            
            for key,val in params.items():
                self.h[key]=np.zeros_like(val)
        
        for key in params.keys():
            self.h[key] += grad[key] * grad[key]
            params[key] -= self.lr * grads[key] / (np.sqru(self.h[key]) + 1e-7)
            # 1e-7을 더해주는 이유는 self.h[key]에 0이 담겨 있다 해도 0으로 나누는 사태를 막아준다.
            

 위 그림을 보면 최솟값을 향해 효율적으로 움직이는 것을 알 수 있다. 

 

 

(4) Adam

 모멘텀은 공이 바닥을 구르는 듯한 움직임을 보였다. AdaGrad는 매개변수의 원소마다 적응적으로 갱신 정도를 조정했다. 이 두 기법을 융합한 기법이 Adam이다. 하이퍼파라미터의 편향 보정이 진행된다는 점도 Adam의 특징이다.

 

<어느 갱신 방법을 이용할 것인가?>

 위 그림과 같이 사용한 기법에 따라 갱신 경로가 다르다. 이 그림만 보면 AdaGrad가 가장 나은것 같은데, 사실 그 결과는 풀어야 할 문제가 무엇이냐에 따라 달라지므로 주의해야 한다. 또 당연하지만 (학습률 등의) 하이퍼파라미터를 어떻게 설정하느냐에 따라서도 결과가 바뀐다.