Pytorch_第四篇_使用pytorch快速搭建神經網絡實現二分類任務(包含示例)

使用pytorch快速搭建神經網絡實現二分類任務(包含示例)


Introduce

上一篇學習筆記介紹了不使用pytorch包裝好的神經網絡框架實現logistic回歸模型,并且根據autograd實現了神經網絡參數更新。

本文介紹利用pytorch快速搭建神經網絡。即利用torch.nn以及torch.optim庫來快捷搭建一個簡單的神經網絡來實現二分類功能。

  • 利用pytorch已經包裝好的庫(torch.nn)來快速搭建神經網絡結構。
  • 利用已經包裝好的包含各種優化算法的庫(torch.optim)來優化神經網絡中的參數,如權值參數w和閾值參數b。

以下均為初學者筆記,如有錯誤請不吝指出。


Build a neural network structure

假設我們要搭建一個帶有兩個隱層的神經網絡來實現節點的二分類,輸入層包括2個節點(輸入節點特征),兩個隱層均包含5個節點(特征映射),輸出層包括2個節點(分別輸出屬于對應節點標簽的概率)。如下圖所示:


image

上圖從左右到右為輸入層、隱藏層、隱藏層、輸出層,各層之間采用全連接結構。神經網絡兩隱藏層的激活函數均采用sigmoid函數,輸出層最后采用softmax函數歸一化概率。

網絡搭建過程中使用的torch.nn相關模塊介紹如下:

  • torch.nn.Sequential:是一個時序容器,我們可以通過調用其構造器,將神經網絡模塊按照輸入層到輸出層的順序傳入,以此構造完整的神經網絡結構,具體用法參考如下神經網絡搭建代碼。
  • torch.nn.Linear:設置網絡中的全連接層,用來實現網絡中節點輸入的線性求和,即實現如下線性變換函數:

y = xA^T + b


'''
搭建神經網絡,
輸入層包括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)
)'''


Configure Loss Function and Optimizer

note: torch.optim庫中封裝了許多常用的優化方法,這邊使用了最常用的隨機梯度下降來優化網絡參數。例子中使用了交叉熵損失作為代價函數,其實torch.nn中也封裝了許多代價函數,具體可以查看官方文檔。對于pytorch中各種損失函數的學習以及優化方法的學習將在后期進行補充。
配置損失函數和優化器的代碼如下所示:

# 配置損失函數和優化器
optimizer = torch.optim.SGD(net.parameters(),lr=0.01) # 優化器使用隨機梯度下降,傳入網絡參數和學習率
loss_func = torch.nn.CrossEntropyLoss() # 損失函數使用交叉熵損失函數

Model Training

神經網絡訓練過程大致如下:首先輸入數據,接著神經網絡進行前向傳播,計算輸出層的輸出,進而計算預先定義好的損失(如本例中的交叉熵損失),接著進行誤差反向傳播,利用事先設置的優化方法(如本例中的隨機梯度下降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

本文參考-2

附完整代碼

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])


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,197評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,415評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,104評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,884評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,647評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,130評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,208評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,366評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,887評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,737評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,939評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,478評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,174評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,586評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,827評論 1 283
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,608評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,914評論 2 372