如何在 keras 中计算接收操作特征 (ROC) 和 AUC?

Posted

技术标签:

【中文标题】如何在 keras 中计算接收操作特征 (ROC) 和 AUC?【英文标题】:How to compute Receiving Operating Characteristic (ROC) and AUC in keras? 【发布时间】:2017-04-23 06:53:38 【问题描述】:

我有一个用 keras 编写的多输出 (200) 二进制分类模型。

在此模型中,我想添加其他指标,例如 ROC 和 AUC,但据我所知,keras 没有内置的 ROC 和 AUC 指标函数。

我尝试从 scikit-learn 导入 ROC、AUC 函数

from sklearn.metrics import roc_curve, auc
from keras.models import Sequential
from keras.layers import Dense
.
.
.
model.add(Dense(200, activation='relu'))
model.add(Dense(300, activation='relu'))
model.add(Dense(400, activation='relu'))
model.add(Dense(300, activation='relu'))
model.add(Dense(200,init='normal', activation='softmax')) #outputlayer

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

但它给出了这个错误:

Exception: Invalid metric: roc_curve

keras应该如何添加ROC、AUC?

【问题讨论】:

编写自己的 AUC 函数并执行 model.predict - 请参阅 here 从您的帖子中不清楚您是否要为每个输出分别计算 AUC。 【参考方案1】:

由于无法通过 mini-batch 计算 ROC&AUC,只能在一个 epoch 结束时计算。 jamartinh 有一个解决方案,为方便起见,我修补了以下代码:

from sklearn.metrics import roc_auc_score
from keras.callbacks import Callback
class RocCallback(Callback):
    def __init__(self,training_data,validation_data):
        self.x = training_data[0]
        self.y = training_data[1]
        self.x_val = validation_data[0]
        self.y_val = validation_data[1]


    def on_train_begin(self, logs=):
        return

    def on_train_end(self, logs=):
        return

    def on_epoch_begin(self, epoch, logs=):
        return

    def on_epoch_end(self, epoch, logs=):
        y_pred_train = self.model.predict_proba(self.x)
        roc_train = roc_auc_score(self.y, y_pred_train)
        y_pred_val = self.model.predict_proba(self.x_val)
        roc_val = roc_auc_score(self.y_val, y_pred_val)
        print('\rroc-auc_train: %s - roc-auc_val: %s' % (str(round(roc_train,4)),str(round(roc_val,4))),end=100*' '+'\n')
        return

    def on_batch_begin(self, batch, logs=):
        return

    def on_batch_end(self, batch, logs=):
        return

roc = RocCallback(training_data=(X_train, y_train),
                  validation_data=(X_test, y_test))

model.fit(X_train, y_train, 
          validation_data=(X_test, y_test),
          callbacks=[roc])

使用tf.contrib.metrics.streaming_auc 的更易破解的方式:

import numpy as np
import tensorflow as tf
from sklearn.metrics import roc_auc_score
from sklearn.datasets import make_classification
from keras.models import Sequential
from keras.layers import Dense
from keras.utils import np_utils
from keras.callbacks import Callback, EarlyStopping


# define roc_callback, inspired by https://github.com/keras-team/keras/issues/6050#issuecomment-329996505
def auc_roc(y_true, y_pred):
    # any tensorflow metric
    value, update_op = tf.contrib.metrics.streaming_auc(y_pred, y_true)

    # find all variables created for this metric
    metric_vars = [i for i in tf.local_variables() if 'auc_roc' in i.name.split('/')[1]]

    # Add metric variables to GLOBAL_VARIABLES collection.
    # They will be initialized for new session.
    for v in metric_vars:
        tf.add_to_collection(tf.GraphKeys.GLOBAL_VARIABLES, v)

    # force to update metric values
    with tf.control_dependencies([update_op]):
        value = tf.identity(value)
        return value

