资讯中心

Unet+Resnet医学图像分割实战:多尺度训练与多类别改造

📅 2026/9/30 5:52:30
Unet+Resnet医学图像分割实战:多尺度训练与多类别改造
简介这份资源是面向深度学习图像分割初学者与进阶者的实战项目包以Unet为主干网络、Resnet为backbone聚焦子宫颈细胞核的二分类分割任务同时演示多尺度训练与多类别分割的完整实现思路。包内共804个文件以jpg与png图像数据为主辅以py训练与推理脚本、pyc缓存、xml标注、txt日志及pth权重文件压缩包约113.33MB数据集、代码与训练好的权重一应俱全经测试可直接运行。项目仅训练50个epochs全局像素准确度即达0.89、miou为0.82继续加大训练轮数性能还有提升空间。训练脚本会自动将数据随机缩放至0.5至1.5倍实现多尺度训练utils中的compute_gray函数可将mask灰度值保存至txt并自动定义UNET输出通道学习率采用cos衰减损失与iou曲线、各类别iou、recall、precision及全局准确率均可在run目录与训练日志中查看推理时只需将待测图像放入inference目录并运行predict脚本即可无需额外参数。目前已有228人学习适合希望快速上手分割项目、理解多尺度训练与多类别分割流程的读者参考。1. 从一份 113MB 的细胞核分割包说起UnetResnet 到底能跑出什么子宫颈细胞核分割是个听起来很窄、实际上很典型的任务2 分类背景和细胞核图像里目标密集、边界粘连、尺度差异大。很多做医学图像的朋友第一次跑分割要么卡在 mask 灰度值映射上要么被多类别输出通道数搞晕要么训完发现小目标全糊了。这份 113MB 的实战包给的就是一条已经跑通的路径——Unet 做骨架Resnet 做 backbone训练时随机缩放 0.5 到 1.5 倍做多尺度增强50 个 epoch 全局像素准确率 0.89、miou 0.72。它适合两类人刚入门想找一个能直接跑通的分割项目练手以及手头有自己数据、想拿这套多尺度多类别流程改一改就用的从业者。下面我按「资源是什么、怎么跑、坑在哪、怎么进阶」拆开讲代码和参数都能直接抄。2. UnetResnet 的结构选型与多尺度训练机制2.1 为什么是 Resnet 做 backbone 而不是原版 Unet 编码器原版 Unet 的编码器是几层卷积堆出来的感受野有限层数一深梯度就不好传。Resnet 的残差结构把这个问题绕开了跳跃连接让梯度能直接回传深层特征也能保住。常见做法是拿 Resnet34 或 Resnet50 的 stage 输出当编码器特征再接到 Unet 的解码器上做上采样和拼接。这样做的直接好处是细胞核这种边界模糊、纹理细的目标深层语义特征比浅层卷积更稳。选 Resnet 还有一层工程上的考虑预训练权重好找。医学图像数据量通常不大从零训容易过拟合加载 ImageNet 预训练权重再微调收敛快很多。这份包里权重文件是训练好的但你自己换数据时backbone 部分建议还是走预训练初始化。2.2 多尺度训练是怎么实现的多尺度训练的核心动作在 train 脚本里每读一张图随机缩放到设定尺寸的 0.5 到 1.5 倍之间再送进网络。这不是简单的 resize 增强它逼着网络在不同尺度下都能认出细胞核——大尺度看整体分布小尺度看边界细节。细胞核分割里目标大小差异本来就大固定尺度训练很容易让某一类尺寸的目标被忽略。实现上一般是在 Dataset 的__getitem__里做随机缩放同时把 image 和 mask 用同一组参数缩放保证像素对齐。缩放后再随机裁剪到网络输入尺寸。这里有个细节缩放比例是连续均匀采样还是离散几个档位会影响训练稳定性。连续采样增强更充分但 batch 内尺度差异大BN 层统计量会抖离散档位稳一些增强力度弱一点。这份包用的是连续区间配合 cos 学习率衰减50 epoch 能到 0.72 miou说明这个组合是work的。2.3 compute_gray 与输出通道自动定义多类别分割最容易翻车的地方就是 mask 的灰度值和类别索引对不上。utils 里的compute_gray函数干的事就是扫描所有 mask把出现过的灰度值收集起来写进 txt然后根据这个列表自动决定 UNET 输出几个 channel。2 分类就是背景细胞核两个通道如果以后换成 5 类改数据就行网络输出层会自动跟着变。这个设计省掉了手动改 num_classes 的步骤但也埋了个前提mask 灰度值必须是离散的、有限的几个值。如果你的 mask 是经过插值或者抗锯齿处理的灰度值会出现一堆中间值compute_gray 收集出来的列表会爆炸输出通道数直接失控。所以 mask 在预处理阶段一定要保证是最近邻缩放或者原始标注别用双线性插值。2.4 学习率 cos 衰减与训练日志学习率用余弦退火从初始值平滑降到接近 0。相比 step 衰减cos 衰减在训练后期学习率更小权重更新更细对分割这种像素级任务比较友好。训练日志里记录了每个类别的 iou、recall、precision还有全局像素准确率run_results 目录下用 matplotlib 画了 loss 和 iou 曲线。看日志有个经验如果训练集 iou 还在涨、测试集 iou 平了甚至掉了说明过拟合该加增强或者早停如果两个都平在低位多半是学习率或者尺度设置有问题。50 epoch 这个量级曲线一般还没完全收敛加大 epoch 性能还能往上走但要注意测试集 iou 的拐点。3. 从零跑通训练与推理环境、命令与参数3.1 环境准备与依赖这份包是 Python PyTorch 路线环境配置不复杂但版本要对齐。常见做法是用 conda 建一个独立环境避免和系统里的包打架。# 创建环境python 版本建议 3.8 到 3.10 conda create -n unet_seg python3.9 -y conda activate unet_seg # 安装 pytorch按自己 cuda 版本选这里以 cu118 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 其余依赖 pip install numpy opencv-python matplotlib pillow tqdm逻辑说明torch 和 torchvision 必须版本匹配单独 pip install torch 有时会拉到 cpu 版训练慢到怀疑人生。装完在 python 里跑import torch; print(torch.cuda.is_available())返回 True 才算对。opencv 用来读图和做缩放matplotlib 画曲线tqdm 看进度条。3.2 数据目录结构与 mask 检查包里的 jpg 文件是图像样本mask 一般放在对应目录下。跑之前先确认三件事图像和 mask 文件名能对上、mask 是单通道灰度图、灰度值只有背景和细胞核两类。可以用下面这段脚本快速体检import cv2 import numpy as np import os mask_dir data/masks gray_values set() for name in os.listdir(mask_dir): mask cv2.imread(os.path.join(mask_dir, name), cv2.IMREAD_GRAYSCALE) if mask is None: print(读不到:, name) continue gray_values.update(np.unique(mask).tolist()) print(出现的灰度值:, sorted(gray_values))逻辑说明IMREAD_GRAYSCALE强制按单通道读避免三通道 mask 混进来。np.unique把每张 mask 里出现过的灰度值收集起来最后打印。如果输出是[0, 255]这种干净的两值说明可以直接用如果出现[0, 1, 2, 128, 255]一堆值就得先做灰度映射否则 compute_gray 会给你定义出五六个输出通道。3.3 启动训练与关键参数训练入口是 train 脚本直接跑就行但有几个参数值得按自己数据调python train.py \ --data_root ./data \ --epochs 50 \ --batch_size 8 \ --lr 1e-3 \ --input_size 256 \ --scale_range 0.5 1.5参数说明epochs控制训练轮数50 是包里的默认值想冲更高 miou 可以加到 100 到 150但要盯着测试集曲线batch_size受显存限制8 是 256 输入尺寸下的常见值显存不够就降到 4同时把 lr 按比例降一点lr初始学习率cos 衰减会从它开始往下走input_size是网络输入尺寸多尺度缩放后裁剪到这个大小scale_range就是多尺度的 0.5 到 1.5 倍区间改窄一点训练更稳改宽一点增强更狠。训练过程中 run_results 目录会生成 loss 和 iou 曲线图日志文件里能看到每个 epoch 的详细指标。如果 loss 一开始就 nan多半是学习率太大或者数据里有脏样本先把 lr 降到 1e-4 试。3.4 推理把图丢进 inference 直接跑推理流程被设计得很省事待推理图像放进 inference 目录运行 predict 脚本不需要传参数。python predict.py逻辑说明predict 脚本会自动加载训练好的权重遍历 inference 目录下的图输出分割结果。常见做法是输出 mask 图或者叠加图具体看脚本实现。这里要注意输入图像的尺寸和训练时的一致性——如果训练用的是 256 输入推理图太大或太小脚本内部的 resize 逻辑要能兜住否则结果会偏。跑完检查一下输出目录确认每张输入都有对应结果没有漏图。4. 避坑与排查多尺度、mask 和显存的血泪经验4.1 现象训练 loss 震荡厉害iou 上不去原因多尺度缩放区间太宽batch 内图像尺度差异过大BN 层统计量在每个 batch 之间跳变导致梯度方向不稳。解决先把 scale_range 收窄到 0.8 到 1.2 跑几个 epoch 看曲线是否平滑稳了再逐步放宽。或者把 BN 换成 GNGroupNorm对 batch 内尺度差异不敏感但改网络结构要动代码新手先调缩放区间更省事。4.2 现象compute_gray 报错或者输出通道数对不上原因mask 灰度值不连续。标注工具导出时做了抗锯齿或者用双线性插值缩放过 mask导致出现大量中间灰度值。解决mask 的缩放一律用最近邻插值cv2.resize(mask, size, interpolationcv2.INTER_NEAREST)。如果已经有一批脏 mask写个映射脚本把灰度值归到最近的类别值上再重新跑 compute_gray。4.3 现象训练到一半显存爆了原因多尺度训练时缩放后的图像尺寸不固定某些 batch 里恰好都是放大 1.5 倍的图显存占用比预期高。解决在 Dataset 里做缩放后统一裁剪到固定 input_size别让整张大图直接进网络。另外可以把 batch_size 调小配合梯度累积模拟大 batch。显存监控用nvidia-smi -l 1看峰值占用再定 batch。4.4 现象推理结果全是背景或者全是前景原因权重加载失败或者推理时的预处理和训练时不一致。比如训练时做了归一化推理时忘了做网络输入分布对不上。解决检查 predict 脚本里的预处理步骤确认归一化参数和训练时一致。再确认权重文件路径对不对加载后打印一下网络输出的取值范围正常应该在 0 到 1 之间经过 sigmoid 或 softmax。如果输出全是 0 或 1多半是权重没加载上。4.5 现象测试集 iou 比训练集低很多原因数据量小过拟合。50 epoch 对医学图像来说不算多但如果训练集本身只有几十张图网络会把训练集背下来。解决加数据增强除了多尺度还可以加随机翻转、旋转、亮度扰动。另外可以冻结 backbone 前几层只训解码器减少参数量。如果测试集 iou 持续低于训练集 0.2 以上考虑加 dropout 或者 weight decay。5. 进阶把 2 分类流程改成多类别分割的实操5.1 多类别改造的三个动作这份包虽然标的是 2 分类但 compute_gray 的设计已经为多类别留了口子。改成多类别要动三个地方第一mask 的灰度值要重新映射成 0 到 N-1 的连续整数每个值代表一个类第二损失函数从二分类的 BCE 换成多分类的 CrossEntropyLoss 或者多标签的 BCE第三输出通道数由 compute_gray 自动决定不用手动改。import numpy as np # 假设原始 mask 灰度值是 [0, 128, 255]对应背景、类1、类2 mapping {0: 0, 128: 1, 255: 2} def remap_mask(mask): out np.zeros_like(mask, dtypenp.uint8) for old, new in mapping.items(): out[mask old] new return out逻辑说明mapping字典把原始灰度值映射到连续类别索引remap_mask逐类替换。跑完这个再让 compute_gray 去扫它收集到的就是[0, 1, 2]输出通道自动变成 3。注意映射前先确认原始 mask 里到底有哪些灰度值别拍脑袋写 mapping。5.2 多类别下的 iou 计算与日志解读多类别分割的 miou 是每个类 iou 的平均值背景类通常 iou 很高会拉高均值所以看日志时要分开看每个类的 iou。细胞核分割里如果细胞核类 iou 只有 0.5 而背景 0.95miou 0.72 看着还行实际细胞核分割质量一般。改进方向是给细胞核类加权或者在 loss 里对少样本类加大权重。5.3 验证模型有没有真正学到东西除了看 iou我习惯做两件事一是把预测 mask 叠加到原图上肉眼检查边界二是挑几张训练集里没有的图做推理看泛化。如果叠加图上细胞核边界毛糙、粘连处断不开说明解码器的上采样还不够细可以加一层 skip connection 或者换更深的 backbone。如果推理图整体偏移检查预处理里的 resize 和 padding 是否和训练一致。从那以后我每次拿到一个新的分割包都强制先跑一遍 mask 灰度值检查再跑一个 epoch 看 loss 曲线确认数据管道没问题才开长训练。这套流程帮我省了不少返工时间。希望帮到你。本文还有配套的精品资源点击获取

看完文章,想为自己的企业也做一次专业网站诊断?

尧图顾问免费为您评估现有网站,并给出建站/改版建议与报价方案。

免费获取方案