bev-project/BEV_FEATURE_SCALE_ANALYSIS.md

10 KiB
Raw Blame History

BEV特征尺度详解 - Phase 4A Stage 1配置

📋 目录

  1. BEV特征生成流程
  2. 多尺度处理细节
  3. 任务头输入分析
  4. 关键问题解答

🔄 BEV特征生成流程

阶段1: 多模态编码 → 单尺度BEV

Camera分支 (多尺度图像 → 单尺度BEV)

输入图像 (6×3×256×704)
    ↓
[SwinTransformer Backbone]
├─ out_indices: [1, 2, 3]  # 输出3个尺度
├─ Stage 1: (B, 192, H/4, W/4)
├─ Stage 2: (B, 384, H/8, W/8)
└─ Stage 3: (B, 768, H/16, W/16)
    ↓
[GeneralizedLSSFPN Neck]
├─ 将3个尺度融合到统一通道
└─ 输出: 3个尺度×256通道
    ↓
[DepthLSSTransform]
├─ 3D几何变换 (Lift-Splat-Shoot)
├─ xbound: [-54.0, 54.0, 0.2]  # Stage 1: 0.2m分辨率
├─ ybound: [-54.0, 54.0, 0.2]
├─ downsample: 2
└─ 输出: **单个BEV特征** (B, 80, 360, 360)
         ^^^^^^^^^^^^^^^^
         关键多尺度图像特征被投影到单一BEV平面

LiDAR分支 (3D点云 → 单尺度BEV)

点云输入
    ↓
[Voxelization]
└─ Voxel Size: [0.075, 0.075, 0.2]
    ↓
[SparseEncoder Backbone]
├─ 多尺度稀疏卷积
├─ encoder_channels: [[16,16,32], [32,32,64], [64,64,128], [128,128]]
└─ 输出: **单个BEV特征** (B, 256, 360, 360)
         ^^^^^^^^^^^^^^^^
         关键3D稀疏特征被压缩到2D BEV

融合阶段 (多模态 → 统一BEV)

Camera BEV (B, 80, 360, 360)  ┐
                              ├─→ [ConvFuser] → (B, 256, 360, 360)
LiDAR BEV (B, 256, 360, 360)  ┘                  ^^^^^^^^^^^^^^
                                                  统一的单尺度BEV特征

重要结论1

从骨干网络多尺度形成的BEV是【单个尺度】
虽然Camera和LiDAR编码器内部使用多尺度特征提取但最终输出的BEV特征是统一的单一尺度 (360×360 @ 0.2m分辨率)。


阶段2: Decoder处理 → 多尺度再生成

SECOND Backbone (单尺度输入 → 多尺度输出)

配置:
  in_channels: 256          # 输入单尺度BEV
  out_channels: [128, 256]  # 输出2个尺度
  layer_nums: [5, 5]
  layer_strides: [1, 2]     # 第1层stride=1第2层stride=2
融合BEV (B, 256, 360, 360)
    ↓
[Block 1: stride=1]
├─ 5层卷积
└─ 输出: (B, 128, 360, 360)  ← Scale 1 (原分辨率)
    ↓
[Block 2: stride=2]
├─ 5层卷积 + 下采样
└─ 输出: (B, 256, 180, 180)  ← Scale 2 (1/2分辨率)

SECONDFPN Neck (多尺度融合 → 单尺度输出)

配置:
  in_channels: [128, 256]     # 输入2个尺度
  out_channels: [256, 256]    # 每个尺度输出256通道
  upsample_strides: [1, 2]    # Scale1不变Scale2上采样2倍
Scale 1: (B, 128, 360, 360) → Conv → (B, 256, 360, 360)
                                          ↓
Scale 2: (B, 256, 180, 180) → Deconv(×2) → (B, 256, 360, 360)
                                          ↓
                                      Concat
                                          ↓
                            最终输出: (B, 512, 360, 360)
                                      ^^^^^^^^^^^^^^^^^^^^
                                      单尺度BEV特征 (通道拼接)

