总分下降之后,先问错在哪里
这篇方法回顾按主题归档,不对应某次实测结果。模型表现不理想时,直接更换网络往往会同时改变太多因素,难以判断问题有没有被解决。误差分析的作用,是把「效果不好」拆成带证据的假设。
第一份报告应能回到具体样本:输入版本、参考标注、预测、概率或置信度、预处理配置,以及所属患者或场景。只有汇总分数而没有逐例输出,后续讨论很容易停留在猜测。
建立一张可以复查的错误地图
对二值分割,先把真阳性、假阳性和假阴性标在同一空间位置。下面函数接收已对齐的二值掩膜,返回分类编码,不生成任何模拟性能数据。
import numpy as np
def error_map(pred, reference):
p = np.asarray(pred, dtype=bool)
g = np.asarray(reference, dtype=bool)
if p.shape != g.shape:
raise ValueError("mask shapes must match")
result = np.zeros(p.shape, dtype=np.uint8)
result[p & g] = 1 # 真阳性
result[p & ~g] = 2 # 假阳性
result[~p & g] = 3 # 假阴性
return result
显示时固定颜色,并保留原图背景。只展示错误掩膜,会丢失低对比度、伪影和标注歧义的上下文。输入如果是概率图,应先按已冻结的阈值二值化,不能依赖布尔转换。
分类任务也应明确混淆矩阵的行列含义,例如 scikit-learn 使用真实类别为行、预测类别为列。官方定义
按机制分组,而非只挑最差图片
可从目标大小、边界对比度、采集条件、伪影类型和空间位置建立分组。每个组既记录错误数量,也记录样本总数。一个错误多的组,可能仅仅是它在数据中占比高。
最差样本适合发现严重问题,随机抽样的普通样本则有助于判断问题有多普遍。两者应同时保留,且尽量在患者或独立场景层面统计,避免同一体数据的连续切片占满报告。
分组标签也需要可信来源。「困难病例」若只是看到失败后临时起的名字,就很难支持可重复的比较。可以先形成探索性分组,再在下一轮验证中冻结定义。
把观察写成可被推翻的假设
例如,细结构集中漏检可以产生多个候选解释:重采样抹去了目标、训练裁剪缺少前景,或标注本身存在不一致。每个解释都对应不同的最小检查。
先查看原分辨率与输入分辨率的目标宽度,再检查实际进入训练的前景比例,最后复核代表性标注。如果目标进入网络之前已经消失,增加模型层数并不能补回输入信息。
实验记录可采用「观察—候选原因—对照改动—预期证据」四列。预期证据要具体到某类错误应如何变化,同时明确可能的副作用。这样即使改动无效,也能排除一个假设。
改进要在固定协议下兑现
优先处理影响严重、出现稳定、诊断证据较充分的问题。标注错误与模型错误应分开记录;修正参考标注后,应更新数据版本并重新计算对照结果,避免让新模型与旧标注下的历史分数直接比较。
每次改动都回看目标错误组和整体分布。降低阈值可能减少漏检,也可能扩大误报;连通域过滤可能清理噪点,也可能删除真实小目标。只有前后使用相同评估协议,这些取舍才有可解释性。
如果持续根据测试样本修方案,这批数据就承担了验证作用,需要另设最终留出集。误差分析的产物应是下一次明确的实验,而不是一份越来越长、却无法指导行动的截图收藏。
参考
- scikit-learn
confusion_matrix:错误类别与矩阵方向的接口约定。 - Datasheets for Datasets:记录数据来源、组成与使用边界的研究框架。