網站建設合同 免責聲明怎么推廣自己的公司
目錄
- 1. 從全連接層到卷積層
- 2. 圖像卷積
- 2.1 互相關運算
- 2.2 卷積層
- 2.3 圖像中目標的邊緣檢測
- 2.4 學習卷積核
- 2.5 特征映射和感受野
- 3. 填充和步幅
- 3.1 填充
- 3.2 步幅
- 4. 多輸入多輸出通道
- 4.1 多輸入通道
- 4.2 多輸出通道
- 4.3 1×1卷積核
- 5. 匯聚層
- 5.1 最大匯聚層和平均匯聚層
- 5.2 填充和步幅
- 5.3 多個通道
1. 從全連接層到卷積層
- 多層感知機對圖像處理是百萬維度,模型不可實現(xiàn)。
- 如果要在圖片中找到某個物體,尋找方法應該和物體位置無關。
適合計算機視覺的神經網絡架構:
- 平移不變性:不管檢測對象出現(xiàn)在圖像中的哪個位置,神經網絡前幾層應該對相同圖像區(qū)域有相似的反應。
- 局部性:神經網絡的前面幾層應該只探索輸入圖像中的局部區(qū)域,而不過度在意圖像中相隔較遠區(qū)域的關系。
2. 圖像卷積
2.1 互相關運算
嚴格來說,卷積層所表達的運算其實是互相關運算。
不同顏色所選的區(qū)域與同一個卷積核做互相關運算,最后得到輸出。
同理,卷積核滑動進行互相關運算。最終得到高度為2,寬度為2的輸出。
輸出大小:
"""定義corr2d函數(shù):1、該函數(shù)接受輸入張量X和卷積核張量K,并返回輸出張量Y2、輸出大小 = 輸入大小n(k)×n(w) - 卷積核大小k(h)×k(w)3、即:(n(k)-k(h)+1) × (n(w)-k(w)+1 )
"""
import torch
from torch import nn
from d2l import torch as d2ldef corr2d(X, K): #@save"""計算二維互相關運算"""# 卷積核的高度h和寬度w,K指卷積核Kernelh, w = K.shape# 設置輸出Y的大小,用0進行填充Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))# 對局部區(qū)域做互相關運算for i in range(Y.shape[0]):for j in range(Y.shape[1]):Y[i, j] = (X[i:i + h, j:j + w] * K).sum()return Y
對上圖進行驗證
2.2 卷積層
定義卷積層Conv2D:
- 卷積層對輸入和卷積核權重進行互相關運算;
- 并在添加標量偏置之后產生輸出。
"""定義卷積層Conv2D:1、卷積層對輸入和卷積核權重進行互相關運算;2、并在添加標量偏置之后產生輸出。
"""
class Conv2D(nn.Module):def __init__(self, kernel_size):super().__init__()# 設置權重self.weight = nn.Parameter(torch.rand(kernel_size))# 設置偏置self.bias = nn.Parameter(torch.zeros(1))# corr2d(X, K)def forward(self, x):return corr2d(x, self.weight) + self.bias
2.3 圖像中目標的邊緣檢測
# 卷積層的一個簡單應用:通過找到像素變化的位置,來檢測圖像中不同顏色的邊緣。
# 1、構造一個6×8像素的黑白圖像
X = torch.ones((6, 8))
X[:, 2:6] = 0
X
# 2、我們構造一個高度為1、寬度為2的卷積核K(水平相鄰元素相同輸出為0)
K = torch.tensor([[1.0, -1.0]])Y = corr2d(X, K)
Y
2.4 學習卷積核
"""由X生成Y的卷積核:1、構造一個卷積層,并將其卷積核初始化為隨機張量;2、在每次迭代中,比較Y與卷積層輸出的平方誤差,然后計算梯度來更新卷積核;3、使用內置的二維卷積層,并忽略偏置。
"""
# 構造一個二維卷積層,它具有1個輸出通道和形狀為(1,2)的卷積核
conv2d = nn.Conv2d(1, 1, kernel_size=(1, 2), bias=False)# 這個二維卷積層使用四維輸入和輸出格式(批量大小、通道、高度、寬度),
# 其中批量大小和通道數(shù)都為1
X = X.reshape((1, 1, 6, 8))
Y = Y.reshape((1, 1, 6, 7))
lr = 3e-2 # 學習率# 進行訓練,輪數(shù)為10。計算梯度并進行更新,輸出loss
for i in range(10):# 定義損失函數(shù):交叉熵損失Y_hat = conv2d(X)l = (Y_hat - Y) ** 2# 梯度置零conv2d.zero_grad()l.sum().backward()# 迭代卷積核# 梯度更新:w = w - lr * w'conv2d.weight.data[:] -= lr * conv2d.weight.grad# 每隔2輪輸出一次if(i + 1) % 2 ==0:print(f'epoch{i+1}, loss{l.sum():.3f}')
這里可以看到學習的卷積核接近之前邊緣檢測的卷積核。
2.5 特征映射和感受野
- 輸出的卷積層有時被稱為特征映射。
- 在卷積神經網絡中,對于某一層的任意元素x,其感受野是指在前向傳播期間可能影響x計算的所有元素。
3. 填充和步幅
- 問題一:應用了連續(xù)卷積,最終得到的輸出遠小于輸入大小,使得原始圖像的邊界丟失了許多有用信息,我們希望輸入大小和輸出大小相同?
解決:填充:在輸入圖像的邊界填充元素(通常填充元素是0)- 問題二:有時原始的輸入分辨率十分冗余,我們可能希望大幅降低圖像的寬度和高度?
解決:步幅:設置卷積核滑動的步幅來減少采樣次數(shù)- 問題三:卷積核為什么一般選擇奇數(shù)?
解決:保持空間維度的同時,我們可以在頂部和底部填充相同數(shù)量的行,在左側和右側填充相同數(shù)量的列。
3.1 填充
填充(padding):在輸入圖像的邊界填充元素(通常填充元素是0)
"""填充:1、輸入給定8×8,輸出要求8×82、卷積核的大小為3×3,所有側邊填充1個像素
"""
import torch
from torch import nn# 為了方便起見,我們定義了一個計算卷積層的函數(shù)。
# 此函數(shù)初始化卷積層權重,并對輸入和輸出提高和縮減相應的維數(shù)
def comp_conv2d(conv2d, X):# 這里的(1,1)表示批量大小和通道數(shù)都是1X = X.reshape((1, 1) + X.shape)Y = conv2d(X)# 省略前兩個維度:批量大小和通道(1, 1, 8, 8)return Y.reshape(Y.shape[2:])conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1)
X = torch.rand(size=(8, 8))
print(X)
print(conv2d)
print(comp_conv2d(conv2d, X))
comp_conv2d(conv2d, X).shape
# 卷積核為5×3時,為了使輸入和輸出相同,高度填充2,寬度填充1
conv2d = nn.Conv2d(1, 1, kernel_size=(5, 3), padding=(2, 1))
comp_conv2d(conv2d, X).shape
3.2 步幅
步幅(stride):每次滑動元素的數(shù)量
"""步幅:1、每次滑動元素的數(shù)量;2、為了高效計算或是縮減采樣次數(shù),卷積窗口可以跳過中間位置,每次滑動多個元素。
"""
# 將高度和寬度的步幅設置為2,從而將輸入的高度和寬度減半
# (8 + 2 - 3) / 2 = 4
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
comp_conv2d(conv2d, X).shape
4. 多輸入多輸出通道
4.1 多輸入通道
當輸入包含多個通道時,需要構造一個與輸入數(shù)據具有相同輸入通道數(shù)的卷積核,以便與輸入數(shù)據進行互相關運算。
import torch
from d2l import torch as d2ldef corr2d_multi_in(X, K):# 先遍歷“X”和“K”的第0個維度(通道維度),再把它們加在一起return sum(d2l.corr2d(x, k) for x, k in zip(X, K))# 構造輸入張量X和核張量K,以驗證互相關運算的輸出
X = torch.tensor([[[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]],[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]])
K = torch.tensor([[[0.0 ,1.0], [2.0, 3.0]],[[1.0, 2.0], [3.0, 4.0]]])corr2d_muti_in(X, K)
4.2 多輸出通道
多輸出通道:
- 在最流行的神經網絡架構中,隨著神經網絡層數(shù)的加深,我們常會增加輸出通道的維數(shù),通過減少空間分辨率以獲得更大的通道深度。
- 將每個通道看作對不同特征的響應。
# 實現(xiàn)一個計算多個通道的輸出的互相關函數(shù)
def corr2d_multi_in_out(X, K):# 迭代“K”的第0個維度,每次都對輸入“X”執(zhí)行互相關運算。# 最后將所有結果都疊加在一起return torch.stack([corr2d_multi_in(X, k) for k in K], 0)# 通過將核張量K與K+1(K中每個元素加1)和K+2連接起來,構造了一個具有3個輸出通道的卷積核。
K = torch.stack((K, K + 1, K + 2), 0)# (輸出通道數(shù),輸入通道數(shù),高度,寬度)
K.shape
4.3 1×1卷積核
- 1×1卷積核被經常用來改變通道,相當于全連接層
- 可以對輸入和輸出的形狀進行調整
# 使用全連接層實現(xiàn)1×1卷積
def corr2d_multi_in_out_1x1(X, K):c_i, h, w = X.shape# K:(輸出通道,輸入通道,高度,寬度)c_o = K.shape[0]X = X.reshape((c_i, h * w))K = K.reshape((c_o, c_i))# 全連接層中的矩陣乘法Y = torch.matmul(K, X)return Y.reshape((c_o, h, w))X = torch.normal(0, 1, (3, 3, 3))
K = torch.normal(0, 1, (2, 3, 1, 1))Y1 = corr2d_multi_in_out_1x1(X, K)
Y2 = corr2d_multi_in_out(X, K)
assert float(torch.abs(Y1 - Y2).sum()) < 1e-6
print(Y1)
print(Y2)
5. 匯聚層
通過逐漸聚合信息,生成越來越粗糙的映射,最終實現(xiàn)學習全局表示的目標,同時將卷積圖層的所有優(yōu)勢保留在中間層。
匯聚(pooling)層(也叫做池化層):
- 降低卷積層對位置的敏感性
- 降低對空間降采樣表示的敏感性
5.1 最大匯聚層和平均匯聚層
匯聚層與卷積層的原理大體相似,只不過把互相關運算換成求最大值或者求平均值
# 最大匯聚層和平均匯聚層
"""定義匯聚層:1、設置匯聚層與輸出的大小2、設置模式:大匯聚層和平均匯聚層
"""
import torch
from torch import nn
from d2l import torch as d2l# 默認為最大匯聚層
def pool2d(X, pool_size, mode='max'):# 獲取匯聚層的高度和寬度p_h, p_w = pool_size# 設置輸出層Y的高度和寬度Y = torch.zeros((X.shape[0] - p_h + 1, X.shape[1] - p_w + 1))# 進行遍歷,相當于對矩陣的局部區(qū)域[i:i+p_h, j:j+p_w]求最大值/平均值for i in range(Y.shape[0]):for j in range(Y.shape[1]):if mode == 'max':Y[i, j] = X[i: i + p_h, j: j + p_w].max()if mode == 'avg':Y[i, j] = X[i: i + p_h, j: j + p_w].mean()return Y# 構建輸入張量X,驗證二維最大匯聚層輸出
X = torch.tensor([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
print(X)
print('最大匯聚層:\n', pool2d(X, (2, 2)))
print('平均匯聚層:\n', pool2d(X, (2, 2), 'avg'))
# print(f'最大匯聚層:{'\n'+pool2d(X, (2, 2))}')
# print(f'平均匯聚層:{pool2d(X, (2, 2), 'avg')}')
5.2 填充和步幅
與卷積層一樣,匯聚層也可以改變輸出形狀
# 構造了一個輸入張量X,它有四個維度,其中樣本數(shù)和通道數(shù)都是1
X = torch.arange(16, dtype=torch.float32).reshape((1, 1, 4, 4))
X
5.3 多個通道
多個通道:
- 在處理多通道輸入數(shù)據時,匯聚層在每個輸入通道上單獨運算,而不是像卷積層一樣在通道上對輸入進行匯總
- 匯聚層的輸出通道數(shù)與輸入通道數(shù)相同。
"""多個通道:1、在處理多通道輸入數(shù)據時,匯聚層在每個輸入通道上單獨運算,而不是像卷積層一樣在通道上對輸入進行匯總。2、匯聚層的輸出通道數(shù)與輸入通道數(shù)相同。
"""
X = torch.cat((X, X + 1), 1)
X
pool2d = nn.MaxPool2d(3, padding=1, stride=2)
pool2d(X)