• Gated-SCNN: Gated Shape CNNs for Semantic Segmentation论文阅读笔记


    如何将知识分离出来?

    作者在论文中argue到,CNN在设计的过程中有一个固有的无效性,因为他们会将color,shape和纹理信息一起处理(感觉可以找个时间介绍一些,图像中的color,shape或者texture信息对于图像的特征提取有哪些帮助作用)。但是实际上这些不同的信息,比如color或者shape,texture对于识别来说的话,应该是包含不同的数量的信息的。作者举了一个例子,一个人刚开始看一个物体的时候,需要看到完整地,细节地物体的边界,从而能够得到具有辨别性的shape编码。但是color和texture就相对包含一些low-level的信息,意思是,对于物体的识别就没有轮廓那么重要。这种思路实际上可以解释为什么resnet需要residual skip来提升网络的性能,或者是dense connection。以你为,通过添加这种additional connectivity能够帮助不同类型的信息通过不同scale的深度进行融合流通(个人感觉这个说服力对于解释为什么resnet work比较有说服力)。

    这篇文章做了啥?

    作者说到,在这篇文章中,他们提出了一个新的,two-stream CNN,能够显式的讲shape information独立成一个processing branch。两个stream,分别是传统cnn的stream,另外一个是shape stream,能够并行的处理信息。除了非常顶层的layer,作者说不允许两个stream信息的融合。
    作者说到这篇文章的主要核心就是用一个门来控制两路信息的交互。具体来讲就是,作者利用传统cnn stream的high-level的information来denoise前几层shape stream的activations。这么一操作,shape stream能够有效的处理相关的信息。而且只使用比较浅的网络。为了能够使得shape information,作者在shape stream上添加了语义边界loss。我们更进一步的利用了一个新的loss function,来使得segmentation result和gt进行对齐。
    并且作者还说道,他们的GSCNN是plug-and-play的,可以用在任何cnn上。作者做了大量的实验,比deep lab-v3的结果在miou指标上高了1.5个百分点,在f-boundary指标上高了4%个百分点。而且作者说他们的实验结果在一些很小的物体上的表现性能会更好,比如电线杆,交通标识或者交通灯等。

    相关工作的介绍

    语义分割进展

    作者貌似说文献6已经有人用边界信息来refine实验结果,但是和他们不一样的是,作者是inject the learned boundary information到cnn的中间层,而不是最终的结果。作者还指出,之前文献42也用了two stream network,但是他们是恢复由pooling降低的高分辨率的feature。文献15,35,48提出了用于学习结构信息pixel级别的仿射信息,他们主要用来学习一个特定信息传播模块,作者提出的是学习高质量的shape information。

    multitask learning

    有一些工作是用来提出互补任务的学习。作者的目标并不是训练一个多任务的网络,而是能够通过利用分割和边界对偶性质来加强结构化信息的表示。文献12,4能够同时学习分割和边界检测的结果。31和40能够学习intermediate的表示来辅助分割结果。但是这些工作对于边界的约束只在loss function上,作者直接将边界信息注入到网络的中间层去,并且提出了一个对偶任务loss来同时refine 分割的mask和边界预测的结果。

    gated convolution

    最近的在语言模型上的研究表明卷积上的gating mechanism是有效果的,比如文献14提出了取代循环网络中的循环connection的gated temporal convolution。文献53提出了一个soft-gating的图像不全的机制。文献46提出了gated pixelcnn来做图像生成。这里作者用gated covolution opreator来做语义分割以及控制两个stream信息之间的流动。

    Gated Shape CNN

    相当于是作者把shape这一个分支独立出来,因为考虑到shape对于分割而言是非常具有意义的,其实对于很多任务而言都是具有意义的,比如双目深度估计或者是单目深度估计,都是比较有意义的。作者整体的pipline如下

    作者整体的pipline如上图,就是用backbone接出来几路,用于做gate相关的东西,作者代码里面写的很详细
    我将作者代码的detail绘制了一个图,如下


    最终网络的输出是一个edge map,一个是分割的结果。
    关于边缘图,相当于作者是用一个branch,单独输出最终的边缘图,这种边缘图可以指导网络分割的结果。
    随便可视化了一张图片,原图如下图所示,

    根据分割图获取的边缘图的ground truth如下图所示

    当然,下图是作者对于上图的gt增强的的结果。
    作者将输出的edge_out和candy算子得到的结果一起concate到aspp中,关于aspp,只deeplab-v3提及的一个模块。下面是ASPP代码的解析

    ASPP代码模块解析

    看了一下ASPP作者的代码,当然在这里作者融合了edge的信息,代码块如下

    class _AtrousSpatialPyramidPoolingModule(nn.Module):
        '''
        operations performed:
          1x1 x depth
          3x3 x depth dilation 6
          3x3 x depth dilation 12
          3x3 x depth dilation 18
          image pooling
          concatenate all together
          Final 1x1 conv
        '''
    
        def __init__(self, in_dim, reduction_dim=256, output_stride=16, rates=[6, 12, 18]):
            super(_AtrousSpatialPyramidPoolingModule, self).__init__()
    
            # Check if we are using distributed BN and use the nn from encoding.nn
            # library rather than using standard pytorch.nn
    
            if output_stride == 8:
                rates = [2 * r for r in rates]
            elif output_stride == 16:
                pass
            else:
                raise 'output stride of {} not supported'.format(output_stride)
    
            self.features = []
            # 1x1
            self.features.append(
                nn.Sequential(nn.Conv2d(in_dim, reduction_dim, kernel_size=1, bias=False),
                              Norm2d(reduction_dim), nn.ReLU(inplace=True)))
            # other rates
            for r in rates:
                self.features.append(nn.Sequential(
                    nn.Conv2d(in_dim, reduction_dim, kernel_size=3,
                              dilation=r, padding=r, bias=False),
                    Norm2d(reduction_dim),
                    nn.ReLU(inplace=True)
                ))
            self.features = torch.nn.ModuleList(self.features)  # 经过计算,发现四者的size是一样的
    
            # img level features
            self.img_pooling = nn.AdaptiveAvgPool2d(1)
            self.img_conv = nn.Sequential(
                nn.Conv2d(in_dim, reduction_dim, kernel_size=1, bias=False),
                Norm2d(reduction_dim), nn.ReLU(inplace=True))
            self.edge_conv = nn.Sequential(
                nn.Conv2d(1, reduction_dim, kernel_size=1, bias=False),
                Norm2d(reduction_dim), nn.ReLU(inplace=True))
             
    
        def forward(self, x, edge):
            x_size = x.size()
    
            img_features = self.img_pooling(x)
            img_features = self.img_conv(img_features)
            img_features = F.interpolate(img_features, x_size[2:],
                                         mode='bilinear',align_corners=True)
            out = img_features
    
            edge_features = F.interpolate(edge, x_size[2:],
                                          mode='bilinear',align_corners=True)
            edge_features = self.edge_conv(edge_features)
            out = torch.cat((out, edge_features), 1)
    
            for f in self.features:
                y = f(x)
                out = torch.cat((out, y), 1)  # 二者concate在一起经过aspp
            return out
    

    ASPP是另外一篇文章提出来的,这里作者只是,将backnone和最后输出的edge信息在一起输入了aspp。aspp实际上是利用四路不同的空洞卷积并行处理输入的feature map,不同的空洞卷积的dilation不同,感受野也不一样,这对于提取不同尺度的信息。从上面的这个module可以看出,作者最后将上采样得到的edge_features和out concate到一起,然后依次经过ASPP模块,一个很自然的问题是,ASPP四路并行,虽然用不同的dilation和padding,尽管strid一样,如何能够保证输出的feature map的尺寸一样,使之能够concate到一起?
    根据输出的feature map的尺寸计算公式

    [W_{output} = lfloor frac{W_{in}+2*pading-dilation*(k-1)-1}{s}+1 floor ]

    从上面这个公式可以看出,如果要保证(W_{output})是一样的话,(s)固定,则需要保证(W_{in}+2*pading-dilation*(k-1)-1)对于不同的dilation是一样的,这就是ASPP实现的关键。因为(W_{in})是固定的,所以就需要保证(2*pading-dilation*(k-1))对于不同的dilation是一样的,显然,仔细观察上面的self.features的卷积参数,作者第一个的卷积的padding默认是0,kernel size默认是1,所以20-1(1-1)=0。对于剩下的卷积里面的参数,padding都是为dilation,k为3,所以2*dilation-dilation(3-1)=0,可以看出,这样就能够保证不同dilation输出的feature map的尺寸是一样的,这样后续的concate就会方便很多。

    loss

    作者定义了四个loss,对于分割或者是edge检测的结果,分别定义了cross entropy loss。然后还定义了对偶loss,关于对偶loss,作者的两个对偶loss分别定义如下

    另外一个对偶loss,作者说探究了边界以及分割的结果,也并没有看太懂,但是一个值得学习的点就是作者用一个可微的函数替代了argmax操作,感觉这个还是挺值得学习的。

    实验结果

    作者在cityspace数据集合上达到了比较好的实验结果。并且作者做了ablation study,说不加gate或者不加candy得到的结果,结果时好时坏。
    作者展示了一下,shape stream最终输出的结果

    以及作者展示了一下误差图

    可以看出,deep-lab v3的误差是比较小的。
    btw,作者也可视化了一下三个gate的实验结果,

    越往后越具有高层次的信息。
    根据分割的结果,作者能够从分割的结果得到原图的边缘图,可以看出,分割得到的图的边缘还是挺准的

    总结一下

    感觉这种inject这种low-level相关的信息还是挺值得学习的,就是单独出来一个stream,这种stream与backbone有某种关联,这样可以强化分割得到的结果。这种low指导high level的方向感觉在很多任务中都会用到,也可能是未来的一个研究的方向。

  • 相关阅读:
    Android服务器——TomCat服务器的搭建
    Ubuntu16.04 Liunx下同时安装Anaconda2与Anaconda3
    android中代码操作外部SD卡出错:W/System.err(1595): Caused by: libcore.io.ErrnoException: open failed: EACCES (Permission denied)
    查准率与查全率(precision and recall) 的个人理解
    Python游戏-实现键盘控制功能
    UGUI世界坐标转换为UI本地坐标(游戏Hud的实现)
    LoadRunner中遭遇交互数据加密的处理方案
    [Java]链表的打印,反转与删除
    优化程序性能(3)——提高并行性
    基本排序算法的python实现
  • 原文地址:https://www.cnblogs.com/yongjieShi/p/12528226.html
Copyright © 2020-2023  润新知