데이터 한 그릇

신경망 학습 본문

딥러닝/밑바닥부터 시작하는 딥러닝

신경망 학습

장사이언스 2022. 1. 7. 17:12

데이터에서 학습하는 신경망

여기서 말하는 `학습` : 가중치의 최적값을 자동으로 찾는 것

손실함수를 통해서 최적의 가중치 값을 찾는다.

손실함수의 값을 가급적 작게 만드는 기법으로 함수의 기울기를 활용하는 경사법 소개.

 


 

  1. 처음부터 데이터가 없이, 알고리즘을 무(無)에서 개발.
  2. 머신러닝을 통해서 개발
    • 이미지에서 특징 추출
    • 특징의 패턴을 기계학습으로 학습
    • 이미지 데이터를 벡터로 변환 -> 벡터를 이용해서 svm,knn 가용 가능.
      • 하지만 문제에 따라서 그 특징을 다르게 찾아야 한다. 숫자와 강아지 사진의 경우 다른 특징을 생각해야 한다.
    • 결국 기계학습도 사람의 개입이 들어간다.
  3. 신경망(딥러닝)
    • 이미지를 있는 그대로 학습한다.
    • 머신러닝에서는 특징을 사람이 설계했지만, 신경망은 이미지에 포함된 중요한 특징까지도 기계가 스스로 학습.
    • 이러한 의미로 딥러닝을 `종단간 기계학습` 이라고 부름, 처음부터 끝까지 라는 의미

훈련 데이터와 시험 데이터

훈련데이터와 테스트 데이터로 나뉨

과적합 피하기 위함.

모두의 딥러닝이나 파이썬 머신러닝 완벽 가이드 기록에 그 이유가 있음

 


손실 함수

신경망은 하나의 `척도` 를 가지고 최고의 매개변수를 탐구한다.

그 척도는 바로 손실 함수(loss function) 이다.

 

오차제곱합(Mean Squared Error)

손실 함수의 종류도 여러 개인데, 그 중에 가장 많이 쓰이는 함수는 오차제곱합.

(모두의 딥러닝 참고)

 

교차 엔트로피 오차

 

또 다른 손실함수로 교차 엔트로피 오차가 존재한다. (cross entropy error)

 

식은 다음과 같다.

 

-시그마(tk * loge^yk)

(수식 찾기 프로그램 쓰기 귀찮다 ㅈㅅ)

 

여기서 tk는 실제 정답값을 의미하고 yk 는 예측값을 의미한다.

k는 데이터의 차원 수를 의미한다.

즉, tk는 정답벡터(10개) 중에서 k번째 값을 의미한다. yk는 예측벡터(10개) 값들 중에서 k번째 값을 의미한다.

이때 정답값은 원핫 코딩으로 이루어져 있기에 값이 1이다. 정답이 아닌 값이 k = 2라고 한다면, t2 = 0이다

 

따라서 교차 엔트로피 오차 함수는 정답일때의 출력이 전체 값을 정하게 된다.

(출력은 정답만으로 이루어져 있다. (원핫 인코딩 때문에 정답이 아니면 0이기 때문에))

 

다시 설명하면 예를 들어서

밑에와 같이

t = [0,0,1,0,0,0,0,0,0,0]

y = [0.1,0.05,0.6,0.0,0.05,0.1,0.0,0.1,0.0,0.0]

이렇게 있을 때 정답을 기준으로 교차 엔트로피 오차 함수에 변수를 대입한다.

위는 인덱스 2가 정답이므로 예측값에서 인덱스 2를 찾는다.

그럼 `-시그마log0.6` 이 오차 값이다. 이 경우는 0.51이다.

그럼 반대로 신경망이 오판을 했을 때의 오차를 보자.

y = [0.1,0.05,0.1,0.0,0.05,0.1,0.0,0.6,0.0,0.0] 이라고 신경망이 예측했으면,

식은 `-시그마log0.1` 이 된다. 이 경우는 2.3이다.

 

로그 함수의 형태를 보면 x가 0에 가까워질수록 y는 작아지고 x가 1에 가까워질수록 y는 0이된다.

교차 엔트로피도 마찬가지로, 정답에 해당하는 출력이 커질수록 0에 다가가고 출력이 작아질수록 오차는 커진다.

 


미니배치 학습

위의 과정(교차 엔트로피 오차)은 데이터 하나에 대한 오차를 구하는 식이다.

