一、反捲積(轉置卷積)
反捲積通常用於將低維特徵映射成高維輸入,與卷積操作的作用相反。一般反捲積只能還原圖片的大小,不能將圖片還原爲原來的圖片。反捲積操作的時候有兩種情況,分爲步長爲1和步長大於1。
1. stride = 1
- stride=1時,反捲積操作時在特徵圖周圍填充0,至於添加多少padding,就要看原圖和特徵圖的大小關係。比如原圖大小爲4 * 4 ,卷積核大小爲3 * 3,步長爲1,卷積後的特徵圖大小爲:2 * 2,那麼現在要將這個尺寸的特徵圖反捲積成4 * 4 大小,那麼先填充padding=2的0,也即添加兩圈。然後用3 * 3 卷積核進行卷積,得到了5 * 5 大小的圖片。如圖所示:
卷積操作:
反捲積操作:
2.stride > 1
- 當步長大於1時,先在周圍添加0, 然後按照步長等於1時的操作進行,如下圖所示的操作:
- 步長大於2時的反捲積操作:
3. 反捲積操作實現
from torchvision.transforms import ToTensor, ToPILImage
import torch.nn as nn
import matplotlib.pyplot as plt
from PIL import Image
# 顯示原始圖像
orginal_img = Image.open("yellow/dog.jpg")
plt.subplot(1, 3, 1)
plt.axis('off')
plt.title("orginal pic")
plt.imshow(orginal_img)
# 顯示卷積後的圖像
img = ToTensor()(orginal_img)
conv = nn.Conv2d(3, 3, 3, 1)
y = conv(img.unsqueeze(0))
conv_img = ToPILImage("RGB")(y.squeeze(0))
plt.subplot(1, 3, 2)
plt.axis('off')
plt.title("conv pic")
plt.imshow(conv_img)
#顯示反捲積後的圖像
transconv = nn.ConvTranspose2d(3, 3, 3, 1)
trans_img = transconv(y)
trans_img = ToPILImage("RGB")(trans_img.squeeze(0))
plt.subplot(1, 3, 3)
plt.axis('off')
plt.title("transconv pic")
plt.imshow(trans_img)
plt.show()
上述代碼只是簡單的展示了反捲積如何實現,它與卷積的實現方法很相似。
二、反池化
1. 反池化操作
反池化過程主要介紹兩種池化:最大池化的反池化和平均池化的反池化。
其中最大池化在反池化時要記錄最大值所在的位置,然後其餘位置用0補充,平均池化一般用鄰近元素作填充。如下圖所示:
3. 反池化操作的實現
from torchvision.transforms import ToTensor, ToPILImage
import torch.nn as nn
import matplotlib.pyplot as plt
from PIL import Image
# 顯示原始圖像
orginal_img = Image.open("yellow/dog.jpg")
plt.subplot(1, 3, 1)
plt.axis('off')
plt.title("orginal pic")
plt.imshow(orginal_img)
# 卷積層
img = ToTensor()(orginal_img)
conv = nn.Conv2d(3, 3, 3, 1)
y = conv(img.unsqueeze(0))
# 池化層,顯示池化後的圖片
"""
參數return_indices:表示返回最大值所在的位置,最大池化在進行反池化操作哦時要記錄最大值所在的位置。
"""
pool = nn.MaxPool2d(2, 2, return_indices=True)
pool_y, index = pool(y)
pool_img = ToPILImage("RGB")(pool_y.squeeze())
plt.subplot(1, 3, 2)
plt.axis('off')
plt.title("pool pic")
plt.imshow(pool_img)
# 反池化操作並顯示反池化後的圖片
unpool = nn.MaxUnpool2d(2, 2)
y = unpool(pool_y, index)
# 對比池化操作輸出的值和反池化操作輸出值的大小
print("池化後的值:", pool_y)
print("反池化後的值:", y)
unpool_img = ToPILImage("RGB")(y.squeeze())
plt.subplot(1, 3, 3)
plt.axis('off')
plt.title("unpool pic")
plt.imshow(unpool_img)
plt.show()
池化的作用:
- 減小特徵圖大小
- 降低過擬合,降低過擬合是減小輸出大小的結果,它同樣也減少了後續層中的參數的數量。
- 池化操作很暴力的丟棄了一些圖片的特徵,可以用大步長的卷積代替池化操作,這樣就可以保證圖片特徵不丟失。
三、普通上採樣
(1)最鄰近插值
最鄰近插值算法的原理:在原圖像中找到最鄰近的一個點,然後把這個點的像素值插入到目標圖像中,最近臨插值算法優點是算法簡單易於實現,但是缺點是由於相鄰像素點的像素值相同,容易出現色塊現象。
(2)雙線性插值
- 雙線性插值原理解釋
首先在Q11Q21、Q12Q22方向上進行兩次線性插值,得到R1、R2;然後在R1R2方向再做一次線性插值得到P點,這就是雙線性插值。
雙線性插值原理動圖:
圖片來源:https://www.cnblogs.com/SpiritAmos/p/11991528.html
(3) 最鄰近插值和雙線性插值的實現:
from torchvision.transforms import ToTensor, ToPILImage
import torch.nn as nn
import matplotlib.pyplot as plt
from PIL import Image
import torch.nn.functional as F
orginal_img = Image.open("yellow/dog.jpg")
plt.subplot(1, 3, 1)
plt.axis('off')
plt.title("orginal pic")
plt.imshow(orginal_img)
img = ToTensor()(orginal_img)
conv = nn.Conv2d(3, 3, 3, 1)
y = conv(img.unsqueeze(0))
trans_conv = nn.ConvTranspose2d(3, 3, 3, 1)
y = trans_conv(y)
# pool = nn.MaxPool2d(2, 2)
# pool_y = pool(y)
# 最鄰近插值,參數scale_factor 表示放大或縮小倍數
"""
以下兩種寫法都可以用F.interpolate()函數代替
upsample = nn.UpsamplingNearest2d(scale_factor=2)
upsample = nn.Upsample(scale_factor=2, mode='nearest')
"""
z1 = F.interpolate(y, scale_factor=2, mode='nearest')
near_conv_img = ToPILImage("RGB")(z1.squeeze(0))
plt.subplot(1, 3, 2)
plt.axis('off')
plt.title("nearest")
plt.imshow(near_conv_img)
# 雙線性插值,雙線性插值中參數align_corners是對齊角的意思
"""
以下兩種寫法都可以用F.interpolate()函數代替
upsample = nn.UpsamplingBilinear2d(scale_factor=2)
upsample = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)
"""
z2 = F.interpolate(y, scale_factor=2, mode='bilinear', align_corners=True)
linear_conv_img = ToPILImage("RGB")(z2.squeeze(0))
plt.subplot(1, 3, 3)
plt.axis('off')
plt.title("bilinear")
plt.imshow(linear_conv_img)
plt.show()