본문 바로가기

Python/DeepLearning

신경망 학습의 핵심 개념 - 매개변수 갱신

 신경망 학습의 목적은 무엇일까? 이는 손실 함수의 값을 낮추는 매개변수를 찾는 것이다. 매개변수의 최적값을 찾는 과정을 최적화라고 한다. 변수는 레이어가 많아질수록 증가하고 적합한 매개변수를 우연히 찾는 것은 불가능에 가깝다. 최적의 매개변수를 찾기 위해서 매개변수의 기울기를 이용했고 기울기에 따라 값을 갱신하여 최적 값을 찾아내었다. 이 기본적인 방법을 확률적 경사 하강법(SGD)라고 한다.


(1) 확률적 경사 하강법

$$W → W - \eta\frac{\delta L}{\delta W}$$

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]

 기울어진 방향으로 일정거리만큼 움직이면서 최적값을 찾는 방법이다. 


(2) 모멘텀 (Momentum)

$$ v ← \alpha v - \eta\frac{\delta L}{\delta W} $$

속도를 적용하여 기울기 방향으로 가속한다.

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]

(3) AdaGrad

 여태는 학습률을 임의로 정해주었는데 이 값은 엄청 중요하다. 때문에 적절하게 학습률을 정해주는 기술이 있다. 각각의 매개변수에 맞게 학습률을 맞춤형으로 정해준다.

$$ h ← h + \frac{\delta L}{\ delta W} \odot \frac{\delta L}{\delta W} $$

$$ W ← W - \eta\frac{1}{\sqrt[]{h}}\frac{\delta L}{\delta W} $$

class 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]
            params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)

(4) Momentum + AdaGrad = Adam

 솔직히 무슨 말인지 이해안감. 그냥 속도 + 값에 따른 학습률 조정

class Adam:
    def __init__(self, lr=0.001, beta1=0.9, beta2=0.999):
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.iter = 0
        self.m = None
        self.v = None      
    def update(self, params, grads):
        if self.m is None:
            self.m, self.v = {}, {}
            for key, val in params.items():
                self.m[key] = np.zeros_like(val)
                self.v[key] = np.zeros_like(val)
                
        self.iter += 1
        lr_t  = self.lr * np.sqrt(1.0 - self.beta2**self.iter) / (1.0 - self.beta1**self.iter)         
        
        for key in params.keys():
            #self.m[key] = self.beta1*self.m[key] + (1-self.beta1)*grads[key]
            #self.v[key] = self.beta2*self.v[key] + (1-self.beta2)*(grads[key]**2)
            self.m[key] += (1 - self.beta1) * (grads[key] - self.m[key])
            self.v[key] += (1 - self.beta2) * (grads[key]**2 - self.v[key])
            
            params[key] -= lr_t * self.m[key] / (np.sqrt(self.v[key]) + 1e-7)
            
            #unbias_m += (1 - self.beta1) * (grads[key] - self.m[key]) # correct bias
            #unbisa_b += (1 - self.beta2) * (grads[key]*grads[key] - self.v[key]) # correct bias
            #params[key] += self.lr * unbias_m / (np.sqrt(unbisa_b) + 1e-7)