1. 基本概念
我们先来理解下面几个概念:
True Positive (真正, TP) :实例为正类被预测为正类
True Negative(真负, TN):实例为正类被预测为负类
False Positive(假正, FP):实例为负类被预测为正类
False Negative(假负, FN):实例为负类被预测为负类
2. ROC曲线
ROC(Receiver Operating Characteristic)全称为 受试者工作特征,ROC曲线的Y轴为TPR(真正例率),X轴为FPR(假正例率),对角线对应于“随机猜测”模型,而坐标(0, 1)对应于理想模型,越靠近(0, 1)点效果越好。
TPR就是查全率(Recall),含义:识别出真正实例占所有正实例的比例。
FPR的含义是:识别出假正实例占所有负实例的比例。 所有确实为假的样本中,被误判为真的样本。
曲线如下图:
学习器的比较:
(1)如果一个学习器的ROC曲线包住另一个学习器的ROC曲线,那么就是前者性能由于后者。
(2)如果两个ROC曲线发生交叉,那么就看他们ROC曲线下的面积,谁的面积大谁的性能更优。
3. AUC
AUC(Area Under Curve)曲线下的面积。如果模型是完美的,那么AUC=1,如果这个模型是简单的随机测试模型,那么它的AUC=0.5,两条ROC曲线,谁的AUC越大,谁的性能就越好。
4. 其他的辨别方法
其他的判别方法比较重要的有FAR和FRR。
误识率(FAR):就是将其他人误作为指定人员的概率,可以用下面的公式来计算,FAR值越小越好。
真识率(TAR):表示正确接受的比例。是指在识别过程中,识别两张人脸图片为同一个人,在实际中也是同一个人。TAR的值越大越好,最大为1。
拒识率(FRR):就是将指定人员误识作其他人员的概率。
等识率(EER):取某个值T时,使得 FAR=FRR,此时FAR或FRR的值。
5. 代码
此代码是在insight face人脸识别算法里摘取的部分代码:
def calculate_roc(thresholds, embeddings1, embeddings2, actual_issame, nrof_folds=10, pca = 0):
assert(embeddings1.shape[0] == embeddings2.shape[0])
assert(embeddings1.shape[1] == embeddings2.shape[1]) # embedding中特征点对数是否相等
nrof_pairs = min(len(actual_issame), embeddings1.shape[0]) # lfw中点对的个数,共有6000对
nrof_thresholds = len(thresholds) # thresholds是一个长度为400的数组,从0开始,间隔0.01
k_fold = LFold(n_splits=nrof_folds, shuffle=False)
tprs = np.zeros((nrof_folds,nrof_thresholds)) # ptrs是一个10x400的数组
fprs = np.zeros((nrof_folds,nrof_thresholds)) # fprs是一个10x400的数组
accuracy = np.zeros((nrof_folds)) # accuracy是一个1x10的数组
indices = np.arange(nrof_pairs) # indices的范围为(0, 6000)
#print('pca', pca)
if pca==0: # 是否使用pca进行压缩
diff = np.subtract(embeddings1, embeddings2)
dist = np.sum(np.square(diff),1) # 计算特征点之间的距离
for fold_idx, (train_set, test_set) in enumerate(k_fold.split(indices)): # 将数据分为10份,1份是测试,9份是训练
#print('train_set', train_set)
#print('test_set', test_set)
if pca>0: # 如果使用了pca进行压缩
print('doing pca on', fold_idx)
embed1_train = embeddings1[train_set]
embed2_train = embeddings2[train_set]
_embed_train = np.concatenate( (embed1_train, embed2_train), axis=0 )
#print(_embed_train.shape)
pca_model = PCA(n_components=pca)
pca_model.fit(_embed_train)
embed1 = pca_model.transform(embeddings1) # 从pca中解压出真正的特征值embed
embed2 = pca_model.transform(embeddings2)
embed1 = sklearn.preprocessing.normalize(embed1)
embed2 = sklearn.preprocessing.normalize(embed2)
#print(embed1.shape, embed2.shape)
diff = np.subtract(embed1, embed2) # 计算特征点之间的距离
dist = np.sum(np.square(diff),1)
# Find the best threshold for the fold
acc_train = np.zeros((nrof_thresholds))
for threshold_idx, threshold in enumerate(thresholds): # 在0-4中,间隔0.01,找到其中acc_train最大的值作为阈值
_, _, acc_train[threshold_idx] = calculate_accuracy(threshold, dist[train_set], actual_issame[train_set])
best_threshold_index = np.argmax(acc_train) # 得到最好的 threshold_index
#print('threshold', thresholds[best_threshold_index])
for threshold_idx, threshold in enumerate(thresholds):
tprs[fold_idx,threshold_idx], fprs[fold_idx,threshold_idx], _ = calculate_accuracy(threshold, dist[test_set], actual_issame[test_set])
# 根据上面获取的最佳阈值,求测试数据集的准确率,作为最终的准确率
_, _, accuracy[fold_idx] = calculate_accuracy(thresholds[best_threshold_index], dist[test_set], actual_issame[test_set])
tpr = np.mean(tprs,0) # 由于还有交叉验证,因此还需要求10次tprs和fprs数组中的均值
fpr = np.mean(fprs,0)
return tpr, fpr, accuracy
def calculate_accuracy(threshold, dist, actual_issame):
predict_issame = np.less(dist, threshold)
tp = np.sum(np.logical_and(predict_issame, actual_issame)) # 真正
fp = np.sum(np.logical_and(predict_issame, np.logical_not(actual_issame))) # 假正
tn = np.sum(np.logical_and(np.logical_not(predict_issame), np.logical_not(actual_issame))) # 真负
fn = np.sum(np.logical_and(np.logical_not(predict_issame), actual_issame)) # 假负
tpr = 0 if (tp+fn==0) else float(tp) / float(tp+fn)
fpr = 0 if (fp+tn==0) else float(fp) / float(fp+tn)
acc = float(tp+tn)/dist.size
return tpr, fpr, acc
from sklearn import metrics
from scipy import interpolate
from scipy.optimize import brentq
tpr, fpr, accuracy, val, val_std, far = evaluate(embeddings, issame_list, nrof_folds=nfolds)
auc = metrics.auc(fpr, tpr) # calculate auc by sklearn metrics
eer = brentq(lambda x: 1. - x - interpolate.interp1d(fpr, tpr)(x), 0., 1.)
print('Area Under Curve (AUC): %1.3f' % auc)
print('Equal Error Rate (EER): %1.3f' % eer)
References:
[2] 深度学习常用的模型评估指标