# generation a small dataset
N_all = 10000
N_tr = int(0.7 * N_all)
N_te = N_all - N_tr
X, y = make_classification(n_samples=N_all, n_features=20, n_classes=2)
y = np_utils.to_categorical(y, num_classes=2)

X_train, X_valid = X[:N_tr, :], X[N_tr:, :]
y_train, y_valid = y[:N_tr, :], y[N_tr:, :]

# model & train
model = Sequential()
model.add(Dense(2, activation="softmax", input_shape=(X.shape[1],)))

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

my_callbacks = [EarlyStopping(monitor='auc_roc', patience=300, verbose=1, mode='max')]

model.fit(X, y,
          validation_split=0.3,
          shuffle=True,
          batch_size=32, nb_epoch=5, verbose=1,
          callbacks=my_callbacks)

# # or use independent valid set
# model.fit(X_train, y_train,
#           validation_data=(X_valid, y_valid),
#           batch_size=32, nb_epoch=5, verbose=1,
#           callbacks=my_callbacks)

【讨论】:

是否可以在每个 epoch 的不同验证集上调用 roc_callback,比如在 fit 方法中指定 validation_split 和 shuffle=True,然后将验证集传递给 roç 回调?我不确定这样做的正确语法。有什么帮助吗?谢谢 @AhmedBesbes 我已经更新了这个答案。现在,它包含一个使用tf.contrib.metrics.streaming_auc 的解决方案。可以使用validation_split shuffle ,运行速度更快。 这应该是公认的解决方案。使用 AUC 作为度量是行不通的,因为 Keras 会计算每个 minibatch 的 AUC 并对结果进行平均,这样的计算对 AUC 无效(但它是为了准确度)【参考方案2】:

和你一样,我更喜欢使用 scikit-learn 的内置方法来评估 AUROC。我发现在 keras 中最好和最简单的方法是创建一个自定义指标。如果 tensorflow 是您的后端,只需几行代码即可实现:

import tensorflow as tf
from sklearn.metrics import roc_auc_score

def auroc(y_true, y_pred):
    return tf.py_func(roc_auc_score, (y_true, y_pred), tf.double)

# Build Model...

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

由于您的模型有多个输出,因此创建其他答案中提到的自定义回调不适用于您的情况,但这会起作用。此外,这种方法允许在训练数据和验证数据上评估指标,而 keras 回调无法访问训练数据,因此只能用于评估训练数据的性能。

【讨论】:

几个 epoch 后,我得到一个:ValueError:y_true 中只有一个类。在这种情况下没有定义 ROC AUC 分数。 这可能发生在其中一个批次中。使用 try&catch 解决了这个问题,但不完全按照这个答案中的建议:***.com/a/45139405/4548320 因为我使用 TensorFlow 作为后端,所以 try 和 catch 不起作用。我必须定义一个新函数 auc2 将 try&catch 放入其中并将 auc2 作为参数发送给 tf.py_func @Guy 我试过的一个解决方案来自这个链接:***.com/questions/45139163/…,作者是 Dmitry Konovalov。它对我有用 和我做的很相似,但是你必须为Keras返回一个值(不能使用pass) @Guys 你能告诉我你是如何解决 ValueError 的问题的吗?即 y_true 中只有一个类。您能分享一下您是如何制作新函数 auc2 的吗? @user_12,实际上我删除了代码。应该避免这种解决方案。这个例外只是一个更大问题的症状:AUC 不应该像 Keras 那样在 minibatch 上计算和平均。相反,它应该使用回调来计算。使用此解决方案(在此页面中找到):***.com/a/46844409/4548320【参考方案3】:

以下解决方案对我有用:

import tensorflow as tf
from keras import backend as K

def auc(y_true, y_pred):
    auc = tf.metrics.auc(y_true, y_pred)[1]
    K.get_session().run(tf.local_variables_initializer())
    return auc

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

【讨论】:

