경사 하강법: 딥러닝 기초 시리즈 4

경사하강법(Gradient Descent)은 기계 학습 및 최적화 알고리즘에서 중요한 개념으로, 주로 함수의 최솟값을 찾거나 모델을 학습하는 데 활용됩니다.

이 알고리즘은 모델 파라미터를 조정하여 비용 함수를 최소화하는 과정으로 사용됩니다.

이 글 에서는 간단한 경사하강법의 원리를 설명하고, 파이썬 코드로 구현해 보겠습니다.


목차

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

참고 문헌 및 참고자료: 밑바닥부터 시작하는 딥러닝


최적화 알고리즘

딥러닝에서 최적화 알고리즘은 모델의 가중치 및 편향을 조정하여 손실 함수를 최소화하는 방법을 결정하는 중요한 구성 요소입니다. 다음은 최적화 알고리즘의 작동 방식을 상세히 설명하는 일반적인 단계입니다:

  1. 초기화:
    • 모델의 가중치와 편향은 무작위로 초기화됩니다.
    • 이러한 초기화는 주로 작은 무작위 값을 가지며, 이후 학습 중에 최적화 알고리즘을 통해 조정됩니다.
  2. 손실 함수 계산:
    • 주어진 학습 데이터와 모델의 현재 가중치 및 편향을 사용하여 손실 함수를 계산합니다.
    • 손실 함수는 모델의 출력과 실제 정답 사이의 차이를 나타냅니다.
  3. 그래디언트 계산:
    • 손실 함수의 그래디언트(기울기)를 계산합니다. 이는 손실 함수가 어떻게 가중치와 편향에 대한 변화를 원하는지를 나타냅니다.
    • 그래디언트 계산은 역전파(backpropagation) 알고리즘을 사용하여 수행됩니다.
  4. 파라미터 업데이트:
    • 계산된 그래디언트를 사용하여 가중치와 편향을 업데이트합니다.
    • 이 부분에서 최적화 알고리즘을 이용합니다. (경사 하강법, 확률적 경사 하강법, 모멘텀, Adagrad, RMSprop, Adam 등)
  5. 반복:
    • 위의 단계(손실 함수 계산, 그래디언트 계산, 파라미터 업데이트)를 여러 번 반복하여 모델을 학습합니다.
    • 전체 학습 데이터셋에 대한 여러 번의 반복(에폭)을 통해 모델의 성능을 향상시킵니다.
  6. 종료 조건:
    • 종료 조건은 더 이상 손실이 줄어들지 않거나 학습 과정이 수렴할 때 종료됩니다.
    • 종료 조건을 설정하고 모니터링하여 학습을 멈추는 시점을 결정합니다.

이러한 단계를 통해 최적화 알고리즘은 딥러닝 모델의 가중치를 조정하여 손실 함수를 최소화하고, 모델을 주어진 작업에 적합하게 만듭니다. 최적화 알고리즘은 딥러닝 학습의 핵심이며, 다양한 변형 및 개선된 알고리즘이 개발되어 있습니다.


경사 하강법 (Gradient Descent)이란?

경사 하강법은 가장 기본이 되는 최적화 알고리즘 입니다.

경사하강법은 주어진 함수(비용 함수)의 최솟값을 찾기 위해 현재 위치에서 함수의 기울기(그래디언트)를 계산하고, 그 기울기의 반대 방향으로 이동하여 최솟값에 접근하는 최적화 알고리즘입니다. 이 과정은 다음과 같이 요약할 수 있습니다.

  1. 초기화: 시작 위치를 임의로 선택하거나 미리 정의된 값을 사용하여 파라미터를 초기화합니다.
  2. 그래디언트 계산: 현재 위치에서 비용 함수의 그래디언트(기울기)를 계산합니다. 이는 함수가 현재 위치에서 어떻게 변하는지를 나타냅니다.
  3. 파라미터 업데이트: 그래디언트의 반대 방향으로 파라미터를 업데이트합니다. 이때 학습률(learning rate)이 사용되며, 이 값은 한 번의 업데이트 당 얼마나 멀리 이동할지를 제어합니다.
  4. 반복: 위 단계를 반복하여 비용 함수의 최솟값을 찾을 때까지 파라미터를 업데이트합니다. 또는 미리 정의된 반복 횟수(epoch)를 수행하면서 멈출 수도 있습니다.

