简介:图像分割是计算机视觉中的核心任务,其目标是对图像中的每个像素进行分类,在医学影像、自动驾驶、遥感分析等领域具有广泛应用。深度学习模型的性能不仅取决于网络结构,更依赖于数据的组织与预处理质量。UNet作为经典的编码器-解码器分割网络,通过跳跃连接融合多尺度特征,在中小规模数据集上表现出色。然而,实际工程中,从神经网络构建到模型训练之间,数据集的解压、目录检查、格式校验、数据增强与加载器编写等环节常成为影响最终精度的关键。本文以一份UNet图像分割数据集为例,系统演示了从压缩包校验、目录解析、标签可视化,到PyTorch Dataset与DataLoader构建,再到UNet训练、损失函数选择与超参数调优的完整流程,并总结了常见报错与解决技巧,帮助读者快速搭建可靠的分割训练管线。 搞到一份unet图像分割数据集.zip,第一反应多半是赶紧解压、跑起来。但作为一个拿这种压缩包喂过不少模型的人,我必须先泼一盆冷水:zip解压只是入场券,真正决定你模型好坏的动作,全在解压之后。unet图像分割最怕的从来不是网络结构不好写,而是数据从压缩包到训练管线这一段没处理好,后面全是空中楼阁。

这篇文章我会把手里的这份unet图像分割数据集.zip当作完整案例,从解压、检查目录、预处理、写数据集加载器,到unet训练调参、常见报错排查,从头到尾拆一遍。无论你是刚接触图像分割的新手,还是想快速用unet验证想法的人,这篇都能直接照着操作,少走很多弯路。

1. 拿到数据包之后:解压检查比你想的更重要

1.1 解压前先校验文件完整性

很多人拿到压缩包就双击解压,结果解到一半报错,才发现文件损坏、下载不完整。这个习惯在职场上吃过太多亏,所以我现在拿到任何数据集的zip,第一件事永远是校验完整性。

先看哈希值。正规渠道下载的数据集通常会给一个MD5或SHA256,比如README里可能写了 md5sum 。Linux或macOS直接执行:

md5sum unet图像分割数据集.zip

Windows PowerShell下用:

Get-FileHash .\unet图像分割数据集.zip -Algorithm MD5

如果作者没给哈希,那就直接尝试列一下zip内容,看能否完整读取:

unzip -t unet图像分割数据集.zip

-t 参数会逐文件测试压缩包完整性,输出 OK 就没问题。如果这里报了 file is not a zip file 或者 End-of-central-directory signature not found ,基本可以断定文件下载中断,多半得重新下载。这类报错我遇到最多的场景是网盘客户端限速导致文件没下全,其次是浏览器下载中断但后缀名已经是zip,看起来像完整的,实际上根本打不开。

解压命令我平时最常用两套,一套是系统自带的unzip:

unzip unet图像分割数据集.zip -d ./unet_dataset

-d 是指定解压目录,避免把所有文件撒在当前目录里。另一套是用Python的zipfile处理特殊场景,比如某些压缩包带了奇怪的编码,系统unzip解出来文件名是乱码,zipfile配合cp437转gbk可以救回来。不过这是后话,下面单独讲。

1.2 解压之后必查的目录结构

解压完成后先别急着写代码,先打开目录,花两分钟看清楚这三个问题:

第一,数据是怎么划分的。常见的有两种:一种是一整个文件夹,里面图片和标签混合在一起,需要自己按比例划分train/val/test;另一种是在压缩包里就分好了 train/ 、 val/ 、 test/ 目录,并且每个目录底下还有 images/ 和 masks/ (有的叫 labels/ 或 annotations/ )。我手里这份就是后一种,结构大概长这样:

unet图像分割数据集/
├── train/
│   ├── images/          # 原图
│   │   ├── 0001.png
│   │   ├── 0002.png
│   │   └── ...
│   └── masks/           # 标签图
│       ├── 0001.png
│       ├── 0002.png
│       └── ...
├── val/
└── test/

第二,原图和标签是否一一对应。这个看似不是问题,实际经常出问题。有些标签是8位彩色图,有些是24位,有些是调色板PNG,看着是人眼识别的分割结果,读进代码里却出现三个通道,直接把训练搞崩。我的习惯是写一个遍历脚本,逐对检查图片尺寸是否一致、文件后缀是否一致,再输出几张标签的独有像素值,几行Python就能搞定:

