恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
小样本HE病理图像细胞分割:从数据预处理到U-Net训练
首页
资讯中心
/
小样本HE病理图像细胞分割:从数据预处理到U-Net训练
小样本HE病理图像细胞分割:从数据预处理到U-Net训练
发布时间:2026/10/4 3:23:27
简介这套乳腺癌细胞分割图片数据集面向病理图像分析与深度学习研究者围绕HE染色组织病理图像中的细胞分割任务构建旨在支撑良性细胞与恶性细胞的自动分类研究。压缩包内共232个文件含116张TIF格式组织病理图像及116个对应的XML标注文件图像与真实标注逐张匹配整体约93.7MB便于直接用于模型训练与验证。目前已有270人浏览学习适合作为医学影像分割、目标检测等方向的实验数据。HE染色是常规组织学手段因大多数细胞近乎透明且缺乏固有色素需借助特定染料识别生物结构该数据集正是针对此类图像提供细胞区域标注使研究者能省去繁琐的人工标注步骤专注分割网络的搭建与调优为后续细胞良恶性判别奠定数据基础。1. 乳腺癌细胞分割58 张 HE 病理图能做什么值得下吗做病理图像的从业者都清楚分割模型在公开自然图像上再强换到 HE 染色切片上照样失灵。这个乳腺癌细胞分割图片数据集只有 58 张组织病理学图像统一是 HE 染色附有真实标注文件命名里直接标了 benign 和 malignant。它的价值不在量大而在于样本小到刚好能逼你把数据管线处理干净染色归一化怎么做、patch 怎么切、验证集怎么分才不穿帮。适合想跑通细胞级分割流程的算法工程师、做医学影像课题的学生以及需要一份小样本基准数据验证 U-Net 类模型的从业者。别嫌它小小数据反而更容易暴露工程问题也更适合用有限的显存做完整实验。2. 先读透数据HE 染色规律、文件名编码与目录摆放这个数据集的命名并不复杂但信息密度很高最值得关注的几个字段直接决定了标签怎么组织、验证集怎么划分。如果跳过这一步直接进入训练很容易在数据划分上翻车。这一章先把染色背景、文件名规则和目录组织讲清楚。2.1 为什么是 HE 染色颜色信息对细胞分割的意义常规组织学使用苏木素和伊红染色也就是常说的 HE。大多数细胞基本上是透明的几乎没有固有色素所以必须用染料把特定结构显示出来。苏木素会把细胞核染成蓝紫色伊红则让细胞质和细胞外基质呈现粉红色。这种对比让细胞核的轮廓在图像里变得相对清晰因此 HE 染色图像成为病理细胞分割最基础的训练素材。从深度学习的角度看颜色在 HE 图里是强特称。模型可以依靠核的蓝紫色和胞浆的粉红色来识别区域而不需要理解复杂纹理。但问题也随之而来不同切片、不同批次的染色浓度、扫描设备差异都会导致颜色漂移。同一个病例的切片可能偏蓝另一个病例可能偏红。58 张图虽然量不大但只要是来自不同 ytma 编号的病例染色差异基本躲不掉。后续做染色归一化不是因为模型学不会颜色而是为了让模型不要过度依赖“这个蓝紫色只属于某个病例”这类偷懒特征。2.2 从文件名里拆出标签信息benign / malignant 与 CCD 后缀文件名是理解数据集的第一入口。以 ytma49_042203_benign2_ccd.tif 和 ytma12_010804_malignant2_ccd.tif 为例按常见病理图像命名习惯可以拆成几个有意义的部分。文件名片段示例常见含义ytma49 / ytma12ytma49病例编号或组织芯片编号代表样本来源042203 / 010804042203切片编号、时间批次或位置编号用来区分同一病例的不同切片benign2 / malignant2benign2图像级标签良性/恶性数字是该类别样本序号ccdccd采集设备类型说明该图由 CCD 相机拍摄在实际操作里ytma 后面的编号可能是患者编号也可能是组织阵列编号我一般直接把它当作 case_id 来处理。benign2 和 malignant2 是图像级类别标签本来用于后续的良恶性分类任务。但分割任务需要像素级标注图像级标签只是辅助信息不能替代真实标签。ccd 后缀对模型没有直接影响但提醒你这类图的拍摄设备比较统一如果以后混入 scanner 采样的图光照和纹理会有明显差异。2.3 目录组织与划分按病例分组避免数据“穿帮”拿到数据后我不会急着写模型先把目录整理成 images/ 和 masks/ 两棵平行树。真实标签不管是什么格式最终都要能跟原始 tif 文件名一一对齐。常见做法是mkdir -p breast_cell_seg/{images,masks} # 假设原始 tif 在 ./raw标签文件在 ./raw_masks find ./raw -name *.tif | while read f; do base$(basename $f) # 提取病例号用于后续按病例划分 case_id$(echo $base | cut -d_ -f1) echo $base belongs to $case_id cp $f breast_cell_seg/images/ # 如果标签文件存在同名文件复制到 masks if [ -f ./raw_masks/$base ]; then cp ./raw_masks/$base breast_cell_seg/masks/ fi done这段脚本用 cut 提取下划线分隔的第一段作为病例号然后把图像复制到 images 目录。注意这里用的是 cp如果磁盘紧张可以改成 ln -s 或者直接 mv。关键点是 mask 文件名必须和图像文件名完全一致否则后续 Dataloader 按文件名配对时会出现错位而且这种错位不会报错只会造成训练标签张冠李戴。真正要重视的是验证集划分。58 张图如果直接随机 split同一个病例的不同切片很可能同时出现在训练集和验证集中。模型在训练时已经见过该病例的染色风格和同源组织纹理验证指标会比真实场景高出一截。我一般会写一个小脚本统计病例分布import os import re files [f for f in os.listdir(breast_cell_seg/images) if f.endswith(.tif)] case_ids [] for f in files: m re.match(r(ytma\d)_, f) case_ids.append(m.group(1) if m else f) case_counts {} for c in case_ids: case_counts[c] case_counts.get(c, 0) 1 print(case_counts)这个脚本用正则把 ytma 开头的病例号提出来统计每个病例有多少张图。如果某个病例只有 1 张图把它放到训练集验证集就永远见不到这个病例的表现把它放到验证集训练时又少了这个病例的信息。对于这种情况宁可做留一病例交叉验证也不要按文件名随机分配。58 张的小数据集千万不能在这个环节节省时间。2.4 真实标注与图像配对动手前先做一次像素级体检很多数据集自带的 ground truth 并不都是标准二值 mask可能是灰度标签图也可能是带颜色编码的 PNG。这个数据集的摘要里只说“附有真实数据”没有细说文件格式所以第一件事就是检查标签跟图像的 shape 和值域是否匹配。import tifffile import numpy as np img tifffile.imread(breast_cell_seg/images/ytma49_042203_benign2_ccd.tif) mask_path breast_cell_seg/masks/ytma49_042203_benign2_ccd.tif mask tifffile.imread(mask_path) print(image shape:, img.shape, img.dtype) print(mask shape:, mask.shape, mask.dtype) print(mask unique values:, np.unique(mask))如果 mask 的 shape 和 img 不一致通常是因为标签图是单通道而原图是三通道或者标签图经过缩放。这时需要根据原始分辨率做对齐常见做法是先用 PIL 或 cv2 检查尺寸再用最近邻插值把 mask 缩回原图大小注意不能使用线性插值否则会引入中间灰度值导致二值标签变成软标签。如果 mask 的值域范围是 0 和 255要除以 255 转成 0 和 1如果存在 1 和 2 这类编码需要重新映射。这一步最好写进预处理脚本每次加载数据前自动断言一次而不是靠肉眼抽查。3. 训练前的预处理TIF 读取、染色归一化与 patch 化模型训练之前预处理占了整个工作量的百分之六十。TIF 的读法、归一化的选择、patch 的大小和重叠度最后都会显著影响分割结果。这一章按实际执行顺序来写从文件读取一路到训练样本生成。3.1 正确读取 TIF位深、通道与分辨率病理图像通常是 16 位 TIF而不是常见的 8 位 JPG。直接用 PIL 打开 16 位 TIF 时很多版本会默认转成 8 位造成信息截断。更稳妥的做法是用 tifffile 读取保留原始 dtype 和通道信息。import tifffile import numpy as np img tifffile.imread(breast_cell_seg/images/ytma49_042203_benign2_ccd.tif) print(shape:, img.shape, dtype:, img.dtype)输出可能是 (H, W, 3)也可能是 (H, W)三通道是 RGB 彩色图单通道是灰度图。如果是 uint16范围在 0 到 65535需要缩放到 0 到 1再转 float32。不要盲目使用 cv2.imread因为 cv2 对某些多页 TIF 只读第一页而且会把颜色通道变成 BGR 顺序。读取之后我还会顺手把所有图的尺寸和 dtype 打印到一个文件里确认 58 张图分辨率是否一致。如果发现某张图是 2000x2000另一张是 4000x4000就要在 patch 化之前统一步长否则后面 batch 拼接会出问题。3.2 染色归一化小样本下最容易被跳过的一步染色归一化在 HE 病理图里几乎是标配。常见的做法叫 Macenko 染色分离它把图像分解成染色浓度矩阵再映射到一个标准染色空间。这种方法效果好但需要额外依赖而且参数调起来比较麻烦。对于初学者或者只想跑通流程的人来说做逐通道标准化也可以起到很大作用。def normalize_channel_wise(img, meanNone, stdNone): img img.astype(np.float32) / 255.0 # 输入是 (H, W, C) flat img.reshape(-1, img.shape[-1]) if mean is None or std is None: mean flat.mean(axis0) std flat.std(axis0) 1e-6 img (img - mean) / std return img.astype(np.float32)这段代码按 RGB 三个通道分别做标准化把每个通道拉到零均值单位方差。关键点在于训练集和验证集必须用同一组 mean/std。有些工程上的常见误用是每张图用自己的 mean/std 做归一化这样确实把颜色都拉到了同一个范围但会抹掉染色差异信息而且训练和验证的统计口径不一致。正确做法是先在整个训练集上统计 mean/std保存成 npy推理时再用这组统计量。如果你的项目里染色差异特别明显还是建议上 Macenko 或 SPCN 这类染色归一化库。58 张小数据集里模型很容易把颜色当捷径染色归一化可以强迫模型去学形态结构。3.3 把大图切成 patch尺寸、重叠与边缘处理病理切片整张图动辄几千乘几千像素显存再大也很难直接训练。常见做法是滑窗切 patch常用尺寸是 256x256 或 512x512。为了让细胞核不被切在边界上patch 之间要有重叠一般设置 64 到 128 像素。import numpy as np def extract_patches(img, mask, patch_size256, overlap64): h, w img.shape[:2] stride patch_size - overlap patches_img [] patches_mask [] for y in range(0, h - patch_size 1, stride): for x in range(0, w - patch_size 1, stride): p_img img[y:y patch_size, x:x patch_size] p_mask mask[y:y patch_size, x:x patch_size] patches_img.append(p_img) patches_mask.append(p_mask) return np.stack(patches_img), np.stack(patches_mask)代码逻辑是从左上角开始以 stride 为步长向右向下滑窗直到窗口无法完整覆盖为止。overlap 越大同一区域被切的次数越多样本数量越大但样本重复度也越高。如果原图是 2000x2000patch_size 256overlap 64相当于 stride 192大约能切出 10x10 共 100 个 patch。如果 overlap 改为 128stride 128patch 数量变成 14x14 共 196 个。注意边缘处理代码里没有 padding所以右边和下边会漏掉一部分像素。我一般会先把图像用 reflect 模式 padding 到可被 stride 整除的尺寸避免漏掉边缘组织。3.4 mask 二值化与前景占比检查切完 patch 后很多 patch 可能是全背景里面没有任何细胞区域。这类 patch 如果直接丢进训练会让模型不停地把背景预测为背景造成类别不平衡。正确做法是统计每个 patch 中前景像素占比把全背景 patch 过滤掉。def filter_background(images, masks, threshold0.01): out_img [] out_mask [] for img, mask in zip(images, masks): foreground_ratio (mask 0).mean() if foreground_ratio threshold: out_img.append(img) out_mask.append(mask) return np.stack(out_img), np.stack(out_mask)threshold 一般取 0.01也就是说一个 256x256 的 patch 中至少有大约 650 个像素属于前景才进入训练。如果 threshold 设得过高会把只有零星细胞核的弱阳性 patch 丢掉导致模型对小细胞团不敏感。对于这个乳腺癌数据集我建议先用 0.005 试一下看剩余 patch 数量是否足够训练再决定要不要提高。4. 用 U-Net 做细胞分割模型搭建、训练与评估预处理做完后模型选型就变成了核心问题。用 U-Net 不是因为它是最新最火的架构而是它在小样本医学分割场景里足够稳。这一章从选型理由开始给出可运行的网络结构和训练参数。4.1 选型依据U-Net 在病理小数据上的优势U-Net 是编码器-解码器结构编码器逐步下采样解码器逐步恢复分辨率skip connection 把编码器浅层细节传给解码器因此小目标边界保留得比单纯空洞卷积类网络更好。在 58 张图这种规模下模型参数量太大很容易过拟合U-Net 从 32 通道起步的版本参数量适中一个普通 GPU 就能训练。对比之下Mask R-CNN 做实例分割能区分每一个独立细胞但需要更精细的标注而且训练更不稳定。DeepLab 系列擅长多尺度语义分割但在病理图上感受野太大反而容易丢失细胞核边缘。因此第一轮实验用 U-Net 是性价比最高的方案。后续如果想把单个细胞分开可以在 U-Net 输出上做分水岭后处理不必一开始就上实例分割模型。4.2 U-Net 网络结构搭建这里给出一个三下采样、三上采样的简化 U-Net用 PyTorch 实现核心结构完整且容易修改。import torch import torch.nn as nn class DoubleConv(nn.Module): def __init__(self, in_ch, out_ch): super().__init__() self.conv nn.Sequential( nn.Conv2d(in_ch, out_ch, 3, padding1), nn.BatchNorm2d(out_ch), nn.ReLU(inplaceTrue), nn.Conv2d(out_ch, out_ch, 3, padding1), nn.BatchNorm2d(out_ch), nn.ReLU(inplaceTrue) ) def forward(self, x): return self.conv(x) class UNet(nn.Module): def __init__(self, in_ch3, out_ch1, base32): super().__init__() self.enc1 DoubleConv(in_ch, base) self.pool1 nn.MaxPool2d(2) self.enc2 DoubleConv(base, base * 2) self.pool2 nn.MaxPool2d(2) self.enc3 DoubleConv(base * 2, base * 4) self.pool3 nn.MaxPool2d(2) self.bridge DoubleConv(base * 4, base * 8) self.up1 nn.ConvTranspose2d(base * 8, base * 4, 2, stride2) self.dec1 DoubleConv(base * 8, base * 4) self.up2 nn.ConvTranspose2d(base * 4, base * 2, 2, stride2) self.dec2 DoubleConv(base * 4, base * 2) self.up3 nn.ConvTranspose2d(base * 2, base, 2, stride2) self.dec3 DoubleConv(base * 2, base) self.out nn.Conv2d(base, out_ch, 1) def forward(self, x): e1 self.enc1(x) e2 self.enc2(self.pool1(e1)) e3 self.enc3(self.pool2(e2)) b self.bridge(self.pool3(e3)) d1 self.dec1(torch.cat([self.up1(b), e3], dim1)) d2 self.dec2(torch.cat([self.up2(d1), e2], dim1)) d3 self.dec3(torch.cat([self.up3(d2), e1], dim1)) return self.out(d3)网络的核心是 DoubleConv每个模块包含两个 3x3 卷积、BatchNorm 和 ReLU。编码器部分每经过一次池化通道数翻倍从 32 到 64 再到 128bridge 部分是 256 通道。上采样用转置卷积把特征图尺寸翻倍然后与对应编码器输出在通道维度做 concat。由于 concat 后的通道数是原来的两倍所以 decoder 的第一个 DoubleConv 输入通道也要跟着翻倍具体就是 base8 和 base4 的写法。参数设定方面in_ch3 对应 RGB 输入out_ch1 是二分类输出接 Sigmoid 变成概率图base32 是基础通道数如果显存紧张改成 16。需要注意的是如果把输入改成灰度单通道in_ch 要改为 1并且预处理也要改。4.3 损失函数与训练参数Dice 加权是关键细胞分割标签里背景占比通常远高于前景纯二元交叉熵会让模型偏向把所有像素预测为背景。常见解决方法是让 Dice Loss 和 BCE 联合使用。import torch import torch.nn.functional as F def dice_loss(logits, targets): probs torch.sigmoid(logits) smooth 1.0 intersection (probs * targets).sum() dice (2.0 * intersection smooth) / (probs.sum() targets.sum() smooth) return 1 - dice def bce_dice_loss(logits, targets): bce F.binary_cross_entropy_with_logits(logits, targets) return bce dice_loss(logits, targets)bce 负责逐像素的类别判断dice 负责整体区域的形状约束。smooth 参数防止前景和背景均为空时出现除零。targets 需要用 float 类型的张量值域 0 到 1不能是 LongTensor。实际使用时我会把 Dice Loss 的权重放到 1BCE 权重也保留为 1不额外调权重。如果遇到前景特别稀疏可以尝试把 Dice Loss 权重提高到 2。训练参数上这套配置在小数据集上比较稳。参数值说明优化器Adam / AdamWAdam 适应性学习率适合医学分割学习率1e-4过高容易震荡过低收敛慢weight_decay1e-5轻微正则防止过拟合batch_size8256x256 patch 时显存约 6-8Gepochs50配合早停不一定跑满早停 patience10验证集 Dice 连续 10 个 epoch 不升则停止4.4 训练循环骨架固定随机种子、保存最佳模型小数据训练一定要固定随机种子否则每次结果差异很大很难判断改参数到底是变好还是随机波动。训练循环里还需要保存验证集 Dice 最高的模型而不是最后一次 epoch 的模型。import torch import numpy as np def set_seed(seed): np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) def train_one_epoch(model, loader, optimizer, device): model.train() total_loss 0.0 for img, mask in loader: img img.to(device) mask mask.to(device) logits model(img) loss bce_dice_loss(logits, mask) optimizer.zero_grad() loss.backward() optimizer.step() total_loss loss.item() return total_loss / len(loader)这里输入 mask 需要是 float 类型网络输出 logits 后直接在损失函数里算 Sigmoid。注意如果标签是 0 和 1 之外的整数要先转成 float。训练时 monitor 验证集 Dice每个 epoch 后计算滑动平均保存 best state_dict。显存不够时可以把 batch_size 降到 4相应学习率也降到 5e-5否则梯度更新不稳定。4.5 评估指标与可视化分割模型不能只看准确率因为即使全部预测为背景准确率也可能很高。最常用的指标是 IoU 和 Dice计算方式如下import numpy as np def compute_metrics(pred_mask, gt_mask): pred (pred_mask 0.5).astype(np.uint8) gt (gt_mask 0.5).astype(np.uint8) inter np.logical_and(pred, gt).sum() union np.logical_or(pred, gt).sum() iou inter / (union 1e-6) dice (2 * inter) / (pred.sum() gt.sum() 1e-6) return iou, dicepred_mask 是模型输出的 0 到 1 概率图阈值取 0.5。如果发现前景像素占比低导致 Dice 波动大可以把阈值降低到 0.3 再看。58 张图规模下我一般做 5 折交叉验证每一折输出一个平均 IoU 和一个平均 Dice同时保存几张可视化的测试图。指标不是唯一标准肉眼检查边界是否贴着细胞核轮廓同样重要。如果模型把一片模糊细胞团全预测成前景Dice 可能不低但病理上不可用。5. 避坑与常见问题58 张小数据集上的四个血泪教训小数据集训练像走钢丝每一条踩进去都要花大半天排查。下面按现象到原因再到解决的结构写都是我在类似病理数据集上真实遇到过的问题。5.1 染色差异让模型学到“颜色分布”而不是细胞形态现象模型在训练集上 Dice 0.85但换到一个没见过的病例预测结果出现大片假阳性尤其在切片边缘和空白区域。原因HE 染色批次不同背景颜色差异很大。模型抓住的背景规律其实是“这个病例染色偏蓝”而不是“深色团块是细胞核”。如果训练集里某个病例的图像特别多颜色过拟合会非常明显。解决先做染色归一化或至少逐通道标准化并且保证训练集和验证集用同一组统计量。另外可以做一个消融实验把输入改成灰度图只保留结构信息如果灰度输入的表现接近 RGB说明模型确实在靠颜色作弊。从工程角度我还会把所有病例的像素均值画出来如果有病例明显偏离整体分布优先检查它是否被单独落在某个 fold 里。5.2 不按病例划分数据验证指标虚高现象随机拆分做交叉验证时平均 Dice 很高但把模型部署到其他数据集上表现明显下降。原因同一个 ytma 编号下的不同切片在训练集和验证集之间发生了泄漏。模型在训练时已经见过这个病例的染色风格验证指标自然好看但真实场景遇到的是陌生病例。解决严格按病例分组划分数据。建议写一个按 case_id 进行 GroupShuffleSplit 的脚本而不是用 random split。具体实现上先收集所有 case_id按病例编号分 fold保证一个 case 的所有图像只出现在训练侧或验证侧。如果某个病例只有 1 张图可以做留一病例验证或者直接把它排除在训练集外用其余数据训练再用它做测试。这样评估出来的指标才有参考价值。5.3 patch 尺寸选错细胞被切碎或显存爆炸现象用 512x512 patch 训练时显存经常溢出验证时边缘细胞的预测断裂换成 128x128 patch显存没问题但大块肿瘤区域预测出很多空洞。原因patch 尺寸和细胞核尺寸不匹配。如果 patch 只有细胞核直径的两三倍一个完整的细胞核会被窗口切到几个 patch 里每个 patch 中都只看到半个核模型自然学不出完整边界。反过来patch 太大导致 batch size 只能设小训练不稳定。解决在预处理阶段先统计 mask 中细胞核的等效直径。用连通域分析找到每个前景区域算出中位直径 dpatch size 取 4d 左右overlap 取 64 或 d 附近的整数值。如果显存不足优先减小 U-Net 的 base 通道数而不是压缩 patch。因为通道数减少只是牺牲模型容量patch 太小会直接破坏目标结构。5.4 数据增强没同步图像和 mask 错位现象训练早期 loss 不降甚至出现 NaN。检查训练图时发现细胞核在图像里是正着的mask 里的对应区域却是翻转的。原因对图像和 mask 分别用了不同的随机种子做随机翻转或旋转。比如图像随机水平翻转时mask 没有做相同的变换导致两者完全错位。很多新手写增强代码时习惯对 img 调用一次 random再对 mask 调用一次 random这样两边的随机状态不一样。解决所有随机几何变换必须同时作用于图像和 mask。用 PyTorch 写自定义 Dataset 时可以先取一个随机数决定是否翻转然后对 img 和 mask 调用同一个 flip 函数如果使用 albumentations直接在一个 transform 里同时传 image 和 mask。另外HE 图像不建议做颜色抖动或随机亮度调整因为这会和染色归一化的目标冲突。想增强数据多样性应该用弹性形变或轻微旋转。还有一条容易忽略的mask 在增强后要保持二值状态。如果用某些插值方式放大或旋转 mask会产生 0.4 这样的中间值计算 Dice 时被当成模糊标签导致指标偏低。处理 mask 时一律使用最近邻插值。6. 把 58 张小数据用到极致伪标签迭代与级联验证小数据集训练 U-Net 只是第一步真正让模型效果再上一个台阶的是伪标签迭代和级联验证。第一轮训练完成后用训练好的模型对没有标注或置信度不高的测试图进行预测得到概率图。把概率大于 0.9 且周围区域稳定的像素作为伪 mask人工挑几张边界清晰的 patch 校正后混入训练集做第二轮微调。这里有个前提伪标签只能加入训练集绝不能混入验证集。如果验证集里混入了带伪标签的数据评估结果就不再可靠。更实用的是级联分类。既然文件名已经带了 benign 和 malignant 的标签可以用分割结果反推良恶性分类。具体做法是用 U-Net 输出的 mask 计算形态学特征比如细胞核总面积、平均核周长、核密度、核质比把这些特征输入随机森林或单层 MLP做二分类。如果分割质量差这些特征会乱成一团分类准确率也上不去。这相当于用分类任务反过来监督分割模型的质量。我自己的验证习惯是固定一个随机种子按病例做 5 折交叉验证每一折都保存三样东西一是这一折的 IoU 和 Dice二是两张典型测试图的可视化结果三是整图的预测概率图。概率图不仅用来调阈值也会留作伪标签迭代的输入。保存内容用途每折 IoU / Dice判断模型稳定性是否受某个病例影响2-3 张可视化切片确认边界走向是否符合细胞核形态预测概率图伪标签迭代、级联分类特征提取从那以后我每碰一个小样本病理数据集都会强制走一遍染色归一化、按病例划分、同源增强、交叉验证的流程。指标虚高时第一反应不是调模型而是回头查数据切分和标签对齐。这些东西比换一个更复杂的网络更能决定项目能不能落地。希望帮到你。本文还有配套的精品资源点击获取