一维卷积filter_从零开始学Pytorch(七)之卷积神经网络
卷積神經(jīng)網(wǎng)絡(luò)基礎(chǔ)
我們介紹卷積神經(jīng)網(wǎng)絡(luò)的卷積層和池化層,并解釋填充、步幅、輸入通道和輸出通道的含義。
import torch
from torch.autograd import Variable
a=Variable(torch.FloatTensor([[2.,4.]]),requires_grad=True)
b=torch.zeros(1,2)
b[0,0]=a[0,0]**2+a[0,1]
b[0,1]=a[0,1]**2+a[0,0]
out=2*b
#其參數(shù)要傳入和out維度一樣的矩陣
out.backward(torch.FloatTensor([[1.,2.]]))
print('input:{}'.format(a.data))
print('output:{}'.format(out.data))
print('input gradients are:{}'.format(a.grad))輸出:input:tensor([[2., 4.]])
output:tensor([[16., 36.]])
input gradients are:tensor([[12., 34.]])
二維卷積層
最常見的二維卷積層,常用于處理圖像數(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)的輸出。
圖1 二維互相關(guān)運(yùn)算
下面我們用corr2d函數(shù)實(shí)現(xiàn)二維互相關(guān)運(yùn)算,它接受輸入數(shù)組X與核數(shù)組K,并輸出數(shù)組Y。
import torch
import torch.nn as nndef corr2d(X, K):H, W = X.shapeh, w = K.shapeY = 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)造一張
的圖像,中間4列為黑(0),其余為白(1),希望檢測(cè)到顏色邊緣。我們的標(biāo)簽是一個(gè)的二維數(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)輸出: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è)
卷積層,通過卷積層來檢測(cè)顏色邊緣。onv2d = 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.gradconv2d.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)輸出:Step 5, loss 3.968
Step 10, loss 0.448
Step 15, loss 0.052
Step 20, loss 0.006
Step 25, loss 0.001
Step 30, loss 0.000
tensor([[ 0.9969, -0.9993]])
tensor([0.0013])
互相關(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)。影響元素
的前向計(jì)算的所有可能輸入?yún)^(qū)域(可能大于輸入的實(shí)際尺寸)叫做的感受野(receptive field)。以圖1為例,輸入中陰影部分的四個(gè)元素是輸出中陰影部分元素的感受野。我們將圖中形狀為
的輸出記為,將與另一個(gè)形狀為的核數(shù)組做互相關(guān)運(yùn)算,輸出單個(gè)元素。那么,在上的感受野包括的全部四個(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ì)算
如果原輸入的高和寬是
和,卷積核的高和寬是和,在高的兩側(cè)一共填充行,在寬的兩側(cè)一共填充列,則輸出形狀為:我們?cè)诰矸e神經(jīng)網(wǎng)絡(luò)中使用奇數(shù)高寬的核,比如
,的卷積核,對(duì)于高度(或?qū)挾?#xff09;為大小為的核,令步幅為1,在高(或?qū)?#xff09;兩側(cè)選擇大小為的填充,便可保持輸入與輸出尺寸相同。步幅
在互相關(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í),輸出形狀為:如果
,,那么輸出形狀將簡(jiǎn)化為。更進(jìn)一步,如果輸入的高和寬能分別被高和寬上的步幅整除,那么輸出形狀將是。當(dāng)
時(shí),我們稱填充為;當(dāng)時(shí),我們稱步幅為。多輸入通道和多輸出通道
之前的輸入和輸出都是二維數(shù)組,但真實(shí)數(shù)據(jù)的維度經(jīng)常更高。例如,彩色圖像在高和寬2個(gè)維度外還有RGB(紅、綠、藍(lán))3個(gè)顏色通道。假設(shè)彩色圖像的高和寬分別是
和(像素),那么它可以表示為一個(gè)的多維數(shù)組,我們將大小為3的這一維稱為通道(channel)維。多輸入通道
卷積層的輸入可以包含多個(gè)通道,圖4展示了一個(gè)含2個(gè)輸入通道的二維互相關(guān)計(jì)算的例子。
圖4 含2個(gè)輸入通道的互相關(guān)計(jì)算
假設(shè)輸入數(shù)據(jù)的通道數(shù)為
,卷積核形狀為,我們?yōu)槊總€(gè)輸入通道各分配一個(gè)形狀為的核數(shù)組,將個(gè)互相關(guān)運(yùn)算的二維輸出按通道相加,得到一個(gè)二維數(shù)組作為輸出。我們把個(gè)核數(shù)組在通道維上連結(jié),即得到一個(gè)形狀為的卷積核。多輸出通道
卷積層的輸出也可以包含多個(gè)通道,設(shè)卷積核輸入通道數(shù)和輸出通道數(shù)分別為
和,高和寬分別為和。如果希望得到含多個(gè)通道的輸出,我們可以為每個(gè)輸出通道分別創(chuàng)建形狀為的核數(shù)組,將它們?cè)谳敵鐾ǖ谰S上連結(jié),卷積核的形狀即。對(duì)于輸出通道的卷積核,我們提供這樣一種理解,一個(gè)
的核數(shù)組可以提取某種局部特征,但是輸入可能具有相當(dāng)豐富的特征,我們需要有多個(gè)這樣的的核數(shù)組,不同的核數(shù)組提取的是不同的特征。1x1卷積層
最后討論形狀為
的卷積核,我們通常稱這樣的卷積運(yùn)算為卷積,稱包含這種卷積核的卷積層為卷積層。圖5展示了使用輸入通道數(shù)為3、輸出通道數(shù)為2的卷積核的互相關(guān)計(jì)算。圖5 1x1卷積核的互相關(guān)計(jì)算。輸入和輸出具有相同的高和寬
卷積核可在不改變高寬的情況下,調(diào)整通道數(shù)。卷積核不識(shí)別高和寬維度上相鄰元素構(gòu)成的模式,其主要計(jì)算發(fā)生在通道維上。假設(shè)我們將通道維當(dāng)作特征維,將高和寬維度上的元素當(dāng)成數(shù)據(jù)樣本,那么卷積層的作用與全連接層等價(jià)。卷積層與全連接層的對(duì)比
二維卷積層經(jīng)常用于處理圖像,與此前的全連接層相比,它主要有兩個(gè)優(yōu)勢(shì):
一是全連接層把圖像展平成一個(gè)向量,在輸入圖像上相鄰的元素可能因?yàn)檎蛊讲僮鞑辉傧噜?#xff0c;網(wǎng)絡(luò)難以捕捉局部信息。而卷積層的設(shè)計(jì),天然地具有提取局部信息的能力。
二是卷積層的參數(shù)量更少。不考慮偏置的情況下,一個(gè)形狀為
的卷積核的參數(shù)量是,與輸入圖像的寬高無關(guān)。假如一個(gè)卷積層的輸入和輸出形狀分別是和,如果要用全連接層進(jìn)行連接,參數(shù)數(shù)量就是。使用卷積層可以以較少的參數(shù)數(shù)量來處理更大的圖像。卷積層的簡(jiǎn)潔實(shí)現(xiàn)
我們使用Pytorch中的nn.Conv2d類來實(shí)現(xiàn)二維卷積層,主要關(guān)注以下幾個(gè)構(gòu)造函數(shù)參數(shù):
in_channels(python:int) – Number of channels in the input imagout_channels(python:int) – Number of channels produced by the convolutionkernel_size(python:int or tuple) – Size of the convolving kernelstride(python:int or tuple, optional) – Stride of the convolution. Default: 1padding(python:int or tuple, optional) – Zero-padding added to both sides of the input. Default: 0bias(bool, optional) – If True, adds a learnable bias to the output. Default: True
forward函數(shù)的參數(shù)為一個(gè)四維張量,形狀為
X = torch.rand(4, 2, 3, 5)
print(X.shape)conv2d = nn.Conv2d(in_channels=2, out_channels=3, kernel_size=(3, 5), stride=1, padding=(1, 2))
Y = conv2d(X)
print('Y.shape: ', Y.shape)
print('weight.shape: ', conv2d.weight.shape)
print('bias.shape: ', conv2d.bias.shape)
print(conv2d.weight.data)輸出: torch.Size([4, 2, 3, 5])
Y.shape: torch.Size([4, 3, 3, 5])
weight.shape: torch.Size([3, 2, 3, 5])
bias.shape: torch.Size([3])
tensor([[[[-0.1092, 0.1168, 0.1400, -0.0465, -0.0568],
[-0.1320, -0.0556, 0.0207, -0.1416, -0.0540],
[ 0.0343, -0.0288, -0.0365, -0.0165, -0.1696]],
[[-0.0617, -0.1310, -0.1756, -0.1772, 0.0684],
[ 0.0529, -0.1666, 0.0058, -0.0135, -0.1763],
[ 0.1499, -0.0324, -0.1448, -0.0840, 0.1811]]],
[[[-0.0828, 0.1220, -0.1168, -0.0692, 0.1630], [-0.0491, -0.0292, -0.1773, -0.1622, 0.0116], [ 0.0757, 0.1569, -0.0121, -0.0682, -0.1187]],
[[ 0.0505, 0.0952, -0.1747, -0.1405, 0.0541], [ 0.1089, 0.0578, -0.1252, 0.1132, -0.0673], [-0.1200, 0.1759, 0.1563, -0.1153, 0.1390]]],
[[[ 0.0374, -0.1512, 0.1735, 0.1097, -0.0539], [-0.0002, 0.0969, 0.1322, 0.0050, 0.1296], [ 0.0055, 0.1743, -0.1126, -0.0422, 0.1633]],
[[-0.1269, -0.1741, -0.0255, -0.1518, -0.0297], [-0.1162, 0.0448, 0.0955, 0.0330, 0.1388], [ 0.1559, 0.1346, 0.0025, -0.1658, 0.0995]]]])
池化
二維池化層
池化層主要用于緩解卷積層對(duì)位置的過度敏感性。同卷積層一樣,池化層每次對(duì)輸入數(shù)據(jù)的一個(gè)固定形狀窗口(又稱池化窗口)中的元素計(jì)算輸出,池化層直接計(jì)算池化窗口內(nèi)元素的最大值或者平均值,該運(yùn)算也分別叫做最大池化或平均池化。圖6展示了池化窗口形狀為
的最大池化。圖6 池化窗口形狀為 2 x 2 的最大池化
二維平均池化的工作原理與二維最大池化類似,但將最大運(yùn)算符替換成平均運(yùn)算符。池化窗口形狀為
的池化層稱為池化層,其中的池化運(yùn)算叫作池化。池化層也可以在輸入的高和寬兩側(cè)填充并調(diào)整窗口的移動(dòng)步幅來改變輸出形狀。池化層填充和步幅與卷積層填充和步幅的工作機(jī)制一樣。
在處理多通道輸入數(shù)據(jù)時(shí),池化層對(duì)每個(gè)輸入通道分別池化,但不會(huì)像卷積層那樣將各通道的結(jié)果按通道相加。這意味著池化層的輸出通道數(shù)與輸入通道數(shù)相等。
池化層的簡(jiǎn)潔實(shí)現(xiàn)
我們使用Pytorch中的nn.MaxPool2d實(shí)現(xiàn)最大池化層,關(guān)注以下構(gòu)造函數(shù)參數(shù):
kernel_size– the size of the window to take a max overstride– the stride of the window. Default value is kernel_sizepadding– implicit zero padding to be added on both sides
forward函數(shù)的參數(shù)為一個(gè)四維張量,形狀為
X = torch.arange(32, dtype=torch.float32).view(1, 2, 4, 4)
pool2d = nn.MaxPool2d(kernel_size=3, padding=1, stride=(2, 1))
Y = pool2d(X)
print(X)
print(Y)輸出: tensor([[[[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.]],
[[16., 17., 18., 19.],
[20., 21., 22., 23.],
[24., 25., 26., 27.],
[28., 29., 30., 31.]]]])
tensor([[[[ 5., 6., 7., 7.],
[13., 14., 15., 15.]],
[[21., 22., 23., 23.],
[29., 30., 31., 31.]]]])
總結(jié)
以上是生活随笔為你收集整理的一维卷积filter_从零开始学Pytorch(七)之卷积神经网络的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 求教八卦的兄弟姐妹!不小心用360手机卫
- 下一篇: 天气甚好下一句是什么呢?