경사하강법의 공식은 아래와 같습니다.

x= x - \eta \frac{\partial f}{\partial x}

여기서 \frac{\partial f}{\partial x} 는 편미분으로 변수가 여러개인 다변수 함수의 미분입니다. 다르게 표현하면 아래와 같습니다.

w= w - \eta \nabla_w J

또한 \nabla 는 미분 기호 입니다.


경사 하강법 예시

그럼이제 경사하강법에 대한 예시를 한번 보겠습니다. 우선 아래의 함수에 대한 경사하강법을 해 보겠습니다.

f(x)=((x-2)^2-3) \times (x+3)^2

이를 파이썬으로 나타낸후 그래프를 그려보면 아래와 같이 나오게 됩니다.

Python
import numpy as np
import matplotlib.pyplot as plt

def example_function(x):
    return ((x-2)**2-3)*((x+3)**2)
x=np.arange(-5,5,0.01)
y=example_function(x)

plt.plot(x,y)
plt.show()
예시 함수의 그래프

이 함수에서 기울기가 0이 되는 구간은 3개 입니다. 이부분에 집중을 하여 경사 하강법을 시작해 보도록 하겠습니다.

이 함수의 미분값은 아래와 같이 나타낼 수 있습니다.

f(x)=((x-2)^2-3) \times (x+3)^2 A=((x-2)^2-3), B= (x+3)^2 f'(x)=A' \times B + A \times B'

f'(x)=2(x-2) \times (x+3)^2 + ((x-2)^2+3) \times (x+3) 이 식을 파이썬 으로 정의 하면 아래와 같습니다.

Python
def gradient(x):
    dA = 2 * (x - 2) * ((x + 3) ** 2)
    dB = ((x - 2) ** 2 - 3) * 2 * (x + 3)
    return dA + dB

그리고 경사하강법 공식: x= x - \eta \frac{\partial f}{\partial x}을 파이썬으로 나타내면 아래와 같고 여기서 initial_x 는 초기의 시작점이고, Learning_rate는 \eta 이고 num_iterations는 몇걸음을 내려가는지의 횟수를 나타냅니다.

Python
def gradient_descent(initial_x, learning_rate, num_iterations):
    x = initial_x #1
    x_history = [x] #2
    
    for i in range(num_iterations): #3
        grad = gradient(x) #4
        x = x - learning_rate * grad #5
        x_history.append(x) #6
    
    return x_history  #7
  • #1: x의 초기값입니다.
  • #2: x의 초기값 부터 시작해서 한걸음씩 횟수를 진행한 발자취를 기록합니다.
  • #3: num_iterations 의 걸음걸이 횟수마다 반복합니다.
  • #4: 위에서 정의한 그레디언트 함수입니다.
  • #5: 경사하강법의 핵심 공식입니다.
  • #6: x_history에 한걸음 진행 할 때 마다 기록합니다.
  • #6: 최종적으로 나온 값을 내보냅니다.

시작점, 학습률, 걸음횟수를 바꿔가며 실행해보기

이제 시작점과, 학습률(Learning rate: eta), 걸음횟수를 적당히 넣어 실행시켜보겠습니다. 넘파이를 불러오고 우선 위의 함수들을 처음 부터 다시 정의해 보겠습니다.

Python
import numpy as np
import matplotlib.pyplot as plt

def example_function(x):
    return ((x-2)**2-3)*((x+3)**2)
