这里我将通过一个小例子来讲述转置卷积的步骤,并通过代码来验证这个步骤的正确性。首先我们先来看看转置卷积的步骤,如下:
是不是还是懵逼的状态呢,不用急,现在就通过一个例子来讲述这个过程。首先我们假设输入特征图的尺寸为2*2大小,s=2,k=3,p=0,如下图所示:
第一步我们需要在特征图元素间填充s-1=1 行、列 0 (即填充1行0,1列0),变换后特征图如下:
第二步我们需要在输入特征图四周填充k-p-1=2 行、列0(即填充2行0,2列0),变换后特征图如下:
第三步我们需要将卷积核上下、左右翻转,得到新的卷积核【卷积核尺寸为k=3】,卷积核变化过程如下:
最后一步,我们做正常的卷积即可【注:拿第二步得到的特征图和第三步翻转后得到的卷积核做正常卷积】,结果如下:
至此我们就从完成了转置卷积,从一个2*2大小的特征图变成了一个5*5大小的特征图,如下图所示(忽略了中间步骤):
为了让大家更直观的感受转置卷积的过程,我从Github
上down了一个此过程动态图供大家参考,如下:【注:需要动态图点击☞☞☞自取】
通过上文的讲述,相信你已经对转置卷积的步骤比较清楚了。这时候你就可以试试图1中结构,看看应用上述的方法能否得到对应的结构。需要注意的是,在第一次转置卷积时,使用的参数k=4,s=1,p=0
,后面的参数都为k=4,s=2,p=1
,如下图所示:
如果你按照我的步骤试了试,可能会发出一些吐槽,这也太麻烦了,我只想计算一下经过转置卷积后特征图的的变化,即知道输入特征图尺寸以及k、s、p算出输出特征图尺寸,这步骤也太复杂了。于是好奇有没有什么公式可以很方便的计算呢?enmmm,我这么说,那肯定有嘛,公式如下图所示:
对于上述公式我做3点说明:
现在有了这个公式,大家再去试试叭。
接下来我将通过一个小实验验证上面的过程,代码如下:
import torch
import torch.nn as nn
#转置卷积
def transposed_conv_official():
feature_map = torch.as_tensor([[1, 2],
[0, 1]], dtype=torch.float32).reshape([1, 1, 2, 2])
print(feature_map)
trans_conv = nn.ConvTranspose2d(in_channels=1, out_channels=1,
kernel_size=3, stride=2, bias=False)
trans_conv.load_state_dict({"weight": torch.as_tensor([[1, 0, 1],
[1, 1, 0],
[0, 0, 1]], dtype=torch.float32).reshape([1, 1, 3, 3])})
print(trans_conv.weight)
output = trans_conv(feature_map)
print(output)
def transposed_conv_self():
feature_map = torch.as_tensor([[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 2, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0]], dtype=torch.float32).reshape([1, 1, 7, 7])
print(feature_map)
conv = nn.Conv2d(in_channels=1, out_channels=1,
kernel_size=3, stride=1, bias=False)
conv.load_state_dict({"weight": torch.as_tensor([[1, 0, 0],
[0, 1, 1],
[1, 0, 1]], dtype=torch.float32).reshape([1, 1, 3, 3])})
print(conv.weight)
output = conv(feature_map)
print(output)
def main():
transposed_conv_official()
print("---------------")
transposed_conv_self()
if __name__ == '__main__':
main()
首先我们先通过transposed_conv_official()
函数来封装一个转置卷积过程,可以看到我们的输入为[[1,2],[0,1]],卷积核为[[1,0,1],[1,1,0],[0,0,1]],采用k=3,s=2,p=0进行转置卷积【注:这些参数和我前文讲解转置卷积步骤的用例参数是一致的】,我们来看一下程序输出的结果:可以发现程序输出和我们前面理论计算得到的结果是一致的。
接着我们封装了transposed_conv_self
函数,这个函数定义的是一个正常的卷积,输入是理论第2步得到的特征图,卷积核是第三步翻转后得到的卷积核,经过卷积后输出结果如下:结果和前面的一致。
那么通过这个例子就大致证明了转置卷积的步骤确实是我们理论步骤所述。
【呼~~这部分终于讲完了,这部分参考链接如下:参考视频】
如若文章对你有所帮助,那就