728x90
반응형

이전 Deep Learning 포스팅

[Deep Learning] 1. 단층 퍼셉트론과 다층 퍼셉트론
[Deep Learning] 2. 신경망 (Sigmoid, ReLU)

[Deep Learning] 3. 출력층 (항등함수, 소프트맥스함수)



 

 

 

저번 포스팅에서는 출력층의 항등함수를 이용하여 회귀, 소프트맥스함수를 이용하여 분류하는 문제를 다루었다. 이번 포스팅에서는 신경망 학습 이라는 주제를 다룰 것이다.

 

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

 

 

 

1. 데이터를 통한 학습

 

신경망의 특징은 데이터를 보고 학습 할 수 있다는 점이다. 데이터에서 학습한다는 것은 가중치 매개변수의 값을 데이터를 보고 자동으로 결정한다는 뜻이다. 앞서 배웠던 퍼셉트론에서 진리표를 통해 수작업으로 매개변수 값을 설정하였는데, 이러한 매개변수 설정과정을 신경망을 통해서 처리 할 수 있다. 그러나 매개 변수 값 (가중치, 편향 값)은 실제 신경망에서 정하려면 수천, 수만개에 이른다. 이러한 많은 매개변수들을 사람이 직접 설정할수는 없으므로 신경망 학습을 통해 정할 수 있다.

 

기계학습(머신러닝)에서는 데이터가 생명이다. 데이터에서 답을 찾고 데이터에서 패턴을 발견하고 데이터로 이야기를 만드는 것이 기계학습이다. 데이터가 주어졌을 때 패턴을 찾으려는 시도를 하게 되는데, 패턴을 찾으려면 먼저 "특징"을 추출해야한다.

 

이 특징을 이미지로부터 추출하고 그 특징의 패턴을 기계학습 기술로 학습하는 방법이 있다. 여기서의 특징은 입력 데이터에서 본질적인 중요한 데이터를 정확하게 추출할 수 있도록 설계된 변환기를 뜻한다. 이미지의 특징은 보통 벡터로 표현하고, 컴퓨터 비전 분야에서는 SIFT, SURF, HOG 등의 특징을 사용한다. 이런 특징을 사용하여 이미지 데이터를 벡터로 변환하고, 변환된 벡터를 가지고 지도 학습 방식의 대표 분류법인 SVM, KNN 등으로 학습 할 수 있다.

 

이와 같이 머신러닝에서는 수집된 데이터를 통해 규칙을 찾아내는 역할을 "기계"가 담당하게 된다. 그러나 여기서 중요한 점은 이미지를 벡터로 변환할 때 사용하는 특징은 여전히 "사람"이 설계하게 된다. 즉, 강아지의 얼굴을 구분하려 할 때 숫자를 인식할 때와는 다른 특징을 사람이 생각해야한다.

 

이와 같이 주어진 데이터에서 특징을 추출하고 결과를 내는 방식은 다음과 같이 세가지로 나누어 질 수 있다.

 

(그림 1) 데이터를 통해 결과를 내는 세가지 방식

 

 

신경망은 데이터를 그대로 학습한다. 두번째 접근 방식에서는 특징을 사람이 설계 했지만, 신경망은 이미지에 포함된 중요한 특징까지도 기계가 학습하게 된다.

 

이를 종단간 기계학습, 즉 End-To-End 라고 할 수 있다. 처음부터 끝까지 입력 데이터에서 목표한 출력 데이터를 사람의 개입 없이 얻을 수 있기 때문이다.

 

 

 

 

 

2. 훈련데이터(Training Data)와 시험데이터(Test Data)

 

머신러닝의 문제는 데이터를 훈련데이터와 시험데이터로 나누어 학습과 실험을 수행하는 것이 일반적이다. 우선 훈련 데이터만 사용하여 학습하면서 최적의 매개변수를 찾게 된다. 그런 다음 시험 데이터를 사용하여 앞서 훈련한 모델의 실력을 평가하게 된다.

 

우리는 범용적으로 사용 할 수 있는 모델을 생성하는 것이 목표이기 때문에 이 범용 능력을 제대로 평가하기 위해 훈련 데이터와 시험 데이터를 분리하는 것이다. 이는 아직 보지 못한 미지의 데이터를 가지고 문제를 올바르게 풀어내는 능력이라고도 할 수 있다.

 

이러한 범용 능력을 획득하는 것이 기게학습의 최종 목표이다.

 

예를 들어 손글씨 인식의 경우 한사람이 쓴 데이터로만 학습하게 된다면 머신러닝의 목표와 맞지 않게 된다. 즉, 임의의 사람의 임의의 글자를 판독해야 범용 능력을 지닌 머신러닝이 된다.

 

그래서 한 데이터 셋에만 지나치게 최적화 된 상태를 Overfiting 이라고 한다.

 

 

 

 

 

3. 손실 함수 (Loss Function)

 

 

신경망 학습에서는 현재의 상태를 하나의 지표로 표현 할 수 있다. 그리고 그 지표를 가장 좋게 만들어주는 가중치 매개변수의 값을 탐색할 수 있다. 신경망도 하나의 지표를 기준으로 최적의 매개변수 값을 탐색하게 된다.

 

신경망 학습에서 사용하는 지표는 손실함수라고 한다. 이 손실함수는 임의의 함수를 사용할 수도 있지만 일반적으로는 평균 제곱 오차와 교차 엔트로피 오차를 사용한다.

 

즉, 손실함수는 신경망 성능의 '나쁨'을 나타내는 지표로, 현재의 신경망이 훈련 데이터를 얼마나 잘 처리하지 못하느냐를 나타낸다.

 

 

 

3.1 평균제곱오차(Mean Squared Error, MSE)

 

가장 많이 쓰이는 손실함수는 평균제곱오차이다. 평균 제곱오차는 수식으로 다음과 같다.

 

(수식 1) 평균제곱오차 손실함수

 

여기서 yk는 신경망의 출력, tk는 정답 레이블, k는 데이터의 차원 수를 나타낸다.

예를 들어 손글씨 숫자 인식의 경우 yk와 tk는 다음과 같다.

 

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

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

 

신경망의 출력 y는 소프트맥스 함수의 출력이다. 소프트맥스 함수의 출력은 확률로 해석 할 수 있으므로, 이 예에서는 이미지가 '0' 일 확률은 0.1, 1일 확률은 0.05 등...

 

정답 레이블인 t는 정답을 가리키는 위치의 원소는 1로, 그 외에는 0으로 표기하게 된다. 여기에서는 숫자 2(숫자의 시작은 0)에 해당하는 원소의 값이 1이므로 정답이 2 임을 알 수 있다. 이처럼 한 원소만 1로 하고 그 외에는 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]

>>> mean_squared_error(np.array(y), np.array(t))

0.0975000000

 

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

>>> mean_squared_error(np.array(y), np.array(t))

0.5975000000

 

두가지 예시가 있는데 첫번째 예시는 2일 확률이 가장 높다고 추정하였고, 두번째 예시는 7일 확률이 가장 높다고 추정하였다. 손실함수를 사용하였을 때 첫번째 예시의 오차가 작았다. 즉, 평균 제곱 오차 기준으로는 첫 번째 추정 결과가 정답에 더 가까울 것으로 판단 할 수 있다.

 

 

 

 

 

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

 

또 다른 손실함수로서 교차 엔트로피 오차도 자주 이용한다. 교차 엔트로피 오차의 수식은 다음과 같다.

 

(수식 2) 교차엔트로피 오차 수식

 

여기서 log는 밑이 e인 자연로그 이다. yk는 신경망의 출력, tk는 정답레이블이다.

 