x=np.arange(-5,5,0.01)
y=example_function(x)

def gradient(x):
    dA = 2 * (x - 2) * ((x + 3) ** 2)
    dB = ((x - 2) ** 2 - 3) * 2 * (x + 3)
    return dA + dB

def gradient_descent(initial_x, learning_rate, num_iterations):
    x = initial_x #1
    x_history = [x] #2
    
    for i in range(num_iterations): #3
        grad = gradient(x) #4
        x = x - learning_rate * grad #5
        x_history.append(x) #6
    
    return x_history  #7

그 후에 적당한 변수를 넣어 실행시켜보겠습니다.

Python
initial_x = -0.9  # 초기값 설정
learning_rate = 0.01  # 학습률 설정
num_iterations = 50  # 반복 횟수 설정

x_history = gradient_descent(initial_x, learning_rate, num_iterations)

x = np.arange(-5, 5, 0.01)
y = example_function(x)

plt.plot(x, y)
plt.plot(x_history, [example_function(x) for x in x_history], 'ro-')
plt.show()

다양 한 초기값에 대한 그래프는 아래와 같습니다. 모든경우에서 한걸음을 내딛을때마다 기울기가 점점 감소하는 쪽으로 이동하는 것을 할 수 있습니다. 하지만 여기서 문제점은 우리가 찾아야할 점은 함수의 최소값을 찾아야 하지만 기울기가 0인점이 모두 최소점이 아니라는 점입니다.

즉 다시 말하자면 아래의 그림과 같이 또랑에 빠져서 나오지 못하여 최저값이 아닌 점(안정점)에 수렴할 수 있다는 점입니다. 그래서 초기값이 굉장히 중요합니다.

학습률 설명에 대한 그래프

또한 학습률(Learning Rate)값이 너무낮으면 보폭이 너무작아 학습이 길어지고, 너무 크면 보폭이 너무커 발산할 수도 있습니다.

아래 그래프의 초기값 및 학습률

  • initial_x = -4  # 초기값 설정
  • learning_rate = 0.094  # 학습률 설정
  • num_iterations = 4  # 반복 횟수 설정
발산 설명에 대한 그래프

이렇게 경사하강법에 대해 알아보았는데요 이 경사하강법은 그 이외에 다양한 실용적인 알고리즘이 있습니다.


그 이외의 최적화 알고리즘

그 이외에 경사 하강법에서 파생된 다양한 최적화 알고리즘이 있습니다. 이러한 알고리즘들은 경사 하강법을 기반으로 하며, 보다 효과적으로 수렴하거나 다양한 문제에 대응할 수 있도록 변형되거나 확장된 것들입니다. 아래에 몇 가지 경사 하강법을 파생시킨 최적화 알고리즘이 있습니다.

  1. 확률적 경사 하강법 (Stochastic Gradient Descent, SGD): 기본 경사 하강법에서 미니배치(작은 데이터 샘플 그룹)를 사용하여 각 반복에서 그래디언트를 계산하고 가중치를 업데이트합니다. 이것은 대규모 데이터셋에 더 효율적입니다.
  2. 미니배치 경사 하강법 (Mini-Batch Gradient Descent): SGD와 기본 경사 하강법의 절충안으로, 미니배치 크기를 조절하여 계산 효율성과 수렴 속도를 조절할 수 있습니다.
  3. 모멘텀 경사 하강법 (Momentum Gradient Descent): 경사 하강법에 물리학적인 특성인 관성을 추가하여 이전 그래디언트의 영향을 고려하는 방법으로, 수렴 속도를 향상시킵니다.
  4. Adagrad: 각각의 매개 변수에 다른 학습률을 적용하여 자주 업데이트되는 매개 변수에는 작은 학습률을 적용하고 드물게 업데이트되는 매개 변수에는 큰 학습률을 적용합니다.
  5. RMSProp (Root Mean Square Propagation): Adagrad의 단점을 보완하기 위해 그래디언트의 제곱값을 지수 이동 평균으로 사용하여 학습률을 조절하는 방법입니다.
  6. Adam: 아담은 모멘텀과 RMSProp의 아이디어를 결합한 최적화 알고리즘으로, 많은 신경망 모델에서 사용되며 수렴 속도를 빠르게 만들어줍니다.
  7. Rprop: 아담과 유사하게 매개 변수별로 학습률을 독립적으로 조절하는데 중점을 두지만, 그래디언트의 부호를 사용하여 학습률을 조절합니다.