请注意 - 如果您使用的是tensorflow.keras 而不仅仅是keras,您当然应该使用from tensorflow.keras import backend as K,否则您会因为版本不同而出错。 另一个注意事项:Tensorflow 的 AUC 是一个近似值,与 sklearn 的结果不同。 github.com/tensorflow/tensorflow/issues/14834 请注意,此解决方案不会为您提供准确的 AUC,只是一个近似值,因为 Keras 对小批量的结果进行平均,它也可能因此引发不必要的异常。也许这段代码很短,但你真的应该考虑其他答案之一。【参考方案4】:

我这样解决了我的问题

假设您有测试数据集 x_test 的特征和 y_test 的相应目标。

首先,我们使用经过训练的模型从特征中预测目标

 y_pred = model.predict_proba(x_test)

然后我们从 sklearn 导入 roc_auc_score 函数,然后简单地将原始目标和预测目标传递给函数。

 roc_auc_score(y_test, y_pred)

【讨论】:

【参考方案5】:

您可以在训练期间通过以下方式提供指标来监控 auc:

METRICS = [
      keras.metrics.TruePositives(name='tp'),
      keras.metrics.FalsePositives(name='fp'),
      keras.metrics.TrueNegatives(name='tn'),
      keras.metrics.FalseNegatives(name='fn'), 
      keras.metrics.BinaryAccuracy(name='accuracy'),
      keras.metrics.Precision(name='precision'),
      keras.metrics.Recall(name='recall'),
      keras.metrics.AUC(name='auc'),
]


model = keras.Sequential([
    keras.layers.Dense(16, activation='relu', input_shape=(train_features.shape[-1],)),
    keras.layers.Dense(1, activation='sigmoid'),
  ])

model.compile(
    optimizer=keras.optimizers.Adam(lr=1e-3)
    loss=keras.losses.BinaryCrossentropy(),
    metrics=METRICS)

更详细的教程见:https://www.tensorflow.org/tutorials/structured_data/imbalanced_data

【讨论】:

这是我书中事实上的答案!【参考方案6】:

'roc_curve','auc' 不是标准度量,您不能像这样将它们传递给度量变量,这是不允许的。 您可以传递诸如“fmeasure”之类的标准指标。

在此处查看可用指标:https://keras.io/metrics/ 您可能还想看看制作自己的自定义指标:https://keras.io/metrics/#custom-metrics

还可以查看此博客中提到的 ROC、AUC 的 generate_results 方法... https://vkolachalama.blogspot.in/2016/05/keras-implementation-of-mlp-neural.html

【讨论】:

【参考方案7】:

除了上面的答案,我得到了错误“ValueError: bad input shape ...”,所以我指定概率向量如下:

y_pred = model.predict_proba(x_test)[:,1]
auc = roc_auc_score(y_test, y_pred)
print(auc)

【讨论】:

【参考方案8】:

使用 tf.keras.metrics.AUC() 设置您的模型架构: 阅读 Classification metrics based on True/False positives & negatives 上的 Keras 文档。

def model_architecture_ann(in_dim,lr=0.0001):
    model = Sequential()
    model.add(Dense(512, input_dim=X_train_filtered.shape[1], activation='relu'))
    model.add(Dense(1, activation='sigmoid'))
    opt = keras.optimizers.SGD(learning_rate=0.001)
    auc=tf.keras.metrics.AUC()
    model.compile(loss='binary_crossentropy', optimizer=opt, metrics=[tf.keras.metrics.AUC(name='auc')])    
    model.summary()
    return model

【讨论】:

以上是关于如何在 keras 中计算接收操作特征 (ROC) 和 AUC?的主要内容,如果未能解决你的问题,请参考以下文章

ROC 曲线,以及AUC计算方式

ROC和AUC介绍以及如何计算AUC

ROC曲线

AUC、ROC、FROC简介

1万字说明白Receiver Operating curve(ROC) 受试者操作特征曲线

ValueError:尝试计算 ROC 曲线时输入形状错误 (2, 256, 3)