怎样通俗易懂地解释反卷积?

论坛 期权论坛 股票     
期权匿名问答   2023-2-1 21:17   20358   5
定义:反卷积(deconvolution)是指通过 计算 输出和已知输入 ,求 未知输入的过程。
应用1:图像识别。
应用2:可以从一组模糊的光切图像中提取出清晰的序列图像。如--AutoQuant三维反卷积软件。

知乎相关问题  --怎样通俗易懂地解释卷积?
分享到 :
0 人收藏

5 个回复

倒序浏览
2#
期权匿名回答  16级独孤 | 2023-2-1 21:18:00 发帖IP地址来自 北京
反卷积的理解

为了理解反卷积,我们先从1D的步长为2的简单卷积的例子开始:
长度为8的一维信号 ,通过长度为4的一维滤波器 进行一维卷积填充得到长度为5的一维信号 中的区域表示用0填充, 中的灰色区域表示乘以0。



长度为8的一维信号x,通过长度为4的一维滤波器f进行一维卷积填充得到长度为5的一维信号y。x中的区域表示用0填充,f中的灰色区域表示乘以0。

的灰色区域对 值并没有贡献。图1可以看出,步幅为2的卷积是一个下采样操作。
为了理解卷积与反卷积的关系,我们查看步幅为2的裁剪转置卷积:



图中长度为5的一维信号x_1通过长度为4的一维滤波器f_1进行裁剪卷积得到长度为8的一维信号y_1。y_1中的灰色区域表示裁剪。

图2说明了1维的裁剪转置卷积过程,这是一个上采样的操作。图中长度为5的一维信号 通过长度为4的一维滤波器 进行裁剪卷积得到长度为8的一维信号 中的灰色区域表示裁剪。
注意到图2的 是图一的 的转置; 由于转置矩阵,填充卷积变成了裁剪卷积。图二的整个过程相当于图一过程的反向传播,所以转置卷积又叫做反卷积。而在神经网络中,卷积层和反卷积层的梯度就由此求出:内核w定义了前向传递的矩阵 和后向转置的矩阵 , 误差是通过将损失与转置权重矩阵相乘来反向传播的。
注意图2的计算过程, 计算两次才滑动一次,步幅应该算1/2,因此反卷积又叫做分数步幅卷积。
通过以上的分析可以知道,反卷积其实就是一种特殊的卷积,完全可以用直接卷积来替代反卷积。
反卷积的推导

刚刚举了一个较为简单的例子,现在进行简单地推导。把图像展开成一维向量之后,情况就和上一节提到的一样。
假设输入图像input为4×4的矩阵:


卷积核kernel为3×3的矩阵:


在步长strides=1,填充padding=0的情况下,按卷积公式计算得输出图像尺寸为2×2。
即:


现在把input展开成列向量 ,output展开成列向量 ,则:


那么卷积操作就可以用矩阵乘法来描述:


这个权重矩阵 ,我们可以推导出来,是一个稀疏矩阵


而反卷积操作就是要通过 得到 ,则反卷积操作可以写成:


反卷积图像尺寸变化的公式:


其中,


反卷积的等效性

为了加深对反卷积的理解,给出以下几种情况以更加直观地感受反卷积,感受卷积与反卷积的等小型。

  • 无填充、单位步幅的卷积对应的反卷积
正向卷积,考虑一个3×3的核在4×4输入上的卷积,具有单位步长和无填充(如i=4,k=3,s=1和p=0)。这时会产生2×2的输出:



一个3×3的核在4×4输入上的卷积,具有单位步长和无填充(如i=4,k=3,s=1和p=0)

反向这个卷积,输入2×2时会有4×4的输出。
反向卷积可以通过使用单位步幅在2×2输入上卷积3×3的核得到2×2的输出,该输入填充有2×2零边界(如i’=2,k’=3,s’=1和p’=2):



使用单位步幅在2×2输入上卷积3×3的核得到2×2的输出,该输入填充有2×2零边界(如i’=2,k’=3,s’=1和p’=2)

可以看到,内核和步幅的大小保持不变,但反卷积的输入现在是零填充的,这时反卷积相当于填0后得到一个更大尺寸的输入,然后再正向卷积。

  • 半填充,单位步幅的卷积对应的反卷积
假设半填充卷积的输出大小与其输入大小相同,可以合理预期半填充卷积的转置的等效卷积本身就是半填充卷积。
使用半填充和单位步长(即,i=5,k=3,s=1和p=1)在5x5输入上卷积3x3内核的反向传递等效于使用半填充和单位步长(即i'=5,k'=k,s'=1和p'=1)在5x5输入上卷积3x3内核。



使用半填充和单位步长(即,i=5,k=3,s=1和p=1)在5x5输入上卷积3x3内核的转置。它等效于使用半填充和单位步长(即i'=5,k'=k,s'=1和p'=1)在5x5输入上卷积3x3内核。


  • 全填充,单位步幅的卷积对应的反卷积
知道无填充的转置等效卷积涉及全填充操作(情况1),那么也很容易推出:完全填充卷积的转置等效是非填充卷积。
使用全填充和单位步幅(即i=5,k=3,s=1和p=2)对5x5输入卷积3x3内核:



使用全填充和单位步幅(即i=5,k=3,s=1和p=2)对5x5输入卷积3x3内核:

上述操作的反向传递等效于使用单位步幅(即i'=7,k’=k,s'=1和p'=0)在7x7输入上卷积3x3内核:



使用单位步幅(即i'=7,k’=k,s'=1和p'=0)在7x7输入上卷积3x3内核


  • 无零填充、非单位步幅的卷积对应的反卷积
使用2×2步长(即i=5,k=3,s=2和p=0)在5×5输入上卷积3x3内核:



使用2×2步长(即i=5,k=3,s=2和p=0)在5×5输入上卷积3x3内核:

它的反向传递等效于在2x2输入(在输入之间插入1个零)上卷积3x3内核,使用单位步长填充2x2零边界(即,i'=2,i''=3,k'=k,s'=1且p'=2)。



在2x2输入(在输入之间插入1个零)上卷积3x3内核,使用单位步长填充2x2零边界(即,i'=2,i''=3,k'=k,s'=1且p'=2)

可以看出,通过在输入矩阵的元素间插入0使核以比单位步幅更慢的速度移动。所以反卷积又叫分数步幅卷积。
使用2x2步长(即i=5,k=3,s=2和p=1)对5x5输入填充1x1零边界的3×3内核:



使用2x2步长(即i=5,k=3,s=2和p=1)对5x5输入填充1x1零边界的3×3内核

它的反向传递相当于使用单位步幅(即,i'=3,i''=5,k'=k)在3x3输入(在输入之间插入零)上卷积3x3内核,并填充有1x1的零边界,s'=1且p'=1):



使用单位步幅(即,i'=3,i''=5,k'=k)在3x3输入(在输入之间插入零)上卷积3x3内核,并填充有1x1的零边界,s'=1且p'=1)

使用2x2步长(即,i=6,k=3,s=2和p=1)在填充有1x1零边界的6x6输入上卷积3x3的核:



使用2x2步长(即,i=6,k=3,s=2和p=1)在填充有1x1零边界的6x6输入上卷积3x3的核

