728x90
반응형

매개변수 갱신

  • 신경망 학습의 목적은 손실 함수의 값을 가능한 한 낮추는 매개변수를 찾는 것이었다.
  • 매개변수의 최적값을 찾는 문제이며, 이런 문제를 푸는 것을 최적화(optimization)라 한다.
  • 매개변수 공간은 매우 넓고 복잡해서 최적의 솔루션을 찾기 어렵다. 또한 심층 신경망에서는 매개변수의 수가 엄청나게 많아져서 사태는 더욱 심각해진다.
  • 최적의 매개변수 값을 찾는 단서로 기울기(미분,오차역전파)를 이용했다. 매개변수의 기울기를 구해, 기울어진 방향으로 매개변수 값을 갱신하는 일을 반복해 점점 최적의 값에 다가갔다.
  • 이것이 확률적 경사 하강법(SGD)이란 단순한 방법, 매개변수 공간을 무작정 찾는 것보다는 '똑똑한'방법이다. 
  • 지금 서 있는 장소에서 가장 크게 기울어진 방향으로 가자는 것이 SGD전략 - 반복시 언젠가 '깊은 곳' 찾아갈 수 있을지도 모른다.

 

확률적 경사 하강법(SGD)

 

수식

[그림1] 수식

SGD 구현

  • 인수 lr은 learning rate(학습률)를 뜻한다.
class SGD:
    def __init__(self, lr=0.01):
        self.lr = lr # lr learning rate(학습률) 
        
    def update(self, params, grads):
        for key in params.keys():
            params[key] -= self.lr * grads[key]
            

 

SGD단점

  • 비등방성(anisotropy) 함수(방향에 따라 성질, 즉 기울기가 달라지는 함수)에서는 탐색 경로가 비효율적이다.
  • 비등방성 함수에서는 SGD같이 무작정 기울어진 방향으로 진행하는 단순한 방식보다 더 영리한 묘안이 간절해진다.
  • SGD가 지그재그로 탐색하는 근본 원인은 기울어진 방향이 본래의 최솟값과 다른 방향을 가리켜서라는 점도 있다.
  • SGD단점을 개선해주는 모멘텀, AdaGrad, Adam 세 방법이 있다.

SGD에 의한 최적화 갱신 경로

  • 최솟값인 (0,0)까지 지그재그로 이동하니 비효율적이다.

[그림2] SGD에 의한 최적화 갱신 경로

 

 

 

 

모멘텀(Momentum)

  • 운동량을 뜻한다. - 물리와 관련이 있다.

수식

[그림3] 모멘텀 수식

  • W는 갱신할 가중치 매개변수, n은 학습률이다. v라는 변수가 새로 나오지만 물리에서 말하는 속도 velocity에 해당한다.

 

모멘텀의 이미지

[그림4] 모멘텀의 이미지 : 공이 그릇의 곡면(기울기)를 따라 구르듯 움직인다.

모멘텀 구현

# 모멘텀 구현
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]
            
  • 인스턴스 변수 v = 물체의 속도 
  • update()가 처음 호출될 때 매개변수와 같은 구조의 데이터를 딕셔너리 변수로 저장한다.

 

모멘텀에 의한 최적화 갱신 경로

  • 공이 그릇 바닥을 구르듯 움직인다.
  • SGD와 비교하면 지그재그가 덜한다.
  • x축의 힘은 아주 작지만 방향은 변하지 않아서 한 방향으로 일정하게 가속하기 때문이다.
  • y축의 힘은 크지만 위아래로 번갈아 받아서 상충하여 y축의 방향은 안정적이지 않다.
  • 전체적으로 SGD보다 x축 방향으로 빠르게 다가가 지그재그 움직임이 줄어든다.

[그림5] 모멘텀에 의한 최적화 갱신 경로

 

AdaGrad

  • 신경망 학습에서는 학습률 값이 중요하다. 이 값이 너무 작으면 학습 시간이 너무 길어지고, 반대로 너무 크면 발산해 학습이 제대로 이뤄지지 않는다.
  • 학습률을 정하는 효과적 기술로 학습률 감소(learning rate decay)가 있다.  - 학습을 진행하면서 학습률을 점차 줄여가는 방식
    • 처음에는 크게 학습하다가 조금씩 작게 학습한다는 얘기, 실제 신경망 학습에 자주 쓰인다.
  • 학습률을 서서히 낮추는 가장 간단한 방법은 매개변수 '전체'의 학습률 값을 일괄적으로 낮추는 방법이다. 
    • - 이것을 더욱 발전시킨 것이 AdaGrad - '각각의' 매개변수에 '맞춤형'값을 만들어준다.
  • AdaGrad는 개별 매개변수에 적응적으로(adaptive) 학습률을 조저앟며 학습을 진행한다.

AdaGrad 갱신 방법 수식

[그림6] AdaGrad 갱신 방법 수신

  • W는 갱신할 가중치 매개변수, 알파L/알W은 W에 대한 손실 함수의 기울기, h는 기존 기존 기울기 값을 제곱해 계속 더해준다.

