小编典典

为什么 binary_crossentropy 和 categorical_crossentropy 对同一个问题给出不同的表现?

all

我正在尝试训练 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'])

直观地说,为什么我要使用分类交叉熵是有道理的,我不明白为什么我用二进制得到好的结果,而用分类的结果却很差。


阅读 66

收藏
2022-06-29

共1个答案

小编典典

分类和二元交叉熵之间存在明显性能差异的原因是用户 xtof54在他的回答中已经报告了以下)内容,即:

evaluate当使用带有超过 2 个标签的 binary_crossentropy 时,使用Keras 方法计算的准确度完全错误

我想详细说明这一点,展示实际的潜在问题,解释它,并提供补救措施。

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

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

更新
:在我的帖子之后,我发现这个问题已经在这个答案中确定了。

2022-06-29