경사하강법(Gradient Descent)

경사하강법(Gradient Descent)은 최적화 알고리즘 중 하나로, 함수의 최솟값을 찾기 위해 사용됩니다.

함수의 최솟값을 찾는 것은 다양한 분야에서 중요한 문제 중 하나입니다.

가장 기본적인 이유는 함수의 최솟값이 주어졌을 때, 그 함수를 최소화하는 입력값을 찾을 수 있다는 점입니다.

여기서 그래디언트(Gradient)란, 다변수 함수에서 각 변수들의 편미분 값들을 모아놓은 벡터를 의미합니다. 그래디언트는 함수의 기울기와 같은 의미를 가지며, 각 변수의 변화에 따른 함수값의 변화량을 나타냅니다.

경사하강법(Gradient Descent)은 함수의 최솟값을 찾는 최적화 알고리즘 중 하나로, 그래디언트를 이용해 함수의 기울기가 낮아지는 방향으로 일정한 크기의 스텝을 내딛어 최솟값을 찾아가는 방법입니다. 경사하강법은 그래디언트를 이용해 함수의 기울기 정보를 활용하는 방법으로, 최적화 문제를 푸는 데에 그래디언트를 사용할 수 있습니다.

따라서, 그래디언트는 함수의 기울기를 나타내는 벡터이고, 경사하강법은 그래디언트를 이용한 최적화 알고리즘입니다.

이런 경사 하강법은 기울기(Gradient 경사)를 이용하여 함수의 최솟값을 찾아가는 알고리즘이기 때문에, 다양한 분야에서 활용될 수 있습니다.

예를 들어, 어떤 남성이 어떤 여성에게 관심을 가지고 있고, 그 여성의 호감도를 최대화하기 위해서는 어떻게 해야 할까요? 우선, 이 남성은 자신의 매력을 최대한 발휘하기 위해 노력해야 합니다. 즉, 여성이 좋아할만한 자신의 장점을 찾아내고, 그것을 최대한 드러내야 합니다.

이것을 경사 하강법의 관점에서 보면, 남성은 여성이 좋아할만한 자신의 매력을 함수의 값으로 생각할 수 있습니다. 그리고 이 함수의 값이 가장 크게 만드는 요소를 찾아내야 합니다. 이 요소는 여러 가지 요인으로 구성될 수 있습니다. 예를 들어, 남성의 외모, 성격, 재능 등이 그것입니다. 이 중에서 여성이 가장 중요하게 생각하는 것을 찾아서, 그것을 개선해 나가야 합니다.

그리고 이 과정은 여러 번의 시도와 실패를 거쳐서 이루어집니다. 즉, 처음에는 여성이 좋아하는 요소를 정확히 파악하기 어렵기 때문에, 여러 가지 요소를 시도해보고, 그 결과를 측정해보아야 합니다. 이것이 경사 하강법에서 말하는 “기울기를 계산하고, 그 기울기가 가장 낮은 방향으로 이동하는” 과정입니다. 이를 통해 점차적으로 자신의 매력을 극대화할 수 있게 됩니다.

따라서 경사 하강법은 남녀 관계에서도 적용될 수 있으며, 자신의 매력을 최대화하기 위해서는 여러 가지 요소를 시도하고, 그 결과를 측정하여 점차 개선해 나가야 한다는 것을 알 수 있습니다.

또, 일상 생활에서는 스마트폰이나 태블릿 PC 등의 기기를 사용할 때 최적의 배터리 수명을 찾는 것이 경사 하강법과 비슷한 개념으로 생각할 수 있습니다. 배터리 수명은 여러 요인에 의해 영향을 받기 때문에, 이를 최적화하기 위해서는 배터리 사용량, 화면 밝기, Wi-Fi 연결 등 다양한 요소를 고려해야 합니다. 이때 경사 하강법을 이용하여 배터리 사용량과 화면 밝기 등의 요소를 조절해가며, 배터리 수명을 최대한 늘릴 수 있습니다.

또 다른 예로는 운동을 예로 들 수 있습니다. 운동할 때도 목표로 하는 몸매나 체력을 달성하기 위해서는 어떤 운동을 하고, 어떤 식사를 해야할지 고민할 필요가 있습니다. 이때 운동 시간, 식사 메뉴 등의 요소를 경사 하강법을 이용하여 조절하면, 목표하는 몸매나 체력을 달성하는 데 더욱 효과적일 수 있습니다.

경제학에서는 이익을 극대화하기 위한 최적의 가격을 찾는 데 사용되며, 공학에서는 자동차의 에너지 효율성을 최대화하기 위한 최적의 디자인을 찾는 데 사용됩니다.

또한 함수의 최솟값을 찾는 것은 인공지능, 머신러닝, 딥러닝 등의 분야에서도 매우 중요합니다. 이러한 분야에서는 함수의 최솟값을 찾는 것이 최적화 문제의 핵심적인 목표 중 하나이기 때문입니다. 예를 들어, 회귀분석에서는 오차를 최소화하는 모델 파라미터를 찾기 위해, 신경망에서는 손실 함수를 최소화하는 가중치를 찾기 위해, 최적화 알고리즘을 사용하여 함수의 최솟값을 찾습니다.
예를 들어, 선형 회귀 분석에서는 입력값과 출력값 사이의 관계를 나타내는 모델을 학습하는데, 이때 모델의 학습을 위해서는 모델의 예측값과 실제값의 차이인 오차를 최소화하는 최적의 모델 파라미터를 찾아야 합니다. 이때 경사하강법을 사용하여 오차를 최소화하는 최적의 모델 파라미터를 찾을 수 있습니다.

따라서 함수의 최솟값을 찾는 것은 다양한 분야에서 최적화 문제를 해결하기 위해 매우 중요합니다.

경사하강법은 먼저 임의의 시작점에서 시작하여, 현재 위치에서 함수의 기울기(경사)를 계산하고, 그 기울기가 가장 낮은 방향으로 이동합니다. 그리고 그 방향으로 일정 거리만큼 이동한 후에 다시 기울기를 계산하고, 이동합니다. 이 과정을 반복하여, 함수의 최솟값에 도달합니다.

간단한 파이썬 코드는 다음과 같습니다.

def gradient_descent(f, df, x0, lr, max_iter):
    x = x0
    for i in range(max_iter):
        grad = df(x)
        x = x - lr * grad
    return x

여기서 f는 최솟값을 찾으려는 함수이며, df는 f의 기울기(도함수)입니다. x0는 시작점입니다. lr은 학습률(learning rate)이며, 이 값은 한 번의 반복에서 이동할 거리를 결정합니다. max_iter는 최대 반복 횟수입니다.

 

또 아래의 코드는 간단한 2차 함수인 x^2 + y^2를 최소화하는 과정을 경사하강법으로 시각화하는 코드입니다.

실행 결과( Corlab으로 실행하기)

import numpy as np
import matplotlib.pyplot as plt

# 함수 정의
def f(x, y):
    return x**2 + y**2

# 편미분 함수 정의
def df_dx(x, y):
    return 2*x

def df_dy(x, y):
    return 2*y

# 하이퍼파라미터 정의
LEARNING_RATE = 0.1
MAX_ITERATIONS = 50

# 초기값 설정
x = 4.0
y = 4.0

# 경사하강법 알고리즘
for i in range(MAX_ITERATIONS):
    # 현재 위치에서 기울기 계산
    gradient_x = df_dx(x, y)
    gradient_y = df_dy(x, y)
    
    # 경사하강법 업데이트
    x -= LEARNING_RATE * gradient_x
    y -= LEARNING_RATE * gradient_y
    
    # 시각화를 위한 저장
    plt.scatter(x, y, color='red')

# 함수 시각화
x_vals = np.linspace(-6, 6, 100)
y_vals = np.linspace(-6, 6, 100)
x_mesh, y_mesh = np.meshgrid(x_vals, y_vals)
z = f(x_mesh, y_mesh)

plt.contour(x_mesh, y_mesh, z, levels=np.logspace(-1, 3, 10))
plt.colorbar()
plt.show()

Jax를 사용한 간단한 그래디언트 계산

JAX를 사용하면 자동 미분 기능을 활용하여 그래디언트를 간단하게 계산할 수 있습니다.
위 코드에서 그래디언트를 계산하는 부분은 다음과 같습니다.

# 현재 위치에서 기울기 계산
gradient_x = df_dx(x, y)
gradient_y = df_dy(x, y)

df_dx 함수와 df_dy 함수를 이용하여 각각 x, y에 대한 편미분을 계산하고, 이를 gradient_x와 gradient_y 변수에 할당합니다. 이후 경사하강법 알고리즘에서 이 값을 이용하여 모델을 업데이트합니다.
JAX를 사용하면 자동 미분 기능을 활용하여 그래디언트를 간단하게 계산할 수 있습니다.
JAX에서는 grad() 함수를 사용하여 함수의 그래디언트를 계산할 수 있습니다. 따라서 위의 코드는 다음과 같이 변경될 수 있습니다.

실행하기

import jax.numpy as jnp
from jax import grad
import matplotlib.pyplot as plt

# 함수 정의
def f(x):
    return x[0]**2 + x[1]**2

# 하이퍼파라미터 정의
LEARNING_RATE = 0.1
MAX_ITERATIONS = 50

# 초기값 설정
x = jnp.array([4.0, 4.0])

# 그래디언트 계산 함수
grad_f = grad(f)

# 경사하강법 알고리즘
for i in range(MAX_ITERATIONS):
    # 현재 위치에서 그래디언트 계산
    gradient = grad_f(x)
    
    # 경사하강법 업데이트
    x -= LEARNING_RATE * gradient
    
    # 시각화를 위한 저장
    plt.scatter(x[0], x[1], color='red')

# 함수 시각화
x_vals = jnp.linspace(-6, 6, 100)
y_vals = jnp.linspace(-6, 6, 100)
x_mesh, y_mesh = jnp.meshgrid(x_vals, y_vals)
z = f([x_mesh, y_mesh])

plt.contour(x_mesh, y_mesh, z, levels=jnp.logspace(-1, 3, 10))
plt.colorbar()
plt.show()

위 코드에서는 jax.numpy를 jnp라는 별칭으로 사용하고 있으며, 함수 f(x)를 x의 요소 중 첫 번째와 두 번째 요소에 대한 제곱합으로 정의하였습니다. 그리고 jax.grad 함수를 사용하여 f(x)의 그래디언트를 자동으로 계산합니다. 그래디언트를 계산하기 위해 x가 필요하므로, x를 jnp.array로 선언하였습니다. 이후 경사하강법 알고리즘은 이전과 동일하게 작성하였습니다. 마지막으로 함수를 시각화하기 위한 코드는 이전과 동일합니다.

왕초보! 텐서플로우 2.0 머신러닝 기초 강좌