├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── THIRD_PARTY_LICENSES ├── assets ├── Create_IAM_role.png ├── Launch_terminal.png ├── SageMaker_console.png ├── Select_pytorch_image.png ├── Select_tensorflow_image.png ├── Studio_domain.png ├── Studio_launcher.png ├── Studio_menu_bar.png ├── instance_types.png ├── mask_rcnn_arch.jpeg ├── notebook_pytorch_kernel.png ├── notebook_tensorflow_kernel.png ├── running_instances.png └── traffic.png ├── pytorch ├── README.md ├── Sagemaker.ipynb ├── Tutorial.ipynb ├── configs │ ├── __init__.py │ └── config.py ├── cuda_utils │ ├── README.md │ ├── setup.py │ ├── smcv_utils │ │ ├── ROIAlign.h │ │ ├── ROIPool.h │ │ ├── SigmoidFocalLoss.h │ │ ├── anchor_generator.h │ │ ├── box_encode.h │ │ ├── box_iou.h │ │ ├── cpu │ │ │ ├── ROIAlign_cpu.cpp │ │ │ ├── nms_cpu.cpp │ │ │ └── vision.h │ │ ├── cuda │ │ │ ├── ROIAlign_cuda.cu │ │ │ ├── ROIPool_cuda.cu │ │ │ ├── SigmoidFocalLoss_cuda.cu │ │ │ ├── anchor_generator.cu │ │ │ ├── box_encode.cu │ │ │ ├── box_iou.cu │ │ │ ├── generate_mask_targets.cu │ │ │ ├── match_proposals.cu │ │ │ ├── nhwc.cpp │ │ │ ├── nhwc.h │ │ │ ├── nhwc │ │ │ │ ├── Descriptors.cpp │ │ │ │ ├── Descriptors.h │ │ │ │ ├── Exceptions.h │ │ │ │ ├── LaunchUtils.h │ │ │ │ ├── ParamsHash.h │ │ │ │ ├── Types.cpp │ │ │ │ ├── Types.h │ │ │ │ ├── UpSample.cuh │ │ │ │ ├── UpSampleNearest2d.cu │ │ │ │ ├── conv.cpp │ │ │ │ ├── max_pool.cu │ │ │ │ └── transforms.cpp │ │ │ ├── nms.cu │ │ │ ├── nms_batched.cu │ │ │ ├── rpn_generate_proposals.cu │ │ │ ├── rpn_generate_proposals.h │ │ │ ├── rpn_generate_proposals_batched.cu │ │ │ └── vision.h │ │ ├── generate_mask_targets.h │ │ ├── match_proposals.h │ │ ├── nms.h │ │ ├── nms_batched.h │ │ ├── rpn_generate_proposals_batched.h │ │ └── vision.cpp │ └── tests │ │ ├── test_anchors.py │ │ ├── test_iou.py │ │ ├── test_matcher.py │ │ ├── test_nms.py │ │ └── test_roi_align.py ├── launch_ddp.py ├── sagemakercv │ ├── __init__.py │ ├── core │ │ ├── __init__.py │ │ ├── balanced_positive_negative_sampler.py │ │ ├── box_coder.py │ │ ├── matcher.py │ │ ├── poolers.py │ │ ├── structures │ │ │ ├── __init__.py │ │ │ ├── bounding_box.py │ │ │ ├── boxlist_ops.py │ │ │ ├── image_list.py │ │ │ ├── keypoint.py │ │ │ └── segmentation_mask.py │ │ └── utils.py │ ├── data │ │ ├── README.md │ │ ├── __init__.py │ │ ├── build.py │ │ ├── collate_batch.py │ │ ├── datasets │ │ │ ├── __init__.py │ │ │ ├── coco.py │ │ │ ├── concat_dataset.py │ │ │ ├── evaluation │ │ │ │ ├── __init__.py │ │ │ │ ├── coco │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── coco_eval.py │ │ │ │ │ └── coco_labels.py │ │ │ │ └── voc │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── voc_eval.py │ │ │ ├── list_dataset.py │ │ │ └── voc.py │ │ ├── samplers │ │ │ ├── __init__.py │ │ │ ├── distributed.py │ │ │ ├── grouped_batch_sampler.py │ │ │ └── iteration_based_batch_sampler.py │ │ └── transforms │ │ │ ├── __init__.py │ │ │ ├── build.py │ │ │ └── transforms.py │ ├── detection │ │ ├── __init__.py │ │ ├── backbone │ │ │ ├── __init__.py │ │ │ ├── backbone.py │ │ │ ├── fpn.py │ │ │ └── resnet.py │ │ ├── detector │ │ │ ├── __init__.py │ │ │ ├── detectors.py │ │ │ └── generalized_rcnn.py │ │ ├── registry.py │ │ ├── roi_heads │ │ │ ├── __init__.py │ │ │ ├── box_head │ │ │ │ ├── __init__.py │ │ │ │ ├── box_head.py │ │ │ │ ├── inference.py │ │ │ │ ├── loss.py │ │ │ │ ├── roi_box_feature_extractors.py │ │ │ │ └── roi_box_predictors.py │ │ │ ├── keypoint_head │ │ │ │ ├── __init__.py │ │ │ │ ├── inference.py │ │ │ │ ├── keypoint_head.py │ │ │ │ ├── loss.py │ │ │ │ ├── roi_keypoint_feature_extractors.py │ │ │ │ └── roi_keypoint_predictors.py │ │ │ ├── mask_head │ │ │ │ ├── __init__.py │ │ │ │ ├── inference.py │ │ │ │ ├── loss.py │ │ │ │ ├── mask_head.py │ │ │ │ ├── roi_mask_feature_extractors.py │ │ │ │ └── roi_mask_predictors.py │ │ │ └── roi_heads.py │ │ └── rpn │ │ │ ├── __init__.py │ │ │ ├── anchor_generator.py │ │ │ ├── inference.py │ │ │ ├── loss.py │ │ │ ├── rpn.py │ │ │ └── utils.py │ ├── inference │ │ ├── __init__.py │ │ ├── inference.py │ │ └── tester.py │ ├── layers │ │ ├── __init__.py │ │ ├── _utils.py │ │ ├── batch_norm.py │ │ ├── ce_loss.py │ │ ├── conv_module.py │ │ ├── iou_loss.py │ │ ├── make_layers.py │ │ ├── misc.py │ │ ├── nhwc │ │ │ ├── UpSampleNearest2d.py │ │ │ ├── __init__.py │ │ │ ├── batch_norm.py │ │ │ ├── conv.py │ │ │ ├── init.py │ │ │ ├── max_pool.py │ │ │ ├── misc.py │ │ │ └── transforms.py │ │ ├── nms.py │ │ ├── pisa_loss.py │ │ ├── roi_align.py │ │ ├── roi_pool.py │ │ ├── sigmoid_focal_loss.py │ │ └── smooth_l1_loss.py │ ├── training │ │ ├── __init__.py │ │ ├── build.py │ │ ├── optimizers │ │ │ ├── __init__.py │ │ │ ├── fused_novograd.py │ │ │ ├── mlperf_fp16_optimizer.py │ │ │ ├── mlperf_fused_sgd.py │ │ │ └── schedulers │ │ │ │ ├── __init__.py │ │ │ │ ├── cosine_lr_scheduler.py │ │ │ │ └── lr_scheduler.py │ │ └── trainers.py │ └── utils │ │ ├── README.md │ │ ├── __init__.py │ │ ├── async_evaluator.py │ │ ├── c2_model_loading.py │ │ ├── checkpoint.py │ │ ├── collect_env.py │ │ ├── comm.py │ │ ├── cv2_util.py │ │ ├── dist_utils.py │ │ ├── env.py │ │ ├── fileio │ │ ├── __init__.py │ │ ├── handlers │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ ├── json_handler.py │ │ │ ├── pickle_handler.py │ │ │ └── yaml_handler.py │ │ ├── io.py │ │ └── parse.py │ │ ├── imports.py │ │ ├── logger.py │ │ ├── loss_utils.py │ │ ├── metric_logger.py │ │ ├── miscellaneous.py │ │ ├── mlperf_logger.py │ │ ├── model_serialization.py │ │ ├── model_zoo.py │ │ ├── registry.py │ │ ├── runner │ │ ├── __init__.py │ │ ├── builder.py │ │ ├── hooks │ │ │ ├── __init__.py │ │ │ ├── amp_optimizer.py │ │ │ ├── checkpoint.py │ │ │ ├── coco_evaluation_hook.py │ │ │ ├── fp16_optimizer.py │ │ │ ├── hook.py │ │ │ ├── iter_timer.py │ │ │ └── logger │ │ │ │ ├── __init__.py │ │ │ │ ├── base.py │ │ │ │ └── text.py │ │ ├── log_buffer.py │ │ ├── priority.py │ │ └── runner.py │ │ └── visualize.py ├── setup.py ├── train.py └── utils.py ├── tensorflow ├── Sagemaker.ipynb ├── Tutorial.ipynb ├── configs │ ├── __init__.py │ └── default_config.py ├── sagemakercv │ ├── __init__.py │ ├── core │ │ ├── __init__.py │ │ ├── anchors.py │ │ ├── argmax_matcher.py │ │ ├── balanced_positive_negative_sampler.py │ │ ├── box_coder.py │ │ ├── box_list.py │ │ ├── box_utils.py │ │ ├── builder.py │ │ ├── faster_rcnn_box_coder.py │ │ ├── matcher.py │ │ ├── minibatch_sampler.py │ │ ├── nms_ops.py │ │ ├── ops.py │ │ ├── postprocess_ops.py │ │ ├── preprocess_ops.py │ │ ├── preprocessor.py │ │ ├── region_similarity_calculator.py │ │ ├── roi_ops.py │ │ ├── shape_utils.py │ │ ├── spatial_transform_ops.py │ │ ├── target_assigner.py │ │ └── training_ops.py │ ├── data │ │ ├── __init__.py │ │ ├── builder.py │ │ └── coco │ │ │ ├── __init__.py │ │ │ ├── coco_labels.py │ │ │ ├── coco_metric.py │ │ │ ├── coco_utils.py │ │ │ ├── create_coco_tf_record.py │ │ │ ├── dataloader.py │ │ │ ├── dataloader_utils.py │ │ │ ├── evaluation.py │ │ │ ├── process_coco_tfrecord.sh │ │ │ └── tf_example_decoder.py │ ├── detection │ │ ├── __init__.py │ │ ├── backbones │ │ │ ├── __init__.py │ │ │ └── resnet.py │ │ ├── builder.py │ │ ├── dense_heads │ │ │ ├── __init__.py │ │ │ ├── anchor_head.py │ │ │ └── rpn_head.py │ │ ├── detectors │ │ │ ├── __init__.py │ │ │ └── two_stage_detector.py │ │ ├── necks │ │ │ ├── __init__.py │ │ │ └── fpn.py │ │ └── roi_heads │ │ │ ├── __init__.py │ │ │ ├── bbox_heads │ │ │ ├── __init__.py │ │ │ └── standard_bbox_head.py │ │ │ ├── cascade_roi_head.py │ │ │ ├── mask_heads │ │ │ ├── __init__.py │ │ │ └── standard_mask_head.py │ │ │ └── standard_roi_head.py │ ├── layers │ │ ├── __init__.py │ │ ├── conv_module.py │ │ └── evo_norm.py │ ├── training │ │ ├── __init__.py │ │ ├── builder.py │ │ ├── losses │ │ │ ├── __init__.py │ │ │ ├── frcnn_losses.py │ │ │ ├── losses.py │ │ │ └── rpn_losses.py │ │ ├── optimizers │ │ │ ├── __init__.py │ │ │ ├── momentum.py │ │ │ ├── novograd.py │ │ │ ├── schedulers │ │ │ │ ├── __init__.py │ │ │ │ ├── schedulers.py │ │ │ │ └── warmup_scheduler.py │ │ │ └── weight_decay_optimizer.py │ │ └── trainers.py │ └── utils │ │ ├── __init__.py │ │ ├── dist_utils.py │ │ ├── fileio │ │ ├── __init__.py │ │ ├── handlers │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ ├── json_handler.py │ │ │ ├── pickle_handler.py │ │ │ └── yaml_handler.py │ │ ├── io.py │ │ └── parse.py │ │ ├── imports.py │ │ ├── logger.py │ │ ├── logging_formatter.py │ │ ├── metaclasses.py │ │ ├── paths_catalog.py │ │ ├── registry.py │ │ ├── runner │ │ ├── __init__.py │ │ ├── builder.py │ │ ├── hooks │ │ │ ├── __init__.py │ │ │ ├── checkpoint.py │ │ │ ├── evaluation.py │ │ │ ├── graph_visualizer.py │ │ │ ├── hook.py │ │ │ ├── image_visualizer.py │ │ │ ├── iter_timer.py │ │ │ ├── logger │ │ │ │ ├── __init__.py │ │ │ │ ├── base.py │ │ │ │ ├── tensorboard.py │ │ │ │ └── text.py │ │ │ ├── profiler.py │ │ │ └── system_monitor.py │ │ ├── log_buffer.py │ │ ├── priority.py │ │ └── runner.py │ │ └── visualization.py ├── setup.py └── train.py └── version.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 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 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## SageMakerCV 2 | 3 | SageMakerCV offers a collection of deep learning computer vision models in both PyTorch and TensorFlow. These models incorporate custom CUDA operations, SageMaker Distributed Data Parallel for distributed training, mixed precision training options, and algorithmic improvements. 4 | 5 | For more information see the SageMakerCV blog, as well as the Mask RCNN in under 7 minutes blog from Re:Invent 2020. 6 | 7 | Tutorial notebooks to get started in PyTorch and Tensorflow are provided in their respective directories. 8 | 9 | ## Security 10 | 11 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 12 | 13 | ## License 14 | 15 | This project is licensed under the Apache-2.0 License. 16 | 17 | -------------------------------------------------------------------------------- /assets/Create_IAM_role.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/assets/Create_IAM_role.png -------------------------------------------------------------------------------- /assets/Launch_terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/assets/Launch_terminal.png -------------------------------------------------------------------------------- /assets/SageMaker_console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/assets/SageMaker_console.png -------------------------------------------------------------------------------- /assets/Select_pytorch_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/assets/Select_pytorch_image.png -------------------------------------------------------------------------------- /assets/Select_tensorflow_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/assets/Select_tensorflow_image.png -------------------------------------------------------------------------------- /assets/Studio_domain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/assets/Studio_domain.png -------------------------------------------------------------------------------- /assets/Studio_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/assets/Studio_launcher.png -------------------------------------------------------------------------------- /assets/Studio_menu_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/assets/Studio_menu_bar.png -------------------------------------------------------------------------------- /assets/instance_types.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/assets/instance_types.png -------------------------------------------------------------------------------- /assets/mask_rcnn_arch.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/assets/mask_rcnn_arch.jpeg -------------------------------------------------------------------------------- /assets/notebook_pytorch_kernel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/assets/notebook_pytorch_kernel.png -------------------------------------------------------------------------------- /assets/notebook_tensorflow_kernel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/assets/notebook_tensorflow_kernel.png -------------------------------------------------------------------------------- /assets/running_instances.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/assets/running_instances.png -------------------------------------------------------------------------------- /assets/traffic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/assets/traffic.png -------------------------------------------------------------------------------- /pytorch/README.md: -------------------------------------------------------------------------------- 1 | This model uses spcialized CUDA utilities originally developed by Nvidia for MLPerf, and modified for use with SageMaker. Compiled whls are included in the setup.py file. For users who need to compile from source, the utilities can be found in [SMCV Cuda Utils](https://github.com/aws-samples/amazon-sagemaker-cv/tree/main/pytorch/cuda_utils). -------------------------------------------------------------------------------- /pytorch/configs/__init__.py: -------------------------------------------------------------------------------- 1 | from .config import _C as cfg 2 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import glob 4 | import os 5 | import copy 6 | import torch 7 | from setuptools import find_packages 8 | from setuptools import setup 9 | from torch.utils.cpp_extension import CUDA_HOME 10 | from torch.utils.cpp_extension import CppExtension 11 | from torch.utils.cpp_extension import CUDAExtension 12 | 13 | requirements = ["torch", "torchvision"] 14 | 15 | 16 | def get_extensions(): 17 | this_dir = os.path.dirname(os.path.abspath(__file__)) 18 | extensions_dir = os.path.join(this_dir, "smcv_utils") 19 | 20 | main_file = glob.glob(os.path.join(extensions_dir, "vision.cpp")) 21 | main_file_nhwc = glob.glob(os.path.join(extensions_dir, "cuda/nhwc.cpp")) 22 | source_cpu = glob.glob(os.path.join(extensions_dir, "cpu", "*.cpp")) 23 | source_cuda = glob.glob(os.path.join(extensions_dir, "cuda", "*.cu")) 24 | source_cuda_nhwc = glob.glob(os.path.join(extensions_dir, "cuda/nhwc", "*.cu")) 25 | source_cpp_nhwc = glob.glob(os.path.join(extensions_dir, "cuda/nhwc", "*.cpp")) 26 | 27 | sources = main_file + source_cpu 28 | sources_nhwc = source_cpp_nhwc + source_cuda_nhwc + main_file_nhwc 29 | extension = CppExtension 30 | 31 | extra_compile_args = {"cxx": []} 32 | define_macros = [] 33 | 34 | if CUDA_HOME is not None: 35 | extension = CUDAExtension 36 | sources += source_cuda 37 | 38 | define_macros += [("WITH_CUDA", None)] 39 | extra_compile_args["nvcc"] = [ 40 | "-DCUDA_HAS_FP16=1", 41 | "-D__CUDA_NO_HALF_OPERATORS__", 42 | "-D__CUDA_NO_HALF_CONVERSIONS__", 43 | "-D__CUDA_NO_HALF2_OPERATORS__", 44 | ] 45 | 46 | sources = [os.path.join(extensions_dir, s) for s in sources] 47 | 48 | include_dirs = [extensions_dir] 49 | 50 | ext_modules = [ 51 | extension( 52 | "smcv_utils._C", 53 | sources, 54 | include_dirs=include_dirs, 55 | define_macros=define_macros, 56 | extra_compile_args=extra_compile_args, 57 | ), 58 | extension("smcv_utils.NHWC", 59 | sources_nhwc, 60 | include_dirs=include_dirs, 61 | define_macros=define_macros, 62 | extra_compile_args=copy.deepcopy(extra_compile_args), 63 | ) 64 | ] 65 | 66 | return ext_modules 67 | 68 | 69 | setup( 70 | name="smcv_utils", 71 | version="0.0.1", 72 | author="Amazon Web Services", 73 | url="https://github.com/aws/amazon-sagemakercv-utils-nvidia", 74 | description="Computer vision PyTorch addons for Amazon SageMaker with Nvidia GPUs", 75 | packages=find_packages(exclude=("configs", "tests",)), 76 | ext_modules=get_extensions(), 77 | cmdclass={"build_ext": torch.utils.cpp_extension.BuildExtension}, 78 | ) 79 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/ROIAlign.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | #pragma once 3 | 4 | #include "cpu/vision.h" 5 | 6 | #ifdef WITH_CUDA 7 | #include "cuda/vision.h" 8 | #endif 9 | 10 | // Interface for Python 11 | at::Tensor ROIAlign_forward(const at::Tensor& input, 12 | const at::Tensor& rois, 13 | const float spatial_scale, 14 | const int pooled_height, 15 | const int pooled_width, 16 | const int sampling_ratio, 17 | const bool is_nhwc) { 18 | if (input.is_cuda()) { 19 | #ifdef WITH_CUDA 20 | return ROIAlign_forward_cuda(input, rois, spatial_scale, pooled_height, pooled_width, sampling_ratio, is_nhwc); 21 | #else 22 | AT_ERROR("Not compiled with GPU support"); 23 | #endif 24 | } 25 | return ROIAlign_forward_cpu(input, rois, spatial_scale, pooled_height, pooled_width, sampling_ratio); 26 | } 27 | 28 | at::Tensor ROIAlign_backward(const at::Tensor& grad, 29 | const at::Tensor& rois, 30 | const float spatial_scale, 31 | const int pooled_height, 32 | const int pooled_width, 33 | const int batch_size, 34 | const int channels, 35 | const int height, 36 | const int width, 37 | const int sampling_ratio, 38 | const bool is_nhwc) { 39 | if (grad.is_cuda()) { 40 | #ifdef WITH_CUDA 41 | return ROIAlign_backward_cuda(grad, rois, spatial_scale, pooled_height, pooled_width, batch_size, channels, height, width, sampling_ratio, is_nhwc); 42 | #else 43 | AT_ERROR("Not compiled with GPU support"); 44 | #endif 45 | } 46 | AT_ERROR("Not implemented on the CPU"); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/ROIPool.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | #pragma once 3 | 4 | #include "cpu/vision.h" 5 | 6 | #ifdef WITH_CUDA 7 | #include "cuda/vision.h" 8 | #endif 9 | 10 | 11 | std::tuple ROIPool_forward(const at::Tensor& input, 12 | const at::Tensor& rois, 13 | const float spatial_scale, 14 | const int pooled_height, 15 | const int pooled_width) { 16 | if (input.is_cuda()) { 17 | #ifdef WITH_CUDA 18 | return ROIPool_forward_cuda(input, rois, spatial_scale, pooled_height, pooled_width); 19 | #else 20 | AT_ERROR("Not compiled with GPU support"); 21 | #endif 22 | } 23 | AT_ERROR("Not implemented on the CPU"); 24 | } 25 | 26 | at::Tensor ROIPool_backward(const at::Tensor& grad, 27 | const at::Tensor& input, 28 | const at::Tensor& rois, 29 | const at::Tensor& argmax, 30 | const float spatial_scale, 31 | const int pooled_height, 32 | const int pooled_width, 33 | const int batch_size, 34 | const int channels, 35 | const int height, 36 | const int width) { 37 | if (grad.is_cuda()) { 38 | #ifdef WITH_CUDA 39 | return ROIPool_backward_cuda(grad, input, rois, argmax, spatial_scale, pooled_height, pooled_width, batch_size, channels, height, width); 40 | #else 41 | AT_ERROR("Not compiled with GPU support"); 42 | #endif 43 | } 44 | AT_ERROR("Not implemented on the CPU"); 45 | } 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/SigmoidFocalLoss.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cpu/vision.h" 4 | 5 | #ifdef WITH_CUDA 6 | #include "cuda/vision.h" 7 | #endif 8 | 9 | // Interface for Python 10 | at::Tensor SigmoidFocalLoss_forward( 11 | const at::Tensor& logits, 12 | const at::Tensor& targets, 13 | const int num_classes, 14 | const float gamma, 15 | const float alpha) { 16 | if (logits.type().is_cuda()) { 17 | #ifdef WITH_CUDA 18 | return SigmoidFocalLoss_forward_cuda(logits, targets, num_classes, gamma, alpha); 19 | #else 20 | AT_ERROR("Not compiled with GPU support"); 21 | #endif 22 | } 23 | AT_ERROR("Not implemented on the CPU"); 24 | } 25 | 26 | at::Tensor SigmoidFocalLoss_backward( 27 | const at::Tensor& logits, 28 | const at::Tensor& targets, 29 | const at::Tensor& d_losses, 30 | const int num_classes, 31 | const float gamma, 32 | const float alpha) { 33 | if (logits.type().is_cuda()) { 34 | #ifdef WITH_CUDA 35 | return SigmoidFocalLoss_backward_cuda(logits, targets, d_losses, num_classes, gamma, alpha); 36 | #else 37 | AT_ERROR("Not compiled with GPU support"); 38 | #endif 39 | } 40 | AT_ERROR("Not implemented on the CPU"); 41 | } 42 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/anchor_generator.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | 18 | ******************************************************************************/ 19 | 20 | #pragma once 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | std::vector anchor_generator(at::Tensor& image_height, 28 | at::Tensor& image_width, 29 | std::vector feature_map_size, // (height, width) 30 | at::Tensor& cell_anchors, // shape: [1, 3, 4] 31 | const int stride, 32 | const float straddle_thresh); 33 | 34 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/box_encode.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | #include "cuda/vision.h" 19 | #ifndef _box_encode_h_ 20 | #define _box_encode_h_ 21 | 22 | std::vector box_encode(at::Tensor boxes, at::Tensor anchors, float wx, float wy, float ww, float wh){ 23 | std::vector result = box_encode_cuda(boxes, anchors, wx, wy, ww, wh); 24 | return result; 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/box_iou.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | #include "cuda/vision.h" 19 | #ifndef _box_iou_h_ 20 | #define _box_iou_h_ 21 | 22 | at::Tensor box_iou(at::Tensor box1, at::Tensor box2){ 23 | at::Tensor result = box_iou_cuda(box1, box2); 24 | return result; 25 | } 26 | 27 | #endif 28 | 29 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/cpu/nms_cpu.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | #include "cpu/vision.h" 3 | 4 | 5 | template 6 | at::Tensor nms_cpu_kernel(const at::Tensor& dets, 7 | const at::Tensor& scores, 8 | const float threshold) { 9 | AT_ASSERTM(!dets.is_cuda(), "dets must be a CPU tensor"); 10 | AT_ASSERTM(!scores.is_cuda(), "scores must be a CPU tensor"); 11 | AT_ASSERTM(dets.scalar_type() == scores.scalar_type(), "dets should have the same type as scores"); 12 | 13 | if (dets.numel() == 0) { 14 | return at::empty({0}, dets.options().dtype(at::kLong).device(at::kCPU)); 15 | } 16 | 17 | auto x1_t = dets.select(1, 0).contiguous(); 18 | auto y1_t = dets.select(1, 1).contiguous(); 19 | auto x2_t = dets.select(1, 2).contiguous(); 20 | auto y2_t = dets.select(1, 3).contiguous(); 21 | 22 | at::Tensor areas_t = (x2_t - x1_t + 1) * (y2_t - y1_t + 1); 23 | 24 | auto order_t = std::get<1>(scores.sort(0, /* descending=*/true)); 25 | 26 | auto ndets = dets.size(0); 27 | at::Tensor suppressed_t = at::zeros({ndets}, dets.options().dtype(at::kByte).device(at::kCPU)); 28 | 29 | auto suppressed = suppressed_t.data_ptr(); 30 | auto order = order_t.data_ptr(); 31 | auto x1 = x1_t.data_ptr(); 32 | auto y1 = y1_t.data_ptr(); 33 | auto x2 = x2_t.data_ptr(); 34 | auto y2 = y2_t.data_ptr(); 35 | auto areas = areas_t.data_ptr(); 36 | 37 | for (int64_t _i = 0; _i < ndets; _i++) { 38 | auto i = order[_i]; 39 | if (suppressed[i] == 1) 40 | continue; 41 | auto ix1 = x1[i]; 42 | auto iy1 = y1[i]; 43 | auto ix2 = x2[i]; 44 | auto iy2 = y2[i]; 45 | auto iarea = areas[i]; 46 | 47 | for (int64_t _j = _i + 1; _j < ndets; _j++) { 48 | auto j = order[_j]; 49 | if (suppressed[j] == 1) 50 | continue; 51 | auto xx1 = std::max(ix1, x1[j]); 52 | auto yy1 = std::max(iy1, y1[j]); 53 | auto xx2 = std::min(ix2, x2[j]); 54 | auto yy2 = std::min(iy2, y2[j]); 55 | 56 | auto w = std::max(static_cast(0), xx2 - xx1 + 1); 57 | auto h = std::max(static_cast(0), yy2 - yy1 + 1); 58 | auto inter = w * h; 59 | auto ovr = inter / (iarea + areas[j] - inter); 60 | if (ovr >= threshold) 61 | suppressed[j] = 1; 62 | } 63 | } 64 | return at::nonzero(suppressed_t == 0).squeeze(1); 65 | } 66 | 67 | at::Tensor nms_cpu(const at::Tensor& dets, 68 | const at::Tensor& scores, 69 | const float threshold) { 70 | at::Tensor result; 71 | AT_DISPATCH_FLOATING_TYPES(dets.scalar_type(), "nms", [&] { 72 | result = nms_cpu_kernel(dets, scores, threshold); 73 | }); 74 | return result; 75 | } 76 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/cpu/vision.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | #pragma once 3 | #include 4 | 5 | 6 | at::Tensor ROIAlign_forward_cpu(const at::Tensor& input, 7 | const at::Tensor& rois, 8 | const float spatial_scale, 9 | const int pooled_height, 10 | const int pooled_width, 11 | const int sampling_ratio); 12 | 13 | 14 | at::Tensor nms_cpu(const at::Tensor& dets, 15 | const at::Tensor& scores, 16 | const float threshold); 17 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/cuda/nhwc.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "nhwc.h" 18 | 19 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 20 | m.def("cudnn_convolution_nhwc", &at::native::nhwc::cudnn_convolution_nhwc, "cudnn_convolution_nhwc"); 21 | m.def("cudnn_convolution_transpose_nhwc", &at::native::nhwc::cudnn_convolution_transpose_nhwc, "cudnn_convolution_transpose_nhwc"); 22 | m.def("cudnn_convolution_transpose_backward_nhwc", &at::native::nhwc::cudnn_convolution_transpose_backward_nhwc, "cudnn_convolution_transpose_backward_nhwc"); 23 | m.def("cudnn_convolution_transpose_with_bias_nhwc", &at::native::nhwc::cudnn_convolution_transpose_with_bias_nhwc, "cudnn_convolution_transpose_nhwc"); 24 | m.def("cudnn_convolution_transpose_backward_with_bias_nhwc", &at::native::nhwc::cudnn_convolution_transpose_backward_with_bias_nhwc, "cudnn_convolution_transpose_backward_nhwc"); 25 | m.def("cudnn_convolution_with_bias_nhwc", &at::native::nhwc::cudnn_convolution_with_bias_nhwc, "cudnn_convolution_with_bias_nhwc"); 26 | m.def("cudnn_convolution_backward_nhwc", &at::native::nhwc::cudnn_convolution_backward_nhwc, "cudnn_convolution_backward_nhwc"); 27 | m.def("cudnn_convolution_backward_with_bias_nhwc", &at::native::nhwc::cudnn_convolution_backward_with_bias_nhwc, "cudnn_convolution_backward_with_bias_nhwc"); 28 | m.def("cudnnNhwcToNchw", &at::native::nhwc::cudnnNhwcToNchw, "cudnnNhwcToNchw"); 29 | m.def("cudnnNchwToNhwc", &at::native::nhwc::cudnnNchwToNhwc, "cudnnNhcwToNhwc"); 30 | m.def("upsample_nearest2d_cuda", &at::native::nhwc::upsample_nearest2d_cuda, "upsample_nearest2d_cuda"); 31 | m.def("upsample_nearest2d_backward_cuda", &at::native::nhwc::upsample_nearest2d_backward_cuda, "upsample_nearest2d_backward_cuda"); 32 | // MaxPool 33 | m.def("max_pool_fwd_nhwc", &max_pool_nhwc_fwd, "max_pool_fwd_nhwc"); 34 | m.def("max_pool_bwd_nhwc", &max_pool_nhwc_bwd, "max_pool_bwd_nhwc"); 35 | } 36 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/cuda/nhwc/LaunchUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace at { 5 | namespace native { 6 | 7 | // returns 2**floor(log2(n)) 8 | static int lastPow2(unsigned int n) { 9 | n |= (n >> 1); 10 | n |= (n >> 2); 11 | n |= (n >> 4); 12 | n |= (n >> 8); 13 | n |= (n >> 16); 14 | return std::max(1, n - (n >> 1)); 15 | } 16 | 17 | } // namespace native 18 | } // namespace at 19 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/cuda/nhwc/ParamsHash.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | 18 | ******************************************************************************/ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | 25 | namespace at { namespace native { namespace nhwc { 26 | 27 | // Hashing machinery for Params 28 | // Fowler–Noll–Vo hash function 29 | // see https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function 30 | template 31 | struct ParamsHash { 32 | // Params must be a POD because we read out its memory 33 | // contenst as char* when hashing 34 | static_assert(std::is_pod::value, "Params is not POD"); 35 | 36 | size_t operator()(const Params& params) const { 37 | auto ptr = reinterpret_cast(¶ms); 38 | uint32_t value = 0x811C9DC5; 39 | for (int i = 0; i < (int)sizeof(Params); ++i) { 40 | value ^= ptr[i]; 41 | value *= 0x01000193; 42 | } 43 | return (size_t)value; 44 | } 45 | }; 46 | 47 | template 48 | struct ParamsEqual { 49 | // Params must be a POD because we read out its memory 50 | // contenst as char* when comparing 51 | static_assert(std::is_pod::value, "Params is not POD"); 52 | 53 | bool operator()(const Params& a, const Params& b) const { 54 | auto ptr1 = reinterpret_cast(&a); 55 | auto ptr2 = reinterpret_cast(&b); 56 | return memcmp(ptr1, ptr2, sizeof(Params)) == 0; 57 | } 58 | }; 59 | 60 | 61 | }}} // at::native 62 | 63 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/cuda/nhwc/Types.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace at { namespace native { 5 | 6 | cudnnDataType_t getCudnnDataType(const at::Tensor& tensor) { 7 | if (tensor.scalar_type() == at::kFloat) { 8 | return CUDNN_DATA_FLOAT; 9 | } else if (tensor.scalar_type() == at::kDouble) { 10 | return CUDNN_DATA_DOUBLE; 11 | } else if (tensor.scalar_type() == at::kHalf) { 12 | return CUDNN_DATA_HALF; 13 | } 14 | std::string msg("getCudnnDataType() not supported for "); 15 | msg += toString(tensor.scalar_type()); 16 | throw std::runtime_error(msg); 17 | } 18 | 19 | int64_t cudnn_version() { 20 | return CUDNN_VERSION; 21 | } 22 | 23 | }} 24 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/cuda/nhwc/Types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace at { namespace native { 7 | 8 | cudnnDataType_t getCudnnDataType(const at::Tensor& tensor); 9 | 10 | int64_t cudnn_version(); 11 | 12 | }} 13 | 14 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/cuda/nhwc/UpSample.cuh: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | namespace at { 8 | namespace native { 9 | 10 | /* TODO: move this to a common place */ 11 | template 12 | __device__ inline scalar_t min(scalar_t a, scalar_t b) { 13 | return a < b ? a : b; 14 | } 15 | 16 | template 17 | __device__ inline scalar_t max(scalar_t a, scalar_t b) { 18 | return a > b ? a : b; 19 | } 20 | 21 | 22 | static inline void upsample_2d_shape_check_nhwc( 23 | const Tensor& input, 24 | const Tensor& grad_output, 25 | int nbatch, 26 | int nchannels, 27 | int input_height, 28 | int input_width, 29 | int output_height, 30 | int output_width) { 31 | TORCH_CHECK( 32 | input_height > 0 && input_width > 0 && output_height > 0 && 33 | output_width > 0, 34 | "input and output sizes should be greater than 0," 35 | " but got input (H: ", 36 | input_height, 37 | ", W: ", 38 | input_width, 39 | ") output (H: ", 40 | output_height, 41 | ", W: ", 42 | output_width, 43 | ")"); 44 | 45 | if (input.defined()) { 46 | TORCH_CHECK( 47 | input.numel() != 0 && input.dim() == 4, 48 | "non-empty 4D input tensor expected but got a tensor with sizes ", 49 | input.sizes()); 50 | } else if (grad_output.defined()) { 51 | check_dim_size(grad_output, 4, 0, nbatch); 52 | check_dim_size(grad_output, 4, 1, output_height); 53 | check_dim_size(grad_output, 4, 2, output_width); 54 | check_dim_size(grad_output, 4, 3, nchannels); 55 | } 56 | } 57 | 58 | __device__ __forceinline__ static int nearest_neighbor_compute_source_index( 59 | const float scale, 60 | int dst_index, 61 | int input_size) { 62 | const int src_index = 63 | min(static_cast(floorf(dst_index * scale)), input_size - 1); 64 | return src_index; 65 | } 66 | 67 | 68 | } // namespace native 69 | } // namespace at 70 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/cuda/nhwc/transforms.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | 18 | ******************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "THC/THC.h" 27 | #include "torch/torch.h" 28 | #include 29 | #include "Descriptors.h" 30 | //#include 31 | #include "Types.h" 32 | #include 33 | #include "ParamsHash.h" 34 | 35 | #include 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | namespace at { namespace native { namespace nhwc { 46 | 47 | at::Tensor cudnnNhwcToNchw(const at::Tensor& input) { 48 | 49 | int N = input.size(0); 50 | int C = input.size(3); 51 | int H = input.size(1); 52 | int W = input.size(2); 53 | at::Tensor output = at::empty({N,C,H,W}, input.options()); 54 | auto handle = getCudnnHandle(); 55 | auto dataType = getCudnnDataType(input); 56 | at::native::nhwc::TensorDescriptor in_desc; 57 | at::native::nchw::TensorDescriptor out_desc; 58 | in_desc.set(input); 59 | out_desc.set(output); 60 | float alpha=1.0f; 61 | float beta=0.0f; 62 | cudnnTransformTensor(handle, &alpha, in_desc.desc(), input.data_ptr(), &beta, out_desc.desc(), output.data_ptr()); 63 | return output; 64 | } 65 | 66 | at::Tensor cudnnNchwToNhwc(const at::Tensor& input) { 67 | 68 | int N = input.size(0); 69 | int C = input.size(1); 70 | int H = input.size(2); 71 | int W = input.size(3); 72 | at::Tensor output = at::empty({N,H,W,C}, input.options()); 73 | auto handle = getCudnnHandle(); 74 | auto dataType = getCudnnDataType(input); 75 | at::native::nchw::TensorDescriptor in_desc; 76 | at::native::nhwc::TensorDescriptor out_desc; 77 | in_desc.set(input); 78 | out_desc.set(output); 79 | float alpha=1.0f; 80 | float beta=0.0f; 81 | cudnnTransformTensor(handle, &alpha, in_desc.desc(), input.data_ptr(), &beta, out_desc.desc(), output.data_ptr()); 82 | return output; 83 | } 84 | }}} 85 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/cuda/rpn_generate_proposals.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | namespace rpn { 25 | /** 26 | * Generate boxes associated to topN pre-NMS scores 27 | */ 28 | std::vector GeneratePreNMSUprightBoxes( 29 | const int num_images, 30 | const int A, 31 | const int H, 32 | const int W, 33 | at::Tensor& sorted_indices, // topK sorted pre_nms_topn indices 34 | at::Tensor& sorted_scores, // topK sorted pre_nms_topn scores [N, A, H, W] 35 | at::Tensor& bbox_deltas, // [N, A*4, H, W] (full, unsorted / sliced) 36 | at::Tensor& anchors, // input (full, unsorted, unsliced) 37 | at::Tensor& image_shapes, // (h, w) of images 38 | const int pre_nms_nboxes, 39 | const int rpn_min_size, 40 | const float bbox_xform_clip_default, 41 | const bool correct_transform_coords); 42 | } // namespace rpn 43 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/generate_mask_targets.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | #include "cpu/vision.h" 19 | #ifndef _generate_mask_targets_h_ 20 | #define _generate_mask_targets_h_ 21 | 22 | at::Tensor generate_mask_targets( at::Tensor dense_vector, const std::vector> polygons, const at::Tensor anchors, const int mask_size){ 23 | at::Tensor result = generate_mask_targets_cuda(dense_vector, polygons,anchors, mask_size); 24 | return result; 25 | } 26 | 27 | #endif 28 | 29 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/match_proposals.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | #include "cuda/vision.h" 19 | #ifndef _match_proposals_h_ 20 | #define _match_proposals_h_ 21 | 22 | 23 | at::Tensor match_proposals( at::Tensor match_quality_matrix, bool allow_low_quality_matches, float low_th, float high_th){ 24 | at::Tensor result = match_proposals_cuda( match_quality_matrix, allow_low_quality_matches, low_th, high_th); 25 | return result; 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/nms.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | 18 | ******************************************************************************/ 19 | #pragma once 20 | #include "cpu/vision.h" 21 | 22 | #ifdef WITH_CUDA 23 | #include "cuda/vision.h" 24 | #endif 25 | 26 | 27 | at::Tensor nms(const at::Tensor& dets, 28 | const at::Tensor& scores, 29 | const float threshold) { 30 | 31 | if (dets.is_cuda()) { 32 | #ifdef WITH_CUDA 33 | // TODO raise error if not compiled with CUDA 34 | if (dets.numel() == 0) 35 | return at::empty({0}, dets.options().dtype(at::kLong).device(at::kCPU)); 36 | auto b = at::cat({dets, scores.unsqueeze(1)}, 1); 37 | return nms_cuda(b, threshold); 38 | #else 39 | AT_ERROR("Not compiled with GPU support"); 40 | #endif 41 | } 42 | 43 | at::Tensor result = nms_cpu(dets, scores, threshold); 44 | return result; 45 | } 46 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/nms_batched.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | #include "cuda/vision.h" 19 | #ifndef _nms_batched_h_ 20 | #define _nms_batched_h_ 21 | 22 | // initial_pos_mask is the initial positive masks for boxes, 1 if it is kept and 0 otherwise 23 | at::Tensor nms_batched(const at::Tensor boxes_cat, 24 | const std::vector n_boxes_vec, 25 | const at::Tensor n_boxes, const at::Tensor initial_pos_mask, 26 | const float nms_overlap_thresh){ 27 | at::Tensor result = nms_batched_cuda(boxes_cat, 28 | n_boxes_vec, 29 | n_boxes, initial_pos_mask, 30 | nms_overlap_thresh); 31 | return result; 32 | 33 | } 34 | 35 | #endif 36 | 37 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/rpn_generate_proposals_batched.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "cuda/vision.h" 4 | #ifndef _rpn_batched_h_ 5 | #define _rpn_batched_h_ 6 | 7 | 8 | std::vector GeneratePreNMSUprightBoxesBatched( 9 | const int num_images, 10 | const int A, 11 | const int K_max, 12 | const int max_anchors, 13 | at::Tensor& hw_array, 14 | at::Tensor& num_anchors_per_level, 15 | at::Tensor& sorted_indices, // topK sorted pre_nms_topn indices 16 | at::Tensor& sorted_scores, // topK sorted pre_nms_topn scores [N, A, H, W] 17 | at::Tensor& bbox_deltas, // [N, A*4, H, W] (full, unsorted / sliced) 18 | at::Tensor& anchors, // input (full, unsorted, unsliced) 19 | at::Tensor& image_shapes, // (h, w) of images 20 | const int pre_nms_nboxes, 21 | const int rpn_min_size, 22 | const float bbox_xform_clip_default, 23 | const bool correct_transform_coords){ 24 | std::vector result = rpn::GeneratePreNMSUprightBoxesBatched_cuda(num_images,A,K_max,max_anchors,hw_array, \ 25 | num_anchors_per_level, sorted_indices,sorted_scores,bbox_deltas,anchors,image_shapes,pre_nms_nboxes, \ 26 | rpn_min_size, bbox_xform_clip_default,correct_transform_coords); 27 | return result; 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/smcv_utils/vision.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | // Copyright (c) 2018-2019 NVIDIA CORPORATION. All rights reserved. 3 | #include "nms.h" 4 | #include "ROIAlign.h" 5 | #include "ROIPool.h" 6 | #include "SigmoidFocalLoss.h" 7 | #include "generate_mask_targets.h" 8 | #include "box_iou.h" 9 | #include "box_encode.h" 10 | #include "match_proposals.h" 11 | #include "nms_batched.h" 12 | #include "anchor_generator.h" 13 | #include "rpn_generate_proposals_batched.h" 14 | #ifdef WITH_CUDA 15 | #include "cuda/rpn_generate_proposals.h" 16 | //#include "cuda/rpn_generate_proposals_batched.h" 17 | #endif 18 | 19 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 20 | m.def("nms", &nms, "non-maximum suppression"); 21 | m.def("roi_align_forward", &ROIAlign_forward, "ROIAlign_forward"); 22 | m.def("roi_align_backward", &ROIAlign_backward, "ROIAlign_backward"); 23 | m.def("roi_pool_forward", &ROIPool_forward, "ROIPool_forward"); 24 | m.def("roi_pool_backward", &ROIPool_backward, "ROIPool_backward"); 25 | m.def("sigmoid_focalloss_forward", &SigmoidFocalLoss_forward, "SigmoidFocalLoss_forward"); 26 | m.def("sigmoid_focalloss_backward", &SigmoidFocalLoss_backward, "SigmoidFocalLoss_backward"); 27 | m.def("generate_mask_targets", &generate_mask_targets, "generate_mask_targets"); 28 | m.def("box_iou", &box_iou, "box_iou"); 29 | m.def("box_encode", &box_encode, "box_encode"); 30 | m.def("match_proposals", &match_proposals, "match_proposals"); 31 | 32 | m.def("nms_batched", &nms_batched, "nms_batched"); 33 | m.def("anchor_generator", &anchor_generator, "anchor_generator"); 34 | #ifdef WITH_CUDA 35 | m.def("GeneratePreNMSUprightBoxesBatched", &GeneratePreNMSUprightBoxesBatched, "RPN Proposal Generation Batched"); 36 | #endif 37 | } 38 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/tests/test_anchors.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from collections import OrderedDict 3 | from smcv_utils import _C 4 | 5 | # Anchor generator tests 6 | cell_anchors = OrderedDict() 7 | cell_anchors[0] = torch.tensor([[-22., -10., 25., 13.], [-14., -14., 17., 17.], [-10., -22., 13., 25.]]).to('cuda') 8 | cell_anchors[1] = torch.tensor([[-40., -20., 47., 27.], [-28., -28., 35., 35.], [-20., -44., 27., 51.]]).to('cuda') 9 | cell_anchors[2] = torch.tensor([[-84., -40., 99., 55.], [-56., -56., 71., 71.], [-36., -80., 51., 95.]]).to('cuda') 10 | cell_anchors[3] = torch.tensor([[-164., -72., 195., 103.], [-112., -112., 143., 143.], [ -76., -168., 107., 199.]]).to('cuda') 11 | cell_anchors[4] = torch.tensor([[-332., -152., 395., 215.], [-224., -224., 287., 287.], [-148., -328., 211., 391.]]).to('cuda') 12 | 13 | straddle_thresh = 0 14 | 15 | feature_sizes = [[200, 304], [100, 152], [50, 76], [25, 38], [13, 19]] 16 | 17 | image_sizes = torch.tensor([[1199, 800], 18 | [1132, 800], 19 | [1196, 800], 20 | [1066, 800], 21 | [1066, 800], 22 | [1003, 800], 23 | [1066, 800], 24 | [1199, 800]], dtype=torch.int32).to('cuda') 25 | 26 | strides = (4, 8, 16, 32, 64) 27 | 28 | anchor_sums = [367353600, 91838400., 22959600., 5739900., 1516086.] 29 | inds_inside_sums = [112304, 26398, 5698, 1004, 90] 30 | 31 | def test_anchor_generator(): 32 | for cell_anchor, feature_size, image_size, stride, anchor_sum, ind_sum \ 33 | in zip(cell_anchors, feature_sizes, image_sizes, strides, anchor_sums, inds_inside_sums): 34 | anchors, inds_inside = _C.anchor_generator(*image_size, 35 | feature_size, 36 | cell_anchors[cell_anchor], 37 | stride, straddle_thresh) 38 | assert anchors.sum()==anchor_sum 39 | assert inds_inside.sum()==ind_sum 40 | 41 | if __name__=='__main__': 42 | test_anchor_generator() 43 | -------------------------------------------------------------------------------- /pytorch/cuda_utils/tests/test_roi_align.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from smcv_utils import _C 3 | 4 | mock_features = torch.rand([4, 256, 200, 304]).to('cuda') 5 | 6 | mock_rois = torch.tensor([[0.0000e+00, 1.8608e+02, 1.4605e+02, 2.9531e+02, 2.5412e+02], 7 | [0.0000e+00, 3.5388e+02, 1.5888e+02, 3.9574e+02, 2.7582e+02], 8 | [1.0000e+00, 6.9182e+02, 3.7617e+02, 8.1049e+02, 4.4675e+02], 9 | [1.0000e+00, 8.0659e+02, 6.1406e+02, 8.1942e+02, 6.3665e+02], 10 | [1.0000e+00, 6.7051e+02, 4.1811e+02, 8.7968e+02, 5.1437e+02], 11 | [2.0000e+00, 5.1053e+02, 7.0108e+01, 9.7426e+02, 7.8913e+02], 12 | [2.0000e+00, 4.5144e+02, 2.1227e+01, 7.4031e+02, 6.1709e+02], 13 | [3.0000e+00, 1.6321e+02, 5.0146e+02, 5.7366e+02, 7.4601e+02]]).to('cuda') 14 | 15 | spatial_scale = .25 16 | sampling_ratio = 2 17 | output_size = (7, 7) 18 | NHWC = False 19 | 20 | def test_roi_align(): 21 | extracted_features = _C.roi_align_forward(mock_features, mock_rois, spatial_scale, *output_size, sampling_ratio, NHWC) 22 | assert tuple(extracted_features.shape)==(8, 256, 7, 7) 23 | 24 | if __name__=='__main__': 25 | test_roi_align() 26 | -------------------------------------------------------------------------------- /pytorch/launch_ddp.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import subprocess 4 | import json 5 | from utils import get_training_world, unarchive_data 6 | from datetime import datetime 7 | 8 | if __name__ == "__main__": 9 | start_time = datetime.now() 10 | print('Starting training...') 11 | # print("Training started at {}".format(start_time)) 12 | world = get_training_world() 13 | sm_args = json.loads(os.environ["SM_HPS"]) 14 | # if "unarchive" in sm_args: 15 | # data_dir = sm_args.pop("unarchive") 16 | # unarchive_data(data_dir) 17 | # print("Unarchive completed in {}".format(datetime.now() - start_time)) 18 | args = [f"--{key} {value}" for key, value in sm_args.items()] 19 | launch_config = ["python -m torch.distributed.launch", 20 | "--nnodes", str(world['number_of_machines']), 21 | "--node_rank", str(world['machine_rank']), 22 | "--nproc_per_node", str(world['number_of_processes']), 23 | "--master_addr", world['master_addr'], 24 | "--master_port", world['master_port'], 25 | "/opt/ml/code/train.py"] 26 | launch_config.extend(args) 27 | joint_cmd = " ".join(str(x) for x in launch_config) 28 | print("Following command will be executed: \n", joint_cmd) 29 | 30 | process = subprocess.Popen(joint_cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, shell=True) 31 | 32 | while True: 33 | output = process.stdout.readline() 34 | 35 | if process.poll() is not None: 36 | break 37 | if output: 38 | print(output.decode("utf-8").strip()) 39 | rc = process.poll() 40 | 41 | if process.returncode != 0: 42 | raise subprocess.CalledProcessError(returncode=process.returncode, cmd=joint_cmd) 43 | 44 | sys.exit(process.returncode) 45 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/pytorch/sagemakercv/__init__.py -------------------------------------------------------------------------------- /pytorch/sagemakercv/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/pytorch/sagemakercv/core/__init__.py -------------------------------------------------------------------------------- /pytorch/sagemakercv/core/structures/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/pytorch/sagemakercv/core/structures/__init__.py -------------------------------------------------------------------------------- /pytorch/sagemakercv/core/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | """ 3 | Miscellaneous utility functions 4 | """ 5 | 6 | import torch 7 | 8 | 9 | def cat(tensors, dim=0): 10 | """ 11 | Efficient version of torch.cat that avoids a copy if there is only a single element in a list 12 | """ 13 | assert isinstance(tensors, (list, tuple)) 14 | if len(tensors) == 1: 15 | return tensors[0] 16 | return torch.cat(tensors, dim) 17 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/data/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | from .build import make_data_loader, Prefetcher 3 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/data/collate_batch.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | from sagemakercv.core.structures.image_list import to_image_list 3 | 4 | 5 | class BatchCollator(object): 6 | """ 7 | From a list of samples from the dataset, 8 | returns the batched images and targets. 9 | This should be passed to the DataLoader 10 | """ 11 | 12 | def __init__(self, size_divisible=0, shapes=None, passthrough=False): 13 | self.size_divisible = size_divisible 14 | self.shapes = shapes 15 | print(f'shapes={shapes}') 16 | self.passthrough = passthrough 17 | print(f'passthrough={passthrough}') 18 | 19 | def __call__(self, batch): 20 | transposed_batch = list(zip(*batch)) 21 | if self.passthrough: 22 | images = transposed_batch[0] 23 | targets = transposed_batch[1] 24 | img_ids = transposed_batch[2] 25 | else: 26 | images = to_image_list(transposed_batch[0], self.size_divisible, self.shapes) 27 | targets = transposed_batch[1] 28 | img_ids = transposed_batch[2] 29 | return images, targets, img_ids 30 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/data/datasets/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | from .coco import COCODataset, S3COCODataset 3 | from .voc import PascalVOCDataset 4 | from .concat_dataset import ConcatDataset 5 | 6 | __all__ = ["COCODataset", "S3COCODataset", "ConcatDataset", "PascalVOCDataset"] 7 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/data/datasets/concat_dataset.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | import bisect 3 | 4 | from torch.utils.data.dataset import ConcatDataset as _ConcatDataset 5 | 6 | 7 | class ConcatDataset(_ConcatDataset): 8 | """ 9 | Same as torch.utils.data.dataset.ConcatDataset, but exposes an extra 10 | method for querying the sizes of the image 11 | """ 12 | 13 | def get_idxs(self, idx): 14 | dataset_idx = bisect.bisect_right(self.cumulative_sizes, idx) 15 | if dataset_idx == 0: 16 | sample_idx = idx 17 | else: 18 | sample_idx = idx - self.cumulative_sizes[dataset_idx - 1] 19 | return dataset_idx, sample_idx 20 | 21 | def get_img_info(self, idx): 22 | dataset_idx, sample_idx = self.get_idxs(idx) 23 | return self.datasets[dataset_idx].get_img_info(sample_idx) 24 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/data/datasets/evaluation/__init__.py: -------------------------------------------------------------------------------- 1 | from sagemakercv.data import datasets 2 | 3 | from .coco import coco_evaluation 4 | from .voc import voc_evaluation 5 | 6 | 7 | def evaluate(dataset, predictions, output_folder, **kwargs): 8 | """evaluate dataset using different methods based on dataset type. 9 | Args: 10 | dataset: Dataset object 11 | predictions(list[BoxList]): each item in the list represents the 12 | prediction results for one image. 13 | output_folder: output folder, to save evaluation files or results. 14 | **kwargs: other args. 15 | Returns: 16 | evaluation result 17 | """ 18 | args = dict( 19 | dataset=dataset, predictions=predictions, output_folder=output_folder, **kwargs 20 | ) 21 | if isinstance(dataset, datasets.COCODataset): 22 | return coco_evaluation(**args) 23 | if isinstance(dataset, datasets.S3COCODataset): 24 | return coco_evaluation(**args) 25 | elif isinstance(dataset, datasets.PascalVOCDataset): 26 | return voc_evaluation(**args) 27 | else: 28 | dataset_name = dataset.__class__.__name__ 29 | raise NotImplementedError("Unsupported dataset type {}.".format(dataset_name)) 30 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/data/datasets/evaluation/coco/__init__.py: -------------------------------------------------------------------------------- 1 | from .coco_eval import do_coco_evaluation 2 | 3 | 4 | def coco_evaluation( 5 | dataset, 6 | predictions, 7 | output_folder, 8 | box_only, 9 | iou_types, 10 | expected_results, 11 | expected_results_sigma_tol, 12 | ): 13 | return do_coco_evaluation( 14 | dataset=dataset, 15 | predictions=predictions, 16 | box_only=box_only, 17 | output_folder=output_folder, 18 | iou_types=iou_types, 19 | expected_results=expected_results, 20 | expected_results_sigma_tol=expected_results_sigma_tol, 21 | ) 22 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/data/datasets/evaluation/coco/coco_labels.py: -------------------------------------------------------------------------------- 1 | coco_categories = { 2 | 0: 'unlabeled', 3 | 1: 'person', 4 | 2: 'bicycle', 5 | 3: 'car', 6 | 4: 'motorcycle', 7 | 5: 'airplane', 8 | 6: 'bus', 9 | 7: 'train', 10 | 8: 'truck', 11 | 9: 'boat', 12 | 10: 'traffic light', 13 | 11: 'fire hydrant', 14 | 12: 'stop sign', 15 | 13: 'parking meter', 16 | 14: 'bench', 17 | 15: 'bird', 18 | 16: 'cat', 19 | 17: 'dog', 20 | 18: 'horse', 21 | 19: 'sheep', 22 | 20: 'cow', 23 | 21: 'elephant', 24 | 22: 'bear', 25 | 23: 'zebra', 26 | 24: 'giraffe', 27 | 25: 'backpack', 28 | 26: 'umbrella', 29 | 27: 'handbag', 30 | 28: 'tie', 31 | 29: 'suitcase', 32 | 30: 'frisbee', 33 | 31: 'skis', 34 | 32: 'snowboard', 35 | 33: 'sports ball', 36 | 34: 'kite', 37 | 35: 'baseball bat', 38 | 36: 'baseball glove', 39 | 37: 'skateboard', 40 | 38: 'surfboard', 41 | 39: 'tennis racket', 42 | 40: 'bottle', 43 | 41: 'wine glass', 44 | 42: 'cup', 45 | 43: 'fork', 46 | 44: 'knife', 47 | 45: 'spoon', 48 | 46: 'bowl', 49 | 47: 'banana', 50 | 48: 'apple', 51 | 49: 'sandwich', 52 | 50: 'orange', 53 | 51: 'broccoli', 54 | 52: 'carrot', 55 | 53: 'hot dog', 56 | 54: 'pizza', 57 | 55: 'donut', 58 | 56: 'cake', 59 | 57: 'chair', 60 | 58: 'couch', 61 | 59: 'potted plant', 62 | 60: 'bed', 63 | 61: 'dining table', 64 | 62: 'toilet', 65 | 63: 'tv', 66 | 64: 'laptop', 67 | 65: 'mouse', 68 | 66: 'remote', 69 | 67: 'keyboard', 70 | 68: 'cell phone', 71 | 69: 'microwave', 72 | 70: 'oven', 73 | 71: 'toaster', 74 | 72: 'sink', 75 | 73: 'refrigerator', 76 | 74: 'book', 77 | 75: 'clock', 78 | 76: 'vase', 79 | 77: 'scissors', 80 | 78: 'teddy bear', 81 | 79: 'hair drier', 82 | 80: 'toothbrush'} -------------------------------------------------------------------------------- /pytorch/sagemakercv/data/datasets/evaluation/voc/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from .voc_eval import do_voc_evaluation 4 | 5 | 6 | def voc_evaluation(dataset, predictions, output_folder, box_only, **_): 7 | logger = logging.getLogger("maskrcnn_benchmark.inference") 8 | if box_only: 9 | logger.warning("voc evaluation doesn't support box_only, ignored.") 10 | logger.info("performing voc evaluation, ignored iou_types.") 11 | return do_voc_evaluation( 12 | dataset=dataset, 13 | predictions=predictions, 14 | output_folder=output_folder, 15 | logger=logger, 16 | ) 17 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/data/datasets/list_dataset.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | """ 3 | Simple dataset class that wraps a list of path names 4 | """ 5 | 6 | from PIL import Image 7 | 8 | from sagemakercv.core.structures.bounding_box import BoxList 9 | 10 | 11 | class ListDataset(object): 12 | def __init__(self, image_lists, transforms=None): 13 | self.image_lists = image_lists 14 | self.transforms = transforms 15 | 16 | def __getitem__(self, item): 17 | img = Image.open(self.image_lists[item]).convert("RGB") 18 | 19 | # dummy target 20 | w, h = img.size 21 | target = BoxList([[0, 0, w, h]], img.size, mode="xyxy") 22 | 23 | if self.transforms is not None: 24 | img, target = self.transforms(img, target) 25 | 26 | return img, target 27 | 28 | def __len__(self): 29 | return len(self.image_lists) 30 | 31 | def get_img_info(self, item): 32 | """ 33 | Return the image dimensions for the image, without 34 | loading and pre-processing it 35 | """ 36 | pass 37 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/data/samplers/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | from .distributed import DistributedSampler 3 | from .grouped_batch_sampler import GroupedBatchSampler 4 | from .iteration_based_batch_sampler import IterationBasedBatchSampler 5 | 6 | __all__ = ["DistributedSampler", "GroupedBatchSampler", "IterationBasedBatchSampler"] 7 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/data/samplers/iteration_based_batch_sampler.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | # Copyright (c) 2018-2019 NVIDIA CORPORATION. All rights reserved. 3 | from torch.utils.data.sampler import BatchSampler 4 | 5 | 6 | class IterationBasedBatchSampler(BatchSampler): 7 | """ 8 | Wraps a BatchSampler, resampling from it until 9 | a specified number of iterations have been sampled 10 | """ 11 | 12 | def __init__(self, batch_sampler, num_iterations, start_iter=0, random_number_generator=None): 13 | self.batch_sampler = batch_sampler 14 | self.num_iterations = num_iterations 15 | self.start_iter = start_iter 16 | self.random_number_generator = random_number_generator 17 | 18 | def __iter__(self): 19 | iteration = self.start_iter 20 | while iteration <= self.num_iterations: 21 | # if the underlying sampler has a set_epoch method, like 22 | # DistributedSampler, used for making each process see 23 | # a different split of the dataset, then set it 24 | if hasattr(self.batch_sampler.sampler, "set_epoch"): 25 | if self.random_number_generator is not None: 26 | iteration_seed = self.random_number_generator.randint(0, 2 ** 32 - 1) 27 | self.batch_sampler.sampler.set_epoch(iteration_seed) 28 | else: 29 | self.batch_sampler.sampler.set_epoch(iteration) 30 | for batch in self.batch_sampler: 31 | iteration += 1 32 | if iteration > self.num_iterations: 33 | break 34 | yield batch 35 | 36 | def __len__(self): 37 | return self.num_iterations 38 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/data/transforms/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | from .transforms import Compose 3 | from .transforms import Resize 4 | from .transforms import RandomHorizontalFlip 5 | from .transforms import ToTensor 6 | from .transforms import Normalize 7 | 8 | from .build import build_transforms 9 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/data/transforms/build.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | from . import transforms as T 3 | 4 | 5 | def build_transforms(cfg, is_train=True, is_fp16=True, is_hybrid=False): 6 | if is_train: 7 | min_size = cfg.INPUT.MIN_SIZE_TRAIN 8 | max_size = cfg.INPUT.MAX_SIZE_TRAIN 9 | flip_prob = 0.5 # cfg.INPUT.FLIP_PROB_TRAIN 10 | else: 11 | min_size = cfg.INPUT.MIN_SIZE_TEST 12 | max_size = cfg.INPUT.MAX_SIZE_TEST 13 | flip_prob = 0 14 | 15 | to_bgr255 = cfg.INPUT.TO_BGR255 16 | normalize_transform = T.Normalize( 17 | mean=cfg.INPUT.PIXEL_MEAN, std=cfg.INPUT.PIXEL_STD, to_bgr255=to_bgr255 18 | ) 19 | 20 | if is_hybrid: 21 | ops = [ 22 | T.Resize(min_size, max_size), 23 | T.RandomHorizontalFlip(flip_prob), 24 | T.ToHalf(), 25 | normalize_transform 26 | ] 27 | else: 28 | ops = [ 29 | T.Resize(min_size, max_size), 30 | T.RandomHorizontalFlip(flip_prob), 31 | T.ToTensor(), 32 | normalize_transform 33 | ] 34 | if is_fp16: 35 | ops.append(T.ToHalf()) 36 | transform = T.Compose(ops) 37 | 38 | return transform 39 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/detection/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/pytorch/sagemakercv/detection/__init__.py -------------------------------------------------------------------------------- /pytorch/sagemakercv/detection/backbone/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | from .backbone import build_backbone 3 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/detection/detector/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | from .detectors import build_detection_model 3 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/detection/detector/detectors.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | from .generalized_rcnn import GeneralizedRCNN 3 | 4 | 5 | _DETECTION_META_ARCHITECTURES = {"GeneralizedRCNN": GeneralizedRCNN} 6 | 7 | 8 | def build_detection_model(cfg): 9 | meta_arch = _DETECTION_META_ARCHITECTURES[cfg.MODEL.META_ARCHITECTURE] 10 | return meta_arch(cfg) 11 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/detection/registry.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | 3 | from sagemakercv.utils.registry import Registry 4 | 5 | BACKBONES = Registry() 6 | ROI_BOX_FEATURE_EXTRACTORS = Registry() 7 | ROI_BOX_PREDICTOR = Registry() 8 | ROI_BOX_HEAD = Registry() 9 | RPN_HEADS = Registry() 10 | DENSE_HEADS = Registry() 11 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/detection/roi_heads/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/pytorch/sagemakercv/detection/roi_heads/__init__.py -------------------------------------------------------------------------------- /pytorch/sagemakercv/detection/roi_heads/box_head/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/pytorch/sagemakercv/detection/roi_heads/box_head/__init__.py -------------------------------------------------------------------------------- /pytorch/sagemakercv/detection/roi_heads/keypoint_head/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/pytorch/sagemakercv/detection/roi_heads/keypoint_head/__init__.py -------------------------------------------------------------------------------- /pytorch/sagemakercv/detection/roi_heads/keypoint_head/keypoint_head.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | from .roi_keypoint_feature_extractors import make_roi_keypoint_feature_extractor 4 | from .roi_keypoint_predictors import make_roi_keypoint_predictor 5 | from .inference import make_roi_keypoint_post_processor 6 | from .loss import make_roi_keypoint_loss_evaluator 7 | 8 | 9 | class ROIKeypointHead(torch.nn.Module): 10 | def __init__(self, cfg): 11 | super(ROIKeypointHead, self).__init__() 12 | self.cfg = cfg.clone() 13 | self.feature_extractor = make_roi_keypoint_feature_extractor(cfg) 14 | self.predictor = make_roi_keypoint_predictor(cfg) 15 | self.post_processor = make_roi_keypoint_post_processor(cfg) 16 | self.loss_evaluator = make_roi_keypoint_loss_evaluator(cfg) 17 | 18 | def forward(self, features, proposals, targets=None): 19 | """ 20 | Arguments: 21 | features (list[Tensor]): feature-maps from possibly several levels 22 | proposals (list[BoxList]): proposal boxes 23 | targets (list[BoxList], optional): the ground-truth targets. 24 | 25 | Returns: 26 | x (Tensor): the result of the feature extractor 27 | proposals (list[BoxList]): during training, the original proposals 28 | are returned. During testing, the predicted boxlists are returned 29 | with the `mask` field set 30 | losses (dict[Tensor]): During training, returns the losses for the 31 | head. During testing, returns an empty dict. 32 | """ 33 | if self.training: 34 | with torch.no_grad(): 35 | proposals = self.loss_evaluator.subsample(proposals, targets) 36 | 37 | x = self.feature_extractor(features, proposals) 38 | kp_logits = self.predictor(x) 39 | 40 | if not self.training: 41 | result = self.post_processor(kp_logits, proposals) 42 | return x, result, {} 43 | 44 | loss_kp = self.loss_evaluator(proposals.float(), kp_logits.float()) 45 | 46 | return x, proposals, dict(loss_kp=loss_kp) 47 | 48 | 49 | def build_roi_keypoint_head(cfg): 50 | return ROIKeypointHead(cfg) 51 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/detection/roi_heads/keypoint_head/roi_keypoint_feature_extractors.py: -------------------------------------------------------------------------------- 1 | from torch import nn 2 | from torch.nn import functional as F 3 | 4 | from sagemakercv.core.poolers import Pooler 5 | 6 | from sagemakercv.layers import Conv2d 7 | 8 | 9 | class KeypointRCNNFeatureExtractor(nn.Module): 10 | def __init__(self, cfg): 11 | super(KeypointRCNNFeatureExtractor, self).__init__() 12 | 13 | resolution = cfg.MODEL.ROI_KEYPOINT_HEAD.POOLER_RESOLUTION 14 | scales = cfg.MODEL.ROI_KEYPOINT_HEAD.POOLER_SCALES 15 | sampling_ratio = cfg.MODEL.ROI_KEYPOINT_HEAD.POOLER_SAMPLING_RATIO 16 | pooler = Pooler( 17 | output_size=(resolution, resolution), 18 | scales=scales, 19 | sampling_ratio=sampling_ratio, 20 | ) 21 | self.pooler = pooler 22 | 23 | input_features = cfg.MODEL.BACKBONE.OUT_CHANNELS 24 | layers = cfg.MODEL.ROI_KEYPOINT_HEAD.CONV_LAYERS 25 | next_feature = input_features 26 | self.blocks = [] 27 | for layer_idx, layer_features in enumerate(layers, 1): 28 | layer_name = "conv_fcn{}".format(layer_idx) 29 | module = Conv2d(next_feature, layer_features, 3, stride=1, padding=1) 30 | nn.init.kaiming_normal_(module.weight, mode="fan_out", nonlinearity="relu") 31 | nn.init.constant_(module.bias, 0) 32 | self.add_module(layer_name, module) 33 | next_feature = layer_features 34 | self.blocks.append(layer_name) 35 | 36 | def forward(self, x, proposals): 37 | x = self.pooler(x, proposals) 38 | for layer_name in self.blocks: 39 | x = F.relu(getattr(self, layer_name)(x)) 40 | return x 41 | 42 | 43 | _ROI_KEYPOINT_FEATURE_EXTRACTORS = { 44 | "KeypointRCNNFeatureExtractor": KeypointRCNNFeatureExtractor 45 | } 46 | 47 | 48 | def make_roi_keypoint_feature_extractor(cfg): 49 | func = _ROI_KEYPOINT_FEATURE_EXTRACTORS[ 50 | cfg.MODEL.ROI_KEYPOINT_HEAD.FEATURE_EXTRACTOR 51 | ] 52 | return func(cfg) 53 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/detection/roi_heads/keypoint_head/roi_keypoint_predictors.py: -------------------------------------------------------------------------------- 1 | from torch import nn 2 | from torch.nn import functional as F 3 | 4 | from sagemakercv import layers 5 | 6 | 7 | class KeypointRCNNPredictor(nn.Module): 8 | def __init__(self, cfg): 9 | super(KeypointRCNNPredictor, self).__init__() 10 | input_features = cfg.MODEL.ROI_KEYPOINT_HEAD.CONV_LAYERS[-1] 11 | num_keypoints = cfg.MODEL.ROI_KEYPOINT_HEAD.NUM_CLASSES 12 | deconv_kernel = 4 13 | self.kps_score_lowres = layers.ConvTranspose2d( 14 | input_features, 15 | num_keypoints, 16 | deconv_kernel, 17 | stride=2, 18 | padding=deconv_kernel // 2 - 1, 19 | ) 20 | nn.init.kaiming_normal_( 21 | self.kps_score_lowres.weight, mode="fan_out", nonlinearity="relu" 22 | ) 23 | nn.init.constant_(self.kps_score_lowres.bias, 0) 24 | self.up_scale = 2 25 | 26 | def forward(self, x): 27 | x = self.kps_score_lowres(x) 28 | x = layers.interpolate( 29 | x, scale_factor=self.up_scale, mode="bilinear", align_corners=False 30 | ) 31 | return x 32 | 33 | 34 | _ROI_KEYPOINT_PREDICTOR = {"KeypointRCNNPredictor": KeypointRCNNPredictor} 35 | 36 | 37 | def make_roi_keypoint_predictor(cfg): 38 | func = _ROI_KEYPOINT_PREDICTOR[cfg.MODEL.ROI_KEYPOINT_HEAD.PREDICTOR] 39 | return func(cfg) 40 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/detection/roi_heads/mask_head/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/pytorch/sagemakercv/detection/roi_heads/mask_head/__init__.py -------------------------------------------------------------------------------- /pytorch/sagemakercv/detection/roi_heads/mask_head/roi_mask_feature_extractors.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | # Copyright (c) 2018-2019 NVIDIA CORPORATION. All rights reserved. 3 | from torch import nn 4 | from torch.nn import functional as F 5 | 6 | from ..box_head.roi_box_feature_extractors import ResNet50Conv5ROIFeatureExtractor 7 | from sagemakercv.core.poolers import Pooler 8 | from sagemakercv.layers.make_layers import make_conv3x3 9 | from smcv_utils import _C 10 | from sagemakercv.layers.nhwc import nchw_to_nhwc_transform, nhwc_to_nchw_transform 11 | 12 | class MaskRCNNFPNFeatureExtractor(nn.Module): 13 | """ 14 | Heads for FPN for classification 15 | """ 16 | 17 | def __init__(self, cfg): 18 | """ 19 | Arguments: 20 | num_classes (int): number of output classes 21 | input_size (int): number of channels of the input once it's flattened 22 | representation_size (int): size of the intermediate representation 23 | """ 24 | super(MaskRCNNFPNFeatureExtractor, self).__init__() 25 | 26 | resolution = cfg.MODEL.ROI_MASK_HEAD.POOLER_RESOLUTION 27 | scales = cfg.MODEL.ROI_MASK_HEAD.POOLER_SCALES 28 | sampling_ratio = cfg.MODEL.ROI_MASK_HEAD.POOLER_SAMPLING_RATIO 29 | pooler = Pooler( 30 | output_size=(resolution, resolution), 31 | scales=scales, 32 | sampling_ratio=sampling_ratio, 33 | is_nhwc = cfg.OPT_LEVEL=="O4" 34 | ) 35 | input_size = cfg.MODEL.BACKBONE.OUT_CHANNELS 36 | self.pooler = pooler 37 | 38 | use_gn = cfg.MODEL.ROI_MASK_HEAD.USE_GN 39 | layers = cfg.MODEL.ROI_MASK_HEAD.CONV_LAYERS 40 | dilation = cfg.MODEL.ROI_MASK_HEAD.DILATION 41 | 42 | next_feature = input_size 43 | self.blocks = [] 44 | for layer_idx, layer_features in enumerate(layers, 1): 45 | layer_name = "mask_fcn{}".format(layer_idx) 46 | module = make_conv3x3(next_feature, layer_features, 47 | dilation=dilation, stride=1, use_gn=use_gn, nhwc=cfg.OPT_LEVEL=="O4" 48 | ) 49 | self.add_module(layer_name, module) 50 | next_feature = layer_features 51 | self.blocks.append(layer_name) 52 | self.nhwc = cfg.OPT_LEVEL=="O4" 53 | 54 | def forward(self, x, proposals): 55 | x = self.pooler(x, proposals) 56 | for layer_name in self.blocks: 57 | x = F.relu(getattr(self, layer_name)(x)) 58 | return x 59 | 60 | 61 | _ROI_MASK_FEATURE_EXTRACTORS = { 62 | "ResNet50Conv5ROIFeatureExtractor": ResNet50Conv5ROIFeatureExtractor, 63 | "MaskRCNNFPNFeatureExtractor": MaskRCNNFPNFeatureExtractor, 64 | } 65 | 66 | 67 | def make_roi_mask_feature_extractor(cfg): 68 | func = _ROI_MASK_FEATURE_EXTRACTORS[cfg.MODEL.ROI_MASK_HEAD.FEATURE_EXTRACTOR] 69 | return func(cfg) 70 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/detection/roi_heads/mask_head/roi_mask_predictors.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | # Copyright (c) 2018-2019 NVIDIA CORPORATION. All rights reserved. 3 | from torch import nn 4 | from torch.nn import functional as F 5 | 6 | from sagemakercv.layers import Conv2d 7 | from sagemakercv.layers import ConvTranspose2d 8 | from sagemakercv.layers.nhwc.misc import Conv2d_NHWC 9 | from sagemakercv.layers.nhwc import ConvTranspose2d_NHWC 10 | from sagemakercv.layers.nhwc import nhwc_to_nchw_transform, nchw_to_nhwc_transform 11 | from sagemakercv.layers.nhwc import init 12 | 13 | class MaskRCNNC4Predictor(nn.Module): 14 | def __init__(self, cfg): 15 | super(MaskRCNNC4Predictor, self).__init__() 16 | num_classes = cfg.MODEL.ROI_BOX_HEAD.NUM_CLASSES 17 | dim_reduced = cfg.MODEL.ROI_MASK_HEAD.CONV_LAYERS[-1] 18 | 19 | if cfg.MODEL.ROI_HEADS.USE_FPN: 20 | num_inputs = dim_reduced 21 | else: 22 | stage_index = 4 23 | stage2_relative_factor = 2 ** (stage_index - 1) 24 | res2_out_channels = cfg.MODEL.RESNETS.RES2_OUT_CHANNELS 25 | num_inputs = res2_out_channels * stage2_relative_factor 26 | self.nhwc = cfg.OPT_LEVEL=="O4" 27 | conv = Conv2d_NHWC if self.nhwc else Conv2d 28 | conv_transpose = ConvTranspose2d_NHWC if self.nhwc else ConvTranspose2d 29 | self.conv5_mask = conv_transpose(num_inputs, dim_reduced, 2, 2, 0) 30 | self.mask_fcn_logits = conv(dim_reduced, num_classes, 1, 1, 0) 31 | 32 | for name, param in self.named_parameters(): 33 | if "bias" in name: 34 | nn.init.constant_(param, 0) 35 | elif "weight" in name: 36 | # Caffe2 implementation uses MSRAFill, which in fact 37 | # corresponds to kaiming_normal_ in PyTorch 38 | #is_layer_nhwc = self.nhwc and 'conv5' in name 39 | init.kaiming_normal_(param, mode="fan_out", nonlinearity="relu", nhwc=self.nhwc) 40 | 41 | def forward(self, x): 42 | #TODO: this transpose may be needed for modularity of Detectron repo 43 | # if self.nhwc: 44 | # x = nchw_to_nhwc_transform(x) 45 | x = F.relu(self.conv5_mask(x)) 46 | logits = self.mask_fcn_logits(x) 47 | if self.nhwc: 48 | logits = nhwc_to_nchw_transform(logits) 49 | return logits 50 | 51 | 52 | _ROI_MASK_PREDICTOR = {"MaskRCNNC4Predictor": MaskRCNNC4Predictor} 53 | 54 | 55 | def make_roi_mask_predictor(cfg): 56 | func = _ROI_MASK_PREDICTOR[cfg.MODEL.ROI_MASK_HEAD.PREDICTOR] 57 | return func(cfg) 58 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/detection/rpn/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | # from .rpn import build_rpn 3 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/detection/rpn/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | """ 3 | Utility functions minipulating the prediction layers 4 | """ 5 | 6 | from sagemakercv.core.utils import cat 7 | 8 | import torch 9 | 10 | def permute_and_flatten(layer, N, A, C, H, W): 11 | layer = layer.view(N, -1, C, H, W) 12 | layer = layer.permute(0, 3, 4, 1, 2) 13 | layer = layer.reshape(N, -1, C) 14 | return layer 15 | 16 | 17 | def concat_box_prediction_layers(box_cls, box_regression): 18 | box_cls_flattened = [] 19 | box_regression_flattened = [] 20 | # for each feature level, permute the outputs to make them be in the 21 | # same format as the labels. Note that the labels are computed for 22 | # all feature levels concatenated, so we keep the same representation 23 | # for the objectness and the box_regression 24 | for box_cls_per_level, box_regression_per_level in zip( 25 | box_cls, box_regression 26 | ): 27 | N, AxC, H, W = box_cls_per_level.shape 28 | Ax4 = box_regression_per_level.shape[1] 29 | A = Ax4 // 4 30 | C = AxC // A 31 | box_cls_per_level = permute_and_flatten( 32 | box_cls_per_level, N, A, C, H, W 33 | ) 34 | box_cls_flattened.append(box_cls_per_level) 35 | 36 | box_regression_per_level = permute_and_flatten( 37 | box_regression_per_level, N, A, 4, H, W 38 | ) 39 | box_regression_flattened.append(box_regression_per_level) 40 | # concatenate on the first dimension (representing the feature levels), to 41 | # take into account the way the labels were generated (with all feature maps 42 | # being concatenated as well) 43 | box_cls = cat(box_cls_flattened, dim=1).reshape(-1, C) 44 | box_regression = cat(box_regression_flattened, dim=1).reshape(-1, 4) 45 | return box_cls, box_regression 46 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/inference/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/pytorch/sagemakercv/inference/__init__.py -------------------------------------------------------------------------------- /pytorch/sagemakercv/inference/tester.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | # Copyright (c) 2018-2019 NVIDIA CORPORATION. All rights reserved. 3 | import torch 4 | 5 | import os 6 | 7 | #from mlperf_logging.mllog import constants 8 | 9 | from sagemakercv.data.build import make_data_loader 10 | from .inference import inference 11 | from sagemakercv.utils.miscellaneous import mkdir 12 | #from sagemakercv.utils.mlperf_logger import log_event 13 | from sagemakercv.utils.comm import synchronize 14 | 15 | _first_test = True 16 | 17 | def test(cfg, model, distributed): 18 | #if distributed: 19 | # model = model.module 20 | torch.cuda.empty_cache() # TODO check if it helps 21 | iou_types = ("bbox",) 22 | if cfg.MODEL.MASK_ON: 23 | iou_types = iou_types + ("segm",) 24 | data_loaders_val = make_data_loader(cfg, is_train=False, is_distributed=distributed) 25 | dataset_names = [f"evaluation_dataset_{i}" for i in range(len(data_loaders_val))] #cfg.DATASETS.TEST 26 | output_folders = [None] * len(dataset_names) 27 | if cfg.OUTPUT_DIR: 28 | for idx, dataset_name in enumerate(dataset_names): 29 | output_folder = os.path.join(cfg.OUTPUT_DIR, "inference", dataset_name) 30 | mkdir(output_folder) 31 | output_folders[idx] = output_folder 32 | 33 | global _first_test 34 | if _first_test: 35 | #log_event(key=constants.EVAL_SAMPLES, value=len(data_loaders_val)) 36 | _first_test = False 37 | 38 | results = [] 39 | for output_folder, dataset_name, data_loader_val in zip(output_folders, dataset_names, data_loaders_val): 40 | result = inference( 41 | model, 42 | data_loader_val, 43 | dataset_name=dataset_name, 44 | iou_types=iou_types, 45 | box_only=cfg.MODEL.RPN_ONLY, 46 | device=cfg.MODEL.DEVICE, 47 | expected_results=cfg.TEST.EXPECTED_RESULTS, 48 | expected_results_sigma_tol=cfg.TEST.EXPECTED_RESULTS_SIGMA_TOL, 49 | output_folder=output_folder, 50 | ) 51 | # Note: this synchronize() would break async results by not allowing them 52 | # to actually be async 53 | # synchronize() 54 | results.append(result) 55 | return results 56 | 57 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/layers/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | import torch 3 | 4 | from .batch_norm import FrozenBatchNorm2d 5 | from .misc import Conv2d 6 | from .misc import ConvTranspose2d 7 | from .misc import interpolate 8 | from .nms import nms 9 | from .roi_align import ROIAlign 10 | from .roi_align import roi_align 11 | from .roi_pool import ROIPool 12 | from .roi_pool import roi_pool 13 | from .smooth_l1_loss import smooth_l1_loss 14 | from .sigmoid_focal_loss import SigmoidFocalLoss 15 | from .iou_loss import GIoULoss 16 | from .pisa_loss import isr_p, carl_loss, bbox2roi 17 | from .ce_loss import CrossEntropyLoss 18 | __all__ = ["nms", "roi_align", "ROIAlign", "roi_pool", "ROIPool", 19 | "smooth_l1_loss", "Conv2d", "ConvTranspose2d", "interpolate", 20 | "FrozenBatchNorm2d", "SigmoidFocalLoss", "GIoULoss", "isr_p", "carl_loss", "bbox2roi", "CrossEntropyLoss" 21 | ] -------------------------------------------------------------------------------- /pytorch/sagemakercv/layers/_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | import glob 3 | import os.path 4 | 5 | import torch 6 | 7 | try: 8 | from torch.utils.cpp_extension import load as load_ext 9 | from torch.utils.cpp_extension import CUDA_HOME 10 | except ImportError: 11 | raise ImportError("The cpp layer extensions requires PyTorch 0.4 or higher") 12 | 13 | 14 | def _load_C_extensions(): 15 | this_dir = os.path.dirname(os.path.abspath(__file__)) 16 | this_dir = os.path.dirname(this_dir) 17 | this_dir = os.path.join(this_dir, "csrc") 18 | 19 | main_file = glob.glob(os.path.join(this_dir, "*.cpp")) 20 | source_cpu = glob.glob(os.path.join(this_dir, "cpu", "*.cpp")) 21 | source_cuda = glob.glob(os.path.join(this_dir, "cuda", "*.cu")) 22 | 23 | source = main_file + source_cpu 24 | 25 | extra_cflags = [] 26 | if torch.cuda.is_available() and CUDA_HOME is not None: 27 | source.extend(source_cuda) 28 | extra_cflags = ["-DWITH_CUDA"] 29 | source = [os.path.join(this_dir, s) for s in source] 30 | extra_include_paths = [this_dir] 31 | return load_ext( 32 | "torchvision", 33 | source, 34 | extra_cflags=extra_cflags, 35 | extra_include_paths=extra_include_paths, 36 | ) 37 | 38 | 39 | _C = _load_C_extensions() 40 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/layers/batch_norm.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | # Copyright (c) 2018-2019 NVIDIA CORPORATION. All rights reserved. 3 | import torch 4 | from torch import nn 5 | 6 | 7 | class FrozenBatchNorm2d(torch.jit.ScriptModule): 8 | """ 9 | BatchNorm2d where the batch statistics and the affine parameters 10 | are fixed 11 | """ 12 | 13 | def __init__(self, n): 14 | super(FrozenBatchNorm2d, self).__init__() 15 | self.register_buffer("weight", torch.ones(n)) 16 | self.register_buffer("bias", torch.zeros(n)) 17 | self.register_buffer("running_mean", torch.zeros(n)) 18 | self.register_buffer("running_var", torch.ones(n)) 19 | 20 | @torch.jit.script_method 21 | def forward(self, x): 22 | scale = self.weight * self.running_var.rsqrt() 23 | bias = self.bias - self.running_mean * scale 24 | scale = scale.reshape(1, -1, 1, 1) 25 | bias = bias.reshape(1, -1, 1, 1) 26 | return x * scale + bias 27 | 28 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/layers/conv_module.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn.functional as F 3 | 4 | class Mish(torch.nn.Module): 5 | """ The MISH activation function (https://github.com/digantamisra98/Mish) """ 6 | 7 | def __init__(self): 8 | super(Mish, self).__init__() 9 | 10 | def forward(self, x): 11 | return x * torch.tanh(F.softplus(x)) 12 | 13 | class ConvModule(torch.nn.Module): 14 | 15 | def __init__(self, 16 | in_channels, 17 | out_channels, 18 | kernel_size, 19 | stride=1, 20 | padding=0, 21 | bn=False, 22 | activation=None 23 | ): 24 | super(ConvModule, self).__init__() 25 | self.conv = torch.nn.Conv2d( 26 | in_channels=in_channels, 27 | out_channels=out_channels, 28 | kernel_size=kernel_size, 29 | stride=stride, 30 | padding=padding, 31 | bias=not bn, 32 | ) 33 | if bn: 34 | self.bn = torch.nn.BatchNorm2d(out_channels, momentum=0.1, eps=1e-5) 35 | if activation=='leaky': 36 | self.activation = torch.nn.LeakyReLU(0.1) 37 | elif activation=='mish': 38 | self.activtion = Mish() 39 | elif activation=='relu': 40 | self.activation = torch.nn.ReLU() 41 | 42 | def forward(self, x): 43 | x = self.conv(x) 44 | if hasattr(self, 'bn'): 45 | x = self.bn(x) 46 | if hasattr(self, 'activation'): 47 | x = self.activation(x) 48 | return x -------------------------------------------------------------------------------- /pytorch/sagemakercv/layers/nhwc/UpSampleNearest2d.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import torch 16 | from torch.nn.modules.pooling import MaxPool2d 17 | from apex import amp 18 | 19 | from smcv_utils import NHWC 20 | 21 | class UpSampleNearest2d_NHWC_Impl(torch.autograd.Function): 22 | @staticmethod 23 | def forward(ctx, x, output_size): 24 | ctx.output_size = output_size 25 | ctx.input_size = x.shape 26 | y = NHWC.upsample_nearest2d_cuda(x, output_size) 27 | # Need to save y as well 28 | return y 29 | 30 | @staticmethod 31 | def backward(ctx, y_grad): 32 | input_size = ctx.input_size 33 | output_size = ctx.output_size 34 | 35 | return NHWC.upsample_nearest2d_backward_cuda( 36 | y_grad, 37 | output_size, 38 | input_size), None 39 | 40 | class UpSampleNearest2d_NHWC(torch.nn.Module): 41 | def __init__(self, output_size): 42 | super(UpSampleNearest2d_NHWC, self).__init__() 43 | self.output_size = output_size 44 | def forward(self, x): 45 | return UpSampleNearest2d_NHWC_Impl.apply(x, 46 | self.output_size) 47 | 48 | def upsample_nearest2d(x, output_size): 49 | op = UpSampleNearest2d_NHWC(output_size) 50 | return op(x) 51 | 52 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/layers/nhwc/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | import torch 3 | from .misc import Conv2d_NHWC, ConvTranspose2d_NHWC 4 | from .misc import nhwc_to_nchw_transform, nchw_to_nhwc_transform, interpolate_nhwc 5 | from .UpSampleNearest2d import upsample_nearest2d 6 | from .max_pool import MaxPool2d_NHWC 7 | from .init import * 8 | from .batch_norm import FrozenBatchNorm2d_NHWC 9 | 10 | __all__ = ["Conv2d_NHWC", "MaxPool2d_NHWC", "ConvTranspose2d_NHWC", 11 | "FrozenBatchNorm2d_NHWC", "nhwc_to_nchw_transform", "nchw_to_nhwc_transform", 12 | "upsample_nearest2d", "interpolate_nhwc" 13 | ] 14 | 15 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/layers/nhwc/batch_norm.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import torch 16 | from torch import nn 17 | from sagemakercv.layers import FrozenBatchNorm2d 18 | 19 | class FrozenBatchNorm2d_NHWC(torch.jit.ScriptModule): 20 | """ 21 | BatchNorm2d where the batch statistics and the affine parameters 22 | are fixed 23 | """ 24 | 25 | def __init__(self, n): 26 | super(FrozenBatchNorm2d_NHWC, self).__init__() 27 | self.register_buffer("weight", torch.ones(n)) 28 | self.register_buffer("bias", torch.zeros(n)) 29 | self.register_buffer("running_mean", torch.zeros(n)) 30 | self.register_buffer("running_var", torch.ones(n)) 31 | 32 | @torch.jit.script_method 33 | def forward(self, x): 34 | scale = self.weight * self.running_var.rsqrt() 35 | bias = self.bias - self.running_mean * scale 36 | scale = scale.reshape(1, 1, 1, -1) 37 | bias = bias.reshape(1, 1, 1, -1) 38 | return x * scale + bias 39 | 40 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/layers/nhwc/init.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import torch 16 | from torch import nn 17 | from torch.nn import functional as F 18 | 19 | def kaiming_uniform_(tensor, a=0, mode='fan_in', nonlinearity='leaky_relu', nhwc=False): 20 | if nhwc: 21 | weight_tensor_nchw = tensor.data.permute(0,3,1,2).contiguous() 22 | else: 23 | weight_tensor_nchw = tensor 24 | nn.init.kaiming_uniform_(weight_tensor_nchw, a=a, mode=mode, nonlinearity=nonlinearity) 25 | if nhwc: 26 | tensor.data.copy_(weight_tensor_nchw.permute(0,2,3,1).contiguous()) 27 | 28 | def kaiming_normal_(tensor, a=0, mode='fan_in', nonlinearity='relu', nhwc=False): 29 | if nhwc: 30 | weight_tensor_nchw = tensor.data.permute(0,3,1,2).contiguous() 31 | else: 32 | weight_tensor_nchw = tensor 33 | nn.init.kaiming_normal_(weight_tensor_nchw, a=a, mode=mode, nonlinearity=nonlinearity) 34 | if nhwc: 35 | tensor.data.copy_(weight_tensor_nchw.permute(0,2,3,1).contiguous()) 36 | 37 | def normal_(tensor, mean=0.0, std=1.0, nhwc=False): 38 | if nhwc: 39 | weight_tensor_nchw = tensor.data.permute(0,3,1,2).contiguous() 40 | else: 41 | weight_tensor_nchw = tensor 42 | nn.init.normal_(weight_tensor_nchw, mean=mean, std=std) 43 | if nhwc: 44 | tensor.data.copy_(weight_tensor_nchw.permute(0,2,3,1).contiguous()) 45 | 46 | def constant_(tensor, val, nhwc=False): 47 | if nhwc and len(tensor.shape) == 4: 48 | weight_tensor_nchw = tensor.data.permute(0,3,1,2).contiguous() 49 | else: 50 | weight_tensor_nchw = tensor 51 | nn.init.constant_(weight_tensor_nchw, val=val) 52 | if nhwc and len(tensor.shape) == 4: 53 | tensor.data.copy_(weight_tensor_nchw.permute(0,2,3,1).contiguous()) 54 | 55 | 56 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/layers/nhwc/max_pool.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import torch 16 | from torch.nn.modules.pooling import MaxPool2d 17 | from apex import amp 18 | 19 | from smcv_utils import NHWC 20 | 21 | class max_pool_NHWC_impl(torch.autograd.Function): 22 | @staticmethod 23 | def forward(ctx, x, kernel_size, stride, padding, dilation): 24 | ctx.kernel_size = kernel_size 25 | ctx.stride = stride if stride is not None else 0 26 | ctx.padding = padding 27 | ctx.dilation = dilation 28 | 29 | y = NHWC.max_pool_fwd_nhwc(x, kernel_size, stride, padding, dilation) 30 | 31 | # Need to save y as well 32 | ctx.save_for_backward(x, y) 33 | return y 34 | 35 | @staticmethod 36 | def backward(ctx, y_grad): 37 | x, y = ctx.saved_variables 38 | 39 | kernel = ctx.kernel_size 40 | stride = ctx.stride 41 | padding = ctx.padding 42 | dilation = ctx.dilation 43 | 44 | return NHWC.max_pool_bwd_nhwc(x, 45 | y, 46 | y_grad, 47 | kernel, 48 | stride, 49 | padding, 50 | dilation), None, None, None, None 51 | 52 | class MaxPool2d_NHWC(MaxPool2d): 53 | def __init__(self, kernel_size, stride=None, padding=0): 54 | super(MaxPool2d_NHWC, self).__init__(kernel_size, stride=stride, padding=padding) 55 | def forward(self, x): 56 | return max_pool_NHWC_impl.apply(x, 57 | self.kernel_size, 58 | self.stride, 59 | self.padding, 60 | self.dilation) 61 | 62 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/layers/nhwc/transforms.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import torch 16 | from apex import amp 17 | from smcv_utils import NHWC 18 | 19 | class NHWCToNCHW_Impl(torch.autograd.Function): 20 | @staticmethod 21 | def forward(ctx, x): 22 | y = NHWC.cudnnNhwcToNchw(x) 23 | return y 24 | 25 | @staticmethod 26 | def backward(ctx, y_grad): 27 | x_grad = NHWC.cudnnNchwToNhwc(y_grad) 28 | return x_grad 29 | 30 | class NCHWToNHWC_Impl(torch.autograd.Function): 31 | @staticmethod 32 | def forward(ctx, x): 33 | y = NHWC.cudnnNchwToNhwc(x) 34 | return y 35 | 36 | @staticmethod 37 | def backward(ctx, y_grad): 38 | x_grad = NHWC.cudnnNhwcToNchw(y_grad) 39 | return x_grad 40 | 41 | class NHWCToNCHW(torch.nn.Module): 42 | def __init__(self): 43 | super(NHWCToNCHW, self).__init__() 44 | def forward(self, x): 45 | return NHWCToNCHW_Impl.apply(x) 46 | 47 | class NCHWToNHWC(torch.nn.Module): 48 | def __init__(self): 49 | super(NCHWToNHWC, self).__init__() 50 | def forward(self, x): 51 | return NCHWToNHWC_Impl.apply(x) 52 | 53 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/layers/nms.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | # Copyright (c) 2018-2019 NVIDIA CORPORATION. All rights reserved. 3 | # from ._utils import _C 4 | from smcv_utils import _C 5 | 6 | from apex import amp 7 | 8 | # Only valid with fp32 inputs - give AMP the hint 9 | nms = amp.float_function(_C.nms) 10 | 11 | # nms.__doc__ = """ 12 | # This function performs Non-maximum suppresion""" 13 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/layers/roi_pool.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | # Copyright (c) 2018-2019 NVIDIA CORPORATION. All rights reserved. 3 | import torch 4 | from torch import nn 5 | from torch.autograd import Function 6 | from torch.autograd.function import once_differentiable 7 | from torch.nn.modules.utils import _pair 8 | 9 | from smcv_utils import _C 10 | 11 | from apex import amp 12 | 13 | class _ROIPool(Function): 14 | @staticmethod 15 | def forward(ctx, input, roi, output_size, spatial_scale): 16 | ctx.output_size = _pair(output_size) 17 | ctx.spatial_scale = spatial_scale 18 | ctx.input_shape = input.size() 19 | output, argmax = _C.roi_pool_forward( 20 | input, roi, spatial_scale, output_size[0], output_size[1] 21 | ) 22 | ctx.save_for_backward(input, roi, argmax) 23 | return output 24 | 25 | @staticmethod 26 | @once_differentiable 27 | def backward(ctx, grad_output): 28 | input, rois, argmax = ctx.saved_tensors 29 | output_size = ctx.output_size 30 | spatial_scale = ctx.spatial_scale 31 | bs, ch, h, w = ctx.input_shape 32 | grad_input = _C.roi_pool_backward( 33 | grad_output, 34 | input, 35 | rois, 36 | argmax, 37 | spatial_scale, 38 | output_size[0], 39 | output_size[1], 40 | bs, 41 | ch, 42 | h, 43 | w, 44 | ) 45 | return grad_input, None, None, None 46 | 47 | 48 | roi_pool = _ROIPool.apply 49 | 50 | 51 | class ROIPool(nn.Module): 52 | def __init__(self, output_size, spatial_scale): 53 | super(ROIPool, self).__init__() 54 | self.output_size = output_size 55 | self.spatial_scale = spatial_scale 56 | 57 | def forward(self, input, rois): 58 | return roi_pool(input.float(), rois, self.output_size, self.spatial_scale) 59 | 60 | def __repr__(self): 61 | tmpstr = self.__class__.__name__ + "(" 62 | tmpstr += "output_size=" + str(self.output_size) 63 | tmpstr += ", spatial_scale=" + str(self.spatial_scale) 64 | tmpstr += ")" 65 | return tmpstr 66 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/layers/sigmoid_focal_loss.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch import nn 3 | from torch.autograd import Function 4 | from torch.autograd.function import once_differentiable 5 | 6 | from smcv_utils import _C 7 | 8 | # TODO: Use JIT to replace CUDA implementation in the future. 9 | class _SigmoidFocalLoss(Function): 10 | @staticmethod 11 | def forward(ctx, logits, targets, gamma, alpha): 12 | ctx.save_for_backward(logits, targets) 13 | num_classes = logits.shape[1] 14 | ctx.num_classes = num_classes 15 | ctx.gamma = gamma 16 | ctx.alpha = alpha 17 | 18 | losses = _C.sigmoid_focalloss_forward( 19 | logits, targets, num_classes, gamma, alpha 20 | ) 21 | return losses 22 | 23 | @staticmethod 24 | @once_differentiable 25 | def backward(ctx, d_loss): 26 | logits, targets = ctx.saved_tensors 27 | num_classes = ctx.num_classes 28 | gamma = ctx.gamma 29 | alpha = ctx.alpha 30 | d_loss = d_loss.contiguous() 31 | d_logits = _C.sigmoid_focalloss_backward( 32 | logits, targets, d_loss, num_classes, gamma, alpha 33 | ) 34 | return d_logits, None, None, None, None 35 | 36 | 37 | sigmoid_focal_loss_cuda = _SigmoidFocalLoss.apply 38 | 39 | 40 | def sigmoid_focal_loss_cpu(logits, targets, gamma, alpha): 41 | num_classes = logits.shape[1] 42 | gamma = gamma[0] 43 | alpha = alpha[0] 44 | dtype = targets.dtype 45 | device = targets.device 46 | class_range = torch.arange(1, num_classes+1, dtype=dtype, device=device).unsqueeze(0) 47 | 48 | t = targets.unsqueeze(1) 49 | p = torch.sigmoid(logits) 50 | term1 = (1 - p) ** gamma * torch.log(p) 51 | term2 = p ** gamma * torch.log(1 - p) 52 | return -(t == class_range).float() * term1 * alpha - ((t != class_range) * (t >= 0)).float() * term2 * (1 - alpha) 53 | 54 | 55 | class SigmoidFocalLoss(nn.Module): 56 | def __init__(self, gamma, alpha): 57 | super(SigmoidFocalLoss, self).__init__() 58 | self.gamma = gamma 59 | self.alpha = alpha 60 | 61 | def forward(self, logits, targets): 62 | device = logits.device 63 | if logits.is_cuda: 64 | loss_func = sigmoid_focal_loss_cuda 65 | else: 66 | loss_func = sigmoid_focal_loss_cpu 67 | 68 | loss = loss_func(logits, targets, self.gamma, self.alpha) 69 | return loss.sum() 70 | 71 | def __repr__(self): 72 | tmpstr = self.__class__.__name__ + "(" 73 | tmpstr += "gamma=" + str(self.gamma) 74 | tmpstr += ", alpha=" + str(self.alpha) 75 | tmpstr += ")" 76 | return tmpstr 77 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/layers/smooth_l1_loss.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | import torch 3 | from ..utils.loss_utils import weighted_loss 4 | 5 | # TODO maybe push this to nn? 6 | @weighted_loss 7 | def smooth_l1_loss(input, target, beta=1. / 9, size_average=True): 8 | """ 9 | very similar to the smooth_l1_loss from pytorch, but with 10 | the extra beta parameter 11 | """ 12 | n = torch.abs(input - target) 13 | cond = n < beta 14 | loss = torch.where(cond, 0.5 * n ** 2 / beta, n - 0.5 * beta) 15 | if size_average: 16 | return loss.mean() 17 | return loss.sum() 18 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/training/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | from .build import make_optimizer 3 | from .build import make_lr_scheduler 4 | from .optimizers.schedulers.lr_scheduler import WarmupMultiStepLR 5 | from .optimizers.mlperf_fp16_optimizer import MLPerfFP16Optimizer 6 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/training/optimizers/__init__.py: -------------------------------------------------------------------------------- 1 | from .mlperf_fp16_optimizer import MLPerfFP16Optimizer 2 | from .mlperf_fused_sgd import MLPerfFusedSGD -------------------------------------------------------------------------------- /pytorch/sagemakercv/training/optimizers/schedulers/__init__.py: -------------------------------------------------------------------------------- 1 | from .cosine_lr_scheduler import CosineAnnealingWarmUpRestarts 2 | from .lr_scheduler import WarmupMultiStepLR -------------------------------------------------------------------------------- /pytorch/sagemakercv/training/optimizers/schedulers/lr_scheduler.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | # Copyright (c) 2018-2019 NVIDIA CORPORATION. All rights reserved. 3 | from bisect import bisect_right 4 | 5 | import torch 6 | 7 | 8 | # FIXME ideally this would be achieved with a CombinedLRScheduler, 9 | # separating MultiStepLR with WarmupLR 10 | # but the current LRScheduler design doesn't allow it 11 | class WarmupMultiStepLR(torch.optim.lr_scheduler._LRScheduler): 12 | def __init__( 13 | self, 14 | optimizer, 15 | milestones, 16 | gamma=0.1, 17 | warmup_factor=1.0 / 3, 18 | warmup_iters=500, 19 | warmup_method="linear", 20 | last_epoch=-1, 21 | ): 22 | if not list(milestones) == sorted(milestones): 23 | raise ValueError( 24 | "Milestones should be a list of" " increasing integers. Got {}", 25 | milestones, 26 | ) 27 | 28 | if warmup_method not in ("constant", "linear", "mlperf_linear"): 29 | raise ValueError( 30 | "Only 'constant' or 'linear' warmup_method accepted" 31 | "got {}".format(warmup_method) 32 | ) 33 | self.milestones = milestones 34 | self.gamma = gamma 35 | self.warmup_factor = warmup_factor 36 | self.warmup_iters = warmup_iters 37 | self.warmup_method = warmup_method 38 | super(WarmupMultiStepLR, self).__init__(optimizer, last_epoch) 39 | 40 | def get_lr(self): 41 | warmup_factor = 1 42 | # optional offset to each base_lr 43 | delta = 0. 44 | 45 | if self.last_epoch < self.warmup_iters: 46 | if self.warmup_method == "constant": 47 | warmup_factor = self.warmup_factor 48 | elif self.warmup_method == "linear": 49 | alpha = float(self.last_epoch) / self.warmup_iters 50 | warmup_factor = self.warmup_factor * (1 - alpha) + alpha 51 | # MLPerf-specific warmup definition 52 | elif self.warmup_method == "mlperf_linear": 53 | delta = (self.warmup_iters - self.last_epoch) * self.warmup_factor 54 | return [ 55 | (base_lr - delta) 56 | * warmup_factor 57 | * self.gamma ** bisect_right(self.milestones, self.last_epoch) 58 | for base_lr in self.base_lrs 59 | ] 60 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/training/trainers.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import apex 3 | 4 | def train_step(images, targets, model, optimizer, scheduler, device, opt_level, grad_clip=0.0): 5 | optimizer.zero_grad() 6 | # images = images.to(device) 7 | # targets = [target.to(device) for target in targets] 8 | loss_dict = model(images, targets) 9 | losses = sum(loss for loss in loss_dict.values()) 10 | if opt_level=="O4": 11 | optimizer.backward(losses) 12 | else: 13 | with apex.amp.scale_loss(losses, optimizer) as scaled_loss: 14 | scaled_loss.backward() 15 | if grad_clip>0.0: 16 | torch.nn.utils.clip_grad_norm_(model.parameters(), grad_clip) 17 | optimizer.step() 18 | scheduler.step() 19 | loss_dict['total_loss'] = losses 20 | return loss_dict 21 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/README.md: -------------------------------------------------------------------------------- 1 | # Utility functions 2 | 3 | This folder contain utility functions that are not used in the 4 | core library, but are useful for building models or training 5 | code using the config system. 6 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/pytorch/sagemakercv/utils/__init__.py -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/collect_env.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | import PIL 3 | 4 | from torch.utils.collect_env import get_pretty_env_info 5 | 6 | 7 | def get_pil_version(): 8 | return "\n Pillow ({})".format(PIL.__version__) 9 | 10 | 11 | def collect_env_info(): 12 | env_str = get_pretty_env_info() 13 | env_str += get_pil_version() 14 | return env_str 15 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/cv2_util.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for cv2 utility functions and maintaining version compatibility 3 | between 3.x and 4.x 4 | """ 5 | import cv2 6 | 7 | 8 | def findContours(*args, **kwargs): 9 | """ 10 | Wraps cv2.findContours to maintain compatiblity between versions 11 | 3 and 4 12 | 13 | Returns: 14 | contours, hierarchy 15 | """ 16 | if cv2.__version__.startswith('4'): 17 | contours, hierarchy = cv2.findContours(*args, **kwargs) 18 | elif cv2.__version__.startswith('3'): 19 | _, contours, hierarchy = cv2.findContours(*args, **kwargs) 20 | else: 21 | raise AssertionError( 22 | 'cv2 must be either version 3 or 4 to call this method') 23 | 24 | return contours, hierarchy 25 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/env.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | import os 3 | 4 | from sagemakercv.utils.imports import import_file 5 | 6 | 7 | def setup_environment(): 8 | """Perform environment setup work. The default setup is a no-op, but this 9 | function allows the user to specify a Python source file that performs 10 | custom setup work that may be necessary to their computing environment. 11 | """ 12 | custom_module_path = os.environ.get("TORCH_DETECTRON_ENV_MODULE") 13 | if custom_module_path: 14 | setup_custom_environment(custom_module_path) 15 | else: 16 | # The default setup is a no-op 17 | pass 18 | 19 | 20 | def setup_custom_environment(custom_module_path): 21 | """Load custom environment setup from a Python source file and run the setup 22 | function. 23 | """ 24 | module = import_file("maskrcnn_benchmark.utils.env.custom_module", custom_module_path) 25 | assert hasattr(module, "setup_environment") and callable( 26 | module.setup_environment 27 | ), ( 28 | "Custom environment module defined in {} does not have the " 29 | "required callable attribute 'setup_environment'." 30 | ).format( 31 | custom_module_path 32 | ) 33 | module.setup_environment() 34 | 35 | 36 | # Force environment setup when this module is imported 37 | setup_environment() 38 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/fileio/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | from .handlers import BaseFileHandler, JsonHandler, PickleHandler, YamlHandler 3 | from .io import dump, load, register_handler 4 | from .parse import dict_from_file, list_from_file 5 | 6 | __all__ = [ 7 | 'load', 'dump', 'register_handler', 'BaseFileHandler', 'JsonHandler', 8 | 'PickleHandler', 'YamlHandler', 'list_from_file', 'dict_from_file' 9 | ] -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/fileio/handlers/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | from .base import BaseFileHandler 3 | from .json_handler import JsonHandler 4 | from .pickle_handler import PickleHandler 5 | from .yaml_handler import YamlHandler 6 | 7 | __all__ = ['BaseFileHandler', 'JsonHandler', 'PickleHandler', 'YamlHandler'] -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/fileio/handlers/base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | from abc import ABCMeta, abstractmethod 3 | 4 | 5 | class BaseFileHandler(object): 6 | 7 | __metaclass__ = ABCMeta # python 2 compatibility 8 | 9 | @abstractmethod 10 | def load_from_fileobj(self, file, **kwargs): 11 | pass 12 | 13 | @abstractmethod 14 | def dump_to_fileobj(self, obj, file, **kwargs): 15 | pass 16 | 17 | @abstractmethod 18 | def dump_to_str(self, obj, **kwargs): 19 | pass 20 | 21 | def load_from_path(self, filepath, mode='r', **kwargs): 22 | with open(filepath, mode) as f: 23 | return self.load_from_fileobj(f, **kwargs) 24 | 25 | def dump_to_path(self, obj, filepath, mode='w', **kwargs): 26 | with open(filepath, mode) as f: 27 | self.dump_to_fileobj(obj, f, **kwargs) 28 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/fileio/handlers/json_handler.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | import json 3 | import numpy as np 4 | 5 | from .base import BaseFileHandler 6 | 7 | class NumpyEncoder(json.JSONEncoder): 8 | def default(self, obj): 9 | if isinstance(obj, np.integer): 10 | return int(obj) 11 | elif isinstance(obj, np.floating): 12 | return float(obj) 13 | elif isinstance(obj, np.ndarray): 14 | return obj.tolist() 15 | else: 16 | return super(NumpyEncoder, self).default(obj) 17 | 18 | class JsonHandler(BaseFileHandler): 19 | 20 | def load_from_fileobj(self, file): 21 | return json.load(file) 22 | 23 | def dump_to_fileobj(self, obj, file, **kwargs): 24 | obj = json.dumps(obj, cls=NumpyEncoder) 25 | json.dump(obj, file, **kwargs) 26 | 27 | def dump_to_str(self, obj, **kwargs): 28 | return json.dumps(obj, **kwargs) 29 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/fileio/handlers/pickle_handler.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | from six.moves import cPickle as pickle 3 | 4 | from .base import BaseFileHandler 5 | 6 | 7 | class PickleHandler(BaseFileHandler): 8 | 9 | def load_from_fileobj(self, file, **kwargs): 10 | return pickle.load(file, **kwargs) 11 | 12 | def load_from_path(self, filepath, **kwargs): 13 | return super(PickleHandler, self).load_from_path( 14 | filepath, mode='rb', **kwargs) 15 | 16 | def dump_to_str(self, obj, **kwargs): 17 | kwargs.setdefault('protocol', 2) 18 | return pickle.dumps(obj, **kwargs) 19 | 20 | def dump_to_fileobj(self, obj, file, **kwargs): 21 | kwargs.setdefault('protocol', 2) 22 | pickle.dump(obj, file, **kwargs) 23 | 24 | def dump_to_path(self, obj, filepath, **kwargs): 25 | super(PickleHandler, self).dump_to_path( 26 | obj, filepath, mode='wb', **kwargs) -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/fileio/handlers/yaml_handler.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | import yaml 3 | 4 | try: 5 | from yaml import CLoader as Loader, CDumper as Dumper 6 | except ImportError: 7 | from yaml import Loader, Dumper 8 | 9 | from .base import BaseFileHandler # isort:skip 10 | 11 | 12 | class YamlHandler(BaseFileHandler): 13 | 14 | def load_from_fileobj(self, file, **kwargs): 15 | kwargs.setdefault('Loader', Loader) 16 | return yaml.load(file, **kwargs) 17 | 18 | def dump_to_fileobj(self, obj, file, **kwargs): 19 | kwargs.setdefault('Dumper', Dumper) 20 | yaml.dump(obj, file, **kwargs) 21 | 22 | def dump_to_str(self, obj, **kwargs): 23 | kwargs.setdefault('Dumper', Dumper) 24 | return yaml.dump(obj, **kwargs) -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/fileio/parse.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | def list_from_file(filename, prefix='', offset=0, max_num=0): 3 | """Load a text file and parse the content as a list of strings. 4 | 5 | Args: 6 | filename (str): Filename. 7 | prefix (str): The prefix to be inserted to the begining of each item. 8 | offset (int): The offset of lines. 9 | max_num (int): The maximum number of lines to be read, 10 | zeros and negatives mean no limitation. 11 | 12 | Returns: 13 | list[str]: A list of strings. 14 | """ 15 | cnt = 0 16 | item_list = [] 17 | with open(filename, 'r') as f: 18 | for _ in range(offset): 19 | f.readline() 20 | for line in f: 21 | if max_num > 0 and cnt >= max_num: 22 | break 23 | item_list.append(prefix + line.rstrip('\n')) 24 | cnt += 1 25 | return item_list 26 | 27 | 28 | def dict_from_file(filename, key_type=str): 29 | """Load a text file and parse the content as a dict. 30 | 31 | Each line of the text file will be two or more columns splited by 32 | whitespaces or tabs. The first column will be parsed as dict keys, and 33 | the following columns will be parsed as dict values. 34 | 35 | Args: 36 | filename(str): Filename. 37 | key_type(type): Type of the dict's keys. str is user by default and 38 | type conversion will be performed if specified. 39 | 40 | Returns: 41 | dict: The parsed contents. 42 | """ 43 | mapping = {} 44 | with open(filename, 'r') as f: 45 | for line in f: 46 | items = line.rstrip('\n').split() 47 | assert len(items) >= 2 48 | key = key_type(items[0]) 49 | val = items[1:] if len(items) > 2 else items[1] 50 | mapping[key] = val 51 | return mapping 52 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/imports.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | import torch 3 | 4 | import importlib 5 | import importlib.util 6 | import sys 7 | 8 | 9 | # from https://stackoverflow.com/questions/67631/how-to-import-a-module-given-the-full-path?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa 10 | def import_file(module_name, file_path, make_importable=False): 11 | spec = importlib.util.spec_from_file_location(module_name, file_path) 12 | module = importlib.util.module_from_spec(spec) 13 | spec.loader.exec_module(module) 14 | if make_importable: 15 | sys.modules[module_name] = module 16 | return module 17 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/logger.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | import logging 3 | import os 4 | import sys 5 | 6 | 7 | def setup_logger(name, save_dir, distributed_rank, filename="log.txt"): 8 | logger = logging.getLogger(name) 9 | logger.setLevel(logging.DEBUG) 10 | # don't log results for the non-master process 11 | if distributed_rank > 0: 12 | return logger 13 | ch = logging.StreamHandler(stream=sys.stdout) 14 | ch.setLevel(logging.DEBUG) 15 | formatter = logging.Formatter("%(asctime)s %(name)s %(levelname)s: %(message)s") 16 | ch.setFormatter(formatter) 17 | logger.addHandler(ch) 18 | 19 | if save_dir: 20 | fh = logging.FileHandler(os.path.join(save_dir, filename)) 21 | fh.setLevel(logging.DEBUG) 22 | fh.setFormatter(formatter) 23 | logger.addHandler(fh) 24 | 25 | return logger 26 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/metric_logger.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | from collections import defaultdict 3 | from collections import deque 4 | 5 | import torch 6 | 7 | 8 | class SmoothedValue(object): 9 | """Track a series of values and provide access to smoothed values over a 10 | window or the global series average. 11 | """ 12 | 13 | def __init__(self, window_size=20): 14 | self.deque = deque(maxlen=window_size) 15 | self.series = [] 16 | self.total = 0.0 17 | self.count = 0 18 | 19 | def update(self, value): 20 | self.deque.append(value) 21 | self.series.append(value) 22 | self.count += 1 23 | self.total += value 24 | 25 | @property 26 | def median(self): 27 | d = torch.tensor(list(self.deque)) 28 | return d.median().item() 29 | 30 | @property 31 | def avg(self): 32 | d = torch.tensor(list(self.deque)) 33 | return d.mean().item() 34 | 35 | @property 36 | def global_avg(self): 37 | return self.total / self.count 38 | 39 | 40 | class MetricLogger(object): 41 | def __init__(self, delimiter="\t"): 42 | self.meters = defaultdict(SmoothedValue) 43 | self.delimiter = delimiter 44 | 45 | def update(self, **kwargs): 46 | for k, v in kwargs.items(): 47 | if isinstance(v, torch.Tensor): 48 | v = v.item() 49 | assert isinstance(v, (float, int)) 50 | self.meters[k].update(v) 51 | 52 | def __getattr__(self, attr): 53 | if attr in self.meters: 54 | return self.meters[attr] 55 | if attr in self.__dict__: 56 | return self.__dict__[attr] 57 | raise AttributeError("'{}' object has no attribute '{}'".format( 58 | type(self).__name__, attr)) 59 | 60 | def __str__(self): 61 | loss_str = [] 62 | for name, meter in self.meters.items(): 63 | loss_str.append( 64 | "{}: {:.4f} ({:.4f})".format(name, meter.median, meter.global_avg) 65 | ) 66 | return self.delimiter.join(loss_str) 67 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/miscellaneous.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | import errno 3 | import os 4 | 5 | 6 | def mkdir(path): 7 | try: 8 | os.makedirs(path) 9 | except OSError as e: 10 | if e.errno != errno.EEXIST: 11 | raise 12 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/registry.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | 3 | 4 | def _register_generic(module_dict, module_name, module): 5 | assert module_name not in module_dict 6 | module_dict[module_name] = module 7 | 8 | 9 | class Registry(dict): 10 | ''' 11 | A helper class for managing registering modules, it extends a dictionary 12 | and provides a register functions. 13 | 14 | Eg. creeting a registry: 15 | some_registry = Registry({"default": default_module}) 16 | 17 | There're two ways of registering new modules: 18 | 1): normal way is just calling register function: 19 | def foo(): 20 | ... 21 | some_registry.register("foo_module", foo) 22 | 2): used as decorator when declaring the module: 23 | @some_registry.register("foo_module") 24 | @some_registry.register("foo_modeul_nickname") 25 | def foo(): 26 | ... 27 | 28 | Access of module is just like using a dictionary, eg: 29 | f = some_registry["foo_modeul"] 30 | ''' 31 | def __init__(self, *args, **kwargs): 32 | super(Registry, self).__init__(*args, **kwargs) 33 | 34 | def register(self, module_name, module=None): 35 | # used as function call 36 | if module is not None: 37 | _register_generic(self, module_name, module) 38 | return 39 | 40 | # used as decorator 41 | def register_fn(fn): 42 | _register_generic(self, module_name, fn) 43 | return fn 44 | 45 | return register_fn 46 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/runner/__init__.py: -------------------------------------------------------------------------------- 1 | from .runner import Runner 2 | from .log_buffer import LogBuffer 3 | from .hooks import * 4 | from .builder import build_hooks 5 | 6 | __all__ = ['Runner', 'LogBuffer'] -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/runner/builder.py: -------------------------------------------------------------------------------- 1 | from ..registry import Registry 2 | 3 | HOOKS = Registry() 4 | 5 | def build_hooks(cfg): 6 | return [HOOKS[hook](cfg) for hook in cfg.HOOKS] 7 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/runner/hooks/__init__.py: -------------------------------------------------------------------------------- 1 | from .checkpoint import CheckpointHook, DetectronCheckpointHook, build_detectron_checkpoint_hook 2 | from .hook import Hook 3 | from .logger import TextLoggerHook, build_text_logger_hook 4 | from .iter_timer import IterTimerHook, build_iter_time_hook 5 | from .fp16_optimizer import FP16_Hook, build_fp16_hook 6 | from .coco_evaluation_hook import build_coco_eval_hook 7 | from .amp_optimizer import build_amp_hook 8 | 9 | __all__ = ['CheckpointHook', 'Hook', 'TextLoggerHook', 'IterTimerHook'] 10 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/runner/hooks/amp_optimizer.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # -*- coding: utf-8 -*- 4 | from .hook import Hook 5 | import os 6 | import apex 7 | from ..builder import HOOKS 8 | from sagemakercv.training.optimizers import MLPerfFP16Optimizer 9 | 10 | class AMP_Hook(Hook): 11 | 12 | def __init__(self, opt_level="O1"): 13 | self.opt_level=opt_level 14 | 15 | def before_run(self, runner): 16 | if self.opt_level=='O4': 17 | runner.model.half() 18 | if "MLPerf" in str(runner.optimizer): 19 | runner.optimizer = MLPerfFP16Optimizer(runner.optimizer, 20 | dynamic_loss_scale=True) 21 | else: 22 | runner.optimizer = apex.fp16_utils.fp16_optimizer.FP16_Optimizer(runner.optimizer, 23 | dynamic_loss_scale=True) 24 | elif self.opt_level in ['O0', 'O1', 'O2', 'O3']: 25 | runner.model, runner.optimizer = apex.amp.initialize(runner.model, runner.optimizer, opt_level=self.opt_level) 26 | else: 27 | raise NotImplementedError("Opt level must be one of O0, O1, O2, O3, O4") 28 | 29 | @HOOKS.register("AMP_Hook") 30 | def build_amp_hook(cfg): 31 | return AMP_Hook(opt_level=cfg.OPT_LEVEL) 32 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/runner/hooks/checkpoint.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # -*- coding: utf-8 -*- 4 | from .hook import Hook 5 | import os 6 | from sagemakercv.utils.checkpoint import Checkpointer, DetectronCheckpointer 7 | from ..builder import HOOKS 8 | 9 | class CheckpointHook(Hook): 10 | 11 | def __init__(self, 12 | interval=1, 13 | save_optimizer=True, 14 | out_dir=None, 15 | **kwargs): 16 | self.interval = interval 17 | self.save_optimizer = save_optimizer 18 | self.out_dir = out_dir 19 | self.args = kwargs 20 | 21 | def before_run(self, runner): 22 | self.checkpointer = Checkpointer( 23 | runner.model, 24 | runner.optimizer, 25 | runner.scheduler, 26 | runner.work_dir, 27 | runner.rank==0 28 | ) 29 | self.extra_checkpoint_data = self.checkpointer.load(runner.cfg.MODEL.WEIGHT, 30 | runner.cfg.OPT_LEVEL=="O4") 31 | 32 | def after_train_epoch(self, runner): 33 | # Disable for now, causing error on training job 34 | if not self.every_n_epochs(runner, self.interval): 35 | return 36 | if not self.out_dir: 37 | self.out_dir = runner.work_dir 38 | if runner.rank==0: 39 | checkpoint_dir = os.path.join(self.out_dir, "{:03d}".format(runner.epoch)) 40 | os.makedirs(checkpoint_dir, exist_ok=True) 41 | self.checkpointer.save("model_{:07d}".format(runner.iter), nhwc=runner.cfg.OPT_LEVEL=="O4") 42 | 43 | class DetectronCheckpointHook(CheckpointHook): 44 | 45 | # TODO fix optimizer state dict to enable saving 46 | def before_run(self, runner): 47 | self.checkpointer = DetectronCheckpointer( 48 | runner.cfg, 49 | runner.model, 50 | None, # runner.optimizer, 51 | None, # runner.scheduler, 52 | runner.work_dir, 53 | runner.rank==0 54 | ) 55 | self.extra_checkpoint_data = self.checkpointer.load(runner.cfg.MODEL.WEIGHT, 56 | runner.cfg.OPT_LEVEL=="O4") 57 | 58 | @HOOKS.register("DetectronCheckpointHook") 59 | def build_detectron_checkpoint_hook(cfg): 60 | return DetectronCheckpointHook(interval=cfg.SAVE_INTERVAL) 61 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/runner/hooks/coco_evaluation_hook.py: -------------------------------------------------------------------------------- 1 | from .hook import Hook 2 | from sagemakercv.inference.tester import test 3 | from sagemakercv.utils.async_evaluator import init, get_evaluator, set_epoch_tag 4 | from sagemakercv.utils.comm import master_only 5 | from sagemakercv.utils.comm import get_world_size 6 | from ..builder import HOOKS 7 | from time import sleep 8 | 9 | class COCOEvaluation(Hook): 10 | 11 | def __init__(self, interval=25, distributed=True, per_epoch=True): 12 | self.interval = interval 13 | self.distributed = distributed 14 | self.running_eval = False 15 | self.per_epoch = per_epoch 16 | 17 | def before_run(self, runner): 18 | init() 19 | 20 | def after_train_epoch(self, runner): 21 | if self.per_epoch: 22 | set_epoch_tag(runner.epoch) 23 | results = test(runner.cfg, runner.model, self.distributed) 24 | self.running_eval = True 25 | 26 | @master_only 27 | def after_train_iter(self, runner): 28 | if self.every_n_inner_iters(runner, self.interval) and self.running_eval: 29 | evaluator = get_evaluator() 30 | self.running_eval = False 31 | all_results = {} 32 | for t, r in evaluator.finished_tasks().items(): 33 | # Note: one indirection due to possibility of multiple test datasets 34 | # we only care about the first 35 | map_results = r# [0] 36 | bbox_map = map_results.results["bbox"]['AP'] 37 | segm_map = map_results.results["segm"]['AP'] \ 38 | if runner.cfg.MODEL.MASK_ON else None 39 | all_results.update({ t : (bbox_map, segm_map) }) 40 | runner.logger.info(all_results) 41 | 42 | def after_run(self, runner): 43 | if not self.per_epoch: 44 | set_epoch_tag(runner.epoch) 45 | results = test(runner.cfg, runner.model, self.distributed) 46 | self.running_eval = True 47 | if runner.rank == 0: 48 | evaluator = get_evaluator() 49 | self.running_eval = False 50 | evaluator.wait_all_tasks() 51 | all_results = {} 52 | for t, r in evaluator.finished_tasks().items(): 53 | # Note: one indirection due to possibility of multiple test datasets 54 | # we only care about the first 55 | map_results = r# [0] 56 | bbox_map = map_results.results["bbox"]['AP'] 57 | segm_map = map_results.results["segm"]['AP'] \ 58 | if runner.cfg.MODEL.MASK_ON else None 59 | all_results.update({ t : (bbox_map, segm_map) }) 60 | runner.logger.info(all_results) 61 | else: 62 | sleep(20) 63 | 64 | @HOOKS.register("COCOEvaluation") 65 | def build_coco_eval_hook(cfg): 66 | return COCOEvaluation(distributed=get_world_size()>1, per_epoch=cfg.TEST.PER_EPOCH_EVAL) -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/runner/hooks/fp16_optimizer.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # -*- coding: utf-8 -*- 4 | from .hook import Hook 5 | import os 6 | import apex 7 | from ..builder import HOOKS 8 | from sagemakercv.training.optimizers import MLPerfFP16Optimizer 9 | 10 | class FP16_Hook(Hook): 11 | 12 | def before_run(self, runner): 13 | if "MLPerf" in str(runner.optimizer): 14 | runner.optimizer = MLPerfFP16Optimizer(runner.optimizer, 15 | dynamic_loss_scale=True) 16 | else: 17 | runner.optimizer = apex.fp16_utils.fp16_optimizer.FP16_Optimizer(runner.optimizer, 18 | dynamic_loss_scale=True) 19 | 20 | @HOOKS.register("FP16_Hook") 21 | def build_fp16_hook(cfg): 22 | return FP16_Hook() 23 | -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/runner/hooks/hook.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | class Hook(object): 3 | 4 | def before_run(self, runner): 5 | pass 6 | 7 | def after_run(self, runner): 8 | pass 9 | 10 | def before_epoch(self, runner): 11 | pass 12 | 13 | def after_epoch(self, runner): 14 | pass 15 | 16 | def before_iter(self, runner): 17 | pass 18 | 19 | def after_iter(self, runner): 20 | pass 21 | 22 | def before_train_epoch(self, runner): 23 | self.before_epoch(runner) 24 | 25 | def before_val_epoch(self, runner): 26 | self.before_epoch(runner) 27 | 28 | def after_train_epoch(self, runner): 29 | self.after_epoch(runner) 30 | 31 | def after_val_epoch(self, runner): 32 | self.after_epoch(runner) 33 | 34 | def before_train_iter(self, runner): 35 | self.before_iter(runner) 36 | 37 | def before_val_iter(self, runner): 38 | self.before_iter(runner) 39 | 40 | def after_train_iter(self, runner): 41 | self.after_iter(runner) 42 | 43 | def after_val_iter(self, runner): 44 | self.after_iter(runner) 45 | 46 | def every_n_epochs(self, runner, n): 47 | return (runner.epoch + 1) % n == 0 if n > 0 else False 48 | 49 | def every_n_inner_iters(self, runner, n): 50 | return (runner.inner_iter + 1) % n == 0 if n > 0 else False 51 | 52 | def every_n_iters(self, runner, n): 53 | return (runner.iter + 1) % n == 0 if n > 0 else False 54 | 55 | def end_of_epoch(self, runner): 56 | return runner.inner_iter + 1 == runner.num_examples -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/runner/hooks/iter_timer.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | import time 3 | import datetime 4 | from .hook import Hook 5 | from ..builder import HOOKS 6 | 7 | class IterTimerHook(Hook): 8 | 9 | def __init__(self, interval=25): 10 | self.interval = interval 11 | 12 | def before_run(self, runner): 13 | self.start_time = datetime.datetime.now() 14 | if runner.rank == 0: 15 | runner.logger.info("Start time: {}".format(str(self.start_time))) 16 | 17 | def before_epoch(self, runner): 18 | self.t = time.time() 19 | 20 | def after_iter(self, runner): 21 | if self.every_n_inner_iters(runner, self.interval) and runner.rank == 0: 22 | iter_time = (time.time() - self.t)/self.interval 23 | runner.log_buffer.update({'time': iter_time}) 24 | self.t = time.time() 25 | 26 | def after_run(self, runner): 27 | end_time = datetime.datetime.now() 28 | if runner.rank == 0: 29 | runner.logger.info("End time: {}".format(str(self.start_time))) 30 | runner.logger.info("Elapsed time: {}".format(str(end_time-self.start_time))) 31 | 32 | @HOOKS.register("IterTimerHook") 33 | def build_iter_time_hook(cfg): 34 | return IterTimerHook(interval=cfg.LOG_INTERVAL) -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/runner/hooks/logger/__init__.py: -------------------------------------------------------------------------------- 1 | from .text import TextLoggerHook, build_text_logger_hook -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/runner/hooks/logger/base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | from abc import ABCMeta, abstractmethod 3 | 4 | from ..hook import Hook 5 | 6 | 7 | class LoggerHook(Hook): 8 | """Base class for logger hooks. 9 | Args: 10 | interval (int): Logging interval (every k iterations). 11 | ignore_last (bool): Ignore the log of last iterations in each epoch 12 | if less than `interval`. 13 | reset_flag (bool): Whether to clear the output buffer after logging. 14 | """ 15 | 16 | __metaclass__ = ABCMeta 17 | 18 | def __init__(self, interval=10, ignore_last=True, reset_flag=False): 19 | self.interval = interval 20 | self.ignore_last = ignore_last 21 | self.reset_flag = reset_flag 22 | 23 | @abstractmethod 24 | def log(self, runner): 25 | pass 26 | 27 | def before_run(self, runner): 28 | for hook in runner.hooks[::-1]: 29 | if isinstance(hook, LoggerHook): 30 | hook.reset_flag = True 31 | break 32 | 33 | def before_epoch(self, runner): 34 | runner.log_buffer.clear() # clear logs of last epoch 35 | 36 | def after_train_iter(self, runner): 37 | if self.every_n_inner_iters(runner, self.interval): 38 | runner.log_buffer.average(self.interval) 39 | elif self.end_of_epoch(runner) and not self.ignore_last: 40 | # not precise but more stable 41 | runner.log_buffer.average(self.interval) 42 | 43 | if runner.log_buffer.ready: 44 | self.log(runner) 45 | if self.reset_flag: 46 | runner.log_buffer.clear_output() 47 | 48 | def after_train_epoch(self, runner): 49 | if runner.log_buffer.ready: 50 | self.log(runner) 51 | if self.reset_flag: 52 | runner.log_buffer.clear_output() 53 | 54 | def after_val_epoch(self, runner): 55 | runner.log_buffer.average() 56 | self.log(runner) 57 | if self.reset_flag: 58 | runner.log_buffer.clear_output() -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/runner/log_buffer.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | from collections import OrderedDict 3 | import torch 4 | 5 | import numpy as np 6 | 7 | 8 | class LogBuffer(object): 9 | 10 | def __init__(self): 11 | self.val_history = OrderedDict() 12 | self.n_history = OrderedDict() 13 | self.output = OrderedDict() 14 | self.ready = False 15 | 16 | def clear(self): 17 | self.val_history.clear() 18 | self.n_history.clear() 19 | self.clear_output() 20 | 21 | def clear_output(self): 22 | self.output.clear() 23 | self.ready = False 24 | 25 | def update(self, vars, count=1): 26 | assert isinstance(vars, dict) 27 | for key, var in vars.items(): 28 | if key not in self.val_history: 29 | self.val_history[key] = [] 30 | self.n_history[key] = [] 31 | if torch.is_tensor(var): 32 | if var.device.type=='cuda': 33 | var = var.cpu() 34 | var = var.detach().numpy() 35 | self.val_history[key].append(var) 36 | self.n_history[key].append(count) 37 | 38 | def average(self, n=0): 39 | """Average latest n values or all values""" 40 | assert n >= 0 41 | for key in self.val_history: 42 | if 'time' in key: 43 | self.output[key] = self.val_history[key][-1] 44 | elif 'image' not in key: # skip images 45 | values = np.array(self.val_history[key][-n:]) 46 | nums = np.array(self.n_history[key][-n:]) 47 | avg = np.sum(values * nums) / np.sum(nums) 48 | self.output[key] = avg 49 | self.ready = True -------------------------------------------------------------------------------- /pytorch/sagemakercv/utils/runner/priority.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | from enum import Enum 3 | 4 | 5 | class Priority(Enum): 6 | """Hook priority levels. 7 | +------------+------------+ 8 | | Level | Value | 9 | +============+============+ 10 | | HIGHEST | 0 | 11 | +------------+------------+ 12 | | VERY_HIGH | 10 | 13 | +------------+------------+ 14 | | HIGH | 30 | 15 | +------------+------------+ 16 | | NORMAL | 50 | 17 | +------------+------------+ 18 | | LOW | 70 | 19 | +------------+------------+ 20 | | VERY_LOW | 90 | 21 | +------------+------------+ 22 | | LOWEST | 100 | 23 | +------------+------------+ 24 | """ 25 | 26 | HIGHEST = 0 27 | VERY_HIGH = 10 28 | HIGH = 30 29 | NORMAL = 50 30 | LOW = 70 31 | VERY_LOW = 90 32 | LOWEST = 100 33 | 34 | 35 | def get_priority(priority): 36 | """Get priority value. 37 | Args: 38 | priority (int or str or :obj:`Priority`): Priority. 39 | Returns: 40 | int: The priority value. 41 | """ 42 | if isinstance(priority, int): 43 | if priority < 0 or priority > 100: 44 | raise ValueError('priority must be between 0 and 100') 45 | return priority 46 | elif isinstance(priority, Priority): 47 | return priority.value 48 | elif isinstance(priority, str): 49 | return Priority[priority.upper()].value 50 | else: 51 | raise TypeError('priority must be an integer or Priority enum value') 52 | -------------------------------------------------------------------------------- /pytorch/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | py_version = f"{sys.version_info.major}{sys.version_info.minor}" 4 | 5 | from setuptools import find_packages 6 | from setuptools import setup 7 | 8 | import torch 9 | 10 | torch_version = ''.join(torch.__version__.split('.')[:2]) 11 | 12 | if py_version=="36": 13 | pycocotools_whl = "https://sagemakercv.s3.us-west-2.amazonaws.com/cocoapi/pycocotools-2.0%2Bnv0.6.0-cp36-cp36m-linux_x86_64.whl" 14 | awsio_whl = "https://aws-s3-plugin.s3-us-west-2.amazonaws.com/binaries/0.0.1/93fdaed/awsio-0.0.1-cp36-cp36m-manylinux1_x86_64.whl" 15 | else: 16 | pycocotools_whl = "https://sagemakercv.s3.us-west-2.amazonaws.com/cocoapi/pycocotools-2.0%2Bnv0.6.0-cp38-cp38-linux_x86_64.whl" 17 | awsio_whl = "https://aws-s3-plugin.s3.us-west-2.amazonaws.com/binaries/0.0.1/1c3e69e/awsio-0.0.1-cp38-cp38-manylinux1_x86_64.whl" 18 | 19 | if torch_version=="16": 20 | smcv_utils_whl = "https://sagemakercv.s3.us-west-2.amazonaws.com/utils/pt-1.6/smcv_utils-0.0.1-cp36-cp36m-linux_x86_64.whl" 21 | elif torch_version=="17": 22 | smcv_utils_whl = "https://sagemakercv.s3.us-west-2.amazonaws.com/utils/pt-1.7/smcv_utils-0.0.1-cp36-cp36m-linux_x86_64.whl" 23 | elif torch_version=="18": 24 | smcv_utils_whl = "https://sagemakercv.s3.us-west-2.amazonaws.com/utils/pt-1.8/smcv_utils-0.0.1-cp36-cp36m-linux_x86_64.whl" 25 | elif torch_version=="19": 26 | smcv_utils_whl = "https://sagemakercv.s3.us-west-2.amazonaws.com/utils/pt-1.9/smcv_utils-0.0.1-cp38-cp38-linux_x86_64.whl" 27 | else: 28 | # build from source. this will take longer on training startup 29 | smcv_utils_whl = "git+https://github.com/aws/amazon-sagemakercv-utils-nvidia.git" 30 | 31 | install_requires = ["yacs", 32 | "matplotlib", 33 | "mpi4py", 34 | "opencv-python", 35 | f"pycocotools @ {pycocotools_whl}", 36 | f"smcv_utils @ {smcv_utils_whl}", 37 | f"awsio @ {awsio_whl}"] 38 | 39 | setup( 40 | name="sagemakercv", 41 | version="0.1", 42 | author="jbsnyder", 43 | url="https://github.com/aws-samples/amazon-sagemaker-cv", 44 | description="Computer vision in Pytorch with Amazon Sagemaker", 45 | packages=find_packages(exclude=("configs", "tests")), 46 | install_requires=install_requires, 47 | ) 48 | -------------------------------------------------------------------------------- /pytorch/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | from ast import literal_eval 4 | import torch 5 | 6 | import importlib 7 | import importlib.util 8 | import sys 9 | 10 | def import_file(module_name, file_path, make_importable=False): 11 | spec = importlib.util.spec_from_file_location(module_name, file_path) 12 | module = importlib.util.module_from_spec(spec) 13 | spec.loader.exec_module(module) 14 | if make_importable: 15 | sys.modules[module_name] = module 16 | return module 17 | 18 | def unarchive_data(data_dir, target='coco.tar'): 19 | print("Unarchiving COCO data") 20 | os.system('tar -xf {0} -C {1}'.format(os.path.join(data_dir, target), data_dir)) 21 | print(os.listdir(data_dir)) 22 | 23 | def get_training_world(): 24 | 25 | """ 26 | Calculates number of devices in Sagemaker distributed cluster 27 | """ 28 | 29 | # Get params of Sagemaker distributed cluster from predefined env variables 30 | num_gpus = int(os.environ["SM_NUM_GPUS"]) 31 | num_cpus = int(os.environ["SM_NUM_CPUS"]) 32 | hosts = json.loads(os.environ["SM_HOSTS"]) 33 | current_host = os.environ["SM_CURRENT_HOST"] 34 | 35 | # Define PyTorch training world 36 | world = {} 37 | world["number_of_processes"] = num_gpus if num_gpus > 0 else num_cpus 38 | world["number_of_machines"] = len(hosts) 39 | world["size"] = world["number_of_processes"] * world["number_of_machines"] 40 | world["machine_rank"] = hosts.index(current_host) 41 | world["master_addr"] = hosts[0] 42 | world["master_port"] = "55555" # port is defined by Sagemaker 43 | 44 | return world 45 | 46 | def is_sm(): 47 | """Check if we're running inside a sagemaker training job 48 | """ 49 | sm_training_env = os.environ.get('SM_TRAINING_ENV', None) 50 | if not isinstance(sm_training_env, dict): 51 | return False 52 | return True 53 | 54 | def is_sm_dist(): 55 | """Check if environment variables are set for Sagemaker Data Distributed 56 | This has not been tested 57 | """ 58 | sm_training_env = os.environ.get('SM_TRAINING_ENV', None) 59 | if not isinstance(sm_training_env, dict): 60 | return False 61 | sm_training_env = literal_eval(sm_training_env) 62 | additional_framework_parameters = sm_training_env.get('additional_framework_parameters', None) 63 | if not isinstance(additional_framework_parameters, dict): 64 | return False 65 | return bool(additional_framework_parameters.get('sagemaker_distributed_dataparallel_enabled', False)) 66 | 67 | def get_herring_world(): 68 | return {"machine_rank": 0, "number_of_processes": 8, "size": 8} 69 | -------------------------------------------------------------------------------- /tensorflow/configs/__init__.py: -------------------------------------------------------------------------------- 1 | from .default_config import _C as cfg 2 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # -*- coding: utf-8 -*- 4 | __version__ = '0.0.0.0' 5 | __all__ = ['__version__'] 6 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/core/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .anchors import AnchorGenerator, AnchorLabeler 19 | from .roi_ops import ProposeROIs 20 | from .training_ops import TargetEncoder, RandomSampler 21 | from .postprocess_ops import BoxDetector 22 | from .spatial_transform_ops import GenericRoIExtractor 23 | 24 | from .builder import (ANCHORS, 25 | ENCODERS, 26 | ROI_EXTRACTORS, 27 | INFERENCE_DETECTORS, 28 | build_anchor_generator, 29 | build_anchor_labeler, 30 | build_anchors, 31 | build_roi_selector) -------------------------------------------------------------------------------- /tensorflow/sagemakercv/data/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .coco.dataloader import CocoInputReader 19 | from .builder import build_dataset -------------------------------------------------------------------------------- /tensorflow/sagemakercv/data/builder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | import os 19 | from sagemakercv.utils import Registry 20 | from sagemakercv.utils.dist_utils import MPI_size 21 | 22 | DATASETS = Registry() 23 | 24 | def build_dataset(cfg, mode='train'): 25 | if mode=='train': 26 | file_pattern = cfg.PATHS.TRAIN_FILE_PATTERN 27 | elif mode in ['eval', 'infer']: 28 | file_pattern = cfg.PATHS.VAL_FILE_PATTERN 29 | else: 30 | raise NotImplementedError 31 | params=dict( 32 | visualize_images_summary=cfg.INPUT.VISUALIZE_IMAGES_SUMMARY, 33 | image_size=cfg.INPUT.IMAGE_SIZE, 34 | min_level=cfg.MODEL.DENSE.MIN_LEVEL, 35 | max_level=cfg.MODEL.DENSE.MAX_LEVEL, 36 | num_scales=cfg.MODEL.DENSE.NUM_SCALES, 37 | aspect_ratios=cfg.MODEL.DENSE.ASPECT_RATIOS, 38 | anchor_scale=cfg.MODEL.DENSE.ANCHOR_SCALE, 39 | include_mask=cfg.MODEL.INCLUDE_MASK, 40 | skip_crowd_during_training=cfg.INPUT.SKIP_CROWDS_DURING_TRAINING, 41 | include_groundtruth_in_features=cfg.INPUT.INCLUDE_GROUNDTRUTH_IN_FEATURES, 42 | use_category=cfg.INPUT.USE_CATEGORY, 43 | augment_input_data=cfg.INPUT.AUGMENT_INPUT_DATA, 44 | gt_mask_size=cfg.INPUT.GT_MASK_SIZE, 45 | num_classes=cfg.INPUT.NUM_CLASSES, 46 | rpn_positive_overlap=cfg.MODEL.DENSE.POSITIVE_OVERLAP, 47 | rpn_negative_overlap=cfg.MODEL.DENSE.NEGATIVE_OVERLAP, 48 | rpn_batch_size_per_im=cfg.MODEL.DENSE.BATCH_SIZE_PER_IMAGE, 49 | rpn_fg_fraction=cfg.MODEL.DENSE.FG_FRACTION, 50 | ) 51 | dataset = DATASETS[cfg.INPUT.DATALOADER] 52 | return dataset(file_pattern, 53 | params, 54 | mode=mode, 55 | batch_size=cfg.INPUT.TRAIN_BATCH_SIZE//MPI_size() if mode=='train' \ 56 | else cfg.INPUT.EVAL_BATCH_SIZE//MPI_size(), 57 | use_instance_mask=cfg.MODEL.INCLUDE_MASK if mode=='train' else False, 58 | )() -------------------------------------------------------------------------------- /tensorflow/sagemakercv/data/coco/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/tensorflow/sagemakercv/data/coco/__init__.py -------------------------------------------------------------------------------- /tensorflow/sagemakercv/data/coco/process_coco_tfrecord.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | set -x 3 | 4 | 5 | if [ -z "$2" ]; then 6 | echo "usage download_and_preprocess_coco.sh [data dir] [output dir]" 7 | exit 8 | fi 9 | 10 | echo "Cloning Tensorflow models directory (for conversion utilities)" 11 | if [ ! -e tf-models ]; then 12 | git clone http://github.com/tensorflow/models tf-models 13 | fi 14 | 15 | (cd tf-models/research && protoc object_detection/protos/*.proto --python_out=.) 16 | 17 | mv tf-models/research/object_detection . 18 | rm -rf tf-models 19 | 20 | # Create the output directories. 21 | COCO_DIR=$1 22 | OUTPUT_DIR=$2 23 | TRAIN_IMAGE_DIR=${COCO_DIR}/train2017 24 | VAL_IMAGE_DIR=${COCO_DIR}/val2017 25 | TRAIN_OBJECT_ANNOTATIONS_FILE=$COCO_DIR/annotations/instances_train2017.json 26 | VAL_OBJECT_ANNOTATIONS_FILE=$COCO_DIR/annotations/instances_val2017.json 27 | TRAIN_CAPTION_FILE=$COCO_DIR/annotations/captions_train2017.json 28 | VAL_CAPTION_FILE=$COCO_DIR/annotations/captions_val2017.json 29 | mkdir -p "${OUTPUT_DIR}" 30 | 31 | python create_coco_tf_record.py --logtostderr \ 32 | --include_masks \ 33 | --train_image_dir="${TRAIN_IMAGE_DIR}" \ 34 | --val_image_dir="${VAL_IMAGE_DIR}" \ 35 | --train_object_annotations_file="${TRAIN_OBJECT_ANNOTATIONS_FILE}" \ 36 | --val_object_annotations_file="${VAL_OBJECT_ANNOTATIONS_FILE}" \ 37 | --train_caption_annotations_file="${TRAIN_CAPTION_FILE}" \ 38 | --val_caption_annotations_file="${VAL_CAPTION_FILE}" \ 39 | --output_dir="${OUTPUT_DIR}" 40 | 41 | rm -rf object_detection 42 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/detection/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .backbones import * 19 | from .dense_heads import * 20 | from .detectors import * 21 | from .necks import * 22 | from .roi_heads import * 23 | from .builder import * 24 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/detection/backbones/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .resnet import Resnet_Model -------------------------------------------------------------------------------- /tensorflow/sagemakercv/detection/builder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from sagemakercv.utils import Registry 19 | 20 | BACKBONES = Registry() 21 | NECKS = Registry() 22 | ROI_EXTRACTORS = Registry() 23 | SHARED_HEADS = Registry() 24 | HEADS = Registry() 25 | DETECTORS = Registry() 26 | 27 | def build_backbone(cfg): 28 | backbone_type = BACKBONES[cfg.MODEL.BACKBONE.CONV_BODY] 29 | return backbone_type(sub_type=cfg.MODEL.BACKBONE.CONV_BODY, 30 | data_format=cfg.MODEL.BACKBONE.DATA_FORMAT, 31 | trainable=cfg.MODEL.BACKBONE.TRAINABLE, 32 | finetune_bn=cfg.MODEL.BACKBONE.FINETUNE_BN, 33 | norm_type=cfg.MODEL.BACKBONE.NORM_TYPE) 34 | 35 | def build_dense_head(cfg): 36 | return HEADS[cfg.MODEL.DENSE.RPN_HEAD](cfg) 37 | 38 | def build_neck(cfg): 39 | return NECKS[cfg.MODEL.BACKBONE.NECK](cfg) 40 | 41 | def build_box_head(cfg): 42 | return HEADS[cfg.MODEL.FRCNN.BBOX_HEAD](cfg) 43 | 44 | def build_mask_head(cfg): 45 | return HEADS[cfg.MODEL.MRCNN.MASK_HEAD](cfg) 46 | 47 | def build_roi_head(cfg): 48 | return HEADS[cfg.MODEL.RCNN.ROI_HEAD](cfg) 49 | 50 | def build_detector(cfg): 51 | return DETECTORS[cfg.MODEL.DETECTOR](cfg) 52 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/detection/dense_heads/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .anchor_head import AnchorHead 19 | from .rpn_head import StandardRPNHead, build_standard_rpn_head -------------------------------------------------------------------------------- /tensorflow/sagemakercv/detection/detectors/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .two_stage_detector import TwoStageDetector, build_two_stage_detector -------------------------------------------------------------------------------- /tensorflow/sagemakercv/detection/necks/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .fpn import FPN -------------------------------------------------------------------------------- /tensorflow/sagemakercv/detection/roi_heads/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .standard_roi_head import StandardRoIHead, build_standard_roi_head 19 | from .bbox_heads import * 20 | from .mask_heads import * 21 | from .cascade_roi_head import CascadeRoIHead, build_cascade_roi_head -------------------------------------------------------------------------------- /tensorflow/sagemakercv/detection/roi_heads/bbox_heads/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .standard_bbox_head import StandardBBoxHead 19 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/detection/roi_heads/mask_heads/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .standard_mask_head import StandardMaskHead 19 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/layers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-cv/806823e6a14c25e4cc184390a0a3633baa97f379/tensorflow/sagemakercv/layers/__init__.py -------------------------------------------------------------------------------- /tensorflow/sagemakercv/layers/evo_norm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | import tensorflow as tf 19 | 20 | class EvoNorm2dS0(tf.keras.layers.Layer): 21 | 22 | def __init__(self, channels, groups=32, eps=1e-5, nonlinear=True): 23 | super(EvoNorm2dS0, self).__init__() 24 | self.groups = groups 25 | self.eps = eps 26 | self.nonlinear = nonlinear 27 | self.gamma = self.add_weight(name="gamma", shape=(1, 1, 1, channels), initializer=tf.initializers.Ones()) 28 | self.beta = self.add_weight(name="beta", shape=(1, 1, 1, channels), initializer=tf.initializers.Zeros()) 29 | self.v = self.add_weight(name="v", shape=(1, 1, 1, channels), initializer=tf.initializers.Ones()) 30 | 31 | def _group_std(self, x): 32 | input_shape = tf.shape(x) 33 | N = input_shape[0] 34 | H = input_shape[1] 35 | W = input_shape[2] 36 | C = input_shape[3] 37 | num_groups = C // self.groups 38 | x = tf.reshape(x, [N, H, W, self.groups, num_groups]) 39 | 40 | _, var = tf.nn.moments(x, [1, 2, 4], keepdims=True) 41 | std = tf.sqrt(var + self.eps) 42 | std = tf.broadcast_to(std, [N, H, W, self.groups, num_groups]) 43 | return tf.reshape(std, input_shape) 44 | 45 | """ 46 | def build(self, input_shape): 47 | in_channels = input_shape[3] 48 | ones_init = tf.ones_initializer() 49 | zeros_init = tf.zeros_initializer() 50 | self.gamma = tf.Variable(initial_value=ones_init(shape=[1, 1, 1, in_channels]), name='gamma') 51 | self.beta = tf.Variable(initial_value=zeros_init(shape=[1, 1, 1, in_channels]), name='beta') 52 | if self.nonlinear: 53 | self.v = tf.Variable(initial_value=ones_init(shape=[1, 1, 1, in_channels]), name='v') 54 | """ 55 | 56 | @tf.function 57 | def call(self, x): 58 | if self.nonlinear: 59 | num = x * tf.nn.sigmoid(self.v * x) 60 | return num / self._group_std(x) * self.gamma + self.beta 61 | else: 62 | return x * self.gamma + self.beta 63 | 64 | if __name__ == "__main__": 65 | # test 66 | test_in = tf.random.uniform([256, 40, 40,128]) 67 | out = EvoNorm2dS0(groups=32)(test_in) 68 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/training/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .losses import * 19 | from .optimizers import * 20 | from .trainers import * 21 | from .builder import build_optimizer, build_scheduler, build_trainer 22 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/training/builder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | import tensorflow as tf 19 | from sagemakercv.utils import Registry 20 | 21 | LOSSES = Registry() 22 | OPTIMIZERS = Registry() 23 | SCHEDULERS = Registry() 24 | SAMPLERS = Registry() 25 | TRAINERS = Registry() 26 | 27 | # TODO Add losses to builders 28 | 29 | def build_scheduler(cfg): 30 | scheduler = SCHEDULERS[cfg.SOLVER.SCHEDULE](cfg) 31 | if cfg.SOLVER.WARMUP: 32 | scheduler = SCHEDULERS[cfg.SOLVER.WARMUP](cfg, scheduler) 33 | return scheduler 34 | 35 | def build_optimizer(cfg): 36 | scheduler = build_scheduler(cfg) 37 | optimizer = OPTIMIZERS[cfg.SOLVER.OPTIMIZER](cfg, scheduler) 38 | if cfg.SOLVER.FP16: 39 | if int(tf.__version__.split('.')[1])<4: 40 | optimizer = tf.keras.mixed_precision.experimental.LossScaleOptimizer(optimizer, 'dynamic') 41 | else: 42 | optimizer = tf.keras.mixed_precision.LossScaleOptimizer(optimizer, 43 | dynamic=True, 44 | initial_scale=2 ** 15, 45 | dynamic_growth_steps=2000 46 | ) 47 | return optimizer 48 | 49 | def build_trainer(cfg, model, optimizer, dist=None): 50 | return TRAINERS[cfg.SOLVER.TRAINER](cfg, model, optimizer, dist) -------------------------------------------------------------------------------- /tensorflow/sagemakercv/training/losses/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .frcnn_losses import FastRCNNLoss, MaskRCNNLoss 19 | from .rpn_losses import RPNLoss 20 | 21 | __all__ = ['FastRCNNLoss', 'MaskRCNNLoss', 'RPNLoss'] -------------------------------------------------------------------------------- /tensorflow/sagemakercv/training/optimizers/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .schedulers import * 19 | from .momentum import build_momentum_optimizer 20 | from .novograd import build_novograd_optimizer -------------------------------------------------------------------------------- /tensorflow/sagemakercv/training/optimizers/schedulers/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .schedulers import build_piecewise_scheduler, build_cosine_scheduler 19 | from .warmup_scheduler import LinearWarmup -------------------------------------------------------------------------------- /tensorflow/sagemakercv/training/optimizers/schedulers/schedulers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | import tensorflow as tf 19 | from ...builder import SCHEDULERS 20 | 21 | @SCHEDULERS.register("PiecewiseConstantDecay") 22 | def build_piecewise_scheduler(cfg): 23 | assert len(cfg.SOLVER.DECAY_STEPS)==len(cfg.SOLVER.DECAY_LR) 24 | scheduler = tf.keras.optimizers.schedules.PiecewiseConstantDecay 25 | return scheduler(cfg.SOLVER.DECAY_STEPS, 26 | [cfg.SOLVER.LR] + [cfg.SOLVER.LR * decay for decay in cfg.SOLVER.DECAY_LR]) 27 | 28 | @SCHEDULERS.register("CosineDecay") 29 | def build_cosine_scheduler(cfg): 30 | scheduler = tf.keras.experimental.CosineDecay 31 | return scheduler(cfg.SOLVER.LR, 32 | cfg.SOLVER.MAX_ITERS, 33 | cfg.SOLVER.ALPHA) 34 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .registry import Registry 19 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/fileio/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | from .handlers import BaseFileHandler, JsonHandler, PickleHandler, YamlHandler 3 | from .io import dump, load, register_handler 4 | from .parse import dict_from_file, list_from_file 5 | 6 | __all__ = [ 7 | 'load', 'dump', 'register_handler', 'BaseFileHandler', 'JsonHandler', 8 | 'PickleHandler', 'YamlHandler', 'list_from_file', 'dict_from_file' 9 | ] 10 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/fileio/handlers/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | from .base import BaseFileHandler 3 | from .json_handler import JsonHandler 4 | from .pickle_handler import PickleHandler 5 | from .yaml_handler import YamlHandler 6 | 7 | __all__ = ['BaseFileHandler', 'JsonHandler', 'PickleHandler', 'YamlHandler'] 8 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/fileio/handlers/base.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | from abc import ABCMeta, abstractmethod 3 | 4 | 5 | class BaseFileHandler(object): 6 | 7 | __metaclass__ = ABCMeta # python 2 compatibility 8 | 9 | @abstractmethod 10 | def load_from_fileobj(self, file, **kwargs): 11 | pass 12 | 13 | @abstractmethod 14 | def dump_to_fileobj(self, obj, file, **kwargs): 15 | pass 16 | 17 | @abstractmethod 18 | def dump_to_str(self, obj, **kwargs): 19 | pass 20 | 21 | def load_from_path(self, filepath, mode='r', **kwargs): 22 | with open(filepath, mode) as f: 23 | return self.load_from_fileobj(f, **kwargs) 24 | 25 | def dump_to_path(self, obj, filepath, mode='w', **kwargs): 26 | with open(filepath, mode) as f: 27 | self.dump_to_fileobj(obj, f, **kwargs) 28 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/fileio/handlers/json_handler.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | import json 3 | import numpy as np 4 | 5 | from .base import BaseFileHandler 6 | 7 | class NumpyEncoder(json.JSONEncoder): 8 | def default(self, obj): 9 | if isinstance(obj, np.integer): 10 | return int(obj) 11 | elif isinstance(obj, np.floating): 12 | return float(obj) 13 | elif isinstance(obj, np.ndarray): 14 | return obj.tolist() 15 | else: 16 | return super(NumpyEncoder, self).default(obj) 17 | 18 | class JsonHandler(BaseFileHandler): 19 | 20 | def load_from_fileobj(self, file): 21 | return json.load(file) 22 | 23 | def dump_to_fileobj(self, obj, file, **kwargs): 24 | obj = json.dumps(obj, cls=NumpyEncoder) 25 | json.dump(obj, file, **kwargs) 26 | 27 | def dump_to_str(self, obj, **kwargs): 28 | return json.dumps(obj, **kwargs) 29 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/fileio/handlers/pickle_handler.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | from six.moves import cPickle as pickle 3 | 4 | from .base import BaseFileHandler 5 | 6 | 7 | class PickleHandler(BaseFileHandler): 8 | 9 | def load_from_fileobj(self, file, **kwargs): 10 | return pickle.load(file, **kwargs) 11 | 12 | def load_from_path(self, filepath, **kwargs): 13 | return super(PickleHandler, self).load_from_path( 14 | filepath, mode='rb', **kwargs) 15 | 16 | def dump_to_str(self, obj, **kwargs): 17 | kwargs.setdefault('protocol', 2) 18 | return pickle.dumps(obj, **kwargs) 19 | 20 | def dump_to_fileobj(self, obj, file, **kwargs): 21 | kwargs.setdefault('protocol', 2) 22 | pickle.dump(obj, file, **kwargs) 23 | 24 | def dump_to_path(self, obj, filepath, **kwargs): 25 | super(PickleHandler, self).dump_to_path( 26 | obj, filepath, mode='wb', **kwargs) 27 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/fileio/handlers/yaml_handler.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | import yaml 3 | 4 | try: 5 | from yaml import CLoader as Loader, CDumper as Dumper 6 | except ImportError: 7 | from yaml import Loader, Dumper 8 | 9 | from .base import BaseFileHandler # isort:skip 10 | 11 | 12 | class YamlHandler(BaseFileHandler): 13 | 14 | def load_from_fileobj(self, file, **kwargs): 15 | kwargs.setdefault('Loader', Loader) 16 | return yaml.load(file, **kwargs) 17 | 18 | def dump_to_fileobj(self, obj, file, **kwargs): 19 | kwargs.setdefault('Dumper', Dumper) 20 | yaml.dump(obj, file, **kwargs) 21 | 22 | def dump_to_str(self, obj, **kwargs): 23 | kwargs.setdefault('Dumper', Dumper) 24 | return yaml.dump(obj, **kwargs) 25 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/fileio/parse.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Open-MMLab. All rights reserved. 2 | def list_from_file(filename, prefix='', offset=0, max_num=0): 3 | """Load a text file and parse the content as a list of strings. 4 | 5 | Args: 6 | filename (str): Filename. 7 | prefix (str): The prefix to be inserted to the begining of each item. 8 | offset (int): The offset of lines. 9 | max_num (int): The maximum number of lines to be read, 10 | zeros and negatives mean no limitation. 11 | 12 | Returns: 13 | list[str]: A list of strings. 14 | """ 15 | cnt = 0 16 | item_list = [] 17 | with open(filename, 'r') as f: 18 | for _ in range(offset): 19 | f.readline() 20 | for line in f: 21 | if max_num > 0 and cnt >= max_num: 22 | break 23 | item_list.append(prefix + line.rstrip('\n')) 24 | cnt += 1 25 | return item_list 26 | 27 | 28 | def dict_from_file(filename, key_type=str): 29 | """Load a text file and parse the content as a dict. 30 | 31 | Each line of the text file will be two or more columns splited by 32 | whitespaces or tabs. The first column will be parsed as dict keys, and 33 | the following columns will be parsed as dict values. 34 | 35 | Args: 36 | filename(str): Filename. 37 | key_type(type): Type of the dict's keys. str is user by default and 38 | type conversion will be performed if specified. 39 | 40 | Returns: 41 | dict: The parsed contents. 42 | """ 43 | mapping = {} 44 | with open(filename, 'r') as f: 45 | for line in f: 46 | items = line.rstrip('\n').split() 47 | assert len(items) >= 2 48 | key = key_type(items[0]) 49 | val = items[1:] if len(items) > 2 else items[1] 50 | mapping[key] = val 51 | return mapping 52 | 53 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/imports.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | import importlib 19 | import importlib.util 20 | import sys 21 | 22 | def import_file(module_name, file_path, make_importable=False): 23 | spec = importlib.util.spec_from_file_location(module_name, file_path) 24 | module = importlib.util.module_from_spec(spec) 25 | spec.loader.exec_module(module) 26 | if make_importable: 27 | sys.modules[module_name] = module 28 | return module -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/logger.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | __all__ = [ 19 | "SingletonMetaClass", 20 | ] 21 | 22 | 23 | class SingletonMetaClass(type): 24 | 25 | _instances = {} 26 | 27 | def __call__(cls, *args, **kwargs): 28 | 29 | if cls not in cls._instances: 30 | cls._instances[cls] = super(SingletonMetaClass, cls).__call__(*args, **kwargs) 31 | 32 | return cls._instances[cls] 33 | 34 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/metaclasses.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | __all__ = [ 19 | "SingletonMetaClass", 20 | ] 21 | 22 | 23 | class SingletonMetaClass(type): 24 | 25 | _instances = {} 26 | 27 | def __call__(cls, *args, **kwargs): 28 | 29 | if cls not in cls._instances: 30 | cls._instances[cls] = super(SingletonMetaClass, cls).__call__(*args, **kwargs) 31 | 32 | return cls._instances[cls] 33 | 34 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/paths_catalog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2018, Facebook, Inc. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | """Centralized catalog of paths.""" 19 | 20 | import os 21 | 22 | class DatasetCatalog(object): 23 | DATA_DIR = os.path.expanduser("~/data") 24 | DATASETS = { 25 | "coco_2017_train": { 26 | "img_file_pattern": "coco/train/train*", 27 | "ann_file": "coco/annotations/instances_train2017.json" 28 | }, 29 | "coco_2017_val": { 30 | "img_file_pattern": "coco/val/val*", 31 | "ann_file": "coco/annotations/instances_val2017.json" 32 | }, 33 | } 34 | 35 | WEIGHTS = os.path.join(DATA_DIR, 'weights/tf/resnet/resnet-nhwc-2018-02-07/model.ckpt-112603') 36 | 37 | OUTPUT_DIR = "/home/ubuntu/models" 38 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/registry.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2018, Facebook, Inc. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | 19 | def _register_generic(module_dict, module_name, module): 20 | assert module_name not in module_dict 21 | module_dict[module_name] = module 22 | 23 | 24 | class Registry(dict): 25 | ''' 26 | A helper class for managing registering modules, it extends a dictionary 27 | and provides a register functions. 28 | 29 | Eg. creeting a registry: 30 | some_registry = Registry({"default": default_module}) 31 | 32 | There're two ways of registering new modules: 33 | 1): normal way is just calling register function: 34 | def foo(): 35 | ... 36 | some_registry.register("foo_module", foo) 37 | 2): used as decorator when declaring the module: 38 | @some_registry.register("foo_module") 39 | @some_registry.register("foo_modeul_nickname") 40 | def foo(): 41 | ... 42 | 43 | Access of module is just like using a dictionary, eg: 44 | f = some_registry["foo_modeul"] 45 | ''' 46 | def __init__(self, *args, **kwargs): 47 | super(Registry, self).__init__(*args, **kwargs) 48 | 49 | def register(self, module_name, module=None): 50 | # used as function call 51 | if module is not None: 52 | _register_generic(self, module_name, module) 53 | return 54 | 55 | # used as decorator 56 | def register_fn(fn): 57 | _register_generic(self, module_name, fn) 58 | return fn 59 | 60 | return register_fn 61 | 62 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/runner/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .log_buffer import LogBuffer 19 | from .runner import Runner 20 | from .priority import get_priority 21 | from .hooks import * 22 | from .builder import build_hooks 23 | 24 | __all__ = [ 25 | 'Runner', 'LogBuffer', 'get_priority'] 26 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/runner/builder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from sagemakercv.utils import Registry 19 | 20 | HOOKS = Registry() 21 | 22 | def build_hooks(cfg): 23 | return [HOOKS[hook](cfg) for hook in cfg.HOOKS] 24 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/runner/hooks/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .checkpoint import CheckpointHook, build_checkpoint_hook 19 | from .hook import Hook 20 | from .iter_timer import IterTimerHook 21 | from .evaluation import CocoEvaluator, build_coco_evaluator 22 | from .logger import (TextLoggerHook, 23 | TensorboardMetricsLogger, 24 | build_text_logger_hook, 25 | build_tensorboard_metrics_logger) 26 | # disable because of term issue in SM 27 | # from .system_monitor import SystemMonitor, build_system_monitor 28 | from .profiler import Profiler, build_profiler 29 | from .graph_visualizer import GraphVisualizer, build_graph_visualizer 30 | from .image_visualizer import ImageVisualizer, build_image_visualizer 31 | 32 | __all__ = ['CheckpointHook', 33 | 'Hook', 34 | 'IterTimerHook', 35 | 'CocoEvaluator', 36 | 'TextLoggerHook', 37 | 'TensorboardMetricsLogger', 38 | 'Profiler', 39 | 'GraphVisualizer', 40 | 'ImageVisualizer'] 41 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/runner/hooks/graph_visualizer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from sagemakercv.utils.runner.hooks import Hook 19 | from sagemakercv.utils.dist_utils import master_only 20 | import tensorflow as tf 21 | from ..builder import HOOKS 22 | 23 | class GraphVisualizer(Hook): 24 | 25 | def __init__(self, step=1): 26 | self.step = step 27 | 28 | @master_only 29 | def before_train_iter(self, runner): 30 | if runner.iter==self.step: 31 | tf.summary.trace_on(graph=True, profiler=True) 32 | 33 | @master_only 34 | def after_train_iter(self, runner): 35 | if runner.iter==self.step: 36 | writer = tf.summary.create_file_writer(runner.tensorboard_dir) 37 | with writer.as_default(): 38 | tf.summary.trace_export( 39 | name="graph_trace", 40 | step=runner.iter, 41 | profiler_outdir=runner.work_dir) 42 | writer.close() 43 | 44 | @HOOKS.register("GraphVisualizer") 45 | def build_graph_visualizer(cfg): 46 | return GraphVisualizer() 47 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/runner/hooks/hook.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2019, Open-MMLab. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | class Hook(object): 19 | 20 | def before_run(self, runner): 21 | pass 22 | 23 | def after_run(self, runner): 24 | pass 25 | 26 | def before_epoch(self, runner): 27 | pass 28 | 29 | def after_epoch(self, runner): 30 | pass 31 | 32 | def before_iter(self, runner): 33 | pass 34 | 35 | def after_iter(self, runner): 36 | pass 37 | 38 | def before_train_epoch(self, runner): 39 | self.before_epoch(runner) 40 | 41 | def before_val_epoch(self, runner): 42 | self.before_epoch(runner) 43 | 44 | def after_train_epoch(self, runner): 45 | self.after_epoch(runner) 46 | 47 | def after_val_epoch(self, runner): 48 | self.after_epoch(runner) 49 | 50 | def before_train_iter(self, runner): 51 | self.before_iter(runner) 52 | 53 | def before_val_iter(self, runner): 54 | self.before_iter(runner) 55 | 56 | def after_train_iter(self, runner): 57 | self.after_iter(runner) 58 | 59 | def after_val_iter(self, runner): 60 | self.after_iter(runner) 61 | 62 | def every_n_epochs(self, runner, n): 63 | return (runner.epoch + 1) % n == 0 if n > 0 else False 64 | 65 | def every_n_inner_iters(self, runner, n): 66 | return (runner.inner_iter + 1) % n == 0 if n > 0 else False 67 | 68 | def every_n_iters(self, runner, n): 69 | return (runner.iter + 1) % n == 0 if n > 0 else False 70 | 71 | def end_of_epoch(self, runner): 72 | return runner.inner_iter + 1 == runner.num_examples 73 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/runner/hooks/iter_timer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2019, Open-MMLab. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | import time 19 | import datetime 20 | from ..builder import HOOKS 21 | 22 | from .hook import Hook 23 | 24 | 25 | class IterTimerHook(Hook): 26 | 27 | def __init__(self, interval=25): 28 | self.interval = interval 29 | 30 | def before_run(self, runner): 31 | self.start_time = datetime.datetime.now() 32 | if runner.rank == 0: 33 | runner.logger.info("Start time: {}".format(str(self.start_time))) 34 | 35 | def before_epoch(self, runner): 36 | self.t = time.time() 37 | 38 | def after_iter(self, runner): 39 | if self.every_n_inner_iters(runner, self.interval) and runner.rank == 0: 40 | iter_time = (time.time() - self.t)/self.interval 41 | runner.log_buffer.update({'time': iter_time}) 42 | runner.log_buffer.update({'images/s': runner.train_batch_size/iter_time}) 43 | self.t = time.time() 44 | 45 | def after_run(self, runner): 46 | end_time = datetime.datetime.now() 47 | if runner.rank == 0: 48 | runner.logger.info("End time: {}".format(str(self.start_time))) 49 | runner.logger.info("Elapsed time: {}".format(str(end_time-self.start_time))) 50 | 51 | @HOOKS.register("IterTimerHook") 52 | def build_iter_timer_hook(cfg): 53 | return IterTimerHook(interval=cfg.LOG_INTERVAL) -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/runner/hooks/logger/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from .text import TextLoggerHook, build_text_logger_hook 19 | from .tensorboard import TensorboardMetricsLogger, build_tensorboard_metrics_logger -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/runner/hooks/logger/base.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2019, Open-MMLab. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from abc import ABCMeta, abstractmethod 19 | 20 | from ..hook import Hook 21 | 22 | 23 | class LoggerHook(Hook): 24 | """Base class for logger hooks. 25 | Args: 26 | interval (int): Logging interval (every k iterations). 27 | ignore_last (bool): Ignore the log of last iterations in each epoch 28 | if less than `interval`. 29 | reset_flag (bool): Whether to clear the output buffer after logging. 30 | """ 31 | 32 | __metaclass__ = ABCMeta 33 | 34 | def __init__(self, interval=10, ignore_last=True, reset_flag=False): 35 | self.interval = interval 36 | self.ignore_last = ignore_last 37 | self.reset_flag = reset_flag 38 | 39 | @abstractmethod 40 | def log(self, runner): 41 | pass 42 | 43 | def before_run(self, runner): 44 | for hook in runner.hooks[::-1]: 45 | if isinstance(hook, LoggerHook): 46 | hook.reset_flag = True 47 | break 48 | 49 | def before_epoch(self, runner): 50 | runner.log_buffer.clear() # clear logs of last epoch 51 | 52 | def after_train_iter(self, runner): 53 | if self.every_n_inner_iters(runner, self.interval): 54 | runner.log_buffer.average(self.interval) 55 | elif self.end_of_epoch(runner) and not self.ignore_last: 56 | # not precise but more stable 57 | runner.log_buffer.average(self.interval) 58 | 59 | if runner.log_buffer.ready: 60 | self.log(runner) 61 | if self.reset_flag: 62 | runner.log_buffer.clear_output() 63 | 64 | def after_train_epoch(self, runner): 65 | if runner.log_buffer.ready: 66 | self.log(runner) 67 | if self.reset_flag: 68 | runner.log_buffer.clear_output() 69 | 70 | def after_val_epoch(self, runner): 71 | runner.log_buffer.average() 72 | self.log(runner) 73 | if self.reset_flag: 74 | runner.log_buffer.clear_output() -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/runner/hooks/logger/tensorboard.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | import os 19 | import re 20 | import tensorflow as tf 21 | from s3fs import S3FileSystem 22 | from concurrent.futures import ThreadPoolExecutor 23 | from sagemakercv.utils.dist_utils import master_only 24 | from .base import LoggerHook 25 | from ...builder import HOOKS 26 | 27 | class TensorboardMetricsLogger(LoggerHook): 28 | 29 | def __init__(self, 30 | name='metrics', 31 | re_match='.*loss', 32 | interval=100, 33 | image_interval=None, 34 | ignore_last=True, 35 | reset_flag=True): 36 | super(TensorboardMetricsLogger, self).__init__(interval, ignore_last, 37 | reset_flag) 38 | self.name = name 39 | if isinstance(re_match, str): 40 | self.re_match = [re_match] 41 | else: 42 | self.re_match = re_match 43 | 44 | @master_only 45 | def log(self, runner): 46 | matched_tensors = [] 47 | for expression in self.re_match: 48 | matched_tensors.extend(list(filter(re.compile(expression).match, 49 | runner.log_buffer.output.keys()))) 50 | writer = tf.summary.create_file_writer(runner.tensorboard_dir) 51 | with writer.as_default(): 52 | for var in matched_tensors: 53 | tag = '{}/{}'.format(self.name, var) 54 | record = runner.log_buffer.output[var] 55 | if isinstance(record, str): 56 | tf.summary.text(tag, record, step=runner.iter) 57 | else: 58 | tf.summary.scalar(tag, record, step=runner.iter) 59 | writer.close() 60 | 61 | @HOOKS.register("TensorboardMetricsLogger") 62 | def build_tensorboard_metrics_logger(cfg): 63 | return TensorboardMetricsLogger(interval=cfg.LOG_INTERVAL) -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/runner/hooks/profiler.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2021, Amazon Web Services. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from sagemakercv.utils.runner.hooks import Hook 19 | from sagemakercv.utils.dist_utils import master_only 20 | import tensorflow as tf 21 | from ..builder import HOOKS 22 | 23 | class Profiler(Hook): 24 | 25 | def __init__(self, start_iter=1024, stop_iter=1152): 26 | self.start_iter = start_iter 27 | self.stop_iter = stop_iter 28 | 29 | @master_only 30 | def after_train_iter(self, runner): 31 | if runner.iter == self.start_iter: 32 | tf.profiler.experimental.start(runner.tensorboard_dir) 33 | elif runner.iter == self.stop_iter: 34 | tf.profiler.experimental.stop() 35 | 36 | @HOOKS.register("Profiler") 37 | def build_profiler(cfg): 38 | return Profiler() -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/runner/log_buffer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2019, Open-MMLab. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from collections import OrderedDict 19 | import tensorflow as tf 20 | 21 | import numpy as np 22 | 23 | 24 | class LogBuffer(object): 25 | 26 | def __init__(self): 27 | self.val_history = OrderedDict() 28 | self.n_history = OrderedDict() 29 | self.output = OrderedDict() 30 | self.ready = False 31 | 32 | def clear(self): 33 | self.val_history.clear() 34 | self.n_history.clear() 35 | self.clear_output() 36 | 37 | def clear_output(self): 38 | self.output.clear() 39 | self.ready = False 40 | 41 | def update(self, vars, count=1): 42 | assert isinstance(vars, dict) 43 | for key, var in vars.items(): 44 | if key not in self.val_history: 45 | self.val_history[key] = [] 46 | self.n_history[key] = [] 47 | if tf.is_tensor(var): 48 | var = var.numpy() 49 | self.val_history[key].append(var) 50 | self.n_history[key].append(count) 51 | 52 | def average(self, n=0): 53 | """Average latest n values or all values""" 54 | assert n >= 0 55 | for key in self.val_history: 56 | if 'time' in key: 57 | self.output[key] = self.val_history[key][-1] 58 | elif 'image' not in key: # skip images 59 | values = np.array(self.val_history[key][-n:]) 60 | nums = np.array(self.n_history[key][-n:]) 61 | avg = np.sum(values * nums) / np.sum(nums) 62 | self.output[key] = avg 63 | self.ready = True 64 | -------------------------------------------------------------------------------- /tensorflow/sagemakercv/utils/runner/priority.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2019, Open-MMLab. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from enum import Enum 19 | 20 | 21 | class Priority(Enum): 22 | """Hook priority levels. 23 | +------------+------------+ 24 | | Level | Value | 25 | +============+============+ 26 | | HIGHEST | 0 | 27 | +------------+------------+ 28 | | VERY_HIGH | 10 | 29 | +------------+------------+ 30 | | HIGH | 30 | 31 | +------------+------------+ 32 | | NORMAL | 50 | 33 | +------------+------------+ 34 | | LOW | 70 | 35 | +------------+------------+ 36 | | VERY_LOW | 90 | 37 | +------------+------------+ 38 | | LOWEST | 100 | 39 | +------------+------------+ 40 | """ 41 | 42 | HIGHEST = 0 43 | VERY_HIGH = 10 44 | HIGH = 30 45 | NORMAL = 50 46 | LOW = 70 47 | VERY_LOW = 90 48 | LOWEST = 100 49 | 50 | 51 | def get_priority(priority): 52 | """Get priority value. 53 | Args: 54 | priority (int or str or :obj:`Priority`): Priority. 55 | Returns: 56 | int: The priority value. 57 | """ 58 | if isinstance(priority, int): 59 | if priority < 0 or priority > 100: 60 | raise ValueError('priority must be between 0 and 100') 61 | return priority 62 | elif isinstance(priority, Priority): 63 | return priority.value 64 | elif isinstance(priority, str): 65 | return Priority[priority.upper()].value 66 | else: 67 | raise TypeError('priority must be an integer or Priority enum value') 68 | -------------------------------------------------------------------------------- /tensorflow/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | py_version = f"{sys.version_info.major}{sys.version_info.minor}" 5 | 6 | from setuptools import find_packages 7 | from setuptools import setup 8 | 9 | if py_version=="37": 10 | pycocotools_whl = "https://sagemakercv.s3.us-west-2.amazonaws.com/cocoapi/pycocotools-2.0%2Bnv0.6.0-cp37-cp37m-linux_x86_64.whl" 11 | else: 12 | pycocotools_whl = "https://sagemakercv.s3.us-west-2.amazonaws.com/cocoapi/pycocotools-2.0%2Bnv0.6.0-cp38-cp38-linux_x86_64.whl" 13 | 14 | 15 | install_requires = ["tensorflow_addons", 16 | "tensorflow_datasets", 17 | "yacs", 18 | "matplotlib", 19 | "mpi4py", 20 | "opencv-python", 21 | f"pycocotools @ {pycocotools_whl}"] 22 | 23 | 24 | 25 | setup( 26 | name="sagemakercv", 27 | version="0.1", 28 | author="jbsnyder", 29 | url="https://github.com/aws-samples/amazon-sagemaker-cv", 30 | description="Computer vision in TensorFlow with Amazon Sagemaker", 31 | packages=find_packages(exclude=("configs", "tests")), 32 | install_requires=install_requires 33 | ) 34 | -------------------------------------------------------------------------------- /tensorflow/train.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.append('..') 3 | import os 4 | import argparse 5 | from configs import cfg 6 | from sagemakercv.detection import build_detector 7 | from sagemakercv.training import build_optimizer, build_scheduler, build_trainer 8 | from sagemakercv.data import build_dataset 9 | from sagemakercv.utils.dist_utils import get_dist_info, MPI_size, is_sm_dist 10 | from sagemakercv.utils.runner import Runner, build_hooks 11 | import tensorflow as tf 12 | 13 | rank, local_rank, size, local_size = get_dist_info() 14 | devices = tf.config.list_physical_devices('GPU') 15 | for device in devices: 16 | tf.config.experimental.set_memory_growth(device, True) 17 | tf.config.set_visible_devices([devices[local_rank]], 'GPU') 18 | logical_devices = tf.config.list_logical_devices('GPU') 19 | 20 | 21 | def main(cfg): 22 | tf.config.optimizer.set_experimental_options({"auto_mixed_precision": cfg.SOLVER.FP16}) 23 | tf.config.optimizer.set_jit(cfg.SOLVER.XLA) 24 | if int(tf.__version__.split('.')[1])>=4: 25 | tf.config.experimental.enable_tensor_float_32_execution(cfg.SOLVER.TF32) 26 | dataset = iter(build_dataset(cfg)) 27 | detector = build_detector(cfg) 28 | features, labels = next(dataset) 29 | result = detector(features, training=False) 30 | optimizer = build_optimizer(cfg) 31 | trainer = build_trainer(cfg, detector, optimizer, dist='smd' if is_sm_dist() else 'hvd') 32 | runner = Runner(trainer, cfg) 33 | hooks = build_hooks(cfg) 34 | for hook in hooks: 35 | runner.register_hook(hook) 36 | runner.run(dataset) 37 | 38 | def parse(): 39 | parser = argparse.ArgumentParser(description='Load model configuration') 40 | parser.add_argument('--config', help='Configuration file to apply on top of base') 41 | parsed, _ = parser.parse_known_args() 42 | return parsed 43 | 44 | if __name__=='__main__': 45 | args = parse() 46 | cfg.merge_from_file(args.config) 47 | assert cfg.INPUT.TRAIN_BATCH_SIZE%MPI_size()==0, f"Batch {cfg.INPUT.TRAIN_BATCH_SIZE} on {MPI_size()} GPUs" 48 | assert cfg.INPUT.EVAL_BATCH_SIZE%MPI_size()==0, f"Batch {cfg.INPUT.EVAL_BATCH_SIZE} on {MPI_size()} GPUs" 49 | main(cfg) 50 | -------------------------------------------------------------------------------- /version.txt: -------------------------------------------------------------------------------- 1 | 0.0.1 --------------------------------------------------------------------------------