from PIL import Image
import numpy as np

mask = Image.open('unet图像分割数据集/train/masks/0001.png')
arr = np.array(mask)
print('shape:', arr.shape)
print('unique values:', np.unique(arr))

这一步能避免后面80%的“训练突然报错”问题。比如我遇到过标签图里目标区域像素值是255而不是1的情况,检查时就会立刻发现,顺手做归一化处理。

第三,有没有README或标注说明文件。很多数据集作者会在压缩包内放一个README.txt或JSON文件,说明每个像素值对应的类别、图像的版权、标注约定等等。这个文件千万别忽略,你后面写混淆矩阵评估时,类别编号全靠它。

1.3 zip解压的隐藏坑

解压zip这个动作看起来简单,实际坑不少。先列个速查表,都是我碰过的:

报错信息 原因 解决思路
file is not a zip file 文件下载中断,或文件本身被当成zip改名了 重新下载,确认Content-Length
could not find end-of-central-directory record zip文件损坏或文件截断,也常见于压缩包未下载完整 检查磁盘空间,重新下载;若在Linux下用 zip -FF 修复一次
invalid zip archive: could not find eocd 解压工具读取不到末尾目录结构,常见于某些网盘生成的文件 尝试用7-Zip或Python zipfile打开;实在不行重新下载
failed to copy spatial iop zip 通常是某款软件导入zip资源包时报的,不是压缩包本身问题 换用更稳定的解压方式,或检查目标磁盘权限
解压出来文件名乱码 zip在Windows下用非UTF-8编码压缩 先用 unzip -O gbk 尝试,或用Python zipfile转码解压

其中“文件名乱码”是我在Linux服务器上遇到最多的。因为Windows下压缩zip默认可能是GBK编码,Linux的unzip默认按UTF-8解,文件名直接变 锟斤拷 。解决办法是用 unzip -O GBK ,或者干脆用Python脚本按编码处理:

import zipfile

zip_path = 'unet图像分割数据集.zip'
out_dir = './unet_dataset'
with zipfile.ZipFile(zip_path, 'r') as zf:
    for info in zf.infolist():
        name = info.filename
        # 尝试按gbk解码恢复正常文件名
        try:
            name = name.encode('cp437').decode('gbk')
        except Exception:
            pass
        zf.extract(info, out_dir)

还有一类情况是压缩包带了密码。如果作者公开了密码,用 unzip -P 密码 即可。如果密码忘了,网上一堆“zip密码移除”工具,说实话成功率有限,暴力破解的成本极高。稳妥做法是找作者要原始数据,或者换一个公开无密码的数据集。

2. 为什么unet能撑起这个数据集的血肉

2.1 网络结构简单回顾

本篇文章不是unet原理的教科书,但你必须理解一个关键点:unet结构天然适合图像分割数据集,尤其是当你手里的数据量不够大时,它在小样本场景下的表现比很多后来的复杂网络要好。

unet的核心结构是编码器-解码器加跳跃连接。编码器部分一遍遍做卷积和池化,本质上是提取不同层级的特征,浅层看到边缘和纹理,深层看到目标主体;解码器部分再一步步上采样,把压缩后的特征图恢复到原图分辨率。难点在于,直接上采样会丢失大量细节,所以unet把编码器每一层输出的特征图,通过跳跃连接直接拼接到解码器对应层,细节信息就这么被传回来了。

我用一句人话总结:跳跃连接让网络在“画轮廓”的时候,手里始终捏着原图细节,而不是光靠脑袋里的模糊印象瞎猜。这就决定了unet在边界恢复、小目标分割上表现优于纯FCN类的结构。对于广告牌分割、口腔疾病分割、道路标线分割这类目标边界比较复杂的数据集,unet确实是最稳妥的起步选择。

2.2 数据质量对网络上限的影响

很多人有个误区:网络结构越强,结果越好。其实在unet这种结构高度成熟的任务上,决定精度的往往是数据。一份数据集里如果存在标签错标、边界过于粗糙、类别严重不平衡,任何模型都救不回来。

