ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

【自动驾驶】Sparse4D 时序输入和 Feature Queue 详解

【自动驾驶】Sparse4D 时序输入和 Feature Queue 详解

Sparse4D 时序输入和 Feature Queue 详解

Sparse V3论文:https://arxiv.org/pdf/2311.11722
源码地址:https://github.com/linxuewu/Sparse4D

概述

Sparse4D 使用时序融合机制来处理多帧数据,通过InstanceBank类管理时序实例和 feature queue。本文将详细解释时序输入和 feature queue 的结构。

1. 时序输入结构

1.1 输入组件

Sparse4D 的输入主要包含三个部分:

  1. 当前帧的多视角图像(img)

    • Shape:[batch_size, num_cams, C, H, W]
    • 例如:[1, 6, 3, 256, 704](batch=1, 6个相机, RGB, 256x704)
  2. 新初始化的实例(instance_feature,anchor)

    • instance_feature:[batch_size, num_anchor, embed_dims]
    • anchor:[batch_size, num_anchor, anchor_dims](通常是10维: x,y,z,w,l,h,yaw,vx,vy,vz)
    • 例如:[1, 900, 256]和[1, 900, 10]
  3. 从前一帧传播的实例(temp_instance_feature,temp_anchor)

    • temp_instance_feature:[batch_size, num_temp_instances, embed_dims]
    • temp_anchor:[batch_size, num_temp_instances, anchor_dims]
    • 例如:[1, 600, 256]和[1, 600, 10]

1.2 时序信息

  • timestamp: 当前帧的时间戳
  • time_interval: 与前一帧的时间间隔
  • T_global: 全局变换矩阵(用于坐标变换)

2. Feature Queue 结构

2.1 InstanceBank 中的缓存

InstanceBank类维护以下缓存变量(在instance_bank.py中定义):

# 缓存的时序实例特征self.cached_feature:[batch_size,num_temp_instances,embed_dims]# 缓存的时序 anchorself.cached_anchor:[batch_size,num_temp_instances,anchor_dims]# 缓存的置信度self.confidence:[batch_size,num_temp_instances]# 时间掩码(用于过滤过期实例)self.mask:[batch_size,num_temp_instances]# 元数据(包含时间戳、变换矩阵等)self.metas:dict

2.2 Feature Queue 的工作流程

步骤 1: 获取实例 (get方法)
defget(self,batch_size,metas=None,dn_metas=None):# 1. 初始化当前帧的实例instance_feature=[batch_size,num_anchor,embed_dims]anchor=[batch_size,num_anchor,anchor_dims]# 2. 如果有缓存的时序实例ifself.cached_anchorisnotNone:# 计算时间间隔time_interval=metas["timestamp"]-self.metas["timestamp"]# 3. 坐标变换:将前一帧的 anchor 变换到当前帧坐标系T_temp2cur=T_global_inv @ T_global_prev self.cached_anchor=anchor_projection(self.cached_anchor,T_temp2cur,time_intervals=[-time_interval])# 4. 时间掩码:过滤掉时间间隔过大的实例self.mask=|time_interval|<=max_time_interval# 5. 返回当前实例和时序实例return(instance_feature,# 当前帧实例特征anchor,# 当前帧 anchorself.cached_feature,# 时序实例特征 (可能为 None)self.cached_anchor,# 时序 anchor (可能为 None)time_interval# 时间间隔)
步骤 2: 更新实例 (update方法)

在单帧解码器之后,更新实例:

defupdate(self,instance_feature,anchor,confidence):# 1. 从当前帧中选择 top-N 个高置信度实例N=num_anchor-num_temp_instances# 例如: 900 - 600 = 300_,(selected_feature,selected_anchor)=topk(confidence,N,instance_feature,anchor)# 2. 将选中的实例与缓存的时序实例拼接selected_feature=concat([self.cached_feature,selected_feature],dim=1)selected_anchor=concat([self.cached_anchor,selected_anchor],dim=1)# 3. 根据时间掩码决定使用时序实例还是新实例instance_feature=where(self.mask,selected_feature,instance_feature)anchor=where(self.mask,selected_anchor,anchor)returninstance_feature,anchor
步骤 3: 缓存实例 (cache方法)

