pytorch 训练过程acc_Pytorch之Softmax多分类任务
在上一篇文章中,筆者介紹了什么是Softmax回歸及其原理。因此在接下來的這篇文章中,我們就來開始動(dòng)手實(shí)現(xiàn)一下Softmax回歸,并且最后要完成利用Softmax模型對(duì)Fashion MINIST進(jìn)行分類的任務(wù)。在開始實(shí)現(xiàn)Softmax之前,我們先來了解一下Fashion MINIST這一數(shù)據(jù)集。
1 數(shù)據(jù)集
1.1 FashionMNIST
數(shù)據(jù)集FashionMNIST雖然名字里面有'MNIST'這個(gè)詞,但是其與手寫體識(shí)別一點(diǎn)關(guān)系也沒有,僅僅只是因?yàn)镕ashionMNIST數(shù)據(jù)集在數(shù)據(jù)集規(guī)模、類別數(shù)量和圖片大小上與MINIST手寫體數(shù)據(jù)集一致。
圖 1. Fashion MINIST數(shù)據(jù)集如圖1所示便為Fashion MNIST數(shù)據(jù)集的部分可視化結(jié)果,其包含有訓(xùn)練集6萬張和測試集1萬張,每張圖片的大小為[28,28]。在Pytorch中,我們可以通過如下代碼對(duì)其進(jìn)行載入:
def?load_dataset():????mnist_train?=?torchvision.datasets.FashionMNIST(root='~/Datasets/FashionMNIST',??train=True,?download=True,transform=transforms.ToTensor())
????mnist_test?=?torchvision.datasets.FashionMNIST(root='~/Datasets/FashionMNIST',???train=False,?download=True,transform=transforms.ToTensor())
????return?mnist_train,?mnist_test
其中參數(shù)root表示指定數(shù)據(jù)集的保存目錄;train表示返回訓(xùn)練集還是測試集;download表示數(shù)據(jù)集不存在時(shí)是否需要下載;transform表示指定一種轉(zhuǎn)換方法,而指定transforms.ToTensor()就是將尺寸為(H x W x C)且數(shù)據(jù)位于[0,255]的PIL圖片或者數(shù)據(jù)類型為np.unit8的numpy數(shù)組轉(zhuǎn)換為尺寸為(C x H x W)且數(shù)據(jù)類型為torch.float32,范圍在的Tensor。
同時(shí),我們還可以通過代碼image= mnist_train[0][0]和label=mnist_train[0][1]來分別訪問一張圖片和其對(duì)應(yīng)的標(biāo)簽值。
1.2 構(gòu)造數(shù)據(jù)集
在模型實(shí)際訓(xùn)練過程中,數(shù)據(jù)讀取經(jīng)常是訓(xùn)練的性能瓶頸。同時(shí),為了能夠更好的訓(xùn)練模型我們通常會(huì)對(duì)數(shù)據(jù)進(jìn)行打亂,以及分批(batch)的將數(shù)據(jù)輸入的模型中。在Pytorch中,我們可以通過DataLoader這個(gè)類來方便的完成上述功能。
start?=?time.time()train_iter?=?torch.utils.data.DataLoader(mnist_test,?batch_size=1024,?shuffle=True,?num_workers=2)
for?x_test,?y_test?in?train_iter:
????print(x_test.shape)
????print('%.2f?sec'?%?(time.time()?-?start))
#結(jié)果
torch.Size([1024,?1,?28,?28])
torch.Size([1024,?1,?28,?28])
torch.Size([1024,?1,?28,?28])
torch.Size([1024,?1,?28,?28])
torch.Size([1024,?1,?28,?28])
torch.Size([1024,?1,?28,?28])
torch.Size([1024,?1,?28,?28])
torch.Size([1024,?1,?28,?28])
torch.Size([1024,?1,?28,?28])
torch.Size([784,?1,?28,?28])
2.60?sec
其中batsh_size表示指定每次返回batsh_size個(gè)樣本;shuffle=True表示對(duì)數(shù)據(jù)集進(jìn)行打亂;num_workers=2表示用兩個(gè)進(jìn)程來讀取數(shù)據(jù)。
但需要注意的是,這里的數(shù)據(jù)集mnist_test是Pytorch內(nèi)置的,那如果是我們自己讀入的數(shù)據(jù)集該怎么使用DataLoader呢?我們只需要首先將自己的數(shù)據(jù)集轉(zhuǎn)換成tensor,然后再通過TensorDataset這個(gè)類來構(gòu)造一個(gè)數(shù)據(jù)集即可。
def?make_dataset():????x?=?torch.linspace(0,?100,?100,?dtype=torch.float32).reshape(-1,?2)
????y?=?torch.randn(50?)
????dataset?=?torch.utils.data.TensorDataset(x,?y)
????return?dataset
此時(shí)返回的dataset數(shù)據(jù)集也就同樣能夠通過DataLoader進(jìn)行讀取。
2 Softmax多分類
在實(shí)現(xiàn)這個(gè)分類模型之前,我們先來介紹一下幾個(gè)需要用到的函數(shù)。
2.1 softmax計(jì)算實(shí)現(xiàn)
在上一篇文章中我們介紹了softmax的計(jì)算公式,其實(shí)現(xiàn)可以通過如下代碼來完成:
def?softmax(x):????s?=?torch.exp(x)
????return?s?/?torch.sum(s,?dim=1,?keepdim=True)#?此處觸發(fā)了廣播機(jī)制
a?=?torch.tensor([[1,2,3.],[2,3,1.]])
print(softmax(a))
#結(jié)果:
tensor([[0.0900,?0.2447,?0.6652],
????????[0.2447,?0.6652,?0.0900]])
其中torch.exp()為計(jì)算每個(gè)元素的指數(shù)次方;sum(s, dim=1, keepdim=True)表示計(jì)算得到每一行的和;最后是按位除操作。需要注意的是傳入的x必須是浮點(diǎn)類型的,不然會(huì)報(bào)錯(cuò)。
2.2 交叉熵計(jì)算實(shí)現(xiàn)
假設(shè)我們現(xiàn)在有兩個(gè)樣本,其預(yù)測得到的概率分布為[0.1,0.3,0.6]和[0.5,0.4,0.1]。同時(shí),正確的標(biāo)簽分布為[0,0,1]和[0,1,0],則對(duì)應(yīng)的交叉熵為。但是,我們?cè)谟么a實(shí)現(xiàn)的時(shí)候完全不用這么麻煩,只需要通過正確的標(biāo)簽找到預(yù)測概率分布中對(duì)應(yīng)的值,再取對(duì)數(shù)即可。
例如[0,0,1]和[0,1,0]這兩個(gè)真實(shí)分布對(duì)應(yīng)的標(biāo)簽就應(yīng)該是2和1(從0開始),因此我們只需要分別取[0.1,0.3,0.6]和[0.5,0.4,0.1]中第2個(gè)元素0.6和第1個(gè)原始0.4,再取對(duì)數(shù)就能實(shí)現(xiàn)交叉熵的計(jì)算。
上述過程通過如下代碼便可完成:
def?crossEntropy(logits,y):????c?=?-torch.log(logits.gather(1,y.reshape(-1,1)))
????return?torch.sum(c)#?注意這里返回的是和
logits?=?torch.tensor([[0.1,?0.3,?0.6],?[0.5,?0.4,?0.1]])
y?=?torch.LongTensor([2,?1])
c?=?crossEntropy(logits,y)
print(c)
#結(jié)果
tensor(1.4271)
其中.gather()就是根據(jù)指定維度和索引,選擇對(duì)應(yīng)位置上的元素。同時(shí),需要注意的是logits的每一行為一個(gè)樣本的概率分布,因此我們需要在行上進(jìn)行索引操作,故gather()的第一個(gè)參數(shù)應(yīng)該是1,這一點(diǎn)一定要注意。
2.3 準(zhǔn)確率計(jì)算實(shí)現(xiàn)
在前面介紹softmax時(shí)說到,對(duì)于每個(gè)樣本的預(yù)測類別,我們會(huì)選擇對(duì)應(yīng)概率值最大的類別作為輸出結(jié)果。因此,在計(jì)算預(yù)測的準(zhǔn)確率時(shí),我們首先需要通過torch.argmax()這個(gè)函數(shù)來返回預(yù)測得到的標(biāo)簽。
y_true?=?torch.tensor([[2,1]])logits?=?torch.tensor([[0.1,0.3,0.6],[0.5,0.4,0.1]])
y_pred?=?logits.argmax(1)
print(y_pred)
#結(jié)果
tensor([2,?0])
最后,我們將預(yù)測得到的標(biāo)簽同正確標(biāo)簽進(jìn)行對(duì)比即可求得準(zhǔn)確率。
def?accuracy(y_true,logits):????acc?=?(logits.argmax(1)?==?y_true).float().mean()
????return?acc.item()
print(accuracy(y_true,logits))
#結(jié)果
0.5
2.4 評(píng)估模型
一般我們訓(xùn)練得到一個(gè)模型后都需要對(duì)其在測試集上進(jìn)行評(píng)估,也就是在測試集上計(jì)算其總的準(zhǔn)確率。因此,我們首先需要計(jì)算得到所有預(yù)測對(duì)的樣本(而不僅僅只是一個(gè)batch),然后再除以總的樣本數(shù)即可。
def?evaluate(data_iter,?forward,?input_nodes,?w,?b):????acc_sum,?n?=?0.0,?0
????for?x,?y?in?data_iter:
????????logits?=?forward(x,?input_nodes,?w,?b)
????????acc_sum?+=?(logits.argmax(1)?==?y).float().sum().item()
????????n?+=?len(y)
????return?acc_sum?/?n
2.5 分類模型實(shí)現(xiàn)
w?=?torch.tensor(np.random.normal(0,?0.5,?[input_nodes,?output_nodes]),?????????????????dtype=torch.float32,?requires_grad=True)
b?=?torch.tensor(np.random.randn(output_nodes),?dtype=torch.float32,?requires_grad=True)
for?epoch?in?range(epochs):
????for?i,?(x,?y)?in?enumerate(train_iter):
????????logits?=?forward(x,?input_nodes,?w,?b)
????????l?=?crossEntropy(y,?logits)
????????l.backward()
????????gradientDescent([w,?b],?lr)
????????acc?=?accuracy(y,?logits)
????????if?i?%?50?==?0:
????????????print("Epoches[{}/{}]---batch[{}/{}]---acc{:.4}---loss?{:.4}".format(
????????????????epoches,?epoch,?len(mnist_train)?//?batch_size,?i,?acc,l))
????????????acc?=?evaluate(test_iter,?forward,?input_nodes,?w,?b)
????????????print("Epoches[{}/{}]--acc?on?test{:.4}".format(epochs,?epoch,?acc))
#?結(jié)果:
Epochs[8000/20]--acc?on?test0.8323
Epochs[8000/21]---batch[468/0]---acc0.8516---loss?47.13
Epochs[8000/21]---batch[468/50]---acc0.8203---loss?67.22
Epochs[8000/21]---batch[468/100]---acc0.9219---loss?38.74
Epochs[8000/21]---batch[468/150]---acc0.8516---loss?57.39
Epochs[8000/21]---batch[468/200]---acc0.8281---loss?74.76
Epochs[8000/21]---batch[468/250]---acc0.8672---loss?55.32
Epochs[8000/21]---batch[468/300]---acc0.8281---loss?60.19
可以看到,大約20輪迭代后,softmax模型在測試集上的準(zhǔn)確率就達(dá)到了0.83左右。
3 總結(jié)
在這篇文章中,筆者首先介紹了FashionMNIST數(shù)據(jù)集。然后接著介紹了如何使用Pytorch中的DataLoader來構(gòu)造訓(xùn)練數(shù)據(jù)迭代器。最后,介紹了如何通過Pytorch來一步步的實(shí)現(xiàn)Softmax分類模型,包括如何實(shí)現(xiàn)softmax操作、如何快捷的計(jì)算交叉熵、如何計(jì)算模型的準(zhǔn)確率等等。本次內(nèi)容就到此結(jié)束,感謝您的閱讀!
本次內(nèi)容就到此結(jié)束,感謝您的閱讀!如果你覺得上述內(nèi)容對(duì)你有所幫助,歡迎關(guān)注并傳播本公眾號(hào)!若有任何疑問與建議,請(qǐng)?zhí)砑庸P者微信'nulls8'進(jìn)行交流。青山不改,綠水長流,我們?cè)聛砜蜅R?#xff01;
引用
[1]動(dòng)手深度學(xué)習(xí)
[2]示例代碼:https://github.com/moon-hotel/DeepLearningWithMe
推薦閱讀
[1]想明白多分類必須得談邏輯回歸
[2]Pytorch之Linear與MSELoss
[3]Pytorch之?dāng)M合正弦函數(shù)你會(huì)嗎?
[4]你告訴我什么是深度學(xué)習(xí)
[5]《跟我一起深度學(xué)習(xí)》終于來了
總結(jié)
以上是生活随笔為你收集整理的pytorch 训练过程acc_Pytorch之Softmax多分类任务的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux内核怎么修改屏幕旋转方向_运维
- 下一篇: JAVA进阶开发之(内部类概述)