File size: 8,102 Bytes
0e9808f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# 已知问题与边界 · 上线前必读

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

---

## 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 随产线不良率剧烈变化 ★★★

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

$$\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(放行桶纯度)方向相反,不良率越低越好看:

$$\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。**这是循环论证。**

真实的约束是**分数分离度**:

$$\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.csv` 的 `test_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 类缺陷的数据。