首页 > 编程知识 正文

常用的图像分割方法,unet是什么

时间:2023-05-05 18:00:06 阅读:44236 作者:3727

文章转自:微信公众号【机器学习炼丹术】。 文章转载或交流联系作者微信: cyx645016617

Unet其实很简单,所以今天的文章不是很长。喜欢的话可以参与文中的讨论、在文章末尾点赞、在看点一下呗。

0概述语义分割(Semantic Segmentation )是图像处理和机器视觉的重要分支。 与分类任务不同,语义分割需要判断图像的各像素点的类别,并正确分割。 语义分割目前已广泛应用于自动驾驶、自动关键图、医学影像等领域。

上图为自动驾驶中的移动分割任务的分割结果,可以从一张图片中有效的识别出汽车(深蓝色),行人(红色),红绿灯(黄色),道路(浅紫色)等

Unet可以说是最常用、最简单的一种分割模式。 简单、高效、易懂、易于构建,可以从小数据开始集中训练。

Unet已经是非常旧的分割模型,是2015年《U-Net: Convolutional Networks for Biomedical Image Segmentation》提出的模型

论文连接: https://arxiv.org/abs/1505.04597

Unet以前是更旧的FCN网络。 FCN是全聚合网络垃圾,这个基本上是一个框架,到现在的分割网络,谁敢说用不到卷积层呢。,但是FCN网络的精度很低,比Unet更难使用。 现在也有Segnet、Mask RCNN、DeepLabv3等网络,今天先介绍一下Unet。 到底不能一口变成胖子。

1因为1 Unet Unet其实很简单,所以今天的文章不是很长。

1.1提出初衷(不重要) Unet提出的初衷是为了解决医学图像分割的问题; 获取上下文信息和位置信息的u型网络结构; 在2015年的ISBI cell tracking竞赛中,获得了多个第一名,一开始这是为了解决细胞层面的分割的任务的1.2网络结构

这个结构首先卷积和池化图像。 在Unet论文中池化4次。 例如,如果第一个图像是224x224,则它会呈现四种不同大小的特征: 112x112、56x56、28x28和14x14。然后我们对14x14的特征图做上采样或者反卷积,得到28x28的特征图,这个28x28的特征图与之前的28x28的特征图进行通道伤的拼接concat,然后再对拼接之后的特征图做卷积和上采样,得到56x56的特征图,再与之前的56x56的特征拼接,卷积,再上采样,经过四次上采样可以得到一个与输入图像尺寸相同的224x224的预测结果。

实际上,从总体上看,这也是编码器-解码器的结构:

Unet网络非常简单,前半部分是特征提取,后半部分是上采样。 在一些文献中,这种结构称为编码器-解码器结构,因为网络的整体结构是大英文u,所以称为U-net。

编码器:左半部分,在两个3x3卷积层(RELU )和一个2x2最大轮询层中构成下采样模块(由)后的代码可知); 解码器:有一半,一个上采样卷积层(卷积层)的特征是由连接concat的两个3x3卷积层(ReLU )重复组成(在代码中可见); 当时,Unet更早提出的FCN网络使用拼接作为特征图的融合方式。

FCN通过将特征图的对应像素值相加来融合特征的U-net通过通道数的连接,可以形成更厚的特征。 当然,这将消耗更多内存Unet的好处我感觉是:网络层越深得到的特征图,有着更大的视野域,浅层卷积关注纹理特征,深层网络关注本质的那种特征,所以深层浅层特征都是有格子的意义的;另外一点是通过反卷积得到的更大的尺寸的特征图的边缘,是缺少信息的,毕竟每一次下采样提炼特征的同时,也必然会损失一些边缘特征,而失去的特征并不能从上采样中找回,因此通过特征的拼接,来实现边缘特征的一个找回。

2为什么Unet在医学图像分割中表现良好,这是一个开放的问题。 大家如果觉得怎么样的话,欢迎回答讨论。

大多数医学图像语义分割任务首先使用Unet作为baseline。 当然,上一章中介绍的Unet的优点一定会成为这个问题的答案。 这里是医疗影像的特点

根据网友的讨论,得到的结果是:

医学影像意义比较简单,结构固定。 因此,由于语义信息与自动驾驶等相比是单一的,所以不需要筛选、过滤无用的信息。医疗影像的所有特征都很重要,因此低级特征和高级语义特征都很重要,所以U型结构的skip connection结构(特征拼接)更好派上用场

由于医学影像数据较少、难以获得,数据量可能会在数百到100之间,因此使用DeepLabv3等大型网络模型会更容易进行拟合。 大规模网络的优点是具有更强的图像表现能力,比较简单,数量多

