(一)转置卷积
我们之前的卷积神经网络中的卷积不会增输入的高和宽,通常要么不变,要么减半。如果我们想要增大图像只能使用padding的方法,但是padding并不是一个很好的想法,因为padding出来的值是0,是不参与计算的。而语义分割是基于像素级别的,也就是说如果我们使用普通的卷积的话,只会使得图片越来越小,然后就并不能进行很好的预测。
转置卷积是一种卷积,能够用来增加输入的宽高。同卷积不同,卷积一般是做下采样,而它通常用作上采样。
就是让输入的每一个值都和kernel做卷积,然后求和,变成想要的形状的output。有点和之前的卷积反过来差不多。如果是需要padding的话,需要增加在output上面。
(1)为什么叫做“转置”呢?
对于原来的卷积 ,可以构造出一个V,使得卷积等价于举证乘法:。这里的Y' ,X' 对应的是X,Y的向量版本。
转置卷积则等价于 ,
!!!但是转置卷积不是卷积的逆运算。在数学中反卷积才是卷积的逆运算。
(2)转置卷积的步骤
这节课的padding和stride,感觉老师讲错了。所以我补充一个教程:
【1】https://www.bilibili.com/video/BV1mh411J7U4?spm_id_from=333.337.search-card.all.click&vd_source=9e5b81656aa2144357f0dca1094e9cbe
(二)代码实现
import torch
from torch import nn
from d2l import torch as d2l
def trans_conv(x,k):
"""转置卷积"""
h,w = k.shape
y = torch.zeros((x.shape[0]+h-1,x.shape[1]+w-1))
for i in range(x.shape[0]):
for j in range(x.shape[1]):
# 元素乘以转置卷积核,结果累加
y[i:i+h, j:j+w] += x[i,j] * k
return y
x = torch.tensor([[0.,1.],[2.,3.]])
k = torch.tensor([[0.,1.],[2.,3.]])
print(trans_conv(x,k))
x = torch.tensor([[0.0,1.],[2.,3.]])
k = torch.tensor([[0.,1.],[2.,3.]])
print(trans_conv(x,k))
# 使用torch中的高级API,获得相同的结果。
x,k = x.reshape(1,1,2,2), k.reshape(1,1,2,2)
tconv = nn.ConvTranspose2d(1,1,kernel_size=2,bias=False)
tconv.weight.data = k
print(tconv(x))
# 填充,步幅和多通道
# 填充:填充为1时,即默认最外圈为填充,输出时删除第一行第一列,最后一行,最后一列
tconv = nn.ConvTranspose2d(1,1,2,padding=1,bias=False)
tconv.weight.data = k
print(tconv(x))
# 步幅为2
tconv = nn.ConvTranspose2d(1,1,2,stride=4,bias=False)
tconv.weight.data = k
print(tconv(x))
# 多通道,通道的变化是一样的
x = torch.randn((1,10,16,16))
conv = nn.Conv2d(10,20,kernel_size=6,padding=2,stride=2) # out_size = ((in_size - K + 2P) / S) +1
tconv = nn.ConvTranspose2d(20,10,kernel_size=6,padding=2,stride=2) # out_size = (in_size -1)*S-2P+k
print(tconv(conv(x)).shape) # torch.Size([1, 10, 16, 16])
print(conv(x).shape) # torch.Size([1, 20, 8, 8])
# 与矩阵乘法之间的关系
X = torch.arange(9.0).reshape(3, 3)
K = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
Y = d2l.corr2d(X, K)
Y
def kernel2matrix(K):
k, W = torch.zeros(5), torch.zeros((4, 9))
k[:2], k[3:5] = K[0, :], K[1, :]
W[0, :5], W[1, 1:6], W[2, 3:8], W[3, 4:] = k, k, k, k
return W
W = kernel2matrix(K)
W
Y == torch.matmul(W, X.reshape(-1)).reshape(2, 2)
Z = trans_conv(Y, K)
Z == torch.matmul(W.T, Y.reshape(-1)).reshape(3, 3)
网友评论