Unverified Commit 5d1cbe77 authored by Wenwei Zhang's avatar Wenwei Zhang Committed by GitHub
Browse files

Refine docs and license (#11)

* Refine docs and license

* Change order of install

* Clean unnecessary requirements

* Install mmdet manually in readthedocs

* delete mmdet install

* reformat docstring in code

* Refine docs

* Reformat

* fix format issue
parent 2527c580
......@@ -4,6 +4,5 @@ python:
version: 3.7
install:
- requirements: requirements/docs.txt
- requirements: requirements/build.txt
- requirements: requirements/runtime.txt
- requirements: requirements/readthedocs.txt
Copyright 2018-2019 Open-MMLab. All rights reserved.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018-2019 Open-MMLab.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
......@@ -19,6 +19,16 @@ evaluation
.. automodule:: mmdet3d.core.evaluation
:members:
visualizer
^^^^^^^^^^^^^^^
.. automodule:: mmdet3d.core.visualizer
:members:
voxel
^^^^^^^^^^^^^^^
.. automodule:: mmdet3d.core.voxel
:members:
post_processing
^^^^^^^^^^^^^^^
.. automodule:: mmdet3d.core.post_processing
......@@ -27,16 +37,9 @@ post_processing
mmdet3d.datasets
----------------
datasets
^^^^^^^^^^
.. automodule:: mmdet3d.datasets
:members:
pipelines
^^^^^^^^^^
.. automodule:: mmdet3d.datasets.pipelines
:members:
mmdet3d.models
--------------
......
......@@ -6,7 +6,7 @@ You may also pass `--options xxx.yyy=zzz` to see updated config.
## Config File Structure
There are 4 basic component types under `config/_base_`, dataset, model, schedule, default_runtime.
Many methods could be easily constructed with one of each like SECOND, PointPillars, PartA2 and VoteNet.
Many methods could be easily constructed with one of each like SECOND, PointPillars, PartA2, and VoteNet.
The configs that are composed by components from `_base_` are called _primitive_.
For all configs under the same folder, it is recommended to have only **one** _primitive_ config. All other configs should inherit from the _primitive_ config. In this way, the maximum of inheritance level is 3.
......
......@@ -252,8 +252,8 @@ By default we evaluate the model on the validation set after each epoch, you can
evaluation = dict(interval=12) # This evaluate the model per 12 epoch.
```
**\*Important\***: The default learning rate in config files is for 8 GPUs and the exact batch size is marked by the config's file name, e.g. '2x8' means 2 samples per GPU using 8 GPUs.
According to the [Linear Scaling Rule](https://arxiv.org/abs/1706.02677), you need to set the learning rate proportional to the batch size if you use different GPUs or images per GPU, e.g., lr=0.01 for 4 GPUs * 2 img/gpu and lr=0.08 for 16 GPUs * 4 img/gpu.
**Important**: The default learning rate in config files is for 8 GPUs and the exact batch size is marked by the config's file name, e.g. '2x8' means 2 samples per GPU using 8 GPUs.
According to the [Linear Scaling Rule](https://arxiv.org/abs/1706.02677), you need to set the learning rate proportional to the batch size if you use different GPUs or images per GPU, e.g., lr=0.01 for 4 GPUs * 2 img/gpu and lr=0.08 for 16 GPUs * 4 img/gpu. However, since most of the models in this repo use ADAM rather than SGD for optimization, the rule may not hold and users need to tune the learning rate by themselves.
### Train with a single GPU
......@@ -314,7 +314,14 @@ CUDA_VISIBLE_DEVICES=4,5,6,7 PORT=29501 ./tools/dist_train.sh ${CONFIG_FILE} 4
If you use launch training jobs with Slurm, there are two ways to specify the ports.
1. Modify the config files (usually the 6th line from the bottom in config files) to set different communication ports.
1. Set the port through `--options`. This is more recommended since it does not change the original configs.
```shell
CUDA_VISIBLE_DEVICES=0,1,2,3 GPUS=4 ./tools/slurm_train.sh ${PARTITION} ${JOB_NAME} config1.py ${WORK_DIR} --options 'dist_params.port=29500'
CUDA_VISIBLE_DEVICES=4,5,6,7 GPUS=4 ./tools/slurm_train.sh ${PARTITION} ${JOB_NAME} config2.py ${WORK_DIR} --options 'dist_params.port=29501'
```
2. Modify the config files (usually the 6th line from the bottom in config files) to set different communication ports.
In `config1.py`,
......@@ -335,13 +342,6 @@ If you use launch training jobs with Slurm, there are two ways to specify the po
CUDA_VISIBLE_DEVICES=4,5,6,7 GPUS=4 ./tools/slurm_train.sh ${PARTITION} ${JOB_NAME} config2.py ${WORK_DIR}
```
2. Set the port through `--options`. This is more recommended since it does not change the original configs.
```shell
CUDA_VISIBLE_DEVICES=0,1,2,3 GPUS=4 ./tools/slurm_train.sh ${PARTITION} ${JOB_NAME} config1.py ${WORK_DIR} --options 'dist_params.port=29500'
CUDA_VISIBLE_DEVICES=4,5,6,7 GPUS=4 ./tools/slurm_train.sh ${PARTITION} ${JOB_NAME} config2.py ${WORK_DIR} --options 'dist_params.port=29501'
```
## Useful tools
We provide lots of useful tools under `tools/` directory.
......
......@@ -45,18 +45,31 @@ conda install pytorch=1.3.1 cudatoolkit=9.2 torchvision=0.4.2 -c pytorch
If you build PyTorch from source instead of installing the prebuilt pacakge,
you can use more CUDA versions such as 9.0.
c. Clone the mmdetection repository.
c. Install [MMCV](https://mmcv.readthedocs.io/en/latest/).
*mmcv-full* is necessary since MMDetection3D relies on MMDetection, CUDA ops in *mmcv-full* are required.
The pre-build *mmcv-full* could be installed by running: (available versions could be found [here](https://mmcv.readthedocs.io/en/latest/#install-with-pip))
```shell
git clone https://github.com/open-mmlab/mmdetection.git
cd mmdetection
pip install mmcv-full==latest+torch1.5.0+cu101 -f https://openmmlab.oss-accelerate.aliyuncs.com/mmcv/dist/index.html
```
Optionally, you could also build the full version from source:
```shell
pip install mmcv-full
```
d. Install [MMDetection](https://github.com/open-mmlab/mmdetection).
```shell
pip install git+https://github.com/open-mmlab/mmdetection.git
```
d. Install build requirements and then install mmdetection.
(We install our forked version of pycocotools via the github repo instead of pypi
for better compatibility with our repo.)
Optionally, you could also build MMDetection from source in case you want to modify the code:
```shell
git clone https://github.com/open-mmlab/mmdetection.git
cd mmdetection
pip install -r requirements/build.txt
pip install cython # cython is necessary for pycocotools
pip install "git+https://github.com/open-mmlab/cocoapi.git#subdirectory=pycocotools"
......@@ -69,17 +82,16 @@ If you build mmdetection on macOS, replace the last command with
CC=clang CXX=clang++ CFLAGS='-stdlib=libc++' pip install -e .
```
e. Clone the mmdetection3d repository.
e. Clone the MMDetection3D repository.
```shell
git clone https://github.com/open-mmlab/mmdetection3d.git
cd mmdetection3d
```
f.Install build requirements and then install mmdetection3d.
f.Install build requirements and then install MMDetection3D.
```shell
pip install -r requirements/build.txt
pip install -v -e . # or "python setup.py develop"
```
......@@ -116,17 +128,16 @@ conda activate open-mmlab
# install latest pytorch prebuilt with the default prebuilt CUDA version (usually the latest)
conda install -c pytorch pytorch torchvision -y
# install mmcv
pip install mmcv-full
# install mmdetection
git clone https://github.com/open-mmlab/mmdetection.git
cd mmdetection
pip install -r requirements/build.txt
pip install cython
pip install "git+https://github.com/open-mmlab/cocoapi.git#subdirectory=pycocotools"
pip install -v -e .
cd ..
# install mmdetection3d
git clone https://github.com/open-mmlab/mmdetection3d.git
cd mmdetection3d
pip install -r requirements/build.txt
pip install -v -e .
```
......
......@@ -107,8 +107,7 @@ class Anchor3DRangeGenerator(object):
def single_level_grid_anchors(self, featmap_size, scale, device='cuda'):
"""Generate grid anchors of a single level feature map.
Note:
This function is usually called by method ``self.grid_anchors``.
This function is usually called by method ``self.grid_anchors``.
Args:
featmap_size (tuple[int]): Size of the feature map.
......@@ -215,19 +214,20 @@ class AlignedAnchor3DRangeGenerator(Anchor3DRangeGenerator):
"""Aligned 3D Anchor Generator by range.
This anchor generator uses a different manner to generate the positions
of anchors' centers from `Anchor3DRangeGenerator`.
of anchors' centers from :class:`Anchor3DRangeGenerator`.
Note:
The `align` means that the anchor's center is aligned with the voxel grid,
which is also the feature grid. The previous implementation of
`Anchor3DRangeGenerator` does not generate the anchors' center according
to the voxel grid. Rather, it generates the center by uniformly
distributing the anchors inside the minimum and maximum anchor ranges
according to the feature map sizes.
However, this makes the anchors center does not match the feature grid.
The AlignedAnchor3DRangeGenerator add + 1 when using the feature map sizes
to obtain the corners of the voxel grid. Then it shifts the coordinates to
the center of voxel grid and use the left up corner to distribute anchors.
The `align` means that the anchor's center is aligned with the voxel
grid, which is also the feature grid. The previous implementation of
:class:`Anchor3DRangeGenerator` does not generate the anchors' center
according to the voxel grid. Rather, it generates the center by
uniformly distributing the anchors inside the minimum and maximum
anchor ranges according to the feature map sizes.
However, this makes the anchors center does not match the feature grid.
The :class:`AlignedAnchor3DRangeGenerator` add + 1 when using the
feature map sizes to obtain the corners of the voxel grid. Then it
shifts the coordinates to the center of voxel grid and use the left
up corner to distribute anchors.
Args:
anchor_corner (bool): Whether to align with the corner of the voxel
......
......@@ -24,6 +24,13 @@ class BaseInstance3DBoxes(object):
origin (tuple[float]): The relative position of origin in the box.
Default to (0.5, 0.5, 0). This will guide the box be converted to
(0.5, 0.5, 0) mode.
Attributes:
tensor (torch.Tensor): Float matrix of N x box_dim.
box_dim (int): Integer indicating the dimension of a box.
Each row is (x, y, z, x_size, y_size, z_size, yaw, ...).
with_yaw (bool): If True, the value of yaw will be set to 0 as minmax
boxes.
"""
def __init__(self, tensor, box_dim=7, with_yaw=True, origin=(0.5, 0.5, 0)):
......@@ -59,58 +66,32 @@ class BaseInstance3DBoxes(object):
@property
def volume(self):
"""Compute the volume of all the boxes.
Returns:
torch.Tensor: A vector with volume of each box.
"""
"""torch.Tensor: A vector with volume of each box."""
return self.tensor[:, 3] * self.tensor[:, 4] * self.tensor[:, 5]
@property
def dims(self):
"""Calculate the length in each dimension of all the boxes.
Convert the boxes to the form of (x_size, y_size, z_size).
Returns:
torch.Tensor: Corners of each box with size (N, 8, 3).
"""
"""torch.Tensor: Corners of each box with size (N, 8, 3)."""
return self.tensor[:, 3:6]
@property
def yaw(self):
"""Obtain the rotations of all the boxes.
Returns:
torch.Tensor: A vector with yaw of each box.
"""
"""torch.Tensor: A vector with yaw of each box."""
return self.tensor[:, 6]
@property
def height(self):
"""Obtain the height of all the boxes.
Returns:
torch.Tensor: A vector with height of each box.
"""
"""torch.Tensor: A vector with height of each box."""
return self.tensor[:, 5]
@property
def top_height(self):
"""Obtain the top height of all the boxes.
Returns:
torch.Tensor: A vector with the top height of each box.
"""
"""torch.Tensor: A vector with the top height of each box."""
return self.bottom_height + self.height
@property
def bottom_height(self):
"""Obtain the bottom's height of all the boxes.
Returns:
torch.Tensor: A vector with bottom's height of each box.
"""
"""torch.Tensor: A vector with bottom's height of each box."""
return self.tensor[:, 2]
@property
......@@ -124,7 +105,7 @@ class BaseInstance3DBoxes(object):
The relative position of the centers in different kinds of
boxes are different, e.g., the relative center of a boxes is
(0.5, 1.0, 0.5) in camera and (0.5, 0.5, 0) in lidar.
It is recommended to use `bottom_center` or `gravity_center`
It is recommended to use ``bottom_center`` or ``gravity_center``
for more clear usage.
Returns:
......@@ -134,29 +115,17 @@ class BaseInstance3DBoxes(object):
@property
def bottom_center(self):
"""Calculate the bottom center of all the boxes.
Returns:
torch.Tensor: A tensor with center of each box.
"""
"""torch.Tensor: A tensor with center of each box."""
return self.tensor[:, :3]
@property
def gravity_center(self):
"""Calculate the gravity center of all the boxes.
Returns:
torch.Tensor: A tensor with center of each box.
"""
"""torch.Tensor: A tensor with center of each box."""
pass
@property
def corners(self):
"""Calculate the coordinates of corners of all the boxes.
Returns:
torch.Tensor: a tensor with 8 corners of each box.
"""
"""torch.Tensor: a tensor with 8 corners of each box."""
pass
@abstractmethod
......@@ -224,7 +193,7 @@ class BaseInstance3DBoxes(object):
@abstractmethod
def convert_to(self, dst, rt_mat=None):
"""Convert self to `dst` mode.
"""Convert self to ``dst`` mode.
Args:
dst (:obj:`BoxMode`): The target Box mode.
......@@ -235,8 +204,8 @@ class BaseInstance3DBoxes(object):
to LiDAR. This requires a transformation matrix.
Returns:
A new object of :class:`BaseInstance3DBoxes` after indexing: \
The converted box of the same type in the `dst` mode.
:obj:`BaseInstance3DBoxes`: The converted box of the same type \
in the `dst` mode.
"""
pass
......@@ -294,7 +263,8 @@ class BaseInstance3DBoxes(object):
subject to Pytorch's indexing semantics.
Returns:
A new object of :class:`BaseInstances3DBoxes` after indexing.
:obj:`BaseInstances3DBoxes`: A new object of \
:class:`BaseInstances3DBoxes` after indexing.
"""
original_type = type(self)
if isinstance(item, int):
......@@ -415,8 +385,8 @@ class BaseInstance3DBoxes(object):
"""Calculate 3D overlaps of two boxes.
Note:
This function calculates the overlaps between boxes1 and boxes2,
boxes1 and boxes2 are not necessarily in the same type.
This function calculates the overlaps between ``boxes1`` and
``boxes2``, ``boxes1`` and ``boxes2`` should be in the same type.
Args:
boxes1 (:obj:`BaseInstanceBoxes`): Boxes 1 contain N boxes.
......@@ -424,7 +394,7 @@ class BaseInstance3DBoxes(object):
mode (str, optional): Mode of iou calculation. Defaults to 'iou'.
Returns:
torch.Tensor: Calculated iou of boxes.
torch.Tensor: Calculated iou of boxes' heights.
"""
assert isinstance(boxes1, BaseInstance3DBoxes)
assert isinstance(boxes2, BaseInstance3DBoxes)
......@@ -477,8 +447,8 @@ class BaseInstance3DBoxes(object):
data (torch.Tensor | numpy.array | list): Data to be copied.
Returns:
:obj:`BaseInstance3DBoxes`: A new bbox with data and other \
properties are similar to self.
:obj:`BaseInstance3DBoxes`: A new bbox object with ``data``, \
the object's other properties are similar to ``self``.
"""
new_tensor = self.tensor.new_tensor(data) \
if not isinstance(data, torch.Tensor) else data.to(self.device)
......
......@@ -36,39 +36,23 @@ class CameraInstance3DBoxes(BaseInstance3DBoxes):
@property
def height(self):
"""Obtain the heights of all the boxes.
Returns:
torch.Tensor: A vector with height of each box.
"""
"""torch.Tensor: A vector with height of each box."""
return self.tensor[:, 4]
@property
def top_height(self):
"""Obtain the top height of all the boxes.
Returns:
torch.Tensor: A vector with the top height of each box.
"""
"""torch.Tensor: A vector with the top height of each box."""
# the positive direction is down rather than up
return self.bottom_height - self.height
@property
def bottom_height(self):
"""Obtain the bottom's height of all the boxes.
Returns:
torch.Tensor: A vector with bottom's height of each box.
"""
"""torch.Tensor: A vector with bottom's height of each box."""
return self.tensor[:, 1]
@property
def gravity_center(self):
"""Calculate the gravity center of all the boxes.
Returns:
torch.Tensor: A tensor with center of each box.
"""
"""torch.Tensor: A tensor with center of each box."""
bottom_center = self.bottom_center
gravity_center = torch.zeros_like(bottom_center)
gravity_center[:, [0, 2]] = bottom_center[:, [0, 2]]
......@@ -77,7 +61,7 @@ class CameraInstance3DBoxes(BaseInstance3DBoxes):
@property
def corners(self):
"""Calculate the coordinates of corners of all the boxes.
"""torch.Tensor: Coordinates of corners of all the boxes in shape (N, 8, 3).
Convert the boxes to in clockwise order, in the form of
(x0y0z0, x0y0z1, x0y1z1, x0y1z0, x1y0z0, x1y0z1, x1y1z1, x1y1z0)
......@@ -98,9 +82,6 @@ class CameraInstance3DBoxes(BaseInstance3DBoxes):
|
v
down y
Returns:
torch.Tensor: Corners of each box with size (N, 8, 3).
"""
# TODO: rotation_3d_in_axis function do not support
# empty tensor currently.
......@@ -122,21 +103,14 @@ class CameraInstance3DBoxes(BaseInstance3DBoxes):
@property
def bev(self):
"""Calculate the 2D bounding boxes in BEV with rotation.
Returns:
torch.Tensor: A n x 5 tensor of 2D BEV box of each box. \
The box is in XYWHR format.
"""
"""torch.Tensor: A n x 5 tensor of 2D BEV box of each box
with rotation in XYWHR format."""
return self.tensor[:, [0, 2, 3, 5, 6]]
@property
def nearest_bev(self):
"""Calculate the 2D bounding boxes in BEV without rotation.
Returns:
torch.Tensor: A tensor of 2D BEV box of each box.
"""
"""torch.Tensor: A tensor of 2D BEV box of each box
without rotation."""
# Obtain BEV boxes with rotation in XZWHR format
bev_rotated_boxes = self.bev
# convert the rotation to a valid range
......@@ -226,9 +200,9 @@ class CameraInstance3DBoxes(BaseInstance3DBoxes):
(x_min, z_min, x_max, z_max).
Note:
In the original implementation of SECOND, checking whether
a box in the range checks whether the points are in a convex
polygon, we try to reduce the burden for simpler cases.
The original implementation of SECOND checks whether boxes in
a range by checking whether the points are in a convex
polygon, we reduce the burden for simpler cases.
Returns:
torch.Tensor: Indicating whether each box is inside \
......@@ -244,22 +218,19 @@ class CameraInstance3DBoxes(BaseInstance3DBoxes):
def height_overlaps(cls, boxes1, boxes2, mode='iou'):
"""Calculate height overlaps of two boxes.
Note:
This function calculates the height overlaps between boxes1 and
boxes2, where boxes1 and boxes2 should be in the same type.
This function calculates the height overlaps between ``boxes1`` and
``boxes2``, where ``boxes1`` and ``boxes2`` should be in the same type.
Args:
boxes1 (:obj:`BaseInstanceBoxes`): Boxes 1 contain N boxes.
boxes2 (:obj:`BaseInstanceBoxes`): Boxes 2 contain M boxes.
boxes1 (:obj:`CameraInstance3DBoxes`): Boxes 1 contain N boxes.
boxes2 (:obj:`CameraInstance3DBoxes`): Boxes 2 contain M boxes.
mode (str, optional): Mode of iou calculation. Defaults to 'iou'.
Returns:
torch.Tensor: Calculated iou of boxes.
torch.Tensor: Calculated iou of boxes' heights.
"""
assert isinstance(boxes1, BaseInstance3DBoxes)
assert isinstance(boxes2, BaseInstance3DBoxes)
assert type(boxes1) == type(boxes2), '"boxes1" and "boxes2" should' \
f'be in the same type, got {type(boxes1)} and {type(boxes2)}.'
assert isinstance(boxes1, CameraInstance3DBoxes)
assert isinstance(boxes2, CameraInstance3DBoxes)
boxes1_top_height = boxes1.top_height.view(-1, 1)
boxes1_bottom_height = boxes1.bottom_height.view(-1, 1)
......@@ -275,19 +246,19 @@ class CameraInstance3DBoxes(BaseInstance3DBoxes):
return overlaps_h
def convert_to(self, dst, rt_mat=None):
"""Convert self to `dst` mode.
"""Convert self to ``dst`` mode.
Args:
dst (:obj:`BoxMode`): The target Box mode.
rt_mat (np.dnarray | torch.Tensor): The rotation and translation
matrix between different coordinates. Defaults to None.
The conversion from `src` coordinates to `dst` coordinates
The conversion from ``src`` coordinates to ``dst`` coordinates
usually comes along the change of sensors, e.g., from camera
to LiDAR. This requires a transformation matrix.
Returns:
:obj:`BaseInstance3DBoxes`: \
The converted box of the same type in the `dst` mode.
The converted box of the same type in the ``dst`` mode.
"""
from .box_3d_mode import Box3DMode
return Box3DMode.convert(
......
......@@ -24,7 +24,7 @@ class DepthInstance3DBoxes(BaseInstance3DBoxes):
The yaw is 0 at the positive direction of x axis, and increases from
the positive direction of x to the positive direction of y.
Args:
Attributes:
tensor (torch.Tensor): Float matrix of N x box_dim.
box_dim (int): Integer indicates the dimension of a box
Each row is (x, y, z, x_size, y_size, z_size, yaw, ...).
......@@ -34,11 +34,7 @@ class DepthInstance3DBoxes(BaseInstance3DBoxes):
@property
def gravity_center(self):
"""Calculate the gravity center of all the boxes.
Returns:
torch.Tensor: A tensor with center of each box.
"""
"""torch.Tensor: A tensor with center of each box."""
bottom_center = self.bottom_center
gravity_center = torch.zeros_like(bottom_center)
gravity_center[:, :2] = bottom_center[:, :2]
......@@ -47,10 +43,11 @@ class DepthInstance3DBoxes(BaseInstance3DBoxes):
@property
def corners(self):
"""Calculate the coordinates of corners of all the boxes.
"""torch.Tensor: Coordinates of corners of all the boxes
in shape (N, 8, 3).
Convert the boxes to corners in clockwise order, in form of
(x0y0z0, x0y0z1, x0y1z1, x0y1z0, x1y0z0, x1y0z1, x1y1z1, x1y1z0)
``(x0y0z0, x0y0z1, x0y1z1, x0y1z0, x1y0z0, x1y0z1, x1y1z1, x1y1z0)``
.. code-block:: none
......@@ -66,9 +63,6 @@ class DepthInstance3DBoxes(BaseInstance3DBoxes):
| / oriign | /
(x0, y0, z0) + ----------- + --------> right x
(x1, y0, z0)
Returns:
torch.Tensor: Corners of each box with size (N, 8, 3).
"""
# TODO: rotation_3d_in_axis function do not support
# empty tensor currently.
......@@ -90,21 +84,14 @@ class DepthInstance3DBoxes(BaseInstance3DBoxes):
@property
def bev(self):
"""Calculate the 2D bounding boxes in BEV with rotation.
Returns:
torch.Tensor: A n x 5 tensor of 2D BEV box of each box. \
The box is in XYWHR format.
"""
"""torch.Tensor: A n x 5 tensor of 2D BEV box of each box
in XYWHR format."""
return self.tensor[:, [0, 1, 3, 4, 6]]
@property
def nearest_bev(self):
"""Calculate the 2D bounding boxes in BEV without rotation.
Returns:
torch.Tensor: A tensor of 2D BEV box of each box.
"""
"""torch.Tensor: A tensor of 2D BEV box of each box
without rotation."""
# Obtain BEV boxes with rotation in XYWHR format
bev_rotated_boxes = self.bev
# convert the rotation to a valid range
......@@ -219,19 +206,19 @@ class DepthInstance3DBoxes(BaseInstance3DBoxes):
return in_range_flags
def convert_to(self, dst, rt_mat=None):
"""Convert self to `dst` mode.
"""Convert self to ``dst`` mode.
Args:
dst (:obj:`BoxMode`): The target Box mode.
rt_mat (np.ndarray | torch.Tensor): The rotation and translation
matrix between different coordinates. Defaults to None.
The conversion from `src` coordinates to `dst` coordinates
The conversion from ``src`` coordinates to ``dst`` coordinates
usually comes along the change of sensors, e.g., from camera
to LiDAR. This requires a transformation matrix.
Returns:
:obj:`BaseInstance3DBoxes`: \
The converted box of the same type in the `dst` mode.
:obj:`DepthInstance3DBoxes`: \
The converted box of the same type in the ``dst`` mode.
"""
from .box_3d_mode import Box3DMode
return Box3DMode.convert(
......
......@@ -34,11 +34,7 @@ class LiDARInstance3DBoxes(BaseInstance3DBoxes):
@property
def gravity_center(self):
"""Calculate the gravity center of all the boxes.
Returns:
torch.Tensor: A tensor with center of each box.
"""
"""torch.Tensor: A tensor with center of each box."""
bottom_center = self.bottom_center
gravity_center = torch.zeros_like(bottom_center)
gravity_center[:, :2] = bottom_center[:, :2]
......@@ -47,10 +43,11 @@ class LiDARInstance3DBoxes(BaseInstance3DBoxes):
@property
def corners(self):
"""Calculate the coordinates of corners of all the boxes.
"""torch.Tensor: Coordinates of corners of all the boxes
in shape (N, 8, 3).
Convert the boxes to corners in clockwise order, in form of
(x0y0z0, x0y0z1, x0y1z1, x0y1z0, x1y0z0, x1y0z1, x1y1z1, x1y1z0)
``(x0y0z0, x0y0z1, x0y1z1, x0y1z0, x1y0z0, x1y0z1, x1y1z1, x1y1z0)``
.. code-block:: none
......@@ -66,9 +63,6 @@ class LiDARInstance3DBoxes(BaseInstance3DBoxes):
| / oriign | /
left y<-------- + ----------- + (x0, y1, z0)
(x0, y0, z0)
Returns:
torch.Tensor: Corners of each box with size (N, 8, 3).
"""
# TODO: rotation_3d_in_axis function do not support
# empty tensor currently.
......@@ -90,21 +84,14 @@ class LiDARInstance3DBoxes(BaseInstance3DBoxes):
@property
def bev(self):
"""Calculate the 2D bounding boxes in BEV with rotation.
Returns:
torch.Tensor: A n x 5 tensor of 2D BEV box of each box. \
The box is in XYWHR format.
"""
"""torch.Tensor: 2D BEV box of each box with rotation
in XYWHR format."""
return self.tensor[:, [0, 1, 3, 4, 6]]
@property
def nearest_bev(self):
"""Calculate the 2D bounding boxes in BEV without rotation.
Returns:
torch.Tensor: A tensor of 2D BEV box of each box.
"""
"""torch.Tensor: A tensor of 2D BEV box of each box
without rotation."""
# Obtain BEV boxes with rotation in XYWHR format
bev_rotated_boxes = self.bev
# convert the rotation to a valid range
......@@ -198,9 +185,9 @@ class LiDARInstance3DBoxes(BaseInstance3DBoxes):
(x_min, y_min, x_max, y_max)
Note:
In the original implementation of SECOND, checking whether
a box in the range checks whether the points are in a convex
polygon, we try to reduce the burdun for simpler cases.
The original implementation of SECOND checks whether boxes in
a range by checking whether the points are in a convex
polygon, we reduce the burden for simpler cases.
Returns:
torch.Tensor: Whether each box is inside the reference range.
......@@ -212,19 +199,19 @@ class LiDARInstance3DBoxes(BaseInstance3DBoxes):
return in_range_flags
def convert_to(self, dst, rt_mat=None):
"""Convert self to `dst` mode.
"""Convert self to ``dst`` mode.
Args:
dst (:obj:`BoxMode`): the target Box mode
rt_mat (np.ndarray | torch.Tensor): The rotation and translation
matrix between different coordinates. Defaults to None.
The conversion from `src` coordinates to `dst` coordinates
The conversion from ``src`` coordinates to ``dst`` coordinates
usually comes along the change of sensors, e.g., from camera
to LiDAR. This requires a transformation matrix.
Returns:
:obj:`BaseInstance3DBoxes`: \
The converted box of the same type in the `dst` mode.
The converted box of the same type in the ``dst`` mode.
"""
from .box_3d_mode import Box3DMode
return Box3DMode.convert(
......
......@@ -5,7 +5,7 @@ from os import path as osp
def _write_ply(points, out_filename):
"""Write points into ply format for meshlab visualization.
"""Write points into ``ply`` format for meshlab visualization.
Args:
points (np.ndarray): Points in shape (N, dim).
......
# These must be installed before building mmdetection
numpy
torch>=1.3
mmcv
torch
torchvision
git+https://github.com/open-mmlab/mmdetection.git
lyft_dataset_sdk
networkx>=2.2,<2.3
trimesh>=2.35.39,<2.35.40
matplotlib
mmcv>=1.0.2
# we may unlock the verion of numba in the future
numba==0.48.0
numpy
nuscenes-devkit==1.0.5
lyft_dataset_sdk
# need older pillow until torchvision is fixed
Pillow<=6.2.2
plyfile
six
terminaltables
torch>=1.3
torchvision
# by default we also use tensorboard to log results
tensorboard
trimesh>=2.35.39,<2.35.40
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment