我正在尝试训练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'))
然后,我使用分类交叉熵作为损失函数来编译它:
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
或
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
直觉上,我想使用分类交叉熵是有道理的,我不明白为什么我用二进制得到的结果好,而用分类得到的结果差。
我遇到了一个“颠倒”的问题-我在分类交叉熵(2个类)方面得到了很好的结果,而在二进制交叉熵方面却很差。似乎问题出在错误的激活功能上。正确的设置为:
这完全取决于您处理的分类问题的类型。主要有三类
在第一种情况下,应使用二进制交叉熵,并将目标编码为一个热向量。
在第二种情况下,应使用分类交叉熵,目标应编码为one-Hot向量。
在最后一种情况下,应使用二进制交叉熵,并将目标编码为一个热向量。每个输出神经元(或单元)被视为一个单独的随机二进制变量,整个输出向量的损失是单个二进制变量损失的乘积。因此,它是每个单个输出单元的二进制交叉熵的乘积。
二元交叉熵定义为
分类交叉熵定义为
其中c
是运行在类C
数量上的索引。
分类之间明显的性能差异的原因
当使用具有两个以上标签的二进制交叉熵时,使用Keras方法计算的精度显然是错误的
我想对此进行更多的阐述,展示实际的根本问题,解释它,并提供补救措施。
这种行为不是bug;根本原因是一个相当微妙的
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
有效,您的第二个:
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
不会产生您期望的结果,但原因不是使用二进制交叉熵(至少在原则上,这是一个绝对有效的损失函数)。
为什么会这样?如果检查度量源代码,Keras不会定义单个精度度量,而是定义几个不同的度量,其中包括二进制精度和分类精度。在幕后发生的事情是,由于您选择了二进制交叉熵作为损失函数,并且没有指定特定的精度度量,Keras(错误地…)推断您对二进制精度感兴趣,这就是它返回的结果,而实际上您对分类精度感兴趣。
让我们使用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
为了解决这一问题,即使用二进制交叉熵作为损失函数(如我所说,至少在原则上,这没有错),同时仍能获得当前问题所需的分类精度,您应该在模型编译中明确要求分类精度,如下所示:
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
更新:在我的帖子之后,我发现这个问题已经在这个答案中被发现了。
问题内容: 查看以下代码,并请解释为什么该方法和函数给出两个不同的输出。 输出: 问题答案: 计算子字符串的非重叠出现次数: 返回substring sub 的不重叠出现的次数。 在字符串中恰好有一个这样的子字符串出现的位置:就在开头。因此计数 应该 返回。 一般来说,空字符串将匹配给定字符串中的 所有位置 ,包括开始和结束处的正确 位置 ,因此计数应 始终 为长度加1: 这是因为空字符串被认为存
Java 中的字节长度为 8 位。一个
类别:账户余额 我已经把这两个类都放在Balance.java和Account tBalance.java.这两个文件都在E:/程序/MyPack. Balance.java编译没有错误但是当我编译Account tBalance.java它给出错误:找不到符号"平衡". 我无法弄清楚为什么当两个类都在同一个包中声明时? 我正在使用javac B从MyPack编译alance.javajavac
问题内容: 我以为运算符检查对象的相等性。但事实并非如此: 问题答案: *Python *将相同的内存 位置用于方法和,这是*两个对象,它们的生命周期不重叠,因此对它们返回相同的标识。请参阅下面的详细说明。 从is运算符的文档中: 运算符是否测试对象标识:并且仅当x和y是同一对象时,x is y才是true。 从ID的文档中 返回对象的“身份”。这是一个整数(或长整数),在此对象的生存期内,此整数
问题内容: public class Test { public static void main(String[] args) { int i = 10; i = i++; System.out.println(“value of i is : ” + i); } } 输出为: 当我在执行类似的代码时,输出为。 问题答案: 关于此问题,这是未定义的行为,因为您试图在同一行的同一序列点内多次修改同
<代码>car\U gear字段在数据库中填写为“stick”(斗杆)。在图像标记后,输出更改为“自动” 为什么结果是$car\u result1-