keras中是否有基于精度或召回率而不是损失的优化程序?

fre*_*ata 7 metrics machine-learning keras

我正在开发一个只有两个类别的分段神经网络,即0和1(0是背景,而1是我想在图像上找到的对象)。在每个图像上,大约1的80%和0的20%。如您所见,数据集是不平衡的,并且会导致结果错误。我的准确度是85%,损失很低,但这仅仅是因为我的模型善于寻找背景!

我想将优化器基于另一个指标,例如精度或召回率,在这种情况下更有用。

有人知道如何实现吗?

jla*_*nik 7

不。要进行“梯度下降”,您需要计算梯度。为此,函数需要以某种方式平滑。Precision/Recall 或accuracy 不是一个平滑的函数,它只有梯度为无穷大的尖锐边缘和梯度为零的平坦地方。因此,您不能使用任何类型的数值方法来找到此类函数的最小值 - 您将不得不使用某种组合优化,这将是 NP-hard。


Ale*_*xis 7

由于我们的评论不够清晰,让我为您提供代码以跟踪您的需求。您不会使用精度或召回率来进行优化。您只需将它们作为有效分数进行跟踪即可获得最佳权重。请勿将损失,优化程序,指标等混合使用。它们不是同一件事的意思。

def precision(y_true, y_pred, threshold_shift=0.5-THRESHOLD):

    # just in case 
    y_pred = K.clip(y_pred, 0, 1)

    # shifting the prediction threshold from .5 if needed
    y_pred_bin = K.round(y_pred + threshold_shift)

    tp = K.sum(K.round(y_true * y_pred_bin)) + K.epsilon()
    fp = K.sum(K.round(K.clip(y_pred_bin - y_true, 0, 1)))

    precision = tp / (tp + fp)
    return precision


def recall(y_true, y_pred, threshold_shift=0.5-THRESHOLD):

    # just in case 
    y_pred = K.clip(y_pred, 0, 1)

    # shifting the prediction threshold from .5 if needed
    y_pred_bin = K.round(y_pred + threshold_shift)

    tp = K.sum(K.round(y_true * y_pred_bin)) + K.epsilon()
    fn = K.sum(K.round(K.clip(y_true - y_pred_bin, 0, 1)))

    recall = tp / (tp + fn)
    return recall


def fbeta(y_true, y_pred, threshold_shift=0.5-THRESHOLD):
    beta = 2

    # just in case 
    y_pred = K.clip(y_pred, 0, 1)

    # shifting the prediction threshold from .5 if needed
    y_pred_bin = K.round(y_pred + threshold_shift)

    tp = K.sum(K.round(y_true * y_pred_bin)) + K.epsilon()
    fp = K.sum(K.round(K.clip(y_pred_bin - y_true, 0, 1)))
    fn = K.sum(K.round(K.clip(y_true - y_pred, 0, 1)))

    precision = tp / (tp + fp)
    recall = tp / (tp + fn)

    beta_squared = beta ** 2
    return (beta_squared + 1) * (precision * recall) / (beta_squared * precision + recall) 


def model_fit(X,y,X_test,y_test):
    class_weight={
    1: 1/(np.sum(y) / len(y)),
    0:1}
    np.random.seed(47)
    model = Sequential()
    model.add(Dense(1000, input_shape=(X.shape[1],)))
    model.add(Activation('relu'))
    model.add(Dropout(0.35))
    model.add(Dense(500))
    model.add(Activation('relu'))
    model.add(Dropout(0.35))
    model.add(Dense(250))
    model.add(Activation('relu'))
    model.add(Dropout(0.35))
    model.add(Dense(1))
    model.add(Activation('sigmoid'))

    model.compile(loss='binary_crossentropy', optimizer='adamax',metrics=[fbeta,precision,recall])
    model.fit(X, y,validation_data=(X_test,y_test), epochs=200, batch_size=50, verbose=2,class_weight = class_weight)
    return model
Run Code Online (Sandbox Code Playgroud)


J T*_*ana 6

正如其他人所说,精度/召回率不能直接用作损失函数。然而,已经发现更好的代理损失函数有助于整个系列的精度/召回相关函数(例如 ROC AUC、固定召回的精度等)

研究论文不可分解目标的可扩展学习通过使用某些计算边界来回避组合优化的方法涵盖了这一点,并且作者编写的一些 Tensorflow 代码可以在tensorflow/models存储库中找到。此外,StackOverflow 上有一个后续问题,其答案是将其改编为可用的 Keras 损失函数。

特别感谢 Francois Chollet 和Keras 问题线程中的其他参与者提出了该研究论文。您可能还会发现该线程为当前的问题提供了其他有用的见解。