Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OpenDAS
mmdetection3d
Commits
8dd8da12
"git@developer.sourcefind.cn:OpenDAS/ollama.git" did not exist on "08b933cc10b036bbd164d6dc35b2362ef0b216ca"
Commit
8dd8da12
authored
May 24, 2022
by
ZwwWayne
Committed by
ChaimZhu
Jul 20, 2022
Browse files
fix spconv2 issue in unit tests
parent
c9b69f5a
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
319 additions
and
4 deletions
+319
-4
mmdet3d/datasets/builder.py
mmdet3d/datasets/builder.py
+1
-1
mmdet3d/models/middle_encoders/sparse_unet.py.a4045c791738bd571c7508cf4e033703.tmp
...oders/sparse_unet.py.a4045c791738bd571c7508cf4e033703.tmp
+309
-0
mmdet3d/ops/spconv/__init__.py
mmdet3d/ops/spconv/__init__.py
+1
-1
mmdet3d/ops/spconv/compat_spconv2.py
mmdet3d/ops/spconv/compat_spconv2.py
+0
-0
tests/test_models/test_common_modules/test_sparse_unet.py
tests/test_models/test_common_modules/test_sparse_unet.py
+8
-2
No files found.
mmdet3d/datasets/builder.py
View file @
8dd8da12
...
@@ -3,7 +3,7 @@ import platform
...
@@ -3,7 +3,7 @@ import platform
from
mmcv.utils
import
build_from_cfg
from
mmcv.utils
import
build_from_cfg
from
mmdet
.datasets
import
DATASETS
as
MMDET_DATASETS
from
mmdet
3d.registry
import
DATASETS
from
mmdet.datasets.builder
import
_concat_dataset
from
mmdet.datasets.builder
import
_concat_dataset
if
platform
.
system
()
!=
'Windows'
:
if
platform
.
system
()
!=
'Windows'
:
...
...
mmdet3d/models/middle_encoders/sparse_unet.py.a4045c791738bd571c7508cf4e033703.tmp
0 → 100644
View file @
8dd8da12
# Copyright (c) OpenMMLab. All rights reserved.
import torch
from mmdet3d.ops.spconv import IS_SPCONV2_AVAILABLE
if IS_SPCONV2_AVAILABLE:
from spconv.pytorch import SparseConvTensor, SparseSequential
else:
from mmcv.ops import SparseConvTensor, SparseSequential
from mmcv.runner import BaseModule, auto_fp16
from mmdet3d.ops import SparseBasicBlock, make_sparse_convmodule
from ..builder import MIDDLE_ENCODERS
@MIDDLE_ENCODERS.register_module()
class SparseUNet(BaseModule):
r"""SparseUNet for PartA^2.
See the `paper <https://arxiv.org/abs/1907.03670>`_ for more details.
Args:
in_channels (int): The number of input channels.
sparse_shape (list[int]): The sparse shape of input tensor.
norm_cfg (dict): Config of normalization layer.
base_channels (int): Out channels for conv_input layer.
output_channels (int): Out channels for conv_out layer.
encoder_channels (tuple[tuple[int]]):
Convolutional channels of each encode block.
encoder_paddings (tuple[tuple[int]]): Paddings of each encode block.
decoder_channels (tuple[tuple[int]]):
Convolutional channels of each decode block.
decoder_paddings (tuple[tuple[int]]): Paddings of each decode block.
"""
def __init__(self,
in_channels,
sparse_shape,
order=('conv', 'norm', 'act'),
norm_cfg=dict(type='BN1d', eps=1e-3, momentum=0.01),
base_channels=16,
output_channels=128,
encoder_channels=((16, ), (32, 32, 32), (64, 64, 64), (64, 64,
64)),
encoder_paddings=((1, ), (1, 1, 1), (1, 1, 1), ((0, 1, 1), 1,
1)),
decoder_channels=((64, 64, 64), (64, 64, 32), (32, 32, 16),
(16, 16, 16)),
decoder_paddings=((1, 0), (1, 0), (0, 0), (0, 1)),
init_cfg=None):
super().__init__(init_cfg=init_cfg)
self.sparse_shape = sparse_shape
self.in_channels = in_channels
self.order = order
self.base_channels = base_channels
self.output_channels = output_channels
self.encoder_channels = encoder_channels
self.encoder_paddings = encoder_paddings
self.decoder_channels = decoder_channels
self.decoder_paddings = decoder_paddings
self.stage_num = len(self.encoder_channels)
self.fp16_enabled = False
# Spconv init all weight on its own
assert isinstance(order, tuple) and len(order) == 3
assert set(order) == {'conv', 'norm', 'act'}
if self.order[0] != 'conv': # pre activate
self.conv_input = make_sparse_convmodule(
in_channels,
self.base_channels,
3,
norm_cfg=norm_cfg,
padding=1,
indice_key='subm1',
conv_type='SubMConv3d',
order=('conv', ))
else: # post activate
self.conv_input = make_sparse_convmodule(
in_channels,
self.base_channels,
3,
norm_cfg=norm_cfg,
padding=1,
indice_key='subm1',
conv_type='SubMConv3d')
encoder_out_channels = self.make_encoder_layers(
make_sparse_convmodule, norm_cfg, self.base_channels)
self.make_decoder_layers(make_sparse_convmodule, norm_cfg,
encoder_out_channels)
self.conv_out = make_sparse_convmodule(
encoder_out_channels,
self.output_channels,
kernel_size=(3, 1, 1),
stride=(2, 1, 1),
norm_cfg=norm_cfg,
padding=0,
indice_key='spconv_down2',
conv_type='SparseConv3d')
@auto_fp16(apply_to=('voxel_features', ))
def forward(self, voxel_features, coors, batch_size):
"""Forward of SparseUNet.
Args:
voxel_features (torch.float32): Voxel features in shape [N, C].
coors (torch.int32): Coordinates in shape [N, 4],
the columns in the order of (batch_idx, z_idx, y_idx, x_idx).
batch_size (int): Batch size.
Returns:
dict[str, torch.Tensor]: Backbone features.
"""
coors = coors.int()
input_sp_tensor = SparseConvTensor(voxel_features, coors,
self.sparse_shape, batch_size)
x = self.conv_input(input_sp_tensor)
encode_features = []
for encoder_layer in self.encoder_layers:
x = encoder_layer(x)
encode_features.append(x)
# for detection head
# [200, 176, 5] -> [200, 176, 2]
out = self.conv_out(encode_features[-1])
spatial_features = out.dense()
N, C, D, H, W = spatial_features.shape
spatial_features = spatial_features.view(N, C * D, H, W)
# for segmentation head, with output shape:
# [400, 352, 11] <- [200, 176, 5]
# [800, 704, 21] <- [400, 352, 11]
# [1600, 1408, 41] <- [800, 704, 21]
# [1600, 1408, 41] <- [1600, 1408, 41]
decode_features = []
x = encode_features[-1]
for i in range(self.stage_num, 0, -1):
x = self.decoder_layer_forward(encode_features[i - 1], x,
getattr(self, f'lateral_layer{i}'),
getattr(self, f'merge_layer{i}'),
getattr(self, f'upsample_layer{i}'))
decode_features.append(x)
seg_features = decode_features[-1].features
ret = dict(
spatial_features=spatial_features, seg_features=seg_features)
return ret
def decoder_layer_forward(self, x_lateral, x_bottom, lateral_layer,
merge_layer, upsample_layer):
"""Forward of upsample and residual block.
Args:
x_lateral (:obj:`SparseConvTensor`): Lateral tensor.
x_bottom (:obj:`SparseConvTensor`): Feature from bottom layer.
lateral_layer (SparseBasicBlock): Convolution for lateral tensor.
merge_layer (SparseSequential): Convolution for merging features.
upsample_layer (SparseSequential): Convolution for upsampling.
Returns:
:obj:`SparseConvTensor`: Upsampled feature.
"""
x = lateral_layer(x_lateral)
if IS_SPCONV2_AVAILABLE:
# TODO: try to clean this since it is for the compatibility
# between spconv 1.x & 2
x = x.replace_feature(
torch.cat((x_bottom.features, x.features), dim=1))
else:
x.features = torch.cat((x_bottom.features, x.features), dim=1)
x_merge = merge_layer(x)
x = self.reduce_channel(x, x_merge.features.shape[1])
if IS_SPCONV2_AVAILABLE:
# TODO: try to clean this since it is for the compatibility
# between spconv 1.x & 2
x = x.replace_feature(x_merge.features + x.features)
else:
x.features = x_merge.features + x.features
x = upsample_layer(x)
return x
@staticmethod
def reduce_channel(x, out_channels):
"""reduce channel for element-wise addition.
Args:
x (:obj:`SparseConvTensor`): Sparse tensor, ``x.features``
are in shape (N, C1).
out_channels (int): The number of channel after reduction.
Returns:
:obj:`SparseConvTensor`: Channel reduced feature.
"""
features = x.features
n, in_channels = features.shape
assert (in_channels % out_channels
== 0) and (in_channels >= out_channels)
x.features = features.view(n, out_channels, -1).sum(dim=2)
return x
def make_encoder_layers(self, make_block, norm_cfg, in_channels):
"""make encoder layers using sparse convs.
Args:
make_block (method): A bounded function to build blocks.
norm_cfg (dict[str]): Config of normalization layer.
in_channels (int): The number of encoder input channels.
Returns:
int: The number of encoder output channels.
"""
self.encoder_layers = SparseSequential()
for i, blocks in enumerate(self.encoder_channels):
blocks_list = []
for j, out_channels in enumerate(tuple(blocks)):
padding = tuple(self.encoder_paddings[i])[j]
# each stage started with a spconv layer
# except the first stage
if i != 0 and j == 0:
blocks_list.append(
make_block(
in_channels,
out_channels,
3,
norm_cfg=norm_cfg,
stride=2,
padding=padding,
indice_key=f'spconv{i + 1}',
conv_type='SparseConv3d'))
else:
blocks_list.append(
make_block(
in_channels,
out_channels,
3,
norm_cfg=norm_cfg,
padding=padding,
indice_key=f'subm{i + 1}',
conv_type='SubMConv3d'))
in_channels = out_channels
stage_name = f'encoder_layer{i + 1}'
stage_layers = SparseSequential(*blocks_list)
self.encoder_layers.add_module(stage_name, stage_layers)
return out_channels
def make_decoder_layers(self, make_block, norm_cfg, in_channels):
"""make decoder layers using sparse convs.
Args:
make_block (method): A bounded function to build blocks.
norm_cfg (dict[str]): Config of normalization layer.
in_channels (int): The number of encoder input channels.
Returns:
int: The number of encoder output channels.
"""
block_num = len(self.decoder_channels)
for i, block_channels in enumerate(self.decoder_channels):
paddings = self.decoder_paddings[i]
setattr(
self, f'lateral_layer{block_num - i}',
SparseBasicBlock(
in_channels,
block_channels[0],
conv_cfg=dict(
type='SubMConv3d', indice_key=f'subm{block_num - i}'),
norm_cfg=norm_cfg))
setattr(
self, f'merge_layer{block_num - i}',
make_block(
in_channels * 2,
block_channels[1],
3,
norm_cfg=norm_cfg,
padding=paddings[0],
indice_key=f'subm{block_num - i}',
conv_type='SubMConv3d'))
if block_num - i != 1:
setattr(
self, f'upsample_layer{block_num - i}',
make_block(
in_channels,
block_channels[2],
3,
norm_cfg=norm_cfg,
indice_key=f'spconv{block_num - i}',
conv_type='SparseInverseConv3d'))
else:
# use submanifold conv instead of inverse conv
# in the last block
setattr(
self, f'upsample_layer{block_num - i}',
make_block(
in_channels,
block_channels[2],
3,
norm_cfg=norm_cfg,
padding=paddings[1],
indice_key='subm1',
conv_type='SubMConv3d'))
in_channels = block_channels[2]
mmdet3d/ops/spconv/__init__.py
View file @
8dd8da12
# Copyright (c) OpenMMLab. All rights reserved.
# Copyright (c) OpenMMLab. All rights reserved.
from
.
overwrite_spconv.write
_spconv2
import
register_spconv2
from
.
compat
_spconv2
import
register_spconv2
try
:
try
:
import
spconv
import
spconv
...
...
mmdet3d/ops/spconv/
overwrite_spconv/write
_spconv2.py
→
mmdet3d/ops/spconv/
compat
_spconv2.py
View file @
8dd8da12
File moved
tests/test_models/test_common_modules/test_sparse_unet.py
View file @
8dd8da12
# Copyright (c) OpenMMLab. All rights reserved.
# Copyright (c) OpenMMLab. All rights reserved.
import
pytest
import
pytest
import
torch
import
torch
from
mmcv.ops
import
(
SparseConv3d
,
SparseConvTensor
,
SparseInverseConv3d
,
SubMConv3d
)
from
mmdet3d.ops
import
SparseBasicBlock
from
mmdet3d.ops
import
SparseBasicBlock
from
mmdet3d.ops.spconv
import
IS_SPCONV2_AVAILABLE
if
IS_SPCONV2_AVAILABLE
:
from
spconv.pytorch
import
(
SparseConv3d
,
SparseConvTensor
,
SparseInverseConv3d
,
SubMConv3d
)
else
:
from
mmcv.ops
import
(
SparseConv3d
,
SparseConvTensor
,
SparseInverseConv3d
,
SubMConv3d
)
def
test_SparseUNet
():
def
test_SparseUNet
():
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment