Files
yolov26_3d/eval_tools/docs/README_VAL_MERGED.md
2026-06-24 09:35:46 +08:00

304 lines
9.0 KiB
Markdown
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 合并模型评测指南
## 概述
`val_merged_model.py` 是专门用于评测合并双ROI模型的脚本。它基于 `val.py` 的评测逻辑但针对双ROI模型进行了适配。
## 功能特性
1. **双ROI数据加载**为ROI0和ROI1分别创建数据加载器
2. **同步推理**同时对两个ROI进行推理
3. **跨ROI结果融合**使用NmsForScale算法合并两个ROI的检测结果避免重复检测
4. **完整指标计算**计算2D mAP和3D指标深度误差、方向误差、中心点误差
## 工作流程
```
输入数据
ROI0 Dataloader → 推理 → NMS → ↘
跨ROI融合 → 2D/3D指标计算
ROI1 Dataloader → 推理 → NMS → ↗
```
### 详细步骤
1. **加载合并模型**:加载包含 `model_roi0``model_roi1` 的合并模型
2. **创建数据加载器**
- ROI0: 裁剪区域 [0, 120, 1920, 1080]
- ROI1: 中心区域 [704, 352],原始图像 [1920, 1080]
3. **推理**对两个ROI同时进行前向传播
4. **NMS**对每个ROI的检测结果独立进行NMS
5. **跨ROI融合**使用NmsForScale算法合并检测结果
- 移除边缘伪影IoU > 0.9且超出ROI边界
- 抑制重复检测IoU > 0.3保留更靠近ROI中心的检测
- 移除高度包含的检测IoU_in > 0.8
6. **指标计算**:对融合后的结果计算评测指标
## 使用方法
### 基本用法
```bash
python eval_tools/val_merged_model.py \
--data data/mono3d.yaml \
--weights release/yolov5s-30w/merged_model.pt \
--imgsz 704 352 \
--batch-size 1
```
### 参数说明
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `--data` | `data/mono3d.yaml` | 数据集配置文件路径 |
| `--weights` | 必需 | 合并模型权重文件路径(.pt格式|
| `--batch-size` | `1` | 批大小仅支持1|
| `--imgsz` | `[704, 352]` | 推理图像尺寸 [宽度, 高度] |
| `--conf-thres` | `0.001` | NMS置信度阈值低值用于AP计算|
| `--conf-thres-plot` | `0.25` | 可视化和3D指标的置信度阈值 |
| `--iou-thres` | `0.6` | NMS的IoU阈值 |
| `--max-det` | `300` | 每张图片最大检测数 |
| `--device` | `''` | 设备(如'0'或'cpu'|
| `--workers` | `8` | 数据加载器工作线程数 |
| `--project` | `runs/val_merged` | 结果保存目录 |
| `--name` | `exp` | 实验名称 |
| `--verbose` | - | 按类别报告mAP |
| `--half` | - | 使用FP16半精度推理 |
### 完整示例
```bash
# 基本评测
python eval_tools/val_merged_model.py \
--data data/mono3d.yaml \
--weights release/yolov5s-30w/merged_model.pt \
--imgsz 704 352
# 使用GPU加速和半精度
python eval_tools/val_merged_model.py \
--data data/mono3d.yaml \
--weights release/yolov5s-30w/merged_model.pt \
--imgsz 704 352 \
--device 0 \
--half
# 详细输出按类别显示mAP
python eval_tools/val_merged_model.py \
--data data/mono3d.yaml \
--weights release/yolov5s-30w/merged_model.pt \
--imgsz 704 352 \
--verbose
# 自定义输出目录
python eval_tools/val_merged_model.py \
--data data/mono3d.yaml \
--weights release/yolov5s-30w/merged_model.pt \
--imgsz 704 352 \
--project runs/my_eval \
--name merged_exp1
```
## 输出结果
### 控制台输出
评测过程中会实时显示:
```
Class Images Instances P R mAP50 mAP50-95 Matched Depth(m) Orient(°) Center(m)
all 50 150 0.856 0.823 0.891 0.672 89 2.345 12.678 0.234
```
- **Class**: 类别名称
- **Images**: 处理的图片数量
- **Instances**: 真实标注数量
- **P**: 精确率
- **R**: 召回率
- **mAP50**: mAP@0.5
- **mAP50-95**: mAP@0.5:0.95
- **Matched**: 3D匹配的检测数
- **Depth(m)**: 平均深度误差(米)
- **Orient(°)**: 平均方向误差(度)
- **Center(m)**: 平均中心点误差(米)
### 最终统计
```
3D Metrics (Fused ROI0+ROI1):
Total matched: 89
Depth error (abs): 2.345m
Orientation error: 12.678°
Center error: 0.234m
```
### 保存的文件
结果保存在 `--project/--name` 目录下:
- `confusion_matrix.png`: 混淆矩阵图
- `F1_curve.png`: F1曲线
- `P_curve.png`: 精确率曲线
- `R_curve.png`: 召回率曲线
- `PR_curve.png`: PR曲线
## ROI配置
脚本内置了ROI配置`test_val_merged_model.py` 保持一致:
```python
# ROI0: 裁剪区域
roi0 = (0, 120, 1920, 1080)
ori_img_size_roi0 = None
# ROI1: 中心区域
roi1 = (704, 352)
ori_img_size_roi1 = (1920, 1080)
# 跨ROI NMS使用的ROI坐标原始图像坐标系
roi_list = [
(0, 120, 1920, 1080), # ROI0
(608, 364, 1312, 716) # ROI1在原始图像中的坐标
]
```
## 跨ROI NMS算法
`NmsForScale` 函数实现了跨ROI的检测融合
1. **边缘伪影过滤**
- 计算检测框与ROI的IoU
- 如果IoU > 0.9且检测框超出ROI边界则移除
2. **重复检测抑制**
- 对于来自不同ROI的检测框
- 如果IoU > 0.3(高度重叠)
- 保留距离ROI中心更近的检测
3. **包含关系处理**
- 如果一个检测框被另一个检测框高度包含IoU_in > 0.8
- 移除被包含的检测框
## 注意事项
1. **批大小限制**:合并模型评测仅支持 `batch_size=1`
2. **模型格式**仅支持PyTorch .pt格式的合并模型包含Model_Merged类
3. **数据集要求**数据集必须包含3D标注48列标签格式
4. **内存使用**同时加载两个ROI的数据会增加内存使用
5. **速度**由于需要推理两个ROI和跨ROI融合速度会比单ROI评测慢
## 与单ROI评测的对比
| 特性 | val.py (单ROI) | val_merged_model.py (双ROI) |
|------|----------------|------------------------------|
| 批大小 | 支持任意 | 仅支持1 |
| 数据加载器 | 单个 | 两个ROI0+ROI1|
| 推理次数 | 1次/图像 | 2次/图像 |
| NMS | 单次 | 2次独立+跨ROI融合 |
| 结果 | 单ROI检测 | 融合后的全图检测 |
| 速度 | 快 | 较慢约2倍推理时间|
| 覆盖范围 | 单个ROI | 全图覆盖 |
## 故障排除
### 问题1模型加载失败
```
ValueError: Model at xxx is not a merged dual-ROI model
```
**解决方法**:确保模型是通过 `merge_models_of_2roi.py` 创建的合并模型,包含 `model_roi0``model_roi1` 属性。
### 问题2数据加载器长度不匹配
```
WARNING Dataloader lengths mismatch: ROI0=100, ROI1=98
```
**解决方法**检查数据集配置确保两个ROI访问相同的图像文件。
### 问题3路径不匹配
```
WARNING Path mismatch: xxx vs yyy
```
**解决方法**:这通常表示两个数据加载器返回的图像顺序不一致,检查数据集配置和路径。
### 问题4内存不足
**解决方法**
- 减少 `--workers` 数量
- 使用 `--half` 启用FP16推理
- 在CPU上运行`--device cpu`
## 相关文件
- `val.py`: 单ROI模型评测脚本
- `merge_models_of_2roi.py`: 合并两个ROI模型的脚本
- `test_val_merged_model.py`: 合并模型推理测试脚本(仅推理,不计算指标)
- `val_merged_model.py`: 本脚本,合并模型完整评测
## 工作流程示例
完整的训练+合并+评测流程:
```bash
# 1. 训练ROI0模型
python train_mono3d.py --data data/mono3d.yaml --roi 0 120 1920 1080 --weights yolov5s.pt
# 2. 训练ROI1模型
python train_mono3d.py --data data/mono3d.yaml --roi 704 352 --ori-img-size 1920 1080 --weights yolov5s.pt
# 3. 评测单个模型(可选)
python val.py --weights runs/train/roi0_exp/weights/last.pt --data data/mono3d.yaml --roi 0 120 1920 1080
python val.py --weights runs/train/roi1_exp/weights/last.pt --data data/mono3d.yaml --roi 704 352 --ori-img-size 1920 1080
# 4. 合并模型
python eval_tools/merge_models_of_2roi.py \
--roi0_model_path runs/train/roi0_exp/weights/last.pt \
--roi1_model_path runs/train/roi1_exp/weights/last.pt \
--save_dir release/merged \
--skip-export # 仅保存合并模型不导出ONNX
# 5. 评测合并模型
python eval_tools/val_merged_model.py \
--data data/mono3d.yaml \
--weights release/merged/merged_model.pt \
--imgsz 704 352
# 6. 推理测试(可选)
python eval_tools/test_val_merged_model.py \
--source /path/to/test/images \
--weights release/merged/merged_model.pt \
--model-type torchscript
```
## 扩展说明
如果需要修改ROI配置编辑脚本中的以下部分
```python
# 在 run() 函数中约第375行
roi0 = (0, 120, 1920, 1080) # 修改ROI0坐标
roi1 = (704, 352) # 修改ROI1尺寸
ori_img_size_roi1 = (1920, 1080) # 修改原始图像尺寸
# 在跨ROI NMS部分约第431行
roi_list = [
(0, 120, 1920, 1080), # ROI0坐标
(608, 364, 1312, 716) # ROI1在原始图像中的坐标需要计算
]
```
计算ROI1在原始图像中的坐标
```python
# 如果ROI1是中心裁剪计算方式
ori_w, ori_h = 1920, 1080
roi1_w, roi1_h = 704, 352
x1 = (ori_w - roi1_w) // 2 # 608
y1 = (ori_h - roi1_h) // 2 # 364
x2 = x1 + roi1_w # 1312
y2 = y1 + roi1_h # 716
```