pytorch的多分类问题
多分類問(wèn)題softmax的分類器
為什么要探索多分類
之前我們?cè)谔幚硖悄虿?shù)據(jù)集的時(shí)候我們只是有兩種分類,但是很多情況的數(shù)據(jù)集不只有兩種,例如MNIST數(shù)據(jù)集就是手寫(xiě)數(shù)字的數(shù)據(jù)集有10種不同的標(biāo)簽。所以我們必須有處理多種分類標(biāo)簽的能力。
探索多分類
是否還可以使用二分類的操作?
當(dāng)然還是可以使用二分類的方法來(lái)解決這個(gè)問(wèn)題,某分類設(shè)置位p=1其他全部p=0就可以了,還是使用交叉熵?fù)p失函數(shù)來(lái)處理。
這里我們要注意到,我們的樣本必須是只有一個(gè)選擇的,所以我們的輸出數(shù)據(jù)當(dāng)中只能有一個(gè)輸出的數(shù)據(jù)比較大,要對(duì)其他形成抑制,或者描述為所有的輸出的和必須是1。但是我們使用上面的方法并不能滿足,甚至所有的分類的輸出都是0.8或0.9這種。
如果我們這樣做呢?將十種輸出的最后一種轉(zhuǎn)化為1減去其他輸出,這樣是否可行呢?實(shí)際上也并不行,因?yàn)槲覀內(nèi)绻@樣處理將會(huì)導(dǎo)致十種輸出的結(jié)果過(guò)程并不相同,導(dǎo)致系統(tǒng)的并行能力下降,使得整體的效率下降。
那該怎么實(shí)現(xiàn)?
所以我們的輸出應(yīng)當(dāng)是一個(gè)分布,我們前面的一些層還是可以使用sigmoid來(lái)做一個(gè)層,最后我們要用一個(gè)特殊層來(lái)完成一個(gè)將原有輸出轉(zhuǎn)化位一個(gè)分布的操作。
我們看一下我們需要做到什么內(nèi)容:
1.輸出的內(nèi)容和是一個(gè)1 。
2.輸出的內(nèi)容都在0-1之間。
我們可以想到第一個(gè)內(nèi)容比較好實(shí)現(xiàn)我們只需要讓輸出是一個(gè)分?jǐn)?shù)就行了。分母設(shè)置成一樣的內(nèi)容,分子的和等于這個(gè)分母。這是十分容易的。
之后我們?cè)賮?lái)分析第二個(gè),想要讓輸出是0-1,在我們已經(jīng)做到第一個(gè)要求的情況下,我們想做到第二個(gè),其實(shí)只需要所有的輸出全部都是大于0的就可以完成了。這樣我們就想到了一個(gè)東西指數(shù)函數(shù),指數(shù)函數(shù)的值永遠(yuǎn)是大于0的。這樣問(wèn)題就解決了。
所以我們只需要使用一個(gè)softmax層,這個(gè)層的運(yùn)算如下:
這樣就可以完成我們的需求。
我們來(lái)看一個(gè)實(shí)際的例子就更好理解了:
這樣我們就理解了softmax層
那么損失函數(shù)又該怎么做
我們實(shí)際上還是需要使用交叉熵?fù)p失函數(shù),我們看一下交叉熵?fù)p失函數(shù),其實(shí)是什么情況,我們知道交叉熵?fù)p失函數(shù)是根據(jù)其中的概率進(jìn)行計(jì)算的,因?yàn)槲覀兪谴驑?biāo)簽,除了1的就全是0所以我們需要計(jì)算的內(nèi)容其實(shí)可以簡(jiǎn)化:
所以其實(shí)loss函數(shù)就發(fā)生了變化:
整體的情況就變成了如下的情況:
這個(gè)其實(shí)就是NLL損失函數(shù):
這個(gè)是理論上的情況,但是我們?cè)趐ytorch當(dāng)中其實(shí)并沒(méi)有這么復(fù)雜,我們可以直接使用交叉熵?fù)p失函數(shù)來(lái)將從softmax直接一下子全部包含了。注意我們最后一層是不需要使用激活的,最后一層其實(shí)是交叉熵?fù)p失函數(shù)直接替我們完成了這個(gè)操作。
這里一個(gè)關(guān)鍵是一定要區(qū)分清楚NLL損失和交叉熵?fù)p失。
圖像張量的問(wèn)題
如果一個(gè)灰度圖就是一個(gè)單通道的圖,我們平時(shí)看到的彩色圖像其實(shí)是三通道(Channel)的RGB,所以我們?cè)诒硎緢D像張量的時(shí)候一般是whc就是(寬度*高 *通道)
為什么我們要將數(shù)據(jù)轉(zhuǎn)化位N(0,1)因?yàn)檫@種標(biāo)準(zhǔn)分布的數(shù)據(jù)對(duì)于神經(jīng)網(wǎng)絡(luò)來(lái)說(shuō)是最好的,對(duì)于神經(jīng)網(wǎng)絡(luò)來(lái)說(shuō)訓(xùn)練效果是最好的
什么時(shí)候進(jìn)行transform的問(wèn)題
我們實(shí)際上是將transform定義在了datasets的位置。使用的下面的代碼:
trian_set = datasets.MNIST(root='./data',train=True,download=True,transform=transform)我們注意這樣子的一個(gè)問(wèn)題,這個(gè)MNIST數(shù)據(jù)集畢竟是一個(gè)圖片,其實(shí)占地方不小的,所以我們不能直接將其讀入內(nèi)存,所以我們不能讀進(jìn)來(lái)再transform,需要每次從文件讀進(jìn)來(lái)一個(gè)之后再進(jìn)行transform。
構(gòu)建神經(jīng)網(wǎng)絡(luò)
因?yàn)槲覀兪褂玫氖侨B接神經(jīng)網(wǎng)絡(luò),所以我們最后輸入的一個(gè)數(shù)據(jù)應(yīng)當(dāng)是一個(gè)矩陣(二維的)但是我們這里的輸入實(shí)際上是一個(gè)四維的輸入,數(shù)據(jù)量*通道數(shù)*寬*高,所以我們要轉(zhuǎn)化一下,這里就需要使用view函數(shù)了,具體使用下面的函數(shù)
x= x.view(-1,784)之后我們畫(huà)一個(gè)圖,寫(xiě)模型就好寫(xiě)了
代碼實(shí)現(xiàn)
import numpy import torch from torchvision import transforms from torchvision import datasets import torch.nn.functional as F import torch.optim as optim from torch.utils.data import Dataset from torch.utils.data import DataLoader#這里我們要理解這個(gè)from的作用,使用一個(gè)from#transeforms 主要是用來(lái)做圖像處理 # optim主要是包含優(yōu)化器的 #首先明白下面這個(gè)東西是個(gè)什么東西? #這個(gè)東西是個(gè)轉(zhuǎn)化器,可以對(duì)輸入的內(nèi)容做我們規(guī)定好的操作, # 具體操作就是下面[]中定義的。 #這里注意一個(gè)細(xì)節(jié)transforms和transform的區(qū)別,帶s的表示是一片,不帶s的是一個(gè),我們實(shí)例化的一個(gè) batch_size=64 transform= transforms.Compose([#這個(gè)首先轉(zhuǎn)化為一個(gè)張量transforms.ToTensor(),#為了更好的學(xué)習(xí)效果我們需要一個(gè)標(biāo)準(zhǔn)化的過(guò)程,前一個(gè)參數(shù)是均值后一個(gè)是方差# 這兩個(gè)參數(shù)都是MNIST數(shù)據(jù)集使用的,如果是自己的數(shù)據(jù)集這個(gè)要算一下。transforms.Normalize((0.1307,),(0.3081,)) ]) #這里其實(shí)和之前的一樣的,只是加了一個(gè)transform=的參數(shù) trian_set = datasets.MNIST(root='./data',train=True,download=True,transform=transform) trian_loader= DataLoader(trian_set,shuffle=True,batch_size=batch_size) test_set =datasets.MNIST(root='./data',train=False,download=True,transform=transform) test_loader= DataLoader(test_set,shuffle=True,batch_size=batch_size) class myModol(torch.nn.Module):def __init__(self):super(myModol,self).__init__()self.l1=torch.nn.Linear(784,512)self.l2=torch.nn.Linear(512,256)self.l3=torch.nn.Linear(256,128)self.l4=torch.nn.Linear(128,64)self.l5=torch.nn.Linear(64,10)def forward(self,x):#前面的-1代表著看著情況進(jìn)行變化。#這里我們注意我們的這里輸入的784不是隨便輸入的,# 是有實(shí)際意義的,MNIST的數(shù)據(jù)集的輸入是1*28*28的,# 所以我們想要轉(zhuǎn)化為二維的時(shí)候,一定要尊重原有的實(shí)際意義x=x.view(-1,784)x=F.relu(self.l1(x))x=F.relu(self.l2(x))x=F.relu(self.l3(x))x=F.relu(self.l4(x))return self.l5(x)#因?yàn)槲覀冏詈笫褂玫氖墙徊骒負(fù)p失函數(shù)已經(jīng)將激活層抱進(jìn)去了不用再單獨(dú)寫(xiě)了 model=myModol() #使用一個(gè)交叉熵?fù)p失函數(shù) criterion=torch.nn.CrossEntropyLoss() #因?yàn)槲覀冇?jì)算量已經(jīng)比較大了所以要使用一個(gè)帶有沖量的優(yōu)化器。 opminster= optim.SGD(model.parameters(),lr=0.01,momentum=0.5) def train(epoch):train_loss=0.0for batch_idx,data in enumerate(trian_loader,0):m_input,target=dataopminster.zero_grad()outputs= model(m_input)loss=criterion(outputs,target)loss.backward()opminster.step()train_loss+=loss.item()if batch_idx%300==299:#每300次才輸出一次,另外因?yàn)槲覀兌际菑?開(kāi)始計(jì)數(shù)所以我們需要+1print('[%d,%5d]loss:%.3f'%(epoch+1,batch_idx+1,train_loss/300))train_loss=0 def test():#定義幾個(gè)計(jì)數(shù)變量correct=0total=0#因?yàn)槲覀冊(cè)谟?jì)算損失的時(shí)候是不需要進(jìn)行梯度計(jì)算的,# 所以這里取消梯度計(jì)算來(lái)增加速度。with torch.no_grad():for data in test_loader:images,targets=dataoutputs=model(images)#這里我們注意我們?cè)谳敵龅臅r(shí)候是一個(gè)最大值,一個(gè)最大值角標(biāo),我們只需要最大值角標(biāo),# 這里我們注意dim=1的這個(gè)問(wèn)題,dim=0代表每列找一個(gè),dim=1代表每行找。_,predicted=torch.max(outputs.data,dim=1)#這里我們注意一個(gè)問(wèn)題就是返回的形式是torch.Size,# 這個(gè)玩意是一個(gè)元組,這里是(行數(shù),列數(shù))所以我們要取出來(lái)第0個(gè)。total+=targets.size(0)#我們注意這里張量比較的使用問(wèn)題correct+=(predicted==targets).sum().item()print('acc on test set:%d%%'%(100*correct/total)) if __name__=='__main__':for epoch in range(10):train(epoch)test() #但是我們這里的全連接層得到的準(zhǔn)確度并不高,因?yàn)槲覀兪菍D上的所有信息都全部利用了 #其實(shí)決定圖片的數(shù)字到底是多少并不是由全部的情況決定的。總結(jié)
以上是生活随笔為你收集整理的pytorch的多分类问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: pytorch处理多维输入的问题
- 下一篇: 梯度消失的问题