이러한 최적화 알고리즘들은 다양한 머신러닝 및 딥러닝 모델에서 사용되며, 그 중에서도 어떤 알고리즘이 가장 잘 작동하는지는 데이터 및 모델의 특성에 따라 다를 수 있습니다. 따라서 문제에 가장 적합한 최적화 알고리즘을 선택하고 매개 변수를 효과적으로 조정하는 것이 중요합니다. 그 이외에도 다양한 최적화 알고리즘이 있습니다.

다음 챕터 에서는 다른 많은 최적화 알고리즘 중에 deepfacelab에 쓰였던 AdaBelief 알고리즘에 대해 설명해 드리겠습니다.

함께 참고하면 좋은 글

deepfacelive:실시간 딥 페이크 만들어보기

deepfacelive를위한 DFM 모델만들기

Xseg-더 빠른 효율로 deepfacelab모델 만들기

AdaBelief 최적화 알고리즘

AdaBelief는 최근에 개발된 최적화 알고리즘이고, 주로 딥러닝 모델의 훈련에서 사용됩니다. AdaBelief는 모멘텀과 Adagrad의 아이디어를 결합하고 더 나아가 경사 추정치에 대한 예측 오차를 최소화하여 효율적인 학습을 가능하게 합니다. 복잡한 딥러닝 모델에 AdaBelief를 적용하는 예제를 보여드리겠습니다.

다음은 간단한 신경망 모델을 훈련시키는데 AdaBelief를 사용하는 코드 예제입니다. 주의: 아래 코드는 실제 실행 환경에서는 돌릴 수 없으므로 참고용입니다.

우선 기본적으로 이해할때 필요한 항들을 보겠습니다.

  • 목표 함수: J(\theta)
  • 학습률(learning rate): \alpha
  • 모멘텀 항(momentum term): \beta_1, \beta_2
  • 무한대로 발산하게 하지 않기 위한 작은 수: \epsilon
  • 초기 값: m_0 = 0, \; v_0 = 0, \; \theta_0= 초기 파라미터 t=0

진행 순서

  1. 반복횟수를 증가시킵니다.t = t + 1
  2. 목표함수의 그레디언트를 계산합니다. 기울기가 0인곳을 찾습니다. g_t = \nabla J(\theta_{t-1})
  3. 이동 평균을 계산합니다. \beta_1는 이동평균 감쇠계수입니다. m_t = \beta_1 m_{t-1} + (1-\beta_1) g_t
  4. 이동 분산을 계산합니다. \beta_2는 이동분 감쇠계수입니다. v_t = \beta_2 v_{t-1} + (1-\beta_2) (g_t - m_t)^2
  5. 첫 번째 모멘트의 초기 편향을 보정합니다. \hat{m}_t = \frac{m_t}{1 - \beta_1^t}
  6. 두 번째 모멘트의 초기 편향을 보정합니다. \hat{v}_t = \frac{v_t}{1 - \beta_2^t}
  7. 편향이 보정된 첫 번째와 두 번째 모멘트를 사용하여 매개변수를 업데이트 합니다.\theta_t = \theta_{t-1} - \alpha \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon}

\text{Output: } \theta_t: 최적화된 파라미터, 주로 weight 값입니다.

이제 경사하강법과 adabelief 를 한번 비교해 파이썬 코드를 작성해 보겠습니다.

