本文对OpenMMLab在Monocular 3D detection领域做的两项工作FCOS3D和PGD(也被称作FCOS3D++)进行介绍。
在此之前,建议大家通过这篇博客:“3Dfy” A General 2D Detector: 纯视觉 3D 检测再思考,来回顾单目3D目标检测的更多细节。
T. Wang, X. Zhu, J. Pang, and D. Lin. FCOS3D: Fully convolutional one-stage monocular
3d object detection. In Proceedings of the IEEE/CVF International Conference on Computer
Vision (ICCV) Workshops, 2021.
论文
代码
3D检测由于其固有的不适定性,比传统的2D情况更具挑战性,这主要体现在深度信息的缺乏。在本文中,我们通过建立在全卷积单级检测器上的实践来研究这个问题,并提出了一个通用框架FCOS3D。具体而言,我们首先将通常定义的7-DoF 3D位置投影到2D图像上,并获得投影的中心点,与之前的2D中心相比,我们将其命名为3D中心。利用该投影,3D中心包含2.5D信息,即2D位置及其相应深度。2D位置可以进一步减少到从图像上的某个点的2D偏移,这用作可以在不同特征级别之间归一化的唯一2D属性。相比之下,深度、3D尺寸和方向被视为解耦后的3D属性。然后,考虑到对象的2D比例,将对象分布到不同的特征级别,并仅根据训练过程的投影3D中心进行分配。此外,基于3D中心用2D高斯分布重新定义中心度,以拟合3D目标公式。所有这些都使该框架简单而有效,消除了任何2D检测或2D-3D对应先验。
全卷积一阶段检测器通常由三个部件组成:用于特征提取的Backbone、用于多级分支构造的Neck和用于密集预测的Head
在回归分支中,不同于FCOS在2D中的情况(回归每个点到顶部/底部/左侧/右侧的距离,如下图中的 t , b , l , r t,b,l,r t,b,l,r所示),FCOS3D将通常定义的7-DoF回归目标转换为2.5D中心和3D尺寸,其中2.5D中心可以通过相机固有矩阵轻松转换回3D空间。
回归2.5D中心可以进一步减少为回归从中心到特定前景点的偏移 Δ x , Δ y \Delta x,\Delta y Δx,Δy、 以及其相应的深度 d d d,对于3D尺寸,预测以下属性:
总的来说,分类分支需要输出目标的类别标签和属性标签,而回归分支则需要预测 Δ x , Δ y , d , w , l , h , θ , v x , v y , C θ , c \Delta x,\Delta y,d,w,l,h,\theta,v_x,v_y,C_{\theta},c Δx,Δy,d,w,l,h,θ,vx,vy,Cθ,c这些属性。
对于分类分支和不同的回归分支,FCOS3D分别定义其损失,并对其进行加权求和:
给定输入图像,通过网络进行推理,获取带有 class scores, attribute scores 和 center-ness 预测结果的 bounding boxes,之后将class score 和 centerness 相乘作为每个预测框的confidence,并在鸟瞰图中进行旋转非最大抑制(NMS),以获得最终结果。
为了训练具有FPN的检测器,我们需要设计一种将目标分配到不同级别特征层的策略,FCOS讨论了两个关键问题:
FCOS为抑制远离目标中心的预测目标,增加了center-ness分支:
c = min ( l ∗ , r ∗ ) max ( l ∗ , r ∗ ) × min ( t ∗ , b ∗ ) max ( t ∗ , b ∗ ) c=\sqrt{\frac{\min \left(l^*, r^*\right)}{\max \left(l^*, r^*\right)} \times \frac{\min \left(t^*, b^*\right)}{\max \left(t^*, b^*\right)}} c=max(l∗,r∗)min(l∗,r∗)×max(t∗,b∗)min(t∗,b∗)
由于3D回归目标被更改为基于3D center-based 的范式,所以FCOS3D通过以投影的3D中心为原点的2D高斯分布来定义center-ness,其二维高斯分布简化为:
c = e − α ( ( Δ x ) 2 + ( Δ y ) 2 ) c=e^{-\alpha\left((\Delta x)^2+(\Delta y)^2\right)} c=e−α((Δx)2+(Δy)2)
实验数据集:NuScenes
评价指标
【MMDetection3D】基于单目(Monocular)的3D目标检测入门实战
官方源码:mmdetection3d
mmdetection3d算法库及nuScenes数据集的下载、配置可以参考官方博客:基于视觉的 3D 检测,本文不再赘述。
CUDA_VISIBLE_DEVICES=0,1 tools/dist_train.sh configs/fcos3d/fcos3d_r101_caffe_fpn_gn-head_dcn_2x8_1x_nus-mono3d.py 2
FCOSMono3D(
(backbone): ResNet(
(conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
(layer1): ResLayer(
(0): Bottleneck(
(conv1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(downsample): Sequential(
(0): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(1): Bottleneck(
(conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
)
(2): Bottleneck(
(conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
)
)
// 以下三层省略
(layer2):
(layer3):
(layer4):
)
init_cfg={'type': 'Pretrained', 'checkpoint': 'open-mmlab://detectron2/resnet101_caffe'}
(neck): FPN(
(lateral_convs): ModuleList(
(0): ConvModule(
(conv): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1))
)
(1): ConvModule(
(conv): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1))
)
(2): ConvModule(
(conv): Conv2d(2048, 256, kernel_size=(1, 1), stride=(1, 1))
)
)
(fpn_convs): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
)
(1): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
)
(2): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
)
(3): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
)
(4): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
)
)
)
init_cfg={'type': 'Xavier', 'layer': 'Conv2d', 'distribution': 'uniform'}
(bbox_head): FCOSMono3DHead(
(loss_cls): FocalLoss()
(loss_bbox): SmoothL1Loss()
(loss_dir): CrossEntropyLoss(avg_non_ignore=False)
(loss_attr): CrossEntropyLoss(avg_non_ignore=False)
(cls_convs): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
(1): ConvModule(
(conv): ModulatedDeformConv2dPack(
(conv_offset): Conv2d(256, 27, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
)
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(reg_convs): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
(1): ConvModule(
(conv): ModulatedDeformConv2dPack(
(conv_offset): Conv2d(256, 27, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
)
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(conv_cls_prev): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(conv_cls): Conv2d(256, 10, kernel_size=(1, 1), stride=(1, 1))
(conv_reg_prevs): ModuleList(
(0): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(1): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(2): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(3): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(4): None
)
(conv_regs): ModuleList(
(0): Conv2d(256, 2, kernel_size=(1, 1), stride=(1, 1))
(1): Conv2d(256, 1, kernel_size=(1, 1), stride=(1, 1))
(2): Conv2d(256, 3, kernel_size=(1, 1), stride=(1, 1))
(3): Conv2d(256, 1, kernel_size=(1, 1), stride=(1, 1))
(4): Conv2d(256, 2, kernel_size=(1, 1), stride=(1, 1))
)
(conv_dir_cls_prev): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(conv_dir_cls): Conv2d(256, 2, kernel_size=(1, 1), stride=(1, 1))
(conv_attr_prev): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(conv_attr): Conv2d(256, 9, kernel_size=(1, 1), stride=(1, 1))
(conv_centerness_prev): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 64, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(conv_centerness): Conv2d(64, 1, kernel_size=(1, 1), stride=(1, 1))
(scales): ModuleList(
(0): ModuleList(
(0): Scale()
(1): Scale()
(2): Scale()
)
(1): ModuleList(
(0): Scale()
(1): Scale()
(2): Scale()
)
(2): ModuleList(
(0): Scale()
(1): Scale()
(2): Scale()
)
(3): ModuleList(
(0): Scale()
(1): Scale()
(2): Scale()
)
(4): ModuleList(
(0): Scale()
(1): Scale()
(2): Scale()
)
)
(loss_centerness): CrossEntropyLoss(avg_non_ignore=False)
)
)
python tools/test.py configs/fcos3d/fcos3d_r101_caffe_fpn_gn-head_dcn_2x8_1x_nus-mini-mono3d.py work_dirs/fcos3d_r101_caffe_fpn_gn-head_dcn_2x8_1x_nus-mini-mono3d/latest.pth --show --show-dir ./outputs/fcos3d/
结果如下:
可以看到检测到的重叠框非常多,效果很差,分析可知应该是NMS阈值和得分阈值设置过低导致,修改/mmdetection3d/configs/_base_/models/fcos3d.py
中的test_cfg
,将score_thr
设置为0.2:
test_cfg=dict(
use_rotate_nms=True,
nms_across_levels=False,
nms_pre=1000,
nms_thr=0.8,
score_thr=0.2,
min_bbox_size=0,
max_per_img=200))
再次进行测试和可视化,结果如下:
T. Wang, X. Zhu, J. Pang, and D. Lin. Probabilistic and Geometric Depth: Detecting Objects in Perspective. Proceedings of the 5th Conference on Robot Learning, PMLR 164:1475-1485, 2022.
论文
代码
很有意思的是,这篇PGD的作者是FCOS3D原班人马,可以认为是FCOS3D++。FCOS3D是基于Direct Regression的,而PGD则是Geometry-based,是在FCOS3D的基础上,利用提出的head定制模块对深度回归部分进行了改进。
当前的单目3D检测可以简化为实例深度估计问题:不准确的实例深度阻碍了所有其他3D属性预测,无法提高整体检测性能。先前的方法使用额外繁琐的深度估计模型来补充2D检测器的深度信息,或者直接将深度视为3D定位任务的一个维度来简化框架,但仍然使用简单的方法,以回归的方式从孤立的实例或像素中估计深度。我们观察到,除了每个对象本身,其他对象在图像中共存,它们之间的几何关系可能是保证准确估计的有价值的约束。受这些观察的启发,我们提出了概率和几何深度(PGD),该方法联合利用概率深度不确定性和共存对象之间的几何关系,以实现精确的深度估计。具体而言,由于在这种不适定环境中,每个实例的初步深度估计通常是不准确的,因此我们结合了概率表示来捕获估计深度的不确定性。我们首先将深度值划分为一组区间,并通过分布的期望值计算深度,来自分布的top-k置信分数的平均值被视为深度的不确定性。
Oracle使用不同的数据集和指标进行分析,从左到右:KITTI上基于3D IoU的mAP、NuScenes检测分数(NDS)和NuScenes上基于距离的mAP。依次用真值来替换 3D 检测器不同输出结果时最终的检测性能(注意是替换不同 attribute 的 dense prediction map,这样可以将回归目标建模所带来的影响包含在内)。
可以发现,在深度估计的准确率只有当前水平时,其他的回归目标用真值替代并不能带来预期提升,反而有时候甚至会有副作用。而当深度估计准确时,检测性能可以实现质的提升。因此可以推断,纯视觉 3D 检测问题在当前发展阶段几乎可以被归结为一个 instance depth estimation 问题。
因此,PGD一方面建模了深度估计的不确定性,另一方面通过透视几何关系建立这些具有不确定性的检测目标之间的深度传播图,通过全局的信息来增强深度估计的准确度
PGD在FCOS3D整体框架的基础上,主要关注实例深度估计的难题,首先引入概率深度估计模块来建模不确定性,然后从深度传播图中得到几何深度,最后融合二者得到最终的深度预测值
从这一部分开始,本文将围绕着 概率表示的局部深度估计+基于目标几何关系的深度估计 这两部分进行讨论,会出现大量复杂的数学推理和表示。
对于一阶段检测器,直接深度估计一般是沿着回归分支的一个small head,输出密集的深度图: D R ∈ R H × W D_R \in \mathbb{R}^{H \times W} DR∈RH×W。本文在此基础上,考虑到深度值在一定范围内是连续的,将深度区间均匀量化为一组离散值,设置等距间隔,将其视为分类任务,离散化网络的输出为:
D P = ω T softmax ( D P M ) D_P=\omega^T \text { softmax }\left(D_{P M}\right) DP=ωT softmax (DPM)
其中, ω \omega ω为人为设置的间隔点, D P M D_{PM} DPM为深度值离散区间分类输出的feature map(这一块我也不太明白,可能不对)。每个孤立实例的局部深度估计为:
D L = σ ( λ ) D R + ( 1 − σ ( λ ) ) D P D_L=\sigma(\lambda) D_R+(1-\sigma(\lambda)) D_P DL=σ(λ)DR+(1−σ(λ))DP
其中, λ \lambda λ为数据不可知的参数, σ \sigma σ为sigmoid函数。
利用孤立实例的深度预测 D L D_L DL和不确定性估计的深度置信分数,我们可以进一步基于上下文几何关系构建传播图。考虑典型的驾驶场景:可以利用一般约束,即几乎所有物体都在地面上。针对深度估计问题,我们提出了一种几何深度传播机制,考虑了实例之间的相互依赖性。已知相机的内参矩阵:
P = ( f 0 c u − f b x 0 f c v − f b y 0 0 1 − f b z ) P=\left(\begin{array}{cccc} f & 0 & c_u & -f b_x \\ 0 & f & c_v & -f b_y \\ 0 & 0 & 1 & -f b_z \end{array}\right) P=⎝ ⎛f000f0cucv1−fbx−fby−fbz⎠ ⎞
其中各参数含义如下:
给定相机坐标系下某点的3D位置 x 3 D = ( x , y , z , 1 ) T \mathbf{x}^{3 \mathrm{D}}=(x, y, z, 1)^T x3D=(x,y,z,1)T,可以利用相机内参矩阵 P P P,将其投影为图像中的2D位置 x 2 D = ( u ′ , v ′ , 1 ) T \mathbf{x}^{2 \mathbf{D}}=\left(u^{\prime}, v^{\prime}, 1\right)^T x2D=(u′,v′,1)T:
d x 2 D = P x 3 D d \mathbf{x}_{\mathbf{2 D}}=P \mathbf{x}_{3 \mathrm{D}} dx2D=Px3D
为了简化结果,将 v 0 v_0 v0替换为 v + c v v+c_v v+cv,其中 v v v表示目标到地平线的距离(如下图所示,向下为正方向),然后我们得到:
v d = f ( y − b y + c v b z ) v d=f\left(y-b_y+c_v b_z\right) vd=f(y−by+cvbz)
u u u的关系类似。考虑到所有对象都在地面上的约束,对象的底部中心始终共享相同的 y y y(相机坐标中的高度),因此接下来主要考虑 v v v的关系。给定两个物体1和2,它们的中心深度之间的关系为:
d 2 = v 1 v 2 d 1 + f v 2 ( y 2 − y 1 ) ≈ v 1 v 2 d 1 + f 2 v 2 ( h 1 3 D − h 2 3 D ) ≜ d 1 → 2 P d_2=\frac{v_1}{v_2} d_1+\frac{f}{v_2}\left(y_2-y_1\right) \approx \frac{v_1}{v_2} d_1+\frac{f}{2 v_2}\left(h_1^{3 D}-h_2^{3 D}\right) \triangleq d_{1 \rightarrow 2}^P d2=v2v1d1+v2f(y2−y1)≈v2v1d1+2v2f(h13D−h23D)≜d1→2P
对于一幅图像上的n个目标,可以根据上述公式定义他们之间的几何深度信息:
d i G = ∑ j = 1 k s j → i e d j → i P d_i^G=\sum_{j=1}^k s_{j \rightarrow i}^e d_{j \rightarrow i}^P diG=j=1∑ksj→iedj→iP
其中, s j → i e \boldsymbol{s}_{j \rightarrow i}^e sj→ie与目标之间的距离, k k k为选定的与目标 i i i置信度 s j → i e s_{j→i}^e sj→ie 最高的目标集合。值得注意的是, D G D_G DG没有可学习的参数,不参与网络的反向转播过程。
网络的深度估计包含两个方面:局部的深度估计 D L D_L DL以及基于目标之间几何关系的深度估计 D G D_G DG,其中 α ∈ R H × W α∈R^{H×W} α∈RH×W为可学习参数:
D = σ ( α ) ∘ D L + ( 1 − σ ( α ) ) ∘ D G D=\sigma(\alpha) \circ D_L+(1-\sigma(\alpha)) \circ D_G D=σ(α)∘DL+(1−σ(α))∘DG
【MMDetection3D】基于单目(Monocular)的3D目标检测入门实战
官方源码:mmdetection3d
训练、测试及可视化同FCOS3D,在此不再赘述。
PGD整体框架中的backbone和neck与FCOS3D类似,但Head有很大改动,这里给出mmdetection3d中关于PGD检测头的配置信息:
(bbox_head): PGDHead(
(loss_cls): FocalLoss()
(loss_bbox): SmoothL1Loss()
(loss_dir): CrossEntropyLoss(avg_non_ignore=False)
(loss_attr): CrossEntropyLoss(avg_non_ignore=False)
(cls_convs): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
(1): ConvModule(
(conv): ModulatedDeformConv2dPack(
(conv_offset): Conv2d(256, 27, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
)
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(reg_convs): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
(1): ConvModule(
(conv): ModulatedDeformConv2dPack(
(conv_offset): Conv2d(256, 27, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
)
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(conv_cls_prev): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(conv_cls): Conv2d(256, 10, kernel_size=(1, 1), stride=(1, 1))
(conv_reg_prevs): ModuleList(
(0): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(1): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(2): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(3): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(4): None
(5): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
)
(conv_regs): ModuleList(
(0): Conv2d(256, 2, kernel_size=(1, 1), stride=(1, 1))
(1): Conv2d(256, 1, kernel_size=(1, 1), stride=(1, 1))
(2): Conv2d(256, 3, kernel_size=(1, 1), stride=(1, 1))
(3): Conv2d(256, 1, kernel_size=(1, 1), stride=(1, 1))
(4): Conv2d(256, 2, kernel_size=(1, 1), stride=(1, 1))
(5): Conv2d(256, 4, kernel_size=(1, 1), stride=(1, 1))
)
(conv_dir_cls_prev): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(conv_dir_cls): Conv2d(256, 2, kernel_size=(1, 1), stride=(1, 1))
(conv_attr_prev): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(conv_attr): Conv2d(256, 9, kernel_size=(1, 1), stride=(1, 1))
(conv_depth_cls_prev): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(conv_depth_cls): Conv2d(256, 6, kernel_size=(1, 1), stride=(1, 1))
(conv_centerness_prev): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 64, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
)
)
(conv_centerness): Conv2d(64, 1, kernel_size=(1, 1), stride=(1, 1))
(scales): ModuleList(
(0): ModuleList(
(0): Scale()
(1): Scale()
(2): Scale()
(3): Scale()
)
(1): ModuleList(
(0): Scale()
(1): Scale()
(2): Scale()
(3): Scale()
)
(2): ModuleList(
(0): Scale()
(1): Scale()
(2): Scale()
(3): Scale()
)
(3): ModuleList(
(0): Scale()
(1): Scale()
(2): Scale()
(3): Scale()
)
(4): ModuleList(
(0): Scale()
(1): Scale()
(2): Scale()
(3): Scale()
)
)
(loss_centerness): CrossEntropyLoss(avg_non_ignore=False)
(loss_depth): SmoothL1Loss()
(loss_bbox2d): SmoothL1Loss()
(loss_consistency): GIoULoss()
)
“3Dfy” A General 2D Detector: 纯视觉 3D 检测再思考
27. FCOS3D - 单阶段 3D 目标检测 (anchor-free)
单目3D目标检测论文汇总(一)
自动驾驶 2D 单目\双目\多目视觉方法 一(Pseudo-LiDAR,Mono3D,FCOS3D,PSMNet)
CoRL 2021单目三维目标检测算法PGD