def _eval_predictions(self, tasks, predictions): """ Evaluate predictions on the given tasks. Fill self._results with the metrics of the tasks. """ self._logger.info("Preparing results for COCO format ...") coco_results = list( itertools.chain(*[x["instances"] for x in predictions])) # unmap the category ids for COCO if hasattr(self._metadata, "thing_dataset_id_to_contiguous_id"): reverse_id_mapping = { v: k for k, v in self._metadata.thing_dataset_id_to_contiguous_id.items() } for result in coco_results: result["category_id"] = reverse_id_mapping[ result["category_id"]] if self._output_dir: file_path = os.path.join(self._output_dir, "coco_instances_results.json") self._logger.info("Saving results to {}".format(file_path)) with PathManager.open(file_path, "w") as f: f.write(json.dumps(coco_results)) f.flush() if not self._do_evaluation: self._logger.info("Annotations are not available for evaluation.") return self._logger.info("Evaluating predictions ...") for task in sorted(tasks): assert task == "bbox", "Task {} is not supported".format(task) coco_eval = ( self._evaluate_predictions_on_coco( self._coco_api, coco_results) if len(coco_results) > 0 else None # cocoapi does not handle empty results very well ) res = self._derive_coco_results( coco_eval, task, class_names=self._metadata.get("thing_classes")) self._results[task] = res
def find_relative_file(original_file, relative_import_path, level): cur_file = os.path.dirname(original_file) for _ in range(level - 1): cur_file = os.path.dirname(cur_file) cur_name = relative_import_path.lstrip(".") for part in cur_name.split("."): cur_file = os.path.join(cur_file, part) # NOTE: directory import is not handled. Because then it's unclear # if such import should produce python module or DictConfig. This can # be discussed further if needed. if not cur_file.endswith(".py"): cur_file += ".py" if not PathManager.isfile(cur_file): raise ImportError( f"Cannot import name {relative_import_path} from " f"{original_file}: {cur_file} has to exist.") return cur_file
def execute_on_entry(cls: type, entry: Dict[str, Any], context: Dict[str, Any]): import cv2 import numpy as np image_fpath = PathManager.get_local_path(entry["file_name"]) image = cv2.imread(image_fpath, cv2.IMREAD_GRAYSCALE) image = np.tile(image[:, :, np.newaxis], [1, 1, 3]) datas = cls._extract_data_for_visualizers_from_entry( context["vis_specs"], entry) visualizer = context["visualizer"] image_vis = visualizer.visualize(image, datas) entry_idx = context["entry_idx"] + 1 out_fname = cls._get_out_fname(entry_idx, context["out_fname"]) cv2.imwrite(out_fname, image_vis) logger.info(f"Output saved to {out_fname}") context["entry_idx"] += 1
def inject_gan_datasets(cfg): if cfg.D2GO_DATA.DATASETS.GAN_INJECTION.ENABLE: name = cfg.D2GO_DATA.DATASETS.GAN_INJECTION.NAME cfg.merge_from_list( ["DATASETS.TRAIN", [name], "DATASETS.TEST", [name]]) json_path = cfg.D2GO_DATA.DATASETS.GAN_INJECTION.JSON_PATH assert PathManager.isfile(json_path), ( "{} is not valid!".format(json_path)) input_src_path = cfg.D2GO_DATA.DATASETS.GAN_INJECTION.INPUT_SRC_DIR assert PathManager.isfile(input_src_path), ( "{} is not valid!".format(input_src_path)) input_folder = "/tmp/{}/input".format(name) gt_src_path = cfg.D2GO_DATA.DATASETS.GAN_INJECTION.GT_SRC_DIR if PathManager.isfile(gt_src_path): gt_folder = "/tmp/{}/gt".format(name) else: gt_src_path = None gt_folder = None mask_src_path = cfg.D2GO_DATA.DATASETS.GAN_INJECTION.MASK_SRC_DIR if PathManager.isfile(mask_src_path): mask_folder = "/tmp/{}/mask".format(name) else: mask_src_path = None mask_folder = None real_src_path = cfg.D2GO_DATA.DATASETS.GAN_INJECTION.REAL_SRC_DIR if PathManager.isfile(real_src_path): real_folder = "/tmp/{}/mask".format(name) real_json_path = cfg.D2GO_DATA.DATASETS.GAN_INJECTION.REAL_JSON_PATH assert PathManager.isfile(real_json_path), ( "{} is not valid!".format(real_json_path)) else: real_src_path = None real_folder = None real_json_path = None register_folder_dataset( name, json_path, input_folder, gt_folder, mask_folder, input_src_path, gt_src_path, mask_src_path, real_json_path, real_folder, real_src_path, )
def evaluate(self): """ Returns: dict: has a key "segm", whose value is a dict of "AP" and "AP50". """ comm.synchronize() if comm.get_rank() > 0: return import cityscapesscripts.evaluation.evalInstanceLevelSemanticLabeling as cityscapes_eval self._logger.info("Evaluating results under {} ...".format( self._temp_dir)) # set some global states in cityscapes evaluation API, before evaluating cityscapes_eval.args.predictionPath = os.path.abspath(self._temp_dir) cityscapes_eval.args.predictionWalk = None cityscapes_eval.args.JSONOutput = False cityscapes_eval.args.colorized = False cityscapes_eval.args.gtInstancesFile = os.path.join( self._temp_dir, "gtInstances.json") # These lines are adopted from # https://github.com/mcordts/cityscapesScripts/blob/master/cityscapesscripts/evaluation/evalInstanceLevelSemanticLabeling.py # noqa gt_dir = PathManager.get_local_path(self._metadata.gt_dir) groundTruthImgList = glob.glob( os.path.join(gt_dir, "*", "*_gtFine_instanceIds.png")) assert len( groundTruthImgList ), "Cannot find any ground truth images to use for evaluation. Searched for: {}".format( cityscapes_eval.args.groundTruthSearch) predictionImgList = [] for gt in groundTruthImgList: predictionImgList.append( cityscapes_eval.getPrediction(gt, cityscapes_eval.args)) results = cityscapes_eval.evaluateImgLists( predictionImgList, groundTruthImgList, cityscapes_eval.args)["averages"] ret = OrderedDict() ret["segm"] = { "AP": results["allAp"] * 100, "AP50": results["allAp50%"] * 100 } self._working_dir.cleanup() return ret
def load_lvis_json(annotations_json_file: str, image_root: str, dataset_name: str): """ Loads a JSON file with annotations in LVIS instances format. Replaces `detectron2.data.datasets.coco.load_lvis_json` to handle metadata in a more flexible way. Postpones category mapping to a later stage to be able to combine several datasets with different (but coherent) sets of categories. Args: annotations_json_file: str Path to the JSON file with annotations in COCO instances format. image_root: str directory that contains all the images dataset_name: str the name that identifies a dataset, e.g. "densepose_coco_2014_train" extra_annotation_keys: Optional[List[str]] If provided, these keys are used to extract additional data from the annotations. """ lvis_api = _load_lvis_annotations(PathManager.get_local_path(annotations_json_file)) _add_categories_metadata(dataset_name) # sort indices for reproducible results img_ids = sorted(lvis_api.imgs.keys()) # imgs is a list of dicts, each looks something like: # {'license': 4, # 'url': 'http://farm6.staticflickr.com/5454/9413846304_881d5e5c3b_z.jpg', # 'file_name': 'COCO_val2014_000000001268.jpg', # 'height': 427, # 'width': 640, # 'date_captured': '2013-11-17 05:57:24', # 'id': 1268} imgs = lvis_api.load_imgs(img_ids) logger = logging.getLogger(__name__) logger.info("Loaded {} images in LVIS format from {}".format(len(imgs), annotations_json_file)) # anns is a list[list[dict]], where each dict is an annotation # record for an object. The inner list enumerates the objects in an image # and the outer list enumerates over images. anns = [lvis_api.img_ann_map[img_id] for img_id in img_ids] _verify_annotations_have_unique_ids(annotations_json_file, anns) dataset_records = _combine_images_with_annotations(dataset_name, image_root, imgs, anns) return dataset_records
def _eval_box_proposals(self, predictions): """ Evaluate the box proposals in predictions. Fill self._results with the metrics for "box_proposals" task. """ if self._output_dir: # Saving generated box proposals to file. # Predicted box_proposals are in XYXY_ABS mode. bbox_mode = BoxMode.XYXY_ABS.value ids, boxes, objectness_logits = [], [], [] for prediction in predictions: ids.append(prediction["image_id"]) boxes.append( prediction["proposals"].proposal_boxes.tensor.numpy()) objectness_logits.append( prediction["proposals"].objectness_logits.numpy()) proposal_data = { "boxes": boxes, "objectness_logits": objectness_logits, "ids": ids, "bbox_mode": bbox_mode, } with PathManager.open( os.path.join(self._output_dir, "box_proposals.pkl"), "wb") as f: pickle.dump(proposal_data, f) if not self._do_evaluation: self._logger.info("Annotations are not available for evaluation.") return self._logger.info("Evaluating bbox proposals ...") res = {} areas = {"all": "", "small": "s", "medium": "m", "large": "l"} for limit in [100, 1000]: for area, suffix in areas.items(): stats = _evaluate_box_proposals(predictions, self._coco_api, area=area, limit=limit) key = "AR{}@{:d}".format(suffix, limit) res[key] = float(stats["ar"].item() * 100) self._logger.info("Proposal metrics: \n" + create_small_table(res)) self._results["box_proposals"] = res
def read_sem_seg_file_with_prefetch(file_name: str, prefetched=None): """ Segmentation mask annotations can be stored as: .PNG files .npy uncompressed numpy files """ assert file_name.endswith(".png") or file_name.endswith(".npy") sem_seg_type = file_name[-len(".---"):] if sem_seg_type == ".png": return read_image_with_prefetch(file_name, format="L", prefetched=prefetched) elif sem_seg_type == ".npy": if prefetched is None: with PathManager.open(file_name, "rb") as f: return np.load(f) else: return prefetched.numpy()
def export_caffe2_tracing(cfg, torch_model, inputs): tracer = Caffe2Tracer(cfg, torch_model, inputs) if args.format == "caffe2": caffe2_model = tracer.export_caffe2() caffe2_model.save_protobuf(args.output) # draw the caffe2 graph caffe2_model.save_graph(os.path.join(args.output, "model.svg"), inputs=inputs) return caffe2_model elif args.format == "onnx": onnx_model = tracer.export_onnx() onnx.save(onnx_model, os.path.join(args.output, "model.onnx")) elif args.format == "torchscript": ts_model = tracer.export_torchscript() with PathManager.open(os.path.join(args.output, "model.ts"), "wb") as f: torch.jit.save(ts_model, f) dump_torchscript_IR(ts_model, args.output)
def get_path_pairs(img_folder, mask_folder): img_paths = [] mask_paths = [] print("Before listing", img_folder) filenames = PathManager.ls(img_folder) for filename in filenames: print("found: ", filename) basename, _ = os.path.splitext(filename) if filename.endswith(".jpg"): imgpath = os.path.join(img_folder, filename) maskname = basename + ".png" maskpath = os.path.join(mask_folder, maskname) img_paths.append(imgpath) mask_paths.append(maskpath) # if PathManager.isfile(maskpath): # else: # print('cannot find the mask:', maskpath) return img_paths, mask_paths
def __init__(self, dataset_name, distributed, output_dir=None, embedder=None): self._embedder = embedder self._distributed = distributed self._output_dir = output_dir self._cpu_device = torch.device("cpu") self._logger = logging.getLogger(__name__) self._metadata = MetadataCatalog.get(dataset_name) self._min_threshold = 0.5 json_file = PathManager.get_local_path(self._metadata.json_file) with contextlib.redirect_stdout(io.StringIO()): self._coco_api = COCO(json_file) maybe_filter_and_map_categories_cocoapi(dataset_name, self._coco_api)
def __init__(self, dataset_name, distributed, output_dir=None, embedder=None): self._embedder = embedder self._distributed = distributed self._output_dir = output_dir self._cpu_device = torch.device("cpu") self._logger = logging.getLogger(__name__) self._metadata = MetadataCatalog.get(dataset_name) self._min_threshold = 0.5 json_file = PathManager.get_local_path(self._metadata.json_file) with contextlib.redirect_stdout(io.StringIO()): self._coco_api = COCO(json_file) self.mesh_name = self._coco_api.anns[list( self._coco_api.anns.keys())[0]].get("ref_model", "smpl_27554")
def __init__(self, dataset_name): """ Args: dataset_name (str): name of the dataset, e.g., "voc_2007_test" """ self._dataset_name = dataset_name meta = MetadataCatalog.get(dataset_name) # Too many tiny files, download all to local for speed. annotation_dir_local = PathManager.get_local_path( os.path.join(meta.dirname, "Annotations/") ) self._anno_file_template = os.path.join(annotation_dir_local, "{}.xml") self._image_set_path = os.path.join(meta.dirname, "ImageSets", "Main", meta.split + ".txt") self._class_names = meta.thing_classes assert meta.year in [2007, 2012], meta.year self._is_2007 = meta.year == 2007 self._cpu_device = torch.device("cpu") self._logger = logging.getLogger(__name__)
def read_image(file_name, format=None): """ Read an image into the given format. Will apply rotation and flipping if the image has such exif information. Args: file_name (str): image file path format (str): one of the supported image modes in PIL, or "BGR" or "YUV-BT.601". Returns: image (np.ndarray): an HWC image in the given format, which is 0-255, uint8 for supported image modes in PIL or "BGR"; float (0-1 for Y) for YUV-BT.601. """ with PathManager.open(file_name, "rb") as f: image = Image.open(f) # work around this bug: https://github.com/python-pillow/Pillow/issues/3973 image = _apply_exif_orientation(image) return convert_PIL_to_numpy(image, format)
def after_step(self): if len(self.prefixes) == 0: return if (self.trainer.iter + 1) % self._period == 0 or ( self.trainer.iter >= self.trainer.max_iter - 1): # Get latest ckpt file name latest_ckpt_path = os.path.join(self._output_dir, "last_checkpoint") assert os.path.exists(latest_ckpt_path), ( f"File: {latest_ckpt_path} not found!") with open(latest_ckpt_path) as fp: latest_ckpt = fp.read().strip() # Dump all log files # Some log files may have been uploaded before, but we need to update them for dir_path, dir_names, file_names in os.walk(self._output_dir): for file_name in sorted(file_names): local = os.path.join(dir_path, file_name) if re.match(r"model_\d*\.pth", file_name) and file_name != latest_ckpt: self.logger.info( "Remove local log file: {}.".format(local)) os.remove(local) continue for prefix, bucket in zip(self.prefixes, self.buckets): remote = os.path.join( prefix, "detectron2", dir_path.split("/detectron2/")[1], file_name) upload_result = PathManager.upload(local, remote, bucket=bucket) if upload_result: self.logger.info( "Dump output file from {} to {}.".format( local, remote)) else: self.logger.warning( "Failed to dump output file from {} to {}.". format(local, remote))
def export_scripting(torch_model): assert TORCH_VERSION >= (1, 8) fields = { "proposal_boxes": Boxes, "objectness_logits": Tensor, "pred_boxes": Boxes, "scores": Tensor, "pred_classes": Tensor, "pred_masks": Tensor, "pred_keypoints": torch.Tensor, "pred_keypoint_heatmaps": torch.Tensor, } assert args.format == "torchscript", "Scripting only supports torchscript format." ts_model = export_torchscript_with_instances(torch_model, fields) with PathManager.open(os.path.join(args.output, "model.ts"), "wb") as f: torch.jit.save(ts_model, f) dump_torchscript_IR(ts_model, args.output) # TODO inference in Python now missing postprocessing glue code return None
def merge_from_file(self, cfg_filename: str, allow_unsafe: bool = True) -> None: assert PathManager.isfile( cfg_filename), f"Config file '{cfg_filename}' does not exist!" loaded_cfg = self.load_yaml_with_base(cfg_filename, allow_unsafe=allow_unsafe) loaded_cfg = type(self)(loaded_cfg) # defaults.py needs to import CfgNode from .defaults import _C latest_ver = _C.VERSION assert ( latest_ver == self.VERSION ), "CfgNode.merge_from_file is only allowed on a config object of latest version!" logger = logging.getLogger(__name__) loaded_ver = loaded_cfg.get("VERSION", None) if loaded_ver is None: from .compat import guess_version loaded_ver = guess_version(loaded_cfg, cfg_filename) assert loaded_ver <= self.VERSION, "Cannot merge a v{} config into a v{} config.".format( loaded_ver, self.VERSION) if loaded_ver == self.VERSION: self.merge_from_other_cfg(loaded_cfg) else: # compat.py needs to import CfgNode from .compat import upgrade_config, downgrade_config logger.warning( "Loading an old v{} config file '{}' by automatically upgrading to v{}. " "See docs/CHANGELOG.md for instructions to update your files.". format(loaded_ver, cfg_filename, self.VERSION)) # To convert, first obtain a full config at an old version old_self = downgrade_config(self, to_version=loaded_ver) old_self.merge_from_other_cfg(loaded_cfg) new_config = upgrade_config(old_self) self.clear() self.update(new_config)
def export_scripting(torch_model): assert TORCH_VERSION >= (1, 8) fields = { "proposal_boxes": Boxes, "objectness_logits": Tensor, "pred_boxes": Boxes, "scores": Tensor, "pred_classes": Tensor, "pred_masks": Tensor, "pred_keypoints": torch.Tensor, "pred_keypoint_heatmaps": torch.Tensor, } assert args.format == "torchscript", "Scripting only supports torchscript format." class ScriptableAdapterBase(nn.Module): # Use this adapter to workaround https://github.com/pytorch/pytorch/issues/46944 # by not retuning instances but dicts. Otherwise the exported model is not deployable def __init__(self): super().__init__() self.model = torch_model self.eval() if isinstance(torch_model, GeneralizedRCNN): class ScriptableAdapter(ScriptableAdapterBase): def forward(self, inputs: Tuple[Dict[str, torch.Tensor]]) -> List[Dict[str, Tensor]]: instances = self.model.inference(inputs, do_postprocess=False) return [i.get_fields() for i in instances] else: class ScriptableAdapter(ScriptableAdapterBase): def forward(self, inputs: Tuple[Dict[str, torch.Tensor]]) -> List[Dict[str, Tensor]]: instances = self.model(inputs) return [i.get_fields() for i in instances] ts_model = scripting_with_instances(ScriptableAdapter(), fields) with PathManager.open(os.path.join(args.output, "model.ts"), "wb") as f: torch.jit.save(ts_model, f) dump_torchscript_IR(ts_model, args.output) # TODO inference in Python now missing postprocessing glue code return None
def evaluate(self): comm.synchronize() if comm.get_rank() > 0: return # Load the Cityscapes eval script *after* setting the required env var, # since the script reads CITYSCAPES_DATASET into global variables at load time. import cityscapesscripts.evaluation.evalPixelLevelSemanticLabeling as cityscapes_eval self._logger.info("Evaluating results under {} ...".format( self._temp_dir)) # set some global states in cityscapes evaluation API, before evaluating cityscapes_eval.args.predictionPath = os.path.abspath(self._temp_dir) cityscapes_eval.args.predictionWalk = None cityscapes_eval.args.JSONOutput = False cityscapes_eval.args.colorized = False # These lines are adopted from # https://github.com/mcordts/cityscapesScripts/blob/master/cityscapesscripts/evaluation/evalPixelLevelSemanticLabeling.py # noqa gt_dir = PathManager.get_local_path(self._metadata.gt_dir) groundTruthImgList = glob.glob( os.path.join(gt_dir, "*", "*_gtFine_labelIds.png")) assert len( groundTruthImgList ), "Cannot find any ground truth images to use for evaluation. Searched for: {}".format( cityscapes_eval.args.groundTruthSearch) predictionImgList = [] for gt in groundTruthImgList: predictionImgList.append( cityscapes_eval.getPrediction(cityscapes_eval.args, gt)) results = cityscapes_eval.evaluateImgLists(predictionImgList, groundTruthImgList, cityscapes_eval.args) ret = OrderedDict() ret["sem_seg"] = { "IoU": 100.0 * results["averageScoreClasses"], "iIoU": 100.0 * results["averageScoreInstClasses"], "IoU_sup": 100.0 * results["averageScoreCategories"], "iIoU_sup": 100.0 * results["averageScoreInstCategories"], } self._working_dir.cleanup() return ret
def process_predictions(frame, predictions): with PathManager.open("instances_predictions.pth", "a") as f: torch.save(predictions, f) frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) if "panoptic_seg" in predictions: panoptic_seg, segments_info = predictions["panoptic_seg"] vis_frame = video_visualizer.draw_panoptic_seg_predictions( frame, panoptic_seg.to(self.cpu_device), segments_info) elif "instances" in predictions: predictions = predictions["instances"].to(self.cpu_device) vis_frame = video_visualizer.draw_instance_predictions( frame, predictions) elif "sem_seg" in predictions: vis_frame = video_visualizer.draw_sem_seg( frame, predictions["sem_seg"].argmax(dim=0).to(self.cpu_device)) # Converts Matplotlib RGB format to OpenCV BGR format vis_frame = cv2.cvtColor(vis_frame.get_image(), cv2.COLOR_RGB2BGR) return vis_frame
def get_sample_coco_image(tensor=True): """ Args: tensor (bool): if True, returns 3xHxW tensor. else, returns a HxWx3 numpy array. Returns: an image, in BGR color. """ try: file_name = DatasetCatalog.get("coco_2017_val_100")[0]["file_name"] if not PathManager.exists(file_name): raise FileNotFoundError() except IOError: # for public CI to run file_name = "http://images.cocodataset.org/train2017/000000000009.jpg" ret = read_image(file_name, format="BGR") if tensor: ret = torch.from_numpy(np.ascontiguousarray(ret.transpose(2, 0, 1))) return ret
def _load_lvis_annotations(json_file: str): """ Load COCO annotations from a JSON file Args: json_file: str Path to the file to load annotations from Returns: Instance of `pycocotools.coco.COCO` that provides access to annotations data """ from lvis import LVIS json_file = PathManager.get_local_path(json_file) logger = logging.getLogger(__name__) timer = Timer() lvis_api = LVIS(json_file) if timer.seconds() > 1: logger.info("Loading {} takes {:.2f} seconds.".format(json_file, timer.seconds())) return lvis_api
def _load_file(self, filename): if filename.endswith(".pkl"): with PathManager.open(filename, "rb") as f: data = pickle.load(f, encoding="latin1") if "model" in data and "__author__" in data: # file is in Detectron2 model zoo format self.logger.info("Reading a file from '{}'".format(data["__author__"])) return data else: # assume file is from Caffe2 / Detectron1 model zoo if "blobs" in data: # Detection models have "blobs", but ImageNet models don't data = data["blobs"] data = {k: v for k, v in data.items() if not k.endswith("_momentum")} return {"model": data, "__author__": "Caffe2", "matching_heuristics": True} loaded = super()._load_file(filename) # load native pth checkpoint if "model" not in loaded: loaded = {"model": loaded} return loaded
def main( cfg: CfgNode, output_dir: str, task_cls: Type[GeneralizedRCNNTask] = GeneralizedRCNNTask, eval_only: bool = False, num_machines: int = 1, num_processes: int = 1, ) -> TrainOutput: """Main function for launching a training with lightning trainer Args: cfg: D2go config node num_machines: Number of nodes used for distributed training num_processes: Number of processes on each node. eval_only: True if run evaluation only. """ # FIXME: make comm.get_world_size() work properly. setup_after_launch(cfg, output_dir, _scale_world_size=False) auto_scale_world_size(cfg, new_world_size=num_machines * num_processes) task = task_cls.from_config(cfg, eval_only) trainer_params = get_trainer_params(cfg, num_machines, num_processes) last_checkpoint = os.path.join(cfg.OUTPUT_DIR, "last.ckpt") if PathManager.exists(last_checkpoint): # resume training from checkpoint trainer_params["resume_from_checkpoint"] = last_checkpoint logger.info(f"Resuming training from checkpoint: {last_checkpoint}.") trainer = pl.Trainer(**trainer_params) model_configs = None if eval_only: do_test(trainer, task) else: model_configs = do_train(cfg, trainer, task) return TrainOutput( output_dir=cfg.OUTPUT_DIR, tensorboard_log_dir=trainer_params["logger"].log_dir, accuracy=task.eval_res, model_configs=model_configs, )
def parse_rec(filename): """Parse a PASCAL VOC xml file.""" with PathManager.open(filename) as f: tree = ET.parse(f) objects = [] for obj in tree.findall("object"): obj_struct = {} obj_struct["name"] = obj.find("name").text obj_struct["pose"] = obj.find("pose").text obj_struct["truncated"] = int(obj.find("truncated").text) obj_struct["difficult"] = int(obj.find("difficult").text) bbox = obj.find("bndbox") obj_struct["bbox"] = [ int(bbox.find("xmin").text), int(bbox.find("ymin").text), int(bbox.find("xmax").text), int(bbox.find("ymax").text), ] objects.append(obj_struct) return objects
def __init__(self, dataset_name, tasks=None, distributed=True, output_dir=None): """ Args: dataset_name (str): name of the dataset to be evaluated. It must have the following corresponding metadata: "json_file": the path to the LVIS format annotation tasks (tuple[str]): tasks that can be evaluated under the given configuration. A task is one of "bbox", "segm". By default, will infer this automatically from predictions. distributed (True): if True, will collect results from all ranks for evaluation. Otherwise, will evaluate the results in the current process. output_dir (str): optional, an output directory to dump results. """ from lvis import LVIS self._logger = logging.getLogger(__name__) if tasks is not None and isinstance(tasks, CfgNode): self._logger.warn( "COCO Evaluator instantiated using config, this is deprecated behavior." " Please pass in explicit arguments instead.") self._tasks = None # Infering it from predictions should be better else: self._tasks = tasks self._distributed = distributed self._output_dir = output_dir self._cpu_device = torch.device("cpu") self._metadata = MetadataCatalog.get(dataset_name) json_file = PathManager.get_local_path(self._metadata.json_file) self._lvis_api = LVIS(json_file) # Test set json files do not contain annotations (evaluation must be # performed using the LVIS evaluation server). self._do_evaluation = len(self._lvis_api.get_ann_ids()) > 0
def new_import(name, globals=None, locals=None, fromlist=(), level=0): if ( # Only deal with relative imports inside config files level != 0 and globals is not None and (globals.get("__package__", "") or "").startswith(_CFG_PACKAGE_NAME) ): cur_file = find_relative_file(globals["__file__"], name, level) _validate_py_syntax(cur_file) spec = importlib.machinery.ModuleSpec( _random_package_name(cur_file), None, origin=cur_file ) module = importlib.util.module_from_spec(spec) module.__file__ = cur_file with PathManager.open(cur_file) as f: content = f.read() exec(compile(content, cur_file, "exec"), module.__dict__) for name in fromlist: # turn imported dict into DictConfig automatically val = _cast_to_config(module.__dict__[name]) module.__dict__[name] = val return module return old_import(name, globals, locals, fromlist=fromlist, level=level)
def read_keyframe_helper_data(fpath: str): """ Read keyframe data from a file in CSV format: the header should contain "video_id" and "keyframes" fields. Value specifications are: video_id: int keyframes: list(int) Example of contents: video_id,keyframes 2,"[1,11,21,31,41,51,61,71,81]" Args: fpath (str): File containing keyframe data Return: video_id_to_keyframes (dict: int -> list(int)): for a given video ID it contains a list of keyframes for that video """ video_id_to_keyframes = {} try: with PathManager.open(fpath, "r") as io: csv_reader = csv.reader(io) # pyre-ignore[6] header = next(csv_reader) video_id_idx = header.index("video_id") keyframes_idx = header.index("keyframes") for row in csv_reader: video_id = int(row[video_id_idx]) assert ( video_id not in video_id_to_keyframes ), f"Duplicate keyframes entry for video {fpath}" video_id_to_keyframes[video_id] = ( [int(v) for v in row[keyframes_idx][1:-1].split(",")] if len(row[keyframes_idx]) > 2 else [] ) except Exception as e: logger = logging.getLogger(__name__) logger.warning(f"Error reading keyframe helper data from {fpath}: {e}") return video_id_to_keyframes
def prepare_for_launch(args): """ Load config, figure out working directory, create runner. - when args.config_file is empty, returned cfg will be the default one - returned output_dir will always be non empty, args.output_dir has higher priority than cfg.OUTPUT_DIR. """ print(args) runner = create_runner(args.runner) cfg = runner.get_default_cfg() if args.config_file: with PathManager.open(reroute_config_path(args.config_file), "r") as f: print("Loaded config file {}:\n{}".format(args.config_file, f.read())) cfg.merge_from_file(args.config_file) cfg.merge_from_list(args.opts) else: cfg = create_cfg_from_cli_args(args, default_cfg=cfg) cfg.freeze() assert args.output_dir or args.config_file output_dir = args.output_dir or cfg.OUTPUT_DIR return cfg, output_dir, runner
def __init__(self, img_folder, ann_folder, ann_file, transforms=None, return_masks=True): with PathManager.open(ann_file, "r") as f: self.coco = json.load(f) # sort 'images' field so that they are aligned with 'annotations' # i.e., in alphabetical order self.coco["images"] = sorted(self.coco["images"], key=lambda x: x["id"]) # sanity check if "annotations" in self.coco: for img, ann in zip(self.coco["images"], self.coco["annotations"]): assert img["file_name"][:-4] == ann["file_name"][:-4] self.img_folder = img_folder self.ann_folder = ann_folder self.ann_file = ann_file self.transforms = transforms self.return_masks = return_masks