重要结论2

Decoder输出【单个尺度】的BEV特征
SECONDFPN将多尺度特征上采样到统一分辨率后concat输出512通道的单尺度BEV。


🎯 任务头输入分析

3D检测头 (TransFusionHead)

# bevfusion.py L346
pred_dict = head(x, metas)  # x是单个tensor

# 配置
heads:
  object:
    type: TransFusionHead
    in_channels: 512  # ← 接收512通道的单尺度BEV

输入: (B, 512, 360, 360) - 单个尺度的BEV特征

处理流程:

(B, 512, 360, 360)
    ↓
[Heatmap Branch]
└─ 生成检测热图 (B, num_classes, H, W)
    ↓
[Transformer Decoder]
├─ Query-based检测
└─ 精细化Bbox预测

BEV分割头 (EnhancedBEVSegmentationHead)

# bevfusion.py L349
losses = head(x, gt_masks_bev)  # x是单个tensor

# 配置
heads:
  map:
    type: EnhancedBEVSegmentationHead
    in_channels: 512  # ← 接收512通道的单尺度BEV
    decoder_channels: [256, 256, 128, 128]  # 内部4层decoder
    grid_transform:
      input_scope: [[-54.0, 54.0, 0.75], [-54.0, 54.0, 0.75]]  # 360×360
      output_scope: [[-50, 50, 0.167], [-50, 50, 0.167]]       # 600×600

输入: (B, 512, 360, 360) - 单个尺度的BEV特征

处理流程:

(B, 512, 360, 360)
    ↓
[Grid Transform]  # 双线性插值
└─ 从360×360上采样到384×384 (padding到540×540范围)
    ↓
[ASPP多尺度特征提取]
├─ 1×1卷积
├─ 3×3空洞卷积 (rate=6)
├─ 3×3空洞卷积 (rate=12)
└─ 3×3空洞卷积 (rate=18)
    ↓
[注意力机制]
├─ Channel Attention (SE)
└─ Spatial Attention
    ↓
[4层Decoder上采样]
├─ Layer 1: 256通道 → 上采样
├─ Layer 2: 256通道 → 上采样
├─ Layer 3: 128通道 → 上采样
└─ Layer 4: 128通道 → 上采样到600×600
    ↓
[Per-class分类器]
└─ 输出: (B, 6, 600, 600)  # 6个类别的分割结果

重要结论3

检测头和分割头都接收【单个尺度】的BEV特征
两个任务头共享同一个512通道的BEV特征 (360×360),然后各自进行任务特定的处理。


关键问题解答

Q1: 从骨干多尺度形成的BEV是一个尺度还是多个

答案:单个尺度 (360×360)

详细解释

  1. Camera编码器内部使用多尺度特征 (SwinTransformer的3个输出)
  2. LiDAR编码器内部使用多尺度稀疏卷积
  3. 最终投影到BEV空间时,都被统一到单一分辨率:
    • Camera: 通过DepthLSSTransform投影 → 360×360 @ 0.2m
    • LiDAR: 通过Voxelize+压缩 → 360×360 @ 0.2m
  4. 融合后仍是单尺度256通道 × 360×360

原因

  • BEV空间的物理分辨率是统一的 (xbound/ybound定义)
  • 多模态融合需要空间对齐,必须是同一尺度

Q2: 3D检测头和分割头的输入是单个BEV尺寸还是多个

答案:单个尺寸 (512×360×360)

详细解释

  1. 输入统一两个头都接收decoder输出的同一个tensor

    x = self.decoder["neck"](x)  # (B, 512, 360, 360)
    
    # 检测头
    pred_dict = self.heads["object"](x, metas)
    
    # 分割头
    losses = self.heads["map"](x, gt_masks_bev)
    
  2. 内部处理不同

    • 检测头保持360×360在这个尺度上做heatmap和transformer
    • 分割头上采样到600×600 (通过grid_transform)
  3. 为什么不直接输入多尺度?

    • 架构设计简洁统一的BEV特征更易于多任务学习
    • 计算效率:避免多尺度特征的重复计算
    • 特征共享:两个任务共享前面提取的高层语义

