欠下的帐总归还是要还的,之前一直拖着,总是懒得写tf.metrics
这个API的一些用法,今天总算是克服了懒癌,总结一下用tf.metrics
遇到的一些坑。
- 博客中涉及到的所有代码都已经传到澜子的Github上啦~欢迎互粉哇。
插一句闲话,这一次的博客基本上用的都是 Jupyter,感觉一级好用啊。可以一边写代码,一边记markdown,忍不住上一张效果图,再次欢迎大噶去我的Github上看一看,而且Github支持 jupyter notebook 显示,真得效果很好。
在这篇伪Tensorflow-tf-metrics中,澜子介绍了tf.metrics
中涉及的一些指标和概念,包括:精确率(precision),召回率(recall),准确率(accuracy),AUC,混淆矩阵(confusion matrix)。下面先给出官方的API文档,看看这个模块中都有哪些隐藏秘笈。
看了官方文档之后,大噶可能会发现其中有好多可以调用的函数,不仅有precision
/ accuracy
/ auc
/ recall
,还有precision_at_k
/ recall_at_k
,更有precision_at_thresholds
/ precision_at_top_k
/ sparse_precision_at_k
…天啦噜,这都是什么呀,澜子已经彻底晕了,到底要怎么用啊(眼冒金星中)。别急,让我一个坑一个坑地告诉你。
划重点
首先,这篇文章是受到Ronny Restrepo的启发,
这是一篇很好的文章,将tf.metrics.accuracy()
讲解滴很清楚,本文就模仿他的思路,验证一下precision
的计算。
精确率的计算公式
$$ Precision = \frac{truePositive}{truePositive + falsePositive} $$
让我们先造点数据,传统算算看
1 | import tensorflow as tf |
Precision :0.8889
上述方法的问题
由于硬件方面的一些限制,导致此方法不能扩展到大型数据集,比如当数据集很大时,就无法一次性适应内存。
因而,为了使其可扩展,我们希望使评估指标能够逐步更新,每批新的预测和标签。 为此,我们需要跟踪两个值。
- 正确预测的正样本数量
- 预测样本中所有正样本的数量
所以我们要这么做
1 | # Initialize running variables |
怎么用上面的函数呢?
接下来的两个例子,给出了运用的具体代码,并且可以更好滴帮助我们理解tf.metrics.precision()
的计算逻辑以及对应输出所代表的含义
样本整体准确率(直接计算)
1 | # Overall precision |
[NP] SCORE: 0.8889
批次准确率(直接计算)
1 | # Batch precision |
1 | [NP] batch 0 score: 1.0000 |
不要小瞧这两个变量和三个函数
上面说了这么多,感觉没有tensorflow的什么事哇,别急,先看一个tensorflow的官方文档
放一个官方的解释
tensorflow/tensorflow/python/ops/metrics_impl.py
- Github代码中precision的解释部分
The
precision
function creates two local variables,
true_positives
andfalse_positives
, that are used to compute the precision. This value is ultimately returned asprecision
, an idempotent operation that simply dividestrue_positives
by the sum oftrue_positives
andfalse_positives
.
For estimation of the metric over a stream of data, the function creates anupdate_op
operation that updates these variables and returns theprecision
.
两个变量和 tf.metrics.precision()
的关系
官方文档提及的two local variables :true_postives
和 false_positives
分别对应上文定义的两个变量。
- true_postives–N_TRUE_P
- false_postives–N_PRED_P - N_TRUE_P
三个函数和头大的update_op
官方文档提及的update_op
和precision
分别对应上文定义的两个函数
- precision–calculate_precision()
- update_op–update_running_variables()
大家不要被这个update_op
搞晕,其实从字面来理解就是一个变量更新的操作,上文的代码中,就是通过reset_running_variables()
的位置来决定何时对变量进行更新,其实就是对应于tf.variables_initializer()
。我之所以一直用错这个API,是因为我将tf.variables_initializer()
放在了错误的位置,导致变量没有按照我的预期正常更新,进而结果一直不正确。具体看看tensorflow是怎么实现的吧。
Overall precision using tensorflow
1 | # Overall precision using tensorflow |
1 | [TF] SCORE: 0.8889 |
Batch precision using tensorflow
1 | # Batch precision using tensorflow |
1 | [TF] batch 0 score: 1.0000 |
再次划重点
大噶一定要注意
session.run(running_vars_initializer)
score = session.run(tf_metric)
这两行代码在计算整体样本精确度以及批次精确度所在位置的不同。
澜子第一次的时候由于粗心,并没有注意两段代码的不同,才会导致tf计算结果和普通计算结果不一致
还需要注意的点
不要在一个sess.run()
里面同时调用tf_metric
和tf_metric_update
,下面的代码是错误的示范
1 | _ , score = session.run([tf_metric_update,tf_metric],\ |
update_op究竟返回了什么捏
此处参考了
stackoverflow的一个回答
具体代码如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29rel = tf.placeholder(tf.int64, [1,3])
rec = tf.constant([[7, 5, 10, 6, 3, 1, 8, 12, 31, 88]], tf.int64)
precision, update_op = tf.metrics.precision_at_k(rel, rec, 10)
sess = tf.Session()
sess.run(tf.local_variables_initializer())
stream_vars = [i for i in tf.local_variables()]
#Get the local variables true_positive and false_positive
print("[PRECSION_1]: ",sess.run(precision, {rel:[[1,5,10]]})) # nan
#tf.metrics.precision maintains two variables true_positives
#and false_positives, each starts at zero.
#so the output at this step is 'nan'
print("[UPDATE_OP_1]:",sess.run(update_op, {rel:[[1,5,10]]})) #0.2
#when the update_op is called, it updates true_positives
#and false_positives using labels and predictions.
print("[STREAM_VARS_1]:",sess.run(stream_vars)) #[2.0, 8.0]
# Get true positive rate and false positive rate
print("[PRECISION_1]:",sess.run(precision,{rel:[[1,10,15]]})) # 0.2
#So calling precision will use true_positives and false_positives and outputs 0.2
print("[UPDATE_OP_2]:",sess.run(update_op,{rel:[[1,10,15]]})) #0.15
#the update_op updates the values to the new calculated value 0.15.
print("[STREAM_VARS_2]:",sess.run(stream_vars)) #[3.0, 17.0]
1 | [PRECSION_1]: nan |
tf.metrics.precision_at_k
上面的代码中,我们看到运用的是tf.metrics.precision_at_k()
这个API,这里的k
是什么呢?
首先,我们要理解一个概念,究竟什么是Precision at k
,这里有两份资料,应该能很好地帮助你理解这个概念。
澜子就是看了这两份资料之后,理解了Precision at k
的概念的。
然后我们来看看这个函数是怎么用的,第一步当然要先看看输入啦。
1 | tf.metrics.precision_at_k( |
我们重点关注labels,predictions,k这三个参数,应该可以满足日常简单地使用了。
那labels,predictions,k的输入形式是什么样的呢?
闲话不说,直接看看上面的栗子。栗子中rel
其实对应为labels
,rec
对应为predictions
,那k
又是什么意思呢?
划重点:这里的k
表明你需要对多少个预测样本进行排序。这样说可能有一点抽象,给一个解释。
Precision@k = (Recommended items @k that are relevant) / (# Recommended items @k)
可以先去看一下
Github,
发现其实在tf.metrics.precision_at_k
这个函数中,对于predictions
会根据输入的k值
进行top_k
操作。
对应上面的代码中,当k=10
,即对rec = tf.constant([[7, 5, 10, 6, 3, 1, 8, 12, 31, 88]], tf.int64)
所有的样本进行排序,进而在函数中实际运用的是rec
中样本数值从大到小排列的索引值。这样解释应该就能看懂上面代码的意思了。
后来,澜子又在
看到有人问怎么用tf.metrics.sparse_average_precision_at_k
,就又去求是了一波,
还完成了知乎的技术首答以及stackoverflow上第一个赞,
欢迎互粉知乎
和stackoverflow哇。下面给出栗子和简单解释啦。
1 | import tensorflow as tf |
简单解释一下
首先
y_true
代表标签值(未经过one-hot),shape:(batch_size, num_labels)
,y_pred
代表预测值(logit值) ,shape:(batch_size, num_classes)
其次,要注意的是
tf.metrics.sparse_average_precision_at_k
中会采用top_k
根据不同的k值
对y_pred
进行排序操作 ,所以tmp_rank
是为了帮助大噶理解究竟y_pred在函数中进行了怎样的转换。然后,
stream_vars = [i for i in tf.local_variables()]
这一行是为了帮助大噶理解tf.metrics.sparse_average_precision_at_k
创建的tf.local_varibles
实际输出值,进而可以更好地理解这个函数的用法。具体看这个例子,当
k=1
时,只有第一个batch的预测输出是和标签匹配的 ,所以最终输出为:1/6 = 0.166666
;当k=2
时,除了第一个batch的预测输出,第三个batch的预测输出也是和标签匹配的,所以最终输出为:(1+(1/2))/6 = 0.25。
P.S:在以后的tf版本里,将tf.metrics.average_precision_at_k
替代tf.metrics.sparse_average_precision_at_k