网络测试和学习demo

This commit is contained in:
cyy_mac
2026-05-09 17:03:40 +08:00
parent edbe8fdbf9
commit 78298e56f1
9 changed files with 2868 additions and 0 deletions

View File

@@ -0,0 +1,419 @@
# 网络结构学习指南
> 论文:[Cross Fusion of Point Cloud and Learned Image for Loop Closure Detection](../Cross_Fusion_of_Point_Cloud_and_Learned_Image_for_Loop_Closure_Detection.pdf)
---
## 目录
1. [项目总览](#1-项目总览)
2. [网络结构全景图](#2-网络结构全景图)
3. [ALNet — 图像特征提取器](#3-alnet--图像特征提取器)
4. [RICNN — 旋转不变CNN](#4-ricnn--旋转不变cnn)
5. [EncodePosition — 位置编码](#5-encodeposition--位置编码)
6. [Converter — 跨模态特征转换器](#6-converter--跨模态特征转换器)
7. [Generator & FusionHead — 特征生成与融合](#7-generator--fusionhead--特征生成与融合)
8. [LocalPool — 局部特征聚合](#8-localpool--局部特征聚合)
9. [NetVLAD — 全局描述子聚合](#9-netvlad--全局描述子聚合)
10. [UOTHead — 最优传输位姿估计](#10-uothead--最优传输位姿估计)
11. [完整数据流](#11-完整数据流)
12. [学习路线建议](#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融合
```python
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小时
```bash
# 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运行推理
### 运行环境
```bash
conda activate fusion_cyy
cd network_learning
```
所有可视化图像输出在 `network_learning/output/` 目录。
---
*基于代码版本: commit c3d268f*