卷積神經網絡+用pytorch構建神經網絡

1. 神經網絡

1.1 神經網絡是怎麼工作的?

首先神經網絡的結構包括三個層次:輸入層、隱藏層和輸出層。如下圖所示:
在這裏插入圖片描述
其中每個圓圈代表一個神經元,輸入層和隱藏層之間有很多箭頭相連接,每個連接都有一個權值,同層的神經元沒有連接,通常神經網絡都是全l連接的,也就是所有層都相互有鏈接且中間沒有斷層。

第一層有4個輸入結點,每個輸入節點分別對應五個權值,則可以讓輸入的數據分別和權值作矩陣乘法最後再相加,得到的數據即爲第二層,以此類推。最後會得到值Oj。

1.2 神經網絡爲什麼要這樣工作呢?

主要從兩個方面來說:損失和優化

神經網絡輸出結果的分類問題最常用的方法是設置n個輸出節點(n爲類別的個數),將分類的結果看成概率事件,符合一定的概率分佈。通常使用softmax迴歸將神經網絡前向傳播的到的結果也變成概率分佈。

softmax迴歸

計算公式:
在這裏插入圖片描述
過程圖示是這樣的:

然後將得到的輸出結果變成了概率輸出:

損失

計算公式:
在這裏插入圖片描述
爲了衡量神經網絡預測的概率分佈與真實概率分佈之間的距離,要對結果進行one-hot編碼:

最終結果是H(y) = -0.1log(0.1)

爲了減少這個損失值,即找到損失函數的最小值,我們通常採用梯度下降算法,

梯度下降算法

之前有詳細說過梯度下降算法,這裏不再贅述——傳送門

反向傳播算法

反向傳播算法實際就是:我們使用鏈式求導法則,反向層層推進,計算出每一層神經節點的偏導數,然後使用梯度下降,不斷調整每一個節點的權重,從而達到求得全局最小值的目的。

2.卷積神經網絡

2.1 與傳統卷積神經網絡的區別

傳統的多層神經網絡只有輸入層、隱藏層、輸出層。其中隱藏層層數依情況而定。

首先什麼是卷積?

對圖像(不同的數據窗口數據)和濾波矩陣(一組固定的權重:因爲每個神經元的多個權重固定,所以又可以看做一個恆定的濾波器filter)做內積(逐個元素相乘再求和)的操作就是卷積,也是卷積神經網絡的名字來源。

卷積神經網絡CNN,在原來多層神經網絡上加入了更有效的特徵學習部分,具體就是在全連接層之前增加了卷積層、激活層和池化層。卷積神經網絡出現,使得神經網絡層數得以加深,“深度” 學習由此而來。

2.2 卷積神經網絡工作原理

如圖:在這裏插入圖片描述
新增的三個層次的作用分別是:

卷積層:通過在原始圖像上平移來提取特徵
激活層:增加非線性分割能力
池化層:減少學習的參數,降低網絡的複雜度(最大池化和平均池化)

下邊分別對這三個層次進行展開論述:

卷積層

四個參數:

  • 過濾器
    過濾器的大小是指設定的,一般都爲3x3、5x5、7x7等
  • 深度
    輸出深度(個數)是由卷積中的Filter的個數決定
    在這裏插入圖片描述
  • 步幅
    也叫步長,就是Filter移動的間隔大小,
  • 零填充
    主要爲了解決步長移動與Filter大大小不合適,不能剛好移動到邊緣的情況。
    在這裏插入圖片描述

激活函數——Relu

常見的激活函數有sigmod、softmax
relu等,但我們常用的是Relu,因爲他可以減少梯度消失和梯度爆炸情況。

函數圖像如下:
在這裏插入圖片描述

池化計算

池化層的作用主要是通過採樣減少參數數量。常用的是最大值池化,也就是在n個樣本中取最大值,作爲新的樣本值,如下圖:
在這裏插入圖片描述
池化後深度不變。

全連接層

前面的卷積和池化相當於做特徵工程,後面的全連接相當於做特徵加權,最後的全連接層在整個卷積神經網絡中起到 “分類器” 的作用。

2.3 卷積神經網絡常見架構

在這裏插入圖片描述

3. 使用Pytorch搭建神經網絡

1.先定義網絡:寫網絡Net的Class,聲明網絡的實例net=Net(),

2.定義優化器opt=torch.optim.xxx(net.parameters(),lr=xxx),

