본문 바로가기
처음부터 하는 딥러닝

[딥러닝 기초] 손실 함수 (Loss function)

by 빈이름 2023. 5. 17.

이번엔 손실 함수에 대해 좀 더 자세히 다뤄보겠습니다.

 

손실 함수란, 모델의 예측값과 실제 데이터의 값 사이의 차이를 측정하기 위한 함수라고 할 수 있습니다. 손실 함수는 '목적 함수(Objective function)'라고도 합니다.

실제값과 예측값 사이의 차이(loss)는 적을수록 좋겠죠. 이를 줄이기 위해 경사 하강법(Gradient descent)을 수행합니다. 경사 하강법은 미분을 기반으로 하기 때문에 손실 함수 또한 미분 가능해야 합니다.

 

손실 함수는 목적 함수라고도 불리는 만큼, 학습의 목적에 따라 손실 함수의 유형도 달라집니다.

딥러닝에서의 목적은 크게 2가지로 나눌 수 있을 것 같습니다. (회귀(regression)와 분류(classification))

지금부터 각 목적에 알맞는 손실 함수들을 하나씩 소개해 드리겠습니다.

1. 회귀 (Regression)

위키 문서에 따르면 '회귀 분석'이란, 관찰된 연속형 변수들에 대해 두 변수 사이의 모형을 구한 뒤 적합도를 측정해 내는 분석 방법입니다.

파란 선을 우리가 예측한 모델, 빨간 점들을 실제 데이터라고 할 때, 회귀 분석은 이 둘 사이의 차이를 측정하는 방법이라고 할 수 있다.

딥러닝 모델 학습에 빗대어 좀 더 쉽게 설명하자면, 위 그래프의 파란 선을 우리의 모델의 예측값, 빨간 점들을 실제 데이터의 분포라고 할 때, 이 둘의 차이를 측정하는 것이라고 할 수 있겠습니다. 주택 가격 예측과 같은 문제들을 회귀 문제의 예시로 들 수 있겠습니다.

 

