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

or

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

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


当前回答

这是一个很有趣的案例。实际上,在你的设置中,下面的语句是正确的:

binary_crossentropy = len(class_id_index) * categorical_crossentropy

这意味着在一个常数乘法因子之前,你的损失是相等的。你在训练阶段观察到的奇怪行为可能是以下现象的一个例子:

At the beginning the most frequent class is dominating the loss - so network is learning to predict mostly this class for every example. After it learnt the most frequent pattern it starts discriminating among less frequent classes. But when you are using adam - the learning rate has a much smaller value than it had at the beginning of training (it's because of the nature of this optimizer). It makes training slower and prevents your network from e.g. leaving a poor local minimum less possible.

这就是为什么这个常量因子在binary_crossentropy的情况下可能有用。在许多个epoch之后-学习率值大于在categorical_crossentropy情况。当我注意到这种行为或/和使用以下模式调整类权重时,我通常会重新开始训练(和学习阶段)几次:

class_weight = 1 / class_frequency

这使得不太频繁的类的损失在训练开始时和优化过程的进一步部分平衡了主导类损失的影响。

编辑:

事实上,我检查了,即使在数学方面

binary_crossentropy = len(class_id_index) * categorical_crossentropy

应该成立——对于keras,这不是真的,因为keras会自动将所有输出归一化为和为1。这就是这种奇怪行为背后的实际原因,因为在多分类的情况下,这种规范化会损害训练。

其他回答

由于这是一个多类问题,你必须使用categorical_crossentropy,二元交叉熵会产生虚假的结果,很可能只会评估前两个类。

对于一个多类问题,50%的概率是相当不错的,这取决于类的数量。如果您有n个类,那么100/n是通过输出一个随机类可以获得的最小性能。

我遇到了一个“倒置”的问题-我用categorical_crossentropy(2个类)得到了很好的结果,而用binary_crossentropy得到了很差的结果。看来问题出在激活函数错了。正确的设置是:

对于binary_crossentropy: sigmoid激活,标量目标 对于categorical_crossentropy: softmax激活,单热编码目标

这是一个很有趣的案例。实际上,在你的设置中,下面的语句是正确的:

binary_crossentropy = len(class_id_index) * categorical_crossentropy

这意味着在一个常数乘法因子之前,你的损失是相等的。你在训练阶段观察到的奇怪行为可能是以下现象的一个例子:

At the beginning the most frequent class is dominating the loss - so network is learning to predict mostly this class for every example. After it learnt the most frequent pattern it starts discriminating among less frequent classes. But when you are using adam - the learning rate has a much smaller value than it had at the beginning of training (it's because of the nature of this optimizer). It makes training slower and prevents your network from e.g. leaving a poor local minimum less possible.

这就是为什么这个常量因子在binary_crossentropy的情况下可能有用。在许多个epoch之后-学习率值大于在categorical_crossentropy情况。当我注意到这种行为或/和使用以下模式调整类权重时,我通常会重新开始训练(和学习阶段)几次:

class_weight = 1 / class_frequency

这使得不太频繁的类的损失在训练开始时和优化过程的进一步部分平衡了主导类损失的影响。

编辑:

事实上,我检查了,即使在数学方面

binary_crossentropy = len(class_id_index) * categorical_crossentropy

应该成立——对于keras,这不是真的,因为keras会自动将所有输出归一化为和为1。这就是这种奇怪行为背后的实际原因,因为在多分类的情况下,这种规范化会损害训练。

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

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

True_label = [0,1,0,0] Predicted_label = [0,0,1,0]

当使用categorical_crossentropy时,准确率仅为0,它只关心你是否得到了相关的类。

然而,当使用binary_crossentropy时,对所有类都计算精度,这个预测的准确率为50%。最终结果将是两种情况下个体准确度的平均值。

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

在评论@Marcin的答案后,我更仔细地检查了我的一个学生的代码,在那里我发现了同样奇怪的行为,即使只有2个纪元!(所以@Marcin的解释在我的情况下不太可能)。

我发现答案其实很简单:当使用超过2个标签的binary_crossentropy时,用Keras方法evaluate计算的准确性完全错误。你可以自己重新计算准确率(首先调用Keras方法“predict”,然后计算由predict返回的正确答案的数量):你得到了真正的准确率,这比Keras的“evaluate”要低得多。