Unet——pytorch

                                                                                                                                                                                                                                                                                                                                                                                                                                                                  

Unet的一些概念

Unet 的初衷:

是为了解决生物医学图像方面的问题,最初也是在细胞数据集上使用的,由于效果确实很好后来也被广泛的应用在语义分割的各个方向,比如卫星图像分割,工业瑕疵检测等。

Unet 的优势:

1,可以在小数据集上达到较好的效果。以往的网络模型依赖于大量的数据集进行训练,但是在医学图像的分割中,往往能够训练的数据相对较小而检测目标又会比较大,在unet网络中使用了数据增强;

2,可以对每个像素点进行分割,获得更高的分割准确率;

3,在训练过程中使用高梯度下降,这使得训练模型的学习率处在一个自我调节的过程中;

4,权重划分。权重划分公式为:

w(x)=w_{c}(x)+w_{0}\cdot exp\left ( -\frac{(d_{1}(x)+d_{2}(x))^{2}}{2\sigma ^{2}} \right )

w_{c}是用于平衡类别频率的权重图d_{1}代表到最近细胞的边界的距离,d_{2}​代表到第二近的细胞的边界的距离。基于经验我们设定w_{0}=10,σ≈5像素

5,引入图像镜像操作,能够更好的对数据进行训练。

Unet的网络结构

基本概念:

U-Net的结构是用编码和解码,它左边和右边很类似(完全对称),U形的左侧是一个编码的过程,右侧是一个解码的过程。

1,网络是一个全卷积网络(即网络中没有全连接操作)

2,网络的输入是一张572*572的边缘经过镜像操作的图片

3,通过两次卷积之后得到特征图像,然后经过池化进行收缩

4,重复步骤3,总共进行4次

5,通过复制和裁剪,融合之后再经过两次卷积,然后反卷积进行解码

6,重复步骤5,总共进行4次

7,经过两次卷积和一次1*1卷积得到最终的结果。

代码解释:

conv1*1:

1)对于单通道图像,其作用仅仅是进行线性运算;

2)对于多通道图像,会遍历图像所在的位置,将每个位置处所有通道的值作为其输入,与1*1卷积核中对应通道的值进行线性运算。本质上可以视为一个全连接神经网络。

(conv1*1一般只改变输出的通道数,而不改变输出的宽度和高度;而Pooling操作一般只改变输出的宽和高,而不改变通道数)

模型代码:

关于两层conv3*3:

import torch.nn as nn
 
class DoubleConv(nn.Module):
    """(convolution => [BN] => ReLU) * 2"""
 
    def __init__(self, in_channels, out_channels):
        super().__init__()
        self.double_conv = nn.Sequential(#torch.nn.Sequential是一个时序容器,modules会以它们传人的顺序被添加到容器中
            nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=0),
            nn.BatchNorm2d(out_channels), #归一化处理,为了避免在进行relu之前因为数据过大而导致网络性能不稳定
            nn.ReLU(inplace=True),
            nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=0),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True)
        )
 
    def forward(self, x):
        return self.double_conv(x)

关于max pool 2*2:

import torch.nn as nn

class Down(nn.Module):
    "downscaling and maxpool 2*2 then coupleconv”

    def __int__(self, in_channenls, out_channels):
        
        super().__init__()
        self.maxpool_conv = nn.Sequential(
            nn.MaxPool2d(2),
            Douleconv(in_channenls,out_channels)
        )

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

关于copy  and crop 以及 up conv:

class Up(nn.Module):
    """Upscaling then double conv"""

    def __init__(self, in_channels, out_channels, bilinear=True):
        super().__init__()

        # if bilinear, use the normal convolutions to reduce the number of channels
        if bilinear:
            self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)
            self.conv = DoubleConv(in_channels, out_channels, in_channels // 2)
        else:
            self.up = nn.ConvTranspose2d(in_channels, in_channels // 2, kernel_size=2, stride=2)
            self.conv = DoubleConv(in_channels, out_channels)

    def forward(self, x1, x2):
        x1 = self.up(x1)
        # input is CHW
        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])
        # if you have padding issues, see
        # https://github.com/HaiyongJiang/U-Net-Pytorch-Unstructured-Buggy/commit/0e854509c2cea854e247a9c615f175f76fbb2e3a
        # https://github.com/xiaopeng-liao/Pytorch-UNet/commit/8ebac70e633bac59fc22bb5195e513d5832fb3bd
        x = torch.cat([x2, x1], dim=1)
        return self.conv(x)

关于conv1*1:

class OutConv(nn.Module):
    def __init__(self, in_channels, out_channels):
        super(OutConv, self).__init__()
        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=1)

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

应用

1,主要用于医学分割

2,姿态估计;

3,Gan网络。

联系:VGG——resnet——FCN——Unet

问题

1,图像分割为什么要采用先编码后解码的形式?

