人脸识别相似度计算方法
在人臉識別中,我們通常采用歐氏距離和余弦距離來衡量人臉特征的相似度,判別是否為同一個人。
歐氏距離
歐氏距離比較簡單,采用歐氏公式直接計算兩個點之間的距離,如下:
代碼:
diff = np.subtract(feature1, feature2) dist = np.sqrt(np.sum(np.square(diff)))feature1.shape 和feature2.shape 為(n, )
?
余弦距離
余弦距離,也稱為余弦相似度,是用向量空間中兩個向量夾角的余弦值作為衡量兩個個體間差異的大小的度量。
當(dāng)兩個向量直接的夾角趨向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?
區(qū)別
歐氏距離計算的是空間中兩個點的絕對距離,距離dist越小,特征越相似;
余弦距離衡量的是空間中兩個向量的夾角,夾角越靠近0,即dist越接近1,特征越相似。
?
閾值選取
以下是一段摘自facenet 的代碼:
def distance(embeddings1, embeddings2, distance_metric=0):if distance_metric==0:# Euclidian distancediff = np.subtract(embeddings1, embeddings2)dist = np.sum(np.square(diff),1)elif distance_metric==1:# Distance based on cosine similaritydot = np.sum(np.multiply(embeddings1, embeddings2), axis=1)norm = np.linalg.norm(embeddings1, axis=1) * np.linalg.norm(embeddings2, axis=1)similarity = dot / normdist = np.arccos(similarity) / math.pielse:raise 'Undefined distance metric %d' % distance_metric return distdef 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.0dist = distance(embeddings1-mean, embeddings2-mean, distance_metric)# Find the best threshold for the foldacc_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, accuracydef 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.sizereturn tpr, fpr, acc def evaluate(embeddings, actual_issame, nrof_folds=10, distance_metric=0, subtract_mean=False):# Calculate evaluation metricsthresholds = 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從上面的代碼,可以看到其實我們在實際的人臉識別中,可以對標(biāo)準(zhǔn)的歐氏距離和余弦距離做適當(dāng)?shù)姆糯?/strong>,這樣在更有利于閾值的比較,更精準(zhǔn)。那么閾值我們怎么選值呢?在上面第二段代碼中可以找到答案,可以看到最佳閾值是可以算出來的,代碼 thresholds = np.arange(0, 4, 0.001) ,最佳閾值在(0, 4)之間進(jìn)行查找,在acc_train 最高時的threshold來當(dāng)中最佳閾值。
diff = np.subtract(embeddings1, embeddings2) dist = np.sum(np.square(diff),1)通過跑LFW數(shù)據(jù)集測試,facenet算法下,歐氏距離經(jīng)過上面兩個語句變形后的最佳閾值為1.21;在arcface算法,mobilefacenet模型下自己閾值為1.45,可見在選取閾值的時候要根據(jù)自己的model來計算一下才合適。
?
更新:2020.11.6
關(guān)于歐氏距離怎么轉(zhuǎn)換為百分比的問題
我們在百度等AI開放平臺會看到人臉相似度是一個百分比,我們要怎么把歐氏轉(zhuǎn)換為百分比呢,今天就說一下自己的思路。
首先我們想到的是sigmoid函數(shù),這個函數(shù)y的范圍是(0, 1),對應(yīng)的百分比范圍0%~100%,我們同樣可以通過sigmoid函數(shù)的變形來實現(xiàn)映射。
通過上面的式子實現(xiàn)百分比的計算,我們只需要計算參數(shù),就可以計算百分比了。
計算方法:我們在驗證集里面跑一下,把歐氏距離最大的值x1記錄下來,此時設(shè)定一個該值對應(yīng)最大百分比(比如95%),然后在把歐氏距離最小的值x2也記錄下來,對應(yīng)最小百分比(比如5%),然后把x1, x2代入上式子,就可以算出,?的值。
?
參考:
https://blog.csdn.net/liunian920305/article/details/73456736
https://blog.csdn.net/u014657795/article/details/85850891
https://www.zhihu.com/question/312564645?rf=403423583
?
總結(jié)
以上是生活随笔為你收集整理的人脸识别相似度计算方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python入门学习—字典(FishC)
- 下一篇: c++ 测试串口速率_纳米软件案例之电流