
简介这是一份面向医学图像分析与深度学习研究者的乳腺癌细胞分割图片数据集适用于计算机视觉、数字病理及辅助诊断等方向的算法实验与课程设计。数据集包含58张HE染色组织病理学图像图像经由苏木素和伊红染色使细胞结构清晰可见由于多数细胞透明且缺乏固有色素分割难度较高而该数据提供真实标注可直接用于训练和验证细胞分割模型并为后续良性细胞和恶性细胞的分类提供前期基础。整份压缩包共232个文件其中116个tif格式的原始组织切片图像与116个xml格式的标注文件一一对应总体积约93.7MB结构规范便于配对加载。目前已有269人学习下载是入门病理图像分割、评测不同网络架构或开展科研预实验的实用资源。1. 乳腺癌细胞分割图片数据集病理 AI 的起点是数据不是模型HE 染色的乳腺癌切片里细胞核的形态、密度和排列是病理医生判断肿瘤分级的直接证据。所谓乳腺癌细胞分割图片数据集就是把这种视觉证据变成模型可学习的样本每个细胞核的边界被标注成掩膜或轮廓配套原始图像一起交给分割模型训练。做过这个任务的人都会同意瓶颈不在网络结构而在数据本身——细胞核密集贴在一起、边界像素层面模糊、不同实验室染色深浅差异极大同一张切片两个病理医生标注的 Dice 能差出好几个点。这篇文章面向医学图像分析、病理 AI 或细胞计数的工程师把可落地路径讲透数据集怎么选、标注怎么做、预处理关键步骤、模型与损失函数配置、结果验证。2. 乳腺癌细胞分割数据集怎么选公开来源、标注粒度与许可边界2.1 病理图像与自然图像数据集的三点本质差异细胞分割数据集和 COCO 这类自然图像数据集有三点本质差异选型前必须先建立这个认知。第一是成像协议病理切片要经过福尔马林固定、石蜡包埋、切片和 HE 染色同一块组织在不同实验室做出来颜色差异很大这会直接影响分割模型的跨机构泛化所以染色归一化几乎是流水线上必有的环节。第二是标注对象自然图像里一个类别通常对应一个完整物体而乳腺癌切片里细胞核是密集排列的实例相邻核的边界在像素层面几乎贴合一份标注到底把边界画在核膜内沿还是外沿直接决定掩膜面积和后续指标。第三是数据规模公开的乳腺癌细胞核级标注数据通常只有几百张小图或几十张全切片和 ImageNet 差几个数量级这意味着数据增强、交叉验证和迁移学习不是可选项而是训练流程的默认组成部分。拿到一份数据集我一般先做四个检查切片来源是否同一台扫描仪、标注是核中心点还是像素掩膜、有没有病理医生双人复核、验证集是否按患者划分而不是按图像随机切。第四个问题最容易被忽略同一患者的相邻切片内容高度相似按图像随机划分会让验证集指标虚高这在病理数据里几乎是必踩的坑。检查标注格式时直接扫一遍掩膜文件确认是二值图还是多类别图from PIL import Image import numpy as np import glob for m in sorted(glob.glob(data/masks/*.png))[:5]: arr np.array(Image.open(m)) uniq np.unique(arr) print(f{m}: shape{arr.shape} unique{uniq} max{arr.max()}) # 输出解读 # unique[0 1] - 二值掩膜背景 0 / 前景 1最常见 # unique[0 1 2] - 多类别图需确认 1/2 各代表什么 # max 远大于 1 - 实例 Id 掩膜训练前必须转成二值图这段代码的价值在于提前暴露掩膜格式不一致的问题。很多公开数据的掩膜是实例级 Id 图而不是二值图直接当分割标签用会在损失函数里引入虚假的类别数统一在数据加载层做(arr 0).astype(np.float32)是更稳妥的做法比改每个数据源的文件本身省事得多。2.2 公开数据集类型对比与选型判断目前能检索到的乳腺癌相关数据集按标注粒度可以分成四类选型时对照这张表判断标注粒度数据集代表标注内容适合任务选型注意点图像级标签BACHICIAR 2018癌/非癌、原位癌/浸润癌分类预训练、弱监督初始化用于分割需配合 CAM 或 MIL区域级多边形部分 WSI 标注项目肿瘤区域、坏死区域区域粗分割、ROI 裁剪粒度不足以做细胞计数细胞核掩膜BreCaHAD、MoNuSeg每个核的像素级轮廓语义/实例分割确认核边界定义是否一致核中心点密度计数类数据核中心坐标计数、密度图回归需后处理转掩膜或换点监督损失BACH 是乳腺癌组织学图像解析领域引用率很高的公开挑战赛数据包含经过病理医生复核的乳腺组织图像适合先跑通分类基线再用类别激活图生成弱监督的初始 ROI。BreCaHAD 提供乳腺癌组织图像的细胞级标注规模不大但标注质量高适合做微调验证。MoNuSeg 是多器官细胞核分割数据其中包含乳腺来源的切片每个核有独立掩膜是训练细胞分割模型常用的预训练来源。2018 年 Data Science Bowl 发布的细胞核分割数据集虽然混合了多器官但样本量大、标注统一适合作为大规模预训练阶段的数据。另有 TNBC 乳腺癌数据集包含三阴性乳腺癌切片的精细细胞级标注很多研究肿瘤微环境的论文都会引用它。需要提醒的是这些数据集的染色条件、扫描倍率和标注风格都不一致直接跨域推理的效果往往不理想。我一般推荐的路线是用 MoNuSeg 或 Data Science Bowl 这类量大者做第一阶段预训练再用目标域数据哪怕只有几百张做第二阶段微调。这个两阶段策略在病理分割的实践里很常见比迷信某个单一数据集可靠得多。提示检索数据集时注意区分掩膜标注和检测框标注。很多病理数据标注的是核中心点或矩形框而不是像素掩膜这会直接影响损失函数和数据加载的实现。2.3 数据许可与伦理边界医学图像的数据许可比自然图像严格得多。公开数据集一般会附带使用协议常见限制包括仅限非商业研究、禁止重新分发、要求引用原始论文、不得用于临床诊断决策。使用前至少确认三点数据是否已去标识化患者姓名、病例号、采集机构是否被移除协议是否允许你所在组织的用途商业模型训练尤其要查这一条模型输出是否可能反推患者身份发布演示或开源权重时要格外注意。这类数据几乎都来自医院伦理审批过的研究项目任何重新标注和二次发布都应当沿用原始协议的约束。实际操作中我建议把每个数据集的许可摘要记在一个 README 里和数据集文件放在一起避免项目交接时说不清来源。3. 乳腺癌细胞分割数据集的标注与预处理从病理切片到训练样本3.1 标注工具与标注规范自建数据集时标注环节决定分割质量的上限。常用工具里QuPath 是病理领域使用最广的开源标注软件直接支持全切片图像和多边形标注导出 GeoJSON 或掩膜都很方便适合病理科协作场景CVAT 适合标注团队远程协作支持多边形与分割掩膜导出格式和 YOLO-seg、COCO 兼容配合开源训练平台可以串起从标注到训练的完整闭环napari 适合已经用 Python 脚本做预处理的团队标注和算法验证可以在同一个环境里完成。工具选择没有绝对标准关键是导出格式能否被你后续的数据加载代码直接消费。标注规范比工具更重要需要和病理医生确认三件事。第一是细胞核边界定义标注核膜内沿、外沿还是染色质弥散边界不同定义会让掩膜面积差出 10% 以上也会让标注者之间的一致性大幅下降。第二是贴边核的处理在切块边缘被截断的细胞核常见做法是照常标注但训练时对边缘区域降低损失权重避免模型学到半截核的错误先验。第三是质量复核至少两位标注者独立标注同一批图用 Dice 或 F1 计算一致性低于 0.85 就要回到规则讨论而不是继续往下标。标注阶段省掉复核后面所有指标都会带着噪声这是我最想强调的一点。3.2 染色归一化摆脱扫描仪和染色批次偏见HE 切片在不同实验室甚至同一实验室不同批次之间染色差异都很大。如果直接用原始图像训练模型会把染色深浅当成特征一起学换一个数据源性能就明显下降。染色归一化的目标是把所有图像的颜色分布对齐到一个参考标准常见做法有两种Reinhard 方法在 LAB 颜色空间做均值和标准差的匹配实现简单、速度快Macenko 方法更进一步先估计 HE 两种染料的染色向量再分离染色强度理论上更符合组织化学原理但对参数和图像质量更敏感。Reinhard 方法的实现很短适合先跑通流程import numpy as np from skimage import color def reinhard_normalize(src, ref, alpha0.5): 把 src 的染色分布对齐到 ref。 alpha1.0 完全对齐到参考图alpha0.0 保持原图不处理。 输入要求是 0~1 的 float RGB 图读取后用 astype(np.float32)/255.0 转换。 src_lab color.rgb2lab(src) ref_lab color.rgb2lab(ref) dst np.empty_like(src_lab) for c in range(3): # L/a/b 三个通道分别对齐 s_mean, s_std src_lab[..., c].mean(), src_lab[..., c].std() r_mean, r_std ref_lab[..., c].mean(), ref_lab[..., c].std() dst[..., c] (src_lab[..., c] - s_mean) * (r_std / s_std) r_mean dst[..., c] alpha * dst[..., c] (1 - alpha) * src_lab[..., c] # LAB 通道有固定有效范围clip 是必要的 dst[..., 0] np.clip(dst[..., 0], 0, 100) dst[..., 1:] np.clip(dst[..., 1:], -128, 127) return color.lab2rgb(dst)逻辑说明先把图像从 RGB 转到 LABL 通道是亮度a、b 是颜色对立通道这样分离亮度和颜色后逐通道做标准化把源图的均值和标准差替换成参考图的染色差异就大体抹平了。alpha 参数用于控制回归强度纯 Reinhard 是 alpha1.0但对个别染色极端的切片完全对齐会出现色彩断层保留 0.2~0.5 的原图成分更稳妥。参考图一般取目标数据集里染色最标准的一张或者对多张图取平均。比 Reinhard 更进一步的是 Macenko 方法它假设 HE 染色符合比尔-朗伯定律把每个像素的 RGB 值分解成苏木精和伊红的浓度系数然后再对齐浓度分布常见病理图像库里一般有现成实现但如果你的数据染色相对一致Reinhard 已经完全够用没必要为归一化引入额外复杂度。3.3 切块、数据增强与类别平衡全切片图像通常有数万像素边长没法直接进网络切块是必做的一步。常见参数在 20 倍扫描倍率下用 512x512 的 patch相邻 patch 重叠 64~128 像素在 40 倍率下建议降采样或改用 256x256 patch否则单个细胞核对应的像素数太多模型感受野不够。切块时把无效背景剔除比如组织占比低于 20% 的 patch 直接丢弃能省下大量无效计算。数据增强参考这张表比自然图像任务更克制增强项参数建议说明随机旋转/翻转90 度旋转 水平/垂直翻转组织学图像无方向性放心用弹性形变sigma3~5模拟切片形变小幅即可亮度/对比度抖动幅度 0.1~0.15模拟染色批次差异可替代部分归一化随机裁剪从 patch 内再裁 0.8~1.0 倍增加边界多样性类别不平衡在细胞分割里是实质问题大部分 patch 中背景像素占 80% 以上直接用交叉熵会让模型倾向把所有像素判成背景。常见做法是在损失函数里加 Dice 项兜底见下一章或者给背景类降权。对贴边核的边缘像素可以在前景掩膜上做 1~2 像素的内缩用腐蚀后的核作为监督目标能明显降低边界区域的分歧这个技巧在标注质量参差的数据上尤其有效。4. 用乳腺癌细胞分割数据集训练模型U-Net、YOLO-Seg 与超参配置4.1 语义分割和实例分割怎么选细胞分割任务的输出需求决定模型选型。如果下游只需要细胞密度、核面积分布这类整体统计语义分割就够了U-Net 是最稳妥的选择结构简单、小数据下不容易过拟合、训练资源要求低CPU 上都能完成推理。如果下游需要逐个细胞核做形态分析或准确计数就需要实例分割常见方案是 YOLO-Seg 或带分割分支的两阶段检测器。区分两者的核心是输出是否带实例 Id语义分割输出一张二值图挨在一起的核无法区分实例分割输出每个核的独立轮廓和类别。我的判断标准是看标注格式和数据量。语义分割只需要二值掩膜标注成本低几百张图就能训出可用的模型实例分割需要每个核的独立实例 Id标注成本高出一截贴边核和粘连核的处理也更麻烦。如果数据量在两千张以内我一般建议先训 U-Net 语义分割再做分水岭后处理把粘连核拆开多数场景的精度已经够用只有对单核级指标要求很高时才上实例分割。反过来如果原始标注本来就是核中心点或实例掩膜直接用实例分割反而省事不用在语义到实例的后处理上绕路。4.2 最小可跑通的训练配置用 PyTorch 生态训练分割模型成熟做法是 segmentation-models-pytorch 库一行代码拿到带预训练编码器的 U-Netimport torch import segmentation_models_pytorch as smp model smp.Unet( encoder_nameresnet34, # 编码器病理任务常用 resnet34 或 efficientnet-b0 encoder_weightsimagenet, # ImageNet 预训练小数据迁移的关键 in_channels3, classes1, # 二分类分割 activationsigmoid, # 输出 [0,1] 概率图 ) loss_fn smp.losses.DiceLoss(modebinary) optimizer torch.optim.AdamW(model.parameters(), lr1e-4) scheduler torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max50)参数说明编码器选 resnet34 是训练速度和精度之间的平衡点数据量小就换 resnet18数据量大或追求精度再上 efficientnet-b0encoder_weights 必须保留病理图像迁移自 ImageNet 在前几层依然有效这是小数据能训起来的关键classes1 表示输出一张前景概率图配合 DiceLoss 的 binary 模式。AdamW 的学习率从 1e-4 起步比自然图像任务常用的 1e-3 低一个量级因为医学分割 batch 小、标注噪声敏感学习率大了权重更新容易被单张图的噪声带偏。训练循环本身很常规但有一个容易忽略的点每轮结束要在验证集上用滑动窗口做重叠推理再算指标而不是直接整图前向否则指标会虚高。如果团队用的是开源训练平台注意确认它是否支持自定义损失函数和按患者划分数据集这两点不满足的话平台功能再完整也不适合病理分割。for epoch in range(100): model.train() for imgs, masks in train_loader: imgs, masks imgs.to(device), masks.to(device) pred model(imgs) # [B, 1, H, W] 概率图 loss loss_fn(pred, masks) optimizer.zero_grad() loss.backward() optimizer.step() scheduler.step() val_dice validate(model, val_loader) # 自定义验证函数 if val_dice best_dice: best_dice val_dice torch.save(model.state_dict(), best_unet.pth)4.3 损失函数与训练超参数细胞分割的损失函数我通常组合 Dice 和 BCE。单独用 BCE 在背景占多数时收敛慢单独用 Dice 在前景小时梯度不稳定各占一半是最常见的做法。很多开源实现默认只有交叉熵换成组合损失后小目标分割的收敛速度差别明显。bce torch.nn.BCELoss() dice smp.losses.DiceLoss(modebinary) def combined_loss(pred, mask): return 0.5 * bce(pred, mask) 0.5 * dice(pred, mask)如果细胞核面积特别小可以把 Dice 的权重提高到 0.7如果核边界特别模糊加一个边界损失或对核内侧像素加权更有效。超参数总体建议如下超参数建议值说明patch size512x51220x覆盖足够上下文显存友好batch size8~16显存不够用梯度累积补初始学习率1e-4AdamWSGD 的话用 1e-2学习率调度CosineAnnealing比 StepLR 对分割更平滑训练轮数80~120以验证集 Dice 做提前停止冻结编码器前 5 轮先用预训练特征稳住解码器前 5 轮冻结编码器是很多人忽略的小技巧让随机初始化的解码器先适应预训练特征再放开全部参数能避免前期权重互相干扰导致的损失震荡。这个策略在标注质量一般的数据集上提升尤其明显。4.4 评估指标与模型导出分割模型不能只看一个 Dice。像素级指标里Dice 和 IoU 最常用公式分别是 2TP/(2TPFPFN) 和 TP/(TPFPFN)都反映掩膜重合度但 Dice 对小目标更敏感IoU 对整体重合更严格。对象级指标里把预测核和标注核按 IoU 是否大于 0.5 匹配再算精确率和召回率得到对象级 F1这才是对下游计数任务更真实的度量。一份只报 Dice 不报对象级 F1 的分割报告在病理场景里说服力不够。模型导出到推理端时U-Net 转 ONNX 后在 CPU 上跑 512x512 patch 只有几十毫秒足够离线分析如果走 YOLO-Seg 路线标注要转成归一化多边形格式并确认导出的模型版本和推理框架兼容。训练平台把图片标注、数据集管理、模型训练和模型导出串成闭环后剩下的重点就转移到数据侧的质检上。5. 乳腺癌细胞分割结果的验证与排错清单5.1 按患者拆分的交叉验证分割数据集最常见的指标虚高来自划分方式错误。同一患者的连续切片在形态上高度相似如果随机按图像划分训练集和验证集里会出现来自同一患者的图像模型相当于提前见过答案。正确做法是按患者文件夹划分确保一个患者的所有图像只出现在一个集合里做 5 折交叉验证时每一折都要重新执行这个约束不能只在第一次划分时遵守。检查方法很直接统计验证集每个患者的图像数和平均 Dice如果某几个患者的指标明显高于其他患者基本可以断定有数据泄漏回头查划分逻辑。5.2 切块推理的拼接与后处理全切片推理时切块预测再拼接会在 patch 边缘留下拼接缝肉眼看不明显但对细胞这样的小目标边界上的概率跳变足以影响计数。处理办法是重叠推理取平均import numpy as np import torch def predict_tiled(model, wsi, patch512, overlap64, devicecuda): 整张切片的重叠切块推理重叠区取平均消除拼接缝。 step patch - overlap h, w wsi.shape[:2] out np.zeros((h, w), dtypenp.float32) count np.zeros((h, w), dtypenp.float32) model.eval() with torch.no_grad(): for y in range(0, h, step): for x in range(0, w, step): tile wsi[y:y patch, x:x patch] # 转成 [1, C, H, W]训练时若有归一化这里要套用相同预处理 t torch.from_numpy(tile).permute(2, 0, 1).unsqueeze(0).float().to(device) mask model(t)[0, 0].cpu().numpy() # 模型带 sigmoid输出概率图 out[y:y patch, x:x patch] mask count[y:y patch, x:x patch] 1 return out / np.maximum(count, 1)这段代码用一张计数图记录每个像素被预测的次数拼接时对重叠区做加权平均patch 边缘的概率跳变被平滑掉。overlap 取 64~128 像素即可再增大收益有限。拿到概率图后用 0.5 阈值二值化再对粘连核做分水岭后处理就能得到实例级结果。5.3 一份可操作的质检清单最后给一份每次交付前都会过一遍的质检清单验证集是否按患者划分重新跑划分脚本确认没有同患者串集染色归一化的参考图在训练和验证间是否独立防止参考统计泄漏进验证Dice 之外是否记录了对象级 F1两项同时看才能反映计数任务的真实水平预测结果是否抽样交给病理医生复核至少 20 张图确认边界定义一致复核意见要落到标注规范里而不是只修这一次模型在不同扫描仪或染色批次数据上的性能差是否在可接受范围这决定部署时要不要做针对性微调。逐项过完把每个患者的 Dice、对象级 F1 和对应预测掩膜一起归档后续模型迭代直接拿这份基线对比。本文还有配套的精品资源点击获取