본문 바로가기
Deep Learning/밑바닥부터 시작하는 딥러닝

손실 함수

by 대소기 2022. 1. 25.

데이터를 통한 학습

기계학습 방식과 신경망 방식

* 기계학습은 데이터에서 특징을 추출해 특징의 패턴을 학습하는 방식으로 이뤄진다.

* 이 때 두가지 방법이 있다.

1) 사람이 직접 알고리즘 구성

2) 사람은 특징 추출에만 개입하고, 기계가 특징에서 패턴을 찾아 학습하기

- ex) 컴퓨터비전 분야에서 SIFT, HOG 등의 방식을 통해 이미지의 특징을 인간이 추출하면 기계는 SVM, KNN등을 통해 특징에서 패턴을 찾는다.

* 신경망 방식은 기계학습의 두 가지 방식과는 달리, 모든 과정을 기계가 자동으로 진행한다. 특징을 추출하는 것과 특징에서 패턴을 찾아 학습하는 것 모두 스스로 학습하는 것이다.

Training data와 Test data

* 기계학습의 데이터셋은 두가지 혹은 세가지로 분리되어야 한다. 두 가지의 경우 Training set, Test set이 될 것이고, 세 가지의 경우 Training set, Validation set, Test set이 될 것이다.

* 이렇게 데이터셋을 분리하는 이유는 학습이 잘 되었는지를 검증하기 위해서이다. 학습이 잘 되었다는 것의 판단 기준은 바로 모델의 범용성이다. 범용성이 좋지 않은 모델을 overfitting 되었다고 한다. 모델이 우리가 집어넣은 데이터셋의 일반적인 패턴을 학습하지 않고, 데이터셋만의 패턴을 학습하게 되는 것이다. 모델의 최종적인 목적은 overfitting 된 모델이 아닌 generalized 된 모델을 구성하는 것이 되어야 한다.

* 그래서 우리는 가지고 있는 데이터셋 중 일부를 학습 과정에서 제외시킨 후 검증 과정에서 제외되었던 데이터셋으로 범용성이 좋은 모델인지를 검증하게 된다.

손실함수(Loss Function)

* 손실함수는 모델의 성능을 나타내는 지표이다. 모델은 손실함수를 최소화 하는 방향으로 가중치를 갱신하게 된다.

* 보통 성능을 평가할 때는 '성능이 얼마나 좋은지'에 대해 나타내곤 한다. 하지만 기계학습에서 사용되는 손실함수는 '성능이 얼마나 나쁜지'에 대해 나타낸다. 이는 손실함수의 기본 아이디어인 '실제 값과 예측 값의 차이' 때문이다. 실제 값과 예측 값의 차이를 손실함수 값으로 나타내기 때문에 손실함수 값 만큼 성능이 나쁘다고 표현하게 된다. 계속 공부하고 이해하다 보면 외울 필요는 없는 내용이니 그렇구나 하고 넘어가자.

 

오차제곱합(SSE, Sum of Squares for Error)

$E = {1 \over 2} \sum\limits_{k} (y_k - t_k)^2$

 

* 오차 제곱합은 위 식을 통해 구할 수 있다. y는 모델을 통해 예측된 값이고, t는 정답 lable을 뜻한다. 예측값과 실제 값의 차이를 제곱해서 모두 더한 결과를 SSE라고 한다.

* 파이썬 코드로 구현하면 아래와 같다.

def sum_squares_error(y, t):
	return 0.5 * np.sum((y-t)**2)

 

교차 엔트로피 오차(Cross Entropy Error, CEE)

 

$E = \sum\limits_{k} t_k log y_k$

* 일단 cross entropy라고 부르는 경우를 더 많이 들은 것 같은데, 교차 엔트로피 오차라는 말도 자주 쓰이는지는 모르겠다. 본 포스팅에서는 cross entropy라고 부르겠다.

* 여기서도 y는 모델의 예측값, t는 정답 레이블을 뜻한다.

* cross entropy는 분류 문제에서 사용되는 loss function이기 때문에, 정답 레이블은 one-hot encoding 되어있다. 예를 들어 mnist에서 숫자를 분류하는 문제에서 정답 레이블 4의 경우 [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]과 같은 형태를 띤다고 할 수 있다. 이 이야기가 왜 중요하냐면 다음에 설명할 cross entropy의 출력에 대해 설명할 때 필요하기 때문이다.

* cross entropy의 식을 보면 $t_k$와 $log y_k$가 곱해진 값을 모두 더한다는 것을 알 수 있다. 이 때 $t_k$와 $y_k$ 모두 $t_k$는 one-hot encoding되어 있는 정답 레이블이고, y_k는 softmax 등을 사용해 레이블당 확률 값을 나타낸다. $t_k$에서 정답인 클래스 빼고는 모두 0이기 때문에 $y_k$와 곱해져도 0이 된다. 반면 정답 클래스의 경우 1이기 때문에 동일한 클래스의 log(예측 확률)과 곱해져도 0이 되지 않는데, 이 때문에 정답 클래스의 확률값의 log가 k번째 예측의 손실함수 값을 정의한다고 할 수 있다.

* 말로 길게 설명하다보니 이해가 되지 않을 수 있는데 아래 예시를 보자.

 

$t_k$ = [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]

$y_k$ = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0.6, 0.4]

