空洞卷积详解(输入输出大小分析)

空洞卷积

 空洞卷积的提出主要是为了解决图像分割问题中存在的信息丢失问题,之前的图像分割算法往往会使用深度卷积神经网络,卷积层之间往往会夹杂着池化层来增大感受野,最后再通过一系列的上采样操作来将小尺寸的特征图样变换到输入图像的大小输出。使用池化层固然可以增加感受野,但是这一操作过程中会丢失许多的信息,这一点和hinton对于池化层的想法不谋而合。而同样的在上采样过程中,从小尺寸变换到大尺寸会存在着精度损失的问题,这一点在图像先缩小再复原的过程就可见端倪。因此我们需要一种可以不使用池化(下采样)和上采样,就能增加感受野的操作来代替原本的池化+上采样操作。空洞卷积应运而生。

空洞卷积和普通卷积

 空洞卷积和普通卷积的区别不大,只是多了一个 "dilation rate"的参数,这个参数定义了卷积核中两相邻元素的距离。普通卷积中卷积核中不同元素是紧密相连的,而在空洞卷积的卷积核中不同元素的距离可以不为1,这个距离越大意味着空洞卷积的感受野越大; 或者也可以认为是一个相同感受野大小的普通卷积,只是中间填充了许多权重不更新的零值。普通卷积和空洞卷积的示意图如下所示
在这里插入图片描述
在这里插入图片描述

上图即为普通卷积,下图为dilation rate=2时的空洞卷积,可以看出一个 3 × 3 3\times3 3×3大小的空洞卷积在进行卷积操作时,核捏内元素的距离为2,实际上等价于一个 5 × 5 5\times 5 5×5大小的只在棋盘区域存在非零值的普通卷积。

 而普通卷积可以通过padding操作使得输入输出特征图样的大小相同,因此空洞卷积拥有了以下两个优势。1

  1. 扩大感受野: 使用空洞卷积可以使得参数量相同的情况下,增加卷积的感受野,原本 3 × 3 3\times3 3×3的卷积核只能覆盖面积为9的区域,而相同参数量的空洞卷积可以覆盖面积为25的感受野。且随着dilation rate的提升,感受野会进一步的増大。起到了原本池化层的作用。
  2. 保持图像分辨率:由于空洞卷积可以认为是稀疏的普通卷积,在运算过程中我们可以通过paddding使得输入输出特征图样的分辨率相同。从而在图像分割任务中,避免了下采样和上采样带来的信息损失。

 以上两个优势使得空洞卷积较好的适应于图像分割任务,可以摒弃原本的池化和上采样操作。而据作者在论文中的描述,通过设置不同的dilation rate,卷积操作拥有了不同大小的感受野,可以获得多尺度的信息2。因此作者使用了连续7层dilation rate不完全相分别为{1, 1, 2, 4, 8, 16, 1, 1}的空洞卷积层构成了”上下文模块(context module)",从而可以聚合多尺度的上下文信息3。(说实话,没看出这里和多尺度有啥关系,笔者所认为的多尺度信息应该指的是对不同分辨率的特征图样进行操作,如FPN;或者是使用不同大小的卷积核对同一特征图样进行操作,再进行拼接,如GoogLeNet,但这里的空洞卷积层是连缀在一起的,基本就类似于一系列不同大小的卷积层级联,没看出和多尺度的联系在哪,也没找到解释,可能作者意思是只要使用了不同大小的卷积核就算是多尺度。
在这里插入图片描述

空洞卷积感受野的计算

 空洞卷积感受野的计算和普通卷积是一样的,只是需要将真实的卷积核大小用dilataionn rate补足即可。堆叠后的普通卷积感受野大小为4:

r n = r n − 1 + ( k n − 1 ) ∏ n = 1 n − 1 s i r_n=r_{n-1}+(k_n-1)\prod^{n-1}_{n=1}s_i rn=rn1+(kn1)n=1n1si
其中 r n r_n rn为本层的感受野大小, k n k_n kn为本层的核尺寸(实际覆盖尺寸,空洞卷积需要考虑dilation rate,池化层同理), s i s_i si为第 i i i层的步长。
根据上述公式我们可以计算出三个连续堆叠的 3 × 3 3\times3 3×3,dilation rate ={1,2,4}的空洞卷积层感受野分别为{3,7,15},这就是为何原作者会说空洞卷积支持感受野大小的指数增长。

