首页 > 编程知识 正文

稀疏矩阵卷积,反卷积公式

时间:2023-05-05 18:28:13 阅读:131306 作者:1254

前言普通卷积(直接卷积)反卷积的形象化反卷积总结

前言

卷积反卷积,也称为反卷积。 然而,倒排卷积是目前最正规和主流的名称。 因为这个名称更恰当地描述了卷积的计算过程,其他名字容易引起误解。 在主要的深度学习框架(如TensorFlow、Pytorch和Keras )中,函数名称为conv_transpose。 所以,在学习卷积置换之前,我们一定要弄清标准名称,遇到别人进行卷积,即使是反卷积,也要纠正它,让不准确的命名早日淹没在历史长河中。

让我们先来解释一下为什么人们喜欢把反卷积称为反卷积或反卷积。 首先举个例子,使用3x3卷积核对4x4输入进行普通卷积时,会得到2x2的输出。 另一方面,反卷积在22输入通过相同3x3大小的卷积核时得到4x4的输出,这看起来像普通卷积的逆过程。 仿佛加法的逆过程是减法,乘法的逆过程是除法,自然这两个操作被认为是可逆的过程。 但实际上两者没有任何关系,操作过程也不可逆。 在这里,让我们一点一点地抽丝剥茧,深入理解卷积的思想吧。

常见的卷积(直接卷积)常见的卷积过程是众所周知的,并且可以直观地理解为彩色小窗口(卷积内核)通过将原始输入图像一步一步地移位来通过加权计算获得输出特征。 如下图所示。

但是,实际上在计算机上计算时,不是像这样按位置进行滑动计算,而是因为效率低。 计算机将卷积内核转换为等效矩阵,并将输入转换为向量。 通过输入向量和卷积核矩阵的乘法得到输出向量。 的向量整形后,可以得到我们的二维输出特性。 具体操作如下图所示。 由于我们的3x3卷积核在输入上的不同位置进行4次卷积,所以用补零的方法将卷积核分别放置在4x4矩阵的四角。 这样我们的输入就可以直接和这四个4x4的矩阵卷积,放弃了幻灯片这个操作步骤。

此外,通过减去生长向量,四个4x4卷积核esen将生长向量连接起来,如下图所示。

设向量量化图像为I I I,向量量化卷积矩阵为C C C,输出特征向量为O O O

有:

I T C=O T I^T*C=O^T ITC=OT

如下图所示。

1x16的行向量乘以16x4的矩阵,得到了1x4的行向量。 3358www.Sina.com/没错。 这就是那么反过来将一个1x4的向量乘以一个4x16的矩阵是不是就能得到一个1x16的行向量呢?的思想。

对于用于替换卷积的常见卷积操作(此处,仅考虑最简单的填充,以及stride=1的情况),卷越大使输入的数据越小。 根据卷积核的大小,步长大小的不同,输出的大小也有很大的变化。 但是,在某些情况下,需要输入较小的特征,如何输出更大尺寸的特征呢? 例如,图像语义分割往往要求最终输出的特征尺寸与原始输入尺寸相同,但在网络卷积内核化过程中特征图的尺寸逐渐变小。 在这里置换卷积会有帮助。 在数学上,置换卷积的操作也非常简单,只要将通常的卷积操作反向即可。

与上述公式相对应,有倒排卷积公式:

O T C T=I T O^T*C^T=I^T OTCT=IT

如下图所示。

需要注意的是,这两个操作并不可逆,对于相同的卷积核,经过倒排卷积操作也不会恢复到原来的数值,剩下的是

有原始的形状。
所以转置卷积的名字就由此而来,而并不是“反卷积”或者是“逆卷积”,不好的名称容易给人以误解。

形象化的转置卷积

但是仅仅按照矩阵转置形式来理解转置卷积似乎有些抽象,不像直接卷积那样理解的直观。所以我们也来尝试一下可视化转置卷积。前面说了在将直接卷积向量化的时候是将卷积核补零然后拉成列向量,现在我们有了一个新的转置卷积矩阵,可以将这个过程反过来,把16个列向量再转换成卷积核。以第一列向量为例,如下图:

