학습이란?

학습이란 훈련 데이터로부터 가중치 매개변수의 최적값을 자동으로 획득하는 것을 뜻한다. 신경망이 학습할 수 있도록 해주는 지표로 손실 함수가 있는데, 이 손실 함수의 결과값을 가장 작게 만드는 가중치 매개변수를 찾는 것이 학습의 목표이다.

신경망의 특징은 데이터를 보고 학습한다는 것, 즉 가중치 매개변수의 값을 데이터를 보고 자동으로 결정한다는 것이다. 매개변수가 수천개 수만개이기 때문에 사람이 수작업으로 정한다는 것은 말이 안된다. 즉 기계가 이 매개변수를 자동으로 찾아줘야 한다.


데이터 주도 학습

기계학습에서는 데이터가 생명이다. 사람이 어떠한 패턴을 찾아낼 때는, 경험과 직관을 단서로 시행착오를 통해 진행한다. 하지만 기계학습은 사람의 개입을 최소화하고 데이터로부터 패턴을 찾으려 시도하는 특성을 갖고 있다.

위의 손글씨 사진을 보고 '5'를 분류하는 알고리즘을 생각해보자. 보통 사람이라면 어렵지 않게 인식하지만, 좀 더 글씨체가 다양해진다면 사람마다 글 쓰는 버릇이 달라 '5'를 특징짓는 규칙을 찾기 힘들다. 이러한 해결방법으로 이미지에서 특징을 추출하고 특징(feature)의 패턴을 기계학습 기술로 학습하는 방법이 존재한다. 예시로 이미지의 데이터를 벡터로 변환하고, 변환된 값을 가지고 지도 학습의 대표 분류 기법인 SVM, KNN 등을 활용할 수 있다.

이렇게 기계학습은 데이터로부터 규칙을 찾아내는 효율이 매우 높다. 하지만 이미지를 벡터로 변환할 때 사용하는 특징은 여전히 '사람'이 설계해야 하는 것에 주의해야 한다.

앞서 말한 내용들을 정리하면 바로 위 그림과 같다. 정리하자면 신경망은 이미지에 포함된 중요한 특징까지도 '기계'가 스스로 학습한다는 것이다.

훈련 데이터와 시험 데이터

 신경망 학습 설명에 앞서, 기계학습에서 데이터를 취급할 때 주의할 점이 있다. 기계학습 문제는 보통 데이터를 훈련 데이터(training data)시험 데이터(test data)로 나눈다. 왜 이렇게 데이터를 나눠야 할까? 답은 바로 모델의 범용 능력때문이다. 범용 능력의 뜻은 아직 보지 못한 데이터로도 문제를 올바르게 풀어내는 능력이다. 마치 모의고사만 풀다가 수능 문제에 내가 공부한 개념들을 적용시키는 것을 연상할 수 있다.

 하지만 앞의 예시로 공부를 함에 앞서 문제집의 기출문제만 똑같이 계속 푼다면 새로운 문제에 응용할 수 없다. 이처럼 정해져 있는 데이터셋에만 과도하게 최적화된 상태를 오버피팅(overfitting)이라고 하는데, 이 오버피팅을 피하는 것이 기계학습의 중요한 과제이다.


손실 함수

"사람들에게 지금 얼마나 행복하나요?"라고 물으면 보통 "아주 행복해요" 혹은 "전 행복하지 않아요"라고 말한다. 하지만 놀랍게도 "제 행복 지수는 10.23입니다"라고 대답한다면 질문한 사람은 당황하기 마련이다. 이처럼 신경망 학습에서도 현재의 상태를 지표로 나타내는 것이 바로 손실 함수(cost function)이다. 이 손실 함수는 일반적으로 오차제곱합과 교차 엔트로피 오차라는 것을 사용한다.

 

오차제곱합

