바이너리 classification 문제를 풀려고하면 둘 중 어떤걸 써야하나.. 뭐가 다른가 궁금해서 찾아보았다
우선 binary_crossentropy 소스
def binary_crossentropy(target, output, from_logits=False):
"""Binary crossentropy between an output tensor and a target tensor.
# Arguments
target: A tensor with the same shape as `output`.
output: A tensor.
from_logits: Whether `output` is expected to be a logits tensor.
By default, we consider that `output`
encodes a probability distribution.
# Returns
A tensor.
"""
# Note: tf.nn.sigmoid_cross_entropy_with_logits
# expects logits, Keras expects probabilities.
if not from_logits:
# transform back to logits
_epsilon = _to_tensor(epsilon(), output.dtype.base_dtype)
output = tf.clip_by_value(output, _epsilon, 1 - _epsilon)
output = tf.log(output / (1 - output))
return tf.nn.sigmoid_cross_entropy_with_logits(labels=target,
logits=output)
코드를 보면 기본적으로 logits=False로 되어있다.
따라서 if not form_logits: 구문을 보면 transform back to logits이라고 되어있다.
다시말해서 inverse sigmoid를 해줌으로서 확률값을 logit값으로 변경해주는 것이다.
$$ y = 1/(1+ \exp(-x)) \longleftrightarrow x = \ln(y/(1-y)) $$
혹시 logit이 뭔지 모른다면 아래링크가 도움이 될 것이다.
그 이유는 return에 있는 sigmoid_cross_entropy_with_logits 함수 에서
z * -log(sigmoid(x)) + (1 - z) * -log(1 - sigmoid(x)) 이런 짓을 해주기 때문이다...!!
엄청 비효율적이다... 굳이 sigmoid한걸 inverse해서 다시 sigmoid 해준다
아마도 tf backend로 keras를 사용하려하다보니 이렇게 된것 같다
어쨌든 binary_crossentropy를 쓰면서 from_logits옵션을 따로 주지 않는 경우에는 ouput layer에 sigmoid를 추가해주어야 한다
만약 from_logits = True 으로 한다면 마지막에 sigmoid activation을 하지 않아야한다.
이번에는 categorical_crossentropy를 보자
def categorical_crossentropy(target, output, from_logits=False, axis=-1):
"""Categorical crossentropy between an output tensor and a target tensor.
# Arguments
target: A tensor of the same shape as `output`.
output: A tensor resulting from a softmax
(unless `from_logits` is True, in which
case `output` is expected to be the logits).
from_logits: Boolean, whether `output` is the
result of a softmax, or is a tensor of logits.
axis: Int specifying the channels axis. `axis=-1`
corresponds to data format `channels_last`,
and `axis=1` corresponds to data format
`channels_first`.
# Returns
Output tensor.
# Raises
ValueError: if `axis` is neither -1 nor one of
the axes of `output`.
"""
output_dimensions = list(range(len(output.get_shape())))
if axis != -1 and axis not in output_dimensions:
raise ValueError(
'{}{}{}'.format(
'Unexpected channels axis {}. '.format(axis),
'Expected to be -1 or one of the axes of `output`, ',
'which has {} dimensions.'.format(len(output.get_shape()))))
# Note: tf.nn.softmax_cross_entropy_with_logits
# expects logits, Keras expects probabilities.
if not from_logits:
# scale preds so that the class probas of each sample sum to 1
output /= tf.reduce_sum(output, axis, True)
# manual computation of crossentropy
_epsilon = _to_tensor(epsilon(), output.dtype.base_dtype)
output = tf.clip_by_value(output, _epsilon, 1. - _epsilon)
return - tf.reduce_sum(target * tf.log(output), axis)
else:
return tf.nn.softmax_cross_entropy_with_logits(labels=target,
logits=output)
마찬가지로 logit옵션이 기본적으로 False이며 return값은 nagative likelihood이다.
또한 output sum을 1로 scaling 해주긴 하지만, 확률값으로의 변환은 따로 없기 때문에
multiclass classification 문제를 해결하고자 한다면 마지막에 softmax를 해주어야한다.
from_logits=True로 하면 softmax 가 자동으로 적용된다.
결론적으로 둘의 차이는 output layer가 sigmoid이냐 softmax이냐 라고 볼 수 있으며
내가 가진 label 값이 0 or 1 이면서 sigmoid_cross_entropy를 loss로 하고 싶으면 binary_crossentropy 를 쓰면 된다
내가 가진 label이 [0,1] or [1,0] 의 형태이면서 softmax_cross_entropy를 loss로 하고자 할 때는 categorical_crossentropy를 쓰면 된다
label 이 0 or 1 인데 softmax_cross_entropy를 쓰고싶으면 sparse_categorical_crossentropy를 쓰면 된다
binary_crossentropy는 logistic regression 아니면 별로 쓸일이 없을 거 같긴하다.
웬만하면 categorical_crossentropy나 sparse_categorical_crossentropy를 쓸듯
'Study > 머신러닝' 카테고리의 다른 글
Tensorflow CuDNN RNN vs 그냥 RNN 비교 (0) | 2020.05.12 |
---|---|
Bazel을 이용해 Tensorflow Lite 빌드해보기 (1) | 2020.03.31 |
Tensorflow2.0 / CUDA / Nvidia driver 호환 (0) | 2020.02.14 |
docker 에서 한국어 설정하기 (0) | 2020.02.05 |
Depthwise Separable Convolution 이해 (0) | 2019.12.05 |
댓글