⌈ 传知代码 ⌋ 使用稀疏查询进行3D目标检测

173 阅读5分钟

前情提要

本文是传知代码平台中的相关前沿知识与技术的分享~

接下来我们即将进入一个全新的空间,对技术有一个全新的视角~

本文所涉及所有资源均在传知代码平台可获取

以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦!!!

以下内容干货满满,跟上步伐吧~


💡本章重点

  • 使用稀疏查询进行3D目标检测

🍞一. 概述

在这里插入图片描述 SparseBEV是一个基于查询的单阶段检测器,具有L个解码器层。SparseBEV首先使用图像主干和FPN结构逐帧处理输入的多摄像机视频。之后,在BEV空间中初始化一组稀疏支柱查询,并通过自适应自注意力进行聚合。这些查询通过自适应时空采样和自适应混合与图像特征交互,以进行3D目标检测。


🍞二. 方法

尺度自适应自我注意力机制

基于密集BEV的方法通常使用BEV编码器来对多尺度BEV特征进行编码,然而,由于SparseBEV没有明确的构建BEV特征,如何在BEV空间中聚合多尺度特征仍然是一个挑战。

在这项工作中,SparseBEV认为自注意可以发挥BEV编码器的作用,因为查询是在BEV空间中定义的。因此,SparseBEV提出了尺度自适应自注意(SASA),它在查询的指导下学习适当的感受域。

在这里插入图片描述  注意力机制不仅考虑查询特征之间的相似性,还考虑它们之间的距离,公式如下:

在这里插入图片描述 自适应时空采样

对于每一帧,SparseBEV使用线性层从查询特征自适应地生成一组采样偏移量,这些偏移被转换为基于查询支柱的3D采样点。

在这里插入图片描述 与BEVFormer的可变形注意力相比,SparseBEV的采样点对查询柱和查询特征都具有自适应性,从而更好地覆盖不同大小的对象。此外,这些点不限于查询,因为SparseBEV不限制采样偏移的范围。

接下来,SparseBEV根据运动扭曲采样点来执行时间对齐。在自动驾驶中,有两种运动,一种是自我运动,一种是对象运动。自车运动描述汽车在环境中行驶时从自身角度的运动,而对象运动是指环境中其他物体在自动驾驶汽车周围移动时的运动。

处理对象运动

在自动驾驶中,瞬时速度可以等于短时间窗口内的平均速度,因此,SparseBEV使用查询中的速度矢量,自适应地将采样点扭曲到以前的时间戳。

在这里插入图片描述 处理自车运动

接下来,我们SparseBEV数据集提供的自我姿态对采样点进行扭曲。首先将点变换到全局坐标系,然后变换到帧t的局部坐标系。

在这里插入图片描述


🍞三.演示效果

在这里插入图片描述 在这里插入图片描述


🍞四.核心逻辑

前向过程

    def forward(self, mlvl_feats,img_metas):
        # 类似于DAB-DETR,其中查询被显式表示为最终的结果,所以可以直接进行细化处理,采用同样的操作,所以属于静态
        query_bbox = self.init_query_bbox.weight.clone()  # [Q, 10] 
        #query_bbox[..., :3] = query_bbox[..., :3].sigmoid()
        
        # query denoising
        B = mlvl_feats[0].shape[0] 
        # BEV中都是在头部就使用了prepare_dn的形式,头部就完成了所有的事情,包括预测的结果,query其中是包含噪声的情况
        query_bbox, query_feat, attn_mask, mask_dict = self.prepare_for_dn_input(B, query_bbox, self.label_enc, img_metas)
        
        cls_scores, bbox_preds = self.transformer(
                query_bbox,
                query_feat,
                mlvl_feats,
                attn_mask=attn_mask,
                img_metas=img_metas,
            )
        # 将边界框重新转换为现实坐标中
        bbox_preds[..., 0] = bbox_preds[..., 0] * (self.pc_range[3] - self.pc_range[0]) + self.pc_range[0]
        bbox_preds[..., 1] = bbox_preds[..., 1] * (self.pc_range[4] - self.pc_range[1]) + self.pc_range[1]
        bbox_preds[..., 2] = bbox_preds[..., 2] * (self.pc_range[5] - self.pc_range[2]) + self.pc_range[2]

        bbox_preds = torch.cat([
            bbox_preds[..., 0:2],
            bbox_preds[..., 3:5],
            bbox_preds[..., 2:3],
            bbox_preds[..., 5:10],
        ], dim=-1)  # [cx, cy, w, l, cz, h, sin, cos, vx, vy]
        # 如果采用了denoise的形式,这是一步重构策略比较重要,
        
        if mask_dict is not None and mask_dict['pad_size'] > 0:  # if using query denoising
            # 此时获得的是denoise后的结果
            output_known_cls_scores = cls_scores[:, :, :mask_dict['pad_size'], :]
            output_known_bbox_preds = bbox_preds[:, :, :mask_dict['pad_size'], :]
            # 此时是需要进行match的情况
            output_cls_scores = cls_scores[:, :, mask_dict['pad_size']:, :]
            output_bbox_preds = bbox_preds[:, :, mask_dict['pad_size']:, :]
            # 此时是输出的结果,但输出的结果不一定需要完全正确,真值是没有output的形式
            mask_dict['output_known_lbs_bboxes'] = (output_known_cls_scores, output_known_bbox_preds)
            # 将其进行修改,其中all_cls_scores只保存match的query的形式
            outs = {
                'all_cls_scores': output_cls_scores,
                'all_bbox_preds': output_bbox_preds,
                'enc_cls_scores': None,
                'enc_bbox_preds': None, 
                'dn_mask_dict': mask_dict,
            }
        else:
            outs = {
                'all_cls_scores': cls_scores,
                'all_bbox_preds': bbox_preds,
                'enc_cls_scores': None,
                'enc_bbox_preds': None, 
            }

        return outs

部署方式

# Install PyTorch 2.0 + CUDA 11.8
conda create -n sparsebev python=3.8
conda activate sparsebev
conda install pytorch==2.0.0 torchvision==0.15.0 pytorch-cuda=11.8 -c pytorch -c nvidia
# PyTorch 1.10.2 + CUDA 10.2 for older GPUs
conda create -n sparsebev python=3.8
conda activate sparsebev
conda install pytorch==1.10.2 torchvision==0.11.3 cudatoolkit=10.2 -c pytorch

# Install other dependencies:
pip install openmim
mim install mmcv-full==1.6.0
mim install mmdet==2.28.2
mim install mmsegmentation==0.30.0
mim install mmdet3d==1.0.0rc6
pip install setuptools==59.5.0
pip install numpy==1.23.5


# Install turbojpeg and pillow-simd to speed up data loading (optional but important):

sudo apt-get update
sudo apt-get install -y libturbojpeg
pip install pyturbojpeg
pip uninstall pillow
pip install pillow-simd==9.0.0.post1
pip install numpy==1.23.5
pip install fvcore
pip install einops


# Compile CUDA extensions:


cd models/csrc
python setup.py build_ext --inplace

🫓总结

综上,我们基本了解了“一项全新的技术啦” :lollipop: ~~

恭喜你的内功又双叒叕得到了提高!!!

感谢你们的阅读:satisfied:

后续还会继续更新:heartbeat:,欢迎持续关注:pushpin:哟~

:dizzy:如果有错误❌,欢迎指正呀:dizzy:

:sparkles:如果觉得收获满满,可以点点赞👍支持一下哟~:sparkles:

【传知科技 -- 了解更多新知识】