From b777ddd6515a743404ca532a2160473ed75b0b9a Mon Sep 17 00:00:00 2001 From: OWAL Admin Date: Fri, 23 Oct 2020 03:55:43 +0000 Subject: [PATCH 01/24] Added optional support to return heatmaps and backbone features during inference of top-down pose model --- demo/top_down_img_demo.py | 8 ++-- demo/top_down_img_demo_with_mmdet.py | 6 ++- demo/top_down_video_demo_with_mmdet.py | 6 ++- mmpose/apis/inference.py | 56 +++++++++++++++++--------- mmpose/models/detectors/top_down.py | 33 ++++++++++----- 5 files changed, 73 insertions(+), 36 deletions(-) diff --git a/demo/top_down_img_demo.py b/demo/top_down_img_demo.py index ddd5c65293..ba5a4c85cc 100644 --- a/demo/top_down_img_demo.py +++ b/demo/top_down_img_demo.py @@ -66,13 +66,15 @@ def main(): bbox = ann['bbox'] person_bboxes.append(bbox) - # test a single image, with a list of bboxes. - pose_results, heatmaps = inference_top_down_pose_model( + # test a single image, with a list of bboxes + pose_results, heatmaps, backbone_features = inference_top_down_pose_model( pose_model, image_name, person_bboxes, format='xywh', - dataset=dataset) + dataset=dataset, + return_heatmap=False, + return_backbone_features=False) if args.out_img_root == '': out_file = None diff --git a/demo/top_down_img_demo_with_mmdet.py b/demo/top_down_img_demo_with_mmdet.py index edf573c643..160058fcf7 100644 --- a/demo/top_down_img_demo_with_mmdet.py +++ b/demo/top_down_img_demo_with_mmdet.py @@ -64,13 +64,15 @@ def main(): person_bboxes = det_results[0].copy() # test a single image, with a list of bboxes. - pose_results, heatmaps = inference_top_down_pose_model( + pose_results, heatmaps, backbone_features = inference_top_down_pose_model( pose_model, image_name, person_bboxes, bbox_thr=args.bbox_thr, format='xyxy', - dataset=dataset) + dataset=dataset, + return_heatmap=False, + return_backbone_features=False) if args.out_img_root == '': out_file = None diff --git a/demo/top_down_video_demo_with_mmdet.py b/demo/top_down_video_demo_with_mmdet.py index ddad592f8f..3d9d1df14e 100644 --- a/demo/top_down_video_demo_with_mmdet.py +++ b/demo/top_down_video_demo_with_mmdet.py @@ -81,13 +81,15 @@ def main(): person_bboxes = det_results[0].copy() # test a single image, with a list of bboxes. - pose_results, heatmaps = inference_top_down_pose_model( + pose_results, heatmaps, backbone_features = inference_top_down_pose_model( pose_model, img, person_bboxes, bbox_thr=args.bbox_thr, format='xyxy', - dataset=dataset) + dataset=dataset, + return_heatmap=False, + return_backbone_features=False) # show the results vis_img = vis_pose_result( diff --git a/mmpose/apis/inference.py b/mmpose/apis/inference.py index 459e5a5766..1325b9d9a7 100644 --- a/mmpose/apis/inference.py +++ b/mmpose/apis/inference.py @@ -132,7 +132,9 @@ def __call__(self, results): return results -def _inference_single_pose_model(model, img_or_path, bbox, dataset): +def _inference_single_pose_model(model, img_or_path, bbox, dataset, + return_heatmap=False, + return_backbone_features=False): """Inference a single bbox. num_keypoints: K @@ -143,10 +145,13 @@ def _inference_single_pose_model(model, img_or_path, bbox, dataset): bbox (list | np.ndarray): Bounding boxes (with scores), shaped (4, ) or (5, ). (left, top, width, height, [score]) dataset (str): Dataset name. + return_heatmap (bool) : To return heatmap + return_backbone_features (bool) : To return backbone features Returns: ndarray[Kx3]: Predicted pose x, y, score. ndarray[NxKxHxW]: Model output heatmap. + ndarray[NxKxHxW]: Model backbone features. """ cfg = model.cfg device = next(model.parameters()).device @@ -223,10 +228,13 @@ def _inference_single_pose_model(model, img_or_path, bbox, dataset): # forward the model with torch.no_grad(): - all_preds, _, _, heatmap = model( - return_loss=False, img=data['img'], img_metas=data['img_metas']) + all_preds, _, _, heatmap, backbone_features = model( + return_loss=False, + return_heatmap=return_heatmap, + return_backbone_features=return_backbone_features, + img=data['img'], img_metas=data['img_metas']) - return all_preds[0], heatmap + return all_preds[0], heatmap, backbone_features def inference_top_down_pose_model(model, @@ -234,6 +242,8 @@ def inference_top_down_pose_model(model, person_bboxes, bbox_thr=None, format='xywh', + return_heatmap=False, + return_backbone_features=False, dataset='TopDownCocoDataset'): """Inference a single image with a list of person bounding boxes. @@ -253,38 +263,44 @@ def inference_top_down_pose_model(model, 'xyxy' means (left, top, right, bottom), 'xywh' means (left, top, width, height). dataset (str): Dataset name, e.g. 'TopDownCocoDataset'. + return_heamap (bool) : To return heatmaps + return_backbone_features (bool) : To return backbone features Returns: - list[dict]: The bbox & pose info. - + list[dict]: The bbox & pose info, Each item in the list is a dictionary, containing the bbox: (left, top, right, bottom, [score]) and the pose (ndarray[Kx3]): x, y, score + list[ndarray]: The heatmap + list[ndarray]: The backbone features + """ # only two kinds of bbox format is supported. assert format in ['xyxy', 'xywh'] # transform the bboxes format to xywh if format == 'xyxy': person_bboxes = _xyxy2xywh(np.array(person_bboxes)) + pose_results = [] - heatmaps = [] - + heatmaps=[] + backbone_features=[] if len(person_bboxes) > 0: if bbox_thr is not None: person_bboxes = person_bboxes[person_bboxes[:, 4] > bbox_thr] for bbox in person_bboxes: - pose, heatmap = _inference_single_pose_model( - model, img_or_path, bbox, dataset) - pose_results.append({ - 'bbox': - _xywh2xyxy(np.expand_dims(np.array(bbox), 0)), - 'keypoints': - pose, - }) - - heatmaps.append(heatmap) - - return pose_results, heatmaps + pose, heatmap, backbone_feat = _inference_single_pose_model( + model, img_or_path, bbox, dataset, return_heatmap, return_backbone_features) + + if return_heatmap: + heatmaps.append(heatmap) + + if backbone_features: + backbone_features.append(backbone_feat) + + pose_results.append({'bbox': _xywh2xyxy(np.expand_dims(np.array(bbox), 0)), + 'keypoints': pose}) + + return pose_results, heatmaps, backbone_features def inference_bottom_up_pose_model(model, img_or_path): diff --git a/mmpose/models/detectors/top_down.py b/mmpose/models/detectors/top_down.py index 209900f1ef..e0a31c642b 100644 --- a/mmpose/models/detectors/top_down.py +++ b/mmpose/models/detectors/top_down.py @@ -64,6 +64,8 @@ def forward(self, target_weight=None, img_metas=None, return_loss=True, + return_heatmap=False, + return_backbone_features=False, **kwargs): """Calls either forward_train or forward_test depending on whether return_loss=True. Note this setting will change the expected inputs. @@ -104,7 +106,7 @@ def forward(self, return self.forward_train(img, target, target_weight, img_metas, **kwargs) else: - return self.forward_test(img, img_metas, **kwargs) + return self.forward_test(img, img_metas, return_heatmap, return_backbone_features, **kwargs) def forward_train(self, img, target, target_weight, img_metas, **kwargs): """Defines the computation performed at every call when training.""" @@ -175,16 +177,26 @@ def forward_train(self, img, target, target_weight, img_metas, **kwargs): return losses - def forward_test(self, img, img_metas, **kwargs): + def forward_test(self, img, img_metas, return_heatmap, return_backbone_features, **kwargs): """Defines the computation performed at every call when testing.""" assert img.size(0) == 1 assert len(img_metas) == 1 - img_metas = img_metas[0] - - flip_pairs = img_metas['flip_pairs'] - # compute output + backbone_features = None + + # compute backbone features output = self.backbone(img) + + if return_backbone_features: + backbone_features = output.detach().cpu().numpy() + + all_preds, all_boxes, image_path, heatmap = process_head(output, img_metas, return_heatmap=return_heatmap) + return all_preds, all_boxes, image_path, heatmap, backbone_features + + def process_head(self, output, img_metas, return_heatmap=False): + """Process heatmap and keypoints from backbone features.""" + flip_pairs = img_metas['flip_pairs'] + if self.with_keypoint: output = self.keypoint_head(output) @@ -238,9 +250,12 @@ def forward_test(self, img, img_metas, **kwargs): all_boxes[0, 4] = np.prod(s * 200.0, axis=1) all_boxes[0, 5] = score image_path.extend(img_metas['image_file']) - - return all_preds, all_boxes, image_path, output_heatmap - + + if return_heatmap: + return all_preds, all_boxes, image_path, output_heatmap + else: + return all_preds, all_boxes, image_path, None + def show_result(self, img, result, From 698981a9b08641826f9036c8263a4982db2fda13 Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Fri, 23 Oct 2020 19:06:32 +0000 Subject: [PATCH 02/24] Added hooks for extracting layer outputs defined by name (and heatmap) --- demo/top_down_img_demo.py | 16 +++--- demo/top_down_img_demo_with_mmdet.py | 5 +- demo/top_down_video_demo_with_mmdet.py | 9 +-- mmpose/apis/inference.py | 80 +++++++++++++++++--------- mmpose/models/detectors/top_down.py | 33 +++++------ 5 files changed, 85 insertions(+), 58 deletions(-) diff --git a/demo/top_down_img_demo.py b/demo/top_down_img_demo.py index ba5a4c85cc..1a88e3100e 100644 --- a/demo/top_down_img_demo.py +++ b/demo/top_down_img_demo.py @@ -49,7 +49,9 @@ def main(): dataset = pose_model.cfg.data['test']['type'] img_keys = list(coco.imgs.keys()) - + + output_layer_names = ('heatmap') #None + # process each image for i in range(len(img_keys)): # get bounding box annotations @@ -67,15 +69,15 @@ def main(): person_bboxes.append(bbox) # test a single image, with a list of bboxes - pose_results, heatmaps, backbone_features = inference_top_down_pose_model( + pose_results, returned_outputs = inference_top_down_pose_model( pose_model, - image_name, + img, person_bboxes, - format='xywh', + bbox_thr=args.bbox_thr, + format='xyxy', dataset=dataset, - return_heatmap=False, - return_backbone_features=False) - + outputs=output_layer_names) + if args.out_img_root == '': out_file = None else: diff --git a/demo/top_down_img_demo_with_mmdet.py b/demo/top_down_img_demo_with_mmdet.py index 160058fcf7..b325f8ba83 100644 --- a/demo/top_down_img_demo_with_mmdet.py +++ b/demo/top_down_img_demo_with_mmdet.py @@ -64,6 +64,8 @@ def main(): person_bboxes = det_results[0].copy() # test a single image, with a list of bboxes. + + output_layer_names = ('heatmap') #None pose_results, heatmaps, backbone_features = inference_top_down_pose_model( pose_model, image_name, @@ -71,8 +73,7 @@ def main(): bbox_thr=args.bbox_thr, format='xyxy', dataset=dataset, - return_heatmap=False, - return_backbone_features=False) + outputs=output_layer_names) if args.out_img_root == '': out_file = None diff --git a/demo/top_down_video_demo_with_mmdet.py b/demo/top_down_video_demo_with_mmdet.py index 3d9d1df14e..2b9e37f131 100644 --- a/demo/top_down_video_demo_with_mmdet.py +++ b/demo/top_down_video_demo_with_mmdet.py @@ -54,7 +54,7 @@ def main(): dataset = pose_model.cfg.data['test']['type'] cap = cv2.VideoCapture(args.video_path) - + if args.out_video_root == '': save_out_video = False else: @@ -71,6 +71,8 @@ def main(): f'vis_{os.path.basename(args.video_path)}'), fourcc, fps, size) + output_layer_names = ('heatmap') #None + while (cap.isOpened()): flag, img = cap.read() if not flag: @@ -81,15 +83,14 @@ def main(): person_bboxes = det_results[0].copy() # test a single image, with a list of bboxes. - pose_results, heatmaps, backbone_features = inference_top_down_pose_model( + pose_results, returned_outputs = inference_top_down_pose_model( pose_model, img, person_bboxes, bbox_thr=args.bbox_thr, format='xyxy', dataset=dataset, - return_heatmap=False, - return_backbone_features=False) + outputs=output_layer_names) # show the results vis_img = vis_pose_result( diff --git a/mmpose/apis/inference.py b/mmpose/apis/inference.py index 1325b9d9a7..5a6db96d52 100644 --- a/mmpose/apis/inference.py +++ b/mmpose/apis/inference.py @@ -1,4 +1,6 @@ import os +import functools +from collections import OrderedDict import mmcv import numpy as np @@ -131,10 +133,7 @@ def __call__(self, results): results['img'] = img return results - -def _inference_single_pose_model(model, img_or_path, bbox, dataset, - return_heatmap=False, - return_backbone_features=False): +def _inference_single_pose_model(model, img_or_path, bbox, dataset, outputs=None): """Inference a single bbox. num_keypoints: K @@ -145,7 +144,7 @@ def _inference_single_pose_model(model, img_or_path, bbox, dataset, bbox (list | np.ndarray): Bounding boxes (with scores), shaped (4, ) or (5, ). (left, top, width, height, [score]) dataset (str): Dataset name. - return_heatmap (bool) : To return heatmap + outputs (list(str) : List of layer names whose output is to be returned return_backbone_features (bool) : To return backbone features Returns: @@ -228,23 +227,54 @@ def _inference_single_pose_model(model, img_or_path, bbox, dataset, # forward the model with torch.no_grad(): - all_preds, _, _, heatmap, backbone_features = model( - return_loss=False, - return_heatmap=return_heatmap, - return_backbone_features=return_backbone_features, - img=data['img'], img_metas=data['img_metas']) + # prepare hooks to return ouputs + returned_outputs = OrderedDict() + return_heatmap = False + handles = [] + def hook_wrapper(name): + def hook(model, input, output): + returned_outputs[name] = output.detach().cpu().numpy() + return hook + + if isinstance(outputs, (list, tuple)): + for name in outputs: + try: + layer = rgetattr(model, name) + h = layer.register_forward_hook(hook_wrapper(name)) + except Exception as e: + #raise AttributeError(f'Module {name} not found') + continue + handles.append(h) + + if 'heatmap' or 'heatmaps' in outputs: + return_heatmap = True + + all_preds, _, _ = model(return_loss=False, + return_heatmap=return_heatmap, + img=data['img'], img_metas=data['img_metas']) + + if return_heatmap: + returned_outputs['heatmap'] = model.output_heatmap - return all_preds[0], heatmap, backbone_features + #clear handles (if any) + for h in handles: + h.remove() + + return all_preds[0], returned_outputs +# using wonder's beautiful simplification: https://stackoverflow.com/questions/31174295/getattr-and-setattr-on-nested-objects/31174427?noredirect=1#comment86638618_31174427 +def rgetattr(obj, attr, *args): + def _getattr(obj, attr): + return getattr(obj, attr, *args) + return functools.reduce(_getattr, [obj] + attr.split('.')) def inference_top_down_pose_model(model, img_or_path, person_bboxes, bbox_thr=None, format='xywh', - return_heatmap=False, - return_backbone_features=False, - dataset='TopDownCocoDataset'): + dataset='TopDownCocoDataset', + outputs=None): """Inference a single image with a list of person bounding boxes. num_people: P @@ -263,7 +293,7 @@ def inference_top_down_pose_model(model, 'xyxy' means (left, top, right, bottom), 'xywh' means (left, top, width, height). dataset (str): Dataset name, e.g. 'TopDownCocoDataset'. - return_heamap (bool) : To return heatmaps + outputs (list(str)) : To return heatmaps return_backbone_features (bool) : To return backbone features Returns: @@ -271,8 +301,7 @@ def inference_top_down_pose_model(model, Each item in the list is a dictionary, containing the bbox: (left, top, right, bottom, [score]) and the pose (ndarray[Kx3]): x, y, score - list[ndarray]: The heatmap - list[ndarray]: The backbone features + list[ndarray]: Names of layers whose output is to be returned """ # only two kinds of bbox format is supported. @@ -282,25 +311,22 @@ def inference_top_down_pose_model(model, person_bboxes = _xyxy2xywh(np.array(person_bboxes)) pose_results = [] - heatmaps=[] - backbone_features=[] + returned_outputs = [] + if len(person_bboxes) > 0: if bbox_thr is not None: person_bboxes = person_bboxes[person_bboxes[:, 4] > bbox_thr] for bbox in person_bboxes: - pose, heatmap, backbone_feat = _inference_single_pose_model( - model, img_or_path, bbox, dataset, return_heatmap, return_backbone_features) + pose, returned_features = _inference_single_pose_model(model, img_or_path, bbox, + dataset, outputs=outputs) - if return_heatmap: - heatmaps.append(heatmap) - - if backbone_features: - backbone_features.append(backbone_feat) + if outputs is not None: + returned_outputs.append(returned_features) pose_results.append({'bbox': _xywh2xyxy(np.expand_dims(np.array(bbox), 0)), 'keypoints': pose}) - return pose_results, heatmaps, backbone_features + return pose_results, returned_outputs def inference_bottom_up_pose_model(model, img_or_path): diff --git a/mmpose/models/detectors/top_down.py b/mmpose/models/detectors/top_down.py index e0a31c642b..5010b11bf4 100644 --- a/mmpose/models/detectors/top_down.py +++ b/mmpose/models/detectors/top_down.py @@ -1,5 +1,4 @@ import math - import cv2 import mmcv import numpy as np @@ -65,7 +64,6 @@ def forward(self, img_metas=None, return_loss=True, return_heatmap=False, - return_backbone_features=False, **kwargs): """Calls either forward_train or forward_test depending on whether return_loss=True. Note this setting will change the expected inputs. @@ -97,16 +95,16 @@ def forward(self, - "bbox_score": score of bbox return_loss (bool): Option to `return loss`. `return loss=True` for training, `return loss=False` for validation & test. + outputs (list(str) | tuple(str)) : layer_nae Returns: dict|tuple: if `return loss` is true, then return losses. Otherwise, return predicted poses, boxes and image paths. """ if return_loss: - return self.forward_train(img, target, target_weight, img_metas, - **kwargs) + return self.forward_train(img, target, target_weight, img_metas, **kwargs) else: - return self.forward_test(img, img_metas, return_heatmap, return_backbone_features, **kwargs) + return self.forward_test(img, img_metas, return_heatmap = return_heatmap, **kwargs) def forward_train(self, img, target, target_weight, img_metas, **kwargs): """Defines the computation performed at every call when training.""" @@ -176,24 +174,23 @@ def forward_train(self, img, target, target_weight, img_metas, **kwargs): losses['acc_pose'] = float(avg_acc) return losses - - def forward_test(self, img, img_metas, return_heatmap, return_backbone_features, **kwargs): + + def forward_test(self, img, img_metas, return_heatmap = False, **kwargs): """Defines the computation performed at every call when testing.""" assert img.size(0) == 1 assert len(img_metas) == 1 img_metas = img_metas[0] - backbone_features = None # compute backbone features output = self.backbone(img) - if return_backbone_features: - backbone_features = output.detach().cpu().numpy() - - all_preds, all_boxes, image_path, heatmap = process_head(output, img_metas, return_heatmap=return_heatmap) - return all_preds, all_boxes, image_path, heatmap, backbone_features + # process head + all_preds, all_boxes, image_path = self.process_head(output, img, img_metas, return_heatmap=return_heatmap) + + return all_preds, all_boxes, image_path - def process_head(self, output, img_metas, return_heatmap=False): + + def process_head(self, output, img, img_metas, return_heatmap=False): """Process heatmap and keypoints from backbone features.""" flip_pairs = img_metas['flip_pairs'] @@ -224,6 +221,9 @@ def process_head(self, output, img_metas, return_heatmap=False): output = (output + output_flipped) * 0.5 output_heatmap = output.detach().cpu().numpy() + if return_heatmap: + self.output_heatmap = output_heatmap + c = img_metas['center'].reshape(1, -1) s = img_metas['scale'].reshape(1, -1) @@ -251,10 +251,7 @@ def process_head(self, output, img_metas, return_heatmap=False): all_boxes[0, 5] = score image_path.extend(img_metas['image_file']) - if return_heatmap: - return all_preds, all_boxes, image_path, output_heatmap - else: - return all_preds, all_boxes, image_path, None + return all_preds, all_boxes, image_path def show_result(self, img, From 3aaf5837eb7eb595206c8915ffa9c1be0076b335 Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Fri, 23 Oct 2020 19:22:47 +0000 Subject: [PATCH 03/24] Fixed docstring --- mmpose/apis/inference.py | 6 ++---- mmpose/models/detectors/top_down.py | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/mmpose/apis/inference.py b/mmpose/apis/inference.py index 5a6db96d52..67c546912d 100644 --- a/mmpose/apis/inference.py +++ b/mmpose/apis/inference.py @@ -145,12 +145,10 @@ def _inference_single_pose_model(model, img_or_path, bbox, dataset, outputs=None shaped (4, ) or (5, ). (left, top, width, height, [score]) dataset (str): Dataset name. outputs (list(str) : List of layer names whose output is to be returned - return_backbone_features (bool) : To return backbone features - + Returns: ndarray[Kx3]: Predicted pose x, y, score. - ndarray[NxKxHxW]: Model output heatmap. - ndarray[NxKxHxW]: Model backbone features. + dict: Output feature maps of layer names specified in `outputs` """ cfg = model.cfg device = next(model.parameters()).device diff --git a/mmpose/models/detectors/top_down.py b/mmpose/models/detectors/top_down.py index 5010b11bf4..56475d5204 100644 --- a/mmpose/models/detectors/top_down.py +++ b/mmpose/models/detectors/top_down.py @@ -95,7 +95,7 @@ def forward(self, - "bbox_score": score of bbox return_loss (bool): Option to `return loss`. `return loss=True` for training, `return loss=False` for validation & test. - outputs (list(str) | tuple(str)) : layer_nae + return_heatmap (bool) : Option to return heatmap. Returns: dict|tuple: if `return loss` is true, then return losses. From 346b81c728ee03a64684be1e5edceece1aab45f4 Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Fri, 23 Oct 2020 19:36:00 +0000 Subject: [PATCH 04/24] return heatmap condition fix --- mmpose/apis/inference.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmpose/apis/inference.py b/mmpose/apis/inference.py index 67c546912d..ddf18589f3 100644 --- a/mmpose/apis/inference.py +++ b/mmpose/apis/inference.py @@ -244,7 +244,7 @@ def hook(model, input, output): continue handles.append(h) - if 'heatmap' or 'heatmaps' in outputs: + if any(x in outputs for x in ('heatmap', 'heatmaps')): return_heatmap = True all_preds, _, _ = model(return_loss=False, From 8c3c6c03c51987480ea50dac1f8d079f86bc5cfc Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Fri, 23 Oct 2020 20:07:31 +0000 Subject: [PATCH 05/24] Docstring fixes --- mmpose/apis/inference.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmpose/apis/inference.py b/mmpose/apis/inference.py index ddf18589f3..02ce5dd4ea 100644 --- a/mmpose/apis/inference.py +++ b/mmpose/apis/inference.py @@ -144,7 +144,7 @@ def _inference_single_pose_model(model, img_or_path, bbox, dataset, outputs=None bbox (list | np.ndarray): Bounding boxes (with scores), shaped (4, ) or (5, ). (left, top, width, height, [score]) dataset (str): Dataset name. - outputs (list(str) : List of layer names whose output is to be returned + outputs (list[str]): Names of layers whose output is to be returned Returns: ndarray[Kx3]: Predicted pose x, y, score. @@ -299,7 +299,7 @@ def inference_top_down_pose_model(model, Each item in the list is a dictionary, containing the bbox: (left, top, right, bottom, [score]) and the pose (ndarray[Kx3]): x, y, score - list[ndarray]: Names of layers whose output is to be returned + list[str]: Names of layers whose output is to be returned """ # only two kinds of bbox format is supported. From 972bc41b90cbb1b66d1923226998c9bc57254000 Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Fri, 23 Oct 2020 20:12:49 +0000 Subject: [PATCH 06/24] Docstring fixes --- mmpose/apis/inference.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmpose/apis/inference.py b/mmpose/apis/inference.py index 02ce5dd4ea..9bdfa6c618 100644 --- a/mmpose/apis/inference.py +++ b/mmpose/apis/inference.py @@ -299,7 +299,7 @@ def inference_top_down_pose_model(model, Each item in the list is a dictionary, containing the bbox: (left, top, right, bottom, [score]) and the pose (ndarray[Kx3]): x, y, score - list[str]: Names of layers whose output is to be returned + list[dict]: Returned output feature maps from layers specified in `outputs` """ # only two kinds of bbox format is supported. From 7166d64c37ad3165015ec258b375c058db01fcf0 Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Fri, 23 Oct 2020 20:36:37 +0000 Subject: [PATCH 07/24] Docstring fixes --- mmpose/apis/inference.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mmpose/apis/inference.py b/mmpose/apis/inference.py index 9bdfa6c618..1aa869e0ab 100644 --- a/mmpose/apis/inference.py +++ b/mmpose/apis/inference.py @@ -291,8 +291,7 @@ def inference_top_down_pose_model(model, 'xyxy' means (left, top, right, bottom), 'xywh' means (left, top, width, height). dataset (str): Dataset name, e.g. 'TopDownCocoDataset'. - outputs (list(str)) : To return heatmaps - return_backbone_features (bool) : To return backbone features + outputs (list(str) | tuple(str)) : Names of layers whose outputs need to be returned Returns: list[dict]: The bbox & pose info, From 6cca49b9cf4cade203e5eddf3f7586979e8aa414 Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Fri, 23 Oct 2020 22:02:13 +0000 Subject: [PATCH 08/24] 'image' call fix --- demo/top_down_img_demo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/top_down_img_demo.py b/demo/top_down_img_demo.py index 1a88e3100e..8f0df6e237 100644 --- a/demo/top_down_img_demo.py +++ b/demo/top_down_img_demo.py @@ -71,7 +71,7 @@ def main(): # test a single image, with a list of bboxes pose_results, returned_outputs = inference_top_down_pose_model( pose_model, - img, + image, person_bboxes, bbox_thr=args.bbox_thr, format='xyxy', From e7b09dbdd54a93f8acff2f668edc01647fb6fe4b Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Sat, 24 Oct 2020 17:50:55 +0000 Subject: [PATCH 09/24] Fixed linting errors --- demo/top_down_img_demo.py | 8 +-- demo/top_down_img_demo_with_mmdet.py | 4 +- demo/top_down_video_demo_with_mmdet.py | 6 +-- mmpose/apis/inference.py | 72 +++++++++++++++++--------- mmpose/models/detectors/top_down.py | 29 ++++++----- 5 files changed, 72 insertions(+), 47 deletions(-) diff --git a/demo/top_down_img_demo.py b/demo/top_down_img_demo.py index 8f0df6e237..e371e0fdd3 100644 --- a/demo/top_down_img_demo.py +++ b/demo/top_down_img_demo.py @@ -49,9 +49,9 @@ def main(): dataset = pose_model.cfg.data['test']['type'] img_keys = list(coco.imgs.keys()) - - output_layer_names = ('heatmap') #None - + + output_layer_names = ('heatmap') # default : None + # process each image for i in range(len(img_keys)): # get bounding box annotations @@ -77,7 +77,7 @@ def main(): format='xyxy', dataset=dataset, outputs=output_layer_names) - + if args.out_img_root == '': out_file = None else: diff --git a/demo/top_down_img_demo_with_mmdet.py b/demo/top_down_img_demo_with_mmdet.py index b325f8ba83..39bde06fd0 100644 --- a/demo/top_down_img_demo_with_mmdet.py +++ b/demo/top_down_img_demo_with_mmdet.py @@ -64,8 +64,8 @@ def main(): person_bboxes = det_results[0].copy() # test a single image, with a list of bboxes. - - output_layer_names = ('heatmap') #None + + output_layer_names = ('heatmap') # default : None pose_results, heatmaps, backbone_features = inference_top_down_pose_model( pose_model, image_name, diff --git a/demo/top_down_video_demo_with_mmdet.py b/demo/top_down_video_demo_with_mmdet.py index 2b9e37f131..e6d99ea007 100644 --- a/demo/top_down_video_demo_with_mmdet.py +++ b/demo/top_down_video_demo_with_mmdet.py @@ -54,7 +54,7 @@ def main(): dataset = pose_model.cfg.data['test']['type'] cap = cv2.VideoCapture(args.video_path) - + if args.out_video_root == '': save_out_video = False else: @@ -71,8 +71,8 @@ def main(): f'vis_{os.path.basename(args.video_path)}'), fourcc, fps, size) - output_layer_names = ('heatmap') #None - + output_layer_names = ('heatmap') # default : None + while (cap.isOpened()): flag, img = cap.read() if not flag: diff --git a/mmpose/apis/inference.py b/mmpose/apis/inference.py index 1aa869e0ab..cf61d3577e 100644 --- a/mmpose/apis/inference.py +++ b/mmpose/apis/inference.py @@ -1,5 +1,5 @@ -import os import functools +import os from collections import OrderedDict import mmcv @@ -133,7 +133,12 @@ def __call__(self, results): results['img'] = img return results -def _inference_single_pose_model(model, img_or_path, bbox, dataset, outputs=None): + +def _inference_single_pose_model(model, + img_or_path, + bbox, + dataset, + outputs=None): """Inference a single bbox. num_keypoints: K @@ -145,7 +150,7 @@ def _inference_single_pose_model(model, img_or_path, bbox, dataset, outputs=None shaped (4, ) or (5, ). (left, top, width, height, [score]) dataset (str): Dataset name. outputs (list[str]): Names of layers whose output is to be returned - + Returns: ndarray[Kx3]: Predicted pose x, y, score. dict: Output feature maps of layer names specified in `outputs` @@ -229,43 +234,55 @@ def _inference_single_pose_model(model, img_or_path, bbox, dataset, outputs=None returned_outputs = OrderedDict() return_heatmap = False handles = [] + def hook_wrapper(name): + def hook(model, input, output): returned_outputs[name] = output.detach().cpu().numpy() + return hook if isinstance(outputs, (list, tuple)): for name in outputs: + layer = rgetattr(model, name) try: - layer = rgetattr(model, name) h = layer.register_forward_hook(hook_wrapper(name)) - except Exception as e: - #raise AttributeError(f'Module {name} not found') - continue + except AttributeError: + if name in ('heatmap', 'heatmaps'): + continue + else: + raise AttributeError(f'Module {name} not found') handles.append(h) if any(x in outputs for x in ('heatmap', 'heatmaps')): return_heatmap = True - - all_preds, _, _ = model(return_loss=False, - return_heatmap=return_heatmap, - img=data['img'], img_metas=data['img_metas']) + + all_preds, _, _ = model( + return_loss=False, + return_heatmap=return_heatmap, + img=data['img'], + img_metas=data['img_metas']) if return_heatmap: returned_outputs['heatmap'] = model.output_heatmap - #clear handles (if any) + # clear handles (if any) for h in handles: h.remove() - + return all_preds[0], returned_outputs -# using wonder's beautiful simplification: https://stackoverflow.com/questions/31174295/getattr-and-setattr-on-nested-objects/31174427?noredirect=1#comment86638618_31174427 + +# using wonder's beautiful simplification: +# https://stackoverflow.com/questions/31174295/getattr-and-setattr-on-nested-objects def rgetattr(obj, attr, *args): + def _getattr(obj, attr): return getattr(obj, attr, *args) + return functools.reduce(_getattr, [obj] + attr.split('.')) + def inference_top_down_pose_model(model, img_or_path, person_bboxes, @@ -291,22 +308,23 @@ def inference_top_down_pose_model(model, 'xyxy' means (left, top, right, bottom), 'xywh' means (left, top, width, height). dataset (str): Dataset name, e.g. 'TopDownCocoDataset'. - outputs (list(str) | tuple(str)) : Names of layers whose outputs need to be returned + outputs (list(str) | tuple(str)) : Names of layers whose outputs + need to be returned. Returns: list[dict]: The bbox & pose info, Each item in the list is a dictionary, containing the bbox: (left, top, right, bottom, [score]) and the pose (ndarray[Kx3]): x, y, score - list[dict]: Returned output feature maps from layers specified in `outputs` - + list[dict]: Returned output feature maps from layers + specified in `outputs`. """ # only two kinds of bbox format is supported. assert format in ['xyxy', 'xywh'] # transform the bboxes format to xywh if format == 'xyxy': person_bboxes = _xyxy2xywh(np.array(person_bboxes)) - + pose_results = [] returned_outputs = [] @@ -314,15 +332,19 @@ def inference_top_down_pose_model(model, if bbox_thr is not None: person_bboxes = person_bboxes[person_bboxes[:, 4] > bbox_thr] for bbox in person_bboxes: - pose, returned_features = _inference_single_pose_model(model, img_or_path, bbox, - dataset, outputs=outputs) - + pose, returned_features = _inference_single_pose_model( + model, img_or_path, bbox, dataset, outputs=outputs) + if outputs is not None: returned_outputs.append(returned_features) - - pose_results.append({'bbox': _xywh2xyxy(np.expand_dims(np.array(bbox), 0)), - 'keypoints': pose}) - + + pose_results.append({ + 'bbox': + _xywh2xyxy(np.expand_dims(np.array(bbox), 0)), + 'keypoints': + pose + }) + return pose_results, returned_outputs diff --git a/mmpose/models/detectors/top_down.py b/mmpose/models/detectors/top_down.py index 56475d5204..b50ec2ddb5 100644 --- a/mmpose/models/detectors/top_down.py +++ b/mmpose/models/detectors/top_down.py @@ -1,4 +1,5 @@ import math + import cv2 import mmcv import numpy as np @@ -102,9 +103,11 @@ def forward(self, Otherwise, return predicted poses, boxes and image paths. """ if return_loss: - return self.forward_train(img, target, target_weight, img_metas, **kwargs) + return self.forward_train(img, target, target_weight, img_metas, + **kwargs) else: - return self.forward_test(img, img_metas, return_heatmap = return_heatmap, **kwargs) + return self.forward_test( + img, img_metas, return_heatmap=return_heatmap, **kwargs) def forward_train(self, img, target, target_weight, img_metas, **kwargs): """Defines the computation performed at every call when training.""" @@ -174,26 +177,26 @@ def forward_train(self, img, target, target_weight, img_metas, **kwargs): losses['acc_pose'] = float(avg_acc) return losses - - def forward_test(self, img, img_metas, return_heatmap = False, **kwargs): + + def forward_test(self, img, img_metas, return_heatmap=False, **kwargs): """Defines the computation performed at every call when testing.""" assert img.size(0) == 1 assert len(img_metas) == 1 img_metas = img_metas[0] - + # compute backbone features output = self.backbone(img) - + # process head - all_preds, all_boxes, image_path = self.process_head(output, img, img_metas, return_heatmap=return_heatmap) - + all_preds, all_boxes, image_path = self.process_head( + output, img, img_metas, return_heatmap=return_heatmap) + return all_preds, all_boxes, image_path - def process_head(self, output, img, img_metas, return_heatmap=False): """Process heatmap and keypoints from backbone features.""" flip_pairs = img_metas['flip_pairs'] - + if self.with_keypoint: output = self.keypoint_head(output) @@ -223,7 +226,7 @@ def process_head(self, output, img, img_metas, return_heatmap=False): output_heatmap = output.detach().cpu().numpy() if return_heatmap: self.output_heatmap = output_heatmap - + c = img_metas['center'].reshape(1, -1) s = img_metas['scale'].reshape(1, -1) @@ -250,9 +253,9 @@ def process_head(self, output, img, img_metas, return_heatmap=False): all_boxes[0, 4] = np.prod(s * 200.0, axis=1) all_boxes[0, 5] = score image_path.extend(img_metas['image_file']) - + return all_preds, all_boxes, image_path - + def show_result(self, img, result, From c5d1452726e67e0a31b0057f2f261192bf5b73b2 Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Sun, 25 Oct 2020 14:29:21 +0000 Subject: [PATCH 10/24] fixed top down demo --- demo/top_down_img_demo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/top_down_img_demo.py b/demo/top_down_img_demo.py index e371e0fdd3..8fc7983324 100644 --- a/demo/top_down_img_demo.py +++ b/demo/top_down_img_demo.py @@ -71,10 +71,10 @@ def main(): # test a single image, with a list of bboxes pose_results, returned_outputs = inference_top_down_pose_model( pose_model, - image, + image_name, person_bboxes, bbox_thr=args.bbox_thr, - format='xyxy', + format='xywh', dataset=dataset, outputs=output_layer_names) From 382ecf0d49d64cd0a14ec106ceca0c73143c7fff Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Sun, 25 Oct 2020 14:45:02 +0000 Subject: [PATCH 11/24] fixed evaluate func --- mmpose/datasets/datasets/top_down/topdown_coco_dataset.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mmpose/datasets/datasets/top_down/topdown_coco_dataset.py b/mmpose/datasets/datasets/top_down/topdown_coco_dataset.py index e8c8100c01..8a5ef7db5b 100644 --- a/mmpose/datasets/datasets/top_down/topdown_coco_dataset.py +++ b/mmpose/datasets/datasets/top_down/topdown_coco_dataset.py @@ -294,7 +294,7 @@ def evaluate(self, outputs, res_folder, metric='mAP', **kwargs): heatmap width: W Args: - outputs (list(preds, boxes, image_path, output_heatmap)) + outputs (list(preds, boxes, image_path)) :preds (np.ndarray[1,K,3]): The first two dimensions are coordinates, score is the third dimension of the array. :boxes (np.ndarray[1,6]): [center[0], center[1], scale[0] @@ -302,8 +302,6 @@ def evaluate(self, outputs, res_folder, metric='mAP', **kwargs): :image_path (list[str]): For example, [ '/', 'v','a', 'l', '2', '0', '1', '7', '/', '0', '0', '0', '0', '0', '0', '3', '9', '7', '1', '3', '3', '.', 'j', 'p', 'g'] - :output_heatmap (np.ndarray[N, K, H, W]): model outpus. - res_folder (str): Path of directory to save the results. metric (str | list[str]): Metric to be performed. Defaults: 'mAP'. @@ -319,7 +317,7 @@ def evaluate(self, outputs, res_folder, metric='mAP', **kwargs): res_file = os.path.join(res_folder, 'result_keypoints.json') kpts = defaultdict(list) - for preds, boxes, image_path, _ in outputs: + for preds, boxes, image_path in outputs: str_image_path = ''.join(image_path) image_id = self.name2id[os.path.basename(str_image_path)] From 94c679816addb317193fdcb4c9d4c30d0ef31f20 Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Sun, 25 Oct 2020 15:05:05 +0000 Subject: [PATCH 12/24] Fixed evaluate func --- .../datasets/datasets/top_down/topdown_freihand_dataset.py | 2 +- mmpose/datasets/datasets/top_down/topdown_mpii_dataset.py | 5 ++--- .../datasets/datasets/top_down/topdown_mpii_trb_dataset.py | 6 ++---- .../datasets/top_down/topdown_onehand10k_dataset.py | 2 +- .../datasets/datasets/top_down/topdown_panoptic_dataset.py | 2 +- 5 files changed, 7 insertions(+), 10 deletions(-) diff --git a/mmpose/datasets/datasets/top_down/topdown_freihand_dataset.py b/mmpose/datasets/datasets/top_down/topdown_freihand_dataset.py index 1a2461bf11..217d346587 100644 --- a/mmpose/datasets/datasets/top_down/topdown_freihand_dataset.py +++ b/mmpose/datasets/datasets/top_down/topdown_freihand_dataset.py @@ -177,7 +177,7 @@ def evaluate(self, outputs, res_folder, metric='PCK', **kwargs): kpts = [] - for preds, boxes, image_path, _ in outputs: + for preds, boxes, image_path in outputs: str_image_path = ''.join(image_path) image_id = int(osp.basename(osp.splitext(str_image_path)[0])) diff --git a/mmpose/datasets/datasets/top_down/topdown_mpii_dataset.py b/mmpose/datasets/datasets/top_down/topdown_mpii_dataset.py index efbc2bf443..32ac0cefc6 100644 --- a/mmpose/datasets/datasets/top_down/topdown_mpii_dataset.py +++ b/mmpose/datasets/datasets/top_down/topdown_mpii_dataset.py @@ -126,7 +126,7 @@ def evaluate(self, outputs, res_folder, metric='PCKh', **kwargs): heatmap width: W Args: - outputs(list(preds, boxes, image_path, output_heatmap)): + outputs(list(preds, boxes, image_path)): * preds(np.ndarray[1,K,3]): The first two dimensions are coordinates, score is the third dimension of the array. @@ -134,7 +134,6 @@ def evaluate(self, outputs, res_folder, metric='PCKh', **kwargs): , scale[1],area, score] * image_path(list[str]): For example, ['0', '0', '0', '0', '0', '1', '1', '6', '3', '.', 'j', 'p', 'g'] - * output_heatmap (np.ndarray[N, K, H, W]): model outputs. res_folder(str): Path of directory to save the results. metric (str | list[str]): Metrics to be performed. @@ -150,7 +149,7 @@ def evaluate(self, outputs, res_folder, metric='PCKh', **kwargs): if metric not in allowed_metrics: raise KeyError(f'metric {metric} is not supported') - preds = np.stack([kpts[0] for kpts, _, _, _ in outputs]) + preds = np.stack([kpts[0] for kpts, _, _, in outputs]) # convert 0-based index to 1-based index, # and get the first two dimensions. diff --git a/mmpose/datasets/datasets/top_down/topdown_mpii_trb_dataset.py b/mmpose/datasets/datasets/top_down/topdown_mpii_trb_dataset.py index 924b4d0570..daad8d09d9 100644 --- a/mmpose/datasets/datasets/top_down/topdown_mpii_trb_dataset.py +++ b/mmpose/datasets/datasets/top_down/topdown_mpii_trb_dataset.py @@ -149,7 +149,7 @@ def evaluate(self, outputs, res_folder, metric='PCKh', **kwargs): heatmap width: W Args: - outputs(list(preds, boxes, image_path, output_heatmap)): + outputs(list(preds, boxes, image_path)): * preds(np.ndarray[1,K,3]): The first two dimensions are coordinates, score is the third dimension of the array. @@ -157,8 +157,6 @@ def evaluate(self, outputs, res_folder, metric='PCKh', **kwargs): , scale[1],area, score] * image_path(list[str]): For example, ['0', '0', '0', '0', '0', '1', '1', '6', '3', '.', 'j', 'p', 'g'] - * output_heatmap (np.ndarray[N, K, H, W]): model outputs. - res_folder(str): Path of directory to save the results. metric (str | list[str]): Metrics to be performed. Defaults: 'PCKh'. @@ -176,7 +174,7 @@ def evaluate(self, outputs, res_folder, metric='PCKh', **kwargs): kpts = [] - for preds, boxes, image_path, _ in outputs: + for preds, boxes, image_path in outputs: str_image_path = ''.join(image_path) image_id = int(osp.basename(osp.splitext(str_image_path)[0])) diff --git a/mmpose/datasets/datasets/top_down/topdown_onehand10k_dataset.py b/mmpose/datasets/datasets/top_down/topdown_onehand10k_dataset.py index 991b880624..86902fe3da 100644 --- a/mmpose/datasets/datasets/top_down/topdown_onehand10k_dataset.py +++ b/mmpose/datasets/datasets/top_down/topdown_onehand10k_dataset.py @@ -177,7 +177,7 @@ def evaluate(self, outputs, res_folder, metric='PCK', **kwargs): kpts = [] - for preds, boxes, image_path, _ in outputs: + for preds, boxes, image_path in outputs: str_image_path = ''.join(image_path) image_id = int(osp.basename(osp.splitext(str_image_path)[0])) diff --git a/mmpose/datasets/datasets/top_down/topdown_panoptic_dataset.py b/mmpose/datasets/datasets/top_down/topdown_panoptic_dataset.py index bceaf63cc2..a4c8df0eae 100644 --- a/mmpose/datasets/datasets/top_down/topdown_panoptic_dataset.py +++ b/mmpose/datasets/datasets/top_down/topdown_panoptic_dataset.py @@ -190,7 +190,7 @@ def evaluate(self, outputs, res_folder, metric='PCKh', **kwargs): kpts = [] - for preds, boxes, image_path, _ in outputs: + for preds, boxes, image_path in outputs: str_image_path = ''.join(image_path) image_id = self.name2id[str_image_path[len(self.img_prefix):]] From c66222c64868a4a2a03d84cf9c84c3e5ecd8f03f Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Mon, 26 Oct 2020 14:43:51 +0000 Subject: [PATCH 13/24] Fixed json loader in tests --- demo/top_down_img_demo.py | 2 +- demo/top_down_img_demo_with_mmdet.py | 2 +- demo/top_down_video_demo_with_mmdet.py | 2 +- tests/data/smpl/test_joint_regressor.npy | Bin 0 -> 1323008 bytes tests/test_datasets/test_top_down_dataset.py | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 tests/data/smpl/test_joint_regressor.npy diff --git a/demo/top_down_img_demo.py b/demo/top_down_img_demo.py index 8fc7983324..5edf2f7cf0 100644 --- a/demo/top_down_img_demo.py +++ b/demo/top_down_img_demo.py @@ -50,7 +50,7 @@ def main(): img_keys = list(coco.imgs.keys()) - output_layer_names = ('heatmap') # default : None + output_layer_names = ('heatmap', ) # default : None # process each image for i in range(len(img_keys)): diff --git a/demo/top_down_img_demo_with_mmdet.py b/demo/top_down_img_demo_with_mmdet.py index 39bde06fd0..dee96eb40e 100644 --- a/demo/top_down_img_demo_with_mmdet.py +++ b/demo/top_down_img_demo_with_mmdet.py @@ -65,7 +65,7 @@ def main(): # test a single image, with a list of bboxes. - output_layer_names = ('heatmap') # default : None + output_layer_names = ('heatmap', ) # default : None pose_results, heatmaps, backbone_features = inference_top_down_pose_model( pose_model, image_name, diff --git a/demo/top_down_video_demo_with_mmdet.py b/demo/top_down_video_demo_with_mmdet.py index e6d99ea007..747b8e474c 100644 --- a/demo/top_down_video_demo_with_mmdet.py +++ b/demo/top_down_video_demo_with_mmdet.py @@ -71,7 +71,7 @@ def main(): f'vis_{os.path.basename(args.video_path)}'), fourcc, fps, size) - output_layer_names = ('heatmap') # default : None + output_layer_names = ('heatmap', ) # default : None while (cap.isOpened()): flag, img = cap.read() diff --git a/tests/data/smpl/test_joint_regressor.npy b/tests/data/smpl/test_joint_regressor.npy new file mode 100644 index 0000000000000000000000000000000000000000..2a247b4f8362f8ca544d5fce929b2d102c87287e GIT binary patch literal 1323008 zcmeIuu@1pd0EOXNJ;mKFNe2;;60?n13?^x`jX_jy#Uh@<3#(T!n7)5IXZ+sV{bqL< zWRL6_tGYX-xD0XC6fqC6Y12KG*JGQi`unfTOIP=QcP?*rzem$q9_GbjGS0&*{M0ZL z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5Fqe(fe+;{ B8^{0v literal 0 HcmV?d00001 diff --git a/tests/test_datasets/test_top_down_dataset.py b/tests/test_datasets/test_top_down_dataset.py index dab3fffba7..0b78fd8bb5 100644 --- a/tests/test_datasets/test_top_down_dataset.py +++ b/tests/test_datasets/test_top_down_dataset.py @@ -21,7 +21,7 @@ def load_json_to_output(json_name, prefix=''): box = np.array([0, 0, 0, 0, 0, 0], dtype=np.float32).reshape(1, -1) img_path = [] img_path[:0] = os.path.join(prefix, image_info['file_name']) - output = (keypoints, box, img_path, None) + output = (keypoints, box, img_path) outputs.append(output) return outputs From ad1209a890bec13a18a476c9ffb7d312231329c0 Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Mon, 26 Oct 2020 17:03:48 +0000 Subject: [PATCH 14/24] Cleanup --- mmpose/apis/inference.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mmpose/apis/inference.py b/mmpose/apis/inference.py index cf61d3577e..b70d89844d 100644 --- a/mmpose/apis/inference.py +++ b/mmpose/apis/inference.py @@ -249,14 +249,11 @@ def hook(model, input, output): h = layer.register_forward_hook(hook_wrapper(name)) except AttributeError: if name in ('heatmap', 'heatmaps'): - continue + return_heatmap = True else: raise AttributeError(f'Module {name} not found') handles.append(h) - if any(x in outputs for x in ('heatmap', 'heatmaps')): - return_heatmap = True - all_preds, _, _ = model( return_loss=False, return_heatmap=return_heatmap, From b9ca48310b1b8f80c26df929c892eb894c281259 Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Mon, 26 Oct 2020 17:28:44 +0000 Subject: [PATCH 15/24] try catch fix --- mmpose/apis/inference.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmpose/apis/inference.py b/mmpose/apis/inference.py index b70d89844d..cd8662f2c9 100644 --- a/mmpose/apis/inference.py +++ b/mmpose/apis/inference.py @@ -244,8 +244,8 @@ def hook(model, input, output): if isinstance(outputs, (list, tuple)): for name in outputs: - layer = rgetattr(model, name) try: + layer = rgetattr(model, name) h = layer.register_forward_hook(hook_wrapper(name)) except AttributeError: if name in ('heatmap', 'heatmaps'): From 502754d26051c966d551c6d20c15ed715efc42f2 Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Mon, 26 Oct 2020 17:30:04 +0000 Subject: [PATCH 16/24] try catch fix --- mmpose/apis/inference.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmpose/apis/inference.py b/mmpose/apis/inference.py index cd8662f2c9..d09b9c103d 100644 --- a/mmpose/apis/inference.py +++ b/mmpose/apis/inference.py @@ -250,10 +250,10 @@ def hook(model, input, output): except AttributeError: if name in ('heatmap', 'heatmaps'): return_heatmap = True + continue else: raise AttributeError(f'Module {name} not found') handles.append(h) - all_preds, _, _ = model( return_loss=False, return_heatmap=return_heatmap, From c0933d6d5f5663e342d338af3304cdf7da119e7a Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Fri, 30 Oct 2020 14:54:13 +0000 Subject: [PATCH 17/24] Fixed model forward_test return signature to return heatmap --- demo/top_down_img_demo_with_mmdet.py | 2 +- mmpose/apis/inference.py | 20 +++++++++---------- .../datasets/top_down/topdown_coco_dataset.py | 5 +++-- .../top_down/topdown_freihand_dataset.py | 2 +- .../datasets/top_down/topdown_mpii_dataset.py | 5 +++-- .../top_down/topdown_mpii_trb_dataset.py | 5 +++-- .../top_down/topdown_onehand10k_dataset.py | 2 +- .../top_down/topdown_panoptic_dataset.py | 2 +- mmpose/models/detectors/top_down.py | 15 +++++++------- tests/test_datasets/test_top_down_dataset.py | 2 +- 10 files changed, 32 insertions(+), 28 deletions(-) diff --git a/demo/top_down_img_demo_with_mmdet.py b/demo/top_down_img_demo_with_mmdet.py index dee96eb40e..5deeb6ccd5 100644 --- a/demo/top_down_img_demo_with_mmdet.py +++ b/demo/top_down_img_demo_with_mmdet.py @@ -66,7 +66,7 @@ def main(): # test a single image, with a list of bboxes. output_layer_names = ('heatmap', ) # default : None - pose_results, heatmaps, backbone_features = inference_top_down_pose_model( + pose_results, returned_outputs = inference_top_down_pose_model( pose_model, image_name, person_bboxes, diff --git a/mmpose/apis/inference.py b/mmpose/apis/inference.py index d09b9c103d..aef79aa1c5 100644 --- a/mmpose/apis/inference.py +++ b/mmpose/apis/inference.py @@ -149,11 +149,12 @@ def _inference_single_pose_model(model, bbox (list | np.ndarray): Bounding boxes (with scores), shaped (4, ) or (5, ). (left, top, width, height, [score]) dataset (str): Dataset name. - outputs (list[str]): Names of layers whose output is to be returned + outputs (list[str] | tuple[str]): Names of layers whose output is + to be returned, default: None Returns: ndarray[Kx3]: Predicted pose x, y, score. - dict: Output feature maps of layer names specified in `outputs` + dict: Output feature maps of layers specified in `outputs`. """ cfg = model.cfg device = next(model.parameters()).device @@ -254,15 +255,14 @@ def hook(model, input, output): else: raise AttributeError(f'Module {name} not found') handles.append(h) - all_preds, _, _ = model( + all_preds, _, _, heatmap = model( return_loss=False, return_heatmap=return_heatmap, img=data['img'], img_metas=data['img_metas']) - if return_heatmap: - returned_outputs['heatmap'] = model.output_heatmap - + if heatmap: + returned_outputs['heatmap'] = heatmap # clear handles (if any) for h in handles: h.remove() @@ -306,14 +306,14 @@ def inference_top_down_pose_model(model, 'xywh' means (left, top, width, height). dataset (str): Dataset name, e.g. 'TopDownCocoDataset'. outputs (list(str) | tuple(str)) : Names of layers whose outputs - need to be returned. + need to be returned, default: None Returns: list[dict]: The bbox & pose info, Each item in the list is a dictionary, containing the bbox: (left, top, right, bottom, [score]) and the pose (ndarray[Kx3]): x, y, score - list[dict]: Returned output feature maps from layers + list[dict[np.ndarray[N, K, H, W]]]: Output feature maps from layers specified in `outputs`. """ # only two kinds of bbox format is supported. @@ -329,11 +329,11 @@ def inference_top_down_pose_model(model, if bbox_thr is not None: person_bboxes = person_bboxes[person_bboxes[:, 4] > bbox_thr] for bbox in person_bboxes: - pose, returned_features = _inference_single_pose_model( + pose, outputs_returned = _inference_single_pose_model( model, img_or_path, bbox, dataset, outputs=outputs) if outputs is not None: - returned_outputs.append(returned_features) + returned_outputs.append(outputs_returned) pose_results.append({ 'bbox': diff --git a/mmpose/datasets/datasets/top_down/topdown_coco_dataset.py b/mmpose/datasets/datasets/top_down/topdown_coco_dataset.py index 8a5ef7db5b..76df456a41 100644 --- a/mmpose/datasets/datasets/top_down/topdown_coco_dataset.py +++ b/mmpose/datasets/datasets/top_down/topdown_coco_dataset.py @@ -294,7 +294,7 @@ def evaluate(self, outputs, res_folder, metric='mAP', **kwargs): heatmap width: W Args: - outputs (list(preds, boxes, image_path)) + outputs (list(preds, boxes, image_path, heatmap)) :preds (np.ndarray[1,K,3]): The first two dimensions are coordinates, score is the third dimension of the array. :boxes (np.ndarray[1,6]): [center[0], center[1], scale[0] @@ -302,6 +302,7 @@ def evaluate(self, outputs, res_folder, metric='mAP', **kwargs): :image_path (list[str]): For example, [ '/', 'v','a', 'l', '2', '0', '1', '7', '/', '0', '0', '0', '0', '0', '0', '3', '9', '7', '1', '3', '3', '.', 'j', 'p', 'g'] + :heatmap (np.ndarray[N, K, H, W]): model output heatmap. res_folder (str): Path of directory to save the results. metric (str | list[str]): Metric to be performed. Defaults: 'mAP'. @@ -317,7 +318,7 @@ def evaluate(self, outputs, res_folder, metric='mAP', **kwargs): res_file = os.path.join(res_folder, 'result_keypoints.json') kpts = defaultdict(list) - for preds, boxes, image_path in outputs: + for preds, boxes, image_path, _ in outputs: str_image_path = ''.join(image_path) image_id = self.name2id[os.path.basename(str_image_path)] diff --git a/mmpose/datasets/datasets/top_down/topdown_freihand_dataset.py b/mmpose/datasets/datasets/top_down/topdown_freihand_dataset.py index 217d346587..1a2461bf11 100644 --- a/mmpose/datasets/datasets/top_down/topdown_freihand_dataset.py +++ b/mmpose/datasets/datasets/top_down/topdown_freihand_dataset.py @@ -177,7 +177,7 @@ def evaluate(self, outputs, res_folder, metric='PCK', **kwargs): kpts = [] - for preds, boxes, image_path in outputs: + for preds, boxes, image_path, _ in outputs: str_image_path = ''.join(image_path) image_id = int(osp.basename(osp.splitext(str_image_path)[0])) diff --git a/mmpose/datasets/datasets/top_down/topdown_mpii_dataset.py b/mmpose/datasets/datasets/top_down/topdown_mpii_dataset.py index 32ac0cefc6..907e6c3101 100644 --- a/mmpose/datasets/datasets/top_down/topdown_mpii_dataset.py +++ b/mmpose/datasets/datasets/top_down/topdown_mpii_dataset.py @@ -126,7 +126,7 @@ def evaluate(self, outputs, res_folder, metric='PCKh', **kwargs): heatmap width: W Args: - outputs(list(preds, boxes, image_path)): + outputs(list(preds, boxes, image_path, heatmap)): * preds(np.ndarray[1,K,3]): The first two dimensions are coordinates, score is the third dimension of the array. @@ -134,6 +134,7 @@ def evaluate(self, outputs, res_folder, metric='PCKh', **kwargs): , scale[1],area, score] * image_path(list[str]): For example, ['0', '0', '0', '0', '0', '1', '1', '6', '3', '.', 'j', 'p', 'g'] + * heatmap (np.ndarray[N, K, H, W]): model output heatmap. res_folder(str): Path of directory to save the results. metric (str | list[str]): Metrics to be performed. @@ -149,7 +150,7 @@ def evaluate(self, outputs, res_folder, metric='PCKh', **kwargs): if metric not in allowed_metrics: raise KeyError(f'metric {metric} is not supported') - preds = np.stack([kpts[0] for kpts, _, _, in outputs]) + preds = np.stack([kpts[0] for kpts, _, _, _ in outputs]) # convert 0-based index to 1-based index, # and get the first two dimensions. diff --git a/mmpose/datasets/datasets/top_down/topdown_mpii_trb_dataset.py b/mmpose/datasets/datasets/top_down/topdown_mpii_trb_dataset.py index daad8d09d9..e4e0bb3c32 100644 --- a/mmpose/datasets/datasets/top_down/topdown_mpii_trb_dataset.py +++ b/mmpose/datasets/datasets/top_down/topdown_mpii_trb_dataset.py @@ -149,7 +149,7 @@ def evaluate(self, outputs, res_folder, metric='PCKh', **kwargs): heatmap width: W Args: - outputs(list(preds, boxes, image_path)): + outputs(list(preds, boxes, image_path, heatmap)): * preds(np.ndarray[1,K,3]): The first two dimensions are coordinates, score is the third dimension of the array. @@ -157,6 +157,7 @@ def evaluate(self, outputs, res_folder, metric='PCKh', **kwargs): , scale[1],area, score] * image_path(list[str]): For example, ['0', '0', '0', '0', '0', '1', '1', '6', '3', '.', 'j', 'p', 'g'] + * heatmap (np.ndarray[N, K, H, W]): model output heatmap. res_folder(str): Path of directory to save the results. metric (str | list[str]): Metrics to be performed. Defaults: 'PCKh'. @@ -174,7 +175,7 @@ def evaluate(self, outputs, res_folder, metric='PCKh', **kwargs): kpts = [] - for preds, boxes, image_path in outputs: + for preds, boxes, image_path, _ in outputs: str_image_path = ''.join(image_path) image_id = int(osp.basename(osp.splitext(str_image_path)[0])) diff --git a/mmpose/datasets/datasets/top_down/topdown_onehand10k_dataset.py b/mmpose/datasets/datasets/top_down/topdown_onehand10k_dataset.py index 86902fe3da..991b880624 100644 --- a/mmpose/datasets/datasets/top_down/topdown_onehand10k_dataset.py +++ b/mmpose/datasets/datasets/top_down/topdown_onehand10k_dataset.py @@ -177,7 +177,7 @@ def evaluate(self, outputs, res_folder, metric='PCK', **kwargs): kpts = [] - for preds, boxes, image_path in outputs: + for preds, boxes, image_path, _ in outputs: str_image_path = ''.join(image_path) image_id = int(osp.basename(osp.splitext(str_image_path)[0])) diff --git a/mmpose/datasets/datasets/top_down/topdown_panoptic_dataset.py b/mmpose/datasets/datasets/top_down/topdown_panoptic_dataset.py index a4c8df0eae..bceaf63cc2 100644 --- a/mmpose/datasets/datasets/top_down/topdown_panoptic_dataset.py +++ b/mmpose/datasets/datasets/top_down/topdown_panoptic_dataset.py @@ -190,7 +190,7 @@ def evaluate(self, outputs, res_folder, metric='PCKh', **kwargs): kpts = [] - for preds, boxes, image_path in outputs: + for preds, boxes, image_path, _ in outputs: str_image_path = ''.join(image_path) image_id = self.name2id[str_image_path[len(self.img_prefix):]] diff --git a/mmpose/models/detectors/top_down.py b/mmpose/models/detectors/top_down.py index b50ec2ddb5..c66e4b3b46 100644 --- a/mmpose/models/detectors/top_down.py +++ b/mmpose/models/detectors/top_down.py @@ -100,7 +100,8 @@ def forward(self, Returns: dict|tuple: if `return loss` is true, then return losses. - Otherwise, return predicted poses, boxes and image paths. + Otherwise, return predicted poses, boxes, image paths + and heatmaps. """ if return_loss: return self.forward_train(img, target, target_weight, img_metas, @@ -188,10 +189,10 @@ def forward_test(self, img, img_metas, return_heatmap=False, **kwargs): output = self.backbone(img) # process head - all_preds, all_boxes, image_path = self.process_head( + all_preds, all_boxes, image_path, heatmap = self.process_head( output, img, img_metas, return_heatmap=return_heatmap) - return all_preds, all_boxes, image_path + return all_preds, all_boxes, image_path, heatmap def process_head(self, output, img, img_metas, return_heatmap=False): """Process heatmap and keypoints from backbone features.""" @@ -224,9 +225,6 @@ def process_head(self, output, img, img_metas, return_heatmap=False): output = (output + output_flipped) * 0.5 output_heatmap = output.detach().cpu().numpy() - if return_heatmap: - self.output_heatmap = output_heatmap - c = img_metas['center'].reshape(1, -1) s = img_metas['scale'].reshape(1, -1) @@ -254,7 +252,10 @@ def process_head(self, output, img, img_metas, return_heatmap=False): all_boxes[0, 5] = score image_path.extend(img_metas['image_file']) - return all_preds, all_boxes, image_path + if not return_heatmap: + output_heatmap = None + + return all_preds, all_boxes, image_path, output_heatmap def show_result(self, img, diff --git a/tests/test_datasets/test_top_down_dataset.py b/tests/test_datasets/test_top_down_dataset.py index 0b78fd8bb5..dab3fffba7 100644 --- a/tests/test_datasets/test_top_down_dataset.py +++ b/tests/test_datasets/test_top_down_dataset.py @@ -21,7 +21,7 @@ def load_json_to_output(json_name, prefix=''): box = np.array([0, 0, 0, 0, 0, 0], dtype=np.float32).reshape(1, -1) img_path = [] img_path[:0] = os.path.join(prefix, image_info['file_name']) - output = (keypoints, box, img_path) + output = (keypoints, box, img_path, None) outputs.append(output) return outputs From a50bc87a9e0fd88060ef75b2f34f4a7d80dca345 Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Fri, 30 Oct 2020 16:21:39 +0000 Subject: [PATCH 18/24] Deleted test file --- tests/data/smpl/test_joint_regressor.npy | Bin 1323008 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/data/smpl/test_joint_regressor.npy diff --git a/tests/data/smpl/test_joint_regressor.npy b/tests/data/smpl/test_joint_regressor.npy deleted file mode 100644 index 2a247b4f8362f8ca544d5fce929b2d102c87287e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1323008 zcmeIuu@1pd0EOXNJ;mKFNe2;;60?n13?^x`jX_jy#Uh@<3#(T!n7)5IXZ+sV{bqL< zWRL6_tGYX-xD0XC6fqC6Y12KG*JGQi`unfTOIP=QcP?*rzem$q9_GbjGS0&*{M0ZL z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5Fqe(fe+;{ B8^{0v From 64f05cb0fcd6c68f152d20fdc34ec155d28e9b78 Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Fri, 30 Oct 2020 16:34:06 +0000 Subject: [PATCH 19/24] Added .npy to ignore list --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ce54486a53..2bd70821aa 100644 --- a/.gitignore +++ b/.gitignore @@ -113,6 +113,7 @@ mmpose/version.py *.pkl *.pkl.json *.log.json +*.npy work_dirs/ # Pytorch From e18ae69b260e93625ba14e886a907089c297f12a Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Fri, 30 Oct 2020 20:35:28 +0000 Subject: [PATCH 20/24] Optimized layer output hooks logic --- mmpose/apis/inference.py | 91 ++++++++++++++-------------------------- mmpose/utils/hooks.py | 65 ++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 59 deletions(-) create mode 100644 mmpose/utils/hooks.py diff --git a/mmpose/apis/inference.py b/mmpose/apis/inference.py index aef79aa1c5..0beeaeb7d0 100644 --- a/mmpose/apis/inference.py +++ b/mmpose/apis/inference.py @@ -1,6 +1,4 @@ -import functools import os -from collections import OrderedDict import mmcv import numpy as np @@ -10,6 +8,7 @@ from mmpose.datasets.pipelines import Compose from mmpose.models import build_posenet +from mmpose.utils.hooks import OutputsHook os.environ['KMP_DUPLICATE_LIB_OK'] = 'TRUE' @@ -138,7 +137,7 @@ def _inference_single_pose_model(model, img_or_path, bbox, dataset, - outputs=None): + return_heatmap=False): """Inference a single bbox. num_keypoints: K @@ -154,8 +153,9 @@ def _inference_single_pose_model(model, Returns: ndarray[Kx3]: Predicted pose x, y, score. - dict: Output feature maps of layers specified in `outputs`. + heatmap[N, K, H, W]: Model output heatmap. """ + cfg = model.cfg device = next(model.parameters()).device @@ -231,53 +231,12 @@ def _inference_single_pose_model(model, # forward the model with torch.no_grad(): - # prepare hooks to return ouputs - returned_outputs = OrderedDict() - return_heatmap = False - handles = [] - - def hook_wrapper(name): - - def hook(model, input, output): - returned_outputs[name] = output.detach().cpu().numpy() - - return hook - - if isinstance(outputs, (list, tuple)): - for name in outputs: - try: - layer = rgetattr(model, name) - h = layer.register_forward_hook(hook_wrapper(name)) - except AttributeError: - if name in ('heatmap', 'heatmaps'): - return_heatmap = True - continue - else: - raise AttributeError(f'Module {name} not found') - handles.append(h) all_preds, _, _, heatmap = model( return_loss=False, return_heatmap=return_heatmap, img=data['img'], img_metas=data['img_metas']) - - if heatmap: - returned_outputs['heatmap'] = heatmap - # clear handles (if any) - for h in handles: - h.remove() - - return all_preds[0], returned_outputs - - -# using wonder's beautiful simplification: -# https://stackoverflow.com/questions/31174295/getattr-and-setattr-on-nested-objects -def rgetattr(obj, attr, *args): - - def _getattr(obj, attr): - return getattr(obj, attr, *args) - - return functools.reduce(_getattr, [obj] + attr.split('.')) + return all_preds[0], heatmap def inference_top_down_pose_model(model, @@ -322,25 +281,39 @@ def inference_top_down_pose_model(model, if format == 'xyxy': person_bboxes = _xyxy2xywh(np.array(person_bboxes)) + return_heatmap = False + if isinstance(outputs, (list, tuple)) and any( + x in outputs for x in ('heatmap', 'heatmaps')): + return_heatmap = True + pose_results = [] returned_outputs = [] if len(person_bboxes) > 0: if bbox_thr is not None: person_bboxes = person_bboxes[person_bboxes[:, 4] > bbox_thr] - for bbox in person_bboxes: - pose, outputs_returned = _inference_single_pose_model( - model, img_or_path, bbox, dataset, outputs=outputs) - - if outputs is not None: - returned_outputs.append(outputs_returned) - - pose_results.append({ - 'bbox': - _xywh2xyxy(np.expand_dims(np.array(bbox), 0)), - 'keypoints': - pose - }) + + with OutputsHook(model, outputs=outputs) as h: + for bbox in person_bboxes: + pose, heatmap = _inference_single_pose_model( + model, + img_or_path, + bbox, + dataset, + return_heatmap=return_heatmap) + + if outputs is not None: + outputs_returned = dict(h.layer_outputs) + if return_heatmap: + outputs_returned['heatmap'] = heatmap + returned_outputs.append(outputs_returned) + + pose_results.append({ + 'bbox': + _xywh2xyxy(np.expand_dims(np.array(bbox), 0)), + 'keypoints': + pose + }) return pose_results, returned_outputs diff --git a/mmpose/utils/hooks.py b/mmpose/utils/hooks.py new file mode 100644 index 0000000000..f9f6fdff8b --- /dev/null +++ b/mmpose/utils/hooks.py @@ -0,0 +1,65 @@ +import functools + + +class Hook: + + def __init__(self, module): + self.module = module + self.handles = None + self.register(self.module) + + def register(self, module): + pass + + def remove(self): + pass + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.remove() + + +class OutputsHook(Hook): + + def __init__(self, module, outputs=None): + self.outputs = outputs + self.layer_outputs = {} + super().__init__(module) + + def register(self, module): + + def hook_wrapper(name): + + def hook(model, input, output): + self.layer_outputs[name] = output.detach().cpu().numpy() + + return hook + + self.handles = [] + if isinstance(self.outputs, (list, tuple)): + for name in self.outputs: + try: + layer = rgetattr(module, name) + h = layer.register_forward_hook(hook_wrapper(name)) + except AttributeError: + if name in ('heatmap', 'heatmaps'): + continue + else: + raise AttributeError(f'Module {name} not found') + self.handles.append(h) + + def remove(self): + for h in self.handles: + h.remove() + + +# using wonder's beautiful simplification: +# https://stackoverflow.com/questions/31174295/getattr-and-setattr-on-nested-objects +def rgetattr(obj, attr, *args): + + def _getattr(obj, attr): + return getattr(obj, attr, *args) + + return functools.reduce(_getattr, [obj] + attr.split('.')) From 4ca5391ce04df977b807d14e15348c5b276a782b Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Fri, 30 Oct 2020 21:29:34 +0000 Subject: [PATCH 21/24] Decoupled heatmap from output layer names. --- demo/top_down_img_demo.py | 5 ++++- demo/top_down_img_demo_with_mmdet.py | 6 +++++- demo/top_down_video_demo_with_mmdet.py | 5 ++++- mmpose/apis/inference.py | 22 +++++++++------------- mmpose/utils/hooks.py | 13 +++++++------ 5 files changed, 29 insertions(+), 22 deletions(-) diff --git a/demo/top_down_img_demo.py b/demo/top_down_img_demo.py index 5edf2f7cf0..0923ba7f43 100644 --- a/demo/top_down_img_demo.py +++ b/demo/top_down_img_demo.py @@ -50,7 +50,9 @@ def main(): img_keys = list(coco.imgs.keys()) - output_layer_names = ('heatmap', ) # default : None + # optional + return_heatmap = False + output_layer_names = ('backbone', ) # default : None # process each image for i in range(len(img_keys)): @@ -76,6 +78,7 @@ def main(): bbox_thr=args.bbox_thr, format='xywh', dataset=dataset, + return_heatmap=return_heatmap, outputs=output_layer_names) if args.out_img_root == '': diff --git a/demo/top_down_img_demo_with_mmdet.py b/demo/top_down_img_demo_with_mmdet.py index 5deeb6ccd5..047fa29c91 100644 --- a/demo/top_down_img_demo_with_mmdet.py +++ b/demo/top_down_img_demo_with_mmdet.py @@ -65,7 +65,10 @@ def main(): # test a single image, with a list of bboxes. - output_layer_names = ('heatmap', ) # default : None + # optional + return_heatmap = False + output_layer_names = ('backbone', ) # default : None + pose_results, returned_outputs = inference_top_down_pose_model( pose_model, image_name, @@ -73,6 +76,7 @@ def main(): bbox_thr=args.bbox_thr, format='xyxy', dataset=dataset, + return_heatmap=return_heatmap, outputs=output_layer_names) if args.out_img_root == '': diff --git a/demo/top_down_video_demo_with_mmdet.py b/demo/top_down_video_demo_with_mmdet.py index 747b8e474c..bdf87dd0ed 100644 --- a/demo/top_down_video_demo_with_mmdet.py +++ b/demo/top_down_video_demo_with_mmdet.py @@ -71,7 +71,9 @@ def main(): f'vis_{os.path.basename(args.video_path)}'), fourcc, fps, size) - output_layer_names = ('heatmap', ) # default : None + # optional + return_heatmap = False + output_layer_names = ('backbone', ) # default : None while (cap.isOpened()): flag, img = cap.read() @@ -90,6 +92,7 @@ def main(): bbox_thr=args.bbox_thr, format='xyxy', dataset=dataset, + return_heatmap=return_heatmap, outputs=output_layer_names) # show the results diff --git a/mmpose/apis/inference.py b/mmpose/apis/inference.py index 0beeaeb7d0..58539514d0 100644 --- a/mmpose/apis/inference.py +++ b/mmpose/apis/inference.py @@ -245,6 +245,7 @@ def inference_top_down_pose_model(model, bbox_thr=None, format='xywh', dataset='TopDownCocoDataset', + return_heatmap=False, outputs=None): """Inference a single image with a list of person bounding boxes. @@ -264,6 +265,7 @@ def inference_top_down_pose_model(model, 'xyxy' means (left, top, right, bottom), 'xywh' means (left, top, width, height). dataset (str): Dataset name, e.g. 'TopDownCocoDataset'. + return_heatmap (bool) : Flag to return heatmap, default: False outputs (list(str) | tuple(str)) : Names of layers whose outputs need to be returned, default: None @@ -272,8 +274,9 @@ def inference_top_down_pose_model(model, Each item in the list is a dictionary, containing the bbox: (left, top, right, bottom, [score]) and the pose (ndarray[Kx3]): x, y, score - list[dict[np.ndarray[N, K, H, W]]]: Output feature maps from layers - specified in `outputs`. + list[dict[np.ndarray[N, K, H, W] | torch.tensor[N, K, H, W]]]: + Output feature maps from layers specified in `outputs`. + Includes 'heatmap' if `return_heatmap` is True. """ # only two kinds of bbox format is supported. assert format in ['xyxy', 'xywh'] @@ -281,11 +284,6 @@ def inference_top_down_pose_model(model, if format == 'xyxy': person_bboxes = _xyxy2xywh(np.array(person_bboxes)) - return_heatmap = False - if isinstance(outputs, (list, tuple)) and any( - x in outputs for x in ('heatmap', 'heatmaps')): - return_heatmap = True - pose_results = [] returned_outputs = [] @@ -293,7 +291,7 @@ def inference_top_down_pose_model(model, if bbox_thr is not None: person_bboxes = person_bboxes[person_bboxes[:, 4] > bbox_thr] - with OutputsHook(model, outputs=outputs) as h: + with OutputsHook(model, outputs=outputs, as_tensor=True) as h: for bbox in person_bboxes: pose, heatmap = _inference_single_pose_model( model, @@ -302,12 +300,10 @@ def inference_top_down_pose_model(model, dataset, return_heatmap=return_heatmap) - if outputs is not None: - outputs_returned = dict(h.layer_outputs) - if return_heatmap: - outputs_returned['heatmap'] = heatmap - returned_outputs.append(outputs_returned) + if return_heatmap: + h.layer_outputs['heatmap'] = heatmap + returned_outputs.append(h.layer_outputs) pose_results.append({ 'bbox': _xywh2xyxy(np.expand_dims(np.array(bbox), 0)), diff --git a/mmpose/utils/hooks.py b/mmpose/utils/hooks.py index f9f6fdff8b..7c97c0b6d8 100644 --- a/mmpose/utils/hooks.py +++ b/mmpose/utils/hooks.py @@ -23,8 +23,9 @@ def __exit__(self, exc_type, exc_val, exc_tb): class OutputsHook(Hook): - def __init__(self, module, outputs=None): + def __init__(self, module, outputs=None, as_tensor=False): self.outputs = outputs + self.as_tensor = as_tensor self.layer_outputs = {} super().__init__(module) @@ -33,7 +34,10 @@ def register(self, module): def hook_wrapper(name): def hook(model, input, output): - self.layer_outputs[name] = output.detach().cpu().numpy() + if self.as_tensor: + self.layer_outputs[name] = output + else: + self.layer_outputs[name] = output.detach().cpu().numpy() return hook @@ -44,10 +48,7 @@ def hook(model, input, output): layer = rgetattr(module, name) h = layer.register_forward_hook(hook_wrapper(name)) except AttributeError: - if name in ('heatmap', 'heatmaps'): - continue - else: - raise AttributeError(f'Module {name} not found') + raise AttributeError(f'Module {name} not found') self.handles.append(h) def remove(self): From 383dad97b894400f641497c95c614966b369f255 Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Sat, 31 Oct 2020 03:52:16 +0000 Subject: [PATCH 22/24] Refactored mmpose.utils.hooks --- mmpose/apis/inference.py | 4 ++-- mmpose/utils/hooks.py | 31 +++++++++---------------------- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/mmpose/apis/inference.py b/mmpose/apis/inference.py index 58539514d0..e64e4d0e1f 100644 --- a/mmpose/apis/inference.py +++ b/mmpose/apis/inference.py @@ -8,7 +8,7 @@ from mmpose.datasets.pipelines import Compose from mmpose.models import build_posenet -from mmpose.utils.hooks import OutputsHook +from mmpose.utils.hooks import OutputHook os.environ['KMP_DUPLICATE_LIB_OK'] = 'TRUE' @@ -291,7 +291,7 @@ def inference_top_down_pose_model(model, if bbox_thr is not None: person_bboxes = person_bboxes[person_bboxes[:, 4] > bbox_thr] - with OutputsHook(model, outputs=outputs, as_tensor=True) as h: + with OutputHook(model, outputs=outputs, as_tensor=True) as h: for bbox in person_bboxes: pose, heatmap = _inference_single_pose_model( model, diff --git a/mmpose/utils/hooks.py b/mmpose/utils/hooks.py index 7c97c0b6d8..519e643878 100644 --- a/mmpose/utils/hooks.py +++ b/mmpose/utils/hooks.py @@ -1,33 +1,14 @@ import functools -class Hook: - - def __init__(self, module): - self.module = module - self.handles = None - self.register(self.module) - - def register(self, module): - pass - - def remove(self): - pass - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - self.remove() - - -class OutputsHook(Hook): +class OutputHook: def __init__(self, module, outputs=None, as_tensor=False): + self.module = module self.outputs = outputs self.as_tensor = as_tensor self.layer_outputs = {} - super().__init__(module) + self.register(self.module) def register(self, module): @@ -55,6 +36,12 @@ def remove(self): for h in self.handles: h.remove() + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.remove() + # using wonder's beautiful simplification: # https://stackoverflow.com/questions/31174295/getattr-and-setattr-on-nested-objects From 6941a7238ce802ad69137c6f3b6886f2f6a8d37e Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Sat, 31 Oct 2020 03:55:26 +0000 Subject: [PATCH 23/24] Fixed mmpose.utils.hooks --- mmpose/utils/hooks.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mmpose/utils/hooks.py b/mmpose/utils/hooks.py index 519e643878..6fe06a457f 100644 --- a/mmpose/utils/hooks.py +++ b/mmpose/utils/hooks.py @@ -4,11 +4,10 @@ class OutputHook: def __init__(self, module, outputs=None, as_tensor=False): - self.module = module self.outputs = outputs self.as_tensor = as_tensor self.layer_outputs = {} - self.register(self.module) + self.register(module) def register(self, module): From 2fffccb19dad3b59184b41be94653f75523b8585 Mon Sep 17 00:00:00 2001 From: vsatyakumar Date: Sat, 31 Oct 2020 14:14:00 +0000 Subject: [PATCH 24/24] Fixed output_layer_names default in top down demos --- demo/top_down_img_demo.py | 4 +++- demo/top_down_img_demo_with_mmdet.py | 4 +++- demo/top_down_video_demo_with_mmdet.py | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/demo/top_down_img_demo.py b/demo/top_down_img_demo.py index 0923ba7f43..5b089da371 100644 --- a/demo/top_down_img_demo.py +++ b/demo/top_down_img_demo.py @@ -52,7 +52,9 @@ def main(): # optional return_heatmap = False - output_layer_names = ('backbone', ) # default : None + + # e.g. use ('backbone', ) to return backbone feature + output_layer_names = None # process each image for i in range(len(img_keys)): diff --git a/demo/top_down_img_demo_with_mmdet.py b/demo/top_down_img_demo_with_mmdet.py index 047fa29c91..28ba3ecc75 100644 --- a/demo/top_down_img_demo_with_mmdet.py +++ b/demo/top_down_img_demo_with_mmdet.py @@ -67,7 +67,9 @@ def main(): # optional return_heatmap = False - output_layer_names = ('backbone', ) # default : None + + # e.g. use ('backbone', ) to return backbone feature + output_layer_names = None pose_results, returned_outputs = inference_top_down_pose_model( pose_model, diff --git a/demo/top_down_video_demo_with_mmdet.py b/demo/top_down_video_demo_with_mmdet.py index bdf87dd0ed..54b3e047cc 100644 --- a/demo/top_down_video_demo_with_mmdet.py +++ b/demo/top_down_video_demo_with_mmdet.py @@ -73,7 +73,9 @@ def main(): # optional return_heatmap = False - output_layer_names = ('backbone', ) # default : None + + # e.g. use ('backbone', ) to return backbone feature + output_layer_names = None while (cap.isOpened()): flag, img = cap.read()