ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI-For-Beginners 语义分割实战指南:从像素级分类到医学图像分割(SegNet 与 U-Net 完整实现)

AI-For-Beginners 语义分割实战指南:从像素级分类到医学图像分割(SegNet 与 U-Net 完整实现) 教程人工智能机器学习深度学习【免费下载链接】AI-For-Beginners12 Weeks, 24 Lessons, AI for All!项目地址https://gitcode.com/GitHub_Trending/ai/AI-For-Beginners点击查看免费下载本篇技术指南基于 AI-For-Beginners 课程第 12 课《Segmentation》分割展开讲解如何将计算机视觉任务从框出目标的目标检测推进到逐像素分类的分割并结合仓库内的两个可运行 NotebookPyTorch 与 TensorFlow 双版本与课后实验完整走通语义分割 / 实例分割 → 编码器-解码器架构 → 医学图像皮肤痣 PH² 数据集分割的实战链路。读完本篇你将掌握分割网络的数据加载、模型搭建SegNet、U-Net、损失函数选择交叉熵 / BCE、训练与评估像素准确率全流程并能独立完成一次人体分割实验。一、分割从边界框到像素级分类在此前的目标检测Object Detection学习中模型通过预测目标的边界框bounding box来定位物体。但很多任务并不止于框出物体而要求更精确的目标定位——比如把照片中的人物轮廓完整抠出来这正是本节的主题分割Segmentation。分割可以被看作逐像素分类pixel classification对于图像中的每一个像素模型都必须预测它的类别背景也是其中一个类别。也就是说分割模型的输出不是几个坐标框而是一张与输入同尺寸的类别图。语义分割与实例分割分割有两大主流算法语义分割Semantic segmentation只判断每个像素属于哪个类别不区分同一类别中的不同物体。例如图像中有 10 只羊语义分割把它们全部标为羊这一类。实例分割Instance segmentation在给出像素类别的同时把同一类别的不同个体拆分成不同实例10 只羊会被标记为 10 个不同对象。从结构上看目标检测只输出若干矩形框而分割任务中模型要对图像里每一个像素作出判断。这种更强的粒度让分割在自动驾驶道路、行人、车道线的像素级识别、医学影像器官、病灶区域勾画等场景中成为关键能力。二、分割网络的统一架构编码器-解码器Encoder-Decoder尽管用于分割的神经网络架构有很多种但它们都具有相同的总体结构。从某种意义上说这种结构与你在本课程第 9 课Autoencoders中学习的自编码器相似——区别在于自编码器的目标是重构原始图像而分割网络的目标是重构一张**掩码mask**图。因此一个分割网络包含以下两个部分编码器Encoder从输入图像中提取特征解码器Decoder把这些特征转换为掩码图像——输出与输入尺寸相同通道数等于类别数。这一结构也解释了为何通道数等于类别数对每个像素而言模型要输出一个长度为类别数的向量背景占其中一类取 argmax 即得该像素的最终类别。当任务只有目标 / 背景两类时解码器末尾只需输出 1 个通道如仓库 Notebook 中out_channels1的做法。SegNet最朴素的编码器-解码器仓库中的 SemanticSegmentationPytorch.ipynb 首先实现了一个最简架构SegNet编码器使用带卷积和池化的标准 CNN解码器使用包含卷积和上采样upsampling的反卷积 CNN并通过批归一化Batch Normalization让多层网络训练更稳定。PyTorch 版 SegNet 的核心代码节选自SemanticSegmentationPytorch.ipynbclass SegNet(nn.Module): def __init__(self): super().__init__() # 编码器4 组 3x3 卷积 ReLU BatchNorm 2x2 最大池化 self.enc_conv0 nn.Conv2d(in_channels3, out_channels16, kernel_size(3,3), padding1) self.act0 nn.ReLU() self.bn0 nn.BatchNorm2d(16) self.pool0 nn.MaxPool2d(kernel_size(2,2)) # ... enc_conv1(16→32)、enc_conv2(32→64)、enc_conv3(64→128) 结构同理 # 瓶颈层通道数提升到 256 self.bottleneck_conv nn.Conv2d(in_channels128, out_channels256, kernel_size(3,3), padding1) # 解码器4 组双线性上采样 卷积 BatchNorm通道逐级回降 self.upsample0 nn.UpsamplingBilinear2d(scale_factor2) self.dec_conv0 nn.Conv2d(in_channels256, out_channels128, kernel_size(3,3), padding1) # ... dec_conv1(128→64)、dec_conv2(64→32) 结构同理 # 最终输出1 个通道二分类掩码 self.upsample3 nn.UpsamplingBilinear2d(scale_factor2) self.dec_conv3 nn.Conv2d(in_channels32, out_channels1, kernel_size(1,1)) self.sigmoid nn.Sigmoid() def forward(self, x): e0 self.pool0(self.bn0(self.act0(self.enc_conv0(x)))) # e1、e2、e3 同理 b self.bottleneck_conv(e3) d0 self.dec_bn0(self.dec_act0(self.dec_conv0(self.upsample0(b)))) # d1、d2 同理 d3 self.sigmoid(self.dec_conv3(self.upsample3(d2))) return d3U-Net用跳跃连接留住细节SegNet 的架构很自然但并不是最精确的编码器先对原图施加金字塔式 CNN 结构会降低图像特征的空间精度当解码器重建图像时无法正确还原像素位置。这引出了**跳跃连接skip connections**的思想在编码器和解码器对应的卷积层之间建立直连通道。该架构在语义分割中极为常用被称为U-Net。每个卷积层上的跳跃连接帮助网络保留来自该层原始输入的特征信息从而缓解下采样带来的细节丢失。仓库的 Notebook 中使用了一个相对简单的 CNN 编码器并指出 U-Net 也可以使用更复杂的特征提取骨干网络例如 ResNet-50。U-Net 在 PyTorch 中的关键差异点在于解码器输入通道的拼接# 编码器每层激活后、池化前的特征图被保留用于拼接 cat0 self.bn0(self.act0(self.enc_conv0(x))) cat1 self.bn1(self.act1(self.enc_conv1(e0))) cat2 self.bn2(self.act2(self.enc_conv2(e1))) cat3 self.bn3(self.act3(self.enc_conv3(e2))) b self.bottleneck_conv(e3) # 解码器每一层都与对应尺度的编码器特征做通道拼接torch.cat d0 self.dec_bn0(self.dec_act0(self.dec_conv0(torch.cat((self.upsample0(b), cat3), dim1)))) d1 self.dec_bn1(self.dec_act1(self.dec_conv1(torch.cat((self.upsample1(d0), cat2), dim1)))) d2 self.dec_bn2(self.dec_act2(self.dec_conv2(torch.cat((self.upsample2(d1), cat1), dim1)))) d3 self.sigmoid(self.dec_conv3(torch.cat((self.upsample3(d2), cat0), dim1))))可以看到 U-Net 解码器各层输入通道数384 / 192 / 96 / 48恰好是上采样特征 跳跃连接特征的叠加这正是跳跃连接在实现层面的直接体现。TensorFlow 版SemanticSegmentationTF.ipynb用keras.Concatenate(axis3)完成同样操作。三、分割的损失函数为什么不能只用 MSE分割任务的损失函数值得特别关注。训练经典自编码器时我们需要度量两张图像的相似度可以用均方误差MSE。但在分割中目标掩码图的每个像素代表一个类别编号沿第三维做 one-hot 编码因此必须使用专门用于分类的损失函数——交叉熵损失cross-entropy loss并对所有像素求平均。当掩码为二分类如痣 / 背景时使用二分类交叉熵损失Binary Cross-EntropyBCE。✅One-hot 编码是将类别标签编码为长度等于类别数向量的方式分割任务中通常沿通道维第三维展开。例如二分类时类别 0 编码为[1, 0]类别 1 编码为[0, 1]。仓库的 PyTorch Notebook 在搭建模型后直接配置了优化器与损失函数model SegNet().to(device) optimizer optim.Adam(model.parameters(), lrlr, weight_decayweight_decay) loss_fn nn.BCEWithLogitsLoss() # 二分类交叉熵TensorFlow 版与之对应model SegNet() # tf.keras.Model optimizer optimizers.Adam(learning_ratelr, decayweight_decay) loss_fn losses.BinaryCrossentropy(from_logitsTrue) # 使用 logits 形式的 BCE model.compile(lossloss_fn, optimizeroptimizer)选择 BCE 而非 MSE 的直觉是逐像素分类本质上是分类问题而分类任务用交叉熵族损失收敛更稳、梯度更合理MSE 是为回归 / 图像重构设计的直接套用于像素类别预测会弱化分类边界的学习信号。四、医学图像分割实战PH² 皮肤镜数据集本节课程的实战场景是训练一个网络在医学图像上识别人类的痣nevus俗称胎记/痦子。数据来源为PH² 皮肤镜图像数据库PH² Database of dermoscopy images。数据集概览共200 张图像分为三个类别典型痣typical nevus、非典型痣atypical nevus、黑色素瘤melanoma每张图像都配有一张对应的掩码mask标出痣的区域。训练目标是把任意一个痣从背景中分割出来即二分类痣 / 背景。这种技术尤其适合此类医学成像任务——肿瘤、病灶的精确边界对诊断意义重大。下图展示了 PH² 数据集中的原始图像与掩码图像与掩码均由 PH² 数据库提供数据集下载与预处理Notebook 中通过命令行下载 PH² 数据集的 RAR 压缩包并解压需要系统安装unrar工具Linux 下可用包管理器安装wget https://www.dropbox.com/s/k88qukc20ljnbuo/PH2Dataset.rar unrar x -Y PH2Dataset.rar随后定义数据加载函数遍历PH2Dataset/PH2 Dataset images目录凡是目录名以_Dermoscopic_Image结尾的读取为原图以_lesion结尾的读取为掩码将所有图像缩放到256×256并按比例切分训练集与测试集。PyTorch 版SemanticSegmentationPytorch.ipynbdef load_dataset(train_part, rootPH2Dataset): images [] masks [] for root, dirs, files in os.walk(os.path.join(root, PH2 Dataset images)): if root.endswith(_Dermoscopic_Image): images.append(imread(os.path.join(root, files[0]))) if root.endswith(_lesion): masks.append(imread(os.path.join(root, files[0]))) size (256, 256) # 原图双线性缩放anti_aliasingTrue images torch.permute(torch.FloatTensor( np.array([resize(image, size, modeconstant, anti_aliasingTrue) for image in images])), (0, 3, 1, 2)) # 掩码最近邻缩放后二值化0.5并增加通道维 masks torch.FloatTensor( np.array([resize(mask, size, modeconstant, anti_aliasingFalse) 0.5 for mask in masks]) ).unsqueeze(1) indices np.random.permutation(range(len(images))) train_part int(train_part * len(images)) train_ind, test_ind indices[:train_part], indices[train_part:] return (images[train_ind], masks[train_ind]), (images[test_ind], masks[test_ind]) train_dataset, test_dataset load_dataset(train_size)这里有两个值得注意的预处理细节掩码缩放使用anti_aliasingFalse并做 0.5二值化掩码是标注图而非自然图像缩放后需要通过阈值重新二值化避免插值产生模糊的中间值破坏标签语义PyTorch 版将张量置换为(N, C, H, W)布局(0, 3, 1, 2)以匹配卷积层的通道优先约定TensorFlow 版则保持(N, H, W, C)两者与各自框架的数据约定一致。超参数配置PyTorch Notebook 给出的实验配置用于 SegNet 与 U-Net 两套模型device cuda:0 if torch.cuda.is_available() else cpu train_size 0.9 # 90% 数据用于训练 lr 1e-3 # Adam 学习率 weight_decay 1e-6 # L2 权重衰减 batch_size 32 epochs 30TensorFlow Notebook 的配置则按 80/20 划分数据并训练更多轮次train_size 0.8 lr 3e-4 weight_decay 8e-9 batch_size 64 epochs 100五、训练循环与评估两个可运行的 Notebook 实验PyTorch 版训练循环PyTorch Notebook 的训练函数遵循标准的前向传播 → 计算损失 → 反向传播 → 更新参数流程并在每个 epoch 后于测试集上评估损失def train(dataloaders, model, loss_fn, optimizer, epochs, device): train_dataloader, test_dataloader dataloaders[0], dataloaders[1] tqdm_iter tqdm(range(epochs)) for epoch in tqdm_iter: model.train() train_loss 0.0 for batch in train_dataloader: imgs, labels batch imgs, labels imgs.to(device), labels.to(device) preds model(imgs) loss loss_fn(preds, labels) optimizer.zero_grad() loss.backward() optimizer.step() train_loss loss.item() model.eval() test_loss 0.0 with torch.no_grad(): for batch in test_dataloader: imgs, labels batch imgs, labels imgs.to(device), labels.to(device) loss loss_fn(model(imgs), labels) test_loss loss.item() train_loss / len(train_dataloader) test_loss / len(test_dataloader) tqdm_iter.set_postfix({train loss:: train_loss, test loss:: test_loss}, refreshTrue)Notebook 中 SegNet 与 U-Net 各训练 30 个 epoch运行耗时分别约 16 分钟与 29 分钟通过tqdm实时观察训练/测试损失。TensorFlow 版则直接使用 Keras 的model.fit(..., validation_data...)完成 100 个 epoch 的训练两种框架的教学思路完全对齐。评估掩码可视化与像素准确率评估时将测试图像的模型输出与真实掩码并排绘制直观对比分割效果。由于二分类输出是概率图预测掩码通过对输出做 0.5阈值得到# PyTorch 版 predictions.append((model(img).detach().cpu()[0] 0.5).float())# TensorFlow 版 pred np.array(model.predict(img)) predictions.append(pred[0, :, :, 0] 0.5)除了可视化分割模型还有正式的评价指标。最容易理解的指标是像素准确率pixel accuracy被正确分类的像素所占百分比即$$\text{pixel accuracy}\frac{\text{分类正确的像素数}}{\text{总像素数}}$$在课程实验的直观对比中SegNet 与 U-Net 都能较好地将痣与背景分离而 U-Net 借助跳跃连接在边缘细节上通常更具优势实验日志显示 U-Net 的测试损失最终更低约 0.15 vs SegNet 约 0.45可分别在两个 Notebook 的训练输出中查看。运行环境依赖仓库 binder/requirements.txt 列出了运行这些 Notebook 所需的环境其中与本课直接相关的关键依赖包括深度学习框架tensorflow2.13.1、keras3.13.2TF 版 Notebook以及 PyTorch 生态torchvisionNotebook 中与torch一并导入图像处理scikit-image0.21.0imread、resize、pillow12.2.0辅助工具tqdm4.66.5进度条、matplotlib可视化Notebook 中使用plt、numpy。你可以在 binder 配置 与 requirements.txt 中查看完整的虚拟环境定义。六、课后实验人体分割Assignment本课的课后作业lab/README.md要求完成人体分割Human Body Segmentation应用场景非常贴近现实在视频制作例如天气预报中我们经常需要把人从摄像机画面中抠出来叠加到其他背景上。传统做法是色度键chroma key技术——让人站在纯色背景前拍摄再把背景替换掉。本次实验将训练一个神经网络模型来直接抠出人体剪影从而摆脱对纯色背景的依赖。实验要点数据集使用 Kaggle 上的Segmentation Full Body MADS Dataset人体全身分割数据集从 Kaggle 手动下载后解压到当前目录起点 Notebook打开 lab/BodySegmentation.ipynb其中先通过plt.imread读取segmentation_full_body_mads_dataset_1192_img/images目录下的图像与其对应的masks掩码并可视化图像与掩码的配对效果之后复用本课学习的编码器-解码器架构与 BCE 损失完成训练。七、延伸挑战与自学方向挑战Challenge人体分割只是针对人像的常见任务之一其他重要任务还包括骨骼检测skeleton detection与姿态检测pose detection。可以尝试 OpenPose 库了解姿态检测的实现方式。回顾与自学Review Self Study建议进一步了解分割的更多应用场景并自主研究**实例分割Instance Segmentation与全景分割Panoptic Segmentation**两个子领域——实例分割已在本课开头介绍全景分割则把语义与实例两类输出统一到一个框架中。八、课程内相关资源汇总本课主文档12-Segmentation/README.mdPyTorch 实验SemanticSegmentationPytorch.ipynbTensorFlow 实验SemanticSegmentationTF.ipynb课后作业说明lab/README.md 与 lab/BodySegmentation.ipynb前置知识目标检测第 11 课、自编码器第 9 课计算机视觉模块总览4-ComputerVision/README.md运行环境binder/requirements.txt、environment.yml小结分割是比边界框更精细的图像理解技术它把任务从框出目标升级为逐像素分类。其通用骨架是编码器-解码器结构——SegNet 提供最朴素的对应对称设计U-Net 通过跳跃连接显著改善分割边界的精度。训练时请牢记分割与重构的本质区别目标掩码是类别标签而非图像因此损失函数应选用逐像素平均的交叉熵二分类场景下则是 BCE。通过 PH² 医学图像数据集PyTorch / TensorFlow 双版本 Notebook与人体分割课后实验你可以完整复现数据加载 → 模型搭建 → 训练 → 掩码可视化与像素准确率评估的整套实战流程并将这一能力迁移到更多像素级理解任务中。赞分享教程人工智能机器学习深度学习【免费下载链接】AI-For-Beginners12 Weeks, 24 Lessons, AI for All!项目地址https://gitcode.com/GitHub_Trending/ai/AI-For-Beginners点击查看免费下载相关推荐AI-For-Beginners 图像分割实战指南从像素级分类到医学影像病变分割AI For Beginners 图像分割实战指南从像素级分类到医学影像病变分割 图像分割Segmentation是计算机视觉中比目标检测更进一步的任务教程人工智能机器学习深度学习AI-For-Beginners 图像分割实战从像素级分类原理到医学图像与人体分割实现AI For Beginners 图像分割实战从像素级分类原理到医学图像与人体分割实现 导读 本篇文章基于开源课程 AI For Beginners 的 Co教程人工智能机器学习深度学习AI-For-Beginners 图像分割实战从像素级分类到语义分割的编码器-解码器架构与医学影像应用AI For Beginners 图像分割实战从像素级分类到语义分割的编码器 解码器架构与医学影像应用 导读 本文围绕 AI For Beginners 课教程人工智能机器学习深度学习上一篇快速上手3步制作专业MDX词典的终极指南下一篇三步实现百度文库文档纯净打印告别付费弹窗轻松获取完整内容创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表