跳到主要内容

精确率、召回率与数据增广:把 99.7% 的骗子改造成能用的筛查器

这一章讲三件事: 上章那个 99.7% 的骗子怎么被两个新指标当场拆穿;训练为什么会被 400:1 的失衡数据拉塌、怎么救;以及救活之后冒出来的过拟合,怎么用数据增广压下去。 位置:三步流水线第 ③ 步(分类)的收官。本章结束时,分类器第一次达到「对放射科医生有用」的水平。

1. 两只狗:错误的两个方向

书里用两只狗给这章定了调1:

  • Chirpy(小猎犬):见什么都叫——消防车、猫头鹰、末班车。窃贼来了它一定叫,但你每晚被它吵醒三次。从不错过,代价是全是误报。
  • Dozer(老猎犬):睡得很死,但一旦叫了,几乎可以确定出了事。从不乱报,代价是漏掉的多。

上一章的模型就是 Dozer 的极端版:它一次都不「叫」(全判阴性),所以永远不误报——也永远抓不到结节。两种错,代价完全不同:筛查场景漏掉一个肿瘤是事故,多报一个可疑点只是让医生多看一眼。单一指标分不清这两种错,这正是 99.7% 能骗人的原因。

2. 把「对」和「错」各拆成两种

判定一个二分类结果,先按「真实是什么 × 模型说什么」分成四格2:

模型说「是结节」 模型说「不是」
真是结节 真阳性 TP(抓到了) 假阴性 FN(漏了)
不是结节 假阳性 FP(误报) 真阴性 TN(放对)

图说:左列是「报警」,右列是「放行」;上行错是漏,下行错是冤。

两个新指标各盯一列3:

  • 召回率(recall)= TP ÷ (TP+FN):真结节里,抓住了多少。「别漏」。医学文献里它也叫灵敏度(sensitivity)。
  • 精确率(precision)= TP ÷ (TP+FP):报警的里面,有多少是真的。「别冤」。

Chirpy 召回率满分、精确率惨淡;Dozer 相反。一个好筛查器要两个都高——但它们是跷跷板:阈值往「多报」挪,召回涨精确跌。

3. F1:把两个数压成一个,但压得有讲究

调参时要一个数来定输赢,把精确率(P)和召回率(R)合成 F1。书里把候选方案逐个试了一遍,每种输法都讲得明白4:

  • 算术平均 (P+R)/2:P=1、R=0 和 P=R=0.5 都得 0.5——Dozer 式废物和平衡选手同分,不行。
  • 取小 min(P,R):方向对(逮住短板),但太粗:P 从 0.5 涨到 0.9,只要 R=0.5 不动,分数一动不动,白改进。
  • 相乘 P×R(几何平均的平方):在指标都还低的早期,两个小于 1 的数一乘直接塌到接近 0,前期进步全被压没。
  • F1 = 2PR/(P+R),即 P 和 R 的调和平均(倒数的平均再取倒数,天然被较小的那个拽住):等值线有一道深「肘弯」,把分数往「两个都高」的角落赶,短板一动分数就动。

主走查来了——拿新指标重读上一章的 E1 日志5:

旧指标(第 13 章):E1 trn 99.7% correct ← 看着像 A+
新指标(本 章):E1 trn 0.0000 prc, 0.0000 rcl, nan f1

图说:同一个模型,同一轮训练。换个量法,从 A+ 变成零分。

逐格对:模型全判阴性,TP=0 → 召回率 0/(0+136)=0;精确率 0/(0+0) 是除零,报 nan(计算里「不是一个数」的标记);F1 同为 nan。书里有句狠话:从 A+ 跌到零,算你走运——如果指标没把这个模型报成垃圾,那是指标的缺陷,不是模型的优点5

4. 治根:为什么 400:1 会把训练拉塌

指标只是照出病,接着治病。为什么模型塌成「全判阴性」?书里把第一个 epoch 的梯度来源拆成了三组6:

50 万个阴性样本:约一半已被判对(25 万,梯度≈0,不推)
一半还想把输出往「阴」拉(25 万,使劲推)
1215 个阳性样本:约一半想把输出往「阳」拉(约 600,使劲推)

推力比 ≈ 250000 : 600 ≈ 400 : 1 —— 方向没有任何悬念

换成批次视角更直观:batch 32 个样本,平均 15 个批次才轮到 1 个阳性;其余 14 个批次里,每一个样本都在把模型往「判阴」推6。模型不是学坏了,它是找到了损失函数面前的最优解——我们给的目标本身有问题。

解法:交替采样,把数据掰回 1:1

书里改了 Dataset 的取样逻辑:加一个 ratio_int 开关,奇数下标返回阴性样本、偶数下标返回阳性样本,取模回绕——阳性样本不够就循环着用;__len__ 硬编码(把数值直接写死在代码里)成 200000(不再等于真实候选数),让每个 epoch 短一点7。DataLoader 自带的 sampler 机制也能做加权采样,书里讨论后放弃了:那样「哪些样本算阳性」的知识会泄漏到 Dataset 外面,破坏封装7

一个刻意的「不修」:验证集保持 400:1 不平衡——因为真实世界就是不平衡的,评估必须模拟部署环境8

效果分两步兑现,先看第一轮(E1,平衡后)9:训练集 F1 0.928——上一章同一轮是 nan(精确率召回率双零);验证集召回率 79.4%,136 个真结节抓住了 108 个,上一章是 0 个;精确率 0.110、F1 0.194。

代价记在阴性那一侧:阴性样本的正确率从 100% 退到 98.4%,拿这 1.6% 换来阳性那边从 0% 到 79.4%。而且这一轮只喂了 20 万个样本,不到不平衡版那 50 多万的一半,时间也省了一半以上9

精确率 0.110 看着惨,书里紧跟着算了一笔账把它救回来:54971 个阴性样本里哪怕只错 1%,也是 约 550 个假警报,而整个验证集统共只有 136 个真阳性——误报是真阳性的四倍。但换个方向看这笔账:医生多看 550 个小方块,省掉的是亲手翻完 55107 个;筛掉 98.4% 的阴性,等于把放射科医生的效率放大约 10 倍9。筛查器的精确率可以低,只要误报便宜。

第二步是作者的追问:还有 20.6% 的阳性漏在外面(136 个里 28 个没抓到),再多训几轮会不会补上?会——第二轮 E2 的召回率涨到 84.6%(115/136),比 E1 多抓 7 个10。这个 84.6% 就是下一节那条曲线的起点,而不是终点。

5. 新病:1215 个阳性被背了下来

「多训几轮」这个念头,继续往下跑就变成了一个老故事。把 20 轮的验证集召回率排成一列看10:

E2 84.6%(115/136) ← 上一节的终点,这里是起点
E5 82.4%(112/136)
E10 76.5%(104/136)
E20 72.1%( 98/136)

图说:同期训练集 F1 从 0.987 升到 0.997。训练集越来越好,验证集越来越差。

一升一降是过拟合的教科书形状(第 05 章的定义):训练损失逼近零、验证损失反而在涨10。多训的那 18 轮不但没补上漏掉的 28 个,还又赔进去 17 个。

原因书里点破了:阳性训练样本只有 1215 个,交替采样让每个 epoch 反复见同一批,重复再多次,也不会变得更难记10。书的比喻:好模型看脸龄,学的是皱纹和灰发;过拟合模型记的是「那个发型、那副眼镜——是 Frank,62.8 岁」,连 Frank 的儿子都被认成 Frank11

解法:数据增广——让模型想背也背不下

数据增广(data augmentation)是对训练样本做合成修改,每个 epoch 看到的都是没见过的变体:记住所有变体比学会规律还难,模型被迫选后者12

书里先给了一个反例划清「什么不算增广」:把每张图角上 4 个像素的红色通道改成随机值,数据集能「扩大 40 亿倍」——但主体原封不动,照背不误。增广的变体必须像真实数据的另一种可能,不能只像原图的噪点版12

五种真增广,每条都有医学语境的讲究13:

增广做什么讲究
翻转镜像上下方向对应重力,临床项目得先问专家能不能翻
平移挪几个体素中心不必死守在正中央
缩放放大缩小结节本来就有大有小
旋转转个角度只在横断面(X-Y)内转——体素非立方,绕别轴转会拧坏形状
加噪体素值加随机扰动破坏性:加多了会淹没真实结构,实测单用反而更差

工程上一条死规矩:缓存必须放在增广之前。第 12 章的磁盘缓存存的是「原始切块」;如果存增广后的结果,每个 epoch 读到的都是同一批变体,增广白做——而且增广函数本身一改,旧缓存全是错的13

结果(书里 TensorBoard 曲线的结论):全增广版召回率最高、也最扛过拟合,代价是总正确率和精确率都降;单用旋转几乎追平全增广且精确率更高。书里按场景选了全增广:筛查要的是召回率,F1 只用来决定保存哪个 epoch 的权重14

6. 作者的判断与证据

说法性质
精确率/召回率/F1 的定义与取舍标准内容,四种合成法的对比是书里的推演,可复算4
「从 A+ 到零算你走运」作者观点,但论证在书内站得住5
400:1 拉塌梯度的三组账有据,基于第一个 epoch 的实际样本数6
交替采样优于 sampler 方案作者的工程判断,理由是封装;可争论7
「效率放大 10 倍」有据的换算(550 假警报 vs 55107 全量),依赖「误报便宜」的前提9
噪声增广有害、旋转最划算实测结论(各增广单独跑的曲线),换数据集未必成立14

书里还有一个必须转达的专栏:模型从带有现实偏见的数据里学习,会把偏见一并学走——「和人一样,种族歧视是学来的」。这问题至今没有通用解法15

7. 边界与局限

  • F1 给精确率和召回率同等权重;筛查场景其实更看重召回率,书里用「F1 只决定保存点、场景决定选哪个模型」绕开了,更重的场合该用带权重的 Fβ(书外概念,书里没讲)。
  • 交替采样让每个 epoch 只见到数据的一个子集,极端样本可能长期轮不上。
  • 增广参数(平移几个体素、噪声多大)是手调的,书里没给系统搜法。
  • 「效率 10 倍」依赖误报成本低的假设;若每个假警报都触发昂贵复查,结论要重算。

8. 可带走的

  1. 错误分两种,代价各不同;单一指标分不清,先想清你的场景怕哪种。
  2. 召回率管漏、精确率管冤;阈值是两者的跷跷板。
  3. F1 是调和平均,天然逮短板;别用算术平均,它给 Dozer 式模型发奖。
  4. 指标若没把垃圾模型报成垃圾,是指标的缺陷——换指标比调模型优先。
  5. 不平衡会定死梯度方向:算一下「15 个批次才见 1 个阳性」这种账,比看 loss 更早预知塌方。
  6. 训练集可以掰平衡,验证集必须保持真实分布——评估要模拟部署。
  7. 小样本(样本很少的那个类别)类被反复见 = 被背下来;增广让「背」比「学」更难。
  8. 增广要像真实数据的另一种可能;缓存放在增广之前;破坏性增广(噪声)慎用。

9. 原文地图

主题原书章原文位置
Chirpy 与 Dozerch14text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:110(搜「Chirpy」) · :148(搜「Dozer barks」)
TP/FP/FN/TN 四格ch14text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:140(搜「false positive is an event」)
召回率与精确率ch14text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:251(搜「Make sure you never miss」) · :266(搜「sensitivity」)
F1 与四种合成法ch14text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:8(搜「F1 score」) · :430(搜「harmonic mean」) · :434(搜「deep elbow」)
新指标现形 nanch14text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:542(搜「nan f1」)
400:1 与 15 批次账ch14text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:616(搜「400:1 ratio」) · :677(搜「15 batches」)
ratio_int 交替采样ch14text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:768(搜「ratio_int」) · :838(搜「200000」)
验证集保持不平衡ch14text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:716(搜「real world is imbalanced」)
平衡后 E1 的实测日志ch14text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:896(搜「0.9277 f1」) · :900(搜「0.7941 recall」) · :903(搜「108 of 136」)
550 假警报与 10 倍效率ch14text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:914(搜「54,971 × 0.01」) · :922(搜「radiologist」)
「再多训几轮」与 20 epoch 过拟合ch14text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:926(搜「20.6% of positive samples」) · :939(搜「115 of 136」) · :963(搜「0.7206」)
Frank 脸龄比喻ch14text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:1042(搜「Frank」)
40 亿倍伪增广ch14text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:1095(搜「4 billion」)
五种增广与缓存顺序ch14text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:1106(搜「five specific types」) · :1174(搜「caching」) · :1247(搜「X-Y plane」)
增广结果取舍ch14text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:1435(搜「rotation-augmented」) · :1439(搜「use case」)
偏见专栏ch14text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:700(搜「racism is learned」)