这里将输入还原为一个2x2的舒心的楼房,新的卷积核由于只有左上角有非零值直接简化为右侧的形式。对每一个列向量都做这样的变换可以得到:

这是一个很有趣的结果,结合整体来看,仿佛有一个更大的卷积核在2x2大小的输入滑动。但是输入太小,每一次卷积只能对应卷积核的一部分。我们来把更大的卷积核补全,如下图:

这里和直接卷积有很大的区别,直接卷积我们是用一个“小窗户”去看一个“大世界”,而转置卷积是用一个“大窗户”的一部分去看“小世界”。这里有一点需要注意,我们定义的卷积核是左上角为a,右下角为i,但在可视化转置卷积中,需要将卷积核旋转180°后再进行卷积。由于输入图像太小,我们按照卷积核尺寸来进行补零操作,每边的补零数量显而易见是2,即3-1。这样我们就将一个转置卷积操作转换为对应的直接卷积。如下图:


总结一下将转置卷积转换为直接卷积的步骤:(这里只考虑stride=1,padding=0的情况)
设卷积核大小为k*k,输入为方形矩阵

对输入进行四边补零,单边补零的数量为k-1将卷积核旋转180°,在新的输入上进行直接卷积

对上面的结论我们在TensorFlow中验证一下。
验证实验代码:

首先调用TensorFlow的conv_transpose函数来进行转置卷积

import tensorflow as tfx = tf.reshape(tf.constant([[1,2], [4,5]],dtype=tf.float32), [1, 2, 2, 1])kernel = tf.reshape(tf.constant([[1,2,3], [4,5,6], [7,8,9]],dtype=tf.float32), [3, 3, 1, 1])transpose_conv = tf.nn.conv2d_transpose(x, kernel, output_shape=[1, 4, 4, 1], strides=[1,1,1,1], padding='VALID')sess = tf.Session()print(sess.run(x))print(sess.run(kernel))print(sess.run(transpose_conv))

输出结果如下:

tf转置卷积input: 1 2 4 5kernel: 1 2 3 4 5 6 7 8 9output: 1 4 7 6 8 26 38 27 23 62 74 48 28 67 76 45

接下来按照上面的方式,将转置卷积转换为一个等效的直接卷积

# 转换为等效普通卷积x2 = tf.reshape(tf.constant([[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 1, 2, 0, 0], [0, 0, 4, 5, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]],dtype=tf.float32), [1, 6, 6, 1])kernel2 = tf.reshape(tf.constant([[9,8,7], [6,5,4], [3,2,1]],dtype=tf.float32), [3, 3, 1, 1])conv = tf.nn.conv2d(x2,kernel2,strides=[1,1,1,1],padding='VALID')print(sess.run(x2))print(sess.run(kernel2))print(sess.run(conv))

输出结果和转置卷积相同

等效直接卷积input: 0 0 0 0 0 0补零 0 0 0 0 0 0 0 0 1 2 0 0 0 0 4 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0kernel: 9 8 7旋转180度 6 5 4 3 2 1output: 1 4 7 6输出不变 8 26 38 27 23 62 74 48 28 67 76 45

实验结果和我们的预测一致。

总结

通过这一篇文章,仔细的梳理的了转置卷积由来以及其等效的直接卷积形式。希望以后在使用转置卷积的过程中可以做到心中有数,有画面。有关其他不同参数的转置卷积还有很多,比如当stride不为1时怎么办,padding不为0时怎么办。关于这些细节的讨论建议可以去参看参考文献:https://arxiv.org/pdf/1603.07285.pdf 。这里作者做了更加详尽的讨论,这里就不赘述了。

参考

https://arxiv.org/pdf/1603.07285.pdf
https://iksinc.online/tag/transposed-convolution/
https://zhuanlan.zhihu.com/p/48501100
https://blog.csdn.net/silence2015/article/details/78649734
https://blog.csdn.net/u014722627/article/details/60574260

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。