U-Net 语义分割详解:原论文、PyTorch 实现与真实消融实

U-Net 已经发表十余年,但它仍是语义分割中最值得先掌握的结构之一。原因不复杂:编码器负责压缩上下文,解码器负责恢复分辨率,同尺度跳跃连接把定位信息送回解码端。后来出现的 UNet++、Attention U-Net、3D U-Net、nnU-Net 以及大量 Transformer、状态空间模型变体,都没有绕开这组基本矛盾------语义需要大感受野,边界需要高分辨率

这篇文章从 2015 年原论文出发,给出张量尺寸、损失函数、PyTorch 实现和一组可复查的小型实验。文中的训练曲线、预测结果、中间特征与消融数据均来自实际运行,不使用示意数字。

阅读路线

|---------------------|---------------------------|-------------------------|-------------------|
| 结构 编码器、解码器、Skip | 原论文 valid conv、权重图、切块 | 实现与实验 PyTorch、曲线、消融 | 进阶 论文、开源项目、视频 |


1. 语义分割在求什么

给定输入图像

网络输出每个像素的类别分数

二分类通常令 ,输出前景 logit;多分类令 ,每个像素对应 个类别分数。训练阶段保留 logits,推理时再做 Sigmoid 或 Softmax。

语义分割与相邻任务的区别如下。

任务 输出 同类实例是否区分
图像分类 整张图一个类别 不涉及
目标检测 类别与边界框 区分
语义分割 每个像素一个类别 不区分
实例分割 每个实例一个掩码 区分

下面的样例从左到右分别是输入、人工标注与预测。分割结果不能只看整体轮廓,还要检查边界、孔洞、小目标和相邻对象之间是否粘连。

图 1 Oxford-IIIT Pet 输入、标注与预测示例

处理数据时有一条很容易被忽略的规则:图像可以使用双线性插值,离散标签必须使用最近邻插值。如果对类别掩码使用双线性插值,标签中会出现原本不存在的中间值,损失函数看到的监督信号已经被污染。


2. U-Net 的结构与张量流

图 2 现代 same-padding U-Net 数据流

2.1 编码器

编码器由重复的卷积块和下采样组成。每下降一级,空间尺寸通常减半,通道数增加:

复制代码
256×256×64
→ 128×128×128
→ 64×64×256
→ 32×32×512
→ 16×16×1024

较浅的特征保留边缘、纹理和精确坐标;较深的特征拥有更大感受野,更适合判断"这是什么"。下采样换来了语义范围,也丢掉了细边界和小目标信息。

二维卷积的输出尺寸为

时,输入输出尺寸相同,即常说的 same padding。

2.2 解码器

解码器逐级上采样,把低分辨率语义恢复到原图尺度。常见实现有两种:

  • 转置卷积:参数可学习,但需要留意棋盘格伪影;
  • 双线性插值加卷积:实现直接,尺寸控制更稳定。

上采样只能放大特征,不能凭空还原池化前的坐标,所以还需要跳跃连接。

2.3 Skip Connection

U-Net 把编码器同尺度特征与解码器特征沿通道维拼接:

复制代码
x = torch.cat([skip, x], dim=1)

假设两路特征都是 B×256×64×64,拼接后得到 B×512×64×64。后续卷积负责融合浅层定位信息和深层语义。

Concat 与 Add 的差别不只是写法:

融合方式 通道变化 特点
Concat 相加 信息保留充分,但更占显存
Add 不变 轻量,但要求两路通道一致

如果输入尺寸不是 的倍数,连续下采样后可能出现奇数尺寸,导致上采样结果与 skip 对不上。工程中不要依赖"刚好整除",而应显式对齐到 skip 的尺寸:

复制代码
x = F.interpolate(x, size=skip.shape[-2:], mode="bilinear", align_corners=False)

2.4 1×1 输出卷积

