Pytorch筆記之 多層感知機實現MNIST資料集分類

ckxllf發表於2021-04-07

  前言

  複雜的神經網路也是由許多神經元組成,在深度學習領域,神經元即感知機。深度學習透過許多感知機,儘可能的學習一個任務的複雜數學表示。神經網路在模擬生物神經元時,創造性的引入非線性的函式,透過判斷是否達到閾值,來覺得訊號是否輸出,完成資訊傳遞。因此,在階躍函式的基礎上,進一步最佳化,擴充,得到sigmoid啟用函式、Relu、leak ReLu等,細細品味,你將發現這構思的巧妙性、合理性。

  一、Torch相關包介紹

  torch.nn :完成神經網路一些相關操作,包含了在計算機視覺任務中常用到的卷積,池化等一些列API介面實現。

  torch.nn.fubctional : 可以比nn更進一步接觸實現底層程式碼的修改。

  torch.nn.optim:最佳化器,提供了學習率設定,及更好的梯度下降方式的選擇。

  torchvision:計算機視覺任務的工具,提供了常用的資料集,模型,轉換函式等。實現視覺類任務如分類、目標檢測、分割必不可少的。

  匯入所需包(示例):

  import torch

  import torch.nn as nn

  import torch.nn.functional as F

  import torch.optim as optim

  from torchvision import datasets,transforms

  若提示出錯,可使用命令列視窗,進行 conda install 安裝。或者在pycharm中進行安裝,以pycharm為例:輸入要安裝的包,點選安裝即可。

  二、搭建多層感知機

  1.MNIST介紹

  MNIST簡介: 包含0-9 共10個手寫數字,每個數字由7000張(高度28*寬度28)的影像,將70k資料,分為了訓練集60K,測試集10大小。本節,透過感知機實現對MNIST手寫數字的分類。

  程式碼如下(示例):

  import numpy as np

  import pandas as pd

  import matplotlib.pyplot as plt

  import seaborn as sns

  import warnings

  warnings.filterwarnings('ignore')

  import ssl

  ssl._create_default_https_context = ssl._create_unverified_context

  2.下載MNIST資料集

  程式碼如下:

  ‘./data’:設定要儲存的下載目錄。

  train=True:設定要下載的是60k的訓練資料集。

  download=True:如果當前資料夾沒有資料集,則從網上下載。

  transforms.ToTensor():下載的資料集為numpy格式,需要轉換為張量格式。

  transforms.Normalize((0.1307,), (0.3081,):(此項非必要設定項)為了更好的訓練結果,因為影像的資料值是0-1之間,將資料值正則花在0左右,對模型梯度下降效果更好。

  batch_size=batch_size, shuffle=True:設定批次大小,隨機打算資料。

  測試集設定類似

  #MNIST 資料集

  #設定訓練的批次大小、學習率、及訓練代數

  batch_size=200

  learning_rate=0.001

  epochs=20

  #下載資料集

  train_loader = torch.utils.data.DataLoader(

  datasets.MNIST('./data', train=True, download=True,

  transform=transforms.Compose([

  transforms.ToTensor(),

  transforms.Normalize((0.1307,), (0.3081,))

  ])),

  batch_size=batch_size, shuffle=True)

  test_loader = torch.utils.data.DataLoader(

  datasets.MNIST('./data', train=False, download=True, transform=transforms.Compose([

  transforms.ToTensor(),

  transforms.Normalize((0.1307,), (0.3081,))

  ])),

  batch_size=batch_size, shuffle=True)

  3.搭建神經網路層

  1.權重和偏置

  程式碼如下:

  w1,b1:第一層網路感知機。輸入影像大小是28*28=784,因此輸入為784,輸出設定為100(這個引數隨意設定,可以嘗試不同的數目檢視效果)因為W要轉置所以輸入放後面,輸出放前面。b1為第一層網路對應的偏置項。

  w2, b2:與上敘述類似。

  ==w3, b3 ==:注意輸出要與分類的10個數字類別數一致,其他與上述類似。

  requires_grad=True:此項設定為True,表示要對w,b求梯度。

  #生成 三個神經網路成,對應感知節分別為第一層100,第二成200,第三層10,即要分類的數目

  w1, b1 = torch.randn(100, 784, requires_grad=True),\

  torch.zeros(100, requires_grad=True)

  w2, b2 = torch.randn(200, 100, requires_grad=True),\

  torch.zeros(200, requires_grad=True)

  w3, b3 = torch.randn(10, 200, requires_grad=True),\

  torch.zeros(10, requires_grad=True)

  2.定義前向計算網路

  程式碼如下:

  relu啟用函式:確保網路的非線性,實現更好的分類效果。

  #定義前向網路計算,每層神經網路輸出後增加relu啟用函式,確保網路的非線性,實現更好的分類效果

  def forward(x):

  x = x@w1.t() + b1

  x = F.relu(x)

  x = x@w2.t() + b2

  x = F.relu(x)

  x = x@w3.t() + b3

  x = F.relu(x)

  return x

  3.定義梯度最佳化器及損失函式設定

  程式碼如下:

  .CrossEntropyLoss():損失採用交叉熵損失函式。

  .SGD:採用隨機梯度下降,並設定學習率。

  #定義最佳化器,採用SGD隨機梯度下降的方式對w1, b1, w2, b2, w3, b3進行最佳化

  optimizer = optim.SGD([w1, b1, w2, b2, w3, b3], lr=learning_rate)

  #定義採用交叉熵作為損失函式

  criteon = nn.CrossEntropyLoss()

  4.完成程式設計

  程式碼如下:

  #設定迭代次數

  for epoch in range(epochs):

  for batch_idx, (data, target) in enumerate(train_loader):

  #將資料打平為(批次,高度*寬度),-1代表所有

  data = data.view(-1, 28*28)

  #將資料輸入到網路中

  cal_data = forward(data)

  #將計算的資料與目標資料求誤差損失

  loss = criteon(cal_data, target)

  #將梯度值初始化為0

  optimizer.zero_grad()

  #pytorch計算梯度值

  loss.backward()

  #更新梯度值

  optimizer.step()

  #每隔25*batcsize(200) = 5000 列印輸出結果

  if batch_idx % 25 == 0:

  print('訓練代數: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(

  epoch, batch_idx * len(data), len(train_loader.dataset),

  100. * batch_idx / len(train_loader), loss.item()))

  #將測試誤差及正確率清0

  test_loss = 0

  correct = 0

  #取測試集資料及目標資料

  for data, target in test_loader:

  data = data.view(-1, 28 * 28)

  logits = forward(data)

  #誤差累加

  test_loss += criteon(logits, target).item()

  #取出預測最大值的索引編號,即預測值

  pred = logits.data.argmax(dim=1)

  #統計正確預測的個數

  correct += pred.eq(target.data).sum()

  test_loss /= len(test_loader.dataset)

  #列印輸出測試誤差及準確率

  print('\n測試集: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(

  test_loss, correct, len(test_loader.dataset),

  100. * correct / len(test_loader.dataset)))

  三、完整程式碼程式

  因為我們自己隨機生成的初始化 w1,w2,w3,達到的效能並不好。所以我們可以採用大神何凱明的初始化權重對w1,w2,w3 進行初始化賦值,準確率可以達到90%。小夥伴們可以嘗試下,將初始化賦值程式碼遮蔽,對比檢視效果。

  程式碼如下:

  import torch

  import torch.nn as nn

  import torch.nn.functional as F

  import torch.optim as optim

  from torchvision import datasets,transforms

  #MNIST 資料集

  #設定訓練的批次大小、學習率、及訓練代數

  batch_size=200

  learning_rate=0.001

  epochs=20

  #下載資料集

  train_loader = torch.utils.data.DataLoader(

  datasets.MNIST('./data', train=True, download=True,

  transform=transforms.Compose([

  transforms.ToTensor(),

  transforms.Normalize((0.1307,), (0.3081,))

  ])),

  batch_size=batch_size, shuffle=True)

  test_loader = torch.utils.data.DataLoader(

  datasets.MNIST('./data', train=False, download=True, transform=transforms.Compose([

  transforms.ToTensor(),

  transforms.Normalize((0.1307,), (0.3081,))

  ])), 北海購房網

  batch_size=batch_size, shuffle=True)

  #生成三層神經網路成,對應感知機分別為第一層100,第二成200,第三層10,即要分類的數目

  w1, b1 = torch.randn(100, 784, requires_grad=True),\

  torch.zeros(100, requires_grad=True)

  w2, b2 = torch.randn(200, 100, requires_grad=True),\

  torch.zeros(200, requires_grad=True)

  w3, b3 = torch.randn(10, 200, requires_grad=True),\

  torch.zeros(10, requires_grad=True)

  #採用何凱明大神的初始化權重,準確率更高,權重的合理初始化很重要

  torch.nn.init.kaiming_normal_(w1)

  torch.nn.init.kaiming_normal_(w2)

  torch.nn.init.kaiming_normal_(w3)

  #定義前向網路計算,每層神經網路輸出後增加relu啟用函式,確保網路的非線性,實現更好的分類效果

  def forward(x):

  x = x@w1.t() + b1

  x = F.relu(x)

  x = x@w2.t() + b2

  x = F.relu(x)

  x = x@w3.t() + b3

  x = F.relu(x)

  return x

  #定義最佳化器,採用SGD隨機梯度下降的方式對w1, b1, w2, b2, w3, b3進行最佳化

  optimizer = optim.SGD([w1, b1, w2, b2, w3, b3], lr=learning_rate)

  #定義採用交叉熵作為損失函式

  criteon = nn.CrossEntropyLoss()

  # 設定迭代次數

  for epoch in range(epochs):

  for batch_idx, (data, target) in enumerate(train_loader):

  # 將資料打平為(批次,高度*寬度),-1代表所有

  data = data.view(-1, 28 * 28)

  # 將資料輸入到網路中

  cal_data = forward(data)

  # 將計算的資料與目標資料求誤差損失

  loss = criteon(cal_data, target)

  # 將梯度值初始化為0

  optimizer.zero_grad()

  # pytorch計算梯度值

  loss.backward()

  # 更新梯度值

  optimizer.step()

  # 每隔25*batcsize(200) = 5000 列印輸出結果

  if batch_idx % 25 == 0:

  print('訓練代數: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(

  epoch, batch_idx * len(data), len(train_loader.dataset),

  100. * batch_idx / len(train_loader), loss.item()))

  # 將測試誤差及正確率清0

  test_loss = 0

  correct = 0

  # 取測試集資料及目標資料

  for data, target in test_loader:

  data = data.view(-1, 28 * 28)

  logits = forward(data)

  # 誤差累加

  test_loss += criteon(logits, target).item()

  # 取出預測最大值的索引編號,即預測值

  pred = logits.data.argmax(dim=1)

  # 統計正確預測的個數

  correct += pred.eq(target.data).sum()

  test_loss /= len(test_loader.dataset)

  # 列印輸出測試誤差及準確率

  print('\n測試集: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(

  test_loss, correct, len(test_loader.dataset),

  100. * correct / len(test_loader.dataset)))

  輸出結果。

  總結

  這一節,我們從底層搭建了一個三層的感知機神經網路,對手寫數字資料集MNIST進行訓練和測試,達到了92%的正確率。權重的隨機初始化,對結果是很重要的,但在torch更高層的API使用中提供了很好的初始化。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69945560/viewspace-2766904/,如需轉載,請註明出處,否則將追究法律責任。

相關文章