classification task에서는 loss function으로 Cross-Entropy을 주로 사용한다.
binary classification일 때는 이 BinaryCrossentropy를 사용하고
multi-class classification인 경우엔 CategoricalCrossentropy를 사용하게 되는데,
명확하게 차이에 대한 이해 없이 기계적으로 사용하기도 하였다.
이번 포스팅에서는 classification task에서 사용되는 Cross-Entropy에 대해서 알아보도록 하겠다.
시작에 앞서
- 이 포스팅에서는 정보이론적으로 Cross-Entropy를 다루지 않는다.
- 코드 예제는 Tensorflow를 기준으로 진행한다.
Multi-class classification 분류 문제에서 Cross-Entropy
Multi-class classification의 경우 output layer에서 Softmax를 한 뒤, CategoricalCrossntropy를 사용하여 Cross-Entropy를 구한다.
(one-hot encoding을 하지 않은 경우 SparseCategoricalCrossentropy를 사용하지만 내부적으로는 동일하기 때문에 이는 넘어가겠다)
이에 대한 수식은 다음과 같다.
$$\text{Categorical Cross-Entropy} = -\sum_{i=1}^{n} y_{i}\cdot\log({\hat y_{i}})$$
(batch로 처리하는 경우엔 해당 batch의 Cross-Entropy 값들의 평균을 구해주면 된다)
예를 들어 다음과 같이 레이블 데이터와 그에 대한 예측 데이터가 있다고 하였을 때
$y = [0, 0, 1, 0 ,0]$
$\hat y = [0.01, 0.09, 0.88, 0.015, 0.005]$
Cross-Entropy 값은 다음과 같이 구할 수 있다.
$CCE = -(0 \cdot \log(0.01) + 0 \cdot \log(0.09)+ 1 \cdot \log(0.88) + 0 \cdot \log(0.015) + 0 \cdot \log(0.005))$
$\qquad \quad = -(0 + 0 + \log(0.88) + 0 + 0)$
$\qquad \quad = -\log(0.88) $
$\qquad \quad = 0.1278$
코드로 Cross-Entropy 값을 구해보면 수식을 통해 구한 값과 유사하게 나오는 것을 확인할 수 있다.
import numpy as np
from tensorflow.keras.losses import CategoricalCrossentropy
y = np.array([0, 0, 1, 0 ,0])
y_hat = np.array([0.01, 0.09, 0.88, 0.015, 0.005])
print(CategoricalCrossentropy()(y, y_hat))
# tf.Tensor(0.12783338, shape=(), dtype=float32)
Binary classification에서 Cross-Entropy
Binary classification의 경우 output layer에서 Sigmoid를 한 뒤,
BinaryCrossentropy를 사용하여 Cross-Entropy를 구한다.
이에 대한 수식은 다음과 같다.
$$\text{Binary Cross-Entropy} = -(y \cdot \log(\hat y) + (1 - y) \cdot \log(1 - \hat y)) $$
(batch로 처리하는 경우엔 해당 batch의 Cross-Entropy 값들의 평균을 구해주면 된다)
예를 들어 다음과 같이 레이블 데이터와 그에 대한 예측 데이터가 있다고 하였을 때
$y = 0$
$\hat y = 0.013$
Cross-Entropy 값은 다음과 같이 구할 수 있다.
$BCE = -(0 \cdot \log(0.013) + (1-0) \cdot \log(1 - 0.013) )$
$\qquad = - \log(0.987)$
$\qquad = 0.013094$
코드로 Cross-Entropy 값을 구해보면 수식을 통해 구한 값과 유사하게 나오는 것을 확인할 수 있다.
import numpy as np
from tensorflow.keras.losses import BinaryCrossentropy
y = np.array([0])
y_hat = np.array([0.013])
print(BinaryCrossentropy()(y, y_hat))
# tf.Tensor(0.013085251, shape=(), dtype=float32)
왜 Binary Cross-Entropy와 Binary Cross-Entropy는 다른 수식을 사용하는가?
수식 자체만 놓고 봤을 때는 서로 다른 수식이라고 이해할 수 있지만, 근본적으로는 같은 수식을 사용한다고 볼 수 있다.
Binary classification을 class가 2개(1과 0)인 Multi-class classification 이라고 볼 수도 있는데,
이때의 Categorical Cross-Entropy는 다음과 같이 구할 수 있게된다.
$$-\sum_{i=1}^{n} y_{i} \cdot \log(\hat y_{i}) = -(y \cdot \log(\hat y) + (1-y) \cdot \log(1 - \hat y) )$$
(class 0에 대한 확률 = 1 - class 1에 대한 확률)
이는 곧 Binary Cross-Entropy와 동일하다는 것을 확인할 수 있다.
추가적으로 아래와 같이 Binary classification을 0과 1에 대한 Multi-class classification 구조로 바꾼 뒤,
Cross-Entropy 값을 계산하였을 때도 동일한 것을 확인할 수 있다.
import numpy as np
from tensorflow.keras.losses import BinaryCrossentropy
binary_y = np.array([1])
binary_y_hat = np.array([0.6])
print("Binary:\t\t", BinaryCrossentropy()(binary_y, binary_y_hat))
multi_y_true = np.array([1, 0])
multi_y_pred = np.array([0.6, 0.4])
print("Multi-class:\t", CategoricalCrossentropy()(multi_y_true, multi_y_pred))
# Binary: tf.Tensor(0.5108256, shape=(), dtype=float32)
# Multi-class: tf.Tensor(0.5108256, shape=(), dtype=float32)
이와 관련된 Sigmoid와 Softmax의 관계에 대해서는 여기를 참고하길 바란다.
Multi-label classification 분류 문제에서 Cross-Entropy
Multi-label classification의 경우 Cross-Entropy를 구하는 것은
각 class에 대해 Binary Cross-Entropy를 구하여 더하는 것이라고 보면된다.
Tensorflow를 통해 위 Multi-label classification에 대한 모델링한다면 아래와 같이 코드가 나올 수 있다.
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
model = tf.keras.models.Sequential([
...
# output layer
Dense(3, activation="sigmoid")
])
model.compile(loss="binary_crossentropy",
...)
예를 들어 다음과 같이 레이블 데이터와 그에 대한 예측 데이터가 있다고 하였을 때
$y = [1, 0, 1] $
$\hat y = [0.8, 0.15, 0.96]$
Cross-Entropy 값은 다음과 같이 구할 수 있다.
$BCE = -( 1 \cdot \log(0.8) + (1-1) \cdot \log(1 - 0.8) $
$\qquad \quad + 0 \cdot \log(0.15) + (1-0) \cdot \log(1 - 0.15) $
$\qquad \quad + 1 \cdot \log(0.96) + (1-1) \cdot \log(1 - 0.96) ) $
$\qquad = - (\log(0.8) + \log(0.85) + \log(0.96))$
$\qquad = 0.4265$
코드로 Cross-Entropy 값을 구해보면 수식을 통해 구한 값과 다르게 나오는데,
코드 상으로는 Cross-Entropy를 모두 더한 뒤에 class 수 만큼 값을 나눠주기 때문이다.
(3을 곱해주면 앞서 수식을 통해 구한 값과 유사한 값이 나온다)
import numpy as np
from tensorflow.keras.losses import BinaryCrossentropy
y = np.array([1, 0, 1])
y_hat = np.array([0.8, 0.15, 0.96])
print(BinaryCrossentropy()(y, y_hat))
# tf.Tensor(0.14216149, shape=(), dtype=float32)
참고
'Machine Learning' 카테고리의 다른 글
앙상블 기법 (0) | 2024.06.02 |
---|---|
ROC Curve (0) | 2024.05.23 |
L1, L2 Regularization (0) | 2024.05.07 |
Feature scaling 과 머신러닝 학습 (0) | 2024.04.26 |
Gradient Descent (0) | 2024.03.03 |
댓글