티스토리 뷰

2020/10/23 - [Study/인공지능] - Optimizer : Momentum, NAG ( 인공지능 기초 #14 )

 

learning rate가 변수마다 스텝마다 바뀝니다.

 

처음 시작점부터 최소점까지는 멀기 때문에 성큼성큼가다가 (보폭을 크게) 시간이 지나면 점점 목적지에 다가가게 되니까 보폭을 작게 조정합니다.

 

큰 변화를 겪은 변수의 러닝레이트는 크게 작아지고, 작은 변화를 겪은 변수의 러닝레이트는 작게 작아집니다. ( 이유는 x 와 y가 있을때 x축으로 더 크게 이동했다면, y축은 아직 먼 가능성이 높고 x축은 목표에 가까워 졌을 가능성이 높아졌다고 보기 때문입니다. )

 

 

Hadamard product 라는 기호입니다. 연산은 아래와 같습니다 ( 각 행렬의 위치를 덧셈처럼 위치마다 곱한값이 결과 )

Hadamard product
벡터의 루트기호와 역수 기호는 좌표별 루트, 좌표별 역수 
Hn에는 좌표별 그레디언트 제곱값이 누적되어있습니다. 

 

AdaGrad의 점화식

h_n에 루트를 씌우고 각 원소에 역수를 취함

 

Xn+1 = Xn - 러닝레이트*그데디언트(Xn)  >> 경사하강법의 점화식입니다.

 

AdaGrad는 위에 1/루트h_n만 추가된것입니다. 이는 그레디언트의 제곱값이 누적되어 있고, 즉 원소별로 어디가 더 큰 변화가 있었는지를 알게 해주는 지표가 됩니다. 큰 변화가 있을수록 분모가 커짐에 따라 더욱 더 적은 러닝레이트를 가지게 되고, 그 변수의 위치는 더 작은 보폭으로 이동을 할 것입니다.

 

 

여기서 중점은 h_n을 구하는 것과, h_n을 구할때는 지금까지 구했던 모든 h_0부터 h_n-1을 더하고 xn의 그레디언트의 제곱을 더한다는 것과

 

x_n+1을 구할때 루트 h_n분의 1을 아망프러덕트를 해준다는 것이 중점입니다.

 

class AdaGrad:

    """AdaGrad"""

    def __init__(self, lr=0.01):
        self.lr = lr
        self.h = None
        
    def update(self, params, 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] += grads[key] * grads[key] #아담하르프러덕트 , 행렬의 곱셈은 np.dot(x행렬,y행렬) 로 씀 *로하면 아담하르프러덕트 값으로 나옴 
            params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7) # 기존의 파라메타 (xn - 러닝레이트 * 그레디언트 / 루트hn분의 1   1e-7 이걸 더해주는 이유는 혹시나 분모가 0이될까봐 방지용으로 붙여주는 것이다.
            

 

 

처음에는 큰 보폭으로 목적지를 찾아가기 때문에 초반에는 빠르지만, 어뎁티브 그레디언트는 누적치 h_n이 너무 커져서 보폭이 너무너무 작아져서 학습이 거의 되기 않는 문제가 있습니다.

 

이를 보완하기 하고 발전시킨 RMSProp은 이전 누적치와 현재 gradient의 좌표별 제곱의 가중치 평균을 생각합니다.

 

즉 AdaGrad보다 최근값과 과거값에서 어떤것에 중점을 줄지 정하여 계산합니다. ( r=3/4면 과거에 3/4 , 현재에 1/4를 곱하는것이므로 과거에 힘을 주는 것 반대도 가능 )

 

RMSProp의 점화식

class RMSprop:

    """RMSprop"""

    def __init__(self, lr=0.01, decay_rate = 0.99):
        self.lr = lr
        self.decay_rate = decay_rate
        self.h = None
        
    def update(self, params, 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] *= self.decay_rate
            self.h[key] += (1 - self.decay_rate) * grads[key] * grads[key] #h_n 구하는것
            params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7) # 점화식 (xn+1 구하기)

 

댓글
최근에 올라온 글
최근에 달린 댓글
250x250