快速入门PyTorch(2)--如何构建一个神经网络
2019 第?43?篇,總第?67?篇文章
本文大約?4600?字,閱讀大約需要?10?分鐘
快速入門 PyTorch 教程第二篇,這篇介紹如何構建一個神經網絡。上一篇文章:
快速入門Pytorch(1)--安裝、張量以及梯度
本文的目錄:
3. 神經網絡
在 PyTorch 中?torch.nn?專門用于實現神經網絡。其中?nn.Module?包含了網絡層的搭建,以及一個方法--?forward(input)?,并返回網絡的輸出?outptu?.
下面是一個經典的 LeNet 網絡,用于對字符進行分類。
對于神經網絡來說,一個標準的訓練流程是這樣的:
定義一個多層的神經網絡
對數據集的預處理并準備作為網絡的輸入
將數據輸入到網絡
計算網絡的損失
反向傳播,計算梯度
更新網絡的梯度,一個簡單的更新規則是?weight = weight - learning_rate * gradient
3.1 定義網絡
首先定義一個神經網絡,下面是一個 5 層的卷積神經網絡,包含兩層卷積層和三層全連接層:
import?torch import?torch.nn?as?nn import?torch.nn.functional?as?Fclass?Net(nn.Module):def?__init__(self):super(Net,?self).__init__()#?輸入圖像是單通道,conv1?kenrnel?size=5*5,輸出通道?6self.conv1?=?nn.Conv2d(1,?6,?5)#?conv2?kernel?size=5*5,?輸出通道?16self.conv2?=?nn.Conv2d(6,?16,?5)#?全連接層self.fc1?=?nn.Linear(16*5*5,?120)self.fc2?=?nn.Linear(120,?84)self.fc3?=?nn.Linear(84,?10)def?forward(self,?x):#?max-pooling?采用一個?(2,2)?的滑動窗口x?=?F.max_pool2d(F.relu(self.conv1(x)),?(2,?2))#?核(kernel)大小是方形的話,可僅定義一個數字,如?(2,2)?用?2?即可x?=?F.max_pool2d(F.relu(self.conv2(x)),?2)x?=?x.view(-1,?self.num_flat_features(x))x?=?F.relu(self.fc1(x))x?=?F.relu(self.fc2(x))x?=?self.fc3(x)return?xdef?num_flat_features(self,?x):#?除了?batch?維度外的所有維度size?=?x.size()[1:]num_features?=?1for?s?in?size:num_features?*=?sreturn?num_featuresnet?=?Net() print(net)打印網絡結構:
Net((conv1):?Conv2d(1,?6,?kernel_size=(5,?5),?stride=(1,?1))(conv2):?Conv2d(6,?16,?kernel_size=(5,?5),?stride=(1,?1))(fc1):?Linear(in_features=400,?out_features=120,?bias=True)(fc2):?Linear(in_features=120,?out_features=84,?bias=True)(fc3):?Linear(in_features=84,?out_features=10,?bias=True) )這里必須實現?forward?函數,而?backward?函數在采用?autograd?時就自動定義好了,在?forward?方法可以采用任何的張量操作。
net.parameters()?可以返回網絡的訓練參數,使用例子如下:
params?=?list(net.parameters()) print('參數數量:?',?len(params)) #?conv1.weight print('第一個參數大小:?',?params[0].size())輸出:
參數數量:??10 第一個參數大小:??torch.Size([6,?1,?5,?5])然后簡單測試下這個網絡,隨機生成一個 32*32 的輸入:
#?隨機定義一個變量輸入網絡 input?=?torch.randn(1,?1,?32,?32) out?=?net(input) print(out)輸出結果:
tensor([[?0.1005,??0.0263,??0.0013,?-0.1157,?-0.1197,?-0.0141,??0.1425,?-0.0521,0.0689,??0.0220]],?grad_fn=<ThAddmmBackward>)接著反向傳播需要先清空梯度緩存,并反向傳播隨機梯度:
#?清空所有參數的梯度緩存,然后計算隨機梯度進行反向傳播 net.zero_grad() out.backward(torch.randn(1,?10))注意:
torch.nn?只支持小批量(mini-batches)數據,也就是輸入不能是單個樣本,比如對于?nn.Conv2d?接收的輸入是一個 4 維張量--nSamples * nChannels * Height * Width?。
所以,如果你輸入的是單個樣本,需要采用?input.unsqueeze(0)?來擴充一個假的 batch 維度,即從 3 維變為 4 維。
3.2 損失函數
損失函數的輸入是?(output, target)?,即網絡輸出和真實標簽對的數據,然后返回一個數值表示網絡輸出和真實標簽的差距。
PyTorch 中其實已經定義了不少的損失函數,這里僅采用簡單的均方誤差:nn.MSELoss?,例子如下:
output?=?net(input) #?定義偽標簽 target?=?torch.randn(10) #?調整大小,使得和?output?一樣的?size target?=?target.view(1,?-1) criterion?=?nn.MSELoss()loss?=?criterion(output,?target) print(loss)輸出如下:
tensor(0.6524,?grad_fn=<MseLossBackward>)這里,整個網絡的數據輸入到輸出經歷的計算圖如下所示,其實也就是數據從輸入層到輸出層,計算?loss?的過程。
input?->?conv2d?->?relu?->?maxpool2d?->?conv2d?->?relu?->?maxpool2d->?view?->?linear?->?relu?->?linear?->?relu?->?linear->?MSELoss->?loss如果調用?loss.backward()?,那么整個圖都是可微分的,也就是說包括?loss?,圖中的所有張量變量,只要其屬性?requires_grad=True?,那么其梯度?.grad張量都會隨著梯度一直累計。
用代碼來說明:
#?MSELoss print(loss.grad_fn) #?Linear?layer print(loss.grad_fn.next_functions[0][0]) #?Relu print(loss.grad_fn.next_functions[0][0].next_functions[0][0])輸出:
<MseLossBackward?object?at?0x0000019C0C349908><ThAddmmBackward?object?at?0x0000019C0C365A58><ExpandBackward?object?at?0x0000019C0C3659E8>3.3 反向傳播
反向傳播的實現只需要調用?loss.backward()?即可,當然首先需要清空當前梯度緩存,即.zero_grad()?方法,否則之前的梯度會累加到當前的梯度,這樣會影響權值參數的更新。
下面是一個簡單的例子,以?conv1?層的偏置參數?bias?在反向傳播前后的結果為例:
#?清空所有參數的梯度緩存 net.zero_grad() print('conv1.bias.grad?before?backward') print(net.conv1.bias.grad)loss.backward()print('conv1.bias.grad?after?backward') print(net.conv1.bias.grad)輸出結果:
conv1.bias.grad?before?backward tensor([0.,?0.,?0.,?0.,?0.,?0.])conv1.bias.grad?after?backward tensor([?0.0069,??0.0021,??0.0090,?-0.0060,?-0.0008,?-0.0073])了解更多有關?torch.nn?庫,可以查看官方文檔:
https://pytorch.org/docs/stable/nn.html
3.4 更新權重
采用隨機梯度下降(Stochastic Gradient Descent, SGD)方法的最簡單的更新權重規則如下:
weight = weight - learning_rate * gradient
按照這個規則,代碼實現如下所示:
#?簡單實現權重的更新例子 learning_rate?=?0.01 for?f?in?net.parameters():f.data.sub_(f.grad.data?*?learning_rate)但是這只是最簡單的規則,深度學習有很多的優化算法,不僅僅是?SGD,還有?Nesterov-SGD, Adam, RMSProp?等等,為了采用這些不同的方法,這里采用?torch.optim?庫,使用例子如下所示:
import?torch.optim?as?optim #?創建優化器 optimizer?=?optim.SGD(net.parameters(),?lr=0.01)#?在訓練過程中執行下列操作 optimizer.zero_grad()?#?清空梯度緩存 output?=?net(input) loss?=?criterion(output,?target) loss.backward() #?更新權重 optimizer.step()注意,同樣需要調用?optimizer.zero_grad()?方法清空梯度緩存。
本小節教程:
https://pytorch.org/tutorials/beginner/blitz/neural_networks_tutorial.html
本小節的代碼:
https://github.com/ccc013/DeepLearning_Notes/blob/master/Pytorch/practise/neural_network.ipynb
小結
第二篇主要介紹了搭建一個神經網絡,包括定義網絡、選擇損失函數、反向傳播計算梯度和更新權值參數。
歡迎關注我的微信公眾號--機器學習與計算機視覺,或者掃描下方的二維碼,大家一起交流,學習和進步!
往期精彩推薦
機器學習系列
初學者的機器學習入門實戰教程!
模型評估、過擬合欠擬合以及超參數調優方法
常用機器學習算法匯總比較(完)
常用機器學習算法匯總比較(上)
機器學習入門系列(2)--如何構建一個完整的機器學習項目(一)
特征工程之數據預處理(上)
來了解下計算機視覺的八大應用
Github項目 & 資源教程推薦
[Github 項目推薦] 一個更好閱讀和查找論文的網站
[資源分享] TensorFlow 官方中文版教程來了
必讀的AI和深度學習博客
[教程]一份簡單易懂的 TensorFlow 教程
[資源]推薦一些Python書籍和教程,入門和進階的都有!
[Github項目推薦] 機器學習& Python 知識點速查表
[Github項目推薦] 推薦三個助你更好利用Github的工具
Github上的各大高校資料以及國外公開課視頻
這些單詞你都念對了嗎?順便推薦三份程序員專屬英語教程!
總結
以上是生活随笔為你收集整理的快速入门PyTorch(2)--如何构建一个神经网络的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WAP PUSH
- 下一篇: 联网时浏览器跳出MSN中国