├── .gitignore ├── LICENSE ├── MANIFEST.in ├── NOTICE ├── README.md ├── configs ├── action_recognition │ ├── E3D_X3DL_FLOPs.py │ ├── E3D_X3DM_FLOPs.py │ ├── E3D_X3DS_FLOPs.py │ ├── README.md │ └── models │ │ ├── E3D_L.txt │ │ ├── E3D_M.txt │ │ └── E3D_S.txt ├── classification │ ├── MBV2_FLOPs.py │ ├── R50_FLOPs.py │ ├── README.md │ ├── deepmad_29M_224.py │ ├── deepmad_29M_288.py │ ├── deepmad_50M.py │ ├── deepmad_89M.py │ ├── deepmad_R18_FLOPs.py │ ├── deepmad_R34_FLOPs.py │ ├── deepmad_R50_FLOPs.py │ └── models │ │ ├── R152-like.txt │ │ ├── R18-like.txt │ │ ├── R50-like.txt │ │ ├── deepmad-29M-224.txt │ │ ├── deepmad-29M-288.txt │ │ ├── deepmad-50M.txt │ │ ├── deepmad-89M.txt │ │ ├── deepmad-R18.txt │ │ ├── deepmad-R34.txt │ │ └── deepmad-R50.txt ├── damoyolo │ ├── damoyolo_k1kx_small.py │ ├── damoyolo_k1kx_tiny.py │ └── damoyolo_kxkx_medium.py ├── detection │ ├── R50_FLOPs.py │ ├── R50_FLOPs_predictor.py │ ├── README.md │ └── models │ │ ├── gfocal_maedet │ │ ├── gfocal_r50_fpn_ms6x.py │ │ ├── maedet_l_6x_lr0.02.py │ │ ├── maedet_m_6x_lr0.02.py │ │ └── maedet_s_6x_lr0.02.py │ │ ├── madnas.py │ │ ├── maedet_l.txt │ │ ├── maedet_m.txt │ │ └── maedet_s.txt └── quant │ ├── Mixed_19d2G.py │ ├── Mixed_7d0G.py │ ├── README.md │ └── models │ ├── mixed19d2G.txt │ └── mixed7d0G.txt ├── docs └── arch.png ├── get_started.md ├── installation.md ├── modelscope ├── __init__.py ├── fileio │ ├── __init__.py │ ├── file.py │ ├── format │ │ ├── __init__.py │ │ ├── base.py │ │ ├── json.py │ │ └── yaml.py │ └── io.py ├── utils │ ├── __init__.py │ ├── config.py │ ├── config_ds.py │ ├── constant.py │ ├── data_utils.py │ ├── error.py │ ├── file_utils.py │ ├── import_utils.py │ ├── json_utils.py │ ├── logger.py │ ├── megatron_utils.py │ ├── metric.py │ ├── model_tag.py │ ├── plugins.py │ ├── registry.py │ ├── tensor_utils.py │ ├── timer.py │ ├── torch_utils.py │ ├── type_assert.py │ └── typing.py └── version.py ├── requirements ├── nas.txt └── tests.txt ├── setup.cfg ├── setup.py ├── tinynas ├── __init__.py ├── budgets │ ├── README.md │ ├── __init__.py │ ├── base.py │ ├── budgets.py │ └── builder.py ├── deploy │ ├── cnn3dnet │ │ ├── cnn3dnet.py │ │ ├── demo.py │ │ └── modules │ │ │ ├── __init__.py │ │ │ ├── blocks_basic_3D.py │ │ │ └── super_res3d_k1dwk1.py │ └── cnnnet │ │ ├── cnnnet.py │ │ ├── demo.py │ │ └── modules │ │ ├── __init__.py │ │ ├── blocks_basic.py │ │ ├── qconv.py │ │ ├── super_quant_res_k1dwk1.py │ │ ├── super_res_k1dwk1.py │ │ ├── super_res_k1dwsek1.py │ │ ├── super_res_k1kx.py │ │ ├── super_res_k1kxk1.py │ │ └── super_res_kxkx.py ├── evolutions │ ├── README.md │ ├── __init__.py │ └── population.py ├── latency │ ├── __init__.py │ ├── builder.py │ ├── op_predictor.py │ ├── op_profiler │ │ ├── R50.txt │ │ ├── README.md │ │ ├── V100 │ │ │ ├── conv_data.out │ │ │ ├── conv_data.out.fp16 │ │ │ ├── conv_data.out.fp16.damoyolo │ │ │ └── conv_data.out.int8 │ │ ├── __init__.py │ │ ├── op_profiler.jpg │ │ ├── predictor.py │ │ ├── python │ │ │ ├── README.md │ │ │ ├── __init__.py │ │ │ ├── config.in │ │ │ ├── read_log.py │ │ │ ├── sample.sh │ │ │ └── sampler.py │ │ ├── test_predictor.py │ │ └── util.py │ └── robust_gpu_predictor.py ├── models │ ├── README.md │ ├── __init__.py │ ├── base.py │ ├── blocks_cnn_2d │ │ ├── __init__.py │ │ ├── blocks_basic.py │ │ ├── qconv.py │ │ ├── super_quant_res_k1dwk1.py │ │ ├── super_res_k1dwk1.py │ │ ├── super_res_k1dwsek1.py │ │ ├── super_res_k1kx.py │ │ ├── super_res_k1kxk1.py │ │ └── super_res_kxkx.py │ ├── blocks_cnn_3d │ │ ├── __init__.py │ │ ├── blocks_basic_3D.py │ │ └── super_res3d_k1dwk1.py │ ├── builder.py │ ├── cnn3dnet.py │ └── cnnnet.py ├── scores │ ├── README.md │ ├── __init__.py │ ├── builder.py │ ├── compute_deepmad.py │ ├── compute_ensemble.py │ ├── compute_madnas.py │ ├── compute_random.py │ └── compute_stentr.py ├── searchers │ ├── README.md │ ├── __init__.py │ ├── base.py │ ├── builder.py │ ├── searcher.py │ └── synchonizer.py ├── spaces │ ├── README.md │ ├── __init__.py │ ├── base.py │ ├── builder.py │ ├── mutator │ │ ├── __init__.py │ │ ├── base.py │ │ ├── basic_mutators.py │ │ ├── builder.py │ │ ├── conv3d_bn_relu_mutator.py │ │ ├── conv_bn_relu_mutator.py │ │ ├── super_quant_res_k1dwk1_mutator.py │ │ ├── super_res3d_k1dwk1_mutator.py │ │ ├── super_res_k1dwk1_mutator.py │ │ ├── super_res_k1kx_mutator.py │ │ └── super_res_k1kxk1_mutator.py │ ├── random_sample.py │ ├── space_3d_k1dwk1.py │ ├── space_k1dwk1.py │ ├── space_k1dwsek1.py │ ├── space_k1kx.py │ ├── space_k1kxk1.py │ ├── space_kxkx.py │ ├── space_quant_k1dwk1.py │ └── space_utils.py ├── strategy │ ├── README.md │ ├── __init__.py │ └── strategy.py └── utils │ ├── __init__.py │ ├── dict_action.py │ ├── dist_utils.py │ ├── file_utils.py │ ├── import_utils.py │ ├── logger.py │ └── misc.py └── tools ├── dist_search.sh ├── export.py ├── local_search.sh └── search.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | *.patch 7 | save_model/ 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | wheels/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | /package 30 | /temp 31 | MANIFEST 32 | 33 | # PyInstaller 34 | # Usually these files are written by a python script from a template 35 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 36 | *.manifest 37 | *.spec 38 | 39 | # Installer logs 40 | pip-log.txt 41 | pip-delete-this-directory.txt 42 | 43 | # Unit test / coverage reports 44 | htmlcov/ 45 | .tox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | .hypothesis/ 53 | .pytest_cache/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # pyenv 81 | .python-version 82 | 83 | # celery beat schedule file 84 | celerybeat-schedule 85 | 86 | # SageMath parsed files 87 | *.sage.py 88 | 89 | # Environments 90 | .env 91 | .venv 92 | env/ 93 | venv/ 94 | ENV/ 95 | env.bak/ 96 | venv.bak/ 97 | 98 | # Spyder project settings 99 | .spyderproject 100 | .spyproject 101 | 102 | # Rope project settings 103 | .ropeproject 104 | 105 | # mkdocs documentation 106 | /site 107 | 108 | # mypy 109 | .mypy_cache/ 110 | 111 | .vscode 112 | .idea 113 | 114 | # custom 115 | *.pkl 116 | *.pkl.json 117 | *.log.json 118 | *.whl 119 | *.tar.gz 120 | *.swp 121 | *.log 122 | *.tar.gz 123 | .DS_Store 124 | replace.sh 125 | result.png 126 | 127 | # Pytorch 128 | *.pth 129 | *.pt 130 | tinynas/configs 131 | tinynas/tools 132 | tinynas/modelscope 133 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include tinynas *gz *.txt * 2 | recursive-include tinynas/configs * 3 | recursive-include tinynas/tools *.sh *.py 4 | -------------------------------------------------------------------------------- /configs/action_recognition/E3D_X3DL_FLOPs.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | work_dir = './save_model/E3DM_FLOPs_185e8/' 6 | log_level = 'INFO' # INFO/DEBUG/ERROR 7 | log_freq = 1000 8 | 9 | """ video config """ 10 | image_size = 312 11 | frames = 16 12 | 13 | """ Model config """ 14 | model = dict( 15 | type = 'Cnn3DNet', 16 | structure_info = [ 17 | {'class': 'Conv3DKXBNRELU', 'in': 3, 'out': 24, 's': 2, 'kt': 1, 'k': 3}, \ 18 | {'class': 'SuperRes3DK1DWK1', 'in': 24, 'out': 24, 's': 2, 'kt': 1, 'k': 5, 'L': 1, 'btn': 48}, \ 19 | {'class': 'SuperRes3DK1DWK1', 'in': 24, 'out': 48, 's': 2, 'kt': 3, 'k': 3, 'L': 1, 'btn': 96}, \ 20 | {'class': 'SuperRes3DK1DWK1', 'in': 48, 'out': 96, 's': 2, 'kt': 3, 'k': 3, 'L': 1, 'btn': 192}, \ 21 | {'class': 'SuperRes3DK1DWK1', 'in': 96, 'out': 96, 's': 1, 'kt': 3, 'k': 3, 'L': 1, 'btn': 192}, \ 22 | {'class': 'SuperRes3DK1DWK1', 'in': 96, 'out': 192, 's': 2, 'kt': 3, 'k': 3, 'L': 1, 'btn': 384}, \ 23 | {'class': 'Conv3DKXBNRELU', 'in': 192, 'out': 512, 's': 1, 'kt': 1, 'k': 1},\ 24 | ] 25 | ) 26 | 27 | """ Budget config """ 28 | budgets = [ 29 | dict(type = "flops", budget = 185e8), 30 | dict(type = "layers",budget = 167), 31 | ] 32 | 33 | """ Score config """ 34 | score = dict(type = 'stentr', multi_block_ratio = [0,0,0,0,1], frames=16) 35 | 36 | """ Space config """ 37 | space = dict( 38 | type = 'space_3d_k1dwk1', 39 | image_size = image_size, 40 | ) 41 | 42 | """ Search config """ 43 | search=dict( 44 | minor_mutation = False, # whether fix the stage layer 45 | minor_iter = 100000, # which iteration to enable minor_mutation 46 | popu_size = 256, 47 | num_random_nets = 100000, # the searching iterations 48 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 49 | num_network = 1, 50 | ) 51 | 52 | -------------------------------------------------------------------------------- /configs/action_recognition/E3D_X3DM_FLOPs.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | work_dir = './save_model/E3DM_FLOPs_50e8/' 6 | log_level = 'INFO' # INFO/DEBUG/ERROR 7 | log_freq = 1000 8 | 9 | """ video config """ 10 | image_size = 224 11 | frames = 16 12 | 13 | """ Model config """ 14 | model = dict( 15 | type = 'Cnn3DNet', 16 | structure_info = [ 17 | {'class': 'Conv3DKXBNRELU', 'in': 3, 'out': 24, 's': 2, 'kt': 1, 'k': 3}, \ 18 | {'class': 'SuperRes3DK1DWK1', 'in': 24, 'out': 24, 's': 2, 'kt': 1, 'k': 5, 'L': 1, 'btn': 48}, \ 19 | {'class': 'SuperRes3DK1DWK1', 'in': 24, 'out': 48, 's': 2, 'kt': 3, 'k': 3, 'L': 1, 'btn': 96}, \ 20 | {'class': 'SuperRes3DK1DWK1', 'in': 48, 'out': 96, 's': 2, 'kt': 3, 'k': 3, 'L': 1, 'btn': 192}, \ 21 | {'class': 'SuperRes3DK1DWK1', 'in': 96, 'out': 96, 's': 1, 'kt': 3, 'k': 3, 'L': 1, 'btn': 192}, \ 22 | {'class': 'SuperRes3DK1DWK1', 'in': 96, 'out': 192, 's': 2, 'kt': 3, 'k': 3, 'L': 1, 'btn': 384}, \ 23 | {'class': 'Conv3DKXBNRELU', 'in': 192, 'out': 512, 's': 1, 'kt': 1, 'k': 1},\ 24 | ] 25 | ) 26 | 27 | """ Budget config """ 28 | budgets = [ 29 | dict(type = "flops", budget = 50e8), 30 | dict(type = "layers",budget = 83), 31 | ] 32 | 33 | """ Score config """ 34 | score = dict(type = 'stentr', multi_block_ratio = [0,0,0,0,1], frames=16) 35 | 36 | """ Space config """ 37 | space = dict( 38 | type = 'space_3d_k1dwk1', 39 | image_size = image_size, 40 | ) 41 | 42 | """ Search config """ 43 | search=dict( 44 | minor_mutation = False, # whether fix the stage layer 45 | minor_iter = 100000, # which iteration to enable minor_mutation 46 | popu_size = 256, 47 | num_random_nets = 100000, # the searching iterations 48 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 49 | num_network = 1, 50 | ) 51 | 52 | -------------------------------------------------------------------------------- /configs/action_recognition/E3D_X3DS_FLOPs.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | work_dir = './save_model/E3DS_FLOPs_20e8/' 6 | log_level = 'INFO' # INFO/DEBUG/ERROR 7 | log_freq = 1000 8 | 9 | """ video config """ 10 | image_size = 160 11 | frames = 13 12 | 13 | """ Model config """ 14 | model = dict( 15 | type = 'Cnn3DNet', 16 | structure_info = [ 17 | {'class': 'Conv3DKXBNRELU', 'in': 3, 'out': 24, 's': 2, 'kt': 1, 'k': 3}, \ 18 | {'class': 'SuperRes3DK1DWK1', 'in': 24, 'out': 24, 's': 2, 'kt': 1, 'k': 5, 'L': 1, 'btn': 48}, \ 19 | {'class': 'SuperRes3DK1DWK1', 'in': 24, 'out': 48, 's': 2, 'kt': 3, 'k': 3, 'L': 1, 'btn': 96}, \ 20 | {'class': 'SuperRes3DK1DWK1', 'in': 48, 'out': 96, 's': 2, 'kt': 3, 'k': 3, 'L': 1, 'btn': 192}, \ 21 | {'class': 'SuperRes3DK1DWK1', 'in': 96, 'out': 96, 's': 1, 'kt': 3, 'k': 3, 'L': 1, 'btn': 192}, \ 22 | {'class': 'SuperRes3DK1DWK1', 'in': 96, 'out': 192, 's': 2, 'kt': 3, 'k': 3, 'L': 1, 'btn': 384}, \ 23 | {'class': 'Conv3DKXBNRELU', 'in': 192, 'out': 512, 's': 1, 'kt': 1, 'k': 1},\ 24 | ] 25 | ) 26 | 27 | """ Budget config """ 28 | budgets = [ 29 | dict(type = "flops", budget = 20e8), 30 | dict(type = "layers",budget = 83), 31 | ] 32 | 33 | """ Score config """ 34 | score = dict(type = 'stentr', multi_block_ratio = [0,0,0,0,1], frames=13) 35 | 36 | """ Space config """ 37 | space = dict( 38 | type = 'space_3d_k1dwk1', 39 | image_size = image_size, 40 | ) 41 | 42 | """ Search config """ 43 | search=dict( 44 | minor_mutation = False, # whether fix the stage layer 45 | minor_iter = 500000, # which iteration to enable minor_mutation 46 | popu_size = 256, 47 | num_random_nets = 500000, # the searching iterations 48 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 49 | num_network = 1, 50 | ) 51 | 52 | -------------------------------------------------------------------------------- /configs/action_recognition/README.md: -------------------------------------------------------------------------------- 1 | ## Abstract 2 | 3 | * **Instruction** 4 | 5 | We search efficient E3D backbones for action recognition and E3D-S/M/L are aligned with X3D-S/M/L.
6 | 7 | 8 | * **Use the searching configs for Classification** 9 | 10 | ```shell 11 | sh tools/dist_search.sh configs/E3D_X3DS_FLOPs.py 12 | ``` 13 | **`E3D_X3DS_FLOPs.py` is the config for searching X3DS-like model within the budget of FLOPs using STEntr Score.** 14 | 15 | **`E3D_X3DM_FLOPs.py` is the config for searching X3DM-like model within the budget of FLOPs using STEntr Score.** 16 | 17 | **`E3D_X3DL_FLOPs.py` is the config for searching X3DL-like model within the budget of FLOPs using STEntr Score.** 18 | 19 | * **Use searched models in your own training pipeline** 20 | 21 | **copy `tinynas/deploy/cnn3dnet` to your pipeline, then** 22 | ```python 23 | from cnn3dnet import Cnn3DNet 24 | # for classifictaion 25 | model = Cnn3DNet(num_classes=classes, 26 | structure_txt=structure_txt, 27 | out_indices=(4,), 28 | classfication=True) 29 | 30 | # if load with pretrained model 31 | model.init_weights(pretrained=pretrained_pth) 32 | ``` 33 | 34 | *** 35 | 36 | ## Results on Sth-Sth V1 37 | 38 | | Backbone | size | FLOPs (G) | Top-1 | Top-5 | Structure | 39 | |:---------:|:-------:|:-------:|:-------:|:-------:|:--------:| 40 | | E3D-S | 160 | 1.9 | 47.1 | 75.6| [txt](models/E3D_S.txt) | 41 | | E3D-M | 224 | 4.7 | 49.4 | 78.1| [txt](models/E3D_M.txt) | 42 | | E3D-L | 312 | 18.3 | 51.1 | 78.7| [txt](models/E3D_L.txt) | 43 | 44 | 45 | 46 | *** 47 | ## Citation 48 | 49 | If you find this toolbox useful, please support us by citing this work as 50 | 51 | ``` 52 | @inproceedings{iclr23maxste, 53 | title = {Maximizing Spatio-Temporal Entropy of Deep 3D CNNs for Efficient Video Recognition}, 54 | author = {Junyan Wang and Zhenhong Sun and Yichen Qian and Dong Gong and Xiuyu Sun and Ming Lin and Maurice Pagnucco and Yang Song }, 55 | journal = {International Conference on Learning Representations}, 56 | year = {2023}, 57 | } 58 | ``` 59 | -------------------------------------------------------------------------------- /configs/action_recognition/models/E3D_L.txt: -------------------------------------------------------------------------------- 1 | { 'best_structures':[[ {'class': 'Conv3DKXBNRELU', 'in': 3, 'k': 3, 'kt': 1, 'out': 24, 's': 2}, 2 | { 'L': 3, 3 | 'btn': 32, 4 | 'class': 'SuperRes3DK1DWK1', 5 | 'in': 24, 6 | 'inner_class': 'Res3DK1DWK1', 7 | 'k': 5, 8 | 'kt': 1, 9 | 'out': 24, 10 | 's': 2}, 11 | { 'L': 13, 12 | 'btn': 120, 13 | 'class': 'SuperRes3DK1DWK1', 14 | 'in': 24, 15 | 'inner_class': 'Res3DK1DWK1', 16 | 'k': 3, 17 | 'kt': 3, 18 | 'out': 48, 19 | 's': 2}, 20 | { 'L': 13, 21 | 'btn': 176, 22 | 'class': 'SuperRes3DK1DWK1', 23 | 'in': 48, 24 | 'inner_class': 'Res3DK1DWK1', 25 | 'k': 3, 26 | 'kt': 3, 27 | 'out': 120, 28 | 's': 2}, 29 | { 'L': 13, 30 | 'btn': 176, 31 | 'class': 'SuperRes3DK1DWK1', 32 | 'in': 120, 33 | 'inner_class': 'Res3DK1DWK1', 34 | 'k': 3, 35 | 'kt': 3, 36 | 'out': 120, 37 | 's': 1}, 38 | { 'L': 13, 39 | 'btn': 480, 40 | 'class': 'SuperRes3DK1DWK1', 41 | 'in': 120, 42 | 'inner_class': 'Res3DK1DWK1', 43 | 'k': 3, 44 | 'kt': 3, 45 | 'out': 192, 46 | 's': 2}, 47 | {'class': 'Conv3DKXBNRELU', 'in': 192, 'k': 1, 'kt': 1, 'out': 512, 's': 1}]], 48 | 'space_arch': 'Cnn3DNet'} -------------------------------------------------------------------------------- /configs/action_recognition/models/E3D_M.txt: -------------------------------------------------------------------------------- 1 | {'best_structures': [[ 2 | {'class': 'Conv3DKXBNRELU', 'in': 3, 'k': 3, 'kt': 1, 'out': 24, 's': 2}, 3 | { 'L': 3, 4 | 'btn': 32, 5 | 'class': 'SuperRes3DK1DWK1', 6 | 'in': 24, 7 | 'inner_class': 'Res3DK1DWK1', 8 | 'k': 5, 9 | 'kt': 1, 10 | 'out': 24, 11 | 's': 2}, 12 | { 'L': 6, 13 | 'btn': 96, 14 | 'class': 'SuperRes3DK1DWK1', 15 | 'in': 24, 16 | 'inner_class': 'Res3DK1DWK1', 17 | 'k': 3, 18 | 'kt': 3, 19 | 'out': 64, 20 | 's': 2}, 21 | { 'L': 6, 22 | 'btn': 176, 23 | 'class': 'SuperRes3DK1DWK1', 24 | 'in': 64, 25 | 'inner_class': 'Res3DK1DWK1', 26 | 'k': 3, 27 | 'kt': 3, 28 | 'out': 120, 29 | 's': 2}, 30 | { 'L': 6, 31 | 'btn': 176, 32 | 'class': 'SuperRes3DK1DWK1', 33 | 'in': 120, 34 | 'inner_class': 'Res3DK1DWK1', 35 | 'k': 3, 36 | 'kt': 3, 37 | 'out': 120, 38 | 's': 1}, 39 | { 'L': 6, 40 | 'btn': 464, 41 | 'class': 'SuperRes3DK1DWK1', 42 | 'in': 120, 43 | 'inner_class': 'Res3DK1DWK1', 44 | 'k': 3, 45 | 'kt': 3, 46 | 'out': 184, 47 | 's': 2}, 48 | {'class': 'Conv3DKXBNRELU', 'in': 184, 'k': 1, 'kt': 1, 'out': 512, 's': 1}]], 49 | 'space_arch': 'Cnn3DNet'} -------------------------------------------------------------------------------- /configs/action_recognition/models/E3D_S.txt: -------------------------------------------------------------------------------- 1 | {'best_structures': [[ 2 | {'class': 'Conv3DKXBNRELU', 'in': 3, 'k': 3, 'kt': 1, 'out': 24, 's': 2}, 3 | { 'L': 3, 4 | 'btn': 32, 5 | 'class': 'SuperRes3DK1DWK1', 6 | 'in': 24, 7 | 'inner_class': 'Res3DK1DWK1', 8 | 'k': 5, 9 | 'kt': 1, 10 | 'out': 24, 11 | 's': 2}, 12 | { 'L': 6, 13 | 'btn': 96, 14 | 'class': 'SuperRes3DK1DWK1', 15 | 'in': 24, 16 | 'inner_class': 'Res3DK1DWK1', 17 | 'k': 3, 18 | 'kt': 3, 19 | 'out': 48, 20 | 's': 2}, 21 | { 'L': 6, 22 | 'btn': 176, 23 | 'class': 'SuperRes3DK1DWK1', 24 | 'in': 48, 25 | 'inner_class': 'Res3DK1DWK1', 26 | 'k': 3, 27 | 'kt': 3, 28 | 'out': 120, 29 | 's': 2}, 30 | { 'L': 6, 31 | 'btn': 176, 32 | 'class': 'SuperRes3DK1DWK1', 33 | 'in': 120, 34 | 'inner_class': 'Res3DK1DWK1', 35 | 'k': 3, 36 | 'kt': 3, 37 | 'out': 120, 38 | 's': 1}, 39 | { 'L': 6, 40 | 'btn': 384, 41 | 'class': 'SuperRes3DK1DWK1', 42 | 'in': 120, 43 | 'inner_class': 'Res3DK1DWK1', 44 | 'k': 3, 45 | 'kt': 3, 46 | 'out': 256, 47 | 's': 2}, 48 | {'class': 'Conv3DKXBNRELU', 'in': 256, 'k': 1, 'kt': 1, 'out': 512, 's': 1}]], 49 | 'space_arch': 'Cnn3DNet'} -------------------------------------------------------------------------------- /configs/classification/MBV2_FLOPs.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | work_dir = './save_model/mbv2_flops300e6/' 6 | log_level = 'INFO' # INFO/DEBUG/ERROR 7 | log_freq = 1000 8 | 9 | """ image config """ 10 | image_size = 224 # 224 for Imagenet, 480 for detection, 160 for mcu 11 | 12 | """ Model config """ 13 | model = dict( 14 | type = 'CnnNet', 15 | structure_info =[\ 16 | {'class': 'ConvKXBNRELU', 'in': 3, 'out': 16, 's': 2, 'k': 3}, \ 17 | {'class': 'SuperResK1DWK1', 'in': 16, 'out': 24, 's': 2, 'k': 3, 'L': 1, 'btn': 48}, \ 18 | {'class': 'SuperResK1DWK1', 'in': 24, 'out': 48, 's': 2, 'k': 3, 'L': 1, 'btn': 96}, \ 19 | {'class': 'SuperResK1DWK1', 'in': 48, 'out': 64, 's': 2, 'k': 3, 'L': 1, 'btn': 128}, \ 20 | {'class': 'SuperResK1DWK1', 'in': 64, 'out': 96, 's': 1, 'k': 3, 'L': 1, 'btn': 192}, \ 21 | {'class': 'SuperResK1DWK1', 'in': 96, 'out': 192, 's': 2, 'k': 3, 'L': 1, 'btn': 384}, \ 22 | {'class': 'ConvKXBNRELU', 'in': 192, 'out': 1280, 's': 1, 'k': 1}, \ 23 | ] 24 | ) 25 | 26 | """ Budget config """ 27 | budgets = [ 28 | dict(type = "flops", budget = 300e6), 29 | dict(type = "layers",budget = 53), 30 | ] 31 | 32 | """ Score config """ 33 | score = dict(type = 'madnas', multi_block_ratio = [0,0,0,0,1]) 34 | 35 | """ Space config """ 36 | space = dict( 37 | type = 'space_k1dwk1', 38 | image_size = image_size, 39 | ) 40 | 41 | """ Search config """ 42 | search=dict( 43 | minor_mutation = False, # whether fix the stage layer 44 | minor_iter = 100000, # which iteration to enable minor_mutation 45 | popu_size = 256, 46 | num_random_nets = 100000, # the searching iterations 47 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 48 | num_network = 1, 49 | ) 50 | 51 | -------------------------------------------------------------------------------- /configs/classification/R50_FLOPs.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | work_dir = './save_model/R50_R224_FLOPs41e8/' 6 | log_level = 'INFO' # INFO/DEBUG/ERROR 7 | log_freq = 1000 8 | 9 | """ image config """ 10 | image_size = 224 # 224 for Imagenet, 480 for detection, 160 for mcu 11 | 12 | """ Model config """ 13 | model = dict( 14 | type = 'CnnNet', 15 | structure_info = [ 16 | {'class': 'ConvKXBNRELU', 'in': 3, 'out': 32, 's': 2, 'k': 3}, \ 17 | {'class': 'SuperResK1KXK1', 'in': 32, 'out': 256, 's': 2, 'k': 3, 'L': 1, 'btn': 64}, \ 18 | {'class': 'SuperResK1KXK1', 'in': 256, 'out': 512, 's': 2, 'k': 3, 'L': 1, 'btn': 128}, \ 19 | {'class': 'SuperResK1KXK1', 'in': 512, 'out': 768, 's': 2, 'k': 3, 'L': 1, 'btn': 256}, \ 20 | {'class': 'SuperResK1KXK1', 'in': 768, 'out': 1024, 's': 1, 'k': 3, 'L': 1, 'btn': 256}, \ 21 | {'class': 'SuperResK1KXK1', 'in': 1024, 'out': 2048, 's': 2, 'k': 3, 'L': 1, 'btn': 512}, \ 22 | ] 23 | ) 24 | 25 | """ Budget config """ 26 | budgets = [ 27 | dict(type = "flops", budget = 41e8), 28 | dict(type = "layers",budget = 49), 29 | dict(type = "model_size", budget = 25.55e6) 30 | ] 31 | 32 | """ Score config """ 33 | score = dict(type = 'madnas', multi_block_ratio = [0,0,0,0,1]) 34 | 35 | """ Space config """ 36 | space = dict( 37 | type = 'space_k1kxk1', 38 | image_size = image_size, 39 | ) 40 | 41 | """ Search config """ 42 | search=dict( 43 | minor_mutation = False, # whether fix the stage layer 44 | minor_iter = 100000, # which iteration to enable minor_mutation 45 | popu_size = 256, 46 | num_random_nets = 100000, # the searching iterations 47 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 48 | num_network = 1, 49 | ) 50 | 51 | -------------------------------------------------------------------------------- /configs/classification/README.md: -------------------------------------------------------------------------------- 1 | ## Abstract 2 | 3 | * **Instruction** 4 | 5 | In this folder, we provide the structure txt and parameters of the model searched by TinyNAS.

