feat(localization): SHAP Partition 定位方法,并把每图框数上限默认收紧为 1

新增基于 SHAP Partition explainer 的定位,与 Grad-CAM 形成互补对照:

- engine/shap_explain.py:对目标类别求 SHAP 归因(只保留正贡献),以及方框平滑。
  遮挡用数值 masker 而非教程里的 inpaint_telea——后者依赖 opencv,而我们的图已做过
  逐图标准化,用 0(即该图均值)遮挡语义更干净
- scripts/shap_boxes.py:按类别抽样生成标签,并输出「原图 | Grad-CAM | SHAP」并排图
- shap 放入可选依赖组:uv sync --group explain

实测(225 张,每类 15):SHAP 在小目标类别上明显更准,框面积占比
blackdot 0.019 vs 0.269(14 倍)、mosquito 0.030 vs 0.173、whitedot 0.076 vs 0.253。
原因是 Grad-CAM 受限于 8x8 特征图(每格 16x16 像素),几像素的黑点根本不可分辨。
代价是单张 0.55 秒,全量 11k 张约 1.7 小时,而 Grad-CAM 全量只要 2 分钟。

调参时发现的坑:SHAP 第一版全部出 0 框,因为沿用了给 8x8 调的
min_area_ratio=0.02(在 128x128 上等于 328 像素)。参数不能跨分辨率照搬,
SHAP 默认改为 0.002。

--max-boxes 两个脚本都默认改为 1(原为 2):一张裁片通常只对应一处缺陷。
库函数 cam_to_boxes 的默认值同步收紧,相关测试改为显式传参而不依赖默认值。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Shaun Zhou
2026-09-10 16:10:50 +08:00
co-authored by Claude Opus 5
parent fc7136fddf
commit 9aa87d31a6
9 changed files with 2173 additions and 1344 deletions
+5 -1
View File
@@ -105,7 +105,11 @@ def main() -> int:
)
parser.add_argument("--threshold", type=float, default=0.4, help="热力图阈值(相对最大值)")
parser.add_argument("--padding", type=float, default=0.1, help="框四周外扩比例")
parser.add_argument("--max-boxes", type=int, default=2, help="每张图最多几个框")
parser.add_argument(
"--max-boxes", type=int, default=1,
help="每张图最多保留几个框(按连通域内热力总和排序取前 N 个)。"
"默认 1:一张裁片通常只对应一处缺陷,多出来的框多半是噪声",
)
parser.add_argument(
"--min-area-ratio", type=float, default=0.02, help="连通域面积下限(占整图比例)"
)