☰
宫颈细胞图像分类实战:从数据准备到模型部署
2026/10/5 6:07:28 网站建设 项目流程

简介:面向深度学习与医学图像处理方向的研究者,这份PDF论文聚焦卷积神经网络在宫颈细胞图像分类中的应用,针对传统细胞学检查依赖人工、分割精度要求高、欠发达地区难以普及等痛点,提出了一种端到端的自动分类思路。资源为单文件PDF,压缩包大小1.56MB,正文包含摘要、关键词、研究背景、方法设计与实验结果,结构完整,便于直接阅读或打印。方法部分详细介绍了复制预训练网络参数进行迁移学习、分批次输入图像、Softmax输出概率、交叉熵损失函数,并引入批归一化与反向传播优化;实验采用5折交叉验证,在Herlev数据集上使特异性、调和平均数和准确率较常用基准分别提高19.46%、10.71%和5.09%,结果数据与对比图表均可作为参考。目前已有201人学习这份PDF,适合需要了解CNN在医学图像分类中落地方法、学习迁移学习与批归一化实践技巧,或参考学术论文写作框架的读者。

1. 宫颈细胞图像分类:为什么值得啃下这份技术文档

宫颈癌筛查是病理科每天都要面对的高强度工作,一张液基薄层制片上往往有几万个细胞,医生在显微镜下逐个判读,既费眼又费时,而且不同年资的医生判读一致性并不理想。用卷积神经网络来做宫颈细胞图像分类,本质上是把这件事拆成“用图像分类算法先做初筛,把明显正常的片子挑出去,让医生集中精力看可疑样本”。这个思路并不新鲜,但真正落地时,你会发现精度上得去、推理速度也够快,难的反而是数据准备和类别定义这些看起来不起眼的环节。这篇笔记适合正在做医学图像分类、或者刚拿到这个方向课题的工程师和研究生,我会从数据、模型选型、训练和评估一路讲到具体踩过的坑。这份PDF文档大概率也是一条同样的技术路线,如果你正在读它,那正好对照着往下看。

为什么我会说这个方向值得投入?因为宫颈细胞图像和自然图像有一个很大的不同:它的背景复杂、细胞重叠、染色深浅不一,常规的图像分类模型直接搬过来往往效果很差。但好消息是,公开的宫颈细胞数据集并不少,而且单张图像的信息密度高,一个中等规模的CNN就能达到可用的准确率,不需要像自然图像那样堆上千层的网络。接下来的内容,我会按自己做过的一套完整流程来拆解。

2. 任务定义与数据准备:先别碰模型,把宫颈细胞的类别边界弄清楚

2.1 宫颈细胞分类到底在分什么:二分类、五分类还是TBS分级

做宫颈细胞图像分类,第一个要明确的不是用什么网络,而是分几类。目前公开数据集里最常见的是两类和五类的划分。两类就是把细胞分为正常和异常,简单直接,适合做初筛。五类则是按照Bethesda报告系统(TBS)的术语来分,比如正常鳞状上皮细胞、ASC-US(非典型鳞状细胞,意义不明确)、LSIL(低度鳞状上皮内病变)、HSIL(高度鳞状上皮内病变)、ASC-H等,这更贴近病理医生的实际工作习惯,但也意味着标注成本更高、类别间边界更模糊。

我一般会建议项目初期的同学先用二分类跑通整个流程,因为二分类的标注一致性更高,多人标注时争吵少,模型也容易收敛。但如果你是要发表论文或者做产品原型,五分类是绕不开的,因为筛查场景里真正有价值的是把HSIL和ASC-H这些高风险类别找出来,而不是简单地说一句“异常”。还有一种更细的做法是按单个细胞来分类,而不是按整张图分类,这取决于你的数据标注粒度,后面会详细说。

2.2 公开数据集怎么选:从SIPaKMeD到Herlev,各自的坑在哪

现在做宫颈细胞分类,常见的数据集主要有SIPaKMeD、Herlev、Motic、CRIC等。SIPaKMeD是目前用得比较多的一个,它从液基制片中裁剪出单个细胞图像,类别划分比较细,图像尺寸也统一,适合直接喂给CNN。Herlev数据集历史悠久,是单细胞图像的鼻祖级数据集,但它的图像是显微镜下手工裁剪的,背景比较干净,和真实的液基制片场景差距较大。如果你用Herlev训练完直接拿去测SIPaKMeD或者自己采集的数据,精度掉十几个点都很正常。