空洞卷积的不足

 空洞卷积固然可以增大感受野,但不难看出它其实是忽略了一部分的像素间信息,这就带来了以下两个问题:

  1. 局部相关性丢失:由于空洞卷积在计算是一种网格形式计算的,小于网格分辨率的元素都不会参与到计算,这就意味着我们执行卷积操作时其实不会考虑到小范围内的信息。如下图所示连续 3 × 3 , d = 1 3\times3,d=1 3×3,d=1空洞卷积:
    在这里插入图片描述

越往左层数越高,可以看出最高层的信息来自于网格顶点的9个元素,而这9个元素又分别计算低一层的25个元素,但这25元素之间的关系并不十分紧密,最高层的距离为2的左上元素和中上元素在低一层的局部联系已经很弱了,更不消说再往下探一层。因此使用空洞卷积难以捕捉到元素的局部相关性。
2. 小尺度检测无力
 这一点其实是前一点引申出来的,既然局部相关信息考察不充分,那如果存在着小尺寸的物体,这种检测方式就有可能将其略过了。

后续改进方案

 针对空洞卷积局部相关性不足的缺项,后续研究产生了两种方案。

1. 混合

 混合方案是用另一种角度来思考空洞卷积,它可以认为是对图像进行不同其实位置的下采样,在下采样图像上进行普通卷积后再拼接回原始大小,如下图所示:
在这里插入图片描述

而相关性不足的原因就是拼接时只是简单的见缝插针,而并没有对不同位置的值进行信息融合。因此混合方案很简单,不同采样卷积结果进行融合即可:
在这里插入图片描述

2. 标准化构造

 既然问题出在由于dialation rate的设置使得高层的元素只利用到了感受野范围内的部分元素,那么我们只需要通过适当设计dialation rate使得感受野内全体元素都得到利用即可。HDC(Hyperbrid dilation Convolution)由此诞生,区别于context module的点在于它在不同层使用了不同的dilation rate,并且他们之间要符合一定的规律如下:

  1. 不同层间的dilation rate不可以拥有除1以外的公因数。这一点比较好理解,如果设定为[2,4,4]这种形式,原本网格状感受野的本质并没有改变。
  2. 次低层上的两非零元素的最大距离 M 2 < k 2 M_2<k_2 M2<k2。某层非零元素的最大距离 M i M_i Mi指的是当我们反推感受野时两个被利用元素间的最大距离,也就是空洞的最大长度。 k i k_i ki为实际上采用的卷积核大小(不考虑dilation)。当满足 M 2 < k 2 M_2<k_2 M2<k2这一条件时,我们至少可以在第一层使用大小为 k 2 × k 2 k_2\times k_2 k2×k2的普通卷积来实现感受野全覆盖。假定使用了n个空洞卷积层, M n = r n M_n=r_n Mn=rn,我们可以通过倒推的方式来求出 M 2 M_2 M2。其中第 i i i层非零元素的最大距离 M i M_i Mi计算公式为:
    M i = m a x [ r i ,   M i + 1 − 2 r i ,   M i + 1 − 2 ( M i + 1 − r i ) ] M_i=max[r_i,\ M_{i+1}-2r_i,\ M_{i+1}-2(M_{i+1}-r_i)] Mi=max[ri, Mi+12ri, Mi+12(Mi+1ri)]
    其中 r i r_i ri为第i层的dilation rate。整体其实是在描述感受野边界点距离可能的情况,用图分析比较简单,如下:
    在这里插入图片描述

使用以上两个准则,我们可以倒序设计出一组可行的空洞卷积层,再重复使用这组参数设计即可。例如使用{1,2,5,1,2,5},{1,2,5}的覆盖效果如下,颜色越深说明该位置元素参与计算的次数越多。
在这里插入图片描述

