🧠 具體講解神經網絡中的轉置卷積(Transposed Convolution)
🧭 1. 轉置卷積的動機:為什么我們需要它?
標準卷積通常會降低特征圖的空間尺寸(比如從 64x64 → 32x32),這對于提取高級特征很有用。但在某些任務中,比如:
- 圖像生成(如 GAN)
- 圖像分割(如 U-Net 的解碼器)
- 上采樣(upsampling)
我們需要把特征圖的尺寸還原回來(比如從 32x32 → 64x64),而且希望這個還原是可學習的,也就是說參數可訓練。
這時候就需要 轉置卷積(也叫反卷積、fractionally strided convolution)。
🧱 2. 什么是轉置卷積?直覺理解
我們先從標準卷積的矩陣乘法視角出發來看。
標準卷積可以被視為:
y = K x y = Kx y=Kx
其中 K K K 是一個稀疏的矩陣(由卷積核擴展而來)。
那么轉置卷積就是這個線性變換的轉置矩陣乘法:
轉置卷積是:
x = K T y x = K^T y x=KTy
直覺上:
- 標準卷積:壓縮/整合信息
- 轉置卷積:擴展/重建信息
🧮 3. 數學公式和計算流程
設輸入特征圖大小為 C i n × H i n × W i n C_{in} \times H_{in} \times W_{in} Cin?×Hin?×Win?,
卷積核大小為 K × K K \times K K×K,步長為 S S S,padding 為 P P P,輸出通道數為 C o u t C_{out} Cout?。
標準卷積輸出尺寸計算:
H o u t = ? H i n + 2 P ? K S ? + 1 H_{out} = \left\lfloor \frac{H_{in} + 2P - K}{S} \right\rfloor + 1 Hout?=?SHin?+2P?K??+1
轉置卷積輸出尺寸計算:
H o u t = ( H i n ? 1 ) ? S ? 2 P + K H_{out} = (H_{in} - 1) \cdot S - 2P + K Hout?=(Hin??1)?S?2P+K
你可以看到,轉置卷積公式中是乘而不是除,所以它有上采樣的效果。
🔄 4. 轉置卷積是怎么運作的?圖示直覺(描述)
- 在輸入之間插入空格(步長為 2 就在像素間插入 1 個零)
- 在這個“稀疏圖像”上進行普通卷積
- 因為插入了零,卷積核掃描時會“擴大視野”,從而生成更大的輸出
這種方式又叫 “fractionally strided convolution”(因為它“模擬”了小于 1 的步長)
🧠 5. 與標準卷積的反向傳播的關系
這其實是轉置卷積名字的由來!
- 在實現標準卷積的 反向傳播 時,梯度傳播過程中的某一步就需要一個類似轉置卷積的操作來“還原”梯度。
- 這也是為什么 PyTorch 中
ConvTranspose2d
是Conv2d
的“梯度反向過程”的實現。
所以:
轉置卷積并不是“把卷積反過來”,而是在反向傳播中自然出現的操作。
📦 6. PyTorch 實現
import torch
import torch.nn as nn# 轉置卷積層:輸入通道3,輸出通道16,kernel_size=3,stride=2,padding=1
conv_transpose = nn.ConvTranspose2d(in_channels=3, out_channels=16, kernel_size=3, stride=2, padding=1, output_padding=1)x = torch.randn(1, 3, 32, 32)
y = conv_transpose(x)
print(y.shape) # torch.Size([1, 16, 64, 64])
注意:
output_padding 是為了調節輸出大小(因為整數除法/乘法可能不是精確反轉)
轉置卷積參數量和普通卷積一樣: C i n × C o u t × K 2 C_{in} \times C_{out} \times K^2 Cin?×Cout?×K2
🔁 7. 參數與輸出尺寸公式總結
對于 ConvTranspose2d
,輸出大小計算公式為:
H o u t = ( H i n ? 1 ) ? S ? 2 P + K + output_padding H_{out} = (H_{in} - 1) \cdot S - 2P + K + \text{output\_padding} Hout?=(Hin??1)?S?2P+K+output_padding
這里:
- H i n H_{in} Hin?:輸入高度
- S S S:stride(步長)
- P P P:padding
- K K K:kernel size(卷積核大小)
output_padding
:用于解決無法精確還原的邊界問題
🔬 8. 轉置卷積 vs 上采樣+卷積
我們也可以用非轉置卷積實現上采樣 + 卷積操作:
import torch.nn.functional as Fx = torch.randn(1, 3, 32, 32)
x_up = F.interpolate(x, scale_factor=2, mode='nearest') # 最近鄰上采樣
conv = nn.Conv2d(3, 16, kernel_size=3, padding=1)
y = conv(x_up)
區別在于:
方法 | 可學習參數 | 是否精確上采樣 | 計算效率 |
---|---|---|---|
轉置卷積 | ? 是 | ? 是 | ? 快 |
上采樣 + 卷積 | ? 是 | ? 是 | 較慢,但更可控 |
💣 9. 轉置卷積的常見問題:Checkerboard Artifacts
因為卷積核在插值時可能導致像素間不均勻的覆蓋區域,轉置卷積有時會出現“棋盤格偽影”。
🛠? 解決方式:
- 使用
上采樣 + 卷積
替代 - 使用更小的 kernel 和 stride
- 加強正則化,或使用 PixelShuffle 等替代方式
🧪 10. 實際應用:U-Net 解碼器
在 U-Net 的上采樣階段,我們希望將低分辨率特征圖還原為高分辨率(最終恢復為原圖大小)。
self.upconv = nn.ConvTranspose2d(64, 32, kernel_size=2, stride=2)
然后 concat encoder 輸出 + decoder 輸出,再繼續卷積。
轉置卷積在這一步:
- 學習“如何恢復圖像細節”
- 與 skip connection 保持 spatial 對齊
- 輸出最終的分割圖像或生成圖像