我踩过的坑是直接用SIPaKMeD的原始划分来训练,没仔细看每个类别的样本数。它的正常类别样本量远大于异常类别,直接训练出来的模型会把几乎所有测试样本都判成正常,准确率看着有80%多,实际上异常类别的召回率只有20%。所以拿到任何一个数据集,第一件事不是看精度,而是先统计每个类别的样本数和图像尺寸分布,把长尾情况摸清楚再决定用什么样的训练策略。

2.3 预处理与数据增强:宫颈细胞的染色归一化为什么比随机裁剪更重要

医学图像预处理和自然图像有一个显著差异:自然图像可以放心做随机裁剪、水平翻转,但宫颈细胞图像对空间位置不敏感,却对颜色极其敏感。不同医院、不同批次的制片染色深浅不一样,同一个细胞在苏木精-伊红染色下和巴氏染色下的特征差异巨大。如果模型在染色偏深的图上训练,遇到染色偏浅的真实样本,精度会急剧下降。所以染色归一化(Stain Normalization)是这个任务里最重要的一步预处理,常见做法是用Reinhard算法或者Macenko算法把每张图的颜色分布对齐到一张参考图上。

数据增强方面,我一般会保留随机旋转和随机缩放,因为细胞在制片上什么朝向都有,尺度也不同。但不会用太大的随机裁剪,因为裁剪掉细胞边缘的信息会影响分类。还有一个值得做的增强是模拟不同染色条件下的颜色扰动,比如在HSV空间对色相和饱和度做小幅抖动,这比单纯加高斯噪声有效得多。预处理阶段的输出格式建议统一为224x224或299x299的RGB图,这对应着ResNet和Inception系列的标准输入尺寸。

3. 模型选型与网络结构:从ResNet到轻量化CNN,怎么选才不亏

3.1 为什么宫颈细胞分类不需要追求最深的网络

很多刚接触这个方向的同学上来就问我,是不是用EfficientNet或者最新的ConvNeXt会更好。我的回答是,这取决于你的数据量、算力和部署目标。宫颈细胞分类任务的难点不在于捕捉极其细微的纹理差异,而在于处理好细胞核的大小、核质比、染色质分布这些相对宏观的特征。一个18层的ResNet,也就是ResNet18,配合好的预处理和数据增强,在SIPaKMeD的5分类任务上就能达到90%以上的准确率。更深的网络带来的提升往往是零点几个百分点,但训练时间和过拟合风险会明显上升。

如果你要做实时筛查,或者在医院的普通工作站上跑,那轻量化网络是更实际的选择。MobileNetV3和ShuffleNetV2在保持80%以上精度的同时,模型体积只有几MB,推理速度在CPU上也能跑到每秒几十张。我的建议是先用ResNet50做基线实验,把流程跑通,确认数据没有问题之后,再做模型压缩的对比实验。这比一开始就在网络结构上纠结要高效得多。

3.2 迁移学习的正确姿势:加载ImageNet权重,但冻结和解冻的策略要讲究

宫颈细胞图像和ImageNet的自然图像相差很大,但迁移学习依然有效,因为它能保留底层边缘、纹理等通用特征。常见的做法是加载ImageNet预训练权重,先冻结除最后几层之外的所有层,只训练全连接层,等损失不再下降时,再解冻后面的卷积块进行微调。这个策略能避免在训练初期因为学习率过大而破坏预训练特征。

全连接层的替换要特别注意:如果原来的分类数是1000,你要改成自己的类别数,比如5。最后一层的输出维度是5,对应着五个类别的logits。微调时的学习率要比正常训练小一个数量级,我一般用0.0001到0.0005之间,优化器用Adam或者SGD加动量都行,但SGD加动量在微调时收敛更稳,不容易在局部极小值附近震荡。

3.3 从单细胞到全视野:两种推理方式的取舍

这里有一个容易被忽略的问题:你的模型是在单细胞图像上训练的还是整张切片上训练的。如果只有单细胞级别的标注,那推理时就要先做细胞检测和裁剪,再把每个细胞送进分类模型,最后汇总整张片的统计结果。这种方式的精度取决于细胞检测的质量,检测漏了,分类再准也没用。如果做的是整张图的二分类,那模型直接输出整张片的正常或异常概率,省去了检测步骤,但可解释性差,医生不太容易信任。

我自己的经验是,如果预算有限,优先做单细胞分类加简单的核检测,这样既能定位异常细胞,又能给医生一个直观的判读依据。后面有条件再上目标检测模型来联合优化。这两种方式对应着完全不同的数据标注规范和标签体系,在选题阶段就要想清楚,否则后期返工成本极高。

4. 训练流程与模型评估:用代码把一条可行的基线跑通

4.1 数据准备的代码结构:从文件夹到DataLoader,注意标签泄漏

先假设你已经拿到了一个按类别分文件夹的数据集,目录结构类似data/train/normal/、data/train/abnormal/。下面这段代码用PyTorch把训练集和验证集加载起来,并做了最基本的预处理。

import torch from torchvision import datasets, transforms from torch.utils.data import DataLoader # 训练集的预处理:染色归一化是前提,这里用简单的颜色抖动模拟 train_transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.RandomRotation(15), # 细胞朝向随机,旋转增强很有效 transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.1), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) # 验证集不做增强,只做尺寸统一和标准化 val_transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) train_dataset = datasets.ImageFolder('data/train', transform=train_transform) val_dataset = datasets.ImageFolder('data/val', transform=val_transform) train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=4, pin_memory=True) val_loader = DataLoader(val_dataset, batch_size=32, shuffle=False, num_workers=4, pin_memory=True) print(f"训练集类别数: {len(train_dataset.classes)}") # 输出示例: 训练集类别数: 5

这段代码里最关键的是ImageFolder会自动根据子文件夹名生成类别标签,所以文件夹名字一定要和类别对应好。验证集用shuffle=False是为了保证评估时标签顺序稳定。realme N brush的标准化参数用的是ImageNet的均值和方差,这个在迁移学习时不要改。

4.2 训练主循环:计类别权重、早停和学习率调度

宫颈细胞数据集普遍存在类别不平衡,直接用一个普通的交叉熵损失函数会让多数类主导训练。常见做法是给每个类别一个权重,样本少的类别权重高。PyTorch里可以这样实现:

import torch.nn as nn # 假设类别0是HSIL,样本数最少,权重给到3.0 # 其余类别的权重通过样本数反比计算 class_counts = [5000, 3000, 800, 400, 600] # 需要替换为实际统计结果 total = sum(class_counts) weights = [total / (len(class_counts) * c) for c in class_counts] weights = torch.tensor(weights, dtype=torch.float32) criterion = nn.CrossEntropyLoss(weight=weights.to('cuda'))

这里有个细节:权重过大容易让模型过拟合少数类,一个安全的范围是让权重的最大值不超过3倍最小值。如果做了权重之后训练损失降不下去,可以先去掉权重训练几个epoch看看基线。

训练循环本身不复杂,但学习率调度和早停是必须写的。我习惯用ReduceLROnPlateau,当验证集损失连续5个epoch不下降时,学习率乘以0.5。同时记录验证集AUC,连续10个epoch不创新高就停止训练,并加载最优模型。这一步能省下大量人工盯训练的时间。

4.3 评估指标别只看准确率:混淆矩阵和每类召回率才是关键

医学图像分类里,准确率的参考价值有限。假设异常类别只占5%,你全部预测为正常,准确率也有95%,但这个模型毫无用处。对于宫颈细胞分类,我至少会看三样东西:混淆矩阵、每个类别的召回率和精确率、以及AUC。尤其是HSIL这类高风险类别,召回率比精确率重要得多——漏掉一个HSIL的后果远比多报一个正常严重得多。

from sklearn.metrics import confusion_matrix, classification_report import numpy as np def evaluate(model, val_loader): model.eval() all_preds = [] all_labels = [] with torch.no_grad(): for images, labels in val_loader: images = images.cuda() outputs = model(images) _, preds = torch.max(outputs, 1) all_preds.extend(preds.cpu().numpy()) all_labels.extend(labels.numpy()) print(confusion_matrix(all_labels, all_preds)) print(classification_report(all_labels, all_preds, target_names=['normal', 'ASC-US', 'LSIL', 'HSIL', 'ASC-H']))

