卷積神經(jīng)網(wǎng)絡(luò)簡介
? 卷積神經(jīng)網(wǎng)絡(luò)(Convolutional Neural Network,CNN或ConvNet)是一種具有局部連接、權(quán)重共享等特性的深層前饋神經(jīng)網(wǎng)絡(luò)。卷積神經(jīng)網(wǎng)絡(luò)最早是主要用來處理圖像信息。如果用全連接前饋網(wǎng)絡(luò)來處理圖像時,會存在以下兩個問題:(1)參數(shù)太多(2)局部不變性特征
? 卷積神經(jīng)網(wǎng)絡(luò)是受生物學(xué)上感受野的機制而提出。感受野(Receptive Field)主要是指聽覺、視覺等神經(jīng)系統(tǒng)中一些神經(jīng)元的特性,即神經(jīng)元只接受其所支配的刺激區(qū)域內(nèi)的信號。在視覺神經(jīng)系統(tǒng)中,視覺皮層中的神經(jīng)細胞的輸出依賴于視網(wǎng)膜上的光感受器。視網(wǎng)膜上的光感受器受刺激興奮時,將神經(jīng)沖動信號傳到視覺皮層,但不是所有視覺皮層中的神經(jīng)元都會接受這些信號。一個神經(jīng)元的感受野是指視網(wǎng)膜上的特定區(qū)域,只有這個區(qū)域內(nèi)的刺激才能夠激活該神經(jīng)元。
? 目前的卷積神經(jīng)網(wǎng)絡(luò)一般是由卷積層、匯聚層和全連接層交叉堆疊而成的前饋神經(jīng)網(wǎng)絡(luò),使用反向傳播算法進行訓(xùn)練。卷積神經(jīng)網(wǎng)絡(luò)有三個結(jié)構(gòu)上的特性:局部連接,權(quán)重共享以及匯聚。這些特性使得卷積神經(jīng)網(wǎng)絡(luò)具有一定程度上的平移、縮放和旋轉(zhuǎn)不變性。和前饋神經(jīng)網(wǎng)絡(luò)相比,卷積神經(jīng)網(wǎng)絡(luò)的參數(shù)更少。
2、卷積名詞雜燴
卷積(Convolution):是一種數(shù)學(xué)操作。
濾波器(filter):
簡單移動平均:一般情況下濾波器的長度m遠小于信號序列長度n。當(dāng)濾波器wk = 1/m, 1 ≤ k ≤ m時,卷積相當(dāng)于信號序列的簡單移動平均(窗口大小為m)。
特征映射(Feature Map):在圖像處理中,卷積經(jīng)常作為特征提取的有效方法。一幅圖像在經(jīng)過卷積操作后得到結(jié)果
互相關(guān)(Cross-Correlation):互相關(guān)(Cross-Correlation)是一個衡翻轉(zhuǎn)就是從兩個維度(從上到下、從左到右)顛倒次序,即旋轉(zhuǎn)180 度。量兩個序列相關(guān)性的函數(shù),通常是用滑動窗口的點積計算來實現(xiàn)。
濾波器的步長(Stride):指濾波器在滑動時的時間間隔。
零填充(Zero Padding):是在輸入向量兩端進行補零。
匯聚層(Pooling Layer):匯聚層(Pooling Layer)也叫子采樣層(Subsampling Layer),其作用是進行特征選擇,降低特征數(shù)量,并從而減少參數(shù)數(shù)量。
匯聚(Pooling):對每個區(qū)域進行下采樣(Down Sampling)得到一個值,作為這個區(qū)域的概括。
凈輸入:沒有經(jīng)過非線性激活函數(shù)的凈活性值(Net Activation)。
3、卷積操作辨別:
卷積與互相關(guān)的區(qū)別僅僅在于卷積核是否進行翻轉(zhuǎn),也可以理解為圖像是否進行翻轉(zhuǎn)
窄卷積與寬卷積、等寬卷積:
窄卷積:步長s = 1,兩端不補零p = 0,卷積后輸出長度為n ? m + 1。
寬卷積:步長s = 1,兩端補零p = m ? 1,卷積后輸出長度n + m ? 1。
等寬卷積:步長s = 1,兩端補零p = (m ?1)/2,卷積后輸出長度n。
Pytorch構(gòu)建CNN模型
在上一章節(jié)我們講解了如何使用Pytorch來讀取賽題數(shù)據(jù)集,本節(jié)我們使用本章學(xué)習(xí)到的知識構(gòu)件一個簡單的CNN模型,完成字符識別功能。
在Pytorch中構(gòu)建CNN模型非常簡單,只需要定義好模型的參數(shù)和正向傳播即可,Pytorch會根據(jù)正向傳播自動計算反向傳播。
在本章我們會構(gòu)建一個非常簡單的CNN,然后進行訓(xùn)練。這個CNN模型包括兩個卷積層,最后并聯(lián)6個全連接層進行分類
import torch
torch.manual_seed(0)
torch.backends.cudnn.deterministic = False
torch.backends.cudnn.benchmark = True
import torchvision.models as models
import torchvision.transforms as transforms
import torchvision.datasets as datasets
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable
from torch.utils.data.dataset import Dataset
# 定義模型
class SVHN_Model1(nn.Module):
? ? def __init__(self):
? ? ? ? super(SVHN_Model1, self).__init__()
? ? ? ? # CNN提取特征模塊
? ? ? ? self.cnn = nn.Sequential(
? ? ? ? ? ? nn.Conv2d(3, 16, kernel_size=(3, 3), stride=(2, 2)),
? ? ? ? ? ? nn.ReLU(),?
? ? ? ? ? ? nn.MaxPool2d(2),
? ? ? ? ? ? nn.Conv2d(16, 32, kernel_size=(3, 3), stride=(2, 2)),
? ? ? ? ? ? nn.ReLU(),
? ? ? ? ? ? nn.MaxPool2d(2),
? ? ? ? )
? ? ? ? #
? ? ? ? self.fc1 = nn.Linear(32*3*7, 11)
? ? ? ? self.fc2 = nn.Linear(32*3*7, 11)
? ? ? ? self.fc3 = nn.Linear(32*3*7, 11)
? ? ? ? self.fc4 = nn.Linear(32*3*7, 11)
? ? ? ? self.fc5 = nn.Linear(32*3*7, 11)
? ? ? ? self.fc6 = nn.Linear(32*3*7, 11)
? ?
? ? def forward(self, img):? ? ? ?
? ? ? ? feat = self.cnn(img)
? ? ? ? feat = feat.view(feat.shape[0], -1)
? ? ? ? c1 = self.fc1(feat)
? ? ? ? c2 = self.fc2(feat)
? ? ? ? c3 = self.fc3(feat)
? ? ? ? c4 = self.fc4(feat)
? ? ? ? c5 = self.fc5(feat)
? ? ? ? c6 = self.fc6(feat)
? ? ? ? return c1, c2, c3, c4, c5, c6
? ?
model = SVHN_Model1()
接下來是訓(xùn)練代碼:
# 損失函數(shù)
criterion = nn.CrossEntropyLoss()
# 優(yōu)化器
optimizer = torch.optim.Adam(model.parameters(), 0.005)
loss_plot, c0_plot = [], []
# 迭代10個Epoch
for epoch in range(10):
? ? for data in train_loader:
? ? ? ? c0, c1, c2, c3, c4, c5 = model(data[0])
? ? ? ? loss = criterion(c0, data[1][:, 0]) + \
? ? ? ? ? ? ? ? criterion(c1, data[1][:, 1]) + \
? ? ? ? ? ? ? ? criterion(c2, data[1][:, 2]) + \
? ? ? ? ? ? ? ? criterion(c3, data[1][:, 3]) + \
? ? ? ? ? ? ? ? criterion(c4, data[1][:, 4]) + \
? ? ? ? ? ? ? ? criterion(c5, data[1][:, 5])
? ? ? ? loss /= 6
? ? ? ? optimizer.zero_grad()
? ? ? ? loss.backward()
? ? ? ? optimizer.step()
? ? ? ?
? ? ? ? loss_plot.append(loss.item())
? ? ? ? c0_plot.append((c0.argmax(1) == data[1][:, 0]).sum().item()*1.0 / c0.shape[0])
? ? ? ?
? ? print(epoch)