多層感知機的從零開始實現——2020.2.24


其他博客:

多層感知機概述:https://www.cnblogs.com/somedayLi/p/12313804.html
多層感知機簡潔實現:https:////www.cnblogs.com/somedayLi/p/12359420.html

下⾯實現⼀個多層感知機。⾸先導⼊實現所需的包或模塊。

# 導包
import torch
import numpy as np
import sys
sys.path.append("..")
import d2lzh_pytorch as d2l

1. 獲取和讀取數據:

這⾥繼續使⽤Fashion-MNIST數據集。我們將使⽤多層感知機對圖像進⾏分類。

# 1.獲取和讀取數據
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

2. 定義模型參數

Fashion-MNIST數據集中圖像形狀為\(28 \times 28\),類別數為 10 。本節中我們依然使⽤⻓度為 \(28 \times 28 = 784\) 的向量表示每⼀張圖像。因此,輸⼊個數為784,輸出個數為10。實驗中,我們設超參數隱藏單元個數為256。

# 2 定義模型參數
num_inputs, num_outputs, num_hiddens = 784, 10, 256

w1 = torch.tensor(np.random.normal(0, 0.01, (num_inputs, num_hiddens)),dtype=torch.float)
b1 = torch.zeros(num_hiddens, dtype=torch.float)
w2 = torch.tensor(np.random.normal(0, 0.01, (num_hiddens, num_outputs)), dtype=torch.float)
b2 = torch.zeros(num_outputs, dtype=torch.float)

params = [w1, b1, w2, b2]
for param in params:
    param.requires_grad_(requires_grad=True)

3. 定義激活函數

使⽤基礎的 max 函數來實現ReLU,⽽⾮直接調⽤ relu 函數。

# 3 定義激活函數
def relu(x):
    return torch.max(input=x, other=torch.tensor(0.0))

4. 定義模型

同softmax回歸⼀樣,我們通過 view 函數將每張原始圖像改成⻓度為 num_inputs 的向量。然后實現概述中的多層感知機的計算表達式。

# 4 定義模型
def net(x):
    x = x.view((-1, num_inputs))
    H = relu(torch.matmul(x,w1) + b1)
    return torch.matmul(H, w2) + b2

5. 定義損失函數

為了得到更好的數值穩定性,我們直接使⽤PyTorch提供的包括softmax運算和交叉熵損失計算的函數。

# 5 定義損失函數
loss = torch.nn.CrossEntropyLoss()

6. 訓練模型

訓練多層感知機的步驟和3.6節中訓練softmax回歸的步驟沒什么區別。我們直接調⽤ d2lzh_pytorch 包中的 train_ch3 函數,它的實現已經在3.6節⾥介紹過。我們在這⾥設超參數迭代周期數為5,學習率為100.0。

注:由於原書的mxnet中的 SoftmaxCrossEntropyLoss 在反向傳播的時候相對於沿batch維求和了,⽽PyTorch默認的是求平均,所以⽤PyTorch計算得到的loss⽐mxnet⼩很多(⼤概是maxnet計算得到的1/batch_size這個量級),所以反向傳播得到的梯度也⼩很多,所以為了得到差不多的學習效果,我們把學習率調得成原書的約batch_size倍,原書的學習率為0.5,這⾥設置成100.0。(之所以這么⼤,應該是因為d2lzh_pytorch⾥⾯的sgd函數在更新的時候除以了batch_size,其實PyTorch在計算loss的時候已經除過⼀次了,sgd這⾥應該不⽤除了)

# 6 訓練模型
num_epochs, lr = 5, 100.0
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params, lr)

這一步稍稍費時一點,花了大概1min左右。
運行結果:

epoch 1, loss 0.0031, train acc 0.713, test acc 0.815
epoch 2, loss 0.0019, train acc 0.826, test acc 0.817
epoch 3, loss 0.0017, train acc 0.843, test acc 0.754
epoch 4, loss 0.0015, train acc 0.857, test acc 0.799
epoch 5, loss 0.0014, train acc 0.866, test acc 0.860

