refactor: 合并为单一的框生成入口,gradcam / shap 可选,默认全量
此前是两个脚本:gradcam_boxes.py 全量跑但只有一种方法,shap_boxes.py 默认抽样 且强制输出对比图。两者合并为 scripts/generate_boxes.py: - --method gradcam|shap 二选一,默认 gradcam - 默认对全量数据生成;--limit / --per-class 降级为试参数用的可选项 - --min-area-ratio 缺省随方法而变(gradcam 0.02、shap 0.002):两者归因图分辨率差 16 倍,同一个小黑点在 128x128 上只占百来像素,共用阈值会被整个滤掉 产出改为符合 CLAUDE.md 工作流第 8 步的规格,是一个自成一体的 YOLO 数据集: images/ 是原图硬链接、labels/ 是 YOLO 标签、heatmaps/ 是热力图叠加框。 images/ 与 labels/ 的对应关系符合仓库的 YOLO 约定,FilmDefectDataset 可直接读取, 把分类产出接回了检测训练链路(已加测试验证这条闭环)。 热力图目标类别改为模型 top1 预测(原为目录标注),--target label 可切回; summary.json 记录两者一致率(实测 0.9873)。 修掉一个会静默丢标签的 bug:产出按预测类别分目录,不同源目录下的同名图 (dirA/x.png 与 dirB/x.png)若被预测到同一类会写同一个标签路径,后写的覆盖前者。 现在显式检测并中止,提示用 export_clusters.py --prefix-parent 重新导出。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
9aa87d31a6
commit
57446c2f10
@@ -632,52 +632,64 @@ model:
|
||||
只加载 backbone,分类头仍随机初始化。`frozen_backbone: true` 可以单独衡量
|
||||
自监督特征本身有多好。
|
||||
|
||||
## 从分类到定位:Grad-CAM 生成框标签
|
||||
## 从分类到定位:生成框标签
|
||||
|
||||
分类模型只学过"这是什么缺陷",没学过"缺陷在哪"。Grad-CAM 把分类分数对卷积特征的梯度
|
||||
当作通道重要性,加权求和得到空间热力图——这是分类模型隐含的定位线索。阈值化 +
|
||||
取连通域外接矩形,就得到弱监督的框标签:
|
||||
分类模型只学过"这是什么缺陷",没学过"缺陷在哪"。归因方法能把分类分数反推回空间位置,
|
||||
阈值化 + 取连通域外接矩形,就得到弱监督的框标签:
|
||||
|
||||
```bash
|
||||
uv run python scripts/gradcam_boxes.py --checkpoint runs/classify/best.pth
|
||||
# Grad-CAM(默认,全量 11k 张约 2 分钟)
|
||||
uv run python scripts/generate_boxes.py --out runs/boxes_gradcam --method gradcam
|
||||
|
||||
# SHAP Partition(更精细,全量约 1.7 小时)
|
||||
uv run python scripts/generate_boxes.py --out runs/boxes_shap --method shap
|
||||
```
|
||||
|
||||
**默认对全量数据生成**;`--limit` / `--per-class` 只用于快速试参数。
|
||||
|
||||
### 产出是自成一体的 YOLO 数据集
|
||||
|
||||
```
|
||||
runs/gradcam_boxes/
|
||||
├── labels/<类别>/<图名>.txt # YOLO 格式 class_id cx cy w h,可直接喂给检测训练
|
||||
├── viz/<类别>/<图名>.png # 原图 | 热力图 | 叠加+框,供人工核对
|
||||
runs/<name>/
|
||||
├── images/<类别>/<图名>.png # 硬链接到原图,不占额外磁盘
|
||||
├── labels/<类别>/<图名>.txt # YOLO:class_id cx cy w h(归一化)
|
||||
├── heatmaps/<类别>/<图名>.png # 热力图叠加原图 + 框,供人工核对
|
||||
├── data.yaml
|
||||
└── summary.json
|
||||
```
|
||||
|
||||
**框的类别取自图片所在目录**(人工归类结果),不是模型预测——即使模型分错,
|
||||
要的也是该图真实类别的热力区域。
|
||||
`images/` 与 `labels/` 的对应关系符合本仓库的 YOLO 约定,所以 `FilmDefectDataset`
|
||||
能直接读——这一步把分类的产出接回了检测训练链路。
|
||||
|
||||
### 分辨率是主要限制
|
||||
热力图默认针对模型的 **top1 预测类别**;`--target label` 改用图片所在目录的标注类别。
|
||||
`summary.json` 里的 `prediction_matches_folder_label` 记录两者的一致率(实测 0.987)。
|
||||
|
||||
resnet18 在 128×128 输入下各层的 CAM 尺寸:layer4 只有 4×4、layer3 是 8×8、layer2 是 16×16。
|
||||
层越浅越精细,但类别判别性越弱。`--stage`(4~7 对应 layer1~4)可选,默认 6 即 **layer3**:
|
||||
### 两种方法的取舍
|
||||
|
||||
| stage | CAM | 实测(每类抽 3 张,共 45 张) |
|
||||
| | `gradcam` | `shap` |
|
||||
| --- | --- | --- |
|
||||
| 7 (layer4) | 4×4 | 100% 出 1 个框,但只有 16 个格子,框很粗 |
|
||||
| **6 (layer3)** | **8×8** | **76% 出 1 框、20% 出 2 框,热力区域与缺陷贴合** |
|
||||
| 5 (layer2) | 16×16 | 40% 出不了框,响应太散 |
|
||||
| 分辨率 | 受限于特征图(layer3 @128² 只有 8×8) | 与输入同分辨率(128×128) |
|
||||
| 单张耗时 | ~0.01 秒 | ~0.55 秒 |
|
||||
| 小目标 | 几像素的黑点在 8×8 上不可分辨 | 能贴合到几十像素的目标 |
|
||||
|
||||
### 几个调参点
|
||||
实测框面积占比(越小越贴合缺陷本体):`blackdot` 0.019(shap) vs 0.269(gradcam)、
|
||||
`mosquito` 0.030 vs 0.173、`whitedot` 0.076 vs 0.253。小目标类别上 SHAP 明显更准,
|
||||
代价是慢 50 倍。SHAP 需要 `uv sync --group explain`。
|
||||
|
||||
### 调参
|
||||
|
||||
- `--max-boxes`(默认 1):一张裁片通常只对应一处缺陷,多出来的框多半是噪声
|
||||
- `--threshold`(默认 0.4):热力图相对最大值的阈值
|
||||
- `--max-boxes`(默认 1):每张图最多保留几个框,按连通域内热力总和排序取前 N 个。
|
||||
一张裁片通常只对应一处缺陷,多出来的框多半是噪声;确实有多缺陷的图再调大
|
||||
- `--peak-ratio`(默认 0.75):次要连通域的峰值要达到全局最大值的这个比例才保留。
|
||||
不加这条会在没有缺陷的角落刷出假框
|
||||
- `--padding`(默认 0.1):框四周外扩。CAM 倾向只覆盖最具判别性的部位(缺陷中心),
|
||||
往往比真实缺陷范围小
|
||||
- `--viz-per-class`(默认 20):每类存多少张可视化;`--viz-all` 全存(很慢很占盘)
|
||||
- `--min-area-ratio`:**缺省随方法而变**(gradcam 0.02、shap 0.002)。两者归因图分辨率
|
||||
差 16 倍,同一个小黑点在 128×128 上只占百来像素,沿用 0.02(=328 像素)会被整个滤掉
|
||||
- `--peak-ratio`(默认 0.75):次要连通域的峰值需达全局最大值的这个比例,滤掉弱响应假框
|
||||
- `--padding`(默认 0.1):框四周外扩。归因倾向只覆盖最具判别性的部位,往往偏小
|
||||
- `--stage`(gradcam,默认 6=layer3):layer4 只有 4×4 太粗,layer2 响应太散
|
||||
- `--no-heatmaps` / `--no-images`:只要标签时可跳过
|
||||
|
||||
> **不是所有类别都可定位。** `normal`/`black`/`edge_clean` 这类描述的是整图属性而非
|
||||
> 局部缺陷,它们的框没有物理意义。真正有用的是 `blackdot`/`whitedot`/`mosquito`/
|
||||
> `grease`/`zigzag` 这些有局部目标的类别。
|
||||
> **不是所有类别都可定位。** `normal`/`black`/`edge_clean` 描述的是整图属性而非局部缺陷,
|
||||
> 它们的框没有物理意义。真正有用的是 `blackdot`/`whitedot`/`mosquito`/`grease` 这些
|
||||
> 有局部目标的类别。
|
||||
|
||||
## 方法
|
||||
|
||||
|
||||
Reference in New Issue
Block a user