转置卷积(Transposed Convolution)—— 上采样
核心思想:每个输入像素"铺开"成一个核
普通卷积是多个输入像素合并成1个输出像素。
转置卷积反过来:1个输入像素"生成"多个输出像素。
具体例子
设定
- 输入:2×2 的特征图
- 卷积核:2×2(为了简单,实际常用 3×3)
- 步长 stride = 2
输入: 卷积核: ┌───┬───┐ ┌───┬───┐ │ a │ b │ │ w │ x │ ├───┼───┤ ├───┼───┤ │ c │ d │ │ y │ z │ └───┴───┘ └───┴───┘转置卷积的"铺砖"过程
核心操作:每个输入像素 × 整个卷积核,然后按 stride 间隔铺到输出图上。
第一步:输入像素 a 铺开
a 位于左上角,在输出图的 (0,0) 位置铺一个 2×2 的块:
列0 列1 列2 列3 ┌─────┬─────┬─────┬─────┐ 行0 │ a·w │ a·x │ │ │ ├─────┼─────┼─────┼─────┤ 行1 │ a·y │ a·z │ │ │ ├─────┼─────┼─────┼─────┤ 行2 │ │ │ │ │ ├─────┼─────┼─────┼─────┤ 行3 │ │ │ │ │ └─────┴─────┴─────┴─────┘第二步:输入像素 b 铺开
b 在输入的右边,所以向右移动 stride=2 格,在 (0,2) 位置铺:
列0 列1 列2 列3 ┌─────┬─────┬─────┬─────┐ 行0 │ a·w │ a·x │ b·w │ b·x │ ├─────┼─────┼─────┼─────┤ 行1 │ a·y │ a·z │ b·y │ b·z │ ├─────┼─────┼─────┼─────┤ 行2 │ │ │ │ │ ├─────┼─────┼─────┼─────┤ 行3 │ │ │ │ │ └─────┴─────┴─────┴─────┘第三步:输入像素 c 铺开
c 在输入的下边,向下移动 stride=2 格,在 (2,0) 位置铺:
列0 列1 列2 列3 ┌─────┬─────┬─────┬─────┐ 行0 │ a·w │ a·x │ b·w │ b·x │ ├─────┼─────┼─────┼─────┤ 行1 │ a·y │ a·z │ b·y │ b·z │ ├─────┼─────┼─────┼─────┤ 行2 │ c·w │ c·x │ │ │ ├─────┼─────┼─────┼─────┤ 行3 │ c·y │ c·z │ │ │ └─────┴─────┴─────┴─────┘第四步:输入像素 d 铺开
d 在右下角,向右下各移 2 格,在 (2,2) 位置铺:
列0 列1 列2 列3 ┌───────┬───────┬───────┬───────┐ 行0 │ a·w │ a·x │ b·w │ b·x │ ├───────┼───────┼───────┼───────┤ 行1 │ a·y │ a·z │ b·y │ b·z │ ├───────┼───────┼───────┼───────┤ 行2 │ c·w │ c·x │ d·w │ d·x │ ├───────┼───────┼───────┼───────┤ 行3 │ c·y │ c·z │ d·y │ d·z │ └───────┴───────┴───────┴───────┘关键观察
在这个例子里,没有重叠!
因为:
- 输入 2×2,核 2×2,stride=2
- 每个核铺开后刚好填满 2×2 的区域
- 四个核铺开后刚好填满 4×4,互不重叠
输出尺寸 = 输入尺寸 × stride = 2 × 2 = 4
如果核更大,就会重叠!
假设核是 3×3,输入还是 2×2,stride=2:
输入: 卷积核: ┌───┬───┐ ┌───┬───┬───┐ │ a │ b │ │w1 │w2 │w3 │ ├───┼───┤ ├───┼───┼───┤ │ c │ d │ │w4 │w5 │w6 │ └───┴───┘ ├───┼───┼───┤ │w7 │w8 │w9 │ └───┴───┴───┘a 铺开(左上角):
列0 列1 列2 列3 列4 ┌──────┬──────┬──────┬──────┬──────┐ 行0 │a·w1 │a·w2 │a·w3 │ │ │ ├──────┼──────┼──────┼──────┼──────┤ 行1 │a·w4 │a·w5 │a·w6 │ │ │ ├──────┼──────┼──────┼──────┼──────┤ 行2 │a·w7 │a·w8 │a·w9 │ │ │ ├──────┼──────┼──────┼──────┼──────┤ 行3 │ │ │ │ │ │ ├──────┼──────┼──────┼──────┼──────┤ 行4 │ │ │ │ │ │ └──────┴──────┴──────┴──────┴──────┘b 铺开(向右移 2 格):
┌──────┬──────┬──────┬──────┬──────┐ 行0 │a·w1 │a·w2 │a·w3+b·w1│b·w2 │b·w3│ ← 列2重叠了! ├──────┼──────┼──────┼──────┼──────┤ 行1 │a·w4 │a·w5 │a·w6+b·w4│b·w5 │b·w6│ ← 列2重叠了! ├──────┼──────┼──────┼──────┼──────┤ 行2 │a·w7 │a·w8 │a·w9+b·w7│b·w8 │b·w9│ ← 列2重叠了! ├──────┼──────┼──────┼──────┼──────┤ ... (c 和 d 继续往下铺,行2也会重叠)重叠区域 = 对应位置相加!
这就是棋盘格伪影的来源——重叠不均匀时,某些位置被多加或少加。
直观类比
| 普通卷积 | 转置卷积 | |
|---|---|---|
| 类比 | 把4块小瓷砖压成1块大瓷砖 | 把1块瓷砖敲碎成4块,铺到4个位置 |
| 输入→输出 | 多个→1个(合并) | 1个→多个(铺开) |
| 形象理解 | “压缩” | “膨胀” |
输出尺寸公式
输出尺寸 = (输入尺寸 - 1) × stride - 2 × padding + kernel_size + output_padding最常用配置(让输出刚好是输入的整数倍):
stride=2, kernel=3, padding=1, output_padding=1 输出 = (输入 - 1) × 2 + 1 = 输入 × 2 - 1... 不对 正确配置: stride=2, kernel=4, padding=1, output_padding=0 输出 = (2-1)×2 - 2×1 + 4 = 2 - 2 + 4 = 4 ✓ (输入2×2 → 输出4×4)实际上 PyTorch 的ConvTranspose2d会自动计算,你只需要告诉它:
in_channels,out_channelskernel_sizestridepadding
一句话总结
转置卷积 = 每个输入像素 × 卷积核,然后按 stride 间隔"铺"到输出图上,重叠的地方相加。
它不是真正的"反卷积",只是一种能放大特征图的可学习上采样方法。