量少的医学影像并没有那么多的内容需要表述,因此也有人发现在小数量级中,分割的SOTA模型与轻量的Unet并没有神恶魔优势

医学影像往往是多模态的。比方说ISLES脑梗竞赛中,官方提供了CBF,MTT,CBV等多中模态的数据(这一点听不懂也无妨)。因此医学影像任务中,往往需要自己设计网络去提取不同的模态特征,因此轻量结构简单的Unet可以有更大的操作空间。

3 Pytorch模型代码

这个是我自己写的代码,所以并不是很精简,但是应该很好理解,和我之前讲解的完全一致,(有任何问题都可以和我交流:cyx645016617):

import torchimport torch.nn as nnimport torch.nn.functional as Fclass double_conv2d_bn(nn.Module): def __init__(self,in_channels,out_channels,kernel_size=3,strides=1,padding=1): super(double_conv2d_bn,self).__init__() self.conv1 = nn.Conv2d(in_channels,out_channels, kernel_size=kernel_size, stride = strides,padding=padding,bias=True) self.conv2 = nn.Conv2d(out_channels,out_channels, kernel_size = kernel_size, stride = strides,padding=padding,bias=True) self.bn1 = nn.BatchNorm2d(out_channels) self.bn2 = nn.BatchNorm2d(out_channels) def forward(self,x): out = F.relu(self.bn1(self.conv1(x))) out = F.relu(self.bn2(self.conv2(out))) return out class deconv2d_bn(nn.Module): def __init__(self,in_channels,out_channels,kernel_size=2,strides=2): super(deconv2d_bn,self).__init__() self.conv1 = nn.ConvTranspose2d(in_channels,out_channels, kernel_size = kernel_size, stride = strides,bias=True) self.bn1 = nn.BatchNorm2d(out_channels) def forward(self,x): out = F.relu(self.bn1(self.conv1(x))) return out class Unet(nn.Module): def __init__(self): super(Unet,self).__init__() self.layer1_conv = double_conv2d_bn(1,8) self.layer2_conv = double_conv2d_bn(8,16) self.layer3_conv = double_conv2d_bn(16,32) self.layer4_conv = double_conv2d_bn(32,64) self.layer5_conv = double_conv2d_bn(64,128) self.layer6_conv = double_conv2d_bn(128,64) self.layer7_conv = double_conv2d_bn(64,32) self.layer8_conv = double_conv2d_bn(32,16) self.layer9_conv = double_conv2d_bn(16,8) self.layer10_conv = nn.Conv2d(8,1,kernel_size=3, stride=1,padding=1,bias=True) self.deconv1 = deconv2d_bn(128,64) self.deconv2 = deconv2d_bn(64,32) self.deconv3 = deconv2d_bn(32,16) self.deconv4 = deconv2d_bn(16,8) self.sigmoid = nn.Sigmoid() def forward(self,x): conv1 = self.layer1_conv(x) pool1 = F.max_pool2d(conv1,2) conv2 = self.layer2_conv(pool1) pool2 = F.max_pool2d(conv2,2) conv3 = self.layer3_conv(pool2) pool3 = F.max_pool2d(conv3,2) conv4 = self.layer4_conv(pool3) pool4 = F.max_pool2d(conv4,2) conv5 = self.layer5_conv(pool4) convt1 = self.deconv1(conv5) concat1 = torch.cat([convt1,conv4],dim=1) conv6 = self.layer6_conv(concat1) convt2 = self.deconv2(conv6) concat2 = torch.cat([convt2,conv3],dim=1) conv7 = self.layer7_conv(concat2) convt3 = self.deconv3(conv7) concat3 = torch.cat([convt3,conv2],dim=1) conv8 = self.layer8_conv(concat3) convt4 = self.deconv4(conv8) concat4 = torch.cat([convt4,conv1],dim=1) conv9 = self.layer9_conv(concat4) outp = self.layer10_conv(conv9) outp = self.sigmoid(outp) return outp model = Unet()inp = torch.rand(10,1,224,224)outp = model(inp)print(outp.shape)==> torch.Size([10, 1, 224, 224])

先把上采样和两个卷积层分别构建好,供Unet模型构建中重复使用。然后模型的输出和输入是相同的尺寸,说明模型可以运行。

参考博客:

https://blog.csdn.net/wangdongwei0/article/details/82393275https://www.zhihu.com/question/269914775?sort=createdhttps://zhuanlan.zhihu.com/p/90418337

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。