参考


  1. 吃透空洞卷积(Dilated Convolutions) ↩︎

  2. 总结-空洞卷积(Dilated/Atrous Convolution) ↩︎

  3. 如何理解空洞卷积(dilated convolution)? ↩︎

  4. 深度神经网络中的感受野(Receptive Field) ↩︎

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: Java输入输出流是构建在基础输入输出流之上的一个抽象概念,它提供了对输入输出操作的高级抽象,可以让程序员更加便捷的进行输入输出操作。Java输入输出流提供了丰富的类,可以操作文件、网络、内存、设备等数据源,它们可以按照字节流或字符流的方式操作数据。 ### 回答2: Java 输入输出流是用于在程序中读取数据和写入数据的机制。在Java中,输入输出流是通过流的方式来实现数据的读取和写入。 输入流用于从外部获取数据,比如从键盘读取用户输入,或从文件中读取数据。常见的输入流有:System.in(标准输入流,即键盘输入)、FileInputStream(文件输入流,读取文件中的数据)等。通过输入流,可以将数据从外部输入到程序中。 输出流用于将程序中的数据输出到外部,比如将数据输出到控制台、写入文件等。常见的输出流有:System.out(标准输出流,即控制台输出)、FileOutputStream(文件输出流,将数据写入到文件中)等。通过输出流,可以将数据从程序中输出到外部。 Java输入流按照读取方式的不同可以分为字节流和字符流。字节流使用字节(8位)为单位进行数据传输,适合处理二进制文件或者文本文件。常见的字节流有:InputStream(字节输入流)、FileInputStream(文件输入流)等。字符流使用字符(16位)为单位进行数据传输,适合处理文本文件。常见的字符流有:Reader(字符输入流)、FileReader(文件字符输入流)等。 Java输出流同样也按照写入方式的不同可以分为字节流和字符流。字节流使用字节(8位)为单位进行数据传输,适合处理二进制文件或者文本文件。常见的字节流有:OutputStream(字节输出流)、FileOutputStream(文件输出流)等。字符流使用字符(16位)为单位进行数据传输,适合处理文本文件。常见的字符流有:Writer(字符输出流)、FileWriter(文件字符输出流)等。 通过使用Java的输入输出流,我们可以在程序中灵活地读取外部数据和将程序数据输出到外部。这为我们处理各种类型的数据提供了方便和灵活性。同时,还需要注意在使用完输入输出流后及时关闭流资源,以避免资源泄露和占用。 ### 回答3: Java 的输入输出流是在程序中进行输入和输出操作的一种方式,用来实现与外部设备的数据传输。 Java 提供了两种常用的输入输出流:字节流和字符流。字节流以字节为单位进行输入输出,字符流以字符为单位进行输入输出。字节流适用于二进制文件的读写,如图像、音频等文件;字符流适用于文本文件的读写。 Java 的输入流用来将外部数据读入程序中,输出流用来将程序的数据输出到外部设备中。 常见的字节输入流有 InputStream 和其子类,如 FileInputStream,用于从文件中读取字节数据;常见的字符输入流有 Reader 和其子类,如 FileReader,用于从文件中读取字符数据。 常见的字节输出流有 OutputStream 和其子类,如 FileOutputStream,用于向文件中写入字节数据;常见的字符输出流有 Writer 和其子类,如 FileWriter,用于向文件中写入字符数据。 使用输入输出流的基本步骤是:创建输入输出流对象,打开数据源或目标文件,根据需要进行读取或写入操作,关闭流。 在读取或写入数据时,可以通过缓冲流来提高效率。BufferedInputStream 和 BufferedOutputStream 是字节缓冲流的实现类,BufferedReader 和 BufferedWriter 是字符缓冲流的实现类。 除了文件输入输出流外,Java 还提供了其他类型的输入输出流,如网络输入输出流和内存输入输出流,用于不同的应用场景。 总之,Java 的输入输出流是一种用于在程序中进行数据读写的方式,提供了丰富的输入输出流类和方法,能够满足不同的需求。熟练掌握输入输出流的使用,对于开发Java应用程序是非常重要的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值