bev-project/archive/docs_old/BEVFusion内存占用分析_20251101.md

10 KiB
Raw Blame History

BEVFusion 训练内存占用分析报告

生成时间: 2025-11-01
配置: Phase 4A Stage 1 - 8卡训练
显存占用: 28.8-29.3GB/32GB (88-89%)
Batch Size: 1/GPU


📊 总体内存占用

当前状态

GPU显存总量: 32768 MB (32GB)
实际占用:    28800-29300 MB (28.8-29.3GB)
使用率:      88-89%
峰值显存:    18893 MB (日志记录)
剩余空间:    3.5-4GB

内存分配概览

组件 显存占用 占比 说明
模型参数 ~3.5GB 12% 所有层的参数
梯度 ~3.5GB 12% 反向传播梯度
优化器状态 ~7GB 24% Adam (2×参数量)
激活值 ~12GB 41% ⚠️ 最大消耗
BEV Pool临时 ~2GB 7% LSS变换缓存
数据加载 ~1GB 4% 输入数据缓存
总计 ~29GB 100%

🔍 各模块详细分析

1. Camera Backbone (Swin Transformer)

参数量: ~28M
显存占用: ~3.5GB

配置:
  embed_dims: 96
  depths: [2, 2, 6, 2]  # 12层
  num_heads: [3, 6, 12, 24]
  input: 6×3×900×1600 (6 cameras, batch=1)
  
关键优化点:
  with_cp: false  # ❌ 未启用gradient checkpointing

内存分解

参数权重:    ~110MB
梯度:         ~110MB
激活值 (无CP): ~2.8GB  ⚠️ 最大消耗
  - Layer 1-2:   ~800MB
  - Layer 3-8:   ~1.5GB  (最深的6层)
  - Layer 9-12:  ~500MB

优化建议

# 启用gradient checkpointing可节省 ~2GB
model.encoders.camera.backbone.with_cp: true

2. LSS Transform (DepthLSSTransform)

参数量: ~15M
显存占用: ~6GB

配置:
  in_channels: 256
  out_channels: 80
  image_size: [900, 1600]
  feature_size: [112, 200]  # H/8, W/8
  D: 118  # depth bins (1-60m, 0.5m间隔)
  BEV分辨率: 540×540 (0.2m)

内存分解

1. Depth Transform:
   - dtransform网络:    ~50MB
   - depthnet:          ~60MB
   
2. 激活值(最耗内存):
   - 输入特征:          1×6×256×112×200 = ~1.5GB
   - Depth map:        1×6×118×112×200 = ~1.5GB
   - 外积操作:          1×6×80×118×112×200 = ~8.9GB ⚠️⚠️
   - BEV pooling临时:  ~2GB
   
3. Downsample (2×):
   - 540×540 → 270×270
   - 3层卷积:           ~500MB

关键瓶颈 ⚠️

# depth_lss.py line 93
x = depth.unsqueeze(1) * x[:, self.D : (self.D + self.C)].unsqueeze(2)
# 形状: [1, 6, 80, 118, 112, 200]
# 大小: 1*6*80*118*112*200*4bytes = ~9GB ⚠️

优化方案

  1. 降低depth bins: D=118 → D=80 (可节省~2GB)
  2. 分相机处理(串行)
  3. 使用fp16混合精度训练

3. LiDAR Encoder (SparseEncoder)

参数量: ~5M
显存占用: ~1.2GB

配置:
  voxel_size: [0.075, 0.075, 0.2]
  max_voxels: [120000, 160000]
  sparse_shape: [1440, 1440, 41]
  encoder_channels: [[16,16,32], [32,32,64], [64,64,128], [128,128]]

内存分解

稀疏体素:      ~600MB  (120k voxels, sparse)
3D卷积激活:    ~400MB  (sparse操作高效)
特征输出:      ~200MB  (256 channels)

优势: 稀疏卷积显存高效


4. Fuser + Decoder

参数量: ~8M
显存占用: ~2.5GB

Fuser (ConvFuser):
  融合: Camera BEV (270×270×80) + LiDAR (270×270×256)
  输出: 270×270×256
  显存: ~500MB
  
