Optimization

재구몬·2021년 7월 27일
0

Deep Learning

목록 보기
3/12
post-thumbnail

Mini-Batch Gradient Descent


Mini-Batch

먼저 미니배치에 대한 설명을 이어나가기 전에 배치 경사 하강법(Batch Gradient descent)에 대해서 알아보도록 하자. m개의 테스트 예들로 이루어진 훈련 집합에서 매 훈련 과정 단계에서 모든 m개의 테스트 예제들을 적용할 경우 이를 배치 경사 하강법 이라고 한다. 즉, 우리가 흔히 알고 있는 경사 하강법이 이에 해당한다.하지만 일부 상황에서 배치 경사 하강법이 매우 비효율적으로 작용하는 시점이 생긴다. 바로 m이 너무 큰 상황에서 한 단계의 훈련을 위해 소요되는 시간 비용이 상황이 그것이다. 이를 위해서 모든 m개의 테스트 예제들을 쪼개고, 이 예제들을 모두 훈련하는 것을 한번의 시대(epoch)으로 설정하여 훈련을 하는 방식을 사용하는데 이것이 바로 미니 배치 경사 하강법(Mini-Batch Gradient descent)이다.

위의 사진은 훈련 예제를 64개의 미니 배치에 맞추어 쪼갠 모습이다. 먼저 위와 같은 상황을 만들기 위해서는 훈련 예제들의 섞이(shuffle)과정이 필요하다. 훈련 예제들이 편향된 분포를 보일 수 있기 때문에 효과적인 미니 배치 경사 하강법을 위해서는 무작위로 섞는 과정이 선행되어야 한다.

Stochastic Gradient Descent

확률적 경사 하강법(Stochastic Gradient Descent)은 하나의 예제를 미니배치로 설정하여 훈련을 시키는 방식으로 진행된다. 확률적 경사 하강법의 경우는 최적화로 가는 과정이 뒤죽박죽이며 벡터화를 통한 빠른 병렬 계산의 이점을 누리지 못하기 때문에 최적화 과정에서 속도를 높이지 못한다는 점에서 비효율적인 방법이다.

def random_mini_batches(X, Y, mini_batch_size = 64, seed = 0):
    m = X.shape[1]
    mini_batches = []
        
    # Step 1: Shuffle (X, Y)
    permutation = list(np.random.permutation(m))
    shuffled_X = X[:, permutation]
    shuffled_Y = Y[:, permutation].reshape((1, m))
    
    inc = mini_batch_size

    # Step 2 - Partition (shuffled_X, shuffled_Y).
    num_complete_minibatches = math.floor(m / mini_batch_size)
    for k in range(0, num_complete_minibatches):
        mini_batch_X = shuffled_X[:, k * mini_batch_size : (k+1) * mini_batch_size]
        mini_batch_Y = shuffled_Y[:, k * mini_batch_size : (k+1) * mini_batch_size]

        mini_batch = (mini_batch_X, mini_batch_Y)
        mini_batches.append(mini_batch)
    
    if m % mini_batch_size != 0:
        mini_batch_X = shuffled_X[:, num_complete_minibatches * mini_batch_size :]
        mini_batch_Y = shuffled_Y[:, num_complete_minibatches * mini_batch_size :]

        mini_batch = (mini_batch_X, mini_batch_Y)
        mini_batches.append(mini_batch)
    
    return mini_batches

Momentum


Exponentially Weighted Average

지수 이동평균(Exponetially Weighted Average)는 기온, 주가와 같이 시간에 따라 변하는 데이터의 경향을 파악하기 위해서 β\beta를 설정하여 일정 기간동안의 값들을 고려하는 과정을 말한다. VtV_t를 경향을 파악하기 위한 값이며, θt\theta_t를 특정 시간에서의 값, 마지막으로 β\beta를 조정 파라미터라고 가정하자.

 Vt=βVt1+(1β)θt\ V_t = \beta V_{t-1} + (1-\beta)\theta_t

위의 식을 살펴보면 β\beta의 값에 따라서 평균적으로 고려되는 기간이 변하게 된다. 이를 이용해 최근 n일 동안의 기온, 주가의 경향을 파악하여 경향을 나타내는 그래프를 그릴 수 있게된다.

Why Momentum?

그렇다면 운동량(Momentum)이라는 개념이 왜 필요한 건인가? 미니 배치 경사 하강법을 이용하게 되면 큰 훈련 집합을 이용하더라도 빠르게 훈련을 시킬 수 있다는 장점이 존재하지만, 훈련의 변동성(Ocilliation)이 배치 경사 하강법에 비해 큰편이다.

위의 그림을 살펴보면 최적화 과정에서의 진폭이 큰 것을 볼 수 있다. 단순히 빨간색 선을 따라서 최적화를 하는 것이 아니라 이전까지의 경향성(속도)를 고려하여 경사 하강법을 진행한다면 진폭을 줄인 상태에서 기존의 운동방향을 고려하여 더해준다면 부드럽게(smooth) 최적화 지점에 도달할 수 있게된다.
이 방식을 안장점(saddle point)에서 훈련 과정이 느려지는 문제를 지속적으로 운동을 해오던 방향으로 값을 보정해서 더해주기 때문에 더 빠르게 안장점을 탈출할 수 있다는 장점이 생긴다.

