U-Net医学图像分割实战:PyTorch实现与训练调优全解析
2026/9/11 2:10:40 网站建设 项目流程

简介:这份U-Net代码包聚焦医学图像分割、语义分割与多类别分割三类常见任务,面向深度学习初学者以及需要快速搭建分割基准的算法工程师。整体基于PyTorch框架实现,包含数据集加载、数据增强、模型定义、训练、预测、混淆矩阵生成、均值方差统计等环节,构成一套可独立运行的完整流程。代码中对U-Net的收缩路径、扩展路径以及跳跃连接进行了清晰定义,能够在小样本医学图像上学习上下文语义与细致边界,适合处理病灶区域定位、组织结构提取等实际问题。资源包共31个文件,以Python源码和编译后的pyc文件为主,同时附带工程配置、依赖清单与说明文档,压缩后仅16KB,非常轻量。目前已有466人学习下载,可以作为医学图像分割课题的起点代码,也可以在此基础上替换数据集、调整网络结构或继续融合注意力机制,便于二次开发与实验扩展。

1. 为什么说 U-Net 是医学图像分割的默认起点

做医学图像分割的人,不管最终选什么网络,绕不开的第一份参考代码大概率都是 U-Net。这个结构在 2015 年提出,到现在十多年过去,仍然是小样本场景下最稳的 baseline。这套代码就是一份完整的 PyTorch 实现,包含 model.py(网络结构)、dataset.py(数据加载)、train.py(训练脚本)、predict.py(推理脚本)以及 confuse_matrix.py(评估脚本),可以直接跑通从数据预处理到结果评估的完整流程。

项目结构里值得注意的细节是 requirements.txt 和 transforms.py,前者锁定了依赖版本,后者提供了训练时的数据增强策略。对于数据集特别小的医学影像任务,这两个文件往往比网络结构本身更影响最终结果。接下来会沿着“结构原理 → 数据准备 → 训练与推理 → 评估与改进”这条线,把这套代码拆开讲透,顺便把最容易踩的坑标出来。

2. U-Net 结构与多类别分割的语义对齐

2.1 收缩路径如何用最少的参数捕获上下文

打开 model.py 可以看到,收缩路径由 5 个 block 组成,每个 block 做两次 3×3 卷积,后面接 ReLU 激活和 2×2 最大池化下采样。这里有一个反直觉的点:U-Net 没有用主流的预训练骨干网络,而是从零开始训练。原因在于医学图像和 ImageNet 自然图像分布差异太大,预训练权重反而可能引入噪声。

# model.py 中收缩路径的核心块 class DoubleConv(nn.Module): def __init__(self, in_ch, out_ch): super(DoubleConv, self).__init__() self.conv = nn.Sequential( nn.Conv2d(in_ch, out_ch, 3, padding=1), nn.BatchNorm2d(out_ch), nn.ReLU(inplace=True), nn.Conv2d(out_ch, out_ch, 3, padding=1), nn.BatchNorm2d(out_ch), nn.ReLU(inplace=True) ) def forward(self, x): return self.conv(x)

上面代码中的 DoubleConv 是构建 U-Net 的基础模块。每次卷积后都接 BatchNorm,相比原始论文多了 BN 层,作用是在 batch size 较小时维持梯度稳定性。padding 设为 1 是为了保持特征图尺寸不变,这样与扩展路径拼接时不需要做额外裁剪,也简化了多类别分割时类别数变化带来的维度适配问题。

下采样次数决定了网络能感知的最大范围。5 次池化后,最深层的特征图尺寸是输入图像的 1/32,每个像素的感受野已经覆盖原始图像的主要区域。对多类别分割来说,这意味着大器官(如肝脏、肺叶)的类别判别能力强,但小目标的细节恢复仍依赖跳跃连接提供的浅层特征。

2.2 跳跃连接与扩展路径的特征融合逻辑

扩展路径做对称的上采样。每个 block 先做一次 2×2 转置卷积把分辨率翻倍,然后与收缩路径对应层做 channel 维度的拼接。这个拼接是 U-Net 的核心:深层特征含有丰富的语义类别信息,浅层特征保留了空间边界信息,两者拼接后,网络在恢复分辨率的同时能持续参考高分辨率特征图。