Python
# 필요한 라이브러리 불러오기
import numpy as np
import matplotlib.pyplot as plt

# 기본 예시 함수입니다.
def example_function(x):
    return ((x-2)**2-3)*((x+3)**2)

def gradient(x):
    dA = 2 * (x - 2) * ((x + 3) ** 2)
    dB = ((x - 2) ** 2 - 3) * 2 * (x + 3)
    return dA + dB

# AdaBelief 함수입니다.
def adabelief_optimization(initial_theta, alpha=0.01, beta1=0.9, beta2=0.999, epsilon=1e-8, steps=1000):
    theta = initial_theta
    m = 0
    v = 0
    theta_history = [theta]
    for t in range(1, steps + 1):
        g = gradient(theta)
        m = beta1 * m + (1 - beta1) * g
        v = beta2 * v + (1 - beta2) * (g - m)**2
        m_hat = m / (1 - beta1 ** t)
        v_hat = v / (1 - beta2 ** t)
        theta = theta - alpha * m_hat / (np.sqrt(v_hat) + epsilon)
        theta_history.append(theta)
    return np.array([theta_history])

# 경사 하강법 함수입니다.
def gradient_descent(initial_x, learning_rate, num_iterations):
    x = initial_x
    x_history = [x]
    
    for i in range(num_iterations):
        grad = gradient(x)
        x = x - learning_rate * grad
        x_history.append(x)
    return np.array([x_history])

위코드에서 우선 기본 Adabelief 함수와, 경사하강법 함수를 정의 했습니다.

Python
# 초기 값
learning_rate = 0.01  # 학습률
num_iterations = 100 # 반복횟수
initial_x = -4 # 초기 값

# AdaBelief를 위한 추가 초기 값
beta1 = 0.9   # 첫 번째 모멘텀 (이동 평균) 에 대한 계수
beta2 = 0.999 # 두 번째 모멘텀 (이동 분산)에 대한 계수
epsilon = 1e-8 # 분모가 0이되는 것을 방지하고 연산의 안정성을 위한 값

# 경사 하강과 AdaBelief의 결괏 값
gd_history=gradient_descent(initial_x, learning_rate, num_iterations)
adabelief_history = adabelief_optimization(-4.0, learning_rate, beta1, beta2, epsilon, num_iterations)

각 최적화 함수에 대하여 초기값을 지정해 주고 경사하강법과, Adabelief를 실행시켜 줍니다.

Python
# Visualization for Basic Gradient Descent and AdaBelief side by side
fig, axes = plt.subplots(1, 2, figsize=(12, 6))

x=np.arange(-4,4,0.1)
y=example_function(x)

# 경사 하강법 그래프 그리기
axes[0].plot(x, y, label='Objective Function')
axes[0].scatter(gd_history, [example_function(t) for t in gd_history], c='red', label='GD Optimization Path')
axes[0].set_title('Optimization using Basic Gradient Descent')
axes[0].set_xlabel('x')
axes[0].set_ylabel('example_function(x)')
axes[0].legend()
axes[0].grid(True)

# AdaBelief 그래프 그리기
axes[1].plot(x, y, label='Objective Function')
axes[1].scatter(adabelief_history, [example_function(t) for t in adabelief_history], c='blue', label='AdaBelief Optimization Path')
axes[1].set_title('Optimization using AdaBelief')
axes[1].set_xlabel('x')
axes[1].set_ylabel('example_function(x)')
axes[1].legend()
axes[1].grid(True)

plt.tight_layout()
plt.show()

그 후에 그래프를 그려주면 아래와 같은 결과가 나옵니다.

경사하강법과, Adabelief에 대한 설명 그래프

이렇게 그래프가 그려졌습니다. 하지만 이 두 그래프 값에서 동일하게 안장점(미분값이 0이지만 최저값이 아닌점)에 머무르고 있습니다. 그래서 초기값에 따라 결과가 달라질 수 있습니다.