它的反向传递相当于:使用单位步幅在2x2输入(在输入之间插入1个零)上卷积3x3内核,该输入填充有1x1零边界(我在底部和右侧边缘添加了一个大小的额外边界)(即,i'=3,2'=5,a=1,k'=k,s'=1且p'=1)



使用单位步幅在2x2输入(在输入之间插入1个零)上卷积3x3内核,该输入填充有1x1零边界

反卷积与棋盘伪影

棋盘伪影为什么会产生?
当内核大小(输出窗口大小)不能被步幅(顶部点之间的间距)整除时,反卷积具有不均匀的重叠


重叠图案也以二维形式形成。两个轴上的不均匀重叠相乘在一起,形成了不同大小的典型棋盘状图案:


从上图可以看出,不均匀的重叠在两个维度上往往会更加极端,因为这两个图案相乘,所以不均匀度会平方。例如,在一维中,步幅为2,大小为3的反卷积的某些输出的输入数量是其他的两倍,但在二维中,这变成了四倍。
现在,神经网络在创建图像时通常使用多层反卷积,从一系列较低分辨率的描述中迭代构建更大的图像。虽然这些堆叠的反卷积可以消除伪影,但它们通常会复合,在各种尺度上产生伪影:


如何抑制棋盘伪影?
一种方法是确保使用除以步幅的内核大小,避免重叠问题。这相当于“亚像素卷积”。然而,虽然这种方法有帮助,但反卷积仍然很容易陷入创建伪影。
另一种方法是将上采样到更高分辨率从卷积中分离出来以计算特征。例如,可以调整图像大小(使用最近邻插值或双线性插值),然后进行卷积层。


参考

https://arxiv.org/abs/1609.07009
https://arxiv.org/abs/1603.07285
https://zhuanlan.zhihu.com/p/48501100
https://distill.pub/2016/deconv-checkerboard/
https://blog.csdn.net/rotk2015/article/details/102500371
3#
期权匿名回答  16级独孤 | 2023-2-1 21:18:58 发帖IP地址来自 北京
转置卷积定义

        对于很多生成模型(如GAN中的生成器、自动编码器(Autoencoder)、语义分割等模型)。我们通常希望进行与正常卷积相反的转换,即我们希望执行上采样,比如自动编码器或者语义分割。(对于语义分割,首先用编码器提取特征图,然后用解码器回复原始图像大小,这样来分类原始图像的每个像素。)
        实现上采样的传统方法是应用插值方案或人工创建规则。而神经网络等现代架构则倾向于让网络自己自动学习合适的变换,无需人类干预。为了做到这一点,我们可以使用转置卷积。
        转置卷积在文献中也被称为去卷积(Deconvolution)或微步幅卷积(Fractionally strided convolution)。但是,需要指出去卷积这个名称并不是很合适,因为转置卷积并非信号/图像处理领域定义的那种真正的去卷积。从技术上讲,信号处理中的去卷积是卷积运算的逆运算。但这里却不是这种运算。后面我们会介绍为什么将这种运算称为转置卷积更自然且更合适。
        我们可以使用常见卷积实现转置卷积。这里我们用一个简单的例子来说明,输入层为,先进行填充值Padding为单位步长的零填充,再使用步长Stride为1的卷积核进行卷积操作则实现了上采样,上采样输出的大小为


        值得一提的是,可以通过各种填充和步长,我们可以将同样的输入映射到不同的图像尺寸。下图,转置卷积被应用在同一张的输入上(输入之间插入了一个零,并且周围加了的单位步长的零填充)上应用的卷积核,得到的结果(即上采样结果)大小为


        通过观察上述例子中的转置卷积能够帮助我们构建起一些直观的认识。但为了进一步应用转置卷积,我们还需要了解计算机的矩阵乘法是如何实现的。从实现过程的角度我们可以理解为何转置卷积才是最合适的名称。
        在卷积中,我们这样定义:用代表卷积核,为输入图像,为输出图像。经过卷积(矩阵乘法)后,我们将从大图像下采样为小图像。这种矩阵乘法实现遵循
        下面的例子展示了这种运算在计算机内的工作方式。它将输入平展()矩阵,并将卷积核转换为一个稀疏矩阵()。然后,在稀疏矩阵和平展的输入之间使用矩阵乘法。之后,再将所得到的矩阵()转为输出。


        此时,若用卷积核对应稀疏矩阵的转置)乘以输出的平展()所得到的结果()的形状和输入的形状()相同。


        但值得注意的是,上述两次操作并不是可逆关系,对于同一个卷积核(因非其稀疏矩阵不是正交矩阵),结果转置操作之后并不能恢复到原始的数值,而仅仅保留原始的形状,所以转置卷积的名字由此而来。并回答了上面提到的疑问,相比于“逆卷积”而言转置卷积更加准确。
        转置矩阵的算术解释可参考:https://arxiv.org/abs/1603.07285