6 | 7 | * **Use the searching configs for Classification** 8 | ```shell 9 | sh tools/dist_search.sh configs/MBV2_FLOPs.py 10 | ``` 11 | **`MBV2_FLOPs.py` is the config for searching MBV2-like model within the budget of FLOPs.** 12 | 13 | **`R50_FLOPs.py` is the config for searching R50-like model within the budget of FLOPs.** 14 | 15 | **`deepmad_R18_FLOPs.py` is the config for searching R18-like model within the budget of FLOPs using DeepMAD.** 16 | 17 | **`deepmad_R34_FLOPs.py` is the config for searching R34-like model within the budget of FLOPs using DeepMAD.** 18 | 19 | **`deepmad_R50_FLOPs.py` is the config for searching R50-like model within the budget of FLOPs using DeepMAD.** 20 | 21 | **`deepmad_29M_224.py` is the config for searching 29M SoTA model with 224 resolution within the budget of FLOPs using DeepMAD.** 22 | 23 | **`deepmad_29M_288.py` is the config for searching 29M SoTA model with 288 resolution within the budget of FLOPs using DeepMAD.** 24 | 25 | **`deepmad_50M.py` is the config for searching 50M SoTA model within the budget of FLOPs using DeepMAD.** 26 | 27 | **`deepmad_89M.py` is the config for searching 89M SoTA model within the budget of FLOPs using DeepMAD.**

