反卷积 订阅
在数学中,反卷积是一种基于算法的过程,用于反转卷积对记录数据的影响。 反卷积的概念广泛用于信号处理和图像处理技术。 由于这些技术反过来在许多科学和工程学科中广泛使用,因此反卷积可以应用到许多领域。 展开全文
在数学中,反卷积是一种基于算法的过程,用于反转卷积对记录数据的影响。 反卷积的概念广泛用于信号处理和图像处理技术。 由于这些技术反过来在许多科学和工程学科中广泛使用,因此反卷积可以应用到许多领域。
信息
广泛应用
信道均衡、图像恢复、语音识别
所属类别
信号处理中一类基本问题
中文名
反卷积
外文名
deconvolution
反卷积简介
反卷积是信号处理中一类基本问题,广泛应用于信道均衡、图像恢复、语音识别、地震学、无损探伤等领域,也可应用于未知输入估计和故障辨识问题。一般来说,反卷积的目的是找到一个形式的卷积方程的解: 通常, 是一些记录的信号,f是我们希望恢复的一些信号,但是在我们记录它之前已经与其他一些信号 卷积。 函数 可以表示仪器的传递函数或应用于物理系统的驱动力。 如果我们知道 或者至少知道 的形式,那么我们可以执行确定性反卷积。 但是,如果我们不知道 ,那么我们需要估计它。 这通常是使用统计估计方法完成的。在物理测量中,通常更接近: 在这种情况下 是进入我们记录的信号的噪音。 如果我们假设当我们尝试对 进行统计估计时噪声信号或图像是无噪声的,那么我们的估计将是不正确的。 反过来,我们对f的估计也是不正确的。 信噪比越低,我们对解卷积信号的估计就越差。 这就是信号逆滤波通常不是一个好的解决方案的原因。 但是,如果我们至少有一些关于数据中噪声类型的知识(例如,白噪声),我们可能能够通过诸如维纳解卷积等技术来改进对f的估计。反卷积通常是通过计算记录信号h的傅里叶变换和传递函数 ,在频域中应用解卷积来实现的,在没有噪声的情况下这仅仅是: , 和 分别是 , 和 的傅里叶变换。 最后进行逆傅里叶变换F以找到估计的解卷积信号f。反卷积和时间序列分析的基础很大程度上由麻省理工学院的诺伯特·维纳在他的书“外推,插值和平稳时间序列的平滑”(1949)中确定的。这本书是根据维纳在第二次世界大战期间所做的工作制作的,但那时是保密的。 应用这些理论的一些早期尝试是在天气预报和经济学领域。 [1] 
收起全文
精华内容
下载资源
问答
  • 反卷积

    2021-07-20 06:12:10
    参考:...反卷积的数学含义,通过反卷积可以将通过卷积的输出信号,完全还原输入信号 但是 在卷积中原始数据已经丢失,还原的知识一个相同大小的用特征值表达的数据 ...

    参考:https://blog.csdn.net/fu6543210/article/details/80407911https://blog.csdn.net/fu6543210/article/details/80408704

    什么是反卷积

    反卷积的数学含义,通过反卷积可以将通过卷积的输出信号,完全还原输入信号
    但是 在卷积中原始数据已经丢失,还原的知识一个相同大小的用特征值表达的数据

    展开全文
  • 反卷积求信道,使用反卷积指令仿真信道,查看信号和信道的状态
  • 压缩包中是反卷积神经网络的相关介绍文档整合。
  • 反卷积:WAV文件的卷积和反卷积支持的信号处理功能:相关,卷积,反卷积,采用希尔伯特变换的卷积,采用希尔伯特变换的卷积版权所有(c)2008-2016,作者:Klaus Michael Indlekofer。 版权所有。 注意:有特殊限制...
  • 反卷积和信号复原-反卷积和信号复原.part04.rar 反卷积和信号复原 反卷积和信号复原是信号处理技术中具有理论挑战性的分支。本身内容大致分为三个部分:理论基础,一维信号反卷积和图像复原。
  • 反卷积和信号复原-反卷积和信号复原.part05.rar 反卷积和信号复原 反卷积和信号复原是信号处理技术中具有理论挑战性的分支。本身内容大致分为三个部分:理论基础,一维信号反卷积和图像复原。
  • 反卷积和信号复原-反卷积和信号复原.part01.rar 反卷积和信号复原 反卷积和信号复原是信号处理技术中具有理论挑战性的分支。本身内容大致分为三个部分:理论基础,一维信号反卷积和图像复原。
  • 反卷积和信号复原-反卷积和信号复原.part03.rar 反卷积和信号复原 反卷积和信号复原是信号处理技术中具有理论挑战性的分支。本身内容大致分为三个部分:理论基础,一维信号反卷积和图像复原。
  • 反卷积和信号复原-反卷积和信号复原.part07.rar 反卷积和信号复原 反卷积和信号复原是信号处理技术中具有理论挑战性的分支。本身内容大致分为三个部分:理论基础,一维信号反卷积和图像复原。
  • 反卷积和信号复原-反卷积和信号复原.part09.rar 反卷积和信号复原 反卷积和信号复原是信号处理技术中具有理论挑战性的分支。本身内容大致分为三个部分:理论基础,一维信号反卷积和图像复原。
  • 反卷积和信号复原-反卷积和信号复原.part08.rar 反卷积和信号复原 反卷积和信号复原是信号处理技术中具有理论挑战性的分支。本身内容大致分为三个部分:理论基础,一维信号反卷积和图像复原。
  • 反卷积和信号复原-反卷积和信号复原.part06.rar 反卷积和信号复原 反卷积和信号复原是信号处理技术中具有理论挑战性的分支。本身内容大致分为三个部分:理论基础,一维信号反卷积和图像复原。
  • 反卷积和信号复原-反卷积和信号复原.part02.rar 反卷积和信号复原 反卷积和信号复原是信号处理技术中具有理论挑战性的分支。本身内容大致分为三个部分:理论基础,一维信号反卷积和图像复原。
  • 上一篇文章已经介绍过卷积的实现,这篇文章我们学习反卷积原理,同样,在了解反卷积原理后,在后面手写python代码实现反卷积。 1 反卷积原理 反卷积原理不太好用文字描述,这里直接以一个简单例子描述反卷积过程...

    最近看到一个巨牛的人工智能教程,分享一下给大家。教程不仅是零基础,通俗易懂,而且非常风趣幽默,像看小说一样!觉得太牛了,所以分享给大家。平时碎片时间可以当小说看,【点这里可以去膜拜一下大神的“小说”】

    上一篇文章已经介绍过卷积的实现,这篇文章我们学习反卷积原理,同样,在了解反卷积原理后,在后面手写python代码实现反卷积。

    1 反卷积原理

    反卷积原理不太好用文字描述,这里直接以一个简单例子描述反卷积过程。

    假设输入如下:

    [[1,0,1],
     [0,2,1],
     [1,1,0]]
    

    反卷积卷积核如下:

    [[ 1, 0, 1],
     [-1, 1, 0],
     [ 0,-1, 0]]
    
    

    现在通过stride=2来进行反卷积,使得尺寸由原来的3*3变为6*6.那么在Tensorflow框架中,反卷积的过程如下(不同框架在裁剪这步可能不一样):

    反卷积实现例子
    其实通过我绘制的这张图,就已经把原理讲的很清楚了。大致步奏就是,先填充0,然后进行卷积,卷积过程跟上一篇文章讲述的一致。最后一步还要进行裁剪。好了,原理讲完了,(#.#)…

    2 代码实现

    上一篇文章我们只针对了输出通道数为1进行代码实现,在这篇文章中,反卷积我们将输出通道设置为多个,这样更符合实际场景。

    先定义输入和卷积核:

    input_data=[
                   [[1,0,1],
                    [0,2,1],
                    [1,1,0]],
    
                   [[2,0,2],
                    [0,1,0],
                    [1,0,0]],
    
                   [[1,1,1],
                    [2,2,0],
                    [1,1,1]],
    
                   [[1,1,2],
                    [1,0,1],
                    [0,2,2]]
    
                ]
    weights_data=[ 
                  [[[ 1, 0, 1],
                    [-1, 1, 0],
                    [ 0,-1, 0]],
                   [[-1, 0, 1],
                    [ 0, 0, 1],
                    [ 1, 1, 1]],
                   [[ 0, 1, 1],
                    [ 2, 0, 1],
                    [ 1, 2, 1]], 
                   [[ 1, 1, 1],
                    [ 0, 2, 1],
                    [ 1, 0, 1]]],
    
                  [[[ 1, 0, 2],
                    [-2, 1, 1],
                    [ 1,-1, 0]],
                   [[-1, 0, 1],
                    [-1, 2, 1],
                    [ 1, 1, 1]],
                   [[ 0, 0, 0],
                    [ 2, 2, 1],
                    [ 1,-1, 1]], 
                   [[ 2, 1, 1],
                    [ 0,-1, 1],
                    [ 1, 1, 1]]]  
               ]
    
    

    上面定义的输入和卷积核,在接下的运算过程如下图所示:

    执行过程

    可以看到实际上,反卷积和卷积基本一致,差别在于,反卷积需要填充过程,并在最后一步需要裁剪。具体实现代码如下:

    #根据输入map([h,w])和卷积核([k,k]),计算卷积后的feature map
    import numpy as np
    def compute_conv(fm,kernel):
        [h,w]=fm.shape 
        [k,_]=kernel.shape 
        r=int(k/2)
        #定义边界填充0后的map
        padding_fm=np.zeros([h+2,w+2],np.float32)
        #保存计算结果
        rs=np.zeros([h,w],np.float32) 
        #将输入在指定该区域赋值,即除了4个边界后,剩下的区域
        padding_fm[1:h+1,1:w+1]=fm 
        #对每个点为中心的区域遍历
        for i in range(1,h+1):
            for j in range(1,w+1): 
                #取出当前点为中心的k*k区域
                roi=padding_fm[i-r:i+r+1,j-r:j+r+1]
                #计算当前点的卷积,对k*k个点点乘后求和
                rs[i-1][j-1]=np.sum(roi*kernel)
     
        return rs
     
    #填充0
    def fill_zeros(input):
        [c,h,w]=input.shape
        rs=np.zeros([c,h*2+1,w*2+1],np.float32)
        
        for i in range(c):
            for j in range(h):
                for k in range(w): 
                    rs[i,2*j+1,2*k+1]=input[i,j,k] 
        return rs
    
    def my_deconv(input,weights):
        #weights shape=[out_c,in_c,h,w]
        [out_c,in_c,h,w]=weights.shape   
        out_h=h*2
        out_w=w*2
        rs=[]
        for i in range(out_c):
            w=weights[i]
            tmp=np.zeros([out_h,out_w],np.float32)
            for j in range(in_c):
                conv=compute_conv(input[j],w[j])
                #注意裁剪,最后一行和最后一列去掉
                tmp=tmp+conv[0:out_h,0:out_w]
            rs.append(tmp)
       
        return rs 
    
     
    def main():  
        input=np.asarray(input_data,np.float32)
        input= fill_zeros(input)
        weights=np.asarray(weights_data,np.float32)
        deconv=my_deconv(input,weights)
       
        print(np.asarray(deconv))
    
    if __name__=='__main__':
        main()
    

    计算卷积代码,跟上一篇文章一致。代码直接看注释,不再解释。运行结果如下:

    [[[  4.   3.   6.   2.   7.   3.]
      [  4.   3.   3.   2.   7.   5.]
      [  8.   6.   8.   5.  11.   2.]
      [  3.   2.   7.   2.   3.   3.]
      [  5.   5.  11.   3.   9.   3.]
      [  2.   1.   4.   5.   4.   4.]]
    
     [[  4.   1.   7.   0.   7.   2.]
      [  5.   6.   0.   1.   8.   5.]
      [  8.   0.   8.  -2.  14.   2.]
      [  3.   3.   9.   8.   1.   0.]
      [  3.   0.  13.   0.  11.   2.]
      [  3.   5.   3.   1.   3.   0.]]]
    
    

    为了验证实现的代码的正确性,我们使用tensorflow的conv2d_transpose函数执行相同的输入和卷积核,看看结果是否一致。验证代码如下:

    import tensorflow as tf
    import numpy as np 
    def tf_conv2d_transpose(input,weights):
        #input_shape=[n,height,width,channel]
        input_shape = input.get_shape().as_list()
        #weights shape=[height,width,out_c,in_c]
        weights_shape=weights.get_shape().as_list() 
        output_shape=[input_shape[0], input_shape[1]*2 , input_shape[2]*2 , weights_shape[2]]
         
        print("output_shape:",output_shape)
        
        deconv=tf.nn.conv2d_transpose(input,weights,output_shape=output_shape,
            strides=[1, 2, 2, 1], padding='SAME')
        return deconv
    
    def main(): 
        weights_np=np.asarray(weights_data,np.float32)
        #将输入的每个卷积核旋转180°
        weights_np=np.rot90(weights_np,2,(2,3))
    
        const_input = tf.constant(input_data , tf.float32)
        const_weights = tf.constant(weights_np , tf.float32 )
    
        
        input = tf.Variable(const_input,name="input")
        #[c,h,w]------>[h,w,c]
        input=tf.transpose(input,perm=(1,2,0))
        #[h,w,c]------>[n,h,w,c]
        input=tf.expand_dims(input,0)
        
        #weights shape=[out_c,in_c,h,w]
        weights = tf.Variable(const_weights,name="weights")
        #[out_c,in_c,h,w]------>[h,w,out_c,in_c]
        weights=tf.transpose(weights,perm=(2,3,0,1))
       
        #执行tensorflow的反卷积
        deconv=tf_conv2d_transpose(input,weights) 
    
        init=tf.global_variables_initializer()
        sess=tf.Session()
        sess.run(init)
        
        deconv_val  = sess.run(deconv) 
    
        hwc=deconv_val[0]
        print(hwc) 
    
    if __name__=='__main__':
        main() 
    
    

    上面代码中,有几点需要注意:

    1. 每个卷积核需要旋转180°后,再传入tf.nn.conv2d_transpose函数中,因为tf.nn.conv2d_transpose内部会旋转180°,所以提前旋转,再经过内部旋转后,能保证卷积核跟我们所使用的卷积核的数据排列一致。
    2. 我们定义的输入的shape为[c,h,w]需要转为tensorflow所使用的[n,h,w,c]。
    3. 我们定义的卷积核shape为[out_c,in_c,h,w],需要转为tensorflow反卷积中所使用的[h,w,out_c,in_c]

    执行上面代码后,执行结果如下:

    [[  4.   3.   6.   2.   7.   3.]
     [  4.   3.   3.   2.   7.   5.]
     [  8.   6.   8.   5.  11.   2.]
     [  3.   2.   7.   2.   3.   3.]
     [  5.   5.  11.   3.   9.   3.]
     [  2.   1.   4.   5.   4.   4.]]
    [[  4.   1.   7.   0.   7.   2.]
     [  5.   6.   0.   1.   8.   5.]
     [  8.   0.   8.  -2.  14.   2.]
     [  3.   3.   9.   8.   1.   0.]
     [  3.   0.  13.   0.  11.   2.]
     [  3.   5.   3.   1.   3.   0.]]
    
    

    对比结果可以看到,数据是一致的,证明前面手写的python实现的反卷积代码是正确的。

    展开全文
  • 反卷积图像应用

    2018-05-10 21:45:09
    详细讲解卷积与反卷积,可以应用于图像去模糊,详细讲解了一维信号反卷积和二维信号反卷积
  • 一文搞懂反卷积,转置卷积

    万次阅读 多人点赞 2018-07-18 15:06:59
    一文搞懂反卷积,转置卷积 前言 本文翻译自《Up-sampling with Transposed Convolution》,这篇文章对转置卷积和反卷积有着很好的解释,这里将其翻译为中文,以飨国人。 如有谬误,请联系指正。转载请注明出处...

    前言

    本文翻译自《Up-sampling with Transposed Convolution》,这篇文章对转置卷积和反卷积有着很好的解释,这里将其翻译为中文,以飨国人。如有谬误,请联系指正。转载请注明出处。

    ∇ \nabla 联系方式:

    e-mail: FesianXu@gmail.com

    QQ: 973926198

    github: https://github.com/FesianXu

    知乎专栏: 计算机视觉/计算机图形理论与应用

    微信公众号
    qrcode


    用转置卷积进行上采样

    对于上采用的需求

    当我们用神经网络生成图片的时候,经常需要将一些低分辨率的图片转换为高分辨率的图片。
    lowtohigh

    对于这种上采样(up-sampling)操作,目前有着一些插值方法进行处理:

    1. 最近邻插值(Nearest neighbor interpolation)
    2. 双线性插值(Bi-Linear interpolation)
    3. 双立方插值(Bi-Cubic interpolation)

    以上的这些方法都是一些插值方法,需要我们在决定网络结构的时候进行挑选。这些方法就像是人工特征工程一样,并没有给神经网络学习的余地,神经网络不能自己学习如何更好地进行插值,这个显然是不够理想的。

    为什么是转置卷积

    转置卷积(Transposed Convolution)常常在一些文献中也称之为反卷积(Deconvolution)和部分跨越卷积(Fractionally-strided Convolution),因为称之为反卷积容易让人以为和数字信号处理中反卷积混起来,造成不必要的误解,因此下文都将称为转置卷积,并且建议各位不要采用反卷积这个称呼。

    如果我们想要我们的网络可以学习到最好地上采样的方法,我们这个时候就可以采用转置卷积。这个方法不会使用预先定义的插值方法,它具有可以学习的参数。理解转置卷积这个概念是很重要的,因为它在若干重要的文献中都有所应用,如:

    1. DCGAN中的生成器将会用随机值转变为一个全尺寸(full-size)的图片,这个时候就需要用到转置卷积。
    2. 在语义分割中,会使用卷积层在编码器中进行特征提取,然后在解码层中进行恢复为原先的尺寸,这样才可以对原来图像的每个像素都进行分类。这个过程同样需要用到转置卷积。

    卷积操作

    让我们回顾下卷积操作是怎么工作的,并且我们将会从一个小例子中直观的感受卷积操作。假设我们有一个 4 × 4 4 \times 4 4×4的矩阵,我们将在这个矩阵上应用 3 × 3 3 \times 3 3×3的卷积核,并且不添加任何填充(padding),步进参数(stride)设置为1,就像下图所示,输出为一个 2 × 2 2 \times 2 2×2的矩阵。
    这里写图片描述

    这个卷积操作在输入矩阵和卷积核中,对每个元素的乘积进行相加。因为我们没有任何填充和使用1为步进,因此我们只能对这个操作进行4次,因此我们的输出矩阵尺寸为 2 × 2 2 \times 2 2×2
    这里写图片描述
    这种卷积操作使得输入值和输出值之间存在有位置上的连接关系,举例来说,输入矩阵左上方的值将会影响到输出矩阵的左上方的值。更具体而言, 3 × 3 3 \times 3 3×3的卷积核是用来连接输入矩阵中的9个值,并且将其转变为输出矩阵的一个值的。一个卷积操作是一个多对一(many-to-one)的映射关系。让我们记住这个,我们接下来将会用得着。

    反过来操作吧

    现在,假设我们想要反过来操作。我们想要将输入矩阵中的一个值映射到输出矩阵的9个值,这将是一个一对多(one-to-many)的映射关系。这个就像是卷积操作的反操作,其核心观点就是用转置卷积。举个例子,我们对一个 2 × 2 2 \times 2 2×2的矩阵进行上采样为 4 × 4 4 \times 4 4×4的矩阵。这个操作将会维护一个1对应9的映射关系。
    这里写图片描述
    因此就结论而言,卷积操作是多对一,而转置卷积操作是一对多,如下图所示,每一个“对”而言,都需要维护一个权值。
    在这里插入图片描述

    但是我们将如何具体操作呢?为了接下来的讨论,我们需要定义一个卷积矩阵(convolution matrix)和相应的转置卷积矩阵(transposed convolution matrix)。

    卷积矩阵

    我们可以将一个卷积操作用一个矩阵表示。这个表示很简单,无非就是将卷积核重新排列到我们可以用普通的矩阵乘法进行矩阵卷积操作。如下图就是原始的卷积核:
    这里写图片描述
    我们对这个 3 × 3 3 \times 3 3×3的卷积核进行重新排列,得到了下面这个 4 × 16 4 \times 16 4×16的卷积矩阵:
    这里写图片描述

    这个便是卷积矩阵了,这个矩阵的每一行都定义了一个卷积操作。下图将会更加直观地告诉你这个重排列是怎么进行的。每一个卷积矩阵的行都是通过重新排列卷积核的元素,并且添加0补充(zero padding)进行的。
    这里写图片描述
    为了将卷积操作表示为卷积矩阵和输入矩阵的向量乘法,我们将输入矩阵 4 × 4 4 \times 4 4×4摊平(flatten)为一个列向量,形状为 16 × 1 16 \times 1 16×1,如下图所示。
    这里写图片描述

    我们可以将这个 4 × 16 4 \times 16 4×16的卷积矩阵和 1 × 16 1 \times 16 1×16的输入列向量进行矩阵乘法,这样我们就得到了输出列向量。
    这里写图片描述

    这个输出的 4 × 1 4 \times 1 4×1的矩阵可以重新塑性为一个 2 × 2 2 \times 2 2×2的矩阵,而这个矩阵正是和我们一开始通过传统的卷积操作得到的一模一样。
    这里写图片描述

    简单来说,这个卷积矩阵除了重新排列卷积核的权重之外就没有啥了,然后卷积操作可以通过表示为卷积矩阵和输入矩阵的列向量形式的矩阵乘积形式进行表达。

    所以各位发现了吗,关键点就在于这个卷积矩阵,你可以从16( 4 × 4 4 \times 4 4×4)到4( 2 × 2 2 \times 2 2×2)因为这个卷积矩阵尺寸正是 4 × 16 4 \times 16 4×16的,然后呢,如果你有一个 16 × 4 16 \times 4 16×4的矩阵,你就可以从4( 2 × 2 2 \times 2 2×2)到16( 4 × 4 4 \times 4 4×4)了,这不就是一个上采样的操作吗?啊哈!让我们继续吧!

    转置卷积矩阵

    我们想要从4( 2 × 2 2 \times 2 2×2)到16( 4 × 4 4 \times 4 4×4),因此我们使用了一个 16 × 4 16 \times 4 16×4的矩阵,但是还有一件事情需要注意,我们是想要维护一个1到9的映射关系。

    假设我们转置这个卷积矩阵 C    ( 4 × 16 ) C \ \ (4 \times 16) C  (4×16)变为 C T    ( 16 × 4 ) C^T \ \ (16 \times 4) CT  (16×4)。我们可以对 C T C_T CT和列向量 ( 4 × 1 ) (4 \times 1) (4×1)进行矩阵乘法,从而生成一个 16 × 1 16 \times 1 16×1的输出矩阵。这个转置矩阵正是将一个元素映射到了9个元素。
    这里写图片描述

    这个输出可以塑形为 ( 4 × 4 ) (4 \times 4) (4×4)的矩阵:
    这里写图片描述

    我们只是对小矩阵 ( 2 × 2 ) (2 \times 2) (2×2)进行上采样为一个更大尺寸的矩阵 ( 4 × 4 ) (4 \times 4) (4×4)。这个转置卷积矩阵维护了一个1个元素到9个元素的映射关系,因为这个关系正表现在了其转置卷积元素上。

    需要注意的是:这里的转置卷积矩阵的参数,不一定从原始的卷积矩阵中简单转置得到的,转置这个操作只是提供了转置卷积矩阵的形状而已。

    总结

    转置卷积操作构建了和普通的卷积操作一样的连接关系,只不过这个是从反向方向开始连接的。我们可以用它进行上采样。另外,这个转置卷积矩阵的参数是可以学习的,因此我们不需要一些人为预先定义的方法。即使它被称为转置卷积,它并不是意味着我们将一些现存的卷积矩阵简单转置并且使用其转置后的值。

    从本质来说,转置卷积不是一个卷积,但是我们可以将其看成卷积,并且当成卷积这样去用。我们通过在输入矩阵中的元素之间插入0进行补充,从而实现尺寸上采样,然后通过普通的卷积操作就可以产生和转置卷积相同的效果了。你在一些文章中将会发现他们都是这样解释转置卷积的,但是这个因为在卷积操作之前需要通过添加0进行上采样,因此是比较低效率的。

    注意:转置卷积会导致生成图像中出现棋盘效应(checkerboard artifacts),这篇文章《Deconvolution and Checkerboard Artifacts》推荐了一种上采样的操作(也就是插值操作),这个操作接在一个卷积操作后面以减少这种现象。如果你的主要目的是生成尽可能少棋盘效应的图像,那么这篇文章就值得你去阅读。


    补充内容

    评论区有朋友提出了一个问题,我觉得可能有些朋友也会有类似的疑问因此在这里统一讨论下,问题为:

    博主您好,我觉的转置卷积矩阵的参数随着训练过程不断被优化,但是它是在随机初始化的基础上进行优化,还是在原始卷积矩阵的基础上进行优化? – CSDN user https://me.csdn.net/BistuSim

    这个问题其实可以通过观察深度学习框架的实现方式进行,我选用的是pytorch,我们打开torch.nn.ConvTranspose1d的源码,发现有:

    class ConvTranspose1d(_ConvTransposeMixin, _ConvNd):
        def __init__(self, in_channels, out_channels, kernel_size, stride=1,
                     padding=0, output_padding=0, groups=1, bias=True, dilation=1):
            kernel_size = _single(kernel_size)
            stride = _single(stride)
            padding = _single(padding)
            dilation = _single(dilation)
            output_padding = _single(output_padding)
            super(ConvTranspose1d, self).__init__(
                in_channels, out_channels, kernel_size, stride, padding, dilation,
                True, output_padding, groups, bias)
    
        @weak_script_method
        def forward(self, input, output_size=None):
            # type: (Tensor, Optional[List[int]]) -> Tensor
            output_padding = self._output_padding(input, output_size, self.stride, self.padding, self.kernel_size)
            return F.conv_transpose1d(
                input, self.weight, self.bias, self.stride, self.padding,
                output_padding, self.groups, self.dilation)
    

    不难发现其实我们的卷积核参数weights其实是在超类中定义的,我们转到_ConvNd,代码如:

    class _ConvNd(Module):
        __constants__ = ['stride', 'padding', 'dilation', 'groups', 'bias']
        def __init__(self, in_channels, out_channels, kernel_size, stride,
                     padding, dilation, transposed, output_padding, groups, bias):
            super(_ConvNd, self).__init__()
            if in_channels % groups != 0:
                raise ValueError('in_channels must be divisible by groups')
            if out_channels % groups != 0:
                raise ValueError('out_channels must be divisible by groups')
            self.in_channels = in_channels
            self.out_channels = out_channels
            self.kernel_size = kernel_size
            self.stride = stride
            self.padding = padding
            self.dilation = dilation
            self.transposed = transposed
            self.output_padding = output_padding
            self.groups = groups
            if transposed:
                self.weight = Parameter(torch.Tensor(
                    in_channels, out_channels // groups, *kernel_size))
            else:
                self.weight = Parameter(torch.Tensor(
                    out_channels, in_channels // groups, *kernel_size))
            if bias:
                self.bias = Parameter(torch.Tensor(out_channels))
            else:
                self.register_parameter('bias', None)
            self.reset_parameters()
    

    我们可以清楚的发现,其实weights或者是bias的初始化就是一般地初始化一个符合一定尺寸要求的Tensor即可了,我们也可以发现其在forward过程中并没有所真的去根据输入进行权值的所谓“转置”之类的操作。因此我认为只要一般地进行随机初始化即可了。

    而且,我们如果同时去观察torch.nn.Conv2d的类的话,其实也可以发现,其参数都是通过_ConvNd去进行初始化的,因此Conv2dConvTranspose2D的参数初始化除了尺寸的区别,其他应该类似。


    引用

    1. A guide to convolution arithmetic for deep learning.(Vincent Dumoulin, Francesco Visin).[https://arxiv.org/abs/1603.07285]

    2. Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks.(Alec Radford, Luke Metz, Soumith Chintala)
      [https://arxiv.org/pdf/1511.06434v2.pdf]

    3. Fully Convolutional Networks for Semantic Segmentation.(Jonathan Long, Evan Shelhamer, Trevor Darrell)
      [https://people.eecs.berkeley.edu/~jonlong/long_shelhamer_fcn.pdf]

    4. Deconvolution and Checkerboard Artifacts.(Augustus Odena, Vincent Dumoulin, Chris Olah)
      [https://distill.pub/2016/deconv-checkerboard/]

    展开全文
  • 彻底搞懂CNN中的卷积和反卷积

    万次阅读 多人点赞 2019-01-05 22:37:25
    卷积和反卷积在CNN中经常被用到,想要彻底搞懂并不是那么容易。本文主要分三个部分来讲解卷积和反卷积,分别包括概念、工作过程、代码示例,其中代码实践部分主结合TensorFlow框架来进行实践。给大家介绍一个卷积...

    前言

    卷积反卷积在CNN中经常被用到,想要彻底搞懂并不是那么容易。本文主要分三个部分来讲解卷积和反卷积,分别包括概念工作过程代码示例,其中代码实践部分主结合TensorFlow框架来进行实践。给大家介绍一个卷积过程的可视化工具,这个项目是github上面的一个开源项目。
    在这里插入图片描述

    卷积和反卷积

    卷积(Convolutional):卷积在图像处理领域被广泛的应用,像滤波边缘检测图片锐化等,都是通过不同的卷积核来实现的。在卷积神经网络中通过卷积操作可以提取图片中的特征,低层的卷积层可以提取到图片的一些边缘线条等特征,高层的卷积能够从低层的卷积层中学到更复杂的特征,从而实现到图片的分类和识别。
    反卷积:反卷积也被称为转置卷积,反卷积其实就是卷积的逆过程。大家可能对于反卷积的认识有一个误区,以为通过反卷积就可以获取到经过卷积之前的图片,实际上通过反卷积操作并不能还原出卷积之前的图片,只能还原出卷积之前图片的尺寸。那么到底反卷积有什么作用呢?通过反卷积可以用来可视化卷积的过程,反卷积在GAN等领域中有着大量的应用。

    工作过程

    卷积

    在这里插入图片描述
    上图展示了一个卷积的过程,其中蓝色的图片(4*4)表示的是进行卷积的图片,阴影的图片(3*3)表示的是卷积核,绿色的图片(2*2)表示是进行卷积计算之后的图片。在卷积操作中有几个比较重要的参数,输入图片的尺寸、步长、卷积核的大小、输出图片的尺寸、填充大小
    下面用一个图来详细介绍这些参数:
    在这里插入图片描述
    输入图片的尺寸:上图中的蓝色图片(55),表示的是需要进行卷积操作的图片,在后面的公式中有 i i i来表示输入图片的尺寸。
    卷积核的大小:上图中的会移动阴影图片表示的是卷积核(4
    4),通过不同参数不同大小的卷积核可以提取到图片的不同特征,后面用 k k k表示卷积核的尺寸。
    步长:是指卷积核移动的长度,通过上图可以发现卷积核水平方向移动的步长和垂直方向移动的步长是一样的都是1,后面用 s s s表示步长。
    填充大小:是指在输入图片周围填充的圈数,通常都是用0来进行填充的,上图中蓝色图片周围两圈虚线的矩形表示的是填充的值,所以填充掉是2,后面用 p p p来表示填充大小。
    输出图片的尺寸:经过卷积操作之后获取到的图片的大小,上图的绿色图片(6*6),后面用o来表示。
    如果已知 i 、 k 、 p 、 s i、k、p、s ikps,可以求得 o o o,计算公式如下:
    o = i − k + 2 ∗ p s + 1 o=\frac{i-k+2*p}{s}+1 o=sik+2p+1

    反卷积

    在这里插入图片描述

    上图展示一个反卷积的工作过程,乍看一下好像反卷积和卷积的工作过程差不多,主要的区别在于反卷积输出图片的尺寸会大于输入图片的尺寸,通过增加padding来实现这一操作,上图展示的是一个strides(步长)为1的反卷积。下面看一个strides不为1的反卷积
    在这里插入图片描述
    上图中的反卷积的stride为2,通过间隔插入padding来实现的。同样,可以根据反卷积的 o 、 s 、 k 、 p o、s、k、p oskp参数来计算反卷积的输出 i i i,也就是卷积的输入。公式如下: i = ( o − 1 ) ∗ s + k − 2 ∗ p i=(o-1)*s+k-2*p i=(o1)s+k2p,其实就是根据上式推导出来的。

    代码示例

    为了便于大家理解卷积和反卷积工作过程,将会使用图示的方式来展示卷积和反卷积的工作过程,并利用tensorflow的卷积和反卷积函数来进行验证。

    卷积

    使用tensorflow来实现卷积的时候,主要利用tf.nn.conv2d函数来实现的,先介绍一下函数的参数
    功能说明:通过4维的input和filter来计算2维卷积

    • input:4维的tensor,需要进行卷积的矩阵
    • filter:4维的tensor,卷积核的参数,需要和input具有相同的数据类型,[filter_height,filter_width,in_channels,out_channels],其中filter_height表示卷积核的高,filter_width表示卷积核的宽,in_channels表示需要进行卷积图片的通道数,out_channels卷积之后输出的通道数
    • strides:int类型的列表,设置卷积核滑动的步长
    • padding:填充类型有"SAME"和"VALID"两种模式,当步长为1时,padding为"SAME"可以保持输出与输入的尺寸具有相同的大小。
    • use_cudnn_on_gpu:使用cudnn来加速卷积,默认是True
    • data_format:输入数据的格式,有"NHWC"和"NCHW"两种模式,默认使用的是"NHWC",表示[batch,height,width,channels],"NCHW"数据格式[batch,channels,height,width]
    • dilations:一维的list,默认是[1,1,1,1],用来设置卷积核的扩展
    • name:操作的名称

    TensorFlow提供的卷积函数padding只有"SAME""VALID"两种模式,所以输出矩阵的尺寸大小与之前的公式有所不同,下面介绍这两种模式下输出矩阵尺寸的计算公式:
    padding为SAME时 c e i l ( i / s ) ceil(i/s) ceil(i/s),其中 i i i表示输入矩阵的大小,s表示卷积核的步长,ceil函数表示向上取整。下图展示是一个padding为SAME的卷积,卷积开始的时候保证卷积核的中心位于输入矩阵角的顶点位置
    在这里插入图片描述
    padding为VALID时 c e i l ( ( i − k + 1 ) / s ) ceil((i-k+1)/s) ceil((ik+1)/s) k k k表示卷积核的尺寸。下图展示的是一个padding为VALID的卷积过程,卷积核始终都是位于输入矩阵内进行移动
    在这里插入图片描述

        x1 = tf.constant(1.0, shape=[1,4,4,3])
        x2 = tf.constant(1.0,shape=[1,6,6,3])
        kernel = tf.constant(1.0,shape=[3,3,3,1])
    
        y1_1 = tf.nn.conv2d(x1,kernel,strides=[1,2,2,1],padding="SAME")
        y1_2 = tf.nn.conv2d(x1,kernel,strides=[1,2,2,1],padding="VALID")
        y2_1 = tf.nn.conv2d(x2,kernel,strides=[1,2,2,1],padding="SAME")
        y2_2 = tf.nn.conv2d(x2,kernel,strides=[1,2,2,1],padding="VALID")
    
        sess = tf.InteractiveSession()
        tf.global_variables_initializer()
        x1,y1_1,y1_2,x2,y2_1,y2_2 = sess.run([x1,y1_1,y1_2,x2,y2_1,y2_2])
        print(x1.shape)         #(1, 4, 4, 3)
        print(y1_1.shape)       #(1, 2, 2, 1)
        print(y1_2.shape)       #(1, 1, 1, 1)
        print(x2.shape)         #(1, 6, 6, 3)
        print(y2_1.shape)       #(1, 3, 3, 1)
        print(y2_2.shape)       #(1, 2, 2, 1)
    

    下面看一个卷积的计算例子

        x1 = tf.constant([i*0.1 for i in range(16)],shape=
        	[1,4,4,1],dtype=tf.float32)
        kernel = tf.ones(shape=[3,3,1,1],dtype=tf.float32)
        conv1 = tf.nn.conv2d(x1,kernel,strides=
        	[1,1,1,1],padding="VALID")
        sess = tf.InteractiveSession()
        tf.global_variables_initializer()
        conv1 = sess.run(conv1)
        print(conv1)
    

    在这里插入图片描述
    在这里插入图片描述
    将卷积核与输入矩阵对应的位置进行乘加计算即可,对于多维输入矩阵和多维卷积核的卷积计算,将卷积后的结果进行堆叠,作为最终卷积的输出结果。

    反卷积

    tensorflow提供了tf.nn.conv2d_transpose函数来计算反卷积
    功能说明:计算反卷积(转置卷积)

    • value:4维的tensor,float类型,需要进行反卷积的矩阵
    • filter:卷积核,参数格式[height,width,output_channels,in_channels],这里需要注意output_channels和in_channels的顺序
    • output_shape:一维的Tensor,设置反卷积输出矩阵的shape
    • strides:反卷积的步长
    • padding:"SAME"和"VALID"两种模式
    • data_format:和之前卷积参数一样
    • name:操作的名称
    if __name__ == "__main__":
        x1 = tf.constant([4.5,5.4,8.1,9.0],shape=
        	[1,2,2,1],dtype=tf.float32)
        dev_con1 = tf.ones(shape=[3,3,1,1],dtype=tf.float32)
        y1 = tf.nn.conv2d_transpose(x1,dev_con1,output_shape=
        	[1,4,4,1],strides=[1,1,1,1],padding="VALID")
        sess = tf.InteractiveSession()
        tf.global_variables_initializer()
        y1,x1 = sess.run([y1,x1])
        print(y1)
        print(x1)
    

    在这里插入图片描述
    需要注意的是,通过反卷积并不能还原卷积之前的矩阵,只能从大小上进行还原,反卷积的本质还是卷积,只是在进行卷积之前,会进行一个自动的padding补0,从而使得输出的矩阵与指定输出矩阵的shape相同。框架本身,会根据你设定的反卷积值来计算输入矩阵的尺寸,如果shape不符合,则会报错。
    错误提示:InvalidArgumentError (see above for traceback): Conv2DSlowBackpropInput,这时候需要检查反卷积的参数与输入矩阵之间的shape是否符合。计算规则可以根据padding为SAME还是VALID来计算输入和输出矩阵的shape是否相符合。如上例中,根据反卷积的参数来计算输入矩阵的shape:因为padding是VALID模式,所以我们套用 c e i l ( ( i − k + 1 ) / s ) = c e i l ( ( 4 − 3 + 1 ) / 1 ) = 2 ceil((i-k+1)/s)=ceil((4-3+1)/1)=2 ceil((ik+1)/s)=ceil((43+1)/1)=2,而输入矩阵x1的shape刚好是2*2,所以符合。
    上面介绍的反卷积的stride是1,接下来看一个stride不为1的例子

        x1 = tf.constant([4.5,5.4,8.1,9.0],shape=
        	[1,2,2,1],dtype=tf.float32)
        dev_con1 = tf.ones(shape=[3,3,1,1],dtype=tf.float32)
        y1 = tf.nn.conv2d_transpose(x1,dev_con1,output_shape=
        	[1,6,6,1],strides=[1,2,2,1],padding="VALID")
        sess = tf.InteractiveSession()
        tf.global_variables_initializer()
        y1,x1 = sess.run([y1,x1])
    
        print(x1)
        print(y1)
    

    在这里插入图片描述
    需要注意的是,在进行反卷积的时候设置的stride并不是指反卷积在进行卷积时候卷积核的移动步长,而是被卷积矩阵填充的padding,仔细观察红色框内可以发现之前输入矩阵之间有一行和一列0的填充

    展开全文
  • 反卷积.ppt

    2013-03-16 21:47:16
    反卷积

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 27,406
精华内容 10,962
关键字:

反卷积