# model.py 中扩展路径的上采样与拼接 class Up(nn.Module): def __init__(self, in_ch, out_ch): super(Up, self).__init__() self.up = nn.ConvTranspose2d(in_ch, in_ch // 2, 2, stride=2) self.conv = DoubleConv(in_ch, out_ch) def forward(self, x1, x2): x1 = self.up(x1) diffY = x2.size()[2] - x1.size()[2] diffX = x2.size()[3] - x1.size()[3] x1 = F.pad(x1, [diffX // 2, diffX - diffX // 2, diffY // 2, diffY - diffY // 2]) x = torch.cat([x2, x1], dim=1) return self.conv(x)

拼接操作把通道数翻倍,然后通过 DoubleConv 压缩到目标通道数。这里对 x1 的 padding 处理很关键,它解决了输入尺寸不是 2 的整数次幂时,转置卷积与收缩路径特征图尺寸不一致的问题。在实际项目中,建议在数据预处理阶段就把图像统一缩放到 512×512 或 256×256,这样这段 padding 逻辑会走空分支,减少不必要的边界伪影。

多类别分割需要改动的只有输出层。原始 U-Net 在最后一层用 1×1 卷积把通道数映射为 2(前景/背景),这里改成类别数即可,比如肝脏、肿瘤、血管三个类别就输出 3 个 channel,每个 channel 对应一个类别的像素概率图,配合 softmax 就能得到每个像素的类别标签。

2.3 损失函数设计与类别不均衡处理

train.py 里默认使用交叉熵损失函数,这对二分类足够。但多类别分割时,如果各类别像素数量差距很大(例如肿瘤区域只占整幅图像的 2%),模型很容易把所有像素都预测为背景类别。常见做法是给损失函数加上权重,或者直接用 Dice Loss。

# train.py 中可切换的损失函数 def dice_loss(pred, target, smooth=1.0): pred = torch.softmax(pred, dim=1) target_onehot = torch.nn.functional.one_hot(target, num_classes=pred.shape[1]).permute(0, 3, 1, 2).float() intersection = (pred * target_onehot).sum(dim=(2, 3)) union = pred.sum(dim=(2, 3)) + target_onehot.sum(dim=(2, 3)) dice = (2.0 * intersection + smooth) / (union + smooth) return 1.0 - dice.mean()

这段 Dice Loss 实现有几个细节值得注意。smooth 参数防止分子分母同时为零,一般取 1.0。目标标签先做 one-hot 编码,再与 softmax 输出的概率图逐像素求交集,每个类别独立计算 Dice 系数,最后取平均作为损失。实际项目中通常把交叉熵和 Dice Loss 按 0.5:0.5 加权混合,既能保证类别不均衡下的收敛稳定性,又保留交叉熵对像素级预测的精细梯度。

3. 从 dataset.py 到 transforms.py:数据管道搭建与增强策略

3.1 Dataset 类与文件路径约定

查看 dataset.py 可以看到,数据集的加载方式依赖一个 txt 文件列表,每一行记录一张训练图像的路径,对应的 mask 按命名规则匹配。这种做法比 ImageFolder 方式更适合医学图像场景,因为医学数据往往不是标准目录结构,而是按病例号、序列号等维度组织。

# dataset.py 中数据加载的核心逻辑 class MedicalDataset(Dataset): def __init__(self, root, split='train', transform=None): self.file_list = [] with open(os.path.join(root, f'{split}.txt'), 'r') as f: for line in f.readlines(): self.file_list.append(line.strip()) self.transform = transform def __getitem__(self, idx): img_path = self.file_list[idx] mask_path = img_path.replace('images', 'masks').replace('.jpg', '.png') image = cv2.imread(img_path) mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE) if self.transform: image, mask = self.transform(image, mask) return image, mask

文件命名约定在这里起到了关键作用。images 目录下存储原始图像,masks 目录下存储标注文件,通过路径替换自动匹配。医疗影像数据集的标注格式非常多,比如 NIfTI、DICOM,但训练时统一转换为 PNG/JPG 可以降低 IO 开销。这里的关键是把标注读取为灰度图(IMREAD_GRAYSCALE),这样 mask 的每个像素值代表一个类别 ID,多类别分割时只需要在标注时把不同类别的像素值设为 1、2、3 即可,不需要额外存储 one-hot 格式的标注文件。

Dataset 类的返回值是 image 和 mask 的 tuple,其中 mask 是长整型张量,维度为 H×W,而 image 是 H×W×3 的浮点张量。两者维度不同,在训练循环中分别送入模型和损失函数。很多初次接触分割任务的读者会在这一步犯错,直接在模型输入处对 mask 做 squeeze,实际上 mask 不需要也不应该增加 channel 维度。

3.2 transforms.py 中的数据增强与同步变换

transforms.py 并不是简单的 torchvision.transforms 封装,而是针对“图像和 mask 必须同步变换”这一需求做了专门设计。医学图像分割增强的关键是平移、旋转、翻转、缩放这些几何变换,同时保证 mask 与图像经历相同的空间变换,否则标签会错位。

# transforms.py 中同步变换实现 class RandomRotate: def __init__(self, angle_range=(-15, 15)): self.angle_range = angle_range def __call__(self, image, mask): angle = random.uniform(*self.angle_range) h, w = image.shape[:2] matrix = cv2.getRotationMatrix2D((w // 2, h // 2), angle, 1.0) image = cv2.warpAffine(image, matrix, (w, h), flags=cv2.INTER_LINEAR) mask = cv2.warpAffine(mask, matrix, (w, h), flags=cv2.INTER_NEAREST) return image, mask

这段代码里最关键的一行是 mask 旋转时使用 INTER_NEAREST 插值,而图像使用 INTER_LINEAR。如果用双线性插值处理 mask,边缘会产生介于 0 和 1 之间的非整数像素值,导致类别标签出现非法取值。最近邻插值虽然会产生锯齿状边缘,但可以保证 mask 中每个像素值仍然是有效的类别 ID。

增强策略在训练和验证时需要区别对待。一般会在训练集上使用随机旋转、翻转、亮度抖动和随机缩放,验证集只做 resize 和归一化。如果训练数据量少于 200 张,可以进一步叠加弹性形变和 cutout 增强来缓解过拟合,U-Net 对形变类增强的鲁棒性比较好,因为它本身对空间位置的敏感度就比较低。

3.3 均值标准差计算与归一化边界

代码中 compute_mean_std 脚本的存在说明归一化参数不是写死的,而是根据具体数据集计算得出。医学图像的像素分布和自然图像差异很大,比如 X 光片背景是纯黑,MRI 图像的灰度范围随设备参数变化,使用 ImageNet 的均值标准差做归一化效果往往不理想。

python compute_mean_std.py --data_dir data/images

该脚本会扫描所有训练图像,计算每个 channel 的均值和标准差,输出结果直接填入 train.py 的 transform 参数。如果数据集包含不同模态的图像,例如同时有 CT 和 MRI,建议分别计算归一化参数,或者按模态分组进行归一化。混合使用统一参数会引入模态间的分布差异,导致模型在某一模态上的分割精度下降。

4. Train 与 Predict:单卡训练完整的参数调优流程

4.1 训练参数设置与学习率策略

train.py 中暴露的训练参数包括批量大小、初始学习率、训练轮数、验证集比例与模型保存频率。医学分割任务的 batch size 通常受限于 GPU 显存,512×512 的输入图像配合 U-Net 在单卡上只能跑 8~16 的 batch。

python train.py --data_dir datasets/ --num_classes 3 --batch_size 8 --epochs 100 --lr 0.001 --gpu 0

--num_classes 设置时要注意,包含背景类和其他前景类。比如希望分割肝脏和肿瘤两个类别,num_classes 应该设为 3(背景、肝脏、肿瘤)。这是多类别分割最常见的错误,少算一个类别会导致 channel 维度不匹配或损失函数无法收敛。--lr 选择 0.001 对应 Adam 优化器,如果改用 SGD 则需要调低到 0.01 并配合 momentum 和 weight decay,否则前期收敛过慢。

训练过程中建议使用余弦退火或降低学习率策略。固定学习率训练 U-Net 经常出现损失在前 20 轮快速下降后进入平台期,余弦退火能让模型在后期以较小的步长精细搜索边界附近的最优解,对分割精度的提升通常在 1% 到 2% 的 Dice 系数。训练参数可按下表设置:

参数推荐值适用场景
batch_size8~16512×512 输入、单卡 16G 显存
lr0.001(Adam)、0.01(SGD)小数据集用较低学习率更稳
num_classes背景数 + 前景类别总数多类别分割,漏背景是高频错误
epochs100~200验证损失 20 轮不降时触发早停
validation_split0.2 或固定列表文件调参期建议固定验证集

验证集的划分在代码里支持两种方式。如果传入 validation_split 数值,则从训练集中按比例随机切分;如果固定使用单独的验证列表文件,则每次实验保持完全一致的验证集。倾向后者,尤其是在调参阶段,固定验证集可以避免随机切分带来的验证指标波动,让你真正比较网络结构或损失函数改动带来的效果差异。

4.2 从 checkpoint 恢复训练与多卡扩展

train.py 中保存的 checkpoint 包含模型参数、优化器状态、当前 epoch 和最佳验证指标。恢复训练时需要把这几部分一起加载,如果只恢复模型参数,优化器的状态会被重置。学习率调度器内部维护了当前 step 计数,直接恢复训练会导致学习率跳回初始值,破坏原有训练曲线。

python train.py --resume checkpoints/best_model.pth

关于多卡训练,代码默认是单卡模式。如果只有一张显卡,不需要额外配置。如果有多张显卡,需要将模型封装为 DataParallel,同时将 batch size 等比例扩大。需要留意的是,BatchNorm 层在数据并行模式下使用全局统计信息,当输入图像尺寸较大时,建议使用 DistributedDataParallel 而不是简单 DataParallel,否则各个进程的 BN 统计不同步,收敛抖动会比较明显。

对于训练曲线,建议同时记录训练损失和验证损失,每当验证指标不再提升时保存一份 checkpoint,最后用验证 Dice 最高的权重做预测。很多情况下训练损失可以降到很低,但验证损失在中间某个 epoch 开始反弹,这就是过拟合信号。U-Net 参数量不小,在 100 张以内的小数据集上,过拟合通常在 60 个 epoch 左右出现,此时应提前停止或降低学习率。

4.3 推理脚本中的输入预处理与后处理细节

predict.py 承担了从加载单个图像到输出分割结果的完整流程。除了基础的手动归一化,脚本还实现了一个实际功能:图像输入尺寸不匹配时自动执行 padding。医学图像原始尺寸五花八门,除了 512×512,有些扫描图是 1024×1024,需要划分 patch 做推理。

# predict.py 中推理前图像尺寸修正 def preprocess_image(img_path, target_size=512): image = cv2.imread(img_path) h, w = image.shape[:2] scale = target_size / max(h, w) new_w, new_h = int(w * scale), int(h * scale) image = cv2.resize(image, (new_w, new_h)) pad_w, pad_h = target_size - new_w, target_size - new_h image = cv2.copyMakeBorder(image, 0, pad_h, 0, pad_w, cv2.BORDER_CONSTANT, value=0) return image

这段代码采用等比缩放加边界填充的方案,保持原始长宽比,避免直接 resize 导致的空间形变。目标尺寸设为网络输入要求,一般是 512 或 256。注意 pad 值设置为 0 意味着边界像素的亮度值被填充为黑色,如果训练时使用的是平均像素填充,则需要保持一致的填充值,否则推理性能会下降。

后处理部分,predict.py 对每个像素取类别通道的最大值索引,生成与输入分辨率相同的标注图。另外还保留了概率图输出,softmax 后每个通道对应一个类别的置信度。对置信度较低的像素点,可以设置阈值过滤后标记为不确定区域,或者配合条件随机场进行空间平滑。在血管分割等细长结构场景中,直接取 argmax 会产生很多断裂的小线段,此时可以先对概率图做形态学闭运算,再用阈值取最终结果。

4.4 双线性上采样替代转置卷积的边界问题

转置卷积在特征图尺寸不是输入图像整数倍时会引入棋盘伪影。具体来说,当扩展路径最后一层的特征图尺寸需要上采样到原始分辨率,而上采样倍率与卷积核大小不匹配时,转置卷积输出的某些区域会比其他区域多一部分叠加响应,表现为网格状纹理。

# 使用双线性插值替代部分转置卷积 class UpSample(nn.Module): def __init__(self, in_ch, out_ch): super(UpSample, self).__init__() self.up = nn.Sequential( nn.Upsample(scale_factor=2, mode='bilinear', align_corners=False), nn.Conv2d(in_ch, out_ch, 3, padding=1) )

如果要替换 model.py 中标准的上采样方式,可以直接把 Up 类中的转置卷积换成 Upsample 加卷积的组合。这种设计的优点是避免棋盘伪影,缺点是参数量增加,且可能丢失转置卷积学到的可变形位置信息。经验是:对小器官、细血管的分割任务,用双线性插值替代转置卷积后 Dice 指数会有小幅提升;但对大区域结构(如整个肺叶),两者效果几乎无差异,此时转置卷积的参数量更省,训练速度更快。

5. 评估与改进:混淆矩阵与 Diffusion U-Net 扩展方向

5.1 混淆矩阵的类别可视化与误分类分析