28 | 29 | 30 | * **Use searched models in your own training pipeline** 31 | 32 | **copy `tinynas/deploy/cnnnet` to your pipeline, then** 33 | ```python 34 | from cnnnet import CnnNet 35 | # for classifictaion 36 | model = CnnNet(num_classes=classes, 37 | structure_txt=structure_txt, 38 | out_indices=(4,), 39 | classfication=True) 40 | 41 | # if load with pretrained model 42 | model.init_weights(pretrained=pretrained_pth) 43 | ``` 44 | *** 45 | 46 | ## Results and Models 47 | 48 | | Backbone | size | Param (M) | FLOPs (G) | Top-1 | Structure | Download | 49 | |:---------:|:-------:|:-------:|:-------:|:-------:|:--------:|:------:| 50 | | R18-like | 224 | 10.8 | 1.7 | 78.44 | [txt](models/R18-like.txt) |[model](https://idstcv.oss-cn-zhangjiakou.aliyuncs.com/TinyNAS/classfication/R18-like.pth.tar) | 51 | | R50-like | 224 | 21.3 | 3.6 | 80.04 | [txt](models/R50-like.txt) |[model](https://idstcv.oss-cn-zhangjiakou.aliyuncs.com/TinyNAS/classfication/R50-like.pth.tar) | 52 | | R152-like | 224 | 53.5 | 10.5 | 81.59 | [txt](models/R152-like.txt) |[model](https://idstcv.oss-cn-zhangjiakou.aliyuncs.com/TinyNAS/classfication/R152-like.pth.tar) | 53 | 54 | 55 | **Note**: 56 | 57 | 1. These models are trained on ImageNet dataset with 8 NVIDIA V100 GPUs. 58 | 2. Use SGD optimizer with momentum 0.9; weight decay 5e-5 for ImageNet; initial learning rate 0.1 with 480 epochs. 59 | 60 | *** 61 | ## Citation 62 | 63 | If you find this toolbox useful, please support us by citing this work as 64 | ``` 65 | @inproceedings{cvpr2023deepmad, 66 | title = {DeepMAD: Mathematical Architecture Design for Deep Convolutional Neural Network}, 67 | author = {Xuan Shen, Yaohua Wang, Ming Lin, Dylan Huang, Hao Tang, Xiuyu Sun, Yanzhi Wang}, 68 | booktitle = {Conference on Computer Vision and Pattern Recognition 2023}, 69 | year = {2023}, 70 | url = {https://arxiv.org/abs/2303.02165} 71 | } 72 | ``` 73 | 74 | ``` 75 | @inproceedings{zennas, 76 | title = {Zen-NAS: A Zero-Shot NAS for High-Performance Deep Image Recognition}, 77 | author = {Ming Lin and Pichao Wang and Zhenhong Sun and Hesen Chen and Xiuyu Sun and Qi Qian and Hao Li and Rong Jin}, 78 | booktitle = {2021 IEEE/CVF International Conference on Computer Vision}, 79 | year = {2021}, 80 | } 81 | ``` 82 | -------------------------------------------------------------------------------- /configs/classification/deepmad_29M_224.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | # The DeepMAD method is from the paper https://arxiv.org/abs/2303.02165 of Alibaba. 5 | 6 | work_dir = './save_model/deepmad-29M-224/' 7 | log_level = 'INFO' # INFO/DEBUG/ERROR 8 | log_freq = 1000 9 | 10 | """ image config """ 11 | image_size = 224 12 | 13 | """ Model config """ 14 | model = dict( 15 | type = 'CnnNet', 16 | structure_info = [ 17 | {'class': 'ConvKXBNRELU', 'in': 3, 'out': 32, 's': 2, 'k': 3}, \ 18 | {'class': 'SuperResK1DWSEK1', 'in': 32, 'out': 72, 's': 2, 'k': 3, 'L': 1, 'btn': 432}, \ 19 | {'class': 'SuperResK1DWSEK1', 'in': 72, 'out': 128, 's': 2, 'k': 3, 'L': 1, 'btn': 768}, \ 20 | {'class': 'SuperResK1DWSEK1', 'in': 128, 'out': 192, 's': 2, 'k': 3, 'L': 1, 'btn': 1152}, \ 21 | {'class': 'SuperResK1DWSEK1', 'in': 192, 'out': 288, 's': 2, 'k': 3, 'L': 1, 'btn': 1728}, \ 22 | {'class': 'SuperResK1DWSEK1', 'in': 288, 'out': 448, 's': 1, 'k': 3, 'L': 1, 'btn': 2688}, \ 23 | {'class': 'ConvKXBNRELU', 'in': 448, 'out': 1792, 's': 1, 'k': 1}, \ 24 | ] 25 | ) 26 | 27 | """ Budget config """ 28 | budgets = [ 29 | dict(type = "flops", budget = 4.5e9), 30 | dict(type = "model_size", budget = 29e6), 31 | dict(type = "efficient_score", budget = 0.5) 32 | ] 33 | 34 | """ Score config """ 35 | score = dict(type = 'deepmad', multi_block_ratio = [1,1,1,1,8], alpha1=1, alpha2=1, depth_penalty_ratio=10.) 36 | 37 | """ Space config """ 38 | space = dict( 39 | type = 'space_k1dwsek1', 40 | image_size = image_size, 41 | ) 42 | 43 | """ Search config """ 44 | search=dict( 45 | minor_mutation = False, # whether fix the stage layer 46 | minor_iter = 100000, # which iteration to enable minor_mutation 47 | popu_size = 256, 48 | num_random_nets = 500000, # the searching iterations 49 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 50 | num_network = 1, 51 | ) 52 | 53 | -------------------------------------------------------------------------------- /configs/classification/deepmad_29M_288.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | # The DeepMAD method is from the paper https://arxiv.org/abs/2303.02165 of Alibaba. 5 | 6 | work_dir = './save_model/deepmad_29M_288/' 7 | log_level = 'INFO' # INFO/DEBUG/ERROR 8 | log_freq = 1000 9 | 10 | """ image config """ 11 | image_size = 288 12 | 13 | """ Model config """ 14 | model = dict( 15 | type = 'CnnNet', 16 | structure_info = [ 17 | {'class': 'ConvKXBNRELU', 'in': 3, 'out': 16, 's': 2, 'k': 3}, \ 18 | {'class': 'SuperResK1DWSEK1', 'in': 16, 'out': 32, 's': 2, 'k': 3, 'L': 1, 'btn': 192}, \ 19 | {'class': 'SuperResK1DWSEK1', 'in': 32, 'out': 48, 's': 2, 'k': 3, 'L': 1, 'btn': 288}, \ 20 | {'class': 'SuperResK1DWSEK1', 'in': 48, 'out': 72, 's': 2, 'k': 3, 'L': 1, 'btn': 432}, \ 21 | {'class': 'SuperResK1DWSEK1', 'in': 72, 'out': 108, 's': 1, 'k': 3, 'L': 1, 'btn': 648}, \ 22 | {'class': 'SuperResK1DWSEK1', 'in': 108, 'out': 162, 's': 2, 'k': 3, 'L': 1, 'btn': 972}, \ 23 | {'class': 'ConvKXBNRELU', 'in': 162, 'out': 1792, 's': 1, 'k': 1}, \ 24 | ] 25 | ) 26 | 27 | """ Budget config """ 28 | budgets = [ 29 | dict(type = "flops", budget = 4.5e9), 30 | dict(type = "model_size", budget = 29e6), 31 | dict(type = "efficient_score", budget = 0.5) 32 | ] 33 | 34 | """ Score config """ 35 | score = dict(type = 'deepmad', multi_block_ratio = [1,1,1,1,8], alpha1=1, alpha2=1, depth_penalty_ratio=10.) 36 | 37 | """ Space config """ 38 | space = dict( 39 | type = 'space_k1dwsek1', 40 | image_size = image_size, 41 | ) 42 | 43 | """ Search config """ 44 | search=dict( 45 | minor_mutation = False, # whether fix the stage layer 46 | minor_iter = 100000, # which iteration to enable minor_mutation 47 | popu_size = 256, 48 | num_random_nets = 500000, # the searching iterations 49 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 50 | num_network = 1, 51 | ) 52 | 53 | -------------------------------------------------------------------------------- /configs/classification/deepmad_50M.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | # The DeepMAD method is from the paper https://arxiv.org/abs/2303.02165 of Alibaba. 5 | 6 | work_dir = './save_model/deepmad_50M/' 7 | log_level = 'INFO' # INFO/DEBUG/ERROR 8 | log_freq = 1000 9 | 10 | """ image config """ 11 | image_size = 224 12 | 13 | """ Model config """ 14 | model = dict( 15 | type = 'CnnNet', 16 | structure_info = [ 17 | {'class': 'ConvKXBNRELU', 'in': 3, 'out': 48, 's': 2, 'k': 3}, \ 18 | {'class': 'SuperResK1DWSEK1', 'in': 48, 'out':84, 's': 2, 'k': 3, 'L': 1, 'btn': 504}, \ 19 | {'class': 'SuperResK1DWSEK1', 'in': 84, 'out': 144, 's': 2, 'k': 3, 'L': 1, 'btn': 864}, \ 20 | {'class': 'SuperResK1DWSEK1', 'in': 144, 'out': 216, 's': 2, 'k': 3, 'L': 1, 'btn': 1296}, \ 21 | {'class': 'SuperResK1DWSEK1', 'in': 216, 'out': 324, 's': 2, 'k': 3, 'L': 1, 'btn': 1944}, \ 22 | {'class': 'SuperResK1DWSEK1', 'in': 324, 'out': 512, 's': 1, 'k': 3, 'L': 1, 'btn': 3072}, \ 23 | {'class': 'ConvKXBNRELU', 'in': 512, 'out': 2048, 's': 1, 'k': 1}, \ 24 | ] 25 | ) 26 | 27 | """ Budget config """ 28 | budgets = [ 29 | dict(type = "flops", budget = 8.7e9), 30 | dict(type = "model_size", budget = 50e6), 31 | dict(type = "efficient_score", budget = 0.5) 32 | ] 33 | 34 | """ Score config """ 35 | score = dict(type = 'deepmad', multi_block_ratio = [1,1,1,1,8], alpha1=1, alpha2=1, depth_penalty_ratio=10.) 36 | 37 | """ Space config """ 38 | space = dict( 39 | type = 'space_k1dwsek1', 40 | image_size = image_size, 41 | ) 42 | 43 | """ Search config """ 44 | search=dict( 45 | minor_mutation = False, # whether fix the stage layer 46 | minor_iter = 100000, # which iteration to enable minor_mutation 47 | popu_size = 256, 48 | num_random_nets = 500000, # the searching iterations 49 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 50 | num_network = 1, 51 | ) 52 | 53 | -------------------------------------------------------------------------------- /configs/classification/deepmad_89M.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | # The DeepMAD method is from the paper https://arxiv.org/abs/2303.02165 of Alibaba. 5 | 6 | work_dir = './save_model/deepmad_89M/' 7 | log_level = 'INFO' # INFO/DEBUG/ERROR 8 | log_freq = 1000 9 | 10 | """ image config """ 11 | image_size = 224 12 | 13 | """ Model config """ 14 | model = dict( 15 | type = 'CnnNet', 16 | structure_info = [ 17 | {'class': 'ConvKXBNRELU', 'in': 3, 'out': 64, 's': 2, 'k': 3}, \ 18 | {'class': 'SuperResK1DWSEK1', 'in': 64, 'out': 144, 's': 2, 'k': 3, 'L': 1, 'btn': 865}, \ 19 | {'class': 'SuperResK1DWSEK1', 'in': 144, 'out': 216, 's': 2, 'k': 3, 'L': 1, 'btn': 1296}, \ 20 | {'class': 'SuperResK1DWSEK1', 'in': 216, 'out': 324, 's': 2, 'k': 3, 'L': 1, 'btn': 1944}, \ 21 | {'class': 'SuperResK1DWSEK1', 'in': 324, 'out': 486, 's': 2, 'k': 3, 'L': 1, 'btn': 2916}, \ 22 | {'class': 'SuperResK1DWSEK1', 'in': 486, 'out': 729, 's': 1, 'k': 3, 'L': 1, 'btn': 4374}, \ 23 | {'class': 'ConvKXBNRELU', 'in': 729, 'out': 2560, 's': 1, 'k': 1}, \ 24 | ] 25 | ) 26 | 27 | """ Budget config """ 28 | budgets = [ 29 | dict(type = "flops", budget = 15.4e9), 30 | dict(type = "model_size", budget = 89e6), 31 | dict(type = "efficient_score", budget = 0.5) 32 | ] 33 | 34 | """ Score config """ 35 | score = dict(type = 'deepmad', multi_block_ratio = [1,1,1,1,8], alpha1=1, alpha2=1, depth_penalty_ratio=10.) 36 | 37 | """ Space config """ 38 | space = dict( 39 | type = 'space_k1dwsek1', 40 | image_size = image_size, 41 | ) 42 | 43 | """ Search config """ 44 | search=dict( 45 | minor_mutation = False, # whether fix the stage layer 46 | minor_iter = 100000, # which iteration to enable minor_mutation 47 | popu_size = 256, 48 | num_random_nets = 500000, # the searching iterations 49 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 50 | num_network = 1, 51 | ) 52 | 53 | -------------------------------------------------------------------------------- /configs/classification/deepmad_R18_FLOPs.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | # The DeepMAD method is from the paper https://arxiv.org/abs/2303.02165 of Alibaba. 5 | 6 | work_dir = './save_model/deepmad_R18/' 7 | log_level = 'INFO' # INFO/DEBUG/ERROR 8 | log_freq = 1000 9 | 10 | """ image config """ 11 | image_size = 224 12 | 13 | """ Model config """ 14 | model = dict( 15 | type = 'CnnNet', 16 | structure_info = [ 17 | {'class': 'ConvKXBNRELU', 'in': 3, 'out': 32, 's': 2, 'k': 3}, \ 18 | {'class': 'SuperResK1KXK1', 'in': 32, 'out': 256, 's': 2, 'k': 3, 'L': 1, 'btn': 64}, \ 19 | {'class': 'SuperResK1KXK1', 'in': 256, 'out': 512, 's': 2, 'k': 3, 'L': 1, 'btn': 128}, \ 20 | {'class': 'SuperResK1KXK1', 'in': 512, 'out': 768, 's': 2, 'k': 3, 'L': 1, 'btn': 256}, \ 21 | {'class': 'SuperResK1KXK1', 'in': 768, 'out': 1024, 's': 1, 'k': 3, 'L': 1, 'btn': 256}, \ 22 | {'class': 'SuperResK1KXK1', 'in': 1024, 'out': 2048, 's': 2, 'k': 3, 'L': 1, 'btn': 512}, \ 23 | ] 24 | ) 25 | 26 | """ Budget config """ 27 | budgets = [ 28 | dict(type = "flops", budget = 1.82e9), 29 | dict(type = "model_size", budget = 11.69e6), 30 | dict(type = "efficient_score", budget = 0.3) 31 | ] 32 | 33 | """ Score config """ 34 | score = dict(type = 'deepmad', multi_block_ratio = [1,1,1,1,8], alpha1=1, alpha2=1, depth_penalty_ratio=10.) 35 | 36 | """ Space config """ 37 | space = dict( 38 | type = 'space_k1kxk1', 39 | image_size = image_size, 40 | ) 41 | 42 | """ Search config """ 43 | search=dict( 44 | minor_mutation = False, # whether fix the stage layer 45 | minor_iter = 100000, # which iteration to enable minor_mutation 46 | popu_size = 256, 47 | num_random_nets = 500000, # the searching iterations 48 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 49 | num_network = 1, 50 | ) 51 | 52 | -------------------------------------------------------------------------------- /configs/classification/deepmad_R34_FLOPs.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | # The DeepMAD method is from the paper https://arxiv.org/abs/2303.02165 of Alibaba. 5 | 6 | work_dir = './save_model/deepmad_R34/' 7 | log_level = 'INFO' # INFO/DEBUG/ERROR 8 | log_freq = 1000 9 | 10 | """ image config """ 11 | image_size = 224 12 | 13 | """ Model config """ 14 | model = dict( 15 | type = 'CnnNet', 16 | structure_info = [ 17 | {'class': 'ConvKXBNRELU', 'in': 3, 'out': 32, 's': 2, 'k': 3}, \ 18 | {'class': 'SuperResK1KXK1', 'in': 32, 'out': 256, 's': 2, 'k': 3, 'L': 1, 'btn': 64}, \ 19 | {'class': 'SuperResK1KXK1', 'in': 256, 'out': 512, 's': 2, 'k': 3, 'L': 1, 'btn': 128}, \ 20 | {'class': 'SuperResK1KXK1', 'in': 512, 'out': 768, 's': 2, 'k': 3, 'L': 1, 'btn': 256}, \ 21 | {'class': 'SuperResK1KXK1', 'in': 768, 'out': 1024, 's': 1, 'k': 3, 'L': 1, 'btn': 256}, \ 22 | {'class': 'SuperResK1KXK1', 'in': 1024, 'out': 2048, 's': 2, 'k': 3, 'L': 1, 'btn': 512}, \ 23 | ] 24 | ) 25 | 26 | """ Budget config """ 27 | budgets = [ 28 | dict(type = "flops", budget = 3.68e9), 29 | dict(type = "model_size", budget = 21.80e6), 30 | dict(type = "efficient_score", budget = 0.3) 31 | ] 32 | 33 | """ Score config """ 34 | score = dict(type = 'deepmad', multi_block_ratio = [1,1,1,1,8], alpha1=1, alpha2=1, depth_penalty_ratio=10.) 35 | 36 | """ Space config """ 37 | space = dict( 38 | type = 'space_k1kxk1', 39 | image_size = image_size, 40 | ) 41 | 42 | """ Search config """ 43 | search=dict( 44 | minor_mutation = False, # whether fix the stage layer 45 | minor_iter = 100000, # which iteration to enable minor_mutation 46 | popu_size = 256, 47 | num_random_nets = 500000, # the searching iterations 48 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 49 | num_network = 1, 50 | ) 51 | 52 | -------------------------------------------------------------------------------- /configs/classification/deepmad_R50_FLOPs.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | # The DeepMAD method is from the paper https://arxiv.org/abs/2303.02165 of Alibaba. 5 | 6 | work_dir = './save_model/deepmad_R50/' 7 | log_level = 'INFO' # INFO/DEBUG/ERROR 8 | log_freq = 1000 9 | 10 | """ image config """ 11 | image_size = 224 12 | 13 | """ Model config """ 14 | model = dict( 15 | type = 'CnnNet', 16 | structure_info = [ 17 | {'class': 'ConvKXBNRELU', 'in': 3, 'out': 32, 's': 2, 'k': 3}, \ 18 | {'class': 'SuperResK1KXK1', 'in': 32, 'out': 256, 's': 2, 'k': 3, 'L': 1, 'btn': 64}, \ 19 | {'class': 'SuperResK1KXK1', 'in': 256, 'out': 512, 's': 2, 'k': 3, 'L': 1, 'btn': 128}, \ 20 | {'class': 'SuperResK1KXK1', 'in': 512, 'out': 768, 's': 2, 'k': 3, 'L': 1, 'btn': 256}, \ 21 | {'class': 'SuperResK1KXK1', 'in': 768, 'out': 1024, 's': 1, 'k': 3, 'L': 1, 'btn': 256}, \ 22 | {'class': 'SuperResK1KXK1', 'in': 1024, 'out': 2048, 's': 2, 'k': 3, 'L': 1, 'btn': 512}, \ 23 | ] 24 | ) 25 | 26 | """ Budget config """ 27 | budgets = [ 28 | dict(type = "flops", budget = 4.13e9), 29 | dict(type = "model_size", budget = 25.55e6), 30 | dict(type = "efficient_score", budget = 0.3) 31 | ] 32 | 33 | """ Score config """ 34 | score = dict(type = 'deepmad', multi_block_ratio = [1,1,1,1,8], alpha1=1, alpha2=1, depth_penalty_ratio=10.) 35 | 36 | """ Space config """ 37 | space = dict( 38 | type = 'space_k1kxk1', 39 | image_size = image_size, 40 | ) 41 | 42 | """ Search config """ 43 | search=dict( 44 | minor_mutation = False, # whether fix the stage layer 45 | minor_iter = 100000, # which iteration to enable minor_mutation 46 | popu_size = 256, 47 | num_random_nets = 500000, # the searching iterations 48 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 49 | num_network = 1, 50 | ) 51 | 52 | -------------------------------------------------------------------------------- /configs/classification/models/R152-like.txt: -------------------------------------------------------------------------------- 1 | { 'best_structures':[ [ 2 | {'class': 'ConvKXBNRELU', 'in': 3, 'k': 3, 'out': 128, 's': 2}, 3 | { 'L': 4, 4 | 'btn': 88, 5 | 'class': 'SuperResK1KXK1', 6 | 'in': 128, 7 | 'k': 3, 8 | 'out': 512, 9 | 's': 2}, 10 | { 'L': 8, 11 | 'btn': 176, 12 | 'class': 'SuperResK1KXK1', 13 | 'in': 512, 14 | 'k': 3, 15 | 'out': 720, 16 | 's': 2}, 17 | { 'L': 13, 18 | 'btn': 256, 19 | 'class': 'SuperResK1KXK1', 20 | 'in': 720, 21 | 'k': 3, 22 | 'out': 720, 23 | 's': 2}, 24 | { 'L': 10, 25 | 'btn': 360, 26 | 'class': 'SuperResK1KXK1', 27 | 'in': 720, 28 | 'k': 3, 29 | 'out': 1024, 30 | 's': 2}, 31 | { 'L': 12, 32 | 'btn': 256, 33 | 'class': 'SuperResK1KXK1', 34 | 'in': 1024, 35 | 'k': 3, 36 | 'out': 1024, 37 | 's': 1}]], 38 | 'space_arch': 'CnnNet'} -------------------------------------------------------------------------------- /configs/classification/models/R18-like.txt: -------------------------------------------------------------------------------- 1 | { 'best_structures':[ [ 2 | {'class': 'ConvKXBNRELU', 'in': 3, 'k': 3, 'out': 40, 's': 2}, 3 | { 'L': 2, 4 | 'btn': 64, 5 | 'class': 'SuperResK1KXK1', 6 | 'in': 40, 7 | 'k': 3, 8 | 'out': 256, 9 | 's': 2}, 10 | { 'L': 3, 11 | 'btn': 88, 12 | 'class': 'SuperResK1KXK1', 13 | 'in': 256, 14 | 'k': 3, 15 | 'out': 360, 16 | 's': 2}, 17 | { 'L': 6, 18 | 'btn': 128, 19 | 'class': 'SuperResK1KXK1', 20 | 'in': 360, 21 | 'k': 3, 22 | 'out': 512, 23 | 's': 2}, 24 | { 'L': 4, 25 | 'btn': 176, 26 | 'class': 'SuperResK1KXK1', 27 | 'in': 512, 28 | 'k': 3, 29 | 'out': 512, 30 | 's': 2}, 31 | { 'L': 12, 32 | 'btn': 176, 33 | 'class': 'SuperResK1KXK1', 34 | 'in': 512, 35 | 'k': 3, 36 | 'out': 512, 37 | 's': 1}]], 38 | 'space_arch': 'CnnNet'} -------------------------------------------------------------------------------- /configs/classification/models/R50-like.txt: -------------------------------------------------------------------------------- 1 | { 'best_structures':[ [ 2 | {'class': 'ConvKXBNRELU', 'in': 3, 'k': 3, 'out': 16, 's': 2}, 3 | { 'L': 6, 4 | 'btn': 64, 5 | 'class': 'SuperResK1KXK1', 6 | 'in': 16, 7 | 'k': 3, 8 | 'out': 256, 9 | 's': 2}, 10 | { 'L': 8, 11 | 'btn': 88, 12 | 'class': 'SuperResK1KXK1', 13 | 'in': 256, 14 | 'k': 3, 15 | 'out': 360, 16 | 's': 2}, 17 | { 'L': 7, 18 | 'btn': 176, 19 | 'class': 'SuperResK1KXK1', 20 | 'in': 360, 21 | 'k': 3, 22 | 'out': 512, 23 | 's': 2}, 24 | { 'L': 2, 25 | 'btn': 360, 26 | 'class': 'SuperResK1KXK1', 27 | 'in': 512, 28 | 'k': 3, 29 | 'out': 720, 30 | 's': 2}, 31 | { 'L': 4, 32 | 'btn': 256, 33 | 'class': 'SuperResK1KXK1', 34 | 'in': 720, 35 | 'k': 3, 36 | 'out': 2896, 37 | 's': 1}]], 38 | 'space_arch': 'CnnNet'} -------------------------------------------------------------------------------- /configs/classification/models/deepmad-29M-224.txt: -------------------------------------------------------------------------------- 1 | { 'best_structures':[ [ 2 | {'class': 'ConvKXBNRELU', 'in': 3, 'k': 3, 'out': 40, 's': 2}, 3 | { 'L': 2, 'btn': 240, 'class': 'SuperResK1DWSEK1', 'in': 40, 'inner_class': 'ResK1DWSEK1', 'k': 5, 'out': 40, 's': 1}, 4 | { 'L': 4, 'btn': 512, 'class': 'SuperResK1DWSEK1', 'in': 40, 'inner_class': 'ResK1DWSEK1', 'k': 5, 'out': 85, 's': 2}, 5 | { 'L': 6, 'btn': 800, 'class': 'SuperResK1DWSEK1', 'in': 85, 'inner_class': 'ResK1DWSEK1', 'k': 5, 'out': 134, 's': 2}, 6 | { 'L': 6, 'btn': 1208, 'class': 'SuperResK1DWSEK1', 'in': 134, 'inner_class': 'ResK1DWSEK1', 'k': 5, 'out': 201, 's': 2}, 7 | { 'L': 5, 'btn': 1872, 'class': 'SuperResK1DWSEK1', 'in': 201, 'inner_class': 'ResK1DWSEK1', 'k': 5, 'out': 312, 's': 2}, 8 | {'class': 'ConvKXBNRELU', 'in': 312, 'k': 1, 'out': 1792, 's': 1}]], 9 | 'space_arch': 'CnnNet'} 10 | 11 | -------------------------------------------------------------------------------- /configs/classification/models/deepmad-29M-288.txt: -------------------------------------------------------------------------------- 1 | { 'best_structures':[ [ 2 | {'class': 'ConvKXBNRELU', 'in': 3, 'k': 3, 'out': 40, 's': 2}, 3 | { 'L': 4, 4 | 'btn': 368, 5 | 'class': 'SuperResK1DWSEK1', 6 | 'in': 40, 7 | 'inner_class': 'ResK1DWSEK1', 8 | 'k': 5, 9 | 'out': 61, 10 | 's': 2}, 11 | { 'L': 4, 12 | 'btn': 576, 13 | 'class': 'SuperResK1DWSEK1', 14 | 'in': 61, 15 | 'inner_class': 'ResK1DWSEK1', 16 | 'k': 5, 17 | 'out': 96, 18 | 's': 2}, 19 | { 'L': 5, 20 | 'btn': 872, 21 | 'class': 'SuperResK1DWSEK1', 22 | 'in': 96, 23 | 'inner_class': 'ResK1DWSEK1', 24 | 'k': 5, 25 | 'out': 145, 26 | 's': 2}, 27 | { 'L': 6, 28 | 'btn': 1304, 29 | 'class': 'SuperResK1DWSEK1', 30 | 'in': 145, 31 | 'inner_class': 'ResK1DWSEK1', 32 | 'k': 5, 33 | 'out': 217, 34 | 's': 1}, 35 | { 'L': 4, 36 | 'btn': 1968, 37 | 'class': 'SuperResK1DWSEK1', 38 | 'in': 217, 39 | 'inner_class': 'ResK1DWSEK1', 40 | 'k': 5, 41 | 'out': 328, 42 | 's': 2}, 43 | {'class': 'ConvKXBNRELU', 'in': 328, 'k': 1, 'out': 1792, 's': 1}]], 44 | 'space_arch': 'CnnNet'} 45 | -------------------------------------------------------------------------------- /configs/classification/models/deepmad-50M.txt: -------------------------------------------------------------------------------- 1 | { 'best_structures':[ [ 2 | {'class': 'ConvKXBNRELU', 'in': 3, 'k': 3, 'out': 48, 's': 2}, 3 | {'L': 7, 'btn': 672, 'class': 'SuperResK1DWSEK1', 'in': 48, 'inner_class': 'ResK1DWSEK1', 'k': 5, 'out': 112, 's': 2}, 4 | {'L': 9, 'btn': 1008, 'class': 'SuperResK1DWSEK1', 'in': 112, 'inner_class': 'ResK1DWSEK1', 'k': 5, 'out': 168, 's': 2}, 5 | {'L': 7, 'btn': 1512, 'class': 'SuperResK1DWSEK1', 'in': 168, 'inner_class': 'ResK1DWSEK1', 'k': 5, 'out': 252, 's': 2}, 6 | {'L': 3, 'btn': 2272, 'class': 'SuperResK1DWSEK1', 'in': 252, 'inner_class': 'ResK1DWSEK1', 'k': 5, 'out': 378, 's': 2}, 7 | {'L': 1, 'btn': 3456, 'class': 'SuperResK1DWSEK1', 'in': 378, 'inner_class': 'ResK1DWSEK1', 'k': 3, 'out': 576, 's': 1}, 8 | {'class': 'ConvKXBNRELU', 'in': 576, 'k': 1, 'out': 2048, 's': 1}]], 9 | 'space_arch': 'CnnNet'} 10 | -------------------------------------------------------------------------------- /configs/classification/models/deepmad-89M.txt: -------------------------------------------------------------------------------- 1 | { 'best_structures':[ [ 2 | {'class': 'ConvKXBNRELU', 'in': 3, 'k': 3, 'out': 56, 's': 2}, 3 | {'L': 10, 'btn': 816, 'class': 'SuperResK1DWSEK1', 'in': 56, 'inner_class': 'ResK1DWSEK1', 'k': 5, 'out': 136, 's': 2}, 4 | {'L': 9, 'btn': 1224, 'class': 'SuperResK1DWSEK1', 'in': 136, 'inner_class': 'ResK1DWSEK1', 'k': 5, 'out': 204, 's': 2}, 5 | {'L': 7, 'btn': 1952, 'class': 'SuperResK1DWSEK1', 'in': 204, 'inner_class': 'ResK1DWSEK1', 'k': 5, 'out': 326, 's': 2}, 6 | {'L': 4, 'btn': 2944, 'class': 'SuperResK1DWSEK1', 'in': 326, 'inner_class': 'ResK1DWSEK1', 'k': 5, 'out': 490, 's': 2}, 7 | {'L': 1, 'btn': 4464, 'class': 'SuperResK1DWSEK1', 'in': 490, 'inner_class': 'ResK1DWSEK1', 'k': 3, 'out': 744, 's': 1}, 8 | {'class': 'ConvKXBNRELU', 'in': 744, 'k': 1, 'out': 2560, 's': 1}]], 9 | 'space_arch': 'CnnNet'} 10 | 11 | -------------------------------------------------------------------------------- /configs/classification/models/deepmad-R18.txt: -------------------------------------------------------------------------------- 1 | { 'best_structures':[ [ 2 | {'class': 'ConvKXBNRELU', 'in': 3, 'k': 3, 'out': 32, 's': 2}, 3 | { 'L': 1, 'btn': 40, 'class': 'SuperResK1KXK1', 'in': 32, 'inner_class': 'ResK1KXK1', 'k': 5, 'out': 96, 's': 2}, 4 | { 'L': 6, 'btn': 40, 'class': 'SuperResK1KXK1', 'in': 96, 'inner_class': 'ResK1KXK1', 'k': 5, 'out': 384, 's': 2}, 5 | { 'L': 9, 'btn': 64, 'class': 'SuperResK1KXK1', 'in': 384, 'inner_class': 'ResK1KXK1', 'k': 5, 'out': 384, 's': 2}, 6 | { 'L': 10, 'btn': 104, 'class': 'SuperResK1KXK1', 'in': 384, 'inner_class': 'ResK1KXK1', 'k': 3, 'out': 1024, 's': 1}, 7 | { 'L': 12, 'btn': 104, 'class': 'SuperResK1KXK1', 'in': 1024, 'inner_class': 'ResK1KXK1', 'k': 5, 'out': 672, 's': 2}]], 8 | 'space_arch': 'CnnNet'} 9 | -------------------------------------------------------------------------------- /configs/classification/models/deepmad-R34.txt: -------------------------------------------------------------------------------- 1 | { 'best_structures':[ [ 2 | {'class': 'ConvKXBNRELU', 'in': 3, 'k': 3, 'out': 24, 's': 2}, 3 | { 'L': 1, 'btn': 24, 'class': 'SuperResK1KXK1', 'in': 24, 'inner_class': 'ResK1KXK1', 'k': 5, 'out': 128, 's': 2}, 4 | { 'L': 10, 'btn': 48, 'class': 'SuperResK1KXK1', 'in': 128, 'inner_class': 'ResK1KXK1', 'k': 5, 'out': 512, 's': 2}, 5 | { 'L': 13, 'btn': 88, 'class': 'SuperResK1KXK1', 'in': 512, 'inner_class': 'ResK1KXK1', 'k': 5, 'out': 896, 's': 2}, 6 | { 'L': 11, 'btn': 104, 'class': 'SuperResK1KXK1', 'in': 896, 'inner_class': 'ResK1KXK1', 'k': 5, 'out': 1024, 's': 1}, 7 | { 'L': 14, 'btn': 128, 'class': 'SuperResK1KXK1', 'in': 1024, 'inner_class': 'ResK1KXK1', 'k': 5, 'out': 616, 's': 2}]], 8 | 'space_arch': 'CnnNet'} -------------------------------------------------------------------------------- /configs/classification/models/deepmad-R50.txt: -------------------------------------------------------------------------------- 1 | { 'best_structures':[ [ 2 | {'class': 'ConvKXBNRELU', 'in': 3, 'k': 3, 'out': 32, 's': 2}, 3 | { 'L': 1, 4 | 'btn': 40, 5 | 'class': 'SuperResK1KXK1', 6 | 'in': 32, 7 | 'inner_class': 'ResK1KXK1', 8 | 'k': 5, 9 | 'out': 128, 10 | 's': 2}, 11 | { 'L': 11, 12 | 'btn': 48, 13 | 'class': 'SuperResK1KXK1', 14 | 'in': 128, 15 | 'inner_class': 'ResK1KXK1', 16 | 'k': 5, 17 | 'out': 512, 18 | 's': 2}, 19 | { 'L': 12, 20 | 'btn': 88, 21 | 'class': 'SuperResK1KXK1', 22 | 'in': 512, 23 | 'inner_class': 'ResK1KXK1', 24 | 'k': 5, 25 | 'out': 872, 26 | 's': 2}, 27 | { 'L': 13, 28 | 'btn': 104, 29 | 'class': 'SuperResK1KXK1', 30 | 'in': 872, 31 | 'inner_class': 'ResK1KXK1', 32 | 'k': 5, 33 | 'out': 1024, 34 | 's': 1}, 35 | { 'L': 15, 36 | 'btn': 120, 37 | 'class': 'SuperResK1KXK1', 38 | 'in': 1024, 39 | 'inner_class': 'ResK1KXK1', 40 | 'k': 5, 41 | 'out': 1232, 42 | 's': 2}]], 43 | 'space_arch': 'CnnNet'} 44 | -------------------------------------------------------------------------------- /configs/damoyolo/damoyolo_k1kx_small.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | work_dir = './save_model/k1kx_R640_layers25_lat12e-5/' 6 | log_level = 'INFO' # INFO/DEBUG/ERROR 7 | log_freq = 1000 8 | """ image config """ 9 | image_size = 320 # 224 for Imagenet, 160 for mcu 10 | 11 | """ Model config """ 12 | model = dict( 13 | type = 'CnnNet', 14 | structure_info = [ 15 | {'class': 'ConvKXBNRELU', 'in': 12, 'out': 32, 's': 1, 'k': 3}, 16 | {'class': 'SuperResK1KX', 'in': 32, 'out': 48, 's': 2, 'k': 3, 'L': 1, 'btn': 32}, 17 | {'class': 'SuperResK1KX', 'in': 48, 'out': 96, 's': 2, 'k': 3, 'L': 1, 'btn': 48}, 18 | {'class': 'SuperResK1KX', 'in': 96, 'out': 96, 's': 2, 'k': 3, 'L': 1, 'btn': 96}, 19 | {'class': 'SuperResK1KX', 'in': 96, 'out': 192, 's': 1, 'k': 3, 'L': 1, 'btn': 96}, 20 | {'class': 'SuperResK1KX', 'in': 192, 'out': 384, 's': 2, 'k': 3, 'L': 1, 'btn': 192}, 21 | ] 22 | ) 23 | 24 | """ Latency config """ 25 | latency = dict( 26 | type = 'OpPredictor', 27 | data_type = "FP16_DAMOYOLO", 28 | batch_size = 32, 29 | image_size = image_size, 30 | ) 31 | 32 | """ Budget config """ 33 | budgets = [ 34 | dict(type = "layers",budget = 25), 35 | dict(type = "latency", budget = 12e-5) 36 | ] 37 | 38 | """ Score config """ 39 | score = dict(type = 'madnas', multi_block_ratio = [0,0,1,1,16]) 40 | 41 | """ Space config """ 42 | space = dict( 43 | type = 'space_k1kx', 44 | image_size = image_size, 45 | channel_range_list = [None, None, [64, 128], None, [128, 256], [256, 512]], 46 | kernel_size_list = [3], 47 | 48 | ) 49 | 50 | """ Search config """ 51 | search=dict( 52 | minor_mutation = False, # whether fix the stage layer 53 | minor_iter = 100000, # which iteration to enable minor_mutation 54 | popu_size = 512, 55 | num_random_nets = 500000, # the searching iterations 56 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 57 | num_network = 1, 58 | ) 59 | 60 | -------------------------------------------------------------------------------- /configs/damoyolo/damoyolo_k1kx_tiny.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | work_dir = './save_model/k1kx_R640_layers25_lat8e-5/' 6 | log_level = 'INFO' # INFO/DEBUG/ERROR 7 | 8 | """ image config """ 9 | image_size = 320 # 224 for Imagenet, 160 for mcu 10 | 11 | """ Model config """ 12 | model = dict( 13 | type = 'CnnNet', 14 | structure_info = [ 15 | {'class': 'ConvKXBNRELU', 'in': 12, 'out': 32, 's': 1, 'k': 3}, 16 | {'class': 'SuperResK1KX', 'in': 32, 'out': 48, 's': 2, 'k': 3, 'L': 1, 'btn': 32}, 17 | {'class': 'SuperResK1KX', 'in': 48, 'out': 96, 's': 2, 'k': 3, 'L': 1, 'btn': 48}, 18 | {'class': 'SuperResK1KX', 'in': 96, 'out': 96, 's': 2, 'k': 3, 'L': 1, 'btn': 96}, 19 | {'class': 'SuperResK1KX', 'in': 96, 'out': 192, 's': 1, 'k': 3, 'L': 1, 'btn': 96}, 20 | {'class': 'SuperResK1KX', 'in': 192, 'out': 384, 's': 2, 'k': 3, 'L': 1, 'btn': 192}, 21 | ] 22 | ) 23 | 24 | """ Latency config """ 25 | latency = dict( 26 | type = 'OpPredictor', 27 | data_type = "FP16_DAMOYOLO", 28 | batch_size = 32, 29 | image_size = image_size, 30 | ) 31 | 32 | """ Budget config """ 33 | budgets = [ 34 | dict(type = "layers",budget = 20), 35 | dict(type = "latency", budget = 8e-5) 36 | ] 37 | 38 | """ Score config """ 39 | score = dict(type = 'madnas', multi_block_ratio = [0,0,1,1,16]) 40 | 41 | """ Space config """ 42 | space = dict( 43 | type = 'space_k1kx', 44 | image_size = image_size, 45 | channel_range_list = [None, None, [64, 96], None, [128, 192], [256, 384]], 46 | kernel_size_list = [3], 47 | ) 48 | 49 | """ Search config """ 50 | search=dict( 51 | minor_mutation = False, # whether fix the stage layer 52 | minor_iter = 100000, # which iteration to enable minor_mutation 53 | popu_size = 512, 54 | num_random_nets = 500000, # the searching iterations 55 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 56 | num_network = 1, 57 | ) 58 | 59 | -------------------------------------------------------------------------------- /configs/damoyolo/damoyolo_kxkx_medium.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | work_dir = './save_model/kxkx_R640_layers20_lat4e-4/' 6 | log_level = 'INFO' # INFO/DEBUG/ERROR 7 | log_freq = 1000 8 | 9 | """ image config """ 10 | image_size = 320 # 224 for Imagenet, 160 for mcu 11 | 12 | """ Model config """ 13 | model = dict( 14 | type = 'CnnNet', 15 | structure_info = [ 16 | {'class': 'ConvKXBNRELU', 'in': 12, 'out': 32, 's': 1, 'k': 3}, 17 | {'class': 'SuperResKXKX', 'in': 32, 'out': 48, 's': 2, 'k': 3, 'L': 1, 'btn': 32}, 18 | {'class': 'SuperResKXKX', 'in': 48, 'out': 96, 's': 2, 'k': 3, 'L': 1, 'btn': 48}, 19 | {'class': 'SuperResKXKX', 'in': 96, 'out': 96, 's': 2, 'k': 3, 'L': 1, 'btn': 96}, 20 | {'class': 'SuperResKXKX', 'in': 96, 'out': 192, 's': 1, 'k': 3, 'L': 1, 'btn': 96}, 21 | {'class': 'SuperResKXKX', 'in': 192, 'out': 384, 's': 2, 'k': 3, 'L': 1, 'btn': 192}, 22 | ] 23 | ) 24 | 25 | """ Latency config """ 26 | latency = dict( 27 | type = 'OpPredictor', 28 | data_type = "FP16_DAMOYOLO", 29 | batch_size = 32, 30 | image_size = image_size, 31 | ) 32 | 33 | """ Budget config """ 34 | budgets = [ 35 | dict(type = "layers",budget = 20), 36 | dict(type = "latency", budget = 4e-4) 37 | ] 38 | 39 | """ Score config """ 40 | score = dict(type = 'madnas', multi_block_ratio = [0,0,1,1,16]) 41 | 42 | """ Space config """ 43 | space = dict( 44 | type = 'space_kxkx', 45 | image_size = image_size, 46 | channel_range_list = [None, None, [64, 128], None, [128, 256], [256, 512]], 47 | kernel_size_list = [3], 48 | ) 49 | 50 | """ Search config """ 51 | search=dict( 52 | minor_mutation = False, # whether fix the stage layer 53 | minor_iter = 100000, # which iteration to enable minor_mutation 54 | popu_size = 512, 55 | num_random_nets = 500000, # the searching iterations 56 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 57 | num_network = 1, 58 | ) 59 | 60 | -------------------------------------------------------------------------------- /configs/detection/R50_FLOPs.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | work_dir = './save_model/R50_R480_FLOPs188e8/' 6 | log_level = 'INFO' # INFO/DEBUG/ERROR 7 | log_freq = 1000 8 | 9 | """ image config """ 10 | image_size = 480 # 224 for Imagenet, 480 for detection, 160 for mcu 11 | 12 | """ Model config """ 13 | model = dict( 14 | type = 'CnnNet', 15 | structure_info = [ 16 | {'class': 'ConvKXBNRELU', 'in': 3, 'out': 32, 's': 2, 'k': 3}, \ 17 | {'class': 'SuperResK1KXK1', 'in': 32, 'out': 256, 's': 2, 'k': 3, 'L': 1, 'btn': 64}, \ 18 | {'class': 'SuperResK1KXK1', 'in': 256, 'out': 512, 's': 2, 'k': 3, 'L': 1, 'btn': 128}, \ 19 | {'class': 'SuperResK1KXK1', 'in': 512, 'out': 768, 's': 2, 'k': 3, 'L': 1, 'btn': 256}, \ 20 | {'class': 'SuperResK1KXK1', 'in': 768, 'out': 1024, 's': 1, 'k': 3, 'L': 1, 'btn': 256}, \ 21 | {'class': 'SuperResK1KXK1', 'in': 1024, 'out': 2048, 's': 2, 'k': 3, 'L': 1, 'btn': 512}, \ 22 | ] 23 | ) 24 | 25 | """ Budget config """ 26 | budgets = [ 27 | dict(type = "flops", budget = 188e8), 28 | dict(type = "layers",budget = 91), 29 | ] 30 | 31 | """ Score config """ 32 | score = dict(type = 'madnas', multi_block_ratio = [0,0,1,1,6]) 33 | 34 | """ Space config """ 35 | space = dict( 36 | type = 'space_k1kxk1', 37 | image_size = image_size, 38 | ) 39 | 40 | """ Search config """ 41 | search=dict( 42 | minor_mutation = False, # whether fix the stage layer 43 | minor_iter = 100000, # which iteration to enable minor_mutation 44 | popu_size = 256, 45 | num_random_nets = 100000, # the searching iterations 46 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 47 | num_network = 1, 48 | ) 49 | 50 | -------------------------------------------------------------------------------- /configs/detection/R50_FLOPs_predictor.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | work_dir = './save_model/R50_R480_FLOPs188e8_predictor/' 6 | log_level = 'INFO' # INFO/DEBUG/ERROR 7 | log_freq = 1000 8 | 9 | """ image config """ 10 | image_size = 480 # 224 for Imagenet, 480 for detection, 160 for mcu 11 | 12 | """ Model config """ 13 | model = dict( 14 | type = 'CnnNet', 15 | structure_info = [ 16 | {'class': 'ConvKXBNRELU', 'in': 3, 'out': 32, 's': 2, 'k': 3}, \ 17 | {'class': 'SuperResK1KXK1', 'in': 32, 'out': 256, 's': 2, 'k': 3, 'L': 1, 'btn': 64}, \ 18 | {'class': 'SuperResK1KXK1', 'in': 256, 'out': 512, 's': 2, 'k': 3, 'L': 1, 'btn': 128}, \ 19 | {'class': 'SuperResK1KXK1', 'in': 512, 'out': 768, 's': 2, 'k': 3, 'L': 1, 'btn': 256}, \ 20 | {'class': 'SuperResK1KXK1', 'in': 768, 'out': 1024, 's': 1, 'k': 3, 'L': 1, 'btn': 256}, \ 21 | {'class': 'SuperResK1KXK1', 'in': 1024, 'out': 2048, 's': 2, 'k': 3, 'L': 1, 'btn': 512}, \ 22 | ] 23 | ) 24 | 25 | """ Latency config """ 26 | latency = dict( 27 | type = 'OpPredictor', 28 | data_type = "FP16", 29 | batch_size = 32, 30 | image_size = image_size, 31 | ) 32 | 33 | """ Budget config """ 34 | budgets = [ 35 | dict(type = "flops", budget = 188e8), 36 | dict(type = "latency", budget = 8e-4), 37 | dict(type = "layers",budget = 91), 38 | ] 39 | 40 | """ Score config """ 41 | score = dict(type = 'madnas', multi_block_ratio = [0,0,1,1,6]) 42 | 43 | """ Space config """ 44 | space = dict( 45 | type = 'space_k1kxk1', 46 | image_size = image_size, 47 | ) 48 | 49 | """ Search config """ 50 | search=dict( 51 | minor_mutation = False, # whether fix the stage layer 52 | minor_iter = 100000, # which iteration to enable minor_mutation 53 | popu_size = 256, 54 | num_random_nets = 100000, # the searching iterations 55 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 56 | num_network = 1, 57 | ) 58 | 59 | -------------------------------------------------------------------------------- /configs/detection/models/gfocal_maedet/maedet_l_6x_lr0.02.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021-2022 Alibaba Group Holding Limited. 2 | 3 | _base_ = 'gfocal_r50_fpn_ms6x.py' 4 | # model settings 5 | model = dict( 6 | backbone=dict( 7 | type='MadNas', 8 | net_str="configs/gfocal_madnas/maedet_l.txt", 9 | out_indices=(1,2,3,4), 10 | init_cfg=None), # if load pretrained model, fill the path of the pth file. 11 | neck=dict( 12 | type='FPN', 13 | in_channels=[144, 608, 1912, 2400], 14 | out_channels=256, 15 | start_level=1, 16 | add_extra_convs='on_output', # use P5 17 | num_outs=5), 18 | ) 19 | # training and testing settings 20 | img_norm_cfg = dict( 21 | mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True) 22 | train_pipeline = [ 23 | dict(type='LoadImageFromFile'), 24 | dict(type='LoadAnnotations', with_bbox=True), 25 | dict( 26 | type='Resize', 27 | img_scale=[(1333, 480), (1333, 960)], 28 | multiscale_mode='range', 29 | keep_ratio=True), 30 | dict(type='RandomFlip', flip_ratio=0.5), 31 | dict(type='Normalize', **img_norm_cfg), 32 | dict(type='Pad', size_divisor=32), 33 | dict(type='DefaultFormatBundle'), 34 | dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']), 35 | ] 36 | test_pipeline = [ 37 | dict(type='LoadImageFromFile'), 38 | dict( 39 | type='MultiScaleFlipAug', 40 | img_scale=(1333, 800), 41 | flip=False, 42 | transforms=[ 43 | dict(type='Resize', keep_ratio=True), 44 | dict(type='RandomFlip'), 45 | dict(type='Normalize', **img_norm_cfg), 46 | dict(type='Pad', size_divisor=32), 47 | dict(type='ImageToTensor', keys=['img']), 48 | dict(type='Collect', keys=['img']), 49 | ]) 50 | ] 51 | data = dict( 52 | train=dict(pipeline=train_pipeline), 53 | val=dict(pipeline=test_pipeline), 54 | test=dict(pipeline=test_pipeline)) 55 | # optimizer 56 | optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001) 57 | 58 | # learning policy 59 | lr_config = dict( 60 | warmup='linear', 61 | warmup_iters=7330, 62 | warmup_ratio=0.1, 63 | step=[65, 71]) 64 | total_epochs = 73 65 | use_syncBN_torch = True -------------------------------------------------------------------------------- /configs/detection/models/gfocal_maedet/maedet_m_6x_lr0.02.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021-2022 Alibaba Group Holding Limited. 2 | 3 | _base_ = 'gfocal_r50_fpn_ms6x.py' 4 | # model settings 5 | model = dict( 6 | backbone=dict( 7 | type='MadNas', 8 | net_str="configs/gfocal_madnas/maedet_m.txt", 9 | out_indices=(1,2,3,4), 10 | init_cfg=None), # if load pretrained model, fill the path of the pth file. 11 | neck=dict( 12 | type='FPN', 13 | in_channels=[120, 512, 1632, 2048], 14 | out_channels=256, 15 | start_level=1, 16 | add_extra_convs='on_output', # use P5 17 | num_outs=5), 18 | ) 19 | # training and testing settings 20 | img_norm_cfg = dict( 21 | mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True) 22 | train_pipeline = [ 23 | dict(type='LoadImageFromFile'), 24 | dict(type='LoadAnnotations', with_bbox=True), 25 | dict( 26 | type='Resize', 27 | img_scale=[(1333, 480), (1333, 960)], 28 | multiscale_mode='range', 29 | keep_ratio=True), 30 | dict(type='RandomFlip', flip_ratio=0.5), 31 | dict(type='Normalize', **img_norm_cfg), 32 | dict(type='Pad', size_divisor=32), 33 | dict(type='DefaultFormatBundle'), 34 | dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']), 35 | ] 36 | test_pipeline = [ 37 | dict(type='LoadImageFromFile'), 38 | dict( 39 | type='MultiScaleFlipAug', 40 | img_scale=(1333, 800), 41 | flip=False, 42 | transforms=[ 43 | dict(type='Resize', keep_ratio=True), 44 | dict(type='RandomFlip'), 45 | dict(type='Normalize', **img_norm_cfg), 46 | dict(type='Pad', size_divisor=32), 47 | dict(type='ImageToTensor', keys=['img']), 48 | dict(type='Collect', keys=['img']), 49 | ]) 50 | ] 51 | data = dict( 52 | train=dict(pipeline=train_pipeline), 53 | val=dict(pipeline=test_pipeline), 54 | test=dict(pipeline=test_pipeline)) 55 | # optimizer 56 | optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001) 57 | 58 | # learning policy 59 | lr_config = dict( 60 | warmup='linear', 61 | warmup_iters=7330, 62 | warmup_ratio=0.1, 63 | step=[65, 71]) 64 | total_epochs = 73 65 | use_syncBN_torch = True -------------------------------------------------------------------------------- /configs/detection/models/gfocal_maedet/maedet_s_6x_lr0.02.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021-2022 Alibaba Group Holding Limited. 2 | 3 | _base_ = 'gfocal_r50_fpn_ms6x.py' 4 | # model settings 5 | model = dict( 6 | backbone=dict( 7 | type='MadNas', 8 | net_str="configs/gfocal_madnas/maedet_s.txt", 9 | out_indices=(1,2,3,4), 10 | init_cfg=None), # if load pretrained model, fill the path of the pth file. 11 | neck=dict( 12 | type='FPN', 13 | in_channels=[48, 272, 1024, 2048], 14 | out_channels=192, 15 | start_level=1, 16 | add_extra_convs='on_output', # use P5 17 | num_outs=5), 18 | bbox_head=dict( 19 | in_channels=192, 20 | feat_channels=192), 21 | ) 22 | # training and testing settings 23 | img_norm_cfg = dict( 24 | mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True) 25 | train_pipeline = [ 26 | dict(type='LoadImageFromFile'), 27 | dict(type='LoadAnnotations', with_bbox=True), 28 | dict( 29 | type='Resize', 30 | img_scale=[(1333, 480), (1333, 960)], 31 | multiscale_mode='range', 32 | keep_ratio=True), 33 | dict(type='RandomFlip', flip_ratio=0.5), 34 | dict(type='Normalize', **img_norm_cfg), 35 | dict(type='Pad', size_divisor=32), 36 | dict(type='DefaultFormatBundle'), 37 | dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']), 38 | ] 39 | test_pipeline = [ 40 | dict(type='LoadImageFromFile'), 41 | dict( 42 | type='MultiScaleFlipAug', 43 | img_scale=(1333, 800), 44 | flip=False, 45 | transforms=[ 46 | dict(type='Resize', keep_ratio=True), 47 | dict(type='RandomFlip'), 48 | dict(type='Normalize', **img_norm_cfg), 49 | dict(type='Pad', size_divisor=32), 50 | dict(type='ImageToTensor', keys=['img']), 51 | dict(type='Collect', keys=['img']), 52 | ]) 53 | ] 54 | data = dict( 55 | train=dict(pipeline=train_pipeline), 56 | val=dict(pipeline=test_pipeline), 57 | test=dict(pipeline=test_pipeline)) 58 | # optimizer 59 | optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001) 60 | 61 | # learning policy 62 | lr_config = dict( 63 | warmup='linear', 64 | warmup_iters=7330, 65 | warmup_ratio=0.1, 66 | step=[65, 71]) 67 | total_epochs = 73 68 | use_syncBN_torch = True -------------------------------------------------------------------------------- /configs/detection/models/madnas.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021-2022 Alibaba Group Holding Limited. 2 | 3 | import os,sys 4 | import torch 5 | import torch.nn as nn 6 | from cnnnet import CnnNet 7 | from ..builder import BACKBONES 8 | import ast 9 | 10 | sys.path.append(os.path.dirname(os.path.abspath(__file__))) 11 | sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 12 | 13 | from mmcv.cnn import ConvModule, constant_init, kaiming_init 14 | from torch.nn.modules.batchnorm import _BatchNorm 15 | 16 | 17 | @BACKBONES.register_module 18 | class MadNas(nn.Module): 19 | def __init__(self, structure_txt=None, out_indices=(1, 2, 3, 4), init_cfg=None): 20 | super(MadNas, self).__init__() 21 | with open(structure_txt, 'r') as fin: 22 | content = fin.read() 23 | output_structures = ast.literal_eval(content) 24 | 25 | network_arch = output_structures['space_arch'] 26 | best_structure = output_structures['best_structures'][0] 27 | self.body = CnnNet(structure_info=best_structure, out_indices=out_indices, no_create=False) 28 | if init_cfg is not None and os.path.isfile(init_cfg): 29 | self.body.init_weights(init_cfg) 30 | 31 | def init_weights(self, pretrained=None): 32 | for m in self.modules(): 33 | if isinstance(m, nn.Conv2d): 34 | kaiming_init(m) 35 | elif isinstance(m, (_BatchNorm, nn.GroupNorm)): 36 | constant_init(m, 1) 37 | 38 | def forward(self, x): 39 | """Forward function.""" 40 | return self.body(x) 41 | 42 | 43 | if __name__ == "__main__": 44 | pass -------------------------------------------------------------------------------- /configs/detection/models/maedet_l.txt: -------------------------------------------------------------------------------- 1 | { 'best_structures':[ [ 2 | {'class': 'ConvKXBNRELU', 'in': 3, 'out': 80, 's': 2, 'k': 3}, 3 | {'class': 'SuperResK1KXK1', 'in': 80, 'out': 144, 's': 2, 'k': 3, 'L': 2, 'btn': 80}, 4 | {'class': 'SuperResK1KXK1', 'in': 144, 'out': 608, 's': 2, 'k': 5, 'L': 12, 'btn': 88}, 5 | {'class': 'SuperResK1KXK1', 'in': 608, 'out': 1912, 's': 2, 'k': 5, 'L': 12, 'btn': 136}, 6 | {'class': 'SuperResK1KXK1', 'in': 1912, 'out': 2400, 's': 2, 'k': 5, 'L': 10, 'btn': 220}]], 7 | 'space_arch': 'CnnNet'} 8 | -------------------------------------------------------------------------------- /configs/detection/models/maedet_m.txt: -------------------------------------------------------------------------------- 1 | { 'best_structures':[ [ 2 | {'class': 'ConvKXBNRELU', 'in': 3, 'out': 64, 's': 2, 'k': 3}, 3 | {'class': 'SuperResK1KXK1', 'in': 64, 'out': 120, 's': 2, 'k': 3, 'L': 2, 'btn': 64}, 4 | {'class': 'SuperResK1KXK1', 'in': 120, 'out': 512, 's': 2, 'k': 5, 'L': 10, 'btn': 72}, 5 | {'class': 'SuperResK1KXK1', 'in': 512, 'out': 1632, 's': 2, 'k': 5, 'L': 10, 'btn': 112}, 6 | {'class': 'SuperResK1KXK1', 'in': 1632, 'out': 2048, 's': 2, 'k': 5, 'L': 8, 'btn': 184}]], 7 | 'space_arch': 'CnnNet'} -------------------------------------------------------------------------------- /configs/detection/models/maedet_s.txt: -------------------------------------------------------------------------------- 1 | { 'best_structures':[ [ 2 | {'class': 'ConvKXBNRELU', 'in': 3, 'out': 32, 's': 2, 'k': 3}, 3 | {'class': 'SuperResK1KXK1', 'in': 32, 'out': 48, 's': 2, 'k': 5, 'L': 2, 'btn': 32}, 4 | {'class': 'SuperResK1KXK1', 'in': 48, 'out': 272, 's': 2, 'k': 3, 'L': 4, 'btn': 120}, 5 | {'class': 'SuperResK1KXK1', 'in': 272, 'out': 1024, 's': 2, 'k': 5, 'L': 10, 'btn': 80}, 6 | {'class': 'SuperResK1KXK1', 'in': 1024, 'out': 2048, 's': 2, 'k': 3, 'L': 10, 'btn': 240}]], 7 | 'space_arch': 'CnnNet'} 8 | -------------------------------------------------------------------------------- /configs/quant/Mixed_19d2G.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | work_dir = './save_model/mbv2_8bits_flops300e6_layers47/' 6 | log_level = 'INFO' # INFO/DEBUG/ERROR 7 | log_freq = 1000 8 | 9 | """ image config """ 10 | image_size = 224 # 224 for Imagenet, 480 for detection, 160 for mcu 11 | 12 | init_bit=4 13 | bits_list = [init_bit, init_bit, init_bit] 14 | """ Model config """ 15 | model = dict( 16 | type = 'CnnNet', 17 | structure_info = [ 18 | {'class': 'ConvKXBNRELU', 'in': 3, 'out': 16, 's': 2, 'k': 3, 'nbitsA':8, 'nbitsW':8}, \ 19 | {'class': 'SuperQuantResK1DWK1', 'in': 16, 'out': 24, 's': 2, 'k': 3, 'L': 1, 'btn': 48, 'nbitsA':bits_list, 'nbitsW':bits_list}, \ 20 | {'class': 'SuperQuantResK1DWK1', 'in': 24, 'out': 48, 's': 2, 'k': 3, 'L': 1, 'btn': 96, 'nbitsA':bits_list, 'nbitsW':bits_list}, \ 21 | {'class': 'SuperQuantResK1DWK1', 'in': 48, 'out': 64, 's': 2, 'k': 3, 'L': 1, 'btn': 128, 'nbitsA':bits_list, 'nbitsW':bits_list}, \ 22 | {'class': 'SuperQuantResK1DWK1', 'in': 64, 'out': 96, 's': 1, 'k': 3, 'L': 1, 'btn': 192, 'nbitsA':bits_list, 'nbitsW':bits_list}, \ 23 | {'class': 'SuperQuantResK1DWK1', 'in': 96, 'out': 192, 's': 2, 'k': 3, 'L': 1, 'btn': 384, 'nbitsA':bits_list, 'nbitsW':bits_list}, \ 24 | {'class': 'ConvKXBNRELU', 'in': 192, 'out': 1280, 's': 1, 'k': 1, 'nbitsA':init_bit, 'nbitsW':init_bit}, \ 25 | ] 26 | ) 27 | 28 | """ Budget config """ 29 | budgets = [ 30 | dict(type = "flops", budget = 300e6), 31 | dict(type = "layers",budget = 47), 32 | ] 33 | 34 | """ Score config """ 35 | score = dict( 36 | type = 'madnas', 37 | multi_block_ratio = [0,0,1,1,6], 38 | init_std = 4, 39 | init_std_act = 5, 40 | ) 41 | 42 | """ Space config """ 43 | space = dict( 44 | type = 'space_quant_k1dwk1', 45 | image_size = image_size, 46 | ) 47 | 48 | """ Search config """ 49 | search=dict( 50 | minor_mutation = False, # whether fix the stage layer 51 | minor_iter = 100000, # which iteration to enable minor_mutation 52 | popu_size = 512, 53 | num_random_nets = 500000, # the searching iterations 54 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 55 | num_network = 1, 56 | ) 57 | 58 | -------------------------------------------------------------------------------- /configs/quant/Mixed_7d0G.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | work_dir = './save_model/mbv2_4bits_flops109e6_layers47/' 6 | log_level = 'INFO' # INFO/DEBUG/ERROR 7 | log_freq = 1000 8 | 9 | """ image config """ 10 | image_size = 224 # 224 for Imagenet, 480 for detection, 160 for mcu 11 | 12 | init_bit=4 13 | bits_list = [init_bit, init_bit, init_bit] 14 | """ Model config """ 15 | model = dict( 16 | type = 'CnnNet', 17 | structure_info = [ 18 | {'class': 'ConvKXBNRELU', 'in': 3, 'out': 16, 's': 2, 'k': 3, 'nbitsA':8, 'nbitsW':8}, \ 19 | {'class': 'SuperQuantResK1DWK1', 'in': 16, 'out': 24, 's': 2, 'k': 3, 'L': 1, 'btn': 48, 'nbitsA':bits_list, 'nbitsW':bits_list}, \ 20 | {'class': 'SuperQuantResK1DWK1', 'in': 24, 'out': 48, 's': 2, 'k': 3, 'L': 1, 'btn': 96, 'nbitsA':bits_list, 'nbitsW':bits_list}, \ 21 | {'class': 'SuperQuantResK1DWK1', 'in': 48, 'out': 64, 's': 2, 'k': 3, 'L': 1, 'btn': 128, 'nbitsA':bits_list, 'nbitsW':bits_list}, \ 22 | {'class': 'SuperQuantResK1DWK1', 'in': 64, 'out': 96, 's': 1, 'k': 3, 'L': 1, 'btn': 192, 'nbitsA':bits_list, 'nbitsW':bits_list}, \ 23 | {'class': 'SuperQuantResK1DWK1', 'in': 96, 'out': 192, 's': 2, 'k': 3, 'L': 1, 'btn': 384, 'nbitsA':bits_list, 'nbitsW':bits_list}, \ 24 | {'class': 'ConvKXBNRELU', 'in': 192, 'out': 1280, 's': 1, 'k': 1, 'nbitsA':init_bit, 'nbitsW':init_bit}, \ 25 | ] 26 | ) 27 | 28 | """ Budget config """ 29 | budgets = [ 30 | dict(type = "flops", budget = 109e6), 31 | dict(type = "layers",budget = 47), 32 | ] 33 | 34 | """ Score config """ 35 | score = dict( 36 | type = 'madnas', 37 | multi_block_ratio = [0,0,1,1,6], 38 | init_std = 4, 39 | init_std_act = 5, 40 | ) 41 | 42 | """ Space config """ 43 | space = dict( 44 | type = 'space_quant_k1dwk1', 45 | image_size = image_size, 46 | ) 47 | 48 | """ Search config """ 49 | search=dict( 50 | minor_mutation = False, # whether fix the stage layer 51 | minor_iter = 100000, # which iteration to enable minor_mutation 52 | popu_size = 256, 53 | num_random_nets = 500000, # the searching iterations 54 | sync_size_ratio = 1.0, # control each thread sync number: ratio * popu_size 55 | num_network = 1, 56 | ) 57 | 58 | -------------------------------------------------------------------------------- /configs/quant/README.md: -------------------------------------------------------------------------------- 1 | ## Abstract 2 | 3 | * **Instruction** 4 | 5 | We propose Quantization Entropy Score (QE-Score) to calculate the entropy for searching efficient low-precision backbones. In this folder, we provide the example scripts and structure txt for quantization models, which are aligned with MobileNetV2-4/8bit. 6 | Mixed7d0G is aligned with MobileNetV2-4bit, while Mixed19d2G is aligned with MobileNetV2-8bit. The training pipeline is released on the [QE-Score official repository](https://github.com/implus/GFocalV2).

