当前位置: 首页 > news >正文

BEVDet-4D 代码详细解析

一、介绍

BEVDet4D 由黄俊杰等人发表于22年3月首次对BEVDet加入时序特征。它通过缓存上一帧的BEV特征,经过空间对齐操作拼接操作,将上一帧和当前帧中对应特征进行融合。从而极大的减小了速度预测误差。

图1:BEVDet4D网络架构图

二、改进点

1. 网络结构改进: 在时间融合前,增加额外的BEV编码器(两个残差单元),用于强化稀疏特征,便于时序融合。

2. 时序融合:Align(对齐) + Concatenate, 融合后能正确反映它车运动特征。

三、时序融合分析

方案1:直接Concatenate

图2:无对齐的时序融合

如图2,没有空间特征对齐,在自车坐标系下,自车(红)不动,静止物体(绿)运动,运动物体(蓝)运动更多。

则静止物体ego坐标系下的两帧位移差公式如下:

上公式可以看到,如果直接拼接两帧特征,则后续的学习目标只关联自车运动{T} \begin{matrix} e(T-1) \\ e(T) \end{matrix}

方案2:Align + Concatenate

Align空间对齐: 为了避免方案1情况,把上一帧的BEV特征乘以{T} \begin{matrix} e(T-1) \\ e(T) \end{matrix}的逆来消除自车(ego)运动实现空间对齐,再concat当前帧BEV特征融合。

如下图,对齐后静止车辆不动,运动车辆运动。

图3:空间对齐的时序融合

四、代码详解

空间对齐代码在shift_featue()中。

#mmdet3d/models/detectors/bevdet.py
def shift_feature(self, input, sensor2keyegos, bda, bda_adj=None):#生成变换网格grid = self.gen_grid(input, sensor2keyegos, bda, bda_adj=bda_adj)#执行特征变换output = F.grid_sample(input, grid.to(input.dtype), align_corners=True)return output #[1, 80, 128, 128]

1、建立网格

#mmdet3d/models/detectors/bevdet.py   
def gen_grid(self, input, sensor2keyegos, bda, bda_adj=None):n, c, h, w = input.shape_, v, _, _ = sensor2keyegos[0].shape #传感器到关键帧的变换矩阵#----------------------------------#-1. 基础网格生成 (n,h,w,3,1):(n,128,128,3,1)#----------------------------------if self.grid is None: #检查是否有缓存网格# generate gridxs = torch.linspace(0, w - 1, w, dtype=input.dtype,device=input.device).view(1, w).expand(h, w) # (0,1,...w-1)^ hys = torch.linspace(0, h - 1, h, dtype=input.dtype,device=input.device).view(h, 1).expand(h, w) #(0,1,...h-1)^ wgrid = torch.stack((xs, ys, torch.ones_like(xs)), -1) #堆叠表示:网格位置(h,w,3)->[x,y,1]self.grid = grid #(128,128,3)else:grid = self.gridgrid = grid.view(1, h, w, 3).expand(n, h, w, 3).view(n, h, w, 3, 1) #(n,128,128,3,1)

2. 提取基础变换矩阵

c02l0 = sensor2keyegos[0][:, 0:1, :, :]  # 当前帧到关键帧ego坐标系的变换矩阵
c12l0 = sensor2keyegos[1][:, 0:1, :, :]  # 前一帧到关键帧ego坐标系的变换矩阵

3. BEV增强变换矩阵

图6:转换矩阵分别应用BEV增强
        # 处理当前帧的BEV数据增强(bda)bda_ = torch.zeros((n, 1, 4, 4), dtype=grid.dtype).to(grid) #(n, 1, 4, 4)bda = bda.unsqueeze(1) #[n,3,3] ->[n,1,3,3]bda_[:, :, :4, :4] = bda #将3x3bda旋转、缩放矩阵放入左上角bda_[:, :, 3, 3] = 1  #设置齐次坐标缩放因子为1(仿射变换)c02l0 = bda_.matmul(c02l0) #当前帧转换矩阵应用bda增强# 处理相邻帧的BEV数据增强(bda_adj)if bda_adj is not None:bda_ = torch.zeros((n, 1, 4, 4), dtype=grid.dtype).to(grid)bda_[:, :, :3, :3] = bda_adj.unsqueeze(1)bda_[:, :, 3, 3] = 1c12l0 = bda_.matmul(c12l0) #前一帧转换矩阵应用bda增强