$log(y_k)$ = [0, 0, 0, 0, 0, 0, 0, 0, 0, -0.51, -0.92]

 

$t_k * log(y_k)$ = [0, 0, 0, 0, 0, 0, 0, 0, 0, -0.51, 0]

 

* 위에서 정답 클래스에 해당하는 확률값이 손실함수 값을 결정한다는 것을 알았다. 위 그래프는 log x의 그래프이다. 그래프를 보면 x=1일 때 0이고 x가 0에 가까워질수록 y값이 작아지는 것을 확인할 수 있다. 정답 클래스에 해당하는 확률값이 1에 가까워질수록, 다시말해 정답 label을 100%에 가깝게 예측할 수록 값은 0에 가까워지는 것을 알 수 있다.

 

 

* 이제 cross entropy에 대해 배웠으니 python code로 구현해보자.

 

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

* y에 delta를 더해준 이유는 numpy에서 log 0 을 -inf(- 무한대)로 인식하기 때문이다.

 

 

미니배치(Mini Batch) 학습

 

* 지금까지는 데이터 하나에 대한 손실함수 계산만 살펴보았지만, 더 확장해서 데이터 전체에 대한 손실함수 값에 대해 살펴보자. 

 

데이터 전체에 대한 cross entropy

 

$ E = - {1 \over N} \sum \limits_{n} \sum \limits_{k} (t_{nk} log y_{nk})$

* 데이터 전체에 대한 cross entropy 를 구하는 식은 위와 같다. 앞서 데이터 하나를 대상으로 한 cross entropy와 크게 다를 것은 없다. 다만 모든 데이터의 손실을 더하기 때문에 N으로 나눠 정규화를 해준다는 점이 추가되었다.

 

Mini-Batch 학습

* 우리는 데이터 전체에 대한 손실 값들을 고려해야 한다. 그런데 만약 데이터 60000개 혹은 너무 양이 방대해서 60000000000개 있다고 해보자. 이 때 모든 손실을 계산하는것이 과연 효율적일까? 시간과 메모리를 엄청나게 소비하게 될 것이다. 

* 우리는 이러한 비효율을 방지하고자 mini-batch 방식을 사용한다. 통계학에서 표본의 수가 크다면 모집단의 특성을 대표하는 것으로 간주한다. 동일하게 전체 데이터를 모두 사용하지 않고, random하게 데이터를 뽑아 학습시키는 것을 mini-batch 학습이라고 한다.

* mini-batch 학습을 python 코드로 구현해보자.

import sys, os
sys.path.append(os.pardir)
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)   #(60000, 784)
print(t_train.shape)   #(60000, 10)

* mnist 모델을 로드하였다.

 

train_size = x_train.shape[0]   #60000
batch_size = 10
batch_mask = np.random.choice(train_size, batch_size)

x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]

* 60000개 중 random하게 추출한 10개의 표본을 하나의 batch로 구성하는 코드이다.

 

 

배치용 cross entropy 구하기

 

1) 데이터가 하나인 경우와 데이터가 여러개일 경우 모두 처리 가능한 함수

 

def cross_entropy_error(y, t):
	
    # 데이터가 1개라면(y의 차원이 1일 때)
    if y.ndim == 1: 
    	# t, y의 axis를 추가해줌.
        t = t.reshape(1, t.size) 
        y = y.reshape(1, y.size)
        
    batch_size = y.shape[0]
    return -np.sum(t * np.log(y + 1e-7)) / batch_size

 

2) 정답 레이블이 2, 7 등의 숫자로 주어져있을 때(one-hot encoding 되어있지 않을 때)

 

def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)  
        y = y.reshape(1, y.size)
        
    batch_size = y.shape[0]
    return -np.sum(np.log( y[np.arange(batch_size), t] + 1e-7 )) / batch_size

 

* 정답 class 에 해당하는 예측값(확률값) 만 사용하여 cross entropy를 계산하는 방식으로 구현되었다.

 

 

손실함수 설정 이유(매개변수를 지표로 사용하지 않는 이유)

 

* 훈련중 모델의 평가 지표로서 손실함수를 사용하는 이유가 과연 무엇일까? 우리는 정확도를 높이기 위해 모델을 훈련시킨다. 그렇다면 '정확도' (예를 들어 0.3, 0.9와 같은 ) 를 사용하면 되지 않을까? 결과 먼저 말하자면 정확도라는 지표는 사용할 수 없다. 이유를 살펴보자.

* 우리는 훈련 과정에서 미분을 통해 가중치, 편향을 갱신하게 된다(추후에 이에 대한 더 자세한 설명을 하겠다). 손실함수를 사용한다면, 미분을 통해 계산한 기울기는 가중치가 양의 방향 혹은 음의 방향으로 변할 때 손실 함수의 값이 어떻게 변화하는지를 나타낸다. 이를 통해 우리는 손실함수의 값이 감소하는 방향으로 가중치를 갱신하게 된다. 

* 하지만, 정확도를 지표로 사용하면 미분 값이 대부분의 장소에서 0이기 때문에 이러한 가중치 갱신을 할 수가 없게 된다.

 

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

Backpropagation  (0) 2022.01.27
경사하강법(Gradient Descent method)  (0) 2022.01.25
수치 미분  (0) 2022.01.25
신경망  (0) 2021.11.23
퍼셉트론  (0) 2021.11.17