Decoder (SECOND):
  backbone层数: 2 (5+5 layers)
  out_channels: [128, 256]
  显存: ~2GB

5. BEV Segmentation Head (Enhanced)

参数量: ~12M
显存占用: ~4.5GB

配置:
  in_channels: 256
  decoder_channels: [256, 256, 128, 128]  # 4层
  GT分辨率: 600×600
  类别数: 6
  deep_supervision: true  # 3个辅助输出

内存分解

1. ASPP模块:
   - 5个分支并行:    ~800MB
   
2. 4层Decoder:
   - Layer 1: 256→256  ~1.2GB (最大分辨率)
   - Layer 2: 256→256  ~1.2GB
   - Layer 3: 256→128  ~600MB
   - Layer 4: 128→128  ~600MB
   
3. Deep Supervision:
   - 主输出: 600×600×6    ~40MB
   - 辅助1: 300×300×6     ~10MB
   - 辅助2: 150×150×6     ~3MB
   - 损失计算临时:        ~200MB
   
4. Channel + Spatial Attention:
   - 额外激活:            ~300MB

优化建议

  • 可将decoder_channels减少为[256, 128, 128, 64]
  • 节省约1.5GB显存

6. 3D Detection Head (TransFusion)

参数量: ~6M
显存占用: ~2.5GB

配置:
  num_proposals: 200
  transformer layers: 1
  heatmap分支 + bbox回归分支

内存分解

Heatmap生成:      ~800MB
Query特征:        ~600MB
Transformer:      ~800MB
损失计算:         ~300MB

7. 优化器状态 (AdamW)

参数量: ~73M (总参数)
显存占用: ~7GB

# AdamW存储2个动量缓存
参数:         73M × 4 bytes = 292MB
梯度:         73M × 4 bytes = 292MB
Momentum 1:   73M × 4 bytes = 292MB ×2 = 584MB
Momentum 2:   73M × 4 bytes = 292MB ×2 = 584MB
Master weights (fp16): 73M × 2 bytes = 146MB

总计: ~7GB

🎯 内存优化方案

方案1: 启用Gradient Checkpointing

预期节省: 2-3GB

# multitask_BEV2X_phase4a_stage1.yaml
model:
  encoders:
    camera:
      backbone:
        with_cp: true  # 启用checkpointing

原理: 不保存中间激活,反向传播时重新计算
代价: 训练速度降低~15%
适用: 显存受限场景


方案2: 混合精度训练 (FP16)

预期节省: 30-40%显存 (~10GB)

# multitask_BEV2X_phase4a_stage1.yaml
fp16:
  loss_scale: dynamic

优势:

  • 显存减半
  • 训练速度提升20-30%
  • V100原生支持Tensor Core

注意:

  • 需要loss scaling防止梯度下溢
  • 某些层可能需要fp32 (BatchNorm)

方案3: 降低LSS Depth Bins

预期节省: 2-3GB

model:
  encoders:
    camera:
      vtransform:
        dbound: [1.0, 60.0, 1.0]  # 从0.5改为1.0
        # D: 59 (vs 118)

影响:

  • 深度分辨率降低
  • 对远处物体检测精度略降

方案4: 减少BEV Decoder层数

预期节省: 1-1.5GB

model:
  heads:
    map:
      decoder_channels: [256, 128, 128, 64]  # 从[256,256,128,128]

影响:

  • 分割精度可能略降
  • 需要重新训练验证

方案5: 增大Batch Size (推荐)

当前可行性: 有3.5-4GB剩余显存

data:
  samples_per_gpu: 2  # 从1增加到2
  workers_per_gpu: 2  # 从0增加到2

预期效果:

  • 训练速度提升~30%
  • 梯度更稳定
  • 可能需要调整学习率

配合优化:

  • FP16: batch可增加到4
  • FP16 + Checkpointing: batch可增加到6

方案6: 降低输入分辨率

预期节省: 2-3GB

# 当前: 900×1600
# 优化: 720×1280 (降低20%)
image_size: [720, 1280]

影响:

  • 远处小目标检测精度降低
  • 分割边界质量略降

💡 推荐优化组合

组合A: 保持精度增大Batch (推荐)

# 1. 启用FP16
fp16:
  loss_scale: dynamic