MSE도 그렇고 교차 엔트로피 오차도 그렇고 우리가 구하려고 하는 것은 전체 데이터에 대한 오차값이다.(손실함수값)

MSE 같은 경우 예측값과 실제값의 차이를 제곱하는 과정을 모든 데이터에 거쳐서 합하고 데이터의 개수로 나눈다.

교차 엔트로피 오차도 마찬가지다. 위의 교차 엔트로피 오차 식을 N개로 확장하고 (시그마로), 데이터 개수 N개로 나누어 평균 손실 함수 값을 구한다.

그런데 MNIST 훈련 데이터는 60,000건의 데이터를 가지고 있다. 그 이외에도 다양한 빅데이터 데이터들은 몇 만건에서 많으면 수십만건의 데이터를 가지고 있다.

따라서 모든 데이터들의 손실 함수 값을 구하는 건 굉장히 오랜 시간이 걸릴 수 있다.

따라서 표본 데이터들을 뽑아서 그 안에서 평균 손실 함수 값을 구하여 그 값을 모집단의 근삿값으로 측정한다.

그러면 계산 시간이 많이 줄어들 것이다.

이 일부 데이터를 `미니배치` 라고 한다.

그리고 이러한 학습을 `미니배치 학습` 이라고 한다.

 


왜 손실 함수를 설정하는가?

 

모두의 딥러닝에서 살펴봤듯이 우리는 최적의 매개변수를 탐색할 때, 손실 함수를 사용한다.

즉 어떤 매개변수의 값이 손실 함수의 값을 최소화 할지 탐색한다.

이 탐색 과정에서 매개변수의 값을 미분하게 된다.(미분값찾기), 이 미분값을 단서로 최적의 매개변수 값을 추적한다.

 

여기서 매개변수 값을 미분한다는 것은 어떤 뜻이냐?

**가중치 매개변수의 값을 아주 조금 바꿨을 때, 손실 함수가 어떻게 변하나라는 의미.**

예를 들어서 어떤 매개변수 가중치 ax의 a에 집중한다고 해보자. ax를 미분하여 최적의 매개변수 가중치 단서를 찾으려고 한다. 이때 미분값이 도출이 될텐데 이 미분값의 의미는 가중치 매개변수 a의 값을 미세하게 조금 바꿨을 때, 손실 함수가 어떻게 변하나라는 의미다.

만일 미분값이 음수가 도출이 되면 가중치 매개변수를 양의 방향으로 바꿔가고 만일 양수가 도출이 되면 가중치 매개변수를 음의 방향으로 바꿔가서 최적의 가중치 매개변수 값을 도출한다. (미분값이 0에 가깝게)

 

**정확도(Accuracy) 를 지표로 삼지 않는 이유**는, 정확도를 지표로 삼으면 미분을 했을 때 대부분의 장소에서 미분값이 0이 도출되기 때문이다.

만일 100장의 사진 중에 32장의 사진을 맞췄다고 가정한다면 정확도는 32%이다.

이때 가중치 매개변수의 값을 미세하게 조정한다면 정확도 지표는 그대로 32%일 것이다.

즉 매개변수를 약간만 조정해서는 정확도 지표가 개선되지 않고 일정하게 유지된다.

하물며 개선이 된다고 하더라도 연속된 수치로 변화(실수단위로) 하는 게 아니라 불연속적으로 변화할 것이다.(int 단위로 띄엄띄엄)

 

하지만 손실 함수값을 기준으로 삼는다면 연속된 수치로 값이 변화한다.

이러한 이유는 활성화 함수로 `계단 함수` 를 사용하지 않는 이유와 유사하다.

계단 함수의 미분은 대부분의 장소에서 0이다. 그렇게 되면 손실 함수를 이용하는 이유가 없어진다.

왜냐하면 가중치 매개변수의 작은 변화가 주는 파장을 계단 함수가 말살하여 손실 함수의 값에는 아무런 변화가 없기 때문이다.

 

계단 함수는 한순간만 변화를 일으키지만, 시그모이드는 그 모양의 매끈함 덕에 미분을 했을 때 연속적으로 바뀐다. 즉 어느 장소라도 0이 아니다.

 


수치 미분

미분

내가 10분에 2km 달렸을 때, 평균 속도는 2/10 = 0.2km, 즉 1분에 0.2km 평균 속도를 가졌음을 의미한다.

하지만, 이는 평균적인 속도를 의미하는데, 순간적인 속도를 구하고 싶다면 미분을 해야만 한다.

