|
|
|
|
|
from typing import Sequence, Union |
|
|
|
|
|
from mmcv.cnn import build_activation_layer, build_norm_layer |
|
|
from mmengine.model import BaseModule |
|
|
from torch import nn |
|
|
|
|
|
from mmdet3d.utils import ConfigType, OptConfigType |
|
|
from .torchsparse import IS_TORCHSPARSE_AVAILABLE |
|
|
|
|
|
if IS_TORCHSPARSE_AVAILABLE: |
|
|
import torchsparse.nn as spnn |
|
|
from torchsparse.tensor import SparseTensor |
|
|
else: |
|
|
SparseTensor = None |
|
|
|
|
|
|
|
|
class TorchSparseConvModule(BaseModule): |
|
|
"""A torchsparse conv block that bundles conv/norm/activation layers. |
|
|
|
|
|
Args: |
|
|
in_channels (int): In channels of block. |
|
|
out_channels (int): Out channels of block. |
|
|
kernel_size (int or Tuple[int]): Kernel_size of block. |
|
|
stride (int or Tuple[int]): Stride of the first block. Defaults to 1. |
|
|
dilation (int): Dilation of block. Defaults to 1. |
|
|
bias (bool): Whether use bias in conv. Defaults to False. |
|
|
transposed (bool): Whether use transposed convolution operator. |
|
|
Defaults to False. |
|
|
norm_cfg (:obj:`ConfigDict` or dict): The config of normalization. |
|
|
init_cfg (:obj:`ConfigDict` or dict, optional): Initialization config. |
|
|
Defaults to None. |
|
|
""" |
|
|
|
|
|
def __init__(self, |
|
|
in_channels: int, |
|
|
out_channels: int, |
|
|
kernel_size: Union[int, Sequence[int]], |
|
|
stride: Union[int, Sequence[int]] = 1, |
|
|
dilation: int = 1, |
|
|
bias: bool = False, |
|
|
transposed: bool = False, |
|
|
norm_cfg: ConfigType = dict(type='TorchSparseBN'), |
|
|
act_cfg: ConfigType = dict( |
|
|
type='TorchSparseReLU', inplace=True), |
|
|
init_cfg: OptConfigType = None, |
|
|
**kwargs) -> None: |
|
|
super().__init__(init_cfg) |
|
|
layers = [ |
|
|
spnn.Conv3d(in_channels, out_channels, kernel_size, stride, |
|
|
dilation, bias, transposed) |
|
|
] |
|
|
if norm_cfg is not None: |
|
|
_, norm = build_norm_layer(norm_cfg, out_channels) |
|
|
layers.append(norm) |
|
|
if act_cfg is not None: |
|
|
activation = build_activation_layer(act_cfg) |
|
|
layers.append(activation) |
|
|
self.net = nn.Sequential(*layers) |
|
|
|
|
|
def forward(self, x: SparseTensor) -> SparseTensor: |
|
|
out = self.net(x) |
|
|
return out |
|
|
|
|
|
|
|
|
class TorchSparseBasicBlock(BaseModule): |
|
|
"""Torchsparse residual basic block for MinkUNet. |
|
|
|
|
|
Args: |
|
|
in_channels (int): In channels of block. |
|
|
out_channels (int): Out channels of block. |
|
|
kernel_size (int or Tuple[int]): Kernel_size of block. |
|
|
stride (int or Tuple[int]): Stride of the first block. Defaults to 1. |
|
|
dilation (int): Dilation of block. Defaults to 1. |
|
|
bias (bool): Whether use bias in conv. Defaults to False. |
|
|
norm_cfg (:obj:`ConfigDict` or dict): The config of normalization. |
|
|
init_cfg (:obj:`ConfigDict` or dict, optional): Initialization config. |
|
|
Defaults to None. |
|
|
""" |
|
|
|
|
|
def __init__(self, |
|
|
in_channels: int, |
|
|
out_channels: int, |
|
|
kernel_size: Union[int, Sequence[int]] = 3, |
|
|
stride: Union[int, Sequence[int]] = 1, |
|
|
dilation: int = 1, |
|
|
bias: bool = False, |
|
|
norm_cfg: ConfigType = dict(type='TorchSparseBN'), |
|
|
init_cfg: OptConfigType = None, |
|
|
**kwargs) -> None: |
|
|
super().__init__(init_cfg) |
|
|
_, norm1 = build_norm_layer(norm_cfg, out_channels) |
|
|
_, norm2 = build_norm_layer(norm_cfg, out_channels) |
|
|
|
|
|
self.net = nn.Sequential( |
|
|
spnn.Conv3d(in_channels, out_channels, kernel_size, stride, |
|
|
dilation, bias), norm1, spnn.ReLU(inplace=True), |
|
|
spnn.Conv3d( |
|
|
out_channels, |
|
|
out_channels, |
|
|
kernel_size, |
|
|
stride=1, |
|
|
dilation=dilation, |
|
|
bias=bias), norm2) |
|
|
|
|
|
if in_channels == out_channels and stride == 1: |
|
|
self.downsample = nn.Identity() |
|
|
else: |
|
|
_, norm3 = build_norm_layer(norm_cfg, out_channels) |
|
|
self.downsample = nn.Sequential( |
|
|
spnn.Conv3d( |
|
|
in_channels, |
|
|
out_channels, |
|
|
kernel_size=1, |
|
|
stride=stride, |
|
|
dilation=dilation, |
|
|
bias=bias), norm3) |
|
|
|
|
|
self.relu = spnn.ReLU(inplace=True) |
|
|
|
|
|
def forward(self, x: SparseTensor) -> SparseTensor: |
|
|
out = self.relu(self.net(x) + self.downsample(x)) |
|
|
return out |
|
|
|
|
|
|
|
|
class TorchSparseBottleneck(BaseModule): |
|
|
"""Torchsparse residual basic block for MinkUNet. |
|
|
|
|
|
Args: |
|
|
in_channels (int): In channels of block. |
|
|
out_channels (int): Out channels of block. |
|
|
kernel_size (int or Tuple[int]): Kernel_size of block. |
|
|
stride (int or Tuple[int]): Stride of the second block. Defaults to 1. |
|
|
dilation (int): Dilation of block. Defaults to 1. |
|
|
bias (bool): Whether use bias in conv. Defaults to False. |
|
|
norm_cfg (:obj:`ConfigDict` or dict): The config of normalization. |
|
|
init_cfg (:obj:`ConfigDict` or dict, optional): Initialization config. |
|
|
Defaults to None. |
|
|
""" |
|
|
|
|
|
def __init__(self, |
|
|
in_channels: int, |
|
|
out_channels: int, |
|
|
kernel_size: Union[int, Sequence[int]] = 3, |
|
|
stride: Union[int, Sequence[int]] = 1, |
|
|
dilation: int = 1, |
|
|
bias: bool = False, |
|
|
norm_cfg: ConfigType = dict(type='TorchSparseBN'), |
|
|
init_cfg: OptConfigType = None, |
|
|
**kwargs) -> None: |
|
|
super().__init__(init_cfg) |
|
|
_, norm1 = build_norm_layer(norm_cfg, out_channels) |
|
|
_, norm2 = build_norm_layer(norm_cfg, out_channels) |
|
|
_, norm3 = build_norm_layer(norm_cfg, out_channels) |
|
|
|
|
|
self.net = nn.Sequential( |
|
|
spnn.Conv3d( |
|
|
in_channels, |
|
|
out_channels, |
|
|
kernel_size=1, |
|
|
stride=1, |
|
|
dilation=dilation, |
|
|
bias=bias), norm1, spnn.ReLU(inplace=True), |
|
|
spnn.Conv3d( |
|
|
out_channels, |
|
|
out_channels, |
|
|
kernel_size, |
|
|
stride, |
|
|
dilation=dilation, |
|
|
bias=bias), norm2, spnn.ReLU(inplace=True), |
|
|
spnn.Conv3d( |
|
|
out_channels, |
|
|
out_channels, |
|
|
kernel_size=1, |
|
|
stride=1, |
|
|
dilation=dilation, |
|
|
bias=bias), norm3) |
|
|
|
|
|
if in_channels == out_channels and stride == 1: |
|
|
self.downsample = nn.Identity() |
|
|
else: |
|
|
_, norm4 = build_norm_layer(norm_cfg, out_channels) |
|
|
self.downsample = nn.Sequential( |
|
|
spnn.Conv3d( |
|
|
in_channels, |
|
|
out_channels, |
|
|
kernel_size=1, |
|
|
stride=stride, |
|
|
dilation=dilation, |
|
|
bias=bias), norm4) |
|
|
|
|
|
self.relu = spnn.ReLU(inplace=True) |
|
|
|
|
|
def forward(self, x: SparseTensor) -> SparseTensor: |
|
|
out = self.relu(self.net(x) + self.downsample(x)) |
|
|
return out |
|
|
|