1)下采样是为了图像识别,可以降低显存和计算量;增大感受野,使卷积获得更全局性的特征提取;多级语义融合可以使得分类更加准确;

2)上采样是为了便于分割处理,输出得到分割结果mask。当然,上采样不能够恢复成为原始图像,这个过程中已经丢失了许多特征,因此unet中使用了copy and crop来做补充。

2,上采样过程中使用skip-connection保留细节,那这个过程中像素点增加,不会导致下采样过程中降低的显存和计算量增加回来吗,为什么这样能得到一个好的效果?

1)个人认为unet图像分割的下采样可能更主要的是为了增大感受野,同时在增大感受野的过程中计算量的显存得到降低;

2)而在上采样的过程中,是为了提升其精度,但是大量的padding确实造成了巨大的冗余,这也是unet网络慢的一个原因。

有个说法,cnn网络分类精度和定位精度难以共存,那unet下采样增大感受野skip-connection增加精度的方式是否对这个说法有一定的冲击?

训练部分

相关参数:

learning_rate:学习率决定了权值的更新速度,设置得太大会使结果超过最优值,太小会使下降速度过慢。在训练模型时,通常会遇到:我们训练模型时已经平衡了模型的训练速度和loss去选择相对合适的学习率,但是训练集的loss降低到一定程度之后就不再下降了,而是在一个区间来回,这种情况可以通过适当降低学习率来实现,但是学习率的降低又会延长训练时间。

一般的解决办法是——学习率衰弱(learning rate decay)基本思想是:学习率随着训练的进行逐渐衰弱。

val_percent:验证集的划分比例,这里采用了整个数据集的90%做训练集,10%做验证集;

weight_decay: 的作用是用当前可学习参数p的值修改偏导数g_{t}=g_{t}+(p*weightdecay)weight_decay的作用是正则化,和RMSProp并无直接关系,但是可以一定程度上缓解过拟合

save_checkpoint:checkpoint检查点,不仅保存模型的参数,优化器参数,还有loss,epoch等(相当于一个保存模型的文件夹)。

amp:自动混合精度。

 monmenrum:动量来源于牛顿定律,基本思想是为了找到最优,SGD通常来说下降速度比较快,但却容易造成另一个问题,就是更新过程不稳定,容易出现震荡。加入“惯性”的影响,就是在更新下降方向的时候不仅要考虑到当前的方向,也要考虑到上一次的更新方向,两者加权,某些情况下可以避免震荡,摆脱局部凹域的束缚,进入全局凹域。动量,就是上一次更新方向所占的权值。当误差曲面中存在平坦区域,SGD可以更快的学习,是梯度下降法中一种常用的加速技术。
对于一般的SGD,其表达式为:
w := w - lr * dw
即沿负梯度方向下降。而添加momentum的SGD形式如下:
v := mu * v - lr * dw
w := w + v
其中mu为momentum系数,即如果上一次的momentum(v)与这一次的负梯度方向是相同的,则这次下降的幅度就会很大,就起到加速迭代收敛的作用。当刚开始训练的时候,把动量设小,或者直接就置为0,然后慢慢增大动量,有时候效果比较好。

gradient_clipping:梯度裁剪。

优化器:

传统梯度优化:

BGD:批量梯度下降算法,在训练的时候选用所有的训练集进行计算;

SGD:随机梯度下降算法,在训练的时候只选用一个数据进行训练;

MBGD:小批量梯度下降算法,在训练的时候只选用小部分数据进行训练;

虽然这三种算法在选择数据集量的时候不同,但是他们在进行参数优化的时候是相同的;一般采用小批量梯度下降算法,即选择部分数据进行训练,因为它们更新参数的时候采用相同的参数,因此它们统称为“传统梯度更新算法”,基本思想是:先设定一个学习率\lambda,参数沿梯度的反方向移动,假设需要更新的参数为\theta,梯度为g,则其更新策略可表示为:

\theta \leftarrow \theta -\lambda g

传统算法的优化算法:

针对传统梯度优化过于依赖学习率的选取的缺点问题,许多优化算法从梯度方向和学习率两方面入手。有些从梯度方向入手,如动量更新策略;有些从学习率入手,这涉及到调参的问题;还有的从两方面同时入手,如自适应更新策略;

AdaGrad算法:

适合处理稀疏数据,通过参数来调整合适的学习率,对稀疏参数进行大幅更新和对频繁参数进行小幅更新。可能是因为其累计梯度平方导致学习率过早或过量的减少所致,它在某些深度学习模型上有着不错的效果,但仍不够优秀。

RMSProp算法:

RMSProp算法通过修改AdaGrad得来,其目的是在非凸背景下效果更好。针对梯度平方和累计越来越大的问题,RMSProp指数加权的移动平均代替梯度平方和。RMSProp为了使用移动平均,还引入了一个新的超参数\rho,用来控制移动平均的长度范围。它在深度学习中被广泛用于深度神经网络优化。

  • 2
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值