즉, 직전 1분데 달린 거리, 직전 1초에 달린 거리, 직전 0.1초에 달린 거리를 구하고 싶다면 미분을 해야만 한다.

이렇게 한 순간의 변화량(거리) 을 구하는 것. 평균적인 변화량(거리)이 아니라.

미분 식은 다음가 같다.

df(x)/dx = lim(f(x + h) - f(x) / h ), (h -> 0)

이 식대로 그대로 구현하려고 하면 문제가 발생한다.

 

**수치미분의 문제점**

h를 무한히 0에 가깝게 하기 때문에 임의로 엄청 작은 값을 대입을 하면 컴퓨터가 계산하지 못하고 `반올림 오차` 를일으킨다. 예를 들어서 1e-50 으로 h를 설정했다면 컴퓨터가 float 으로 인식해서 출력을 하면 0.0으로 출력한다.

개선법은 사람들이 h의 적당한 값을 정해놓은 것. 10^-4 로 지정하면 된다.

또한 다른 문제가 존재하는데, 저 식은 진정한 미분 값이 아니라 x+h 와 x 사이의 기울기를 뜻한다. 즉, x일 때의 순간 기울기 값이 아니다. 이는 h를 무한대로 0으로 가깝게 할 수 없는 문제 때문에 발생한 문제다.

따라서 f(x+h) - f(x) 는 진정한 미분 값과 오차가 있을 수 밖에 없다.

이 오차를 줄이기 위해서 f(x-h) - f(x+h) 를 하는 경우가 있는데 이 때를 `중심 차분 ` , `중앙 차분` 이라고 한다.

 

#식 만들기

#y = 0.01x^2 =  0.1x

def function_1(x):
    return 0.01 * x **2 + 0.1 * x

import numpy as np
import matplotlib.pyplot as plt

x = np.arange(0.0,20.0,1)
y = function_1(x)

plt.plot(x,y)
plt.xlabel("x")
plt.ylabel("y")
plt.show()

#개선한 미분 값
#x가 5일 때와 10일 때의 순간변화율, 미분값

def numerical_diff(f,x):
    h = 1e-4
    return (f(x+h) - f(x-h)) / (2*h)

print(numerical_diff(function_1, 5))
print(numerical_diff(function_1,10))

 


편미분

변수가 두 개인 식의 미분할 때 사용

 

#변수 두 개의 식 만들기

def function_2(x):
    return x[0]**2 + x[1]**2

 

변수가 두 개이면, 어떤 변수에 대한 미분인지를 결정해야 한다.

af/ax_0 (a가 알파벳 a가 아니라 다른 기호 있는데 못찾겠음 ㅠ) : x_0 에 대해서 미분.

af/ax_1 : x_1 에 대해서 미분

기울기

만일 편미분을 식의 모든 변수에 대해서 한 번에 진행하려고 하면, 기울기가 나온다.

 

def numerical_gradient(f,x):
    h = 1e-4
    grad = np.zeros_like(x)
    
    for idx in range(x.size):
        tmp_val = x[idx]
        
        x[idx] = tmp_val + h
        fxh1 = f(x)
        
        x[idx] = tmp_val - h
        fxh2 = f(x)
        
        grad[idx] = (fxh1 - fxh2) / (2*h)
        x[idx] = tmp_val
    return grad

 

경사하강법

def gradient_descent(f, init_x, lr = 0.01, step_num = 100):
    x = init_x
    
    for i in range(step_num):
        grad = numerical_gradient(f,x)
        
        x-= lr * grad
    return x

def function_2(x):
    return x[0] ** 2 + x[1] ** 2

init_x = np.array([-3.0,4.0])
gradient_descent(function_2, init_x = init_x, lr = 0.1, step_num = 100)

 

 

학습률을 잘 설정 하니까 점점 기울기가 0에 가까워 지는 걸 볼 수 있음.

신경망에서의 기울기

신경망 학습에서도 기울기를 구해야 하는데,

여기서 말하는 기울기는 가중치 매개변수에 대한 손실 함수의 기울기.

'딥러닝 > 밑바닥부터 시작하는 딥러닝' 카테고리의 다른 글

합성곱 신경망(CNN)  (0) 2022.01.09
학습 관련 기술들  (0) 2022.01.08
오차역전파  (0) 2022.01.07
신경망  (0) 2022.01.07
퍼셉트론  (0) 2022.01.07
Comments