基于tensorflow的流量指标的自定义指标会返回NaN

时间:2017-06-26 16:51:57

标签: python tensorflow

我正在尝试将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出了点问题,但我无法理解。 由P获得的值Rmetric_fn具有形式 Tensor("precision/value:0", shape=(), dtype=float32)。我觉得这有点奇怪。我期待一个标量张量。

感谢任何帮助。

2 个答案:

答案 0 :(得分:10)

我认为问题可能来自于您在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))

答案 1 :(得分:2)

tf.learn.MetricSpec __init__第一个参数是metric_fn

文档说:

  

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

由于您希望在metric_fn中使用流操作,因此您无法返回单个Tensor,但您必须考虑到流操作具有必须更新的内部状态。

因此,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语句(未计算插入张量流图),但必须使用{{3} (图中的计算)。

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

要在tf.condP更新后强制评估R,您可以使用tf.cond

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)