MNIST Lab 기본 구현 4편
Cross Entropy Loss는 모델이 정답 클래스에 얼마나 낮은 확률을 줬는지 벌점으로 바꾸는 함수다. MNIST에서는 정수 label을 이용해 정답 칸의 확률만 뽑아 계산한다.
1. 손실 함수는 모델의 벌점이다
정답이 3인데 모델이 3번 칸에 0.9를 주면 잘한 것이다. 반대로 0.01을 주면 크게 틀린 것이다. Cross Entropy는 이 차이를 -log(정답 확률)로 벌점화한다.
| 정답 확률 | -log 값 | 해석 |
|---|---|---|
| 0.9 | 작음 | 정답을 강하게 믿었으므로 벌점이 작다. |
| 0.5 | 중간 | 애매하게 맞혔다. |
| 0.01 | 큼 | 정답을 거의 믿지 않았으므로 벌점이 크다. |
2. 최종 구현 코드
def cross_entropy_loss(y_pred, y_true):
batch_size = y_pred.shape[0]
probs = np.clip(y_pred, 1e-7, 1.0)
correct_probs = probs[np.arange(batch_size), y_true]
loss = -np.mean(np.log(correct_probs))
return loss
np.clip이 필요한 이유
예측 확률이 0이면 log(0)이 되어 계산이 무한대로 터진다. 그래서 아주 작은 값 1e-7 아래로 내려가지 않게 막는다.
3. 정답 칸만 뽑는 인덱싱
y_pred = np.array([
[0.1, 0.7, 0.2],
[0.8, 0.1, 0.1],
])
y_true = np.array([1, 0])
correct_probs = y_pred[np.arange(2), y_true]
# [0.7, 0.8]
첫 번째 데이터의 정답은 1번 칸이므로 0.7을 뽑고, 두 번째 데이터의 정답은 0번 칸이므로 0.8을 뽑는다.
4. 테스트가 묻는 것
| 테스트 | 확인 조건 |
|---|---|
| test_cross_entropy_loss_scalar | loss가 스칼라이고 0보다 큰가 |
| test_cross_entropy_loss_perfect | 정답 확률이 거의 1이면 loss가 거의 0인가 |
이번 글에서 기억할 것
Cross Entropy Loss는 정답 칸의 예측 확률만 뽑아 -log 벌점의 batch 평균으로 바꾸는 함수다.
스스로 점검
- 왜 오답 칸의 확률을 직접 더하지 않는가?
- np.clip이 없으면 어떤 문제가 생길 수 있는가?
- 정수 label과 one-hot label의 차이는 무엇인가?
다음 글 예고
다음 글에서는 SGD를 구현한다. 이제 계산된 gradient를 이용해 실제 파라미터를 갱신한다.