1. 程式人生 > >pytorch入門——邊學邊練04一個簡單網路

pytorch入門——邊學邊練04一個簡單網路

訪問本站觀看效果更佳

寫在前面

經過前面三節基礎課程,我們可以來一些更加複雜的內容了,今天我們一起來看一個簡單的神經網路是如何構成的,並仔細看看神經網路與之前的邏輯迴歸等課程有什麼區別。完整程式碼參見feedforward_neural_network

概念

前面和大家討論了線性分類器。但既然是線性的分類器,自然沒有辦法處理一些非線性結構,比如下圖:
image1
解決辦法是多層神經網路,底層神經元的輸出是高層神經元的輸入。我們可以在中間橫著畫一條線,再豎著畫一條線。每畫一條線就是使用了一個神經元。大家還記不記得上一節我們講到的利用10sigmod函式加上一個線性結構對手寫數字進行識別?如果我們把這些神經元的輸出當作輸入,後面再連線一個神經元就能達到很強的分類能力。原理性的知識點這裡不多做贅述,我們直接來講怎麼做吧!

目標以及思路

為了和先前的實驗進行對比,本節我們依然打算使用mnist資料集,進行手寫目標分類。這樣有一個好處,資料的載入以及整體的框架都不需要大的改動,我們可以集中精力把思路放在修改模型上。之前我們只使用了一個nn.Linear作為model,現在我們把它改掉,資料的介面都不用變,是不是很方便?

網路結構設計

複雜的事物往往是簡單事物的疊加。我們前面提到系統表達能力不足是因為線性的model限制了表達複雜模型的能力。我們需要把模型變成非線性結構。非線性結構如何來實現呢?這裡我們只需要做出一個微小的改動,增加一層啟用函式。從圖形上看,輸入和輸出無法再用一個線性的公式加以表達。有興趣的同學可以去看看deep learning

的相關書籍。我們重點看看網路設計。

# Fully connected neural network with one hidden layer
class NeuralNet(nn.Module):
    def __init__(self, input_size, hidden_size, num_classes):
        super(NeuralNet, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden_size) 
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(hidden_size, num_classes)  
    
    def forward(self, x):
        out = self.fc1(x)
        out = self.relu(out)
        out = self.fc2(out)
        return out

仔細觀察我們的改動非常簡單,像一個三明治一樣,兩個nn.Linear夾住了一個nn.ReLU。其中線性整流函式(Rectified Linear Unit, ReLU),又稱修正線性單元, 是一種人工神經網路中常用的啟用函式(activation function),通常指代以斜坡函式及其變種為代表的非線性函式。 相比於傳統的神經網路啟用函式,諸如邏輯函式(Logistic sigmoid)和tanh等雙曲函式,線性整流函式有著以下幾方面的優勢:
*更加有效率的梯度下降法以及反向傳播:避免了梯度爆炸和梯度消失問題

*簡化計算過程:沒有了其他複雜啟用函式中諸如指數函式的影響;同時活躍度的分散性使得神經網路整體計算成本下降

具體實現

為精簡篇幅,這裡我僅僅展示一部分操作:
首先現在可以用用GPU了,怎麼用呢?只需要定義device,然後告訴資料是把資料放到device裡計算還是放到numpy裡計算啊~

# Device configuration
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

反正都是套路,寫上就對了。
接著我們要問一個問題了,nn.Linear的輸入引數與資料有關,我們可以不去考慮,那麼hidden_size設定多少好呢?我們設定超引數如下:

# Hyper-parameters 
input_size = 784
hidden_size = 500
num_classes = 10
num_epochs = 5
batch_size = 100
learning_rate = 0.001

其實超引數的設定可能就是要多試試了,當然調參也是有技巧的。跑個幾輪看看loss變化幅度,自己估計一下,多試幾次就行。
列印一下網路結構:

NeuralNet(
  (fc1): Linear(in_features=784, out_features=500, bias=True)
  (relu): ReLU()
  (fc2): Linear(in_features=500, out_features=10, bias=True)
)

損失函式以及優化器:

# Loss and optimizer
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)  

結果如下:

Epoch [1/5], Step [100/600], Loss: 0.2624
Epoch [1/5], Step [200/600], Loss: 0.3268
Epoch [1/5], Step [300/600], Loss: 0.2965
Epoch [1/5], Step [400/600], Loss: 0.1089
Epoch [1/5], Step [500/600], Loss: 0.0886
Epoch [1/5], Step [600/600], Loss: 0.3102
Epoch [2/5], Step [100/600], Loss: 0.1234
Epoch [2/5], Step [200/600], Loss: 0.0823
……………………………………………………………………………………………………………
Epoch [4/5], Step [400/600], Loss: 0.0220
Epoch [4/5], Step [500/600], Loss: 0.0245
Epoch [4/5], Step [600/600], Loss: 0.0079
Epoch [5/5], Step [100/600], Loss: 0.0318
Epoch [5/5], Step [200/600], Loss: 0.1382
Epoch [5/5], Step [300/600], Loss: 0.0397
Epoch [5/5], Step [400/600], Loss: 0.0215
Epoch [5/5], Step [500/600], Loss: 0.0479
Epoch [5/5], Step [600/600], Loss: 0.0614
Accuracy of the network on the 10000 test images: 97.89 %

小結

我們前前後後折騰了那麼久,應該熟悉pytorch的基本操作了吧?後面我們來看點複雜的東西吧!未完待續