所以解压完zip后的第二个核心动作,是可视化检查标签。把原图和mask叠加起来看,用半透明方式把mask盖到原图上,直接肉眼扫个几十张。这一步能发现很多问题:有些mask边界比原图目标大了一圈,有些mask里混入了噪声点,有些是背景和目标标反了。训练之前花半小时可视化检查,比训练完之后花三天调参都管用。

还有一个常见问题是类别不平衡。比如牙齿数据集里,背景像素占了95%,目标只占5%。如果直接用普通交叉熵,模型会学成一个“什么都是背景”的分类器,loss看起来很低,但目标一个都分不出来。面对这种情况,loss函数、样本权重、数据增强都要相应调整,这点我放在后面单独讲。

3. 数据预处理:从图片路径到可训练张量

3.1 尺寸统一与归一化

图像分割对输入尺寸有硬性要求。unet本身是全卷积结构,理论上可以接受任意尺寸,但为了训练时batch能对齐,必须统一到一个固定尺寸。常见选择是256x256或512x512,视显存大小而定。

统一尺寸有两种思路,最简单是直接resize。用OpenCV一行搞定:

import cv2
img = cv2.imread('xxx.png')
img = cv2.resize(img, (512, 512), interpolation=cv2.INTER_LINEAR)
mask = cv2.resize(mask, (512, 512), interpolation=cv2.INTER_NEAREST)

注意一个细节:原图resize用线性插值没问题,但mask的resize必须用 INTER_NEAREST ,也就是最近邻插值。否则双线性插值会在标签边缘产生介于类别之间的像素值,比如类别0和类别1之间插出0.5,后处理直接懵。

另一种思路是padding,把图片等比缩放后填充到目标尺寸,标签也跟着做同样的padding。这种能保持原始形状不变形,但实现略麻烦。我建议新手先用resize,跑通流程后再考虑保形状。

归一化方面,图像一般按ImageNet的mean和std做标准化,或者简单粗暴地除以255。对大多数分割任务来说,除以255足够。这里有个很容易踩的坑:如果用了预训练encoder,归一化必须和预训练时的统计值一致,否则迁移效果会打折扣。

3.2 数据增强要原图和标签一起做

图像分割的数据增强比分类更讲究,因为你要保证原图做了旋转、翻转、缩放,标签图必须做完全一致的变换。手动实现很容易出错,所以我直接用 albumentations 库,它对分割任务做了很好的封装:

import albumentations as A
from albumentations.pytorch import ToTensorV2

transform = A.Compose([
    A.RandomResizedCrop(512, 512, scale=(0.5, 1.0)),
    A.HorizontalFlip(p=0.5),
    A.VerticalFlip(p=0.1),
    A.RandomBrightnessContrast(p=0.3),
    A.RandomRotate90(p=0.5),
    A.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),
    ToTensorV2(),
])

# 使用
aug = transform(image=image, mask=mask)
image_t = aug['image']
mask_t = aug['mask']

albumentations 的Compose默认会自动对不同类型做不同处理,image走图像增强,mask走图像变换,差值方式单独控制。这是目前做分割最省心的增强方案。

如果是医学影像类数据集,我建议保守一点,少用强随机裁剪和剧烈颜色抖动,因为病灶或组织的位置有解剖学意义,翻转可能破坏这种语义。像无人机航拍数据集则可以放心用旋转翻转,甚至加一些马赛克增强,提升对不同地物朝向的鲁棒性。

3.3 自定义Dataset与DataLoader

写一个标准的PyTorch Dataset,核心是让 __getitem__ 返回原图和对应的标签张量。我以前经历过一个低级错误:Dataset里忘了把mask转成long类型,导致CrossEntropyLoss在计算时报类型错误。所以这里一步到位:

import torch
from torch.utils.data import Dataset
from PIL import Image
import numpy as np

class SegmentationDataset(Dataset):
    def __init__(self, image_dir, mask_dir, transform=None):
        self.image_dir = image_dir
        self.mask_dir = mask_dir
        self.transform = transform
        self.images = sorted(list(image_dir.glob('*.png')))

    def __len__(self):
        return len(self.images)

    def __getitem__(self, idx):
        img = Image.open(self.images[idx]).convert('RGB')
        img = np.array(img)
        mask = Image.open(self.mask_dir / self.images[idx].name).convert('L')
        mask = np.array(mask)
        # 如果标签类别不是从0开始连续编号,可能需要做一次映射
        if self.transform:
            aug = self.transform(image=img, mask=mask)
            img = aug['image']
            mask = aug['mask']
        mask = mask.squeeze(0).long()
        return img, mask

