forked from facebookresearch/detectron2
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: Support flop/activation counting for 100 inputs. Reviewed By: rbgirshick Differential Revision: D20988652 fbshipit-source-id: 394bd3050fd4edc0d726bdb431edd40211f66810
- Loading branch information
1 parent
5525cf5
commit 4bd92bb
Showing
4 changed files
with
184 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
# -*- coding: utf-8 -*- | ||
# noqa: B950 | ||
|
||
import logging | ||
from collections import Counter | ||
import tqdm | ||
|
||
from detectron2.checkpoint import DetectionCheckpointer | ||
from detectron2.config import get_cfg | ||
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 ( | ||
activation_count_operators, | ||
flop_count_operators, | ||
parameter_count_table, | ||
) | ||
from detectron2.utils.logger import setup_logger | ||
|
||
logger = logging.getLogger("detectron2") | ||
|
||
|
||
def setup(args): | ||
cfg = get_cfg() | ||
cfg.merge_from_file(args.config_file) | ||
cfg.DATALOADER.NUM_WORKERS = 0 | ||
cfg.merge_from_list(args.opts) | ||
cfg.freeze() | ||
setup_logger() | ||
return cfg | ||
|
||
|
||
def do_flop(cfg): | ||
data_loader = build_detection_test_loader(cfg, cfg.DATASETS.TEST[0]) | ||
model = build_model(cfg) | ||
DetectionCheckpointer(model).load(cfg.MODEL.WEIGHTS) | ||
model.eval() | ||
|
||
counts = Counter() | ||
for idx, data in zip(tqdm.trange(args.num_inputs), data_loader): # noqa | ||
counts += flop_count_operators(model, data) | ||
logger.info( | ||
"(G)Flops for Each Type of Operators:\n" + str([(k, v / idx) for k, v in counts.items()]) | ||
) | ||
|
||
|
||
def do_activation(cfg): | ||
data_loader = build_detection_test_loader(cfg, cfg.DATASETS.TEST[0]) | ||
model = build_model(cfg) | ||
DetectionCheckpointer(model).load(cfg.MODEL.WEIGHTS) | ||
model.eval() | ||
|
||
counts = Counter() | ||
for idx, data in zip(tqdm.trange(args.num_inputs), data_loader): # noqa | ||
counts += activation_count_operators(model, data) | ||
logger.info( | ||
"(Million) Activations for Each Type of Operators:\n" | ||
+ str([(k, v / idx) for k, v in counts.items()]) | ||
) | ||
|
||
|
||
def do_parameter(cfg): | ||
model = build_model(cfg) | ||
logger.info("Parameter Count:\n" + parameter_count_table(model, max_depth=5)) | ||
|
||
|
||
def do_structure(cfg): | ||
model = build_model(cfg) | ||
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( | ||
"--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) |