가장 많이 쓰이는 손실 함수로 오차제곱합(sum of squares for error, SSE)이라는 것이 있다. 수식은 위 그림과 같고, yk는 신경망의 출력, tk는 정답 레이블, k는 데이터의 차원 수를 나타낸다. 전에 배우는 손글씨 숫자 인식 예에서 yk와 tk는 다음과 같은 원소 10개짜리 데이터이다.

이 배열들의 원소는 첫 번째 인덱스부터 순서대로 숫자 0,1,2,3,4,....일 때의 값이다. 여기에서 출력 y는 소프트맥스 함수의 출력인데 소프트맥스는 확률로 해석할 수 있으므로, 이미지가 0일 확률은 0.1, 1일 확률은 0.05라고 해석할 수 있다. 정답 레이블인 t는 정답을 가리키는 위치의 원소로 1을, 그 외에는 0을 표기한다. 여기에서는 숫자 2에 해당하는 원소의 값이 1이므로 정답이 2임을 알 수 있다. 이처럼 한 원소만 1로, 그 외에는 0으로 나타내는 표기범을 원-핫 인코딩이라고 한다.

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

오차제곱합을 파이썬으로 구현해보면 위와 같이 원소의 출력(추정 값)과 정답 레이블(참 값)의 차이를 제곱한 후, 그 총합으로 나타낼 수 있다.

결과를 해석하는 법을 예시로 살펴보자. 첫 번째 예시는 2일 확률이 0.6으로 가장 높고, 두 번째 예시는 7일 확률이 0.6으로 가장 높은 예시이다. 두 예시 다 정답은 2일 때이지만 첫 번쨰 예시 손실 함수가 더 작기 때문에 정답에 더 가깝다고 해석할 수 있다.


교차 엔트로피 오차

또 다른 손실 함수로는 교차 엔트로피 오차(cross entropy error, CEE)가 잇다. 수식은 위와 같고 정답일 때의 추정(tk가 1일 때의 yk)의 자연로그를 계산하는 식이 된다. 예를 들어 정답 레이블이 2이고, 이 때의 신경망 출력이 0.6이라면 교차 엔트로피 오차는 -log0.6 = 0.51이 된다. 또한 같은 조건에서 신경망 출력이 0.1일면 -log0.1 = 2.30이 된다. 즉 교차 엔트로피 오차는 정답일 때의 출력이 전체 값을 정하게 된다.

위 그림에서 보듯이 x가 1일 때 y는 0이 되고, x가 0에 가까워질수도 y의 값은 점점 작아집니다. 다시 말해 정답에 가까울수록 CEE값은 0에 가까워진다고 볼 수 있다.

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

python으로 구현하면 위 코드와 같고 delta를 더한 이유는 가로 안 값이 0이 되지 않도록 아주 작은 값을 더한다.

다시 교차 엔트로피 오차를 해석하는 방법은 정답이 똑같이 2이면 예시 1은 출력이 0.6, 예시 2는 출력이 0.1이다. 두 예시의 교차 엔트로피 오차는 각각 0.51, 2.3이고 결과가 더 작은 첫 번째 추정이 정답일 가능성이 높다고 해석할 수 있다.


미니배치 학습

지금까지 데이터 하나에 대한 손실 함수를 구했으나 이는 매우 비효율적이니, 훈련 데이터 모두에 대한 손실 함수의 합을 구하는 방법을 알아보도록 하자. 

일단 교차엔트로피 오차를 예시로 수식을 알아보자면 데이터가 N개일때 위와 같이 확장할 수 있다. 수식이 복잡해 보이지만 데이터 하나에 대한 손실 함수를 단순히 N개로 확장했을 뿐이고, 마지막에 N으로 나누어 정규화하면서 평균 손실 함수를 구한다. 이렇게 평균을 구해 사용하면 훈련 데이터가 1000개든 10000개든 상관없이 통일된 지표(평균 손실 함수)를 얻을 수 있다.

