为什么二进制交叉熵和分类交叉熵对同一问题给出不同的性能?
0 768
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'])

我不明白为什么使用二进制得到好的结果,而使用分类交叉熵不好。

收藏
2021-02-01 11:13 更新 karry •  2600
共 1 个回答
高赞 时间
0

简短来说,当使用带有超过2个标签的binary_crossentropy时,用Keras方法计算出的精度是完全错误的。

我想对此进行详细说明,加以解释,并提供补救措施。

这不是bug。根本原因是这是一个相当微妙的问题。即Keras实际上是猜测使用哪种精度的,这取决于当你在模型编译metrics=['accuracy'] 时选择的损失函数。

换句话说,当你的第一个编译

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

是有效的,你的第二个:

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

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

这是为什么?如果你检查度量源代码,Keras不会定义一个准确的度量。但是在binary_accuracy 和 categorical_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

Via:https://stackoverflow.com/a/46038271/14964791

收藏
2021-02-01 11:37 更新 anna •  3230