要注意转置卷积有点类似卷积的反向传播,并不是等价于反向传播。因为转置卷积只是恢复了原图的size而没有恢复其值。
卷积
如下上图所示输入是 5 ∗ 5 5*5 5∗5的,卷积核是 3 ∗ 3 3*3 3∗3,然后pading是0,stride是1。卷积过程如第二幅图所示。根据计算公式 ( W − F + 2 P ) / S + 1 (W-F+2P)/S+1 (W−F+2P)/S+1,有 ( 5 − 3 + 2 ∗ 0 ) / 1 + 1 (5-3+2*0)/1+1 (5−3+2∗0)/1+1可以看到卷积之后结果是 3 ∗ 3 3*3 3∗3的feature map。
下面我们使用矩阵来表示这个过程,我们首先将image矩阵和feature map矩阵写成列向量形式:
[ 1 , 1 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 ] T \begin{bmatrix} 1 , 1, 1, 0,0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0 ,1 ,1, 0, 0 ,1 \end{bmatrix}^T [1,1,1,0,0,0,1,1,1,0,0,0,1,1,1,0,0,1,1,0,0,1,1,0,0,1]T
输入的size是(26,1)表示为X,多出来的1是用于bias计算用的。
[ 4 , 3 , 4 , 2 , 4 , 3 , 2 , 3 , 4 ] T \begin{bmatrix} 4, 3,4, 2, 4, 3, 2, 3, 4 \end{bmatrix}^T [4,3,4,2,4,3,2,3,4]T
feature map的size是(9,1)表示为Y
由于我们通过公式 ( W − F + 2 P ) / S + 1 (W-F+2P)/S+1 (W−F+2P)/S+1,已经知道输出Feature map的size为(9,1),所以我们将卷积核展开成size为(9,26)的稀疏矩阵:
[ 1 0 1 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 1 0 1 0 ] \begin{bmatrix} 1 &0 &1 & 0 & 0 &0 &1 & 0 &0 &0 &1 &0 &1 & 0 & 0 &0 & 0& 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 &0 \\ 0& 1 &0 &1 & 0 & 0 &0 &1 & 0 &0 &0 &1 &0 &1 & 0 & 0 &0 & 0& 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0&0& 1 &0 &1 & 0 & 0 &0 &1 & 0 &0 &0 &1 &0 &1 & 0 & 0 &0 & 0& 0 & 0 & 0 & 0 & 0 & 0 &0 \\ 0&0&0&0&0&1 &0 &1 & 0 & 0 &0 &1 & 0 &0 &0 &1 &0 &1 & 0 & 0 &0 & 0& 0 & 0 & 0 & 0 \\ 0&0&0&0&0&0&1 &0 &1 & 0 & 0 &0 &1 & 0 &0 &0 &1 &0 &1 & 0 & 0 &0 & 0& 0 & 0 & 0 \\ 0&0&0&0&0&0&0&1 &0 &1 & 0 & 0 &0 &1 & 0 &0 &0 &1 &0 &1 & 0 & 0 &0 & 0& 0 & 0\\ 0&0&0&0&0&0&0&0&0&0&1 &0 &1 & 0 & 0 &0 &1 & 0 &0 &0 &1 &0 &1 & 0 & 0 &0 \\ 0&0&0&0&0&0&0&0&0&0&0&1 &0 &1 & 0 & 0 &0 &1 & 0 &0 &0 &1 &0 &1 & 0 & 0 \\ 0&0&0&0&0&0&0&0&0&0&0&0&1 &0 &1 & 0 & 0 &0 &1 & 0 &0 &0 &1 &0 &1 & 0 \end{bmatrix} ⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡100000000010000000101000000010000000001000000000100000100010000010101000001010000000001000100000100010100010101010101010001010001000001000100000000010100000101010000010001000001000000000100000000010000000101000000010000000001000000000⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤
可以看见卷积核展成稀疏矩阵是有明显规律的。这个稀疏矩阵称为C。因此卷积的过程就可以表示为:
C X = Y CX=Y CX=Y
可以知道维度(9,26)的矩阵与维度为(26,1)的矩阵点乘得到维度为(9,1)的feature map。 那么对于转置卷积来说,其操作目的就是要使feature map还原到其原来的图像的size。所以用Y点乘C的转置刚好就回到图像的size:
C T Y = X C^TY=X CTY=X
也就是维度(26,9)与维度(9,1)点乘结果刚好为(26,1),再去掉偏置项,就回到原图size。转置卷积的过程就是这样,只不过,只是还原其size,没有还原其值。这个在Gan中常用到,这是因为Gan需要把图还原到真实的size。
为甚说有点类似卷积的反向传播,这是因为卷积网络反向传播时,梯度会从feature map这边映射会原图,所以有点类似于反向传播,但是不等同。
这里我们使用Pytorch来举个栗子:
我们有一张图片是size为(280,280)的png,灰度图像,通道数为1,转为矩阵后size为(1,280,280)。我们先对其进行卷积,然后在进行转置卷积,看看效果:
import torch
from PIL import Image
import torch.nn as nn
import numpy as np
pic=Image.open('test1.png')
pic_array=np.asarray(pic)
print('pic_array.shape:',pic_array.shape)
pic_array_re=pic_array.reshape(1,1,280,280)
print('pic_array.shape_re:',pic_array_re.shape)
pic_tensor=torch.Tensor(pic_array_re)
print('pic_tensor.shape:',pic_tensor.shape)
Cov=nn.Conv2d(1,1,4,1,0) #(inchannels,out_channels,kernel_size,stride,padding)
pic_cov=Cov(pic_tensor)
print('pic_cov.shape:',pic_cov.shape)
Cov_tran=nn.ConvTranspose2d(1,1,4,1,0)
pic_cov_tran=Cov_tran(pic_cov)
print('pic_cov_tran.shape:',pic_cov_tran.shape)
输出结果为:
pic_array.shape: (280, 280)
pic_array.shape_re: (1, 1, 280, 280)
pic_tensor.shape: torch.Size([1, 1, 280, 280])
pic_cov.shape: torch.Size([1, 1, 277, 277])
pic_cov_tran.shape: torch.Size([1, 1, 280, 280])