하지만 1000개도, 10000개도 아닌 몇만개 몇십만개의 데이터를 대상으로 지표를 구하려면 매우 많은 시간이 걸린다. 이렇게 많은 데이터 중 일부를 추려 학습을 수행하는 것을 미니배치(mini-batch)라고 하며, 이러한 학습 방법은 미니배치 학습이라고 한다.

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) = \
	loat_mnist(normalize=True, one_hot_label=True)
   
print(x_train.shape) # (60000, 784)
print(t_train.shape) # (60000, 10)

미니배치 학습을 통해 MNIST 데이터 셋을 읽어오는 코드를 알아보도록 하자. 일단 위와 같은 코드로 데이터를 불러오면 훈련 데이터는 60000개, 입력 데이터는 784, 정답 레이블은 10줄짜리 데이터이다.

train_size = x_train.shape[0]
batch_size = 10
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]

훈련 데이터에서 무작위로 10장만 뽑으려면 위와 같이 batch_size와 np.random.choice를 활용하면 된다.


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

이쯤되면 학습의 지표로 '정확도'를 사용할 수도 있지 않은가?라고 의문을 가질 수 있다. 왜 '정확도'라는 지표를 놔두고 '손실 함수의 값'이라는 방법을 택하는 것일까?

이 의문은 미분의 역할에 주목하면 해결된다. 맨 위에서 말했던 것처럼 신경망 학습에서는 최적의 매개변수를 탐색할 때 손실 함수의 값을 가능한 한 작게하는 매개변수 값을 찾는다. 이 때 매개변수의 미분(기울기)을 계산하고, 그 미분 값을 단서로 매개변수의 값을 서서히 갱신하는 과정을 반복하는 것이다.

가중치 매개변수의 손실함수 미분을 예시로 들자면 '가중치 매개변수의 값을 아주 조금 변화 시켰을 때, 손실 함수가 어떻게 변하나'라는 의미이다. 미분 값이 음수면 가중치 매개변수를 양의 방향으로 변화시켜 손실 함수를 줄일 수 있고, 양수면 음의 방향으로 변화시켜 줄일 수 있다. 미분 값이 0이면 매개변수를 어느 쪽으로 움직여도 손실 함수의 값은 줄어들지 않고, 가중치 매개변수 갱신은 거기서 멈춘다.

다시 정리하자면 정확도를 지표로 삼아서는 안 되는 이유는 미분 값이 대부분의 장소에서 0이 되어 매개변수를 갱신할 수 없기 때문이다.

 

정확도를 지표로 삼으면 매개변수의 미분이 대부분 0이되는 이유는?

구체적인 예를 들어, 한 신경망이 100장의 훈련 데이터 중 32장을 올바르게 인삭한다고 하자. 이 때 정확도는 32%이고, 정확도가 지표였다면 가중치 매개변수의 값을 바꾼다 해도 정확도는 그대로 32%이다. 즉 정확도는 개선되지 않고 일정하게 유지되고, 바뀐다 해도 32.01%와 같은 연속적인 변화보다는 33%, 34%처럼 불연속적인 값으로 바뀌어버린다.

반면 손실 함수를 지표로 삼았다면 0.92543 같은 수치로 나타난다. 매개변수의 값이 조금만 변해도 0.93432처럼 연속적으로 변화한다는 것이다.

정확도는 매개변수의 변화에도 반응을 보이지 않고, 반응이 있더라도 그 값이 불연속적으로 변화한다. 이는 '계단 함수'를 활성화 함수로 사용하지 않는 이유와도 같다. 계단 함수의 미분은 대부분의 장소에서 0이기 때문에 손실 함수를 지표로 삼는 것이 아무 의미가 없고, 반면 시그모이드 함수는 곡선의 기울기가 연속적으로 변화하기 때문에 미분 값이 어느 장소라도 0이 되지 않는다. 이처럼 기울기가 0이 되지 않는 것은 신경망이 올바르게 학습할 수 있다는 것이고 중요한 성질이다.

728x90
반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 라이프코리아트위터 공유하기
  • shared
  • 카카오스토리 공유하기