본문 바로가기
딥러닝관련/기초 이론

신경망 정리 3 (신경망 학습, MSE, Cross entropy loss ....)

by 머리올리자 2021. 5. 12.

학습

훈련 데이터로부터 가중치 매개변수의 최적값을 자동으로 획득하는 것

 

신경망이 학습할 수 있도록 해주는 지표 : 손실 함수

 

이 손실 함수의 결괏값을 가장 작게 만드는 가중치 매개변수를 찾는 것이 학습의 목표

 

데이터에서 학습한다

신경망의 특징 : 데이터를 보고 학습을 할 수 있다는 점

 

학습 → 가중치 매개변수의 값을 데이터를 보고 자동을 결정한다.

 

학습이 필요한 이유..

 

퍼셉트론을 생각해보자.

 

사람이 수작업으로 매개변수의 값을 설정했어야 했다.

 

만약 이 매개변수가 많아 진다면....

 

사람이 일일히 수작업으로 할 수 없다.

 

데이터 주도 학습

기계학습은 데이터가 생명.

 

기계학습에서는 사람의 개입을 최소화하고 수집한 데이터로부터 패턴을 찾으려 시도.

 

만약 숫자 5를 인식하는 프로그램을 구현한다고 가정

 

막상 구현하려 하면 의외로 어려운 작업임을 알 수 있다.

 

사람이라면 어렵지 않게 인식하지만, 그 안에 숨긴 규칙성을 명확한 로직으로 풀기가 만만치 않음

 

사람마다 버릇이 달라 5를 특정짓는 규칙을 찾기도 쉽지 않고 시간도 오래 걸린다.

 

이쯤 되면 0부터 100까지 설계하는 대신 주어진 데이터를 잘 활용해서 해결하고 싶어짐.

 

그런 방법의 하나로 이미지에서 특징(feature)을 추출하고 그 특징의 패턴을 기계학습 기술로 학습하는 방법이 있음 

 

특징 : 입력 데이터 (입력 이미지)에서 본질적인 데이터 (중요한 데이터)를 정확하게 추출할 수 있도록 설계된 변환기

 

즉, 모아진 데이터로부터 규칙을 찾아내는 역할을 '기계'가 담당.

 

이는 알고리즘을 처음부터 설계하는 것보다 효율이 높아 문제를 해결해야 하는 사람의 부담도 덜어준다.

 

다만, 이미지를 벡터로 변환할 때 사용하는 특징을 여전히 '사람'이 설계하는 것임에 주의

 

즉, 문제에 적합한 특징을 쓰지 않으면 좀처럼 좋은 결과를 얻을 수 없다.

 

 

1. 사람이 생각한 알고리즘 → 결과

 

2. 사람이 생각한 특징(SIFT, HOG 등)  → 기계학습(SVM, KNN 등)   결과

 

3. 신경망(딥러닝)  결과

 

딥러닝을 end-to-end machine learning이라고도 함.

 

Training data와 Testing data

기계학습 문제 : training data와 testing data로 나눠 학습과 실험을 수행하는 것이 일반적

 

training data만 사용하여 학습하면서 최적의 매개변수를 찾는다.

 

그런 다음 testing data를 사용하여 앞서 훈련된 모델의 성능을 평가

 

그러면 왜 나눌까?

 

범용적으로 사용할 수 있는 모델을 원하기 때문에

 

한 데이터셋에서만 지나치게 최적화된 상태 오버피팅

 

손실함수

신경망 학습에서는 현재의 상태를 하나의 지표로 표현

 

그 지표를 가장 좋게 만들어주는 가중치 매개변수의 값을 탐색하는 것.

 

신경망 학습에서 사용하는 지표 : 손실 함수

 

 

평균 제곱 오차(mean square error, MSE)

 

출처 : https://en.wikipedia.org/wiki/Mean_squared_error

Yi는 정답 레이블

Yi^hat은 신경망의 출력으로 볼 수 있다.

i는 데이터의 개수

 

MNIST를 인식하는 예시를 들어보자

 

y_hat = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
y = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]

y_hat은 소프트맥스 함수의 출력 (0일 확률 0.1, 1일 확률 0.05...)

 

정답 레이블인 y의 정답의 위치는 1이 있는 곳이므로, 그 외에는 0으로 표현

 

따라서 정답은 2로 볼 수 있다.

 

위의 y와 같이 한 원소만 1로 하고 그 외는 0으로 나타내는 표기법을 원-핫 인코딩.

 

각 원소의 출력과 정답 레이블의 차를 제곱한 후 그 총합을 계산.

 

import numpy as np

def mean_squared_error(y, y_hat):
    return 0.5 * np.sum((y-y_hat) ** 2)

y = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0] # 정답 2


y_hat = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0] # 2일 확률이 높음
print(mean_squared_error(np.array(y), np.array(y_hat)))


y_hat = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0] # 7일 확률이 높음
print(mean_squared_error(np.array(y), np.array(y_hat)))

결과

0.09750000000000003
0.5975

 

신경망의 출력이 정답 레이블과 가까울 때 손실이 줄어든 것을 확인할 수 있다. 

 

교차 엔트로피 오차(cross entropy loss, CEE)

- log는 밑이 e인 자연로그

- y_k : 신경망의 출력

- t_k : 정답 레이블

- t_k : 정답에 해당하는 인덱스의 원소만 1이고 나머지는 0인 원-핫 인코딩

- Cross Entropy Loss는 정답일 때의 추정 (t_k가 1일 때의 y_k)의 자연로그를 계산하는 식

 

ex)

정답 레이블은 '2'가 정답이라고 하고, 신경망의 출력이 0.6이면 cross entropy loss는 -log0.6 = 0.51

정답 레이블은 '2'가 정답이라고 하고, 신경망의 출력이 0.1이면 cross entropy loss는 -log0.1 = 2.30

 

cross entropy loss는 정답일 때의 출력이 전체 값을 정하게 된다.

 

자연로그의 그래프

위 그래프를 보면

x가 1에 가까워질수록 y의 값은 0에 가까워지고

x가 0에 가까워질수록 y의 값은 점점 작아진다.

 

Cross entropy loss 구현

import numpy as np

def cross_entropy_loss(y, t):
    delta = 1e-7
    return -np.sum(t * np.log(y+delta))


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]

print(cross_entropy_loss(np.array(y), np.array(t)))

y = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
print(cross_entropy_loss(np.array(y), np.array(t)))

 

출력

0.510825457099338
2.302584092994546

 

작은 값 delta를 추가하는 이유.

 

np.log 함수에 0을 입력하면 마이너스 무한대를 뜻하는 -inf가 되어 더 이상 계산을 진행할 수 없게 되기 때문.

 

아주 작은 값을 더해서 절대 0이 되지 않도록, 마이너스 무한대가 발생하지 않도록 한 것.

 

미니 배치를 활용한 교차 엔트로피 오차(cross entropy loss, CEE)

 

 

데이터가 N개라면

t_nk : n번째 데이터의 k차원 때의 값, 정답 레이블

y_nk : 신경망의 출력

 

한 개의 데이터를 이용했던 cross entropy loss에서 N개의 데이터로 확장한 것.

 

다만 마지막에 N을 나누어 정규화하고 있음

 

즉, N으로 나눔으로써 '평균 손실 함수'를 구하는 것임.

 

평균을 구해 사용하면 훈련 데이터 개수와 관계없이 언제든 통일된 지표를 얻을 수 있다.

 

ex) 훈련 데이터가 1,000개든 10,000개든 평균 손실 함수를 구할 수 있음.

 

미니 배치의 사용

 

MNIST의 훈련 데이터는 60,000개

 

모든 데이터를 대상으로 손실 함수의 합을 구하려면 시간이 걸림.

 

더 나아가 빅데이터 수준이 되면 그 수는 엄청나게 늘어남.

 

이 많은 데이터를 대상으로 일일이 손실함수를 계산하는 것은 현실적이지 않는다.

 

이런 경우, 데이터 일부를 추려 전체의 '근사치'로 이용할 수 있음

 

이 일부를 미니배치(mini-batch) 라고 함.

 

ex) 60,000장의 훈련 데이터 중에서 100장을 무작위로 뽑아서 그 100장을 이용하여 학습한다고하면 이를 미니배치 학습.

 

 

미니 배치를 이용한 cross entropy loss 구현

 

import sys
import os

import numpy as np
from dataset.mnist import load_mnist

(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)

print(x_train.shape)
print(t_train.shape)

# 훈련 데이터에서 무작위로 10장을 빼내기

train_size = x_train.shape[0]
batch_size = 10
batch_mask = np.random.choice(train_size, batch_size) # 지정한 범위의 수 중에서 무작위로 원하는 개수만 꺼낼 수 있음

print(batch_mask)

def cross_entropy_error(y, t):
    if y.ndim == 1: # y가 1차원이라면 데이터 하나당 cross entropy loss를 구하는 경우는 reshape 함수로 데이터 형상을 바꾼다.
        t = t.reshape(1, t.size) # 정답 레이블
        y = y.reshape(1, y.size) # 신경망 출력

    batch_size = y.shape[0]
    
    # one hot encoding 일 때 
    # return -np.sum(t*np.log(y)) / batch_size

    # one hot encoding 이 아닐 때 -> 숫자 레이블(2, 7...)로 주어졌을 때 
    return -np.sum(np.log(y[np.arange(batch_size), t])) / batch_size

 

구현의 핵심

 

원-핫 인코딩일 때 t가 0인 원소는 cross entorpy loss의 오차도 0이므로 그 계산은 무시해도 좋다는 의미.

 

즉, 정답에 해당하는 신경망의 출력만으로 cross entropy loss를 계산할 수 있다.

 

따라서 원-핫 인코딩 시 t * np.log(y) 였던 부분을 레이블 표현일 때는 np.log(y[np.arange(batch_size), t]로 구현.

 

 

 

내용 참고

book.naver.com/bookdb/book_detail.nhn?bid=11492334

 

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

직접 구현하고 움직여보며 익히는 가장 쉬운 딥러닝 입문서!『밑바닥부터 시작하는 딥러닝』은 라이브러리나 프레임워크에 의존하지 않고, 딥러닝의 핵심을 ‘밑바닥부터’ 직접 만들어보며

book.naver.com