"""Helper for evaluation on the Labeled Faces in the Wild dataset """ # MIT License # # Copyright (c) 2016 David Sandberg # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. from __future__ import absolute_import from __future__ import division from __future__ import print_function import os import argparse import sys import numpy as np from scipy import misc from sklearn.model_selection import KFold from scipy import interpolate import sklearn import datetime import pickle from sklearn.decomposition import PCA import mxnet as mx from mxnet import ndarray as nd sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'common')) import face_image 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]) 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) #print('pca', pca) if pca==0: 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)): #print('train_set', train_set) #print('test_set', test_set) if pca>0: 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) 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): _, _, 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 calculate_val(thresholds, embeddings1, embeddings2, actual_issame, far_target, nrof_folds=10): 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) val = np.zeros(nrof_folds) far = np.zeros(nrof_folds) diff = np.subtract(embeddings1, embeddings2) dist = np.sum(np.square(diff),1) indices = np.arange(nrof_pairs) for fold_idx, (train_set, test_set) in enumerate(k_fold.split(indices)): # Find the threshold that gives FAR = far_target far_train = np.zeros(nrof_thresholds) for threshold_idx, threshold in enumerate(thresholds): _, far_train[threshold_idx] = calculate_val_far(threshold, dist[train_set], actual_issame[train_set]) if np.max(far_train)>=far_target: f = interpolate.interp1d(far_train, thresholds, kind='slinear') threshold = f(far_target) else: threshold = 0.0 val[fold_idx], far[fold_idx] = calculate_val_far(threshold, dist[test_set], actual_issame[test_set]) val_mean = np.mean(val) far_mean = np.mean(far) val_std = np.std(val) return val_mean, val_std, far_mean def calculate_val_far(threshold, dist, actual_issame): predict_issame = np.less(dist, threshold) true_accept = np.sum(np.logical_and(predict_issame, actual_issame)) false_accept = np.sum(np.logical_and(predict_issame, np.logical_not(actual_issame))) n_same = np.sum(actual_issame) n_diff = np.sum(np.logical_not(actual_issame)) val = float(true_accept) / float(n_same) far = float(false_accept) / float(n_diff) return val, far def evaluate(embeddings, actual_issame, nrof_folds=10, pca = 0): # Calculate evaluation metrics thresholds = np.arange(0, 4, 0.01) embeddings1 = embeddings[0::2] embeddings2 = embeddings[1::2] tpr, fpr, accuracy = calculate_roc(thresholds, embeddings1, embeddings2, np.asarray(actual_issame), nrof_folds=nrof_folds, pca = pca) thresholds = np.arange(0, 4, 0.001) val, val_std, far = calculate_val(thresholds, embeddings1, embeddings2, np.asarray(actual_issame), 1e-3, nrof_folds=nrof_folds) return tpr, fpr, accuracy, val, val_std, far def load_bin(path, image_size): bins, issame_list = pickle.load(open(path, 'rb')) data_list = [] for flip in [0,1]: data = nd.empty((len(issame_list)*2, 3, image_size[0], image_size[1])) data_list.append(data) i = 0 for i in xrange(len(issame_list)*2): _bin = bins[i] img = mx.image.imdecode(_bin) img = nd.transpose(img, axes=(2, 0, 1)) for flip in [0,1]: if flip==1: img = mx.ndarray.flip(data=img, axis=2) data_list[flip][i][:] = img i+=1 if i%1000==0: print('loading bin', i) print(data_list[0].shape) return (data_list, issame_list) def test(data_set, mx_model, batch_size, data_extra = None): print('testing verification..') data_list = data_set[0] issame_list = data_set[1] model = mx_model embeddings_list = [] if data_extra is not None: _data_extra = nd.array(data_extra) time_consumed = 0.0 for i in xrange( len(data_list) ): data = data_list[i] embeddings = None ba = 0 while ba0: _max = [int(x) for x in args.max.split(',')] assert len(_max)==2 if len(epochs)>_max[1]: epochs = epochs[_max[0]:_max[1]] else: epochs = [int(x) for x in vec[1].split('|')] print('model number', len(epochs)) time0 = datetime.datetime.now() for epoch in epochs: print('loading',prefix, epoch) model = mx.mod.Module.load(prefix, epoch, context = ctx) model.bind(data_shapes=[('data', (args.batch_size, 3, image_size[0], image_size[1]))], label_shapes=[('softmax_label', (args.batch_size,))]) #model.init_params() nets.append(model) time_now = datetime.datetime.now() diff = time_now - time0 print('model loading time', diff.total_seconds()) ver_list = [] ver_name_list = [] for name in args.target.split(','): path = os.path.join(args.data_dir,name+".bin") if os.path.exists(path): print('loading.. ', name) data_set = load_bin(path, image_size) ver_list.append(data_set) ver_name_list.append(name) for i in xrange(len(ver_list)): results = [] for model in nets: acc1, std1, acc2, std2, xnorm, embeddings_list = test(ver_list[i], model, args.batch_size) print('[%s]XNorm: %f' % (ver_name_list[i], xnorm)) print('[%s]Accuracy: %1.5f+-%1.5f' % (ver_name_list[i], acc1, std1)) print('[%s]Accuracy-Flip: %1.5f+-%1.5f' % (ver_name_list[i], acc2, std2)) results.append(acc2) print('Max of [%s] is %1.5f' % (ver_name_list[i], np.max(results)))