From 0ecad35269dc4b30b6bc83bdcfb54c710a08ce30 Mon Sep 17 00:00:00 2001 From: Hei Law Date: Wed, 17 Apr 2019 13:18:55 -0400 Subject: [PATCH] first commit --- .gitignore | 18 + LICENSE | 29 ++ README.md | 151 +++++++ __init__.py | 2 + conda_packagelist.txt | 81 ++++ configs/CornerNet-multi_scale.json | 54 +++ configs/CornerNet.json | 52 +++ configs/CornerNet_Saccade.json | 56 +++ configs/CornerNet_Squeeze.json | 54 +++ core/__init__.py | 0 core/base.py | 36 ++ core/config.py | 162 +++++++ core/dbs/__init__.py | 6 + core/dbs/base.py | 72 ++++ core/dbs/coco.py | 169 ++++++++ core/dbs/detection.py | 70 ++++ core/detectors.py | 49 +++ core/external/.gitignore | 7 + core/external/Makefile | 3 + core/external/__init__.py | 0 core/external/bbox.pyx | 55 +++ core/external/nms.pyx | 279 +++++++++++++ core/external/setup.py | 23 + core/models/CornerNet.py | 71 ++++ core/models/CornerNet_Saccade.py | 91 ++++ core/models/CornerNet_Squeeze.py | 111 +++++ core/models/__init__.py | 0 core/models/py_utils/__init__.py | 1 + core/models/py_utils/_cpools/.gitignore | 3 + core/models/py_utils/_cpools/__init__.py | 74 ++++ core/models/py_utils/_cpools/setup.py | 15 + .../py_utils/_cpools/src/bottom_pool.cpp | 80 ++++ .../models/py_utils/_cpools/src/left_pool.cpp | 80 ++++ .../py_utils/_cpools/src/right_pool.cpp | 80 ++++ core/models/py_utils/_cpools/src/top_pool.cpp | 80 ++++ core/models/py_utils/data_parallel.py | 116 ++++++ core/models/py_utils/losses.py | 224 ++++++++++ core/models/py_utils/modules.py | 292 +++++++++++++ core/models/py_utils/scatter_gather.py | 38 ++ core/models/py_utils/utils.py | 226 ++++++++++ core/nnet/__init__.py | 0 core/nnet/py_factory.py | 137 ++++++ core/paths.py | 7 + core/sample/__init__.py | 5 + core/sample/cornernet.py | 160 +++++++ core/sample/cornernet_saccade.py | 285 +++++++++++++ core/sample/utils.py | 163 ++++++++ core/test/__init__.py | 5 + core/test/cornernet.py | 176 ++++++++ core/test/cornernet_saccade.py | 394 ++++++++++++++++++ core/utils/__init__.py | 2 + core/utils/timer.py | 25 ++ core/utils/tqdm.py | 25 ++ core/vis_utils.py | 62 +++ demo.jpg | Bin 0 -> 323088 bytes demo.py | 12 + evaluate.py | 104 +++++ train.py | 249 +++++++++++ 58 files changed, 4821 insertions(+) create mode 100755 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 __init__.py create mode 100644 conda_packagelist.txt create mode 100644 configs/CornerNet-multi_scale.json create mode 100755 configs/CornerNet.json create mode 100755 configs/CornerNet_Saccade.json create mode 100755 configs/CornerNet_Squeeze.json create mode 100644 core/__init__.py create mode 100644 core/base.py create mode 100755 core/config.py create mode 100755 core/dbs/__init__.py create mode 100644 core/dbs/base.py create mode 100755 core/dbs/coco.py create mode 100644 core/dbs/detection.py create mode 100644 core/detectors.py create mode 100644 core/external/.gitignore create mode 100644 core/external/Makefile create mode 100644 core/external/__init__.py create mode 100644 core/external/bbox.pyx create mode 100644 core/external/nms.pyx create mode 100644 core/external/setup.py create mode 100755 core/models/CornerNet.py create mode 100644 core/models/CornerNet_Saccade.py create mode 100644 core/models/CornerNet_Squeeze.py create mode 100755 core/models/__init__.py create mode 100644 core/models/py_utils/__init__.py create mode 100644 core/models/py_utils/_cpools/.gitignore create mode 100644 core/models/py_utils/_cpools/__init__.py create mode 100644 core/models/py_utils/_cpools/setup.py create mode 100644 core/models/py_utils/_cpools/src/bottom_pool.cpp create mode 100644 core/models/py_utils/_cpools/src/left_pool.cpp create mode 100644 core/models/py_utils/_cpools/src/right_pool.cpp create mode 100644 core/models/py_utils/_cpools/src/top_pool.cpp create mode 100644 core/models/py_utils/data_parallel.py create mode 100644 core/models/py_utils/losses.py create mode 100644 core/models/py_utils/modules.py create mode 100644 core/models/py_utils/scatter_gather.py create mode 100644 core/models/py_utils/utils.py create mode 100755 core/nnet/__init__.py create mode 100755 core/nnet/py_factory.py create mode 100644 core/paths.py create mode 100644 core/sample/__init__.py create mode 100644 core/sample/cornernet.py create mode 100644 core/sample/cornernet_saccade.py create mode 100644 core/sample/utils.py create mode 100644 core/test/__init__.py create mode 100644 core/test/cornernet.py create mode 100644 core/test/cornernet_saccade.py create mode 100644 core/utils/__init__.py create mode 100644 core/utils/timer.py create mode 100755 core/utils/tqdm.py create mode 100644 core/vis_utils.py create mode 100644 demo.jpg create mode 100755 demo.py create mode 100755 evaluate.py create mode 100755 train.py diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..c1ba535 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +loss/ +data/ +cache/ +tf_cache/ +debug/ +results/ + +misc/outputs + +evaluation/evaluate_object +evaluation/analyze_object + +nnet/__pycache__/ + +*.swp + +*.pyc +*.o* diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9f3e4eb --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2019, Princeton University +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..0a36645 --- /dev/null +++ b/README.md @@ -0,0 +1,151 @@ +# CornerNet-Lite: Training, Evaluation and Testing Code +Code for reproducing results in the following paper: + +**CornerNet-Lite: Efficient Keypoint Based Object Detection** +Hei Law, Yun Teng, Olga Russakovsky, Jia Deng +*arXiv* + +## Getting Started +### Software Requirement +- Python 3.7 +- PyTorch 1.0.0 +- CUDA 10 +- GCC 4.9.2 or above + +### Installing Dependencies +Please first install [Anaconda](https://anaconda.org) and create an Anaconda environment using the provided package list `conda_packagelist.txt`. +``` +conda create --name CornerNet_Lite --file conda_packagelist.txt --channel pytorch +``` + +After you create the environment, please activate it. +``` +source activate CornerNet_Lite +``` + +### Compiling Corner Pooling Layers +Compile the C++ implementation of the corner pooling layers. (GCC4.9.2 or above is required.) +``` +cd /core/models/py_utils/_cpools/ +python setup.py install --user +``` + +### Compiling NMS +Compile the NMS code which are originally from [Faster R-CNN](https://github.com/rbgirshick/py-faster-rcnn/blob/master/lib/nms/cpu_nms.pyx) and [Soft-NMS](https://github.com/bharatsingh430/soft-nms/blob/master/lib/nms/cpu_nms.pyx). +``` +cd /core/external +make +``` + +### Downloading Models +In this repo, we provide models for the following detectors: +- [CornerNet-Saccade](https://drive.google.com/file/d/1MQDyPRI0HgDHxHToudHqQ-2m8TVBciaa/view?usp=sharing) +- [CornerNet-Squeeze](https://drive.google.com/file/d/1qM8BBYCLUBcZx_UmLT0qMXNTh-Yshp4X/view?usp=sharing) +- [CornerNet](https://drive.google.com/file/d/1e8At_iZWyXQgLlMwHkB83kN-AN85Uff1/view?usp=sharing) + +Put the CornerNet-Saccade model under `/cache/nnet/CornerNet_Saccade/`, CornerNet-Squeeze model under `/cache/nnet/CornerNet_Squeeze/` and CornerNet model under `/cache/nnet/CornerNet/`. (\* Note we use underscore instead of dash in both the directory names for CornerNet-Saccade and CornerNet-Squeeze.) + +Note: The CornerNet model is the same as the one in the original [CornerNet repo](https://github.com/princeton-vl/CornerNet). We just ported it to this new repo. + +After downloading the models, you should be able to use the detectors on your own images. We provide a demo script `demo.py` to test if the repo is installed correctly. +``` +python demo.py +``` +This script applies CornerNet-Saccade to `demo.jpg` and writes the results to `demo_out.jpg`. + +In the demo script, the default detector is CornerNet-Saccade. You can modify the demo script to test different detectors. For example, if you want to test CornerNet-Squeeze: +```python +#!/usr/bin/env python + +import cv2 +from core.detectors import CornerNet_Squeeze +from core.vis_utils import draw_bboxes + +detector = CornerNet_Squeeze() +image = cv2.imread("demo.jpg") + +bboxes = detector(image) +image = draw_bboxes(image, bboxes) +cv2.imwrite("demo_out.jpg", image) +``` + +### Using CornerNet-Lite in Your Project +It is also easy to use CornerNet-Lite in your project. You will need to change the directory name from `CornerNet-Lite` to `CornerNet_Lite`. Otherwise, you won't be able to import CornerNet-Lite. +``` +Your project +│ README.md +│ ... +│ foo.py +│ +└───CornerNet_Lite +│ +└───directory1 +│ +└───... +``` + +In `foo.py`, you can easily import CornerNet-Saccade by adding: +```python +from CornerNet_Lite import CornerNet_Saccade + +def foo(): + cornernet = CornerNet_Saccade() + # CornerNet_Saccade is ready to use + + image = cv2.imread('/path/to/your/image') + bboxes = cornernet(image) +``` + +If you want to train or evaluate the detectors on COCO, please move on to the following steps. + +## Training and Evaluation + +### Installing MS COCO APIs +``` +mkdir -p /data +cd /data +git clone git@github.com:cocodataset/cocoapi.git coco +cd /data/coco/PythonAPI +make install +``` + +### Downloading MS COCO Data +- Download the training/validation split we use in our paper from [here](https://drive.google.com/file/d/1dop4188xo5lXDkGtOZUzy2SHOD_COXz4/view?usp=sharing) (originally from [Faster R-CNN](https://github.com/rbgirshick/py-faster-rcnn/tree/master/data)) +- Unzip the file and place `annotations` under `/data/coco` +- Download the images (2014 Train, 2014 Val, 2017 Test) from [here](http://cocodataset.org/#download) +- Create 3 directories, `trainval2014`, `minival2014` and `testdev2017`, under `/data/coco/images/` +- Copy the training/validation/testing images to the corresponding directories according to the annotation files + +To train and evaluate a network, you will need to create a configuration file, which defines the hyperparameters, and a model file, which defines the network architecture. The configuration file should be in JSON format and placed in `/configs/`. Each configuration file should have a corresponding model file in `/core/models/`. i.e. If there is a `.json` in `/configs/`, there should be a `.py` in `/core/models/`. There is only one exception which we will mention later. + +### Training and Evaluating a Model +To train a model: +``` +python train.py +``` + +We provide the configuration files and the model files for CornerNet-Saccade, CornerNet-Squeeze and CornerNet in this repo. Please check the configuration files in `/configs/`. + +To train CornerNet-Saccade: +``` +python train.py CornerNet_Saccade +``` +Please adjust the batch size in `CornerNet_Saccade.json` to accommodate the number of GPUs that are available to you. + +To evaluate the trained model: +``` +python evaluate.py CornerNet_Saccade --testiter 500000 --split +``` + +If you want to test different hyperparameters during evaluation and do not want to overwrite the original configuration file, you can do so by creating a configuration file with a suffix (`-.json`). There is no need to create `-.py` in `/core/models/`. + +To use the new configuration file: +``` +python evaluate.py --testiter --split --suffix +``` + +We also include a configuration file for CornerNet under multi-scale setting, which is `CornerNet-multi_scale.json`, in this repo. + +To use the multi-scale configuration file: +``` +python evaluate.py CornerNet --testiter --split --suffix multi_scale diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..dd957ac --- /dev/null +++ b/__init__.py @@ -0,0 +1,2 @@ +from .core.detectors import CornerNet, CornerNet_Squeeze, CornerNet_Saccade +from .core.vis_utils import draw_bboxes diff --git a/conda_packagelist.txt b/conda_packagelist.txt new file mode 100644 index 0000000..346f63b --- /dev/null +++ b/conda_packagelist.txt @@ -0,0 +1,81 @@ +# This file may be used to create an environment using: +# $ conda create --name --file +# platform: linux-64 +blas=1.0=mkl +bzip2=1.0.6=h14c3975_5 +ca-certificates=2018.12.5=0 +cairo=1.14.12=h8948797_3 +certifi=2018.11.29=py37_0 +cffi=1.11.5=py37he75722e_1 +cuda100=1.0=0 +cycler=0.10.0=py37_0 +cython=0.28.5=py37hf484d3e_0 +dbus=1.13.2=h714fa37_1 +expat=2.2.6=he6710b0_0 +ffmpeg=4.0=hcdf2ecd_0 +fontconfig=2.13.0=h9420a91_0 +freeglut=3.0.0=hf484d3e_5 +freetype=2.9.1=h8a8886c_1 +glib=2.56.2=hd408876_0 +graphite2=1.3.12=h23475e2_2 +gst-plugins-base=1.14.0=hbbd80ab_1 +gstreamer=1.14.0=hb453b48_1 +harfbuzz=1.8.8=hffaf4a1_0 +hdf5=1.10.2=hba1933b_1 +icu=58.2=h9c2bf20_1 +intel-openmp=2019.0=118 +jasper=2.0.14=h07fcdf6_1 +jpeg=9b=h024ee3a_2 +kiwisolver=1.0.1=py37hf484d3e_0 +libedit=3.1.20170329=h6b74fdf_2 +libffi=3.2.1=hd88cf55_4 +libgcc-ng=8.2.0=hdf63c60_1 +libgfortran-ng=7.3.0=hdf63c60_0 +libglu=9.0.0=hf484d3e_1 +libopencv=3.4.2=hb342d67_1 +libopus=1.2.1=hb9ed12e_0 +libpng=1.6.35=hbc83047_0 +libstdcxx-ng=8.2.0=hdf63c60_1 +libtiff=4.0.9=he85c1e1_2 +libuuid=1.0.3=h1bed415_2 +libvpx=1.7.0=h439df22_0 +libxcb=1.13=h1bed415_1 +libxml2=2.9.8=h26e45fe_1 +matplotlib=3.0.2=py37h5429711_0 +mkl=2018.0.3=1 +mkl_fft=1.0.6=py37h7dd41cf_0 +mkl_random=1.0.1=py37h4414c95_1 +ncurses=6.1=hf484d3e_0 +ninja=1.8.2=py37h6bb024c_1 +numpy=1.15.4=py37h1d66e8a_0 +numpy-base=1.15.4=py37h81de0dd_0 +olefile=0.46=py37_0 +opencv=3.4.2=py37h6fd60c2_1 +openssl=1.1.1a=h7b6447c_0 +pcre=8.42=h439df22_0 +pillow=5.2.0=py37heded4f4_0 +pip=10.0.1=py37_0 +pixman=0.34.0=hceecf20_3 +py-opencv=3.4.2=py37hb342d67_1 +pycparser=2.18=py37_1 +pyparsing=2.2.0=py37_1 +pyqt=5.9.2=py37h05f1152_2 +python=3.7.1=h0371630_3 +python-dateutil=2.7.3=py37_0 +pytorch=1.0.0=py3.7_cuda10.0.130_cudnn7.4.1_1 +pytz=2018.5=py37_0 +qt=5.9.7=h5867ecd_1 +readline=7.0=h7b6447c_5 +scikit-learn=0.19.1=py37hedc7406_0 +scipy=1.1.0=py37hfa4b5c9_1 +setuptools=40.2.0=py37_0 +sip=4.19.8=py37hf484d3e_0 +six=1.11.0=py37_1 +sqlite=3.25.3=h7b6447c_0 +tk=8.6.8=hbc83047_0 +torchvision=0.2.1=py37_1 +tornado=5.1=py37h14c3975_0 +tqdm=4.25.0=py37h28b3542_0 +wheel=0.31.1=py37_0 +xz=5.2.4=h14c3975_4 +zlib=1.2.11=ha838bed_2 diff --git a/configs/CornerNet-multi_scale.json b/configs/CornerNet-multi_scale.json new file mode 100644 index 0000000..9c73f7c --- /dev/null +++ b/configs/CornerNet-multi_scale.json @@ -0,0 +1,54 @@ +{ + "system": { + "dataset": "COCO", + "batch_size": 49, + "sampling_function": "cornernet", + + "train_split": "trainval", + "val_split": "minival", + + "learning_rate": 0.00025, + "decay_rate": 10, + + "val_iter": 100, + + "opt_algo": "adam", + "prefetch_size": 5, + + "max_iter": 500000, + "stepsize": 450000, + "snapshot": 5000, + + "chunk_sizes": [4, 5, 5, 5, 5, 5, 5, 5, 5, 5], + + "data_dir": "./data" + }, + + "db": { + "rand_scale_min": 0.6, + "rand_scale_max": 1.4, + "rand_scale_step": 0.1, + "rand_scales": null, + + "rand_crop": true, + "rand_color": true, + + "border": 128, + "gaussian_bump": true, + + "input_size": [511, 511], + "output_sizes": [[128, 128]], + + "test_scales": [0.5, 0.75, 1, 1.25, 1.5], + + "top_k": 100, + "categories": 80, + "ae_threshold": 0.5, + "nms_threshold": 0.5, + + "merge_bbox": true, + "weight_exp": 10, + + "max_per_image": 100 + } +} diff --git a/configs/CornerNet.json b/configs/CornerNet.json new file mode 100755 index 0000000..fd319c9 --- /dev/null +++ b/configs/CornerNet.json @@ -0,0 +1,52 @@ +{ + "system": { + "dataset": "COCO", + "batch_size": 49, + "sampling_function": "cornernet", + + "train_split": "trainval", + "val_split": "minival", + + "learning_rate": 0.00025, + "decay_rate": 10, + + "val_iter": 100, + + "opt_algo": "adam", + "prefetch_size": 5, + + "max_iter": 500000, + "stepsize": 450000, + "snapshot": 5000, + + "chunk_sizes": [4, 5, 5, 5, 5, 5, 5, 5, 5, 5], + + "data_dir": "./data" + }, + + "db": { + "rand_scale_min": 0.6, + "rand_scale_max": 1.4, + "rand_scale_step": 0.1, + "rand_scales": null, + + "rand_crop": true, + "rand_color": true, + + "border": 128, + "gaussian_bump": true, + "gaussian_iou": 0.3, + + "input_size": [511, 511], + "output_sizes": [[128, 128]], + + "test_scales": [1], + + "top_k": 100, + "categories": 80, + "ae_threshold": 0.5, + "nms_threshold": 0.5, + + "max_per_image": 100 + } +} diff --git a/configs/CornerNet_Saccade.json b/configs/CornerNet_Saccade.json new file mode 100755 index 0000000..533b3fa --- /dev/null +++ b/configs/CornerNet_Saccade.json @@ -0,0 +1,56 @@ +{ + "system": { + "dataset": "COCO", + "batch_size": 48, + "sampling_function": "cornernet_saccade", + + "train_split": "trainval", + "val_split": "minival", + + "learning_rate": 0.00025, + "decay_rate": 10, + + "val_iter": 100, + + "opt_algo": "adam", + "prefetch_size": 5, + + "max_iter": 500000, + "stepsize": 450000, + "snapshot": 5000, + + "chunk_sizes": [12, 12, 12, 12] + }, + + "db": { + "rand_scale_min": 0.5, + "rand_scale_max": 1.1, + "rand_scale_step": 0.1, + "rand_scales": null, + + "rand_full_crop": true, + "gaussian_bump": true, + "gaussian_iou": 0.5, + + "min_scale": 16, + "view_sizes": [], + + "height_mult": 31, + "width_mult": 31, + + "input_size": [255, 255], + "output_sizes": [[64, 64]], + + "att_max_crops": 30, + "att_scales": [[1, 2, 4]], + "att_thresholds": [0.3], + + "top_k": 12, + "num_dets": 12, + "categories": 80, + "ae_threshold": 0.3, + "nms_threshold": 0.5, + + "max_per_image": 100 + } +} diff --git a/configs/CornerNet_Squeeze.json b/configs/CornerNet_Squeeze.json new file mode 100755 index 0000000..6d36798 --- /dev/null +++ b/configs/CornerNet_Squeeze.json @@ -0,0 +1,54 @@ +{ + "system": { + "dataset": "COCO", + "batch_size": 55, + "sampling_function": "cornernet", + + "train_split": "trainval", + "val_split": "minival", + + "learning_rate": 0.00025, + "decay_rate": 10, + + "val_iter": 100, + + "opt_algo": "adam", + "prefetch_size": 5, + + "max_iter": 500000, + "stepsize": 450000, + "snapshot": 5000, + + "chunk_sizes": [13, 14, 14, 14], + + "data_dir": "./data" + }, + + "db": { + "rand_scale_min": 0.6, + "rand_scale_max": 1.4, + "rand_scale_step": 0.1, + "rand_scales": null, + + "rand_crop": true, + "rand_color": true, + + "border": 128, + "gaussian_bump": true, + "gaussian_iou": 0.3, + + "input_size": [511, 511], + "output_sizes": [[64, 64]], + + "test_scales": [1], + "test_flipped": false, + + "top_k": 20, + "num_dets": 100, + "categories": 80, + "ae_threshold": 0.5, + "nms_threshold": 0.5, + + "max_per_image": 100 + } +} diff --git a/core/__init__.py b/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/base.py b/core/base.py new file mode 100644 index 0000000..03d41a8 --- /dev/null +++ b/core/base.py @@ -0,0 +1,36 @@ +import json + +from .nnet.py_factory import NetworkFactory + +class Base(object): + def __init__(self, db, nnet, func, model=None): + super(Base, self).__init__() + + self._db = db + self._nnet = nnet + self._func = func + + if model is not None: + self._nnet.load_pretrained_params(model) + + self._nnet.cuda() + self._nnet.eval_mode() + + def _inference(self, image, *args, **kwargs): + return self._func(self._db, self._nnet, image.copy(), *args, **kwargs) + + def __call__(self, image, *args, **kwargs): + categories = self._db.configs["categories"] + bboxes = self._inference(image, *args, **kwargs) + return {self._db.cls2name(j): bboxes[j] for j in range(1, categories + 1)} + +def load_cfg(cfg_file): + with open(cfg_file, "r") as f: + cfg = json.load(f) + + cfg_sys = cfg["system"] + cfg_db = cfg["db"] + return cfg_sys, cfg_db + +def load_nnet(cfg_sys, model): + return NetworkFactory(cfg_sys, model) diff --git a/core/config.py b/core/config.py new file mode 100755 index 0000000..bba2a35 --- /dev/null +++ b/core/config.py @@ -0,0 +1,162 @@ +import os +import numpy as np + +class SystemConfig(object): + def __init__(self): + self._configs = {} + self._configs["dataset"] = None + self._configs["sampling_function"] = "coco_detection" + + # Training Config + self._configs["display"] = 5 + self._configs["snapshot"] = 400 + self._configs["stepsize"] = 5000 + self._configs["learning_rate"] = 0.001 + self._configs["decay_rate"] = 10 + self._configs["max_iter"] = 100000 + self._configs["val_iter"] = 20 + self._configs["batch_size"] = 1 + self._configs["snapshot_name"] = None + self._configs["prefetch_size"] = 100 + self._configs["pretrain"] = None + self._configs["opt_algo"] = "adam" + self._configs["chunk_sizes"] = None + + # Directories + self._configs["data_dir"] = "./data" + self._configs["cache_dir"] = "./cache" + self._configs["config_dir"] = "./config" + self._configs["result_dir"] = "./results" + + # Split + self._configs["train_split"] = "training" + self._configs["val_split"] = "validation" + self._configs["test_split"] = "testdev" + + # Rng + self._configs["data_rng"] = np.random.RandomState(123) + self._configs["nnet_rng"] = np.random.RandomState(317) + + @property + def chunk_sizes(self): + return self._configs["chunk_sizes"] + + @property + def train_split(self): + return self._configs["train_split"] + + @property + def val_split(self): + return self._configs["val_split"] + + @property + def test_split(self): + return self._configs["test_split"] + + @property + def full(self): + return self._configs + + @property + def sampling_function(self): + return self._configs["sampling_function"] + + @property + def data_rng(self): + return self._configs["data_rng"] + + @property + def nnet_rng(self): + return self._configs["nnet_rng"] + + @property + def opt_algo(self): + return self._configs["opt_algo"] + + @property + def prefetch_size(self): + return self._configs["prefetch_size"] + + @property + def pretrain(self): + return self._configs["pretrain"] + + @property + def result_dir(self): + result_dir = os.path.join(self._configs["result_dir"], self.snapshot_name) + if not os.path.exists(result_dir): + os.makedirs(result_dir) + return result_dir + + @property + def dataset(self): + return self._configs["dataset"] + + @property + def snapshot_name(self): + return self._configs["snapshot_name"] + + @property + def snapshot_dir(self): + snapshot_dir = os.path.join(self.cache_dir, "nnet", self.snapshot_name) + + if not os.path.exists(snapshot_dir): + os.makedirs(snapshot_dir) + return snapshot_dir + + @property + def snapshot_file(self): + snapshot_file = os.path.join(self.snapshot_dir, self.snapshot_name + "_{}.pkl") + return snapshot_file + + @property + def config_dir(self): + return self._configs["config_dir"] + + @property + def batch_size(self): + return self._configs["batch_size"] + + @property + def max_iter(self): + return self._configs["max_iter"] + + @property + def learning_rate(self): + return self._configs["learning_rate"] + + @property + def decay_rate(self): + return self._configs["decay_rate"] + + @property + def stepsize(self): + return self._configs["stepsize"] + + @property + def snapshot(self): + return self._configs["snapshot"] + + @property + def display(self): + return self._configs["display"] + + @property + def val_iter(self): + return self._configs["val_iter"] + + @property + def data_dir(self): + return self._configs["data_dir"] + + @property + def cache_dir(self): + if not os.path.exists(self._configs["cache_dir"]): + os.makedirs(self._configs["cache_dir"]) + return self._configs["cache_dir"] + + def update_config(self, new): + for key in new: + if key in self._configs: + self._configs[key] = new[key] + return self diff --git a/core/dbs/__init__.py b/core/dbs/__init__.py new file mode 100755 index 0000000..fa7f7b3 --- /dev/null +++ b/core/dbs/__init__.py @@ -0,0 +1,6 @@ +from .coco import COCO + +datasets = { + "COCO": COCO +} + diff --git a/core/dbs/base.py b/core/dbs/base.py new file mode 100644 index 0000000..e627b11 --- /dev/null +++ b/core/dbs/base.py @@ -0,0 +1,72 @@ +import os +import numpy as np + +class BASE(object): + def __init__(self): + self._split = None + self._db_inds = [] + self._image_ids = [] + + self._mean = np.zeros((3, ), dtype=np.float32) + self._std = np.ones((3, ), dtype=np.float32) + self._eig_val = np.ones((3, ), dtype=np.float32) + self._eig_vec = np.zeros((3, 3), dtype=np.float32) + + self._configs = {} + self._configs["data_aug"] = True + + self._data_rng = None + + @property + def configs(self): + return self._configs + + @property + def mean(self): + return self._mean + + @property + def std(self): + return self._std + + @property + def eig_val(self): + return self._eig_val + + @property + def eig_vec(self): + return self._eig_vec + + @property + def db_inds(self): + return self._db_inds + + @property + def split(self): + return self._split + + def update_config(self, new): + for key in new: + if key in self._configs: + self._configs[key] = new[key] + + def image_ids(self, ind): + return self._image_ids[ind] + + def image_path(self, ind): + pass + + def write_result(self, ind, all_bboxes, all_scores): + pass + + def evaluate(self, name): + pass + + def shuffle_inds(self, quiet=False): + if self._data_rng is None: + self._data_rng = np.random.RandomState(os.getpid()) + + if not quiet: + print("shuffling indices...") + rand_perm = self._data_rng.permutation(len(self._db_inds)) + self._db_inds = self._db_inds[rand_perm] diff --git a/core/dbs/coco.py b/core/dbs/coco.py new file mode 100755 index 0000000..5969581 --- /dev/null +++ b/core/dbs/coco.py @@ -0,0 +1,169 @@ +import os +import json +import numpy as np + +from .detection import DETECTION +from ..paths import get_file_path + +# COCO bounding boxes are 0-indexed + +class COCO(DETECTION): + def __init__(self, db_config, split=None, sys_config=None): + assert split is None or sys_config is not None + super(COCO, self).__init__(db_config) + + self._mean = np.array([0.40789654, 0.44719302, 0.47026115], dtype=np.float32) + self._std = np.array([0.28863828, 0.27408164, 0.27809835], dtype=np.float32) + self._eig_val = np.array([0.2141788, 0.01817699, 0.00341571], dtype=np.float32) + self._eig_vec = np.array([ + [-0.58752847, -0.69563484, 0.41340352], + [-0.5832747, 0.00994535, -0.81221408], + [-0.56089297, 0.71832671, 0.41158938] + ], dtype=np.float32) + + self._coco_cls_ids = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 27, 28, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 67, 70, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 84, 85, 86, 87, 88, 89, 90 + ] + + self._coco_cls_names = [ + 'person', 'bicycle', 'car', 'motorcycle', 'airplane', + 'bus', 'train', 'truck', 'boat', 'traffic light', + 'fire hydrant', 'stop sign', 'parking meter', 'bench', + 'bird', 'cat', 'dog', 'horse','sheep', 'cow', 'elephant', + 'bear', 'zebra','giraffe', 'backpack', 'umbrella', + 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', + 'snowboard','sports ball', 'kite', 'baseball bat', + 'baseball glove', 'skateboard', 'surfboard', + 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', + 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', + 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', + 'donut', 'cake', 'chair', 'couch', 'potted plant', + 'bed', 'dining table', 'toilet', 'tv', 'laptop', + 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', + 'oven', 'toaster', 'sink', 'refrigerator', 'book', + 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', + 'toothbrush' + ] + + self._cls2coco = {ind + 1: coco_id for ind, coco_id in enumerate(self._coco_cls_ids)} + self._coco2cls = {coco_id: cls_id for cls_id, coco_id in self._cls2coco.items()} + self._coco2name = {cls_id: cls_name for cls_id, cls_name in zip(self._coco_cls_ids, self._coco_cls_names)} + self._name2coco = {cls_name: cls_id for cls_name, cls_id in self._coco2name.items()} + + if split is not None: + coco_dir = os.path.join(sys_config.data_dir, "coco") + + self._split = { + "trainval": "trainval2014", + "minival": "minival2014", + "testdev": "testdev2017" + }[split] + self._data_dir = os.path.join(coco_dir, "images", self._split) + self._anno_file = os.path.join(coco_dir, "annotations", "instances_{}.json".format(self._split)) + + self._detections, self._eval_ids = self._load_coco_annos() + self._image_ids = list(self._detections.keys()) + self._db_inds = np.arange(len(self._image_ids)) + + def _load_coco_annos(self): + from pycocotools.coco import COCO + + coco = COCO(self._anno_file) + self._coco = coco + + class_ids = coco.getCatIds() + image_ids = coco.getImgIds() + + eval_ids = {} + detections = {} + for image_id in image_ids: + image = coco.loadImgs(image_id)[0] + dets = [] + + eval_ids[image["file_name"]] = image_id + for class_id in class_ids: + annotation_ids = coco.getAnnIds(imgIds=image["id"], catIds=class_id) + annotations = coco.loadAnns(annotation_ids) + category = self._coco2cls[class_id] + for annotation in annotations: + det = annotation["bbox"] + [category] + det[2] += det[0] + det[3] += det[1] + dets.append(det) + + file_name = image["file_name"] + if len(dets) == 0: + detections[file_name] = np.zeros((0, 5), dtype=np.float32) + else: + detections[file_name] = np.array(dets, dtype=np.float32) + return detections, eval_ids + + def image_path(self, ind): + if self._data_dir is None: + raise ValueError("Data directory is not set") + + db_ind = self._db_inds[ind] + file_name = self._image_ids[db_ind] + return os.path.join(self._data_dir, file_name) + + def detections(self, ind): + db_ind = self._db_inds[ind] + file_name = self._image_ids[db_ind] + return self._detections[file_name].copy() + + def cls2name(self, cls): + coco = self._cls2coco[cls] + return self._coco2name[coco] + + def _to_float(self, x): + return float("{:.2f}".format(x)) + + def convert_to_coco(self, all_bboxes): + detections = [] + for image_id in all_bboxes: + coco_id = self._eval_ids[image_id] + for cls_ind in all_bboxes[image_id]: + category_id = self._cls2coco[cls_ind] + for bbox in all_bboxes[image_id][cls_ind]: + bbox[2] -= bbox[0] + bbox[3] -= bbox[1] + + score = bbox[4] + bbox = list(map(self._to_float, bbox[0:4])) + + detection = { + "image_id": coco_id, + "category_id": category_id, + "bbox": bbox, + "score": float("{:.2f}".format(score)) + } + + detections.append(detection) + return detections + + def evaluate(self, result_json, cls_ids, image_ids): + from pycocotools.cocoeval import COCOeval + + if self._split == "testdev": + return None + + coco = self._coco + + eval_ids = [self._eval_ids[image_id] for image_id in image_ids] + cat_ids = [self._cls2coco[cls_id] for cls_id in cls_ids] + + coco_dets = coco.loadRes(result_json) + coco_eval = COCOeval(coco, coco_dets, "bbox") + coco_eval.params.imgIds = eval_ids + coco_eval.params.catIds = cat_ids + coco_eval.evaluate() + coco_eval.accumulate() + coco_eval.summarize() + return coco_eval.stats[0], coco_eval.stats[12:] diff --git a/core/dbs/detection.py b/core/dbs/detection.py new file mode 100644 index 0000000..6d90aa7 --- /dev/null +++ b/core/dbs/detection.py @@ -0,0 +1,70 @@ +import numpy as np + +from .base import BASE + +class DETECTION(BASE): + def __init__(self, db_config): + super(DETECTION, self).__init__() + + # Configs for training + self._configs["categories"] = 80 + self._configs["rand_scales"] = [1] + self._configs["rand_scale_min"] = 0.8 + self._configs["rand_scale_max"] = 1.4 + self._configs["rand_scale_step"] = 0.2 + + # Configs for both training and testing + self._configs["input_size"] = [383, 383] + self._configs["output_sizes"] = [[96, 96], [48, 48], [24, 24], [12, 12]] + + self._configs["score_threshold"] = 0.05 + self._configs["nms_threshold"] = 0.7 + self._configs["max_per_set"] = 40 + self._configs["max_per_image"] = 100 + self._configs["top_k"] = 20 + self._configs["ae_threshold"] = 1 + self._configs["nms_kernel"] = 3 + self._configs["num_dets"] = 1000 + + self._configs["nms_algorithm"] = "exp_soft_nms" + self._configs["weight_exp"] = 8 + self._configs["merge_bbox"] = False + + self._configs["data_aug"] = True + self._configs["lighting"] = True + + self._configs["border"] = 64 + self._configs["gaussian_bump"] = False + self._configs["gaussian_iou"] = 0.7 + self._configs["gaussian_radius"] = -1 + self._configs["rand_crop"] = False + self._configs["rand_color"] = False + self._configs["rand_center"] = True + + self._configs["init_sizes"] = [192, 255] + self._configs["view_sizes"] = [] + + self._configs["min_scale"] = 16 + self._configs["max_scale"] = 32 + + self._configs["att_sizes"] = [[16, 16], [32, 32], [64, 64]] + self._configs["att_ranges"] = [[96, 256], [32, 96], [0, 32]] + self._configs["att_ratios"] = [16, 8, 4] + self._configs["att_scales"] = [1, 1.5, 2] + self._configs["att_thresholds"] = [0.3, 0.3, 0.3, 0.3] + self._configs["att_nms_ks"] = [3, 3, 3] + self._configs["att_max_crops"] = 8 + self._configs["ref_dets"] = True + + # Configs for testing + self._configs["test_scales"] = [1] + self._configs["test_flipped"] = True + + self.update_config(db_config) + + if self._configs["rand_scales"] is None: + self._configs["rand_scales"] = np.arange( + self._configs["rand_scale_min"], + self._configs["rand_scale_max"], + self._configs["rand_scale_step"] + ) diff --git a/core/detectors.py b/core/detectors.py new file mode 100644 index 0000000..9307abf --- /dev/null +++ b/core/detectors.py @@ -0,0 +1,49 @@ +from .base import Base, load_cfg, load_nnet +from .paths import get_file_path +from .config import SystemConfig +from .dbs.coco import COCO + +class CornerNet(Base): + def __init__(self): + from .test.cornernet import cornernet_inference + from .models.CornerNet import model + + cfg_path = get_file_path("..", "configs", "CornerNet.json") + model_path = get_file_path("..", "cache", "nnet", "CornerNet", "CornerNet_500000.pkl") + + cfg_sys, cfg_db = load_cfg(cfg_path) + sys_cfg = SystemConfig().update_config(cfg_sys) + coco = COCO(cfg_db) + + cornernet = load_nnet(sys_cfg, model()) + super(CornerNet, self).__init__(coco, cornernet, cornernet_inference, model=model_path) + +class CornerNet_Squeeze(Base): + def __init__(self): + from .test.cornernet import cornernet_inference + from .models.CornerNet_Squeeze import model + + cfg_path = get_file_path("..", "configs", "CornerNet_Squeeze.json") + model_path = get_file_path("..", "cache", "nnet", "CornerNet_Squeeze", "CornerNet_Squeeze_500000.pkl") + + cfg_sys, cfg_db = load_cfg(cfg_path) + sys_cfg = SystemConfig().update_config(cfg_sys) + coco = COCO(cfg_db) + + cornernet = load_nnet(sys_cfg, model()) + super(CornerNet_Squeeze, self).__init__(coco, cornernet, cornernet_inference, model=model_path) + +class CornerNet_Saccade(Base): + def __init__(self): + from .test.cornernet_saccade import cornernet_saccade_inference + from .models.CornerNet_Saccade import model + + cfg_path = get_file_path("..", "configs", "CornerNet_Saccade.json") + model_path = get_file_path("..", "cache", "nnet", "CornerNet_Saccade", "CornerNet_Saccade_500000.pkl") + + cfg_sys, cfg_db = load_cfg(cfg_path) + sys_cfg = SystemConfig().update_config(cfg_sys) + coco = COCO(cfg_db) + + cornernet = load_nnet(sys_cfg, model()) + super(CornerNet_Saccade, self).__init__(coco, cornernet, cornernet_saccade_inference, model=model_path) diff --git a/core/external/.gitignore b/core/external/.gitignore new file mode 100644 index 0000000..f7c8c1a --- /dev/null +++ b/core/external/.gitignore @@ -0,0 +1,7 @@ +bbox.c +bbox.cpython-35m-x86_64-linux-gnu.so +bbox.cpython-36m-x86_64-linux-gnu.so + +nms.c +nms.cpython-35m-x86_64-linux-gnu.so +nms.cpython-36m-x86_64-linux-gnu.so diff --git a/core/external/Makefile b/core/external/Makefile new file mode 100644 index 0000000..a482398 --- /dev/null +++ b/core/external/Makefile @@ -0,0 +1,3 @@ +all: + python setup.py build_ext --inplace + rm -rf build diff --git a/core/external/__init__.py b/core/external/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/external/bbox.pyx b/core/external/bbox.pyx new file mode 100644 index 0000000..e14780d --- /dev/null +++ b/core/external/bbox.pyx @@ -0,0 +1,55 @@ +# -------------------------------------------------------- +# Fast R-CNN +# Copyright (c) 2015 Microsoft +# Licensed under The MIT License [see LICENSE for details] +# Written by Sergey Karayev +# -------------------------------------------------------- + +cimport cython +import numpy as np +cimport numpy as np + +DTYPE = np.float +ctypedef np.float_t DTYPE_t + +def bbox_overlaps( + np.ndarray[DTYPE_t, ndim=2] boxes, + np.ndarray[DTYPE_t, ndim=2] query_boxes): + """ + Parameters + ---------- + boxes: (N, 4) ndarray of float + query_boxes: (K, 4) ndarray of float + Returns + ------- + overlaps: (N, K) ndarray of overlap between boxes and query_boxes + """ + cdef unsigned int N = boxes.shape[0] + cdef unsigned int K = query_boxes.shape[0] + cdef np.ndarray[DTYPE_t, ndim=2] overlaps = np.zeros((N, K), dtype=DTYPE) + cdef DTYPE_t iw, ih, box_area + cdef DTYPE_t ua + cdef unsigned int k, n + for k in range(K): + box_area = ( + (query_boxes[k, 2] - query_boxes[k, 0] + 1) * + (query_boxes[k, 3] - query_boxes[k, 1] + 1) + ) + for n in range(N): + iw = ( + min(boxes[n, 2], query_boxes[k, 2]) - + max(boxes[n, 0], query_boxes[k, 0]) + 1 + ) + if iw > 0: + ih = ( + min(boxes[n, 3], query_boxes[k, 3]) - + max(boxes[n, 1], query_boxes[k, 1]) + 1 + ) + if ih > 0: + ua = float( + (boxes[n, 2] - boxes[n, 0] + 1) * + (boxes[n, 3] - boxes[n, 1] + 1) + + box_area - iw * ih + ) + overlaps[n, k] = iw * ih / ua + return overlaps diff --git a/core/external/nms.pyx b/core/external/nms.pyx new file mode 100644 index 0000000..2916328 --- /dev/null +++ b/core/external/nms.pyx @@ -0,0 +1,279 @@ +# -------------------------------------------------------- +# Fast R-CNN +# Copyright (c) 2015 Microsoft +# Licensed under The MIT License [see LICENSE for details] +# Written by Ross Girshick +# -------------------------------------------------------- + +import numpy as np +cimport numpy as np + +cdef inline np.float32_t max(np.float32_t a, np.float32_t b): + return a if a >= b else b + +cdef inline np.float32_t min(np.float32_t a, np.float32_t b): + return a if a <= b else b + +def nms(np.ndarray[np.float32_t, ndim=2] dets, np.float thresh): + cdef np.ndarray[np.float32_t, ndim=1] x1 = dets[:, 0] + cdef np.ndarray[np.float32_t, ndim=1] y1 = dets[:, 1] + cdef np.ndarray[np.float32_t, ndim=1] x2 = dets[:, 2] + cdef np.ndarray[np.float32_t, ndim=1] y2 = dets[:, 3] + cdef np.ndarray[np.float32_t, ndim=1] scores = dets[:, 4] + + cdef np.ndarray[np.float32_t, ndim=1] areas = (x2 - x1 + 1) * (y2 - y1 + 1) + cdef np.ndarray[np.int_t, ndim=1] order = scores.argsort()[::-1] + + cdef int ndets = dets.shape[0] + cdef np.ndarray[np.int_t, ndim=1] suppressed = \ + np.zeros((ndets), dtype=np.int) + + # nominal indices + cdef int _i, _j + # sorted indices + cdef int i, j + # temp variables for box i's (the box currently under consideration) + cdef np.float32_t ix1, iy1, ix2, iy2, iarea + # variables for computing overlap with box j (lower scoring box) + cdef np.float32_t xx1, yy1, xx2, yy2 + cdef np.float32_t w, h + cdef np.float32_t inter, ovr + + keep = [] + for _i in range(ndets): + i = order[_i] + if suppressed[i] == 1: + continue + keep.append(i) + ix1 = x1[i] + iy1 = y1[i] + ix2 = x2[i] + iy2 = y2[i] + iarea = areas[i] + for _j in range(_i + 1, ndets): + j = order[_j] + if suppressed[j] == 1: + continue + xx1 = max(ix1, x1[j]) + yy1 = max(iy1, y1[j]) + xx2 = min(ix2, x2[j]) + yy2 = min(iy2, y2[j]) + w = max(0.0, xx2 - xx1 + 1) + h = max(0.0, yy2 - yy1 + 1) + inter = w * h + ovr = inter / (iarea + areas[j] - inter) + if ovr >= thresh: + suppressed[j] = 1 + + return keep + +def soft_nms(np.ndarray[float, ndim=2] boxes, float sigma=0.5, float Nt=0.3, float threshold=0.001, unsigned int method=0): + cdef unsigned int N = boxes.shape[0] + cdef float iw, ih, box_area + cdef float ua + cdef int pos = 0 + cdef float maxscore = 0 + cdef int maxpos = 0 + cdef float x1,x2,y1,y2,tx1,tx2,ty1,ty2,ts,area,weight,ov + + for i in range(N): + maxscore = boxes[i, 4] + maxpos = i + + tx1 = boxes[i,0] + ty1 = boxes[i,1] + tx2 = boxes[i,2] + ty2 = boxes[i,3] + ts = boxes[i,4] + + pos = i + 1 + # get max box + while pos < N: + if maxscore < boxes[pos, 4]: + maxscore = boxes[pos, 4] + maxpos = pos + pos = pos + 1 + + # add max box as a detection + boxes[i,0] = boxes[maxpos,0] + boxes[i,1] = boxes[maxpos,1] + boxes[i,2] = boxes[maxpos,2] + boxes[i,3] = boxes[maxpos,3] + boxes[i,4] = boxes[maxpos,4] + + # swap ith box with position of max box + boxes[maxpos,0] = tx1 + boxes[maxpos,1] = ty1 + boxes[maxpos,2] = tx2 + boxes[maxpos,3] = ty2 + boxes[maxpos,4] = ts + + tx1 = boxes[i,0] + ty1 = boxes[i,1] + tx2 = boxes[i,2] + ty2 = boxes[i,3] + ts = boxes[i,4] + + pos = i + 1 + # NMS iterations, note that N changes if detection boxes fall below threshold + while pos < N: + x1 = boxes[pos, 0] + y1 = boxes[pos, 1] + x2 = boxes[pos, 2] + y2 = boxes[pos, 3] + s = boxes[pos, 4] + + area = (x2 - x1 + 1) * (y2 - y1 + 1) + iw = (min(tx2, x2) - max(tx1, x1) + 1) + if iw > 0: + ih = (min(ty2, y2) - max(ty1, y1) + 1) + if ih > 0: + ua = float((tx2 - tx1 + 1) * (ty2 - ty1 + 1) + area - iw * ih) + ov = iw * ih / ua #iou between max box and detection box + + if method == 1: # linear + if ov > Nt: + weight = 1 - ov + else: + weight = 1 + elif method == 2: # gaussian + weight = np.exp(-(ov * ov)/sigma) + else: # original NMS + if ov > Nt: + weight = 0 + else: + weight = 1 + + boxes[pos, 4] = weight*boxes[pos, 4] + + # if box score falls below threshold, discard the box by swapping with last box + # update N + if boxes[pos, 4] < threshold: + boxes[pos,0] = boxes[N-1, 0] + boxes[pos,1] = boxes[N-1, 1] + boxes[pos,2] = boxes[N-1, 2] + boxes[pos,3] = boxes[N-1, 3] + boxes[pos,4] = boxes[N-1, 4] + N = N - 1 + pos = pos - 1 + + pos = pos + 1 + + keep = [i for i in range(N)] + return keep + +def soft_nms_merge(np.ndarray[float, ndim=2] boxes, float sigma=0.5, float Nt=0.3, float threshold=0.001, unsigned int method=0, float weight_exp=6): + cdef unsigned int N = boxes.shape[0] + cdef float iw, ih, box_area + cdef float ua + cdef int pos = 0 + cdef float maxscore = 0 + cdef int maxpos = 0 + cdef float x1,x2,y1,y2,tx1,tx2,ty1,ty2,ts,area,weight,ov + cdef float mx1,mx2,my1,my2,mts,mbs,mw + + for i in range(N): + maxscore = boxes[i, 4] + maxpos = i + + tx1 = boxes[i,0] + ty1 = boxes[i,1] + tx2 = boxes[i,2] + ty2 = boxes[i,3] + ts = boxes[i,4] + + pos = i + 1 + # get max box + while pos < N: + if maxscore < boxes[pos, 4]: + maxscore = boxes[pos, 4] + maxpos = pos + pos = pos + 1 + + # add max box as a detection + boxes[i,0] = boxes[maxpos,0] + boxes[i,1] = boxes[maxpos,1] + boxes[i,2] = boxes[maxpos,2] + boxes[i,3] = boxes[maxpos,3] + boxes[i,4] = boxes[maxpos,4] + + mx1 = boxes[i, 0] * boxes[i, 5] + my1 = boxes[i, 1] * boxes[i, 5] + mx2 = boxes[i, 2] * boxes[i, 6] + my2 = boxes[i, 3] * boxes[i, 6] + mts = boxes[i, 5] + mbs = boxes[i, 6] + + # swap ith box with position of max box + boxes[maxpos,0] = tx1 + boxes[maxpos,1] = ty1 + boxes[maxpos,2] = tx2 + boxes[maxpos,3] = ty2 + boxes[maxpos,4] = ts + + tx1 = boxes[i,0] + ty1 = boxes[i,1] + tx2 = boxes[i,2] + ty2 = boxes[i,3] + ts = boxes[i,4] + + pos = i + 1 + # NMS iterations, note that N changes if detection boxes fall below threshold + while pos < N: + x1 = boxes[pos, 0] + y1 = boxes[pos, 1] + x2 = boxes[pos, 2] + y2 = boxes[pos, 3] + s = boxes[pos, 4] + + area = (x2 - x1 + 1) * (y2 - y1 + 1) + iw = (min(tx2, x2) - max(tx1, x1) + 1) + if iw > 0: + ih = (min(ty2, y2) - max(ty1, y1) + 1) + if ih > 0: + ua = float((tx2 - tx1 + 1) * (ty2 - ty1 + 1) + area - iw * ih) + ov = iw * ih / ua #iou between max box and detection box + + if method == 1: # linear + if ov > Nt: + weight = 1 - ov + else: + weight = 1 + elif method == 2: # gaussian + weight = np.exp(-(ov * ov)/sigma) + else: # original NMS + if ov > Nt: + weight = 0 + else: + weight = 1 + + mw = (1 - weight) ** weight_exp + mx1 = mx1 + boxes[pos, 0] * boxes[pos, 5] * mw + my1 = my1 + boxes[pos, 1] * boxes[pos, 5] * mw + mx2 = mx2 + boxes[pos, 2] * boxes[pos, 6] * mw + my2 = my2 + boxes[pos, 3] * boxes[pos, 6] * mw + mts = mts + boxes[pos, 5] * mw + mbs = mbs + boxes[pos, 6] * mw + + boxes[pos, 4] = weight*boxes[pos, 4] + + # if box score falls below threshold, discard the box by swapping with last box + # update N + if boxes[pos, 4] < threshold: + boxes[pos,0] = boxes[N-1, 0] + boxes[pos,1] = boxes[N-1, 1] + boxes[pos,2] = boxes[N-1, 2] + boxes[pos,3] = boxes[N-1, 3] + boxes[pos,4] = boxes[N-1, 4] + N = N - 1 + pos = pos - 1 + + pos = pos + 1 + + boxes[i, 0] = mx1 / mts + boxes[i, 1] = my1 / mts + boxes[i, 2] = mx2 / mbs + boxes[i, 3] = my2 / mbs + + keep = [i for i in range(N)] + return keep diff --git a/core/external/setup.py b/core/external/setup.py new file mode 100644 index 0000000..ca3bd04 --- /dev/null +++ b/core/external/setup.py @@ -0,0 +1,23 @@ +import numpy +from distutils.core import setup +from distutils.extension import Extension +from Cython.Build import cythonize + +extensions = [ + Extension( + "bbox", + ["bbox.pyx"], + extra_compile_args=["-Wno-cpp", "-Wno-unused-function"] + ), + Extension( + "nms", + ["nms.pyx"], + extra_compile_args=["-Wno-cpp", "-Wno-unused-function"] + ) +] + +setup( + name="coco", + ext_modules=cythonize(extensions), + include_dirs=[numpy.get_include()] +) diff --git a/core/models/CornerNet.py b/core/models/CornerNet.py new file mode 100755 index 0000000..6f29940 --- /dev/null +++ b/core/models/CornerNet.py @@ -0,0 +1,71 @@ +import torch +import torch.nn as nn + +from .py_utils import TopPool, BottomPool, LeftPool, RightPool + +from .py_utils.utils import convolution, residual, corner_pool +from .py_utils.losses import CornerNet_Loss +from .py_utils.modules import hg_module, hg, hg_net + +def make_pool_layer(dim): + return nn.Sequential() + +def make_hg_layer(inp_dim, out_dim, modules): + layers = [residual(inp_dim, out_dim, stride=2)] + layers += [residual(out_dim, out_dim) for _ in range(1, modules)] + return nn.Sequential(*layers) + +class model(hg_net): + def _pred_mod(self, dim): + return nn.Sequential( + convolution(3, 256, 256, with_bn=False), + nn.Conv2d(256, dim, (1, 1)) + ) + + def _merge_mod(self): + return nn.Sequential( + nn.Conv2d(256, 256, (1, 1), bias=False), + nn.BatchNorm2d(256) + ) + + def __init__(self): + stacks = 2 + pre = nn.Sequential( + convolution(7, 3, 128, stride=2), + residual(128, 256, stride=2) + ) + hg_mods = nn.ModuleList([ + hg_module( + 5, [256, 256, 384, 384, 384, 512], [2, 2, 2, 2, 2, 4], + make_pool_layer=make_pool_layer, + make_hg_layer=make_hg_layer + ) for _ in range(stacks) + ]) + cnvs = nn.ModuleList([convolution(3, 256, 256) for _ in range(stacks)]) + inters = nn.ModuleList([residual(256, 256) for _ in range(stacks - 1)]) + cnvs_ = nn.ModuleList([self._merge_mod() for _ in range(stacks - 1)]) + inters_ = nn.ModuleList([self._merge_mod() for _ in range(stacks - 1)]) + + hgs = hg(pre, hg_mods, cnvs, inters, cnvs_, inters_) + + tl_modules = nn.ModuleList([corner_pool(256, TopPool, LeftPool) for _ in range(stacks)]) + br_modules = nn.ModuleList([corner_pool(256, BottomPool, RightPool) for _ in range(stacks)]) + + tl_heats = nn.ModuleList([self._pred_mod(80) for _ in range(stacks)]) + br_heats = nn.ModuleList([self._pred_mod(80) for _ in range(stacks)]) + for tl_heat, br_heat in zip(tl_heats, br_heats): + torch.nn.init.constant_(tl_heat[-1].bias, -2.19) + torch.nn.init.constant_(br_heat[-1].bias, -2.19) + + tl_tags = nn.ModuleList([self._pred_mod(1) for _ in range(stacks)]) + br_tags = nn.ModuleList([self._pred_mod(1) for _ in range(stacks)]) + + tl_offs = nn.ModuleList([self._pred_mod(2) for _ in range(stacks)]) + br_offs = nn.ModuleList([self._pred_mod(2) for _ in range(stacks)]) + + super(model, self).__init__( + hgs, tl_modules, br_modules, tl_heats, br_heats, + tl_tags, br_tags, tl_offs, br_offs + ) + + self.loss = CornerNet_Loss(pull_weight=1e-1, push_weight=1e-1) diff --git a/core/models/CornerNet_Saccade.py b/core/models/CornerNet_Saccade.py new file mode 100644 index 0000000..549bd2c --- /dev/null +++ b/core/models/CornerNet_Saccade.py @@ -0,0 +1,91 @@ +import torch +import torch.nn as nn + +from .py_utils import TopPool, BottomPool, LeftPool, RightPool + +from .py_utils.utils import convolution, residual, corner_pool +from .py_utils.losses import CornerNet_Saccade_Loss +from .py_utils.modules import saccade_net, saccade_module, saccade + +def make_pool_layer(dim): + return nn.Sequential() + +def make_hg_layer(inp_dim, out_dim, modules): + layers = [residual(inp_dim, out_dim, stride=2)] + layers += [residual(out_dim, out_dim) for _ in range(1, modules)] + return nn.Sequential(*layers) + +class model(saccade_net): + def _pred_mod(self, dim): + return nn.Sequential( + convolution(3, 256, 256, with_bn=False), + nn.Conv2d(256, dim, (1, 1)) + ) + + def _merge_mod(self): + return nn.Sequential( + nn.Conv2d(256, 256, (1, 1), bias=False), + nn.BatchNorm2d(256) + ) + + def __init__(self): + stacks = 3 + pre = nn.Sequential( + convolution(7, 3, 128, stride=2), + residual(128, 256, stride=2) + ) + hg_mods = nn.ModuleList([ + saccade_module( + 3, [256, 384, 384, 512], [1, 1, 1, 1], + make_pool_layer=make_pool_layer, + make_hg_layer=make_hg_layer + ) for _ in range(stacks) + ]) + cnvs = nn.ModuleList([convolution(3, 256, 256) for _ in range(stacks)]) + inters = nn.ModuleList([residual(256, 256) for _ in range(stacks - 1)]) + cnvs_ = nn.ModuleList([self._merge_mod() for _ in range(stacks - 1)]) + inters_ = nn.ModuleList([self._merge_mod() for _ in range(stacks - 1)]) + + att_mods = nn.ModuleList([ + nn.ModuleList([ + nn.Sequential( + convolution(3, 384, 256, with_bn=False), + nn.Conv2d(256, 1, (1, 1)) + ), + nn.Sequential( + convolution(3, 384, 256, with_bn=False), + nn.Conv2d(256, 1, (1, 1)) + ), + nn.Sequential( + convolution(3, 256, 256, with_bn=False), + nn.Conv2d(256, 1, (1, 1)) + ) + ]) for _ in range(stacks) + ]) + for att_mod in att_mods: + for att in att_mod: + torch.nn.init.constant_(att[-1].bias, -2.19) + + hgs = saccade(pre, hg_mods, cnvs, inters, cnvs_, inters_) + + tl_modules = nn.ModuleList([corner_pool(256, TopPool, LeftPool) for _ in range(stacks)]) + br_modules = nn.ModuleList([corner_pool(256, BottomPool, RightPool) for _ in range(stacks)]) + + tl_heats = nn.ModuleList([self._pred_mod(80) for _ in range(stacks)]) + br_heats = nn.ModuleList([self._pred_mod(80) for _ in range(stacks)]) + for tl_heat, br_heat in zip(tl_heats, br_heats): + torch.nn.init.constant_(tl_heat[-1].bias, -2.19) + torch.nn.init.constant_(br_heat[-1].bias, -2.19) + + tl_tags = nn.ModuleList([self._pred_mod(1) for _ in range(stacks)]) + br_tags = nn.ModuleList([self._pred_mod(1) for _ in range(stacks)]) + + tl_offs = nn.ModuleList([self._pred_mod(2) for _ in range(stacks)]) + br_offs = nn.ModuleList([self._pred_mod(2) for _ in range(stacks)]) + + super(model, self).__init__( + hgs, tl_modules, br_modules, tl_heats, br_heats, + tl_tags, br_tags, tl_offs, br_offs, att_mods + ) + + self.loss = CornerNet_Saccade_Loss(pull_weight=1e-1, push_weight=1e-1) diff --git a/core/models/CornerNet_Squeeze.py b/core/models/CornerNet_Squeeze.py new file mode 100644 index 0000000..4003a15 --- /dev/null +++ b/core/models/CornerNet_Squeeze.py @@ -0,0 +1,111 @@ +import torch +import torch.nn as nn + +from .py_utils import TopPool, BottomPool, LeftPool, RightPool + +from .py_utils.utils import convolution, corner_pool, residual +from .py_utils.losses import CornerNet_Loss +from .py_utils.modules import hg_module, hg, hg_net + +class fire_module(nn.Module): + def __init__(self, inp_dim, out_dim, sr=2, stride=1): + super(fire_module, self).__init__() + self.conv1 = nn.Conv2d(inp_dim, out_dim // sr, kernel_size=1, stride=1, bias=False) + self.bn1 = nn.BatchNorm2d(out_dim // sr) + self.conv_1x1 = nn.Conv2d(out_dim // sr, out_dim // 2, kernel_size=1, stride=stride, bias=False) + self.conv_3x3 = nn.Conv2d(out_dim // sr, out_dim // 2, kernel_size=3, padding=1, + stride=stride, groups=out_dim // sr, bias=False) + self.bn2 = nn.BatchNorm2d(out_dim) + self.skip = (stride == 1 and inp_dim == out_dim) + self.relu = nn.ReLU(inplace=True) + + def forward(self, x): + conv1 = self.conv1(x) + bn1 = self.bn1(conv1) + conv2 = torch.cat((self.conv_1x1(bn1), self.conv_3x3(bn1)), 1) + bn2 = self.bn2(conv2) + if self.skip: + return self.relu(bn2 + x) + else: + return self.relu(bn2) + +def make_pool_layer(dim): + return nn.Sequential() + +def make_unpool_layer(dim): + return nn.ConvTranspose2d(dim, dim, kernel_size=4, stride=2, padding=1) + +def make_layer(inp_dim, out_dim, modules): + layers = [fire_module(inp_dim, out_dim)] + layers += [fire_module(out_dim, out_dim) for _ in range(1, modules)] + return nn.Sequential(*layers) + +def make_layer_revr(inp_dim, out_dim, modules): + layers = [fire_module(inp_dim, inp_dim) for _ in range(modules - 1)] + layers += [fire_module(inp_dim, out_dim)] + return nn.Sequential(*layers) + +def make_hg_layer(inp_dim, out_dim, modules): + layers = [fire_module(inp_dim, out_dim, stride=2)] + layers += [fire_module(out_dim, out_dim) for _ in range(1, modules)] + return nn.Sequential(*layers) + +class model(hg_net): + def _pred_mod(self, dim): + return nn.Sequential( + convolution(1, 256, 256, with_bn=False), + nn.Conv2d(256, dim, (1, 1)) + ) + + def _merge_mod(self): + return nn.Sequential( + nn.Conv2d(256, 256, (1, 1), bias=False), + nn.BatchNorm2d(256) + ) + + def __init__(self): + stacks = 2 + pre = nn.Sequential( + convolution(7, 3, 128, stride=2), + residual(128, 256, stride=2), + residual(256, 256, stride=2) + ) + hg_mods = nn.ModuleList([ + hg_module( + 4, [256, 256, 384, 384, 512], [2, 2, 2, 2, 4], + make_pool_layer=make_pool_layer, + make_unpool_layer=make_unpool_layer, + make_up_layer=make_layer, + make_low_layer=make_layer, + make_hg_layer_revr=make_layer_revr, + make_hg_layer=make_hg_layer + ) for _ in range(stacks) + ]) + cnvs = nn.ModuleList([convolution(3, 256, 256) for _ in range(stacks)]) + inters = nn.ModuleList([residual(256, 256) for _ in range(stacks - 1)]) + cnvs_ = nn.ModuleList([self._merge_mod() for _ in range(stacks - 1)]) + inters_ = nn.ModuleList([self._merge_mod() for _ in range(stacks - 1)]) + + hgs = hg(pre, hg_mods, cnvs, inters, cnvs_, inters_) + + tl_modules = nn.ModuleList([corner_pool(256, TopPool, LeftPool) for _ in range(stacks)]) + br_modules = nn.ModuleList([corner_pool(256, BottomPool, RightPool) for _ in range(stacks)]) + + tl_heats = nn.ModuleList([self._pred_mod(80) for _ in range(stacks)]) + br_heats = nn.ModuleList([self._pred_mod(80) for _ in range(stacks)]) + for tl_heat, br_heat in zip(tl_heats, br_heats): + torch.nn.init.constant_(tl_heat[-1].bias, -2.19) + torch.nn.init.constant_(br_heat[-1].bias, -2.19) + + tl_tags = nn.ModuleList([self._pred_mod(1) for _ in range(stacks)]) + br_tags = nn.ModuleList([self._pred_mod(1) for _ in range(stacks)]) + + tl_offs = nn.ModuleList([self._pred_mod(2) for _ in range(stacks)]) + br_offs = nn.ModuleList([self._pred_mod(2) for _ in range(stacks)]) + + super(model, self).__init__( + hgs, tl_modules, br_modules, tl_heats, br_heats, + tl_tags, br_tags, tl_offs, br_offs + ) + + self.loss = CornerNet_Loss(pull_weight=1e-1, push_weight=1e-1) diff --git a/core/models/__init__.py b/core/models/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/core/models/py_utils/__init__.py b/core/models/py_utils/__init__.py new file mode 100644 index 0000000..c1fde01 --- /dev/null +++ b/core/models/py_utils/__init__.py @@ -0,0 +1 @@ +from ._cpools import TopPool, BottomPool, LeftPool, RightPool diff --git a/core/models/py_utils/_cpools/.gitignore b/core/models/py_utils/_cpools/.gitignore new file mode 100644 index 0000000..6a0882d --- /dev/null +++ b/core/models/py_utils/_cpools/.gitignore @@ -0,0 +1,3 @@ +build/ +cpools.egg-info/ +dist/ diff --git a/core/models/py_utils/_cpools/__init__.py b/core/models/py_utils/_cpools/__init__.py new file mode 100644 index 0000000..1b4e76f --- /dev/null +++ b/core/models/py_utils/_cpools/__init__.py @@ -0,0 +1,74 @@ +import torch + +from torch import nn +from torch.autograd import Function + +import top_pool, bottom_pool, left_pool, right_pool + +class TopPoolFunction(Function): + @staticmethod + def forward(ctx, input): + output = top_pool.forward(input)[0] + ctx.save_for_backward(input) + return output + + @staticmethod + def backward(ctx, grad_output): + input = ctx.saved_variables[0] + output = top_pool.backward(input, grad_output)[0] + return output + +class BottomPoolFunction(Function): + @staticmethod + def forward(ctx, input): + output = bottom_pool.forward(input)[0] + ctx.save_for_backward(input) + return output + + @staticmethod + def backward(ctx, grad_output): + input = ctx.saved_variables[0] + output = bottom_pool.backward(input, grad_output)[0] + return output + +class LeftPoolFunction(Function): + @staticmethod + def forward(ctx, input): + output = left_pool.forward(input)[0] + ctx.save_for_backward(input) + return output + + @staticmethod + def backward(ctx, grad_output): + input = ctx.saved_variables[0] + output = left_pool.backward(input, grad_output)[0] + return output + +class RightPoolFunction(Function): + @staticmethod + def forward(ctx, input): + output = right_pool.forward(input)[0] + ctx.save_for_backward(input) + return output + + @staticmethod + def backward(ctx, grad_output): + input = ctx.saved_variables[0] + output = right_pool.backward(input, grad_output)[0] + return output + +class TopPool(nn.Module): + def forward(self, x): + return TopPoolFunction.apply(x) + +class BottomPool(nn.Module): + def forward(self, x): + return BottomPoolFunction.apply(x) + +class LeftPool(nn.Module): + def forward(self, x): + return LeftPoolFunction.apply(x) + +class RightPool(nn.Module): + def forward(self, x): + return RightPoolFunction.apply(x) diff --git a/core/models/py_utils/_cpools/setup.py b/core/models/py_utils/_cpools/setup.py new file mode 100644 index 0000000..9682833 --- /dev/null +++ b/core/models/py_utils/_cpools/setup.py @@ -0,0 +1,15 @@ +from setuptools import setup +from torch.utils.cpp_extension import BuildExtension, CppExtension + +setup( + name="cpools", + ext_modules=[ + CppExtension("top_pool", ["src/top_pool.cpp"]), + CppExtension("bottom_pool", ["src/bottom_pool.cpp"]), + CppExtension("left_pool", ["src/left_pool.cpp"]), + CppExtension("right_pool", ["src/right_pool.cpp"]) + ], + cmdclass={ + "build_ext": BuildExtension + } +) diff --git a/core/models/py_utils/_cpools/src/bottom_pool.cpp b/core/models/py_utils/_cpools/src/bottom_pool.cpp new file mode 100644 index 0000000..8a20a43 --- /dev/null +++ b/core/models/py_utils/_cpools/src/bottom_pool.cpp @@ -0,0 +1,80 @@ +#include + +#include + +std::vector pool_forward( + at::Tensor input +) { + // Initialize output + at::Tensor output = at::zeros_like(input); + + // Get height + int64_t height = input.size(2); + + output.copy_(input); + + for (int64_t ind = 1; ind < height; ind <<= 1) { + at::Tensor max_temp = at::slice(output, 2, ind, height); + at::Tensor cur_temp = at::slice(output, 2, ind, height); + at::Tensor next_temp = at::slice(output, 2, 0, height-ind); + at::max_out(max_temp, cur_temp, next_temp); + } + + return { + output + }; +} + +std::vector pool_backward( + at::Tensor input, + at::Tensor grad_output +) { + auto output = at::zeros_like(input); + + int32_t batch = input.size(0); + int32_t channel = input.size(1); + int32_t height = input.size(2); + int32_t width = input.size(3); + + auto max_val = torch::zeros({batch, channel, width}, at::device(at::kCUDA).dtype(at::kFloat)); + auto max_ind = torch::zeros({batch, channel, width}, at::device(at::kCUDA).dtype(at::kLong)); + + auto input_temp = input.select(2, 0); + max_val.copy_(input_temp); + + max_ind.fill_(0); + + auto output_temp = output.select(2, 0); + auto grad_output_temp = grad_output.select(2, 0); + output_temp.copy_(grad_output_temp); + + auto un_max_ind = max_ind.unsqueeze(2); + auto gt_mask = torch::zeros({batch, channel, width}, at::device(at::kCUDA).dtype(at::kByte)); + auto max_temp = torch::zeros({batch, channel, width}, at::device(at::kCUDA).dtype(at::kFloat)); + for (int32_t ind = 0; ind < height - 1; ++ind) { + input_temp = input.select(2, ind + 1); + at::gt_out(gt_mask, input_temp, max_val); + + at::masked_select_out(max_temp, input_temp, gt_mask); + max_val.masked_scatter_(gt_mask, max_temp); + max_ind.masked_fill_(gt_mask, ind + 1); + + grad_output_temp = grad_output.select(2, ind + 1).unsqueeze(2); + output.scatter_add_(2, un_max_ind, grad_output_temp); + } + + return { + output + }; +} + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + m.def( + "forward", &pool_forward, "Bottom Pool Forward", + py::call_guard() + ); + m.def( + "backward", &pool_backward, "Bottom Pool Backward", + py::call_guard() + ); +} diff --git a/core/models/py_utils/_cpools/src/left_pool.cpp b/core/models/py_utils/_cpools/src/left_pool.cpp new file mode 100644 index 0000000..c36fc1b --- /dev/null +++ b/core/models/py_utils/_cpools/src/left_pool.cpp @@ -0,0 +1,80 @@ +#include + +#include + +std::vector pool_forward( + at::Tensor input +) { + // Initialize output + at::Tensor output = at::zeros_like(input); + + // Get width + int64_t width = input.size(3); + + output.copy_(input); + + for (int64_t ind = 1; ind < width; ind <<= 1) { + at::Tensor max_temp = at::slice(output, 3, 0, width-ind); + at::Tensor cur_temp = at::slice(output, 3, 0, width-ind); + at::Tensor next_temp = at::slice(output, 3, ind, width); + at::max_out(max_temp, cur_temp, next_temp); + } + + return { + output + }; +} + +std::vector pool_backward( + at::Tensor input, + at::Tensor grad_output +) { + auto output = at::zeros_like(input); + + int32_t batch = input.size(0); + int32_t channel = input.size(1); + int32_t height = input.size(2); + int32_t width = input.size(3); + + auto max_val = torch::zeros({batch, channel, height}, at::device(at::kCUDA).dtype(at::kFloat)); + auto max_ind = torch::zeros({batch, channel, height}, at::device(at::kCUDA).dtype(at::kLong)); + + auto input_temp = input.select(3, width - 1); + max_val.copy_(input_temp); + + max_ind.fill_(width - 1); + + auto output_temp = output.select(3, width - 1); + auto grad_output_temp = grad_output.select(3, width - 1); + output_temp.copy_(grad_output_temp); + + auto un_max_ind = max_ind.unsqueeze(3); + auto gt_mask = torch::zeros({batch, channel, height}, at::device(at::kCUDA).dtype(at::kByte)); + auto max_temp = torch::zeros({batch, channel, height}, at::device(at::kCUDA).dtype(at::kFloat)); + for (int32_t ind = 1; ind < width; ++ind) { + input_temp = input.select(3, width - ind - 1); + at::gt_out(gt_mask, input_temp, max_val); + + at::masked_select_out(max_temp, input_temp, gt_mask); + max_val.masked_scatter_(gt_mask, max_temp); + max_ind.masked_fill_(gt_mask, width - ind - 1); + + grad_output_temp = grad_output.select(3, width - ind - 1).unsqueeze(3); + output.scatter_add_(3, un_max_ind, grad_output_temp); + } + + return { + output + }; +} + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + m.def( + "forward", &pool_forward, "Left Pool Forward", + py::call_guard() + ); + m.def( + "backward", &pool_backward, "Left Pool Backward", + py::call_guard() + ); +} diff --git a/core/models/py_utils/_cpools/src/right_pool.cpp b/core/models/py_utils/_cpools/src/right_pool.cpp new file mode 100644 index 0000000..1b2da43 --- /dev/null +++ b/core/models/py_utils/_cpools/src/right_pool.cpp @@ -0,0 +1,80 @@ +#include + +#include + +std::vector pool_forward( + at::Tensor input +) { + // Initialize output + at::Tensor output = at::zeros_like(input); + + // Get width + int64_t width = input.size(3); + + output.copy_(input); + + for (int64_t ind = 1; ind < width; ind <<= 1) { + at::Tensor max_temp = at::slice(output, 3, ind, width); + at::Tensor cur_temp = at::slice(output, 3, ind, width); + at::Tensor next_temp = at::slice(output, 3, 0, width-ind); + at::max_out(max_temp, cur_temp, next_temp); + } + + return { + output + }; +} + +std::vector pool_backward( + at::Tensor input, + at::Tensor grad_output +) { + at::Tensor output = at::zeros_like(input); + + int32_t batch = input.size(0); + int32_t channel = input.size(1); + int32_t height = input.size(2); + int32_t width = input.size(3); + + auto max_val = torch::zeros({batch, channel, height}, at::device(at::kCUDA).dtype(at::kFloat)); + auto max_ind = torch::zeros({batch, channel, height}, at::device(at::kCUDA).dtype(at::kLong)); + + auto input_temp = input.select(3, 0); + max_val.copy_(input_temp); + + max_ind.fill_(0); + + auto output_temp = output.select(3, 0); + auto grad_output_temp = grad_output.select(3, 0); + output_temp.copy_(grad_output_temp); + + auto un_max_ind = max_ind.unsqueeze(3); + auto gt_mask = torch::zeros({batch, channel, height}, at::device(at::kCUDA).dtype(at::kByte)); + auto max_temp = torch::zeros({batch, channel, height}, at::device(at::kCUDA).dtype(at::kFloat)); + for (int32_t ind = 0; ind < width - 1; ++ind) { + input_temp = input.select(3, ind + 1); + at::gt_out(gt_mask, input_temp, max_val); + + at::masked_select_out(max_temp, input_temp, gt_mask); + max_val.masked_scatter_(gt_mask, max_temp); + max_ind.masked_fill_(gt_mask, ind + 1); + + grad_output_temp = grad_output.select(3, ind + 1).unsqueeze(3); + output.scatter_add_(3, un_max_ind, grad_output_temp); + } + + return { + output + }; +} + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + m.def( + "forward", &pool_forward, "Right Pool Forward", + py::call_guard() + ); + m.def( + "backward", &pool_backward, "Right Pool Backward", + py::call_guard() + ); +} diff --git a/core/models/py_utils/_cpools/src/top_pool.cpp b/core/models/py_utils/_cpools/src/top_pool.cpp new file mode 100644 index 0000000..bc63c49 --- /dev/null +++ b/core/models/py_utils/_cpools/src/top_pool.cpp @@ -0,0 +1,80 @@ +#include + +#include + +std::vector top_pool_forward( + at::Tensor input +) { + // Initialize output + at::Tensor output = at::zeros_like(input); + + // Get height + int64_t height = input.size(2); + + output.copy_(input); + + for (int64_t ind = 1; ind < height; ind <<= 1) { + at::Tensor max_temp = at::slice(output, 2, 0, height-ind); + at::Tensor cur_temp = at::slice(output, 2, 0, height-ind); + at::Tensor next_temp = at::slice(output, 2, ind, height); + at::max_out(max_temp, cur_temp, next_temp); + } + + return { + output + }; +} + +std::vector top_pool_backward( + at::Tensor input, + at::Tensor grad_output +) { + auto output = at::zeros_like(input); + + int32_t batch = input.size(0); + int32_t channel = input.size(1); + int32_t height = input.size(2); + int32_t width = input.size(3); + + auto max_val = torch::zeros({batch, channel, width}, at::device(at::kCUDA).dtype(at::kFloat)); + auto max_ind = torch::zeros({batch, channel, width}, at::device(at::kCUDA).dtype(at::kLong)); + + auto input_temp = input.select(2, height - 1); + max_val.copy_(input_temp); + + max_ind.fill_(height - 1); + + auto output_temp = output.select(2, height - 1); + auto grad_output_temp = grad_output.select(2, height - 1); + output_temp.copy_(grad_output_temp); + + auto un_max_ind = max_ind.unsqueeze(2); + auto gt_mask = torch::zeros({batch, channel, width}, at::device(at::kCUDA).dtype(at::kByte)); + auto max_temp = torch::zeros({batch, channel, width}, at::device(at::kCUDA).dtype(at::kFloat)); + for (int32_t ind = 1; ind < height; ++ind) { + input_temp = input.select(2, height - ind - 1); + at::gt_out(gt_mask, input_temp, max_val); + + at::masked_select_out(max_temp, input_temp, gt_mask); + max_val.masked_scatter_(gt_mask, max_temp); + max_ind.masked_fill_(gt_mask, height - ind - 1); + + grad_output_temp = grad_output.select(2, height - ind - 1).unsqueeze(2); + output.scatter_add_(2, un_max_ind, grad_output_temp); + } + + return { + output + }; +} + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + m.def( + "forward", &top_pool_forward, "Top Pool Forward", + py::call_guard() + ); + m.def( + "backward", &top_pool_backward, "Top Pool Backward", + py::call_guard() + ); +} diff --git a/core/models/py_utils/data_parallel.py b/core/models/py_utils/data_parallel.py new file mode 100644 index 0000000..cc2a5a8 --- /dev/null +++ b/core/models/py_utils/data_parallel.py @@ -0,0 +1,116 @@ +import torch +from torch.nn.modules import Module +from torch.nn.parallel.scatter_gather import gather +from torch.nn.parallel.replicate import replicate +from torch.nn.parallel.parallel_apply import parallel_apply + +from .scatter_gather import scatter_kwargs + +class DataParallel(Module): + r"""Implements data parallelism at the module level. + + This container parallelizes the application of the given module by + splitting the input across the specified devices by chunking in the batch + dimension. In the forward pass, the module is replicated on each device, + and each replica handles a portion of the input. During the backwards + pass, gradients from each replica are summed into the original module. + + The batch size should be larger than the number of GPUs used. It should + also be an integer multiple of the number of GPUs so that each chunk is the + same size (so that each GPU processes the same number of samples). + + See also: :ref:`cuda-nn-dataparallel-instead` + + Arbitrary positional and keyword inputs are allowed to be passed into + DataParallel EXCEPT Tensors. All variables will be scattered on dim + specified (default 0). Primitive types will be broadcasted, but all + other types will be a shallow copy and can be corrupted if written to in + the model's forward pass. + + Args: + module: module to be parallelized + device_ids: CUDA devices (default: all devices) + output_device: device location of output (default: device_ids[0]) + + Example:: + + >>> net = torch.nn.DataParallel(model, device_ids=[0, 1, 2]) + >>> output = net(input_var) + """ + + # TODO: update notes/cuda.rst when this class handles 8+ GPUs well + + def __init__(self, module, device_ids=None, output_device=None, dim=0, chunk_sizes=None): + super(DataParallel, self).__init__() + + if not torch.cuda.is_available(): + self.module = module + self.device_ids = [] + return + + if device_ids is None: + device_ids = list(range(torch.cuda.device_count())) + if output_device is None: + output_device = device_ids[0] + self.dim = dim + self.module = module + self.device_ids = device_ids + self.chunk_sizes = chunk_sizes + self.output_device = output_device + if len(self.device_ids) == 1: + self.module.cuda(device_ids[0]) + + def forward(self, *inputs, **kwargs): + if not self.device_ids: + return self.module(*inputs, **kwargs) + inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids, self.chunk_sizes) + if len(self.device_ids) == 1: + return self.module(*inputs[0], **kwargs[0]) + replicas = self.replicate(self.module, self.device_ids[:len(inputs)]) + outputs = self.parallel_apply(replicas, inputs, kwargs) + return self.gather(outputs, self.output_device) + + def replicate(self, module, device_ids): + return replicate(module, device_ids) + + def scatter(self, inputs, kwargs, device_ids, chunk_sizes): + return scatter_kwargs(inputs, kwargs, device_ids, dim=self.dim, chunk_sizes=self.chunk_sizes) + + def parallel_apply(self, replicas, inputs, kwargs): + return parallel_apply(replicas, inputs, kwargs, self.device_ids[:len(replicas)]) + + def gather(self, outputs, output_device): + return gather(outputs, output_device, dim=self.dim) + + +def data_parallel(module, inputs, device_ids=None, output_device=None, dim=0, module_kwargs=None): + r"""Evaluates module(input) in parallel across the GPUs given in device_ids. + + This is the functional version of the DataParallel module. + + Args: + module: the module to evaluate in parallel + inputs: inputs to the module + device_ids: GPU ids on which to replicate module + output_device: GPU location of the output Use -1 to indicate the CPU. + (default: device_ids[0]) + Returns: + a Variable containing the result of module(input) located on + output_device + """ + if not isinstance(inputs, tuple): + inputs = (inputs,) + + if device_ids is None: + device_ids = list(range(torch.cuda.device_count())) + + if output_device is None: + output_device = device_ids[0] + + inputs, module_kwargs = scatter_kwargs(inputs, module_kwargs, device_ids, dim) + if len(device_ids) == 1: + return module(*inputs[0], **module_kwargs[0]) + used_device_ids = device_ids[:len(inputs)] + replicas = replicate(module, used_device_ids) + outputs = parallel_apply(replicas, inputs, module_kwargs, used_device_ids) + return gather(outputs, output_device, dim) diff --git a/core/models/py_utils/losses.py b/core/models/py_utils/losses.py new file mode 100644 index 0000000..21bffa2 --- /dev/null +++ b/core/models/py_utils/losses.py @@ -0,0 +1,224 @@ +import torch +import torch.nn as nn + +from .utils import _tranpose_and_gather_feat + +def _sigmoid(x): + return torch.clamp(x.sigmoid_(), min=1e-4, max=1-1e-4) + +def _ae_loss(tag0, tag1, mask): + num = mask.sum(dim=1, keepdim=True).float() + tag0 = tag0.squeeze() + tag1 = tag1.squeeze() + + tag_mean = (tag0 + tag1) / 2 + + tag0 = torch.pow(tag0 - tag_mean, 2) / (num + 1e-4) + tag0 = tag0[mask].sum() + tag1 = torch.pow(tag1 - tag_mean, 2) / (num + 1e-4) + tag1 = tag1[mask].sum() + pull = tag0 + tag1 + + mask = mask.unsqueeze(1) + mask.unsqueeze(2) + mask = mask.eq(2) + num = num.unsqueeze(2) + num2 = (num - 1) * num + dist = tag_mean.unsqueeze(1) - tag_mean.unsqueeze(2) + dist = 1 - torch.abs(dist) + dist = nn.functional.relu(dist, inplace=True) + dist = dist - 1 / (num + 1e-4) + dist = dist / (num2 + 1e-4) + dist = dist[mask] + push = dist.sum() + return pull, push + +def _off_loss(off, gt_off, mask): + num = mask.float().sum() + mask = mask.unsqueeze(2).expand_as(gt_off) + + off = off[mask] + gt_off = gt_off[mask] + + off_loss = nn.functional.smooth_l1_loss(off, gt_off, reduction="sum") + off_loss = off_loss / (num + 1e-4) + return off_loss + +def _focal_loss_mask(preds, gt, mask): + pos_inds = gt.eq(1) + neg_inds = gt.lt(1) + + neg_weights = torch.pow(1 - gt[neg_inds], 4) + + pos_mask = mask[pos_inds] + neg_mask = mask[neg_inds] + + loss = 0 + for pred in preds: + pos_pred = pred[pos_inds] + neg_pred = pred[neg_inds] + + pos_loss = torch.log(pos_pred) * torch.pow(1 - pos_pred, 2) * pos_mask + neg_loss = torch.log(1 - neg_pred) * torch.pow(neg_pred, 2) * neg_weights * neg_mask + + num_pos = pos_inds.float().sum() + pos_loss = pos_loss.sum() + neg_loss = neg_loss.sum() + + if pos_pred.nelement() == 0: + loss = loss - neg_loss + else: + loss = loss - (pos_loss + neg_loss) / num_pos + return loss + +def _focal_loss(preds, gt): + pos_inds = gt.eq(1) + neg_inds = gt.lt(1) + + neg_weights = torch.pow(1 - gt[neg_inds], 4) + + loss = 0 + for pred in preds: + pos_pred = pred[pos_inds] + neg_pred = pred[neg_inds] + + pos_loss = torch.log(pos_pred) * torch.pow(1 - pos_pred, 2) + neg_loss = torch.log(1 - neg_pred) * torch.pow(neg_pred, 2) * neg_weights + + num_pos = pos_inds.float().sum() + pos_loss = pos_loss.sum() + neg_loss = neg_loss.sum() + + if pos_pred.nelement() == 0: + loss = loss - neg_loss + else: + loss = loss - (pos_loss + neg_loss) / num_pos + return loss + +class CornerNet_Saccade_Loss(nn.Module): + def __init__(self, pull_weight=1, push_weight=1, off_weight=1, focal_loss=_focal_loss_mask): + super(CornerNet_Saccade_Loss, self).__init__() + + self.pull_weight = pull_weight + self.push_weight = push_weight + self.off_weight = off_weight + self.focal_loss = focal_loss + self.ae_loss = _ae_loss + self.off_loss = _off_loss + + def forward(self, outs, targets): + tl_heats = outs[0] + br_heats = outs[1] + tl_tags = outs[2] + br_tags = outs[3] + tl_offs = outs[4] + br_offs = outs[5] + atts = outs[6] + + gt_tl_heat = targets[0] + gt_br_heat = targets[1] + gt_mask = targets[2] + gt_tl_off = targets[3] + gt_br_off = targets[4] + gt_tl_ind = targets[5] + gt_br_ind = targets[6] + gt_tl_valid = targets[7] + gt_br_valid = targets[8] + gt_atts = targets[9] + + # focal loss + focal_loss = 0 + + tl_heats = [_sigmoid(t) for t in tl_heats] + br_heats = [_sigmoid(b) for b in br_heats] + + focal_loss += self.focal_loss(tl_heats, gt_tl_heat, gt_tl_valid) + focal_loss += self.focal_loss(br_heats, gt_br_heat, gt_br_valid) + + atts = [[_sigmoid(a) for a in att] for att in atts] + atts = [[att[ind] for att in atts] for ind in range(len(gt_atts))] + + att_loss = 0 + for att, gt_att in zip(atts, gt_atts): + att_loss += _focal_loss(att, gt_att) / max(len(att), 1) + + # tag loss + pull_loss = 0 + push_loss = 0 + tl_tags = [_tranpose_and_gather_feat(tl_tag, gt_tl_ind) for tl_tag in tl_tags] + br_tags = [_tranpose_and_gather_feat(br_tag, gt_br_ind) for br_tag in br_tags] + for tl_tag, br_tag in zip(tl_tags, br_tags): + pull, push = self.ae_loss(tl_tag, br_tag, gt_mask) + pull_loss += pull + push_loss += push + pull_loss = self.pull_weight * pull_loss + push_loss = self.push_weight * push_loss + + off_loss = 0 + tl_offs = [_tranpose_and_gather_feat(tl_off, gt_tl_ind) for tl_off in tl_offs] + br_offs = [_tranpose_and_gather_feat(br_off, gt_br_ind) for br_off in br_offs] + for tl_off, br_off in zip(tl_offs, br_offs): + off_loss += self.off_loss(tl_off, gt_tl_off, gt_mask) + off_loss += self.off_loss(br_off, gt_br_off, gt_mask) + off_loss = self.off_weight * off_loss + + loss = (focal_loss + att_loss + pull_loss + push_loss + off_loss) / max(len(tl_heats), 1) + return loss.unsqueeze(0) + +class CornerNet_Loss(nn.Module): + def __init__(self, pull_weight=1, push_weight=1, off_weight=1, focal_loss=_focal_loss): + super(CornerNet_Loss, self).__init__() + + self.pull_weight = pull_weight + self.push_weight = push_weight + self.off_weight = off_weight + self.focal_loss = focal_loss + self.ae_loss = _ae_loss + self.off_loss = _off_loss + + def forward(self, outs, targets): + tl_heats = outs[0] + br_heats = outs[1] + tl_tags = outs[2] + br_tags = outs[3] + tl_offs = outs[4] + br_offs = outs[5] + + gt_tl_heat = targets[0] + gt_br_heat = targets[1] + gt_mask = targets[2] + gt_tl_off = targets[3] + gt_br_off = targets[4] + gt_tl_ind = targets[5] + gt_br_ind = targets[6] + + # focal loss + focal_loss = 0 + + tl_heats = [_sigmoid(t) for t in tl_heats] + br_heats = [_sigmoid(b) for b in br_heats] + + focal_loss += self.focal_loss(tl_heats, gt_tl_heat) + focal_loss += self.focal_loss(br_heats, gt_br_heat) + + # tag loss + pull_loss = 0 + push_loss = 0 + tl_tags = [_tranpose_and_gather_feat(tl_tag, gt_tl_ind) for tl_tag in tl_tags] + br_tags = [_tranpose_and_gather_feat(br_tag, gt_br_ind) for br_tag in br_tags] + for tl_tag, br_tag in zip(tl_tags, br_tags): + pull, push = self.ae_loss(tl_tag, br_tag, gt_mask) + pull_loss += pull + push_loss += push + pull_loss = self.pull_weight * pull_loss + push_loss = self.push_weight * push_loss + + off_loss = 0 + tl_offs = [_tranpose_and_gather_feat(tl_off, gt_tl_ind) for tl_off in tl_offs] + br_offs = [_tranpose_and_gather_feat(br_off, gt_br_ind) for br_off in br_offs] + for tl_off, br_off in zip(tl_offs, br_offs): + off_loss += self.off_loss(tl_off, gt_tl_off, gt_mask) + off_loss += self.off_loss(br_off, gt_br_off, gt_mask) + off_loss = self.off_weight * off_loss + + loss = (focal_loss + pull_loss + push_loss + off_loss) / max(len(tl_heats), 1) + return loss.unsqueeze(0) diff --git a/core/models/py_utils/modules.py b/core/models/py_utils/modules.py new file mode 100644 index 0000000..d28590b --- /dev/null +++ b/core/models/py_utils/modules.py @@ -0,0 +1,292 @@ +import torch +import torch.nn as nn + +from .utils import residual, upsample, merge, _decode + +def _make_layer(inp_dim, out_dim, modules): + layers = [residual(inp_dim, out_dim)] + layers += [residual(out_dim, out_dim) for _ in range(1, modules)] + return nn.Sequential(*layers) + +def _make_layer_revr(inp_dim, out_dim, modules): + layers = [residual(inp_dim, inp_dim) for _ in range(modules - 1)] + layers += [residual(inp_dim, out_dim)] + return nn.Sequential(*layers) + +def _make_pool_layer(dim): + return nn.MaxPool2d(kernel_size=2, stride=2) + +def _make_unpool_layer(dim): + return upsample(scale_factor=2) + +def _make_merge_layer(dim): + return merge() + +class hg_module(nn.Module): + def __init__( + self, n, dims, modules, make_up_layer=_make_layer, + make_pool_layer=_make_pool_layer, make_hg_layer=_make_layer, + make_low_layer=_make_layer, make_hg_layer_revr=_make_layer_revr, + make_unpool_layer=_make_unpool_layer, make_merge_layer=_make_merge_layer + ): + super(hg_module, self).__init__() + + curr_mod = modules[0] + next_mod = modules[1] + + curr_dim = dims[0] + next_dim = dims[1] + + self.n = n + self.up1 = make_up_layer(curr_dim, curr_dim, curr_mod) + self.max1 = make_pool_layer(curr_dim) + self.low1 = make_hg_layer(curr_dim, next_dim, curr_mod) + self.low2 = hg_module( + n - 1, dims[1:], modules[1:], + make_up_layer=make_up_layer, + make_pool_layer=make_pool_layer, + make_hg_layer=make_hg_layer, + make_low_layer=make_low_layer, + make_hg_layer_revr=make_hg_layer_revr, + make_unpool_layer=make_unpool_layer, + make_merge_layer=make_merge_layer + ) if n > 1 else make_low_layer(next_dim, next_dim, next_mod) + self.low3 = make_hg_layer_revr(next_dim, curr_dim, curr_mod) + self.up2 = make_unpool_layer(curr_dim) + self.merg = make_merge_layer(curr_dim) + + def forward(self, x): + up1 = self.up1(x) + max1 = self.max1(x) + low1 = self.low1(max1) + low2 = self.low2(low1) + low3 = self.low3(low2) + up2 = self.up2(low3) + merg = self.merg(up1, up2) + return merg + +class hg(nn.Module): + def __init__(self, pre, hg_modules, cnvs, inters, cnvs_, inters_): + super(hg, self).__init__() + + self.pre = pre + self.hgs = hg_modules + self.cnvs = cnvs + + self.inters = inters + self.inters_ = inters_ + self.cnvs_ = cnvs_ + + def forward(self, x): + inter = self.pre(x) + + cnvs = [] + for ind, (hg_, cnv_) in enumerate(zip(self.hgs, self.cnvs)): + hg = hg_(inter) + cnv = cnv_(hg) + cnvs.append(cnv) + + if ind < len(self.hgs) - 1: + inter = self.inters_[ind](inter) + self.cnvs_[ind](cnv) + inter = nn.functional.relu_(inter) + inter = self.inters[ind](inter) + return cnvs + +class hg_net(nn.Module): + def __init__( + self, hg, tl_modules, br_modules, tl_heats, br_heats, + tl_tags, br_tags, tl_offs, br_offs + ): + super(hg_net, self).__init__() + + self._decode = _decode + + self.hg = hg + + self.tl_modules = tl_modules + self.br_modules = br_modules + + self.tl_heats = tl_heats + self.br_heats = br_heats + + self.tl_tags = tl_tags + self.br_tags = br_tags + + self.tl_offs = tl_offs + self.br_offs = br_offs + + def _train(self, *xs): + image = xs[0] + cnvs = self.hg(image) + + tl_modules = [tl_mod_(cnv) for tl_mod_, cnv in zip(self.tl_modules, cnvs)] + br_modules = [br_mod_(cnv) for br_mod_, cnv in zip(self.br_modules, cnvs)] + tl_heats = [tl_heat_(tl_mod) for tl_heat_, tl_mod in zip(self.tl_heats, tl_modules)] + br_heats = [br_heat_(br_mod) for br_heat_, br_mod in zip(self.br_heats, br_modules)] + tl_tags = [tl_tag_(tl_mod) for tl_tag_, tl_mod in zip(self.tl_tags, tl_modules)] + br_tags = [br_tag_(br_mod) for br_tag_, br_mod in zip(self.br_tags, br_modules)] + tl_offs = [tl_off_(tl_mod) for tl_off_, tl_mod in zip(self.tl_offs, tl_modules)] + br_offs = [br_off_(br_mod) for br_off_, br_mod in zip(self.br_offs, br_modules)] + return [tl_heats, br_heats, tl_tags, br_tags, tl_offs, br_offs] + + def _test(self, *xs, **kwargs): + image = xs[0] + cnvs = self.hg(image) + + tl_mod = self.tl_modules[-1](cnvs[-1]) + br_mod = self.br_modules[-1](cnvs[-1]) + + tl_heat, br_heat = self.tl_heats[-1](tl_mod), self.br_heats[-1](br_mod) + tl_tag, br_tag = self.tl_tags[-1](tl_mod), self.br_tags[-1](br_mod) + tl_off, br_off = self.tl_offs[-1](tl_mod), self.br_offs[-1](br_mod) + + outs = [tl_heat, br_heat, tl_tag, br_tag, tl_off, br_off] + return self._decode(*outs, **kwargs), tl_heat, br_heat, tl_tag, br_tag + + def forward(self, *xs, test=False, **kwargs): + if not test: + return self._train(*xs, **kwargs) + return self._test(*xs, **kwargs) + +class saccade_module(nn.Module): + def __init__( + self, n, dims, modules, make_up_layer=_make_layer, + make_pool_layer=_make_pool_layer, make_hg_layer=_make_layer, + make_low_layer=_make_layer, make_hg_layer_revr=_make_layer_revr, + make_unpool_layer=_make_unpool_layer, make_merge_layer=_make_merge_layer + ): + super(saccade_module, self).__init__() + + curr_mod = modules[0] + next_mod = modules[1] + + curr_dim = dims[0] + next_dim = dims[1] + + self.n = n + self.up1 = make_up_layer(curr_dim, curr_dim, curr_mod) + self.max1 = make_pool_layer(curr_dim) + self.low1 = make_hg_layer(curr_dim, next_dim, curr_mod) + self.low2 = saccade_module( + n - 1, dims[1:], modules[1:], + make_up_layer=make_up_layer, + make_pool_layer=make_pool_layer, + make_hg_layer=make_hg_layer, + make_low_layer=make_low_layer, + make_hg_layer_revr=make_hg_layer_revr, + make_unpool_layer=make_unpool_layer, + make_merge_layer=make_merge_layer + ) if n > 1 else make_low_layer(next_dim, next_dim, next_mod) + self.low3 = make_hg_layer_revr(next_dim, curr_dim, curr_mod) + self.up2 = make_unpool_layer(curr_dim) + self.merg = make_merge_layer(curr_dim) + + def forward(self, x): + up1 = self.up1(x) + max1 = self.max1(x) + low1 = self.low1(max1) + if self.n > 1: + low2, mergs = self.low2(low1) + else: + low2, mergs = self.low2(low1), [] + low3 = self.low3(low2) + up2 = self.up2(low3) + merg = self.merg(up1, up2) + mergs.append(merg) + return merg, mergs + +class saccade(nn.Module): + def __init__(self, pre, hg_modules, cnvs, inters, cnvs_, inters_): + super(saccade, self).__init__() + + self.pre = pre + self.hgs = hg_modules + self.cnvs = cnvs + + self.inters = inters + self.inters_ = inters_ + self.cnvs_ = cnvs_ + + def forward(self, x): + inter = self.pre(x) + + cnvs = [] + atts = [] + for ind, (hg_, cnv_) in enumerate(zip(self.hgs, self.cnvs)): + hg, ups = hg_(inter) + cnv = cnv_(hg) + cnvs.append(cnv) + atts.append(ups) + + if ind < len(self.hgs) - 1: + inter = self.inters_[ind](inter) + self.cnvs_[ind](cnv) + inter = nn.functional.relu_(inter) + inter = self.inters[ind](inter) + return cnvs, atts + +class saccade_net(nn.Module): + def __init__( + self, hg, tl_modules, br_modules, tl_heats, br_heats, + tl_tags, br_tags, tl_offs, br_offs, att_modules, up_start=0 + ): + super(saccade_net, self).__init__() + + self._decode = _decode + + self.hg = hg + + self.tl_modules = tl_modules + self.br_modules = br_modules + self.tl_heats = tl_heats + self.br_heats = br_heats + self.tl_tags = tl_tags + self.br_tags = br_tags + self.tl_offs = tl_offs + self.br_offs = br_offs + + self.att_modules = att_modules + self.up_start = up_start + + def _train(self, *xs): + image = xs[0] + + cnvs, ups = self.hg(image) + ups = [up[self.up_start:] for up in ups] + + tl_modules = [tl_mod_(cnv) for tl_mod_, cnv in zip(self.tl_modules, cnvs)] + br_modules = [br_mod_(cnv) for br_mod_, cnv in zip(self.br_modules, cnvs)] + tl_heats = [tl_heat_(tl_mod) for tl_heat_, tl_mod in zip(self.tl_heats, tl_modules)] + br_heats = [br_heat_(br_mod) for br_heat_, br_mod in zip(self.br_heats, br_modules)] + tl_tags = [tl_tag_(tl_mod) for tl_tag_, tl_mod in zip(self.tl_tags, tl_modules)] + br_tags = [br_tag_(br_mod) for br_tag_, br_mod in zip(self.br_tags, br_modules)] + tl_offs = [tl_off_(tl_mod) for tl_off_, tl_mod in zip(self.tl_offs, tl_modules)] + br_offs = [br_off_(br_mod) for br_off_, br_mod in zip(self.br_offs, br_modules)] + atts = [[att_mod_(u) for att_mod_, u in zip(att_mods, up)] for att_mods, up in zip(self.att_modules, ups)] + return [tl_heats, br_heats, tl_tags, br_tags, tl_offs, br_offs, atts] + + def _test(self, *xs, no_att=False, **kwargs): + image = xs[0] + cnvs, ups = self.hg(image) + ups = [up[self.up_start:] for up in ups] + + if not no_att: + atts = [att_mod_(up) for att_mod_, up in zip(self.att_modules[-1], ups[-1])] + atts = [torch.sigmoid(att) for att in atts] + + tl_mod = self.tl_modules[-1](cnvs[-1]) + br_mod = self.br_modules[-1](cnvs[-1]) + + tl_heat, br_heat = self.tl_heats[-1](tl_mod), self.br_heats[-1](br_mod) + tl_tag, br_tag = self.tl_tags[-1](tl_mod), self.br_tags[-1](br_mod) + tl_off, br_off = self.tl_offs[-1](tl_mod), self.br_offs[-1](br_mod) + + outs = [tl_heat, br_heat, tl_tag, br_tag, tl_off, br_off] + if not no_att: + return self._decode(*outs, **kwargs), atts + else: + return self._decode(*outs, **kwargs) + + def forward(self, *xs, test=False, **kwargs): + if not test: + return self._train(*xs, **kwargs) + return self._test(*xs, **kwargs) diff --git a/core/models/py_utils/scatter_gather.py b/core/models/py_utils/scatter_gather.py new file mode 100644 index 0000000..9a46058 --- /dev/null +++ b/core/models/py_utils/scatter_gather.py @@ -0,0 +1,38 @@ +import torch +from torch.autograd import Variable +from torch.nn.parallel._functions import Scatter, Gather + + +def scatter(inputs, target_gpus, dim=0, chunk_sizes=None): + r""" + Slices variables into approximately equal chunks and + distributes them across given GPUs. Duplicates + references to objects that are not variables. Does not + support Tensors. + """ + def scatter_map(obj): + if isinstance(obj, Variable): + return Scatter.apply(target_gpus, chunk_sizes, dim, obj) + assert not torch.is_tensor(obj), "Tensors not supported in scatter." + if isinstance(obj, tuple): + return list(zip(*map(scatter_map, obj))) + if isinstance(obj, list): + return list(map(list, zip(*map(scatter_map, obj)))) + if isinstance(obj, dict): + return list(map(type(obj), zip(*map(scatter_map, obj.items())))) + return [obj for targets in target_gpus] + + return scatter_map(inputs) + + +def scatter_kwargs(inputs, kwargs, target_gpus, dim=0, chunk_sizes=None): + r"""Scatter with support for kwargs dictionary""" + inputs = scatter(inputs, target_gpus, dim, chunk_sizes) if inputs else [] + kwargs = scatter(kwargs, target_gpus, dim, chunk_sizes) if kwargs else [] + if len(inputs) < len(kwargs): + inputs.extend([() for _ in range(len(kwargs) - len(inputs))]) + elif len(kwargs) < len(inputs): + kwargs.extend([{} for _ in range(len(inputs) - len(kwargs))]) + inputs = tuple(inputs) + kwargs = tuple(kwargs) + return inputs, kwargs diff --git a/core/models/py_utils/utils.py b/core/models/py_utils/utils.py new file mode 100644 index 0000000..85d3e23 --- /dev/null +++ b/core/models/py_utils/utils.py @@ -0,0 +1,226 @@ +import torch +import torch.nn as nn + +def _gather_feat(feat, ind, mask=None): + dim = feat.size(2) + ind = ind.unsqueeze(2).expand(ind.size(0), ind.size(1), dim) + feat = feat.gather(1, ind) + if mask is not None: + mask = mask.unsqueeze(2).expand_as(feat) + feat = feat[mask] + feat = feat.view(-1, dim) + return feat + +def _nms(heat, kernel=1): + pad = (kernel - 1) // 2 + + hmax = nn.functional.max_pool2d(heat, (kernel, kernel), stride=1, padding=pad) + keep = (hmax == heat).float() + return heat * keep + +def _tranpose_and_gather_feat(feat, ind): + feat = feat.permute(0, 2, 3, 1).contiguous() + feat = feat.view(feat.size(0), -1, feat.size(3)) + feat = _gather_feat(feat, ind) + return feat + +def _topk(scores, K=20): + batch, cat, height, width = scores.size() + + topk_scores, topk_inds = torch.topk(scores.view(batch, -1), K) + + topk_clses = (topk_inds / (height * width)).int() + + topk_inds = topk_inds % (height * width) + topk_ys = (topk_inds / width).int().float() + topk_xs = (topk_inds % width).int().float() + return topk_scores, topk_inds, topk_clses, topk_ys, topk_xs + +def _decode( + tl_heat, br_heat, tl_tag, br_tag, tl_regr, br_regr, + K=100, kernel=1, ae_threshold=1, num_dets=1000, no_border=False +): + batch, cat, height, width = tl_heat.size() + + tl_heat = torch.sigmoid(tl_heat) + br_heat = torch.sigmoid(br_heat) + + # perform nms on heatmaps + tl_heat = _nms(tl_heat, kernel=kernel) + br_heat = _nms(br_heat, kernel=kernel) + + tl_scores, tl_inds, tl_clses, tl_ys, tl_xs = _topk(tl_heat, K=K) + br_scores, br_inds, br_clses, br_ys, br_xs = _topk(br_heat, K=K) + + tl_ys = tl_ys.view(batch, K, 1).expand(batch, K, K) + tl_xs = tl_xs.view(batch, K, 1).expand(batch, K, K) + br_ys = br_ys.view(batch, 1, K).expand(batch, K, K) + br_xs = br_xs.view(batch, 1, K).expand(batch, K, K) + + if no_border: + tl_ys_binds = (tl_ys == 0) + tl_xs_binds = (tl_xs == 0) + br_ys_binds = (br_ys == height - 1) + br_xs_binds = (br_xs == width - 1) + + if tl_regr is not None and br_regr is not None: + tl_regr = _tranpose_and_gather_feat(tl_regr, tl_inds) + tl_regr = tl_regr.view(batch, K, 1, 2) + br_regr = _tranpose_and_gather_feat(br_regr, br_inds) + br_regr = br_regr.view(batch, 1, K, 2) + + tl_xs = tl_xs + tl_regr[..., 0] + tl_ys = tl_ys + tl_regr[..., 1] + br_xs = br_xs + br_regr[..., 0] + br_ys = br_ys + br_regr[..., 1] + + # all possible boxes based on top k corners (ignoring class) + bboxes = torch.stack((tl_xs, tl_ys, br_xs, br_ys), dim=3) + + tl_tag = _tranpose_and_gather_feat(tl_tag, tl_inds) + tl_tag = tl_tag.view(batch, K, 1) + br_tag = _tranpose_and_gather_feat(br_tag, br_inds) + br_tag = br_tag.view(batch, 1, K) + dists = torch.abs(tl_tag - br_tag) + + tl_scores = tl_scores.view(batch, K, 1).expand(batch, K, K) + br_scores = br_scores.view(batch, 1, K).expand(batch, K, K) + scores = (tl_scores + br_scores) / 2 + + # reject boxes based on classes + tl_clses = tl_clses.view(batch, K, 1).expand(batch, K, K) + br_clses = br_clses.view(batch, 1, K).expand(batch, K, K) + cls_inds = (tl_clses != br_clses) + + # reject boxes based on distances + dist_inds = (dists > ae_threshold) + + # reject boxes based on widths and heights + width_inds = (br_xs < tl_xs) + height_inds = (br_ys < tl_ys) + + if no_border: + scores[tl_ys_binds] = -1 + scores[tl_xs_binds] = -1 + scores[br_ys_binds] = -1 + scores[br_xs_binds] = -1 + + scores[cls_inds] = -1 + scores[dist_inds] = -1 + scores[width_inds] = -1 + scores[height_inds] = -1 + + scores = scores.view(batch, -1) + scores, inds = torch.topk(scores, num_dets) + scores = scores.unsqueeze(2) + + bboxes = bboxes.view(batch, -1, 4) + bboxes = _gather_feat(bboxes, inds) + + clses = tl_clses.contiguous().view(batch, -1, 1) + clses = _gather_feat(clses, inds).float() + + tl_scores = tl_scores.contiguous().view(batch, -1, 1) + tl_scores = _gather_feat(tl_scores, inds).float() + br_scores = br_scores.contiguous().view(batch, -1, 1) + br_scores = _gather_feat(br_scores, inds).float() + + detections = torch.cat([bboxes, scores, tl_scores, br_scores, clses], dim=2) + return detections + +class upsample(nn.Module): + def __init__(self, scale_factor): + super(upsample, self).__init__() + self.scale_factor = scale_factor + + def forward(self, x): + return nn.functional.interpolate(x, scale_factor=self.scale_factor) + +class merge(nn.Module): + def forward(self, x, y): + return x + y + +class convolution(nn.Module): + def __init__(self, k, inp_dim, out_dim, stride=1, with_bn=True): + super(convolution, self).__init__() + + pad = (k - 1) // 2 + self.conv = nn.Conv2d(inp_dim, out_dim, (k, k), padding=(pad, pad), stride=(stride, stride), bias=not with_bn) + self.bn = nn.BatchNorm2d(out_dim) if with_bn else nn.Sequential() + self.relu = nn.ReLU(inplace=True) + + def forward(self, x): + conv = self.conv(x) + bn = self.bn(conv) + relu = self.relu(bn) + return relu + +class residual(nn.Module): + def __init__(self, inp_dim, out_dim, k=3, stride=1): + super(residual, self).__init__() + p = (k - 1) // 2 + + self.conv1 = nn.Conv2d(inp_dim, out_dim, (k, k), padding=(p, p), stride=(stride, stride), bias=False) + self.bn1 = nn.BatchNorm2d(out_dim) + self.relu1 = nn.ReLU(inplace=True) + + self.conv2 = nn.Conv2d(out_dim, out_dim, (k, k), padding=(p, p), bias=False) + self.bn2 = nn.BatchNorm2d(out_dim) + + self.skip = nn.Sequential( + nn.Conv2d(inp_dim, out_dim, (1, 1), stride=(stride, stride), bias=False), + nn.BatchNorm2d(out_dim) + ) if stride != 1 or inp_dim != out_dim else nn.Sequential() + self.relu = nn.ReLU(inplace=True) + + def forward(self, x): + conv1 = self.conv1(x) + bn1 = self.bn1(conv1) + relu1 = self.relu1(bn1) + + conv2 = self.conv2(relu1) + bn2 = self.bn2(conv2) + + skip = self.skip(x) + return self.relu(bn2 + skip) + +class corner_pool(nn.Module): + def __init__(self, dim, pool1, pool2): + super(corner_pool, self).__init__() + self._init_layers(dim, pool1, pool2) + + def _init_layers(self, dim, pool1, pool2): + self.p1_conv1 = convolution(3, dim, 128) + self.p2_conv1 = convolution(3, dim, 128) + + self.p_conv1 = nn.Conv2d(128, dim, (3, 3), padding=(1, 1), bias=False) + self.p_bn1 = nn.BatchNorm2d(dim) + + self.conv1 = nn.Conv2d(dim, dim, (1, 1), bias=False) + self.bn1 = nn.BatchNorm2d(dim) + self.relu1 = nn.ReLU(inplace=True) + + self.conv2 = convolution(3, dim, dim) + + self.pool1 = pool1() + self.pool2 = pool2() + + def forward(self, x): + # pool 1 + p1_conv1 = self.p1_conv1(x) + pool1 = self.pool1(p1_conv1) + + # pool 2 + p2_conv1 = self.p2_conv1(x) + pool2 = self.pool2(p2_conv1) + + # pool 1 + pool 2 + p_conv1 = self.p_conv1(pool1 + pool2) + p_bn1 = self.p_bn1(p_conv1) + + conv1 = self.conv1(x) + bn1 = self.bn1(conv1) + relu1 = self.relu1(p_bn1 + bn1) + + conv2 = self.conv2(relu1) + return conv2 diff --git a/core/nnet/__init__.py b/core/nnet/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/core/nnet/py_factory.py b/core/nnet/py_factory.py new file mode 100755 index 0000000..ed867cd --- /dev/null +++ b/core/nnet/py_factory.py @@ -0,0 +1,137 @@ +import os +import torch +import pickle +import importlib +import torch.nn as nn + +from ..models.py_utils.data_parallel import DataParallel + +torch.manual_seed(317) + +class Network(nn.Module): + def __init__(self, model, loss): + super(Network, self).__init__() + + self.model = model + self.loss = loss + + def forward(self, xs, ys, **kwargs): + preds = self.model(*xs, **kwargs) + loss = self.loss(preds, ys, **kwargs) + return loss + +# for model backward compatibility +# previously model was wrapped by DataParallel module +class DummyModule(nn.Module): + def __init__(self, model): + super(DummyModule, self).__init__() + self.module = model + + def forward(self, *xs, **kwargs): + return self.module(*xs, **kwargs) + +class NetworkFactory(object): + def __init__(self, system_config, model, distributed=False, gpu=None): + super(NetworkFactory, self).__init__() + + self.system_config = system_config + + self.gpu = gpu + self.model = DummyModule(model) + self.loss = model.loss + self.network = Network(self.model, self.loss) + + if distributed: + from apex.parallel import DistributedDataParallel, convert_syncbn_model + torch.cuda.set_device(gpu) + self.network = self.network.cuda(gpu) + self.network = convert_syncbn_model(self.network) + self.network = DistributedDataParallel(self.network) + else: + self.network = DataParallel(self.network, chunk_sizes=system_config.chunk_sizes) + + total_params = 0 + for params in self.model.parameters(): + num_params = 1 + for x in params.size(): + num_params *= x + total_params += num_params + print("total parameters: {}".format(total_params)) + + if system_config.opt_algo == "adam": + self.optimizer = torch.optim.Adam( + filter(lambda p: p.requires_grad, self.model.parameters()) + ) + elif system_config.opt_algo == "sgd": + self.optimizer = torch.optim.SGD( + filter(lambda p: p.requires_grad, self.model.parameters()), + lr=system_config.learning_rate, + momentum=0.9, weight_decay=0.0001 + ) + else: + raise ValueError("unknown optimizer") + + def cuda(self): + self.model.cuda() + + def train_mode(self): + self.network.train() + + def eval_mode(self): + self.network.eval() + + def _t_cuda(self, xs): + if type(xs) is list: + return [x.cuda(self.gpu, non_blocking=True) for x in xs] + return xs.cuda(self.gpu, non_blocking=True) + + def train(self, xs, ys, **kwargs): + xs = [self._t_cuda(x) for x in xs] + ys = [self._t_cuda(y) for y in ys] + + self.optimizer.zero_grad() + loss = self.network(xs, ys) + loss = loss.mean() + loss.backward() + self.optimizer.step() + + return loss + + def validate(self, xs, ys, **kwargs): + with torch.no_grad(): + xs = [self._t_cuda(x) for x in xs] + ys = [self._t_cuda(y) for y in ys] + + loss = self.network(xs, ys) + loss = loss.mean() + return loss + + def test(self, xs, **kwargs): + with torch.no_grad(): + xs = [self._t_cuda(x) for x in xs] + return self.model(*xs, **kwargs) + + def set_lr(self, lr): + print("setting learning rate to: {}".format(lr)) + for param_group in self.optimizer.param_groups: + param_group["lr"] = lr + + def load_pretrained_params(self, pretrained_model): + print("loading from {}".format(pretrained_model)) + with open(pretrained_model, "rb") as f: + params = torch.load(f) + self.model.load_state_dict(params) + + def load_params(self, iteration): + cache_file = self.system_config.snapshot_file.format(iteration) + print("loading model from {}".format(cache_file)) + with open(cache_file, "rb") as f: + params = torch.load(f) + self.model.load_state_dict(params) + + def save_params(self, iteration): + cache_file = self.system_config.snapshot_file.format(iteration) + print("saving model to {}".format(cache_file)) + with open(cache_file, "wb") as f: + params = self.model.state_dict() + torch.save(params, f) diff --git a/core/paths.py b/core/paths.py new file mode 100644 index 0000000..b487c3d --- /dev/null +++ b/core/paths.py @@ -0,0 +1,7 @@ +import pkg_resources + +_package_name = __name__ + +def get_file_path(*paths): + path = "/".join(paths) + return pkg_resources.resource_filename(_package_name, path) diff --git a/core/sample/__init__.py b/core/sample/__init__.py new file mode 100644 index 0000000..2241054 --- /dev/null +++ b/core/sample/__init__.py @@ -0,0 +1,5 @@ +from .cornernet import cornernet +from .cornernet_saccade import cornernet_saccade + +def data_sampling_func(sys_configs, db, k_ind, data_aug=True, debug=False): + return globals()[sys_configs.sampling_function](sys_configs, db, k_ind, data_aug, debug) diff --git a/core/sample/cornernet.py b/core/sample/cornernet.py new file mode 100644 index 0000000..a4e0796 --- /dev/null +++ b/core/sample/cornernet.py @@ -0,0 +1,160 @@ +import cv2 +import math +import numpy as np +import torch + +from .utils import random_crop, draw_gaussian, gaussian_radius, normalize_, color_jittering_, lighting_ + +def _resize_image(image, detections, size): + detections = detections.copy() + height, width = image.shape[0:2] + new_height, new_width = size + + image = cv2.resize(image, (new_width, new_height)) + + height_ratio = new_height / height + width_ratio = new_width / width + detections[:, 0:4:2] *= width_ratio + detections[:, 1:4:2] *= height_ratio + return image, detections + +def _clip_detections(image, detections): + detections = detections.copy() + height, width = image.shape[0:2] + + detections[:, 0:4:2] = np.clip(detections[:, 0:4:2], 0, width - 1) + detections[:, 1:4:2] = np.clip(detections[:, 1:4:2], 0, height - 1) + keep_inds = ((detections[:, 2] - detections[:, 0]) > 0) & \ + ((detections[:, 3] - detections[:, 1]) > 0) + detections = detections[keep_inds] + return detections + +def cornernet(system_configs, db, k_ind, data_aug, debug): + data_rng = system_configs.data_rng + batch_size = system_configs.batch_size + + categories = db.configs["categories"] + input_size = db.configs["input_size"] + output_size = db.configs["output_sizes"][0] + + border = db.configs["border"] + lighting = db.configs["lighting"] + rand_crop = db.configs["rand_crop"] + rand_color = db.configs["rand_color"] + rand_scales = db.configs["rand_scales"] + gaussian_bump = db.configs["gaussian_bump"] + gaussian_iou = db.configs["gaussian_iou"] + gaussian_rad = db.configs["gaussian_radius"] + + max_tag_len = 128 + + # allocating memory + images = np.zeros((batch_size, 3, input_size[0], input_size[1]), dtype=np.float32) + tl_heatmaps = np.zeros((batch_size, categories, output_size[0], output_size[1]), dtype=np.float32) + br_heatmaps = np.zeros((batch_size, categories, output_size[0], output_size[1]), dtype=np.float32) + tl_regrs = np.zeros((batch_size, max_tag_len, 2), dtype=np.float32) + br_regrs = np.zeros((batch_size, max_tag_len, 2), dtype=np.float32) + tl_tags = np.zeros((batch_size, max_tag_len), dtype=np.int64) + br_tags = np.zeros((batch_size, max_tag_len), dtype=np.int64) + tag_masks = np.zeros((batch_size, max_tag_len), dtype=np.uint8) + tag_lens = np.zeros((batch_size, ), dtype=np.int32) + + db_size = db.db_inds.size + for b_ind in range(batch_size): + if not debug and k_ind == 0: + db.shuffle_inds() + + db_ind = db.db_inds[k_ind] + k_ind = (k_ind + 1) % db_size + + # reading image + image_path = db.image_path(db_ind) + image = cv2.imread(image_path) + + # reading detections + detections = db.detections(db_ind) + + # cropping an image randomly + if not debug and rand_crop: + image, detections = random_crop(image, detections, rand_scales, input_size, border=border) + + image, detections = _resize_image(image, detections, input_size) + detections = _clip_detections(image, detections) + + width_ratio = output_size[1] / input_size[1] + height_ratio = output_size[0] / input_size[0] + + # flipping an image randomly + if not debug and np.random.uniform() > 0.5: + image[:] = image[:, ::-1, :] + width = image.shape[1] + detections[:, [0, 2]] = width - detections[:, [2, 0]] - 1 + + if not debug: + image = image.astype(np.float32) / 255. + if rand_color: + color_jittering_(data_rng, image) + if lighting: + lighting_(data_rng, image, 0.1, db.eig_val, db.eig_vec) + normalize_(image, db.mean, db.std) + images[b_ind] = image.transpose((2, 0, 1)) + + for ind, detection in enumerate(detections): + category = int(detection[-1]) - 1 + + xtl, ytl = detection[0], detection[1] + xbr, ybr = detection[2], detection[3] + + fxtl = (xtl * width_ratio) + fytl = (ytl * height_ratio) + fxbr = (xbr * width_ratio) + fybr = (ybr * height_ratio) + + xtl = int(fxtl) + ytl = int(fytl) + xbr = int(fxbr) + ybr = int(fybr) + + if gaussian_bump: + width = detection[2] - detection[0] + height = detection[3] - detection[1] + + width = math.ceil(width * width_ratio) + height = math.ceil(height * height_ratio) + + if gaussian_rad == -1: + radius = gaussian_radius((height, width), gaussian_iou) + radius = max(0, int(radius)) + else: + radius = gaussian_rad + + draw_gaussian(tl_heatmaps[b_ind, category], [xtl, ytl], radius) + draw_gaussian(br_heatmaps[b_ind, category], [xbr, ybr], radius) + else: + tl_heatmaps[b_ind, category, ytl, xtl] = 1 + br_heatmaps[b_ind, category, ybr, xbr] = 1 + + tag_ind = tag_lens[b_ind] + tl_regrs[b_ind, tag_ind, :] = [fxtl - xtl, fytl - ytl] + br_regrs[b_ind, tag_ind, :] = [fxbr - xbr, fybr - ybr] + tl_tags[b_ind, tag_ind] = ytl * output_size[1] + xtl + br_tags[b_ind, tag_ind] = ybr * output_size[1] + xbr + tag_lens[b_ind] += 1 + + for b_ind in range(batch_size): + tag_len = tag_lens[b_ind] + tag_masks[b_ind, :tag_len] = 1 + + images = torch.from_numpy(images) + tl_heatmaps = torch.from_numpy(tl_heatmaps) + br_heatmaps = torch.from_numpy(br_heatmaps) + tl_regrs = torch.from_numpy(tl_regrs) + br_regrs = torch.from_numpy(br_regrs) + tl_tags = torch.from_numpy(tl_tags) + br_tags = torch.from_numpy(br_tags) + tag_masks = torch.from_numpy(tag_masks) + + return { + "xs": [images], + "ys": [tl_heatmaps, br_heatmaps, tag_masks, tl_regrs, br_regrs, tl_tags, br_tags] + }, k_ind diff --git a/core/sample/cornernet_saccade.py b/core/sample/cornernet_saccade.py new file mode 100644 index 0000000..14e368b --- /dev/null +++ b/core/sample/cornernet_saccade.py @@ -0,0 +1,285 @@ +import cv2 +import math +import torch +import numpy as np + +from .utils import draw_gaussian, gaussian_radius, normalize_, color_jittering_, lighting_, crop_image + +def bbox_overlaps(a_dets, b_dets): + a_widths = a_dets[:, 2] - a_dets[:, 0] + a_heights = a_dets[:, 3] - a_dets[:, 1] + a_areas = a_widths * a_heights + + b_widths = b_dets[:, 2] - b_dets[:, 0] + b_heights = b_dets[:, 3] - b_dets[:, 1] + b_areas = b_widths * b_heights + + return a_areas / b_areas + +def clip_detections(border, detections): + detections = detections.copy() + + y0, y1, x0, x1 = border + det_xs = detections[:, 0:4:2] + det_ys = detections[:, 1:4:2] + np.clip(det_xs, x0, x1 - 1, out=det_xs) + np.clip(det_ys, y0, y1 - 1, out=det_ys) + + keep_inds = ((det_xs[:, 1] - det_xs[:, 0]) > 0) & \ + ((det_ys[:, 1] - det_ys[:, 0]) > 0) + keep_inds = np.where(keep_inds)[0] + return detections[keep_inds], keep_inds + +def crop_image_dets(image, dets, ind, input_size, output_size=None, random_crop=True, rand_center=True): + if ind is not None: + det_x0, det_y0, det_x1, det_y1 = dets[ind, 0:4] + else: + det_x0, det_y0, det_x1, det_y1 = None, None, None, None + + input_height, input_width = input_size + image_height, image_width = image.shape[0:2] + + centered = rand_center and np.random.uniform() > 0.5 + if not random_crop or image_width <= input_width: + xc = image_width // 2 + elif ind is None or not centered: + xmin = max(det_x1 - input_width, 0) if ind is not None else 0 + xmax = min(image_width - input_width, det_x0) if ind is not None else image_width - input_width + xrand = np.random.randint(int(xmin), int(xmax) + 1) + xc = xrand + input_width // 2 + else: + xmin = max((det_x0 + det_x1) // 2 - np.random.randint(0, 15), 0) + xmax = min((det_x0 + det_x1) // 2 + np.random.randint(0, 15), image_width - 1) + xc = np.random.randint(int(xmin), int(xmax) + 1) + + if not random_crop or image_height <= input_height: + yc = image_height // 2 + elif ind is None or not centered: + ymin = max(det_y1 - input_height, 0) if ind is not None else 0 + ymax = min(image_height - input_height, det_y0) if ind is not None else image_height - input_height + yrand = np.random.randint(int(ymin), int(ymax) + 1) + yc = yrand + input_height // 2 + else: + ymin = max((det_y0 + det_y1) // 2 - np.random.randint(0, 15), 0) + ymax = min((det_y0 + det_y1) // 2 + np.random.randint(0, 15), image_height - 1) + yc = np.random.randint(int(ymin), int(ymax) + 1) + + image, border, offset = crop_image(image, [yc, xc], input_size, output_size=output_size) + dets[:, 0:4:2] -= offset[1] + dets[:, 1:4:2] -= offset[0] + return image, dets, border + +def scale_image_detections(image, dets, scale): + height, width = image.shape[0:2] + + new_height = int(height * scale) + new_width = int(width * scale) + + image = cv2.resize(image, (new_width, new_height)) + dets = dets.copy() + dets[:, 0:4] *= scale + return image, dets + +def ref_scale(detections, random_crop=False): + if detections.shape[0] == 0: + return None, None + + if random_crop and np.random.uniform() > 0.7: + return None, None + + ref_ind = np.random.randint(detections.shape[0]) + ref_det = detections[ref_ind].copy() + ref_h = ref_det[3] - ref_det[1] + ref_w = ref_det[2] - ref_det[0] + ref_hw = max(ref_h, ref_w) + + if ref_hw > 96: + return np.random.randint(low=96, high=255) / ref_hw, ref_ind + elif ref_hw > 32: + return np.random.randint(low=32, high=97) / ref_hw, ref_ind + return np.random.randint(low=16, high=33) / ref_hw, ref_ind + +def create_attention_mask(atts, ratios, sizes, detections): + for det in detections: + width = det[2] - det[0] + height = det[3] - det[1] + + max_hw = max(width, height) + for att, ratio, size in zip(atts, ratios, sizes): + if max_hw >= size[0] and max_hw <= size[1]: + x = (det[0] + det[2]) / 2 + y = (det[1] + det[3]) / 2 + x = (x / ratio).astype(np.int32) + y = (y / ratio).astype(np.int32) + att[y, x] = 1 + +def cornernet_saccade(system_configs, db, k_ind, data_aug, debug): + data_rng = system_configs.data_rng + batch_size = system_configs.batch_size + + categories = db.configs["categories"] + input_size = db.configs["input_size"] + output_size = db.configs["output_sizes"][0] + rand_scales = db.configs["rand_scales"] + rand_crop = db.configs["rand_crop"] + rand_center = db.configs["rand_center"] + view_sizes = db.configs["view_sizes"] + + gaussian_iou = db.configs["gaussian_iou"] + gaussian_rad = db.configs["gaussian_radius"] + + att_ratios = db.configs["att_ratios"] + att_ranges = db.configs["att_ranges"] + att_sizes = db.configs["att_sizes"] + + min_scale = db.configs["min_scale"] + max_scale = db.configs["max_scale"] + max_objects = 128 + + images = np.zeros((batch_size, 3, input_size[0], input_size[1]), dtype=np.float32) + tl_heats = np.zeros((batch_size, categories, output_size[0], output_size[1]), dtype=np.float32) + br_heats = np.zeros((batch_size, categories, output_size[0], output_size[1]), dtype=np.float32) + tl_valids = np.zeros((batch_size, categories, output_size[0], output_size[1]), dtype=np.float32) + br_valids = np.zeros((batch_size, categories, output_size[0], output_size[1]), dtype=np.float32) + tl_regrs = np.zeros((batch_size, max_objects, 2), dtype=np.float32) + br_regrs = np.zeros((batch_size, max_objects, 2), dtype=np.float32) + tl_tags = np.zeros((batch_size, max_objects), dtype=np.int64) + br_tags = np.zeros((batch_size, max_objects), dtype=np.int64) + tag_masks = np.zeros((batch_size, max_objects), dtype=np.uint8) + tag_lens = np.zeros((batch_size, ), dtype=np.int32) + attentions = [np.zeros((batch_size, 1, att_size[0], att_size[1]), dtype=np.float32) for att_size in att_sizes] + + db_size = db.db_inds.size + for b_ind in range(batch_size): + if not debug and k_ind == 0: + # if k_ind == 0: + db.shuffle_inds() + + db_ind = db.db_inds[k_ind] + k_ind = (k_ind + 1) % db_size + + image_path = db.image_path(db_ind) + image = cv2.imread(image_path) + + orig_detections = db.detections(db_ind) + keep_inds = np.arange(orig_detections.shape[0]) + + # clip the detections + detections = orig_detections.copy() + border = [0, image.shape[0], 0, image.shape[1]] + detections, clip_inds = clip_detections(border, detections) + keep_inds = keep_inds[clip_inds] + + scale, ref_ind = ref_scale(detections, random_crop=rand_crop) + scale = np.random.choice(rand_scales) if scale is None else scale + + orig_detections[:, 0:4:2] *= scale + orig_detections[:, 1:4:2] *= scale + + image, detections = scale_image_detections(image, detections, scale) + ref_detection = detections[ref_ind].copy() + + image, detections, border = crop_image_dets(image, detections, ref_ind, input_size, rand_center=rand_center) + + detections, clip_inds = clip_detections(border, detections) + keep_inds = keep_inds[clip_inds] + + width_ratio = output_size[1] / input_size[1] + height_ratio = output_size[0] / input_size[0] + + # flipping an image randomly + if not debug and np.random.uniform() > 0.5: + image[:] = image[:, ::-1, :] + width = image.shape[1] + detections[:, [0, 2]] = width - detections[:, [2, 0]] - 1 + create_attention_mask([att[b_ind, 0] for att in attentions], att_ratios, att_ranges, detections) + + if debug: + dimage = image.copy() + for det in detections.astype(np.int32): + cv2.rectangle(dimage, + (det[0], det[1]), + (det[2], det[3]), + (0, 255, 0), 2 + ) + cv2.imwrite('debug/{:03d}.jpg'.format(b_ind), dimage) + overlaps = bbox_overlaps(detections, orig_detections[keep_inds]) > 0.5 + + if not debug: + image = image.astype(np.float32) / 255. + color_jittering_(data_rng, image) + lighting_(data_rng, image, 0.1, db.eig_val, db.eig_vec) + normalize_(image, db.mean, db.std) + images[b_ind] = image.transpose((2, 0, 1)) + + for ind, (detection, overlap) in enumerate(zip(detections, overlaps)): + category = int(detection[-1]) - 1 + + xtl, ytl = detection[0], detection[1] + xbr, ybr = detection[2], detection[3] + + det_height = int(ybr) - int(ytl) + det_width = int(xbr) - int(xtl) + det_max = max(det_height, det_width) + + valid = det_max >= min_scale + + fxtl = (xtl * width_ratio) + fytl = (ytl * height_ratio) + fxbr = (xbr * width_ratio) + fybr = (ybr * height_ratio) + + xtl = int(fxtl) + ytl = int(fytl) + xbr = int(fxbr) + ybr = int(fybr) + + width = detection[2] - detection[0] + height = detection[3] - detection[1] + + width = math.ceil(width * width_ratio) + height = math.ceil(height * height_ratio) + + if gaussian_rad == -1: + radius = gaussian_radius((height, width), gaussian_iou) + radius = max(0, int(radius)) + else: + radius = gaussian_rad + + if overlap and valid: + draw_gaussian(tl_heats[b_ind, category], [xtl, ytl], radius) + draw_gaussian(br_heats[b_ind, category], [xbr, ybr], radius) + + tag_ind = tag_lens[b_ind] + tl_regrs[b_ind, tag_ind, :] = [fxtl - xtl, fytl - ytl] + br_regrs[b_ind, tag_ind, :] = [fxbr - xbr, fybr - ybr] + tl_tags[b_ind, tag_ind] = ytl * output_size[1] + xtl + br_tags[b_ind, tag_ind] = ybr * output_size[1] + xbr + tag_lens[b_ind] += 1 + else: + draw_gaussian(tl_valids[b_ind, category], [xtl, ytl], radius) + draw_gaussian(br_valids[b_ind, category], [xbr, ybr], radius) + + tl_valids = (tl_valids == 0).astype(np.float32) + br_valids = (br_valids == 0).astype(np.float32) + + for b_ind in range(batch_size): + tag_len = tag_lens[b_ind] + tag_masks[b_ind, :tag_len] = 1 + + images = torch.from_numpy(images) + tl_heats = torch.from_numpy(tl_heats) + br_heats = torch.from_numpy(br_heats) + tl_regrs = torch.from_numpy(tl_regrs) + br_regrs = torch.from_numpy(br_regrs) + tl_tags = torch.from_numpy(tl_tags) + br_tags = torch.from_numpy(br_tags) + tag_masks = torch.from_numpy(tag_masks) + tl_valids = torch.from_numpy(tl_valids) + br_valids = torch.from_numpy(br_valids) + attentions = [torch.from_numpy(att) for att in attentions] + + return { + "xs": [images], + "ys": [tl_heats, br_heats, tag_masks, tl_regrs, br_regrs, tl_tags, br_tags, tl_valids, br_valids, attentions] + }, k_ind diff --git a/core/sample/utils.py b/core/sample/utils.py new file mode 100644 index 0000000..fd8f437 --- /dev/null +++ b/core/sample/utils.py @@ -0,0 +1,163 @@ +import cv2 +import numpy as np +import random + +def grayscale(image): + return cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) + +def normalize_(image, mean, std): + image -= mean + image /= std + +def lighting_(data_rng, image, alphastd, eigval, eigvec): + alpha = data_rng.normal(scale=alphastd, size=(3, )) + image += np.dot(eigvec, eigval * alpha) + +def blend_(alpha, image1, image2): + image1 *= alpha + image2 *= (1 - alpha) + image1 += image2 + +def saturation_(data_rng, image, gs, gs_mean, var): + alpha = 1. + data_rng.uniform(low=-var, high=var) + blend_(alpha, image, gs[:, :, None]) + +def brightness_(data_rng, image, gs, gs_mean, var): + alpha = 1. + data_rng.uniform(low=-var, high=var) + image *= alpha + +def contrast_(data_rng, image, gs, gs_mean, var): + alpha = 1. + data_rng.uniform(low=-var, high=var) + blend_(alpha, image, gs_mean) + +def color_jittering_(data_rng, image): + functions = [brightness_, contrast_, saturation_] + random.shuffle(functions) + + gs = grayscale(image) + gs_mean = gs.mean() + for f in functions: + f(data_rng, image, gs, gs_mean, 0.4) + +def gaussian2D(shape, sigma=1): + m, n = [(ss - 1.) / 2. for ss in shape] + y, x = np.ogrid[-m:m+1,-n:n+1] + + h = np.exp(-(x * x + y * y) / (2 * sigma * sigma)) + h[h < np.finfo(h.dtype).eps * h.max()] = 0 + return h + +def draw_gaussian(heatmap, center, radius, k=1): + diameter = 2 * radius + 1 + gaussian = gaussian2D((diameter, diameter), sigma=diameter / 6) + + x, y = center + + height, width = heatmap.shape[0:2] + + left, right = min(x, radius), min(width - x, radius + 1) + top, bottom = min(y, radius), min(height - y, radius + 1) + + masked_heatmap = heatmap[y - top:y + bottom, x - left:x + right] + masked_gaussian = gaussian[radius - top:radius + bottom, radius - left:radius + right] + np.maximum(masked_heatmap, masked_gaussian * k, out=masked_heatmap) + +def gaussian_radius(det_size, min_overlap): + height, width = det_size + + a1 = 1 + b1 = (height + width) + c1 = width * height * (1 - min_overlap) / (1 + min_overlap) + sq1 = np.sqrt(b1 ** 2 - 4 * a1 * c1) + r1 = (b1 - sq1) / (2 * a1) + + a2 = 4 + b2 = 2 * (height + width) + c2 = (1 - min_overlap) * width * height + sq2 = np.sqrt(b2 ** 2 - 4 * a2 * c2) + r2 = (b2 - sq2) / (2 * a2) + + a3 = 4 * min_overlap + b3 = -2 * min_overlap * (height + width) + c3 = (min_overlap - 1) * width * height + sq3 = np.sqrt(b3 ** 2 - 4 * a3 * c3) + r3 = (b3 + sq3) / (2 * a3) + return min(r1, r2, r3) + +def _get_border(border, size): + i = 1 + while size - border // i <= border // i: + i *= 2 + return border // i + +def random_crop(image, detections, random_scales, view_size, border=64): + view_height, view_width = view_size + image_height, image_width = image.shape[0:2] + + scale = np.random.choice(random_scales) + height = int(view_height * scale) + width = int(view_width * scale) + + cropped_image = np.zeros((height, width, 3), dtype=image.dtype) + + w_border = _get_border(border, image_width) + h_border = _get_border(border, image_height) + + ctx = np.random.randint(low=w_border, high=image_width - w_border) + cty = np.random.randint(low=h_border, high=image_height - h_border) + + x0, x1 = max(ctx - width // 2, 0), min(ctx + width // 2, image_width) + y0, y1 = max(cty - height // 2, 0), min(cty + height // 2, image_height) + + left_w, right_w = ctx - x0, x1 - ctx + top_h, bottom_h = cty - y0, y1 - cty + + # crop image + cropped_ctx, cropped_cty = width // 2, height // 2 + x_slice = slice(cropped_ctx - left_w, cropped_ctx + right_w) + y_slice = slice(cropped_cty - top_h, cropped_cty + bottom_h) + cropped_image[y_slice, x_slice, :] = image[y0:y1, x0:x1, :] + + # crop detections + cropped_detections = detections.copy() + cropped_detections[:, 0:4:2] -= x0 + cropped_detections[:, 1:4:2] -= y0 + cropped_detections[:, 0:4:2] += cropped_ctx - left_w + cropped_detections[:, 1:4:2] += cropped_cty - top_h + + return cropped_image, cropped_detections + +def crop_image(image, center, size, output_size=None): + if output_size == None: + output_size = size + + cty, ctx = center + height, width = size + o_height, o_width = output_size + im_height, im_width = image.shape[0:2] + cropped_image = np.zeros((o_height, o_width, 3), dtype=image.dtype) + + x0, x1 = max(0, ctx - width // 2), min(ctx + width // 2, im_width) + y0, y1 = max(0, cty - height // 2), min(cty + height // 2, im_height) + + left, right = ctx - x0, x1 - ctx + top, bottom = cty - y0, y1 - cty + + cropped_cty, cropped_ctx = o_height // 2, o_width // 2 + y_slice = slice(cropped_cty - top, cropped_cty + bottom) + x_slice = slice(cropped_ctx - left, cropped_ctx + right) + cropped_image[y_slice, x_slice, :] = image[y0:y1, x0:x1, :] + + border = np.array([ + cropped_cty - top, + cropped_cty + bottom, + cropped_ctx - left, + cropped_ctx + right + ], dtype=np.float32) + + offset = np.array([ + cty - o_height // 2, + ctx - o_width // 2 + ]) + + return cropped_image, border, offset diff --git a/core/test/__init__.py b/core/test/__init__.py new file mode 100644 index 0000000..080cc8f --- /dev/null +++ b/core/test/__init__.py @@ -0,0 +1,5 @@ +from .cornernet import cornernet +from .cornernet_saccade import cornernet_saccade + +def test_func(sys_config, db, nnet, result_dir, debug=False): + return globals()[sys_config.sampling_function](db, nnet, result_dir, debug=debug) diff --git a/core/test/cornernet.py b/core/test/cornernet.py new file mode 100644 index 0000000..e20f014 --- /dev/null +++ b/core/test/cornernet.py @@ -0,0 +1,176 @@ +import os +import cv2 +import json +import numpy as np +import torch + +from tqdm import tqdm + +from ..utils import Timer +from ..vis_utils import draw_bboxes +from ..sample.utils import crop_image +from ..external.nms import soft_nms, soft_nms_merge + +def rescale_dets_(detections, ratios, borders, sizes): + xs, ys = detections[..., 0:4:2], detections[..., 1:4:2] + xs /= ratios[:, 1][:, None, None] + ys /= ratios[:, 0][:, None, None] + xs -= borders[:, 2][:, None, None] + ys -= borders[:, 0][:, None, None] + np.clip(xs, 0, sizes[:, 1][:, None, None], out=xs) + np.clip(ys, 0, sizes[:, 0][:, None, None], out=ys) + +def decode(nnet, images, K, ae_threshold=0.5, kernel=3, num_dets=1000): + detections = nnet.test([images], ae_threshold=ae_threshold, test=True, K=K, kernel=kernel, num_dets=num_dets)[0] + return detections.data.cpu().numpy() + +def cornernet(db, nnet, result_dir, debug=False, decode_func=decode): + debug_dir = os.path.join(result_dir, "debug") + if not os.path.exists(debug_dir): + os.makedirs(debug_dir) + + if db.split != "trainval2014": + db_inds = db.db_inds[:100] if debug else db.db_inds + else: + db_inds = db.db_inds[:100] if debug else db.db_inds[:5000] + + num_images = db_inds.size + categories = db.configs["categories"] + + timer = Timer() + top_bboxes = {} + for ind in tqdm(range(0, num_images), ncols=80, desc="locating kps"): + db_ind = db_inds[ind] + + image_id = db.image_ids(db_ind) + image_path = db.image_path(db_ind) + image = cv2.imread(image_path) + + timer.tic() + top_bboxes[image_id] = cornernet_inference(db, nnet, image) + timer.toc() + + if debug: + image_path = db.image_path(db_ind) + image = cv2.imread(image_path) + bboxes = { + db.cls2name(j): top_bboxes[image_id][j] + for j in range(1, categories + 1) + } + image = draw_bboxes(image, bboxes) + debug_file = os.path.join(debug_dir, "{}.jpg".format(db_ind)) + cv2.imwrite(debug_file, image) + print('average time: {}'.format(timer.average_time)) + + result_json = os.path.join(result_dir, "results.json") + detections = db.convert_to_coco(top_bboxes) + with open(result_json, "w") as f: + json.dump(detections, f) + + cls_ids = list(range(1, categories + 1)) + image_ids = [db.image_ids(ind) for ind in db_inds] + db.evaluate(result_json, cls_ids, image_ids) + return 0 + +def cornernet_inference(db, nnet, image, decode_func=decode): + K = db.configs["top_k"] + ae_threshold = db.configs["ae_threshold"] + nms_kernel = db.configs["nms_kernel"] + num_dets = db.configs["num_dets"] + test_flipped = db.configs["test_flipped"] + + input_size = db.configs["input_size"] + output_size = db.configs["output_sizes"][0] + + scales = db.configs["test_scales"] + weight_exp = db.configs["weight_exp"] + merge_bbox = db.configs["merge_bbox"] + categories = db.configs["categories"] + nms_threshold = db.configs["nms_threshold"] + max_per_image = db.configs["max_per_image"] + nms_algorithm = { + "nms": 0, + "linear_soft_nms": 1, + "exp_soft_nms": 2 + }[db.configs["nms_algorithm"]] + + height, width = image.shape[0:2] + + height_scale = (input_size[0] + 1) // output_size[0] + width_scale = (input_size[1] + 1) // output_size[1] + + im_mean = torch.cuda.FloatTensor(db.mean).reshape(1, 3, 1, 1) + im_std = torch.cuda.FloatTensor(db.std).reshape(1, 3, 1, 1) + + detections = [] + for scale in scales: + new_height = int(height * scale) + new_width = int(width * scale) + new_center = np.array([new_height // 2, new_width // 2]) + + inp_height = new_height | 127 + inp_width = new_width | 127 + + images = np.zeros((1, 3, inp_height, inp_width), dtype=np.float32) + ratios = np.zeros((1, 2), dtype=np.float32) + borders = np.zeros((1, 4), dtype=np.float32) + sizes = np.zeros((1, 2), dtype=np.float32) + + out_height, out_width = (inp_height + 1) // height_scale, (inp_width + 1) // width_scale + height_ratio = out_height / inp_height + width_ratio = out_width / inp_width + + resized_image = cv2.resize(image, (new_width, new_height)) + resized_image, border, offset = crop_image(resized_image, new_center, [inp_height, inp_width]) + + resized_image = resized_image / 255. + + images[0] = resized_image.transpose((2, 0, 1)) + borders[0] = border + sizes[0] = [int(height * scale), int(width * scale)] + ratios[0] = [height_ratio, width_ratio] + + if test_flipped: + images = np.concatenate((images, images[:, :, :, ::-1]), axis=0) + images = torch.from_numpy(images).cuda() + images -= im_mean + images /= im_std + + dets = decode_func(nnet, images, K, ae_threshold=ae_threshold, kernel=nms_kernel, num_dets=num_dets) + if test_flipped: + dets[1, :, [0, 2]] = out_width - dets[1, :, [2, 0]] + dets = dets.reshape(1, -1, 8) + + rescale_dets_(dets, ratios, borders, sizes) + dets[:, :, 0:4] /= scale + detections.append(dets) + + detections = np.concatenate(detections, axis=1) + + classes = detections[..., -1] + classes = classes[0] + detections = detections[0] + + # reject detections with negative scores + keep_inds = (detections[:, 4] > -1) + detections = detections[keep_inds] + classes = classes[keep_inds] + + top_bboxes = {} + for j in range(categories): + keep_inds = (classes == j) + top_bboxes[j + 1] = detections[keep_inds][:, 0:7].astype(np.float32) + if merge_bbox: + soft_nms_merge(top_bboxes[j + 1], Nt=nms_threshold, method=nms_algorithm, weight_exp=weight_exp) + else: + soft_nms(top_bboxes[j + 1], Nt=nms_threshold, method=nms_algorithm) + top_bboxes[j + 1] = top_bboxes[j + 1][:, 0:5] + + scores = np.hstack([top_bboxes[j][:, -1] for j in range(1, categories + 1)]) + if len(scores) > max_per_image: + kth = len(scores) - max_per_image + thresh = np.partition(scores, kth)[kth] + for j in range(1, categories + 1): + keep_inds = (top_bboxes[j][:, -1] >= thresh) + top_bboxes[j] = top_bboxes[j][keep_inds] + return top_bboxes diff --git a/core/test/cornernet_saccade.py b/core/test/cornernet_saccade.py new file mode 100644 index 0000000..eb0e6bc --- /dev/null +++ b/core/test/cornernet_saccade.py @@ -0,0 +1,394 @@ +import os +import cv2 +import math +import json +import torch +import torch.nn as nn +import numpy as np + +from tqdm import tqdm + +from ..utils import Timer +from ..vis_utils import draw_bboxes +from ..external.nms import soft_nms + +def crop_image_gpu(image, center, size, out_image): + cty, ctx = center + height, width = size + o_height, o_width = out_image.shape[1:3] + im_height, im_width = image.shape[1:3] + + scale = o_height / max(height, width) + x0, x1 = max(0, ctx - width // 2), min(ctx + width // 2, im_width) + y0, y1 = max(0, cty - height // 2), min(cty + height // 2, im_height) + + left, right = ctx - x0, x1 - ctx + top, bottom = cty - y0, y1 - cty + + cropped_cty, cropped_ctx = o_height // 2, o_width // 2 + out_y0, out_y1 = cropped_cty - int(top * scale), cropped_cty + int(bottom * scale) + out_x0, out_x1 = cropped_ctx - int(left * scale), cropped_ctx + int(right * scale) + + new_height = out_y1 - out_y0 + new_width = out_x1 - out_x0 + image = image[:, y0:y1, x0:x1].unsqueeze(0) + out_image[:, out_y0:out_y1, out_x0:out_x1] = nn.functional.interpolate( + image, size=[new_height, new_width], mode='bilinear' + )[0] + + return np.array([cty - height // 2, ctx - width // 2]) + +def remap_dets_(detections, scales, offsets): + xs, ys = detections[..., 0:4:2], detections[..., 1:4:2] + + xs /= scales.reshape(-1, 1, 1) + ys /= scales.reshape(-1, 1, 1) + xs += offsets[:, 1][:, None, None] + ys += offsets[:, 0][:, None, None] + +def att_nms(atts, ks): + pads = [(k - 1) // 2 for k in ks] + pools = [nn.functional.max_pool2d(att, (k, k), stride=1, padding=pad) for k, att, pad in zip(ks, atts, pads)] + keeps = [(att == pool).float() for att, pool in zip(atts, pools)] + atts = [att * keep for att, keep in zip(atts, keeps)] + return atts + +def batch_decode(db, nnet, images, no_att=False): + K = db.configs["top_k"] + ae_threshold = db.configs["ae_threshold"] + kernel = db.configs["nms_kernel"] + num_dets = db.configs["num_dets"] + + att_nms_ks = db.configs["att_nms_ks"] + att_ranges = db.configs["att_ranges"] + + num_images = images.shape[0] + detections = [] + attentions = [[] for _ in range(len(att_ranges))] + + batch_size = 32 + for b_ind in range(math.ceil(num_images / batch_size)): + b_start = b_ind * batch_size + b_end = min(num_images, (b_ind + 1) * batch_size) + + b_images = images[b_start:b_end] + b_outputs = nnet.test( + [b_images], ae_threshold=ae_threshold, K=K, kernel=kernel, + test=True, num_dets=num_dets, no_border=True, no_att=no_att + ) + if no_att: + b_detections = b_outputs + else: + b_detections = b_outputs[0] + b_attentions = b_outputs[1] + b_attentions = att_nms(b_attentions, att_nms_ks) + b_attentions = [b_attention.data.cpu().numpy() for b_attention in b_attentions] + + b_detections = b_detections.data.cpu().numpy() + + detections.append(b_detections) + if not no_att: + for attention, b_attention in zip(attentions, b_attentions): + attention.append(b_attention) + + if not no_att: + attentions = [np.concatenate(atts, axis=0) for atts in attentions] if detections else None + detections = np.concatenate(detections, axis=0) if detections else np.zeros((0, num_dets, 8)) + return detections, attentions + +def decode_atts(db, atts, att_scales, scales, offsets, height, width, thresh, ignore_same=False): + att_ranges = db.configs["att_ranges"] + att_ratios = db.configs["att_ratios"] + input_size = db.configs["input_size"] + + next_ys, next_xs, next_scales, next_scores = [], [], [], [] + + num_atts = atts[0].shape[0] + for aind in range(num_atts): + for att, att_range, att_ratio, att_scale in zip(atts, att_ranges, att_ratios, att_scales): + ys, xs = np.where(att[aind, 0] > thresh) + scores = att[aind, 0, ys, xs] + + ys = ys * att_ratio / scales[aind] + offsets[aind, 0] + xs = xs * att_ratio / scales[aind] + offsets[aind, 1] + + keep = (ys >= 0) & (ys < height) & (xs >= 0) & (xs < width) + ys, xs, scores = ys[keep], xs[keep], scores[keep] + + next_scale = att_scale * scales[aind] + if (ignore_same and att_scale <= 1) or scales[aind] > 2 or next_scale > 4: + continue + + next_scales += [next_scale] * len(xs) + next_scores += scores.tolist() + next_ys += ys.tolist() + next_xs += xs.tolist() + next_ys = np.array(next_ys) + next_xs = np.array(next_xs) + next_scales = np.array(next_scales) + next_scores = np.array(next_scores) + return np.stack((next_ys, next_xs, next_scales, next_scores), axis=1) + +def get_ref_locs(dets): + keep = dets[:, 4] > 0.5 + dets = dets[keep] + + ref_xs = (dets[:, 0] + dets[:, 2]) / 2 + ref_ys = (dets[:, 1] + dets[:, 3]) / 2 + + ref_maxhws = np.maximum(dets[:, 2] - dets[:, 0], dets[:, 3] - dets[:, 1]) + ref_scales = np.zeros_like(ref_maxhws) + ref_scores = dets[:, 4] + + large_inds = ref_maxhws > 96 + medium_inds = (ref_maxhws > 32) & (ref_maxhws <= 96) + small_inds = ref_maxhws <= 32 + + ref_scales[large_inds] = 192 / ref_maxhws[large_inds] + ref_scales[medium_inds] = 64 / ref_maxhws[medium_inds] + ref_scales[small_inds] = 24 / ref_maxhws[small_inds] + + new_locations = np.stack((ref_ys, ref_xs, ref_scales, ref_scores), axis=1) + new_locations[:, 3] = 1 + return new_locations + +def get_locs(db, nnet, image, im_mean, im_std, att_scales, thresh, sizes, ref_dets=True): + att_ranges = db.configs["att_ranges"] + att_ratios = db.configs["att_ratios"] + input_size = db.configs["input_size"] + + height, width = image.shape[1:3] + + locations = [] + for size in sizes: + scale = size / max(height, width) + location = [height // 2, width // 2, scale] + locations.append(location) + + locations = np.array(locations, dtype=np.float32) + images, offsets = prepare_images(db, image, locations, flipped=False) + + images -= im_mean + images /= im_std + + dets, atts = batch_decode(db, nnet, images) + + scales = locations[:, 2] + next_locations = decode_atts(db, atts, att_scales, scales, offsets, height, width, thresh) + + rescale_dets_(db, dets) + remap_dets_(dets, scales, offsets) + + dets = dets.reshape(-1, 8) + keep = dets[:, 4] > 0.3 + dets = dets[keep] + + if ref_dets: + ref_locations = get_ref_locs(dets) + next_locations = np.concatenate((next_locations, ref_locations), axis=0) + next_locations = location_nms(next_locations, thresh=16) + return dets, next_locations, atts + +def location_nms(locations, thresh=15): + next_locations = [] + sorted_inds = np.argsort(locations[:, -1])[::-1] + + locations = locations[sorted_inds] + ys = locations[:, 0] + xs = locations[:, 1] + scales = locations[:, 2] + + dist_ys = np.absolute(ys.reshape(-1, 1) - ys.reshape(1, -1)) + dist_xs = np.absolute(xs.reshape(-1, 1) - xs.reshape(1, -1)) + dists = np.minimum(dist_ys, dist_xs) + ratios = scales.reshape(-1, 1) / scales.reshape(1, -1) + while dists.shape[0] > 0: + next_locations.append(locations[0]) + + scale = scales[0] + dist = dists[0] + ratio = ratios[0] + + keep = (dist > (thresh / scale)) | (ratio > 1.2) | (ratio < 0.8) + + locations = locations[keep] + + scales = scales[keep] + dists = dists[keep, :] + dists = dists[:, keep] + ratios = ratios[keep, :] + ratios = ratios[:, keep] + return np.stack(next_locations) if next_locations else np.zeros((0, 4)) + +def prepare_images(db, image, locs, flipped=True): + input_size = db.configs["input_size"] + num_patches = locs.shape[0] + + images = torch.cuda.FloatTensor(num_patches, 3, input_size[0], input_size[1]).fill_(0) + offsets = np.zeros((num_patches, 2), dtype=np.float32) + for ind, (y, x, scale) in enumerate(locs[:, :3]): + crop_height = int(input_size[0] / scale) + crop_width = int(input_size[1] / scale) + offsets[ind] = crop_image_gpu(image, [int(y), int(x)], [crop_height, crop_width], images[ind]) + return images, offsets + +def rescale_dets_(db, dets): + input_size = db.configs["input_size"] + output_size = db.configs["output_sizes"][0] + + ratios = [o / i for o, i in zip(output_size, input_size)] + dets[..., 0:4:2] /= ratios[1] + dets[..., 1:4:2] /= ratios[0] + +def cornernet_saccade(db, nnet, result_dir, debug=False, decode_func=batch_decode): + debug_dir = os.path.join(result_dir, "debug") + if not os.path.exists(debug_dir): + os.makedirs(debug_dir) + + if db.split != "trainval2014": + db_inds = db.db_inds[:500] if debug else db.db_inds + else: + db_inds = db.db_inds[:100] if debug else db.db_inds[:5000] + + num_images = db_inds.size + categories = db.configs["categories"] + + timer = Timer() + top_bboxes = {} + for k_ind in tqdm(range(0, num_images), ncols=80, desc="locating kps"): + db_ind = db_inds[k_ind] + + image_id = db.image_ids(db_ind) + image_path = db.image_path(db_ind) + image = cv2.imread(image_path) + + timer.tic() + top_bboxes[image_id] = cornernet_saccade_inference(db, nnet, image) + timer.toc() + + if debug: + image_path = db.image_path(db_ind) + image = cv2.imread(image_path) + bboxes = { + db.cls2name(j): top_bboxes[image_id][j] + for j in range(1, categories + 1) + } + image = draw_bboxes(image, bboxes) + debug_file = os.path.join(debug_dir, "{}.jpg".format(db_ind)) + cv2.imwrite(debug_file, image) + print('average time: {}'.format(timer.average_time)) + + result_json = os.path.join(result_dir, "results.json") + detections = db.convert_to_coco(top_bboxes) + with open(result_json, "w") as f: + json.dump(detections, f) + + cls_ids = list(range(1, categories + 1)) + image_ids = [db.image_ids(ind) for ind in db_inds] + db.evaluate(result_json, cls_ids, image_ids) + return 0 + +def cornernet_saccade_inference(db, nnet, image, decode_func=batch_decode): + init_sizes = db.configs["init_sizes"] + ref_dets = db.configs["ref_dets"] + + att_thresholds = db.configs["att_thresholds"] + att_scales = db.configs["att_scales"] + att_max_crops = db.configs["att_max_crops"] + + categories = db.configs["categories"] + nms_threshold = db.configs["nms_threshold"] + max_per_image = db.configs["max_per_image"] + nms_algorithm = { + "nms": 0, + "linear_soft_nms": 1, + "exp_soft_nms": 2 + }[db.configs["nms_algorithm"]] + + num_iterations = len(att_thresholds) + + im_mean = torch.cuda.FloatTensor(db.mean).reshape(1, 3, 1, 1) + im_std = torch.cuda.FloatTensor(db.std).reshape(1, 3, 1, 1) + + detections = [] + height, width = image.shape[0:2] + + image = image / 255. + image = image.transpose((2, 0, 1)).copy() + image = torch.from_numpy(image).cuda(non_blocking=True) + + dets, locations, atts = get_locs( + db, nnet, image, im_mean, im_std, + att_scales[0], att_thresholds[0], + init_sizes, ref_dets=ref_dets + ) + + detections = [dets] + num_patches = locations.shape[0] + + num_crops = 0 + for ind in range(1, num_iterations + 1): + if num_patches == 0: + break + + if num_crops + num_patches > att_max_crops: + max_crops = min(att_max_crops - num_crops, num_patches) + locations = locations[:max_crops] + + num_patches = locations.shape[0] + num_crops += locations.shape[0] + no_att = (ind == num_iterations) + + images, offsets = prepare_images(db, image, locations, flipped=False) + images -= im_mean + images /= im_std + + dets, atts = decode_func(db, nnet, images, no_att=no_att) + dets = dets.reshape(num_patches, -1, 8) + + rescale_dets_(db, dets) + remap_dets_(dets, locations[:, 2], offsets) + + dets = dets.reshape(-1, 8) + keeps = (dets[:, 4] > -1) + dets = dets[keeps] + + detections.append(dets) + + if num_crops == att_max_crops: + break + + if ind < num_iterations: + att_threshold = att_thresholds[ind] + att_scale = att_scales[ind] + + next_locations = decode_atts( + db, atts, att_scale, locations[:, 2], offsets, height, width, att_threshold, ignore_same=True + ) + + if ref_dets: + ref_locations = get_ref_locs(dets) + next_locations = np.concatenate((next_locations, ref_locations), axis=0) + next_locations = location_nms(next_locations, thresh=16) + + locations = next_locations + num_patches = locations.shape[0] + + detections = np.concatenate(detections, axis=0) + classes = detections[..., -1] + + top_bboxes = {} + for j in range(categories): + keep_inds = (classes == j) + top_bboxes[j + 1] = detections[keep_inds][:, 0:7].astype(np.float32) + keep_inds = soft_nms(top_bboxes[j + 1], Nt=nms_threshold, method=nms_algorithm, sigma=0.7) + top_bboxes[j + 1] = top_bboxes[j + 1][keep_inds, 0:5] + + scores = np.hstack([top_bboxes[j][:, -1] for j in range(1, categories + 1)]) + if len(scores) > max_per_image: + kth = len(scores) - max_per_image + thresh = np.partition(scores, kth)[kth] + for j in range(1, categories + 1): + keep_inds = (top_bboxes[j][:, -1] >= thresh) + top_bboxes[j] = top_bboxes[j][keep_inds] + return top_bboxes diff --git a/core/utils/__init__.py b/core/utils/__init__.py new file mode 100644 index 0000000..9f60522 --- /dev/null +++ b/core/utils/__init__.py @@ -0,0 +1,2 @@ +from .tqdm import stdout_to_tqdm +from .timer import Timer diff --git a/core/utils/timer.py b/core/utils/timer.py new file mode 100644 index 0000000..80c29de --- /dev/null +++ b/core/utils/timer.py @@ -0,0 +1,25 @@ +import time + +class Timer(object): + """A simple timer.""" + def __init__(self): + self.total_time = 0. + self.calls = 0 + self.start_time = 0. + self.diff = 0. + self.average_time = 0. + + def tic(self): + # using time.time instead of time.clock because time time.clock + # does not normalize for multithreading + self.start_time = time.time() + + def toc(self, average=True): + self.diff = time.time() - self.start_time + self.total_time += self.diff + self.calls += 1 + self.average_time = self.total_time / self.calls + if average: + return self.average_time + else: + return self.diff diff --git a/core/utils/tqdm.py b/core/utils/tqdm.py new file mode 100755 index 0000000..334dfc1 --- /dev/null +++ b/core/utils/tqdm.py @@ -0,0 +1,25 @@ +import sys +import numpy as np +import contextlib + +from tqdm import tqdm + +class TqdmFile(object): + dummy_file = None + def __init__(self, dummy_file): + self.dummy_file = dummy_file + + def write(self, x): + if len(x.rstrip()) > 0: + tqdm.write(x, file=self.dummy_file) + +@contextlib.contextmanager +def stdout_to_tqdm(): + save_stdout = sys.stdout + try: + sys.stdout = TqdmFile(sys.stdout) + yield save_stdout + except Exception as exc: + raise exc + finally: + sys.stdout = save_stdout diff --git a/core/vis_utils.py b/core/vis_utils.py new file mode 100644 index 0000000..9cbe169 --- /dev/null +++ b/core/vis_utils.py @@ -0,0 +1,62 @@ +import cv2 +import numpy as np + +def draw_bboxes(image, bboxes, font_size=0.5, thresh=0.5, colors=None): + """Draws bounding boxes on an image. + + Args: + image: An image in OpenCV format + bboxes: A dictionary representing bounding boxes of different object + categories, where the keys are the names of the categories and the + values are the bounding boxes. The bounding boxes of category should be + stored in a 2D NumPy array, where each row is a bounding box (x1, y1, + x2, y2, score). + font_size: (Optional) Font size of the category names. + thresh: (Optional) Only bounding boxes with scores above the threshold + will be drawn. + colors: (Optional) Color of bounding boxes for each category. If it is + not provided, this function will use random color for each category. + + Returns: + An image with bounding boxes. + """ + + image = image.copy() + for cat_name in bboxes: + keep_inds = bboxes[cat_name][:, -1] > thresh + cat_size = cv2.getTextSize(cat_name, cv2.FONT_HERSHEY_SIMPLEX, font_size, 2)[0] + + if colors is None: + color = np.random.random((3, )) * 0.6 + 0.4 + color = (color * 255).astype(np.int32).tolist() + else: + color = colors[cat_name] + + for bbox in bboxes[cat_name][keep_inds]: + bbox = bbox[0:4].astype(np.int32) + if bbox[1] - cat_size[1] - 2 < 0: + cv2.rectangle(image, + (bbox[0], bbox[1] + 2), + (bbox[0] + cat_size[0], bbox[1] + cat_size[1] + 2), + color, -1 + ) + cv2.putText(image, cat_name, + (bbox[0], bbox[1] + cat_size[1] + 2), + cv2.FONT_HERSHEY_SIMPLEX, font_size, (0, 0, 0), thickness=1 + ) + else: + cv2.rectangle(image, + (bbox[0], bbox[1] - cat_size[1] - 2), + (bbox[0] + cat_size[0], bbox[1] - 2), + color, -1 + ) + cv2.putText(image, cat_name, + (bbox[0], bbox[1] - 2), + cv2.FONT_HERSHEY_SIMPLEX, font_size, (0, 0, 0), thickness=1 + ) + cv2.rectangle(image, + (bbox[0], bbox[1]), + (bbox[2], bbox[3]), + color, 2 + ) + return image diff --git a/demo.jpg b/demo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fbf2b610cea019c2609d7f2e0bdb2797fbfe340f GIT binary patch literal 323088 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ᆼ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ⅆfE z?^|ZQ(m$f!rSuaW)Lm<+IUL5vCe4DWO9O3R9j`s;*3{V>C{0)_#S}(GDcq{d?ZomF zPh9U2*_QEmzVZ8H002lg6Q@pK(u^~C)&0_Ph$2Ddpgnfj)b~#MeX?}xqSJ`>~=VPdk-k$9Tf<_;--mDO#I= zQkaqrhQ2A-o`N@~_;s!oB$VhZNHTA2W1!x$u>C;Mu-#MGx^acqckNTHc6NNezmAMe zBuR(NU$GWO!J0AHwr*BhRUxrqj}?+WBT0S217X76a|{Z}@PrdO*boNfd`3o-tq7p3 zft83NWbOc)M=3XvepQ#yY(D4Lezfa7RNnJjMEOX%l-4ZYuSzP>6~saR01r|&RPU0U zLd{qz3dghGp2U_N1WUl^#sn?2B&9j`JKhhGw4P!jvfIimj_~M{t?qZ{eT|?ED6+mE zTFT9^<7Bs|*gj z=Tpyna;WhvB_tH6lK}FNMW%Gq+Je5Qy8Whfhg-4q+p1NYSBl;;3b1o#w9>tMBu^Db znjZ8Di71v?gsk#SW@Fsm+-K46@Rt@6@iP}PIepHw!KV~r&_}d=#Q=3yms)yf(I|Ai zQs&{QYuU|iwlWMRv4%D)XE!=m5-h}4Zh5iU?91ODU})r?GZQM53|H_pvU9xZvffT^ zU*Z8e048cK7NWQ1R+%Zcgn?~2o_FdgAM_xWAL}>nEX_e_c9DYG=Xa zqAN99QTtbL*P}hN(z_SRPZNTqd@${GEUcuz#NpZ#kk98z={!G+tt1qgPv^A`bsMK~ z<)^V%EdorTyVtmL_>vDF`2+s|KC4)k6q0(^Vc|SUrEdr?I;)|!Doxie*_moQMWMSmvmyJNy~n=A ykg|Z!EBma@%;(DwR^A-?F-u$RJD*XTL#5(2C(zdv!@Apx2nJLDgY~!XdjHuN;{I9y literal 0 HcmV?d00001 diff --git a/demo.py b/demo.py new file mode 100755 index 0000000..3fcdaf7 --- /dev/null +++ b/demo.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python + +import cv2 +from core.detectors import CornerNet_Saccade +from core.vis_utils import draw_bboxes + +detector = CornerNet_Saccade() +image = cv2.imread("demo.jpg") + +bboxes = detector(image) +image = draw_bboxes(image, bboxes) +cv2.imwrite("demo_out.jpg", image) diff --git a/evaluate.py b/evaluate.py new file mode 100755 index 0000000..fd276d4 --- /dev/null +++ b/evaluate.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +import os +import json +import torch +import pprint +import argparse +import importlib + +from core.dbs import datasets +from core.test import test_func +from core.config import SystemConfig +from core.nnet.py_factory import NetworkFactory + +torch.backends.cudnn.benchmark = False + +def parse_args(): + parser = argparse.ArgumentParser(description="Evaluation Script") + parser.add_argument("cfg_file", help="config file", type=str) + parser.add_argument("--testiter", dest="testiter", + help="test at iteration i", + default=None, type=int) + parser.add_argument("--split", dest="split", + help="which split to use", + default="validation", type=str) + parser.add_argument("--suffix", dest="suffix", default=None, type=str) + parser.add_argument("--debug", action="store_true") + + args = parser.parse_args() + return args + +def make_dirs(directories): + for directory in directories: + if not os.path.exists(directory): + os.makedirs(directory) + +def test(db, system_config, model, args): + split = args.split + testiter = args.testiter + debug = args.debug + suffix = args.suffix + + result_dir = system_config.result_dir + result_dir = os.path.join(result_dir, str(testiter), split) + + if suffix is not None: + result_dir = os.path.join(result_dir, suffix) + + make_dirs([result_dir]) + + test_iter = system_config.max_iter if testiter is None else testiter + print("loading parameters at iteration: {}".format(test_iter)) + + print("building neural network...") + nnet = NetworkFactory(system_config, model) + print("loading parameters...") + nnet.load_params(test_iter) + + nnet.cuda() + nnet.eval_mode() + test_func(system_config, db, nnet, result_dir, debug=debug) + +def main(args): + if args.suffix is None: + cfg_file = os.path.join("./configs", args.cfg_file + ".json") + else: + cfg_file = os.path.join("./configs", args.cfg_file + "-{}.json".format(args.suffix)) + print("cfg_file: {}".format(cfg_file)) + + with open(cfg_file, "r") as f: + config = json.load(f) + + config["system"]["snapshot_name"] = args.cfg_file + system_config = SystemConfig().update_config(config["system"]) + + model_file = "core.models.{}".format(args.cfg_file) + model_file = importlib.import_module(model_file) + model = model_file.model() + + train_split = system_config.train_split + val_split = system_config.val_split + test_split = system_config.test_split + + split = { + "training": train_split, + "validation": val_split, + "testing": test_split + }[args.split] + + print("loading all datasets...") + dataset = system_config.dataset + print("split: {}".format(split)) + testing_db = datasets[dataset](config["db"], split=split, sys_config=system_config) + + print("system config...") + pprint.pprint(system_config.full) + + print("db config...") + pprint.pprint(testing_db.configs) + + test(testing_db, system_config, model, args) + +if __name__ == "__main__": + args = parse_args() + main(args) diff --git a/train.py b/train.py new file mode 100755 index 0000000..88ad348 --- /dev/null +++ b/train.py @@ -0,0 +1,249 @@ +#!/usr/bin/env python +import os +import json +import torch +import numpy as np +import queue +import pprint +import random +import argparse +import importlib +import threading +import traceback +import torch.distributed as dist +import torch.multiprocessing as mp + +from tqdm import tqdm +from torch.multiprocessing import Process, Queue, Pool + +from core.dbs import datasets +from core.utils import stdout_to_tqdm +from core.config import SystemConfig +from core.sample import data_sampling_func +from core.nnet.py_factory import NetworkFactory + +torch.backends.cudnn.enabled = True +torch.backends.cudnn.benchmark = True + +def parse_args(): + parser = argparse.ArgumentParser(description="Training Script") + parser.add_argument("cfg_file", help="config file", type=str) + parser.add_argument("--iter", dest="start_iter", + help="train at iteration i", + default=0, type=int) + parser.add_argument("--workers", default=4, type=int) + parser.add_argument("--initialize", action="store_true") + + parser.add_argument("--distributed", action="store_true") + parser.add_argument("--world-size", default=-1, type=int, + help="number of nodes of distributed training") + parser.add_argument("--rank", default=0, type=int, + help="node rank for distributed training") + parser.add_argument("--dist-url", default=None, type=str, + help="url used to set up distributed training") + parser.add_argument("--dist-backend", default="nccl", type=str) + + args = parser.parse_args() + return args + +def prefetch_data(system_config, db, queue, sample_data, data_aug): + ind = 0 + print("start prefetching data...") + np.random.seed(os.getpid()) + while True: + try: + data, ind = sample_data(system_config, db, ind, data_aug=data_aug) + queue.put(data) + except Exception as e: + traceback.print_exc() + raise e + +def _pin_memory(ts): + if type(ts) is list: + return [t.pin_memory() for t in ts] + return ts.pin_memory() + +def pin_memory(data_queue, pinned_data_queue, sema): + while True: + data = data_queue.get() + + data["xs"] = [_pin_memory(x) for x in data["xs"]] + data["ys"] = [_pin_memory(y) for y in data["ys"]] + + pinned_data_queue.put(data) + + if sema.acquire(blocking=False): + return + +def init_parallel_jobs(system_config, dbs, queue, fn, data_aug): + tasks = [Process(target=prefetch_data, args=(system_config, db, queue, fn, data_aug)) for db in dbs] + for task in tasks: + task.daemon = True + task.start() + return tasks + +def terminate_tasks(tasks): + for task in tasks: + task.terminate() + +def train(training_dbs, validation_db, system_config, model, args): + # reading arguments from command + start_iter = args.start_iter + distributed = args.distributed + world_size = args.world_size + initialize = args.initialize + gpu = args.gpu + rank = args.rank + + # reading arguments from json file + batch_size = system_config.batch_size + learning_rate = system_config.learning_rate + max_iteration = system_config.max_iter + pretrained_model = system_config.pretrain + stepsize = system_config.stepsize + snapshot = system_config.snapshot + val_iter = system_config.val_iter + display = system_config.display + decay_rate = system_config.decay_rate + stepsize = system_config.stepsize + + print("Process {}: building model...".format(rank)) + nnet = NetworkFactory(system_config, model, distributed=distributed, gpu=gpu) + if initialize: + nnet.save_params(0) + exit(0) + + # queues storing data for training + training_queue = Queue(system_config.prefetch_size) + validation_queue = Queue(5) + + # queues storing pinned data for training + pinned_training_queue = queue.Queue(system_config.prefetch_size) + pinned_validation_queue = queue.Queue(5) + + # allocating resources for parallel reading + training_tasks = init_parallel_jobs(system_config, training_dbs, training_queue, data_sampling_func, True) + if val_iter: + validation_tasks = init_parallel_jobs(system_config, [validation_db], validation_queue, data_sampling_func, False) + + training_pin_semaphore = threading.Semaphore() + validation_pin_semaphore = threading.Semaphore() + training_pin_semaphore.acquire() + validation_pin_semaphore.acquire() + + training_pin_args = (training_queue, pinned_training_queue, training_pin_semaphore) + training_pin_thread = threading.Thread(target=pin_memory, args=training_pin_args) + training_pin_thread.daemon = True + training_pin_thread.start() + + validation_pin_args = (validation_queue, pinned_validation_queue, validation_pin_semaphore) + validation_pin_thread = threading.Thread(target=pin_memory, args=validation_pin_args) + validation_pin_thread.daemon = True + validation_pin_thread.start() + + if pretrained_model is not None: + if not os.path.exists(pretrained_model): + raise ValueError("pretrained model does not exist") + print("Process {}: loading from pretrained model".format(rank)) + nnet.load_pretrained_params(pretrained_model) + + if start_iter: + nnet.load_params(start_iter) + learning_rate /= (decay_rate ** (start_iter // stepsize)) + nnet.set_lr(learning_rate) + print("Process {}: training starts from iteration {} with learning_rate {}".format(rank, start_iter + 1, learning_rate)) + else: + nnet.set_lr(learning_rate) + + if rank == 0: + print("training start...") + nnet.cuda() + nnet.train_mode() + with stdout_to_tqdm() as save_stdout: + for iteration in tqdm(range(start_iter + 1, max_iteration + 1), file=save_stdout, ncols=80): + training = pinned_training_queue.get(block=True) + training_loss = nnet.train(**training) + + if display and iteration % display == 0: + print("Process {}: training loss at iteration {}: {}".format(rank, iteration, training_loss.item())) + del training_loss + + if val_iter and validation_db.db_inds.size and iteration % val_iter == 0: + nnet.eval_mode() + validation = pinned_validation_queue.get(block=True) + validation_loss = nnet.validate(**validation) + print("Process {}: validation loss at iteration {}: {}".format(rank, iteration, validation_loss.item())) + nnet.train_mode() + + if iteration % snapshot == 0 and rank == 0: + nnet.save_params(iteration) + + if iteration % stepsize == 0: + learning_rate /= decay_rate + nnet.set_lr(learning_rate) + + # sending signal to kill the thread + training_pin_semaphore.release() + validation_pin_semaphore.release() + + # terminating data fetching processes + terminate_tasks(training_tasks) + terminate_tasks(validation_tasks) + +def main(gpu, ngpus_per_node, args): + args.gpu = gpu + if args.distributed: + args.rank = args.rank * ngpus_per_node + gpu + dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, + world_size=args.world_size, rank=args.rank) + + rank = args.rank + + cfg_file = os.path.join("./configs", args.cfg_file + ".json") + with open(cfg_file, "r") as f: + config = json.load(f) + + config["system"]["snapshot_name"] = args.cfg_file + system_config = SystemConfig().update_config(config["system"]) + + model_file = "core.models.{}".format(args.cfg_file) + model_file = importlib.import_module(model_file) + model = model_file.model() + + train_split = system_config.train_split + val_split = system_config.val_split + + print("Process {}: loading all datasets...".format(rank)) + dataset = system_config.dataset + workers = args.workers + print("Process {}: using {} workers".format(rank, workers)) + training_dbs = [datasets[dataset](config["db"], split=train_split, sys_config=system_config) for _ in range(workers)] + validation_db = datasets[dataset](config["db"], split=val_split, sys_config=system_config) + + if rank == 0: + print("system config...") + pprint.pprint(system_config.full) + + print("db config...") + pprint.pprint(training_dbs[0].configs) + + print("len of db: {}".format(len(training_dbs[0].db_inds))) + print("distributed: {}".format(args.distributed)) + + train(training_dbs, validation_db, system_config, model, args) + +if __name__ == "__main__": + args = parse_args() + + distributed = args.distributed + world_size = args.world_size + + if distributed and world_size < 0: + raise ValueError("world size must be greater than 0 in distributed training") + + ngpus_per_node = torch.cuda.device_count() + if distributed: + args.world_size = ngpus_per_node * args.world_size + mp.spawn(main, nprocs=ngpus_per_node, args=(ngpus_per_node, args)) + else: + main(None, ngpus_per_node, args)