您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關(guān)怎么使用PyTorch實(shí)現(xiàn)MLP并在MNIST數(shù)據(jù)集上驗(yàn)證的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。
簡(jiǎn)介
這是深度學(xué)習(xí)課程的第一個(gè)實(shí)驗(yàn),主要目的就是熟悉 Pytorch 框架。MLP 是多層感知器,我這次實(shí)現(xiàn)的是四層感知器,代碼和思路參考了網(wǎng)上的很多文章。個(gè)人認(rèn)為,感知器的代碼大同小異,尤其是用 Pytorch 實(shí)現(xiàn),除了層數(shù)和參數(shù)外,代碼都很相似。
Pytorch 寫神經(jīng)網(wǎng)絡(luò)的主要步驟主要有以下幾步:
1 構(gòu)建網(wǎng)絡(luò)結(jié)構(gòu)
2 加載數(shù)據(jù)集
3 訓(xùn)練神經(jīng)網(wǎng)絡(luò)(包括優(yōu)化器的選擇和 Loss 的計(jì)算)
4 測(cè)試神經(jīng)網(wǎng)絡(luò)
下面將從這四個(gè)方面介紹 Pytorch 搭建 MLP 的過(guò)程。
項(xiàng)目代碼地址:lab1
過(guò)程
構(gòu)建網(wǎng)絡(luò)結(jié)構(gòu)
神經(jīng)網(wǎng)絡(luò)最重要的就是搭建網(wǎng)絡(luò),第一步就是定義網(wǎng)絡(luò)結(jié)構(gòu)。我這里是創(chuàng)建了一個(gè)四層的感知器,參數(shù)是根據(jù) MNIST 數(shù)據(jù)集設(shè)定的,網(wǎng)絡(luò)結(jié)構(gòu)如下:
# 建立一個(gè)四層感知機(jī)網(wǎng)絡(luò) class MLP(torch.nn.Module): # 繼承 torch 的 Module def __init__(self): super(MLP,self).__init__() # # 初始化三層神經(jīng)網(wǎng)絡(luò) 兩個(gè)全連接的隱藏層,一個(gè)輸出層 self.fc1 = torch.nn.Linear(784,512) # 第一個(gè)隱含層 self.fc2 = torch.nn.Linear(512,128) # 第二個(gè)隱含層 self.fc3 = torch.nn.Linear(128,10) # 輸出層 def forward(self,din): # 前向傳播, 輸入值:din, 返回值 dout din = din.view(-1,28*28) # 將一個(gè)多行的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個(gè)數(shù)字實(shí)際上是10個(gè)類別,輸出是概率分布,最后選取概率最大的作為預(yù)測(cè)值輸出 return dout
網(wǎng)絡(luò)結(jié)構(gòu)其實(shí)很簡(jiǎn)單,設(shè)置了三層 Linear。隱含層激活函數(shù)使用 Relu; 輸出層使用 Softmax。網(wǎng)上還有其他的結(jié)構(gòu)使用了 droupout,我覺(jué)得入門的話有點(diǎn)高級(jí),而且放在這里并沒(méi)有什么用,搞得很麻煩還不能提高準(zhǔn)確率。
加載數(shù)據(jù)集
第二步就是定義全局變量,并加載 MNIST 數(shù)據(jù)集:
# 定義全局變量 n_epochs = 10 # epoch 的數(shù)目 batch_size = 20 # 決定每次讀取多少圖片 # 定義訓(xùn)練集個(gè)測(cè)試集,如果找不到數(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ù)的文件夾即使不存在也沒(méi)關(guān)系,會(huì)自動(dòng)創(chuàng)建
transform 參數(shù),如果不知道要對(duì)數(shù)據(jù)集進(jìn)行什么變化,這里可自動(dòng)忽略
batch_size 參數(shù)的大小決定了一次訓(xùn)練多少數(shù)據(jù),相當(dāng)于定義了每個(gè) epoch 中反向傳播的次數(shù)
num_workers 參數(shù)默認(rèn)是 0,即不并行處理數(shù)據(jù);我這里設(shè)置大于 0 的時(shí)候,總是報(bào)錯(cuò),建議設(shè)成默認(rèn)值
如果不理解 epoch 和 batch_size,可以上網(wǎng)查一下資料。(我剛開(kāi)始學(xué)深度學(xué)習(xí)的時(shí)候也是不懂的)
訓(xùn)練神經(jīng)網(wǎng)絡(luò)
第三步就是訓(xùn)練網(wǎng)絡(luò)了,代碼如下:
# 訓(xùn)練神經(jīng)網(wǎng)絡(luò) def train(): # 定義損失函數(shù)和優(yōu)化器 lossfunc = torch.nn.CrossEntropyLoss() optimizer = torch.optim.SGD(params = model.parameters(), lr = 0.01) # 開(kāi)始訓(xùn)練 for epoch in range(n_epochs): train_loss = 0.0 for data,target in train_loader: optimizer.zero_grad() # 清空上一步的殘余更新參數(shù)值 output = model(data) # 得到預(yù)測(cè)值 loss = lossfunc(output,target) # 計(jì)算兩者的誤差 loss.backward() # 誤差反向傳播, 計(jì)算參數(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))
訓(xùn)練之前要定義損失函數(shù)和優(yōu)化器,這里其實(shí)有很多學(xué)問(wèn),但本文就不講了,理論太多了。
訓(xùn)練過(guò)程就是兩層 for 循環(huán):外層是遍歷訓(xùn)練集的次數(shù);內(nèi)層是每次的批次(batch)。最后,輸出每個(gè) epoch 的 loss。(每次訓(xùn)練的目的是使 loss 函數(shù)減小,以達(dá)到訓(xùn)練集上更高的準(zhǔn)確率)
測(cè)試神經(jīng)網(wǎng)絡(luò)
最后,就是在測(cè)試集上進(jìn)行測(cè)試,代碼如下:
# 在數(shù)據(jù)集上測(cè)試神經(jīng)網(wǎng)絡(luò) def test(): correct = 0 total = 0 with torch.no_grad(): # 訓(xùn)練集中不需要反向傳播 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
這個(gè)測(cè)試的代碼是同學(xué)給我的,我覺(jué)得這個(gè)測(cè)試的代碼特別好,很簡(jiǎn)潔,一直用的這個(gè)。
代碼首先設(shè)置 torch.no_grad(),定義后面的代碼不需要計(jì)算梯度,能夠節(jié)省一些內(nèi)存空間。然后,對(duì)測(cè)試集中的每個(gè) batch 進(jìn)行測(cè)試,統(tǒng)計(jì)總數(shù)和準(zhǔn)確數(shù),最后計(jì)算準(zhǔn)確率并輸出。
通常是選擇邊訓(xùn)練邊測(cè)試的,這里先就按步驟一步一步來(lái)做。
有的測(cè)試代碼前面要加上 model.eval(),表示這是訓(xùn)練狀態(tài)。但這里不需要,如果沒(mé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 # 激勵(lì)函數(shù)的庫(kù) from torchvision import datasets import torchvision.transforms as transforms import numpy as np # 定義全局變量 n_epochs = 10 # epoch 的數(shù)目 batch_size = 20 # 決定每次讀取多少圖片 # 定義訓(xùn)練集個(gè)測(cè)試集,如果找不到數(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) # 建立一個(gè)四層感知機(jī)網(wǎng)絡(luò) class MLP(torch.nn.Module): # 繼承 torch 的 Module def __init__(self): super(MLP,self).__init__() # # 初始化三層神經(jīng)網(wǎng)絡(luò) 兩個(gè)全連接的隱藏層,一個(gè)輸出層 self.fc1 = torch.nn.Linear(784,512) # 第一個(gè)隱含層 self.fc2 = torch.nn.Linear(512,128) # 第二個(gè)隱含層 self.fc3 = torch.nn.Linear(128,10) # 輸出層 def forward(self,din): # 前向傳播, 輸入值:din, 返回值 dout din = din.view(-1,28*28) # 將一個(gè)多行的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個(gè)數(shù)字實(shí)際上是10個(gè)類別,輸出是概率分布,最后選取概率最大的作為預(yù)測(cè)值輸出 return dout # 訓(xùn)練神經(jīng)網(wǎng)絡(luò) def train(): #定義損失函數(shù)和優(yōu)化器 lossfunc = torch.nn.CrossEntropyLoss() optimizer = torch.optim.SGD(params = model.parameters(), lr = 0.01) # 開(kāi)始訓(xùn)練 for epoch in range(n_epochs): train_loss = 0.0 for data,target in train_loader: optimizer.zero_grad() # 清空上一步的殘余更新參數(shù)值 output = model(data) # 得到預(yù)測(cè)值 loss = lossfunc(output,target) # 計(jì)算兩者的誤差 loss.backward() # 誤差反向傳播, 計(jì)算參數(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ù)集,測(cè)試一下準(zhǔn)確率 test() # 在數(shù)據(jù)集上測(cè)試神經(jīng)網(wǎng)絡(luò) def test(): correct = 0 total = 0 with torch.no_grad(): # 訓(xùn)練集中不需要反向傳播 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)絡(luò) model = MLP() if __name__ == '__main__': train()
10 個(gè) epoch 的訓(xùn)練效果,最后能達(dá)到大約 85% 的準(zhǔn)確率??梢赃m當(dāng)增加 epoch,但代碼里沒(méi)有用 gpu 運(yùn)行,可能會(huì)比較慢。
1.PyTorch是相當(dāng)簡(jiǎn)潔且高效快速的框架;2.設(shè)計(jì)追求最少的封裝;3.設(shè)計(jì)符合人類思維,它讓用戶盡可能地專注于實(shí)現(xiàn)自己的想法;4.與google的Tensorflow類似,F(xiàn)AIR的支持足以確保PyTorch獲得持續(xù)的開(kāi)發(fā)更新;5.PyTorch作者親自維護(hù)的論壇 供用戶交流和求教問(wèn)題6.入門簡(jiǎn)單
感謝各位的閱讀!關(guān)于“怎么使用PyTorch實(shí)現(xiàn)MLP并在MNIST數(shù)據(jù)集上驗(yàn)證”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。