DNN/딥러닝

머신러닝의 기초

Return 2021. 6. 23. 08:35

이번 장에서는 경사하강법&오차 역전파 알고리즘을 응용해 선형회귀모델을 만들어 보는 시간을 갖도록 하겠습니다. 

 

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()