(四)PyTorch——多分類問題及深層次神經網絡(mnist數字識別問題)

MNIST是一個非常有名的手寫數字識別數據集,在很多資料中,這個數據集都會被用作深度學習的入門案例。
MNIST數據集是NIST數據集的一個子集,它包含了60000張圖片作爲訓練數據,10000張圖片作爲測試數據。在MNIST數據集中的每一張圖片都代表了0~9中的一個數字。圖片的大小都爲28x28,且數字都會出現在圖片的正中間。

數字圖片及其像素矩陣:(MNIST數據集中圖片的像素大小爲28x28,爲了更清楚的展示,圖中顯示的是14x14矩陣)

在這裏插入圖片描述

MNIST提供了四個文件:

train-images-idx3-ubyte.gz (訓練圖像數據60000個)

train-labels-idx1-ubyte.gz (訓練圖像數據標籤60000個)

t10k-images-idx3-ubyte.gz (測試圖像數據10000個)

t10k-labels-idx1-ubyte.gz (測試圖像數據標籤10000個)
 

PyTorch和TensorFlow都內置mnist數據集。

TensorFlow實現MNIST數字識別問題

 

多分類問題,loss函數使用一個更加複雜的函數,叫交叉熵。

softmax

sigmoid函數可以將任何一個值轉化到0~1之間,對於一個二分類問題,這樣就足夠了,如果不屬於第一類,那麼必定屬於第二類,所以只需要用一個值來表示其屬於其中一類概率,但是對於多分類問題,需要知道其屬於每一類的概率,這個時候需要softmax函數。

 

 

MNIST

 

import numpy as np
import torch
from torchvision.datasets import mnist#導入pytorch內置的mnist數據集
from torch import nn
from torch.autograd import Variable

#使用內置函數下載mnist數據集
train_set=mnist.MNIST('/data',train=True,download=True)
test_set=mnist.MNIST('/data',train=False,download=True)

#查看其中的一個數據集
a_data,a_label=train_set[0]
print(a_data)
print(a_label)

下載完後的文件:

 

 

#這裏讀入的數據是PIL庫中的格式,可以非常方便地將其轉化爲numpy array
a_data=np.array(a_data,dtype='float32')
print(a_data.shape)
#我們可以看到這種圖片的大小是28X28
print(a_data)

 

完整代碼:

import numpy as np
import torch
from torchvision.datasets import mnist#導入pytorch內置的mnist數據集
from torch import nn
from torch.autograd import Variable
import matplotlib.pyplot as plt


#我們可以將數組展示出來,裏面的0就表示黑色,255表示白色
#對於神經網絡,我們第一層的輸入就是28*28=784,所以必須將得到的數據做一個變換
#使用reshape將他們拉平成一個一維向量

def data_tf(x):
    x=np.array(x,dtype='float32')/255
    x=(x-0.5)/0.5#標準化
    x=x.reshape((-1,))#拉平
    x=torch.from_numpy(x)
    return x

train_set=mnist.MNIST('data',train=True,transform=data_tf,download=True)#重新載入數據集,申明定義的數據變換
test_set=mnist.MNIST('data',train=False,transform=data_tf,download=True)
a,a_label=train_set[0]
print(a.shape)
print(a_label)

#使用pytorch自帶的DataLoader定義一個數據迭代器
from torch.utils.data import DataLoader
train_data=DataLoader(train_set,batch_size=64,shuffle=True)
test_data=DataLoader(test_set,batch_size=128,shuffle=False)

#使用這樣的數據迭代器是非常有必要的,如果數據量太大,就無法一次將他們全部讀入內存,所以需要使用Python迭代器,每次生成一個批次的數據
a,a_label=next(iter(train_data))
print(a.shape)
print(a_label.shape)

#使用Sequential定義4層神經網絡
net=nn.Sequential(
    nn.Linear(784,400),
    nn.ReLU(),
    nn.Linear(400,200),
    nn.ReLU(),
    nn.Linear(200,100),
    nn.ReLU(),
    nn.Linear(100,10)
)

#交叉熵在pyTorch中已經內置了,交叉熵的數值穩定性更差,所以內置的函數
#幫我們解決了這個問題

#定義loss函數
criterion=nn.CrossEntropyLoss()
optimizer=torch.optim.SGD(net.parameters(),1e-1)#使用隨機梯度下降,學習率0.1

#開始訓練
losses=[]
acces=[]
eval_losses=[]
eval_acces=[]

for e in range(20):
    train_loss=0
    train_acc=0
    net.train()
    for im,label in train_data:
        im=Variable(im)
        label=Variable(label)
        #前向傳播
        out=net(im)
        loss=criterion(out,label)
        #反向傳播
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        #記錄誤差
        train_loss+=loss.item()
        #計算分類的準確率
        _,pred=out.max(1)
        num_correct=(pred==label).sum().item()
        acc=num_correct/im.shape[0]
        train_acc+=acc
    losses.append(train_loss/len(train_data))
    acces.append(train_acc/len(train_data))
    #在測試集上檢驗效果
    eval_loss=0
    eval_acc=0
    net.eval()#將模型改爲預測模式
    for im,label in test_data:
        im=Variable(im)
        label=Variable(label)
        out=net(im)
        loss=criterion(out,label)
        #記錄誤差
        eval_loss+=loss.item()
        #記錄準確率
        _,pred=out.max(1)
        num_correct=(pred==label).sum().item()
        acc=num_correct/im.shape[0]
        eval_acc+=acc
    eval_losses.append(eval_loss/len(test_data))
    eval_acces.append(eval_acc/len(test_data))
    print('epoch:{},Train Loss:{:.6f},Train Acc:{:.6f},Eval Loss:{:.6f},Eval ACC:{:.6f}'
          .format(e,train_loss/len(train_data),train_acc/len(train_data),
                  eval_loss/len(test_data),eval_acc/len(test_data)))

#畫出loss曲線和準確率曲線
plt.title("train loss")
plt.plot(np.arange(len(losses)),losses)
plt.show()

plt.plot(np.arange(len(acces)),acces)
plt.title('train acc')
plt.show()

plt.plot(np.arange(len(eval_losses)),eval_losses)
plt.title('test loss')
plt.show()

plt.plot(np.arange(len(eval_acces)),eval_acces)
plt.title('test acc')
plt.show()


運行結果:

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章