目錄
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))