pytorch的多分类问题
多分類問題softmax的分類器
為什么要探索多分類
之前我們在處理糖尿病數(shù)據(jù)集的時候我們只是有兩種分類,但是很多情況的數(shù)據(jù)集不只有兩種,例如MNIST數(shù)據(jù)集就是手寫數(shù)字的數(shù)據(jù)集有10種不同的標(biāo)簽。所以我們必須有處理多種分類標(biāo)簽的能力。
探索多分類
是否還可以使用二分類的操作?
當(dāng)然還是可以使用二分類的方法來解決這個問題,某分類設(shè)置位p=1其他全部p=0就可以了,還是使用交叉熵?fù)p失函數(shù)來處理。
這里我們要注意到,我們的樣本必須是只有一個選擇的,所以我們的輸出數(shù)據(jù)當(dāng)中只能有一個輸出的數(shù)據(jù)比較大,要對其他形成抑制,或者描述為所有的輸出的和必須是1。但是我們使用上面的方法并不能滿足,甚至所有的分類的輸出都是0.8或0.9這種。
如果我們這樣做呢?將十種輸出的最后一種轉(zhuǎn)化為1減去其他輸出,這樣是否可行呢?實際上也并不行,因為我們?nèi)绻@樣處理將會導(dǎo)致十種輸出的結(jié)果過程并不相同,導(dǎo)致系統(tǒng)的并行能力下降,使得整體的效率下降。
那該怎么實現(xiàn)?
所以我們的輸出應(yīng)當(dāng)是一個分布,我們前面的一些層還是可以使用sigmoid來做一個層,最后我們要用一個特殊層來完成一個將原有輸出轉(zhuǎn)化位一個分布的操作。
我們看一下我們需要做到什么內(nèi)容:
1.輸出的內(nèi)容和是一個1 。
2.輸出的內(nèi)容都在0-1之間。
我們可以想到第一個內(nèi)容比較好實現(xiàn)我們只需要讓輸出是一個分?jǐn)?shù)就行了。分母設(shè)置成一樣的內(nèi)容,分子的和等于這個分母。這是十分容易的。
之后我們再來分析第二個,想要讓輸出是0-1,在我們已經(jīng)做到第一個要求的情況下,我們想做到第二個,其實只需要所有的輸出全部都是大于0的就可以完成了。這樣我們就想到了一個東西指數(shù)函數(shù),指數(shù)函數(shù)的值永遠(yuǎn)是大于0的。這樣問題就解決了。
所以我們只需要使用一個softmax層,這個層的運(yùn)算如下:
這樣就可以完成我們的需求。
我們來看一個實際的例子就更好理解了:
這樣我們就理解了softmax層
那么損失函數(shù)又該怎么做
我們實際上還是需要使用交叉熵?fù)p失函數(shù),我們看一下交叉熵?fù)p失函數(shù),其實是什么情況,我們知道交叉熵?fù)p失函數(shù)是根據(jù)其中的概率進(jìn)行計算的,因為我們是打標(biāo)簽,除了1的就全是0所以我們需要計算的內(nèi)容其實可以簡化:
所以其實loss函數(shù)就發(fā)生了變化:
整體的情況就變成了如下的情況:
這個其實就是NLL損失函數(shù):
這個是理論上的情況,但是我們在pytorch當(dāng)中其實并沒有這么復(fù)雜,我們可以直接使用交叉熵?fù)p失函數(shù)來將從softmax直接一下子全部包含了。注意我們最后一層是不需要使用激活的,最后一層其實是交叉熵?fù)p失函數(shù)直接替我們完成了這個操作。
這里一個關(guān)鍵是一定要區(qū)分清楚NLL損失和交叉熵?fù)p失。
圖像張量的問題
如果一個灰度圖就是一個單通道的圖,我們平時看到的彩色圖像其實是三通道(Channel)的RGB,所以我們在表示圖像張量的時候一般是whc就是(寬度*高 *通道)
為什么我們要將數(shù)據(jù)轉(zhuǎn)化位N(0,1)因為這種標(biāo)準(zhǔn)分布的數(shù)據(jù)對于神經(jīng)網(wǎng)絡(luò)來說是最好的,對于神經(jīng)網(wǎng)絡(luò)來說訓(xùn)練效果是最好的
什么時候進(jìn)行transform的問題
我們實際上是將transform定義在了datasets的位置。使用的下面的代碼:
trian_set = datasets.MNIST(root='./data',train=True,download=True,transform=transform)我們注意這樣子的一個問題,這個MNIST數(shù)據(jù)集畢竟是一個圖片,其實占地方不小的,所以我們不能直接將其讀入內(nèi)存,所以我們不能讀進(jìn)來再transform,需要每次從文件讀進(jìn)來一個之后再進(jìn)行transform。
構(gòu)建神經(jīng)網(wǎng)絡(luò)
因為我們使用的是全連接神經(jīng)網(wǎng)絡(luò),所以我們最后輸入的一個數(shù)據(jù)應(yīng)當(dāng)是一個矩陣(二維的)但是我們這里的輸入實際上是一個四維的輸入,數(shù)據(jù)量*通道數(shù)*寬*高,所以我們要轉(zhuǎn)化一下,這里就需要使用view函數(shù)了,具體使用下面的函數(shù)
x= x.view(-1,784)之后我們畫一個圖,寫模型就好寫了
代碼實現(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#這里我們要理解這個from的作用,使用一個from#transeforms 主要是用來做圖像處理 # optim主要是包含優(yōu)化器的 #首先明白下面這個東西是個什么東西? #這個東西是個轉(zhuǎn)化器,可以對輸入的內(nèi)容做我們規(guī)定好的操作, # 具體操作就是下面[]中定義的。 #這里注意一個細(xì)節(jié)transforms和transform的區(qū)別,帶s的表示是一片,不帶s的是一個,我們實例化的一個 batch_size=64 transform= transforms.Compose([#這個首先轉(zhuǎn)化為一個張量transforms.ToTensor(),#為了更好的學(xué)習(xí)效果我們需要一個標(biāo)準(zhǔn)化的過程,前一個參數(shù)是均值后一個是方差# 這兩個參數(shù)都是MNIST數(shù)據(jù)集使用的,如果是自己的數(shù)據(jù)集這個要算一下。transforms.Normalize((0.1307,),(0.3081,)) ]) #這里其實和之前的一樣的,只是加了一個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不是隨便輸入的,# 是有實際意義的,MNIST的數(shù)據(jù)集的輸入是1*28*28的,# 所以我們想要轉(zhuǎn)化為二維的時候,一定要尊重原有的實際意義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)#因為我們最后使用的是交叉熵?fù)p失函數(shù)已經(jīng)將激活層抱進(jìn)去了不用再單獨(dú)寫了 model=myModol() #使用一個交叉熵?fù)p失函數(shù) criterion=torch.nn.CrossEntropyLoss() #因為我們計算量已經(jīng)比較大了所以要使用一個帶有沖量的優(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次才輸出一次,另外因為我們都是從0開始計數(shù)所以我們需要+1print('[%d,%5d]loss:%.3f'%(epoch+1,batch_idx+1,train_loss/300))train_loss=0 def test():#定義幾個計數(shù)變量correct=0total=0#因為我們在計算損失的時候是不需要進(jìn)行梯度計算的,# 所以這里取消梯度計算來增加速度。with torch.no_grad():for data in test_loader:images,targets=dataoutputs=model(images)#這里我們注意我們在輸出的時候是一個最大值,一個最大值角標(biāo),我們只需要最大值角標(biāo),# 這里我們注意dim=1的這個問題,dim=0代表每列找一個,dim=1代表每行找。_,predicted=torch.max(outputs.data,dim=1)#這里我們注意一個問題就是返回的形式是torch.Size,# 這個玩意是一個元組,這里是(行數(shù),列數(shù))所以我們要取出來第0個。total+=targets.size(0)#我們注意這里張量比較的使用問題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)確度并不高,因為我們是將圖上的所有信息都全部利用了 #其實決定圖片的數(shù)字到底是多少并不是由全部的情況決定的。總結(jié)
以上是生活随笔為你收集整理的pytorch的多分类问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pytorch处理多维输入的问题
- 下一篇: 梯度消失的问题