filter-inspection / docs /CAVEATS.md
daipath's picture
加入完整文档集:复现指南、逐文件说明、结果汇总、诚实性审计、已知边界
0e9808f verified
|
Raw
History Blame Contribute Delete
8.1 kB

已知问题与边界 · 上线前必读

按严重程度排序。前三条会直接推翻结论的适用性。


1. 样本量不足以证明产线级低误杀率 ★★★

test 只有 185 张良品

最小可分辨误报率 = 1/185 = 0.54%。 比这更低的误报率,本数据集在原理上测不出来

即使观测到 0 误报,Clopper–Pearson 95% 置信上界仍有 **1.61%**。

要达到的目标需要多少张干净良品:

目标 需要误报率 需要良品数(95% 置信、零观测失败)
证明误报率 < 1% < 1% ≈300
产线不良率 5% 下 precision ≥ 99% ≤ 0.048% ≈6,260
产线不良率 2% 下 precision ≥ 99% ≤ 0.019% ≈16,146

这不是模型问题,是统计问题。换更好的模型不会改变它。


2. precision 随产线不良率剧烈变化 ★★★

「判为不良的那堆里混了多少良品」不是模型的固有属性

precision=recPrecP+fpr(1P)\text{precision} = \frac{\text{rec}\cdot P}{\text{rec}\cdot P + \text{fpr}\cdot(1-P)}

同一个模型、同一个阈值:

产线不良率 P 不良桶良品率
54.8%(本 test 人为构造) 1.83%
10% 16.9%
5% 29.5%
2% 51.6%

test 上的 1.83% 是被构造出来的假象。 test 里不良品占 54.8%,产线上通常只有 1–10%。

凡是引用本项目的 precision 数字,必须同时写明对应的不良率。 不写就是误导。

NPV(放行桶纯度)方向相反,不良率越低越好看:

NPV=(1fpr)(1P)(1fpr)(1P)+(1rec)P\text{NPV} = \frac{(1-\text{fpr})(1-P)}{(1-\text{fpr})(1-P) + (1-\text{rec})P}


3. 我在评估口径上犯过的错,以及修正后的数字 ★★★

如实记录,因为这些错误的数字曾经被写进报告。

错误 A:在 test 上选阈值(两次)

  • 一次在 precision_table
  • 一次在早期只有 train/val 的切分里

得到 A 套「不良桶良品率 0%」的漂亮结果。

这是作弊。 阈值在 test 上调,等于把 test 当成了 val。

诚实口径(阈值在 val 上定、test 只评一次,p10_honest.json):

A 套 B 套
不良桶良品率 17.89% 0.00%
test 检出率 22.3% 51.5%
test 误报 1/185 0/185

A 套从 0% 变成 **17.89%**。B 套确实是 0%,但检出率只有 51.5%。

错误 B:把「分辨率不够」当作解释

我曾用「空间分辨率不足」解释为什么达不到目标 precision。这是循环论证。

真实的约束是分数分离度

fprrect1tP1P\text{fpr} \le \frac{\text{rec}\cdot t}{1-t}\cdot\frac{P}{1-P}

($t$ = 目标 precision)。它随 rec 线性缩放,和像素分辨率没有直接关系。

错误 C:probe-B 判为「不通过」

max(良品分数) 当阈值,任何一个离群良品都会把结论毁掉。是阈值选法的问题,不是模型的问题。已修正为通过。

错误 D:「麻点是区域级圈选」

我从一张图推广到整类。实际统计:麻点标注面积中位数 0.22% 图幅,是逐颗描的。 只有 样本_38030_P15261973_2 一个包是画大圈圈住密集区(中位 9.42%)。

错误 E:gwz 归一化更好

我基于「数据有色调漂移」推断灰世界白平衡必然更优。 test 上 imnet 拿了最高 AUROC(0.9976 vs gwz 0.9918)。结论已撤回。


4. 数据质量问题(6 条)

  1. 良品标签约 3.3% 存疑 —— 漏标的真缺陷。已用客观门槛核查,不是估计。误报率数字直接受此影响。
  2. 34 张缺陷图零监督(6 张缺 json + 28 张 shapes 为空),已剔除并记录在 dropped.csv
  3. 崩 / 侧面崩 / 碎 的标注多边形几乎整个画在片体外(片体内比例仅 1–3%)——因为缺陷本身就是「材料缺了一块」。语义上成立,但直接栅格化当分割 GT 会有问题
  4. 麻点标注口径不统一:多数包逐颗描(面积中位 0.15–0.64% 图幅),样本_38030_P15261973_2 画大圈(中位 9.42%),差 20–60 倍
  5. 标注精细度分两档:labelme 3.3.10 顶点中位 80(精描)vs 5.11.4 顶点中位 12(粗框)。**样本_38031 两版本混装**,用前要按版本拆开。
  6. 采集配置色调漂移:B 通道逐日 15→8→5,冷/暖两种配置混在库里。

更根本的一条:判定规格缺失

多亮 × 多大的圆点算麻点、多长的划痕算不良,至今没有书面判据。

所有「漏标率」争议最终都归约到这一条。良品没定义清楚之前,误报率无从谈起。 这是项目最大的非技术阻塞项。


5. 缺陷类型覆盖

客户规格表 11 类:麻点 / 划痕 / 崩角崩边 / 印迹绿色蹭伤 / 黄边 / 隐崩角 / 可擦拭性脏污 / 面次 / 脱膜 / 水渍 / 尺寸异常。

数据集只覆盖前 3 类。 但这 3 类占缺陷图的 **95.8%**。

被整类排除的两类:

类别 张数 排除原因
64 规格表外。改作审计用的未见类硬正样本
不可擦脏 19 「擦不擦得掉」是物理属性,单张图像原理上判不了。强行训检出率仅约 53%

其余 8 类没有任何训练数据,模型对它们的行为完全未知。


6. 分割路线的固有短板

麻点连通域太小。 test 全部麻点图的预测像素合计 6297 px,均摊每图 274 px。

阈值 τ 误报 划痕 崩边 麻点
200 12/185 96.2% 97.1% 73.9%
400 10/185 93.2% 97.1% 17.4%
800 8/185 87.2% 97.1% 0.0%
1600 5/185 64.7% 91.2% 0.0%

任何能把误报压到可接受范围的阈值,都会把麻点整类抹掉。

补救是 7 维几何判据单独捞麻点,但它 oracle 74.6% → honest 64.3%,掉 10 个点: 7 个自由度在 434 张 val 上调必然过拟合,且 A 套选出的阈值到 B 套失效——不可迁移

这是选择分类路线的根本原因。


7. 部署环境限制

  • 输入必须是已裁到单片边界的暗场图,原始尺寸 300–360 px 量级。整版图 / 明场图不适用。
  • GPU 版要求 CUDA 12.x。CUDA 13 或 11 都不行(onnxruntime-gpu 1.28 要 CUDA 13,需钉 1.22.0 / 1.24.4)。
  • libstdc++.so.6 必须显式打包。Ubuntu 24.04 系统库要 GLIBC_2.38,目标机没有会崩。

    这个错的表象是 numpy 导入失败,根因不是 numpy。当时按 numpy 方向排查了很久,是弯路。

  • 单文件程序首次运行要解压到临时目录,第一次慢是正常的
  • 预处理改一个字节,标定好的阈值全部失效。

8. 实验方法学限制

  • AUROC 噪声地板 ±0.005(Hanley–McNeil 标准误,见 cls_test_all.csvtest_se 列)。 榜单前 10 名之间的差距和这个噪声同量级——不要根据 0.001 的差异下结论
  • 没做多种子重复。 训练固定种子 42,但 cuDNN 非确定性算子仍带来抖动。要压过噪声地板必须多种子,本项目没做。
  • cls_eval_all.py 在 test 上横比 42 个模型再挑最好,本身带选择偏差。 脚本会额外打印「按 val 预先选定」的那个模型——只有那个数字是无偏的
  • convnext_tiny.dinov3_lvd1689m 训练失败(val AUROC 0.5132 = 随机)。 不是骨干不行,是 60 epoch / lr 4e-4 这套超参不适配它。没有重调,所以它不构成对 DINOv3 的评价。

建议的下一步(按性价比)

  1. 补足干净良品到 300+ 张,才能证明误报率 < 1%。这是最大瓶颈,且不需要任何算法工作。
  2. 拿到书面判定规格。 良品定义清楚之前,其他优化都在流沙上。
  3. 色调漂移压力测试,验证 gwz 到底有没有用(目前证据是没有)。
  4. 多种子重复,把 ±0.005 的噪声地板压下去,再谈模型选型。
  5. 补采其余 8 类缺陷的数据。