Binary_crossentropyCategorical_crossentropy 함수에선 공통적으로 from_logits 인자를 설정할 수 있습니다.

기본값은 모두 False로 되어있는데요. True, False의 차이점을 보도록 하겠습니다.

먼저 가벼운 예제를 보고 넘어가죠. 다음 두 코드의 차이점은 단순히 from_logits의 차이입니다.

# 1번 코드
cce = tf.keras.losses.CategoricalCrossentropy(from_logits = True)

target = [[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]] 
output = [[1., 0., 0.], [.05, .89, .06], [.05, .01, .94]]

loss = cce(target, output)

print(loss.numpy())
  • 0.5889537
# 2번 코드
cce = tf.keras.losses.CategoricalCrossentropy(from_logits = False)

target = [[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]] 
output = [[1., 0., 0.], [.05, .89, .06], [.05, .01, .94]]

loss = cce(target, output)

print(loss.numpy())
  • 0.059469786

출력값의 차이가 크게 나는 것을 볼 수 있습니다. 동작하는게 다르다는 것을 보여주네요. 결과는 일단 제쳐두고, 다시 from_logits 인자에 대해 얘기해보죠.(밑에 길게 설명되어있지만, 사실 텐서플로우의 logit은 매우 간단합니다.)


from_logits의 의미는 모델이 출력하는 output이 logit인지 아닌지를 판단하는 것으로 생각할 수 있는데요. 이를 해석하려면 logit의 의미를 또 파헤쳐보아야 합니다.

일반적으로 통계학에서 쓰이는 logit과 딥러닝에서 쓰이는 logit은 의미가 다릅니다. 또, 몇몇 사람들의 글을 찾아보면 굳이 텐서플로우가 이를 함수 이름으로 채택하면서 사용자들에게 혼동을 주고 있다고 말하기도 하네요. 사실 이 글의 작성 동기도 함수 사용 과정에서 조금 헷갈려서...

통계학에서 쓰이는 logit은 Logistic Regression을 이야기할 때 자주 쓰이는 logit입니다.

  1. 이때 자주 이야기하는 오즈(odds)는 (성공 확률 / 실패 확률)을 통해 구해지게 됩니다. 하지만 실제 변수를 확률의 범위에서 해석하기엔 조금 애매합니다. 그래서 log를 사용하는데요. 이를 logit 변환이라고 합니다. log를 사용하게 되면, 값의 범위가 [-inf, inf]로 바뀌게 됩니다.
    (오즈값의 범위는 [0, inf] 입니다)
  2. logit 변환의 의미는 예측값(y)과 예측값을 만들어내는 특성값(x)의 관계를 선형관계로 만들어준다는 것입니다. 따라서 로지스틱 회귀식을 사용할 수 있는거죠! 원래 y는 [0, 1]의 확률의 범위였고, 특성값(x)은 [-inf, inf]이기 때문에 관계를 말할 수 없었습니다. 값의 범위가 동일하지 않으면 관계를 해석하기가 쉽지 않을겁니다.

    그래서 이를 해결하고자 logit 변환을 사용해서 값의 범위를 동일하게 맞춰주고, 값의 해석이 유의미하도록 도와주는거죠. 즉, 다시 말해서 logit 변환은 [0, 1] 범위를 가지는 확률을 [-inf, inf] 범위를 가지는 값으로 변환해주는 변환입니다.
  3. 로그를 씌운 오즈비(Odds Ratio)의 역함수를 구해보세요. 시그모이드 함수가 눈에 보일겁니다.

딥러닝에서 쓰이는 logit은 매우 간단합니다. 모델의 출력값이 문제에 맞게 normalize 되었느냐의 여부입니다. 예를 들어, 10개의 이미지를 분류하는 문제에서는 주로 softmax 함수를 사용하는데요.

이때, 모델이 출력값으로 해당 클래스의 범위에서의 확률을 출력한다면, 이를 logit=False라고 표현할 수 있습니다. logit이 아니라 확률값이니까요(이건 저만의 표현인 점을 참고해서 읽어주세요).

반대로 모델의 출력값이 sigmoid 또는 linear를 거쳐서 확률이 아닌 값이 나오게 된다면, logit=True라고 표현할 수 있습니다. 말 그대로 확률이 아니라 logit이니까요.


다시 코드로 돌아가보죠. 먼저 코드를 해석하려면 두 가지 가정이 필요합니다.

(1) Loss Function이 CategoricalCrossEntropy이기 때문에 클래스 분류인 것을 알 수 있다.
(2) output 배열은 모델의 출력값을 나타내며, softmax 함수를 거쳐서 나온 확률값이다.

이제 우리는 왜 2번 코드에서 from_logits=False를 사용했는지 알 수 있습니다. 문제에 알맞게 normalize된 상태이기 때문입니다(값을 전부 더해보면 1입니다, 확률을 예로 든거에요). 반대로 from_logits=True일 때는 output 배열의 값이 logit 상태가 아니기 때문에 우리가 생각한 값과 다른 값이 나오게 된 것입니다. 

tensorflow github source, categorical_crossentropy function

텐서플로우 깃허브의 코드를 보아도 from_logits 인자에 따라 계산 방식이 다른 것을 볼 수 있습니다. from_logits가 True인 경우에는 nn.softmax_cross_entropy_with_logits 함수로 바로 넘어가는데요. 이를 쉽게 설명하면, 출력값이 logit 형태이기 때문에 softmax 함수(logit을 확률로 변환하는 과정) -> crossentropy의 과정을 거치는 함수입니다.


결론: 클래스 분류 문제에서 softmax 함수를 거치면 from_logits = False(default값),

그렇지 않으면 from_logits = True.

+ 텐서플로우에서는 softmax 함수를 거치지 않고, from_logits = True를 사용하는게 numerical stable하다고 설명하고 있다.

 

Reference

https://ko.wikipedia.org/wiki/%EB%A1%9C%EC%A7%80%EC%8A%A4%ED%8B%B1_%ED%9A%8C%EA%B7%80
https://www.tensorflow.org/api_docs/python/tf/keras/losses/CategoricalCrossentropy