confuse_matrix.py 输出的不只是一张图,而是每个类别的混淆矩阵统计。医学图像分割的多类别评估比自然图像评估更关注类别间的具体混淆模式,例如肿瘤分割中最常见的错误往往是把肿瘤边缘混淆为肝脏组织,或者让小血管被判定为背景。

# confuse_matrix.py 中关键统计函数 def compute_confusion_matrix(pred, target, num_classes): pred = pred.flatten() target = target.flatten() matrix = np.zeros((num_classes, num_classes), dtype=np.int64) for p, t in zip(pred, target): matrix[t, p] += 1 return matrix

上面的循环实现通过遍历每个像素,以真实标签为行索引、预测标签为列索引进行累加。如果类别数过多,这种 Python 循环的耗时比较明显,可以换成 numpy 的 bincount 一次性完成统计。有了混淆矩阵,除了计算每个类别的 IoU 和 Dice,更重要的是观察相邻编号类别之间的混淆程度。例如类别 1 和类别 2 混淆严重,说明模型对这两个组织的纹理特征区分能力不足,需要考虑在对应通道上增加监督信息或调整数据采样权重。

单张图像的混淆矩阵不足以定位问题,应在验证集上累计所有图像的混淆矩阵,再归一化为百分比形式查看。对每一个类别输出 precision、recall 与 Dice 的单独指标,再通过掩码叠加的方式把错误分类的像素映射到原图上,快速检查错误是否集中在边缘区域或小目标区域。

5.2 从标准 U-Net 到改进变体:注意力与深度监督

代码里这个 U-Net 是基础版本,没有引入注意力机制或残差模块。真实任务中如果基础版本分割效果不达标,通常会按“先调数据、后调结构”的顺序推进。结构上最简单的改动是加入 Attention Gate,该机制在跳跃连接之前计算浅层特征与深层特征的相似度,对无关区域的浅层特征进行抑制,对相关区域的特征进行增强。

# 一个轻量级 Attention Gate 的简化实现 class AttentionGate(nn.Module): def __init__(self, in_ch_g, in_ch_l, out_ch): super(AttentionGate, self).__init__() self.W_g = nn.Sequential(nn.Conv2d(in_ch_g, out_ch, 1), nn.BatchNorm2d(out_ch)) self.W_x = nn.Sequential(nn.Conv2d(in_ch_l, out_ch, 1), nn.BatchNorm2d(out_ch)) self.psi = nn.Sequential(nn.Conv2d(out_ch, 1, 1), nn.BatchNorm2d(1), nn.Sigmoid()) def forward(self, g, x): g1 = self.W_g(g) x1 = self.W_x(x) psi = self.psi(F.relu(g1 + x1)) return x * psi

这个简化版 Attention Gate 把门控信号和解码器特征相加后,经过 1×1 卷积生成空间注意力权重,并与跳跃连接的浅层特征逐元素相乘。这样做的好处是让跳跃连接的特征不再无差别地全部输入扩展路径,而是有选择地聚焦前景区域。多个类别分割时,注意力权重实际上是类别无关的,如果想要对每个类别分别生成注意力掩码,需要把通道数扩展到类别数量然后逐通道计算。

另一种改动是深度监督。在 U-Net 中,较浅层只有跳跃连接而没有直接的损失信号,导致浅层特征学习偏慢。可以在每个扩展路径 block 后都接一个 1×1 卷积输出分割图,分别计算损失后加权求和,让浅层也能获得直接梯度回传。不过需要留意,深度监督会占用额外显存,并且不同深度的损失权重需要手动调整,否则可能干扰主路径收敛。

5.3 与 Diffusion U-Net 的关系以及在遥感语义分割中的应用

近年来 Diffusion 模型热度很高,其中扩散模型的去噪网络核心也是 U-Net,但加了时间步长嵌入和多分辨率特征融合,结构上和医学分割 U-Net 有差异。这里的代码为扩散模型提供了一个很好的骨架,可以把 predict.py 的输入从单帧图像改成带噪声图像和时间步长 tensor,再在 DoubleConv 中增加 time embedding 的相加,就能迁移到扩散模型的去噪网络中。

在遥感影像语义分割中,这套代码同样适用。遥感图像通常是大尺寸多通道数据,比如 RGB 加近红外,此时只需要修改 dataset.py 中图像读取的通道数量,并把第一层卷积的 in_ch 改为相应数值。与医学图像相比,遥感场景下类别之间的尺度差异更加悬殊,建筑物、道路、植被的像素占比差距很大,因此推荐在代码的损失函数模块中额外引入边界损失或 Lovasz-Softmax 损失,来提升边缘像素的分割一致性。