4. T->T-1帧间变换矩阵

        以关键帧ego坐标系为中介,计算当前帧到前一帧的变换矩阵。

        # 核心公式: l02l1 = c02l0 * inv(c12l0)l02l1 = c02l0.matmul(torch.inverse(c12l0))[:, 0, :, :].view(n, 1, 1, 4, 4)# 通过关键帧坐标系做中介,计算当前帧到相邻帧的变换矩阵# 当前帧传感器坐标系->关键帧自车坐标系->关键帧车体坐标系->前一帧传感器坐标系 '''c02l0 * inv(c12l0)= c02l0 * inv(l12l0 * c12l1)= c02l0 * inv(c12l1) * inv(l12l0)= l02l1 # c02l0==c12l1'''l02l1 = l02l1[:, :, :,[True, True, False, True], :][:, :, :, :,[True, True, False, True]]

5.  BEV 坐标系下的帧间变换(tf)

        #----------------------------------#-3. 特征图到BEV空间变换#----------------------------------#grid_interval:[0.8, 0.8, 8]  grid_lower_bound:[-51.2, -51.2, -5]feat2bev = torch.zeros((3, 3), dtype=grid.dtype).to(grid)feat2bev[0, 0] = self.img_view_transformer.grid_interval[0] #x方向缩放因子:0.8feat2bev[1, 1] = self.img_view_transformer.grid_interval[1] #y方向缩放因子:0.8feat2bev[0, 2] = self.img_view_transformer.grid_lower_bound[0] #x方向偏移:51.2feat2bev[1, 2] = self.img_view_transformer.grid_lower_bound[1] #y方向偏移:51.2feat2bev[2, 2] = 1 #齐次坐标feat2bev = feat2bev.view(1, 3, 3) #(1,3,3)# 组合变换矩阵tf = torch.inverse(feat2bev).matmul(l02l1).matmul(feat2bev) #(n,1,1,4,4)#  BEV空间坐标到点特征图像像素变换 * 当前帧到相邻帧的自车坐标系变换矩阵 * 点从特征图像像素坐标到BEV空间坐标

6. 将变换应用到grid 并归一化

        grid = tf.matmul(grid) #变换矩阵应用到基础网格上 (n,h,w,3,1)normalize_factor = torch.tensor([w - 1.0, h - 1.0],dtype=input.dtype,device=input.device) #[127,127]grid = grid[:, :, :, :2, 0] / normalize_factor.view(1, 1, 1,2) * 2.0 - 1.0#只保留x,y坐标(忽略z轴),移除最后一维(n,h,w,2) /[127,127] * 2 -1 # 归一化到[-1,1]:(0,0)左上角,(w-1,h-1)右下角 变换后(-1,-1)左上角, (1,1)右下角

五、性能:

BEVDet4D

http://www.dtcms.com/a/294270.html

相关文章:

  • 《汇编语言:基于X86处理器》第9章 复习题和练习
  • Linux内存映射原理
  • 基于MCP架构的LLM-Agent融合—构建AI Agent的技术体系与落地实践
  • day060-zabbix监控各种客户端
  • 力扣MySQL(1)
  • python 字符串常用处理函数
  • Zookeeper学习专栏(七):集群监控与管理
  • 解决代码生成过程虚拟总线信号无法直接传递给自定义总线信号问题的方法
  • Python curl_cffi库详解:从入门到精通
  • Redis能完全保证数据不丢失吗?
  • 基于OpenOCD 的 STM32CubeIDE 开发烧录调试环境搭建 DAPLINK/STLINK
  • 《计算机网络》实验报告六 电子邮件
  • 【轨物方案】分布式光伏电站运维升级智能化系列:老电站的数智化重生
  • Zabbix 企业级分布式监控
  • Axios 响应拦截器
  • dfaews
  • vue3笔记(2)自用
  • 设备虚拟化技术
  • 筛选数据-group_concat
  • Go语言实现对象存储——下载任意图片,保存到阿里云存储,并将URL保存到数据库。
  • 【数据库】国产数据库的新机遇:电科金仓以融合技术同步全球竞争
  • Pycaita二次开发基础代码解析:图层管理、基准控制与特征解析深度剖析
  • lwIP学习记录5——裸机lwIP工程学习后的总结
  • 【C++】类和对象(中)构造函数、析构函数
  • 海信IP501H-IP502h_GK6323处理器-原机安卓9专用-优盘卡刷固件包
  • ZLMediaKit流媒体服务器WebRTC页面显示:使用docker部署
  • Android多开实现方案深度分析
  • Android13重置锁屏(2)
  • 论文略读:Knowledge is a Region in Weight Space for Finetuned Language Models
  • springboot集成LangChain4j