【问题标题】:Custom metric based on tensorflow's streaming metrics returns NaN基于 tensorflow 的流式指标的自定义指标返回 NaN
【发布时间】:2017-11-29 14:05:17
【问题描述】:

我正在尝试将 F1 分数定义为 TensorFlow 中 DNNClassifier 的自定义指标。为此,我编写了一个函数

def metric_fn(predictions=[], labels=[], weights=[]):
    P, _ = tf.contrib.metrics.streaming_precision(predictions, labels)
    R, _ = tf.contrib.metrics.streaming_recall(predictions, labels)
    if P + R == 0:
        return 0
    return 2*(P*R)/(P+R)

使用来自 TensorFlow 的 streaming_precisionstreaming_recall 来计算 F1 分数。之后,我在 validation_metrics 中创建了一个新条目:

validation_metrics = {
    "accuracy":
        tf.contrib.learn.MetricSpec(
            metric_fn=tf.contrib.metrics.streaming_accuracy,
            prediction_key=tf.contrib.learn.PredictionKey.CLASSES),
    "precision":
        tf.contrib.learn.MetricSpec(
            metric_fn=tf.contrib.metrics.streaming_precision,
            prediction_key=tf.contrib.learn.PredictionKey.CLASSES),
    "recall":
        tf.contrib.learn.MetricSpec(
            metric_fn=tf.contrib.metrics.streaming_recall,
            prediction_key=tf.contrib.learn.PredictionKey.CLASSES),
    "f1score":
        tf.contrib.learn.MetricSpec(
            metric_fn=metric_fn,
            prediction_key=tf.contrib.learn.PredictionKey.CLASSES)
}

然而,虽然我得到了正确的精度和召回值,f1score 始终是nan

INFO:tensorflow:Saving dict for global step 151: accuracy = 0.982456, accuracy/baseline_label_mean = 0.397661, accuracy/threshold_0.500000_mean = 0.982456, auc = 0.982867, f1score = nan, global_step = 151, labels/actual_label_mean = 0.397661, labels/prediction_mean = 0.406118, loss = 0.310612, precision = 0.971014, precision/positive_threshold_0.500000_mean = 0.971014, recall = 0.985294, recall/positive_threshold_0.500000_mean = 0.985294

我的metric_fn 出了点问题,但我想不通。 metric_fn得到的值PR的形式为 Tensor("precision/value:0", shape=(), dtype=float32)。我觉得这有点奇怪。我期待一个标量张量。

感谢任何帮助。

【问题讨论】:

    标签: python tensorflow


    【解决方案1】:

    我认为问题可能来自您在metric_fn 中使用的流媒体指标没有得到任何更新。

    尝试以下方法(我还根据自己的口味做了一些小改动):

    def metric_fn(predictions=None, labels=None, weights=None):
        P, update_op1 = tf.contrib.metrics.streaming_precision(predictions, labels)
        R, update_op2 = tf.contrib.metrics.streaming_recall(predictions, labels)
        eps = 1e-5;
        return (2*(P*R)/(P+R+eps), tf.group(update_op1, update_op2))
    

    【讨论】:

    • 行得通,谢谢。但是,有一点语法错误(return 语句的第一部分缺少))。
    【解决方案2】:

    tf.learn.MetricSpec__init__ 第一个参数是metric_fn

    文档说:

    metric_fn:用作度量的函数。有关如何将预测、标签和权重传递给此函数的规则,请参见 _adapt_metric_fn。这必须返回一个单一的张量,它被解释为这个度量的一个值,或者一个对 (value_op, update_op),其中 value_op 是要调用以获取度量值的操作,并且应该为每个批次运行 update_op更新内部状态。

    由于您想在 metric_fn 中使用流式操作,因此您不能返回单个张量,但您必须考虑到流式操作具有必须更新的内部状态。

    因此,metric_fn 的第一部分应该是:

    def metric_fn(predictions=[], labels=[], weights=[]):
        P, update_precision = tf.contrib.metrics.streaming_precision(predictions, labels)
        R, update_recall = tf.contrib.metrics.streaming_recall(predictions, labels)
    

    然后,如果您想在满足条件时返回 0,则不能使用 python if 语句(不在 tensorflow 图中计算),但您必须使用 tf.cond(在图中计算)。

    此外,您只想在更新操作之后检查PR的值(否则第一个值未定义或nan)。

    要在PR 更新后强制评估tf.cond,可以使用tf.control_dependencies

    def metric_fn(predictions=[], labels=[], weights=[]):
        P, update_precision = tf.contrib.metrics.streaming_precision(predictions, labels)
        R, update_recall = tf.contrib.metrics.streaming_recall(predictions, labels)
    
        with tf.control_dependencies([P, update_precision, R, update_recall]):
            score = tf.cond(tf.equal(P + R, 0.), lambda: 0, lambda: 2*(P*R)/(P+R))
        return score, tf.group(update_precision, update_recall)
    

    【讨论】:

    • 您不需要control_dependencies,因为这已经在流式指标中得到处理。所以最后归结为我的答案。
    猜你喜欢
    • 2019-02-06
    • 1970-01-01
    • 2018-01-25
    • 2015-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-26
    • 1970-01-01
    相关资源
    最近更新 更多