1、目标检测评价指标:
准确率 (Accuracy),混淆矩阵 (Confusion Matrix),精确率(Precision),召回率(Recall),平均正确率(AP),mean Average Precision(mAP),交并比(IoU),ROC + AUC,非极大值抑制(NMS)
假设原始样本中有两类,其中:
总共有 P 个类别为 1 的样本,假设类别 1 为正例。
总共有 N 个类别为 0 的样本,假设类别 0 为负例。经过分类后:
有 TP 个类别为 1 的样本被系统正确判定为类别 1,FN 个类别为 1 的样本被系统误判定为类别 0,显然有 P=TP+FN;
有 FP 个类别为 0 的样本被系统误判断定为类别 1,TN 个类别为 0 的样本被系统正确判为类别 0,显然有 N=FP+TN;
1.1 准确率 (Accuracy)
A c c u r a c y = T P + T N P + N = T P + T N T P + F N + F P + T N Accuracy = \frac{TP+TN}{P+N}=\frac{TP+TN}{TP+FN+FP+TN} Accuracy=P+NTP+TN=TP+FN+FP+TNTP+TN
准确率一般用来评估模型的全局准确程度,不能包含太多信息,无法全面评价一个模型性能。 反映了被分类器判定的正例中真正的正例样本的比重。
1.2 查准率(Precision)
P r e c i s i o n = T P T P + F P Precision=\frac{TP}{TP+FP} Precision=TP+FPTP
“准”:预测的准确度,就是我们预测会下雨的结果中,实际下雨的地方;结果当然要越多越好;
“全”:所有的实际下雨的地方中,被我们预测有雨的地方越多越好,但是如果多报了,也没有办法。
在一个分类器中,你想要更高的查准率,那么你的阈值要设置的更高,只有这样才能有较高的把握确定我们预测是正例是真正例。一旦我们把阈值设置高了,那我们预测出正例的样本数就少了,那真正例数就更少了,查不全所有的正样例。
1.3 查全率(Recall)
R e c a l l = T P ( T P + F N ) Recall = \frac{TP}{(TP+FN)} Recall=(TP+FN)TP
1.4 F1值
F1 = 2 * 召回率 * 准确率 / (召回率 + 准确率);
这就是传统上通常说的 F1 measure。
1.5 漏警概率(Missing Alarm)
M A = F N ( T P + F N ) = 1 – T P T MA = \frac{FN}{(TP + FN)} = 1–\frac{TP}{T} MA=(TP+FN)FN=1–TTP
反映有多少个正例被漏判。
1.6 虚警概率(False Alarm)
F A = F P ( T P + F P ) FA = \frac{FP}{(TP + FP)} FA=(TP+FP)FP
反映有多少个负例被误判。
1.7 混淆矩阵 (Confusion Matrix)
混淆矩阵中的横轴是模型预测的类别数量统计,纵轴是数据真实标签的数量统计。对角线,表示模型预测和数据标签一致的数目。所以对角线之和除以测试集总数就是准确率。对角线上数字越大越好,在可视化结果中颜色越深,说明模型在该类的预测准确率越高。如果按行来看,每行不在对角线位置的就是错误预测的类别。总的来说,我们希望对角线越高越好,非对角线越低越好。
1.8 平均精度(Average-Precision AP)
AP 就是 Precision-Recall 曲线下面的面积,通常来说一个越好的分类器,AP值越高。
1.9 mean Average Precision (mAP)
mAP 是多个类别AP的平均值。这个mean的意思是对每个类的AP再求平均,得到的就是mAP的值,mAP的大小一定在[0,1]区间,越大越好。该指标是目标检测算法中最重要的一个。
在正样本非常少的情况下,PR 表现的效果会更好。
详情 链接 mAP讲解
1.10 IoU (Intersection over Union)
IoU,即 交并比,是目标检测中常见的评价标准,主要是衡量模型生成的bounding box和ground truth box之间的重叠程度,计算公式为:
I o U = D e t e c t i o n R e s u l t ⋂ G r o u n d T r u t h D e t e c t i o n R e s u l t ⋃ G r o u n d T r u t h IoU=\frac{DetectionResult \bigcap GroundTruth}{DetectionResult \bigcup GroundTruth} IoU=DetectionResult⋃GroundTruthDetectionResult⋂GroundTruth
from __future__ import print_function, absolute_import
import numpy as np
def get_IoU(pred_bbox, gt_box):
"""
:param pred_bbox: predict bbox corrdinate
:param gt_box: ground truth box corrdinate
:return: IoU score
"""
# 计算intersection面积
ixmin = max(pred_bbox[0], gt_box[0])
iymin = max(pred_bbox[1], gt_box[1])
ixmax = min(pred_bbox[2], gt_box[2])
iymax = min(pred_bbox[3], gt_box[3])
interWidth = iymax - iymin
interHeight = ixmax - ixmin
interArea = interHeight * interWidth
#计算Unio面积
unioArea = ((pred_bbox[2] - pred_bbox[0])+1)*((pred_bbox[3] - pred_bbox[1])+1) + ((gt_box[2]-gt_box[0])+1)*((gt_box[3]-gt_box[1])+1)-interArea
overlaps = interArea / unioArea
return overlaps
def get_max_IoU(gt_bbox, pred_bbox):
"""
:param gt_bbox: 一个真实标签的坐标
:param pred_bbox: 多个预测坐标
:return: 返回他们之间的最大值
"""
if pred_bbox.shape[0] > 0:
ixmin = np.maximum(pred_bbox[:, 0], gt_bbox[0])
iymin = np.maximum(pred_bbox[:, 1], gt_bbox[1])
ixmax = np.minimum(pred_bbox[:, 2], gt_bbox[2])
iymin = np.minimum(pred_bbox[:, 3], gt_bbox[3])
interWidth = np.maximum(ixmax - ixmin + 1.0)
interHeigth = np.maximum(iymin - iymin + 1.0)
interArea = interWidth * interHeigth
unioArea = ((pred_bbox[2] - pred_bbox[0])+1)*((pred_bbox[3] - pred_bbox[1])+1) + ((gt_bbox[:, 2]-gt_bbox[:, 0])+1)*((gt_bbox[:, 3]-gt_bbox[:, 1])+1)-interArea
overlaps = interArea / unioArea
ovmax = np.max(overlaps)
jmax = np.argmax(overlaps)
return overlaps, ovmax, jmax
1.11 ROC(Receiver Operating Characteristic)曲线与AUC(Area Under Curve)
ROC曲线:
横坐标:假正率(False positive rate, FPR),
F
P
R
=
F
P
/
N
FPR = FP / N
FPR=FP/N ,代表所有负样本中错误预测为正样本的概率,假警报率;
纵坐标:真正率(True positive rate, TPR),
T
P
R
=
T
P
/
P
TPR = TP / P
TPR=TP/P,代表所有正样本中预测正确的概率,命中率。
对角线对应于随机猜测模型,而(0,1)对应于所有整理排在所有反例之前的理想模型。曲线越接近左上角,分类器的性能越好。
ROC曲线有个很好的特性:当测试集中的正负样本的分布变化的时候,ROC曲线能够保持不变。在实际的数据集中经常会出现类不平衡(class imbalance)现象,即负样本比正样本多很多(或者相反),而且测试数据中的正负样本的分布也可能随着时间变化。
ROC曲线绘制:
(1)根据每个测试样本属于正样本的概率值从大到小排序;
(2)从高到低,依次将“Score”值作为阈值threshold,当测试样本属于正样本的概率大于或等于这个threshold时,我们认为它为正样本,否则为负样本;
(3)每次选取一个不同的threshold,我们就可以得到一组FPR和TPR,即ROC曲线上的一点。
当我们将threshold设置为1和0时,分别可以得到ROC曲线上的(0,0)和(1,1)两个点。将这些(FPR,TPR)对连接起来,就得到了ROC曲线。当threshold取值越多,ROC曲线越平滑。
AUC(Area Under Curve)即为ROC曲线下的面积。AUC越接近于1,分类器性能越好。
物理意义:首先AUC值是一个概率值,当你随机挑选一个正样本以及一个负样本,当前的分类算法根据计算得到的Score值将这个正样本排在负样本前面的概率就是AUC值。当然,AUC值越大,当前的分类算法越有可能将正样本排在负样本前面,即能够更好的分类。
1.12 PR曲线和ROC曲线比较
ROC曲线特点:
(1)优点:当测试集中的正负样本的分布变化的时候,ROC曲线能够保持不变。因为TPR聚焦于正例,FPR聚焦于与负例,使其成为一个比较均衡的评估方法。在实际的数据集中经常会出现类不平衡(class imbalance)现象,即负样本比正样本多很多(或者相反),而且测试数据中的正负样本的分布也可能随着时间变化。
(2)缺点:上文提到ROC曲线的优点是不会随着类别分布的改变而改变,但这在某种程度上也是其缺点。因为负例N增加了很多,而曲线却没变,这等于产生了大量FP。像信息检索中如果主要关心正例的预测准确性的话,这就不可接受了。在类别不平衡的背景下,负例的数目众多致使FPR的增长不明显,导致ROC曲线呈现一个过分乐观的效果估计。ROC曲线的横轴采用FPR,根据FPR ,当负例N的数量远超正例P时,FP的大幅增长只能换来FPR的微小改变。结果是虽然大量负例被错判成正例,在ROC曲线上却无法直观地看出来。(当然也可以只分析ROC曲线左边一小段)
PR曲线:
(1)PR曲线使用了Precision,因此PR曲线的两个指标都聚焦于正例。类别不平衡问题中由于主要关心正例,所以在此情况下PR曲线被广泛认为优于ROC曲线。
使用场景:
1、ROC曲线由于兼顾正例与负例,所以适用于评估分类器的整体性能,相比而言PR曲线完全聚焦于正例。
2、如果有多份数据且存在不同的类别分布,比如信用卡欺诈问题中每个月正例和负例的比例可能都不相同,这时候如果只想单纯地比较分类器的性能且剔除类别分布改变的影响,则ROC曲线比较适合,因为类别分布改变可能使得PR曲线发生变化时好时坏,这种时候难以进行模型比较;反之,如果想测试不同类别分布下对分类器的性能的影响,则PR曲线比较适合。
3、如果想要评估在相同的类别分布下正例的预测情况,则宜选PR曲线。
类别不平衡问题中,ROC曲线通常会给出一个乐观的效果估计,所以大部分时候还是PR曲线更好。
4、最后可以根据具体的应用,在曲线上找到最优的点,得到相对应的precision,recall,f1 score等指标,去调整模型的阈值,从而得到一个符合具体应用的模型。
1.13 非极大值抑制(NMS)
1.13.1 算法原理
非极大值抑制算法(Non-maximum suppression, NMS)的本质是搜索局部极大值,抑制非极大值元素。
物体检测中应用NMS算法的主要目的是消除多余(交叉重复)的窗口,找到最佳物体检测位置。
1.13.2 三邻域情况下NMS的实现
三邻域情况下的NMS即判断一维数组 I [ w ] I[w] I[w] 的元素 I [ i ] I[i] I[i] (2<=i<=w-1) 是否大于其左邻元素 I [ i − 1 ] I[i-1] I[i−1]和右邻元素 I [ i + 1 ] I[i+1] I[i+1]。
程序整体思路:先将box中的数据分别存入 x 1 , y 1 , x 2 , y 2 x_1,y_1,x_2,y_2 x1,y1,x2,y2, s c o r e score score中,分别为坐标和置信度,算出每个框的面积,存入area,基于置信度 s c o r e score score,从小到大进行排序,做一个while循环,取出置信度最高的,即排序后的最后一个,然后将该框进行保留,存入pick中,然后和其他所有的框进行比对,大于规定阈值就将别的框去掉,并将该置信度最高的框和所有比对过程,大于阈值的框存入suppress,for循环后,将 I 中满足suppress条件的置为空。直到 I 为空退出while。
static void sort(int n, const float* x, int* indices)
{
// 排序函数(降序排序),排序后进行交换的是indices中的数据
// n:排序总数// x:带排序数// indices:初始为0~n-1数目
int i, j;
for (i = 0; i < n; i++)
for (j = i + 1; j < n; j++)
{
if (x[indices[j]] > x[indices[i]])
{
//float x_tmp = x[i];
int index_tmp = indices[i];
//x[i] = x[j];
indices[i] = indices[j];
//x[j] = x_tmp;
indices[j] = index_tmp;
}
}
}
static void sort(int n, const float* x, int* indices)
{
// 排序函数(降序排序),排序后进行交换的是indices中的数据
// n:排序总数// x:带排序数// indices:初始为0~n-1数目
int i, j;
for (i = 0; i < n; i++)
for (j = i + 1; j < n; j++)
{
if (x[indices[j]] > x[indices[i]])
{
//float x_tmp = x[i];
int index_tmp = indices[i];
//x[i] = x[j];
indices[i] = indices[j];
//x[j] = x_tmp;
indices[j] = index_tmp;
}
}
}
1.14 边界框回归
Non-Maximum Suppression就是需要根据score矩阵和region的坐标信息,从中找到置信度比较高的bounding box。对于有重叠在一起的预测框,只保留得分最高的那个。
(1)NMS计算出每一个bounding box的面积,然后根据score进行排序,把score最大的bounding box作为队列中首个要比较的对象;
(2)计算其余bounding box与当前最大score与box的IoU,去除IoU大于设定的阈值的bounding box,保留小的IoU得预测框;
(3)然后重复上面的过程,直至候选bounding box为空。
最终,检测了bounding box的过程中有两个阈值,一个就是IoU,另一个是在过程之后,从候选的bounding box中剔除score小于阈值的bounding box。需要注意的是:Non-Maximum Suppression一次处理一个类别,如果有N个类别,Non-Maximum Suppression就需要执行N次。