3.再定義損失函數(自己寫class或者直接用官方的,lossfunc=nn.MSELoss()或者其他。

4.在定義完之後,開始一次一次的循環:

①先清空優化器裏的梯度信息,opt.zero_grad();

②再將input傳入,output=net(input) ,正向傳播

③算損失,loss=lossfunc(target,output) ##這裏target就是參考標準值GT,需要自己準備,和之前傳入的input一一對應

④誤差反向傳播,loss.backward()

⑤更新參數,opt.step()

import torch
import torch.nn.functional as F
from torch.autograd import Variable
import matplotlib.pyplot as plt

x = torch.unsqueeze(torch.linspace(-1,1,100),dim=1)
           #對輸入的制定位置插入維度 1,無torch.unsqueeze,x是向量torch.Size([100]),
           #有之後x是torch.Size([100, 1])的矩陣
y = x**2+0.2*torch.rand(x.size())
           #x的平方,加噪聲(從區間[0,1)的均勻分佈中抽取的一組隨機數,輸出形狀與x相同)
print(x,y,x.size())
x,y = Variable(x),Variable(y)  #將x,y張量轉化爲變量

##定義一個類,用來繼承nn.Module
class Net(torch.nn.Module):
    def __init__(self,n_feature,n_hidden,n_output):#搭建層所要的初始信息,特徵數,隱藏層單元數和輸出單元數
        super(Net,self).__init__()#繼承Net到模塊,官方步驟
        self.hidden = torch.nn.Linear(n_feature,n_hidden)#從輸入層到隱藏層的函數
        self.predict = torch.nn.Linear(n_hidden,n_output)#從隱藏層的輸出層的函數
        
    def forward(self,x):#前向傳播
        x = F.relu(self.hidden(x))#self.hidden(x)給x加權成爲a,用激勵函數將a變成特徵b
        x = self.predict(x)#self.predict(b)給b加權,預測最終結果
        return x #返回最終預測值
net = Net(1,10,1) #只有一個輸入單元,一個輸出單元,隱藏單元定爲10個
print(net)   #搭建神經網絡完畢

plt.ion()
plt.show()

opt = torch.optim.SGD(net.parameters(),lr=0.5)#設置學習率爲0.5,用隨機梯度下降法優化net神經網絡的參數
lossfunc = torch.nn.MSELoss() #設置損失函數爲均方差函數
for t in range(100):#訓練步數100
    prediction=net(x)#預測值
    loss=lossfunc(prediction,y)#預測值與真實值的誤差
    opt.zero_grad()#梯度降0
    loss.backward()#反向傳播
    opt.step()#梯度優化
    
    if t%5 == 0:#此時,打印一下圖片
        plt.cla()#清除當前圖形中的當前活動軸,其他軸不受影響。
        plt.scatter(x.data.numpy(),y.data.numpy())#numpy類型才支持plt,所以要轉化
        plt.plot(x.data.numpy(),prediction.data.numpy(),'r-',lw=3)#擬合線圖
        plt.text(0.5,0,'loss=%.4f'%loss.data[0],fontdict = {'size':10,'color':'red'})#在(0.5,0)的位置寫loss的變化
        plt.pause(0.1)#間隔時間

plt.ioff()
plt.show()

4. 使用Pytorch實現卷積神經網絡

主要實現圖像分類:

import torch
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
from torchvision import transforms
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
from torch import optim


class CNN_net(nn.Module):
    def __init__(self):
        # 先運行nn.Module的初始化函數
        super(CNN_net, self).__init__()
        # 卷積層的定義,輸入爲1channel的灰度圖,輸出爲4特徵,每個卷積kernal爲9*9
        self.conv = nn.Conv2d(1, 4, 9)
        # 均值池化
        self.pool = nn.AvgPool2d(2, 2)
        # 全連接後接softmax
        self.fc = nn.Linear(10*10*4, 10)
        self.softmax = nn.Softmax()

    def forward(self, x):
        # 卷積層,分別是二維卷積->sigmoid激勵->池化
        out = self.conv(x)
        out = F.sigmoid(out)
        out = self.pool(out)
        print(out.size())
        # 將特徵的維度進行變化(batchSize*filterDim*featureDim*featureDim->batchSize*flat_features)
        out = out.view(-1, self.num_flat_features(out))
        # 全連接層和softmax處理
        out = self.fc(out)
        out = self.softmax(out)
        return out
    def num_flat_features(self, x):
        # 四維特徵,第一維是batchSize
        size = x.size()[1:]
        num_features = 1
        for s in size:
            num_features *= s
        return num_features

# 定義一個cnn網絡
net = CNN_net()
print(net)

# 參數設置
learning_rate = 1e-3
batch_size = 100
epoches = 10

# MNIST圖像數據的轉換函數
trans_img = transforms.Compose([
        transforms.ToTensor()
    ])

# 下載MNIST的訓練集和測試集
trainset = MNIST('./MNIST', train=True, transform=trans_img, download=True)
testset = MNIST('./MNIST', train=False, transform=trans_img, download=True)

# 構建Dataloader
trainloader = DataLoader(trainset, batch_size=batch_size, shuffle=True, num_workers=4)
testloader = DataLoader(testset, batch_size=batch_size, shuffle=False, num_workers=4)

# cost function的選用
criterian = nn.CrossEntropyLoss(size_average=False)

# 選用SGD來求解
opt = optim.SGD(net.parameters(), lr=learning_rate, momentum=0.95)

# 訓練過程
for i in range(epoches):
    running_loss = 0.
    running_acc = 0.
    for (img, label) in trainloader:
        # 轉換爲Variable類型
        img = Variable(img)
        label = Variable(label)

        opt.zero_grad()

        # feedforward
        output = net(img)
        loss = criterian(output, label)
        # backward
        loss.backward()
        opt.step()

        # 記錄當前的lost以及batchSize數據對應的分類準確數量
        running_loss += loss.data[0]
        _, predict = torch.max(output, 1)
        correct_num = (predict == label).sum()
        running_acc += correct_num.data[0]

    # 計算並打印訓練的分類準確率
    running_loss /= len(trainset)
    running_acc /= len(trainset)

    print("[%d/%d] Loss: %.5f, Acc: %.2f" %(i+1, epoches, running_loss, 100*running_acc))

# 將當前模型設置到測試模式
net.eval()

# 測試過程
testloss = 0.
testacc = 0.
for (img, label) in testloader:
    # 轉換爲Variable類型
    img = Variable(img)
    label = Variable(label)

    # feedforward
    output = net(img)
    loss = criterian(output, label)

    # 記錄當前的lost以及累加分類正確的樣本數
    testloss += loss.data[0]
    _, predict = torch.max(output, 1)
    num_correct = (predict == label).sum()
    testacc += num_correct.data[0]

# 計算並打印測試集的分類準確率
testloss /= len(testset)
testacc /= len(testset)
print("Test: Loss: %.5f, Acc: %.2f %%" %(testloss, 100*testacc))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章