上一篇學習筆記介紹了不使用pytorch包裝好的神經網絡框架實現logistic迴歸模型,而且根據autograd實現了神經網絡參數更新。html
本文介紹利用pytorch快速搭建神經網絡。即利用torch.nn以及torch.optim庫來快捷搭建一個簡單的神經網絡來實現二分類功能。git
如下均爲初學者筆記。github
假設咱們要搭建一個帶有兩個隱層的神經網絡來實現節點的二分類,輸入層包括2個節點(輸入節點特徵),兩個隱層均包含5個節點(特徵映射),輸出層包括2個節點(分別輸出屬於對應節點標籤的機率)。以下圖所示:
算法
上圖從左右到右爲輸入層、隱藏層、隱藏層、輸出層,各層之間採用全鏈接結構。神經網絡兩隱藏層的激活函數均採用sigmoid函數,輸出層最後採用softmax函數歸一化機率。網絡
網絡搭建過程當中使用的torch.nn相關模塊介紹以下:框架
''' 搭建神經網絡, 輸入層包括2個節點,兩個隱層均包含5個節點,輸出層包括1個節點。''' net = nn.Sequential( nn.Linear(2,5), # 輸入層與第一隱層結點數設置,全鏈接結構 torch.nn.Sigmoid(), # 第一隱層激活函數採用sigmoid nn.Linear(5,5), # 第一隱層與第二隱層結點數設置,全鏈接結構 torch.nn.Sigmoid(), # 第一隱層激活函數採用sigmoid nn.Linear(5,2), # 第二隱層與輸出層層結點數設置,全鏈接結構 nn.Softmax(dim=1) # 因爲有兩個機率輸出,所以對其使用Softmax進行機率歸一化,dim=1表明行歸一化 ) print(net) ''' Sequential( (0): Linear(in_features=2, out_features=5, bias=True) (1): Sigmoid() (2): Linear(in_features=5, out_features=5, bias=True) (3): Sigmoid() (4): Linear(in_features=5, out_features=2, bias=True) (5): Softmax(dim=1) )'''
note: torch.optim庫中封裝了許多經常使用的優化方法,這邊使用了最經常使用的隨機梯度降低來優化網絡參數。例子中使用了交叉熵損失做爲代價函數,其實torch.nn中也封裝了許多代價函數,具體能夠查看官方文檔。對於pytorch中各類損失函數的學習以及優化方法的學習將在後期進行補充。
配置損失函數和優化器的代碼以下所示:函數
# 配置損失函數和優化器 optimizer = torch.optim.SGD(net.parameters(),lr=0.01) # 優化器使用隨機梯度降低,傳入網絡參數和學習率 loss_func = torch.nn.CrossEntropyLoss() # 損失函數使用交叉熵損失函數
神經網絡訓練過程大體以下:首先輸入數據,接着神經網絡進行前向傳播,計算輸出層的輸出,進而計算預先定義好的損失(如本例中的交叉熵損失),接着進行偏差反向傳播,利用事先設置的優化方法(如本例中的隨機梯度降低SGD)來更新網絡中的參數,如權值參數w和閾值參數b。接着反覆進行上述迭代,達到最大迭代次數(num_epoch)或者損失值知足某條件以後訓練中止,從而咱們能夠獲得一個由大量數據訓練完成的神經網絡模型。模型訓練的代碼以下所示:學習
# 模型訓練 num_epoch = 10000 # 最大迭代更新次數 for epoch in range(num_epoch): y_p = net(x_t) # 喂數據並前向傳播 loss = loss_func(y_p,y_t.long()) # 計算損失 ''' PyTorch默認會對梯度進行累加,所以爲了避免使得以前計算的梯度影響到當前計算,須要手動清除梯度。 pyTorch這樣子設置也有許多好處,可是因爲我的能力,還沒徹底弄懂。 ''' optimizer.zero_grad() # 清除梯度 loss.backward() # 計算梯度,偏差回傳 optimizer.step() # 根據計算的梯度,更新網絡中的參數 if epoch % 1000 == 0: print('epoch: {}, loss: {}'.format(epoch, loss.data.item())) ''' 每1000次輸出損失以下: epoch: 0, loss: 0.7303197979927063 epoch: 1000, loss: 0.669952392578125 epoch: 2000, loss: 0.6142827868461609 epoch: 3000, loss: 0.5110923051834106 epoch: 4000, loss: 0.4233965575695038 epoch: 5000, loss: 0.37978556752204895 epoch: 6000, loss: 0.3588798940181732 epoch: 7000, loss: 0.3476340174674988 ...... ''' print("全部樣本的預測標籤: \n",torch.max(y_p,dim = 1)[1]) ''' note:能夠發現前100個標籤預測爲0,後100個樣本標籤預測爲1。所以所訓練模型能夠正確預測訓練集標籤。 全部樣本的預測標籤: tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) '''
'''兩種保存方式 第一種: 保存網絡的全部參數(包括網絡結構) torch.save(net,'net.pkl') 對應加載方式: net1 = torch.load('net.pkl') 第二種: 僅保存網絡中須要訓練的參數 ,即net.state_dict(),如權值參數w和閾值參數b。(不包括網絡結構) torch.save(net.state_dict(),'net_parameter.pkl') 對應加載方式: 加載時須要提供兩個信息: 第一: 網絡結構信息,須要先從新搭建和保存的網絡一樣的網絡結構。 第二: 保存的網絡中的參數的信息,權值和閾值參數。 具體加載方式以下: net = nn.Sequential( nn.Linear(2,5), torch.nn.Sigmoid(), nn.Linear(5,5), torch.nn.Sigmoid(), nn.Linear(5,2), nn.Softmax(dim=1) ) net2.load_state_dict(torch.load('net_parameter.pkl') '''
本文參考-1優化
本文參考-2ui
import torch import torch.nn as nn ''' 使用正態分佈隨機生成兩類數據 第一類有100個點,使用均值爲2,標準差爲1的正態分佈隨機生成,標籤爲0。 第二類有100個點,使用均值爲-2,標準差爲1的正態分佈隨機生成,標籤爲1。 torch.normal(tensor1,tensor2) 輸入兩個張量,tensor1爲正態分佈的均值,tensor2爲正態分佈的標準差。 torch.normal以此抽取tensor1和tensor2中對應位置的元素值構造對應的正態分佈以隨機生成數據,返回數據張量。 ''' x1_t = torch.normal(2*torch.ones(100,2),1) y1_t = torch.zeros(100) x2_t = torch.normal(-2*torch.ones(100,2),1) y2_t = torch.ones(100) x_t = torch.cat((x1_t,x2_t),0) y_t = torch.cat((y1_t,y2_t),0) ''' 搭建神經網絡, 輸入層包括2個節點,兩個隱層均包含5個節點,輸出層包括1個節點。 ''' net = nn.Sequential( nn.Linear(2,5), # 輸入層與第一隱層結點數設置,全鏈接結構 torch.nn.Sigmoid(), # 第一隱層激活函數採用sigmoid nn.Linear(5,5), # 第一隱層與第二隱層結點數設置,全鏈接結構 torch.nn.Sigmoid(), # 第一隱層激活函數採用sigmoid nn.Linear(5,2), # 第二隱層與輸出層層結點數設置,全鏈接結構 nn.Softmax(dim=1) # 因爲有兩個機率輸出,所以對其使用Softmax進行機率歸一化 ) print(net) ''' Sequential( (0): Linear(in_features=2, out_features=5, bias=True) (1): Sigmoid() (2): Linear(in_features=5, out_features=5, bias=True) (3): Sigmoid() (4): Linear(in_features=5, out_features=2, bias=True) (5): Softmax(dim=1) )''' # 配置損失函數和優化器 optimizer = torch.optim.SGD(net.parameters(),lr=0.01) # 優化器使用隨機梯度降低,傳入網絡參數和學習率 loss_func = torch.nn.CrossEntropyLoss() # 損失函數使用交叉熵損失函數 # 模型訓練 num_epoch = 10000 # 最大迭代更新次數 for epoch in range(num_epoch): y_p = net(x_t) # 喂數據並前向傳播 loss = loss_func(y_p,y_t.long()) # 計算損失 ''' PyTorch默認會對梯度進行累加,所以爲了避免使得以前計算的梯度影響到當前計算,須要手動清除梯度。 pyTorch這樣子設置也有許多好處,可是因爲我的能力,還沒徹底弄懂。 ''' optimizer.zero_grad() # 清除梯度 loss.backward() # 計算梯度,偏差回傳 optimizer.step() # 根據計算的梯度,更新網絡中的參數 if epoch % 1000 == 0: print('epoch: {}, loss: {}'.format(epoch, loss.data.item())) ''' torch.max(y_p,dim = 1)[0]是每行最大的值 torch.max(y_p,dim = 1)[0]是每行最大的值的下標,可認爲標籤 ''' print("全部樣本的預測標籤: \n",torch.max(y_p,dim = 1)[1])