Commit 5b42b739 authored by liyinhao's avatar liyinhao
Browse files

Merge branch 'main_tmp' into indoor_pipeline

parents fefbdd12 0df95010
......@@ -16,7 +16,7 @@ before_script:
.linting_template: &linting_template_def
stage: linting
script:
- pip install flake8 yapf isort
- pip install flake8==3.7.9 yapf isort
- flake8 .
- isort -rc --check-only --diff mmdet3d/ tools/ tests/
- yapf -r -d mmdet3d/ tools/ tests/ configs/
......@@ -26,6 +26,7 @@ before_script:
script:
- echo "Start building..."
- pip install "git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI"
- pip install git+https://github.com/open-mmlab/mmcv.git
- pip install git+https://github.com/open-mmlab/mmdetection.git
- python -c "import mmdet; print(mmdet.__version__)"
- pip install -v -e .[all]
......
......@@ -57,13 +57,13 @@ model = dict(
in_channels=256,
layer_nums=[5, 5],
layer_strides=[1, 2],
num_filters=[128, 256],
out_channels=[128, 256],
),
pts_neck=dict(
type='SECONDFPN',
in_channels=[128, 256],
upsample_strides=[1, 2],
num_upsample_filters=[256, 256],
out_channels=[256, 256],
),
pts_bbox_head=dict(
type='SECONDHead',
......
......@@ -28,13 +28,13 @@ model = dict(
in_channels=64,
layer_nums=[3, 5, 5],
layer_strides=[2, 2, 2],
num_filters=[64, 128, 256],
out_channels=[64, 128, 256],
),
neck=dict(
type='SECONDFPN',
in_channels=[64, 128, 256],
upsample_strides=[1, 2, 4],
num_upsample_filters=[128, 128, 128],
out_channels=[128, 128, 128],
),
bbox_head=dict(
type='SECONDHead',
......
......@@ -26,13 +26,13 @@ model = dict(
in_channels=256,
layer_nums=[5, 5],
layer_strides=[1, 2],
num_filters=[128, 256],
out_channels=[128, 256],
),
neck=dict(
type='SECONDFPN',
in_channels=[128, 256],
upsample_strides=[1, 2],
num_upsample_filters=[256, 256],
out_channels=[256, 256],
),
bbox_head=dict(
type='SECONDHead',
......
......@@ -26,13 +26,13 @@ model = dict(
in_channels=256,
layer_nums=[5, 5],
layer_strides=[1, 2],
num_filters=[128, 256],
out_channels=[128, 256],
),
neck=dict(
type='SECONDFPN',
in_channels=[128, 256],
upsample_strides=[1, 2],
num_upsample_filters=[256, 256],
out_channels=[256, 256],
),
bbox_head=dict(
type='SECONDHead',
......
......@@ -22,12 +22,12 @@ model = dict(
in_channels=256,
layer_nums=[5, 5],
layer_strides=[1, 2],
num_filters=[128, 256]),
out_channels=[128, 256]),
neck=dict(
type='SECONDFPN',
in_channels=[128, 256],
upsample_strides=[1, 2],
num_upsample_filters=[256, 256]),
out_channels=[256, 256]),
rpn_head=dict(
type='PartA2RPNHead',
class_name=['Pedestrian', 'Cyclist', 'Car'],
......
......@@ -27,13 +27,13 @@ model = dict(
in_channels=64,
layer_nums=[3, 5, 5],
layer_strides=[2, 2, 2],
num_filters=[64, 128, 256],
out_channels=[64, 128, 256],
),
neck=dict(
type='SECONDFPN',
in_channels=[64, 128, 256],
upsample_strides=[1, 2, 4],
num_upsample_filters=[128, 128, 128],
out_channels=[128, 128, 128],
),
bbox_head=dict(
type='SECONDHead',
......
......@@ -26,13 +26,13 @@ model = dict(
in_channels=256,
layer_nums=[5, 5],
layer_strides=[1, 2],
num_filters=[128, 256],
out_channels=[128, 256],
),
neck=dict(
type='SECONDFPN',
in_channels=[128, 256],
upsample_strides=[1, 2],
num_upsample_filters=[256, 256],
out_channels=[256, 256],
),
bbox_head=dict(
type='SECONDHead',
......
......@@ -34,14 +34,14 @@ model = dict(
norm_cfg=dict(type='naiveSyncBN2d', eps=1e-3, momentum=0.01),
layer_nums=[3, 5, 5],
layer_strides=[2, 2, 2],
num_filters=[64, 128, 256],
out_channels=[64, 128, 256],
),
pts_neck=dict(
type='SECONDFPN',
norm_cfg=dict(type='naiveSyncBN2d', eps=1e-3, momentum=0.01),
in_channels=[64, 128, 256],
upsample_strides=[1, 2, 4],
num_upsample_filters=[128, 128, 128],
out_channels=[128, 128, 128],
),
pts_bbox_head=dict(
type='Anchor3DVeloHead',
......
from functools import partial
import torch.nn as nn
from mmcv.cnn import build_norm_layer
from mmcv.cnn import build_conv_layer, build_norm_layer
from mmcv.runner import load_checkpoint
from mmdet.models import BACKBONES
class Empty(nn.Module):
def __init__(self, *args, **kwargs):
super(Empty, self).__init__()
def forward(self, *args, **kwargs):
if len(args) == 1:
return args[0]
elif len(args) == 0:
return None
return args
@BACKBONES.register_module()
class SECOND(nn.Module):
"""Compare with RPN, RPNV2 support arbitrary number of stage.
"""Backbone network for SECOND/PointPillars/PartA2/MVXNet
Args:
in_channels (int): Input channels
out_channels (list[int]): Output channels for multi-scale feature maps
layer_nums (list[int]): Number of layers in each stage
layer_strides (list[int]): Strides of each stage
norm_cfg (dict): Config dict of normalization layers
conv_cfg (dict): Config dict of convolutional layers
"""
def __init__(self,
in_channels=128,
out_channels=[128, 128, 256],
layer_nums=[3, 5, 5],
layer_strides=[2, 2, 2],
num_filters=[128, 128, 256],
norm_cfg=dict(type='BN', eps=1e-3, momentum=0.01)):
norm_cfg=dict(type='BN', eps=1e-3, momentum=0.01),
conv_cfg=dict(type='Conv2d', bias=False)):
super(SECOND, self).__init__()
assert len(layer_strides) == len(layer_nums)
assert len(num_filters) == len(layer_nums)
if norm_cfg is not None:
Conv2d = partial(nn.Conv2d, bias=False)
else:
Conv2d = partial(nn.Conv2d, bias=True)
assert len(out_channels) == len(layer_nums)
in_filters = [in_channels, *num_filters[:-1]]
in_filters = [in_channels, *out_channels[:-1]]
# note that when stride > 1, conv2d with same padding isn't
# equal to pad-conv2d. we should use pad-conv2d.
blocks = []
for i, layer_num in enumerate(layer_nums):
norm_layer = (
build_norm_layer(norm_cfg, num_filters[i])[1]
if norm_cfg is not None else Empty)
block = [
nn.ZeroPad2d(1),
Conv2d(
in_filters[i], num_filters[i], 3, stride=layer_strides[i]),
norm_layer,
build_conv_layer(
conv_cfg,
in_filters[i],
out_channels[i],
3,
stride=layer_strides[i],
padding=1),
build_norm_layer(norm_cfg, out_channels[i])[1],
nn.ReLU(inplace=True),
]
for j in range(layer_num):
norm_layer = (
build_norm_layer(norm_cfg, num_filters[i])[1]
if norm_cfg is not None else Empty)
block.append(
Conv2d(num_filters[i], num_filters[i], 3, padding=1))
block.append(norm_layer)
build_conv_layer(
conv_cfg,
out_channels[i],
out_channels[i],
3,
padding=1))
block.append(build_norm_layer(norm_cfg, out_channels[i])[1])
block.append(nn.ReLU(inplace=True))
block = nn.Sequential(*block)
......@@ -71,6 +62,8 @@ class SECOND(nn.Module):
self.blocks = nn.ModuleList(blocks)
def init_weights(self, pretrained=None):
# Do not initialize the conv layers
# to follow the original implementation
if isinstance(pretrained, str):
from mmdet3d.utils import get_root_logger
logger = get_root_logger()
......
from functools import partial
import torch
import torch.nn as nn
from mmcv.cnn import build_norm_layer, constant_init, kaiming_init
from torch.nn import Sequential
from torch.nn.modules.batchnorm import _BatchNorm
from mmcv.cnn import (build_norm_layer, build_upsample_layer, constant_init,
is_norm, kaiming_init)
from mmdet.models import NECKS
from .. import builder
......@@ -12,36 +9,40 @@ from .. import builder
@NECKS.register_module()
class SECONDFPN(nn.Module):
"""Compare with RPN, RPNV2 support arbitrary number of stage.
"""FPN used in SECOND/PointPillars/PartA2/MVXNet
Args:
in_channels (list[int]): Input channels of multi-scale feature maps
out_channels (list[int]): Output channels of feature maps
upsample_strides (list[int]): Strides used to upsample the feature maps
norm_cfg (dict): Config dict of normalization layers
upsample_cfg (dict): Config dict of upsample layers
"""
def __init__(self,
use_norm=True,
in_channels=[128, 128, 256],
out_channels=[256, 256, 256],
upsample_strides=[1, 2, 4],
num_upsample_filters=[256, 256, 256],
norm_cfg=dict(type='BN', eps=1e-3, momentum=0.01)):
norm_cfg=dict(type='BN', eps=1e-3, momentum=0.01),
upsample_cfg=dict(type='deconv', bias=False)):
# if for GroupNorm,
# cfg is dict(type='GN', num_groups=num_groups, eps=1e-3, affine=True)
super(SECONDFPN, self).__init__()
assert len(num_upsample_filters) == len(upsample_strides)
assert len(out_channels) == len(upsample_strides) == len(in_channels)
self.in_channels = in_channels
ConvTranspose2d = partial(nn.ConvTranspose2d, bias=False)
self.out_channels = out_channels
deblocks = []
for i, num_upsample_filter in enumerate(num_upsample_filters):
norm_layer = build_norm_layer(norm_cfg, num_upsample_filter)[1]
deblock = Sequential(
ConvTranspose2d(
in_channels[i],
num_upsample_filter,
upsample_strides[i],
stride=upsample_strides[i]),
norm_layer,
nn.ReLU(inplace=True),
)
for i, out_channel in enumerate(out_channels):
upsample_layer = build_upsample_layer(
upsample_cfg,
in_channels=in_channels[i],
out_channels=out_channel,
kernel_size=upsample_strides[i],
stride=upsample_strides[i])
deblock = nn.Sequential(upsample_layer,
build_norm_layer(norm_cfg, out_channel)[1],
nn.ReLU(inplace=True))
deblocks.append(deblock)
self.deblocks = nn.ModuleList(deblocks)
......@@ -49,7 +50,7 @@ class SECONDFPN(nn.Module):
for m in self.modules():
if isinstance(m, nn.Conv2d):
kaiming_init(m)
elif isinstance(m, (_BatchNorm, nn.GroupNorm)):
elif is_norm(m):
constant_init(m, 1)
def forward(self, x):
......@@ -65,30 +66,34 @@ class SECONDFPN(nn.Module):
@NECKS.register_module()
class SECONDFusionFPN(SECONDFPN):
"""Compare with RPN, RPNV2 support arbitrary number of stage.
"""FPN used in multi-modality SECOND/PointPillars
Args:
in_channels (list[int]): Input channels of multi-scale feature maps
out_channels (list[int]): Output channels of feature maps
upsample_strides (list[int]): Strides used to upsample the feature maps
norm_cfg (dict): Config dict of normalization layers
upsample_cfg (dict): Config dict of upsample layers
downsample_rates (list[int]): The downsample rate of feature map in
comparison to the original voxelization input
fusion_layer (dict): Config dict of fusion layers
"""
def __init__(self,
use_norm=True,
in_channels=[128, 128, 256],
out_channels=[256, 256, 256],
upsample_strides=[1, 2, 4],
num_upsample_filters=[256, 256, 256],
norm_cfg=dict(type='BN', eps=1e-3, momentum=0.01),
down_sample_rate=[40, 8, 8],
fusion_layer=None,
cat_points=False):
super(SECONDFusionFPN, self).__init__(
use_norm,
in_channels,
upsample_strides,
num_upsample_filters,
norm_cfg,
)
upsample_cfg=dict(type='deconv', bias=False),
downsample_rates=[40, 8, 8],
fusion_layer=None):
super(SECONDFusionFPN,
self).__init__(in_channels, out_channels, upsample_strides,
norm_cfg, upsample_cfg)
self.fusion_layer = None
if fusion_layer is not None:
self.fusion_layer = builder.build_fusion_layer(fusion_layer)
self.cat_points = cat_points
self.down_sample_rate = down_sample_rate
self.downsample_rates = downsample_rates
def forward(self,
x,
......@@ -107,11 +112,11 @@ class SECONDFusionFPN(SECONDFPN):
downsample_pts_coors = torch.zeros_like(coors)
downsample_pts_coors[:, 0] = coors[:, 0]
downsample_pts_coors[:, 1] = (
coors[:, 1] / self.down_sample_rate[0])
coors[:, 1] / self.downsample_rates[0])
downsample_pts_coors[:, 2] = (
coors[:, 2] / self.down_sample_rate[1])
coors[:, 2] / self.downsample_rates[1])
downsample_pts_coors[:, 3] = (
coors[:, 3] / self.down_sample_rate[2])
coors[:, 3] / self.downsample_rates[2])
# fusion for each point
out = self.fusion_layer(img_feats, points, out,
downsample_pts_coors, img_meta)
......
# These must be installed before building mmdetection
numpy
torch>=1.1
torch>=1.3
matplotlib
mmcv>=0.5.0
mmcv>=0.5.1
numba==0.45.1
numpy
# need older pillow until torchvision is fixed
......
import pytest
def test_secfpn():
neck_cfg = dict(
type='SECONDFPN',
in_channels=[2, 3],
upsample_strides=[1, 2],
out_channels=[4, 6],
)
from mmdet.models.builder import build_neck
neck = build_neck(neck_cfg)
assert neck.deblocks[0][0].in_channels == 2
assert neck.deblocks[1][0].in_channels == 3
assert neck.deblocks[0][0].out_channels == 4
assert neck.deblocks[1][0].out_channels == 6
assert neck.deblocks[0][0].stride == (1, 1)
assert neck.deblocks[1][0].stride == (2, 2)
assert neck is not None
neck_cfg = dict(
type='SECONDFPN',
in_channels=[2, 2],
upsample_strides=[1, 2, 4],
out_channels=[2, 2],
)
with pytest.raises(AssertionError):
build_neck(neck_cfg)
neck_cfg = dict(
type='SECONDFPN',
in_channels=[2, 2, 4],
upsample_strides=[1, 2, 4],
out_channels=[2, 2],
)
with pytest.raises(AssertionError):
build_neck(neck_cfg)
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