Appearance
转置卷积
一、什么是转置卷积
之前我们学的卷积层和汇聚层,都是用来缩小输入图像的空间维度的,比如把大图片变成小图片。但在语义分割这类任务里,我们需要把缩小后的特征图恢复到和输入图片一样的尺寸,这样才能每个像素都对应一个分类结果。转置卷积就是用来做这个的,它可以把小的特征图上采样,变成更大的尺寸,相当于逆转了普通卷积的下采样操作。
二、转置卷积的基本操作
我们先从简单的情况说起,不考虑通道,步幅为 1,也没有填充。假设我们有一个 2×2 的输入张量,和一个 2×2 的卷积核。转置卷积的操作是这样的:
- 先创建一个中间张量,尺寸是 (输入高度 + 卷积核高度 -1) × (输入宽度 + 卷积核宽度 -1),也就是 (2+2-1)×(2+2-1)=3×3,初始化为 0。
- 把输入里的每个元素,乘以卷积核,然后把得到的 2×2 的张量,放到中间张量对应的位置上。比如输入里的 (0,0) 位置的元素,乘以卷积核后,放到中间张量的 (0:2, 0:2) 位置。
- 最后把所有中间结果加起来,就得到了转置卷积的输出。
简单来说,普通卷积是用卷积核 “压缩” 输入,转置卷积是用卷积核 “放大” 输入,把每个输入元素都变成一个卷积核大小的区域,然后叠加起来。
代码实现(PyTorch 版)
我们可以用简单的代码实现这个基本操作:
python
import torch
def trans_conv(X, K):
h, w = K.shape
# 创建中间张量,初始化为0
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.0, 1.0], [2.0, 3.0]])
K = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
print(trans_conv(X, K))运行结果会是一个 3×3 的张量,和我们手动计算的结果一样。
我们也可以用 PyTorch 的高级 API 来实现:
python
# 把输入和卷积核变成四维张量(批量大小,通道数,高度,宽度)
X, K = X.reshape(1, 1, 2, 2), K.reshape(1, 1, 2, 2)
# 创建转置卷积层
tconv = torch.nn.ConvTranspose2d(1, 1, kernel_size=2, bias=False)
# 设置卷积核参数
tconv.weight.data = K
# 计算转置卷积
print(tconv(X))这个结果和我们手动实现的结果是一样的。
三、填充、步幅和多通道
1. 填充
和普通卷积不一样,转置卷积的填充是应用在输出上的。比如我们设置填充为 1,就是把输出的第一行、最后一行、第一列、最后一列都去掉。
python
# 创建填充为1的转置卷积层
tconv = torch.nn.ConvTranspose2d(1, 1, kernel_size=2, padding=1, bias=False)
tconv.weight.data = K
print(tconv(X))这个结果会是一个 1×1 的张量,因为原来的 3×3 输出,去掉了一圈,就变成 1×1 了。
2. 步幅
转置卷积的步幅是设置在输出上的,步幅为 2 的话,就是在中间张量里每隔一个位置放一个结果,这样输出的尺寸会更大。
python
# 创建步幅为2的转置卷积层
tconv = torch.nn.ConvTranspose2d(1, 1, kernel_size=2, stride=2, bias=False)
tconv.weight.data = K
print(tconv(X))这个结果会是一个 4×4 的张量,比步幅为 1 的时候更大。
3. 多通道
转置卷积的多通道和普通卷积是一样的。如果输入有 c_i 个通道,每个通道都有一个卷积核;如果输出有 c_o 个通道,每个输出通道都有一个 c_i×k_h×k_w 的卷积核。
还有一个很有用的性质:如果我们用一个卷积层把 X 变成 Y,然后用一个和这个卷积层超参数一样的转置卷积层,把 Y 变回原来的尺寸,那么转置卷积的输出形状会和 X 一样。比如:
python
# 随机生成一个输入
X = torch.rand(size=(1, 10, 16, 16))
# 创建卷积层
conv = torch.nn.Conv2d(10, 20, kernel_size=5, padding=2, stride=3)
# 创建转置卷积层,超参数和卷积层一样,输出通道数是输入的通道数
tconv = torch.nn.ConvTranspose2d(20, 10, kernel_size=5, padding=2, stride=3)
# 测试一下形状
print(tconv(conv(X)).shape == X.shape) # 结果是True四、转置卷积和矩阵变换的联系
其实转置卷积可以用矩阵乘法来理解。我们可以把普通卷积的卷积核变成一个稀疏的权重矩阵 W,普通卷积的前向传播就是把输入变成向量,然后和 W 相乘。而转置卷积的前向传播,就是把输入向量和 W 的转置相乘。
反过来,普通卷积的反向传播是和 W 的转置相乘,转置卷积的反向传播是和 W 相乘。所以转置卷积相当于交换了普通卷积的前向传播和反向传播。
五、小结
转置卷积是用来上采样的,可以把小的特征图恢复到更大的尺寸,常用于语义分割等任务。
转置卷积的基本操作是把每个输入元素乘以卷积核,然后叠加到中间张量的对应位置。
转置卷积的填充是应用在输出上的,步幅是设置在输出上的,和普通卷积不一样。
转置卷积可以用矩阵乘法来理解,它的前向传播相当于普通卷积的反向传播,反向传播相当于普通卷积的前向传播。
(注:文档部分内容可能由 AI 生成) 源地址