生活随笔
收集整理的這篇文章主要介紹了
基于PyTorch框架的多层全连接神经网络实现MNIST手写数字分类
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
多層全連接神經網絡實現MNIST手寫數字分類 1 簡單的三層全連接神經網絡 2 添加激活函數 3 添加批標準化 4 訓練網絡 5 結論 參考資料
先用PyTorch實現最簡單的三層全連接神經網絡,然后添加激活層查看實驗結果,最后再加上批標準化驗證是否能夠更加有效。
1 簡單的三層全連接神經網絡
對于這個三層網絡,需要傳遞進去的參數包括:輸入的維度,第一次網絡的神經元個數,第二層網絡神經元的個數,以及第三層網絡(輸出層)神經元個數。
import torch
import torch
. nn
as nn
from torch
. autograd
. variable
import Variable
import numpy
as np
class SimpleNet ( nn
. Module
) : def __init__ ( self
, in_dim
, n_hidden_1
, n_hidden_2
, out_dim
) : super ( SimpleNet
, self
) . __init__
( ) self
. layer1
= nn
. Linear
( in_dim
, n_hidden_1
) self
. layer2
= nn
. Linear
( n_hidden_1
, n_hidden_2
) self
. layer3
= nn
. Linear
( n_hidden_2
, out_dim
) def forward ( self
, x
) : x
= self
. layer1
( x
) x
= self
. layer2
( x
) x
= self
. layer3
( x
) return x
2 添加激活函數
class Activation_Net ( nn
. Module
) : def __init__ ( self
, in_dim
, n_hidden_1
, n_hidden_2
, out_dim
) : super ( Activation_Net
, self
) . __init__
( ) self
. layer1
= nn
. Sequential
( nn
. Linear
( in_dim
, n_hidden_1
) , nn
. ReLU
( True ) ) self
. layer2
= nn
. Sequential
( nn
. Linear
( n_hidden_1
, n_hidden_2
) ) self
. layer3
= nn
. Sequential
( nn
. Linear
( n_hidden_2
, out_dim
) ) def forward ( self
, x
) : x
= self
. layer1
( x
) x
= self
. layer2
( x
) x
= self
. layer3
( x
) return x
這里只需要在每層網絡的輸出部分添加激活函數就可以了,nn.Sequential()這個函數是將網絡的層組合到一起,比如上面將nn.Linear()和nn.ReLU()組合到一起作為self.layer。最后一層輸出層不能添加激活函數,因為輸出的結果表示的是實際的得分。
3 添加批標準化
class Batch_Net ( nn
. Module
) : def __init__ ( self
, in_dim
, n_hidden_1
, n_hidden_2
, out_dim
) : super ( Batch_Net
, self
) . __init__
( ) self
. layer1
= nn
. Sequential
( nn
. Linear
( in_dim
, n_hidden_1
) , nn
. BatchNorm1d
( n_hidden_1
) , nn
. ReLU
( True ) ) self
. layer2
= nn
. Sequential
( nn
. Linear
( n_hidden_1
, n_hidden_2
) , nn
. BatchNorm1d
( n_hidden_2
) , nn
. ReLU
( True ) ) self
. layer3
= nn
. Sequential
( nn
. Linear
( n_hidden_2
, out_dim
) ) def forward ( self
, x
) : x
= self
. layer1
( x
) x
= self
. layer2
( x
) x
= self
. layer3
( x
) return x
同樣使用nn.Sequential()將nn.BatchNorm1d()組合到網絡層中,注意批標準化一般放在全連接層的后面,非線性層(激活函數)的前面。
4 訓練網絡
網絡的定義較簡單,現在用MNIST數據集訓練網絡并測試一下每種網絡的結果。 MNIST數據集是一個手寫字體數據集,包括0~9這10個數字,其中有55000張訓練集,10000張測試集,5000張驗證集,圖片是28*28的灰度圖。 導入需要用的包
import torch
from torch
import nn
, optim
from torch
. autograd
import Variable
from torch
. utils
. data
import DataLoader
from torchvision
import datasets
, transforms
import net
batch_size
= 64
learning_rate
= 1e - 2
num_epochs
= 20
數據預處理,需要將數據標準化,運用的函數是torchvision.transforms,它提供了很多圖片預處理的方法。transforms.ToTensor()將圖片轉換成PyTorch中處理的對象Tensor,在轉換的過程中,PyTorch自動將圖片標準化,即Tensor的范圍是0~1。transforms.Normalize()需要傳入兩個參數,第一個是均值,第二個是方差,做的處理就是減均值,再除以方差。
transforms.Compose()將各種預處理操作組合到一起,transforms.Normalize([0.5], [0.5])表示減去0.5再除以0.5,這樣圖片轉換到-1到1之間。因為圖片是灰度圖片,所以只有一個通道,如果是彩色圖像,有三個通道,用transforms.Normalize([mean_r,mean_g,mean_b], [var_r,var_g,var_b])來表示每個通道對應的均值和方差。
data_tf
= transforms
. Compose
( [ transforms
. ToTensor
( ) , transforms
. Normalize
( [ 0.5 ] , [ 0.5 ] ) ]
)
讀取數據集。 通過PyTorch的內置函數torchvision.datasets.MNIST導入數據集,傳入數據預處理。使用torch.utils.data.DataLoader建立一個數據迭代器,傳入數據集和batch_size,通過shuffle=True,來表示每次迭代數據的時候是否將數據打亂。
train_dataset
= datasets
. MNIST
( root
= './data' , train
= True , transform
= data_tf
, download
= True
)
test_dataset
= datasets
. MNIST
( root
= './data' , train
= False , transform
= data_tf
)
train_loader
= DataLoader
( train_dataset
, batch_size
= batch_size
, shuffle
= True )
test_loader
= DataLoader
( test_dataset
, batch_size
= batch_size
, shuffle
= False )
導入網絡,定義損失函數和優化方法。 通過net.SimpleNet定義簡單三層網絡,里面的參數是2828,300,100,10,其中輸入的維度是2828,因為輸入圖片大小是28*28,然后定義兩個隱藏層分別是300和100。最后輸出的結果必須是10,因為這是一個分類問題,一共有0~9這10個數字,所以是10分類。 損失函數定義為分類問題中最常見的損失函數交叉熵,使用隨機梯度下降來優化損失函數。
model
= net
. SimpleNet
( 28 * 28 , 300 , 100 , 10 )
if torch
. cuda
. is_available
( ) : model
= model
. cuda
( )
criterion
= nn
. CrossEntropyLoss
( )
optimizer
= optim
. SGD
( model
. parameters
( ) , lr
= learning_rate
)
開始訓練網絡 img = Variable(img, volatile=True)里面的volatile=True表示前向傳播時,不會保留緩存,因為對于測試集,不需要做反向傳播,所以在前向傳播時釋放內存,節約內存空間。
model
. eval ( )
eval_loss
= 0
eval_acc
= 0
for data
in test_loader
: img
, label
= dataimg
= img
. view
( img
. size
( 0 ) , - 1 ) if torch
. cuda
. is_available
( ) : img
= Variable
( img
, volatile
= True ) . cuda
( ) label
= Variable
( label
, volatile
= True ) . cuda
( ) else : img
= Variable
( img
, volatile
= True ) label
= Variable
( label
, volatile
= True ) out
= model
( img
) loss
= criterion
( out
, label
) eval_loss
+= loss
. data
[ 0 ] * label
. size
( 0 ) _
, pred
= torch
. max ( out
, 1 ) num_correct
= ( pred
== label
) . sum ( ) eval_acc
+= num_correct
. data
[ 0 ]
print ( 'Test Loss:{:.6f},ACC:{:.6f}' . format ( eval_loss
/ ( len ( test_dataset
) ) , eval_acc
/ ( len ( test_dataset
) ) )
)
5 結論
依次測試簡單三層網絡、添加激活層的網絡、添加批標準化的網絡,網絡的預測準確率越來越高,同時還可以通過Dropout、正則化,增加網絡的泛化能力。
import torch
import torch
. nn
from torchvision
import datasets
from torchvision
import transforms
from torch
. utils
. data
import DataLoader
import torch
. nn
. functional
as Fdevice
= torch
. device
( 'cuda:0' if torch
. cuda
. is_available
( ) else 'cpu' )
batch_size
= 32
transform
= transforms
. Compose
( [ transforms
. ToTensor
( )
] )
train_set
= datasets
. MNIST
( root
= './dataset/mnist' , train
= True , transform
= transform
)
train_loader
= DataLoader
( dataset
= train_set
, batch_size
= batch_size
, shuffle
= True , num_workers
= 2 )
test_set
= datasets
. MNIST
( root
= './dataset/mnist' , train
= False , transform
= transform
)
test_loader
= DataLoader
( dataset
= test_set
, batch_size
= batch_size
, shuffle
= False , num_workers
= 2 ) class Net ( torch
. nn
. Module
) : def __init__ ( self
) : super ( Net
, self
) . __init__
( ) self
. conv1
= torch
. nn
. Conv2d
( in_channels
= 1 , out_channels
= 10 , kernel_size
= 5 ) self
. conv2
= torch
. nn
. Conv2d
( in_channels
= 10 , out_channels
= 20 , kernel_size
= 5 ) self
. pooling
= torch
. nn
. MaxPool2d
( kernel_size
= 2 ) self
. fc
= torch
. nn
. Linear
( 320 , 10 ) def forward ( self
, x
) : batch_size
= x
. size
( 0 ) x
= F
. relu
( self
. pooling
( self
. conv1
( x
) ) ) x
= F
. relu
( self
. pooling
( self
. conv2
( x
) ) ) x
= x
. view
( batch_size
, - 1 ) x
= self
. fc
( x
) return xmodel
= Net
( ) . to
( device
)
criterion
= torch
. nn
. CrossEntropyLoss
( )
optimizer
= torch
. optim
. SGD
( params
= model
. parameters
( ) , lr
= 0.01 , momentum
= 0.5 ) def train ( epoch
) : running_loss
= 0 for batch_idx
, data
in enumerate ( train_loader
) : images
, labels
= dataimages
= images
. to
( device
) labels
= labels
. to
( device
) optimizer
. zero_grad
( ) outputs
= model
( images
) loss
= criterion
( outputs
, labels
) loss
. backward
( ) optimizer
. step
( ) running_loss
+= loss
. item
( ) if ( batch_idx
+ 1 ) % 300 == 0 : print ( '[%d,%d],loss is %.2f' % ( epoch
, batch_idx
, running_loss
/ 300 ) ) running_loss
= 0 def test ( ) : correct
= 0 total
= 0 with torch
. no_grad
( ) : for data
in test_loader
: images
, labels
= dataimages
= images
. to
( device
) labels
= labels
. to
( device
) outputs
= model
( images
) _
, predict
= torch
. max ( outputs
, dim
= 1 ) correct
+= ( labels
== predict
) . sum ( ) . item
( ) total
+= labels
. size
( 0 ) print ( 'correct/total:%d/%d,Accuracy:%.2f%%' % ( correct
, total
, 100 * ( correct
/ total
) ) ) if __name__
== '__main__' : for epoch
in range ( 10 ) : train
( epoch
) test
( )
參考資料
廖星宇《深度學習入門之PyTorch》電子工業出版社
與50位技術專家面對面 20年技術見證,附贈技術全景圖
總結
以上是生活随笔 為你收集整理的基于PyTorch框架的多层全连接神经网络实现MNIST手写数字分类 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。