def update_parameters_with_momentum(parameters, grads, v, beta, learning_rate):
    L = len(parameters) // 2 # number of layers in the neural networks
   
    # Momentum update for each parameter
    for l in range(1, L + 1):
        v["dW" + str(l)] = beta * v["dW" + str(l)] + (1-beta) * grads["dW" + str(l)]
        v["db" + str(l)] = beta * v["db" + str(l)] + (1-beta) * grads["db" + str(l)]

        parameters["W" + str(l)] = parameters["W" + str(l)] - learning_rate * v["dW" + str(l)]
        parameters["b" + str(l)] = parameters["b" + str(l)] - learning_rate * v["db" + str(l)]
        
    return parameters, v

Adam


아담 최적화(Adam Optimization)은 가장 효율적인 최적화 방법중 하나인 방법으로 평균 제곱근 전파(RMSprop)방식과 운동량(Momentum)방식을 사용한다. 기존의 최적화 방식과 다른 방식은 각 과정마다 오차수정(bias correction) 절차가 들어간다는 것이다. 지수 이동평균에서의 문제점은 초기의 값에서 고려해야할 이전 값들이 부족하기 때문에 경향을 예측할 때 실제보다 작은 값으로 예측이 된다. 이 문제를 수정하기 위해어 1βt1-\beta^t로 나우어 주어 오차를 수정한다.

RMSprop

평균 제곱근 전파(RMSprop)는 지수 이동평균을 근간으로 후방 전파를 통해 발생한 결과값에 제곱(elementwise square)을 하여 후방 전파값을 나눠주게 된다. 직관적으로 이 방식은 큰 변동을 보이는 후방 전파값의 변화폭을 줄이는 반면, 적은 값으로 나아가는 방향은 꾸준히 빠르게 변화하도록 갱신을 하게된다.

 SdW=β2SdW+(1β2)dW2W=WαdbSdW+ϵ\ S_{dW}=\beta_2 S_{dW}+(1-\beta_2)dW^2\\ W=W-\alpha\frac{db}{\sqrt{S_{dW}}+\epsilon}

Adam optimization

평균 재곱근 전파와 운동량을 경사 하강법에 적용하여 아담 최적화를 다음과 같은 식으로 정리할 수 있다.

{vdW[l]=β1vdW[l]+(1β1)JW[l]vdW[l]corrected=vdW[l]1(β1)tsdW[l]=β2sdW[l]+(1β2)(JW[l])2sdW[l]corrected=sdW[l]1(β2)tW[l]=W[l]αvdW[l]correctedsdW[l]corrected+ε\begin{cases} v_{dW^{[l]}} = \beta_1 v_{dW^{[l]}} + (1 - \beta_1) \frac{\partial \mathcal{J} }{ \partial W^{[l]} } \\ v^{corrected}_{dW^{[l]}} = \frac{v_{dW^{[l]}}}{1 - (\beta_1)^t} \\ s_{dW^{[l]}} = \beta_2 s_{dW^{[l]}} + (1 - \beta_2) (\frac{\partial \mathcal{J} }{\partial W^{[l]} })^2 \\ s^{corrected}_{dW^{[l]}} = \frac{s_{dW^{[l]}}}{1 - (\beta_2)^t} \\ W^{[l]} = W^{[l]} - \alpha \frac{v^{corrected}_{dW^{[l]}}}{\sqrt{s^{corrected}_{dW^{[l]}}} + \varepsilon} \end{cases}
def update_parameters_with_adam(parameters, grads, v, s, t, learning_rate = 0.01,
                                beta1 = 0.9, beta2 = 0.999,  epsilon = 1e-8):
    
    L = len(parameters) // 2
    v_corrected = {}
    s_corrected = {}
    
    # Perform Adam update on all parameters
    for l in range(1, L + 1):
        v["dW" + str(l)] = beta1 * v["dW" + str(l)] + (1 - beta1) * grads["dW" + str(l)]
        v["db" + str(l)] = beta1 * v["db" + str(l)] + (1 - beta1) * grads["db" + str(l)]
       
        v_corrected["dW" + str(l)] = v["dW" + str(l)] / (1 - beta1 ** t)
        v_corrected["db" + str(l)] = v["db" + str(l)] / (1 - beta1 ** t)

        s["dW" + str(l)] = beta2 * s["dW" + str(l)] + (1 - beta2) * (grads["dW" + str(l)] ** 2)
        s["db" + str(l)] = beta2 * s["db" + str(l)] + (1 - beta2) * (grads["db" + str(l)] ** 2)
        
        s_corrected["dW" + str(l)] = s["dW" + str(l)] / (1 - beta2 ** t)
        s_corrected["db" + str(l)] = s["db" + str(l)] / (1 - beta2 ** t)

        parameters["W" + str(l)] = parameters["W" + str(l)] - learning_rate * (v_corrected["dW" + str(l)]) / (np.sqrt(s_corrected["dW" + str(l)]) + epsilon)
        parameters["b" + str(l)] = parameters["b" + str(l)] - learning_rate * (v_corrected["db" + str(l)]) / (np.sqrt(s_corrected["db" + str(l)]) + epsilon)

    return parameters, v, s, v_corrected, s_corrected

Reference

profile
아직 거북이지만 곧 앞질러 갈겁니다.

0개의 댓글