打印出来的classification_report里,重点关注recall那一列。如果你发现HSIL的召回率特别低,先别急着换模型,大概率是标注边界问题,比如HSIL和ASC-H在图像上本来就很难区分,甚至病理医生之间的标注一致性都不高。这时候要做的是合并容易混淆的类别,或者增加这些类别的样本。

5. 宫颈细胞分类的避坑指南:数据、标注与训练的三个重灾区

5.1 染色差异让验证集精度虚高,换数据源直接翻车

现象:在SIPaKMeD上训练,验证集精度92%,拿去测自己医院采集的玻片数据,精度掉到60%出头。

原因:公开数据集和真实液基制片的染色条件、显微镜放大倍数、细胞切割方式都不一样。验证集和训练集来自同一数据源,相当于模型只学会了“这个数据源的正常长什么样”,并没有学到泛化的宫颈细胞特征。

解决:从第一天起就把染色归一化纳入预处理流程,并在训练集之外保留一个完全独立的数据源作为测试集。如果两个数据源的精度差异过大,说明模型过拟合了训练数据源的风格,需要加大颜色扰动增强,或者用风格迁移做数据扩充。

5.2 一张图里有多个细胞,标签到底标谁

现象:模型训练时损失降不下去,验证集AUC在0.75附近震荡,而且预测结果看起来毫无规律。

原因:标注标准不统一是最大的坑。如果一张裁剪图里既有正常细胞又有异常细胞,有的标注者按“存在异常就标异常”来标,有的标注者按“视野中心细胞为准”来标,那么模型接收到的标签噪声极大。

解决:在项目启动时就要和标注团队写清楚标注规范,强烈建议用“多数原则”或“最高级别原则”二选一,不要混用。如果是单个细胞的裁剪图,标注前要由细胞病理专家先做一轮质控,剔除模糊不清、细胞重叠严重的坏图。坏图留在一个单独文件夹里不参与训练,而不是用模型去硬学。

5.3 训练损失正常但类别严重失衡:AUC骗人的另一面

现象:损失收敛了,整体AUC到了0.93,很漂亮,但打开混淆矩阵发现LSIL几乎全被预测成了ASC-US。

原因:类别间特征相似度太高,加上样本量差距大,模型学会了用先验概率来“猜”,在两类之间边界模糊时倾向于输出样本量大的类别。

解决:两种手段配合。第一,用类别权重或Focal Loss让模型更多地关注难分类的少数类样本;第二,检查类别间是否有合并空间,比如ASC-US和LSIL在很多标注体系里就是连续病变谱系,强行分两类只会让模型学到噪声。如果你在做一个实际筛查系统,宁可先合并成“低级别异常”和“高级别异常”两大类,换来更可靠的输出,也不要硬撑着五个细分类别。

6. 把模型落地到推理服务:量化、批量推理与一个可复用的技巧

模型训练好了之后,如果要投入实际使用,还有两步要做:模型压缩和推理封装。常见做法是把训练好的PyTorch模型转换成ONNX,再用量化工具把权重从FP32压到INT8,这样在CPU上的推理速度能提升两到三倍,而精度损失通常在1%以内。转换的时候要注意,模型里的BatchNorm层一般在训练时是批量统计的,导出ONNX时要把模型切到eval模式,否则导出的图里会多出一些动态节点。

批量推理时还有个实用技巧值得分享:用ONNX Runtime的io_binding来管理GPU内存,可以避免反复拷贝张量造成的开销。对于一张玻片上的几千个细胞,流水线式推理能明显缩短整体处理时间。我自己做过的方案里,单张细胞图在INT8量化后的MobileNetV3上推理时间大概是3到5毫秒,一整套流程下来,一张玻片大约需要10秒左右,这个速度已经能接受。

说到这儿,有个我自己的教训想提一下:我第一次做宫颈细胞分类时,花了整整两周调模型结构,想把准确率从91%推到93%,后来发现数据集里有一个类别的标签本身就是错的,修正标注之后准确率直接跳到95%。所以如果你在实验里反复折腾效果都不明显,先停下来看看数据,往往问题不在模型。希望这篇笔记能帮你在自己的项目里少走几步弯路,从数据到模型再到落地,每一步都踩得更稳一些。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询