AdaGrad

  • AdaGrad는 과거의 기울기를 제곱해 계속 더해간다. 그래서 학습을 진행할수록 갱신 강도가 약해진다.
  • 실제로 무한히 계속 학습한다면 어느 순간 갱신량이 0이 되어 전혀 갱신되지 않게 된다.
  • 이 문제를 개선한 방법이 RMSProp이라는 방법이다.

RMSProp

  • 과거의 모든 기울기를 균일하게 더해가는 것이 아니라, 먼 과거의 기울기는 서서히 잊고 새로운 기울기 정보를 크게 게 반영한다.
    • 이것을 지수이동평균(Exponential Moving Average, EMA)라고 하며 과거 기울기의 반영 규모를 기하급수적으로 감소시킨다.

 

AdaGrad 구현

# AdaGrad 구현

class 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]
            params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7) # 1e-7이라는 작은 값이 0으로 나누는 사태를 막아준다.
            
        
  • 1e-7이라는 작은 값을 더하는 이유는 이 작은 값은 self.h[key]에 0이 담겨 있다 해도 0으로 나누는 사태를 막아주기 때문이다.

AdaGrad에 의한 최적화 갱신 경로

[그림7] AdaGrad에 의한 최적화 갱신 경로

  • 최솟값을 향해 효율적으로 움직인다.
  • y축 방향은 기울기가 커서 처음에는 크게 움직이지만, 그 큰 움직임에 비례해 갱신 정도도 큰 폭으로 작아지도록 조정된다. 
  • y축 방향으로 갱신 강도가 빠르게 약해지고, 지그재그 움직임이 줄어든다.

Adam

  • 모멘텀은 공이 그릇 바닥을 구르는 듯한 움직임을 보였다. 
  • AdaGrad는 매개변수의 원소마다 적응적으로 갱신 정도를 조정했다.
  • 이 두 기법을 융합한것이 Adam
  • 2015년 제안된 새로운 방법
  • 이론은 복잡하지만 직관적으로는 모멘텀과 AdaGrad를 융합한 듯한 방법
  • 하이퍼파라미터의 '편향 보정'이 진행된다는 점도 Adam의 특징

Adam에 의한 최적화 갱신 경로

[그림8] Adam에 의한 최적화 갱신 경로

 

네 가지 방법 MNIST 데이터셋으로 본 갱신 방법 비교

import os
import sys
sys.path.append(os.pardir)  # 부모 디렉터리의 파일을 가져올 수 있도록 설정
import matplotlib.pyplot as plt
from mnist import load_mnist
from util import smooth_curve
from multi_layer_net import MultiLayerNet
from optimizer import *


# 0. MNIST 데이터 읽기==========
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)

train_size = x_train.shape[0]
batch_size = 128
max_iterations = 2000


# 1. 실험용 설정==========
optimizers = {}
optimizers['SGD'] = SGD()
optimizers['Momentum'] = Momentum()
optimizers['AdaGrad'] = AdaGrad()
optimizers['Adam'] = Adam()
#optimizers['RMSprop'] = RMSprop()

networks = {}
train_loss = {}
for key in optimizers.keys():
    networks[key] = MultiLayerNet(
        input_size=784, hidden_size_list=[100, 100, 100, 100],
        output_size=10)
    train_loss[key] = []    


# 2. 훈련 시작==========
for i in range(max_iterations):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]
    
    for key in optimizers.keys():
        grads = networks[key].gradient(x_batch, t_batch)
        optimizers[key].update(networks[key].params, grads)
    
        loss = networks[key].loss(x_batch, t_batch)
        train_loss[key].append(loss)
    
    if i % 100 == 0:
        print( "===========" + "iteration:" + str(i) + "===========")
        for key in optimizers.keys():
            loss = networks[key].loss(x_batch, t_batch)
            print(key + ":" + str(loss))


# 3. 그래프 그리기==========
markers = {"SGD": "o", "Momentum": "x", "AdaGrad": "s", "Adam": "D"}
x = np.arange(max_iterations)
for key in optimizers.keys():
    plt.plot(x, smooth_curve(train_loss[key]), marker=markers[key], markevery=100, label=key)
plt.xlabel("iterations")
plt.ylabel("loss")
plt.ylim(0, 1)
plt.legend()
plt.show()

[그림9] 네 가지 방법 비교
[그림11] 
[그림12] 
[그림13] 네 가지 방법 MNIST 데이터셋으로 비교

SGD학습 진도가 가장 느리고 나머지 세 기법의 진도는 비슷하지만 AdaGrad가 조금 더 빠른 것 같다.

하이퍼파라미터인 학습률과 신경망의 구조(층 깊이 등)에 따라 결과가 달라진다는 것이 중요하다.

 

 

 

출처 : 밑바닥부터 시작하는 딥러닝

https://www.hanbit.co.kr/store/books/look.php?p_code=B8475831198

 

밑바닥부터 시작하는 딥러닝

직접 구현하고 움직여보며 익히는 가장 쉬운 딥러닝 입문서

www.hanbit.co.kr

 

728x90
반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기