def test_flops_counter(): with pytest.raises(AssertionError): # input_res should be a tuple model = nn.Conv2d(3, 8, 3) input_res = [1, 3, 16, 16] get_model_complexity_info(model, input_res) with pytest.raises(AssertionError): # len(input_res) >= 2 model = nn.Conv2d(3, 8, 3) input_res = tuple() get_model_complexity_info(model, input_res) # test common layers for item in gt_results: model = item['model'] input = item['input'] flops, params = get_model_complexity_info(model, input, as_strings=False, print_per_layer_stat=False) assert flops == item['flops'] and params == item['params'] # test input constructor model = ExampleModel() x = (3, 16, 16) flops, params = get_model_complexity_info( model, x, as_strings=False, print_per_layer_stat=False, input_constructor=input_constructor) assert flops == 43904.0 and params == 224.0 # test output string model = nn.Conv3d(3, 8, 3) x = (3, 3, 512, 512) flops, params = get_model_complexity_info(model, x, print_per_layer_stat=False) assert flops == '0.17 GFLOPs' and params == str(656) # test print per layer status model = nn.Conv1d(3, 8, 3) x = (3, 16) out = StringIO() get_model_complexity_info(model, x, ost=out) assert out.getvalue() == \ 'Conv1d(0.0 M, 100.000% Params, 0.0 GFLOPs, 100.000% FLOPs, 3, 8, kernel_size=(3,), stride=(1,))\n' # noqa: E501 # test when model is not a common instance model = nn.Sequential(nn.Conv2d(3, 8, 3), nn.Flatten(), nn.Linear(1568, 2)) x = (3, 16, 16) flops, params = get_model_complexity_info(model, x, as_strings=False, print_per_layer_stat=True) assert flops == 47040.0 and params == 3362
def main(): args = parse_args() if len(args.shape) == 1: input_shape = (3, args.shape[0], args.shape[0]) elif len(args.shape) == 2: input_shape = (3, ) + tuple(args.shape) else: raise ValueError('invalid input shape') cfg = Config.fromfile(args.config) model = build_detector( cfg.model, train_cfg=cfg.train_cfg, test_cfg=cfg.test_cfg) if torch.cuda.is_available(): model.cuda() model.eval() if hasattr(model, 'forward_dummy'): model.forward = model.forward_dummy else: raise NotImplementedError( 'FLOPs counter is currently not currently supported with {}'. format(model.__class__.__name__)) flops, params = get_model_complexity_info(model, input_shape) split_line = '=' * 30 print(f'{split_line}\nInput shape: {input_shape}\n' f'Flops: {flops}\nParams: {params}\n{split_line}') print('!!!Please be cautious if you use the results in papers. ' 'You may need to check if all ops are supported and verify that the ' 'flops computation is correct.')
def main(): args = parse_args() if len(args.shape) == 1: input_shape = (3, args.shape[0], args.shape[0]) elif len(args.shape) == 2: input_shape = (3, ) + tuple(args.shape) else: raise ValueError('invalid input shape') cfg = Config.fromfile(args.config) cfg.model.pretrained = None model = build_segmentor(cfg.model, train_cfg=cfg.get('train_cfg'), test_cfg=cfg.get('test_cfg')).cuda() model.eval() if hasattr(model, 'forward_dummy'): model.forward = model.forward_dummy else: raise NotImplementedError( 'FLOPs counter is currently not currently supported with {}'. format(model.__class__.__name__)) with torch.no_grad(): flops, params = get_model_complexity_info(model, input_shape) split_line = '=' * 30 print('{0}\nInput shape: {1}\nFlops: {2}\nParams: {3}\n{0}'.format( split_line, input_shape, flops, params)) print('!!!Please be cautious if you use the results in papers. ' 'You may need to check if all ops are supported and verify that the ' 'flops computation is correct.')
def get_flops(model, input_shape): flops, params = get_model_complexity_info(model, input_shape, as_strings=False) if 'pvt' in model.name: _, H, W = input_shape if 'li' in model.name: # calculate flops of PVTv2_li stage1 = li_sra_flops(H // 4, W // 4, model.block1[0].attn.dim) * len(model.block1) stage2 = li_sra_flops(H // 8, W // 8, model.block2[0].attn.dim) * len(model.block2) stage3 = li_sra_flops(H // 16, W // 16, model.block3[0].attn.dim) * len(model.block3) stage4 = li_sra_flops(H // 32, W // 32, model.block4[0].attn.dim) * len(model.block4) else: # calculate flops of PVT/PVTv2 stage1 = sra_flops(H // 4, W // 4, model.block1[0].attn.sr_ratio, model.block1[0].attn.dim) * len(model.block1) stage2 = sra_flops(H // 8, W // 8, model.block2[0].attn.sr_ratio, model.block2[0].attn.dim) * len(model.block2) stage3 = sra_flops(H // 16, W // 16, model.block3[0].attn.sr_ratio, model.block3[0].attn.dim) * len(model.block3) stage4 = sra_flops(H // 32, W // 32, model.block4[0].attn.sr_ratio, model.block4[0].attn.dim) * len(model.block4) flops += stage1 + stage2 + stage3 + stage4 return flops_to_string(flops), params_to_string(params)
def main(): args = parse_args() if len(args.shape) == 1: input_shape = (3, args.shape[0], args.shape[0]) elif len(args.shape) == 2: input_shape = (3, ) + tuple(args.shape) else: raise ValueError('invalid input shape') cfg = Config.fromfile(args.config) cfg.model.pretrained = None if args.net_params: tag, input_channels, block1, block2, block3, block4, last_channel = args.net_params.split( '-') input_channels = [int(item) for item in input_channels.split('_')] block1 = [int(item) for item in block1.split('_')] block2 = [int(item) for item in block2.split('_')] block3 = [int(item) for item in block3.split('_')] block4 = [int(item) for item in block4.split('_')] last_channel = int(last_channel) inverted_residual_setting = [] for item in [block1, block2, block3, block4]: for _ in range(item[0]): inverted_residual_setting.append([ item[1], item[2:-int(len(item) / 2 - 1)], item[-int(len(item) / 2 - 1):] ]) cfg.model.backbone.input_channel = input_channels cfg.model.backbone.inverted_residual_setting = inverted_residual_setting cfg.model.backbone.last_channel = last_channel model = build_segmentor(cfg.model, train_cfg=cfg.train_cfg, test_cfg=cfg.test_cfg).cuda() model.eval() if hasattr(model, 'forward_dummy'): model.forward = model.forward_dummy else: raise NotImplementedError( 'FLOPs counter is currently not currently supported with {}'. format(model.__class__.__name__)) flops, params = get_model_complexity_info(model, input_shape) split_line = '=' * 30 print('{0}\nInput shape: {1}\nFlops: {2}\nParams: {3}\n{0}'.format( split_line, input_shape, flops, params)) print('!!!Please be cautious if you use the results in papers. ' 'You may need to check if all ops are supported and verify that the ' 'flops computation is correct.')
def main(): args = parse_args() if args.root_work_dir is None: # get the current time stamp now = datetime.now() ts = now.strftime('%Y_%m_%d_%H_%M') args.root_work_dir = f'work_dirs/flops_test_{ts}' mmcv.mkdir_or_exist(osp.abspath(args.root_work_dir)) cfg = mmcv.load(args.config) results = [] for i in range(args.priority + 1): models = cfg['model_list'][f'P{i}'] for cur_model in models: cfg_file = cur_model['config'] model_cfg = Config.fromfile(cfg_file) if 'input_shape' in cur_model.keys(): input_shape = cur_model['input_shape'] input_shape = tuple(map(int, input_shape.split(','))) else: image_size = model_cfg.data_cfg.image_size if isinstance(image_size, list): input_shape = (3, ) + tuple(image_size) else: input_shape = (3, image_size, image_size) model = init_pose_model(cfg_file) if hasattr(model, 'forward_dummy'): model.forward = model.forward_dummy else: raise NotImplementedError( 'FLOPs counter is currently not currently supported ' 'with {}'.format(model.__class__.__name__)) flops, params = get_model_complexity_info( model, input_shape, print_per_layer_stat=False) split_line = '=' * 30 result = f'{split_line}\nModel config:{cfg_file}\n' \ f'Input shape: {input_shape}\n' \ f'Flops: {flops}\nParams: {params}\n{split_line}\n' print(result) results.append(result) print('!!!Please be cautious if you use the results in papers. ' 'You may need to check if all ops are supported and verify that the ' 'flops computation is correct.') with open(osp.join(args.root_work_dir, 'flops.txt'), 'w') as f: for res in results: f.write(res)
def main(): args = parse_args() if len(args.shape) == 1: h = w = args.shape[0] elif len(args.shape) == 2: h, w = args.shape else: raise ValueError('invalid input shape') orig_shape = (3, h, w) divisor = args.size_divisor if divisor > 0: h = int(np.ceil(h / divisor)) * divisor w = int(np.ceil(w / divisor)) * divisor input_shape = (3, h, w) 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']) model = build_detector(cfg.model, train_cfg=cfg.get('train_cfg'), test_cfg=cfg.get('test_cfg')) if torch.cuda.is_available(): model.cuda() model.eval() if hasattr(model, 'forward_dummy'): model.forward = model.forward_dummy else: raise NotImplementedError( 'FLOPs counter is currently not currently supported with {}'. format(model.__class__.__name__)) flops, params = get_model_complexity_info(model, input_shape) split_line = '=' * 30 if divisor > 0 and \ input_shape != orig_shape: print(f'{split_line}\nUse size divisor set input shape ' f'from {orig_shape} to {input_shape}\n') print(f'{split_line}\nInput shape: {input_shape}\n' f'Flops: {flops}\nParams: {params}\n{split_line}') print('!!!Please be cautious if you use the results in papers. ' 'You may need to check if all ops are supported and verify that the ' 'flops computation is correct.')
def get_flops(cfg, input_shape): model = build_classifier(cfg.model) model.eval() if hasattr(model, 'extract_feat'): model.forward = model.extract_feat else: raise NotImplementedError( 'FLOPs counter is currently not currently supported with {}'. format(model.__class__.__name__)) buf = io.StringIO() all_flops, params = get_model_complexity_info(model, input_shape, print_per_layer_stat=True, as_strings=False, ost=buf) buf = buf.getvalue() return all_flops/1e9
def main(): args = parse_args() if args.modality == 'point': assert len(args.shape) == 2, 'invalid input shape' input_shape = tuple(args.shape) elif args.modality == 'image': if len(args.shape) == 1: input_shape = (3, args.shape[0], args.shape[0]) elif len(args.shape) == 2: input_shape = (3, ) + tuple(args.shape) else: raise ValueError('invalid input shape') elif args.modality == 'multi': raise NotImplementedError( 'FLOPs counter is currently not supported for models with ' 'multi-modality input') 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']) model = build_model(cfg.model, train_cfg=cfg.get('train_cfg'), test_cfg=cfg.get('test_cfg')) if torch.cuda.is_available(): model.cuda() model.eval() if hasattr(model, 'forward_dummy'): model.forward = model.forward_dummy else: raise NotImplementedError( 'FLOPs counter is currently not supported for {}'.format( model.__class__.__name__)) flops, params = get_model_complexity_info(model, input_shape) split_line = '=' * 30 print(f'{split_line}\nInput shape: {input_shape}\n' f'Flops: {flops}\nParams: {params}\n{split_line}') print('!!!Please be cautious if you use the results in papers. ' 'You may need to check if all ops are supported and verify that the ' 'flops computation is correct.')
def get_flops(cfg, input_shape): model = build_detector(cfg.model, train_cfg=cfg.train_cfg, test_cfg=cfg.test_cfg) #if torch.cuda.is_available(): # model.cuda() model.eval() if hasattr(model, 'forward_dummy'): model.forward = model.forward_dummy else: raise NotImplementedError( 'FLOPs counter is currently not currently supported with {}'. format(model.__class__.__name__)) buf = io.StringIO() all_flops, params = get_model_complexity_info(model, input_shape, print_per_layer_stat=True, as_strings=False, ost=buf) buf = buf.getvalue() #print(buf) lines = buf.split("\n") names = [ '(stem)', '(layer1)', '(layer2)', '(layer3)', '(layer4)', '(neck)', '(bbox_head)' ] name_ptr = 0 line_num = 0 _flops = [] while name_ptr < len(names): line = lines[line_num].strip() name = names[name_ptr] if line.startswith(name): flops = float(lines[line_num + 1].split(',')[2].strip().split(' ')[0]) _flops.append(flops) name_ptr += 1 line_num += 1 backbone_flops = np.array(_flops[:-2], dtype=np.float32) neck_flops = _flops[-2] head_flops = _flops[-1] return all_flops / 1e9, backbone_flops, neck_flops, head_flops
def main(): args = parse_args() if len(args.shape) == 1: input_shape = (3, args.shape[0], args.shape[0]) elif len(args.shape) == 2: input_shape = (3, ) + tuple(args.shape) else: raise ValueError('invalid input shape') model = init_pose_model(args.config) if args.input_constructor == 'batch': input_constructor = partial(batch_constructor, model, args.batch_size) else: input_constructor = None if args.input_constructor == 'batch': input_constructor = partial(batch_constructor, model, args.batch_size) else: input_constructor = None if hasattr(model, 'forward_dummy'): model.forward = model.forward_dummy else: raise NotImplementedError( 'FLOPs counter is currently not currently supported with {}'. format(model.__class__.__name__)) flops, params = get_model_complexity_info( model, input_shape, input_constructor=input_constructor, print_per_layer_stat=(not args.not_print_per_layer_stat)) split_line = '=' * 30 input_shape = (args.batch_size, ) + input_shape print(f'{split_line}\nInput shape: {input_shape}\n' f'Flops: {flops}\nParams: {params}\n{split_line}') print('!!!Please be cautious if you use the results in papers. ' 'You may need to check if all ops are supported and verify that the ' 'flops computation is correct.')
def is_config_valid(cfg, target_flops, input_shape, eps): model = build_detector(cfg.model, train_cfg=cfg.train_cfg, test_cfg=cfg.test_cfg) if torch.cuda.is_available(): model.cuda() model.eval() if hasattr(model, 'forward_dummy'): model.forward = model.forward_dummy else: raise NotImplementedError( 'FLOPs counter is currently not currently supported with {}'. format(model.__class__.__name__)) flops, params = get_model_complexity_info(model, input_shape, print_per_layer_stat=False, as_strings=False) print('FLOPs:', flops / 1e9) return flops <= (1. + eps) * target_flops and \ flops >= (1. - eps) * target_flops
def main(): args = parse_args() if len(args.shape) == 1: input_shape = (3, args.shape[0], args.shape[0]) elif len(args.shape) == 2: input_shape = (3, ) + tuple(args.shape) elif len(args.shape) == 3: input_shape = (args.shape[0], args.shape[1], args.shape[2]) else: raise ValueError('invalid input shape') if args.config: 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']) if args.model == 'repvgg': model = build_detector(cfg.model, train_cfg=cfg.get('train_cfg'), test_cfg=cfg.get('test_cfg')) elif args.model == 'repblock': model = RepVGGConvModule(in_channels=input_shape[0], out_channels=input_shape[0], kernel_size=3, stride=1, padding=args.dilation, dilation=args.dilation, groups=1, activation='ReLU', padding_mode='zeros', deploy=args.deploy) elif args.model == 'bottleneck': model = Bottleneck( in_channels=input_shape[0], mid_channels=512, # default setting according to yolof neck dilation=args.dilation, ) else: raise NotImplementedError( 'FLOPs counter is currently not currently supported with {}'. format(args.model)) if args.convert_repvgg and args.model == 'repvgg': print("Converting repvgg model") cfg.model.backbone['deploy'] = True deploy_model = build_detector(cfg.model, test_cfg=cfg.get('test_cfg')) model = repvgg_det_model_convert(model, deploy_model) if torch.cuda.is_available(): model.cuda() model.eval() if hasattr(model, 'forward_dummy'): model.forward = model.forward_dummy else: # raise NotImplementedError( # 'FLOPs counter is currently not currently supported with {}'. # format(model.__class__.__name__)) pass flops, params = get_model_complexity_info(model, input_shape) time_usage = speed(model, input_shape) split_line = '=' * 30 print( f'{split_line}\nInput shape: {input_shape}\n' f'Model: {args.model}\nDeploy: {args.deploy}\nDilation: {args.dilation}\nFlops: {flops}\nParams: {params}\nTime: {time_usage} ms\n{split_line}\n' ) print('!!!Please be cautious if you use the results in papers. ' 'You may need to check if all ops are supported and verify that the ' 'flops computation is correct.')
import json import torch from mmcv.cnn import get_model_complexity_info import numpy as np import argparse import os, sys libpath = os.path.join(os.path.dirname(__file__), '../') sys.path.append(libpath) import src def parse_args(): parser = argparse.ArgumentParser() parser.add_argument('-g', '--graph', default='./models/sparse_resnet50v1b/IR_for_reconstruct_graph.json', help='graph json') parser.add_argument('--shape', type=int, nargs=3, default=[3,224,224], help='input shape') return parser.parse_args() if __name__ == '__main__': args = parse_args() with open(args.graph, 'r') as f: graph = json.load(f) trc = src.TorchReconstructor(graph) trc.eval() flops, params = get_model_complexity_info(trc, tuple(args.shape))