머신러닝, 딥러닝 ML, DL/이론

[Deep Learning] 4.신경망 학습, 손실 함수(오차제곱합, 교차 엔트로피 오차)

킹남지 2021. 7. 28. 18:30
반응형

신경망과 활성화 함수에 이어 이번에는 

신경망 학습, 수치 미분, 손실 함수, 배치(미니 배치)에 대해 정리하겠습니다.

 

추후에 좀 더 깊게 볼 필요가 있다고 판단되는 내용은 따로 포스팅을 해보겠습니다.

 

구현과 함께 보고싶으시면 아래 제 깃허브 링크를 참고해주시기 바랍니다.

https://github.com/Kingnamji/BigAI/blob/main/%EB%B0%91%EC%8B%9C%EB%94%A51_re/04_NNTrain.ipynb

 

학습

신경망에서 말하는 학습은 훈련 데이터로부터 가중치 매개변수의 최적값을 자동으로 갱신(update)하는 것을 말합니다. 

학습을 위한 지표로는 손실 함수(loss function)을 사용합니다. 손실 함수의 값을 작게 만드는 가중치 매개변수를 찾는 것이 학습의 목표입니다.

(가중치 매개변수는 전 포스팅에서 언급한 가중치와 편향을 모두 포함합니다.)

 

이번에는 손실 함수의 값을 줄이기 위한 방법으로 경사법, 중에서도 경사 하강법이라는 방법을 알아보겠습니다.

 

퍼셉트론에 관한 내용을 정리할 때는 사람이 적절한 매개변수 값을 설정했습니다. 하지만 실제 신경망은 매개변수가 수천, 수만개를 넘고 1000억개를 넘는 매개변수를 가질 수도 있습니다. (ex : GPT-3, 하이퍼클로바)

 

(네이버의 하이퍼클로바는 2040억개의 매개변수를 가집니다.)

http://m.ddaily.co.kr/m/m_article/?no=214861 

 

네이버는 왜 한국어 AI 모델을 만들었나…“‘글로벌 기술 종속’ 막는다”

[디지털데일리 권하영기자] “네이버에서 초대규모 AI 언어 모델을 개발한다고 했을 때 이런 의문이 많았다. 왜 네이버가 그 많은 자원을 투자해 별도의 AI 모델을 독자적으로 만드냐는 것이다.

www.ddaily.co.kr

 

이렇게 많은 매개변수를 사람이 직접 설정하기는 불가능에 가깝습니다. 따라서 매개변수 값을 신경망의 학습을 통해 정합니다.

사람이 특징을 먼저 추출하고, 데이터에서 규칙을 찾아내는 머신러닝과는 달리 딥러닝에서는 중요한 특징도 신경망을 통해 학습합니다.

 

 

훈련 데이터, 시험 데이터

기계학습 문제에서는 데이터를 훈련 데이터(train data)와 시험 데이터(test data)로 나눠 학습과 실험을 진행합니다.

먼저, 훈련 데이터만 사용해 최적의 매개변수를 찾고 시험 데이터를 사용해 모델을 평가합니다.

 

처음 마주한 문제(데이터)도 올바르게 해결해내는 모델을 만드는 것 즉, 범용 능력이 있는 모델을 만드는 게 기계학습의 최종 목표입니다.

범용 능력을 위해 반드시 훈련 데이터와 시험 데이터를 분리해 평가해야합니다.

 

학습한 데이터에 대해서만 성능이 좋아진다면 그 모델은 실제 문제에는 사용할 수 없습니다.

이렇게 특정 데이터 셋에만 지나치게 최적화 된 상태를 오버피팅(overfitting)이라고 합니다.

오버피팅된 모델은 비유하자면 마치 문제은행식 면허 시험 필기 문제를 달달 외우고 필기 시험을 높은 점수로 통과한 사람이

실제 여러가지 처음 마주한 운전 상황에서는 제대로 된 판단을 못하는 것과 같습니다. 

필기 시험 때는 이미 봤던 문제들이니 답만 잘 내놓았던 것이죠.

 

 

손실 함수

 

신경망 학습에서는 손실 함수라는 지표를 사용합니다. (비용 함수, cost function 이라고 부르기도 합니다.)

손실 함수는 신경망의 성능이 '얼마나 나쁜지'를 나타내는 지표입니다. 손실 함수의 값이 높다면 그만큼 신경망의 성능이 나쁘다. 안좋다 라는 뜻이겠죠. 따라서 신경망 학습에서는 손실 함수 값을 가능한 작게 하는 매개변수 값을 찾습니다.

 

왜 손실 함수?

결국 신경망의 성능이 좋게하는 매개변수 값을 찾기 위함인데 왜 손실함수를 지표로 삼아 학습을 하는 걸까요?

최종 목적은 '정확도'가 높은 신경망이니 정확도를 지표로 학습을 하는게 더 좋지 않을까요? 

 

뒤에 다룰 내용이지만 신경망의 학습은 미분을 사용합니다.

학습은 손실 함수를 각 매개변수에 대해 미분해서 그 값(기울기라고 표현합니다)을 통해 매개변수 값을 갱신하는 과정의 반복입니다.

(이 내용은 나중에 더 깊게 다룹니다.)

 

만약 손실 함수가 아닌 정확도에 대해 미분한다면 어떻게 되는지 생각해봅시다.

예를 들어 신경망이 100개의 훈련 데이터 중 60개를 정확히 맞춘다고 합시다. 그러면 정확도는 60%입니다. 가중치 매개변수 값이 조금 갱신됐다고 해도 정확도는 아마 그대로 60%일겁니다. 변해봤자 59% 또는 61%로 띄엄띄엄 변합니다. 이러면 대부분의 상황에서 미분 값이 즉, 기울기가 0이됩니다. 이러면 매개변수 값의 갱신을 할 수 없습니다.

 

신경망이 지표로 손실 함수를 사용한다면 값이 0.9123과 같이 나올거고, 가중치 매개변수 값을 조금 갱신하면 0.92414와 같이 연속적으로 변합니다. 따라서 신경망 학습의 지표로는 손실 함수를 사용합니다.

 

(계단 함수를 활성화 함수로 이용하지 않는 이유도 위와 동일합니다.)

 

오차제곱합

손실 함수는 아주 많습니다. 그 중 가장 기본적인 손실 함수인, 오차제곱합(sum of squares for error, SSE)를 보겠습니다.

 

오차제곱합의 수식입니다.

 

$E = \frac{1}{2} \displaystyle\sum_k(y_k - t_k)^2$

 

(일반적인 오차제곱합에 1/2가 추가됐습니다. 이렇게 바꿔주는 이유 또한 미분을 수월하게 해주기 위해서입니다.)

 

식처럼 구현도 간단합니다.

# 오차제곱합
def sum_squares_error(y, t): 
    return 0.5 * np.sum((y-t)**2)

 

아래는 사용 예시입니다. 

# 원 핫 인코딩
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0] # 정답 2

# 신경망의 출력 2인 경우
y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
print(sum_squares_error(np.array(y), np.array(t)))

# 신경망의 출력이 7인 경우
y = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
print(sum_squares_error(np.array(y), np.array(t)))

0.09750000000000003
0.5975

신경망의 출력이 2인 경우 정답을 맞췄으니 오차가 더 낮은 것을 확인할 수 있습니다.

 

 

교차 엔트로피 오차

 

또 다른 손실함수인 교차 엔트로피 오차(cross entropy error, CEE)를 보겠습니다.

 

교차 엔트로피 오차의 수식입니다.

 

$E = -\displaystyle\sum_{k}t_k\log{y_k}$

 

$log$는 밑이 $e$인 자연로그, $y_k$는 신경망의 출력 $t_k$는 원 핫 인코딩된 정답 레이블입니다. 

 

예시는  10가지 클래스(0에서 9까지 숫자)를 분류하는 문제로, k = 0 부터 k = 9 까지로 생각하겠습니다. 

만약 정답 레이블이 '3'라면 $t_3$ = 1 이고 나머지 $k \neq 3$일 때, $t_k$ = 0 입니다.

 

신경망의 3에 해당하는 출력 값이 0.6이라면 ( $y_3$ = 0.6 )

교차 엔트로피 오차는   $-\log{0.6} = 0.51$   이 됩니다.

(정답이 아닌 나머지 $t_k$ 는 모두 0이기 때문에 $t_k * \log{y_k}$ = 0 입니다.)

 

y = -log(x)

따라서 정답에 해당하는 출력 값만 고려하면 됩니다.

정답에 해당하는 출력이 1이 된다는 건 해당 클래스가 정답일 것이라고 100%로 예측한 것이기 때문에 오차가 0이라고 생각할 수 있습니다.

 

$y = -\log{x}$ 의 그래프를 보면 정답에 해당하는 출력이 커질수록 0에 가까워지고 1이 되면 0이 됨을 확인할 수 있습니다.

반대로 정답에 해당하는 출력이 작아진다면 $-\log$값은 커집니다. (오차가 커집니다.)

 

마찬가지로 구현해보고 예시로 계산해보겠습니다.

# 교차 엔트로피
def cross_entropy_error(y, t):
    delta = 1e-7 # log에 0 이 입력되는 사태 방지
    return -np.sum(t * np.log(y + delta)) 

# 정답 => 2
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]

# 신경망의 출력이 2인 경우
y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]

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

# 신경망의 출력이 7인 경우
y = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]

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


0.510825457099338
2.302584092994546

신경망의 출력이 2인 경우 오차가 0.5108... 으로 더 낮은 것을 확인할 수 있습니다.

 

 

다음 포스팅에서는 한 개의 훈련 데이터가 아닌 지정한 수의 훈련 데이터로 학습하는 배치(미니 배치) 학습에 대해 알아보고,

그렇게 학습할 때의 교차 엔트로피 구현 등을 살펴 보겠습니다. 

그리고 수치 미분으로 매개변수의 기울기를 구하는 과정도 정리하겠습니다.

 

읽어주셔서 감사합니다 ^^

 

 

 

[참고자료]

[1] 밑바닥부터 시작하는 딥러닝1 (사이토 고키)

반응형