tensorboard 中 auc_precision_recall 曲线 y 轴值的理解

更新:

之前(下面)可能没有说清楚,我强调一下重点。
首先,最重要的整体考虑:我感觉现在还是找问题的阶段,所以最后先不要下结论解释。所谓 “插值错误” 只是一个例子,个人感觉很有可能还有其他我不知道的情况,最起码 “插值错误” 就有很多 “变体现象”,比如 predictions = tf.cast (np.random.choice ([.1, .9], size=n), tf.float32),AUC PR 得到 0.45407957,得到曲线是两个点组成的 0.2 左右的线。具体发生了什么是跟你的数据有关的,即使是在第一个步骤,尽管参数是随机的、跟数据无关的,但预测是跟你的特征作用后的结果,所以不同设定都是不同的。从这个角度讲,个人觉得"画出 PR 曲线看一看"不仅是没有办法的办法,而是其中一种正确思路。
其次,关于你这个问题中我感兴趣的部分主要是两个,第一是训练过程一直保持 0.5,另一个是跳低过一次。下面算是回答你点评中的问题:
1. 这里想说的是第几个步骤(是不是第一个点)跟你出现 0.5 这个问题很可能没有太直接的关系,具体能不能忽略掉应该需要看看 PR 曲线甚至是其他统计结果决定,不好直接下结论。
2. 同样的,我也不确定跳低过的那一次是不是就 “没错”。对于跳低过的那一次,我感兴趣的点在于到底有多低。这篇文章 讲到了 PR 空间的禁区问题,我不是完全理解其中的证明,但大概一个思路是当 recall100%的时候,precision 不可能低于偏移度比例,因为分类找到了所有正值,最差也是所有的负值都是一类错误。但是,随机分类的 AUC PR 是要大于这个曲线的。你的三幅图最低值到了 0.002,好像真的很低,说明你的偏移度可能真的很大,我好奇你这个值是不是低于了随机分类,如果是,感性上说还是挺难得的。
最后,提一个 1.8.0 的更新。今天重跑下面代码是发现有警告:“WARNING:tensorflow:Trapezoidal rule is known to produce incorrect PR-AUCs; please switch to “careful_interpolation” instead.”。仔细看过应该是 1.8.0 的 更新,“careful_interpolation” 也是新的,参考文章就是之前点评中提到的那篇。这个选项在 DNNClassifier 里好像还没用到。如果用这个方法计算下面的例子,得到的是 0.23976201 而不是 0.6105。

之前的发言:

我感觉 AirLRJ 的建议是很好的,楼主应该考虑把可以的模型或者相应步骤的预测值提取出来,画出 PR 曲线看一看。到底出了什么问题,或者是不是真的 AUC PR 是可以检验的。个人认为仅凭楼主的代码分析是不够的,问题很有可能跟楼主的数据特征有关。我对 PR 曲线的了解确实不够深入,但是我能想到的一个特例就是当预测概率为定值,或者说所有的预测概率在一个相对于阈值采样区间很小的范围中时,PR 曲线变成了一个 precision 为偏移度、recall 为 1 的点,这样在接下来的 AUC 数值计算中可能会导致 0.5 左右的 AUC,但这是完全无意义的伪值。这个特例在 tensorflow 中可以的到证实:

import numpy as np
import tensorflow as tf
from tensorboard.plugins.pr_curve import summary

n = 1000
np.random.seed (408)
labels = tf.cast (np.random.choice (2, size=n, p=(0.8, 0.2)), tf.bool)
predictions = tf.random_uniform (shape=[n], minval=0.1, maxval=0.1005, seed=408)
auc = tf.metrics.auc (labels, predictions, curve='PR')
summary_op = summary.op ('Big_AUC-PR', labels, predictions)

with tf.Session () as sess:
    init = tf.local_variables_initializer ()
    sess.run (init)
    auc_value, summ = sess.run ((auc, summary_op))
    with tf.summary.FileWriter ('Big_AUC-PR') as writer:
        writer.add_summary (summ)
    print (auc_value)

得到的 AUC 为 0.6105,tensorboard 中的曲线图为:

当然这只是一个特例,很可能还有其他特例,或者其他可能性,我水平有限,说不上来。不过还是那句话,画出 PR 曲线看看没准有帮助。

另外,想在这里老话重提一遍。之前向楼主和 @M 丶 Sulayman 请教过 AUC-PR 大于 0.5 的问题,但一直没有下文,不知道是不是言语不周有所得罪,在这里先道个歉,请见谅。这次想再提的是以下代码,分类器是最差的均匀随机分类器,我用 1-预测值的方法取反,但取反前后的 AUC-PR 都小于 0.5。

import numpy as np
import tensorflow as tf
from tensorboard.plugins.pr_curve import summary

n = 1000
labels = tf.cast (np.random.choice (2, size=n, p=(0.8, 0.2)), tf.bool)
predictions = tf.random_uniform ([n])
ops = []
for name, pred in zip (['Prediction', '1-prediction'],
                      [predictions, 1-predictions]):
    ops.append (tf.metrics.auc (labels, pred, curve='PR'))
    summary_op = summary.op (name, labels, pred)
ops.append (tf.summary.merge_all ())

with tf.Session () as sess:
    init = tf.local_variables_initializer ()
    sess.run (init)
    auc1, auc2, merged_summary = sess.run (ops)
    with tf.summary.FileWriter ('PR_curve') as writer:
        writer.add_summary (merged_summary)
    print ('Prediction: ', auc1 [1])
    print ('1-prediction: ', auc2 [1])
import numpy as np
import tensorflow as tf
from tensorboard.plugins.pr_curve import summary

n = 1000
labels = tf.cast (np.random.choice (2, size=n, p=(0.8, 0.2)), tf.bool)
predictions = tf.random_uniform ([n])
ops = []
for name, pred in zip (['Prediction', '1-prediction'],
                      [predictions, 1-predictions]):
    ops.append (tf.metrics.auc (labels, pred, curve='PR'))
    summary_op = summary.op (name, labels, pred)
ops.append (tf.summary.merge_all ())

with tf.Session () as sess:
    init = tf.local_variables_initializer ()
    sess.run (init)
    auc1, auc2, merged_summary = sess.run (ops)
    with tf.summary.FileWriter ('PR_curve') as writer:
        writer.add_summary (merged_summary)
    print ('Prediction: ', auc1 [1])
    print ('1-prediction: ', auc2 [1])

没有设随机种子,我得到的结果是 0.20946483 和 0.19511054。PR 曲线图如下:


恳请楼主和 @M 丶 Sulayman 帮忙看看算法 / 代码有什么问题,或者能详细指点一下为什么 AUC-PR 必然大于 0.5,真的非常感谢!


yunhai_luo,发表于 2018-4-29 16:27:56