简介这份资源是一套面向深度学习初学者的图像细胞分割Python实战Demo围绕医疗图像分析场景帮助零基础读者理解并跑通从数据准备到模型预测的完整流程。压缩包共625个文件、约34.32MB其中516张jpg与90张png构成细胞图像数据集8个py源码包含UNet_train.py、UNet_predict.py等核心训练与预测逻辑另有6个xml配置、1个ipynb交互笔记及utils工具目录覆盖数据预处理、模型构建、训练评估各环节。目前已有376人学习下载。读者可借此掌握UNet分割网络的搭建思路、图像转换与辅助函数的组织方式并通过交互式notebook观察实验过程适合作为入门深度学习和图像处理的练手项目也可在此基础上替换数据集开展自己的分割实验。1. 从一堆细胞图到可复现的 UNet 分割 Demo这份源码到底能跑出什么如果你手头有一批细胞显微图像想快速验证「深度学习图像细胞分割」到底能不能落地又不想从零搭数据管线这份基于 Python 的 UNet 细胞分割源码 Demo 值得先拆一遍。它把训练、预测、数据预处理和交互式实验都塞进了一个工程里核心是UNet_train.py和UNet_predict.py两个脚本外加一个gan.ipynb用来做实验性质的训练展示。数据集以 jpg 和 png 为主量级在几百张属于典型的入门级深度学习实践作品适合刚接触图像分割、想跑通「数据→模型→掩膜」完整链路的人。它不是工业级方案但作为理解 UNet 在医疗图像分析中如何工作的起点性价比很高。2. 拆开工程看结构UNet 训练脚本与数据管线怎么串2.1 目录里真正决定能不能跑起来的几个文件拿到一个源码包我习惯先不看代码先看目录里哪些文件是「活的」。这份 Demo 里真正影响运行结果的其实就几类UNet_train.py负责模型训练UNet_predict.py负责推理输出分割掩膜utils目录大概率放着数据加载、图像增强、指标计算这些辅助函数transformer.py从命名看是图像转换或预处理相关。剩下的 jpg/png 是细胞图像数据集xml 是训练过程中保存的参数或状态gan.ipynb是交互式实验入口.iml和.idea是 IDE 配置跟模型效果无关。这里有个容易翻车的点很多人拿到源码直接python UNet_train.py结果报路径错误。原因是训练脚本里往往写死了数据目录的相对路径或绝对路径。我一般会先打开UNet_train.py找到数据加载部分确认它期望的图像放在哪个文件夹、掩膜放在哪个文件夹、文件名有没有配对规则。这份 Demo 的图像文件命名是image_03082.jpg这种格式如果掩膜文件不是同名或同后缀就需要在数据加载函数里改配对逻辑。2.2 训练脚本的关键参数与启动方式UNet 的训练流程本身不复杂输入图像经过下采样编码器提取特征再经过上采样解码器恢复分辨率最后输出每个像素的类别概率。但要让它在你的机器上跑起来几个参数必须对。# UNet_train.py 中常见的训练入口结构示意以实际源码为准 import os import numpy as np from tensorflow.keras.optimizers import Adam from utils.data_loader import load_train_data from utils.model import unet_model # 数据路径这里是最容易出错的地方改成你本机实际路径 train_images_path ./data/train/images train_masks_path ./data/train/masks # 图像尺寸UNet 要求输入尺寸能被 16 整除4 次下采样 IMG_HEIGHT 256 IMG_WIDTH 256 IMG_CHANNELS 3 # 加载数据 X_train, Y_train load_train_data( train_images_path, train_masks_path, img_size(IMG_HEIGHT, IMG_WIDTH) ) # 构建模型 model unet_model(input_shape(IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS)) # 编译分割任务常用二元交叉熵优化器用 Adam model.compile( optimizerAdam(learning_rate1e-4), lossbinary_crossentropy, metrics[accuracy] ) # 训练batch_size 受显存限制4GB 显存建议不超过 8 results model.fit( X_train, Y_train, validation_split0.1, batch_size8, epochs50, verbose1 ) # 保存权重方便 UNet_predict.py 直接加载 model.save(unet_cell_seg.h5)这段代码里IMG_HEIGHT和IMG_WIDTH设成 256 是常见做法因为 UNet 经过 4 次池化后特征图会缩到 16×16再小就不好恢复边界了。batch_size设 8 是保守值显存够可以往上加但要注意学习率也要相应调整。validation_split0.1表示从训练集里切 10% 做验证如果数据量本来就少这个比例可以降到 0.05。损失函数用binary_crossentropy是因为细胞分割通常是二分类像素属于细胞或不属于细胞。如果你的数据是多类细胞就要换成categorical_crossentropy并把最后一层激活函数改成softmax。2.3 预测脚本怎么把模型输出变成可视化掩膜训练完拿到.h5权重后UNet_predict.py的工作就是加载权重、读入新图像、输出分割结果。这里的关键是阈值选择模型输出的是 0 到 1 之间的概率图你需要定一个阈值常见 0.5来决定哪些像素算细胞。# UNet_predict.py 推理流程示意 import cv2 import numpy as np from tensorflow.keras.models import load_model # 加载训练好的模型 model load_model(unet_cell_seg.h5) # 读取待预测图像 img cv2.imread(image_03082.jpg) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img_resized cv2.resize(img, (256, 256)) img_input img_resized / 255.0 # 归一化到 0-1 img_input np.expand_dims(img_input, axis0) # 增加 batch 维度 # 预测输出 shape 为 (1, 256, 256, 1) 的概率图 pred model.predict(img_input)[0, :, :, 0] # 阈值化大于 0.5 判为细胞区域 mask (pred 0.5).astype(np.uint8) * 255 # 保存结果 cv2.imwrite(predicted_mask.png, mask)归一化这一步不能省。训练时如果对图像做了/255.0预测时也必须做同样的处理否则输入分布不一致输出会完全乱掉。阈值 0.5 不是铁律如果发现分割结果偏保守漏掉一些细胞可以降到 0.3 到 0.4如果误检太多就提到 0.6。我一般会先用几张图试不同阈值看哪个更接近肉眼判断。3. 数据预处理与增强让几百张图也能训出稳定模型3.1 细胞图像为什么不能直接 resize 就喂进去细胞显微图像有个特点不同图像之间亮度、对比度、染色深浅差异很大。如果直接把原始 jpg resize 到 256×256 就送进网络模型很容易学到「亮度高就是细胞」这种伪特征换一批图就崩。常见做法是在数据加载阶段做几件事转灰度或统一色彩空间、直方图均衡化、归一化。这份 Demo 里transformer.py大概率承担了部分转换工作但具体做了哪些需要打开确认。如果源码里没有做增强我建议在utils/data_loader.py里补上。最基础的增强包括随机旋转、水平翻转、轻微缩放。细胞图像通常没有方向性旋转和翻转是安全的。但要注意图像和掩膜必须同步变换否则标签就错了。# 在 data_loader 中加入同步增强的示意 import cv2 import numpy as np import random def random_augment(image, mask): # 随机水平翻转 if random.random() 0.5: image cv2.flip(image, 1) mask cv2.flip(mask, 1) # 随机旋转 90 度的整数倍 k random.randint(0, 3) image np.rot90(image, k) mask np.rot90(mask, k) return image, mask这段增强逻辑简单但有效。np.rot90的第二个参数k控制旋转次数每次 90 度。同步操作是关键图像转了掩膜必须跟着转。如果要做更复杂的仿射变换建议用albumentations库它支持图像和掩膜同步变换省去手写配对逻辑的麻烦。3.2 训练集、验证集、测试集怎么切才不泄漏这份 Demo 的数据量在几百张级别如果随机切分容易出现同一张图的不同增强版本同时出现在训练集和验证集里导致验证指标虚高。正确做法是按原始图像切分再做增强。比如 500 张图先分 400 张训练、100 张验证然后只对训练集做增强。验证集保持原始状态用来真实反映模型泛化能力。另一个坑是类别不平衡。细胞图像里细胞区域往往只占整张图的一小部分背景像素远多于前景。如果直接算准确率模型全预测背景也能到 90% 以上。所以训练时最好用 Dice 系数或 IoU 作为监控指标而不是只看 accuracy。如果源码里只写了 accuracy可以在model.compile的metrics里加上tf.keras.metrics.MeanIoU(num_classes2)。4. 避坑与排查跑这份 Demo 时最容易翻车的五个地方4.1 现象训练 loss 一直不降准确率卡在 0.5 左右原因通常是输入数据没有归一化或者掩膜标签的像素值不是 0 和 1 而是 0 和 255。UNet 输出层用 sigmoid 时标签必须是 0 到 1 之间的浮点数。如果掩膜是 0/255 的 uint8损失计算会出问题。解决在数据加载函数里加一行mask mask / 255.0并确认mask的数据类型转成float32。同时检查图像是否做了/255.0归一化。4.2 现象预测结果全黑或全白原因可能是阈值设得不对或者模型根本没训练好。如果训练 loss 正常下降但预测全黑先检查预测时的预处理是否和训练时一致。常见错误是训练时用了 RGB预测时用了 BGROpenCV 默认读入是 BGR导致输入分布完全不同。解决统一用cv2.cvtColor(img, cv2.COLOR_BGR2RGB)转成 RGB或者在训练和预测时都用 BGR。关键是两边一致。4.3 现象显存不足报 OOM 错误原因batch_size太大或者输入图像尺寸太大。256×256 的 UNet 在 4GB 显存上跑 batch_size8 通常没问题但如果源码默认是 512×512 或 batch_size16就容易爆。解决先把batch_size降到 2 或 4确认能跑通后再逐步往上加。如果还不行把输入尺寸降到 128×128但要注意 UNet 的下采样次数也要相应减少否则特征图会缩到 1×1。4.4 现象gan.ipynb打开后无法运行报缺少模块原因notebook 里可能引用了源码包里没有的库或者依赖版本不匹配。这份 Demo 是入门级作品作者的环境未必和你一致。解决先看报错缺哪个模块用pip install补上。如果是 TensorFlow 或 PyTorch 版本问题建议新建虚拟环境按readme.txt里的版本要求安装。没有 readme 的话TensorFlow 2.x 通常比 1.x 兼容性好。4.5 现象训练到一半 loss 突然变成 NaN原因学习率太大或者数据里有异常值比如全黑或全白的图像。细胞图像里如果有损坏文件读进来可能是全零数组导致梯度爆炸。解决把学习率从 1e-3 降到 1e-4 或 1e-5。同时在数据加载时加一个过滤if image.sum() 0: continue跳过空图像。如果 NaN 出现在训练后期可能是过拟合加 Dropout 或早停。5. 进阶技巧用 Dice Loss 和模型集成把分割边界磨得更准跑通基础版本之后如果发现细胞边界分割得毛毛糙糙可以试两个改进。第一个是把损失函数从二元交叉熵换成 Dice Loss或者两者加权组合。交叉熵对每个像素独立计算而 Dice Loss 直接优化预测掩膜和真实掩膜的 overlap对边界更敏感。实现起来不复杂# Dice Loss 实现可作为自定义损失函数传入 model.compile import tensorflow as tf def dice_loss(y_true, y_pred, smooth1e-6): y_true_f tf.reshape(y_true, [-1]) y_pred_f tf.reshape(y_pred, [-1]) intersection tf.reduce_sum(y_true_f * y_pred_f) return 1 - (2. * intersection smooth) / ( tf.reduce_sum(y_true_f) tf.reduce_sum(y_pred_f) smooth ) # 组合损失交叉熵 Dice def combined_loss(y_true, y_pred): bce tf.keras.losses.binary_crossentropy(y_true, y_pred) return bce dice_loss(y_true, y_pred)smooth参数防止分母为零一般设 1e-6。组合损失里交叉熵和 Dice 的权重可以调我一般先用 1:1如果边界还是差就加大 Dice 权重。第二个技巧是模型集成用不同的随机种子训练 3 到 5 个 UNet预测时把概率图平均后再阈值化。这样做能明显减少单模型的随机波动代价是推理时间成倍增加。对于这份 Demo 的数据量集成 3 个模型通常能把 IoU 提升 3 到 5 个百分点。还有一个容易被忽略的点预测时的图像尺寸。如果训练用的是 256×256预测时也必须是 256×256不能直接拿原始尺寸的图进去。如果原始图像很大可以先 resize 到 256 预测再把掩膜 resize 回原始尺寸。但 resize 掩膜时要用最近邻插值否则边界会糊。从那以后我每次跑分割 Demo都强制先拿一张图走完「训练→预测→可视化」全流程确认链路通了再批量跑。希望帮到你。本文还有配套的精品资源点击获取