# 2. 增大Batch
data:
  samples_per_gpu: 4  # 1→4
  workers_per_gpu: 2

# 3. 调整学习率
optimizer:
  lr: 4.0e-05  # 2e-5 × 2

预期:

  • 显存占用: 29GB → 20GB
  • Batch增加: 1×8 → 4×8 = 32
  • 训练速度: 2.67秒/iter → 1.8秒/iter (提升33%)
  • Epoch耗时: 11小时 → 7.5小时
  • 10 epochs: 9.5天 → 6.5天

组合B: 极致优化最大Batch

# 1. FP16 + Gradient Checkpointing
fp16:
  loss_scale: dynamic
model.encoders.camera.backbone.with_cp: true

# 2. 降低LSS深度分辨率
dbound: [1.0, 60.0, 1.0]  # D: 118→59

# 3. 最大Batch
data:
  samples_per_gpu: 8  # 1→8

预期:

  • 显存占用: 29GB → 15GB
  • Batch: 1×8 → 8×8 = 64
  • 训练速度: 提升60%
  • Epoch耗时: 11小时 → 4.5小时
  • 10 epochs: 9.5天 → 4天

代价:

  • 训练速度降低15% (checkpointing)
  • 深度精度略降

组合C: 保守优化

# 仅启用FP16
fp16:
  loss_scale: dynamic

# Batch增加到2
data:
  samples_per_gpu: 2

预期:

  • 显存占用: 29GB → 18GB
  • Batch: 8 → 16
  • Epoch耗时: 11小时 → 8小时
  • 10 epochs: 9.5天 → 7天

📊 各方案对比

方案 显存占用 Batch Epoch耗时 10 Epochs 精度影响 推荐度
当前 29GB 8 11h 9.5天 - -
组合A 20GB 32 7.5h 6.5天
组合B 15GB 64 4.5h 4天 轻微
组合C 18GB 16 8h 7天

🔧 实施步骤推荐组合A

1. 修改配置文件

cd /workspace/bevfusion
cp configs/nuscenes/det/transfusion/secfpn/camera+lidar/swint_v0p075/multitask_BEV2X_phase4a_stage1.yaml \
   configs/nuscenes/det/transfusion/secfpn/camera+lidar/swint_v0p075/multitask_BEV2X_phase4a_stage1_fp16.yaml
# 添加FP16配置
fp16:
  loss_scale: dynamic

# 修改batch配置
data:
  samples_per_gpu: 4
  workers_per_gpu: 2

# 调整学习率batch增加4倍lr也应增加
optimizer:
  lr: 4.0e-05

2. 测试验证

# 先跑1个epoch测试
bash START_FROM_EPOCH1.sh  # 修改为新配置

3. 监控显存

watch -n 5 'nvidia-smi --query-gpu=index,memory.used --format=csv'

📋 注意事项

FP16训练注意

  1. Loss scaling: 必须启用dynamic loss scaling
  2. BatchNorm: 可能需要保持FP32
  3. 梯度裁剪: 适当调整grad_clip阈值
  4. 收敛性: 前几个epoch监控loss是否正常

Gradient Checkpointing注意

  1. 速度: 训练速度降低15-20%
  2. 内存: 节省激活内存,但增加计算
  3. 兼容性: 确保所有层支持checkpointing

Batch Size调整注意

  1. 学习率: 线性缩放batch×2, lr×2
  2. Warmup: 可能需要更长warmup
  3. BatchNorm: 统计量更稳定
  4. 评估: 需要验证最终精度

📌 总结

当前瓶颈

  1. LSS Transform的外积操作 (~9GB) ⚠️⚠️
  2. Swin Transformer激活值 (~2.8GB) ⚠️
  3. BEV Decoder激活值 (~4GB) ⚠️

最优方案

  • 组合A (FP16 + Batch=4)
  • 显存利用率提升训练加速33%
  • 无精度损失
  • 6.5天完成vs 当前9.5天)

立即可行

# 当前有4GB剩余显存
# 可直接增加batch到2无需其他修改
data.samples_per_gpu: 2
# 预计7天完成

分析基于: Phase 4A Stage 1, 8×V100S-32GB, Batch=1
生成时间: 2025-11-01