使用 PyTorch 實現(xiàn) MLP 并在 MNIST 數(shù)據(jù)集上驗證方式
簡介
這是深度學習課程的第一個實驗,主要目的就是熟悉 Pytorch 框架。MLP 是多層感知器,我這次實現(xiàn)的是四層感知器,代碼和思路參考了網(wǎng)上的很多文章。個人認為,感知器的代碼大同小異,尤其是用 Pytorch 實現(xiàn),除了層數(shù)和參數(shù)外,代碼都很相似。
Pytorch 寫神經(jīng)網(wǎng)絡的主要步驟主要有以下幾步:
1 構建網(wǎng)絡結構
2 加載數(shù)據(jù)集
3 訓練神經(jīng)網(wǎng)絡(包括優(yōu)化器的選擇和 Loss 的計算)
4 測試神經(jīng)網(wǎng)絡
下面將從這四個方面介紹 Pytorch 搭建 MLP 的過程。
項目代碼地址:lab1
過程
構建網(wǎng)絡結構
神經(jīng)網(wǎng)絡最重要的就是搭建網(wǎng)絡,第一步就是定義網(wǎng)絡結構。我這里是創(chuàng)建了一個四層的感知器,參數(shù)是根據(jù) MNIST 數(shù)據(jù)集設定的,網(wǎng)絡結構如下:
# 建立一個四層感知機網(wǎng)絡
class MLP(torch.nn.Module): # 繼承 torch 的 Module
def __init__(self):
super(MLP,self).__init__() #
# 初始化三層神經(jīng)網(wǎng)絡 兩個全連接的隱藏層,一個輸出層
self.fc1 = torch.nn.Linear(784,512) # 第一個隱含層
self.fc2 = torch.nn.Linear(512,128) # 第二個隱含層
self.fc3 = torch.nn.Linear(128,10) # 輸出層
def forward(self,din):
# 前向傳播, 輸入值:din, 返回值 dout
din = din.view(-1,28*28) # 將一個多行的Tensor,拼接成一行
dout = F.relu(self.fc1(din)) # 使用 relu 激活函數(shù)
dout = F.relu(self.fc2(dout))
dout = F.softmax(self.fc3(dout), dim=1) # 輸出層使用 softmax 激活函數(shù)
# 10個數(shù)字實際上是10個類別,輸出是概率分布,最后選取概率最大的作為預測值輸出
return dout
網(wǎng)絡結構其實很簡單,設置了三層 Linear。隱含層激活函數(shù)使用 Relu; 輸出層使用 Softmax。網(wǎng)上還有其他的結構使用了 droupout,我覺得入門的話有點高級,而且放在這里并沒有什么用,搞得很麻煩還不能提高準確率。
加載數(shù)據(jù)集
第二步就是定義全局變量,并加載 MNIST 數(shù)據(jù)集:
# 定義全局變量 n_epochs = 10 # epoch 的數(shù)目 batch_size = 20 # 決定每次讀取多少圖片 # 定義訓練集個測試集,如果找不到數(shù)據(jù),就下載 train_data = datasets.MNIST(root = './data', train = True, download = True, transform = transforms.ToTensor()) test_data = datasets.MNIST(root = './data', train = True, download = True, transform = transforms.ToTensor()) # 創(chuàng)建加載器 train_loader = torch.utils.data.DataLoader(train_data, batch_size = batch_size, num_workers = 0) test_loader = torch.utils.data.DataLoader(test_data, batch_size = batch_size, num_workers = 0)
這里參數(shù)很多,所以就有很多需要注意的地方了:
root 參數(shù)的文件夾即使不存在也沒關系,會自動創(chuàng)建
transform 參數(shù),如果不知道要對數(shù)據(jù)集進行什么變化,這里可自動忽略
batch_size 參數(shù)的大小決定了一次訓練多少數(shù)據(jù),相當于定義了每個 epoch 中反向傳播的次數(shù)
num_workers 參數(shù)默認是 0,即不并行處理數(shù)據(jù);我這里設置大于 0 的時候,總是報錯,建議設成默認值
如果不理解 epoch 和 batch_size,可以上網(wǎng)查一下資料。(我剛開始學深度學習的時候也是不懂的)
訓練神經(jīng)網(wǎng)絡
第三步就是訓練網(wǎng)絡了,代碼如下:
# 訓練神經(jīng)網(wǎng)絡
def train():
# 定義損失函數(shù)和優(yōu)化器
lossfunc = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(params = model.parameters(), lr = 0.01)
# 開始訓練
for epoch in range(n_epochs):
train_loss = 0.0
for data,target in train_loader:
optimizer.zero_grad() # 清空上一步的殘余更新參數(shù)值
output = model(data) # 得到預測值
loss = lossfunc(output,target) # 計算兩者的誤差
loss.backward() # 誤差反向傳播, 計算參數(shù)更新值
optimizer.step() # 將參數(shù)更新值施加到 net 的 parameters 上
train_loss += loss.item()*data.size(0)
train_loss = train_loss / len(train_loader.dataset)
print('Epoch: {} \tTraining Loss: {:.6f}'.format(epoch + 1, train_loss))
訓練之前要定義損失函數(shù)和優(yōu)化器,這里其實有很多學問,但本文就不講了,理論太多了。
訓練過程就是兩層 for 循環(huán):外層是遍歷訓練集的次數(shù);內層是每次的批次(batch)。最后,輸出每個 epoch 的 loss。(每次訓練的目的是使 loss 函數(shù)減小,以達到訓練集上更高的準確率)
測試神經(jīng)網(wǎng)絡
最后,就是在測試集上進行測試,代碼如下:
# 在數(shù)據(jù)集上測試神經(jīng)網(wǎng)絡
def test():
correct = 0
total = 0
with torch.no_grad(): # 訓練集中不需要反向傳播
for data in test_loader:
images, labels = data
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy of the network on the test images: %d %%' % (
100 * correct / total))
return 100.0 * correct / total
這個測試的代碼是同學給我的,我覺得這個測試的代碼特別好,很簡潔,一直用的這個。
代碼首先設置 torch.no_grad(),定義后面的代碼不需要計算梯度,能夠節(jié)省一些內存空間。然后,對測試集中的每個 batch 進行測試,統(tǒng)計總數(shù)和準確數(shù),最后計算準確率并輸出。
通常是選擇邊訓練邊測試的,這里先就按步驟一步一步來做。
有的測試代碼前面要加上 model.eval(),表示這是訓練狀態(tài)。但這里不需要,如果沒有 Batch Normalization 和 Dropout 方法,加和不加的效果是一樣的。
完整代碼
'''
系統(tǒng)環(huán)境: Windows10
Python版本: 3.7
PyTorch版本: 1.1.0
cuda: no
'''
import torch
import torch.nn.functional as F # 激勵函數(shù)的庫
from torchvision import datasets
import torchvision.transforms as transforms
import numpy as np
# 定義全局變量
n_epochs = 10 # epoch 的數(shù)目
batch_size = 20 # 決定每次讀取多少圖片
# 定義訓練集個測試集,如果找不到數(shù)據(jù),就下載
train_data = datasets.MNIST(root = './data', train = True, download = True, transform = transforms.ToTensor())
test_data = datasets.MNIST(root = './data', train = True, download = True, transform = transforms.ToTensor())
# 創(chuàng)建加載器
train_loader = torch.utils.data.DataLoader(train_data, batch_size = batch_size, num_workers = 0)
test_loader = torch.utils.data.DataLoader(test_data, batch_size = batch_size, num_workers = 0)
# 建立一個四層感知機網(wǎng)絡
class MLP(torch.nn.Module): # 繼承 torch 的 Module
def __init__(self):
super(MLP,self).__init__() #
# 初始化三層神經(jīng)網(wǎng)絡 兩個全連接的隱藏層,一個輸出層
self.fc1 = torch.nn.Linear(784,512) # 第一個隱含層
self.fc2 = torch.nn.Linear(512,128) # 第二個隱含層
self.fc3 = torch.nn.Linear(128,10) # 輸出層
def forward(self,din):
# 前向傳播, 輸入值:din, 返回值 dout
din = din.view(-1,28*28) # 將一個多行的Tensor,拼接成一行
dout = F.relu(self.fc1(din)) # 使用 relu 激活函數(shù)
dout = F.relu(self.fc2(dout))
dout = F.softmax(self.fc3(dout), dim=1) # 輸出層使用 softmax 激活函數(shù)
# 10個數(shù)字實際上是10個類別,輸出是概率分布,最后選取概率最大的作為預測值輸出
return dout
# 訓練神經(jīng)網(wǎng)絡
def train():
#定義損失函數(shù)和優(yōu)化器
lossfunc = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(params = model.parameters(), lr = 0.01)
# 開始訓練
for epoch in range(n_epochs):
train_loss = 0.0
for data,target in train_loader:
optimizer.zero_grad() # 清空上一步的殘余更新參數(shù)值
output = model(data) # 得到預測值
loss = lossfunc(output,target) # 計算兩者的誤差
loss.backward() # 誤差反向傳播, 計算參數(shù)更新值
optimizer.step() # 將參數(shù)更新值施加到 net 的 parameters 上
train_loss += loss.item()*data.size(0)
train_loss = train_loss / len(train_loader.dataset)
print('Epoch: {} \tTraining Loss: {:.6f}'.format(epoch + 1, train_loss))
# 每遍歷一遍數(shù)據(jù)集,測試一下準確率
test()
# 在數(shù)據(jù)集上測試神經(jīng)網(wǎng)絡
def test():
correct = 0
total = 0
with torch.no_grad(): # 訓練集中不需要反向傳播
for data in test_loader:
images, labels = data
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy of the network on the test images: %d %%' % (
100 * correct / total))
return 100.0 * correct / total
# 聲明感知器網(wǎng)絡
model = MLP()
if __name__ == '__main__':
train()
10 個 epoch 的訓練效果,最后能達到大約 85% 的準確率??梢赃m當增加 epoch,但代碼里沒有用 gpu 運行,可能會比較慢。
以上這篇使用 PyTorch 實現(xiàn) MLP 并在 MNIST 數(shù)據(jù)集上驗證方式就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Python EOL while scanning string literal問題解決方法
這篇文章主要介紹了Python EOL while scanning string literal問題解決方法,本文總結出是數(shù)據(jù)庫數(shù)據(jù)出現(xiàn)問題導致這個問題,需要的朋友可以參考下2015-04-04
matplotlib.pyplot畫圖 圖片的二進制流的獲取方法
今天小編就為大家分享一篇matplotlib.pyplot畫圖 圖片的二進制流的獲取方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-05-05
Python中使用ConfigParser解析ini配置文件實例
這篇文章主要介紹了Python中使用ConfigParser解析ini配置文件實例,本文給出了創(chuàng)建和讀取ini文件的例子,需要的朋友可以參考下2014-08-08
分析解決Python中sqlalchemy數(shù)據(jù)庫連接池QueuePool異常
這篇文章主要來給大家分析sqlalchemy數(shù)據(jù)庫連接池QueuePool的異常,給大家用詳細的圖文方式做出了解決的方案,有需要的朋友可以借鑒參考下,希望可以有所幫助2021-09-09