最后一层 1×1 卷积只改变通道数,不改变空间尺寸。它相当于在每个像素位置使用同一组线性分类器:

  • 二分类:输出 1 个通道;
  • 类互斥分割:输出 个通道;
  • 多标签分割:输出 个独立通道。

3. 2015 年原论文里容易被忽略的细节

原论文题为 U-Net: Convolutional Networks for Biomedical Image Segmentation,发表于 MICCAI 2015。论文结构图如下。

图 3 U-Net 2015 原论文结构图

图源:Ronneberger、Fischer、Brox,MICCAI 2015。

现代教程经常把 U-Net 画成输入输出等大,但原版并不是这样。原论文使用不填充的 3×3 卷积:输入为 572×572,输出为 388×388;编码器特征在送入解码器前需要裁剪,图中因此写的是 copy and crop

项目 2015 原版 现代常见实现
3×3 卷积 valid padding same padding
输入与输出 572→388 通常同尺寸
Skip 对齐 裁剪后拼接 直接拼接或插值对齐
上采样 2×2 up-convolution 转置卷积或插值加卷积
归一化 无 BatchNorm BN、GN、IN 均常见
损失 带像素权重的交叉熵 CE、BCE、Dice、Focal 等
数据增强 强调弹性形变 按任务选择几何与强度增强

这一区分很重要。复现原论文时应保留 valid convolution、crop 与 overlap-tile;做现代工程时,same padding 往往更方便。两者都是 U-Net,但不能把工程改写误认为论文原设定。

3.1 边界加权损失

论文处理细胞分割时,希望模型主动分开相互接触的细胞。作者构造了像素权重图:

其中 是像素到最近、次近细胞边界的距离。两细胞之间的窄缝会得到较大权重。

图 4 原论文边界权重图示例

这个权重图属于损失函数设计,不是注意力模块,也不是网络额外输出。它针对的是"粘连实例如何分开"这一具体问题。

3.2 Overlap-tile

原论文用镜像扩展和重叠切块处理超大显微图像。

图 5 Overlap-tile 策略

现代滑窗推理仍沿用相同思路:切出重叠 patch,分别预测,再用高斯或中心加权融合重叠区域。直接无重叠拼接容易在 patch 边缘留下接缝。

3.3 原论文真正有价值的部分

U-Net 的贡献不只是画出一个 U 形网络。更重要的是三件事:

  1. 把"上下文识别"和"精确定位"放在同一端到端结构里;
  2. 用高分辨率 skip 特征补偿下采样造成的定位损失;
  3. 把网络结构、数据增强、边界损失和大图推理组合成完整方案。

4. 损失函数与指标

4.1 二分类:BCEWithLogits + Dice

BCEWithLogitsLoss 内部已经包含数值稳定的 Sigmoid。训练时直接传 logits,不要提前调用 torch.sigmoid

Soft Dice 直接优化区域重叠:

实践中常用

BCE 提供稳定的逐像素梯度,Dice 对前景稀少更友好。权重不必固定为 0.5,应在验证集上根据前景比例和边界要求调整。

4.2 多分类:CrossEntropyLoss

互斥多分类通常使用 CrossEntropyLoss

  • logits:B×K×H×W,浮点数;
  • target:B×H×Wlong 类型;
  • target 存类别索引,不做 one-hot 也不提前 Softmax。

4.3 Dice、IoU 与边界指标

Dice 和 IoU 都强调区域重叠,但不能完整描述边界质量。医学或细结构任务还应报告 HD95、Surface Dice、Precision 和 Recall。只报一个整体 Dice,可能掩盖小目标、细血管或极端失败样例。

4.4 常见接口错误

现象 常见原因 修正
loss 不下降 标签值为 0/255 或形状错误 二分类掩码转为 0/1 float
CE 报 dtype 错误 target 是 float 改为 long 类别索引
BCE 报尺寸不一致 target 少了通道维 保持 B×1×H×W
指标很好但图很差 大量背景主导像素准确率 改看 Dice、IoU 与错误图
预测全背景 类别失衡、阈值过高或监督损坏 检查正像素比例、logits 与掩码插值

5. 一个清晰可用的 PyTorch U-Net

下面的实现使用 same padding、双线性插值和 concat skip。它保留 logits,可直接接 BCE 或 CE。

复制代码
from __future__ import annotations
import torch
import torch.nn as nn
import torch.nn.functional as F


class DoubleConv(nn.Module):
    def __init__(self, in_ch: int, out_ch: int, norm: str = "batch"):
        super().__init__()

        def norm_layer(c: int):
            if norm == "group":
                groups = min(8, c)
                while c % groups != 0:
                    groups -= 1
                return nn.GroupNorm(groups, c)
            if norm == "none":
                return nn.Identity()
            return nn.BatchNorm2d(c)

        self.net = nn.Sequential(
            nn.Conv2d(in_ch, out_ch, 3, padding=1, bias=False),
            norm_layer(out_ch),
            nn.ReLU(inplace=True),
            nn.Conv2d(out_ch, out_ch, 3, padding=1, bias=False),
            norm_layer(out_ch),
            nn.ReLU(inplace=True),
        )

    def forward(self, x):
        return self.net(x)


class Down(nn.Module):
    def __init__(self, in_ch: int, out_ch: int, norm: str):
        super().__init__()
        self.net = nn.Sequential(
            nn.MaxPool2d(2),
            DoubleConv(in_ch, out_ch, norm),
        )

    def forward(self, x):
        return self.net(x)


class Up(nn.Module):
    def __init__(self, in_ch: int, skip_ch: int, out_ch: int, norm: str):
        super().__init__()
        self.reduce = nn.Conv2d(in_ch, out_ch, 1)
        self.fuse = DoubleConv(out_ch + skip_ch, out_ch, norm)

    def forward(self, x, skip):
        x = F.interpolate(
            x, size=skip.shape[-2:], mode="bilinear", align_corners=False
        )
        x = self.reduce(x)
        x = torch.cat([skip, x], dim=1)
        return self.fuse(x)


class UNet(nn.Module):
    def __init__(
        self,
        in_channels: int = 3,
        num_classes: int = 1,
        widths=(64, 128, 256, 512),
        norm: str = "batch",
    ):
        super().__init__()
        w1, w2, w3, w4 = widths
        self.e1 = DoubleConv(in_channels, w1, norm)
        self.e2 = Down(w1, w2, norm)
        self.e3 = Down(w2, w3, norm)
        self.e4 = Down(w3, w4, norm)
        self.bottleneck = Down(w4, w4 * 2, norm)

        self.d4 = Up(w4 * 2, w4, w4, norm)
        self.d3 = Up(w4, w3, w3, norm)
        self.d2 = Up(w3, w2, w2, norm)
        self.d1 = Up(w2, w1, w1, norm)
        self.head = nn.Conv2d(w1, num_classes, 1)

    def forward(self, x, return_features: bool = False):
        e1 = self.e1(x)
        e2 = self.e2(e1)
        e3 = self.e3(e2)
        e4 = self.e4(e3)
        b = self.bottleneck(e4)

        d4 = self.d4(b, e4)
        d3 = self.d3(d4, e3)
        d2 = self.d2(d3, e2)
        d1 = self.d1(d2, e1)
        logits = self.head(d1)

        if return_features:
            features = {
                "E1": e1, "E2": e2, "E3": e3, "E4": e4,
                "Bottleneck": b, "D4": d4, "D3": d3,
                "D2": d2, "D1": d1,
            }
            return logits, features
        return logits

5.1 BCE + Dice 损失

复制代码
class BCEDiceLoss(nn.Module):
    def __init__(self, bce_weight=0.5, dice_weight=0.5, eps=1e-6):
        super().__init__()
        self.bce_weight = bce_weight
        self.dice_weight = dice_weight
        self.eps = eps

    def forward(self, logits, target):
        bce = F.binary_cross_entropy_with_logits(logits, target)
        prob = torch.sigmoid(logits)
        dims = tuple(range(1, prob.ndim))
        inter = (prob * target).sum(dims)
        denom = prob.sum(dims) + target.sum(dims)
        dice_loss = 1 - (
            (2 * inter + self.eps) / (denom + self.eps)
        ).mean()
        return self.bce_weight * bce + self.dice_weight * dice_loss

5.2 训练与验证

复制代码
def train_one_epoch(model, loader, optimizer, criterion, device):
    model.train()
    total = 0.0
    for image, mask in loader:
        image = image.to(device, non_blocking=True)
        mask = mask.to(device, non_blocking=True).float()

        optimizer.zero_grad(set_to_none=True)
        logits = model(image)
        loss = criterion(logits, mask)
        loss.backward()
        optimizer.step()
        total += loss.item() * image.size(0)
    return total / len(loader.dataset)


@torch.no_grad()
def evaluate(model, loader, criterion, device, threshold=0.5):
    model.eval()
    loss_sum = dice_sum = iou_sum = 0.0

    for image, mask in loader:
        image = image.to(device, non_blocking=True)
        mask = mask.to(device, non_blocking=True).float()
        logits = model(image)
        loss_sum += criterion(logits, mask).item() * image.size(0)

        pred = torch.sigmoid(logits) >= threshold
        truth = mask >= 0.5
        dims = tuple(range(1, pred.ndim))
        tp = (pred & truth).sum(dims).float()
        fp = (pred & ~truth).sum(dims).float()
        fn = (~pred & truth).sum(dims).float()
        dice_sum += ((2 * tp + 1e-7) / (2 * tp + fp + fn + 1e-7)).sum().item()
        iou_sum += ((tp + 1e-7) / (tp + fp + fn + 1e-7)).sum().item()

    n = len(loader.dataset)
    return {
        "loss": loss_sum / n,
        "dice": dice_sum / n,
        "iou": iou_sum / n,
    }

5.3 推理

复制代码
model.eval()
with torch.no_grad():
    logits = model(image.to(device))
    probability = torch.sigmoid(logits)
    mask = (probability >= 0.5).to(torch.uint8)

数据集必须保证以下约定:

复制代码
image: float32, B×3×H×W
mask : float32, B×1×H×W,值为 0 或 1

随机裁剪、翻转和旋转必须同时作用于图像与掩码。对两者分别调用随机增强,会悄悄破坏像素对齐,模型通常只会学到背景统计。

建议把项目拆成以下目录,而不是把所有逻辑塞进一个 notebook:

复制代码
unet_project/
├── datasets/
│   └── dataset.py
├── models/
│   └── unet.py
├── losses/
│   └── dice.py
├── metrics/
│   └── segmentation.py
├── train.py
├── predict.py
├── config.yaml
└── requirements.txt

6. 真实训练实验

为了验证 skip、损失函数和增强的影响,下面使用 Penn-Fudan Pedestrian 数据集做一个小型受控实验。它不是追求榜单结果,而是让四组配置在同一台 CPU 环境中快速跑完。

6.1 实验设置

项目 设置
数据 Penn-Fudan Pedestrian,固定取 100 张
划分 80 张训练,20 张验证
输入 96×96 RGB
模型 3 次下采样,base channel=8
参数量 113,113
卷积 MACs 约 82.58M(96×96 输入)
损失 0.5 BCE + 0.5 Dice
优化器 Adam,初始学习率 1e-3
训练 12 Epoch,seed=42
设备 CPU

这组模型比标准 64 通道、4 次下采样的 U-Net 小得多,因此结果只用于比较同一实验内的相对变化。

6.2 曲线与最佳结果

图 6 标准配置训练曲线

标准配置在第 6 个 Epoch 取得最佳验证结果:

指标 数值
Dice 0.6538
IoU 0.4977
Precision 0.6064
Recall 0.7547

训练损失持续下降,但验证损失在第 6 个 Epoch 之后小幅波动,说明继续训练的收益已经有限。对这类小数据实验,保存最佳验证 checkpoint 比直接使用最后一轮更稳妥。

6.3 预测与错误图

图 7 验证集预测与错误分析

图中四列依次为输入、真值、前景概率和错误叠加:绿色为 TP,青色为 FN,红色为 FP。可以看到三类典型问题:

  1. 拥挤区域粘连:多人轮廓靠得很近,低分辨率概率图难以分开个体;
  2. 细结构漏检:腿、手臂和窄边界更容易出现 FN;
  3. 背景误检:与人体纹理相近的区域产生 FP。

只看一张二值掩码,很难区分"阈值不合适"和"模型根本没有学到"。概率图与 FP/FN 错误图应当成为固定的验证输出。


7. Skip、Loss 与增强的受控消融

四组实验使用相同数据划分、随机种子、训练轮数与评估代码,只改变一个因素。

图 8 U-Net 受控消融结果

配置 Dice IoU 相对标准配置
标准:Skip + BCE/Dice + 增强 0.6538 0.4977 ---
移除 Skip 0.6224 0.4579 Dice -0.0314
仅 BCE 0.6466 0.4904 Dice -0.0072
无增强 0.6599 0.5045 Dice +0.0060

这张表可以得到三个有限而明确的结论。

第一,移除 skip 的下降最明显。 在同一小模型中,解码器缺少浅层定位信息,边界和细结构首先受损。

第二,BCE + Dice 略优于仅 BCE。 前景占比不均衡时,直接优化区域重叠通常有帮助,但本次差距不大,不能把损失函数当成万能模块。

第三,无增强组在这次短实验中略高。 这不等于"增强有害"。单随机种子、12 个 Epoch 和固定验证集不足以支持该结论;合理解释是增强提高了训练难度,而短训练尚未把长期泛化优势表现出来。正式实验至少应增加随机种子、训练预算和外部测试集。


8. 参数量、计算量、显存与特征图

卷积层参数量近似为

输出特征尺寸为 时,卷积 MACs 约为

有些工具把一次乘加记作 1 MAC,有些换算成 2 FLOPs。比较论文或工具结果时,先确认统计口径。

单个激活张量的显存近似为

训练显存还包括梯度、优化器状态、临时算子缓冲以及 skip 特征。U-Net 在高分辨率阶段保留多级 skip,concat 又会临时增加通道,因此显存压力往往集中在浅层和解码融合处,而不是参数最多的瓶颈层。

图 9 训练模型的真实中间特征图

从实际激活可以观察到:

  • 浅层特征响应边缘、亮度变化和局部纹理;
  • 编码越深,空间分辨率越低,响应区域更连贯;
  • 瓶颈层更像粗粒度语义图,不再保留精确轮廓;
  • 解码器在上采样和 skip 融合后逐步恢复边界。

特征图不能只挑"看起来漂亮"的通道。更可靠的做法是固定样本、固定层、固定通道选择规则,并同时展示成功与失败案例。


9. 最有效的排错顺序

语义分割的大多数问题并不来自"模型不够新",而来自数据与评估协议。

9.1 先让模型过拟合极小样本

固定 1~4 张图,关闭随机增强,持续训练到训练 Dice 接近 1。如果做不到,优先检查:

  1. 图像与掩码文件是否一一对应;
  2. 掩码是否真的是 0/1 或合法类别索引;
  3. 几何增强是否同步;
  4. 输出和 target 的形状、dtype 是否匹配;
  5. 损失输入是否为 logits;
  6. 梯度、学习率与参数更新是否正常。

极小样本都无法过拟合时,继续换骨干或加注意力通常没有意义。

9.2 检查数据泄漏

医学、视频和连续切片数据必须按患者、病例或序列划分。把同一患者的相邻切片分到训练集和验证集,会得到漂亮但失真的验证结果。

9.3 小 batch 不要盲用 BatchNorm

3D 分割或大分辨率训练常把 batch size 压到 1~2。此时 BatchNorm 的统计量不稳定,可改用 GroupNorm、InstanceNorm,或冻结预训练编码器中的 BN。

9.4 先分析错误,再调阈值

二分类阈值 0.5 只是默认值。应在验证集上画 Precision-Recall 或 Dice-threshold 曲线,再选择阈值。阈值只能改变 FP/FN 权衡,无法修复模糊标签、数据泄漏和结构性漏检。


10. 变体怎么选

方法 主要改动 适用场景
ResUNet 卷积块加入残差连接 更深网络、优化更稳定
UNet++ 嵌套、多级 skip 融合 多尺度差异明显,显存允许
Attention U-Net 对 skip 做门控 背景复杂、需抑制无关区域
3D U-Net Conv2d 改为 Conv3d CT、MRI、显微体数据
nnU-Net 自动配置预处理、patch、网络和训练方案 医学分割强基线
Swin/SSM U-Net 用注意力或状态空间模块建模长程关系 高分辨率、全局上下文重要
MedSAM/SAM2 提示式掩码生成 交互标注、开放对象分割

一个实用的选型顺序是:

  • 第一次做任务:先跑通普通 U-Net;
  • 医学 2D/3D:优先建立 nnU-Net 强基线;
  • 自然场景:使用成熟框架和预训练编码器;
  • 小目标或边界任务:先检查分辨率、采样、损失和标注质量;
  • 提示式分割:明确 SAM 生成的是对象 mask,不等于固定类别语义分割。

11. 2024---2026 年值得关注的方向

近年的工作不再只是替换编码器。研究重点逐渐转向采样混叠、skip 几何、线性长程建模、基础模型协同、模型合并和评测可信度。

工作 会议 关注点 阅读入口
nnU-Net Revisited MICCAI 2024 强基线与公平评测 论文与评审
SegMamba MICCAI 2024 3D 体数据的线性长程建模 论文 / 代码
SegMAN CVPR 2025 SSM、局部注意力与全尺度上下文 论文 / 代码
LHU-Net MICCAI 2025 轻量 3D 混合建模 论文 / 代码
U-RWKV MICCAI 2025 方向自适应线性长程建模 论文与评审 / 代码
U-Net Transplant MICCAI 2025 多个 3D 分割模型的能力合并 论文 / 代码
CROWn CVPR 2026 抗混叠下采样与跨尺度相位校准 论文 / 代码
AD-GBC CVPR 2026 区域级 skip 特征精炼 论文 / 代码
Spatial-SAM CVPR 2026 3D U-Net 的 SDF 记忆与 SAM2 协同 论文 / 代码

阅读新结构时,建议先问五个问题:

  1. 基线是否使用了同样的数据、预训练、增强和训练预算;
  2. 是否在多个数据集与多个随机种子上稳定成立;
  3. 提升是否超过实验波动;
  4. 是否同时报告边界指标、参数、显存和速度;
  5. 新模块拿掉后,强基线是否仍然被公平训练。

11.1 常用开源项目

以下 Stars 为 2026-08-23 快照,会随时间变化,不能代替代码质量、维护状态和许可证检查。

项目 Stars 许可证 适合做什么
segmentation_models.pytorch 11,703 MIT 快速组合 U-Net、FPN、DeepLab 与预训练编码器
Pytorch-UNet 11,605 GPL-3.0 学习 U-Net 与单任务复现
MMSegmentation 9,924 Apache-2.0 自然场景 benchmark 与配置化训练
nnU-Net 8,816 Apache-2.0 医学 2D/3D 自配置强基线
MONAI 8,625 Apache-2.0 医疗影像 transforms、训练、推理与部署
SAM2 19,741 Apache-2.0 图像与视频提示式分割
MedSAM 4,376 Apache-2.0 医疗提示式分割与域适配

