Files
fusion_LCD/network_learning/LEARNING_GUIDE.md
2026-05-09 17:03:40 +08:00

14 KiB
Raw Permalink Blame History

网络结构学习指南

论文:Cross Fusion of Point Cloud and Learned Image for Loop Closure Detection


目录

  1. 项目总览
  2. 网络结构全景图
  3. ALNet — 图像特征提取器
  4. RICNN — 旋转不变CNN
  5. EncodePosition — 位置编码
  6. Converter — 跨模态特征转换器
  7. Generator & FusionHead — 特征生成与融合
  8. LocalPool — 局部特征聚合
  9. NetVLAD — 全局描述子聚合
  10. UOTHead — 最优传输位姿估计
  11. 完整数据流
  12. 学习路线建议

1. 项目总览

本项目实现点云-图像跨模态融合的闭环检测系统,共包含 9 个网络结构

# 网络 源文件 作用
1 ALNet ALIKE/alnet.py 图像特征提取(关键点+描述子)
2 RICNN BEVNet.py BEV点云特征提取旋转不变
3 EncodePosition BEVNet.py 关键点空间位置编码
4 Converter net.py 跨模态特征空间转换
5 Generator net.py 变长特征→固定大小
6 FusionHead net.py 多来源特征Attention融合
7 LocalPool net.py 多像素特征→单体素聚合
8 NetVLAD netvlad.py 局部特征→全局描述子
9 UOTHead uot.py 最优传输→位姿估计

运行模式

flag 含义 包含模块
bev 仅点云 2, 3, 8
img 仅图像 1
fusion 完整融合 全部 1-9

关键维度

参数
BEV图尺寸 (H×W) 320×320
BEV输入通道 7 (max_z, intensity, density, cx, cy, cz, ci)
图像尺寸 (H×W) 192×576
关键点数量 (BEV/Img) 150
特征维度 128
VLAD聚类数 16
VLAD输出维度 2048 (=16×128)

2. 网络结构全景图

                        ┌─────────────────────────┐
                        │   输入 img + bev + relation│
                        └──────┬──────────┬───────┘
                               │          │
                    ┌──────────┘          └──────────┐
                    ▼                                ▼
            ┌──────────────┐               ┌──────────────┐
            │   ImgHead    │               │   BEVHead    │
            │   (ALNet)    │               │   (RICNN)    │
            │              │               │              │
            │ score_img    │               │ score_bev    │
            │ fea_img      │               │ fea_bev      │
            │ fea_kpl      │               │ fea_kpt_orig │
            │ key_pixels   │               │ key_points   │
            └──────┬───────┘               │ vlad_bev     │
                   │                       └──────┬───────┘
                   │                              │
                   │    ┌─────────────────────────┘
                   │    │
                   ▼    ▼
            ┌─────────────────────────────────────┐
            │           FusionHead                │
            │                                     │
            │  LocalPool → Converter(cvt_bev)     │
            │  GridSample → Converter(cvt_img)    │
            │  Generator → FusionHead(Attention)  │
            │                                     │
            │  fea_kpt_fusion  (B, 128, 150)      │
            └─────────────┬───────────────────────┘
                          │
                  ┌───────▼────────┐
                  │    NetVLAD     │
                  │  vlad_fusion   │
                  └───────┬────────┘
                          │
                  ┌───────▼────────┐
                  │  VLAD 融合      │
                  │  w*fusion +    │
                  │  (1-w)*bev     │
                  └───────┬────────┘
                          │
                  ┌───────▼────────┐
                  │   UOTHead      │
                  │ (仅训练时)      │
                  │→ transformation│
                  └────────────────┘

3. ALNet — 图像特征提取器

源码: ALIKE/alnet.py | Demo: python 01_alnet_demo.py

结构

输入: (B, 3, 192, 576)
  ↓
block1: ConvBlock(3→16)           → (B, 16, 192, 576)
  ↓ MaxPool2d(2)
block2: ResBlock(16→32)           → (B, 32, 96, 288)
  ↓ MaxPool2d(4)
block3: ResBlock(32→64)           → (B, 64, 24, 72)
  ↓ MaxPool2d(4)
block4: ResBlock(64→128)          → (B, 128, 6, 18)
  ↓
特征聚合: 4尺度concat + 上采样    → (B, 128, 192, 576)
  ↓ Conv1x1(128→129)
输出: score(B,1,192,576) + desc(B,128,192,576)