Footnotes

  1. 出处:「14 Improving training with metrics and augmentation」第 110 段(text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:110,搜「Chirpy」)与第 148 段(:148,搜「Dozer barks」)。Chirpy 见什么都叫(误报多),Dozer 一叫必出事(漏报多);「Chirpy 有麻烦数量的假阳性」「Dozer 有麻烦数量的假阴性」。

  2. 出处:「14 Improving training with metrics and augmentation」第 140 段(text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:140,搜「false positive is an event」)与第 147 段(:147,搜「true positives」)。假阳性=被错判为关注对象的事件;真阳性=被正确判中的关注对象;图里用猫代表 FP、窃贼代表 TP、鼠贼代表 FN、鸟代表 TN。

  3. 出处:「14 Improving training with metrics and augmentation」第 251 段(text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:251,搜「Make sure you never miss」)与第 266 段(:266,搜「sensitivity」)。召回率=真阳性/全部阳性,「保证不错过任何事件」;某些语境下召回率叫灵敏度。

  4. 出处:「14 Improving training with metrics and augmentation」第 8 段(text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:8,搜「F1 score」)、第 405 段(:405,搜「elbow」)、第 430 段(:430,搜「harmonic mean」)、第 437 段(:437,搜「minimum」)与第 485 段(:485,搜「geometric mean」)。F1 是精确率与召回率的调和平均;算术平均的等值线没有肘弯、取小太粗、乘积在早期塌到接近零;F1 的等值线有深肘弯,奖励两者平衡。 2

  5. 出处:「14 Improving training with metrics and augmentation」第 542 段(text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:542,搜「nan f1」)与第 555 段(:555,搜「division by zero」)。新指标下 E1:trn 0.0000 prc、0.0000 rcl、nan f1;val 同为 nan——「从 A+ 跌到零,如果幸运的话;指标若没报出垃圾,那是指标的缺陷」。 2 3

  6. 出处:「14 Improving training with metrics and augmentation」第 616 段(text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:616,搜「400:1 ratio」)与第 677 段(:677,搜「15 batches」)。阴性阳性 400:1,「压垮性的不平衡」;约 500/32 ≈ 15 个批次才见到一个阳性样本,之前的批次全是阴性事件。 2 3

  7. 出处:「14 Improving training with metrics and augmentation」第 768 段(text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:768,搜「ratio_int」)、第 759 段(:759,搜「external sampler」)与第 838 段(:838,搜「200000」)。LunaDataset 加 ratio_int 控制正负交替(ratio_int=2 即 2:1 阴:阳);sampler 方案被放弃以保持封装;len 硬编码 200000 缩短 epoch。 2 3

  8. 出处:「14 Improving training with metrics and augmentation」第 716 段(text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:716,搜「real world is imbalanced」)。验证集不掰平衡:「要在真实世界里用,而真实世界就是不平衡的」。

  9. 出处:「14 Improving training with metrics and augmentation」第 896 段(text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:896,搜「0.9277 f1」)、第 900 段(:900,搜「0.7941 recall」)、第 903 段(:903,搜「108 of 136」)、第 905 段(:905,搜「This seems much better」)、第 912 段(:912,搜「Total negative validation samples」)、第 914 段(:914,搜「54,971 × 0.01」)与第 922 段(:922,搜「radiologist」)。--balanced 跑出来的 E1 日志:trn f1 0.9277;val 精确率 0.1102、召回率 0.7941、f1 0.1935,其中 val_pos 79.4%(108 of 136)。作者原话是「放弃了约 1.6% 的阴性正确率(100% → 98.4%),换来 79% 的阳性正确率(0% → 79.4%)」,而且只用了 20 万训练样本、不到不平衡版的一半时间。账:54971 阴性 × 1% 误报 ≈ 550 假阳性,对 136 真阳性约 4:1;筛掉 98.4% 阴性,「让过度劳累的放射科医生效率约高 10 倍」。 2 3 4

  10. 出处:「14 Improving training with metrics and augmentation」第 926 段(text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:926,搜「20.6% of positive samples」)、第 939 段(:939,搜「115 of 136」)与第 963 段(:963,搜「0.7206」)。作者在 E1 之后说「还剩下漏掉的那 20.6% 阳性样本(因为我们正确识别了 79.4%),或许再多训几个 epoch 会有帮助」,于是跑 --epochs 20:E2 val_mal 84.6%(115 of 136)→ E5 82.4% → E10 76.5% → E20 降到 72.1%;同期 trn F1 升到 0.997、val 损失上升;「阳性训练集只有 1215 个,重复多次也不会更难记」。 2 3 4

  11. 出处:「14 Improving training with metrics and augmentation」第 1042 段(text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:1042,搜「Frank」)。过拟合的脸龄模型记的是「那发型那眼镜=Frank,62.8 岁」;连 Frank Jr. 也被认成 Frank。

  12. 出处:「14 Improving training with metrics and augmentation」第 1084 段(text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:1084,搜「synthetic alterations」)与第 1095 段(:1095,搜「4 billion」)。增广=对单个样本做合成修改;反例:改角上 4 个像素能把数据集「扩大 40 亿倍」但毫无用处,对照组是左右翻转。 2

  13. 出处:「14 Improving training with metrics and augmentation」第 1106 段(text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:1106,搜「five specific types」)、第 1174 段(:1174,搜「caching」)、第 1182 段(:1182,搜「gravity」)、第 1247 段(:1247,搜「X-Y plane」)与第 1267 段(:1267,搜「destructive」)。五种:翻转/平移/缩放/旋转/加噪;用 affine_grid+grid_sample 加三线性插值实现;缓存必须位于增广之前;上下翻转涉及重力方向要问专家;旋转只在 X-Y 平面(体素非立方);噪声是破坏性的。 2

  14. 出处:「14 Improving training with metrics and augmentation」第 1423 段(text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:1423,搜「fully augmented」)、第 1435 段(:1435,搜「rotation-augmented」)与第 1439 段(:1439,搜「use case」)。全增广错得更多但召回率好得多、更扛过拟合;旋转单用几乎追平且精确率更好;按用例(要召回率)选全增广,F1 决定保存哪个 epoch。 2

  15. 出处:「14 Improving training with metrics and augmentation」第 691 段(text/22-ch14-14-improving-training-with-metrics-and-augmentat.txt:691,搜「discrimination」)与第 700 段(:700,搜「racism is learned」)。专栏:「discrimination」在分类里是中性词;但模型从含现实偏见(如逮捕率的种族偏差)的数据学习而不纠正,「和人一样,种族歧视是学来的」——未解问题。