HealthyAI

DL) Optimization - Gradient Descent 본문

AI/Deep Learning

DL) Optimization - Gradient Descent

BiteApple 2023. 2. 10. 09:50
반응형

학습 목적

딥러닝에서의 학습이란 최대한 틀리지 않도록 정확성을 높여 나가는 것이다.

 

'얼마나 틀리는지'에 대해 나타내는 함수가 손실 함수(Loss Function) 이다.

 

따라서 학습의 목표는 손실함수의 최솟값을 찾는 것이다.

 

손실함수가 최솟값을 갖을 때의 매개 변수의 값을 찾아내야 하며, 손실함수의 최솟값을 찾아 나가는 것을 최적화 (= Optimization) 라 한다. 그리고 이를 수행하는 최적화 알고리즘을 Optimizer 라고 한다.

 

 

최적화 방법에는 손실함수의 기울기를 활용한 다양한 경사법들이 존재한다.

 

다양한 최적화 방법들(optimization) (= 경사법들) 중 요즘은 Adam 을 가장 많이 사용하는 추세다.

 

우선 다양한 최적화 방법들에 대해  적어 놓았다.

 

 

Optimization Algorithm

  • Batch Gradient Descent (BGD) : 전체 데이터 셋에 대한 에러를 구한 뒤 기울기를 한번만 계산하여 모델의 parameter를 업데이트 하는 방법
    •  장점
      • loss 가 안정적으로 수렴
    •  단점
      • one iteration에 모든 데이터셋을 사용하기 때문에 학습시간이 오래 걸림

 

  • Stochastic Gradient Descent (SGD) : 임의의 하나의 데이터에 대해서 에러를 구한 뒤 기울기를 계산하여, 모델의 parameter를 업데이트 하는 방법
    • BGD 보다 noisy한 이유는 어떤 샘플은 minimum으로 가는 좋은 샘플일 수도 있고 어떤 샘플은 minimum으로 가기 어려운 샘플일 수도 있기 때문이다.
    • 장점
      • 거의 항상 global minimum에 도달
      • local minimum에 빠질 위험이 적다
    • 단점
      • Optimal을 찾지 못할 가능성이 있다
      • 다른 알고리즘에 비해 속도가 느리다
    • code
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]

 

 

  • Mini-Batch Gradient Descent (MGD) : 전체 데이터셋에서 뽑은 미니 배치의 데이터에 대해서 각 데이터에 대한 기울기를 구한 뒤, 그것의 평균 기울기를 통해 모델의 parameter를 업데이트 하는 방법
    • BGD + SGD 장점 합침
    • Typical mini-batch size
      • 64,128,256,512 컴퓨터는 2진수로 계산되기 때문에
      • mini batch 쌍이 GPU CPU 메모리에 들어가지 않는다면 성능은 더 악화됨 
    • 전체 데이터가 m개 일 때
      • mini-batch size = m → Batch gradient descent
      • mini-batch size = 1 → Stochastic gradient descent
      • mini-batch size = n < m → Mini batch gradient descent

 

 

  • Momentum Alogorithm
    • 지수 가중 평균(=지수이동 평균), 데이터의 이동 평균을 구할 때, 오해된 데이터가 미치는 영향을 지수적으로 감쇠 하도록 만들어주는 방법
    •  code
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.v[key] * self.lr - self.momentum * grads[key]
            params[key] += self.v[key]
            

 

  •  Adagrad
    • 가중치에 맞게 학습률을 조정한다. 학습을 효율적으로 돕는다.
    • 각 기울기 마다 이전 기울기의 누적 제곱 합에 반비례하도록 학습률을 조정하여 업데이트 한다
    • 이를 통해 이전에 큰 기울기로 업데이트 된 가중치는 작게 업데이트 하고 , 작은 기울기로 업데이트 된 가중치는 큰 비율로 업데이트 한다
    • code
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)

 

  • RMSprop Algorithm (Root Mean Square Propagation)
    • 단순히 누적 제곱 합을 활용하는 것이 아니라 지수 이동 평균(EMA)를 활용하여 기울기 업데이트 진행
    • 최근의 time step의 기울기를 많이 반영, 과거의 기울기는 조금만 반영
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]
            params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)

 

  • Adam (Adaptive Momentum Estimation)
    • mometum 과 RMSprop를 섞어놓은 최적화 알고리즘, 가장 흔히 사용되는 최적화 알고리즘
    • 1차 모멘텀은 대부분 0.9, 2차 모멘텀은 대부분 0.999
    • code
class Adam:

    """Adam (http://arxiv.org/abs/1412.6980v8)"""

    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)

 

  • Optimization problem solving
    • Learning rate decay
      • learning rate를 천천히 줄여나가는 것
      • 처음에는 learning rate를 크게 하여 빠르게 학습을 진행하고, learning rate값이 점차 작아지면서 최적값 부근의 매우 좁은 범위까지 진입

반응형

'AI > Deep Learning' 카테고리의 다른 글

DL) Loss Function  (0) 2023.04.20
DL) Regularization  (0) 2023.04.20
DL) Training Inference  (0) 2023.04.19
DL) Pre-trained Information  (0) 2023.04.02