设计要点

  • 多尺度特征聚合: 4阶段特征通过1x1conv压缩后上采样拼接兼顾浅层定位精度和深层语义
  • 共享检测+描述: 单一骨干同时输出关键点得分和密集描述子
  • 配置(alike-n): c1=16, c2=32, c3=64, c4=128, dim=128
  • 关键点选择: NMS (radius=2, 2轮) + Top-K=150

各阶段含义

阶段 分辨率 学习内容
block1 原始 边缘、角点等低级特征
block2 1/2 纹理、局部形状
block3 1/8 物体部件、语义信息
block4 1/32 全局上下文、场景级信息

4. RICNN — 旋转不变CNN

源码: BEVNet.py | Demo: python 02_ricnn_demo.py

结构

输入: BEV图像 (B, 3, 320, 320)
  ↓
block1: RIConvBlock(3→16)         → (B, 16, 320, 320)
  ↓ RIMaxpool2d(2)
block2: RIResBlock(16→32)         → (B, 32, 160, 160)
  ↓ RIMaxpool2d(5, stride=4)
block3: RIResBlock(32→64)         → (B, 64, 40, 40)
  ↓ RIMaxpool2d(5, stride=4)
block4: RIResBlock(64→128)        → (B, 128, 10, 10)
  ↓
特征聚合 (同ALNet)                 → (B, 128, 320, 320)
  ↓ Conv1x1(128→129)
输出: score(B,1,320,320) + desc(B,128,320,320)

旋转不变性原理(核心创新)

BEV图像中车辆旋转时点云投影会旋转。RICNN通过以下机制保持特征不变

RIConv2d: 根据kernel位置到中心的欧氏距离分组,同距离共享权重

标准 5×5 kernel (25个独立权重):       RI kernel (3组共享权重):
[0 1 2 3 4]                           [0 1 1 1 0]
[1 2 3 4 5]                           [1 2 2 2 1]
[2 3 4 5 6]                           [1 2 3 2 1]  ← 3组: dis=0,1,2
[1 2 3 4 5]                           [1 2 2 2 1]
[0 1 2 3 4]                           [0 1 1 1 0]

RIMaxpool2d / RIAvgpool2d: 只取圆形区域内像素,排除对角线角点(旋转不一致)

推理优化: disable_ri() 可将RI层转为标准CNN层


5. EncodePosition — 位置编码

源码: BEVNet.py | Demo: 包含在 02_ricnn_demo.py

输入: kpts (B, 150, 4), fea (B, 128, 150)
  ↓
1. 计算150×150关键点欧氏距离矩阵
2. 距离直方图 (16 bins, range=[1,80]m)
3. 直方图归一化
4. MLP: 16→64→64→128
5. fea_out = fea + MLP(hist)  (残差连接)

将关键点间空间关系编码到特征中,帮助网络理解"哪些关键点在物理空间中相邻"。


6. Converter — 跨模态特征转换器

源码: net.py | Demo: python 03_converter_demo.py

输入: x (B, 128, N)  N个特征点
  ├─ 路径1: Self-Attention(MHA) → x2 (B, 128, N)
  ├─ 路径2: Conv1d瓶颈(128→32→16→32→128) → x3 (B, 128, N)
  └─ concat([x2,x3]) → Conv1d(256→128) → 输出 (B, 128, N)

两种使用

转换器 输入 → 输出 含义
cvt_bev 图像特征 → BEV空间 让图像特征"理解"BEV几何
cvt_img BEV特征 → 图像空间 让BEV特征"理解"图像语义

双路径设计MHA捕获全局关系Conv1d做逐点变换互补增强。


7. Generator & FusionHead — 特征生成与融合

源码: net.py | Demo: python 04_generator_fusion_demo.py

Generator (全景特征生成器)

输入: (B, 128, N)  N可变
  ↓ Self-Attention
  ↓ ConvTranspose1d(k3, s3) → 上采样扩展
  ↓ AdaptiveMaxPool1d(150)
输出: (B, 128, 150)  固定K=150

将可变数量的匹配点特征压缩为固定150个与BEV关键点对齐。

FusionHead (跨模态融合头)

输入: (B, 128, 150, 4)  ← [original, gen, gen_gen, kpl_gen]
  ↓
Step 1: 对前3对做 Self-Attn → max聚合
Step 2: Cross-Attn with kpl_gen (图像空间特征)
  ↓
concat(original, cross_out) → Conv1d(256→128)
输出: (B, 128, 150) 融合特征

4种特征来源

