def update_model( self ): with open( self._groundtruth_store, 'wb' ) as fp: pickle.dump( self._training_data, fp ) from mmdet.datasets.custom import CustomDataset train_dataset = CustomDataset( self._groundtruth_store, '.', self._cfg.data.train.img_scale, self._cfg.data.train.img_norm_cfg, size_divisor = self._cfg.data.train.size_divisor, flip_ratio = self._cfg.data.train.flip_ratio, with_mask = self._cfg.data.train.with_mask, with_crowd = self._cfg.data.train.with_crowd, with_label = self._cfg.data.train.with_label ) from mmdet.apis import train_detector train_detector( self._model, train_dataset, self._cfg, distributed = self._distributed, validate = self._validate, logger = self._logger )
def main(): args = parse_args() cfg = Config.fromfile(args.config) if args.cfg_options is not None: cfg.merge_from_dict(args.cfg_options) # import modules from string list. if cfg.get('custom_imports', None): from mmcv.utils import import_modules_from_strings import_modules_from_strings(**cfg['custom_imports']) # set cudnn_benchmark if cfg.get('cudnn_benchmark', False): torch.backends.cudnn.benchmark = True # work_dir is determined in this priority: CLI > segment in file > filename if args.work_dir is not None: # update configs according to CLI args if args.work_dir is not None cfg.work_dir = args.work_dir elif cfg.get('work_dir', None) is None: # use config filename as default work_dir if cfg.work_dir is None cfg.work_dir = osp.join('./work_dirs', osp.splitext(osp.basename(args.config))[0]) # auto resume, scan existing file resume_file = "" if os.path.exists(cfg.work_dir): work_dir_files = os.listdir(cfg.work_dir) work_dir_files = [ f for f in work_dir_files if f.endswith(".pth") and f.split('.')[0] != 'latest' ] if len(work_dir_files) != 0: work_dir_files = sorted( work_dir_files, key=lambda y: int(y.split('.')[0].split('_')[-1]), reverse=True) resume_file = work_dir_files[0] if args.resume_from is not None: cfg.resume_from = args.resume_from # auto resume if args.resume_from is None and resume_file != "": cfg.resume_from = os.path.join(cfg.work_dir, resume_file) print("Auto resume from {}".format(cfg.resume_from)) if args.gpu_ids is not None: cfg.gpu_ids = args.gpu_ids else: cfg.gpu_ids = range(1) if args.gpus is None else range(args.gpus) # init distributed env first, since logger depends on the dist info. if args.launcher == 'none': distributed = False else: distributed = True init_dist(args.launcher, **cfg.dist_params) # re-set gpu_ids with distributed training mode _, world_size = get_dist_info() cfg.gpu_ids = range(world_size) # create work_dir mmcv.mkdir_or_exist(osp.abspath(cfg.work_dir)) # dump config cfg.dump(osp.join(cfg.work_dir, osp.basename(args.config))) # init the logger before other steps timestamp = time.strftime('%Y%m%d_%H%M%S', time.localtime()) log_file = osp.join(cfg.work_dir, f'{timestamp}.log') logger = get_root_logger(log_file=log_file, log_level=cfg.log_level) # init the meta dict to record some important information such as # environment info and seed, which will be logged meta = dict() # log env info env_info_dict = collect_env() env_info = '\n'.join([(f'{k}: {v}') for k, v in env_info_dict.items()]) dash_line = '-' * 60 + '\n' logger.info('Environment info:\n' + dash_line + env_info + '\n' + dash_line) meta['env_info'] = env_info meta['config'] = cfg.pretty_text # log some basic info logger.info(f'Distributed training: {distributed}') logger.info(f'Config:\n{cfg.pretty_text}') # set random seeds if args.seed is not None: logger.info(f'Set random seed to {args.seed}, ' f'deterministic: {args.deterministic}') set_random_seed(args.seed, deterministic=args.deterministic) cfg.seed = args.seed meta['seed'] = args.seed meta['exp_name'] = osp.basename(args.config) model = build_detector(cfg.model, train_cfg=cfg.train_cfg, test_cfg=cfg.test_cfg) print("model", model) datasets = [build_dataset(cfg.data.train)] if len(cfg.workflow) == 2: val_dataset = copy.deepcopy(cfg.data.val) val_dataset.pipeline = cfg.data.train.pipeline datasets.append(build_dataset(val_dataset)) if cfg.checkpoint_config is not None: # save mmdet version, config file content and class names in # checkpoints as meta data cfg.checkpoint_config.meta = dict(mmdet_version=__version__ + get_git_hash()[:7], CLASSES=datasets[0].CLASSES) # add an attribute for visualization convenience model.CLASSES = datasets[0].CLASSES train_detector(model, datasets, cfg, distributed=distributed, validate=(not args.no_validate), timestamp=timestamp, meta=meta)
def main(): args = parse_args() cfg = Config.fromfile(args.config) # set cudnn_benchmark if cfg.get('cudnn_benchmark', False): torch.backends.cudnn.benchmark = True # update configs according to CLI args if args.work_dir is not None: cfg.work_dir = args.work_dir if args.resume_from is not None: cfg.resume_from = args.resume_from cfg.gpus = args.gpus if args.autoscale_lr: # apply the linear scaling rule (https://arxiv.org/abs/1706.02677) cfg.optimizer['lr'] = cfg.optimizer['lr'] * cfg.gpus / 8 # init distributed env first, since logger depends on the dist info. if args.launcher == 'none': distributed = False else: distributed = True init_dist(args.launcher, **cfg.dist_params) # init logger before other steps logger = get_root_logger(cfg.log_level) logger.info('Distributed training: {}'.format(distributed)) # set random seeds if args.seed is not None: logger.info('Set random seed to {}'.format(args.seed)) set_random_seed(args.seed) model = build_detector(cfg.model, train_cfg=cfg.train_cfg, test_cfg=cfg.test_cfg) datasets = [build_dataset(cfg.data.train)] if len(cfg.workflow) == 2: datasets.append(build_dataset(cfg.data.val)) if cfg.checkpoint_config is not None: # save mmdet version, config file content and class names in # checkpoints as meta data cfg.checkpoint_config.meta = dict(mmdet_version=__version__, config=cfg.text, CLASSES=datasets[0].CLASSES) # add an attribute for visualization convenience model.CLASSES = datasets[0].CLASSES train_detector(model, datasets, cfg, distributed=distributed, validate=args.validate, logger=logger) do_test = True if do_test: print('\nDoing inference') from mmdet.datasets import build_dataloader import mmcv from mmcv.parallel import MMDataParallel, MMDistributedDataParallel from mmcv.runner import get_dist_info, load_checkpoint def single_gpu_test(model, data_loader, show=False): model.eval() results = [] dataset = data_loader.dataset prog_bar = mmcv.ProgressBar(len(dataset)) for i, data in enumerate(data_loader): with torch.no_grad(): result = model(return_loss=False, rescale=not show, **data) results.append(result) if show: model.module.show_result(data, result, dataset.img_norm_cfg) batch_size = data['img'][0].size(0) for _ in range(batch_size): prog_bar.update() return results cfg.model.pretrained = None cfg.data.test.test_mode = True dataset = [build_dataset(cfg.data.test)] if cfg.data.test.with_reid: dataset.append(build_dataset(cfg.data.query)) data_loader = [ build_dataloader(ds, imgs_per_gpu=1, workers_per_gpu=cfg.data.workers_per_gpu, dist=distributed, shuffle=False) for ds in dataset ] for i in range(cfg.total_epochs, cfg.total_epochs - 4, -1): model = build_detector(cfg.model, train_cfg=None, test_cfg=cfg.test_cfg) ckpt = os.path.join(cfg.work_dir, 'epoch_' + str(i) + '.pth') load_checkpoint(model, ckpt, map_location='cpu') model = MMDataParallel(model, device_ids=[0]) outputs = [single_gpu_test(model, dl) for dl in data_loader] print('\nStarting evaluate {}'.format(ckpt)) result = dataset[0].evaluate(outputs, dataset) with open(os.path.join(cfg.work_dir, "eva_result.txt"), "a") as fid: fid.write(ckpt + '\n') fid.write(result + '\n')
def maintrain(args): cfg = Config.fromfile(args.config) # New add to setup the dataset, no need to change the configuration file cfg.dataset_type = 'CocoDataset' cfg.data.test.type = 'CocoDataset' cfg.data.test.data_root = args.data_root cfg.data.test.ann_file = args.data_root + 'annotations_val20new.json' #'annotations_valallnew.json' cfg.data.test.img_prefix = '' cfg.data.train.type = 'CocoDataset' cfg.data.train.data_root = args.data_root cfg.data.train.ann_file = args.data_root + 'annotations_train20new.json' #'annotations_trainallnew.json' cfg.data.train.img_prefix = '' cfg.data.val.type = 'CocoDataset' cfg.data.val.data_root = args.data_root cfg.data.val.ann_file = args.data_root + 'annotations_val20new.json' #'annotations_valallnew.json' cfg.data.val.img_prefix = '' #batch size=2, workers=0, eta: 1 day, 5:56:54, memory: 5684 cfg.data.samples_per_gpu = 4 #batch size cfg.data.workers_per_gpu = 4 #eta: 1 day, 6:17:04, memory: 10234 # modify num classes of the model in box head cfg.model.roi_head.bbox_head.num_classes = len(args.classes) # 4 # import modules from string list. if cfg.get('custom_imports', None): #not used from mmcv.utils import import_modules_from_strings import_modules_from_strings(**cfg['custom_imports']) # set cudnn_benchmark, benchmark mode is good whenever your input sizes for your network do not vary. This way, cudnn will look for the optimal set of algorithms for that particular configuration (which takes some time). This usually leads to faster runtime. if cfg.get('cudnn_benchmark', False): torch.backends.cudnn.benchmark = True # work_dir is determined in this priority: CLI > segment in file > filename if args.workdir is not None: # update configs according to CLI args if args.work_dir is not None cfg.work_dir = args.workdir elif cfg.get('work_dir', None) is None: # use config filename as default work_dir if cfg.work_dir is None cfg.work_dir = osp.join('./work_dirs', osp.splitext(osp.basename(args.config))[0]) # create work_dir mmcv.mkdir_or_exist(osp.abspath(cfg.work_dir)) # dump config cfg.dump(osp.join(cfg.work_dir, osp.basename(args.config))) # init the logger before other steps timestamp = time.strftime('%Y%m%d_%H%M%S', time.localtime()) log_file = osp.join(cfg.work_dir, f'{timestamp}.log') logger = get_root_logger(log_file=log_file, log_level=cfg.log_level) cfg.load_from = args.checkpoint if args.resumefrom is not None: cfg.resume_from = args.resumefrom if args.gpuids is not None: cfg.gpu_ids = args.gpuids else: cfg.gpu_ids = range(1) if args.gpus is None else range(args.gpus) # init the meta dict to record some important information such as # environment info and seed, which will be logged meta = dict() # log env info env_info_dict = collect_env() env_info = '\n'.join([(f'{k}: {v}') for k, v in env_info_dict.items()]) dash_line = '-' * 60 + '\n' logger.info('Environment info:\n' + dash_line + env_info + '\n' + dash_line) meta['env_info'] = env_info meta['config'] = cfg.pretty_text # log some basic info distributed = False logger.info(f'Distributed training: {distributed}') logger.info(f'Config:\n{cfg.pretty_text}') # set random seeds if args.seed is not None: #not used logger.info(f'Set random seed to {args.seed}, ' f'deterministic: {args.deterministic}') set_random_seed(args.seed, deterministic=args.deterministic) cfg.seed = args.seed meta['seed'] = args.seed meta['exp_name'] = osp.basename(args.config) model = build_detector(cfg.model, train_cfg=cfg.get('train_cfg'), test_cfg=cfg.get('test_cfg')) datasets = [build_dataset(cfg.data.train)] if len(cfg.workflow) == 2: val_dataset = copy.deepcopy(cfg.data.val) val_dataset.pipeline = cfg.data.train.pipeline datasets.append(build_dataset(val_dataset)) if cfg.checkpoint_config is not None: # save mmdet version, config file content and class names in # checkpoints as meta data cfg.checkpoint_config.meta = dict(mmdet_version=__version__ + get_git_hash()[:7], CLASSES=datasets[0].CLASSES) # add an attribute for visualization convenience model.CLASSES = args.classes #datasets[0].CLASSES train_detector(model, datasets, cfg, distributed=distributed, validate=(not args.novalidate), timestamp=timestamp, meta=meta)
def main(): ''' STEP 1 : 预备,读入配置。 ''' # 从命令行中读取输入参数,并记录在命名空间args中。 args = parse_args() # args指定的config file中读取配置,存储在cfg中。 cfg = Config.fromfile(args.config) # set cudnn_benchmark ''' 设置这个 flag 可以让内置的 cuDNN 的 auto-tuner 自动寻找最适合当前配置的高效算法,来达到优化运行效率的问题。 ''' if cfg.get('cudnn_benchmark', False): torch.backends.cudnn.benchmark = True # update configs according to CLI(command line interface) args if args.work_dir is not None: cfg.work_dir = args.work_dir if args.resume_from is not None: cfg.resume_from = args.resume_from cfg.gpus = args.gpus if args.autoscale_lr: # apply the linear scaling rule (https://arxiv.org/abs/1706.02677) cfg.optimizer['lr'] = cfg.optimizer['lr'] * cfg.gpus / 8 # init distributed env first, since logger depends on the dist info. if args.launcher == 'none': distributed = False else: distributed = True init_dist(args.launcher, **cfg.dist_params) # init logger before other steps logger = get_root_logger(cfg.log_level) logger.info('Distributed training: {}'.format(distributed)) # set random seeds if args.seed is not None: logger.info('Set random seed to {}'.format(args.seed)) set_random_seed(args.seed) ''' STEP 2 : 建立模型。实质是去注册,通过调用Registry类。 ''' model = build_detector(cfg.model, train_cfg=cfg.train_cfg, test_cfg=cfg.test_cfg) ''' STEP 3 : 打包整理数据,并训练模型。 ''' datasets = [build_dataset(cfg.data.train)] if len(cfg.workflow) == 2: datasets.append(build_dataset(cfg.data.val)) if cfg.checkpoint_config is not None: # save mmdet version, config file content and class names in checkpoints as meta data. 保存数据的概况。meta data: 'data about data'. cfg.checkpoint_config.meta = dict(mmdet_version=__version__, config=cfg.text, CLASSES=datasets[0].CLASSES) # add an attribute for visualization convenience model.CLASSES = datasets[0].CLASSES # 训练模型 train_detector(model, datasets, cfg, distributed=distributed, validate=args.validate, logger=logger)
def main(): ''' # 1、设定和读取各种配置; :return: ''' args = parse_args() #cfg: configs/*.py文件里的参数 cfg = Config.fromfile(args.config) # set cudnn_benchmark if cfg.get('cudnn_benchmark', False): torch.backends.cudnn.benchmark = True # update configs according to CLI args if args.work_dir is not None: cfg.work_dir = args.work_dir if args.resume_from is not None: cfg.resume_from = args.resume_from if args.gpu_ids is not None: cfg.gpu_ids = args.gpu_ids else: cfg.gpu_ids = range(1) if args.gpus is None else range(args.gpus) if args.autoscale_lr: # apply the linear scaling rule (https://arxiv.org/abs/1706.02677) cfg.optimizer['lr'] = cfg.optimizer['lr'] * len(cfg.gpu_ids) / 8 # init distributed env first, since logger depends on the dist info. if args.launcher == 'none': distributed = False else: distributed = True init_dist(args.launcher, **cfg.dist_params) # create work_dir mmcv.mkdir_or_exist(osp.abspath(cfg.work_dir)) # init the logger before other steps timestamp = time.strftime('%Y%m%d_%H%M%S', time.localtime()) log_file = osp.join(cfg.work_dir, '{}.log'.format(timestamp)) logger = get_root_logger(log_file=log_file, log_level=cfg.log_level) # init the meta dict to record some important information such as # environment info and seed, which will be logged meta = dict() # log env info env_info_dict = collect_env() env_info = '\n'.join([('{}: {}'.format(k, v)) for k, v in env_info_dict.items()]) dash_line = '-' * 60 + '\n' logger.info('Environment info:\n' + dash_line + env_info + '\n' + dash_line) meta['env_info'] = env_info # log some basic info logger.info('Distributed training: {}'.format(distributed)) logger.info('Config:\n{}'.format(cfg.text)) # set random seeds if args.seed is not None: logger.info('Set random seed to {}, deterministic: {}'.format( args.seed, args.deterministic)) set_random_seed(args.seed, deterministic=args.deterministic) cfg.seed = args.seed meta['seed'] = args.seed ''' # 2、创建模型 第一个参数cfg.model模型配置里面必须要有一个种类type,包括经典的算法如Faster RCNN, MaskRCNN等 其次,还包含几个部分,如backbone, neck, head backbone有深度,stage等信息,如resnet50对应着3,4,6,3四个重复stages neck一般FPN(feature pyramid network),需要指定num_outs几个输出之类的信息(之后会看到) head 就是具体到上层rpn_head, shared_head, bbox_head之类的 如果不清楚我们可以去某个config里面验证一下 返回的是一个类的对象,详见下面的build函数 :return: ''' model = build_detector(cfg.model, train_cfg=cfg.train_cfg, test_cfg=cfg.test_cfg) ''' # 3、创建数据集(使用configs下的py文件里的data字典的train字段) :return: ''' datasets = [build_dataset(cfg.data.train)] if len(cfg.workflow) == 2: #是否添加验证集 val_dataset = copy.deepcopy(cfg.data.val) val_dataset.pipeline = cfg.data.train.pipeline datasets.append(build_dataset(val_dataset)) if cfg.checkpoint_config is not None: # save mmdet version, config file content and class names in # checkpoints as meta data cfg.checkpoint_config.meta = dict(mmdet_version=__version__, config=cfg.text, CLASSES=datasets[0].CLASSES) # add an attribute for visualization convenience model.CLASSES = datasets[0].CLASSES #现在的问题cfg不知道怎么搞 # cfg: configs/*.py文件里的参数 ''' # 4、将模型,数据集和配置传进训练函数 :return: ''' train_detector(model, datasets, cfg, distributed=distributed, validate=args.validate, timestamp=timestamp, meta=meta)
def main(): args = parse_args() cfg = Config.fromfile(args.config) if args.cfg_options is not None: cfg.merge_from_dict(args.cfg_options) # import modules from string list. if cfg.get('custom_imports', None): from mmcv.utils import import_modules_from_strings import_modules_from_strings(**cfg['custom_imports']) # import modules from plguin/xx, registry will be updated if hasattr(cfg, 'plugin') & cfg.plugin: import importlib _module_dir = os.path.dirname(args.config) _module_dir = _module_dir.split('/') _module_path = _module_dir[0] for m in _module_dir[1:]: _module_path = _module_path + '.' + m print(_module_path) plg_lib = importlib.import_module(_module_path) # set cudnn_benchmark if cfg.get('cudnn_benchmark', False): torch.backends.cudnn.benchmark = True # work_dir is determined in this priority: CLI > segment in file > filename if args.work_dir is not None: # update configs according to CLI args if args.work_dir is not None cfg.work_dir = args.work_dir elif cfg.get('work_dir', None) is None: # use config filename as default work_dir if cfg.work_dir is None cfg.work_dir = osp.join('./work_dirs', osp.splitext(osp.basename(args.config))[0]) if args.resume_from is not None: cfg.resume_from = args.resume_from if args.gpu_ids is not None: cfg.gpu_ids = args.gpu_ids else: cfg.gpu_ids = range(1) if args.gpus is None else range(args.gpus) if args.autoscale_lr: # apply the linear scaling rule (https://arxiv.org/abs/1706.02677) cfg.optimizer['lr'] = cfg.optimizer['lr'] * len(cfg.gpu_ids) / 8 # init distributed env first, since logger depends on the dist info. if args.launcher == 'none': distributed = False else: distributed = True init_dist(args.launcher, **cfg.dist_params) # re-set gpu_ids with distributed training mode _, world_size = get_dist_info() cfg.gpu_ids = range(world_size) # create work_dir mmcv.mkdir_or_exist(osp.abspath(cfg.work_dir)) # dump config cfg.dump(osp.join(cfg.work_dir, osp.basename(args.config))) # init the logger before other steps timestamp = time.strftime('%Y%m%d_%H%M%S', time.localtime()) log_file = osp.join(cfg.work_dir, f'{timestamp}.log') logger = get_root_logger(log_file=log_file, log_level=cfg.log_level) # add a logging filter logging_filter = logging.Filter('mmdet') logging_filter.filter = lambda record: record.find('mmdet') != -1 # init the meta dict to record some important information such as # environment info and seed, which will be logged meta = dict() # log env info env_info_dict = collect_env() env_info = '\n'.join([(f'{k}: {v}') for k, v in env_info_dict.items()]) dash_line = '-' * 60 + '\n' logger.info('Environment info:\n' + dash_line + env_info + '\n' + dash_line) meta['env_info'] = env_info meta['config'] = cfg.pretty_text # log some basic info logger.info(f'Distributed training: {distributed}') logger.info(f'Config:\n{cfg.pretty_text}') # set random seeds if args.seed is not None: logger.info(f'Set random seed to {args.seed}, ' f'deterministic: {args.deterministic}') set_random_seed(args.seed, deterministic=args.deterministic) cfg.seed = args.seed meta['seed'] = args.seed meta['exp_name'] = osp.basename(args.config) model = build_detector(cfg.model, train_cfg=cfg.get('train_cfg'), test_cfg=cfg.get('test_cfg')) logger.info(f'Model:\n{model}') datasets = [build_dataset(cfg.data.train)] if len(cfg.workflow) == 2: val_dataset = copy.deepcopy(cfg.data.val) # in case we use a dataset wrapper if 'dataset' in cfg.data.train: val_dataset.pipeline = cfg.data.train.dataset.pipeline else: val_dataset.pipeline = cfg.data.train.pipeline # set test_mode=False here in deep copied config # which do not affect AP/AR calculation later # refer to https://mmdetection3d.readthedocs.io/en/latest/tutorials/customize_runtime.html#customize-workflow # noqa val_dataset.test_mode = False datasets.append(build_dataset(val_dataset)) if cfg.checkpoint_config is not None: # save mmdet version, config file content and class names in # checkpoints as meta data cfg.checkpoint_config.meta = dict(mmdet_version=__version__, config=cfg.pretty_text, CLASSES=datasets[0].CLASSES) # add an attribute for visualization convenience model.CLASSES = datasets[0].CLASSES train_detector(model, datasets, cfg, distributed=distributed, validate=(not args.no_validate), timestamp=timestamp, meta=meta)
def Train(self): self.setup() # create work_dir mmcv.mkdir_or_exist( osp.abspath(self.system_dict["local"]["cfg"].work_dir)) # dump config self.system_dict["local"]["cfg"].dump( osp.join(self.system_dict["local"]["cfg"].work_dir, osp.basename(self.system_dict["params"]["config"]))) # init the logger before other steps timestamp = time.strftime('%Y%m%d_%H%M%S', time.localtime()) log_file = osp.join(self.system_dict["local"]["cfg"].work_dir, f'{timestamp}.log') logger = get_root_logger( log_file=log_file, log_level=self.system_dict["local"]["cfg"].log_level) # init the meta dict to record some important information such as # environment info and seed, which will be logged meta = dict() # log env info env_info_dict = collect_env() env_info = '\n'.join([(f'{k}: {v}') for k, v in env_info_dict.items()]) dash_line = '-' * 60 + '\n' logger.info('Environment info:\n' + dash_line + env_info + '\n' + dash_line) meta['env_info'] = env_info # log some basic info logger.info( f'Distributed training: {self.system_dict["local"]["distributed"]}' ) logger.info(f'Config:\n{self.system_dict["local"]["cfg"].pretty_text}') # set random seeds if self.system_dict["params"]["seed"] is not None: logger.info( f'Set random seed to {self.system_dict["params"]["seed"]}, ' f'deterministic: {args.deterministic}') set_random_seed( self.system_dict["params"]["seed"], deterministic=self.system_dict["params"]["deterministic"]) self.system_dict["local"]["cfg"].seed = self.system_dict["params"][ "seed"] meta['seed'] = self.system_dict["params"]["seed"] model = build_detector( self.system_dict["local"]["cfg"].model, train_cfg=self.system_dict["local"]["cfg"].train_cfg, test_cfg=self.system_dict["local"]["cfg"].test_cfg) datasets = [build_dataset(self.system_dict["local"]["cfg"].data.train)] if len(self.system_dict["local"]["cfg"].workflow) == 2: val_dataset = copy.deepcopy( self.system_dict["local"]["cfg"].data.val) val_dataset.pipeline = self.system_dict["local"][ "cfg"].data.train.pipeline datasets.append(build_dataset(val_dataset)) if self.system_dict["local"]["cfg"].checkpoint_config is not None: # save mmdet version, config file content and class names in # checkpoints as meta data self.system_dict["local"]["cfg"].checkpoint_config.meta = dict( mmdet_version=__version__ + get_git_hash()[:7], config=self.system_dict["local"]["cfg"].pretty_text, CLASSES=datasets[0].CLASSES) # add an attribute for visualization convenience model.CLASSES = datasets[0].CLASSES print("Classes to be trained: {}".format(model.CLASSES)) train_detector( model, datasets, self.system_dict["local"]["cfg"], distributed=self.system_dict["local"]["distributed"], validate=(not self.system_dict["params"]["no_validate"]), timestamp=timestamp, meta=meta)