경사하강법 (Gradient Descent)과 AdaBelief 모두 목적 함수를 최소화하는 방향으로 작동합니다. 그러나 두 알고리즘은 다양한 상황과 문제에 대응할 수 있는 방식이 다릅니다. 여기에는 몇 가지 이유가 있습니다:

  1. 적응적 학습률: AdaBelief와 같은 고급 최적화 알고리즘들은 각 매개변수에 대해 적응적으로 학습률을 조정할 수 있습니다. 이는 특정 매개변수가 자주 업데이트되거나 드물게 업데이트되는 경우에 유용합니다.
  2. 학습률과 모멘텀의 자동 조절: AdaBelief는 모멘텀과 학습률을 자동으로 조절합니다. 이로 인해 수렴 속도가 빨라질 수 있고, 초매개변수 튜닝의 부담이 줄어듭니다.
  3. 수렴 안정성: AdaBelief는 안정적으로 수렴하는 경향이 있어, 초기값이나 학습률에 대한 민감도가 낮습니다.
  4. 대규모 데이터셋과 복잡한 모델: 더 복잡한 모델과 대규모 데이터셋에서는 AdaBelief와 같은 고급 알고리즘이 더 빠르고 정확하게 수렴할 가능성이 높습니다.
  5. 안장점 및 지역 최소값: 고급 알고리즘들은 기본 경사하강법보다 안장점이나 지역 최소값에서 더 쉽게 벗어날 수 있습니다.
  6. 실용성: AdaBelief는 실전에서 다양한 종류의 문제에 적용할 수 있으며, 특히 심층 신경망과 같은 복잡한 모델에서 뛰어난 성능을 보입니다.

위의 예시에서 두 알고리즘이 비슷한 결과를 보이는 것은, 함수가 상대적으로 단순하고 문제가 고차원이 아니기 때문일 수 있습니다. 복잡한 실제 문제에서는 AdaBelief가 더 뛰어난 성능을 보일 수 있습니다.

따라서, 단순한 문제나 작은 데이터셋에서는 기본 경사하강법도 충분할 수 있지만, 실제 세계의 복잡한 문제와 대규모 데이터셋에서는 AdaBelief와 같은 고급 최적화 알고리즘이 더 유용할 수 있습니다.


결론

“이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.”

최적화 알고리즘은 기계 학습과 딥러닝에서 중요한 역할을 하는데, 그 중에서도 경사하강법과 AdaBelief는 널리 사용되는 방법입니다. 경사하강법은 기본적이면서도 효과적인 방법으로, 함수의 최솟값을 찾기 위해 사용됩니다. 하지만 이는 초기값, 학습률 등의 초매개변수에 민감하며, 안장점이나 지역 최소값에 빠질 위험이 있습니다.

반면에, AdaBelief와 같은 고급 최적화 알고리즘은 이러한 문제점을 개선하고 다양한 문제와 데이터셋에 더 적응적입니다. AdaBelief는 적응적 학습률, 모멘텀 조절, 수렴 안정성 등의 장점을 가지고 있습니다. 이로 인해 복잡한 모델과 대규모 데이터셋에서 더 빠르고 정확하게 수렴할 수 있습니다.

따라서, 문제의 복잡성, 데이터셋의 크기, 수렴 속도 등을 고려할 때 AdaBelief와 같은 고급 최적화 알고리즘이 경사하강법보다 더 유용할 수 있습니다. 하지만, 단순한 문제나 작은 데이터셋에서는 기본 경사하강법도 충분히 효과적일 수 있습니다.


함께 참고하면 좋은 글

손실 함수: 딥러닝 기초 시리즈 3

활성화 함수: 딥러닝 기초 시리즈 2

퍼셉트론: 딥러닝 기초 시리즈 1

3 thoughts on “경사 하강법: 딥러닝 기초 시리즈 4”

Leave a Comment