DataLoader的参数也有讲究,特别是 num_workers 。在Linux下设置4或8能用多核CPU做图片解码,明显加快训练。Windows下如果 num_workers 大于0经常报莫名其妙的问题,我一般设0,或者把Dataset读取逻辑封进 if __name__ == '__main__' 里,麻烦但有效。

最后必须提一句:如果一次性把整个数据集读进内存加载,遇到几十万张图会直接把内存撑爆。正确做法是 __getitem__ 里按路径即时读取,这样数据在硬盘上,显存和内存都只保留当前batch的内容。

4. 训练unet的完整实操流程

4.1 构建网络:手写还是用现成库

unet结构本身不复杂,手写一份也就一两百行。基础版可以用类似下面的编码器-解码器写法:

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, 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)

class UNet(nn.Module):
    def __init__(self, in_ch=3, out_ch=num_classes):
        super().__init__()
        # 下采样
        self.enc1 = DoubleConv(in_ch, 64)
        self.enc2 = DoubleConv(64, 128)
        self.enc3 = DoubleConv(128, 256)
        self.enc4 = DoubleConv(256, 512)
        # 中间
        self.pool = nn.MaxPool2d(2)
        self.bottleneck = DoubleConv(512, 1024)
        # 上采样
        self.up4 = nn.ConvTranspose2d(1024, 512, 2, stride=2)
        self.dec4 = DoubleConv(1024, 512)
        self.up3 = nn.ConvTranspose2d(512, 256, 2, stride=2)
        self.dec3 = DoubleConv(512, 256)
        self.up2 = nn.ConvTranspose2d(256, 128, 2, stride=2)
        self.dec2 = DoubleConv(256, 128)
        self.up1 = nn.ConvTranspose2d(128, 64, 2, stride=2)
        self.dec1 = DoubleConv(128, 64)
        self.out = nn.Conv2d(64, out_ch, 1)

    def forward(self, x):
        e1 = self.enc1(x)
        e2 = self.enc2(self.pool(e1))
        e3 = self.enc3(self.pool(e2))
        e4 = self.enc4(self.pool(e3))
        b = self.bottleneck(self.pool(e4))
        d4 = self.dec4(torch.cat([self.up4(b), e4], dim=1))
        d3 = self.dec3(torch.cat([self.up3(d4), e3], dim=1))
        d2 = self.dec2(torch.cat([self.up2(d3), e2], dim=1))
        d1 = self.dec1(torch.cat([self.up1(d2), e1], dim=1))
        return self.out(d1)

关于通道数,这里使用的是最原始的64起步。实际项目中我发现直接用128起步效果会更好,但显存翻倍。如果你的显存在8G以内,建议保留64起步,结合输入尺寸512x512即可,换回来的边界精度足够。

但要注意:手写unet只是学习用途,实际项目我强烈建议直接用 segmentation_models_pytorch 这个库,它封装了各种backbone,可以一键加载resnet34、efficientnet等预训练权重:

import segmentation_models_pytorch as smp

model = smp.Unet(
    encoder_name='resnet34',
    encoder_weights='imagenet',
    in_channels=3,
    classes=num_classes,
)

使用预训练encoder能让小数据集收敛更快。我做个对比实验,同一个中等规模数据集上,用resnet34预训练权重和不初始化直接训练,前者的收敛速度大概快3倍以上,最终IoU高出5到8个百分点。所以拿到的数据集如果规模不大,别浪费预训练这个白嫖的福利。

4.2 损失函数的选择与组合

分割任务中,损失函数直接决定你的模型能不能在类别不平衡下正常训练。我这里给出三种实际使用率最高的方案:

第一种,普通CrossEntropyLoss。数据类别均衡、背景占比不高时用它,简单稳定。代码里只需注意类别数传对即可:

criterion = nn.CrossEntropyLoss()

第二种,DiceLoss或BCE + DiceLoss。当背景占比过高,模型容易把目标区域全判成背景时,用Dice很有用。Dice衡量的是预测和标签的重叠程度,天然对前景更关注。常用组合是0.5 * BCE + Dice:

import torch.nn.functional as F

def bce_dice_loss(pred, mask, alpha=0.5):
    # pred: [B, C, H, W], mask: [B, H, W]
    bce = F.cross_entropy(pred, mask)
    pred_prob = F.softmax(pred, dim=1)
    true_onehot = F.one_hot(mask, num_classes=pred.shape[1]).permute(0, 3, 1, 2).float()
    inter = (pred_prob * true_onehot).sum(dim=(2, 3))
    denom = pred_prob.sum(dim=(2, 3)) + true_onehot.sum(dim=(2, 3))
    dice = (2 * inter + 1e-7) / (denom + 1e-7)
    dice_loss = 1 - dice.mean()
    return alpha * bce + (1 - alpha) * dice_loss

第三种,Focal Loss。当前景目标极端小、类别极不平衡时,Focal Loss通过降低易分类样本的权重,让模型更关注那些难分的稀疏目标,比直接调权重更平滑。不过Focal Loss调参略麻烦,我一般优先尝试前两种,效果不佳再上Focal。

我个人的建议:如果数据集类别数小于5,直接上 0.5*CE + Dice ,基本覆盖绝大多数场景。这个组合对边界质量有明显提升,因为Dice对区域重叠敏感,CE对逐像素分类敏感,互补性很强。

4.3 评估指标与模型保存

训练时除了看loss曲线,还要看评估指标。分割任务最常见的是mIoU和Dice。mIoU是预测和标注交并比的平均,Dice类似但更直观。我训练时每个epoch在验证集上算一次mIoU,同时可视化存几张预测图到输出目录,直接看边界对不对:

def calculate_iou(pred, mask, num_classes):
    ious = []
    for cls in range(num_classes):
        pred_mask = (pred == cls)
        true_mask = (mask == cls)
        inter = (pred_mask & true_mask).sum().item()
        union = (pred_mask | true_mask).sum().item()
        if union == 0:
            ious.append(float('nan'))  # 或跳过
        else:
            ious.append(inter / union)
    return ious

模型保存这里有一个特别容易出错的点:很多人直接把整个model保存成 model.pt ,结果换个环境就用不了,版本不兼容一堆毛病。我推荐的方案是只保存state_dict:

torch.save(model.state_dict(), 'unet_best.pth')

配合一个配置文件存超参数,下次加载时先构建模型结构再load权重,严谨且可迁移。训练中我习惯同时保存 best_iou 和 last_epoch 两份权重,best用于最终测试,last用于意外中断后接着练。

4.4 训练中的超参数设置

这里我直接给一份开箱可用的配置,基于一个中等图像分割数据集,图像尺寸512x512、显存约8G:

参数 推荐值 备注
batch size 8 太小噪声大,太大显存爆
学习率 1e-4 使用Adam,余弦衰减
训练轮数 50-100 早停即可
优化器 Adam / AdamW AdamW略稳
学习率调度 CosineAnnealingLR 后期衰减明显提精度
权重初始化 预训练encoder 明显提升收敛速度

实践里我常用的策略是:先用1e-3跑5个epoch做个warmup,再把学习率降到1e-4正式训练。原因是这个数据集开头loss可能很大,大的初始学习率能帮模型跳出平坦区域,后面小学习率精修边界。

关于显存,如果batch size只能设2或4,建议优先降低图像尺寸而不是减少batch。图像尺寸小了,分割精度掉得很快,但batch小最多是训练不稳定,还能靠梯度累积弥补。梯度累积代码如下:

accumulation_steps = 4
for i, (images, masks) in enumerate(train_loader):
    outputs = model(images)
    loss = criterion(outputs, masks) / accumulation_steps
    loss.backward()
    if (i + 1) % accumulation_steps == 0:
        optimizer.step()
        optimizer.zero_grad()

这个技巧能让你在8G显存上模拟出32的batch size,训练稳定性好很多。

5. 常见问题与排查技巧实录

5.1 解压相关问题的最终处理清单

如果你用的数据集是零散从GitHub或第三方平台下载的zip,解压出问题太常见了。我把这些问题和解决顺序整理成一张速查表,方便直接对照操作:

现象 第一步确认 第二步处理
提示文件不是zip 在Linux下用 file xxx.zip 看实际格式 重下;去除伪装后缀
EOCD记录找不到 下载是否完整 换下载源;用7-Zip自我修复
解压一半报CRC错误 磁盘是否满了 清空空间;用 unzip -x 跳过坏文件
中文文件名乱码 执行 unzip -O gbk 尝试 Python zipfile转码解压
某软件导入zip资源包报错 确认是不是导入工具的问题 解压后让工具加载文件夹而非zip

在处理 failed to copy spatial iop zip 这类问题时,我通常会建议先把zip解压到纯英文路径下,避免某些工具对中文路径兼容性差。

5.2 训练阶段最常踩的5个坑

第一,mask通道数不对。如果标签图上读出来是[H, W, 3],但模型的类别输出是[H, W, C],那要在读取时强制转单通道 convert('L') ,或者加一步 np.take 取第一通道。我曾经有过一次,标签图是三通道RGB但每个通道内容相同,直接训练,loss始终在飘,后来才发现是通道数导致one-hot维度对不上。

第二,标签像素值不是从0开始。比如背景是0,目标是128或255,模型会以为还有几百个类别。处理方式是在Dataset里做映射,把标签值映射成0到num_classes-1,或者先统计 np.unique(mask) 再决定是否除个系数。

第三,显存溢出。最常见的 CUDA out of memory 出现在batch size过大或输入尺寸过大。解决顺序是:减小batch size -> 减小图像尺寸 -> 使用混合精度。PyTorch自带的grad scaler可以开启自动混合精度,显存占用直接减半:

scaler = torch.cuda.amp.GradScaler()
with torch.cuda.amp.autocast():
    output = model(images)
    loss = criterion(output, masks)
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()

第四,训练loss下降但验证指标不涨。这种情况多半是过拟合,数据增强太弱或模型容量太大。先把增强力度调高,再考虑加Dropout或加权重衰减。

第五,mask和image尺寸不匹配导致cat时报错。这个几乎每个人都会踩。解决办法是在Dataset里打印校验:

assert img.shape[:2] == mask.shape[:2], f"mismatch: {img.shape} vs {mask.shape}"

5.3 一点实用的unet改进方向

如果你拿这个数据集训练完了,想进一步提升精度,我建议先别急着换模型,按顺序尝试这几个便宜又有效的改进点:

一是把unet里的普通卷积替换成深度可分离卷积。这个改动能让模型参数量和计算量明显下降,推理速度更快,配合FP16甚至能让batch翻倍。用 segmentation_models_pytorch 时可以直接选 encoder_weights 不同backbone来达到类似效果,比如从resnet34换成efficientnet-b1,精度和速度都会变。

二是加深encoder,或者换成更强的预训练主干,例如resnet101或timm里的convnext。encoder越强,提取的特征越丰富,但对数据集大小要求也越高。小数据集强行换大模型容易过拟合。

三是加attention模块,最简单的是在bottleneck处加一个 scse 或 cbam 模块,把通道注意力加进去。我在实际场景里,摄像头下的分割任务加attention后,边界召回率大概能提1到2个点,代价是显存多了几百M。

四是换用主流的backbone预训练策略,即先在你的数据集子集上做自监督预训练,再微调。不过这个操作对大多数人来说太重了,性价比不如下载现成的预训练权重。

这些改进归根结底是为了解决unet的两个天然短板:感受野不够大、多尺度特征表达弱。你在你自己的数据集上跑完基础版unet,再按上面思路加一点点“大招”,基本能应付绝大多数实际分割场景。

最后我再分享一个经验:训练时如果有条件,每轮看一眼验证集的预测可视化,比盯着IoU曲线可靠一万倍。因为数字会骗人,视觉不会。尤其是你拿到的这份zip里如果有一些特殊类别,比如“背景像目标”的干扰项,光看指标完全发现不了,一可视化就原形毕露。所以每一次解压数据、处理数据、训练模型,最终都要回到“看结果图”这一步来闭环。图像分割这东西,最终是给眼睛看的。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