为什么Keras/tensorflow的sigmoid和crossentropy精度低?

2023-11-27

我有以下简单的神经网络(仅具有 1 个神经元)来测试计算精度sigmoid激活 &binary_crossentropy喀拉斯:

model = Sequential()
model.add(Dense(1, input_dim=1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

为了简化测试,我手动将唯一权重设置为1,偏差设置为0,然后用2点训练集评估模型{(-a, 0), (a, 1)}, i.e.

y = numpy.array([0, 1])
for a in range(40):
    x = numpy.array([-a, a])
    keras_ce[a] = model.evaluate(x, y)[0] # cross-entropy computed by keras/tensorflow
    my_ce[a] = np.log(1+exp(-a)) # My own computation

我的问题:我发现了二元交叉熵(keras_ce)由 Keras/Tensorflow 计算得出的下限为1.09e-7 when a大约是。 16,如下图所示(蓝线)。随着“a”不断增长,它不会进一步减少。这是为什么?

enter image description here

该神经网络只有 1 个神经元,其权重设置为 1,偏差为 0。使用 2 点训练集{(-a, 0), (a, 1)}, the binary_crossentropy is just

-1/2 [ log(1 - 1/(1+exp(a)) ) + log( 1/(1+exp(-a)) ) ] = log(1+exp(-a))

所以交叉熵应该减少为a增加,如上面橙色(“我的”)所示。我可以更改一些 Keras/Tensorflow/Python 设置以提高其精度吗?或者我在某个地方弄错了?我将不胜感激任何建议/评论/答案。


TL;DR 版本:在计算损失函数时,由于数值稳定性,概率值(即 sigmoid 函数的输出)被剪裁。


如果你检查源代码,你会发现使用binary_crossentropy因为损失将导致致电binary_crossentropy函数于损失.py file:

def binary_crossentropy(y_true, y_pred):
    return K.mean(K.binary_crossentropy(y_true, y_pred), axis=-1)

正如您所看到的,它反过来调用等效的后端函数。如果使用 Tensorflow 作为后端,这将导致调用binary_crossentropy函数于张量流后端.py file:

def binary_crossentropy(target, output, from_logits=False):
    """ Docstring ..."""

    # 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)

如你看到的from_logits参数设置为False默认情况下。因此,if 条件的计算结果为 true,因此输出中的值被剪裁到范围内[epsilon, 1-epislon]。这就是为什么无论概率多小或多大,它都不可能小于epsilon并且大于1-epsilon。这解释了为什么输出binary_crossentropy损失也是有限度的。

现在,这里的 epsilon 是什么?它是一个非常小的常数,用于数值稳定性(例如防止被零除或未定义的行为等)。要找出它的值,您可以进一步检查源代码,您可以在通用.py file:

_EPSILON = 1e-7

def epsilon():
    """Returns the value of the fuzz factor used in numeric expressions.
    # Returns
        A float.
    # Example
    ```python
        >>> keras.backend.epsilon()
        1e-07
    ```
    """
    return _EPSILON

如果出于任何原因,您想要更高的精度,您也可以使用以下方法将 epsilon 值设置为较小的常数set_epsilon来自后端的功能:

def set_epsilon(e):
    """Sets the value of the fuzz factor used in numeric expressions.
    # Arguments
        e: float. New value of epsilon.
    # Example
    ```python
        >>> from keras import backend as K
        >>> K.epsilon()
        1e-07
        >>> K.set_epsilon(1e-05)
        >>> K.epsilon()
        1e-05
    ```
    """
    global _EPSILON
    _EPSILON = e

但是,请注意,将 epsilon 设置为极低的正值或零,可能会破坏整个 Keras 计算的稳定性。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么Keras/tensorflow的sigmoid和crossentropy精度低? 的相关文章

随机推荐