Keras中的自定义损失函数可惩罚假阴性

时间:2018-10-08 05:33:10

标签: machine-learning keras deep-learning gradient-descent loss-function

我正在研究一个医学数据集,在该数据集中我要尽可能减少假阴性。对我来说,“实际上没有疾病的时候疾病”的预测对我来说是可以的,但是对“实际上没有疾病的时候没有疾病”的预测对我来说是不可接受的。也就是说,我对FP没问题,但对FN没什么看法。

经过研究,我发现了Keeping higher learning rate for one classusing class weightsensemble learning with specificity/sensitivity等方法。

我使用class_weight = {0 : 0.3,1: 0.7}之类的类权重然后调用model.fit(class_weights=class_weight)达到了接近预期的结果。这给了我非常低的FN,却给了我很高的FP。我正在尝试尽可能减少FP,以保持FN非常低。

我正在努力使用Keras编写自定义损失函数,这将有助于我惩罚误报。感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

我将简要介绍我们要解决的概念。

召回

所有为阳性的中,我们的模型预测为多少?

所有肯定的结果= positive

我们的模型说的是肯定的= said positive

recall

由于召回与FN成反比,因此提高召回率会降低FN。

专长

所有为阴性的中,我们的模型预测有多少为阴性?

所有否定= negative

我们的模型说的是负面的= said negative

specificity

由于召回与FP成反比,因此提高召回率会降低FP。

在您的下一次搜索中,或您执行的与分类相关的任何活动中,知道这些都会使您在交流和理解上更具优势。


解决方案

所以。正如您已经意识到的,这两个概念是相反的。这意味着增加一个可能会减少另一个

由于您希望在召回时获得优先级,但又不想过多地放弃其具体性,因此可以将两者和属性权重结合起来。遵循this answer中明确说明的内容:

import numpy as np
import keras.backend as K

def binary_recall_specificity(y_true, y_pred, recall_weight, spec_weight):

    TN = np.logical_and(K.eval(y_true) == 0, K.eval(y_pred) == 0)
    TP = np.logical_and(K.eval(y_true) == 1, K.eval(y_pred) == 1)

    FP = np.logical_and(K.eval(y_true) == 0, K.eval(y_pred) == 1)
    FN = np.logical_and(K.eval(y_true) == 1, K.eval(y_pred) == 0)

    # Converted as Keras Tensors
    TN = K.sum(K.variable(TN))
    FP = K.sum(K.variable(FP))

    specificity = TN / (TN + FP + K.epsilon())
    recall = TP / (TP + FN + K.epsilon())

    return 1.0 - (recall_weight*recall + spec_weight*specificity)

通知recall_weightspec_weight吗?它们是我们归因于每个指标的权重。对于分发约定,它们应始终添加到1.0¹中,例如recall_weight=0.9specificity_weight=0.1。目的是让您了解最适合您需求的比例。

但是Keras的损失函数必须仅接受(y_true, y_pred)作为参数,因此让我们定义一个包装器:

# Our custom loss' wrapper
def custom_loss(recall_weight, spec_weight):

    def recall_spec_loss(y_true, y_pred):
        return binary_recall_specificity(y_true, y_pred, recall_weight, spec_weight)

    # Returns the (y_true, y_pred) loss function
    return recall_spec_loss

在使用它之前,我们已经

# Build model, add layers, etc
model = my_model
# Getting our loss function for specific weights
loss = custom_loss(recall_weight=0.9, spec_weight=0.1)
# Compiling the model with such loss
model.compile(loss=loss)

¹权重之和必须为1.0,因为在recall=1.0specificity=1.0(完美分数)的情况下,公式

loss1

例如,应该给我们

loss2

很显然,如果我们得到完美的分数,我们希望损失等于0。