[深度学习][转载]人脸识别相似度计算方法
Posted FL1623863129
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[深度学习][转载]人脸识别相似度计算方法相关的知识,希望对你有一定的参考价值。
在人脸识别中,我们通常采用欧氏距离和余弦距离来衡量人脸特征的相似度,判别是否为同一个人。
欧氏距离
欧氏距离比较简单,采用欧氏公式直接计算两个点之间的距离,如下:
代码:
diff = np.subtract(feature1, feature2)
dist = np.sqrt(np.sum(np.square(diff)))
feature1.shape 和feature2.shape 为(n, )
余弦距离
余弦距离,也称为余弦相似度,是用向量空间中两个向量夹角的余弦值作为衡量两个个体间差异的大小的度量。
当两个向量直接的夹角趋向0时,两个向量越接近,差异就越小。此时 = 1,即越接近1值时,说明人脸越相似。
代码:
dot = np.sum(np.multiply(feature1, feature2), axis=1)
norm = np.linalg.norm(feature1, axis=1) * np.linalg.norm(feature2, axis=1)
dist = dot / norm
注意这个代码是np.array 类似于shape为(,128),在实际当中,我的shape是(128,)
此时代码就应该是
dot = np.sum(np.multiply(feature1, feature2), axis=0)
norm = np.linalg.norm(feature1, axis=0) * np.linalg.norm(feature2, axis=0)
dist = dot / norm
区别
欧氏距离计算的是空间中两个点的绝对距离,距离dist越小,特征越相似;
余弦距离衡量的是空间中两个向量的夹角,夹角越靠近0,即dist越接近1,特征越相似。
阈值选取
以下是一段摘自facenet 的代码:
def distance(embeddings1, embeddings2, distance_metric=0):
if distance_metric==0:
# Euclidian distance
diff = np.subtract(embeddings1, embeddings2)
dist = np.sum(np.square(diff),1)
elif distance_metric==1:
# Distance based on cosine similarity
dot = np.sum(np.multiply(embeddings1, embeddings2), axis=1)
norm = np.linalg.norm(embeddings1, axis=1) * np.linalg.norm(embeddings2, axis=1)
similarity = dot / norm
dist = np.arccos(similarity) / math.pi
else:
raise 'Undefined distance metric %d' % distance_metric
return dist
def calculate_roc(thresholds, embeddings1, embeddings2, actual_issame, nrof_folds=10, distance_metric=0, subtract_mean=False):
assert(embeddings1.shape[0] == embeddings2.shape[0])
assert(embeddings1.shape[1] == embeddings2.shape[1])
nrof_pairs = min(len(actual_issame), embeddings1.shape[0])
nrof_thresholds = len(thresholds)
k_fold = KFold(n_splits=nrof_folds, shuffle=False)
tprs = np.zeros((nrof_folds,nrof_thresholds))
fprs = np.zeros((nrof_folds,nrof_thresholds))
accuracy = np.zeros((nrof_folds))
indices = np.arange(nrof_pairs)
for fold_idx, (train_set, test_set) in enumerate(k_fold.split(indices)):
if subtract_mean:
mean = np.mean(np.concatenate([embeddings1[train_set], embeddings2[train_set]]), axis=0)
else:
mean = 0.0
dist = distance(embeddings1-mean, embeddings2-mean, distance_metric)
# Find the best threshold for the fold
acc_train = np.zeros((nrof_thresholds))
for threshold_idx, threshold in enumerate(thresholds):
_, _, acc_train[threshold_idx] = calculate_accuracy(threshold, dist[train_set], actual_issame[train_set])
best_threshold_index = np.argmax(acc_train)
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)
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
def evaluate(embeddings, actual_issame, nrof_folds=10, distance_metric=0, subtract_mean=False):
# Calculate evaluation metrics
thresholds = np.arange(0, 4, 0.01)
embeddings1 = embeddings[0::2]
embeddings2 = embeddings[1::2]
tpr, fpr, accuracy = facenet.calculate_roc(thresholds, embeddings1, embeddings2,
np.asarray(actual_issame), nrof_folds=nrof_folds, distance_metric=distance_metric, subtract_mean=subtract_mean)
thresholds = np.arange(0, 4, 0.001)
val, val_std, far = facenet.calculate_val(thresholds, embeddings1, embeddings2,
np.asarray(actual_issame), 1e-3, nrof_folds=nrof_folds, distance_metric=distance_metric, subtract_mean=subtract_mean)
return tpr, fpr, accuracy, val, val_std, far
从上面的代码,可以看到其实我们在实际的人脸识别中,可以对标准的欧氏距离和余弦距离做适当的放大,这样在更有利于阈值的比较,更精准。那么阈值我们怎么选值呢?在上面第二段代码中可以找到答案,可以看到最佳阈值是可以算出来的,代码 thresholds = np.arange(0, 4, 0.001) ,最佳阈值在(0, 4)之间进行查找,在acc_train 最高时的threshold来当中最佳阈值。
diff = np.subtract(embeddings1, embeddings2)
dist = np.sum(np.square(diff),1)
通过跑LFW数据集测试,facenet算法下,欧氏距离经过上面两个语句变形后的最佳阈值为1.21;在arcface算法,mobilefacenet模型下自己阈值为1.45,可见在选取阈值的时候要根据自己的model来计算一下才合适。
更新:2020.11.6
关于欧氏距离怎么转换为百分比的问题
我们在百度等AI开放平台会看到人脸相似度是一个百分比,我们要怎么把欧氏转换为百分比呢,今天就说一下自己的思路。
首先我们想到的是sigmoid函数,这个函数y的范围是(0, 1),对应的百分比范围0%~100%,我们同样可以通过sigmoid函数的变形来实现映射。
通过上面的式子实现百分比的计算,我们只需要计算参数,就可以计算百分比了。
计算方法:我们在验证集里面跑一下,把欧氏距离最大的值x1记录下来,此时设定一个该值对应最大百分比(比如95%),然后在把欧氏距离最小的值x2也记录下来,对应最小百分比(比如5%),然后把x1, x2代入上式子,就可以算出, 的值。
以上是关于[深度学习][转载]人脸识别相似度计算方法的主要内容,如果未能解决你的问题,请参考以下文章