为什么binary_crossentropy和categorical_crossentropy对同一问题给出不同的性能?
conv-neural-network
deep-learning
keras
machine-learning
7
0

我正在尝试训练CNN以按主题对文本进行分类。当我使用二进制交叉熵时,我的精度约为80%,而使用分类交叉熵时,我的精度约为50%。

我不明白为什么会这样。这是一个多类问题,这并不意味着我必须使用分类交叉熵,而具有二进制交叉熵的结果却毫无意义?

model.add(embedding_layer)
model.add(Dropout(0.25))
# convolution layers
model.add(Conv1D(nb_filter=32,
                    filter_length=4,
                    border_mode='valid',
                    activation='relu'))
model.add(MaxPooling1D(pool_length=2))
# dense layers
model.add(Flatten())
model.add(Dense(256))
model.add(Dropout(0.25))
model.add(Activation('relu'))
# output layer
model.add(Dense(len(class_id_index)))
model.add(Activation('softmax'))

然后我使用categorical_crossentropy作为损失函数像这样编译它:

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

要么

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

从直觉上讲,为什么我要使用分类交叉熵是有意义的,我不明白为什么使用二进制得到好的结果,而使用分类不好的原因。

参考资料:
Stack Overflow
收藏
评论
共 9 个回答
高赞 时间 活跃

查看方程式,您会发现二元互熵不仅惩罚那些标签= 1,预测= 0,而且还惩罚那些标签= 0,预测= 1。

但是, 分类交叉熵只会惩罚那些标签= 1,但是预测=1。这就是为什么我们假设只有一个标签为正的原因。

收藏
评论

在评论@Marcin答案之后,我更仔细地检查了我的一个学生代码,即使在2个纪元之后,我也发现了同样的奇怪行为! (因此,就我而言,@ Marcin的解释不太可能)。

而且我发现答案实际上非常简单:当使用带有2个以上标签的binary_crossentropy时,用Keras方法evaluate的精确度是完全错误的。您可以自己重新计算准确性(通过调用Keras方法“预测”,然后计算由预测返回的正确答案的数量)来检查:您获得的真实准确性要比Keras“评估”的准确性低得多。

收藏
评论

我遇到了一个“倒置”问题-categorical_crossentropy(具有2个类)获得了良好的结果,binary_crossentropy得到了较差的结果。似乎问题在于激活功能错误。正确的设置是:

  • 对于binary_crossentropy :S型激活,标量目标
  • 用于categorical_crossentropy :softmax激活,一热编码目标
收藏
评论

当使用categorical_crossentropy损失时,您的目标应采用分类格式(例如,如果您有10个类别,则每个样本的目标应为全零的10维向量,但与该类别对应的索引处的索引为1除外)例子)。

收藏
评论

这完全取决于您要处理的分类问题的类型。主要分为三类

  • 二进制分类(两个目标类别),
  • 多类别分类(两个以上的排他目标),
  • 多标签分类(两个以上的非排他目标),其中可以同时启用多个目标类别。

在第一种情况下,应使用二进制交叉熵,并且应将目标编码为单热向量。

在第二种情况下,应使用分类交叉熵,并且应将目标编码为单热点向量。

在后一种情况下,应使用二进制交叉熵,并且应将目标编码为单热向量。每个输出神经元(或单位)都被视为一个单独的随机二进制变量,整个输出矢量的损失是单个二进制变量损失的乘积。因此,它是每个单个输出单元的二进制交叉熵的乘积。

二进制交叉熵定义为

在此处输入图片说明

类别交叉熵定义为

在此处输入图片说明

其中c是遍历类数的索引

收藏
评论

@ xtof54在他的答案中已经报告了类别和二进制交叉熵之间明显的性能差异的原因,即:

与Keras方法计算的准确度evaluate是完全错误使用binary_crossentropy具有多于2个标签时

我想对此进行详细说明,说明实际的根本问题,加以解释,并提供补救措施。

这不是错误。根本原因是当您在模型编译中仅包含metrics=['accuracy']时,Keras如何根据所选择的损失函数实际猜测要使用哪种精度,这是一个相当微妙且未记录的问题。换句话说,当您的第一个编译选项

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

是有效的,您的第二个是:

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

不会产生您期望的结果,但是原因不是使用二进制交叉熵(至少在原则上是绝对有效的损失函数)。

这是为什么?如果检查度量标准源代码 ,那么Keras不会定义单个准确性度量标准,而是定义几个不同的度量标准,其中有binary_accuracycategorical_accuracy 。会发生什么引擎盖下的是,既然你选择了二进制交叉熵作为损失函数,并没有规定特定的准确性度量,Keras(错误...)推断出你感兴趣的binary_accuracy ,这是它的回报-实际上,您对categorical_accuracy感兴趣。

让我们使用Keras中的MNIST CNN示例进行以下修改来验证是否是这种情况:

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])  # WRONG way

model.fit(x_train, y_train,
          batch_size=batch_size,
          epochs=2,  # only 2 epochs, for demonstration purposes
          verbose=1,
          validation_data=(x_test, y_test))

# Keras reported accuracy:
score = model.evaluate(x_test, y_test, verbose=0) 
score[1]
# 0.9975801164627075

# Actual accuracy calculated manually:
import numpy as np
y_pred = model.predict(x_test)
acc = sum([np.argmax(y_test[i])==np.argmax(y_pred[i]) for i in range(10000)])/10000
acc
# 0.98780000000000001

score[1]==acc
# False    

为了解决这个问题,即使用二进制交叉熵作为损失函数(如我所说,至少在原则上没有错),同时仍然可以解决当前问题所要求的绝对准确度,您应该明确地要求categorical_accuracy该模型的编译如下:

from keras.metrics import categorical_accuracy
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=[categorical_accuracy])

在MNIST的示例中,经过如上所示的训练,评分和预测测试集后,两个指标现在相同,它们应该是:

# Keras reported accuracy:
score = model.evaluate(x_test, y_test, verbose=0) 
score[1]
# 0.98580000000000001

# Actual accuracy calculated manually:
y_pred = model.predict(x_test)
acc = sum([np.argmax(y_test[i])==np.argmax(y_pred[i]) for i in range(10000)])/10000
acc
# 0.98580000000000001

score[1]==acc
# True    

系统设置:

Python version 3.5.3
Tensorflow version 1.2.1
Keras version 2.0.4

更新 :发布后,我发现此答案中已发现此问题

收藏
评论

一个多类设置下的简单示例来说明

假设您有4个类(onehot编码),下面只是一个预测

true_label = [0,1,0,0]预测_label = [0,0,1,0]

当使用categorical_crossentropy时,精度仅为0,它只在乎您是否正确设置了相关的类。

但是,当使用binary_crossentropy时,将为所有类别计算精度,该预测的准确度将为50%。最终结果将是两种情况下个人准确度的平均值。

对于多类问题(类是互斥的),建议使用categorical_crossentropy;对于多标签问题,建议使用binary_crossentropy。

收藏
评论

由于它是一个多类问题,因此您必须使用categorical_crossentropy,二元交叉熵会产生虚假结果,很可能仅会评估前两个类。

多类问题的50%可能很好,具体取决于类的数量。如果您有n个类别,则通过输出随机类别可以获得100 / n的最低性能。

收藏
评论

这是一个非常有趣的案例。实际上,在您的设置中,以下语句是正确的:

binary_crossentropy = len(class_id_index) * categorical_crossentropy

这意味着,直到一个恒定的乘法因子,您的损失才是等效的。您在训练阶段观察到的怪异行为可能是以下现象的一个示例:

  1. 在开始时,最频繁的课程是损失的主要控制者-因此网络正在学习每个示例的主要预测方法。
  2. 在学习了最频繁的模式后,便开始在较不频繁的班级之间进行区分。但是,当您使用adam ,学习率的值将比培训开始时的值小得多(这是由于此优化器的性质所致)。这会使训练变慢,并防止您的网络减少例如留下较差的本地最小值的可能性。

因此,在binary_crossentropy情况下,此常数可能会有所帮助。在许多次之后-学习率值大于categorical_crossentropy情况。当我注意到这种行为或/和使用以下模式调整班级权重时,我通常会重启训练(和学习阶段)几次:

class_weight = 1 / class_frequency

这使得在训练开始时以及在优化过程的另一部分中,频率较低的班级失去了平衡优势班级损失的影响。

编辑:

实际上-即使在数学情况下,我也进行了检查:

binary_crossentropy = len(class_id_index) * categorical_crossentropy

应该保留-如果是keras ,则不正确,因为keras会自动将所有输出归一化为1 。这是这种奇怪行为背后的实际原因,因为在多分类的情况下,这种归一化会损害训练。

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号