또 tk는 정답에 해당하는 인덱스의 원소만 1이고 나머지는 0인 원-핫 인코딩을 뜻한다. 그래서 실질적으로 정답일 때의 추정의 자연로그를 게산하는 식이 된다. 예를 들어 정답 레이블은 2가 정답이라고 하고 이때의 신경망 출력이 0.6 이라면 교차 엔트로피 오차는 -log0.6 = 0.51 이 된다. 또한, 같은 조건에서 신경망 출력이 0.1 이라면 -log0.1 = 2.30 이 된다. 즉, 교차 엔트로피 오차는 정답일 때의 출력이 전체 값을 정하게 된다.

 

(그림 2) 자연로그 y= logx 의 그래프

 

이는 x가 1일 때 y는 0이 되고, x가 0에 가까워질수록 y의 값은 점점 작아진다. 교차엔트로피 오차 수식에서도 마찬가지로 정답에 해당하는 출력이 커질수록 0에 다가가다가, 그 출력이 1일 때 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]

>>> cross_entropy_error(np.array(y), np.array(t))

0.51082

 

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

>>> cross_entropy_error(np.array(y), np.array(t))

2.30258

 

즉, 결과가 더 작은 첫 번째 추정이 정답일 가능성이 높다고 판단한 것으로 앞서 평균 제곱 오차의 판단과 일치한다.

 

 

 

 

3.3 미니배치 학습

 

머신러닝 문제는 훈련 데이터를 사용해 학습한다. 훈련데이터에 대한 손실 함수의 값을 구하고, 그 값을 최대한 줄여주는 매개변수를 찾아내게 된다. 이렇게 하려면 모든 훈련 데이터를 대상으로 손실 함수 값을 구해야 한다. 즉, 훈련 데이터가 100개 있으면, 그로 부터 계산한 100개의 손실 함수 값들의 합을 지표로 삼는 것이다.

 

지금까지 데이터 하나에 대한 손실함수만 생각해 왔으나 이제 훈련 데이터 모두에 대한 손실 함수의 합을구하는 방법을 생각해봐야 한다.

 

예를 들어 교차 엔트로피 오차 수식은 다음과 같다.

 

(수식 3) N개의 데이터에 대한 교차 엔트로피 오차 수식

 

이 때 데이터가 N개 라면 tnk는 n번째 데이터의 k번째 값을 의미한다. 데이터 하나에 대한 손실 함수인 위 식을 단순히 N개의 데이터로 확장한 것이다. 다만, 마지막에 N으로 나누어 정규화 하고 있다. N으로 나눔으로써 평균 손실 함수를 구하는 것이다. 이렇게 평균을 구해 사용하면 훈련데이터 개수와 관계없이 언제든 통일된 지표를 얻을 수 있다. 예를 들어 훈련 데이터가 1000개든 10000개든 상관 없이 평균 손실 함수를 구할 수 있다.

 

이런데 손글씨 인식할 때 쓰이는 MNIST 데이터 셋은 훈련 데이터가 60,000개 이다. 그래서 모든 데이터를 대상으로 손실 함수의 합을 구하려면 시간이 걸리는데 이러한 빅데이터 수준이 되면 그 수는 수백만에서 수천만도 넘는 거대한 값이 되기도 한다.

 

이 많은 데이터를 대상으로 일일이 손실함수를 계산하는 것은 현실적이지 않다. 이런 경우 데이터 일부를 추려 전체의 근사치로 이용할 수 있다. 신경망 학습에서도 훈련 데이터로부터 일부만 골라 학습을 수행한다. 이 일부를 미니배치(Mni-Batch) 라고 한다. 가령 6만장 훈련 데이터 중에서 100장을 무작위로 뽑아 그 100장만을 사용하여 학습하는 것이다. 이러한 학습 방법을 미니배치라고 한다.

 

이러한 미니 배치용 교차 엔트로피를 구현하기 위해서는 조금만 바꾸어 구현하면 된다.

 

 

 

 

 

4. 손실함수를 사용하는 이유

 

손실함수를 왜 사용하느냐에 대해 궁금증이 생길 수 있다. 예컨대 숫자 인식의 경우도 우리의 궁극적인 목적은 높은 정확도를 끌어내는 매개변수 값을 찾는 것이다. 그렇다면 정확도라는 지표를 놔두고 손실 함수의 값 이라는 우회적인 방법을 택하는 이유는 무엇일까.

 

이 의문은 신경망 학습에서의 '미분'의 역할에 주목한다면 해결된다. 신경망 학습에서는 최적의 매개변수 (가중치와 편향) 값을 탐색할 떄 손실 함수의 값을 가능한 작게 하는 매개변수 값을 찾는다. 이 때 매개변수의 미분을 계산하고, 그 미분 값을 단서로 매개변수의 값을 서서히 갱신하는과정을 반복하게 된다.

 

가령 여기에 가상의 신경망이 있고 그 신경망의 어느 한 가중치 매개변수에 주목한다고 할 때 그 가중치 매개변수의 손실함수의 미분이란 가중치 매개변수의 값을 아주 조금 변화 시켰을 때 손실 함수가 어떻게 변하냐의 의미이다. 만약 이 미분 값이 음수라면 그 가중치 매개변수를 양의 방향으로 변화시켜 손실 함수의 값을 줄일 수 있다. 반대로, 이 미분 값이 양수라면 그 가중치 매개변수를 음의 방향으로 변화시켜 손실 함수의 값을 줄일 수 있다. 그러나 미분 값이 0 이라면 가중치 매개변수를 어느 쪽으로 움직여도 손실 함수의 값은 달라지지 않는다. 그래서 그가중치 매개변수의 갱신은 거기서 멈춘다.

 

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

 

즉, 신경망을 학습할 때 정확도를 지표로 삼아서는 안된다. 정확도를 지표로 하면 매개변수의 미분이 대부분의 장소에서 0이 되기 때문이다.

 

그렇다면 왜 매개변수의 미분이 0이 될까.

 

한 신경망이 100장의 훈련 데이터 중 32장을 올바로 인식한다고 한다. 그렇다면 정확도는 32% 이다. 만약 정확도가 지표였다면 가중치 매개변수의 값을 조금 바꾼다고 해도 정확도는 32%이다. 즉, 매개변수를 약간만 조정해서는 정확도가 개선되지 않고 일정하게 유지될 뿐더러 정확도가 개선된다 하더라도 그 값은 32.xxx 의 값 일 것이다. 이와 같이 연속적인 변화 보다는 33%, 35% 처럼 불연속적인 띄엄띄엄한 값으로 바뀌어 버린다.

 

한편 손실함수를 지표로 삼는다면 현재의 손실함수 값은 0.928... 같은 수치로 나타난다. 그리고 매개변수의 값이 조금 변하면 그에 반응하여 손실함수의 값도 0.934... 와 같은 값으로 변화한다.

 

정확도는 매개변수의 미소한 변화에는 거의 반응을 보이지 않고, 반응이 있더라도 그 값이 불연속적으로 갑자기 변화한다. 이는 계단함수를 활성화 함수로 사용하지 않는 이유와도 같다. (갑자기 0에서 1로 바뀌어 버리기 때문에)

 

계단 함수의 미분은 대부분의 장소에서 0이다. 그 결과 계단함수를 이용하면 손실함수를 지표로 삼는게 아무 의미가 없게 된다. 매개변수의 작은 변화가 주는 파장을 계단 함수가 말살하여 손실함수의 값에는 아무런 변화가 나타나지 않기 때문이다.

 

즉, 계단함수 보다는 시그모이드 함수를 사용하는게 적절하다. 왜냐하면 시그모이드 함수의 기울기 값은 0이 아니기 때문이다.

 

계단 함수는 한순간만 변화를 일으키지만, 시그모이드 함수의 미분은 출력이 연속적으로 변하고 곡선의 기울기도 연속적으로 변하기 때문이다. 즉, 시그모이드 함수의 미분은 어느 장소라도 0이 되지는 않는다.

 

이는 신경망 학습에서 중요한 성질로 기울기가 0이 되지 않는 덕분에 신경망이 올바르게 학습할 수 있는 것이다.

 

 

 

 

 

 

참고자료 1 : 밑바닥부터 시작하는 딥러닝 (책) 

728x90
반응형