외로운 Nova의 작업실
비지도학습 - 선형 회귀 본문
- 선형 회귀
선형 회귀 분석이란 고나찰된 데이터들을 기반으로 하나의 함수를 구해서 관찰되지 않은 데이터의 값을 예측하는 것을 말합니다. 간단하게 축구선수의 슛횟수와 획득한 점수표로 다음 슛횟수에대한 점수는 몇이 되는지 예측하는 선형 회귀 AI를 이해해보겠습니다.
위 표를 보고 다음과 같이 도식화 할 수 있습니다.
이 축구선수가 4번의 슛을 시도할 경우 몇점을 획득하게 될까요? 하나의 함수를 구해보겠습니다. y=ax+b라는 1차함수를 생각할 경우 y=x라는 함수 공식이 관찰된 데이터에 100% 적용된다는 것을 확인할 수 있습니다.
이 축구선수가 4번의 슛을 쏠경우 함수에 따라 4개의 골을 성공할 것이라고 예측할 수 있습니다.
- 평균 제곱 오차
그렇다면 데이터가 아래의 상황일때 더 나은 회귀함수를 찾는 방법은 어떻게될까요?
위와 같은 데이터 분포에서 나올 수 있는 회귀함수는 대략 아래와 같을 것입니다.
이 둘중에 뭐가 더 나은지 비교해보도록 하겠습니다. 비교하는 방법은 데이터 포인트와 회귀 직선까지의 거리를 비교해서 더 작은 값을 가진 회귀 함수가 더 낫다고 할 수 있습니다. 하지만 실무에서는 이 거리의 제곱한 값을 더 많이 사용합니다.
거리를 제곱함으로써 항상 양수인 거리값을 얻는 장점과 두개의 회귀를 비교했을때 쉽게 어느 회귀가 더 나은지 비교할 수 있다는 장점을 볼 수 있습니다. 이처럼 각 데이터 포인트로부터 함수까지의 거리를 제곱한 값을 평균낸 값을 평균 제곱 오차라고합니다. 그림에서 빨간 사각형들의 평균값이 작은 함수가 더 나은 회귀함수입니다.
평균 재곱 오차를 수식으로 나타내면 다음과 같습니다.
- 선형 회귀의 목적 함수
목적함수란 보통 어떤 함수의 최댓값 또는 최솟값을 구하는 함수입니다. 우리가 회귀 함수을 2개 비교할때 평균 제곱 오차가 더 작은 회귀 함수가 더 나은 회귀 함수라고 판단했던 것처럼 우리는 평균 제곱 오차가 최소가 되는 함수를 찾아야합니다. 즉, 선형 회귀 함수의 목적함수(평균 제곱 오차 함수)를 이용해서 최솟값을 찾아야합니다.
평균 제곱 오차 함수는 위에서 본것처럼 2차함수를 띄게됩니다.
이 함수에서 미분값이 0 즉 변곡점인 지점을 찾아야합니다. 이때 찾는 방법은 경사하강법으로 생각해보겠습니다.
- 경사하강법
경사하강법은 최초 회귀 계수를 임의값으로 설정한 후 값을 변경가면서 최소의 평균 제곱 오차를 가지는 회귀 계수를 구하는 방법입니다. 즉, y=ax+b에서 a와 b를 임의값으로 설정한후 변경해가면서 최소의 평균 제곱 오차를 가지는 회귀 계수를 구하는 방법입니다. 이때 y=ax함수 중에서 최고의 회귀함수를 찾는 방법으로 설명해보겠습니다.
먼저 a를 1로 놓은 상황입니다. 평균 제곱 오차는 크고, 미분값은 0이 아니고 + 양수를 띄게됩니다. 따라서 미분값을 줄여나가야합니다. 이때 a를 1에서 무엇으로 바꿀건지 결정하는 계수가 학습률이라고합니다. 학습률이 크면 a값이 크게변경됩니다.
a값을 변경해서 보았더니 미분 값이 조금 줄어들었습니다. 즉 0을 향해가고 있습니다. 이렇게 반복하다보면 아래와 같이 됩니다.
- 실습
실제 y=ax의 형태를 갖는 선형 회귀를 직접 케라스로 구현해보겠습니다.
from keras import optimizers
from keras.models import Sequential
from keras.layers import Dense
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
먼저 데이터를 만들어주겠습니다. 먼저 0에서부터 10까지 총 10개의 x값을 만들고 그에 해당하는 y값은 x에 임의의 수를 더한 값으로 생성합니다.
X = np.linspace(0, 10, 10)
Y = X + np.random.randn(*X.shape)
임의로 생성된 데이터를 조회해보겠습니다.
for x, y in zip(X,Y):
print((round(x,1), round(y,1)))
이제 회귀모델을 케라스의 Sequential을 사용해 만들어보겠습니다. 이번에 만들 모델의 입력은 단순히 x값 하나이기때문에 input_dim은 1로 설정하고 모델의 출력역시 단순한 y값 예측이므로 unist를 1로 설정합니다. activation 함수는 linear로 설정해선형성을 유지하도록 합니다. y = ax + b일 경우 use_bias를 true로 설정해야겠지만 현재 우리의 가설은 y = ax이므로 user_bias를 false로 설정합니다.
model = Sequential()
model.add(Dense(input_dim=1, units=1, activation="linear", use_bias=False))
이제 모델을 학습하기위한 방법을 설정합니다. 이론에서와 마찬가지로 경사하강법으로 평균제곱오차를 줄이는 방법으로 모델을 학습하겠습니다. lr=0.01은 학습률을 0.01로 설정하는 것을 의미합니다. lr이 너무 작을경우 학습의 속도가 너무 느리고 너무 클경우 학습이 제대로 이뤄지지않을 수 있습니다.
ㅍsgd = optimizers.SGD(lr=0.05)
model.compile(optimizer='sgd', loss='mse')
이제 학습전 최초로 설정된 w(a)값을 조회해보겠습니다.
weights = model.layers[0].get_weights()
w = weights[0][0][0]
print('initial w is : ' + str(w))
1.6338617값임을 알 수 있습니다. 이제 학습을 통해 가장 알맞은 a(w)를 찾아보겠습니다.
- 선형회귀 모델 학습
10개의 데이터가 있으므로 배치 사이즈를 10으로 설정해 10개의 데이터에대한 평균 제곱 오차를 사용한 학습을 진행합니다. epochs=10으로 설정해 10번 반복 학습을 진행해 최적의 w를 찾습니다.
model.fit(X, Y, batch_size=10,epochs=10, verbose=1)
로그를 통해 손실(loss)가 점차 줄어드는 것을 알 수 있으며 손실이 줄어든다는 것은 평균 제곱 편차가 줄어든다는 의미입니다. 따라서 7번째 학습부터 손실의 변화가 없는 것을 확인할 수 있는데, 이미 7번째에서 평균 제곱 오차를 최소화하는 a(w)를 찾은 것으로 학습할 수 있습니다.
weights = model.layers[0].get_weights()
w = weights[0][0][0]
print('trained w is : ' + str(w))
위 코드로 학습된 w값이 몇인지 확인해보겠습니다.
0.99236614인 것을 알 수 있습니다.
plt.plot(X, Y, label='data')
plt.plot(X, w*X, label='prediction')
plt.legend()
plt.show()
위 코드로 데이터와 선형회귀 함수의 관계를 살펴보겠습니다.
이렇게 나온 것을 확인할 수 있습니다.
'AI > machine-learning' 카테고리의 다른 글
비지도 학습 - 주성분 분석 (0) | 2023.11.10 |
---|---|
비지도 학습 - 로지스틱 회귀 (0) | 2023.11.07 |
비지도학습 - 군집화 (0) | 2023.11.04 |
앙상블 기법 (0) | 2023.11.03 |
지도 학습 - 나이브 베이즈 (0) | 2023.11.02 |