손실함수(loss function), Cross Entropy Loss

미남로그·2021년 9월 6일
4

손실함수(Loss Function)

손실함수(loss function)은 머신러닝을 공부해보았다면 들어보았을 것입니다. 처음에 미니 데이터셋으로 모델을 돌리고 loss와 accuracy가 어떻게 나올까 두근두근☺하며 기다렸던 기억이 있네요.

(저번에는 폐암 진단 모델을 만들었는데 정확도가 0.57까지 떨어지며 환자를 다 죽일 뻔한 적도 있습니다..)

아무튼 손실 함수(loss function)이란 무엇일까요?

손실함수는 머신러닝에서 모델이 나타내는 확률 분포와 데이터가 따르는 실제 확률 분포 사이의 차이를 나타내는 함수입니다.

즉, 이 값은 0에 가까울수록 모델의 정확도가 높고, 반대로 0에서 멀어질수록 모델의 정확도가 낮습니다.

모델의 확률 분포는 파라미터에 따라 달라지기 때문에 손실 함수 역시 파라미터에 의해 결정됩니다.

데이터가 연속된 값을 가지는 회귀(regression) 문제와는 다르게 이산적인 값을 가지는 분류(classification) 문제에서는 모델의 출력 결과가 로지스틱 함수(logistic function)로 표현됩니다.

분류 클래스가 2개인 로지스틱 함수를 클래스가 n개일 때로 확장한 것이 딥러닝에서 주로 사용하는 softmax function입니다. 이 함수와 데이터의 확률 분포의 차이가 분류 문제의 손실 함수가 됩니다.

Cross Entropy Loss

아까 앞장(보러가기)에서는 KL divergence를 최소화하는 것이 cross entropy를 최소화하는 것과 같았죠. cross entropy도 손실 함수의 한 종류입니다!

위는 cross entropy의 식입니다. 분류 문제에서 데이터의 라벨은 one-hot encoding을 통해 표현됩니다.

원-핫 인코딩은 클래스의 종류가 N가지이고 특정 데이터가 n번째 클래스에 속할 때, n번째 원소만 1이고 나머지는 0으로 채운 N차원 벡터로 바꿔주는 것입니다.

입력 데이터의 특성(feature) 값이 모델을 통과하면 출력 레이어의 소프트맥스 함수에 의해 각각 클래스에 속할 확률이 계산됩니다. 이 확률 값들이 모델이 추정한 확률 분포 Q(x)를 구성하는 값들입니다.

만약 3개의 클래스 c1, c2, c3가 존재하는 분류 문제에서 어떤 데이터의 출력값은 다음과 같습니다.

이 결과는 다음과 같은 식으로 표현될 수 있습니다.

데이터가 실제로 2번 클래스(c2)라면 데이터의 실제 확률 분포는 one-hot encoding과 같은 [0,1,0]입니다. 데이터가 2번 클래스에 포함된다는 사실이 이미 확실하게 알려졌기 때문에 확률 분포는 아래와 같이 계산됩니다.

cross entropy를 사용하면 P(x)와 Q(x)의 차이를 다음과 같이 계산할 수 있습니다.

분류 문제에서는 데이터의 확률 분포가 위와 같이 one-hot vector로 표현되기 때문에, P(x)와 Q(x)의 차이를 cross entropy로 계산할 경우 간단해집니다!

이제 코드로 연습을 해볼 건데요. softmax_output을 사용해보겠습니다.

실습 코드

import numpy as np
import random

# generate random output
# can be modified

class_num = 4
q_vector = []
total = 1

for i in range(class_num-1):
	q = random.uniform(0, total)
    	q_vector.append(round(q,3))
        total = total - q
        
q_vector.append(total)
softmax_output = np.array(q_vector)

print(softmax_output)

[0.382      0.432      0.036      0.14983352]

코드가 안 읽힐 땐, 천천히 뜯어봅시다....🤭 한 번에 읽히면 pass, 전 continue...

Step 1

  • numpy와 random 모듈 불러오기
  • class_num은 4로 지정
  • q_vector for문에서 만들어지는 값을 넣어줄 빈 벡터 생성
  • total = 1은 모든 확률의 합은 1

Step 2 - for문

  • class_num-1 = 3, 4번 반복
  • random.uniform(a, b): a <= b 일 때 a <= N <= b, b < a 일 때 b <= N <= a를 만족하는 임의의 부동 소수점 숫자 N을 반환함
  • 즉, q는 0~1 사이의 값을 랜덤하게 추출
  • q_vector에 나온 q의 값을 소숫점 3번째 자리에 올림하여 append
  • total = total - q 은 1 - q(random값) -> 총 4개가 만들어진다.

Step 3

  • q_vector에 다시 마지막에 계산한 total 값을 append
  • softmax_output란 변수에 q_vector의 ndarray 형식으로 저장
  • 호출

이제 P(x)P(x)를 생성해 Cross Entropy를 계산해 보려고 합니다. p_vector변수를 사용하는 P(x)는 one-hot vector이므로 직접 class_index를 바꿔가며 확인할 수 있습니다.

# can be modified
class_index = 1

p_vector = np.zeros(class_num)
p_vector[class_index-1] = 1

cross_entropy = -np.sum(np.multiply(p_vector, np.log(softmax_output)))

print('model prediction: ' + str(sofemax_output))
print('data label: ' + str(p_vector))
print('cross entropy: ' + str(round(cross_entropy,4)))

model prediction: [0.382      0.432      0.036      0.14983352]
data label: [1. 0. 0. 0.]
cross entropy: 0.9623

다시 코드 리뷰를 해봅시다.🤭

Step 1

  • numpy.zeros(shape, dtype=float, order='C', *, like=None) 의 형식인데요. 간단하게 numpy.zeros는 shape만큼의 0을 return합니다.
  • 즉, class_num만큼의 0 벡터를 만들어줍니다.
  • p_vector에서 class_index-1의 인덱스는 1임을 지정했습니다.

Step 2

  • cross_entropy 공식에 맞게 식을 적어주었습니다. sum은 합, multiply는 괄호 안의 값의 곱, log는 자연로그입니다.

Step 3

  • softmax_output과 p_vector, cross_entropy의 값을 출력합니다.

여기까지 Q(x)분포가 랜덤하게 생성되었을 때 P(x)를 변형시키면서 cross entropy를 계산해볼 수 있는 코드를 함께 보았습니다!

Cross Entropy와 Likelihood의 관계

모델의 파라미터를 θ(세타)로 놓으면, 모델이 표현하는 확률분포는 Q(y|X,θ)로 데이터의 실제 분포는 P(y|X)입니다. 그런데 Q(y|X,θ)는 데이터셋과 파라미터가 주어졌을 때의 예측값의 분포입니다. 이는 likelihood와 같다고 합니다.

X와 y는 데이터셋에 의해 결정되는 값이기 때문에 모델의 식이 바뀌어도 변하지 않습니다. 이 식에서 우리가 변화를 줄 수 있는 부분은 파라미터를 수정할 수 있는 -logQ(y|X,θ)이 될 것이고, cross entropy를 줄이기 위한 파라미터를 구하는 것이 결국 negative log likelihood를 최소화하는 파라미터를 구하는 것과 같습니다.

Likelihood가 무엇인가?

영상

이 영상을 봐야지, 했는데 엄청 밀렸네요... 한 번 보고 정리하는 걸 스스로 숙제로 정해보겠습니다.

profile
미남이 귀엽죠

2개의 댓글

comment-user-thumbnail
2023년 7월 17일

크로스 엔트로피에 대한 도움이 됐습니다. 좋은 자료 감사합니다 :)

1개의 답글