Dan*_*ias 130 machine-learning neural-network deep-learning conv-neural-network keras
我正在尝试培训CNN按主题对文本进行分类.当我使用binary_crossentropy时,我得到~80%acc,而categorical_crossentrop我得到~50%acc.
我不明白为什么会这样.这是一个多类问题,这是否意味着我必须使用分类,二进制结果是没有意义的?
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'))
Run Code Online (Sandbox Code Playgroud)
然后
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
Run Code Online (Sandbox Code Playgroud)
要么
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
Run Code Online (Sandbox Code Playgroud)
des*_*aut 164
分类和二元交叉熵之间明显的性能差异的原因是@ xtof54在他的答案中已经报道了,即:
evaluate当使用带有2个以上标签的binary_crossentropy时,使用Keras方法计算的精度是完全错误的
我想详细说明这一点,展示实际的根本问题,解释它,并提供补救措施.
这种行为不是一个bug; 根本原因是Keras实际上猜测使用哪种准确度是一个相当微妙和无证的问题,这取决于你选择的损失函数,当你简单地包含metrics=['accuracy']在你的模型编译中时.换句话说,当你的第一个编译选项
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
Run Code Online (Sandbox Code Playgroud)
是有效的,你的第二个:
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
Run Code Online (Sandbox Code Playgroud)
不会产生你所期望的,但原因不是使用二元交叉熵(至少在原理上,这是一个绝对有效的损失函数).
这是为什么?如果您检查指标的源代码,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
Run Code Online (Sandbox Code Playgroud)
为了解决这个问题,即使用确实二进制交叉熵作为损失函数(正如我所说的,没有错,至少在原则上),同时还获得了绝对的手头上的问题所需的精度,你应该问明确了categorical_accuracy在模型编译如下:
from keras.metrics import categorical_accuracy
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=[categorical_accuracy])
Run Code Online (Sandbox Code Playgroud)
在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
Run Code Online (Sandbox Code Playgroud)
系统设置:
Python version 3.5.3
Tensorflow version 1.2.1
Keras version 2.0.4
Run Code Online (Sandbox Code Playgroud)
更新:在我的帖子之后,我发现这个问题已经在这个答案中被识别出来了.
Why*_*ote 37
这一切都取决于您正在处理的分类问题的类型.主要有三类;
在第一种情况下,应该使用二进制交叉熵,并且应该将目标编码为单热矢量.
在第二种情况下,应该使用分类交叉熵,并且应该将目标编码为单热矢量.
在最后一种情况下,应该使用二进制交叉熵,并且应该将目标编码为单热矢量.每个输出神经元(或单位)被视为一个单独的随机二进制变量,整个输出向量的损失是单个二进制变量丢失的乘积.因此,它是每个单个输出单元的二元交叉熵的乘积.
二元交叉熵定义如下: 二元交叉熵 和分类交叉熵定义如下: 分类交叉熵
Ale*_*kin 33
我遇到了一个"倒置"的问题 - 我使用categorical_crossentropy(有2个类)并且使用binary_crossentropy很差.似乎问题是错误的激活功能.正确的设置是:
binary_crossentropy:sigmoid激活,标量目标categorical_crossentropy:softmax激活,单热编码目标Mar*_*jko 25
这是非常有趣的案例.实际上在您的设置中,以下陈述是正确的:
binary_crossentropy = len(class_id_index) * categorical_crossentropy
Run Code Online (Sandbox Code Playgroud)
这意味着最多一个乘法因子,您的损失是相等的.您在训练阶段观察到的奇怪行为可能是以下现象的一个例子:
adam- 学习率的值比训练开始时要小得多(这是因为这个优化器的性质).它使训练变得更慢,并且可以防止您的网络更糟糕地保留较差的局部最小值.这就是为什么这个常数因素可能有用的原因binary_crossentropy.在许多时期之后 - 学习率值大于categorical_crossentropy案例.当我注意到这种行为或/和使用以下模式调整类权重时,我通常会重新开始训练(和学习阶段)几次:
class_weight = 1 / class_frequency
Run Code Online (Sandbox Code Playgroud)
这使得来自较不频繁的类的损失在训练开始时和在优化过程的另一部分中平衡主要类损失的影响.
编辑:
实际上 - 我检查过,即使在数学的情况下:
binary_crossentropy = len(class_id_index) * categorical_crossentropy
Run Code Online (Sandbox Code Playgroud)
应该保持 - 如果keras它不是真的,因为keras自动归一化所有输出总结1.这就是这种奇怪行为背后的真正原因,因为在多分类的情况下,这种规范化会损害培训.
xto*_*f54 15
在评论@Marcin回答后,我更仔细地检查了我的一个学生代码,在那里我发现了同样奇怪的行为,即使只有2个时代!(所以@ Marcin的解释在我的情况下不太可能).
我发现答案实际上非常简单:evaluate当使用带有2个以上标签的binary_crossentropy时,使用Keras方法计算的准确性是完全错误的.您可以通过自己重新计算准确性来检查(首先调用Keras方法"预测",然后计算预测返回的正确答案的数量):您获得的真实准确度远低于Keras"评估"的准确度.
小智 6
一个多类设置下的简单示例来说明
假设您有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的最低性能。
| 归档时间: |
|
| 查看次数: |
140535 次 |
| 最近记录: |