이번 글에서는 딥러닝의 가장 기초가 되는 선형 회귀에 대해 다뤄보려고 합니다.
그리고 경사 하강법으로 학습을 하고 나아가 뉴런(유닛) 클래스를 만들어 보는 것까지 얘기하겠습니다.
이 글에서의 코드는 구글의 코랩(Colab)으로 실습합니다.
이 글의 마지막에 제가 실습한 코랩 url을 첨부하겠습니다.
인공지능과 딥러닝에 대한 기본 개념과 이해는 인공지능 카테고리의 다른 글을 참고해주세요.
이 글은 'Do it! 정직하게 코딩하며 배우는 딥러닝 입문' 책으로 공부하며 정리한 글입니다.
선형 회귀
선형 회귀는 머신러닝 알고리즘 중 가장 간단하면서 딥러닝의 기초가 되는 것입니다.
선형 회귀는 다음과 같이 간단한 1차 함수로 표현할 수 있습니다.
y = ax + b
중학교에서 배웠던 1차 함수에서 우리는 a, b가 주어지고 x, y 값을 찾아야 했지만 인공 지능에서 중요한 것은 절편(b)과 기울기(a)를 찾는 것 입니다. 먼저 여러 점이 주어지고 그 점을 가장 잘 표현할 수 있는 1차 함수를 찾는 것이 목적입니다. 그렇게 만들어진 1차 함수들을 '선형 회귀로 만든 모델'이라고 부르고 가장 잘 표현한 하나의 1차 함수가 바로 최적의 모델입니다.
인공 지능에서 중요한 것은 예측입니다. 따라서 이렇게 만들어진 모델로 미지의 점(x)에 대한 예측(y값)을 할 수 있습니다.
경사 하강법
경사 하강법은 모델이 데이터를 잘 표현할 수 있도록 기울기(변화율)를 사용하여 모델을 조금씩 조정하는 최적화 알고리즘입니다.
즉, 회귀 문제를 풀기 위한 많은 알고리즘 중 하나가 경사 하강법이라고 생각하시면 됩니다.
딥러닝에서는 기울기(a)를 가중치를 의미하는 w로 표기하고 y 값은 예측값을 의미하는 y-hat 으로 표기합니다.
따라서 직선의 방정식을 위와 같이 표현할 수 있습니다.
선형 회귀에서 말했듯이 가중치 w와 절편 b를 찾는 것이 중요합니다.
여기서 중요하게 알아야할 것은, 하나의 x, y에 대해 가중치와 절편을 구하는 것입니다. 첫 번째 x에 대해 w, b를 조정하고 그 다음 샘플 x에 대해 w, b를 조정하여 결국 최적의 w, b를 결정하여 최적의 모델을 구하게 됩니다. 이것이 바로 학습입니다.
훈련 데이터에 잘 맞는 w와 b를 찾는 방법은
1. 무작위로 w와 b를 선택합니다. 즉, 무작위로 일단 모델을 만드는 것입니다.
2. 입력 데이터 x에서 샘플 하나를 선택하여 예측값을 계산합니다.
3. 예측값과 샘플의 진짜 y값, 즉 타깃을 비교합니다.
4. 예측값이 y와 더 가까워지도록 w와 b를 조정합니다. (모델 조정)
5. 모든 샘플을 처리할 때까지 2~4 과정을 반복합니다.
4번에서 가중치를 업데이트할 때 변화율로 업데이트하는 방법이 있습니다.
여기서의 변화율은 w를 증가시켰을 때 y_hat이 증가한 양입니다. 각각의 샘플에 대해 가중치의 변화율을 구할 수 있는데 수식으로 정리하면 변화율은 결국 훈련 데이터의 i번째 샘플 x[i] 입니다.
y_hat이 y보다 작은 경우 변화율을 사용해 어떻게 업데이트 할까요?
변화율이 양수이면 x축이 w고 y축이 y_hat인 그래프에서 w가 증가하면 y_hat이 증가하므로 변화율을 가중치에 더하는 방법으로 가중치를 업데이트할 수 있습니다.
변화율이 음수이면 w가 증가하면 y_hat이 감소하므로 변화율(음수)를 가중치에 더하면 y_hat이 증가하므로 가중치를 업데이트할 수 있습니다.
절편을 업데이트할 때도 변화율로 업데이트할 수 있습니다.
이 때의 변화율은 b를 증가시켰을 때 y_hat이 증가한 양입니다. 당연하게도 변화율은 1입니다. 절편이 1 증가하면 그래프 위치가 +y 방향으로 1 증가하기 때문이죠.
y_hat이 y보다 작은 경우 절편을 업데이트하기 위해서는 단순하게 1만 더하면 됩니다.
▶ 여기에 문제가 있습니다. 예측값과 타깃값의 차이가 크면 큰 폭으로 w, b를 조정해야하는데 위의 방법으로는 너무 조금씩밖에 조정되지 않습니다. 그리고 예측값이 y보다 크면 y_hat을 감소시키지 못합니다.
따라서 오차 역전파를 사용하여 더욱 적절하게 w와 b를 업데이트할 수 있습니다.
오차 역전파
오차 역전파란 w와 b의 변화율에 타깃(y)에서 예측값(y_hat)을 뺀 오차를 곱하는 방법입니다.
따라서 오차 역전파를 사용하면 오차의 크기를 반영해 모델을 업데이트할 수 있고 y_hat이 y보다 작은 경우에는 오차가 음수가 되어 가중치와 절편을 줄어드는 방향으로 업데이트할 수 있습니다.
코드는 다음과 같습니다.
err = y_i - y_hat
w = w + x_i * err
b = b + 1 * err
경사 하강법에서는 주어진 훈련 데이터로 여러 번 학습을 합니다. 전체 훈련 데이터를 한 번 학습하는 것을 에포크(epoch) 라고 부릅니다. 일반적으로 수십에서 수천 번의 에포크를 반복합니다.
여러 번 학습하는 것은 2개의 for문으로 처리할 수 있습니다.
전체 훈련 데이터에 대한 학습 -> for문 1개
여러 번의 에포크 반복 -> 위의 for문의 바깥쪽에 for문 1개
손실 함수
손실 함수는 예상한 값과 실제 타깃값의 차이를 함수로 정의한 것입니다.
경사 하강법은 어떤 손실 함수가 정의되었을 때 손실 함수 값이 최소가 되는 점을 찾아가는 방법이 되는 것입니다.
위의 오차 역전파에서 말한 오차로 w와 b를 업데이트한 것은 '제곱 오차'라는 손실 함수를 미분한 것과 같습니다.
여러 손실 함수 중 '제곱 오차'에 대해 알아봅시다.
제곱 오차 식을 가중치에 대해 편미분하고 절편에 대해 편미분하면 그 결과는 다음과 같습니다.
이 때 미분하면 결과값에 2가 나오므로 제곱 오차에 1/2를 곱한 식을 미분합니다.
* 미분적분학 기본 개념 - 미분 결과는 변화율과 같습니다.
가중치에 대해 편미분한 결과는
-(y - y_hat)x 로,
가중치에 대한 제곱 오차의 변화율과 같습니다. 변화율로 가중치를 업데이트할 때는 위의 경사 하강법에서 다뤘던 것과 비슷하게 변화율을 뺍니다. 왜냐하면 예측값이 커져야했던 것과 달리 이 식은 손실 함수이므로 손실 함수는 작을수록 최적의 모델이기 때문이죠.
업데이트 된 가중치는
w = w + (y - y_hat)x
절편에 대해 편미분한 결과는
-(y - y_hat)*1
그리고 위와 같이 절편을 업데이트하면
b = b + (y - y_hat)*1
인공지능 분야에서는 변화율을 gradient(경사) 라고 부릅니다.
뉴런
경사 하강법 알고리즘을 Neuron이라는 이름의 파이썬 클래스로 만들겠습니다.
이 뉴런은 절대 우리 뇌 속의 뉴런과 같지 않습니다. 따라서 뉴런을 유닛이라고도 부릅니다.
이 뉴런 클래스에서의 정방향 계산은 바로 예측값을 계산하는 것을 의미합니다.
역방향 계산은 오차를 이용해 가중치와 절편의 gradient를 계산하는 것을 의미합니다.
class Neuron:
# 초기화 메서드
def __init__(self):
self.w = 1.0 # 학습할 때 가중치와 절편은 시작값이 있어야함
self.b = 1.0
# 정방향 계산을 위한 메서드
def forpass(self, x):
y_hat = x*self.w + self.b
return y_hat
# 역방향 계산 메서드 (오차 역전파)
def backprop(self, x, err):
w_grad = x*err
b_grad = 1*err
return w_grad, b_grad
# 훈련을 위한 메서드
# 가중치와 절편 업데이트. 이 과정이 '훈련'
def fit(self, x, y, epochs=100):
for i in range(epochs): # 100 에포크 반복
for x_i, y_i in zip(x, y): # 모든 샘플에 대해 반복
y_hat = self.forpass(x_i)
err = -(y_i - y_hat)
w_grad, b_grad = self.backprop(x_i, err)
self.w -= w_grad
self.b -= b_grad
신경망 모델을 사용하는 딥러닝은 항상 경사 하강법 알고리즘을 사용합니다.
이 글에서 다룬 경사 하강법 알고리즘이 딥러닝 핵심 중 하나입니다.
위의 개념들을 익히며 코랩으로 실습한 것을 첨부합니다.
https://colab.research.google.com/drive/1kX9aMMmSaQMvixVVpmYj-Yf-tqlka_Ej#scrollTo=KbQaGm4-HpGV
Google Colaboratory
colab.research.google.com
'인공지능 > 딥러닝' 카테고리의 다른 글
[cs231n] Lecture Summary _part I (0) | 2021.06.27 |
---|---|
[Tensorflow] Transfer Learning (0) | 2021.05.30 |
[Tensorflow] 이미지 분류 (0) | 2021.05.30 |
이진 분류_로지스틱 회귀 (0) | 2021.02.22 |