计算机视觉中upsampling(上采样)的三种方式

版权声明:新建了专注于语义分割的QQ群704803384,欢迎交流!!!    https://blog.csdn.net/u014451076/article/details/79156967
bilinear
双线性插值是目前在语义分割中用的比较多的一种方式,比如FCN中就是用的这种方法。 
这种方法特点是不需要进行学习,运行速度快,操作简单。只需要设置好固定的参数值即可,设置的参数就是中心值需要乘以的系数。 
一个简单的例子可以参考如下(来自互联网): 

具体的实现方式,可以直接参考fcn.berkerlyvision.org中的surgery.py如下:

def upsample_filt(size):
    """
    Make a 2D bilinear kernel suitable for upsampling of the given (h, w) size.
    """
    factor = (size + 1) // 2
    if size % 2 == 1:
        center = factor - 1
    else:
        center = factor - 0.5
    og = np.ogrid[:size, :size]
    return (1 - abs(og[0] - center) / factor) * \
           (1 - abs(og[1] - center) / factor)
1
2
3
4
5
6
7
8
9
10
11
12
如果看了上面的简单实例和具体代码还不会使用bilinear,就看最后一个例子,这里以FCN举例, 
在FCN的berkerly官方caffe实现,以voc-fcn32/train.prototxt举例,bilinear部分代码如下:

layer {
  name: "score_fr"
  type: "Convolution"
  bottom: "fc7"
  top: "score_fr"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  convolution_param {
    num_output: 21
    pad: 0
    kernel_size: 1
  }
}
layer {
  name: "upscore"
  type: "Deconvolution"
  bottom: "score_fr"
  top: "upscore"
  param {
    lr_mult: 0
  }
  convolution_param {
    num_output: 21
    bias_term: false
    kernel_size: 64
    stride: 32
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
其中,upscore层使用surgery.py中的upsample_filt函数进行实现(本文第一段代码),相当于设置参数type: ‘bilinear’,这个很容易实现。通过测试可以发现,在forward-propagation过程中,score_fr层的blob shape是[1, 21, 16, 16],经过bilinear后变为[1, 21, 544, 544]。依照代码简单分析就可以发现bilinear的具体计算流程如下: 
(1) 64%2 == 0,所以center的坐标为(31.5, 31.5),note在python中下标从0开始 
(2) 计算出一个64x64的矩阵,每个位置根据代码所示填数,其实就是线性规则 
(3) 二维来看,将score_fr层的16x16的每一个位置的坐标放在31.5位置,也就是在相邻元素之间插入32个位置,周边补充32个位置,不同元素对插入的不同值有影响,则相互叠加,最后将原来的16x16的元素移除,也就形成了32x17 = 544,也就是具体upscore层算出来的值 
放点东西,形象表示一下: 
32个元素 [16x16中的(0,0)元素] 32个元素 [16x16中的(0,1)元素] 32个元素 … 
其中,中括号中的元素不可见

Deconvolution
Deconvolution是目前争议比较多的方法,主要是名字上的争议,由于实现上采用转置卷积核的方法,所以有人说应该叫(transposed convolution),但是思想上是为了还原原有特征图,类似消除原有卷积的某种效果,所以叫反卷积(deconvolution). Caffe中叫deconvolution,这里就继续沿用这个名字. 
要理解deconv,要先了解conv的具体是实现方式,在实现过程中,为了使卷积运算更快的执行,通常转化为矩阵乘法进行处理(因为矩阵乘法有一些加速计算库)。卷积计算通常的两种实现方式是:在caffe中使用im2col的方法,在其他的地方使用toeplitz matrix(托普利兹矩阵)进行实现。 
具体例子参看知乎https://www.zhihu.com/question/43609045?sort=created 
为了更容易地实现deconvolution,直接使deconv的前向传播模拟conv的反向传播,当然,这里只是为了保证尺寸大小互逆,并不能保证值的还原。具体思路可以参考这篇博客http://blog.csdn.net/zsz_shsf/article/details/53201669。 
做几个小例子帮助理解: 
(1) 关于第一节中bilinear的在caffe中使用deconvolution进行实现,上节的bilinear论述过程中使用固定值计算的方法,本节从deconv可视化计算的角度进行理解,https://github.com/vdumoulin/conv_arithmetic 
63个元素 [16x16中的(0,0)元素] 31个元素 [16x16中的(0,1)元素] 31个元素 
其中,中括号中的元素可见 
对以上过程进行卷积运算,注意这里stride 使用1, 最终输出大小为(63+32x15+64-64)/1 + 1 = 544 
这里可以脑补一下计算过程,相当于第一节中的手算叠加 
(2) 对bilinear使用转置运算进行实现,先将64x64的卷积核转化为toeplitz matrix,然后转置,得到544x544,256的矩阵,然后将score_fr转化为1, 256的矩阵,两者矩阵乘法,得到544x544的最终结果,具体过程脑补吧

unpooling
也就是反池化,不需要学习,用的不是太多,参考论文Visualizing and Understanding Convolutional Networks,还有SegNet和DeconvNet 
简单原理:在池化过程中,记录下max-pooling在对应kernel中的坐标,在反池化过程中,将一个元素根据kernel进行放大,根据之前的坐标将元素填写进去,其他位置补0 
实现代码可以看SegNet的实现

end
简单捋了一遍,帮助理解
--------------------- 
作者:明天去哪 
来源:CSDN 
原文:https://blog.csdn.net/u014451076/article/details/79156967 
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/weixin_41036461/article/details/83146568
今日推荐