From bd7fcc92300a210921f33f55fbdbd07e4ac44401 Mon Sep 17 00:00:00 2001 From: nttstar Date: Thu, 1 Feb 2018 19:19:18 +0800 Subject: [PATCH] fix c2c --- src/data.py | 115 ++++++++++++++++++++++++++++++++++++--- src/eval/verification.py | 7 ++- src/train_softmax.py | 17 ++++-- 3 files changed, 124 insertions(+), 15 deletions(-) diff --git a/src/data.py b/src/data.py index c6e7e2e..fe46eb5 100644 --- a/src/data.py +++ b/src/data.py @@ -7,6 +7,7 @@ import random import logging import sys import numbers +import math import sklearn import datetime import numpy as np @@ -72,6 +73,19 @@ class FaceImageIter(io.DataIter): self.imgrec = recordio.MXIndexedRecordIO(path_imgidx, path_imgrec, 'r') # pylint: disable=redefined-variable-type s = self.imgrec.read_idx(0) header, _ = recordio.unpack(s) + self.idx2cos = {} + self.idx2meancos = {} + self.c2c_auto = False + if output_c2c or c2c_threshold>0.0: + path_c2c = os.path.join(os.path.dirname(path_imgrec), 'c2c') + print(path_c2c) + if os.path.exists(path_c2c): + for line in open(path_c2c, 'r'): + vec = line.strip().split(',') + self.idx2cos[int(vec[0])] = float(vec[1]) + else: + self.c2c_auto = True + self.c2c_step = 10000 if header.flag>0: print('header0 label', header.label) self.header0 = (int(header.label[0]), int(header.label[1])) @@ -82,11 +96,22 @@ class FaceImageIter(io.DataIter): for identity in self.seq_identity: s = self.imgrec.read_idx(identity) header, _ = recordio.unpack(s) + a,b = int(header.label[0]), int(header.label[1]) #print('flag', header.flag) #print(header.label) #assert(header.flag==2) - self.id2range[identity] = (int(header.label[0]), int(header.label[1])) + self.id2range[identity] = (a,b) + if len(self.idx2cos)>0: + m = 0.0 + for ii in xrange(a,b): + m+=self.idx2cos[ii] + m/=(b-a) + for ii in xrange(a,b): + self.idx2meancos[ii] = m + #self.idx2meancos[identity] = m + print('id2range', len(self.id2range)) + print(len(self.idx2cos), len(self.idx2meancos)) else: self.imgidx = list(self.imgrec.keys) if shuffle: @@ -159,6 +184,7 @@ class FaceImageIter(io.DataIter): self.triplet_oseq_reset() self.seq_min_size = self.batch_size*2 self.cur = 0 + self.nbatch = 0 self.is_init = False self.times = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] #self.reset() @@ -538,10 +564,63 @@ class FaceImageIter(io.DataIter): # for i in xrange(self.images_per_identity): # _idx = _list[i%len(_list)] # self.seq.append(_idx) + def reset_c2c(self): + self.select_triplets() + for identity,v in self.id2range.iteritems(): + _list = range(*v) + + for idx in _list: + s = imgrec.read_idx(idx) + ocontents.append(s) + embeddings = None + #print(len(ocontents)) + ba = 0 + while True: + bb = min(ba+args.batch_size, len(ocontents)) + if ba>=bb: + break + _batch_size = bb-ba + _batch_size2 = max(_batch_size, args.ctx_num) + data = nd.zeros( (_batch_size2,3, image_size[0], image_size[1]) ) + label = nd.zeros( (_batch_size2,) ) + count = bb-ba + ii=0 + for i in xrange(ba, bb): + header, img = mx.recordio.unpack(ocontents[i]) + img = mx.image.imdecode(img) + img = nd.transpose(img, axes=(2, 0, 1)) + data[ii][:] = img + label[ii][:] = header.label + ii+=1 + while ii<_batch_size2: + data[ii][:] = data[0][:] + label[ii][:] = label[0][:] + ii+=1 + db = mx.io.DataBatch(data=(data,), label=(label,)) + self.mx_model.forward(db, is_train=False) + net_out = self.mx_model.get_outputs() + net_out = net_out[0].asnumpy() + model.forward(db, is_train=False) + net_out = model.get_outputs() + net_out = net_out[0].asnumpy() + if embeddings is None: + embeddings = np.zeros( (len(ocontents), net_out.shape[1])) + embeddings[ba:bb,:] = net_out[0:_batch_size,:] + ba = bb + embeddings = sklearn.preprocessing.normalize(embeddings) + embedding = np.mean(embeddings, axis=0, keepdims=True) + embedding = sklearn.preprocessing.normalize(embedding) + sims = np.dot(embeddings, embedding).flatten() + assert len(sims)==len(_list) + for i in xrange(len(_list)): + _idx = _list[i] + self.idx2cos[_idx] = sims[i] def reset(self): """Resets the iterator to the beginning of the data.""" print('call reset()') + if self.c2c_auto: + self.reset_c2c() self.cur = 0 if self.images_per_identity>0: if self.triplet_mode: @@ -592,12 +671,14 @@ class FaceImageIter(io.DataIter): s = self.imgrec.read_idx(idx) header, img = recordio.unpack(s) label = header.label - if not isinstance(header.label, numbers.Number): - label = header.label[0] - c = header.label[1] - if c0.0: + cos = self.idx2cos[idx] + if cos0: - v = min(0.5, max(0.25,math.log(v+1)*4-1.85)) - v = math.cos(v) + c2c = v + #m = min(0.55, max(0.3,math.log(c2c+1)*4-1.85)) + #v = math.cos(m) + #v = v*v + #_param = [0.5, 0.3, 0.85, 0.7] + _param = [0.5, 0.25, 0.85, 0.65] + _a = (_param[1]-_param[0])/(_param[3]-_param[2]) + m = _param[1]+_a*(c2c-_param[3]) + m = min(_param[0], max(_param[1],m)) + #m = 0.5 + #if c2c<0.77: + # m = 0.3 + #elif c2c<0.82: + # m = 0.4 + #elif c2c>0.88: + # m = 0.55 + v = math.cos(m) v = v*v - print('c2c', i,v) + #print('c2c', i,c2c,m,v) batch_label[i][ll] = v else: diff --git a/src/eval/verification.py b/src/eval/verification.py index cf16a10..754d07d 100644 --- a/src/eval/verification.py +++ b/src/eval/verification.py @@ -185,7 +185,7 @@ def load_bin(path, image_size): print(data_list[0].shape) return (data_list, issame_list) -def test(data_set, mx_model, batch_size, data_extra = None): +def test(data_set, mx_model, batch_size, data_extra = None, label_shape = None): print('testing verification..') data_list = data_set[0] issame_list = data_set[1] @@ -194,6 +194,10 @@ def test(data_set, mx_model, batch_size, data_extra = None): if data_extra is not None: _data_extra = nd.array(data_extra) time_consumed = 0.0 + if label_shape is None: + _label = nd.ones( (batch_size,) ) + else: + _label = nd.ones( label_shape ) for i in xrange( len(data_list) ): data = data_list[i] embeddings = None @@ -202,7 +206,6 @@ def test(data_set, mx_model, batch_size, data_extra = None): bb = min(ba+batch_size, data.shape[0]) count = bb-ba _data = nd.slice_axis(data, axis=0, begin=bb-batch_size, end=bb) - _label = nd.ones( (batch_size,) ) #print(_data.shape, _label.shape) time0 = datetime.datetime.now() if data_extra is None: diff --git a/src/train_softmax.py b/src/train_softmax.py index 0024852..bafcd90 100644 --- a/src/train_softmax.py +++ b/src/train_softmax.py @@ -77,7 +77,10 @@ class AccMetric(mx.metric.EvalMetric): if pred_label.shape != label.shape: pred_label = mx.ndarray.argmax(pred_label, axis=self.axis) pred_label = pred_label.asnumpy().astype('int32').flatten() - label = label.asnumpy().astype('int32').flatten() + label = label.asnumpy() + if label.ndim==2: + label = label[:,0] + label = label.astype('int32').flatten() #print(label) #print('label',label) #print('pred_label', pred_label) @@ -223,7 +226,9 @@ def get_symbol(args, arg_params, aux_params): gt_label = all_label else: gt_label = mx.symbol.slice_axis(all_label, axis=1, begin=0, end=1) + gt_label = mx.symbol.reshape(gt_label, (args.per_batch_size,)) c2c_label = mx.symbol.slice_axis(all_label, axis=1, begin=1, end=2) + c2c_label = mx.symbol.reshape(c2c_label, (args.per_batch_size,)) assert args.loss_type>=0 extra_loss = None if args.loss_type==0: #softmax @@ -319,7 +324,7 @@ def get_symbol(args, arg_params, aux_params): fc7 = mx.sym.FullyConnected(data=nembedding, weight = _weight, no_bias = True, num_hidden=args.num_classes, name='fc7') zy = mx.sym.pick(fc7, gt_label, axis=1) cos_t = zy/s - if m>0.0: + if args.output_c2c==0: cos_m = math.cos(m) sin_m = math.sin(m) mm = math.sin(math.pi-m)*m @@ -345,7 +350,6 @@ def get_symbol(args, arg_params, aux_params): zy_keep = zy - s*mm new_zy = mx.sym.where(cond, new_zy, zy_keep) else: - assert args.output_c2c #set c2c as cosm^2 in data.py cos_m = mx.sym.sqrt(c2c_label) sin_m = 1.0-c2c_label @@ -619,6 +623,9 @@ def train_net(args): coco_mode = True label_name = 'softmax_label' + label_shape = (args.batch_size,) + if args.output_c2c: + label_shape = (args.batch_size,2) if data_extra is None: model = mx.mod.Module( context = ctx, @@ -658,6 +665,7 @@ def train_net(args): rand_mirror = args.rand_mirror, mean = mean, c2c_threshold = args.c2c_threshold, + output_c2c = args.output_c2c, ctx_num = args.ctx_num, images_per_identity = args.images_per_identity, data_extra = data_extra, @@ -679,6 +687,7 @@ def train_net(args): rand_mirror = args.rand_mirror, mean = mean, c2c_threshold = args.c2c_threshold, + output_c2c = args.output_c2c, ctx_num = args.ctx_num, images_per_identity = args.images_per_identity, data_extra = data_extra, @@ -726,7 +735,7 @@ def train_net(args): def ver_test(nbatch): results = [] for i in xrange(len(ver_list)): - acc1, std1, acc2, std2, xnorm, embeddings_list = verification.test(ver_list[i], model, args.batch_size, data_extra) + acc1, std1, acc2, std2, xnorm, embeddings_list = verification.test(ver_list[i], model, args.batch_size, data_extra, label_shape) print('[%s][%d]XNorm: %f' % (ver_name_list[i], nbatch, xnorm)) #print('[%s][%d]Accuracy: %1.5f+-%1.5f' % (ver_name_list[i], nbatch, acc1, std1)) print('[%s][%d]Accuracy-Flip: %1.5f+-%1.5f' % (ver_name_list[i], nbatch, acc2, std2))