使用代码前应确认 commit、预训练权重、数据预处理和许可证。Stars 高不代表适合生产,未声明许可证也不等于可以自由商用。


12. 视频学习路线

不必把所有视频一次看完。先看结构,再完成一次实现,最后按任务进入 nnU-Net、3D 或基础模型。

阶段 视频 时长
中文结构 U-Net 网络结构讲解 · 霹雳吧啦Wz 12:15
中文实战 PyTorch 搭建 U-Net 并训练 DRIVE · 霹雳吧啦Wz 45:01
原论文热身 5 Minute Teaser Presentation of U-Net 5:04
英文代码 PyTorch Image Segmentation with U-Net from Scratch · Aladdin Persson 51:53
医学强基线 nnU-Net: A Self-configuring Method · Fabian Isensee 29:53
3D 入门 3D U-Net for Volumetric Image Segmentation 7:55
医疗工程 Training Segmentation Models with MONAI and MedSAM 15:24
基础模型 Segment Anything Paper Explained 6:15

最短路线是:12 分钟结构课、任选一门完整代码课,然后用自己的数据跑通训练、预测和错误分析。视频中的库版本可能过时,安装与接口以当前官方文档为准。


13. 总结

U-Net 可以用一句话概括:编码器扩大上下文,解码器恢复分辨率,跳跃连接补回定位信息,1×1 卷积完成逐像素分类。

真正把它用好,需要同时处理四个层面:

  • 数据:图像与掩码严格对齐,划分方式没有泄漏;
  • 结构:尺寸、通道和 skip 融合清楚可查;
  • 目标:损失、阈值和指标与任务一致;
  • 实验:强基线、受控变量、多随机种子和失败案例。

U-Net 的长期价值不在于"形状像字母 U",而在于它把语义压缩与定位恢复拆成了清晰、可验证的工程问题。先把这条主线跑通,再讨论注意力、Transformer、Mamba 或基础模型,结论通常会更可靠。


参考资料

  1. Ronneberger O, Fischer P, Brox T. U-Net: Convolutional Networks for Biomedical Image Segmentation. MICCAI, 2015.
  2. Çiçek Ö, et al. 3D U-Net: Learning Dense Volumetric Segmentation from Sparse Annotation. MICCAI, 2016.
  3. Isensee F, et al. nnU-Net: a self-configuring method for deep learning-based biomedical image segmentation. Nature Methods, 2021.
  4. Parkhi O M, et al. Cats and Dogs. CVPR, 2012.
  5. Penn-Fudan Database for Pedestrian Detection and Segmentation.
  6. PyTorch Documentation.
相关推荐
lucas_AI1 小时前
35 种开源文档抽取配置,只有 4 个跨过 F1 0.5
人工智能·算法·llm
穿过生命散发芬芳1 小时前
用 TRAE Work 把零散运维知识,系统化成一本可复用的运维红宝书
人工智能·trae
刘立军1 小时前
中心化配置与 I18n:严格禁止 AI 魔法值与硬编码参数
人工智能·后端·架构
练习时长一年的RL研究者1 小时前
与AI对话后对 Actor-Critic 中 TD Target 的 a‘ 来源总结
算法
两万五千个小时1 小时前
DeepSeek Harness 从 0 开始:18 todo 任务记忆
人工智能·程序员·架构
XZ-0700011 小时前
1-1-可视化-练习
开发语言·python
狂云歌1 小时前
AI写UE的3Dgame
人工智能·3d·ue5·游戏程序
两万五千个小时1 小时前
DeepSeek Harness 从 0 开始:17 plan(计划模式)
人工智能·程序员·架构
用户298698530141 小时前
将 Excel 表格转换为图片的三种实用方法
人工智能·后端·excel