转置卷积

转置卷积 个人备忘总结
转置卷积
上采样方式有三种:双线性或最近邻插值、反池化和转置卷积 。现在见的比较多的是双线性和转置卷积 。在经典的FCN8中用的就是转置卷积(文中称其为反卷积) 。
特点
转置卷积顾名思义是一种卷积方式 , 只是卷积前多了个参数转置的过程 。
优点:可学习 , 理论上模型可以通过学习获取最适合当前数据集的上采样方式 。
缺点:存在棋盘效应 ,  分割边界为锯齿状 。前者可以参考国外大佬的博客 , 消除办法是将设置为的整数倍 。后者为个人经验 , 目前没找到好的解决办法 。
实现
目前在网上看到的对转置卷积实现方式的解释主要有两种 。
以前我偏向第一种解释 , 把图像和参数展成两个数组相乘 , 看着比较简单 。今天打算仔细研究一下 , 结果想了半天没想明白偶数如4*4的卷积核该怎么展开 。
那还能怎么办呢 , 叛变呗 , 第二种解释真香 。这里只讨论最基础的情形 , 即只考虑、和 , 不考虑(文献看的少 , 好像没遇到过上采样时用的) 。
先上两个公式 , 从理论上看一下:
下采样(普通卷积)
L = ( H + 2 ? p a d d i n g ? k e r n e l ) / s t r i d e + 1 L = (H + 2 *- ) /+ 1 L=(H+2??)/+1
上采样(转置卷积)
H = ( L ? 1 ) ? s t r i d e + k e r n e l ? 2 ? p a d d i n g H = (L - 1) *+- 2 *H=(L?1)?+?2?
再举个实际的简单例子 。
首先是下采样 , 为了方便 , 我们设定图片img为44 , 为44 , 为2 , 为1 。对于下采样 , 为了简单img和如下:
对img补零 , 因为为1 , 在img上下左右补一圈0 , 然后以为2滑动 , 很容易就能得到22的卷积结果:
上采样 , 我们设定img为22 , 为4*4 , 为2 , 为1 , 为了方便 , img和如下:
对img补零 , 重点来了 , 补零的依据不是 , 而是 , 并且补零是在img里边进行 , 而不是外围 。
卷积前需要先对进行转置 , 逆时针旋转180° 。
在补零后的图像上滑动 , 滑动间隔固定为1 , 与无关 , 得到一个6*6的上采样结果 。
因为为1 , 我们去掉最外围的一圈 , 得到最终的上采样结果 。
通过拆解转置卷积计算输出尺寸的公式可以清晰看到以上操作的依据
H = ( L ? 1 ) ? s t r i d e + k e r n e l ? 2 ? p a d d i n g H = (L - 1) *+- 2 *H=(L?1)?+?2?
补零:(L - 1) * 个
消融:2 * 行和列 , 即圈
验证
import torchimport torch.nn.functional as Fimport numpy as np#创建imgimg = np.array([1,2,3,4], np.float32)img = np.reshape(img, [1,1,2,2])img = torch.from_numpy(img)#创建kernelw = np.array(range(1,17),np.float32)w = np.reshape(w, [1,1,4,4])w = torch.from_numpy(w)#计算output = F.conv_transpose2d(img, w, None, 2, 1)print(output)
总结
转置卷积与普通卷积在具体实现上都是卷积运算 , 不同的是对于转置卷积:
普通卷积在图像外部补零 , 转置卷积在图像内部补零普通卷积由决定补零个数 , 转置卷积由决定补零个数转置卷积由决定最后消去的圈数
【转置卷积】PS:由于在实际使用中为随机初始化 , 所以不需要特意去关心转置的问题 。