def get_classes(dataset): """Get class names of a dataset.""" alias2name = {} for name, aliases in dataset_aliases.items(): for alias in aliases: alias2name[alias] = name if mmcv.is_str(dataset): if dataset in alias2name: labels = eval(alias2name[dataset] + '_classes()') else: raise ValueError('Unrecognized dataset: {}'.format(dataset)) else: raise TypeError('dataset must a str, but got {}'.format(type(dataset))) return labels
def get_palette(dataset): """Get class palette (RGB) of a dataset.""" alias2name = {} for name, aliases in dataset_aliases.items(): for alias in aliases: alias2name[alias] = name if mmcv.is_str(dataset): if dataset in alias2name: labels = eval(alias2name[dataset] + '_palette()') else: raise ValueError(f'Unrecognized dataset: {dataset}') else: raise TypeError(f'dataset must a str, but got {type(dataset)}') return labels
def coco_eval_with_return(result_files, result_types, coco, max_dets=(100, 300, 1000)): for res_type in result_types: assert res_type in [ 'proposal', 'proposal_fast', 'bbox', 'segm', 'keypoints' ] if mmcv.is_str(coco): coco = COCO(coco) assert isinstance(coco, COCO) if result_types == ['proposal_fast']: ar = fast_eval_recall(result_files, coco, np.array(max_dets)) for i, num in enumerate(max_dets): print('AR@{}\t= {:.4f}'.format(num, ar[i])) return eval_results = {} for res_type in result_types: result_file = result_files[res_type] assert result_file.endswith('.json') coco_dets = coco.loadRes(result_file) img_ids = coco.getImgIds() iou_type = 'bbox' if res_type == 'proposal' else res_type cocoEval = COCOeval(coco, coco_dets, iou_type) cocoEval.params.imgIds = img_ids if res_type == 'proposal': cocoEval.params.useCats = 0 cocoEval.params.maxDets = list(max_dets) cocoEval.evaluate() cocoEval.accumulate() cocoEval.summarize() if res_type == 'segm' or res_type == 'bbox': metric_names = [ 'AP', 'AP50', 'AP75', 'APs', 'APm', 'APl', 'AR1', 'AR10', 'AR100', 'ARs', 'ARm', 'ARl' ] eval_results[res_type] = { metric_names[i]: cocoEval.stats[i] for i in range(len(metric_names)) } else: eval_results[res_type] = cocoEval.stats return eval_results
def __init__(self, model, momentum_encoder, batch_processor, reid_loss_evaluator, optimizer=None, work_dir=None, log_level=logging.INFO, logger=None): assert callable(batch_processor) self.model = model self.momentum_encoder = momentum_encoder if optimizer is not None: self.optimizer = self.init_optimizer(optimizer) else: self.optimizer = None self.batch_processor = batch_processor self.reid_loss_evaluator = reid_loss_evaluator # create work_dir if mmcv.is_str(work_dir): self.work_dir = osp.abspath(work_dir) mmcv.mkdir_or_exist(self.work_dir) elif work_dir is None: self.work_dir = None else: raise TypeError('"work_dir" must be a str or None') # get model name from the model class if hasattr(self.model, 'module'): self._model_name = self.model.module.__class__.__name__ else: self._model_name = self.model.__class__.__name__ self._rank, self._world_size = get_dist_info() self.timestamp = get_time_str() if logger is None: self.logger = self.init_logger(work_dir, log_level) else: self.logger = logger self.log_buffer = LogBuffer() self.mode = None self._hooks = [] self._epoch = 0 self._iter = 0 self._inner_iter = 0 self._max_epochs = 0 self._max_iters = 0
def lvis_eval(result_files, result_types, lvis, max_dets=(100, 300, 1000), existing_json=None): for res_type in result_types: assert res_type in [ 'proposal', 'proposal_fast', 'proposal_fast_percat', 'bbox', 'segm', 'keypoints' ] if mmcv.is_str(lvis): lvis = LVIS(lvis) assert isinstance(lvis, LVIS) if result_types == ['proposal_fast']: ar = lvis_fast_eval_recall(result_files, lvis, np.array(max_dets)) for i, num in enumerate(max_dets): print('AR@{}\t= {:.4f}'.format(num, ar[i])) return elif result_types == ['proposal_fast_percat']: assert existing_json is not None per_cat_recall = {} for cat_id in range(1, 1231): ar = lvis_fast_eval_recall(result_files, lvis, np.array(max_dets), category_id=cat_id) for i, num in enumerate(max_dets): per_cat_recall.update({cat_id: ar}) print('cat{} AR@{}\t= {:.4f}'.format(cat_id, num, ar[i])) pickle.dump(per_cat_recall, open('./{}_per_cat_recall.pt'.format(existing_json), 'wb')) return for res_type in result_types: result_file = result_files[res_type] assert result_file.endswith('.json') iou_type = 'bbox' if res_type == 'proposal' else res_type lvisEval = LVISEval(ANNOTATION_PATH, result_file, iou_type) # lvisEval.params.imgIds = img_ids if res_type == 'proposal': lvisEval.params.use_cats = 0 lvisEval.params.max_dets = list(max_dets) lvisEval.run() lvisEval.print_results()
def print_map_summary(mean_ap, results, dataset=None): """Print mAP and results of each class. Args: mean_ap(float): calculated from `eval_map` results(list): calculated from `eval_map` dataset(None or str or list): dataset name or dataset classes. """ num_scales = len(results[0]['ap']) if isinstance(results[0]['ap'], np.ndarray) else 1 num_classes = len(results) recalls = np.zeros((num_scales, num_classes), dtype=np.float32) precisions = np.zeros((num_scales, num_classes), dtype=np.float32) aps = np.zeros((num_scales, num_classes), dtype=np.float32) num_gts = np.zeros((num_scales, num_classes), dtype=int) for i, cls_result in enumerate(results): if cls_result['recall'].size > 0: recalls[:, i] = np.array(cls_result['recall'], ndmin=2)[:, -1] precisions[:, i] = np.array(cls_result['precision'], ndmin=2)[:, -1] aps[:, i] = cls_result['ap'] num_gts[:, i] = cls_result['num_gts'] if dataset is None: label_names = [str(i) for i in range(1, num_classes + 1)] elif mmcv.is_str(dataset): label_names = get_classes(dataset) else: label_names = dataset if not isinstance(mean_ap, list): mean_ap = [mean_ap] header = ['class', 'gts', 'dets', 'recall', 'precision', 'ap'] for i in range(num_scales): table_data = [header] for j in range(num_classes): row_data = [ label_names[j], num_gts[i, j], results[j]['num_dets'], '{:.3f}'.format(recalls[i, j]), '{:.3f}'.format(precisions[i, j]), '{:.3f}'.format(aps[i, j]) ] table_data.append(row_data) table_data.append(['mAP', '', '', '', '', '{:.3f}'.format(mean_ap[i])]) table = AsciiTable(table_data) table.inner_footing_row_border = True print(table.table)
def coco_eval_pic(result_files, result_types, coco, max_dets=(100, 300, 1000), catIds=None): for res_type in result_types: assert res_type in [ 'proposal', 'proposal_fast', 'bbox', 'segm', 'keypoints' ] if mmcv.is_str(coco): coco = COCO(coco) assert isinstance(coco, COCO) if result_types == ['proposal_fast']: ar = fast_eval_recall(result_files, coco, np.array(max_dets)) for i, num in enumerate(max_dets): print('AR@{}\t= {:.4f}'.format(num, ar[i])) return for res_type in result_types: result_file = result_files[res_type] assert result_file.endswith('.json') coco_dets = coco.loadRes(result_file) img_ids = coco.getImgIds() iou_type = 'bbox' if res_type == 'proposal' else res_type if catIds is not None: cocoEval = COCOeval(coco, coco_dets, iou_type) mAPs = [] for catId in catIds: cocoEval.params.catIds = [catId] cocoEval.params.imgIds = img_ids if res_type == 'proposal': cocoEval.params.useCats = 0 cocoEval.params.maxDets = list(max_dets) cocoEval.evaluate() cocoEval.accumulate() mAP = cocoEval.summarize() mAPs.append(mAP) print(mAPs) else: cocoEval = COCOeval(coco, coco_dets, iou_type) cocoEval.params.imgIds = img_ids if res_type == 'proposal': cocoEval.params.useCats = 0 cocoEval.params.maxDets = list(max_dets) cocoEval.evaluate() cocoEval.accumulate() cocoEval.summarize()
def to_tensor(data): """Convert objects of various python types to :obj:`torch.Tensor`. Supported types are: :class:`numpy.ndarray`, :class:`torch.Tensor`, :class:`Sequence`, :class:`int` and :class:`float`. """ if isinstance(data, torch.Tensor): return data if isinstance(data, np.ndarray): return torch.from_numpy(data) if isinstance(data, Sequence) and not mmcv.is_str(data): return torch.tensor(data) if isinstance(data, int): return torch.LongTensor([data]) if isinstance(data, float): return torch.FloatTensor([data]) raise TypeError(f'type {type(data)} cannot be converted to tensor.')
def coco_eval(result_files, result_types, coco, max_dets=(100, 300, 1000), LRPEval=1, tau=0.5): for res_type in result_types: assert res_type in [ 'proposal', 'proposal_fast', 'bbox', 'segm', 'keypoints' ] if mmcv.is_str(coco): coco = COCO(coco) assert isinstance(coco, COCO) if result_types == ['proposal_fast']: ar = fast_eval_recall(result_files, coco, np.array(max_dets)) for i, num in enumerate(max_dets): print('AR@{}\t= {:.4f}'.format(num, ar[i])) return for res_type in result_types: if isinstance(result_files, str): result_file = result_files elif isinstance(result_files, dict): result_file = result_files[res_type] else: assert TypeError('result_files must be a str or dict') assert result_file.endswith('.json') coco_dets = coco.loadRes(result_file) img_ids = coco.getImgIds() iou_type = 'bbox' if res_type == 'proposal' else res_type cocoEval = COCOeval(coco, coco_dets, iou_type) cocoEval.params.imgIds = img_ids if res_type == 'proposal': cocoEval.params.useCats = 0 cocoEval.params.maxDets = list(max_dets) cocoEval.evaluate() cocoEval.accumulate() cocoEval.summarize() if res_type == 'bbox' and LRPEval > 0: cocoEvalLRP = COCOevalLRP(coco, coco_dets, tau) cocoEvalLRP.evaluate() cocoEvalLRP.accumulate() cocoEvalLRP.summarize()
def _build_module(cfg, registry, default_args): assert isinstance(cfg, dict) and 'type' in cfg assert isinstance(default_args, dict) or default_args is None args = cfg.copy() obj_type = args.pop('type') if mmcv.is_str(obj_type): if obj_type not in registry.module_dict: raise KeyError('{} is not in the {} registry'.format( obj_type, registry.name)) obj_type = registry.module_dict[obj_type] elif not isinstance(obj_type, type): raise TypeError('type must be a str or valid type, but got {}'.format( type(obj_type))) if default_args is not None: for name, value in default_args.items(): args.setdefault(name, value) return obj_type(**args)
def get_palette(palette, num_classes): """Get palette from various inputs. Args: palette (list[tuple] | str | tuple | :obj:`Color`): palette inputs. num_classes (int): the number of classes. Returns: list[tuple[int]]: A list of color tuples. """ assert isinstance(num_classes, int) if isinstance(palette, list): dataset_palette = palette elif isinstance(palette, tuple): dataset_palette = [palette] * num_classes elif palette == 'random' or palette is None: state = np.random.get_state() # random color np.random.seed(42) palette = np.random.randint(0, 256, size=(num_classes, 3)) np.random.set_state(state) dataset_palette = [tuple(c) for c in palette] elif palette == 'coco': from mmdet.datasets import CocoDataset, CocoPanopticDataset dataset_palette = CocoDataset.PALETTE if len(dataset_palette) < num_classes: dataset_palette = CocoPanopticDataset.PALETTE elif palette == 'citys': from mmdet.datasets import CityscapesDataset dataset_palette = CityscapesDataset.PALETTE elif palette == 'voc': from mmdet.datasets import VOCDataset dataset_palette = VOCDataset.PALETTE elif palette == 'wod': from mmdet.datasets import WaymoOpenDataset dataset_palette = WaymoOpenDataset.PALETTE elif mmcv.is_str(palette): dataset_palette = [mmcv.color_val(palette)[::-1]] * num_classes else: raise TypeError(f'Invalid type for palette: {type(palette)}') assert len(dataset_palette) >= num_classes, \ 'The length of palette should not be less than `num_classes`.' return dataset_palette
def main(): """ Main function. """ args = parse_args() if args.input is not None and not args.input.endswith(('.pkl', '.pickle')): raise ValueError('The input file must be a pkl file.') cfg = mmcv.Config.fromfile(args.config) dataset = build_dataset(cfg.data.test) results = mmcv.load(args.input) result_file = results2json(dataset, results, args.input) coco = dataset.coco if mmcv.is_str(coco): coco = COCO(coco) assert isinstance(coco, COCO) eval_type = 'bbox' result_file = result_file[eval_type] coco_dets = coco.loadRes(result_file) img_ids = coco.getImgIds() iou_type = 'bbox' cocoEval = COCOeval(coco, coco_dets, iou_type) cocoEval.params.imgIds = img_ids predictions = cocoEval.cocoDt.imgToAnns gt_annotations = cocoEval.cocoGt.imgToAnns if args.visualize: img_paths = [ dataset.img_prefix + image['file_name'] for image in coco_dets.dataset['images'] ] else: img_paths = None recall, precision, hmean, _ = text_eval(predictions, gt_annotations, cfg.test_cfg.score_thr, images=img_paths, show_recall_graph=args.draw_graph) print('Text detection recall={:.4f} precision={:.4f} hmean={:.4f}'.format( recall, precision, hmean))
def deep_recursive_obj_from_dict(info): """Initialize an object from dict. The dict must contain the key "type", which indicates the object type, it can be either a string or type, such as "list" or ``list``. Remaining fields are treated as the arguments for constructing the object. Args: info (dict): Object types and arguments. parent (:class:`module`): Module which may containing expected object classes. default_args (dict, optional): Default arguments for initializing the object. Returns: any type: Object built from the dict. """ assert isinstance(info, dict) and 'type' in info # TODO: This does not support object dicts nested in non-object dicts. args = info.copy() obj_type = args.pop('type') if mmcv.is_str(obj_type): obj_type = eval_mmcv_str(obj_type) elif not isinstance(obj_type, type): raise TypeError('type must be a str or valid type, but got {}'.format( type(obj_type))) evaluated_args = {} for argname, argval in args.items(): print(argname, type(argval)) if isinstance(argval, dict) and 'type' in argval: evaluated_args[argname] = deep_recursive_obj_from_dict(argval) elif type(argval) == list or type(argval) == tuple: # Transform each dict in the list, else simply append. transformed_list = [] for elem in argval: if isinstance(elem, dict): transformed_list.append(deep_recursive_obj_from_dict(elem)) else: transformed_list.append(elem) evaluated_args[argname] = type(argval)(transformed_list) else: evaluated_args[argname] = argval print(obj_type) return obj_type(**evaluated_args)
def lvis_fast_eval_recall(results, lvis, max_dets, category_id=None, iou_thrs=np.arange(0.5, 0.96, 0.05)): if mmcv.is_str(results): assert results.endswith('.pkl') results = mmcv.load(results) elif not isinstance(results, list): raise TypeError( 'results must be a list of numpy arrays or a filename, not {}'. format(type(results))) gt_bboxes = [] img_ids = lvis.get_img_ids() for i in range(len(img_ids)): ann_ids = lvis.get_ann_ids(img_ids=[img_ids[i]]) ann_info = lvis.load_anns(ann_ids) if len(ann_info) == 0: gt_bboxes.append(np.zeros((0, 4))) continue bboxes = [] for ann in ann_info: # if ann.get('ignore', False) or ann['iscrowd']: # continue if category_id: if ann.get('category_id') != category_id: continue x1, y1, w, h = ann['bbox'] bboxes.append([x1, y1, x1 + w - 1, y1 + h - 1]) bboxes = np.array(bboxes, dtype=np.float32) if bboxes.shape[0] == 0: bboxes = np.zeros((0, 4)) gt_bboxes.append(bboxes) recalls = eval_recalls(gt_bboxes, results, max_dets, iou_thrs, print_summary=False) ar = recalls.mean(axis=1) return ar
def obj_from_dict(info, parent=None, default_args=None): 'Initialize an object from dict.\n\n The dict must contain the key "type", which indicates the object type, it\n can be either a string or type, such as "list" or ``list``. Remaining\n fields are treated as the arguments for constructing the object.\n\n Args:\n info (dict): Object types and arguments.\n parent (:class:`module`): Module which may containing expected object\n classes.\n default_args (dict, optional): Default arguments for initializing the\n object.\n\n Returns:\n any type: Object built from the dict.\n ' assert (isinstance(info, dict) and ('type' in info)) assert (isinstance(default_args, dict) or (default_args is None)) args = info.copy() obj_type = args.pop('type') if mmcv.is_str(obj_type): if (parent is not None): obj_type = getattr(parent, obj_type) else: obj_type = sys.modules[obj_type] elif (not isinstance(obj_type, type)): raise TypeError(''.join([ 'type must be a str or valid type, but got ', '{}'.format(type(obj_type)) ])) if (default_args is not None): for (name, value) in default_args.items(): args.setdefault(name, value) return obj_type(**args)
def evaluate(self, runner, results): if mmcv.is_str(results): assert results.endswith('.pkl') results = mmcv.load(results) elif not isinstance(results, list): raise TypeError( 'results must be a list of numpy arrays or a filename, not {}'. format(type(results))) abs_rel = AverageMeter() sq_rel = AverageMeter() rmse = AverageMeter() rmse_log = AverageMeter() a1 = AverageMeter() a2 = AverageMeter() a3 = AverageMeter() scale = AverageMeter() print('results len is ', results.__len__()) ratio = [] for result in results: abs_rel.update(result['abs_rel']) sq_rel.update(result['sq_rel']) rmse.update(result['rmse']) rmse_log.update(result['rmse_log']) a1.update(result['a1']) a2.update(result['a2']) a3.update(result['a3']) scale.update(result['scale']) ratio.append(result['scale']) runner.log_buffer.output['abs_rel'] = abs_rel.avg runner.log_buffer.output['sq_rel'] = sq_rel.avg runner.log_buffer.output['rmse'] = rmse.avg runner.log_buffer.output['rmse_log'] = rmse_log.avg runner.log_buffer.output['a1'] = a1.avg runner.log_buffer.output['a2'] = a2.avg runner.log_buffer.output['a3'] = a3.avg runner.log_buffer.output['scale mean'] = scale.avg runner.log_buffer.output['scale std'] = np.std(ratio) runner.log_buffer.ready = True
def to_tensor(data): """Convert objects of various python types to :obj:`torch.Tensor`. Supported types are: :class:`numpy.ndarray`, :class:`torch.Tensor`, :class:`Sequence`, :class:`int` and :class:`float`. """ if isinstance(data, torch.Tensor): return data elif isinstance(data, np.ndarray): return torch.from_numpy( data.copy() ) # modified by Yuan.Copy operation will malloc new memory which is contiguous. elif isinstance(data, Sequence) and not mmcv.is_str(data): return torch.tensor(data) elif isinstance(data, int): return torch.LongTensor([data]) elif isinstance(data, float): return torch.FloatTensor([data]) else: raise TypeError('type {} cannot be converted to tensor.'.format( type(data)))
def _to_tensor(self, data): """Convert objects of various python types to :obj:`torch.Tensor`. Supported types are: :class:`numpy.ndarray`, :class:`torch.Tensor`, :class:`Sequence`, :class:`int` and :class:`float`. Args: data (torch.Tensor | numpy.ndarray | Sequence | int | float): Data to be converted. """ if isinstance(data, torch.Tensor): return data elif isinstance(data, np.ndarray): return torch.from_numpy(data) elif isinstance(data, Sequence) and not mmcv.is_str(data): return torch.tensor(data) elif isinstance(data, int): return torch.LongTensor([data]) elif isinstance(data, float): return torch.FloatTensor([data]) else: raise TypeError(f"type {type(data)} cannot be converted to tensor.")
def build_from_cfg(cfg, registry, default_args=None): assert isinstance(cfg, dict) and 'type' in cfg assert isinstance(default_args, dict) or default_args is None args = cfg.copy() obj_type = args.pop('type') if mmcv.is_str(obj_type): obj_cls = registry.get(obj_type) if obj_cls is None: raise KeyError('{} is not in the {} registry'.format( obj_type, registry.name)) elif inspect.isclass(obj_type): obj_cls = obj_type else: raise TypeError('type must be a str or valid type, but got {}'.format( type(obj_type))) if default_args is not None: for name, value in default_args.items(): args.setdefault(name, value) return obj_cls(**args)
def lvis_eval(result_files, result_types, lvis, max_dets=(100, 300, 1000)): for res_type in result_types: assert res_type in [ 'proposal_fast', 'proposal', 'bbox', 'segm' ] if mmcv.is_str(lvis): lvis = LVIS(lvis) assert isinstance(lvis, LVIS) img_ids = lvis.get_img_ids() for res_type in result_types: result_file = result_files['proposal' if res_type == 'proposal_fast' else res_type] if isinstance(result_file, str): assert result_file.endswith('.json') iou_type = 'bbox' if res_type in ['proposal', 'proposal_fast'] else res_type lvisEval = LVISEvalCustom(lvis, result_file, iou_type) lvisEval.params.img_ids = img_ids if res_type == 'proposal_fast': lvis_fast_eval_recall(result_file, lvisEval, np.array(max_dets)) continue elif res_type == 'proposal': lvisEval.params.use_proposal = True for max_det in max_dets: lvisEval.params.max_dets = max_det lvisEval.run() for area_rng in ["small", "medium", "large"]: key = "AR{}@{}".format(area_rng[0], max_det) print('{}={:.3f}'.format(key, lvisEval.get_results()[key])) freq_group = lvisEval.params.img_count_lbl for idx in range(len(freq_group)): key = "AR{}@{}".format(freq_group[idx][0], max_det) print('{}={:.3f}'.format(key, lvisEval.get_results()[key])) key = "AR@{}".format(max_det) print('{}={:.3f}'.format(key, lvisEval.get_results()[key])) continue lvisEval.run() print('-'*8+'{} results'.format(res_type)+'-'*8) lvisEval.print_results()
def coco_eval(result_files, result_types, coco, max_dets=(100, 300, 1000)): for res_type in result_types: assert res_type in [ 'proposal', 'proposal_fast', 'bbox', 'segm', 'keypoints' ] if mmcv.is_str(coco): coco = COCO(coco) # assert isinstance(coco, COCO) if result_types == ['proposal_fast']: ar = fast_eval_recall(result_files, coco, np.array(max_dets)) for i, num in enumerate(max_dets): print('AR@{}\t= {:.4f}'.format(num, ar[i])) return for res_type in result_types: result_file = result_files[res_type] assert result_file.endswith('.json') coco_dets = coco.loadRes(result_file) img_ids = coco.getImgIds() iou_type = 'bbox' if res_type == 'proposal' else res_type cocoEval = COCOeval(coco, coco_dets, iou_type) cocoEval.params.imgIds = img_ids if res_type == 'proposal': cocoEval.params.useCats = 0 cocoEval.params.maxDets = list(max_dets) cocoEval.evaluate() cocoEval.accumulate() cocoEval.summarize() metrics = ['mAP', 'mAP_50', 'mAP_75', 'mAP_s', 'mAP_m', 'mAP_l'] output = dict() for i in range(len(metrics)): key = '{}_{}'.format(res_type, metrics[i]) val = float('{:.3f}'.format(cocoEval.stats[i])) output[key] = val return output
def to_tensor(data): """Convert the input to tensor. :param data: the input to convert :type data: :class:`numpy.ndarray`, :class:`torch.Tensor`,:class:`Sequence`, :class:`int` and :class:`float` :raises TypeError: if the type of the data is not in the type above, it will raise error :return: tensor :rtype: tensor """ if isinstance(data, torch.Tensor): return data elif isinstance(data, np.ndarray): return torch.from_numpy(data) elif isinstance(data, Sequence) and not mmcv.is_str(data): return torch.tensor(data) elif isinstance(data, int): return torch.LongTensor([data]) elif isinstance(data, float): return torch.FloatTensor([data]) else: raise TypeError('type {} cannot be converted to tensor.'.format( type(data)))
def print_recall_summary(recalls, proposal_nums, iou_thrs, row_idxs=None, col_idxs=None, logger=None, work_dir=None): """Print recalls in a table. Args: recalls (ndarray): calculated from `bbox_recalls` proposal_nums (ndarray or list): top N proposals iou_thrs (ndarray or list): iou thresholds row_idxs (ndarray): which rows(proposal nums) to print col_idxs (ndarray): which cols(iou thresholds) to print logger (logging.Logger | str | None): The way to print the recall summary. See `mmdet.utils.print_log()` for details. Default: None. """ proposal_nums = np.array(proposal_nums, dtype=np.int32) iou_thrs = np.array(iou_thrs) if row_idxs is None: row_idxs = np.arange(proposal_nums.size) if col_idxs is None: col_idxs = np.arange(iou_thrs.size) row_header = [''] + iou_thrs[col_idxs].tolist() table_data = [row_header] for i, num in enumerate(proposal_nums[row_idxs]): row = [ '{:.3f}'.format(val) for val in recalls[row_idxs[i], col_idxs].tolist() ] row.insert(0, num) table_data.append(row) table = AsciiTable(table_data) print_log('\n' + table.table, logger=logger) if work_dir is not None and mmcv.is_str(work_dir): with open(work_dir, 'a+') as f: print(table.table, file=f)
def ytvos_eval(result_file, result_types, ytvos, max_dets=(100, 300, 1000)): if mmcv.is_str(ytvos): ytvos = YTVOS(ytvos) assert isinstance(ytvos, YTVOS) # if len(ytvos.anns) == 0: # print("Annotations does not exist") # return assert result_file.endswith('.json') ytvos_dets = ytvos.loadRes(result_file) vid_ids = ytvos.getVidIds() for res_type in result_types: iou_type = res_type ytvosEval = YTVOSeval(ytvos, ytvos_dets, iou_type) ytvosEval.params.vidIds = vid_ids if res_type == 'proposal': ytvosEval.params.useCats = 0 ytvosEval.params.maxDets = list(max_dets) ytvosEval.evaluate() ytvosEval.accumulate() ytvosEval.summarize()
def fast_eval_recall(results, coco, max_dets, iou_thrs=np.arange(0.5, 0.96, 0.05)): if mmcv.is_str(results): assert results.endswith('.pkl') results = mmcv.load(results) elif not isinstance(results, list): raise TypeError( 'results must be a list of numpy arrays or a filenmae, not {}'. format(type(results))) gt_bboxes = [] img_ids = coco.getImgIds() for i in range(len(img_ids)): ann_ids = coco.getAnnIds(imgIds=img_ids[i]) ann_info = coco.loadAnns(ann_ids) if len(ann_info) == 0: gt_bboxes.append(np.zeros((0, 4))) continue bboxes = [] for ann in ann_info: if ann.get('ignore', False) or ann['iscrowd']: continue x1, y1, w, h = ann['bbox'] bboxes.append([x1, y1, x1 + w - 1, y1 + h - 1]) if bboxes.shape[0] == 0: bboxes = np.zeros((0, 4)) gt_bboxes.append(bboxes) recalls = eval_recalls(gt_bboxes, results, max_dets, iou_thrs, print_summary=False) ar = recalls.mean(axis=1) return ar
def build_from_cfg(cfg, registry, default_args=None): """Build a module from config dict. Args: cfg (dict): Config dict. It should at least contain the key "type". registry (:obj:`Registry`): The registry to search the type from. default_args (dict, optional): Default initialization arguments. Returns: obj: The constructed object. """ assert isinstance(cfg, dict) and 'type' in cfg assert isinstance(default_args, dict) or default_args is None args = cfg.copy() obj_type = args.pop('type') if mmcv.is_str(obj_type): # print('obj_type_before:',obj_type) obj_type = registry.get(obj_type) # print('obj_type_after:',obj_type) # obj_type_before: TTFNet # obj_type_after: <class 'mmdet.models.detectors.ttfnet.TTFNet'> # obj_type_before: DarknetV3 # obj_type_after: <class 'mmdet.models.backbones.darknet.DarknetV3'> if obj_type is None: raise KeyError('{} is not in the {} registry'.format( obj_type, registry.name)) elif not inspect.isclass(obj_type): raise TypeError('type must be a str or valid type, but got {}'.format( type(obj_type))) if default_args is not None: for name, value in default_args.items(): # name: train_cfg value: {'vis_every_n_iters': 100, 'debug': False} # name: test_cfg value: {'score_thr': 0.01, 'max_per_img': 100 args.setdefault(name, value) # print('obj_type:',obj_type(**args)) return obj_type(**args)
def to_tensor(data): """Convert objects of various python types to :obj:`torch.Tensor`. Supported types are: :class:`numpy.ndarray`, :class:`torch.Tensor`, :class:`Sequence`, :class:`int` and :class:`float`. """ #print("to tensor") if isinstance(data, torch.Tensor): #print("11") return data elif isinstance(data, np.ndarray): #print(data.dtype) #print("from numpy") return torch.from_numpy(data) elif isinstance(data, Sequence) and not mmcv.is_str(data): return torch.tensor(data) elif isinstance(data, int): print("-----") return torch.FloatTensor([data]) elif isinstance(data, float): return torch.FloatTensor([data]) else: raise TypeError('type {} cannot be converted to tensor.'.format( type(data)))
def _build_module(cfg, registry, default_args): """ 构建网络模型。 :param cfg: ConfigDict对象,配置文件,其中的‘type'定义了模型类型,如‘MaskRCNN'. :param registry: Registry对象,其中的module_dict为dict,其中包含了不同模型的类函数。 :param default_args: :return: 网络模型初始化的对象。 """ assert isinstance(cfg, dict) and 'type' in cfg assert isinstance(default_args, dict) or default_args is None args = cfg.copy() obj_type = args.pop('type') if mmcv.is_str(obj_type): if obj_type not in registry.module_dict: raise KeyError('{} is not in the {} registry'.format( obj_type, registry.name)) obj_type = registry.module_dict[obj_type] elif not isinstance(obj_type, type): raise TypeError('type must be a str or valid type, but got {}'.format( type(obj_type))) if default_args is not None: for name, value in default_args.items(): args.setdefault(name, value) return obj_type(**args)
def coco_eval( result_file, result_types, coco, max_dets=(100, 300, 1000) ): for res_type in result_types: assert res_type in [ "proposal", "proposal_fast", "bbox", "segm", "keypoints", ] if mmcv.is_str(coco): coco = COCO(coco) assert isinstance(coco, COCO) if result_types == ["proposal_fast"]: ar = fast_eval_recall(result_file, coco, np.array(max_dets)) for i, num in enumerate(max_dets): print("AR@{}\t= {:.4f}".format(num, ar[i])) return assert result_file.endswith(".json") coco_dets = coco.loadRes(result_file) img_ids = coco.getImgIds() for res_type in result_types: iou_type = "bbox" if res_type == "proposal" else res_type cocoEval = COCOeval(coco, coco_dets, iou_type) cocoEval.params.imgIds = img_ids if res_type == "proposal": cocoEval.params.useCats = 0 cocoEval.params.maxDets = list(max_dets) cocoEval.evaluate() cocoEval.accumulate() cocoEval.summarize()
def coco_eval(result_files, result_types, coco, max_dets=(100, 300, 1000), classwise=False): for res_type in result_types: assert res_type in [ 'proposal', 'proposal_fast', 'bbox', 'segm', 'keypoints' ] if mmcv.is_str(coco): coco = COCO(coco) assert isinstance(coco, COCO) if result_types == ['proposal_fast']: ar = fast_eval_recall(result_files, coco, np.array(max_dets)) for i, num in enumerate(max_dets): print('AR@{}\t= {:.4f}'.format(num, ar[i])) return for res_type in result_types: if isinstance(result_files, str): result_file = result_files elif isinstance(result_files, dict): result_file = result_files[res_type] else: assert TypeError('result_files must be a str or dict') assert result_file.endswith('.json') coco_dets = coco.loadRes(result_file) img_ids = coco.getImgIds() iou_type = 'bbox' if res_type == 'proposal' else res_type cocoEval = COCOeval(coco, coco_dets, iou_type) cocoEval.params.imgIds = img_ids if res_type == 'proposal': cocoEval.params.useCats = 0 cocoEval.params.maxDets = list(max_dets) cocoEval.evaluate() cocoEval.accumulate() cocoEval.summarize() if classwise: # Compute per-category AP # from https://github.com/facebookresearch/detectron2/blob/03064eb5bafe4a3e5750cc7a16672daf5afe8435/detectron2/evaluation/coco_evaluation.py#L259-L283 # noqa precisions = cocoEval.eval['precision'] catIds = coco.getCatIds() # precision has dims (iou, recall, cls, area range, max dets) assert len(catIds) == precisions.shape[2] results_per_category = [] for idx, catId in enumerate(catIds): # area range index 0: all area ranges # max dets index -1: typically 100 per image nm = coco.loadCats(catId)[0] precision = precisions[:, :, idx, 0, -1] precision = precision[precision > -1] ap = np.mean(precision) if precision.size else float('nan') results_per_category.append( ('{}'.format(nm['name']), '{:0.3f}'.format(float(ap * 100)))) N_COLS = min(6, len(results_per_category) * 2) results_flatten = list(itertools.chain(*results_per_category)) headers = ['category', 'AP'] * (N_COLS // 2) results_2d = itertools.zip_longest( *[results_flatten[i::N_COLS] for i in range(N_COLS)]) table_data = [headers] table_data += [result for result in results_2d] table = AsciiTable(table_data) print(table.table)