实施二元交叉熵损失给出了与 Tensorflow 不同的答案
Implementing Binary Cross Entropy loss gives different answer than Tensorflow's
我正在使用 Raw python 实现 Binary Cross-Entropy 损失函数,但它给我的答案与 Tensorflow 截然不同。
这是我从 Tensorflow 得到的答案:-
import numpy as np
from tensorflow.keras.losses import BinaryCrossentropy
y_true = np.array([1., 1., 1.])
y_pred = np.array([1., 1., 0.])
bce = BinaryCrossentropy()
loss = bce(y_true, y_pred)
print(loss.numpy())
输出:
>>> 5.1416497230529785
据我所知,二元交叉熵的公式是这样的:
我用原始 python 实现了相同的方法,如下所示:
def BinaryCrossEntropy(y_true, y_pred):
m = y_true.shape[1]
y_pred = np.clip(y_pred, 1e-7, 1 - 1e-7)
# Calculating loss
loss = -1/m * (np.dot(y_true.T, np.log(y_pred)) + np.dot((1 - y_true).T, np.log(1 - y_pred)))
return loss
print(BinaryCrossEntropy(np.array([1, 1, 1]).reshape(-1, 1), np.array([1, 1, 0]).reshape(-1, 1)))
但是从这个函数我得到的损失值为:
>>> [[16.11809585]]
怎样才能得到正确答案?
您的实施存在一些问题。这是正确的 numpy
.
def BinaryCrossEntropy(y_true, y_pred):
y_pred = np.clip(y_pred, 1e-7, 1 - 1e-7)
term_0 = (1-y_true) * np.log(1-y_pred + 1e-7)
term_1 = y_true * np.log(y_pred + 1e-7)
return -np.mean(term_0+term_1, axis=0)
print(BinaryCrossEntropy(np.array([1, 1, 1]).reshape(-1, 1),
np.array([1, 1, 0]).reshape(-1, 1)))
[5.14164949]
请注意,在 tf. keras
模型训练期间,最好使用 keras
后端功能。您可以使用 keras
后端实用程序以相同的方式实现它。
def BinaryCrossEntropy(y_true, y_pred):
y_pred = K.clip(y_pred, K.epsilon(), 1 - K.epsilon())
term_0 = (1 - y_true) * K.log(1 - y_pred + K.epsilon())
term_1 = y_true * K.log(y_pred + K.epsilon())
return -K.mean(term_0 + term_1, axis=0)
print(BinaryCrossEntropy(
np.array([1., 1., 1.]).reshape(-1, 1),
np.array([1., 1., 0.]).reshape(-1, 1)
).numpy())
[5.14164949]
在tf.keras.losses.BinaryCrossentropy()
的构造函数中,你会注意到,
tf.keras.losses.BinaryCrossentropy(
from_logits=False, label_smoothing=0, reduction=losses_utils.ReductionV2.AUTO,
name='binary_crossentropy'
)
默认参数 reduction
很可能具有值 Reduction.SUM_OVER_BATCH_SIZE
,如前所述 here。假设我们的模型输出的形状是 [ 1 , 3 ]
。意思是,我们的批量大小是 1,输出 dims 是 3(这并不意味着有 3 类)。我们需要计算第 0 个轴上的平均值,即批量维度。
我会用代码说清楚,
import tensorflow as tf
import numpy as np
y_true = np.array( [1., 1., 1.] ).reshape( 1 , 3 )
y_pred = np.array( [1., 1., 0.] ).reshape( 1 , 3 )
bce = tf.keras.losses.BinaryCrossentropy( from_logits=False , reduction=tf.keras.losses.Reduction.SUM_OVER_BATCH_SIZE )
loss = bce( y_true, y_pred )
print(loss.numpy())
输出是,
5.1416497230529785
Binary Crossentropy的表达式与问题中提到的相同。 N指批量大小。
我们现在自己实施 BCE。首先,我们裁剪模型的输出,将 max
设置为 tf.keras.backend.epsilon()
,将 min
设置为 1 - tf.keras.backend.epsilon()
。 tf.keras.backend.epsilon()
的值为1e-7.
y_pred = np.clip( y_pred , tf.keras.backend.epsilon() , 1 - tf.keras.backend.epsilon() )
使用 BCE 表达式,
p1 = y_true * np.log( y_pred + tf.keras.backend.epsilon() )
p2 = ( 1 - y_true ) * np.log( 1 - y_pred + tf.keras.backend.epsilon() )
print( p1 )
print( p2 )
输出,
[[ 0. 0. -15.42494847]]
[[-0. -0. 0.]]
请注意形状仍然保留。 np.dot
会将它们变成两个元素的数组,即形状 [ 1 , 2 ]
(如您的实现中所示)。
最后,我们将它们相加并使用 np.mean()
在批量维度上计算它们的平均值,
o = -np.mean( p1 + p2 )
print( o )
输出是,
5.141649490132791
您可以通过打印每个术语的 shape
来检查实施中的问题。
我正在使用 Raw python 实现 Binary Cross-Entropy 损失函数,但它给我的答案与 Tensorflow 截然不同。 这是我从 Tensorflow 得到的答案:-
import numpy as np
from tensorflow.keras.losses import BinaryCrossentropy
y_true = np.array([1., 1., 1.])
y_pred = np.array([1., 1., 0.])
bce = BinaryCrossentropy()
loss = bce(y_true, y_pred)
print(loss.numpy())
输出:
>>> 5.1416497230529785
据我所知,二元交叉熵的公式是这样的:
我用原始 python 实现了相同的方法,如下所示:
def BinaryCrossEntropy(y_true, y_pred):
m = y_true.shape[1]
y_pred = np.clip(y_pred, 1e-7, 1 - 1e-7)
# Calculating loss
loss = -1/m * (np.dot(y_true.T, np.log(y_pred)) + np.dot((1 - y_true).T, np.log(1 - y_pred)))
return loss
print(BinaryCrossEntropy(np.array([1, 1, 1]).reshape(-1, 1), np.array([1, 1, 0]).reshape(-1, 1)))
但是从这个函数我得到的损失值为:
>>> [[16.11809585]]
怎样才能得到正确答案?
您的实施存在一些问题。这是正确的 numpy
.
def BinaryCrossEntropy(y_true, y_pred):
y_pred = np.clip(y_pred, 1e-7, 1 - 1e-7)
term_0 = (1-y_true) * np.log(1-y_pred + 1e-7)
term_1 = y_true * np.log(y_pred + 1e-7)
return -np.mean(term_0+term_1, axis=0)
print(BinaryCrossEntropy(np.array([1, 1, 1]).reshape(-1, 1),
np.array([1, 1, 0]).reshape(-1, 1)))
[5.14164949]
请注意,在 tf. keras
模型训练期间,最好使用 keras
后端功能。您可以使用 keras
后端实用程序以相同的方式实现它。
def BinaryCrossEntropy(y_true, y_pred):
y_pred = K.clip(y_pred, K.epsilon(), 1 - K.epsilon())
term_0 = (1 - y_true) * K.log(1 - y_pred + K.epsilon())
term_1 = y_true * K.log(y_pred + K.epsilon())
return -K.mean(term_0 + term_1, axis=0)
print(BinaryCrossEntropy(
np.array([1., 1., 1.]).reshape(-1, 1),
np.array([1., 1., 0.]).reshape(-1, 1)
).numpy())
[5.14164949]
在tf.keras.losses.BinaryCrossentropy()
的构造函数中,你会注意到,
tf.keras.losses.BinaryCrossentropy(
from_logits=False, label_smoothing=0, reduction=losses_utils.ReductionV2.AUTO,
name='binary_crossentropy'
)
默认参数 reduction
很可能具有值 Reduction.SUM_OVER_BATCH_SIZE
,如前所述 here。假设我们的模型输出的形状是 [ 1 , 3 ]
。意思是,我们的批量大小是 1,输出 dims 是 3(这并不意味着有 3 类)。我们需要计算第 0 个轴上的平均值,即批量维度。
我会用代码说清楚,
import tensorflow as tf
import numpy as np
y_true = np.array( [1., 1., 1.] ).reshape( 1 , 3 )
y_pred = np.array( [1., 1., 0.] ).reshape( 1 , 3 )
bce = tf.keras.losses.BinaryCrossentropy( from_logits=False , reduction=tf.keras.losses.Reduction.SUM_OVER_BATCH_SIZE )
loss = bce( y_true, y_pred )
print(loss.numpy())
输出是,
5.1416497230529785
Binary Crossentropy的表达式与问题中提到的相同。 N指批量大小。
我们现在自己实施 BCE。首先,我们裁剪模型的输出,将 max
设置为 tf.keras.backend.epsilon()
,将 min
设置为 1 - tf.keras.backend.epsilon()
。 tf.keras.backend.epsilon()
的值为1e-7.
y_pred = np.clip( y_pred , tf.keras.backend.epsilon() , 1 - tf.keras.backend.epsilon() )
使用 BCE 表达式,
p1 = y_true * np.log( y_pred + tf.keras.backend.epsilon() )
p2 = ( 1 - y_true ) * np.log( 1 - y_pred + tf.keras.backend.epsilon() )
print( p1 )
print( p2 )
输出,
[[ 0. 0. -15.42494847]]
[[-0. -0. 0.]]
请注意形状仍然保留。 np.dot
会将它们变成两个元素的数组,即形状 [ 1 , 2 ]
(如您的实现中所示)。
最后,我们将它们相加并使用 np.mean()
在批量维度上计算它们的平均值,
o = -np.mean( p1 + p2 )
print( o )
输出是,
5.141649490132791
您可以通过打印每个术语的 shape
来检查实施中的问题。