모델 예측값과 실제값 사이의 차이를 나타내기 위해 가장 쉽게 생각할 수 있는 방법은 아래와 같이 실제값($y$)과 예측값($y'$) 사이의 차를 구하는 것일 겁니다.

$$\text{Loss}=y-y'$$

그러나 위 수식을 손실 함수로 그대로 사용할 경우 문제가 발생할 수 있습니다.

 

만약 실제 데이터 값이 4인데, 모델A가 예측한 값은 1이고, 모델 B가 예측한 값은 9라고 가정해 봅시다.

이 때, 모델 A의 loss값은 $4-1=3$이 될 것이고, 모델 B의 loss 값은 $4-9=-5$가 될 것입니다.

그러나 생각해 보면 이는 문제가 있습니다. 모델 A의 loss 값이 모델 B의 loss 값보다 크지만, 실제로 예측값이 실제값에 더 가까운 모델은 A이기 때문입니다.

 

이런 문제를 막기 위해서 회귀의 loss function은 실제값과 예측값 사이의 '차이' 그 자체를 측정할 수 있는 방법들이 사용됩니다.

1-1. MAE Loss (Mean Absolute Error)

MAE Loss는 실제값과 예측값 사이의 차의 절댓값을 loss로 사용합니다. 절댓값 덕분에 loss는 항상 양수로 표현됩니다.

MAE loss는 L1 loss라고도 합니다.

$$\text{Loss}=|y-y'|$$

1-2. MSE Loss (Mean Squared Error)

MSE Loss는 실제값과 예측값 사이의 차를 제곱하여 loss로 사용합니다. 제곱 덕분에 loss는 항상 양수가 됩니다.

MSE Loss는 L2 loss라고도 합니다.

$$\text{Loss}=(y-y')^2$$

1-3. MAE vs. MSE

그렇다면 MAE를 사용했을 때와 MSE를 사용했을 때의 차이점은 뭘까요?

파란 그래프가 y-y'값이라 할 때, MAE loss는 초록 그래프와 같이 되고, MSE loss는 주황색 그래프와 같이 된다.

위 그래프를 보면, MSE Loss가 MAE Loss에 비해 대체로 훨씬 큰 값을 갖게 되는 것을 확인할 수 있습니다. 직관적으로 생각해봐도 1보다 큰 숫자를 제곱하면 원래 값보다 훨씬 커지게 됩다는 것을 알 수 있습니다. 즉, MSE는 실제값과 예측값 사이의 차이가 커질수록 MAE보다 loss가 훨씬 커집니다. 즉, MSE Loss가 MAE Loss보다 데이터의 이상치(outlier)에 더 민감하게 반응할 것입니다.

 

따라서 모델이 outlier들에 더 민감하게 반응하길 원한다면 MSE(L2) Loss를, 아니라면 MAE(L1) Loss를 사용하는 것이 바람직합니다.

좀 극단적으로 그리자면, MAE Loss를 사용한 모델은 파란 그래프와 같이 그려질 것이고, MSE Loss를 사용한 모델은 주황색 그래프와 같이 그려질 것이다.

2. 분류 (Classification)

분류는 몇 가지 정해진 클래스 분류가 존재할 때, 주어진 데이터를 올바른 클래스로 맞게 분류하는 작업을 말합니다. 앞서 봤던 MNIST와 같은 문제들이 대표적인 예시겠죠.

딥러닝에서는 이를 클래스들에 대한 확률 분포로 표현합니다. A일 확률은 0.03, B일 확률은 0.97... 이런 식으로 말이죠.

위와 같이 모델은 결과를 클래스들에 대한 확률 분포 형태로 출력한다.

즉, 분류 문제에서 loss값을 측정하는 것은, 두 개의 확률 분포 사이의 차이를 측정하는 것과 같습니다.

확률 분포의 차이를 측정하는 데는 cross-entropy를 사용할 수 있습니다.

$$L(x|\theta)=-\Sigma^n_m y_m \text{log}y'_m$$

n개의 클래스가 존재할 때, 각 클래스의 실제 확률값 $y_m$에 예측 확률값의 log값 $log(y'_m$)을 곱한 값들의 총합으로 cross-entropy loss를 표현할 수 있습니다.

 

만약 위 그림과 같이 모델의 예측 확률분포가 [0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.82, 0.01, 0.10] 이라고 한다면, 실제로 모델이 내야 하는 확률 분포값은 [0, 0, 0, 0, 0, 0, 0, 1, 0, 0]일 것입니다. 이 두 확률 분포를 비교하기 위해 crossentropy loss를 사용해 보면,

$$-(0\cdot\text{log}(0.01)+0\cdot\text{log}(0.01)+...+1\cdot\text{log}(0.82)...)=-\text{log}(0.82)$$

가 될 것이고, 이는 0.08이 될 것입니다. 실제 확률분포와 거의 유사하다고 볼 수 있겠네요.

 

분류 문제에 cross-entropy Loss가 사용되는 이유는 수학적인 배경지식을 어느정도 필요로 합니다. 이 아래의 설명은 이해하면 너무 좋고, 이해하지 못해도 흐름만 알고 넘어가면 될 것 같습니다.

2-1. Entropy

cross entropy의 핵심을 알기 위해선 정보이론에 대해 알아야 합니다.

정보이론의 핵심 개념은 '잘 일어나지 않는 사건이 자주 일어나는 사건보다 더 많은 정보량을 담고 있다'라는 것입니다.

이를 표현하기 위해 확률과 정보량 사이의 관계를 log를 사용해 표현을 합니다.

정보량 = $-\text{log}p(x_i)$

$-log(x)$ 그래프는 위와 같은 형태입니다. x축이 확률값, y축이 정보량이라고 할 때, log 그래프는 확률값이 커짐에 따라 정보량이 줄어드는 추이를 잘 표현할 수 있습니다.

 

Entropy란, 어떤 확률 분포가 지니고 있는 정보의 양(불확실성)을 측정하기 위한 지표입니다. 엔트로피 H는 아래와 같이 정의할 수 있습니다.

$$H=-\Sigma^N_{i=1}p(x_i)\cdot\text{log}p(x_i)$$

이 entropy는 정보량($-\text{log}p(x_i)$)의 기댓값과 같습니다.

entropy는 말하자면, 어떤 정보 p(x)에 대해 이를 표현하기 위한 최소한의(최적의) 정보량을 나타낸 것이라고 할 수 있습니다.

2-2. Cross-Entropy

딥러닝 모델의 학습에서, 저희는 정확한 정답의 확률 분포를 모르는 상태에서 이를 예측하는 방식으로 학습을 수행합니다. 이 때 우리가 찾고자 하는 정답 확률 분포를 $p(x)$라고 한다면, 저희가 추측하는 분포 $q(x)$는 확실히 $p(x)$와는 다른 형태일 것입니다. 예측한 $q(x)$를 통해 $p(x)$의 데이터를 설명하려고 한다, 이것을 cross-entropy라고 합니다.

$$H(p,q)=-\Sigma^N_{i=1}p(x_i)\cdot\text{log}q(x_i)$$

Entropy는 $p(x)$를 표현하기 위한 최소한의 정보량입니다. 그렇기 때문에 잘못된 $q(x)$를 사용해 이를 표현하고자 하는 cross-entropy는 entropy보다 더 많은 정보량을 갖게 될 것입니다. 또한 그렇기 때문에 $q(x)$가 $p(x)$에 가까워질수록 cross-entropy의 값은 작아지게 됩니다.

따라서, cross-entropy는 $q(x)$가 $p(x)$에 얼마나 근접했는지를 측정하기 위한 지표로 적절하다고 볼 수 있습니다. $p(x)$는 실제 데이터의 확률 분포를, $q(x)$는 모델이 예측한 확률 분포를 나타냅니다.

2-3. Negative Log Likelihood

Cross-Entropy가 정보이론적 관점에서 말하는 두 확률분포의 비교방식이라면, Negative Log Likelihood는 통계학적 관점에서 말하는 두 확률분포의 비교방식입니다. Negative Log Likelihood의 수식은 다음과 같습니다.

$$L(x|\theta)=-\Sigma^n_{m=1} y_m \text{log}y'_m$$

엥 뭐야 Cross-Entropy랑 똑같은거 아닌가요? 네, 똑같습니다. 설명하는 관점이 조금 다르다고 볼 수 있겠네요.

 

Likelihood란, 연속확률변수에서 특정 지점의 확률값을 표현하기 위해 도입된 개념으로, 쉽게 설명하면 특정 사건이 일어날 확률과 같은 개념이라고 볼 수 있습니다.

저희의 목표는 데이터 분포를 가장 잘 나타내는 확률 분포 $p(x)$를 찾는 것입니다. 갑자기 likelihood를 소개한 이유는 여기에 사용될 수 있는 방법이 MLE(Maximum Likelihood Estimation)이기 때문입니다.

 

n개의 클래스가 존재하고, 모델이 예측한 m번째 클래스의 확률값이 $y'_m$이라고 하겠습니다. 그렇다면 m번째 클래스가 실제 데이터에서 $y_m$번 등장할 확률은, 모두 독립시행이기 때문에 모든 확률값을 곱한 $y'^{y_m}_m$이 됩니다. 또한 모든 n개의 클래스가 실행될 확률(likelihood)은 아래와 같이 됩니다.

$$ \Pi^n_m y'^{y_m}_m $$

쉽게 생각해보면, 자주 등장하는 클래스는 그 확률값이 높고, 그렇지 않은 클래스는 확률 값이 낮은 것이 가장 정상적입니다. 그리고 이 때 위의 likelihood 값은 최대가 되겠죠. 그렇기 때문에 MLE는 likelihood값이 최대가 되게 하는 확률 분포 y'을 찾는 것이 최선이다 라고 하는 것입니다.

 

최선의 likelihood를 찾기 위해선 gradient descent와 같이 미분이 사용됩니다. 그러나 위 수식은 곱셈과 제곱 연산이 너무 들어가 있어 미분을 계산하기 어렵습니다. 그래서 일반적으로 log를 씌워서 많이 사용합니다. (이를 log-likelihood라고 합니다.)

$$ \Sigma^n_{m=1} y_m\text{log}y'_m $$

log를 사용함으로써 복잡한 제곱 형태가 곱셈 형태로, 반복되던 곱셈들이 덧셈으로 변환되었습니다.

 

MLE에 따르면 위 수식의 값이 최대가 되도록 해야 합니다. 그러나 이를 loss로 사용하기엔 무리가 있겠네요. Loss는 작은게 좋은 것이니까요. 따라서 여기에 음수를 취해주면, Negative Log Likelihood 식이 완성됩니다.

$$ -\Sigma^n_{m=1} y_m\text{log}y'_m $$

이렇게 저희가 알고 있는 cross-entropy와 같은 수식이 유도되었습니다.

2-4. PyTorch에서 NLL Loss와 CrossEntropyLoss

NLL Loss와 CrossEntropyLoss가 동일한 것으로 보이는데, PyTorch에서는 NLL Loss와 CrossEntropyLoss가 따로 존재합니다.

PyTorch에서 두 loss의 차이는, CrossEntropyLoss=LogSoftmax+NLLLoss와 같습니다.

만약 모델에서 LogSoftmax까지 구현을 했다면, NLLLoss를 사용하면 되고, LogSoftmax가 없다면, NLLLoss를 사용하면 됩니다. 필요에 따라 적절하게 사용해 주면 되겠습니다.

# 모델에 LogSoftmax()까지 구현했을 경우엔 NLLLoss를,
model = nn.Sequential(
    nn.Linear(784, 256),
    nn.Linear(256, 10),
    nn.LogSoftmax()
)

criterion = nn.NLLLoss()

# LogSoftmax()가 없을 땐 CrossEntropyLoss를 쓰면 된다.
model = nn.Sequential(
    nn.Linear(784, 256),
    nn.Linear(256, 10),
)

criterion = nn.CrossEntropyLoss()

 

 

 

3. 정리

Loss function은 풀고자 하는 문제의 유형에 따라 달라집니다.

 

회귀 문제의 경우, MSE, MAE Loss를 사용할 수 있습니다.

이 중에서 MSE의 경우, MAE보다 outlier에 더 민감하게 반응하는 특징을 가집니다.

$$MSE(y', y)=(y-y')^2\\MAE(y', y)=|y-y'|$$

분류 문제는 Cross-Entropy(Negative Log Likelihood) loss가 사용됩니다. CrossEntropyLoss는 두 확률 분포의 차이를 비교하기 위해 사용됩니다.

$$ \text{CrossEntropy}(y',y)=\Sigma^n_{m=1} y_m\text{log}y'_m $$

 

딥러닝이 정말 그 기초적인 원리까지 파고들면 정말 어렵게 느껴지는 것 같습니다. 특히 CrossEntropyLoss에 대해서 조사하면서 머리가 쪼개지는줄 알았습니다. 하지만 전 이런 부분들까지 자세히 모르더라도 딥러닝 개발자가되는데 부족하지 않다고 생각합니다. 그래서 어려우면 '아 그렇구나' 하고 넘어가라고 합니다. 공부하다가 필요하다고 느껴지면 그 때 다시 보면 되죠. 이번 내용도 그런 느낌이었던 것 같습니다. 상황, 문제에 알맞은 loss를 선택할 수 있다면 그 자세한 내용은 일단 덮어두고 넘어가도 좋을 것 같습니다.