山城水果合作社的传送带前,老周站了二十年。他的活儿听起来简单:眼睛一瞟,手一拨,好果进礼盒,烂果进废料箱。碰上中秋礼盒季,他还得把苹果、梨、橙子分进三个筐。后来合作社上了自动分拣机,摄像头咔嚓一拍,屏幕蹦出一个数字——0.92,意思是机器判断「这个苹果坏掉」的把握有九成二。医疗影像 AI 干的事,跟老周一模一样,只是把「水果」换成了 CT、X 光、病理切片,把「筐」换成了诊断结论:这张片子里有没有病灶?良性还是恶性?属于哪种病理分型?这篇文章就借老周的分拣台,把医疗影像分类的二分类、多分类、类别不均衡、数据增强和评估避坑,一件件讲明白。
分类模型是医疗影像 AI 的地基工程。理解二分类与多分类的落地方式、类别不均衡的处理、以及以敏感度为核心的评估体系,是医疗 AI 算法工程师和产品经理入门的第一课。
可视化演示
展示医疗影像二分类决策边界与混淆矩阵热力图,支持模式切换查看良恶性分类效果与诊断性能指标分布。
本节配有交互动效(进入视口后自动加载,约 3KB)。
医疗影像二分类决策边界 良性样本:绿色点集群分布在决策边界一侧,特征值较低 恶性样本:红色点集群分布在另一侧,特征值较高 决策边界:非线性边界有效分离两类病灶特征 y = sigmoid(w·x + b) 类别不均衡需加权损失函数处理。
分类任务概览
山城水果合作社的传送带前,老周面前摆着两种筐。一种只有两个筐:合格、不合格——这是二分类;另一种是一排筐:苹果、梨、橙子各归各——这是多分类。不管是哪种活儿,核心就一句话:看一眼水果,扔进该去的筐。
医疗影像分类模型做的事一模一样,只是「眼睛」换成了深度学习网络,水果换成了 CT、X 光、病理切片,筐换成了诊断标签。输入一张影像 $x$,模型输出一个类别 $y$:有没有病灶、良性还是恶性、属于哪种病理分型。在深度学习里,分类就是学习一个从图像到标签的映射函数。
按候选类别数量,任务分两种:二分类只有两个候选类别,是医疗 AI 产品的地基;多分类候选类别多于两个,是二分类的延伸。医疗影像分类还有三个特点:样本少(常常只有几百到几千张),标注贵(需要高年资医生逐像素勾画),而且医生会追问「凭什么这么判」——所以对可解释性和评估严谨性的要求,比通用图像分类高得多。这也是同样一个分类模型,在医疗场景里要格外小心对待的原因。
1. 条件概率 $P(y = c \mid \boldsymbol{x})$:给定一张影像 $\boldsymbol{x}$,模型估算它属于类别 $c$ 的可能性,比如「这是腺癌」的概率是 0.7。
2. 遍历所有类别 $c \in \{1, 2, \ldots, K\}$:把正常、腺癌、鳞癌……每个候选类别都依次算一遍概率,一个都不能漏。
3. 取最大值 $\arg\max$:比较所有概率,挑出最大的那个类别作为输出,就像老周看哪个筐的「分数」最高就把水果扔进去。
4. 输出预测 $\hat{y}$:最终得到的 $\hat{y}$ 就是机器给出的标签,比如「有病灶」或「腺癌」。
老周的功夫是练出来的——看一眼便知好赖;模型的功夫是算出来的——看一万张、算一千遍概率。接下来,我们把老周面前的几个筐一个个打开,看看每种分类任务背后的门道。
二分类落地
合作社最赚钱的活是给礼盒挑烂果:传送带嗖嗖过,老周眼睛一瞟,手一拨,好果进礼盒,烂果进废料箱。这个「过/不过」的判断,就是二分类。上了自动分拣机后,摄像头咔嚓一拍,屏幕显示 0.92——机器认为「这是烂果」的把握有九成二。
那个 0 到 1 的数字,来自 sigmoid 函数。模型先对影像提取特征,加权求和得到一个原始分数 $z$,再经 sigmoid 压进 (0, 1) 区间,当作阳性概率。医疗里最常见的二分类问题就是「有没有肺结节」「乳腺钼靶是良性还是恶性」,都属于这种二选一。模型最终输出的不是类别本身,而是一个概率,决策由人来做。
输出概率后还需要一个阈值,默认 0.5:不小于 0.5 判阳性,否则判阴性。但医疗场景里阈值是可以拨动的——往左拨,更敏感,漏诊变少但误诊变多;往右拨,更特异,误诊变少但漏诊变多。筛查类产品通常会往左拨:先提示「有病灶」,再让医生复核。漏掉一个病灶的代价,远大于多复查一张片子。这也是二分类落地时最核心的工程决策。
1. logit 值 $z$:模型对输入特征加权求和得到的原始分数,类似老周凭手感给出的「可疑程度分」,可正可负。
2. 指数映射 $e^{-z}$:把任意实数映射到正数区间,分数越高,这个值越小。
3. 归一化 $\frac{1}{1 + e^{-z}}$:分母永远大于 1,整体输出被限制在 (0, 1) 之间,大数变 1,小数变 0。
4. 概率输出 $\sigma(z)$:输出就是「坏果概率」,超过阈值(如 0.5)就判为病灶。
老周把关的底线是「烂果绝不能进礼盒」,医疗二分类的底线是「病灶绝不能放走」。那根阈值拨杆拨到哪儿,取决于你更怕漏诊还是更怕误诊——这是临床决策里永远绕不开的权衡。
多分类落地
中秋礼盒要装三种水果,老周得把混装的一筐分成三堆:苹果、梨、橙子,有时候还得分出「碰伤的苹果」「熟透的梨」这种细类。这就是多分类:从一堆候选里,找出到底该进哪个筐。筐越多,活儿越精细,责任也越大。
医疗影像的多分类大多出现在肿瘤领域:一张病理切片,是腺癌、鳞癌还是小细胞肺癌?一张眼底照片,是轻度、中度还是重度病变?模型这时不再只输出一个 0 到 1 的概率,而是输出一个长度为 $K$ 的向量,每个分量代表「属于第 $k$ 类」的概率,加起来恰好等于 1。把原始分数变成这种概率分布的工具,叫 softmax。它和二分类的 sigmoid 是一家人,只是从「二选一」扩展到了「K 选一」。
softmax 先把每个类别的分数做指数化,再除以所有类别指数化分数之和。于是模型会给出「腺癌 0.70、鳞癌 0.20、小细胞肺癌 0.10」这样的答案,取最大值就是预测类别。多分类还能延伸出多标签分类——一张 CT 可以同时有肺结节和胸膜增厚,相当于一个水果可以同时进两个筐,实践中一般拆成多个二分类来做,每个二分类只管「有没有某一种病」。
1. 原始分数 $z_i$:模型对第 $i$ 个类别(比如「鳞癌」)给出的原始得分,通常可正可负。
2. 指数化 $e^{z_i}$:把分数变成正数,同时放大分数之间的差距,高分更突出。
3. 求和 $\sum_{j=1}^{K} e^{z_j}$:把所有类别的指数化分数加起来,当作「总分」分母。
4. 归一化:每个类别的概率等于自己的指数分除以总分,因此全部概率之和为 1。
老周分三筐的诀窍,不是只看颜色,而是颜色、形状、手感一起打分,哪个筐分数高进哪个筐。多分类模型学的正是这套综合打分的本事。
类别不均衡
合作社的果园管理得极好,一百万个苹果里才有一个烂的。老周要是偷懒全部喊「合格」,准确率高达 99.9999%,能评上年度最佳质检员——但烂果一个都没挑出来,客户的投诉电话马上打爆。这就是类别不均衡的陷阱:准确率是个会骗人的优等生。数据失衡时,模型只要「躺平」就能拿高分,但恰恰什么有用的事都没干。
医疗数据天生不均衡:一万人做肺癌筛查,确诊的可能只有十几个;公开数据集里正常切片常常是病灶切片的几十倍。模型天然会「讨好」多数类,因为只要把一切都判成正常,总损失就很小。于是你会看到准确率 99% 的模型,实际上一个病灶都没发现。这种「高准确率、零召回」的模型在医疗场景里不仅没用,还可能耽误病情。
常见对策有三条。一是过采样:把少数类样本复制或做增强,让两类数量接近;二是欠采样:从多数类里随机抽一部分(适合数据量很大的时候);三是损失加权:在交叉熵损失里给少数类更大的权重,也是最推荐的做法——相当于「判错一个病灶,罚十倍」。权值怎么设?一般按类别频率的反比起步,再在验证集上调,目标是让敏感度和特异度都过线。
1. 单样本损失 $-\log p_{y_i}$:模型给真实类别 $y_i$ 的概率越大,损失越小;概率越接近 0,惩罚越大。
2. 类别权重 $w_{y_i}$:给少数类(如病灶)一个大于 1 的权重,把它的错误「放大」十倍甚至更高。
3. 求平均 $\frac{1}{N} \sum_{i=1}^{N}$:对整批样本求平均损失,作为一次梯度更新的依据。
4. 梯度下降更新:损失被少数类「带着跑」,每次更新都更认真地学少数类样本。
给少数类加权,就像在废料箱上贴告示:「漏掉一个烂果,扣当月奖金;误扔一个好果,只罚五块。」模型自然就把注意力放在那些容易被放走的烂果上。
数据增强技巧
老周带新徒弟,第一天指着苹果说:这是苹果。第二天,他故意把苹果转个面、擦上泥点、混进几个歪果,再让徒弟认。练多了徒弟就明白:不管苹果怎么转、怎么脏,它还是苹果。医疗影像同理——病人躺的角度不同、机器的曝光参数不同,病灶在片子上看起来就有差异,但诊断结论不该变。模型也得经历这种「多看几面」的训练。
数据增强,就是训练时对影像做一系列无害变换,生成多个变体,让同一个病灶以不同姿态出现在模型面前。好处有两层:一是变相扩大样本量,缓解医疗数据不足的窘境;二是逼模型学会「旋转不变、光照不变」,减少过拟合。对医疗影像这种「样本少、标注贵」的场景,数据增强几乎是免费的训练数据。
医疗影像里常用三类增强。几何变换:随机旋转、平移、水平翻转——注意翻转要符合解剖学,左右肺的掩膜要同步镜像;像素变换:调整亮度、对比度、灰度范围,模拟不同机器的成像差异;模拟噪声:叠加高斯噪声、模糊、伪影,模拟低剂量扫描得到的退化图像。增强不是越多越强,要控制幅度,让变换后的图像仍然「像一张真实的片子」。
1. 变换 $T_m(\boldsymbol{x}_i)$:对第 $i$ 张影像做第 $m$ 种增强,比如旋转 15°、加噪声、调亮度,生成一张「新片子」。
2. 预测 $f(\cdot; \theta)$:用参数为 $\theta$ 的模型对增强后的影像做分类预测。
3. 损失 $\ell(y_i, \cdot)$:计算预测与真实标签的差距,跟普通训练一模一样。
4. 多重增强平均 $\frac{1}{M} \sum_{m=1}^{M}$:同一张原图的 $M$ 个变体的损失取平均,相当于一道菜让学徒尝 $M$ 种做法,最后综合打分。
数据增强的哲学,就是老周那句口头禅:同一个苹果,得多看几面才敢下结论。模型看得越全,到了真实世界才越稳。
评估与避坑
季度考核,老周交出一份报告:「本月分拣准确率 99.8%。」老板正要表扬,客户投诉说礼盒里出现了烂果。原来老周只统计了「总共分对多少」,没统计「烂果漏掉几个」。评价一个分拣员,不能只看总准确率,要拆开看:烂果逃走了几个(漏诊)、好果被扔了几个(误诊)。
医疗分类的评估也靠这几个数,它们来自混淆矩阵:TP 真阳性、FN 假阴性(漏诊)、TN 真阴性、FP 假阳性(误诊)。由此衍生出敏感度、特异度、AUC 等指标。筛查类产品敏感度优先,先把可疑的都捞出来;确诊类产品要同时兼顾特异度,减少不必要的穿刺和手术。AUC 则是把不同阈值下「敏感度-特异度」的权衡画成 ROC 曲线,用曲线下面积衡量模型把所有样本按风险正确排序的能力,不依赖具体阈值。
指标之外还有三个绕不开的坑。一是数据泄露:同一患者相邻的几十张切片被随机分到训练集和测试集,模型「考试时见过答案」,评估分虚高 10 个点都不奇怪,必须按患者级别划分数据集。二是标注不一致:两位医生可能对同一张片子给出不同标签,标注本身有噪声,可以考虑多位医生标注、取多数票。三是别在测试集上反复调参,否则测试集慢慢就变成了训练集,分数自然越来越好看。
1. TP 真阳性:实际是病灶,模型也判为病灶——烂果被正确扔进废料箱。
2. FN 假阴性(漏诊):实际是病灶,模型却说正常——烂果混进礼盒,最危险的一种错误。
3. 敏感度 Sens:所有真实病灶中被正确检出的比例,分母是 $TP + FN$,漏诊越少越接近 1。
4. 特异度 Spec:所有真实正常人中被正确排除的比例,分母是 $TN + FP$,误诊越少越接近 1。
后来老周改成了三行汇报:烂果漏几个、好果扔几个、客户投诉几次。医疗 AI 的评估,盯住的也永远是那几个最要命的数字——漏诊率和误诊率,而不是漂亮的总准确率。
AI 应用场景
肺结节 CT 筛查(二分类)
阶段:模型训练与临床部署
解决的问题:影像科医生每天要翻几百张 CT,眼睛疲劳时最容易漏掉小结节。传统方式完全靠医生肉眼逐层看片,耗时且受疲劳影响,漏诊率难以控制。AI 先做「有没有肺结节」的二分类,把可疑片挑出来优先给医生复核,并刻意把敏感度调到 95% 以上,宁可多报也不漏报。
具体案例:某三甲医院在体检 CT 流程中接入筛查模型,阴性片直接出报告,可疑片由医生二次确认,平均报告时间从 20 分钟缩短到 5 分钟。产品上线时把阈值往左拨,保证「任何可疑都不能放走」。
病理切片肿瘤分型(多分类)
阶段:模型选型与多分类落地
解决的问题:病理医生资源稀缺,分型判断主观性强。传统方式下,两位医生对同一张切片的分型一致率只有八成左右。多分类模型把 H&E 染色切片分为腺癌、鳞癌、小细胞肺癌三类,输出各类概率供医生参考。
具体案例:某病理 AI 公司在肺癌数据集上使用 softmax 多分类,辅助医生把分型一致率从 82% 提升到 91%。模型还对低置信度样本(最大概率低于 0.6)主动「拒判」转人工,避免硬着头皮瞎猜。
糖网病眼底筛查(类别不均衡 + 数据增强)
阶段:数据处理与训练策略
解决的问题:社区筛查的眼底照片中健康样本占 95% 以上,病变样本极少,直接训练模型会「全判健康」。这是典型的类别不均衡场景,需要加权损失和数据增强双管齐下。
具体案例:某基层筛查项目中,对少数类病变样本做旋转、亮度增强,损失函数给病变类 5 倍权重,最终模型在保持 95% 特异度的同时,敏感度达到 92%,成为社区医生手里的「第二双眼睛」,把筛查成本降了一个数量级。
Python 演示
import torchimport torch.nn as nn torch.manual_seed(0) # 构造模拟数据: 800 个正常样本(类别0), 200 个病灶样本(类别1)n_normal, n_lesion = 800, 200normal = torch.randn(n_normal, 8) * 0.6lesion = torch.randn(n_lesion, 8) * 0.8 + 1.2X = torch.cat([normal, lesion])y = torch.cat([torch.zeros(n_normal, dtype=torch.long), torch.ones(n_lesion, dtype=torch.long)]) perm = torch.randperm(X.shape[0])X, y = X[perm], y[perm] class MLP(nn.Module): def __init__(self): super().__init__() self.net = nn.Sequential( nn.Linear(8, 16), nn.ReLU(), nn.Linear(16, 2) ) def forward(self, x): return self.net(x) def train(use_weight): model = MLP() opt = torch.optim.Adam(model.parameters(), lr=0.01) weight = torch.tensor([1.0, 4.0]) if use_weight else None criterion = nn.CrossEntropyLoss(weight=weight) for _ in range(200): opt.zero_grad() loss = criterion(model(X), y) loss.backward() opt.step() with torch.no_grad(): pred = model(X).argmax(dim=1) acc = (pred == y).float().mean().item() sens = ((pred == 1) & (y == 1)).sum().item() / (y == 1).sum().item() spec = ((pred == 0) & (y == 0)).sum().item() / (y == 0).sum().item() return acc, sens, spec acc, sens, spec = train(False)print("普通训练 acc=%.3f sens=%.3f spec=%.3f" % (acc, sens, spec))acc, sens, spec = train(True)print("加权训练 acc=%.3f sens=%.3f spec=%.3f" % (acc, sens, spec))
normal = torch.randn(n_normal, 8) * 0.6模拟 800 张「正常」影像的特征向量,特征值集中在小范围。lesion = torch.randn(n_lesion, 8) * 0.8 + 1.2模拟 200 张「病灶」影像,特征整体偏高,两类数据仍有重叠,模拟真实世界的模糊边界。weight = torch.tensor([1.0, 4.0]) if use_weight else None给病灶类 4 倍损失权重,让模型不敢忽视少数类。criterion = nn.CrossEntropyLoss(weight=weight)传入类别权重的交叉熵损失,少数类犯错被放大。sens = ((pred == 1) & (y == 1)).sum().item() / (y == 1).sum().item()敏感度:病灶样本里被正确检出的比例。spec = ((pred == 0) & (y == 0)).sum().item() / (y == 0).sum().item()特异度:正常样本里被正确排除的比例。
常见误区
误区「测试集准确率 99%,模型肯定没问题,可以直接上线了。」在医疗数据上,全判正常也能拿到 99% 的准确率,但病灶一个都没被发现。
正解一定要结合敏感度、特异度、AUC 一起看。就像老周报「分拣准确率 99.8%」,却没说他漏掉了所有烂果。医疗场景要先看漏诊率和误诊率,再看整体准确率。
为何常见:通用图像分类任务里类别基本均衡,准确率有一定参考价值;而医疗数据严重不均衡,初学者容易把惯性思维带过来。
误区「病灶样本太少,我把这几张图复制十遍,不就有 10 倍数据了?」
正解简单复制不增加任何新信息,模型看到的还是同一张图,只会更快过拟合。真正的增强是旋转、翻转、调亮度、加噪声,每次变换都产生一个「没见过」的新变体,才叫信息增益。
为何常见:把「训练时看到的样本次数」误当成「数据多样性」,忽略了增强的本质是模拟真实世界的变化。
误区「增强就是随便转转、翻翻,把通用图像那套拿来直接用。」
正解医疗影像有解剖学语义:左右翻转要确认脏器是否对称、掩膜要同步变换;灰度反转可能让 CT 的黑白含义颠倒;过强的旋转可能让器官变形失实。增强策略也要在验证集上验证,不能盲目堆强度。
为何常见:以为数据增强总是无损的,没意识到医学图像里「方向和灰度都是有意义的信号」。
误区「把所有图像随机打乱,按 8:2 分训练测试集,模型效果很好。」
正解同一患者的几十张相邻切片如果被分到两边,模型相当于在训练时「见过」测试患者的信息,评估分数虚高。必须按患者 ID 分组,保证同一患者的全部图像只出现在一侧。
为何常见:通用分类数据集(如 ImageNet)每张图是独立个体,随机划分没问题;医疗数据同一患者有多张图,照搬方法就踩坑。
误区「敏感度 99%,漏诊几乎为零,这模型太棒了!」
正解敏感度和特异度是一对跷跷板:阈值往左拨,敏感度升高,误诊也变多,医生会被海量假阳性淹没,开出一堆不必要的穿刺复查。临床落地要根据筛查还是确诊场景,找两者的平衡点。
为何常见:只看到「漏诊最可怕」,忘了「误诊也不是零成本」,尤其是过度复查和穿刺带来的风险与开销。
面试题
Q1. 一张胸部 CT「判断有无肺结节」最贴近哪类任务?
- A.二分类任务← 正确答案
- B.多分类任务
- C.回归预测任务
- D.聚类分析任务
答案:A。候选类别只有「有/无」两个,属于二分类;如果还要区分三种以上的病理类型,才算多分类。老周挑烂果是二分类,分苹果梨橙子才是多分类。
Q2. sigmoid 输出 0.85,阈值为 0.5,模型会怎样判定?
- A.无法做出判定
- B.判定为阳性← 正确答案
- C.需要重新训练
- D.判定为阴性
答案:B。0.85 ≥ 0.5,按默认规则判为阳性(有病灶)。阈值可以按临床需求左右移动,但默认分界线就是 0.5。
Q3. softmax 输出的各类别概率之和是多少?
- A.恒等于 0
- B.恒等于 1← 正确答案
- C.恒等于 -1
- D.等于类别总数
答案:B。softmax 的分母是所有类别指数化分数之和,每个概率是「自己的分除以总分」,因此所有概率加起来恒等于 1。这保证了模型输出的是一组合理的概率分布。
Q4. 数据集中正常样本 9900 张、病灶样本 100 张,以下哪种做法最合适?
- A.只关注整体准确率
- B.调大模型学习率
- C.使用类别加权损失← 正确答案
- D.直接删除全部病灶样本
答案:C。类别不均衡时,要给少数类更大损失权重或过采样,让模型认真学病灶样本。删除病灶样本是反向操作;学习率大小与不均衡无关;只看准确率会被「全判正常」骗过去。
Q5. 「敏感度」在病灶筛查中的含义是什么?
- A.健康人被误报的比例
- B.患病者中被检出的比例← 正确答案
- C.全部样本判断正确比例
- D.模型训练速度的快慢
答案:B。敏感度 = TP / (TP + FN),衡量「真正有病的人里有多少被查出来」,对应老周最关心的「烂果漏掉几个」。误报比例和整体准确率分别对应特异度、准确率,与训练速度无关。
Q6. 多分类模型输出「腺癌 0.70、鳞癌 0.20、小细胞肺癌 0.10」,预测类别是?
- A.预测为腺癌← 正确答案
- B.预测为鳞癌
- C.预测为小细胞癌
- D.无法做出判断
答案:A。多分类取概率最大的类别作为预测(argmax),腺癌概率 0.70 最大,因此预测为腺癌。老周也是看哪个筐「分数」最高,就把水果放进哪个筐。
Q7. 以下哪些属于医疗影像的数据增强方式?
- A.随机旋转图像← 正确答案
- B.调整图像亮度← 正确答案
- C.伪造标注标签
- D.水平镜像翻转影像← 正确答案
答案:ABD。旋转、亮度调整、水平翻转都是模拟真实成像差异的无害变换。伪造标注标签属于数据造假,会污染模型,不属于数据增强。
Q8. 处理类别不均衡的常见方法有哪些?
- A.对少数类过采样← 正确答案
- B.对多数类欠采样← 正确答案
- C.损失函数类别加权← 正确答案
- D.大幅提高批次大小
答案:ABC。过采样、欠采样、损失加权都是处理不均衡的经典手段。批次大小主要影响训练稳定性与收敛,与类别不均衡没有直接关系。
Q9. 关于医疗影像分类评估,正确的说法是?
- A.只看总体准确率即可
- B.AUC综合了敏感特异度← 正确答案
- C.特异度与敏感度无关
- D.无需关注漏诊情况
答案:B。AUC 是 ROC 曲线下面积,综合刻画了不同阈值下敏感度与特异度的整体权衡。类别不均衡时准确率会骗人,漏诊率必须关注,敏感度和特异度本质上是跷跷板关系,并非无关。
Q10. 为避免医疗影像数据泄露,应该怎么做?
- A.按患者分组划分数据← 正确答案
- B.随机打乱全部图像划分
- C.同一患者切片放入同侧← 正确答案
- D.增强后按图像随机划分
答案:AC。同一患者的切片高度相似,必须按患者 ID 分组,让同一患者的全部图像只出现在训练集或测试集的一侧。随机打乱、增强后再随机划分都会让同源图像跨集,导致评估分数虚高。