From 7850807bdd2b7bb75efc5ba18c334029136716ac Mon Sep 17 00:00:00 2001 From: tydlwav Date: Thu, 11 Jul 2019 20:48:05 -0400 Subject: [PATCH 1/4] add mean distance for same bag --- scripts/main.py | 6 ++++-- torchreid/engine/engine.py | 5 +++-- torchreid/utils/rerank.py | 23 ++++++++++++++++++++++- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/scripts/main.py b/scripts/main.py index a5c90a6..be89ccc 100755 --- a/scripts/main.py +++ b/scripts/main.py @@ -60,7 +60,8 @@ def build_engine(args, datamanager, model, optimizer, scheduler, experiment=expe scheduler=scheduler, use_cpu=args.use_cpu, label_smooth=args.label_smooth, - experiment=experiment + experiment=experiment, + by_id="mean" ) else: engine = torchreid.engine.ImageTripletEngine( @@ -73,7 +74,8 @@ def build_engine(args, datamanager, model, optimizer, scheduler, experiment=expe scheduler=scheduler, use_cpu=args.use_cpu, label_smooth=args.label_smooth, - experiment=experiment + experiment=experiment, + by_id="mean" ) else: diff --git a/torchreid/engine/engine.py b/torchreid/engine/engine.py index 39cd683..2350a09 100644 --- a/torchreid/engine/engine.py +++ b/torchreid/engine/engine.py @@ -32,7 +32,7 @@ class Engine(object): use_cpu (bool, optional): use cpu. Default is False. """ - def __init__(self, datamanager, model, optimizer=None, scheduler=None, use_cpu=False, experiment=None): + def __init__(self, datamanager, model, optimizer=None, scheduler=None, use_cpu=False, experiment=None, by_id="mean"): self.datamanager = datamanager self.model = model self.optimizer = optimizer @@ -40,6 +40,7 @@ def __init__(self, datamanager, model, optimizer=None, scheduler=None, use_cpu=F self.use_gpu = (torch.cuda.is_available() and not use_cpu) self.writer = None self.experiment = experiment + self.by_id = by_id # check attributes if not isinstance(self.model, nn.Module): @@ -311,7 +312,7 @@ def _evaluate(self, arch, epoch, dataset_name='', queryloader=None, galleryloade print('Computing distance matrix with metric={} ...'.format(dist_metric)) distmat = metrics.compute_distance_matrix(qf, gf, dist_metric) - distmat = distmat.numpy() + distmat = distmat_by_id(distmat.numpy(), q_pids, g_pids, self.by_id) if rerank: print('Applying person re-ranking ...') diff --git a/torchreid/utils/rerank.py b/torchreid/utils/rerank.py index dfe82ed..f75dbad 100644 --- a/torchreid/utils/rerank.py +++ b/torchreid/utils/rerank.py @@ -26,7 +26,7 @@ from __future__ import print_function from __future__ import division -__all__ = ['re_ranking'] +__all__ = ['re_ranking', 'distmat_by_id'] import numpy as np @@ -98,3 +98,24 @@ def re_ranking(q_g_dist, q_q_dist, g_g_dist, k1=20, k2=6, lambda_value=0.3): del jaccard_dist final_dist = final_dist[:query_num,query_num:] return final_dist + +def distmat_by_id(distmat, g_id, by_id): + """ + transforms distance matrix to + """ + if by_id == None: + return distmat + elif by_id == "mean": + unique_ids = set(g_id) + gid_distmat = np.empty((distmat.shape[0], len(unique_ids))) + for bag_id, i in enumerate(unique_ids): + gid_distmat[:, i] = np.mean(distmat[:, np.asarray(g_id) == bag_id], axis=-1, keepdims=True) + return gid_distmat + elif by_id == "self_attention": + # TODO: self attention + return distmat + elif by_id == "multi_head_attention": + # TODO: multi-headed attention + return distmat + else: + raise ValueError('Must be valid by_id method') \ No newline at end of file From 0f1c2f0ff344ede3a662f123745a0a4b3db71664 Mon Sep 17 00:00:00 2001 From: tydlwav Date: Thu, 11 Jul 2019 22:14:52 -0400 Subject: [PATCH 2/4] some bad changes --- scripts/main.py | 3 ++- torchreid/engine/engine.py | 4 ++-- torchreid/engine/image/softmax.py | 2 +- torchreid/engine/image/triplet.py | 2 +- torchreid/utils/__init__.py | 2 +- torchreid/utils/rerank.py | 6 +++--- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/scripts/main.py b/scripts/main.py index be89ccc..3097c3d 100755 --- a/scripts/main.py +++ b/scripts/main.py @@ -53,6 +53,7 @@ def build_datamanager(args): def build_engine(args, datamanager, model, optimizer, scheduler, experiment=experiment): if args.app == 'image': if args.loss == 'softmax': + print('\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n') engine = torchreid.engine.ImageSoftmaxEngine( datamanager, model, @@ -61,7 +62,7 @@ def build_engine(args, datamanager, model, optimizer, scheduler, experiment=expe use_cpu=args.use_cpu, label_smooth=args.label_smooth, experiment=experiment, - by_id="mean" + by_id=None ) else: engine = torchreid.engine.ImageTripletEngine( diff --git a/torchreid/engine/engine.py b/torchreid/engine/engine.py index 2350a09..01480fe 100644 --- a/torchreid/engine/engine.py +++ b/torchreid/engine/engine.py @@ -13,7 +13,7 @@ from torch.nn import functional as F import torchreid -from torchreid.utils import AverageMeter, visualize_ranked_results, visualize_cam, save_checkpoint, re_ranking +from torchreid.utils import AverageMeter, visualize_ranked_results, visualize_cam, save_checkpoint, re_ranking, distmat_by_id from torchreid.losses import DeepSupervision from torchreid import metrics @@ -312,7 +312,7 @@ def _evaluate(self, arch, epoch, dataset_name='', queryloader=None, galleryloade print('Computing distance matrix with metric={} ...'.format(dist_metric)) distmat = metrics.compute_distance_matrix(qf, gf, dist_metric) - distmat = distmat_by_id(distmat.numpy(), q_pids, g_pids, self.by_id) + distmat = distmat_by_id(distmat.numpy(), g_pids, self.by_id) if rerank: print('Applying person re-ranking ...') diff --git a/torchreid/engine/image/softmax.py b/torchreid/engine/image/softmax.py index 03fe0c9..1e4faa0 100644 --- a/torchreid/engine/image/softmax.py +++ b/torchreid/engine/image/softmax.py @@ -63,7 +63,7 @@ class ImageSoftmaxEngine(engine.Engine): """ def __init__(self, datamanager, model, optimizer, scheduler=None, use_cpu=False, - label_smooth=True, experiment=None): + label_smooth=True, experiment=None, by_id="mean"): super(ImageSoftmaxEngine, self).__init__(datamanager, model, optimizer, scheduler, use_cpu, experiment) self.criterion = CrossEntropyLoss( diff --git a/torchreid/engine/image/triplet.py b/torchreid/engine/image/triplet.py index 2d0c4fd..b8c809c 100644 --- a/torchreid/engine/image/triplet.py +++ b/torchreid/engine/image/triplet.py @@ -70,7 +70,7 @@ class ImageTripletEngine(engine.Engine): def __init__(self, datamanager, model, optimizer, margin=0.3, weight_t=1, weight_x=1, scheduler=None, use_cpu=False, - label_smooth=True, experiment=None): + label_smooth=True, experiment=None, by_id="mean"): super(ImageTripletEngine, self).__init__(datamanager, model, optimizer, scheduler, use_cpu, experiment) self.weight_t = weight_t diff --git a/torchreid/utils/__init__.py b/torchreid/utils/__init__.py index fb04b6e..8fedf9b 100644 --- a/torchreid/utils/__init__.py +++ b/torchreid/utils/__init__.py @@ -6,5 +6,5 @@ from .tools import * from .reidtools import * from .torchtools import * -from .rerank import re_ranking +from .rerank import re_ranking, distmat_by_id from .model_complexity import compute_model_complexity diff --git a/torchreid/utils/rerank.py b/torchreid/utils/rerank.py index f75dbad..3a853d7 100644 --- a/torchreid/utils/rerank.py +++ b/torchreid/utils/rerank.py @@ -103,13 +103,13 @@ def distmat_by_id(distmat, g_id, by_id): """ transforms distance matrix to """ - if by_id == None: + if by_id is None: return distmat elif by_id == "mean": unique_ids = set(g_id) gid_distmat = np.empty((distmat.shape[0], len(unique_ids))) - for bag_id, i in enumerate(unique_ids): - gid_distmat[:, i] = np.mean(distmat[:, np.asarray(g_id) == bag_id], axis=-1, keepdims=True) + for i, bag_id in enumerate(unique_ids): + gid_distmat[:, i] = np.mean(distmat[:, np.asarray(g_id) == bag_id], axis=-1) return gid_distmat elif by_id == "self_attention": # TODO: self attention From 05c3f9d1fe123340d09a9b37e68738ff8760469c Mon Sep 17 00:00:00 2001 From: tydlwav Date: Thu, 11 Jul 2019 23:03:14 -0400 Subject: [PATCH 3/4] working reranking --- scripts/main.py | 5 ++--- torchreid/engine/engine.py | 9 +++++---- torchreid/engine/image/softmax.py | 4 ++-- torchreid/engine/image/triplet.py | 4 ++-- torchreid/utils/__init__.py | 3 ++- torchreid/utils/multi_image.py | 27 +++++++++++++++++++++++++++ torchreid/utils/rerank.py | 23 +---------------------- 7 files changed, 41 insertions(+), 34 deletions(-) create mode 100644 torchreid/utils/multi_image.py diff --git a/scripts/main.py b/scripts/main.py index 3097c3d..7709812 100755 --- a/scripts/main.py +++ b/scripts/main.py @@ -53,7 +53,6 @@ def build_datamanager(args): def build_engine(args, datamanager, model, optimizer, scheduler, experiment=experiment): if args.app == 'image': if args.loss == 'softmax': - print('\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n') engine = torchreid.engine.ImageSoftmaxEngine( datamanager, model, @@ -62,7 +61,7 @@ def build_engine(args, datamanager, model, optimizer, scheduler, experiment=expe use_cpu=args.use_cpu, label_smooth=args.label_smooth, experiment=experiment, - by_id=None + combine_method="mean" ) else: engine = torchreid.engine.ImageTripletEngine( @@ -76,7 +75,7 @@ def build_engine(args, datamanager, model, optimizer, scheduler, experiment=expe use_cpu=args.use_cpu, label_smooth=args.label_smooth, experiment=experiment, - by_id="mean" + combine_method="mean" ) else: diff --git a/torchreid/engine/engine.py b/torchreid/engine/engine.py index 01480fe..04b29d7 100644 --- a/torchreid/engine/engine.py +++ b/torchreid/engine/engine.py @@ -13,7 +13,7 @@ from torch.nn import functional as F import torchreid -from torchreid.utils import AverageMeter, visualize_ranked_results, visualize_cam, save_checkpoint, re_ranking, distmat_by_id +from torchreid.utils import AverageMeter, visualize_ranked_results, visualize_cam, save_checkpoint, re_ranking, combine_by_id from torchreid.losses import DeepSupervision from torchreid import metrics @@ -32,7 +32,7 @@ class Engine(object): use_cpu (bool, optional): use cpu. Default is False. """ - def __init__(self, datamanager, model, optimizer=None, scheduler=None, use_cpu=False, experiment=None, by_id="mean"): + def __init__(self, datamanager, model, optimizer=None, scheduler=None, use_cpu=False, experiment=None, combine_method="mean"): self.datamanager = datamanager self.model = model self.optimizer = optimizer @@ -40,7 +40,7 @@ def __init__(self, datamanager, model, optimizer=None, scheduler=None, use_cpu=F self.use_gpu = (torch.cuda.is_available() and not use_cpu) self.writer = None self.experiment = experiment - self.by_id = by_id + self.combine_method = combine_method # check attributes if not isinstance(self.model, nn.Module): @@ -301,6 +301,7 @@ def _evaluate(self, arch, epoch, dataset_name='', queryloader=None, galleryloade gf = torch.cat(gf, 0) g_pids = np.asarray(g_pids) g_camids = np.asarray(g_camids) + gf, g_pids = combine_by_id(gf, g_pids, self.combine_method) print('Done, obtained {}-by-{} matrix'.format(gf.size(0), gf.size(1))) print('Speed: {:.4f} sec/batch'.format(batch_time.avg)) @@ -312,7 +313,7 @@ def _evaluate(self, arch, epoch, dataset_name='', queryloader=None, galleryloade print('Computing distance matrix with metric={} ...'.format(dist_metric)) distmat = metrics.compute_distance_matrix(qf, gf, dist_metric) - distmat = distmat_by_id(distmat.numpy(), g_pids, self.by_id) + distmat = distmat.numpy() if rerank: print('Applying person re-ranking ...') diff --git a/torchreid/engine/image/softmax.py b/torchreid/engine/image/softmax.py index 1e4faa0..facaacc 100644 --- a/torchreid/engine/image/softmax.py +++ b/torchreid/engine/image/softmax.py @@ -63,8 +63,8 @@ class ImageSoftmaxEngine(engine.Engine): """ def __init__(self, datamanager, model, optimizer, scheduler=None, use_cpu=False, - label_smooth=True, experiment=None, by_id="mean"): - super(ImageSoftmaxEngine, self).__init__(datamanager, model, optimizer, scheduler, use_cpu, experiment) + label_smooth=True, experiment=None, combine_method="mean"): + super(ImageSoftmaxEngine, self).__init__(datamanager, model, optimizer, scheduler, use_cpu, experiment, combine_method) self.criterion = CrossEntropyLoss( num_classes=self.datamanager.num_train_pids, diff --git a/torchreid/engine/image/triplet.py b/torchreid/engine/image/triplet.py index b8c809c..406f378 100644 --- a/torchreid/engine/image/triplet.py +++ b/torchreid/engine/image/triplet.py @@ -70,8 +70,8 @@ class ImageTripletEngine(engine.Engine): def __init__(self, datamanager, model, optimizer, margin=0.3, weight_t=1, weight_x=1, scheduler=None, use_cpu=False, - label_smooth=True, experiment=None, by_id="mean"): - super(ImageTripletEngine, self).__init__(datamanager, model, optimizer, scheduler, use_cpu, experiment) + label_smooth=True, experiment=None, combine_method="mean"): + super(ImageTripletEngine, self).__init__(datamanager, model, optimizer, scheduler, use_cpu, experiment, combine_method) self.weight_t = weight_t self.weight_x = weight_x diff --git a/torchreid/utils/__init__.py b/torchreid/utils/__init__.py index 8fedf9b..01e6769 100644 --- a/torchreid/utils/__init__.py +++ b/torchreid/utils/__init__.py @@ -6,5 +6,6 @@ from .tools import * from .reidtools import * from .torchtools import * -from .rerank import re_ranking, distmat_by_id +from .rerank import re_ranking +from .multi_image import combine_by_id from .model_complexity import compute_model_complexity diff --git a/torchreid/utils/multi_image.py b/torchreid/utils/multi_image.py new file mode 100644 index 0000000..709e5c6 --- /dev/null +++ b/torchreid/utils/multi_image.py @@ -0,0 +1,27 @@ +import numpy as np +__all__ = ['combine_by_id'] + +def combine_by_id(gf, g_pids, method): + """ + transforms features of same bag to a bag embedding + """ + if method is None: + return gf, g_pids + elif method == "mean": + gf = gf.numpy() + unique_ids = set(g_pids) + new_g_pids = [] + gf_by_id = np.empty((len(unique_ids), gf.shape[-1])) + for i, gid in enumerate(unique_ids): + gf_by_id[i] = np.mean(gf[np.asarray(g_pids) == gid], axis=0) + new_g_pids.append(gid) + gf = torch.tensor(gf_by_id, dtype=torch.float) + g_pids = np.array(new_g_pids) + elif method == "self_attention": + # TODO: self attention + return distmat + elif method == "multi_head_attention": + # TODO: multi-headed attention + return distmat + else: + raise ValueError('Must be valid by_id method') \ No newline at end of file diff --git a/torchreid/utils/rerank.py b/torchreid/utils/rerank.py index 3a853d7..dfe82ed 100644 --- a/torchreid/utils/rerank.py +++ b/torchreid/utils/rerank.py @@ -26,7 +26,7 @@ from __future__ import print_function from __future__ import division -__all__ = ['re_ranking', 'distmat_by_id'] +__all__ = ['re_ranking'] import numpy as np @@ -98,24 +98,3 @@ def re_ranking(q_g_dist, q_q_dist, g_g_dist, k1=20, k2=6, lambda_value=0.3): del jaccard_dist final_dist = final_dist[:query_num,query_num:] return final_dist - -def distmat_by_id(distmat, g_id, by_id): - """ - transforms distance matrix to - """ - if by_id is None: - return distmat - elif by_id == "mean": - unique_ids = set(g_id) - gid_distmat = np.empty((distmat.shape[0], len(unique_ids))) - for i, bag_id in enumerate(unique_ids): - gid_distmat[:, i] = np.mean(distmat[:, np.asarray(g_id) == bag_id], axis=-1) - return gid_distmat - elif by_id == "self_attention": - # TODO: self attention - return distmat - elif by_id == "multi_head_attention": - # TODO: multi-headed attention - return distmat - else: - raise ValueError('Must be valid by_id method') \ No newline at end of file From e1b9a8bdaee5009794dd79cf83e13fcaace4d2c9 Mon Sep 17 00:00:00 2001 From: tydlwav Date: Thu, 11 Jul 2019 23:32:05 -0400 Subject: [PATCH 4/4] adds argument parsing --- scripts/default_parser.py | 2 ++ scripts/main.py | 4 ++-- torchreid/engine/engine.py | 11 +++++++++++ torchreid/utils/multi_image.py | 8 ++++++-- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/scripts/default_parser.py b/scripts/default_parser.py index df8007d..6796c39 100644 --- a/scripts/default_parser.py +++ b/scripts/default_parser.py @@ -168,6 +168,8 @@ def init_parser(): help='cmc ranks') parser.add_argument('--rerank', action='store_true', help='use person re-ranking (by Zhong et al. CVPR2017)') + parser.add_argument('--combine-method', type=str, default='none', choices=["none", "mean"], + help='use combine method of [none | mean]') parser.add_argument('--visrank', action='store_true', help='visualize ranked results, only available in evaluation mode') diff --git a/scripts/main.py b/scripts/main.py index 7709812..defef76 100755 --- a/scripts/main.py +++ b/scripts/main.py @@ -61,7 +61,7 @@ def build_engine(args, datamanager, model, optimizer, scheduler, experiment=expe use_cpu=args.use_cpu, label_smooth=args.label_smooth, experiment=experiment, - combine_method="mean" + combine_method=args.combine_method ) else: engine = torchreid.engine.ImageTripletEngine( @@ -75,7 +75,7 @@ def build_engine(args, datamanager, model, optimizer, scheduler, experiment=expe use_cpu=args.use_cpu, label_smooth=args.label_smooth, experiment=experiment, - combine_method="mean" + combine_method=args.combine_method ) else: diff --git a/torchreid/engine/engine.py b/torchreid/engine/engine.py index 04b29d7..3fc6f4c 100644 --- a/torchreid/engine/engine.py +++ b/torchreid/engine/engine.py @@ -301,6 +301,17 @@ def _evaluate(self, arch, epoch, dataset_name='', queryloader=None, galleryloade gf = torch.cat(gf, 0) g_pids = np.asarray(g_pids) g_camids = np.asarray(g_camids) + + # gf = gf.numpy() + # unique_ids = set(g_pids) + # new_g_pids = [] + # gf_by_id = np.empty((len(unique_ids), gf.shape[-1])) + # for i, gid in enumerate(unique_ids): + # gf_by_id[i] = np.mean(gf[np.asarray(g_pids) == gid], axis=0) + # new_g_pids.append(gid) + # gf = torch.tensor(gf_by_id, dtype=torch.float) + # g_pids = np.array(new_g_pids) + gf, g_pids = combine_by_id(gf, g_pids, self.combine_method) print('Done, obtained {}-by-{} matrix'.format(gf.size(0), gf.size(1))) diff --git a/torchreid/utils/multi_image.py b/torchreid/utils/multi_image.py index 709e5c6..0c04b38 100644 --- a/torchreid/utils/multi_image.py +++ b/torchreid/utils/multi_image.py @@ -1,13 +1,16 @@ import numpy as np +import torch __all__ = ['combine_by_id'] def combine_by_id(gf, g_pids, method): """ transforms features of same bag to a bag embedding """ - if method is None: + if method == "none": + print("Does not combine by id") return gf, g_pids elif method == "mean": + print("Calculating mean by id ...") gf = gf.numpy() unique_ids = set(g_pids) new_g_pids = [] @@ -17,6 +20,7 @@ def combine_by_id(gf, g_pids, method): new_g_pids.append(gid) gf = torch.tensor(gf_by_id, dtype=torch.float) g_pids = np.array(new_g_pids) + return gf, g_pids elif method == "self_attention": # TODO: self attention return distmat @@ -24,4 +28,4 @@ def combine_by_id(gf, g_pids, method): # TODO: multi-headed attention return distmat else: - raise ValueError('Must be valid by_id method') \ No newline at end of file + raise ValueError('Must be valid combine-method')