特征 来源 空间
original RICNN直接提取 BEV
gen Generator从图像特征生成 图像→BEV
gen_gen cvt_bev(cvt_img(original)) BEV→图像→BEV循环
kpl_gen cvt_img(original) BEV→图像残留

8. LocalPool — 局部特征聚合

源码: net.py | 轻量级模块无独立demo

输入: (B, 128, N, K)  N个体素每体素K个像素(K≤100)
  ↓ Conv2d(100→10, k=1) + MaxPool2d((1,10))
输出: (B, 128, N, 1) → squeeze → (B, 128, N)

一个BEV体素对应图像上多个像素需聚合为单个体素特征1x1 Conv降维 + MaxPool取最显著响应。


9. NetVLAD — 全局描述子聚合

源码: netvlad.py | Demo: python 05_netvlad_demo.py

输入: (B, 128, 150, 1)
  ↓
1. Soft Assignment: Softmax(Conv2d(128→16)(x)) → (B, 16, 150, 1)
2. Residual: x - centroids[16,128] → (B, 16, 150, 128)
3. VLAD Core: Σ(soft_assign × residual) → (B, 16, 128)
4. 归一化: per-cluster L2 → flatten → global L2
输出: (B, 2048)

为什么用VLAD

方法 问题
平均池化 丢失空间分布信息
VLAD 通过聚类保留"哪些类型特征在哪里"的结构信息

VLAD融合

vlads = sigmoid(w) * vlad_fusion + (1 - sigmoid(w)) * vlad_bev

10. UOTHead — 最优传输位姿估计

源码: uot.py | Demo: python 06_uot_demo.py

输入: feat1,feat2 (B,150,128), kpts1,kpts2 (B,150,3)
  ↓
1. Cost Matrix: C = 1 - cosine_sim(feat1, feat2)    → (B, 150, 150)
2. Sinkhorn Unbalanced OT (5 iterations):
   K = exp(-C/ε)  where ε = exp(ε_raw)+0.03
   a, b 交替更新,γ 控制质量正则
   T = diag(a)·K·diag(b)                            → (B, 150, 150)
3. 投影: project_kpts = T @ kpts2 / ΣT              → (B, 150, 3)
4. Weighted SVD → R, t                              → transformation (B, 3, 4)

两个可学习参数

参数 含义 效果
ε 熵正则化 大→平滑匹配, 小→稀疏匹配
γ 质量正则化 大→质量守恒, 小→允许不匹配

非平衡OT允许部分点不匹配对有遮挡的真实场景更鲁棒。


11. 完整数据流

训练时

img → ALNet → fea_img, fea_kpl
bev → RICNN → fea_bev, fea_kpt_original, vlad_bev

relation → grid_sample(fea_img) → fea_pl_dual
         → LocalPool → cvt_bev → fea_pt_dual_gen
         → Generator → fea_kpt_original_gen

         grid_sample(fea_bev) → fea_pt_dual       (训练时)
         → cvt_img → fea_pl_dual_gen               (训练时)

fea_kpt_original → cvt_img → fea_kpl_gen
                → cvt_bev → fea_kpt_gen_gen

FusionHead([original, gen, gen_gen, kpl_gen]) → fea_kpt_fusion
         → NetVLAD → vlad_fusion

vlads = sigmoid(w)*vlad_fusion + (1-sigmoid(w))*vlad_bev

UOTHead(fea_kpt_original) → transformation_original
UOTHead(fea_kpt_fusion)   → transformation_fusion

推理时简化

不执行 UOTHead 和 BEV→图像采样pose_to_frame),只输出 vlads + 局部特征。


12. 学习路线建议

入门约2-3小时

# 1. 全流程概览
python 08_full_pipeline_demo.py --mode all

# 2. 独立分支
python 01_alnet_demo.py    # 图像分支
python 02_ricnn_demo.py    # BEV分支含旋转不变性测试 + 位置编码)

# 3. 融合机制
python 03_converter_demo.py           # 跨模态转换
python 04_generator_fusion_demo.py    # 特征生成 + 融合

# 4. 全局描述子与位姿
python 05_netvlad_demo.py   # VLAD聚合
python 06_uot_demo.py       # 最优传输位姿估计

深入

  1. 阅读论文 Section 3 (Methodology)
  2. 对照代码看每个模块的 forward 函数
  3. 修改demo中的参数关键点数量、VLAD聚类数观察变化
  4. 加载真实checkpoint运行推理

运行环境

conda activate fusion_cyy
cd network_learning

所有可视化图像输出在 network_learning/output/ 目录。


基于代码版本: commit c3d268f