이번 장에서는 경사하강법&오차 역전파 알고리즘을 응용해 선형회귀모델을 만들어 보는 시간을 갖도록 하겠습니다.
1. 먼저 문제 해결을 위해 당뇨병 환자의 데이터를 준비하겠습니다.
from sklearn.datasets import load_diabetes
diabetes = load_diabetes()
2. 입력과 타겟 데이터의 크기를 확인하겠습니다.
print(diabetes.data.shape, diabetes.target.shape)
(442, 10) (442,)
3.당뇨병 환자의 데이터를 시각화 하겠습니다.
import matplotlib.pyplot as plt
plt.scatter(diabetes.data[:,2],diabetes.target) #모든 특성을 하나의 그래프에 그릴 수 없으므로 하나의 특성만 고려한다.
plt.xlabel('x')
plt.ylabel('y')
4.훈련데이터를 준비합니다.
x = diabetes.data[:,2]
y = diabetes.target
경사하강법
y = wx + b에서 w와b를 알고싶다면?
1. 무작위로 w 와 b를 정합니다.
2. x에서 샘플 하나를 선택하여 y를 계산합니다.
3. y^와 선택한 샘플의 진짜 y를 비교합니다.
4. y^ 와 y가 가까워지도록 w,b 조정
#w,b 초기화 하기
w = 1.0
b = 1.0
#훈련 데이터의 첫 번째 샘플 데이터로 y^얻기
y_hat = x[0]*w +b
y_hat
1.0616962065186886
#타겟과 예측 데이터 비교하기
y[0]
151.0
#차이가 크다. w값 조절해 예측값 바꾸기
w_inc = w + 0.1
y_hat_inc = x[0]*w_inc +b
print(y_hat_inc)
1.0678658271705574
#w값 조정한 후 예측값 증가 정도 확인하기
w_rate = (y_hat_inc - y_hat) /(w_inc - w)
w_rate
0.061696206518688734
변화율로 가중치를 업데이트 해보겠습니다.
w_new = w + w_rate
print(w_new)
1.0616962065186888
#### 변화율로 절편 업데이트하기
b_inc = b +0.1
y_hat_inc = x[0]*w + b_inc
print(y_hat_inc)
1.1616962065186887
b_rate = (y_hat_inc - y_hat)/(b_inc - b)
print(b_rate)
1.0
b_new = b + 1
print(b_new)
2.0
오차 역전파(Backpropagation)
y^과 y의 차이를 이용하여 w와b를 업데이트합니다.
1. w와 b를 임의의 값으로 초기화하고 훈련 데이터의 샘플을 하나씩 대입하여 y , y^의 오차를 구한다.
2. 1에서 구한 오차를 w와 b의 변화율에 곱하고 이 값을 이용하여 w와 b를 업데이트 합니다.
3. 만약 y^이 y보다 커지면 오차는 음수가 되어 자동으로 w와 b가 줄어드는 방향으로 업데이트
4. 반대로 y^이 y보다 작아지면 오차는 양수가 되고 w와b는 더 커지도록 업데이트
# 오차와 변화율을 곱하여 가중치 업데이트하기
err = y[0] - y_hat
w_new = w + w_rate*err
b_new = b + 1*err
print(w_new,b_new)
10.250624555904514 150.9383037934813
#두번째 샘플을 사용하여 마찬가지로 오차를 구하고 새로운 w , b를 구해보자
y_hat = x[1]*w_new + b_new
err = y[1] - y_hat
w_rate = x[1] #w_rate식을 정리했을대 샘플값과 같아진다는 점 .
w_new = w_new + w_rate*err
b_new = b_new +1*err
print(w_new , b_new)
14.132317616381767 75.52764127612664
#이런 방식으로 모든 샘플을 사용해 가중치와 절편을 업데이트
for x_i,y_i in zip(x,y):
y_hat = x_i*w +b
err = y_i -y_hat
w_rate = x_i
w = w + w_rate*err
b = b +1*err
print(w,b)
587.8654539985689 99.40935564531424
위에서 도출된 w,b를 통해 선형회귀 직선을 그어봅시다.
plt.scatter(x,y)
pt1 = (-0.1,-0.1*w+b)
pt2 = (0.15,0.15*w+b)
plt.plot([pt1[0],pt2[0]],[pt1[1],pt2[1]])
plt.xlabel('x')
plt.ylabel('y')
plt.show()
산점도의 분포에 비슷하게 직선이 만들어졌지만 아직 부족한것을 알 수 있습니다.
epochs=100으로 준 다음 똑같이 직선을 그려보겠습니다.
#여러 에포크 반복하기.
for i in range(1,100):
for x_i,y_i in zip(x,y):
y_hat = x_i*w +b
err = y_i -y_hat
w_rate = x_i
w = w + w_rate*err
b = b +1*err
print(w,b)
913.5973364345905 123.39414383177204
plt.scatter(x,y)
pt1 = (-0.1,-0.1*w+b)
pt2 = (0.15,0.15*w+b)
plt.plot([pt1[0],pt2[0]],[pt1[1],pt2[1]])
plt.xlabel('x')
plt.ylabel('y')
plt.show()
이렇게 해서 이 데이터에 잘 맞는 머신러닝 모델을 찾았습니다.
y^ = 913.6x + 123.4
이 모델을 바탕으로 예측을 해보면,
x_new = 0.18
y_pred = x_new *w +b
print(y_pred)
287.8416643899983
plt.scatter(x,y)
plt.scatter(x_new , y_pred)
plt.show()
위에서 배운걸 바탕으로 class를 만들어 보았습니다.
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):
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
neuron = Neuron()
neuron.fit(x,y)
plt.scatter(x,y)
pt1 = (-0.1,-0.1*w+b)
pt2 = (0.15,0.15*w+b)
plt.plot([pt1[0],pt2[0]],[pt1[1],pt2[1]])
plt.xlabel('x')
plt.ylabel('y')
plt.show()
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!