在解码完成后,缓存当前帧的实例用于下一帧:

defcache(self,instance_feature,anchor,confidence,metas=None):ifnum_temp_instances<=0:return# 1. 计算置信度confidence=confidence.max(dim=-1).values.sigmoid()# 2. 应用置信度衰减(对已缓存的实例)ifself.confidenceisnotNone:confidence[:,:num_temp_instances]=max(self.confidence*confidence_decay,# 例如: 0.6confidence[:,:num_temp_instances])# 3. 选择 top-K 个实例进行缓存self.confidence,(self.cached_feature,self.cached_anchor)=topk(confidence,num_temp_instances,instance_feature,anchor)# 4. 保存元数据self.metas=metas

3. 时序融合机制

3.1 Temporal GNN 操作

在 decoder 中,使用temp_gnn操作进行时序融合:

# 在 sparse4d_head.py 的 forward 方法中elifop=="temp_gnn":instance_feature=self.graph_model(i,instance_feature,# query: 当前帧实例temp_instance_feature,# key: 时序实例temp_instance_feature,# value: 时序实例query_pos=anchor_embed,# 当前帧 anchor 编码key_pos=temp_anchor_embed,# 时序 anchor 编码attn_mask=attn_maskiftemp_instance_featureisNoneelseNone,)

这是一个 Multi-Head Attention 操作,让当前帧的实例关注时序实例。

3.2 坐标变换

时序实例的 anchor 需要从上一帧坐标系变换到当前帧坐标系:

# 计算变换矩阵T_temp2cur=T_global_inv @ T_global_prev# 投影 anchor(考虑时间间隔和运动)cached_anchor=anchor_projection(cached_anchor,[T_temp2cur],time_intervals=[-time_interval])

4. 配置参数

在配置文件中(sparse4dv3_temporal_r50_1x8_bs6_256x704.py):

instance_bank=dict(type="InstanceBank",num_anchor=900,# 总实例数embed_dims=256,# 特征维度anchor="nuscenes_kmeans900.npy",# anchor 初始化文件anchor_handler=dict(type="SparseBox3DKeyPointsGenerator"),num_temp_instances=600,# 时序实例数(feature queue 大小)confidence_decay=0.6,# 置信度衰减系数feat_grad=False,# 是否对特征求梯度max_time_interval=2.0,# 最大时间间隔(秒))

5. 数据流示例

Frame t-1: └─> cache: [1, 600, 256] features + [1, 600, 10] anchors └─> confidence: [1, 600] Frame t: ├─> 当前帧图像: [1, 6, 3, 256, 704] ├─> 新实例: [1, 900, 256] features + [1, 900, 10] anchors ├─> 时序实例: [1, 600, 256] features + [1, 600, 10] anchors (从 t-1 传播) │ ├─> 坐标变换: 将时序 anchor 变换到当前帧坐标系 ├─> 时间掩码: 过滤过期实例 │ ├─> Temporal GNN: 当前实例 ← 关注 → 时序实例 ├─> 解码器处理... │ └─> 更新 cache: 选择 top-600 个实例缓存到下一帧

6. 关键特性

  1. 自适应时间掩码: 根据时间间隔过滤过期实例
  2. 置信度衰减: 对缓存的实例应用置信度衰减(默认 0.6)
  3. 坐标变换: 自动将时序实例变换到当前帧坐标系
  4. Top-K 选择: 只保留高置信度的实例用于时序融合
  5. 可配置大小:num_temp_instances控制 feature queue 的大小

7. 代码位置

  • InstanceBank类:projects/mmdet3d_plugin/models/instance_bank.py
  • Sparse4DHead类:projects/mmdet3d_plugin/models/sparse4d_head.py
  • 配置文件:projects/configs/sparse4dv3_temporal_r50_1x8_bs6_256x704.py
  • Tutorial:tutorial/tutorial.ipynb
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进