Files
insightface/recognition/_evaluation_/ijb/ijb_1n.py
2021-06-19 23:37:10 +08:00

367 lines
15 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python
# coding: utf-8
import os
import numpy as np
import timeit
import sklearn
import cv2
import sys
import argparse
import glob
import numpy.matlib
import heapq
import math
from datetime import datetime as dt
from sklearn import preprocessing
sys.path.append('./recognition')
from embedding import Embedding
from menpo.visualize import print_progress
from menpo.visualize.viewmatplotlib import sample_colours_from_colourmap
def read_template_subject_id_list(path):
ijb_meta = np.loadtxt(path, dtype=str, skiprows=1, delimiter=',')
templates = ijb_meta[:, 0].astype(np.int)
subject_ids = ijb_meta[:, 1].astype(np.int)
return templates, subject_ids
def read_template_media_list(path):
ijb_meta = np.loadtxt(path, dtype=str)
templates = ijb_meta[:, 1].astype(np.int)
medias = ijb_meta[:, 2].astype(np.int)
return templates, medias
def read_template_pair_list(path):
pairs = np.loadtxt(path, dtype=str)
t1 = pairs[:, 0].astype(np.int)
t2 = pairs[:, 1].astype(np.int)
label = pairs[:, 2].astype(np.int)
return t1, t2, label
#def get_image_feature(feature_path, faceness_path):
# img_feats = np.loadtxt(feature_path)
# faceness_scores = np.loadtxt(faceness_path)
# return img_feats, faceness_scores
def get_image_feature(img_path, img_list_path, model_path, epoch, gpu_id):
img_list = open(img_list_path)
embedding = Embedding(model_path, epoch, gpu_id)
files = img_list.readlines()
print('files:', len(files))
faceness_scores = []
img_feats = []
for img_index, each_line in enumerate(files):
if img_index % 500 == 0:
print('processing', img_index)
name_lmk_score = each_line.strip().split(' ')
img_name = os.path.join(img_path, name_lmk_score[0])
img = cv2.imread(img_name)
lmk = np.array([float(x) for x in name_lmk_score[1:-1]],
dtype=np.float32)
lmk = lmk.reshape((5, 2))
img_feats.append(embedding.get(img, lmk))
faceness_scores.append(name_lmk_score[-1])
img_feats = np.array(img_feats).astype(np.float32)
faceness_scores = np.array(faceness_scores).astype(np.float32)
#img_feats = np.ones( (len(files), 1024), dtype=np.float32) * 0.01
#faceness_scores = np.ones( (len(files), ), dtype=np.float32 )
return img_feats, faceness_scores
def image2template_feature(img_feats=None,
templates=None,
medias=None,
choose_templates=None,
choose_ids=None):
# ==========================================================
# 1. face image feature l2 normalization. img_feats:[number_image x feats_dim]
# 2. compute media feature.
# 3. compute template feature.
# ==========================================================
unique_templates, indices = np.unique(choose_templates, return_index=True)
unique_subjectids = choose_ids[indices]
template_feats = np.zeros((len(unique_templates), img_feats.shape[1]))
for count_template, uqt in enumerate(unique_templates):
(ind_t, ) = np.where(templates == uqt)
face_norm_feats = img_feats[ind_t]
face_medias = medias[ind_t]
unique_medias, unique_media_counts = np.unique(face_medias,
return_counts=True)
media_norm_feats = []
for u, ct in zip(unique_medias, unique_media_counts):
(ind_m, ) = np.where(face_medias == u)
if ct == 1:
media_norm_feats += [face_norm_feats[ind_m]]
else: # image features from the same video will be aggregated into one feature
media_norm_feats += [
np.mean(face_norm_feats[ind_m], 0, keepdims=True)
]
media_norm_feats = np.array(media_norm_feats)
# media_norm_feats = media_norm_feats / np.sqrt(np.sum(media_norm_feats ** 2, -1, keepdims=True))
template_feats[count_template] = np.sum(media_norm_feats, 0)
if count_template % 2000 == 0:
print('Finish Calculating {} template features.'.format(
count_template))
template_norm_feats = template_feats / np.sqrt(
np.sum(template_feats**2, -1, keepdims=True))
return template_norm_feats, unique_templates, unique_subjectids
def verification(template_norm_feats=None,
unique_templates=None,
p1=None,
p2=None):
# ==========================================================
# Compute set-to-set Similarity Score.
# ==========================================================
template2id = np.zeros((max(unique_templates) + 1, 1), dtype=int)
for count_template, uqt in enumerate(unique_templates):
template2id[uqt] = count_template
score = np.zeros((len(p1), )) # save cosine distance between pairs
total_pairs = np.array(range(len(p1)))
batchsize = 100000 # small batchsize instead of all pairs in one batch due to the memory limiation
sublists = [
total_pairs[i:i + batchsize] for i in range(0, len(p1), batchsize)
]
total_sublists = len(sublists)
for c, s in enumerate(sublists):
feat1 = template_norm_feats[template2id[p1[s]]]
feat2 = template_norm_feats[template2id[p2[s]]]
similarity_score = np.sum(feat1 * feat2, -1)
score[s] = similarity_score.flatten()
if c % 10 == 0:
print('Finish {}/{} pairs.'.format(c, total_sublists))
return score
def read_score(path):
with open(path, 'rb') as fid:
img_feats = cPickle.load(fid)
return img_feats
def evaluation(query_feats, gallery_feats, mask):
Fars = [0.01, 0.1]
print(query_feats.shape)
print(gallery_feats.shape)
query_num = query_feats.shape[0]
gallery_num = gallery_feats.shape[0]
similarity = np.dot(query_feats, gallery_feats.T)
print('similarity shape', similarity.shape)
top_inds = np.argsort(-similarity)
print(top_inds.shape)
# calculate top1
correct_num = 0
for i in range(query_num):
j = top_inds[i, 0]
if j == mask[i]:
correct_num += 1
print("top1 = {}".format(correct_num / query_num))
# calculate top5
correct_num = 0
for i in range(query_num):
j = top_inds[i, 0:5]
if mask[i] in j:
correct_num += 1
print("top5 = {}".format(correct_num / query_num))
# calculate 10
correct_num = 0
for i in range(query_num):
j = top_inds[i, 0:10]
if mask[i] in j:
correct_num += 1
print("top10 = {}".format(correct_num / query_num))
neg_pair_num = query_num * gallery_num - query_num
print(neg_pair_num)
required_topk = [math.ceil(query_num * x) for x in Fars]
top_sims = similarity
# calculate fars and tprs
pos_sims = []
for i in range(query_num):
gt = mask[i]
pos_sims.append(top_sims[i, gt])
top_sims[i, gt] = -2.0
pos_sims = np.array(pos_sims)
print(pos_sims.shape)
neg_sims = top_sims[np.where(top_sims > -2.0)]
print("neg_sims num = {}".format(len(neg_sims)))
neg_sims = heapq.nlargest(max(required_topk), neg_sims) # heap sort
print("after sorting , neg_sims num = {}".format(len(neg_sims)))
for far, pos in zip(Fars, required_topk):
th = neg_sims[pos - 1]
recall = np.sum(pos_sims > th) / query_num
print("far = {:.10f} pr = {:.10f} th = {:.10f}".format(
far, recall, th))
def gen_mask(query_ids, reg_ids):
mask = []
for query_id in query_ids:
pos = [i for i, x in enumerate(reg_ids) if query_id == x]
if len(pos) != 1:
raise RuntimeError(
"RegIdsError with id = {} duplicate = {} ".format(
query_id, len(pos)))
mask.append(pos[0])
return mask
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='do ijb 1n test')
# general
parser.add_argument('--model-prefix',
default='',
help='path to load model.')
parser.add_argument('--model-epoch', default=1, type=int, help='')
parser.add_argument('--gpu', default=7, type=int, help='gpu id')
parser.add_argument('--batch-size', default=32, type=int, help='')
parser.add_argument('--job',
default='insightface',
type=str,
help='job name')
parser.add_argument('--target',
default='IJBC',
type=str,
help='target, set to IJBC or IJBB')
args = parser.parse_args()
target = args.target
model_path = args.model_prefix
gpu_id = args.gpu
epoch = args.model_epoch
meta_dir = "%s/meta" % args.target #meta root dir
if target == 'IJBC':
gallery_s1_record = "%s_1N_gallery_G1.csv" % (args.target.lower())
gallery_s2_record = "%s_1N_gallery_G2.csv" % (args.target.lower())
else:
gallery_s1_record = "%s_1N_gallery_S1.csv" % (args.target.lower())
gallery_s2_record = "%s_1N_gallery_S2.csv" % (args.target.lower())
gallery_s1_templates, gallery_s1_subject_ids = read_template_subject_id_list(
os.path.join(meta_dir, gallery_s1_record))
print(gallery_s1_templates.shape, gallery_s1_subject_ids.shape)
gallery_s2_templates, gallery_s2_subject_ids = read_template_subject_id_list(
os.path.join(meta_dir, gallery_s2_record))
print(gallery_s2_templates.shape, gallery_s2_templates.shape)
gallery_templates = np.concatenate(
[gallery_s1_templates, gallery_s2_templates])
gallery_subject_ids = np.concatenate(
[gallery_s1_subject_ids, gallery_s2_subject_ids])
print(gallery_templates.shape, gallery_subject_ids.shape)
media_record = "%s_face_tid_mid.txt" % args.target.lower()
total_templates, total_medias = read_template_media_list(
os.path.join(meta_dir, media_record))
print("total_templates", total_templates.shape, total_medias.shape)
#load image features
start = timeit.default_timer()
feature_path = '' #feature path
face_path = '' #face path
img_path = './%s/loose_crop' % target
img_list_path = './%s/meta/%s_name_5pts_score.txt' % (target,
target.lower())
#img_feats, faceness_scores = get_image_feature(feature_path, face_path)
img_feats, faceness_scores = get_image_feature(img_path, img_list_path,
model_path, epoch, gpu_id)
print('img_feats', img_feats.shape)
print('faceness_scores', faceness_scores.shape)
stop = timeit.default_timer()
print('Time: %.2f s. ' % (stop - start))
print('Feature Shape: ({} , {}) .'.format(img_feats.shape[0],
img_feats.shape[1]))
# compute template features from image features.
start = timeit.default_timer()
# ==========================================================
# Norm feature before aggregation into template feature?
# Feature norm from embedding network and faceness score are able to decrease weights for noise samples (not face).
# ==========================================================
use_norm_score = True # if True, TestMode(N1)
use_detector_score = True # if True, TestMode(D1)
use_flip_test = True # if True, TestMode(F1)
if use_flip_test:
# concat --- F1
#img_input_feats = img_feats
# add --- F2
img_input_feats = img_feats[:, 0:int(
img_feats.shape[1] / 2)] + img_feats[:,
int(img_feats.shape[1] / 2):]
else:
img_input_feats = img_feats[:, 0:int(img_feats.shape[1] / 2)]
if use_norm_score:
img_input_feats = img_input_feats
else:
# normalise features to remove norm information
img_input_feats = img_input_feats / np.sqrt(
np.sum(img_input_feats**2, -1, keepdims=True))
if use_detector_score:
img_input_feats = img_input_feats * np.matlib.repmat(
faceness_scores[:, np.newaxis], 1, img_input_feats.shape[1])
else:
img_input_feats = img_input_feats
print("input features shape", img_input_feats.shape)
#load gallery feature
gallery_templates_feature, gallery_unique_templates, gallery_unique_subject_ids = image2template_feature(
img_input_feats, total_templates, total_medias, gallery_templates,
gallery_subject_ids)
stop = timeit.default_timer()
print('Time: %.2f s. ' % (stop - start))
print("gallery_templates_feature", gallery_templates_feature.shape)
print("gallery_unique_subject_ids", gallery_unique_subject_ids.shape)
#np.savetxt("gallery_templates_feature.txt", gallery_templates_feature)
#np.savetxt("gallery_unique_subject_ids.txt", gallery_unique_subject_ids)
#load prope feature
probe_mixed_record = "%s_1N_probe_mixed.csv" % target.lower()
probe_mixed_templates, probe_mixed_subject_ids = read_template_subject_id_list(
os.path.join(meta_dir, probe_mixed_record))
print(probe_mixed_templates.shape, probe_mixed_subject_ids.shape)
probe_mixed_templates_feature, probe_mixed_unique_templates, probe_mixed_unique_subject_ids = image2template_feature(
img_input_feats, total_templates, total_medias, probe_mixed_templates,
probe_mixed_subject_ids)
print("probe_mixed_templates_feature", probe_mixed_templates_feature.shape)
print("probe_mixed_unique_subject_ids",
probe_mixed_unique_subject_ids.shape)
#np.savetxt("probe_mixed_templates_feature.txt", probe_mixed_templates_feature)
#np.savetxt("probe_mixed_unique_subject_ids.txt", probe_mixed_unique_subject_ids)
#root_dir = "" #feature root dir
#gallery_id_path = "" #id filepath
#gallery_feats_path = "" #feature filelpath
#print("{}: start loading gallery feat {}".format(dt.now(), gallery_id_path))
#gallery_ids, gallery_feats = load_feat_file(root_dir, gallery_id_path, gallery_feats_path)
#print("{}: end loading gallery feat".format(dt.now()))
#
#probe_id_path = "probe_mixed_unique_subject_ids.txt" #probe id filepath
#probe_feats_path = "probe_mixed_templates_feature.txt" #probe feats filepath
#print("{}: start loading probe feat {}".format(dt.now(), probe_id_path))
#probe_ids, probe_feats = load_feat_file(root_dir, probe_id_path, probe_feats_path)
#print("{}: end loading probe feat".format(dt.now()))
gallery_ids = gallery_unique_subject_ids
gallery_feats = gallery_templates_feature
probe_ids = probe_mixed_unique_subject_ids
probe_feats = probe_mixed_templates_feature
mask = gen_mask(probe_ids, gallery_ids)
print("{}: start evaluation".format(dt.now()))
evaluation(probe_feats, gallery_feats, mask)
print("{}: end evaluation".format(dt.now()))