卷積神經(jīng)網(wǎng)絡(luò)基礎(chǔ)
本節(jié)我們介紹卷積神經(jīng)網(wǎng)絡(luò)的基礎(chǔ)概念,主要是卷積層和池化層铭若,并解釋填充洪碳、步幅、輸入通道和輸出通道的含義叼屠。
二維卷積層
本節(jié)介紹的是最常見的二維卷積層瞳腌,常用于處理圖像數(shù)據(jù)。
二維互相關(guān)運(yùn)算
二維互相關(guān)(cross-correlation)運(yùn)算的輸入是一個(gè)二維輸入數(shù)組和一個(gè)二維核(kernel)數(shù)組镜雨,輸出也是一個(gè)二維數(shù)組嫂侍,其中核數(shù)組通常稱為卷積核或過濾器(filter)。卷積核的尺寸通常小于輸入數(shù)組,卷積核在輸入數(shù)組上滑動(dòng)挑宠,在每個(gè)位置上菲盾,卷積核與該位置處的輸入子數(shù)組按元素相乘并求和,得到輸出數(shù)組中相應(yīng)位置的元素各淀。圖1展示了一個(gè)互相關(guān)運(yùn)算的例子懒鉴,陰影部分分別是輸入的第一個(gè)計(jì)算區(qū)域、核數(shù)組以及對(duì)應(yīng)的輸出碎浇。
下面我們用corr2d函數(shù)實(shí)現(xiàn)二維互相關(guān)運(yùn)算临谱,它接受輸入數(shù)組X與核數(shù)組K,并輸出數(shù)組Y奴璃。
import torch
import torch.nn as nn
def corr2d(X, K):
H, W = X.shape
h, w = K.shape
Y = torch.zeros(H - h + 1, W - w + 1)
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
構(gòu)造上圖中的輸入數(shù)組X悉默、核數(shù)組K來驗(yàn)證二維互相關(guān)運(yùn)算的輸出。
X = torch.tensor([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
K = torch.tensor([[0, 1], [2, 3]])
Y = corr2d(X, K)
print(Y)
######
tensor([[19., 25.],
[37., 43.]])
二維卷積層
二維卷積層將輸入和卷積核做互相關(guān)運(yùn)算苟穆,并加上一個(gè)標(biāo)量偏置來得到輸出抄课。卷積層的模型參數(shù)包括卷積核和標(biāo)量偏置。
class Conv2D(nn.Module):
def __init__(self, kernel_size):
super(Conv2D, self).__init__()
self.weight = nn.Parameter(torch.randn(kernel_size))
self.bias = nn.Parameter(torch.randn(1))
def forward(self, x):
return corr2d(x, self.weight) + self.bias
下面我們看一個(gè)例子雳旅,我們構(gòu)造一張 6×8 的圖像跟磨,中間4列為黑(0),其余為白(1)岭辣,希望檢測(cè)到顏色邊緣吱晒。我們的標(biāo)簽是一個(gè) 6×7 的二維數(shù)組甸饱,第2列是1(從1到0的邊緣)沦童,第6列是-1(從0到1的邊緣)。
X = torch.ones(6, 8)
Y = torch.zeros(6, 7)
X[:, 2: 6] = 0
Y[:, 1] = 1
Y[:, 5] = -1
print(X)
print(Y)
結(jié)果如下
tensor([[1., 1., 0., 0., 0., 0., 1., 1.],
[1., 1., 0., 0., 0., 0., 1., 1.],
[1., 1., 0., 0., 0., 0., 1., 1.],
[1., 1., 0., 0., 0., 0., 1., 1.],
[1., 1., 0., 0., 0., 0., 1., 1.],
[1., 1., 0., 0., 0., 0., 1., 1.]])
tensor([[ 0., 1., 0., 0., 0., -1., 0.],
[ 0., 1., 0., 0., 0., -1., 0.],
[ 0., 1., 0., 0., 0., -1., 0.],
[ 0., 1., 0., 0., 0., -1., 0.],
[ 0., 1., 0., 0., 0., -1., 0.],
[ 0., 1., 0., 0., 0., -1., 0.]])
我們希望學(xué)習(xí)一個(gè) 1×2 卷積層叹话,通過卷積層來檢測(cè)顏色邊緣偷遗。
conv2d = Conv2D(kernel_size=(1, 2))
step = 30
lr = 0.01
for i in range(step):
Y_hat = conv2d(X)
l = ((Y_hat - Y) ** 2).sum()
l.backward()
# 梯度下降
conv2d.weight.data -= lr * conv2d.weight.grad
conv2d.bias.data -= lr * conv2d.bias.grad
# 梯度清零
conv2d.weight.grad.zero_()
conv2d.bias.grad.zero_()
if (i + 1) % 5 == 0:
print('Step %d, loss %.3f' % (i + 1, l.item()))
print(conv2d.weight.data)
print(conv2d.bias.data)
結(jié)果如下
Step 5, loss 4.569
Step 10, loss 0.949
Step 15, loss 0.228
Step 20, loss 0.060
Step 25, loss 0.016
Step 30, loss 0.004
tensor([[ 1.0161, -1.0177]])
tensor([0.0009])
互相關(guān)運(yùn)算與卷積運(yùn)算
卷積層得名于卷積運(yùn)算,但卷積層中用到的并非卷積運(yùn)算而是互相關(guān)運(yùn)算驼壶。我們將核數(shù)組上下翻轉(zhuǎn)氏豌、左右翻轉(zhuǎn),再與輸入數(shù)組做互相關(guān)運(yùn)算热凹,這一過程就是卷積運(yùn)算泵喘。由于卷積層的核數(shù)組是可學(xué)習(xí)的,所以使用互相關(guān)運(yùn)算與使用卷積運(yùn)算并無本質(zhì)區(qū)別般妙。
特征圖與感受野
二維卷積層輸出的二維數(shù)組可以看作是輸入在空間維度(寬和高)上某一級(jí)的表征纪铺,也叫特征圖(feature map)。影響元素 x 的前向計(jì)算的所有可能輸入?yún)^(qū)域(可能大于輸入的實(shí)際尺寸)叫做 x 的感受野(receptive field)碟渺。
以圖1為例鲜锚,輸入中陰影部分的四個(gè)元素是輸出中陰影部分元素的感受野。我們將圖中形狀為 2×2 的輸出記為 Y ,將 Y 與另一個(gè)形狀為 2×2 的核數(shù)組做互相關(guān)運(yùn)算芜繁,輸出單個(gè)元素 z 旺隙。那么, z 在 Y 上的感受野包括 Y 的全部四個(gè)元素骏令,在輸入上的感受野包括其中全部9個(gè)元素蔬捷。可見榔袋,我們可以通過更深的卷積神經(jīng)網(wǎng)絡(luò)使特征圖中單個(gè)元素的感受野變得更加廣闊抠刺,從而捕捉輸入上更大尺寸的特征。
填充和步幅
我們介紹卷積層的兩個(gè)超參數(shù)摘昌,即填充和步幅速妖,它們可以對(duì)給定形狀的輸入和卷積核改變輸出形狀。
填充
填充(padding)是指在輸入高和寬的兩側(cè)填充元素(通常是0元素)聪黎,圖2里我們?cè)谠斎敫吆蛯挼膬蓚?cè)分別添加了值為0的元素罕容。
圖2 在輸入的高和寬兩側(cè)分別填充了0元素的二維互相關(guān)計(jì)算
如果原輸入的高和寬是 nh 和 nw ,卷積核的高和寬是 kh 和 kw 稿饰,在高的兩側(cè)一共填充 ph 行锦秒,在寬的兩側(cè)一共填充 pw 列,則輸出形狀為:
(nh+ph?kh+1)×(nw+pw?kw+1)
我們?cè)诰矸e神經(jīng)網(wǎng)絡(luò)中使用奇數(shù)高寬的核喉镰,比如 3×3 旅择, 5×5 的卷積核,對(duì)于高度(或?qū)挾龋榇笮?2k+1 的核侣姆,令步幅為1生真,在高(或?qū)挘﹥蓚?cè)選擇大小為 k 的填充,便可保持輸入與輸出尺寸相同捺宗。
步幅
在互相關(guān)運(yùn)算中柱蟀,卷積核在輸入數(shù)組上滑動(dòng),每次滑動(dòng)的行數(shù)與列數(shù)即是步幅(stride)蚜厉。此前我們使用的步幅都是1长已,圖3展示了在高上步幅為3、在寬上步幅為2的二維互相關(guān)運(yùn)算昼牛。
圖3 高和寬上步幅分別為3和2的二維互相關(guān)運(yùn)算
一般來說术瓮,當(dāng)高上步幅為 sh ,寬上步幅為 sw 時(shí)贰健,輸出形狀為:
?(nh+ph?kh+sh)/sh?×?(nw+pw?kw+sw)/sw?
如果 ph=kh?1 胞四, pw=kw?1 ,那么輸出形狀將簡化為 ?(nh+sh?1)/sh?×?(nw+sw?1)/sw? 霎烙。更進(jìn)一步撬讽,如果輸入的高和寬能分別被高和寬上的步幅整除蕊连,那么輸出形狀將是 (nh/sh)×(nw/sw) 。
當(dāng) ph=pw=p 時(shí)游昼,我們稱填充為 p 甘苍;當(dāng) sh=sw=s 時(shí),我們稱步幅為 s 烘豌。