|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | import logging | 
					
						
						|  | import numpy as np | 
					
						
						|  | from collections import Counter | 
					
						
						|  | import tqdm | 
					
						
						|  | from fvcore.nn import flop_count_table | 
					
						
						|  |  | 
					
						
						|  | from detectron2.checkpoint import DetectionCheckpointer | 
					
						
						|  | from detectron2.config import CfgNode, LazyConfig, get_cfg, instantiate | 
					
						
						|  | from detectron2.data import build_detection_test_loader | 
					
						
						|  | from detectron2.engine import default_argument_parser | 
					
						
						|  | from detectron2.modeling import build_model | 
					
						
						|  | from detectron2.utils.analysis import ( | 
					
						
						|  | FlopCountAnalysis, | 
					
						
						|  | activation_count_operators, | 
					
						
						|  | parameter_count_table, | 
					
						
						|  | ) | 
					
						
						|  | from detectron2.utils.logger import setup_logger | 
					
						
						|  |  | 
					
						
						|  | logger = logging.getLogger("detectron2") | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | def setup(args): | 
					
						
						|  | if args.config_file.endswith(".yaml"): | 
					
						
						|  | cfg = get_cfg() | 
					
						
						|  | cfg.merge_from_file(args.config_file) | 
					
						
						|  | cfg.DATALOADER.NUM_WORKERS = 0 | 
					
						
						|  | cfg.merge_from_list(args.opts) | 
					
						
						|  | cfg.freeze() | 
					
						
						|  | else: | 
					
						
						|  | cfg = LazyConfig.load(args.config_file) | 
					
						
						|  | cfg = LazyConfig.apply_overrides(cfg, args.opts) | 
					
						
						|  | setup_logger(name="fvcore") | 
					
						
						|  | setup_logger() | 
					
						
						|  | return cfg | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | def do_flop(cfg): | 
					
						
						|  | if isinstance(cfg, CfgNode): | 
					
						
						|  | data_loader = build_detection_test_loader(cfg, cfg.DATASETS.TEST[0]) | 
					
						
						|  | model = build_model(cfg) | 
					
						
						|  | DetectionCheckpointer(model).load(cfg.MODEL.WEIGHTS) | 
					
						
						|  | else: | 
					
						
						|  | data_loader = instantiate(cfg.dataloader.test) | 
					
						
						|  | model = instantiate(cfg.model) | 
					
						
						|  | model.to(cfg.train.device) | 
					
						
						|  | DetectionCheckpointer(model).load(cfg.train.init_checkpoint) | 
					
						
						|  | model.eval() | 
					
						
						|  |  | 
					
						
						|  | counts = Counter() | 
					
						
						|  | total_flops = [] | 
					
						
						|  | for idx, data in zip(tqdm.trange(args.num_inputs), data_loader): | 
					
						
						|  | flops = FlopCountAnalysis(model, data) | 
					
						
						|  | if idx > 0: | 
					
						
						|  | flops.unsupported_ops_warnings(False).uncalled_modules_warnings(False) | 
					
						
						|  | counts += flops.by_operator() | 
					
						
						|  | total_flops.append(flops.total()) | 
					
						
						|  |  | 
					
						
						|  | logger.info("Flops table computed from only one input sample:\n" + flop_count_table(flops)) | 
					
						
						|  | logger.info( | 
					
						
						|  | "Average GFlops for each type of operators:\n" | 
					
						
						|  | + str([(k, v / (idx + 1) / 1e9) for k, v in counts.items()]) | 
					
						
						|  | ) | 
					
						
						|  | logger.info( | 
					
						
						|  | "Total GFlops: {:.1f}±{:.1f}".format(np.mean(total_flops) / 1e9, np.std(total_flops) / 1e9) | 
					
						
						|  | ) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | def do_activation(cfg): | 
					
						
						|  | if isinstance(cfg, CfgNode): | 
					
						
						|  | data_loader = build_detection_test_loader(cfg, cfg.DATASETS.TEST[0]) | 
					
						
						|  | model = build_model(cfg) | 
					
						
						|  | DetectionCheckpointer(model).load(cfg.MODEL.WEIGHTS) | 
					
						
						|  | else: | 
					
						
						|  | data_loader = instantiate(cfg.dataloader.test) | 
					
						
						|  | model = instantiate(cfg.model) | 
					
						
						|  | model.to(cfg.train.device) | 
					
						
						|  | DetectionCheckpointer(model).load(cfg.train.init_checkpoint) | 
					
						
						|  | model.eval() | 
					
						
						|  |  | 
					
						
						|  | counts = Counter() | 
					
						
						|  | total_activations = [] | 
					
						
						|  | for idx, data in zip(tqdm.trange(args.num_inputs), data_loader): | 
					
						
						|  | count = activation_count_operators(model, data) | 
					
						
						|  | counts += count | 
					
						
						|  | total_activations.append(sum(count.values())) | 
					
						
						|  | logger.info( | 
					
						
						|  | "(Million) Activations for Each Type of Operators:\n" | 
					
						
						|  | + str([(k, v / idx) for k, v in counts.items()]) | 
					
						
						|  | ) | 
					
						
						|  | logger.info( | 
					
						
						|  | "Total (Million) Activations: {}±{}".format( | 
					
						
						|  | np.mean(total_activations), np.std(total_activations) | 
					
						
						|  | ) | 
					
						
						|  | ) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | def do_parameter(cfg): | 
					
						
						|  | if isinstance(cfg, CfgNode): | 
					
						
						|  | model = build_model(cfg) | 
					
						
						|  | else: | 
					
						
						|  | model = instantiate(cfg.model) | 
					
						
						|  | logger.info("Parameter Count:\n" + parameter_count_table(model, max_depth=5)) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | def do_structure(cfg): | 
					
						
						|  | if isinstance(cfg, CfgNode): | 
					
						
						|  | model = build_model(cfg) | 
					
						
						|  | else: | 
					
						
						|  | model = instantiate(cfg.model) | 
					
						
						|  | logger.info("Model Structure:\n" + str(model)) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | if __name__ == "__main__": | 
					
						
						|  | parser = default_argument_parser( | 
					
						
						|  | epilog=""" | 
					
						
						|  | Examples: | 
					
						
						|  |  | 
					
						
						|  | To show parameters of a model: | 
					
						
						|  | $ ./analyze_model.py --tasks parameter \\ | 
					
						
						|  | --config-file ../configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml | 
					
						
						|  |  | 
					
						
						|  | Flops and activations are data-dependent, therefore inputs and model weights | 
					
						
						|  | are needed to count them: | 
					
						
						|  |  | 
					
						
						|  | $ ./analyze_model.py --num-inputs 100 --tasks flop \\ | 
					
						
						|  | --config-file ../configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml \\ | 
					
						
						|  | MODEL.WEIGHTS /path/to/model.pkl | 
					
						
						|  | """ | 
					
						
						|  | ) | 
					
						
						|  | parser.add_argument( | 
					
						
						|  | "--tasks", | 
					
						
						|  | choices=["flop", "activation", "parameter", "structure"], | 
					
						
						|  | required=True, | 
					
						
						|  | nargs="+", | 
					
						
						|  | ) | 
					
						
						|  | parser.add_argument( | 
					
						
						|  | "-n", | 
					
						
						|  | "--num-inputs", | 
					
						
						|  | default=100, | 
					
						
						|  | type=int, | 
					
						
						|  | help="number of inputs used to compute statistics for flops/activations, " | 
					
						
						|  | "both are data dependent.", | 
					
						
						|  | ) | 
					
						
						|  | args = parser.parse_args() | 
					
						
						|  | assert not args.eval_only | 
					
						
						|  | assert args.num_gpus == 1 | 
					
						
						|  |  | 
					
						
						|  | cfg = setup(args) | 
					
						
						|  |  | 
					
						
						|  | for task in args.tasks: | 
					
						
						|  | { | 
					
						
						|  | "flop": do_flop, | 
					
						
						|  | "activation": do_activation, | 
					
						
						|  | "parameter": do_parameter, | 
					
						
						|  | "structure": do_structure, | 
					
						
						|  | }[task](cfg) | 
					
						
						|  |  |