📐 尺度变化全流程总结

阶段              | 特征尺度数 | 具体尺寸                  | 说明
------------------|-----------|--------------------------|-------------------
Camera Backbone   | 3个尺度   | H/4, H/8, H/16          | 多尺度图像特征
LiDAR Backbone    | 1个尺度   | 1440×1440×41 (3D)       | 稀疏体素特征
BEV投影           | 1个尺度   | 360×360 @ 0.2m          | ★统一到BEV平面
Fuser融合         | 1个尺度   | 256×360×360             | ★多模态统一
Decoder Backbone  | 2个尺度   | 360×360, 180×180        | 短暂的多尺度
Decoder Neck      | 1个尺度   | 512×360×360             | ★上采样+concat
检测头输入        | 1个尺度   | 512×360×360             | ★共享BEV特征
分割头输入        | 1个尺度   | 512×360×360             | ★共享BEV特征
分割头输出        | 1个尺度   | 6×600×600               | 上采样到GT分辨率

核心要点

  1. BEV空间是单尺度的由xbound/ybound统一定义
  2. 多尺度只存在于Decoder内部SECOND backbone输出2个尺度但SECONDFPN立即融合回单尺度
  3. 任务头共享单一BEV特征都是512×360×360
  4. 分割头内部有多尺度decoder4层逐步上采样到600×600

🎯 Phase 4A配置验证

当前训练配置摘要

# Camera BEV生成
vtransform:
  xbound: [-54.0, 54.0, 0.2]  # 360×360
  ybound: [-54.0, 54.0, 0.2]
  downsample: 2

# Decoder
decoder:
  backbone:
    out_channels: [128, 256]   # 2个尺度
  neck:
    in_channels: [128, 256]    # 输入2个尺度
    out_channels: [256, 256]   # 输出拼接→512

# 任务头
heads:
  object:
    in_channels: 512           # 单尺度输入
  map:
    in_channels: 512           # 单尺度输入
    grid_transform:
      output_scope: [[-50, 50, 0.167], [-50, 50, 0.167]]  # 600×600

特征尺寸验证

# 从训练日志验证
Epoch [1][10700/15448]
├─ memory: 18893 MB
├─ loss/map/...: 正常训练 
└─ loss/object/...: 正常训练 

# 说明:
# 1. 两个任务头都正常工作 → 输入尺寸正确
# 2. 显存占用18.9GB → 符合单尺度BEV特征的预期
# 3. 360×360的BEV特征足够支持600×600的分割输出

📚 参考代码位置

组件 文件路径 关键代码行
BEVFusion主流程 mmdet3d/models/fusion_models/bevfusion.py L332-340 (fusion+decoder)
SECOND Backbone mmdet3d/models/backbones/second.py L84-97 (输出多尺度)
SECONDFPN Neck mmdet3d/models/necks/second.py L83-99 (concat成单尺度)
检测头forward mmdet3d/models/fusion_models/bevfusion.py L346
分割头forward mmdet3d/models/fusion_models/bevfusion.py L349
分割头实现 mmdet3d/models/heads/segm/enhanced.py L192-246

🔬 实验建议

如果未来想要尝试多尺度BEV方案可以考虑

  1. 方案A多尺度BEV生成

    • 在DepthLSSTransform阶段生成多个分辨率的BEV (如180×180, 360×360)
    • 但需要修改融合逻辑,增加显存和计算量
  2. 方案B保持当前单尺度设计

    • 优点:架构简洁,特征共享好,显存友好
    • 当前设计已经能支持600×600的高分辨率分割
    • 推荐方案

文档创建时间: 2025-11-03
当前训练阶段: Phase 4A Stage 1 (FP32, Epoch 1, Iter 10700/15448)
BEV分辨率: 360×360 @ 0.2m (Stage 1)
目标分割分辨率: 600×600 @ 0.167m