從上述結果中,即可看出不同損失函數下的准確率的變化,隨着訓練周期越長,損失函數值減小、准確率更高。
對第6步訓練模型稍作修改,輸出運行時間。修改后的代碼:

# 6 訓練模型
import time
num_epochs, lr = 5, 100.0
start = time.time()
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params, lr)
print(time.time() - start)

第二次運行訓練模型訓練結果:

epoch 1, loss 0.0014, train acc 0.870, test acc 0.860
epoch 2, loss 0.0013, train acc 0.876, test acc 0.833
epoch 3, loss 0.0013, train acc 0.880, test acc 0.841
epoch 4, loss 0.0012, train acc 0.885, test acc 0.844
epoch 5, loss 0.0012, train acc 0.887, test acc 0.841
132.66817021369934

第三次運行結果

epoch 1, loss 0.0012, train acc 0.890, test acc 0.872
epoch 2, loss 0.0011, train acc 0.894, test acc 0.808
epoch 3, loss 0.0011, train acc 0.894, test acc 0.870
epoch 4, loss 0.0011, train acc 0.897, test acc 0.869
epoch 5, loss 0.0010, train acc 0.900, test acc 0.873
118.6175651550293

我做了一個嘗試,將學習周期設為10、20,繼續運行:

  • 將學習周期設為10,運行結果:
epoch 1, loss 0.0010, train acc 0.901, test acc 0.876
epoch 2, loss 0.0010, train acc 0.904, test acc 0.857
epoch 3, loss 0.0010, train acc 0.906, test acc 0.854
epoch 4, loss 0.0010, train acc 0.907, test acc 0.862
epoch 5, loss 0.0010, train acc 0.909, test acc 0.826
epoch 6, loss 0.0009, train acc 0.911, test acc 0.865
epoch 7, loss 0.0009, train acc 0.912, test acc 0.884
epoch 8, loss 0.0009, train acc 0.914, test acc 0.884
epoch 9, loss 0.0009, train acc 0.916, test acc 0.881
epoch 10, loss 0.0009, train acc 0.916, test acc 0.856
234.6531686782837
  • 將學習周期設為20,運行結果:
epoch 1, loss 0.0009, train acc 0.917, test acc 0.871
epoch 2, loss 0.0009, train acc 0.918, test acc 0.875
epoch 3, loss 0.0008, train acc 0.922, test acc 0.867
epoch 4, loss 0.0008, train acc 0.923, test acc 0.873
epoch 5, loss 0.0008, train acc 0.924, test acc 0.885
epoch 6, loss 0.0008, train acc 0.925, test acc 0.886
epoch 7, loss 0.0008, train acc 0.926, test acc 0.885
epoch 8, loss 0.0008, train acc 0.926, test acc 0.883
epoch 9, loss 0.0008, train acc 0.929, test acc 0.893
epoch 10, loss 0.0007, train acc 0.929, test acc 0.872
epoch 11, loss 0.0007, train acc 0.930, test acc 0.871
epoch 12, loss 0.0007, train acc 0.932, test acc 0.882
epoch 13, loss 0.0007, train acc 0.933, test acc 0.887
epoch 14, loss 0.0007, train acc 0.934, test acc 0.867
epoch 15, loss 0.0007, train acc 0.935, test acc 0.885
epoch 16, loss 0.0007, train acc 0.936, test acc 0.885
epoch 17, loss 0.0007, train acc 0.937, test acc 0.880
epoch 18, loss 0.0007, train acc 0.937, test acc 0.854
epoch 19, loss 0.0007, train acc 0.939, test acc 0.893
epoch 20, loss 0.0006, train acc 0.939, test acc 0.886
490.9914619922638

不過,這樣訓練下去,因為是全連接層,也很可能導致過擬合,關於防止過擬合,在后續的博客中將持續更新。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM