손실함수와 경사 하강법의 관계

movinggirl·2020년 2월 4일
1

손실함수와 경사 하강법의 관계

  • 경사하강법의 보다 기술적 표현

    • 어떤 손실 함수 (loss function)가 정의되었을 때, 손실함수의 값이 최소가 되는 지점을 찾아가는 방법
  • 손실 함수

    • 예상한 값과 실제 타깃값의 차이를 함수로 정의한 것
    • '오파를 변화율에 곱하여 가중치와 절편 업데이트하기'는 '제곱 오차'라는 손실함수를 미분한 것과 같다.
  • 제곱오차 (squared error)

    • 타깃값(y)과 예측값(y^)을 뺀 다음 제곱한 것
      SE = (y - y^)**2
  • 이전에 가중치와 절편을 업데이트하기 위해 가중치와 절편의 변화율을 각각 구하고, 타깃값과 예측값의 오차를 곱한 것을 가중치와 절편에 더해주는 방식을 이용했다.

  • 그러나 손실함수를 이용한 방식은 다음과 같다.

    • 가중치 업데이트
      1. 가중치에 대하여 제곱오차 미분하기
        • 결과 : -2(y - y^)
        • 좀더 깔끔한 표현을 위하여 초기 제곱오차 공식 수정 -> 1/2(y - y^)**2
      2. 기존의 가중치에서 1의 결과 빼기 :: 빼는 이유는 손실함수의 낮은 쪽으로 이동하기 위함
    • 절편 업데이트
      1. 절편에 대하여 제곱오차 미분하기
        • 결과 : -(y -y^) * 1 :: 초기 제곱오차 공식 수정한 이후 결과
      2. 기존의 절편에서 1의 결과 빼기 :: 빼는 이유는 위와 동일
  • ``

  • 앞으로는 손실함수에 대해 일일이 변화율의 값을 계산하는 대신 편미분을 사용하여 변화율을 계산한다. 변화율은 인공지능 분야에서 특별히 그레이디언트(gradient, 경사)라고 부른다.

손실함수의 여러 이름
  • 비용 함수(cost function)
    • 모든 훈련 데이터에 대한 손실 함수의 합
  • 목적 함수(objective function)
    • 더 일반적인 용어로, 최적화하기 위한 대상 함수를 의미한다.
  • 인공지능 분야에서는 이 세가지 용어를 크게 구분하지 않고 사용하는 경우가 대부분.

선형 회귀를 위한 뉴런 생성

위에서는 경사하강법을 사용한 회귀문제를 직접 구하는 방식과 미분을 사용한 방식(손실함수)으로 검증해보았다. 지금 부터는 배운내용을 종합하여 파이썬 클래스로 생성해볼 것이다.

Neuron 클래스 만들기

  1. init() 메서드 작성
    • 가중치 절편 초기화
  2. 정방향 계산 만들기
    • 정방향 계산을 구한다고 하면 y^을 구한다고 이해하면 된다.
    • 단순한 수식이니 꼭 기억하자 :: y^ = w*x + b
  1. 역방향 계산 만들기
    • 정방향 계산을 통해 얻어낸 y^과 y의 차이, 즉 오차가 다시 가중치와 절편을 업데이트 하는데 사용되는 모습을 본떠서 역방향 계산이라고 부른다.
    • 즉 오차가 역전파(backpropagation)되는 것이다.
  1. 훈련을 위한 fit() 메서드 구현하기
  1. 모델 훈련하기
  1. 학습이 완료된 모델의 가중치와 절편 확인하기

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  # 가중치에 대한 Gradient를 계산
        b_grad = 1 * err  # 절편에 대한 Gradient를 계산
        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   
from sklearn.datasets import load_diabetes
import matplotlib.pyplot as plt

diabetes = load_diabetes()
x = diabetes.data[:,2]
y = diabetes.target # 배열 슬라이싱 샘플 0 1 2 뽑아내기

print(x.shape, y.shape)
(442,) (442,)

neuron = Neuron()
neuron.fit(x,y)


plt.scatter( x, y  )
pt1 = (-0.1, -0.1 * neuron.w + neuron.b )
pt2 = (0.15,  0.15 * neuron.w + neuron.b )
plt.plot( [ pt1[0],pt2[0] ],[ pt1[1],pt2[1] ] )
plt.xlabel('x')
plt.ylabel('y')
plt.show()
        

0개의 댓글