7 | 8 | 9 | * **Use the searching examples for Quantization** 10 | ```shell 11 | sh tools/dist_search.sh Mixed_7d0G.py 12 | ``` 13 | **`mixed_7d0G.py` is the config for searching Mixed7d0G model within the budget of FLOPs of MobileNetV2-4bit.** 14 | 15 | **`mixed_19d2G.py` is the config for searching Mixed19d2G model within the budget of FLOPs of MobileNetV2-8bit.** 16 | 17 | *** 18 | 19 | ## Results and Models 20 | 21 | |Backbone|Param (MB)|BitOps (G)|ImageNet TOP1|Structure|Download| 22 | |:----|:----|:----|:----|:----|:----| 23 | |MBV2-8bit|3.4|19.2|71.90%| -| -| 24 | |MBV2-4bit|2.3|7|68.90%| -|- | 25 | |Mixed19d2G|3.2|18.8|74.80%|[txt](models/mixed7d0G.txt) |[model](https://idstcv.oss-cn-zhangjiakou.aliyuncs.com/LightNAS/quant/mixed-7d0G/quant_238_70.7660.pth.tar) | 26 | |Mixed7d0G|2.2|6.9|70.80%|[txt](models/mixed19d2G.txt) |[model](https://idstcv.oss-cn-zhangjiakou.aliyuncs.com/LightNAS/quant/mixed-19d2G/quant_237_74.8180.pth.tar) | 27 | 28 | The ImageNet training pipeline can be found at [https://github.com/tinyvision/imagenet-training-pipeline ](https://github.com/tinyvision/imagenet-training-pipeline) 29 | 30 | **Note**: 31 | - If searching without quantization, Budget_flops is equal to the base flops as in other tasks. 32 | - If searching with quantization, Budget_flops = Budget_flops_base x (Act_bit / 8bit) x (Weight_bit / 8bit). Hence, BitOps = Budget_flops x 8 x 8. 33 | 34 | 35 | *** 36 | ## Citation 37 | 38 | If you use this toolbox in your research, please cite the paper. 39 | 40 | ``` 41 | @inproceedings{qescore, 42 | title = {Entropy-Driven Mixed-Precision Quantization for Deep Network Design}, 43 | author = {Zhenhong Sun and Ce Ge and Junyan Wang and Ming Lin and Hesen Chen and Hao Li and Xiuyu Sun}, 44 | journal = {Advances in Neural Information Processing Systems}, 45 | year = {2022}, 46 | } 47 | -------------------------------------------------------------------------------- /configs/quant/models/mixed19d2G.txt: -------------------------------------------------------------------------------- 1 | { 'best_structures':[ [ 2 | {'class': 'ConvKXBNRELU', 'in': 3, 'k': 3, 'nbitsA': 8, 'nbitsW': 8, 'out': 16, 's': 2}, 3 | { 'L': 3, 4 | 'btn': 144, 5 | 'class': 'SuperQuantResK1DWK1', 6 | 'in': 16, 7 | 'inner_class': 'ResK1DWK1', 8 | 'k': 5, 9 | 'nbitsA': [5, 5, 5, 5, 5, 5, 5, 5, 5], 10 | 'nbitsW': [5, 5, 5, 5, 5, 5, 5, 5, 5], 11 | 'out': 40, 12 | 's': 2}, 13 | { 'L': 3, 14 | 'btn': 320, 15 | 'class': 'SuperQuantResK1DWK1', 16 | 'in': 40, 17 | 'inner_class': 'ResK1DWK1', 18 | 'k': 5, 19 | 'nbitsA': [5, 5, 5, 5, 5, 5, 5, 5, 5], 20 | 'nbitsW': [5, 5, 5, 5, 5, 5, 5, 5, 5], 21 | 'out': 80, 22 | 's': 2}, 23 | { 'L': 3, 24 | 'btn': 616, 25 | 'class': 'SuperQuantResK1DWK1', 26 | 'in': 80, 27 | 'inner_class': 'ResK1DWK1', 28 | 'k': 5, 29 | 'nbitsA': [5, 5, 5, 5, 5, 5, 5, 5, 5], 30 | 'nbitsW': [4, 4, 4, 4, 4, 4, 4, 4, 4], 31 | 'out': 176, 32 | 's': 2}, 33 | { 'L': 3, 34 | 'btn': 448, 35 | 'class': 'SuperQuantResK1DWK1', 36 | 'in': 176, 37 | 'inner_class': 'ResK1DWK1', 38 | 'k': 5, 39 | 'nbitsA': [5, 5, 5, 4, 4, 4, 5, 5, 5], 40 | 'nbitsW': [5, 5, 5, 5, 5, 5, 5, 5, 5], 41 | 'out': 224, 42 | 's': 1}, 43 | { 'L': 3, 44 | 'btn': 960, 45 | 'class': 'SuperQuantResK1DWK1', 46 | 'in': 224, 47 | 'inner_class': 'ResK1DWK1', 48 | 'k': 5, 49 | 'nbitsA': [5, 5, 5, 5, 5, 5, 5, 5, 5], 50 | 'nbitsW': [5, 5, 5, 5, 5, 5, 5, 5, 5], 51 | 'out': 240, 52 | 's': 2}, 53 | {'class': 'ConvKXBNRELU', 'in': 240, 'k': 1, 'nbitsA': 5, 'nbitsW': 5, 'out': 1280, 's': 1}]], 54 | 'space_arch': 'CnnNet'} -------------------------------------------------------------------------------- /configs/quant/models/mixed7d0G.txt: -------------------------------------------------------------------------------- 1 | { 'best_structures':[ [ 2 | {'class': 'ConvKXBNRELU', 'in': 3, 'k': 3, 'nbitsA': 8, 'nbitsW': 8, 'out': 8, 's': 2}, 3 | { 'L': 3, 4 | 'btn': 64, 5 | 'class': 'SuperQuantResK1DWK1', 6 | 'in': 8, 7 | 'inner_class': 'ResK1DWK1', 8 | 'k': 5, 9 | 'nbitsA': [5, 5, 5, 5, 5, 5, 5, 5, 5], 10 | 'nbitsW': [5, 5, 5, 5, 5, 5, 4, 4, 4], 11 | 'out': 32, 12 | 's': 2}, 13 | { 'L': 3, 14 | 'btn': 128, 15 | 'class': 'SuperQuantResK1DWK1', 16 | 'in': 32, 17 | 'inner_class': 'ResK1DWK1', 18 | 'k': 5, 19 | 'nbitsA': [5, 5, 5, 5, 5, 5, 5, 5, 5], 20 | 'nbitsW': [5, 5, 5, 5, 5, 5, 4, 4, 4], 21 | 'out': 64, 22 | 's': 2}, 23 | { 'L': 3, 24 | 'btn': 224, 25 | 'class': 'SuperQuantResK1DWK1', 26 | 'in': 64, 27 | 'inner_class': 'ResK1DWK1', 28 | 'k': 5, 29 | 'nbitsA': [5, 5, 5, 5, 5, 5, 5, 5, 5], 30 | 'nbitsW': [5, 5, 5, 5, 5, 5, 5, 5, 5], 31 | 'out': 64, 32 | 's': 2}, 33 | { 'L': 3, 34 | 'btn': 336, 35 | 'class': 'SuperQuantResK1DWK1', 36 | 'in': 64, 37 | 'inner_class': 'ResK1DWK1', 38 | 'k': 5, 39 | 'nbitsA': [5, 5, 5, 5, 5, 5, 5, 5, 5], 40 | 'nbitsW': [5, 5, 5, 6, 6, 6, 5, 5, 5], 41 | 'out': 96, 42 | 's': 1}, 43 | { 'L': 3, 44 | 'btn': 672, 45 | 'class': 'SuperQuantResK1DWK1', 46 | 'in': 96, 47 | 'inner_class': 'ResK1DWK1', 48 | 'k': 5, 49 | 'nbitsA': [5, 5, 5, 5, 5, 5, 5, 5, 5], 50 | 'nbitsW': [6, 6, 6, 4, 4, 4, 5, 5, 5], 51 | 'out': 192, 52 | 's': 2}, 53 | {'class': 'ConvKXBNRELU', 'in': 192, 'k': 1, 'nbitsA': 5, 'nbitsW': 5, 'out': 1280, 's': 1}]], 54 | 'space_arch': 'CnnNet'} 55 | -------------------------------------------------------------------------------- /docs/arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba/lightweight-neural-architecture-search/8ccaf889fcd06079d268a355c765e9d0af071612/docs/arch.png -------------------------------------------------------------------------------- /get_started.md: -------------------------------------------------------------------------------- 1 | # Commence usage 2 | 3 | For initial usage, please follow the steps below sequentially. 4 | 5 | ## Search for the model architecture. 6 | 7 | - Directories [configs/classification](configs/classification) and [configs/detection](configs/detection) respectively contain search configuration files for classification and detection, as demonstrated below. 8 | - Taking a classification task as an example, search for the CNN architecture of ResNet-50 and execute the following steps: 9 | 10 | ```shell 11 | sh tools/dist_search.sh configs/classification/R50_FLOPs.py 12 | #or 13 | python tools/search.py configs/classification/R50_FLOPs.py 14 | ``` 15 | 16 | ## Export the search results. 17 | 18 | - [tools/export.py](tools/export.py), A script for exporting the searched model architecture and its related dependencies is provided, allowing for quick verification of the demo 19 | 20 | - For example [R50_FLOPs](configs/classification/R50_FLOPs.py): 21 | 22 | ```shell 23 | python tools/export.py save_model/R50_R224_FLOPs41e8 output_dir 24 | ``` 25 | 26 | Copy the demo deployment and related code to the **output_dir/R50_R224_FLOPs41e8/** directory, which should include the following contents: 27 | 28 | - best_structure.json:Several optimal model architectures that were found during the search. 29 | - demo.py:A simple script demonstrating how to use the models 30 | - cnnnet.py:The class definitions and utility functions used for constructing the models 31 | - modules: The foundational modules of the models. 32 | - weights/:Several optimal model weights that were found during the search (only available for one-shot NAS methods). 33 | 34 | 35 | ## Using the searched architecture. 36 | 37 | - [demo.py](tinynas/deploy/cnnnet/demo.py) is a basic usage example, but you can also run demo.py directly after exporting the model architecture in the previous step. 38 | 39 | - Continuing with the ResNet-50 architecture for a classification task as an example, the core code is explained below: 40 | 41 | - Import dependencies 42 | 43 | ```python 44 | import ast 45 | from cnnnet import CnnNet 46 | ``` 47 | 48 | - Load the optimal structure from a file." 49 | 50 | ```python 51 | with open('best_structure.json', 'r') as fin: 52 | content = fin.read() 53 | output_structures = ast.literal_eval(content) 54 | 55 | network_arch = output_structures['space_arch'] 56 | best_structures = output_structures['best_structures'] 57 | ``` 58 | 59 | - Instantiate the classification backbone network. 60 | 61 | ```python 62 | network_id = 0 # Index number. Multiple structures can be output during the search, as set by num_network=5 in example_cls_res50.sh. 63 | out_indices = (4, ) # Output stage. For classification tasks, only the output from the final stage needs to be obtained. 64 | 65 | backbone = CnnNet( 66 | structure_info=best_structures[network_id], 67 | out_indices=out_indices, 68 | num_classes=1000, 69 | classification=True, 70 | ) 71 | backbone.init_weight(pretrained) 72 | ``` 73 | 74 | - You can now fully utilize the `backbone` :smile: 75 | 76 | - For further usage methods of the CNN detection task model, please refer to [tinynas/deploy/](tinynas/deploy/) 77 | -------------------------------------------------------------------------------- /installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## Additional Requirements 4 | - Linux 5 | - GCC 7+ 6 | - Python 3.6+ 7 | - PyTorch 1.9+ 8 | - CUDA 10.2+ 9 | 10 | ## Dependency Installation 11 | 12 | 1. Create a conda virtual environment and activate 13 | 14 | ```shell 15 | conda create -n tinynas python=3.6 -y 16 | conda activate tinynas 17 | ``` 18 | 19 | 2. Install OpenMPI and mpi4py 20 | 21 | a. Install using conda command(recommended) 22 | 23 | ```shell 24 | conda install -c conda-forge mpi4py=3.0.3 openmpi=4.0.4 25 | ``` 26 | 27 | b. Build from source (More faster when Multi-Process) 28 | - From [Here](https://www.open-mpi.org/software/ompi/v4.0/) download openmpi source code 29 | 30 | ```shell 31 | tar -xzvf openmpi-4.0.1.tar.gz 32 | cd openmpi-4.0.1 33 | ./configure --prefix=$HOME/openmpi 34 | make && make install 35 | ``` 36 | - add mpi to the system path 37 | 38 | ```shell 39 | export PATH=$HOME/openmpi/bin:$PATH 40 | export LD_LIBRARY_PATH=$HOME/openmpi/lib:$LD_LIBRARY_PATH 41 | ``` 42 | - install mpi4py 43 | 44 | ```shell 45 | # conda 46 | conda install -c conda-forge mpi4py 47 | # or pip 48 | pip install mpi4py 49 | ``` 50 | 51 | 3. Run the following commands or [Official Guide](https://pytorch.org/get-started/locally/) install torch and torchvision 52 | 53 | ```shell 54 | conda install pytorch==1.9.0 torchvision==0.10.0 torchaudio==0.9.0 cudatoolkit=10.2 -c pytorch 55 | ``` 56 | > If you see `"Not be found for jpeg"`, please install libjpeg first. 57 | ```shell 58 | sudo yum install libjpeg # for centos 59 | sudo apt install libjpeg-dev # for ubuntu 60 | ``` 61 | 62 | 4. ModelScope (optional) 63 | 64 | > For light-weight, we modify and port some code of modelscope , if you want to experience more features, you can visite [ModelScope](https://modelscope.cn/home) 65 | , or run the following installation commands 66 | ```shell 67 | pip install "modelscope[cv]" -f https://modelscope.oss-cn-beijing.aliyuncs.com/releases/repo.html 68 | ``` 69 | 70 | 5. Other Requirements 71 | 72 | ```shell 73 | pip install -r requirements/nas.txt 74 | ``` 75 | 76 | 6. Installation check 77 | ```python 78 | import tinynas 79 | print(tinynas.__version__) 80 | ``` 81 | -------------------------------------------------------------------------------- /modelscope/__init__.py: -------------------------------------------------------------------------------- 1 | from .version import __release_datetime__, __version__ 2 | 3 | __all__ = ['__version__', '__release_datetime__'] 4 | -------------------------------------------------------------------------------- /modelscope/fileio/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | 3 | from .file import File, LocalStorage 4 | from .io import dump, dumps, load 5 | -------------------------------------------------------------------------------- /modelscope/fileio/format/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | 3 | from .base import FormatHandler 4 | from .json import JsonHandler 5 | from .yaml import YamlHandler 6 | -------------------------------------------------------------------------------- /modelscope/fileio/format/base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | from abc import ABCMeta, abstractmethod 3 | 4 | 5 | class FormatHandler(metaclass=ABCMeta): 6 | # if `text_format` is True, file 7 | # should use text mode otherwise binary mode 8 | text_mode = True 9 | 10 | @abstractmethod 11 | def load(self, file, **kwargs): 12 | pass 13 | 14 | @abstractmethod 15 | def dump(self, obj, file, **kwargs): 16 | pass 17 | 18 | @abstractmethod 19 | def dumps(self, obj, **kwargs): 20 | pass 21 | -------------------------------------------------------------------------------- /modelscope/fileio/format/json.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | import numpy as np 3 | 4 | from .base import FormatHandler 5 | 6 | 7 | def set_default(obj): 8 | """Set default json values for non-serializable values. 9 | 10 | It helps convert ``set``, ``range`` and ``np.ndarray`` data types to list. 11 | It also converts ``np.generic`` (including ``np.int32``, ``np.float32``, 12 | etc.) into plain numbers of plain python built-in types. 13 | """ 14 | if isinstance(obj, (set, range)): 15 | return list(obj) 16 | elif isinstance(obj, np.ndarray): 17 | return obj.tolist() 18 | elif isinstance(obj, np.generic): 19 | return obj.item() 20 | raise TypeError(f'{type(obj)} is unsupported for json dump') 21 | 22 | 23 | class JsonHandler(FormatHandler): 24 | """Use jsonplus, serialization of Python types to JSON that "just works".""" 25 | 26 | def load(self, file): 27 | import jsonplus 28 | return jsonplus.loads(file.read()) 29 | 30 | def dump(self, obj, file, **kwargs): 31 | file.write(self.dumps(obj, **kwargs)) 32 | 33 | def dumps(self, obj, **kwargs): 34 | import jsonplus 35 | kwargs.setdefault('default', set_default) 36 | return jsonplus.dumps(obj, **kwargs) 37 | -------------------------------------------------------------------------------- /modelscope/fileio/format/yaml.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | import yaml 3 | 4 | try: 5 | from yaml import CDumper as Dumper 6 | from yaml import CLoader as Loader 7 | except ImportError: 8 | from yaml import Loader, Dumper # type: ignore 9 | 10 | from .base import FormatHandler # isort:skip 11 | 12 | 13 | class YamlHandler(FormatHandler): 14 | 15 | def load(self, file, **kwargs): 16 | kwargs.setdefault('Loader', Loader) 17 | return yaml.load(file, **kwargs) 18 | 19 | def dump(self, obj, file, **kwargs): 20 | kwargs.setdefault('Dumper', Dumper) 21 | yaml.dump(obj, file, **kwargs) 22 | 23 | def dumps(self, obj, **kwargs): 24 | kwargs.setdefault('Dumper', Dumper) 25 | return yaml.dump(obj, **kwargs) 26 | -------------------------------------------------------------------------------- /modelscope/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba/lightweight-neural-architecture-search/8ccaf889fcd06079d268a355c765e9d0af071612/modelscope/utils/__init__.py -------------------------------------------------------------------------------- /modelscope/utils/config_ds.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | 3 | import os 4 | from pathlib import Path 5 | 6 | # Cache location 7 | from modelscope.hub.constants import DEFAULT_MODELSCOPE_DATA_ENDPOINT 8 | 9 | DEFAULT_CACHE_HOME = Path.home().joinpath('.cache') 10 | CACHE_HOME = os.getenv('CACHE_HOME', DEFAULT_CACHE_HOME) 11 | DEFAULT_MS_CACHE_HOME = os.path.join(CACHE_HOME, 'modelscope', 'hub') 12 | MS_CACHE_HOME = os.path.expanduser( 13 | os.getenv('MS_CACHE_HOME', DEFAULT_MS_CACHE_HOME)) 14 | 15 | DEFAULT_MS_DATASETS_CACHE = os.path.join(MS_CACHE_HOME, 'datasets') 16 | MS_DATASETS_CACHE = Path( 17 | os.getenv('MS_DATASETS_CACHE', DEFAULT_MS_DATASETS_CACHE)) 18 | 19 | DOWNLOADED_DATASETS_DIR = 'downloads' 20 | DEFAULT_DOWNLOADED_DATASETS_PATH = os.path.join(MS_DATASETS_CACHE, 21 | DOWNLOADED_DATASETS_DIR) 22 | DOWNLOADED_DATASETS_PATH = Path( 23 | os.getenv('DOWNLOADED_DATASETS_PATH', DEFAULT_DOWNLOADED_DATASETS_PATH)) 24 | 25 | HUB_DATASET_ENDPOINT = os.environ.get('HUB_DATASET_ENDPOINT', 26 | DEFAULT_MODELSCOPE_DATA_ENDPOINT) 27 | -------------------------------------------------------------------------------- /modelscope/utils/data_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | from collections.abc import Mapping 3 | 4 | import torch 5 | 6 | from modelscope.outputs import ModelOutputBase 7 | 8 | 9 | def to_device(batch, device, non_blocking=False): 10 | """Put the data to the target cuda device just before the forward function. 11 | Args: 12 | batch: The batch data out of the dataloader. 13 | device: (str | torch.device): The target device for the data. 14 | 15 | Returns: The data to the target device. 16 | 17 | """ 18 | if isinstance(batch, ModelOutputBase): 19 | for idx in range(len(batch)): 20 | batch[idx] = to_device(batch[idx], device) 21 | return batch 22 | elif isinstance(batch, dict) or isinstance(batch, Mapping): 23 | return type(batch)({k: to_device(v, device) for k, v in batch.items()}) 24 | elif isinstance(batch, (tuple, list)): 25 | return type(batch)(to_device(v, device) for v in batch) 26 | elif isinstance(batch, torch.Tensor): 27 | return batch.to(device, non_blocking=non_blocking) 28 | else: 29 | return batch 30 | -------------------------------------------------------------------------------- /modelscope/utils/file_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | 3 | import inspect 4 | import os 5 | from pathlib import Path 6 | 7 | 8 | # TODO: remove this api, unify to flattened args 9 | def func_receive_dict_inputs(func): 10 | """to decide if a func could recieve dict inputs or not 11 | 12 | Args: 13 | func (class): the target function to be inspected 14 | 15 | Returns: 16 | bool: if func only has one arg ``input`` or ``inputs``, return True, else return False 17 | """ 18 | full_args_spec = inspect.getfullargspec(func) 19 | varargs = full_args_spec.varargs 20 | varkw = full_args_spec.varkw 21 | if not (varargs is None and varkw is None): 22 | return False 23 | 24 | args = [] if not full_args_spec.args else full_args_spec.args 25 | args.pop(0) if (args and args[0] in ['self', 'cls']) else args 26 | 27 | if len(args) == 1 and args[0] in ['input', 'inputs']: 28 | return True 29 | 30 | return False 31 | 32 | 33 | def get_default_cache_dir(): 34 | """ 35 | default base dir: '~/.cache/modelscope' 36 | """ 37 | default_cache_dir = Path.home().joinpath('.cache', 'modelscope') 38 | return default_cache_dir 39 | 40 | 41 | def read_file(path): 42 | 43 | with open(path, 'r') as f: 44 | text = f.read() 45 | return text 46 | -------------------------------------------------------------------------------- /modelscope/utils/json_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | 3 | import json 4 | import numpy as np 5 | 6 | 7 | class EnhancedEncoder(json.JSONEncoder): 8 | """ Enhanced json encoder for not supported types """ 9 | 10 | def default(self, obj): 11 | if isinstance(obj, np.integer): 12 | return int(obj) 13 | elif isinstance(obj, np.floating): 14 | return float(obj) 15 | elif isinstance(obj, np.ndarray): 16 | return obj.tolist() 17 | return json.JSONEncoder.default(self, obj) 18 | -------------------------------------------------------------------------------- /modelscope/utils/logger.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | 3 | import importlib 4 | import logging 5 | from typing import Optional 6 | 7 | init_loggers = {} 8 | 9 | formatter = logging.Formatter( 10 | '%(asctime)s - %(name)s - %(levelname)s - %(message)s') 11 | 12 | 13 | def get_logger(log_file: Optional[str] = None, 14 | log_level: int = logging.INFO, 15 | file_mode: str = 'w'): 16 | """ Get logging logger 17 | 18 | Args: 19 | log_file: Log filename, if specified, file handler will be added to 20 | logger 21 | log_level: Logging level. 22 | file_mode: Specifies the mode to open the file, if filename is 23 | specified (if filemode is unspecified, it defaults to 'w'). 24 | """ 25 | 26 | logger_name = __name__.split('.')[0] 27 | logger = logging.getLogger(logger_name) 28 | 29 | if logger_name in init_loggers: 30 | add_file_handler_if_needed(logger, log_file, file_mode, log_level) 31 | return logger 32 | 33 | # handle duplicate logs to the console 34 | # Starting in 1.8.0, PyTorch DDP attaches a StreamHandler (NOTSET) 35 | # to the root logger. As logger.propagate is True by default, this root 36 | # level handler causes logging messages from rank>0 processes to 37 | # unexpectedly show up on the console, creating much unwanted clutter. 38 | # To fix this issue, we set the root logger's StreamHandler, if any, to log 39 | # at the ERROR level. 40 | for handler in logger.root.handlers: 41 | if type(handler) is logging.StreamHandler: 42 | handler.setLevel(logging.ERROR) 43 | 44 | stream_handler = logging.StreamHandler() 45 | handlers = [stream_handler] 46 | 47 | if importlib.util.find_spec('torch') is not None: 48 | from modelscope.utils.torch_utils import is_master 49 | is_worker0 = is_master() 50 | else: 51 | is_worker0 = True 52 | 53 | if is_worker0 and log_file is not None: 54 | file_handler = logging.FileHandler(log_file, file_mode) 55 | handlers.append(file_handler) 56 | 57 | for handler in handlers: 58 | handler.setFormatter(formatter) 59 | handler.setLevel(log_level) 60 | logger.addHandler(handler) 61 | 62 | if is_worker0: 63 | logger.setLevel(log_level) 64 | else: 65 | logger.setLevel(logging.ERROR) 66 | 67 | init_loggers[logger_name] = True 68 | 69 | return logger 70 | 71 | 72 | def add_file_handler_if_needed(logger, log_file, file_mode, log_level): 73 | for handler in logger.handlers: 74 | if isinstance(handler, logging.FileHandler): 75 | return 76 | 77 | if importlib.util.find_spec('torch') is not None: 78 | from modelscope.utils.torch_utils import is_master 79 | is_worker0 = is_master() 80 | else: 81 | is_worker0 = True 82 | 83 | if is_worker0 and log_file is not None: 84 | file_handler = logging.FileHandler(log_file, file_mode) 85 | file_handler.setFormatter(formatter) 86 | file_handler.setLevel(log_level) 87 | logger.addHandler(file_handler) 88 | -------------------------------------------------------------------------------- /modelscope/utils/megatron_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | 3 | from typing import Optional 4 | 5 | from megatron_util import initialize_megatron 6 | 7 | from modelscope.utils.config import Config 8 | from modelscope.utils.hub import read_config 9 | 10 | _DEFAULT_CFG_WITH_MODEL_TYPE = { 11 | 'gpt-moe': { 12 | 'version': 'moe', 13 | 'world_size': 8 14 | }, 15 | 'plug': { 16 | 'version': 'v1', 17 | 'world_size': 8, 18 | 'tensor_model_parallel_size': 8, 19 | 'seed': 1234 20 | }, 21 | 'mglm-text-summarization': { 22 | 'version': 'v1', 23 | 'seed': 1234 24 | }, 25 | } 26 | 27 | 28 | def init_megatron_util(cfg: Optional[Config] = None, 29 | model_dir: Optional[str] = None, 30 | **kwargs): 31 | assert not (cfg is None and model_dir is None), \ 32 | 'cfg and model_dir cannot both be None when initializing megatron_util' 33 | if cfg is None: 34 | cfg = read_config(model_dir) 35 | try: 36 | megatron_cfg = cfg.megatron 37 | except AttributeError: 38 | try: 39 | model_type = cfg.model.type 40 | except AttributeError: 41 | # Fit models without model type, such as mglm 42 | model_type = cfg.pipeline.type 43 | megatron_cfg = _DEFAULT_CFG_WITH_MODEL_TYPE[model_type] \ 44 | if model_type in _DEFAULT_CFG_WITH_MODEL_TYPE else {} 45 | megatron_cfg.update(kwargs) 46 | initialize_megatron(megatron_cfg) 47 | -------------------------------------------------------------------------------- /modelscope/utils/metric.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Megvii Inc. All rights reserved. 2 | # Copyright © Alibaba, Inc. and its affiliates. 3 | 4 | import functools 5 | import os 6 | from collections import defaultdict, deque 7 | 8 | import numpy as np 9 | import torch 10 | 11 | __all__ = [ 12 | 'AverageMeter', 13 | 'MeterBuffer', 14 | 'gpu_mem_usage', 15 | ] 16 | 17 | 18 | def gpu_mem_usage(): 19 | """ 20 | Compute the GPU memory usage for the current device (MB). 21 | """ 22 | mem_usage_bytes = torch.cuda.max_memory_allocated() 23 | return mem_usage_bytes / (1024 * 1024) 24 | 25 | 26 | class AverageMeter: 27 | """Track a series of values and provide access to smoothed values over a 28 | window or the global series average. 29 | """ 30 | 31 | def __init__(self, window_size=50): 32 | self._deque = deque(maxlen=window_size) 33 | self._total = 0.0 34 | self._count = 0 35 | 36 | def update(self, value): 37 | self._deque.append(value) 38 | self._count += 1 39 | self._total += value 40 | 41 | @property 42 | def median(self): 43 | d = np.array(list(self._deque)) 44 | return np.median(d) 45 | 46 | @property 47 | def avg(self): 48 | # if deque is empty, nan will be returned. 49 | d = np.array(list(self._deque)) 50 | return d.mean() 51 | 52 | @property 53 | def global_avg(self): 54 | return self._total / max(self._count, 1e-5) 55 | 56 | @property 57 | def latest(self): 58 | return self._deque[-1] if len(self._deque) > 0 else None 59 | 60 | @property 61 | def total(self): 62 | return self._total 63 | 64 | def reset(self): 65 | self._deque.clear() 66 | self._total = 0.0 67 | self._count = 0 68 | 69 | def clear(self): 70 | self._deque.clear() 71 | 72 | 73 | class MeterBuffer(defaultdict): 74 | """Computes and stores the average and current value""" 75 | 76 | def __init__(self, window_size=20): 77 | factory = functools.partial(AverageMeter, window_size=window_size) 78 | super().__init__(factory) 79 | 80 | def reset(self): 81 | for v in self.values(): 82 | v.reset() 83 | 84 | def get_filtered_meter(self, filter_key='time'): 85 | return {k: v for k, v in self.items() if filter_key in k} 86 | 87 | def update(self, values=None, **kwargs): 88 | if values is None: 89 | values = {} 90 | values.update(kwargs) 91 | for k, v in values.items(): 92 | if isinstance(v, torch.Tensor): 93 | v = v.detach() 94 | self[k].update(v) 95 | 96 | def clear_meters(self): 97 | for v in self.values(): 98 | v.clear() 99 | -------------------------------------------------------------------------------- /modelscope/utils/tensor_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # Part of the implementation is borrowed from huggingface/transformers. 3 | from collections.abc import Mapping 4 | 5 | 6 | def torch_nested_numpify(tensors): 7 | """ Numpify nested torch tensors. 8 | 9 | NOTE: If the type of input tensors is dict-like(Mapping, dict, OrderedDict, etc.), the return type will be dict. 10 | 11 | Args: 12 | tensors: Nested torch tensors. 13 | 14 | Returns: 15 | The numpify tensors. 16 | """ 17 | 18 | import torch 19 | "Numpify `tensors` (even if it's a nested list/tuple of tensors)." 20 | if isinstance(tensors, (list, tuple)): 21 | return type(tensors)(torch_nested_numpify(t) for t in tensors) 22 | if isinstance(tensors, Mapping): 23 | # return dict 24 | return {k: torch_nested_numpify(t) for k, t in tensors.items()} 25 | if isinstance(tensors, torch.Tensor): 26 | t = tensors.cpu() 27 | return t.numpy() 28 | return tensors 29 | 30 | 31 | def torch_nested_detach(tensors): 32 | """ Detach nested torch tensors. 33 | 34 | NOTE: If the type of input tensors is dict-like(Mapping, dict, OrderedDict, etc.), the return type will be dict. 35 | 36 | Args: 37 | tensors: Nested torch tensors. 38 | 39 | Returns: 40 | The detached tensors. 41 | """ 42 | 43 | import torch 44 | "Detach `tensors` (even if it's a nested list/tuple of tensors)." 45 | if isinstance(tensors, (list, tuple)): 46 | return type(tensors)(torch_nested_detach(t) for t in tensors) 47 | if isinstance(tensors, Mapping): 48 | return {k: torch_nested_detach(t) for k, t in tensors.items()} 49 | if isinstance(tensors, torch.Tensor): 50 | return tensors.detach() 51 | return tensors 52 | -------------------------------------------------------------------------------- /modelscope/utils/timer.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | # Copyright © Alibaba, Inc. and its affiliates. 3 | 4 | import datetime 5 | import time 6 | 7 | 8 | class Timer(object): 9 | 10 | def __init__(self): 11 | """Recorder of time consumption. 12 | 13 | """ 14 | self.reset() 15 | 16 | @property 17 | def average_time(self): 18 | return self.total_time / self.calls if self.calls > 0 else 0.0 19 | 20 | def tic(self): 21 | # using time.time instead of time.clock because time time.clock 22 | # does not normalize for multithreading 23 | self.start_time = time.time() 24 | 25 | def toc(self, average=True): 26 | self.add(time.time() - self.start_time) 27 | if average: 28 | return self.average_time 29 | else: 30 | return self.diff 31 | 32 | def add(self, time_diff): 33 | self.diff = time_diff 34 | self.total_time += self.diff 35 | self.calls += 1 36 | 37 | def reset(self): 38 | self.total_time = 0.0 39 | self.calls = 0 40 | self.start_time = 0.0 41 | self.diff = 0.0 42 | 43 | def avg_time_str(self): 44 | time_str = str(datetime.timedelta(seconds=self.average_time)) 45 | return time_str 46 | 47 | 48 | def get_time_str(time_diff): 49 | time_str = str(datetime.timedelta(seconds=time_diff)) 50 | return time_str 51 | -------------------------------------------------------------------------------- /modelscope/utils/type_assert.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | 3 | from functools import wraps 4 | from inspect import signature 5 | 6 | 7 | def type_assert(*ty_args, **ty_kwargs): 8 | """a decorator which is used to check the types of arguments in a function or class 9 | Examples: 10 | >>> @type_assert(str) 11 | ... def main(a: str, b: list): 12 | ... print(a, b) 13 | >>> main(1) 14 | Argument a must be a str 15 | 16 | >>> @type_assert(str, (int, str)) 17 | ... def main(a: str, b: int | str): 18 | ... print(a, b) 19 | >>> main('1', [1]) 20 | Argument b must be (, ) 21 | 22 | >>> @type_assert(str, (int, str)) 23 | ... class A: 24 | ... def __init__(self, a: str, b: int | str) 25 | ... print(a, b) 26 | >>> a = A('1', [1]) 27 | Argument b must be (, ) 28 | """ 29 | 30 | def decorate(func): 31 | # If in optimized mode, disable type checking 32 | if not __debug__: 33 | return func 34 | 35 | # Map function argument names to supplied types 36 | sig = signature(func) 37 | bound_types = sig.bind_partial(*ty_args, **ty_kwargs).arguments 38 | 39 | @wraps(func) 40 | def wrapper(*args, **kwargs): 41 | bound_values = sig.bind(*args, **kwargs) 42 | # Enforce type assertions across supplied arguments 43 | for name, value in bound_values.arguments.items(): 44 | if name in bound_types: 45 | if not isinstance(value, bound_types[name]): 46 | raise TypeError('Argument {} must be {}'.format( 47 | name, bound_types[name])) 48 | return func(*args, **kwargs) 49 | 50 | return wrapper 51 | 52 | return decorate 53 | -------------------------------------------------------------------------------- /modelscope/utils/typing.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | 3 | from typing import Dict, List, Tuple, Union 4 | 5 | Image = Union[str, 'Image.Image', 'numpy.ndarray'] 6 | Text = str 7 | Audio = Union[str, bytes, 'np.ndarray'] 8 | Video = Union[str, 'np.ndarray', 'cv2.VideoCapture'] 9 | 10 | Tensor = Union['torch.Tensor', 'tf.Tensor'] 11 | -------------------------------------------------------------------------------- /modelscope/version.py: -------------------------------------------------------------------------------- 1 | # Make sure to modify __release_datetime__ to release time when making official release. 2 | __version__ = '1.2.0' 3 | # default release datetime for branches under active development is set 4 | # to be a time far-far-away-into-the-future 5 | __release_datetime__ = '2099-10-13 08:56:12' 6 | -------------------------------------------------------------------------------- /requirements/nas.txt: -------------------------------------------------------------------------------- 1 | braceexpand 2 | dataclasses 3 | easydict 4 | filelock 5 | ftfy 6 | regex 7 | requests 8 | scipy==1.5.4 9 | tabulate==0.8.9 10 | thop>=0.0.31 11 | tqdm 12 | addict 13 | yapf 14 | packaging 15 | importlib_metadata 16 | -------------------------------------------------------------------------------- /requirements/tests.txt: -------------------------------------------------------------------------------- 1 | expecttest 2 | flake8 3 | isort>=4.3.21 4 | pre-commit 5 | yapf==0.30.0 # use fix version to ensure consistent auto-styling 6 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [isort] 2 | line_length = 79 3 | multi_line_output = 0 4 | known_standard_library = setuptools 5 | known_first_party = modelscope 6 | known_third_party = json,yaml 7 | no_lines_before = STDLIB,LOCALFOLDER 8 | default_section = THIRDPARTY 9 | 10 | [yapf] 11 | BASED_ON_STYLE = pep8 12 | BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF = true 13 | SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN = true 14 | SPLIT_BEFORE_ARITHMETIC_OPERATOR = true 15 | 16 | [codespell] 17 | skip = *.ipynb 18 | quiet-level = 3 19 | ignore-words-list = patten,nd,ty,mot,hist,formating,winn,gool,datas,wan,confids 20 | 21 | [flake8] 22 | select = B,C,E,F,P,T4,W,B9 23 | max-line-length = 120 24 | ignore = F401,F405,F821,W503 25 | exclude = docs/src,*.pyi,.git 26 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import re, os 2 | import shutil 3 | import setuptools 4 | 5 | def get_install_requirements(): 6 | with open('requirements/nas.txt', 'r', encoding='utf-8') as fin: 7 | reqs = [x.strip() for x in fin.read().splitlines()] 8 | reqs = [x for x in reqs if not x.startswith('#')] 9 | return reqs 10 | 11 | with open('tinynas/__init__.py', 'r') as f: 12 | version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', f.read(), 13 | re.MULTILINE).group(1) 14 | 15 | with open('README.md', encoding='utf-8') as f: 16 | readme_md = f.read() 17 | 18 | def pack_resource(): 19 | # pack resource such as configs and tools 20 | root_dir = os.path.dirname(__file__) 21 | proj_dir = os.path.join(root_dir,'tinynas') 22 | 23 | filenames = ['configs', 'tools'] 24 | for filename in filenames: 25 | src_dir = os.path.join(root_dir, filename) 26 | dst_dir = os.path.join(proj_dir, filename) 27 | if os.path.exists(dst_dir): 28 | shutil.rmtree(dst_dir) 29 | shutil.copytree(src_dir, dst_dir) 30 | 31 | if __name__ == '__main__': 32 | pack_resource() 33 | setuptools.setup( 34 | name='tinynas', 35 | version=version, 36 | author='TinyML team of Alibaba DAMO Academy', 37 | description='A lightweight zero-short NAS toolbox for backbone search', 38 | long_description=readme_md, 39 | long_description_content_type='text/markdown', 40 | license='Apache License', 41 | packages=setuptools.find_packages(exclude=['*configs*', '*tools*', '*modelscope*']), 42 | include_package_data=True, 43 | install_requires=get_install_requirements(), 44 | classifiers=[ 45 | 'License :: OSI Approved :: Apache Software License', 46 | 'Programming Language :: Python :: 3', 47 | 'Operating System :: OS Independent' 48 | ], 49 | ) 50 | -------------------------------------------------------------------------------- /tinynas/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | __version__ = '2.0.0' 5 | -------------------------------------------------------------------------------- /tinynas/budgets/README.md: -------------------------------------------------------------------------------- 1 | ## Budgets module 2 | 3 | This module mainly compare between a actual value of one model and a budget value. Currently, only ExceedBudget clas is implemented, which will return false if the model value exceed budget value setting in config. 4 | 5 | - **Surpported Budgets** 6 | 7 | `layers`: the Conv layers budget of the network. 8 | 9 | `flops`: the FLOPs budget of the network. 10 | 11 | `model_size`: the number of parameters budget of the network. 12 | 13 | `latency`: the latency budget of the network. 14 | 15 | `max_feature`: the max feature map budget for MCU of the network. 16 | 17 | `efficient_score`: the efficient score budget of the network. 18 | -------------------------------------------------------------------------------- /tinynas/budgets/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from .builder import build_budget 6 | from .base import * 7 | from .budgets import * 8 | -------------------------------------------------------------------------------- /tinynas/budgets/base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from abc import ABC, abstractmethod 6 | 7 | class BudgetBase(ABC, ): 8 | 9 | def __init__(self, 10 | name, 11 | budget): 12 | super().__init__() 13 | self.budget_name = name 14 | self.budget_value = budget 15 | 16 | @abstractmethod 17 | def __call__(self, input): 18 | pass 19 | 20 | @property 21 | def name(self,): 22 | return self.budget_name 23 | 24 | @property 25 | def budget(self,): 26 | return self.budget_value 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /tinynas/budgets/budgets.py: -------------------------------------------------------------------------------- 1 | from .builder import BUDGETS 2 | from .base import BudgetBase 3 | 4 | @BUDGETS.register_module(module_name = 'layers') 5 | @BUDGETS.register_module(module_name = 'model_size') 6 | @BUDGETS.register_module(module_name = 'flops') 7 | @BUDGETS.register_module(module_name = 'latency') 8 | @BUDGETS.register_module(module_name = 'max_feature') 9 | @BUDGETS.register_module(module_name = 'efficient_score') 10 | class ExceedBudget(BudgetBase): 11 | def __init__(self, name, budget, logger, **kwargs): 12 | super().__init__(name, budget) 13 | self.logger = logger 14 | 15 | def compare(self, model_info): 16 | input = model_info[self.name] 17 | if self.budget < input: 18 | self.logger.debug( 19 | '{} value = {} in the structure_info exceed the budget ={}'. 20 | format(self.name, input, self.budget)) 21 | return False 22 | return True 23 | 24 | def __call__(self, model_info): 25 | return self.compare(model_info) 26 | -------------------------------------------------------------------------------- /tinynas/budgets/builder.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from modelscope.utils.registry import Registry, build_from_cfg 6 | 7 | BUDGETS= Registry('budgets') 8 | 9 | def build_budget(cfg, default_args: dict = None): 10 | """ build budget given a budget name 11 | 12 | Args: 13 | name (str, optional): Model name, if None, default budget 14 | will be used. 15 | default_args (dict, optional): Default initialization arguments. 16 | """ 17 | cfg['name'] = cfg['type'] 18 | return build_from_cfg(cfg, BUDGETS, default_args=default_args) 19 | 20 | -------------------------------------------------------------------------------- /tinynas/deploy/cnn3dnet/demo.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | 3 | import ast 4 | import os 5 | import argparse 6 | import torch 7 | from cnn3dnet import Cnn3DNet 8 | 9 | def parse_args(): 10 | parser = argparse.ArgumentParser() 11 | parser.add_argument('--structure_txt', type=str) 12 | parser.add_argument('--pretrained', type=str, default=None) 13 | args = parser.parse_args() 14 | return args 15 | 16 | def get_backbone(filename, 17 | pretrained=True, 18 | network_id=0, 19 | classification=True #False for detetion 20 | ): 21 | # load best structures 22 | with open(filename, 'r') as fin: 23 | content = fin.read() 24 | output_structures = ast.literal_eval(content) 25 | 26 | network_arch = output_structures['space_arch'] 27 | best_structures = output_structures['best_structures'] 28 | 29 | # If task type is classification, param num_classes is required 30 | out_indices = (1, 2, 3, 4) if not classification else (4, ) 31 | backbone = Cnn3DNet( 32 | structure_info=best_structures[network_id], 33 | out_indices=out_indices, 34 | num_classes=400, 35 | classification=classification) 36 | backbone.init_weights(pretrained) 37 | 38 | return backbone, network_arch 39 | 40 | 41 | if __name__ == '__main__': 42 | # make input 43 | 44 | args = parse_args() 45 | 46 | x = torch.randn(1, 3, 16, 224, 224) 47 | 48 | # instantiation 49 | backbone, network_arch = get_backbone(args.structure_txt, 50 | args.pretrained) 51 | 52 | print(backbone) 53 | # forward 54 | input_data = [x] 55 | backbone.eval() 56 | pred = backbone(*input_data) 57 | 58 | #print output 59 | for o in pred: 60 | print(o.size()) 61 | -------------------------------------------------------------------------------- /tinynas/deploy/cnn3dnet/modules/__init__.py: -------------------------------------------------------------------------------- 1 | from .blocks_basic_3D import * 2 | from .super_res3d_k1dwk1 import * 3 | 4 | 5 | __all_blocks_3D__ = { 6 | 'Conv3DKXBN': Conv3DKXBN, 7 | 'Conv3DKXBNRELU': Conv3DKXBNRELU, 8 | 'BaseSuperBlock3D': BaseSuperBlock3D, 9 | 'Res3DK1DWK1': Res3DK1DWK1, 10 | 'SuperRes3DK1DWK1': SuperRes3DK1DWK1, 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tinynas/deploy/cnnnet/demo.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | 3 | import ast 4 | import os 5 | import argparse 6 | import torch 7 | from cnnnet import CnnNet 8 | 9 | def parse_args(): 10 | parser = argparse.ArgumentParser() 11 | parser.add_argument('--structure_txt', type=str) 12 | parser.add_argument('--pretrained', type=str, default=None) 13 | args = parser.parse_args() 14 | return args 15 | 16 | def get_backbone(filename, 17 | pretrained=True, 18 | network_id=0, 19 | classification=True #False for detetion 20 | ): 21 | # load best structures 22 | with open(filename, 'r') as fin: 23 | content = fin.read() 24 | output_structures = ast.literal_eval(content) 25 | 26 | network_arch = output_structures['space_arch'] 27 | best_structures = output_structures['best_structures'] 28 | 29 | # If task type is classification, param num_classes is required 30 | out_indices = (1, 2, 3, 4) if not classification else (4, ) 31 | backbone = CnnNet( 32 | structure_info=best_structures[network_id], 33 | out_indices=out_indices, 34 | num_classes=1000, 35 | classification=classification) 36 | backbone.init_weights(pretrained) 37 | 38 | return backbone, network_arch 39 | 40 | 41 | if __name__ == '__main__': 42 | # make input 43 | 44 | args = parse_args() 45 | 46 | x = torch.randn(1, 3, 224, 224) 47 | 48 | # instantiation 49 | backbone, network_arch = get_backbone(args.structure_txt, 50 | args.pretrained) 51 | 52 | print(backbone) 53 | # forward 54 | input_data = [x] 55 | backbone.eval() 56 | pred = backbone(*input_data) 57 | 58 | #print output 59 | for o in pred: 60 | print(o.size()) 61 | -------------------------------------------------------------------------------- /tinynas/deploy/cnnnet/modules/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from .blocks_basic import (BaseSuperBlock, ConvKXBN, ConvKXBNRELU, 6 | network_weight_stupid_init) 7 | from .super_res_k1dwk1 import ResK1DWK1, SuperResK1DWK1 8 | from .super_res_k1dwsek1 import ResK1DWSEK1, SuperResK1DWSEK1 9 | from .super_quant_res_k1dwk1 import SuperQuantResK1DWK1 10 | from .super_res_k1kxk1 import ResK1KXK1, SuperResK1KXK1 11 | from .super_res_k1kx import ResK1KX, SuperResK1KX 12 | from .super_res_kxkx import ResKXKX, SuperResKXKX 13 | 14 | __all_blocks__ = { 15 | 'ConvKXBN': ConvKXBN, 16 | 'ConvKXBNRELU': ConvKXBNRELU, 17 | 'BaseSuperBlock': BaseSuperBlock, 18 | 'ResK1KXK1': ResK1KXK1, 19 | 'ResK1KX': ResK1KX, 20 | 'ResKXKX': ResKXKX, 21 | 'ResK1DWK1': ResK1DWK1, 22 | 'ResK1DWSEK1': ResK1DWSEK1, 23 | 'SuperResK1KXK1': SuperResK1KXK1, 24 | 'SuperResK1KX': SuperResK1KX, 25 | 'SuperResKXKX': SuperResKXKX, 26 | 'SuperResK1DWK1': SuperResK1DWK1, 27 | 'SuperResK1DWSEK1': SuperResK1DWSEK1, 28 | 'SuperQuantResK1DWK1': SuperQuantResK1DWK1, 29 | } 30 | -------------------------------------------------------------------------------- /tinynas/deploy/cnnnet/modules/super_quant_res_k1dwk1.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import copy 6 | import os 7 | import sys 8 | from .super_res_k1dwk1 import SuperResK1DWK1 9 | 10 | class SuperQuantResK1DWK1(SuperResK1DWK1): 11 | 12 | def __init__(self, 13 | structure_info, 14 | no_create=False, 15 | dropout_channel=None, 16 | dropout_layer=None, 17 | **kwargs): 18 | ''' 19 | 20 | :param structure_info: { 21 | 'class': 'SuperResK1DWK1', 22 | 'in': in_channels, 23 | 'out': out_channels, 24 | 's': stride (default=1), 25 | 'k': kernel_size, 26 | 'p': padding (default=(k-1)//2, 27 | 'g': grouping (default=1), 28 | 'btn':, bottleneck_channels, 29 | 'L': num_inner_layers, 30 | } 31 | :param NAS_mode: 32 | ''' 33 | super().__init__( 34 | structure_info=structure_info, 35 | no_create=no_create, 36 | dropout_channel=dropout_channel, 37 | dropout_layer=dropout_layer, 38 | **kwargs) 39 | 40 | 41 | __module_blocks__ = { 42 | 'SuperQuantResK1DWK1': SuperQuantResK1DWK1, 43 | } 44 | -------------------------------------------------------------------------------- /tinynas/evolutions/README.md: -------------------------------------------------------------------------------- 1 | ## Population module 2 | 3 | Currently, Only a simple population class is implemented, which maintain the Populaiton. The information in Population consists of different ranked list, including Structure_info, ACC, Score, Paramters, FLOPs, Latency, Layers, Stages. More information for the candidate structure could be added freely. 4 | 5 | - **Population Class** 6 | 7 | `init_population`: Initialize population parameters and information list. 8 | 9 | `update_population`: Update the individual network information that meets the searched budgets. 10 | 11 | `rank_population`: Rank the Population info list with ACC. 12 | 13 | `merge_shared_data`: Merge different Population info between different threads. 14 | 15 | `export_dict`: Export the whole Population info list to a dict for the searching process. 16 | 17 | `get_individual_info`: Get the individual network information with index. 18 | -------------------------------------------------------------------------------- /tinynas/evolutions/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from .population import Population 6 | -------------------------------------------------------------------------------- /tinynas/latency/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from .robust_gpu_predictor import RobustGpuPredictor 6 | from .op_predictor import OpPredictor 7 | from .builder import * 8 | -------------------------------------------------------------------------------- /tinynas/latency/builder.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from modelscope.utils.registry import Registry, build_from_cfg 6 | 7 | LATENCIES = Registry('latencies') 8 | 9 | def build_latency(cfg, default_args: dict = None): 10 | """ build latency given a latency name 11 | 12 | Args: 13 | name (str, optional): Latency name, if None, default latency 14 | will be used. 15 | default_args (dict, optional): Default initialization arguments. 16 | """ 17 | return build_from_cfg(cfg, LATENCIES, default_args=default_args) 18 | 19 | -------------------------------------------------------------------------------- /tinynas/latency/op_predictor.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import numpy as np 3 | from .op_profiler import OpProfiler 4 | from .builder import LATENCIES 5 | 6 | @LATENCIES.register_module(module_name = 'OpPredictor') 7 | class OpPredictor(): 8 | def __init__(self, device_name = 'V100', data_type = 'FP32', batch_size = 32, image_size = 224, logger=None, **kwargs): 9 | 10 | self.logger = logger or logging 11 | self.batch_size = batch_size 12 | self.image_size = image_size 13 | self.predictor = OpProfiler( 14 | device_name = device_name, 15 | data_type = data_type, 16 | logger = self.logger) 17 | 18 | def __call__(self, model): 19 | try: 20 | net_params = model.get_params_for_trt(self.image_size) 21 | # remove other params, only conv and convDW 22 | net_params_conv = [] 23 | for idx, net_param in enumerate(net_params): 24 | if net_param[0] in ['Regular', 'Depthwise']: 25 | net_params_conv.append(net_param) 26 | times = [0] * len(net_params_conv) 27 | 28 | # the unit is millisecond with batch_size, so modify it to second 29 | _, the_latency = self.predictor(net_params_conv, times, 30 | self.batch_size) 31 | the_latency = the_latency / self.batch_size / 1000 32 | except Exception as e: 33 | self.logger.error(str(e)) 34 | the_latency = np.inf 35 | 36 | return the_latency 37 | 38 | -------------------------------------------------------------------------------- /tinynas/latency/op_profiler/R50.txt: -------------------------------------------------------------------------------- 1 | [ {'class': 'ConvKXBNRELU', 'in': 3, 'k': 7, 'out': 64, 's': 2}, 2 | { 'L': 3, 3 | 'btn': 64, 4 | 'class': 'SuperResK1KXK1', 5 | 'in': 64, 6 | 'inner_class': 'ResK1KXK1', 7 | 'k': 3, 8 | 'out': 256, 9 | 's': 2}, 10 | { 'L': 4, 11 | 'btn': 128, 12 | 'class': 'SuperResK1KXK1', 13 | 'in': 256, 14 | 'inner_class': 'ResK1KXK1', 15 | 'k': 3, 16 | 'out': 512, 17 | 's': 2}, 18 | { 'L': 6, 19 | 'btn': 256, 20 | 'class': 'SuperResK1KXK1', 21 | 'in': 512, 22 | 'inner_class': 'ResK1KXK1', 23 | 'k': 3, 24 | 'out': 1024, 25 | 's': 2}, 26 | { 'L': 3, 27 | 'btn': 512, 28 | 'class': 'SuperResK1KXK1', 29 | 'in': 1024, 30 | 'inner_class': 'ResK1KXK1', 31 | 'k': 3, 32 | 'out': 2048, 33 | 's': 2}] 34 | -------------------------------------------------------------------------------- /tinynas/latency/op_profiler/README.md: -------------------------------------------------------------------------------- 1 | *** 2 | ![framework](op_profiler.jpg) 3 | *** 4 | ## Introduction 5 | 6 | 7 | 8 | The latency predictor based on Conv operations profiler, supporting Nvidia GPUs. 9 | 10 | Thanks to the sequential structure of the neural network, we can approximate the latency of the model by summing up the latency of each layer. 11 | 12 | First build a operations latency library containing the latency of sampling Conv operations under a large [configurations](python/config.in). 13 | 14 | Then use the `predictor.py` to predict the summary latency of each layer in the target network structure. The operation which is not in the library is obtained by Scipy Interpolations between other operations. 15 | 16 | 17 | *** 18 |
19 | Major features 20 | 21 | * **Sampling process with python example** 22 | 23 | `python`: the code how to generate the operations latency library on target device. [How to use](python/README.md). 24 | 25 | * **Nvidia GPUs TRT latency** 26 | 27 | `V100`: the sampling operations latency library for Nvidia GPU V100 based TRT with precision of FP32/FP16/INT8 28 | 29 | Other GPUs like P100/T4, could use the sampling code to generate the library like V100. 30 | 31 |
32 | 33 | *** 34 | 35 | ## Format for each element in the library 36 | 37 | ```python 38 | {Conv_type, Batch, In_C, In_H, In_W, Out_C, Kernel, Stride, ElmtFused} Latency 39 | ``` 40 | * Conv_type: 'Regular' or 'Depthwise' convolution 41 | * Batch: batch size, typical = 1, 32, 64, 128 42 | * In_C: input_channels; Out_C: output_channels; In_C=Out_C*Ratio 43 | * In_H: input_height; In_W: input_width 44 | * Kernel: kernel size, typical = 1, 3, 5, 7 45 | * Stride: stride value for convolution, typical = 1, 2 46 | * ElmtFused: whether the elementwise sum operation of the relink structure is included 47 | * Latency: the profiling time of each element 48 | 49 | 50 | ## Format for each element in the predictor 51 | [("Regular", self.stride, elmtfused, self.kernel_size, 1, self.in_channels, input_resolution, self.out_channels)] 52 | 53 | ```python 54 | [Conv_type, Stride, ElmtFused, Kernel, Batch, In_C, In_H, Out_C] 55 | ``` 56 | * Conv_type: 'Regular' or 'Depthwise' 57 | * Stride: stride value for convolution, typical = 1, 2 58 | * ElmtFused: whether the elementwise sum operation of the relink structure is included 59 | * Kernel: kernel size, typical = 1, 3, 5, 7 60 | * Batch: 1, specific batchsize in a hyper parameter for the predictor 61 | * In_C: input_channels; Out_C: output_channels 62 | * In_H: the width the feature map is equal to the height 63 | -------------------------------------------------------------------------------- /tinynas/latency/op_profiler/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from .predictor import OpProfiler 6 | -------------------------------------------------------------------------------- /tinynas/latency/op_profiler/op_profiler.jpg: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:957880a2e8c01d075810b244742e73e373190ed4342cf34e567fde5b5e0a2d0f 3 | size 311735 4 | -------------------------------------------------------------------------------- /tinynas/latency/op_profiler/python/README.md: -------------------------------------------------------------------------------- 1 | *** 2 | ### example 3 | 1. generate the sampling txt with the configurations. 4 | ```shell 5 | python sample.py --config path_to_config_file --nbits 8 --save-file sample 6 | ``` 7 | 8 | 2. Use the shell to inference each convolution with specific program on device, generate log. 9 | ```shell 10 | sh sample.sh 11 | ``` 12 | 13 | 3. read the log to generate the final lib. 14 | 15 | ```shell 16 | python read_log.py 17 | ``` 18 | -------------------------------------------------------------------------------- /tinynas/latency/op_profiler/python/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba/lightweight-neural-architecture-search/8ccaf889fcd06079d268a355c765e9d0af071612/tinynas/latency/op_profiler/python/__init__.py -------------------------------------------------------------------------------- /tinynas/latency/op_profiler/python/config.in: -------------------------------------------------------------------------------- 1 | batch 1 2 | elmt_fused 0 3 | filter_size 1 3 5 7 4 | min_feature_size 7 5 | max_feature_size 256 6 | number_feature_size 16 7 | output_channel 32 64 96 128 160 192 256 384 512 768 1024 1280 1536 1792 1920 2048 8 | stride 1 2 9 | type 0 10 | channel_ratio 4 2 1 0.5 0.25 11 | -------------------------------------------------------------------------------- /tinynas/latency/op_profiler/python/read_log.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import argparse 6 | import ast 7 | import copy 8 | import os 9 | import sys 10 | import time 11 | 12 | import numpy as np 13 | 14 | # {Conv_type, Batch, In_C, In_H, In_W, Out_C, Kernel, Stride, ElmtFused} Latency 15 | str_format = '%s %d %d %d %d %d %d %d %d %d\n' 16 | Conv_type_dict = {0: 'Regular', 1: 'Depthwise'} 17 | 18 | 19 | def parse_args(): 20 | parser = argparse.ArgumentParser() 21 | parser.add_argument('--log_file', type=str, default='log') 22 | parser.add_argument('--nbits', type=int, default=8) 23 | parser.add_argument('--save_file', type=str, default='../conv_data.out') 24 | args = parser.parse_args() 25 | return args 26 | 27 | 28 | def main(): 29 | import pdb 30 | args = parse_args() 31 | lines = open('%s.int%d.txt' % 32 | (args.log_file, args.nbits)).read().splitlines() 33 | iter_flag = False 34 | lib_lines = [] 35 | for line in lines: 36 | if 'iter-' in line: 37 | if iter_flag: 38 | exit() 39 | params = line.split(': ')[1].split(' ') 40 | params_line = '{%s}' % (','.join(params[:-1])) 41 | print(params_line) 42 | iter_flag = True 43 | if iter_flag and 'run time_ms: ' in line: 44 | iter_flag = False 45 | # "run time_ms: 4123.077000 ms" 46 | latency = float(line.split(' ')[2]) 47 | lib_lines.append('%s %f' % (params_line, latency)) 48 | print(latency) 49 | with open(args.save_file + '.int%d' % (args.nbits), 'w') as fw: 50 | fw.writelines('\n'.join(lib_lines)) 51 | 52 | 53 | if __name__ == '__main__': 54 | main() 55 | -------------------------------------------------------------------------------- /tinynas/latency/op_profiler/python/sample.sh: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | nbits="${2:-"8"}" 6 | 7 | DataFile="sample.int8.txt" 8 | 9 | LD_LIBRARY_PATH=sample_lib/:$LD_LIBRARY_PATH 10 | insmod /system/init/soc-nna.ko 11 | 12 | if [ ! -e $DataFile ]; then 13 | echo "Fail to open file" 14 | exit 1 15 | fi 16 | 17 | iter=0 18 | 19 | # {Conv_type, Batch, In_C, In_H, In_W, Out_C, Kernel, Stride, ElmtFused} Latency 20 | while read line 21 | do 22 | [ -z "$line" ] && continue 23 | set -- $line 24 | iter=$((iter+1)) 25 | echo "iter-$iter: $line" 26 | 27 | Conv_type=$(($1)) 28 | Batch=$(($2)) 29 | In_C=$(($3)) 30 | In_H=$(($4)) 31 | In_W=$(($5)) 32 | Out_C=$(($6)) 33 | Kernel=$(($7)) 34 | Stride=$(($8)) 35 | # ElmtFused=$(($9)) 36 | # Latency=$((${10})) 37 | 38 | # call venus_eval_test_uclibc, an example for profiling each convolution. 39 | if [ $iter -gt 3539 ] 40 | then 41 | ./venus_eval_test_uclibc $In_H $In_W $In_C $nbits $Out_C $nbits $Kernel $Kernel $Stride $nbits 42 | fi 43 | done < $DataFile 44 | -------------------------------------------------------------------------------- /tinynas/latency/op_profiler/test_predictor.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import argparse 6 | import logging 7 | ### 8 | import os 9 | 10 | import predictor as opp 11 | import torch 12 | from nas.models import MasterNet 13 | 14 | 15 | def predict_the_latency(save_dir, 16 | plainnet_struct, 17 | resolution, 18 | device_name='V100', 19 | date_type='FP16', 20 | bs_list=[1, 32, 64], 21 | save_onnx=False): 22 | 23 | fw = open('%s/conv_test.out' % (device_name), 'w') 24 | the_model = MasterNet( 25 | num_classes=1000, 26 | structure_txt=plainnet_struct, 27 | no_create=False, 28 | out_indices=(4, )) 29 | print('the model is %s\n' % (str(the_model))) 30 | 31 | net_params = the_model.get_params_for_trt(resolution) 32 | # print(net_params) 33 | # remove other params, only conv and convDW 34 | net_params_conv = [] 35 | for idx, net_param in enumerate(net_params): 36 | if net_param[0] in ['Regular', 'Depthwise']: 37 | net_params_conv.append(net_param) 38 | # print("idx %d: %s"%(idx, net_param)) 39 | times = [0] * len(net_params_conv) 40 | for net_param_conv in net_params_conv: 41 | fw.write('%s %s\n' % (net_param_conv, 0)) 42 | 43 | Predictor_opp = opp.OpProfiler( 44 | device_name=device_name, date_type=date_type) 45 | the_latency_list = [] 46 | for batchsize in bs_list: 47 | _, the_latency = Predictor_opp(net_params_conv, times, batchsize) 48 | the_latency = the_latency / batchsize 49 | the_latency_list.append(the_latency_list) 50 | print('batchsize: %d, the TensorRT predict Latency is %.4f ms' % 51 | (batchsize, the_latency)) 52 | 53 | fw.close() 54 | 55 | if save_onnx: 56 | for batchsize in bs_list: 57 | x = torch.randn( 58 | batchsize, 3, resolution, resolution, requires_grad=False) 59 | out_name = os.path.join( 60 | save_dir, '%s/R50_bs%d.onnx' % (device_name, batchsize)) 61 | os.makedirs(os.path.dirname(out_name), exist_ok=True) 62 | torch.onnx.export(the_model, x, out_name, input_names=['input']) 63 | 64 | return the_latency_list 65 | -------------------------------------------------------------------------------- /tinynas/latency/robust_gpu_predictor.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import argparse 6 | import logging 7 | import os 8 | import sys 9 | import time 10 | 11 | import numpy as np 12 | import torch 13 | from .builder import LATENCIES 14 | 15 | 16 | def __get_latency__(model, batch_size, image_size, channel, gpu, 17 | benchmark_repeat_times, fp16): 18 | device = torch.device('cuda:{}'.format(gpu)) 19 | torch.backends.cudnn.benchmark = True 20 | 21 | torch.cuda.set_device(gpu) 22 | model = model.cuda(gpu) 23 | if fp16: 24 | model = model.half() 25 | dtype = torch.float16 26 | else: 27 | dtype = torch.float32 28 | if type(image_size) == list and len(image_size) == 2: 29 | the_image = torch.randn( 30 | batch_size, 31 | channel, 32 | image_size[0], 33 | image_size[1], 34 | dtype=dtype, 35 | device=device) 36 | else: 37 | the_image = torch.randn( 38 | batch_size, 39 | channel, 40 | image_size, 41 | image_size, 42 | dtype=dtype, 43 | device=device) 44 | model.eval() 45 | warmup_T = 3 46 | with torch.no_grad(): 47 | for i in range(warmup_T): 48 | _ = model(the_image) 49 | start_timer = time.time() 50 | for repeat_count in range(benchmark_repeat_times): 51 | _ = model(the_image) 52 | 53 | end_timer = time.time() 54 | the_latency = (end_timer 55 | - start_timer) / float(benchmark_repeat_times) / batch_size 56 | return the_latency 57 | 58 | @LATENCIES.register_module(module_name = 'RobustGpuPredictor') 59 | class RobustGpuPredictor(): 60 | 61 | def __init__(self, 62 | batch_size, 63 | image_size, 64 | gpu , 65 | channel=3, 66 | fp16=False, 67 | repeat_times=30, 68 | **kwargs): 69 | assert isinstance(gpu, int), 'Must set enable_gpu=True in cfg' 70 | self.batch_size = batch_size 71 | self.image_size = image_size 72 | self.gpu = gpu 73 | self.channel = channel 74 | self.repeat_times = repeat_times 75 | self.fp16 = fp16 76 | assert isinstance(gpu, int) 77 | 78 | def __call__(self, model): 79 | 80 | robust_repeat_times = 10 81 | latency_list = [] 82 | model = model.cuda(self.gpu) 83 | for repeat_count in range(robust_repeat_times): 84 | try: 85 | the_latency = __get_latency__(model, self.batch_size, 86 | self.image_size, self.channel, 87 | self.gpu, 88 | self.repeat_times, 89 | self.fp16) 90 | except Exception as e: 91 | print(e) 92 | the_latency = np.inf 93 | 94 | latency_list.append(the_latency) 95 | 96 | pass # end for 97 | latency_list.sort() 98 | avg_latency = np.mean(latency_list[2:8]) 99 | std_latency = np.std(latency_list[2:8]) 100 | return avg_latency #, std_latency 101 | 102 | 103 | def main(): 104 | pass 105 | 106 | 107 | if __name__ == '__main__': 108 | main() 109 | -------------------------------------------------------------------------------- /tinynas/models/README.md: -------------------------------------------------------------------------------- 1 | ## Models Definition module 2 | 3 | The basic network (supernet) is defined by the unified framework with the structure info list. CnnNet is the overall backbone network, which is composed of differet downsample stages with structure info list. A stage is composed of several blocks, such as Resnet bottleneck block, MobileV2 Depthwise block. Basic block is composed of 2D convolutions. 4 | 5 | *** 6 | ### **SuperModel** 7 | * **`cnnnet.py`**: Define the backbone network for CnnNet, such as classification and detection. 8 | 9 | *** 10 | ### **Typical Structure Info List for CnnNet** 11 | ``` 12 | [{'class': 'ConvKXBNRELU', 'in': 3, 'out': 32, 's': 2, 'k': 3}, 13 | {'class': 'SuperResK1KXK1', 'in': 32, 'out': 256, 's': 2, 'k': 3, 'L': 1, 'btn': 64}, 14 | {'class': 'SuperResK1KXK1', 'in': 256, 'out': 512, 's': 2, 'k': 3, 'L': 1, 'btn': 128}, 15 | {'class': 'SuperResK1KXK1', 'in': 512, 'out': 1024, 's': 2, 'k': 3, 'L': 1, 'btn': 256}, 16 | {'class': 'SuperResK1KXK1', 'in': 1024, 'out': 2048, 's': 2, 'k': 3, 'L': 1, 'btn': 512}, ] 17 | ``` 18 | *** 19 | ### **Supported Blocks** 20 | `Supported 2D CNN blocks:` 21 | ``` 22 | __all_blocks__ = { 23 | 'ConvKXBN': ConvKXBN, 24 | 'ConvKXBNRELU': ConvKXBNRELU, 25 | 'BaseSuperBlock': BaseSuperBlock, 26 | 'ResK1KXK1': ResK1KXK1, 27 | 'ResK1KX': ResK1KX, 28 | 'ResKXKX': ResKXKX, 29 | 'ResK1DWK1': ResK1DWK1, 30 | 'ResK1DWSEK1': ResK1DWSEK1, 31 | 'SuperResK1KXK1': SuperResK1KXK1, 32 | 'SuperResK1KX': SuperResK1KX, 33 | 'SuperResKXKX': SuperResKXKX, 34 | 'SuperResK1DWK1': SuperResK1DWK1, 35 | 'SuperResK1DWSEK1': SuperResK1DWSEK1, 36 | 'SuperQuantResK1DWK1': SuperQuantResK1DWK1, 37 | } 38 | ``` 39 | `Supported 3D CNN blocks:` 40 | 41 | ``` 42 | __all_blocks_3D__ = { 43 | 'Conv3DKXBN': Conv3DKXBN, 44 | 'Conv3DKXBNRELU': Conv3DKXBNRELU, 45 | 'BaseSuperBlock3D': BaseSuperBlock3D, 46 | 'Res3DK1DWK1': Res3DK1DWK1, 47 | 'SuperRes3DK1DWK1': SuperRes3DK1DWK1, 48 | } 49 | ``` 50 | **Note**: 51 | 52 | - `BaseSuperBlock` is the basic class for super block. 53 | - `SuperResK1KXK1` is the derived class from ``BaseSuperBlock`` to unit `L` class `ResK1KXK1`. 54 | - `SuperResK1DWK1` is the derived class from ``BaseSuperBlock`` to unit `L` class `ResK1DWK1`. 55 | - `SuperResK1DWSEK1` is the derived class from ``BaseSuperBlock`` to unit `L` class `ResK1DWSEK1`. 56 | - `SuperResK1KX` is the derived class from ``BaseSuperBlock`` to unit `L` class `ResK1KX`. 57 | - `SuperResKXKX` is the derived class from ``BaseSuperBlock`` to unit `L` class `ResKXKX`. 58 | - `SuperQuantResK1DWK1` is the derived class from ``SuperResK1DWK1``. 59 | - `SuperRes3DK1DWK1` is the derived class from ``BaseSuperBlock`` to unit `L` class `Res3DK1DWK1`. 60 | *** 61 | ### **Useful functions for masternet** 62 | 63 | `get_model_size`: Get the number of parameters of the network 64 | 65 | `get_flops`: Get the FLOPs of the network 66 | 67 | `get_layers`: Get the Conv layers of the network 68 | 69 | `get_latency`: Get the latency from predictor or benchmark 70 | 71 | `get_params_for_trt`: Get the paramters of the network for latency prediction. 72 | 73 | `get_max_feature`: Get the number of max feature map for MCU. 74 | 75 | `get_efficient_score`: Get efficient_score of the network. 76 | 77 | `madnas_forward_pre_GAP`: Get the madnas score of the network, which does not need forward on GPU and has very fast speed . 78 | 79 | `deepmad_forward_pre_GAP`: Get the deepmad score of the network, which does not need forward on GPU and has very fast speed. 80 | 81 | `stentr_forward_pre_GAP`: Get the spatio-temporal entropy score of the network, which does not need forward on GPU and has very fast speed. 82 | 83 | *** 84 | -------------------------------------------------------------------------------- /tinynas/models/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from .builder import build_model 6 | from .cnnnet import CnnNet 7 | from .cnn3dnet import Cnn3DNet 8 | -------------------------------------------------------------------------------- /tinynas/models/base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import ast 6 | import logging 7 | import os 8 | import sys 9 | 10 | from torch import nn 11 | from abc import ABC, abstractmethod 12 | 13 | class Model(ABC, nn.Module): 14 | 15 | def __init__(self, 16 | structure=None, 17 | logger=None): 18 | super().__init__() 19 | self.structure_info = structure 20 | self.logger = logger or logging 21 | 22 | if isinstance(structure, str): 23 | if os.path.exists(structure): 24 | with open(structure, 'r') as fid: 25 | self.structure_info = ''.join( 26 | [x.strip() for x in fid.readlines()]) 27 | self.structure_info = ast.literal_eval(self.structure_info) 28 | 29 | @abstractmethod 30 | def forward(self, *args, **kwargs): 31 | pass 32 | 33 | @abstractmethod 34 | def get_model_size(self, return_list=False): 35 | pass 36 | 37 | @abstractmethod 38 | def get_flops(self, resolution): 39 | pass 40 | 41 | @abstractmethod 42 | def build(self, structure_info): 43 | pass 44 | -------------------------------------------------------------------------------- /tinynas/models/blocks_cnn_2d/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from .blocks_basic import (BaseSuperBlock, ConvKXBN, ConvKXBNRELU, 6 | network_weight_stupid_init) 7 | from .super_res_k1dwk1 import ResK1DWK1, SuperResK1DWK1 8 | from .super_res_k1dwsek1 import ResK1DWSEK1, SuperResK1DWSEK1 9 | from .super_quant_res_k1dwk1 import SuperQuantResK1DWK1 10 | from .super_res_k1kxk1 import ResK1KXK1, SuperResK1KXK1 11 | from .super_res_k1kx import ResK1KX, SuperResK1KX 12 | from .super_res_kxkx import ResKXKX, SuperResKXKX 13 | 14 | __all_blocks__ = { 15 | 'ConvKXBN': ConvKXBN, 16 | 'ConvKXBNRELU': ConvKXBNRELU, 17 | 'BaseSuperBlock': BaseSuperBlock, 18 | 'ResK1KXK1': ResK1KXK1, 19 | 'ResK1KX': ResK1KX, 20 | 'ResKXKX': ResKXKX, 21 | 'ResK1DWK1': ResK1DWK1, 22 | 'ResK1DWSEK1': ResK1DWSEK1, 23 | 'SuperResK1KXK1': SuperResK1KXK1, 24 | 'SuperResK1KX': SuperResK1KX, 25 | 'SuperResKXKX': SuperResKXKX, 26 | 'SuperResK1DWK1': SuperResK1DWK1, 27 | 'SuperResK1DWSEK1': SuperResK1DWSEK1, 28 | 'SuperQuantResK1DWK1': SuperQuantResK1DWK1, 29 | } 30 | -------------------------------------------------------------------------------- /tinynas/models/blocks_cnn_2d/super_quant_res_k1dwk1.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import copy 6 | import os 7 | import sys 8 | from .super_res_k1dwk1 import SuperResK1DWK1 9 | 10 | class SuperQuantResK1DWK1(SuperResK1DWK1): 11 | 12 | def __init__(self, 13 | structure_info, 14 | no_create=False, 15 | dropout_channel=None, 16 | dropout_layer=None, 17 | **kwargs): 18 | ''' 19 | 20 | :param structure_info: { 21 | 'class': 'SuperResK1DWK1', 22 | 'in': in_channels, 23 | 'out': out_channels, 24 | 's': stride (default=1), 25 | 'k': kernel_size, 26 | 'p': padding (default=(k-1)//2, 27 | 'g': grouping (default=1), 28 | 'btn':, bottleneck_channels, 29 | 'L': num_inner_layers, 30 | } 31 | :param NAS_mode: 32 | ''' 33 | super().__init__( 34 | structure_info=structure_info, 35 | no_create=no_create, 36 | dropout_channel=dropout_channel, 37 | dropout_layer=dropout_layer, 38 | **kwargs) 39 | 40 | 41 | __module_blocks__ = { 42 | 'SuperQuantResK1DWK1': SuperQuantResK1DWK1, 43 | } 44 | -------------------------------------------------------------------------------- /tinynas/models/blocks_cnn_3d/__init__.py: -------------------------------------------------------------------------------- 1 | from .blocks_basic_3D import * 2 | from .super_res3d_k1dwk1 import * 3 | 4 | 5 | __all_blocks_3D__ = { 6 | 'Conv3DKXBN': Conv3DKXBN, 7 | 'Conv3DKXBNRELU': Conv3DKXBNRELU, 8 | 'BaseSuperBlock3D': BaseSuperBlock3D, 9 | 'Res3DK1DWK1': Res3DK1DWK1, 10 | 'SuperRes3DK1DWK1': SuperRes3DK1DWK1, 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tinynas/models/builder.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from modelscope.utils.registry import Registry, build_from_cfg 6 | 7 | MODELS= Registry('models') 8 | 9 | def build_model(cfg, default_args: dict = None): 10 | """ build model given a model name 11 | 12 | Args: 13 | name (str, optional): Model name, if None, default model 14 | will be used. 15 | default_args (dict, optional): Default initialization arguments. 16 | """ 17 | return build_from_cfg(cfg, MODELS, default_args=default_args) 18 | 19 | -------------------------------------------------------------------------------- /tinynas/scores/README.md: -------------------------------------------------------------------------------- 1 | ## Score module 2 | 3 | *** 4 | ### **MadNAS Score**: 5 | The version of mathematical formula calculation, which does not need forward on GPU and has very fast speed. 6 | 7 | *** 8 | ### **DeepMad Score**: 9 | The version of mathematical formula calculation, which does not need forward on GPU and has very fast speed. 10 | 11 | ### **Random Score**: 12 | Random generated scores for debug. 13 | 14 | ### **Ensemble Score**: 15 | Calculate combinated score of multiple score_type with ratio. 16 | 17 | 18 | ### **STEntr Score**: 19 | Calculate spatio-temporal entropy score. 20 | -------------------------------------------------------------------------------- /tinynas/scores/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from .builder import build_score 6 | from .compute_madnas import ComputeMadnasScore 7 | from .compute_random import ComputeRandomScore 8 | from .compute_ensemble import ComputeEnsembleScore 9 | from .compute_deepmad import ComputeDeepMadScore 10 | from .compute_stentr import ComputeStentrScore 11 | 12 | -------------------------------------------------------------------------------- /tinynas/scores/builder.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from modelscope.utils.registry import Registry, build_from_cfg 6 | 7 | SCORES = Registry('scores') 8 | 9 | def build_score(cfg, default_args: dict = None): 10 | """ build score given a score name 11 | 12 | Args: 13 | name (str, optional): Score name, if None, default score 14 | will be used. 15 | default_args (dict, optional): Default initialization arguments. 16 | """ 17 | return build_from_cfg(cfg, SCORES, default_args=default_args) 18 | 19 | -------------------------------------------------------------------------------- /tinynas/scores/compute_ensemble.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import logging 6 | import os 7 | import sys 8 | import time 9 | from abc import ABCMeta, abstractmethod 10 | 11 | import numpy as np 12 | import torch 13 | 14 | 15 | from .builder import SCORES, build_score 16 | 17 | @SCORES.register_module(module_name = 'ensemble') 18 | class ComputeEnsembleScore(metaclass=ABCMeta): 19 | 20 | def __init__(self, scores = None, ratio = 1, logger = None, **kwargs): 21 | 22 | self.ratio = ratio 23 | self.logger = logger or logging 24 | self.compute_scores = [] 25 | for cfg in scores: 26 | default_args = {'logger': self.logger} 27 | 28 | compute_score = build_score(cfg, default_args = default_args) 29 | self.compute_scores.append(compute_score) 30 | 31 | def __call__(self, model): 32 | info = {} 33 | info['avg_nas_score'] = 0 34 | info['std_nas_score'] = 0 35 | info['nas_score_list'] = 0 36 | timer_start = time.time() 37 | 38 | for compute_score in self.compute_scores: 39 | score_info = compute_score(model) 40 | for k, v in info.items(): 41 | info[k] += score_info[k] * self.ratio 42 | timer_end = time.time() 43 | info['time'] = timer_end - timer_start 44 | 45 | self.logger.debug('avg_score:%s, consume time is %f ms' % 46 | (info['avg_nas_score'], info['time'] * 1000)) 47 | 48 | return info 49 | 50 | 51 | def main(): 52 | pass 53 | 54 | 55 | if __name__ == '__main__': 56 | main() 57 | pass 58 | -------------------------------------------------------------------------------- /tinynas/scores/compute_madnas.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import logging 6 | import os 7 | import sys 8 | import time 9 | from abc import ABCMeta, abstractmethod 10 | 11 | import numpy as np 12 | import torch 13 | 14 | 15 | from .builder import SCORES 16 | 17 | @SCORES.register_module(module_name = 'madnas') 18 | class ComputeMadnasScore(metaclass=ABCMeta): 19 | 20 | def __init__(self, image_size = 224, multi_block_ratio = [0, 0, 1,1,6], ratio = 1, init_std = 1, init_std_act = 1, logger=None, **kwargs): 21 | self.init_std = init_std 22 | self.init_std_act = init_std_act 23 | self.resolution = image_size 24 | self.ratio_coef = multi_block_ratio 25 | self.ratio = ratio 26 | 27 | self.logger = logger or logging 28 | 29 | def ratio_score(self, stages_num, block_std_list): 30 | 31 | if stages_num != len(self.ratio_coef): 32 | raise ValueError( 33 | 'the length of the stage_features_list (%d) must be equal to the length of ratio_coef (%d)' 34 | % (stages_num, len(self.ratio_coef))) 35 | self.logger.debug( 36 | 'len of stage_features_list:%d, len of block_std_list:%d %s' % 37 | (stages_num, len(block_std_list), [std for std in block_std_list])) 38 | self.logger.debug( 39 | 'stage_idx:%s, stage_block_num:%s, stage_layer_num:%s' % 40 | (self.stage_idx, self.stage_block_num, self.stage_layer_num)) 41 | 42 | nas_score_list = [] 43 | for idx, ratio in enumerate(self.ratio_coef): 44 | if ratio == 0: 45 | nas_score_list.append(0.0) 46 | continue 47 | 48 | # compute std scaling 49 | nas_score_std = 0.0 50 | for idx1 in range(self.stage_block_num[idx]): 51 | nas_score_std += block_std_list[idx1] 52 | 53 | # larger channel and larger resolution, larger performance. 54 | resolution_stage = self.resolution // (2**(idx + 1)) 55 | nas_score_feat = np.log(self.stage_channels[idx]) 56 | # different stage with the different feature map ratio (2**(idx+6))/(4**(idx+1)) 57 | nas_score_stage = nas_score_std + nas_score_feat 58 | # layer_num_idx = self.stage_layer_num[idx] 59 | self.logger.debug( 60 | 'stage:%d, nas_score_stage:%.3f, score_feat:%.3f, log_std:%.3f, resolution:%d' 61 | % (idx, nas_score_stage, nas_score_feat, nas_score_std, 62 | resolution_stage)) 63 | 64 | nas_score_list.append(nas_score_stage * ratio) 65 | self.logger.debug('nas_score:%s' % (np.sum(nas_score_list))) 66 | 67 | return nas_score_list 68 | 69 | def __call__(self, model): 70 | info = {} 71 | timer_start = time.time() 72 | self.stage_idx, self.stage_block_num, self.stage_layer_num, self.stage_channels, self.stage_feature_map_size = model.get_stage_info(self.resolution) 73 | kwarg = {'init_std': self.init_std, 'init_std_act': self.init_std_act} 74 | 75 | block_std_list = model.madnas_forward_pre_GAP(**kwarg) 76 | nas_score_once = self.ratio_score(len(self.stage_idx), block_std_list) 77 | 78 | timer_end = time.time() 79 | nas_score_once = np.array(nas_score_once) * self.ratio 80 | avg_nas_score = np.sum(nas_score_once) 81 | 82 | info['avg_nas_score'] = avg_nas_score 83 | info['std_nas_score'] = avg_nas_score 84 | info['nas_score_list'] = nas_score_once 85 | info['time'] = timer_end - timer_start 86 | self.logger.debug('avg_score:%s, consume time is %f ms' % 87 | (avg_nas_score, info['time'] * 1000)) 88 | 89 | return info 90 | 91 | 92 | def main(): 93 | pass 94 | 95 | 96 | if __name__ == '__main__': 97 | main() 98 | pass 99 | -------------------------------------------------------------------------------- /tinynas/scores/compute_random.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import logging 6 | import os 7 | import sys 8 | import time 9 | from abc import ABCMeta, abstractmethod 10 | from random import random 11 | 12 | import numpy as np 13 | import torch 14 | from torch import nn 15 | from torch.nn import functional as F 16 | 17 | 18 | from .builder import SCORES 19 | 20 | @SCORES.register_module(module_name = 'random') 21 | class ComputeRandomScore(metaclass=ABCMeta): 22 | 23 | def __init__(self, cfg, ratio = 1, logger=None, **kwargs): 24 | # TODO: to be finished after adding nas for transformer 25 | self.gpu = None 26 | self.ratio = ratio 27 | 28 | if logger is None: 29 | self.logger = logging 30 | else: 31 | self.logger = logger 32 | 33 | def __call__(self, model): 34 | ''' 35 | 36 | Args: 37 | model: Model to be compute scores 38 | 39 | Returns: 40 | A dictionary. Key 'avg_nas_score' is necessary. Others ['std_nas_score', 'nas_score_list', 'time'] are 41 | optional. 42 | 43 | ''' 44 | model.eval() 45 | model.requires_grad_(False) 46 | 47 | info = {} 48 | nas_score_list = [] 49 | timer_start = time.time() 50 | 51 | # TODO: calculate scores 52 | nas_score_list.append([random() * 100]) 53 | 54 | timer_end = time.time() 55 | 56 | nas_score_list = np.array(nas_score_list) * self.ratio 57 | avg_nas_score = np.mean(np.sum(nas_score_list, axis=1)) 58 | std_nas_score = np.std(np.sum(nas_score_list, axis=1)) 59 | 60 | info['avg_nas_score'] = avg_nas_score 61 | info['std_nas_score'] = std_nas_score 62 | info['nas_score_list'] = nas_score_list 63 | info['time'] = timer_end - timer_start 64 | self.logger.debug('avg_score:%s, consume time is %f ms\n' % 65 | (avg_nas_score, info['time'] * 1000)) 66 | 67 | del model 68 | torch.cuda.empty_cache() 69 | return info 70 | 71 | 72 | def main(): 73 | model = nn.Conv2d(3, 3, 3) 74 | score_compute = ComputeRandomScore(None) 75 | print(score_compute(model)) 76 | 77 | 78 | if __name__ == '__main__': 79 | main() 80 | pass 81 | -------------------------------------------------------------------------------- /tinynas/scores/compute_stentr.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import logging 6 | import os 7 | import sys 8 | import time 9 | from abc import ABCMeta, abstractmethod 10 | 11 | import numpy as np 12 | import torch 13 | 14 | 15 | from .builder import SCORES 16 | 17 | @SCORES.register_module(module_name = 'stentr') 18 | class ComputeStentrScore(metaclass=ABCMeta): 19 | 20 | def __init__(self, frames = 13, image_size = 160, multi_block_ratio = [0, 0, 1,1,6], ratio = 1, logger=None, **kwargs): 21 | self.frames = frames 22 | self.resolution = image_size 23 | self.ratio_coef = multi_block_ratio 24 | self.ratio = ratio 25 | 26 | self.logger = logger or logging 27 | 28 | def ratio_score(self, stages_num, block_std_list): 29 | 30 | if stages_num != len(self.ratio_coef): 31 | raise ValueError( 32 | 'the length of the stage_features_list (%d) must be equal to the length of ratio_coef (%d)' 33 | % (stages_num, len(self.ratio_coef))) 34 | self.logger.debug( 35 | 'len of stage_features_list:%d, len of block_std_list:%d %s' % 36 | (stages_num, len(block_std_list), [std for std in block_std_list])) 37 | self.logger.debug( 38 | 'stage_idx:%s, stage_block_num:%s, stage_layer_num:%s' % 39 | (self.stage_idx, self.stage_block_num, self.stage_layer_num)) 40 | 41 | nas_score_list = [] 42 | for idx, ratio in enumerate(self.ratio_coef): 43 | if ratio == 0: 44 | nas_score_list.append(0.0) 45 | continue 46 | 47 | # compute std scaling 48 | nas_score_std = 0.0 49 | for idx1 in range(self.stage_block_num[idx]): 50 | nas_score_std += block_std_list[idx1] 51 | 52 | # larger channel and larger resolution, larger performance. 53 | resolution_stage = self.resolution // (2**(idx + 1)) 54 | nas_score_feat = np.log(self.stage_channels[idx]) 55 | # different stage with the different feature map ratio (2**(idx+6))/(4**(idx+1)) 56 | nas_score_stage = nas_score_std + nas_score_feat 57 | # layer_num_idx = self.stage_layer_num[idx] 58 | self.logger.debug( 59 | 'stage:%d, nas_score_stage:%.3f, score_feat:%.3f, log_std:%.3f, resolution:%d' 60 | % (idx, nas_score_stage, nas_score_feat, nas_score_std, 61 | resolution_stage)) 62 | 63 | nas_score_list.append(nas_score_stage * ratio) 64 | self.logger.debug('nas_score:%s' % (np.sum(nas_score_list))) 65 | 66 | return nas_score_list 67 | 68 | def __call__(self, model): 69 | info = {} 70 | timer_start = time.time() 71 | self.stage_idx, self.stage_block_num, self.stage_layer_num, self.stage_channels, self.stage_feature_map_size = model.get_stage_info(self.resolution) 72 | # kwarg = {'init_std': self.init_std, 'init_std_act': self.init_std_act} 73 | kwarg = {'frames': self.frames ,'resolution': self.resolution} 74 | block_std_list = model.stentr_forward_pre_GAP(**kwarg) 75 | nas_score_once = self.ratio_score(len(self.stage_idx), block_std_list) 76 | 77 | timer_end = time.time() 78 | nas_score_once = np.array(nas_score_once) * self.ratio 79 | avg_nas_score = np.sum(nas_score_once) 80 | 81 | info['avg_nas_score'] = avg_nas_score 82 | info['std_nas_score'] = avg_nas_score 83 | info['nas_score_list'] = nas_score_once 84 | info['time'] = timer_end - timer_start 85 | self.logger.debug('avg_score:%s, consume time is %f ms' % 86 | (avg_nas_score, info['time'] * 1000)) 87 | 88 | return info 89 | 90 | 91 | def main(): 92 | pass 93 | 94 | 95 | if __name__ == '__main__': 96 | main() 97 | pass 98 | -------------------------------------------------------------------------------- /tinynas/searchers/README.md: -------------------------------------------------------------------------------- 1 | ## Search Searcher module 2 | Searcher module can be built from a config file and run search process easily, which can execute in local-mode(single-process) or distribute-mode(multi-process). During searching, the master process will cache intermediate results, and export and save the final best structure. 3 | 4 | - **Searcher Class** 5 | 6 | `__init__`: Setup searching envirioment and then build strategy, sychonizer and population. 7 | 8 | `run`: Execute search loop and export the best structure info. 9 | 10 | `search_loop`: Master process collect and assgin newest population with workers and cache intermediate results. Then all processes execute search step. 11 | 12 | `search_step`: In search step, all processes pick a random structure info from population and then mutate a new structure info using strategy. If the new network meets the budget and has a high score, we will insert it to the population. 13 | 14 | `export_cache_generation`: cache the search intermediate population every log_freq . 15 | 16 | `export_result`: save and export best network structure info. 17 | 18 | - **Synchonizer Class** 19 | 20 | Sychonize population information between master and workers using mpi asynchronous communication. 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /tinynas/searchers/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from .base import BaseSearcher 6 | from .searcher import Searcher 7 | from .synchonizer import Synchonizer 8 | from .builder import build_searcher 9 | -------------------------------------------------------------------------------- /tinynas/searchers/base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from abc import ABC, abstractmethod 6 | from modelscope.utils.config import Config 7 | 8 | class BaseSearcher(ABC): 9 | def __init__(self, cfg_file: str): 10 | """ Searcher basic init, should be called in derived class 11 | 12 | Args: 13 | cfg_file: Path to configuration file. 14 | arg_parse_fn: Same as ``parse_fn`` in :obj:`Config.to_args`. 15 | """ 16 | self.cfg = Config.from_file(cfg_file) 17 | 18 | @abstractmethod 19 | def run(self, *args, **kwargs): 20 | """ search process 21 | 22 | Train process should be implemented for specific task or 23 | model, releated paramters have been intialized in 24 | ``BaseSearcher.__init__`` and should be used in this function 25 | """ 26 | pass 27 | -------------------------------------------------------------------------------- /tinynas/searchers/builder.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from modelscope.utils.registry import Registry, build_from_cfg 6 | 7 | SEARCHERS = Registry('searchers') 8 | 9 | def build_searcher(name: str = 'default_searcher', default_args: dict = None): 10 | """ build searcher given a searcher name 11 | 12 | Args: 13 | name (str, optional): Searcher name, if None, default searcher 14 | will be used. 15 | default_args (dict, optional): Default initialization arguments. 16 | """ 17 | cfg = dict(type=name) 18 | return build_from_cfg(cfg, SEARCHERS, default_args=default_args) 19 | 20 | -------------------------------------------------------------------------------- /tinynas/spaces/README.md: -------------------------------------------------------------------------------- 1 | ## Search Space module 2 | *** 3 | **For NAS, search space is very important. Referring to previous network design experience, designing the search space you want can ensure effective search results.** 4 | *** 5 | 6 | ### **Supported Search Space** 7 | * `space_k1kxk1.py`: Base Resnet-like search space for Classification and Detection. 8 | * `space_k1dwk1.py`: Base MobileNetV2-like search space. 9 | * `space_k1dwsek1.py`: Base MobileNetV2-se block search space. 10 | * `space_k1kx.py`: Base small and tiny DAMO-YOLO search space. 11 | * `space_kxkx.py`: Base medium DAMO-YOLO search space. 12 | * `space_quant_k1dwk1.py`: Base search space for Quantization search. 13 | * `space_3d_k1dwk1.py`: Base search space for 3D CNN search. 14 | -------------------------------------------------------------------------------- /tinynas/spaces/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from .base import BaseSpace 6 | from .builder import build_space 7 | from .space_k1kxk1 import Spacek1kxk1 8 | from .space_k1dwk1 import Spacek1dwk1 9 | from .space_k1dwsek1 import Spacek1dwsek1 10 | from .space_k1kx import Spacek1kx 11 | from .space_kxkx import Spacekxkx 12 | from .space_3d_k1dwk1 import Space3Dk1dwk1 13 | from .space_quant_k1dwk1 import SpaceQuantk1dwk1 14 | -------------------------------------------------------------------------------- /tinynas/spaces/base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | import copy 5 | from numpy import random 6 | from abc import ABC, abstractmethod 7 | from .space_utils import (adjust_structures_inplace, __check_block_structure_info_list_valid__) 8 | 9 | class BaseSpace(ABC): 10 | def __init__(self, name = None): 11 | self.name = name 12 | 13 | @abstractmethod 14 | def mutate(self, *args, **kwargs): 15 | return None 16 | 17 | def choice(self,): 18 | return None 19 | 20 | def __call__(self, *args, **kwargs): 21 | return self.mutate(*args, **kwargs) 22 | 23 | class CnnBaseSpace(BaseSpace): 24 | def __init__(self, name = None, image_size = 224, block_num = 2, exclude_stem = False, budget_layers=None, **kwargs): 25 | 26 | super().__init__(name) 27 | self.budget_layers = budget_layers 28 | self.block_num = block_num 29 | self.exclude_stem = exclude_stem 30 | self.image_size = image_size 31 | self.mutators = {} 32 | 33 | def mutate(self, block_structure_info_list, 34 | minor_mutation=False, *args, **kwargs): 35 | block_structure_info_list = copy.deepcopy(block_structure_info_list) 36 | 37 | for mutate_count in range(self.block_num): 38 | is_valid = False 39 | new_block_structure_info_list = block_structure_info_list 40 | 41 | for idx in range(len(block_structure_info_list)): 42 | random_id = random.randint(0, len(block_structure_info_list) - 1) 43 | 44 | if self.exclude_stem: 45 | while random_id == 0: 46 | random_id = random.randint( 47 | 0, 48 | len(block_structure_info_list) - 1) 49 | 50 | mutated_block = self.mutators[block_structure_info_list[random_id] ['class']]( 51 | random_id, 52 | block_structure_info_list, 53 | minor_mutation=minor_mutation) 54 | 55 | if mutated_block is None: 56 | continue 57 | 58 | new_block_structure_info_list = copy.deepcopy(block_structure_info_list) 59 | new_block_structure_info_list[random_id] = mutated_block 60 | 61 | adjust_structures_inplace(new_block_structure_info_list, self.image_size) 62 | if __check_block_structure_info_list_valid__(new_block_structure_info_list, self.budget_layers): 63 | break 64 | pass # end while not is_valid: 65 | block_structure_info_list = new_block_structure_info_list 66 | 67 | return block_structure_info_list 68 | -------------------------------------------------------------------------------- /tinynas/spaces/builder.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from modelscope.utils.registry import Registry, build_from_cfg 6 | 7 | SPACES = Registry('spaces') 8 | 9 | def build_space(cfg, default_args: dict = None): 10 | """ build space given a space name 11 | 12 | Args: 13 | name (str, optional): Space name, if None, default space 14 | will be used. 15 | default_args (dict, optional): Default initialization arguments. 16 | """ 17 | return build_from_cfg(cfg, SPACES, default_args=default_args) 18 | 19 | -------------------------------------------------------------------------------- /tinynas/spaces/mutator/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from .base import Mutator 6 | from .builder import * 7 | from .basic_mutators import * 8 | from .conv_bn_relu_mutator import * 9 | from .conv3d_bn_relu_mutator import * 10 | from .super_res_k1kxk1_mutator import * 11 | from .super_res_k1dwk1_mutator import * 12 | from .super_res_k1kx_mutator import * 13 | from .super_res3d_k1dwk1_mutator import * 14 | from .super_quant_res_k1dwk1_mutator import * 15 | 16 | -------------------------------------------------------------------------------- /tinynas/spaces/mutator/base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from typing import (Any, Iterable, List, Optional, Tuple, cast) 6 | import random 7 | from .builder import MUTATORS 8 | Choice = Any 9 | 10 | class Sampler: 11 | """ 12 | Handles `Mutator.choice()` calls. 13 | """ 14 | 15 | def choice(self, candidates: List[Choice], *args, **kwargs): 16 | raise NotImplementedError() 17 | 18 | def mutation_start(self, *args, **kwargs): 19 | pass 20 | 21 | def mutation_end(self, *args, **kwargs): 22 | pass 23 | 24 | 25 | class RandomSampler(Sampler): 26 | def choice(self, candidates, *args, **kwargs): 27 | return random.choice(candidates) 28 | 29 | @MUTATORS.register_module(module_name = 'BaseMutator') 30 | class Mutator: 31 | 32 | def __init__(self, sampler = None, candidates = None, *args, **kwargs): 33 | self.sampler: Optional[Sampler] = sampler 34 | self.candidates = candidates 35 | if self.sampler is None: 36 | self.sampler = RandomSampler() 37 | self._length = len(self.candidates) 38 | 39 | def length(self): 40 | return self._length 41 | 42 | def bind_sampler(self, sampler: Sampler) -> 'Mutator': 43 | """ 44 | Set the sampler which will handle `Mutator.choice` calls. 45 | """ 46 | self.sampler = sampler 47 | return self 48 | 49 | def __call__(self, *args, **kwargs) ->None: 50 | return self.mutate(*args, **kwargs) 51 | 52 | def mutate(self, *args, **kwargs) -> None: 53 | """ 54 | Abstract method to be implemented by subclass. 55 | Mutate a model in place. 56 | """ 57 | ret = self.sampler.choice(list(self.candidates, *args, **kwargs)) 58 | return ret 59 | 60 | def sample(self, *args, **kwargs) -> None: 61 | """ 62 | Abstract method to be implemented by subclass. 63 | Mutate a model in place. 64 | """ 65 | ret = self.sampler.choice(list(self.candidates, *args, **kwargs)) 66 | return ret 67 | 68 | 69 | -------------------------------------------------------------------------------- /tinynas/spaces/mutator/basic_mutators.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from numpy import random 6 | from .base import Mutator 7 | from .builder import MUTATORS 8 | from ..space_utils import smart_round 9 | 10 | @MUTATORS.register_module(module_name = 'ChannelMutator') 11 | class ChannelMutator(Mutator): 12 | def __init__(self, candidates, the_maximum_channel = 2048, *args, **kwargs): 13 | super().__init__(candidates = candidates) 14 | self.the_maximum_channel = the_maximum_channel 15 | 16 | def mutate(self, channels, *args, **kwargs): 17 | scale = self.sample() 18 | new_channels = smart_round(scale * channels) 19 | new_channels = min(self.the_maximum_channel, new_channels) 20 | return new_channels 21 | 22 | @MUTATORS.register_module(module_name = 'KernelMutator') 23 | class KernelMutator(Mutator): 24 | def __init__(self, candidates, *args, **kwargs): 25 | super().__init__(candidates = candidates) 26 | 27 | def mutate(self, kernel_size, *args, **kwargs): 28 | for i in range(self.length()): 29 | new_kernel_size = self.sample() 30 | if new_kernel_size != kernel_size : 31 | break 32 | return new_kernel_size 33 | 34 | @MUTATORS.register_module(module_name = 'LayerMutator') 35 | class LayerMutator(Mutator): 36 | def __init__(self, candidates, *args, **kwargs): 37 | super().__init__(candidates = candidates) 38 | 39 | def mutate(self, layer, *args, **kwargs): 40 | for i in range(self.length()): 41 | new_layer = layer + self.sample() 42 | new_layer = max(1, new_layer) 43 | if new_layer != layer: 44 | break 45 | return new_layer 46 | 47 | @MUTATORS.register_module(module_name = 'BtnMutator') 48 | class BtnMutator(Mutator): 49 | def __init__(self, candidates, *args, **kwargs): 50 | super().__init__(candidates = candidates) 51 | 52 | def mutate(self, btn_ratio, *args, **kwargs): 53 | for i in range(self.length()): 54 | new_btn_ratio = self.sample() 55 | if new_btn_ratio != btn_ratio: 56 | break 57 | return new_btn_ratio 58 | 59 | @MUTATORS.register_module(module_name = 'NbitsMutator') 60 | class NbitsMutator(Mutator): 61 | def __init__(self, candidates, *args, **kwargs): 62 | super().__init__(candidates = candidates) 63 | 64 | def mutate(self, nbits, *args, **kwargs): 65 | # avoid the endless loop 66 | if self.length() == 1 and nbits in self.candidates: 67 | return nbits 68 | ind = self.candidates.index(nbits) 69 | new_ind = ind 70 | 71 | while new_ind == ind: 72 | new_ind = random.choice((ind - 1, ind + 1)) 73 | new_ind = max(0, new_ind) 74 | new_ind = min(self.length() - 1, new_ind) 75 | return self.candidates[new_ind] 76 | 77 | @MUTATORS.register_module(module_name = 'NbitsListMutator') 78 | class NbitsListMutator(Mutator): 79 | def __init__(self, candidates, nbits_ratio,*args, **kwargs): 80 | super().__init__(candidates = candidates) 81 | self.mutator = NbitsMutator(candidates = candidates) 82 | self.nbits_ratio = nbits_ratio 83 | 84 | def mutate(self, nbits_list, L, *args, **kwargs): 85 | if isinstance(nbits_list, int): 86 | return self.mutator(nbits_list) 87 | else: 88 | inner_layer = len(nbits_list)//L 89 | for layer_idx in range(L): 90 | if random.uniform(0, 1) > self.nbits_ratio: 91 | nbits_list[layer_idx*inner_layer:(layer_idx+1)*inner_layer] = \ 92 | [self.mutator(nbits_list[layer_idx*inner_layer])]*inner_layer 93 | return nbits_list 94 | -------------------------------------------------------------------------------- /tinynas/spaces/mutator/builder.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from modelscope.utils.registry import Registry, build_from_cfg 6 | 7 | MUTATORS= Registry('mutators') 8 | 9 | def build_mutator(name = 'BaseMutator', default_args: dict = None): 10 | cfg = dict(type=name) 11 | return build_from_cfg(cfg, MUTATORS, default_args=default_args) 12 | 13 | def build_channel_mutator(default_args: dict =None): 14 | return build_mutator('ChannelMutator', default_args = default_args) 15 | 16 | def build_layer_mutator(default_args: dict =None): 17 | return build_mutator('LayerMutator', default_args = default_args) 18 | 19 | def build_kernel_mutator(default_args: dict =None): 20 | return build_mutator('KernelMutator', default_args = default_args) 21 | 22 | def build_btn_mutator(default_args: dict =None): 23 | return build_mutator('BtnMutator', default_args = default_args) 24 | 25 | def build_nbits_list_mutator(default_args: dict =None): 26 | return build_mutator('NbitsListMutator', default_args = default_args) 27 | -------------------------------------------------------------------------------- /tinynas/spaces/mutator/conv3d_bn_relu_mutator.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import bisect 6 | import copy 7 | import os 8 | import random 9 | import sys 10 | 11 | from ..space_utils import smart_round 12 | from .builder import * 13 | 14 | @MUTATORS.register_module(module_name = 'Conv3DKXBNRELU') 15 | class Conv3DKXBNRELUMutator(): 16 | def __init__(self, stem_mutate_method_list, 17 | search_channel_list, 18 | search_kernel_size_list, 19 | the_maximum_channel, 20 | the_maximum_stem_channel:int =32, 21 | the_minimum_stem_channel:int = None, 22 | *args, **kwargs): 23 | 24 | kwargs.update(dict(candidates = stem_mutate_method_list)) 25 | self.method_mutator = build_mutator(default_args = kwargs) 26 | 27 | kwargs.update(dict(candidates = search_channel_list, the_maximum_channel = the_maximum_channel)) 28 | self.channel_mutator = build_channel_mutator(kwargs) 29 | 30 | kwargs = dict(candidates = search_kernel_size_list ) 31 | self.kernel_mutator = build_kernel_mutator(kwargs) 32 | self.the_maximum_stem_channel = the_maximum_stem_channel 33 | self.the_minimum_stem_channel = the_minimum_stem_channel 34 | 35 | 36 | def __call__(self, block_id, structure_info_list, *args, **kwargs): 37 | 38 | structure_info = structure_info_list[block_id] 39 | 40 | if block_id == len(structure_info_list) - 1: 41 | return structure_info 42 | 43 | if block_id < len(structure_info_list) - 1: 44 | structure_info_next = structure_info_list[block_id + 1] 45 | structure_info = copy.deepcopy(structure_info) 46 | random_mutate_method = self.method_mutator() 47 | 48 | if random_mutate_method == 'out': 49 | new_out = self.channel_mutator(structure_info['out']) 50 | # Add the constraint: the maximum output of the stem block is 128 51 | new_out = min(self.the_maximum_stem_channel, new_out) 52 | if self.the_minimum_stem_channel: 53 | new_out = max(self.the_minimum_stem_channel, new_out) 54 | 55 | if block_id < len(structure_info_list) - 1: 56 | new_out = min(structure_info_next['out'], new_out) 57 | structure_info['out'] = new_out 58 | return structure_info 59 | 60 | if random_mutate_method == 'k': 61 | new_k = self.kernel_mutator(structure_info['k']) 62 | structure_info['k'] = new_k 63 | return structure_info 64 | 65 | -------------------------------------------------------------------------------- /tinynas/spaces/mutator/conv_bn_relu_mutator.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import bisect 6 | import copy 7 | import os 8 | import random 9 | import sys 10 | 11 | from ..space_utils import smart_round 12 | from .builder import * 13 | 14 | @MUTATORS.register_module(module_name = 'ConvKXBNRELU') 15 | class ConvKXBNRELUMutator(): 16 | def __init__(self, stem_mutate_method_list, 17 | search_channel_list, 18 | search_kernel_size_list, 19 | the_maximum_channel, 20 | the_maximum_stem_channel:int =32, 21 | the_minimum_stem_channel:int = None, 22 | *args, **kwargs): 23 | 24 | kwargs.update(dict(candidates = stem_mutate_method_list)) 25 | self.method_mutator = build_mutator(default_args = kwargs) 26 | 27 | kwargs.update(dict(candidates = search_channel_list, the_maximum_channel = the_maximum_channel)) 28 | self.channel_mutator = build_channel_mutator(kwargs) 29 | 30 | kwargs = dict(candidates = search_kernel_size_list ) 31 | self.kernel_mutator = build_kernel_mutator(kwargs) 32 | self.the_maximum_stem_channel = the_maximum_stem_channel 33 | self.the_minimum_stem_channel = the_minimum_stem_channel 34 | 35 | 36 | def __call__(self, block_id, structure_info_list, *args, **kwargs): 37 | 38 | structure_info = structure_info_list[block_id] 39 | 40 | if block_id == len(structure_info_list) - 1: 41 | return structure_info 42 | 43 | if block_id < len(structure_info_list) - 1: 44 | structure_info_next = structure_info_list[block_id + 1] 45 | structure_info = copy.deepcopy(structure_info) 46 | random_mutate_method = self.method_mutator() 47 | 48 | if random_mutate_method == 'out': 49 | new_out = self.channel_mutator(structure_info['out']) 50 | # Add the constraint: the maximum output of the stem block is 128 51 | new_out = min(self.the_maximum_stem_channel, new_out) 52 | if self.the_minimum_stem_channel: 53 | new_out = max(self.the_minimum_stem_channel, new_out) 54 | 55 | if block_id < len(structure_info_list) - 1: 56 | new_out = min(structure_info_next['out'], new_out) 57 | structure_info['out'] = new_out 58 | return structure_info 59 | 60 | if random_mutate_method == 'k': 61 | new_k = self.kernel_mutator(structure_info['k']) 62 | structure_info['k'] = new_k 63 | return structure_info 64 | 65 | -------------------------------------------------------------------------------- /tinynas/spaces/random_sample.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import random 6 | from .mutator.base import Sampler 7 | 8 | class RandomSampler(Sampler): 9 | def choice(self, candidates): 10 | return random.choice(candidates) 11 | 12 | -------------------------------------------------------------------------------- /tinynas/spaces/space_3d_k1dwk1.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import bisect 6 | import copy 7 | import os 8 | import random 9 | import sys 10 | 11 | from .base import CnnBaseSpace 12 | from .builder import SPACES 13 | from .mutator import build_mutator 14 | 15 | 16 | @SPACES.register_module(module_name = 'space_3d_k1dwk1') 17 | class Space3Dk1dwk1(CnnBaseSpace): 18 | 19 | def __init__(self, name = None, 20 | image_size = 224, 21 | block_num = 2, 22 | exclude_stem = False, 23 | budget_layers=None, 24 | maximum_channel =640, 25 | **kwargs): 26 | 27 | super().__init__(name, image_size = image_size, 28 | block_num = block_num, 29 | exclude_stem = exclude_stem, 30 | budget_layers = budget_layers, 31 | **kwargs) 32 | 33 | kwargs = dict(stem_mutate_method_list = ['out'] , 34 | the_maximum_channel = maximum_channel, 35 | mutate_method_list = ['out', 'k', 'btn', 'L'], 36 | search_kernel_size_list = [(1, 3), (1, 5), (3, 3)], 37 | search_layer_list = [-2, -1, 1, 2], 38 | search_channel_list = [2.0, 1.5, 1.25, 0.8, 0.6, 0.5], 39 | search_btn_ratio_list = [1.5, 2.0, 2.5, 3.0, 3.5, 4.0], 40 | budget_layers = budget_layers 41 | ) 42 | 43 | for n in ['Conv3DKXBNRELU','SuperRes3DK1DWK1']: 44 | self.mutators[n] = build_mutator(n, kwargs) 45 | 46 | -------------------------------------------------------------------------------- /tinynas/spaces/space_k1dwk1.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import bisect 6 | import copy 7 | import os 8 | import random 9 | import sys 10 | 11 | from .base import CnnBaseSpace 12 | from .builder import SPACES 13 | from .space_k1kxk1 import Spacek1kxk1 14 | from .mutator import build_mutator 15 | 16 | 17 | @SPACES.register_module(module_name = 'space_k1dwk1') 18 | class Spacek1dwk1(CnnBaseSpace): 19 | 20 | def __init__(self, name = None, 21 | image_size = 224, 22 | block_num = 2, 23 | exclude_stem = False, 24 | budget_layers=None, 25 | maximum_channel =1280, 26 | **kwargs): 27 | 28 | super().__init__(name, image_size = image_size, 29 | block_num = block_num, 30 | exclude_stem = exclude_stem, 31 | budget_layers = budget_layers, 32 | **kwargs) 33 | 34 | kwargs = dict(stem_mutate_method_list = ['out'] , 35 | the_maximum_channel = maximum_channel, 36 | mutate_method_list = ['out', 'k', 'btn', 'L'], 37 | search_kernel_size_list = [3, 5], 38 | search_layer_list = [-2, -1, 1, 2], 39 | search_channel_list = [2.0, 1.5, 1.25, 0.8, 0.6, 0.5], 40 | search_btn_ratio_list = [1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 5.0, 6.0], 41 | budget_layers = budget_layers 42 | ) 43 | 44 | for n in ['ConvKXBNRELU','SuperResK1DWK1']: 45 | self.mutators[n] = build_mutator(n, kwargs) 46 | 47 | -------------------------------------------------------------------------------- /tinynas/spaces/space_k1dwsek1.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import numpy as np 6 | 7 | from .base import CnnBaseSpace 8 | from .builder import SPACES 9 | from .mutator import build_mutator 10 | 11 | @SPACES.register_module(module_name = 'space_k1dwsek1') 12 | class Spacek1dwsek1(CnnBaseSpace): 13 | 14 | def __init__(self, name = None, 15 | image_size = 224, 16 | block_num = 2, 17 | exclude_stem = False, 18 | budget_layers=None, 19 | maximum_channel =1280, 20 | **kwargs): 21 | 22 | super().__init__(name, image_size = image_size, 23 | block_num = block_num, 24 | exclude_stem = exclude_stem, 25 | budget_layers = budget_layers, 26 | **kwargs) 27 | 28 | kwargs = dict(stem_mutate_method_list = ['out'] , 29 | the_maximum_channel = maximum_channel, 30 | mutate_method_list = ['out', 'k', 'btn', 'L'], 31 | search_kernel_size_list = [3, 5, 7], 32 | search_layer_list = [-2, -1, 1, 2], 33 | search_channel_list = np.arange(0.5, 2.01, 0.1), 34 | search_btn_ratio_list = np.arange(1.5, 6.01, 0.1), 35 | the_maximum_stem_channel = 32, 36 | the_minimum_stem_channel = 16, 37 | budget_layers = budget_layers 38 | ) 39 | 40 | for n in ['ConvKXBNRELU','SuperResK1DWSEK1']: 41 | self.mutators[n] = build_mutator(n, kwargs) 42 | 43 | -------------------------------------------------------------------------------- /tinynas/spaces/space_k1kx.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from .base import CnnBaseSpace 6 | from .builder import SPACES 7 | from .mutator import build_mutator 8 | 9 | @SPACES.register_module(module_name = 'space_k1kx') 10 | class Spacek1kx(CnnBaseSpace): 11 | def __init__(self, name = None, 12 | image_size = 224, 13 | block_num = 2, 14 | exclude_stem = False, 15 | budget_layers=None, 16 | maximum_channel =2048, 17 | channel_range_list = None, 18 | kernel_size_list = None, 19 | **kwargs): 20 | 21 | super().__init__(name, image_size = image_size, 22 | block_num = block_num, 23 | exclude_stem = exclude_stem, 24 | budget_layers = budget_layers, 25 | **kwargs) 26 | defualt_channel_range_list = [None, None, [64, 128], None, [128, 256], [256, 512]] 27 | defualt_kernel_size_list = [3] 28 | 29 | channel_range_list = channel_range_list or defualt_channel_range_list 30 | kernel_size_list = kernel_size_list or defualt_kernel_size_list 31 | 32 | kwargs = dict(stem_mutate_method_list = ['out'] , 33 | mutate_method_list = ['out', 'btn', 'L'], 34 | the_maximum_channel = maximum_channel, 35 | channel_range = channel_range_list, 36 | search_kernel_size_list = kernel_size_list, 37 | search_layer_list = [-2, -1, 1, 2], 38 | search_channel_list = [2.0, 1.5, 1.25, 0.8, 0.6, 0.5], 39 | budget_layers = budget_layers, 40 | btn_minimum_ratio = 10 # the bottleneck must be larger than out/10 41 | ) 42 | for n in ['ConvKXBNRELU','SuperResK1KX']: 43 | self.mutators[n] = build_mutator(n, kwargs) 44 | 45 | -------------------------------------------------------------------------------- /tinynas/spaces/space_k1kxk1.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import bisect 6 | import copy 7 | import os 8 | import random 9 | import sys 10 | 11 | from .base import CnnBaseSpace 12 | from .builder import SPACES 13 | from .mutator import build_mutator 14 | 15 | @SPACES.register_module(module_name = 'space_k1kxk1') 16 | class Spacek1kxk1(CnnBaseSpace): 17 | 18 | def __init__(self, name = None, 19 | image_size = 224, 20 | block_num = 2, 21 | exclude_stem = False, 22 | budget_layers=None, 23 | maximum_channel =2048, 24 | **kwargs): 25 | 26 | super().__init__(name, image_size = image_size, 27 | block_num = block_num, 28 | exclude_stem = exclude_stem, 29 | budget_layers = budget_layers, 30 | **kwargs) 31 | 32 | kwargs = dict(stem_mutate_method_list = ['out'] , 33 | mutate_method_list = ['out', 'k', 'btn', 'L'], 34 | the_maximum_channel = maximum_channel, 35 | search_kernel_size_list = [3, 5], 36 | search_layer_list = [-2, -1, 1, 2], 37 | search_channel_list = [1.5, 1.25, 0.8, 0.6, 0.5], 38 | budget_layers = budget_layers, 39 | btn_minimum_ratio = 10 # the bottleneck must be larger than out/10 40 | ) 41 | for n in ['ConvKXBNRELU','SuperResK1KXK1']: 42 | self.mutators[n] = build_mutator(n, kwargs) 43 | 44 | -------------------------------------------------------------------------------- /tinynas/spaces/space_kxkx.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from .base import CnnBaseSpace 6 | from .builder import SPACES 7 | from .mutator import build_mutator 8 | 9 | @SPACES.register_module(module_name = 'space_kxkx') 10 | class Spacekxkx(CnnBaseSpace): 11 | 12 | def __init__(self, name = None, 13 | image_size = 224, 14 | block_num = 2, 15 | exclude_stem = False, 16 | budget_layers=None, 17 | maximum_channel =2048, 18 | channel_range_list = None, 19 | kernel_size_list = None, 20 | **kwargs): 21 | 22 | super().__init__(name, image_size = image_size, 23 | block_num = block_num, 24 | exclude_stem = exclude_stem, 25 | budget_layers = budget_layers, 26 | **kwargs) 27 | 28 | defualt_channel_range_list = [None, None, [64, 128], None, [128, 256], [256, 512]] 29 | defualt_kernel_size_list = [3] 30 | 31 | channel_range_list = channel_range_list or defualt_channel_range_list 32 | kernel_size_list = kernel_size_list or defualt_kernel_size_list 33 | 34 | kwargs = dict(stem_mutate_method_list = ['out'] , 35 | mutate_method_list = ['out', 'btn', 'L'], 36 | the_maximum_channel = maximum_channel, 37 | channel_range = channel_range_list, 38 | search_kernel_size_list = kernel_size_list, 39 | search_layer_list = [-2, -1, 1, 2], 40 | search_channel_list = [2.0, 1.5, 1.25, 0.8, 0.6, 0.5], 41 | budget_layers = budget_layers, 42 | btn_minimum_ratio = 10 # the bottleneck must be larger than out/10 43 | ) 44 | for n in ['ConvKXBNRELU','SuperResKXKX']: 45 | self.mutators[n] = build_mutator(n, kwargs) 46 | 47 | def choice(self): 48 | return None 49 | 50 | -------------------------------------------------------------------------------- /tinynas/spaces/space_quant_k1dwk1.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import bisect 6 | import copy 7 | import os 8 | import random 9 | import sys 10 | 11 | from .base import CnnBaseSpace 12 | from .builder import SPACES 13 | from .space_k1kxk1 import Spacek1kxk1 14 | from .mutator import build_mutator 15 | 16 | 17 | @SPACES.register_module(module_name = 'space_quant_k1dwk1') 18 | class SpaceQuantk1dwk1(CnnBaseSpace): 19 | def __init__(self, name = None, 20 | image_size = 224, 21 | block_num = 2, 22 | exclude_stem = False, 23 | budget_layers=None, 24 | maximum_channel =1280, 25 | **kwargs): 26 | 27 | super().__init__(name, image_size = image_size, 28 | block_num = block_num, 29 | exclude_stem = exclude_stem, 30 | budget_layers = budget_layers, 31 | **kwargs) 32 | 33 | kwargs = dict(stem_mutate_method_list = ['out'] , 34 | the_maximum_channel = maximum_channel, 35 | nbits_ratio = 0.1, 36 | mutate_method_list = ['out', 'k', 'btn', 'L', 'nbits'], 37 | search_kernel_size_list = [3, 5], 38 | search_layer_list = [-2, -1, 1, 2], 39 | search_channel_list = [2.0, 1.5, 1.25, 0.8, 0.6, 0.5], 40 | search_nbits_list = [3, 4, 5, 6], 41 | search_btn_ratio_list = [1.5, 2.0, 2.5, 3.0, 3.5, 4.0], 42 | budget_layers = budget_layers 43 | ) 44 | 45 | for n in ['ConvKXBNRELU','SuperQuantResK1DWK1']: 46 | self.mutators[n] = build_mutator(n, kwargs) 47 | 48 | -------------------------------------------------------------------------------- /tinynas/spaces/space_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | 6 | def decode_cand_tuple(cand_tuple): 7 | depth = cand_tuple[0] 8 | return depth, list(cand_tuple[1:depth + 1]), list( 9 | cand_tuple[depth + 1:2 * depth + 1]), cand_tuple[-1] 10 | 11 | 12 | def smart_round(x, base=8): 13 | if base is None: 14 | if x > 32 * 8: 15 | round_base = 32 16 | elif x > 16 * 8: 17 | round_base = 16 18 | else: 19 | round_base = 8 20 | else: 21 | round_base = base 22 | 23 | return max(round_base, round(x / float(round_base)) * round_base) 24 | 25 | 26 | def __check_block_structure_info_list_valid__(block_structure_info_list, budget_layers = None): 27 | if len(block_structure_info_list) < 1: 28 | return False 29 | 30 | # check how many conv layers 31 | layers = 0 32 | for block_structure_info in block_structure_info_list: 33 | if 'L' not in block_structure_info.keys(): 34 | layers += 1 35 | elif block_structure_info['class'] in ['SuperResK1KX', 'SuperResKXKX']: 36 | layers += block_structure_info['L'] * 2 37 | else: 38 | layers += block_structure_info['L'] * 3 39 | 40 | if budget_layers is not None and layers > budget_layers: 41 | return False 42 | 43 | return True 44 | 45 | 46 | def adjust_structures_inplace(block_structure_info_list, image_size): 47 | 48 | # adjust channels 49 | last_channels = None 50 | for i, block_structure_info in enumerate(block_structure_info_list): 51 | if last_channels is None: 52 | last_channels = block_structure_info['out'] 53 | continue 54 | else: 55 | block_structure_info_list[i]['in'] = last_channels 56 | last_channels = block_structure_info['out'] 57 | 58 | # adjust kernel size <= feature map / 1.5 59 | resolution = image_size 60 | for i, block_structure_info in enumerate(block_structure_info_list): 61 | stride = block_structure_info['s'] 62 | kernel_size = block_structure_info['k'] 63 | 64 | while kernel_size * 1.5 > resolution: 65 | kernel_size -= 2 66 | 67 | block_structure_info['k'] = kernel_size 68 | 69 | resolution /= stride 70 | 71 | return block_structure_info_list 72 | -------------------------------------------------------------------------------- /tinynas/strategy/README.md: -------------------------------------------------------------------------------- 1 | ## Search Strategy module 2 | *** 3 | **The search strategy contains a large number of module, mainly complete the search space setting, build super model, budgets, scores, latency and so on ** 4 | 5 | - **Strategy Class** 6 | 7 | `build_xxx`: Build sub modules from a cfg dict. 8 | 9 | `budgets`: A property method to get the budgets value setting in cfg. 10 | 11 | `do_compute_nas_score`: Compute a score of a network with specified method. 12 | 13 | `is_satify_budget`: Determine if a network meets budget. If dissatisfied, we will drop it. 14 | 15 | `get_info_for_evolution`: Build a new model from structure info and generate additional information, such as flops/score ans so on. 16 | 17 | -------------------------------------------------------------------------------- /tinynas/strategy/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | from .strategy import Strategy 6 | 7 | -------------------------------------------------------------------------------- /tinynas/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba/lightweight-neural-architecture-search/8ccaf889fcd06079d268a355c765e9d0af071612/tinynas/utils/__init__.py -------------------------------------------------------------------------------- /tinynas/utils/dict_action.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2022 Open-MMLab. All rights reserved. 2 | # Origin file: 3 | # https://github.com/open-mmlab/mmcv/blob/8c23bf140a2d329537aabe8947d6ff3125ae7a16/mmcv/utils/config.py 4 | from argparse import Action 5 | 6 | 7 | class DictAction(Action): 8 | """ 9 | argparse action to split an argument into KEY=VALUE form 10 | on the first = and append to a dictionary. List options can 11 | be passed as comma separated values, i.e 'KEY=V1,V2,V3', or with explicit 12 | brackets, i.e. 'KEY=[V1,V2,V3]'. It also support nested brackets to build 13 | list/tuple values. e.g. 'KEY=[(V1,V2),(V3,V4)]' 14 | """ 15 | 16 | @staticmethod 17 | def _parse_int_float_bool(val): 18 | try: 19 | return int(val) 20 | except ValueError: 21 | pass 22 | try: 23 | return float(val) 24 | except ValueError: 25 | pass 26 | if val.lower() in ['true', 'false']: 27 | return True if val.lower() == 'true' else False 28 | return val 29 | 30 | @staticmethod 31 | def _parse_iterable(val): 32 | """Parse iterable values in the string. 33 | All elements inside '()' or '[]' are treated as iterable values. 34 | Args: 35 | val (str): Value string. 36 | Returns: 37 | list | tuple: The expanded list or tuple from the string. 38 | Examples: 39 | >>> DictAction._parse_iterable('1,2,3') 40 | [1, 2, 3] 41 | >>> DictAction._parse_iterable('[a, b, c]') 42 | ['a', 'b', 'c'] 43 | >>> DictAction._parse_iterable('[(1, 2, 3), [a, b], c]') 44 | [(1, 2, 3), ['a', 'b'], 'c'] 45 | """ 46 | 47 | def find_next_comma(string): 48 | """Find the position of next comma in the string. 49 | If no ',' is found in the string, return the string length. All 50 | chars inside '()' and '[]' are treated as one element and thus ',' 51 | inside these brackets are ignored. 52 | """ 53 | assert (string.count('(') == string.count(')')) and ( 54 | string.count('[') == string.count(']')), \ 55 | f'Imbalanced brackets exist in {string}' 56 | end = len(string) 57 | for idx, char in enumerate(string): 58 | pre = string[:idx] 59 | # The string before this ',' is balanced 60 | if ((char == ',') and (pre.count('(') == pre.count(')')) 61 | and (pre.count('[') == pre.count(']'))): 62 | end = idx 63 | break 64 | return end 65 | 66 | # Strip ' and " characters and replace whitespace. 67 | val = val.strip('\'\"').replace(' ', '') 68 | is_tuple = False 69 | if val.startswith('(') and val.endswith(')'): 70 | is_tuple = True 71 | val = val[1:-1] 72 | elif val.startswith('[') and val.endswith(']'): 73 | val = val[1:-1] 74 | elif ',' not in val: 75 | # val is a single value 76 | return DictAction._parse_int_float_bool(val) 77 | 78 | values = [] 79 | while len(val) > 0: 80 | comma_idx = find_next_comma(val) 81 | element = DictAction._parse_iterable(val[:comma_idx]) 82 | values.append(element) 83 | val = val[comma_idx + 1:] 84 | if is_tuple: 85 | values = tuple(values) 86 | return values 87 | 88 | def __call__(self, parser, namespace, values, option_string=None): 89 | options = {} 90 | for kv in values: 91 | key, val = kv.split('=', maxsplit=1) 92 | options[key] = self._parse_iterable(val) 93 | setattr(namespace, self.dest, options) 94 | -------------------------------------------------------------------------------- /tinynas/utils/dist_utils.py: -------------------------------------------------------------------------------- 1 | import functools 2 | from typing import Callable, List, Optional, Tuple 3 | 4 | def get_dist_info() -> Tuple[int, int]: 5 | 6 | try: 7 | import mpi4py.MPI as MPI 8 | mpi_comm = MPI.COMM_WORLD 9 | rank = mpi_comm.Get_rank() 10 | world_size = mpi_comm.Get_size() 11 | except ImportError: 12 | rank = 0 13 | world_size = 1 14 | return rank, world_size 15 | 16 | def is_master(): 17 | rank, _ = get_dist_info() 18 | return rank == 0 19 | 20 | def master_only(func: Callable) -> Callable: 21 | 22 | @functools.wraps(func) 23 | def wrapper(*args, **kwargs): 24 | rank, _ = get_dist_info() 25 | if rank == 0: 26 | return func(*args, **kwargs) 27 | 28 | return wrapper 29 | 30 | def get_mpi_comm(): 31 | try: 32 | import mpi4py.MPI as MPI 33 | mpi_comm = MPI.COMM_WORLD 34 | except ImportError: 35 | mpi_comm = None 36 | return mpi_comm 37 | 38 | def worker_only(func: Callable) -> Callable: 39 | 40 | @functools.wraps(func) 41 | def wrapper(*args, **kwargs): 42 | rank, _ = get_dist_info() 43 | if rank > 0: 44 | return func(*args, **kwargs) 45 | 46 | return wrapper 47 | -------------------------------------------------------------------------------- /tinynas/utils/file_utils.py: -------------------------------------------------------------------------------- 1 | import distutils.dir_util 2 | import pprint 3 | import importlib.util 4 | 5 | from .import_utils import load_py_module_from_path 6 | from .dist_utils import master_only 7 | 8 | import os 9 | 10 | def mkfilepath(filename): 11 | filename = os.path.expanduser(filename) 12 | distutils.dir_util.mkpath(os.path.dirname(filename)) 13 | 14 | 15 | def mkdir(dirname): 16 | dirname = os.path.expanduser(dirname) 17 | distutils.dir_util.mkpath(dirname) 18 | 19 | 20 | def robust_save(filename, save_function): 21 | mkfilepath(filename) 22 | backup_filename = filename + '.robust_save_temp' 23 | save_function(backup_filename) 24 | if os.path.isfile(filename): 25 | os.remove(filename) 26 | os.rename(backup_filename, filename) 27 | 28 | @master_only 29 | def save_pyobj(filename, pyobj): 30 | mkfilepath(filename) 31 | the_s = pprint.pformat(pyobj, indent=2, width=120, compact=True) 32 | with open(filename, 'w') as fid: 33 | fid.write(the_s) 34 | 35 | def load_pyobj(filename): 36 | with open(filename, 'r') as fid: 37 | the_s = fid.readlines() 38 | 39 | if isinstance(the_s, list): 40 | the_s = ''.join(the_s) 41 | 42 | the_s = the_s.replace('inf', '1e20') 43 | pyobj = ast.literal_eval(the_s) 44 | return pyobj 45 | -------------------------------------------------------------------------------- /tinynas/utils/import_utils.py: -------------------------------------------------------------------------------- 1 | import importlib.util 2 | import os 3 | 4 | def load_py_module_from_path(module_path, module_name=None): 5 | if module_path.find(':') > 0: 6 | split_path = module_path.split(':') 7 | module_path = split_path[0] 8 | function_name = split_path[1] 9 | else: 10 | function_name = None 11 | 12 | if module_name is None: 13 | module_name = module_path.replace('/', '_').replace('.', '_') 14 | 15 | assert os.path.isfile(module_path) 16 | 17 | spec = importlib.util.spec_from_file_location(module_name, module_path) 18 | any_module = importlib.util.module_from_spec(spec) 19 | spec.loader.exec_module(any_module) 20 | if function_name is None: 21 | return any_module 22 | else: 23 | return getattr(any_module, function_name) 24 | -------------------------------------------------------------------------------- /tinynas/utils/logger.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | # https://github.com/alibaba/lightweight-neural-architecture-search. 4 | 5 | import logging 6 | 7 | 8 | def get_logger(name, 9 | rank=0, 10 | log_file=None, 11 | log_level="INFO", 12 | file_mode='w'): 13 | """[summary] 14 | 15 | Args: 16 | name ([type]): [description] 17 | rank (int, optional): [description]. Defaults to 0. 18 | log_file ([type], optional): [description]. Defaults to None. 19 | log_level ([type], optional): [description]. Defaults to logging.INFO. 20 | file_mode (str, optional): [description]. Defaults to 'w'. 21 | 22 | Returns: 23 | [type]: [description] 24 | """ 25 | if log_level.upper() == 'DEBUG': 26 | log_level = logging.DEBUG 27 | elif log_level.upper() == 'ERROR': 28 | log_level = logging.ERROR 29 | elif log_level.upper() == 'WARNING': 30 | log_level = logging.WARNING 31 | else: 32 | log_level = logging.INFO 33 | 34 | logger = logging.getLogger(name) 35 | 36 | for handler in logger.root.handlers: 37 | if type(handler) is logging.StreamHandler: 38 | handler.setLevel(logging.ERROR) 39 | 40 | # all rank will add a StreamHandler for error output 41 | stream_handler = logging.StreamHandler() 42 | handlers = [stream_handler] 43 | 44 | # only rank 0 will add a FileHandler 45 | if rank == 0 and log_file is not None: 46 | file_handler = logging.FileHandler(log_file, file_mode) 47 | handlers.append(file_handler) 48 | 49 | formatter = logging.Formatter( 50 | f'%(asctime)s-%(name)s-%(levelname)s-rank{rank}: %(message)s') 51 | for handler in handlers: 52 | handler.setFormatter(formatter) 53 | handler.setLevel(log_level) 54 | logger.addHandler(handler) 55 | 56 | if rank == 0: 57 | logger.setLevel(log_level) 58 | else: 59 | logger.setLevel(logging.ERROR) 60 | 61 | return logger 62 | 63 | def get_root_logger(name='Search', 64 | rank=0, 65 | log_file=None, 66 | log_level=logging.INFO): 67 | """[summary] 68 | 69 | Args: 70 | name (str, optional): [description]. Defaults to 'nas'. 71 | log_file ([type], optional): [description]. Defaults to None. 72 | log_level ([type], optional): [description]. Defaults to logging.INFO. 73 | 74 | Returns: 75 | [type]: [description] 76 | """ 77 | logger = get_logger( 78 | name=name, rank=rank, log_file=log_file, log_level=log_level) 79 | 80 | return logger 81 | 82 | 83 | class MyLogger(): 84 | 85 | def __init__(self, log_filename=None, verbose=False): 86 | self.log_filename = log_filename 87 | self.verbose = verbose 88 | if self.log_filename is not None: 89 | mkfilepath(self.log_filename) 90 | self.fid = open(self.log_filename, 'w') 91 | else: 92 | self.fid = None 93 | 94 | def info(self, msg): 95 | msg = str(msg) 96 | print(msg) 97 | if self.fid is not None: 98 | self.fid.write(msg + '\n') 99 | self.fid.flush() 100 | 101 | def debug_info(self, msg): 102 | if not self.verbose: 103 | return 104 | msg = str(msg) 105 | print(msg) 106 | if self.fid is not None: 107 | self.fid.write(msg + '\n') 108 | self.fid.flush() 109 | -------------------------------------------------------------------------------- /tools/dist_search.sh: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | 4 | CONFIG=$1 5 | shift 1 6 | CFG_OPTIONS="${*:-""}" 7 | 8 | nproc=64 9 | set -e 10 | 11 | PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \ 12 | mpirun --allow-run-as-root -np ${nproc} -H 127.0.0.1:${nproc} -bind-to none -map-by slot -mca pml ob1 \ 13 | -mca btl ^openib -x NCCL_DEBUG=INFO -x LD_LIBRARY_PATH -x PATH \ 14 | python3 $(dirname "$0")/search.py ${CONFIG} ${CFG_OPTIONS} -------------------------------------------------------------------------------- /tools/export.py: -------------------------------------------------------------------------------- 1 | import ast 2 | import sys 3 | from os.path import basename, expanduser, abspath, dirname, exists, isdir, join 4 | from shutil import copy2, copytree, ignore_patterns, rmtree 5 | import json 6 | 7 | def export( work_dir, export_dir=None, force=False): 8 | 9 | taskid = basename(abspath(expanduser(work_dir))) 10 | base_dir = dirname(dirname(abspath(__file__))) 11 | 12 | if export_dir is None: 13 | export_dir = '.' 14 | 15 | code_dir = join(base_dir, 'tinynas', 'deploy') 16 | 17 | # parse best 18 | best_from = join(work_dir, 'best_structure.txt') 19 | best_config = ast.literal_eval(open(best_from).read()) 20 | arch = best_config['space_arch'].lower() 21 | 22 | # copy source code 23 | deploy_from = join(code_dir, arch) 24 | deploy_to = join(export_dir, taskid) 25 | if exists(deploy_to) and force: 26 | if isdir(deploy_to): 27 | rmtree(deploy_to) 28 | else: 29 | os.remove(deploy_to) 30 | copytree( 31 | deploy_from, 32 | deploy_to, 33 | ignore=ignore_patterns('__pycache__', '*.pyc', '*.md')) 34 | 35 | best_to = join(deploy_to, 'best_structure.json') 36 | json.dump(best_config, open(best_to, 'w'), indent=2) 37 | 38 | # copy weight 39 | weight_from = join(work_dir, 'weights') 40 | if exists(weight_from) and isdir(weight_from): 41 | weight_to = join(deploy_to, 'weights') 42 | copytree(weight_from, weight_to) 43 | 44 | return deploy_to 45 | 46 | 47 | if __name__ == '__main__': 48 | args = {k: v for k, v in enumerate(sys.argv)} 49 | 50 | work_dir = args.get(1, None) 51 | output_dir = args.get(2, None) 52 | 53 | if work_dir is None: 54 | print('work_dir not specified!') 55 | else: 56 | loc = export(work_dir, output_dir, force=True) 57 | print('exported to', loc) 58 | -------------------------------------------------------------------------------- /tools/local_search.sh: -------------------------------------------------------------------------------- 1 | # Copyright (c) Alibaba, Inc. and its affiliates. 2 | # The implementation is also open-sourced by the authors, and available at 3 | 4 | CONFIG=$1 5 | shift 1 6 | CFG_OPTIONS="${*:-""}" 7 | 8 | set -e 9 | 10 | PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \ 11 | python3 $(dirname "$0")/search.py ${CONFIG} ${CFG_OPTIONS} -------------------------------------------------------------------------------- /tools/search.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | from tinynas.searchers import build_searcher 3 | from tinynas.utils.dict_action import DictAction 4 | 5 | def parse_args(): 6 | parser = argparse.ArgumentParser(description='Search a network model') 7 | parser.add_argument('config', help='search config file path') 8 | parser.add_argument( 9 | '--cfg_options', 10 | nargs='+', 11 | action=DictAction, 12 | help='override some settings in the used config, the key-value pair ' 13 | 'in xxx=yyy format will be merged into config file. If the value to ' 14 | 'be overwritten is a list, it should be like key="[a,b]" or key=a,b ' 15 | 'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" ' 16 | 'Note that the quotation marks are necessary and that no white space ' 17 | 'is allowed.') 18 | args = parser.parse_args() 19 | return args 20 | 21 | def main(): 22 | 23 | args = parse_args() 24 | kwargs = dict(cfg_file=args.config) 25 | if args.cfg_options is not None: 26 | kwargs['cfg_options'] = args.cfg_options 27 | searcher = build_searcher(default_args = kwargs) 28 | searcher.run() 29 | 30 | if __name__ == '__main__': 31 | main() 32 | --------------------------------------------------------------------------------