我们通常把模型的各个组成成分分成 6 种类型:
编码器(encoder):包括 voxel encoder 和 middle encoder 等进入 backbone 前所使用的基于体素的方法,如
HardVFE
和PointPillarsScatter
。骨干网络(backbone):通常采用 FCN 网络来提取特征图,如
ResNet
和SECOND
。颈部网络(neck):位于 backbones 和 heads 之间的组成模块,如
FPN
和SECONDFPN
。检测头(head):用于特定任务的组成模块,如
检测框的预测
和掩码的预测
。RoI 提取器(RoI extractor):用于从特征图中提取 RoI 特征的组成模块,如
H3DRoIHead
和PartAggregationROIHead
。损失函数(loss):heads 中用于计算损失函数的组成模块,如
FocalLoss
、L1Loss
和GHMLoss
。
一、自定义模型
添加新的编码器
接下来我们以 HardVFE 为例展示如何开发新的组成模块。
1. 定义一个新的体素编码器(如 HardVFE:即 HV-SECOND 中使用的体素特征编码器)
创建一个新文件 mmdet3d/models/voxel_encoders/voxel_encoder.py
。
import torch.nn as nn
from mmdet3d.registry import MODELS
@MODELS.register_module()
class HardVFE(nn.Module):
def __init__(self, arg1, arg2):
pass
def forward(self, x): # 需要返回一个元组
pass
2. 导入该模块
您可以在 mmdet3d/models/voxel_encoders/__init__.py
中添加以下代码:
from .voxel_encoder import HardVFE
或者在配置文件中添加以下代码,从而避免修改源码:
custom_imports = dict(
imports=['mmdet3d.models.voxel_encoders.voxel_encoder'],
allow_failed_imports=False)
3. 在配置文件中使用体素编码器
model = dict(
...
voxel_encoder=dict(
type='HardVFE',
arg1=xxx,
arg2=yyy),
...
)
添加新的骨干网络
接下来我们以 SECOND(Sparsely Embedded Convolutional Detection)为例展示如何开发新的组成模块。
1. 定义一个新的骨干网络(如 SECOND)
创建一个新文件 mmdet3d/models/backbones/second.py
。
from mmengine.model import BaseModule
from mmdet3d.registry import MODELS
@MODELS.register_module()
class SECOND(BaseModule):
def __init__(self, arg1, arg2):
pass
def forward(self, x): # 需要返回一个元组
pass
2. 导入该模块
您可以在 mmdet3d/mod
model = dict(
...
backbone=dict(
type='SECOND',
arg1=xxx,
arg2=yyy),
...
)
els/backbones/__init__.py
中添加以下代码:
from .second import SECOND
或者在配置文件中添加以下代码,从而避免修改源码:
custom_imports = dict(
imports=['mmdet3d.models.backbones.second'],
allow_failed_imports=False)
3. 在配置文件中使用骨干网络
model = dict(
...
backbone=dict(
type='SECOND',
arg1=xxx,
arg2=yyy),
...
)
添加新的颈部网络
1. 定义一个新的颈部网络(如 SECONDFPN)
创建一个新文件 mmdet3d/models/necks/second_fpn.py
。
from mmengine.model import BaseModule
from mmdet3d.registry import MODELS
@MODELS.register_module()
class SECONDFPN(BaseModule):
def __init__(self,
in_channels=[128, 128, 256],
out_channels=[256, 256, 256],
upsample_strides=[1, 2, 4],
norm_cfg=dict(type='BN', eps=1e-3, momentum=0.01),
upsample_cfg=dict(type='deconv', bias=False),
conv_cfg=dict(type='Conv2d', bias=False),
use_conv_for_no_stride=False,
init_cfg=None):
pass
def forward(self, x):
# 具体实现忽略
pass
2. 导入该模块
您可以在 mmdet3d/models/necks/__init__.py
中添加以下代码:
from .second_fpn import SECONDFPN
或者在配置文件中添加以下代码,从而避免修改源码:
custom_imports = dict(
imports=['mmdet3d.models.necks.second_fpn'],
allow_failed_imports=False)
3. 在配置文件中使用颈部网络
model = dict(
...
neck=dict(
type='SECONDFPN',
in_channels=[64, 128, 256],
upsample_strides=[1, 2, 4],
out_channels=[128, 128, 128]),
...
)
添加新的检测头
接下来我们以 PartA2 Head 为例展示如何开发新的检测头。
注意:此处展示的 PartA2 RoI Head
将用于检测器的第二阶段。对于单阶段的检测头,请参考 mmdet3d/models/dense_heads/
中的例子。由于其简单高效,它们更常用于自动驾驶场景下的 3D 检测中。
首先,在 mmdet3d/models/roi_heads/bbox_heads/parta2_bbox_head.py
中添加新的 bbox head。PartA2 RoI Head
为目标检测实现了一个新的 bbox head。为了实现一个 bbox head,我们通常需要在新模块中实现如下两个函数。有时还需要实现其他相关函数,如 loss
和 get_targets
。
from mmengine.