모델의 오류는 왜 중요할까?
들어가기 전에 한 줄 요약해보겠습니다. 의심하며 본문의 내용을 읽어주세요. 혹시나 다른 내용이 있다면 덧글 부탁드립니다.
- 모델의 계수를 구하기 위해 가중치를 바꿔가며 전역(global) 기울기가 0인 곳을 잘 찾아보자.
들어가기
머신러닝 혹은 딥러닝의 가장 적합한 모델이라 함은 대부분 모델의 오류(error)를 최소화하는 것을 의미한다. 즉, 어떤 모델(단변량 함수)의 계수의 최적값을 찾는 것으로 생각 할 수 있다. 최적화 문제를 풀기위해 경사 하강법이라 부르는 방법을 사용할텐데, 이는 곧 함수의 기울기를 계산하고 경사의 이동방향의 반대 방향으로 이동하여 극값(=0)을 찾는 문제와 같다. 접선의 오류를 찾는 손실함수는 다음 포스트에서 다루도록 하겠다.
(즉 머신러닝/딥러닝 최적 모델은 함수의 기울기와 접선의 오차를 줄이는 것이다)
본 포스트에서는 경사 하강법의 기본 개념에 한하여 설명하도록 하겠다.
(*딥러닝의 경우 때에 따라 다차원 함수의 최소값을 찾아야 한다. 이는 인간의 머리로는 한계가 있다.)
Python 코드를 활용해 간단한 그라디언트 함수를 만들어 보자.
f가 단변수 함수인 경우, 점 x 에서의 미분값은 x가 아주 조금 변했을 때 f(x)의 변화량을 의미한다. x의 변화량을 식에서는 h로 표기한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | from typing import Callable def difference_quoitemt(f: Callable, x: float, h: float): return (f(x+h) - f(x)) / h def square(x: float): return x * x def derivative(x: float): return 2 * x xs = range(-100, 101) acutal_values = [derivative(x) for x in xs] estimate_values = [difference_quoitemt(square, x, h=0.003) for x in xs] #결과 값을 보여주기 위한 그래프 라이브러리 호출 import matplotlib.pyplot as plt plt.title("Actual Derivatives vs. Estimates") plt.plot(xs, acutal_values, 'r-', label='Actual') plt.plot(xs, estimate_values, 'b+', label='Estimate') plt.legend(loc='best') plt.show() |
1 2 3 4 | def partial_difference_quoitemt(f: Callable, v, i, h): w = [v_j + (h if j == i else 0)] for j, v_j in enumerate(v) return (f(w) - f(v)) / h |
일반적인 도함수와 같은 방법으로 그래디언트의 근사값을 구할 수 있다.
1 2 | def estimate_gradient(f: Callable, v, h: float = 0.003): return [partial_difference_quoitemt(f, v, i, h) for i in range(len(v)) |
경사 하강법을 이용해서 3차원 벡터의 최소값을 구해 보자. 임이의 시작점을 잡고, 그래디언트가 아주 작아질 때까지 경사의 반대 방향으로 조금씩 이동하면 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | import numpy as np import matplotlib.pyplot as plt x1 = np.array([2, 6, 4, 8]) x2 = np.array([0, 4, 8, 10]) y = np.array([81, 96, 87, 100]) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.scatter3D(x1, x2, y) plt.show() # 기울기 a의 값과 절편 b의 값을 초기화 a1 = 0 a2 = 0 b = 0 # 학습률을 정의 lr = 0.003 # 에포크 설정 epochs = 100 n = len(x1) # 경사 하강법 시작 for i in range(epochs): y_pred = a1 * x1 + a2 * x2 + b error = y - y_pred a1_diff = (2/n) * sum(-x1 * (error)) a2_diff = (2/n) * sum(-x2 * (error)) b_diff = (2/n) * sum(-(error)) a1 = a1 - lr * a1_diff a2 = a2 - lr * a2_diff b = b - lr * b_diff if i % 100 == 0: print('epoch=%.f, 기울기1=%.04f, 기울기2=%.04F, 절편=%.04f'%(i, a1, a2, b)) |
☑ 적절한 이동 거리 정하기
- 이동 거리(Step size)를 고정
- 시간에 따라 이동 거리를 점차 줄임
- 이동할 때마다 목적 함수를 최소화하는 이동 거리로 정하기
1 2 3 4 5 6 7 8 | from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense model = Sequential() model.add(Dense(30, input_dim=16, activation='relu')) model.add(Dense(1, activation='sigmoid')) model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) |
결국 경사 하강법이란 N 차원의 평면이라 가정한다면, 평면 위에서 보폭과 가고자하는 방향(관성)을 조절하여 지역(local) 최소값을 피해 전역(global) 최소 값을 찾는 것이라 요약할 수 있다. 아래 표는 현재까지 소개된 경사 하강법의 대표적인 방법론 들을 간략하게 도식화한 것입니다. 대부분의 모델 컴파일은 아담으로 가죠? 결국 아담이 답인가요.. 무튼 각자 모델에 맞게 옵티마이저를 잘 사용하여 좋은 결과 있기를 기대해봅니다.
경사하강법을 이용하여 모델(다변량 함수)의 계수(가중치)를 직접 계산하려면 전체 방정식을 알아야하지만, 딥러닝 모델의 경우 우리는 모델이 명시적으로 어떻게 표현되는지 모릅니다. 알더리도 수천 수억개가 넘는 것들을 전부 계산하기는 어렵겠죠. 이때 오차역전파를 이용하면 긴단하고 효율적으로 계산할 수 있습니다. 다음은 오차역전파의 개념을 상세 수식을 활용해 설명하도록 하겠습니다.
출처
[1] 모두의 딥러닝 개정 3판
[2] 전문가를 위한 파이썬




댓글
댓글 쓰기