如果直接做遥感语义分割复现,一个容易忽视的坑是地理坐标信息的丢失。分割网络只关注像素特征,不关心像素对应的地理坐标,而遥感影像中相同地物在不同区域的光谱响应差异很大。常见做法是把经纬度、高度、传感器角度等信息编码成额外 channel 拼接输入,或者先做影像匀色和归一化处理,把不同时相的影像调整到相近的辐射范围,再送入训练。这套代码的数据管道已经支持多通道输入,只需要增加一个通道读取逻辑。

6. 小样本场景下 U-Net 训练的最终技巧

6.1 学习率首轮预热与权重初始化验证

当训练数据少于 50 张时,模型在前几个 epoch 极容易出现损失震荡。常见做法是设置 warm-up 阶段,让学习率从小数值线性增加到目标值,避免初始大步长把随机初始化的权重推入不好的局部区域。在 train.py 中实现起来非常简单,只需在优化器外层封装一个自定义调度器,并在每轮迭代中手动设置学习率。

# 自定义 warm-up 学习率调整器 def adjust_learning_rate(optimizer, epoch, warmup_epochs=5, base_lr=0.001): if epoch < warmup_epochs: lr = base_lr * (epoch + 1) / warmup_epochs else: lr = base_lr * 0.1 ** ((epoch - warmup_epochs) // 30) for param_group in optimizer.param_groups: param_group['lr'] = lr

代码基于当前 epoch 判断是否处于预热阶段,预热结束后每 30 轮学习率衰减为原来的 0.1。注意这里使用的是 epoch 而不是 iteration,对于 batch size 较小的场景,一个 epoch 内迭代轮数不多,用 epoch 控制衰减更稳定。

在使用 U-Net 训练自己的数据集时,很多人忽略对模型权重初始化范围的检查。可以在正式训练前打印第一层卷积输出的均值和方差,如果初始化结果过大或过小,说明模型权重初始化策略不适合当前输入数据分布。遇到这种情况,可把卷积层的初始化改为 Kaiming 初始化,或在预处理阶段减去数据集均值,让初始输入处于激活函数的线性响应区间。

6.2 TTA 测试时增强与多尺度推理

推理阶段的技巧对分割精度的提升非常直接。TTA(测试时增强)的核心思路是把同一张输入图像做水平翻转、垂直翻转、旋转 90 度等变换后分别推理,再对输出概率映射回原坐标系并求平均。这种方法特别适合 U-Net,因为医学图像通常没有方向敏感性,翻转不会改变器官的语义类别。

# predict.py 中 TTA 推理的简化实现 for angle in [0, 90, 180, 270]: rotated = rotate_image(image, angle) prob = model(rotated) prob = rotate_back(prob, angle) prob_sum += prob final_pred = prob_sum / 4

TTA 的加速比通常是 1 份输入对应 4 份推理,显存占用会放大,如果 GPU 显存有限,可以按批次处理或只使用水平翻转和垂直翻转两种变换。多尺度推理则把图像缩放为 0.75、1.0、1.25 倍分别推理再融合。对于医学图像,多尺度融合的效果一般比 TTA 更明显,因为不同器官的最优观察尺度不同,小肿瘤在大尺度下更容易检出,大器官在小尺度下更好分割边界。

6.3 代码中 requirements.txt 与 pip 安装的版本对应

拿到压缩包后先把 requirements.txt 里的依赖安装到干净环境,避免不同版本 PyTorch 对算子实现的细节差异影响复现。常见的是使用以下命令创建虚拟环境并安装依赖。

python -m venv unet_env source unet_env/bin/activate pip install -r requirements.txt

如果 requirements.txt 里锁定的 torch 版本较老,建议先升级到 torch 2.x,因为新版本的自动混合精度和编译优化对训练速度的提升很明显。但升级后需要检查 model.py 中是否使用旧 API,例如旧版本中的torch.nn.functional.pad行为在 2.x 中保持一致,但torchvision.transforms中部分接口已调整位置。遇到旧代码报错时,先查看报错信息涉及的具体函数,直接改为新接口即可,不需要重写结构。

压缩包里的 README 文件如果记录了版本要求,就按 README 建议的环境运行。如果 README 缺失或信息不足,可以参考 train.py 中导入的模块版本范围。建议用 miniconda 管理多个 Python 版本,为每个医学图像分割项目单独建环境,这样不同项目的依赖冲突不会相互影响。

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

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

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

立即咨询