本文來自《老餅講解-BP神經網絡》https://www.bbbdata.com/
目錄
- 一、卷積神經網絡的結構
- 1.1.卷積與池化的作用
- 2.2.全連接層的作用
- 二、卷積神經網絡的運算
- 2.1.卷積層的運算
- 2.2.池化的運算
- 2.3.全連接層運算
- 三、pytorch實現一個CNN例子
- 3.1.模型的搭建
- 3.2.CNN完整訓練代碼
CNN神經網絡常用于圖片識別,是深度學習中常用的模型。
本文簡單快速了解卷積神經網絡是什么東西,并展示一個簡單的示例。
一、卷積神經網絡的結構
一個經典的卷積神經網絡的結構如下:
C代表卷積層,P代表池化層,F代表全連接層。
卷積神經網絡主要的、樸素的用途是圖片識別。即輸入圖片,然后識別圖片的類別,例如輸入一張圖片,識別該圖片是貓還是狗。
1.1.卷積與池化的作用
卷積層與池化層共同是卷積神經網絡的核心,它用于將輸入圖片進行壓縮,例如一張224x224的圖片,經過卷積+池化后,可能得到的就是55x55的圖片,也就是說,卷積與池化的目的就是使得輸入圖片變小,同時盡量不要損失太多與類別相關的信息。例如一張貓的圖片經過卷積與池化之后,盡量減少圖片的大小,但要盡可能地保留"貓"的信息。
2.2.全連接層的作用
全連接層主要用于預測圖片的類別。全連接層實際可以看作一個BP神經網絡模型, 使用"卷積+池化"之后得到的特征來擬合圖片的類別。
二、卷積神經網絡的運算
2.1.卷積層的運算
卷積層的運算如下:
卷積層中的卷積核就是一個矩陣,直觀來看它就是一個窗口,卷積窗口一般為正方形,即長寬一致,
卷積運算通過從左到右,從上往下移動卷積核窗口,將窗口覆蓋的每一小塊輸入進行加權,作為輸出
2.2.池化的運算
池化層是通過一個池化窗口,對輸入進行逐塊掃描,每次將窗口的元素合并為一個元素,
池化層的運算如下:
池化層一般分為均值池化與最大值池化,顧名思義,就是計算時使用均值還是最大值:
2.3.全連接層運算
全連接層就相當于一個BP神經網絡模型,即每一層與下一層都是全連接形式。
假設前一層傳過來的輸入的是X,則當前層的輸出是tanh(WX+b)
三、pytorch實現一個CNN例子
下面以手寫數字識別為例,展示如何使用pytorch實現一個CNN
3.1.模型的搭建
如下所示,就搭建了一個CNN模型
# 卷積神經網絡的結構
class ConvNet(nn.Module):def __init__(self,in_channel,num_classes):super(ConvNet, self).__init__()self.nn_stack=nn.Sequential(#--------------C1層-------------------nn.Conv2d(in_channel,6, kernel_size=5,stride=1,padding=2),nn.ReLU(inplace=True), nn.AvgPool2d(kernel_size=2,stride=2),# 輸出14*14#--------------C2層-------------------nn.Conv2d(6,16, kernel_size=5,stride=1,padding=2),nn.ReLU(inplace=True),nn.AvgPool2d(kernel_size=2,stride=2),# 輸出7*7#--------------C3層-------------------nn.Conv2d(16,80,kernel_size=7,stride=1,padding=0),# 輸出1*1*80#--------------全連接層F4----------nn.Flatten(), # 對C3的結果進行展平nn.Linear(80, 120), nn.ReLU(inplace=True), #--------------全連接層F5---------- nn.Linear(120, num_classes) )def forward(self, x):p = self.nn_stack(x)return p
從代碼里可以看到,只需按自己所設定的結構進行隨意搭建就可以了。
搭建了之后再使用數據進行訓練可以了,然后就可以使用模型對樣本進行預測。
3.2.CNN完整訓練代碼
完整的CNN訓練代碼示例如下:
import torch
from torch import nn
from torch.utils.data import DataLoader
import torchvision
import numpy as np#--------------------模型結構--------------------------------------------
# 卷積神經網絡的結構
class ConvNet(nn.Module):def __init__(self,in_channel,num_classes):super(ConvNet, self).__init__()self.nn_stack=nn.Sequential(#--------------C1層-------------------nn.Conv2d(in_channel,6, kernel_size=5,stride=1,padding=2),nn.ReLU(inplace=True), nn.AvgPool2d(kernel_size=2,stride=2),# 輸出14*14#--------------C2層-------------------nn.Conv2d(6,16, kernel_size=5,stride=1,padding=2),nn.ReLU(inplace=True),nn.AvgPool2d(kernel_size=2,stride=2),# 輸出7*7#--------------C3層-------------------nn.Conv2d(16,80,kernel_size=7,stride=1,padding=0),# 輸出1*1*80#--------------全連接層F4----------nn.Flatten(), # 對C3的結果進行展平nn.Linear(80, 120), nn.ReLU(inplace=True), #--------------全連接層F5---------- nn.Linear(120, num_classes) )def forward(self, x):p = self.nn_stack(x)return p#-----------------------模型訓練---------------------------------------
# 參數初始化函數
def init_param(model):# 初始化權重閾值 param_list = list(model.named_parameters()) # 將模型的參數提取為列表 for i in range(len(param_list)): # 逐個初始化權重、閾值is_weight = i%2==0 # 如果i是偶數,就是權重參數,i是奇數就是閾值參數if is_weight: torch.nn.init.normal_(param_list[i][1],mean=0,std=0.01) # 對于權重,以N(0,0.01)進行隨機初始化else: torch.nn.init.constant_(param_list[i][1],val=0) # 閾值初始化為0# 訓練函數
def train(dataloader,valLoader,model,epochs,goal,device): for epoch in range(epochs): err_num = 0 # 本次epoch評估錯誤的樣本eval_num = 0 # 本次epoch已評估的樣本print('-----------當前epoch:',str(epoch),'----------------') for batch, (imgs, labels) in enumerate(dataloader): # -----訓練模型----- x, y = imgs.to(device), labels.to(device) # 將數據發送到設備optimizer.zero_grad() # 將優化器里的參數梯度清空py = model(x) # 計算模型的預測值 loss = lossFun(py, y) # 計算損失函數值loss.backward() # 更新參數的梯度optimizer.step() # 更新參數# ----計算錯誤率---- idx = torch.argmax(py,axis=1) # 模型的預測類別eval_num = eval_num + len(idx) # 更新本次epoch已評估的樣本err_num = err_num +sum(y != idx) # 更新本次epoch評估錯誤的樣本if(batch%10==0): # 每10批打印一次結果print('err_rate:',err_num/eval_num) # 打印錯誤率# -----------驗證數據誤差--------------------------- model.eval() # 將模型調整為評估狀態val_acc_rate = calAcc(model,valLoader,device) # 計算驗證數據集的準確率model.train() # 將模型調整回訓練狀態print("驗證數據的準確率:",val_acc_rate) # 打印準確率 if((err_num/eval_num)<=goal): # 檢查退出條件break print('訓練步數',str(epoch),',最終訓練誤差',str(err_num/eval_num)) # 計算數據集的準確率
def calAcc(model,dataLoader,device): py = np.empty(0) # 初始化預測結果y = np.empty(0) # 初始化真實結果for batch, (imgs, labels) in enumerate(dataLoader): # 逐批預測cur_py = model(imgs.to(device)) # 計算網絡的輸出cur_py = torch.argmax(cur_py,axis=1) # 將最大者作為預測結果py = np.hstack((py,cur_py.detach().cpu().numpy())) # 記錄本批預測的yy = np.hstack((y,labels)) # 記錄本批真實的yacc_rate = sum(y==py)/len(y) # 計算測試樣本的準確率return acc_rate #--------------------------主流程腳本----------------------------------------------
#-------------------加載數據--------------------------------
train_data = torchvision.datasets.MNIST(root = 'D:\pytorch\data' # 路徑,如果路徑有,就直接從路徑中加載,如果沒有,就聯網獲取,train = True # 獲取訓練數據,transform = torchvision.transforms.ToTensor() # 轉換為tensor數據,download = True # 是否下載,選為True,就下載到root下面,target_transform= None)
val_data = torchvision.datasets.MNIST(root = 'D:\pytorch\data' # 路徑,如果路徑有,就直接從路徑中加載,如果沒有,就聯網獲取,train = False # 獲取測試數據,transform = torchvision.transforms.ToTensor() # 轉換為tensor數據,download = True # 是否下載,選為True,就下載到root下面,target_transform= None) #-------------------模型訓練--------------------------------
trainLoader = DataLoader(train_data, batch_size=1000, shuffle=True) # 將數據裝載到DataLoader
valLoader = DataLoader(val_data , batch_size=100) # 將驗證數據裝載到DataLoader
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 設置訓練設備
model = ConvNet(in_channel =1,num_classes=10).to(device) # 初始化模型,并發送到設備
lossFun = torch.nn.CrossEntropyLoss() # 定義損失函數為交叉熵損失函數
optimizer = torch.optim.SGD(model.parameters(), lr=0.01,momentum =0.9,dampening=0.0005) # 初始化優化器
train(trainLoader,valLoader,model,1000,0.01,device) # 訓練模型,訓練100步,錯誤低于1%時停止訓練# -----------模型效果評估---------------------------
model.eval() # 將模型切換到評估狀態(屏蔽Dropout)
train_acc_rate = calAcc(model,trainLoader,device) # 計算訓練數據集的準確率
print("訓練數據的準確率:",train_acc_rate) # 打印準確率
val_acc_rate = calAcc(model,valLoader,device) # 計算驗證數據集的準確率
print("驗證數據的準確率:",val_acc_rate) # 打印準確率
運行結果如下:
-----------當前epoch: 0 ----------------
err_rate: tensor(0.7000)
驗證數據的準確率: 0.3350877192982456
-----------當前epoch: 1 ----------------
err_rate: tensor(0.6400)
驗證數據的準確率: 0.3350877192982456
-----------當前epoch: 2 ----------------
.......
.......
-----------當前epoch: 77 ----------------
err_rate: tensor(0.0100)
驗證數據的準確率: 1.0
-----------當前epoch: 78 ----------------
err_rate: tensor(0.)
驗證數據的準確率: 1.0
-----------當前epoch: 79 ----------------
err_rate: tensor(0.0200)
驗證數據的準確率: 1.0
-----------當前epoch: 80 ----------------
err_rate: tensor(0.0100)
驗證數據的準確率: 0.9982456140350877
-----------------------------------------
訓練步數 80 ,最終訓練誤差 tensor(0.0088)
訓練數據的準確率: 0.9982456140350877
驗證數據的準確率: 0.9982456140350877
可以看到,識別效果達到了99.8%。CNN模型對圖片的識別是非常有效的。
相關鏈接:
《老餅講解-機器學習》:老餅講解-機器學習教程-通俗易懂
《老餅講解-神經網絡》:老餅講解-matlab神經網絡-通俗易懂
《老餅講解-神經網絡》:老餅講解-深度學習-通俗易懂