1. 棋盘效应(Checkboard artifacts)

        在使用转置卷积时观察到一个棘手的现象(尤其是深色部分常出现)就是"棋盘格子状伪影",被命名为棋盘效应(Checkboard artifacts)。下图直观地展示了棋盘效应(来源:https://distill.pub/2016/deconv-checkerboard/)


        本文仅做简要介绍,详细部分请参考论文:Deconvolution and Checkerboard Artifacts
        棋盘效应是由于转置卷积的“不均匀重叠”(Uneven overlap)的结果。使图像中某个部位的颜色比其他部位更深。尤其是当卷积核(Kernel)的大小不能被步长(Stride)整除时,反卷积就会不均匀重叠。虽然原则上网络可以通过训练调整权重来避免这种情况,但在实践中神经网络很难完全避免这种不均匀重叠。
        下面通过一个详细的例子,更为直观展示棋盘效应。下图的顶部部分是输入层,底部部分为转置卷积输出结果。结果转置卷积操作,小尺寸的输入映射到较大尺寸的输出(体现在长和宽维度)。
        在(a)中,步长为1,卷积核为。如红色部分所展示,输入第一个像素映射到输出上第一个和第二个像素。而正如绿色部分,输入的第二个像素映射到输出上的第二个和第三个像素。则输出上的第二个像素从输入上的第一个和第二个像素接收信息。总而言之,输出中间部分的像素从输入中接收的信息存在重叠区域。在示例(b)中的卷积核大小增加到3时,输出所接收到的大多数信息的中心部分将收缩。但这并不是最大的问题,因为重叠仍然是均匀的。


如果将步幅改为2,在卷积核大小为2的示例中,输出上的所有像素从输入中接收相同数量的信息。由下图(a)可见,此时描以转置卷积的重叠。若将卷积核大小改为4(下图(b)),则均匀重叠区域将收缩,与此同时因为重叠是均匀的,故仍然为有效输出。但如果将卷积核大小改为3,步长为2(下图(c)),以及将卷积核大小改为5,步长为2(下图(d)),问题就出现了,对于这两种情况输出上的每个像素接收的信息量与相邻像素不同。在输出上找不到连续且均匀重叠区域。


        在二维情况下棋盘效应更为严重,下图直观地展示了在二维空间内的棋盘效应。


1.1 如何避免棋盘效应


  • 采取可以被步长整除的卷积核长度
    该方法较好地应对了棋盘效应问题,但仍然不够圆满,因为一旦我们的卷积核学习不均匀,依旧会产生棋盘效应(如下图所示)



  • 插值
    可以直接进行插值Resize操作,然后再进行卷积操作。该方式在超分辨率的相关论文中比较常见。例如我们可以用常见的图形学中常用的双线性插值和近邻插值以及样条插值来进行上采样。


2. 转置卷积的计算

输入层:
超参数:

  • 过滤器个数:
  • 过滤器中卷积核维度:
  • 滑动步长(Stride):
  • 填充值(Padding):
输出层:
(为简化计算,设,则记
其中输出层和输入层之间的参数关系分为两种情况:
情况一:

情况二:

参考资料


  • A Comprehensive Introduction to Different Types of Convolutions in Deep Learning | by Kunlun Bai | Towards Data Science
4#
期权匿名回答  16级独孤 | 2023-2-1 21:19:38 发帖IP地址来自 北京
我就尝试从工程实现的角度去解释反卷积,其实如果去读下深度学习框架的源码就可以看到,反卷积前向和后向传播的实现,恰好就是对应卷积的后向和前向传播,这里简单看下caffe反卷积层的前向实现的源码:
deconv_layer.cpp


可以看到核心计算部分其实是调用了继承自卷积层的反向传播函数:base_conv_layer.cpp


可以看到卷积的反向传播实现就是一个gemm+col2im,所以只要理解了卷积的反向传播的计算过程,那么反卷积的前向计算过程也就懂了。
下面结合卷积运算过程的示例图解释下其前向和反向传播的计算流程:


首先看到卷积的FP计算流程,假设给定卷积输入大小是 Cin * Hin * Win, 假设卷积输出通道数为Cout,卷积核空间大小 K * K,则权值大小是 Cout * Cin * K * K,然后我们知道卷积运算的一个加速方法是转换成矩阵乘法,就是把输入通过 im2col 操作转成 (Cin * K * K ) x (Hout * Wout)大小的矩阵,然后和同样把每个输出通道对应的权值拉成向量,就可以做矩阵乘法了,可以看到乘法结果就是卷积输出结果
关于im2col的解释可参考博客:
caffe im2col 详解然后看下卷积的反向传播,现在是给定输出梯度,反求输入梯度,我们知道输出梯度大小和卷积输出feature map一致,输入梯度大小和输入feature map一致,如果是3x3且步长为2的卷积且pad 为1,那么输出feature map就是大小相当于是输入的一半,那么反向传播看起来就像是把输出梯度变大到输入梯度大小的过程,是不是就和反卷积所做的事情一样了:)。
Ok,那现在来看下,卷积的反向传播怎么做的,转换成矩阵乘法之后,其求导结果和全连接层求导结果类似:
SIGAI:反向传播算法推导-全连接神经网络相当于是把权值转置一下然后和输出梯度做乘法,得到输入梯度的中间结果,看图中卷积BP部分的中间结果大小是 (Cin * K * K ) x (Hout * Wout),那怎么变成 Cin * Hin * Win 呢?还记得卷积前向是首先有个im2col操作吗,那现在就是反过来,用其逆操作col2im,把中间结果的每一列 Cin * K * K 大小的向量,reshape成 (Cin, K,K)的 tensor,然后往输入梯度对应通道的对应位置上回填累加,这里首先会把输入梯度每个位置初始化为0,回填的时候是根据步长滑动回填窗口,就和卷积前向的时候,根据步长滑动卷积窗口一样。然后就完成了把输出梯度变大到输入梯度大小的过程了。
然后理解了卷积的前向和后向计算之后,再来看反卷积就很清晰了,看到下图最下面一行反卷积的前向过程和卷积的反向过程对照来看:


这里再简单画个计算流程图展示下卷积的反向传播和反卷积的前向传播过程,假设卷积和反卷积核大小都是3x3,步长为2,卷积输入大小是4x4,现在假设需要卷积输出或反卷积输入大小是2x2,则根据卷积输出大小计算公式(( input + 2 * pad - kernel )/ stride + 1 )则需要pad 1,则现在看下如何从2x2大小的输入反推输出4x4,为了方便理解,假设权值都是1,卷积输出梯度或者反卷积输入值都是1,输入和输出通道都是1:


中间结果矩阵大小为9x4,然后把每一列reshape成 3x3 大小然后往6x6输出上累加,最后再crop出中间部分,就得到结果了。下面用mxnet简单验证下结果:
import mxnet as mx

data_shape = (1, 1, 2, 2)
data = mx.nd.ones(data_shape)

deconv_weight_shape = (1, 1, 3, 3)
deconv_weight = mx.nd.ones(deconv_weight_shape)

# deconvolution forward
data_deconv = mx.nd.Deconvolution(data=data, weight=deconv_weight,
                                      kernel=(3, 3),
                                      pad=(1, 1),
                                      stride=(2, 2),
                                      adj=(1, 1),
                                      num_filter=1)
print(data_deconv)

# convolution backward
data_sym = mx.sym.Variable('data')
conv_sym = mx.sym.Convolution(data=data_sym, kernel=(3, 3), stride=(2, 2), pad=(1, 1), num_filter=1, no_bias=True, name='conv')
executor = conv_sym.simple_bind(data=(1, 1, 4, 4), ctx=mx.cpu())
mx.nd.ones((1, 1, 3, 3)).copyto(executor.arg_dict['conv_weight'])
executor.backward(mx.nd.ones((1, 1, 2, 2)))

print(executor.grad_dict['data'])从下图结果可以看到打印出的反卷积前向结果和卷积的反向结果与上面计算流程图中的结果一致:



相关资料:
反卷积和上采样+卷积的区别?
5#
期权匿名回答  16级独孤 | 2023-2-1 21:19:56 发帖IP地址来自 北京
阅读本文的基础,是默认已经理解了图像处理中正向卷积的过程(卷积特征提取 - UFLDL)。
什么是反卷积?



  • 上采样(Upsample)
在应用在计算机视觉的深度学习领域,由于输入图像通过卷积神经网络(CNN)提取特征后,输出的尺寸往往会变小,而有时我们需要将图像恢复到原来的尺寸以便进行进一步的计算(e.g.:图像的语义分割),这个采用扩大图像尺寸,实现图像由小分辨率到大分辨率的映射的操作,叫做上采样(Upsample)。


  • 反卷积(Transposed Convolution)
上采样有3种常见的方法:双线性插值(bilinear),反卷积(Transposed Convolution),反池化(Unpooling),我们这里只讨论反卷积。这里指的反卷积,也叫转置卷积,它并不是正向卷积的完全逆过程,用一句话来解释:
反卷积是一种特殊的正向卷积,先按照一定的比例通过补 来扩大输入图像的尺寸,接着旋转卷积核,再进行正向卷积。
反卷积的数学推导


  • 正向卷积的实现过程
假设输入图像 尺寸为 ,元素矩阵为:


卷积核 尺寸为 ,元素矩阵为:


步长 ,填充 ,即
则按照卷积计算公式 ,输出图像 的尺寸为


  • 用矩阵乘法描述卷积
的元素矩阵展开成一个列向量


把输出图像 的元素矩阵展开成一个列向量


对于输入的元素矩阵 和 输出的元素矩阵 ,用矩阵运算描述这个过程:


通过推导,我们可以得到稀疏矩阵

反卷积的操作就是要对这个矩阵运算过程进行逆运算,即通过 得到 ,根据各个矩阵的尺寸大小,我们能很轻易的得到计算的过程,即为反卷积的操作:


但是,如果你代入数字计算会发现,反卷积的操作只是恢复了矩阵 的尺寸大小,并不能恢复 的每个元素值,本文最后会在 tensorflow 平台进行这个实验。

在此之前,我们先给出反卷积图像尺寸变化的公式。


  • 反卷积的输入输出尺寸关系
在进行反卷积时,简单来说,大体上可分为以下两种情况:

Relationship 1:

此时反卷积的输入输出尺寸关系为:



如上图所示,我们选择一个输入 尺寸为 ,卷积核 尺寸为 ,步长 ,填充 ,即 ,则输出 的尺寸为

Relationship 2:

此时反卷积的输入输出尺寸关系为:




如上图所示,我们选择一个输入 的尺寸为 ,卷积核 的尺寸为 ,步长 ,填充 ,即 ,则输出 的尺寸为


  • 反卷积在 FCN 中的应用
在图像语义分割网络 FCN-32s 中,上采样反卷积操作的输入每张图像的尺寸是 ,我们希望进行一次上采样后能恢复成原始图像的尺寸 ,代入公式:


根据上式,我们可以得到一个关于 三者之间关系的等式:


通过实验,最终找出了最合适的一组数据:
在 tensorflow 中实现反卷积



  • 反卷积的具体计算步骤
下面我们用一组实验更直观的解释一下在 tensorflow 中反卷积的过程:
我们令输入图像为:


卷积核为:


case 1
如果要使输出的尺寸是 ,步数 ,tensorflow 中的命令为:
transpose_conv = tf.nn.conv2d_transpose(value=input,
                                        filter=kernel,
                                        output_shape=[1,5,5,1],
                                        strides=2,
                                        padding='SAME')
当执行 transpose_conv 命令时,tensorflow 会先计算卷积类型、输入尺寸、步数和输出尺寸之间的关系是否成立,如果不成立,会直接提示错误,如果成立,执行如下操作:

1. 现根据步数 对输入的内部进行填充,这里 可以理解成输入放大的倍数,即在 的每个元素之间填充 的个数 的关系为:


例如这里举例的 ,即在 的每个元素之间填


因为卷积类型为 same,所以此时,

2. 接下来,用卷积核 对填充后的输入 进行步长 的正向卷积,根据正向卷积输出尺寸公式: 得到输出尺寸是 ,反卷积公式中我们给出的输出尺寸参数 也是为 ,两者相同,所以可以进行计算,结果为:


与 tensorflow 的运行结果相同。

case 2
我们将 case 1 中的输出尺寸 改成 ,其他参数均不变,tensorflow 中的命令为:
transpose_conv = tf.nn.conv2d_transpose(value=input,     
                                        filter=kernel,     
                                        output_shape=[1,6,6,1],   
                                        strides=2,         
                                        padding='SAME')
卷积类型是 same,我们首先在外围填充一圈


这时发现,填充后的输入尺寸与 的卷积核卷积后的输出尺寸是 ,没有达到 ,这就需要继续填充 ,tensorflow 的计算规则是优先在左侧和上侧填充一排 ,填充后的输入变为:


接下来,再对这个填充后的输入与 的卷积核卷积,结果为:


与 tensorflow 的运行结果相同。



  • 反卷积只能恢复尺寸,不能恢复数值
最后,我们要验证一下前文中提到的“如果你代入数字计算会发现,反卷积的操作只是恢复了矩阵 的尺寸大小,并不能恢复 的每个元素值”。

1. 正向卷积:
value = tf.reshape(tf.constant([[1., 2., 3.],              
                                [4., 5., 6.],                                   
                                [7., 8., 9.]]),                     
                   [1, 5, 5, 1])   

filter = tf.reshape(tf.constant([[1., 0.],                                    
                                 [0., 1.]]),                       
                    [2, 2, 1, 1])   

output = tf.nn.conv2d(value, filter, [1, 2, 2, 1], 'SAME')
卷积的结果是:


2. 我们用和正向卷积完全相同的参数对这个结果进行反卷积:
input = tf.reshape(tf.constant([[6., 8., 3.],            
                                [12., 14., 6.],         
                                [7., 8., 9.]]),        
                   [1, 3, 3, 1])   

kernel = tf.reshape(tf.constant([[1., 0.],      
                                 [0., 1.]]),        
                    [2, 2, 1, 1])   

output = tf.nn.conv2d_transpose(value=input,   
                                filter=kernel,  
                                output_shape=[1, 3, 3, 1],   
                                strides=[1, 2, 2, 1],   
                                padding='SAME')
卷积的结果是:


可见,反卷积不能恢复数值,而且,在当 时,即便使用完全相同的参数进行转置卷积,输入的尺寸也不能恢复。
6#
期权匿名回答  16级独孤 | 2023-2-1 21:20:20 发帖IP地址来自 福建
如果知友是想了解卷积神经网络里涉及的 transposed convolution,请参见其他答主的优秀答案。本答案针对的是 deconvolution,即卷积的逆操作,比如:如何使运动模糊的图像通过 deconvolution 变得清晰。
卷积(convolution)的英文释义还有纠缠、绕在一起的意思。一般用二元符号 表示,有时也会看到 甚至 ,主要是为了区别于不同语境中的其他符号。给定函数 ,令

就是 “纠缠”在一起的结果,是一个新函数。在后文中, 就偷懒不写了,但心里一定要做到有数:信号是关于时间的一个函数,可连续可离散;如果放到图像处理,那么每幅图片都是关于空间位置的一个函数,函数值就是亮暗或颜色。
一般来说,在信号处理的语境下,我们把 看作原信号,把 看作卷积核(或称冲激响应), 则称为响应;反卷积就是根据响应和冲激响应,反推回原信号。在图像处理中, 可以是原图片,通过用一个高斯核 卷积得一个糊化图像 ;同理,也可以根据糊化图像和所用的卷积核,逆推回原先的清晰图像。需要注意的是:如果仅从数学定义出发,卷积操作是对称的,即 ,我们并不能说谁被谁“卷”了。至于谁是原信号,谁是卷积核,原则上并不重要。
反卷积操作就是在已知 (或 )的情况下,反推出 (或 )。写下来就是:

我们姑且把 这个符号称为“卷除”,即卷积操作的逆操作。反卷积无非就是如何具体运算 了。这里大致列出三种思路,理解难度从易到难。

  • 长除法(long division)。谢谢 @章小林 提醒,MATLAB 中 deconv() 函数运用的便是长除法。理解长除法为什么可行并不难,可以设定一个简单例子:如 , 卷积求 ,再用 做长除法。能来关注这个问题的知友,九九成便可以在手算过程中完全理解了。长除法的优点还包括计算快,经优化后的复杂度应该是 级别的,其中 ,且 分别代表 的(有效)序列长度。长除法的缺点也很明显,如果信号是定义在实数这样的连续统上的话,长除法就无施展余地了,因为它蕴涵了信号必须“可数”的假设。好在计算机本身也只能处理序列,不光可数,还有限!MATLAB 用长除法计算反卷积是绝对没有问题的。
  • 傅里叶变换(Fourier transform)。对于熟悉 FT 的知友,理解如何用 FT 来实现反卷积,甚至比长除法还简单。本质思路是:把 通过 同态映射到 上,这里 代表所有信号的集合(i.e. ), 代表 FT。其中,最巧妙的就是 ,它直接对应了乘法,真真正正的乘法,不再是卷积。如此一来,它的逆也就是真真正正的除法。这一对应关系有一个响亮的名字唤作“卷积定理”,具体内容已在原回答中展开。

    假设我们用上快速傅里叶变换算法,其算法复杂度也应当在 。与长除法相比,优劣只能靠实践得知了。本人更倾向于长除法,因为 FT 必须对两条序列各做一次,况且计算中引入了复数,而复数运算的开销显然要更多。
  • 线性算子。我们总是说卷积是线性操作,如果正真理解了这一点,很多烧脑的数学概念将一目了然。我们可以把 看作



    对应的线性算子。如此一来:



    我们仅需知道该线性算子的逆就可以了。在离散情况下, 就是一个矩阵和其对应的逆矩阵, 即是 的矩阵乘法。

    再拓展一点,傅立叶变换 FT 本身也对应一个线性算子 ,上面提到的卷积定理本质上就是说:



    常见的线性算子还有积分 ,微分 ,多元微分 ,散度 ,拉普拉斯 等等。更多内容可以在学习泛函时涉及到。
以下为原答案:
如果题主有傅里叶变换的知识背景,反卷积是一个“很显然”(万恶的显然二字 XD)的操作。怎样通俗易懂地解释卷积? 这个知乎问题的高票答主们很喜欢挨老板揍,那我也来举这样的例子。。。
以一百天为限,已知小明分别在第10,第50和第55天挨了屁股。。。就是下图,我们可以把这个叫做源信号或者信号系统的输入,也就是三个冲击。



图一,啥时候挨屁股(系统输入 x[n])

另知,每次挨打后,迅速肿起一公分高度,然后慢慢消肿,如下图。。。信号处理中又作冲击响应



图二,挨单次屁股以后,消肿的过程(冲激响应 h[n])

从图中看,消肿是挺慢的。。。现在,两个序列做卷积,得到这个,叫做信号系统的输出



图三,序列一与序列二的卷积,100天里屁股的状况(系统输出 y[n])

注意,两个100位序列卷积的长度应该是 100+100-1 = 199,我只是把后面99位擦了,反正也接近零,无所谓。上图 x 轴是时间,以天为单位;y 轴是肿的高度,以厘米为单位。可以看到在第55天肿最高,都过1.2公分了,因为在第50天打的还没完全消。。。
关键来了,已知图一、图二,卷积得图三。那么,只知道图二、图三,怎么反过来得图一?也就是知道系统输出和冲击响应,怎么得到系统输入?
我举的这个例子,明眼人一下就能看出来系统输入原来的样子,不就是挨三次屁股嘛。但如果冲击响应复杂一点,就可能没有那么显然了。
假设题主不清楚啥是傅里叶变换,没关系,现在我给你一个黑盒儿叫 DFT,用就是了。功能如下

  • 把一个长度为 的序列,记 ,丢进 DFT 黑盒,得到另一个等长序列,记 (注:懂傅里叶的朋友求别拍,我知道频域序列的下标不该继续使用时域下标)
    表达式: ,同理,
  • 很关键。 号代表卷积, 就是正常的按位乘法)。这就是所谓的,时域卷积对应频域乘积
再你个黑盒叫 IDFT,I 代表 inverse,意思就是 DFT 黑盒的反操作。作用呢就是

  • 。或者说, ,一去一回,啥都没变。同理,
有了上面两个黑盒,我们就能通过图二、图三序列求对应的图一序列了。
既然,
那么,
做一个小小的代数操作就有
IDFT 黑盒登场就有
即,
好了,根据图二冲激响应 和图三系统输出 ,用两次 DFT 黑盒,一次除法,一次 IDFT 黑盒,我们就得到了所需要知道的图一系统输入 因为这相当于把两个卷积在一起的序列再次分开,所以命名反卷积 XD。
如果用 Matlab 的话,对应的代码也只需要一行。
x = ifft(fft(y)./fft(h));
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:399232
帖子:79847
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP