如何使用Pytorch搭建模型
1 模型定義
和TF很像,Pytorch也通過(guò)繼承父類來(lái)搭建模型,同樣也是實(shí)現(xiàn)兩個(gè)方法。在TF中是__init__()和call(),在Pytorch中則是__init__()和forward()。功能類似,都分別是初始化模型內(nèi)部結(jié)構(gòu)和進(jìn)行推理。其它功能比如計(jì)算loss和訓(xùn)練函數(shù),你也可以繼承在里面,當(dāng)然這是可選的。下面搭建一個(gè)判別MNIST手寫(xiě)字的Demo,首先給出模型代碼:
import numpy as np import matplotlib.pyplot as plt import torch from torch import nn,optim from torchsummary import summary from keras.datasets import mnist from keras.utils import to_categorical device = torch.device('cuda') #——————1—————— class ModelTest(nn.Module): def __init__(self,device): super().__init__() self.layer1 = nn.Sequential(nn.Flatten(),nn.Linear(28*28,512),nn.ReLU())#——————2—————— self.layer2 = nn.Sequential(nn.Linear(512,512),nn.ReLU()) self.layer3 = nn.Sequential(nn.Linear(512,512),nn.ReLU()) self.layer4 = nn.Sequential(nn.Linear(512,10),nn.Softmax()) self.to(device) #——————3—————— self.opt = optim.SGD(self.parameters(),lr=0.01)#——————4—————— def forward(self,inputs): #——————5—————— x = self.layer1(inputs) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x) return x def get_loss(self,true_labels,predicts): loss = -true_labels * torch.log(predicts) #——————6—————— loss = torch.mean(loss) return loss def train(self,imgs,labels): predicts = model(imgs) loss = self.get_loss(labels,predicts) self.opt.zero_grad()#——————7—————— loss.backward()#——————8—————— self.opt.step()#——————9—————— model = ModelTest(device) summary(model,(1,28,28),3,device='cuda') #——————10——————
#1:獲取設(shè)備,以方便后面的模型與變量進(jìn)行內(nèi)存遷移,設(shè)備名只有兩種:'cuda'和'cpu'。通常是在你有GPU的情況下需要這樣顯式進(jìn)行設(shè)備的設(shè)置,從而在需要時(shí),你可以將變量從主存遷移到顯存中。如果沒(méi)有GPU,不獲取也沒(méi)事,pytorch會(huì)默認(rèn)將參數(shù)都保存在主存中。
#2:模型中層的定義,可以使用Sequential將想要統(tǒng)一管理的層集中表示為一層。
#3:在初始化中將模型參數(shù)遷移到GPU顯存中,加速運(yùn)算,當(dāng)然你也可以在需要時(shí)在外部執(zhí)行model.to(device)進(jìn)行遷移。
#4:定義模型的優(yōu)化器,和TF不同,pytorch需要在定義時(shí)就將需要梯度下降的參數(shù)傳入,也就是其中的self.parameters(),表示當(dāng)前模型的所有參數(shù)。實(shí)際上你不用擔(dān)心定義優(yōu)化器和模型參數(shù)的順序問(wèn)題,因?yàn)閟elf.parameters()的輸出并不是模型參數(shù)的實(shí)例,而是整個(gè)模型參數(shù)對(duì)象的指針,所以即使你在定義優(yōu)化器之后又定義了一個(gè)層,它依然能優(yōu)化到。當(dāng)然優(yōu)化器你也可以在外部定義,傳入model.parameters()即可。這里定義了一個(gè)隨機(jī)梯度下降。
#5:模型的前向傳播,和TF的call()類似,定義好model()所執(zhí)行的就是這個(gè)函數(shù)。
#6:我將獲取loss的函數(shù)集成在了模型中,這里計(jì)算的是真實(shí)標(biāo)簽和預(yù)測(cè)標(biāo)簽之間的交叉熵。
#7/8/9:在TF中,參數(shù)梯度是保存在梯度帶中的,而在pytorch中,參數(shù)梯度是各自集成在對(duì)應(yīng)的參數(shù)中的,可以使用tensor.grad來(lái)查看。每次對(duì)loss執(zhí)行backward(),pytorch都會(huì)將參與loss計(jì)算的所有可訓(xùn)練參數(shù)關(guān)于loss的梯度疊加進(jìn)去(直接相加)。所以如果我們沒(méi)有疊加梯度的意愿的話,那就要在backward()之前先把之前的梯度刪除。又因?yàn)槲覀兦懊嬉呀?jīng)把待訓(xùn)練的參數(shù)都傳入了優(yōu)化器,所以,對(duì)優(yōu)化器使用zero_grad(),就能把所有待訓(xùn)練參數(shù)中已存在的梯度都清零。那么梯度疊加什么時(shí)候用到呢?比如批量梯度下降,當(dāng)內(nèi)存不夠直接計(jì)算整個(gè)批量的梯度時(shí),我們只能將批量分成一部分一部分來(lái)計(jì)算,每算一個(gè)部分得到loss就backward()一次,從而得到整個(gè)批量的梯度。梯度計(jì)算好后,再執(zhí)行優(yōu)化器的step(),優(yōu)化器根據(jù)可訓(xùn)練參數(shù)的梯度對(duì)其執(zhí)行一步優(yōu)化。
#10:使用torchsummary函數(shù)顯示模型結(jié)構(gòu)。奇怪為什么不把這個(gè)繼承在torch里面,要重新安裝一個(gè)torchsummary庫(kù)。
2 訓(xùn)練及可視化
接下來(lái)使用模型進(jìn)行訓(xùn)練,因?yàn)閜ytorch自帶的MNIST數(shù)據(jù)集并不好用,所以我使用的是Keras自帶的,定義了一個(gè)獲取數(shù)據(jù)的生成器。下面是完整的訓(xùn)練及繪圖代碼(50次迭代記錄一次準(zhǔn)確率):
import numpy as np import matplotlib.pyplot as plt import torch from torch import nn,optim from torchsummary import summary from keras.datasets import mnist from keras.utils import to_categorical device = torch.device('cuda') #——————1—————— class ModelTest(nn.Module): def __init__(self,device): super().__init__() self.layer1 = nn.Sequential(nn.Flatten(),nn.Linear(28*28,512),nn.ReLU())#——————2—————— self.layer2 = nn.Sequential(nn.Linear(512,512),nn.ReLU()) self.layer3 = nn.Sequential(nn.Linear(512,512),nn.ReLU()) self.layer4 = nn.Sequential(nn.Linear(512,10),nn.Softmax()) self.to(device) #——————3—————— self.opt = optim.SGD(self.parameters(),lr=0.01)#——————4—————— def forward(self,inputs): #——————5—————— x = self.layer1(inputs) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x) return x def get_loss(self,true_labels,predicts): loss = -true_labels * torch.log(predicts) #——————6—————— loss = torch.mean(loss) return loss def train(self,imgs,labels): predicts = model(imgs) loss = self.get_loss(labels,predicts) self.opt.zero_grad()#——————7—————— loss.backward()#——————8—————— self.opt.step()#——————9—————— def get_data(device,is_train = True, batch = 1024, num = 10000): train_data,test_data = mnist.load_data() if is_train: imgs,labels = train_data else: imgs,labels = test_data imgs = (imgs/255*2-1)[:,np.newaxis,...] labels = to_categorical(labels,10) imgs = torch.tensor(imgs,dtype=torch.float32).to(device) labels = torch.tensor(labels,dtype=torch.float32).to(device) i = 0 while(True): i += batch if i > num: i = batch yield imgs[i-batch:i],labels[i-batch:i] train_dg = get_data(device, True,batch=4096,num=60000) test_dg = get_data(device, False,batch=5000,num=10000) model = ModelTest(device) summary(model,(1,28,28),11,device='cuda') ACCs = [] import time start = time.time() for j in range(20000): #訓(xùn)練 imgs,labels = next(train_dg) model.train(imgs,labels) #驗(yàn)證 img,label = next(test_dg) predicts = model(img) acc = 1 - torch.count_nonzero(torch.argmax(predicts,axis=1) - torch.argmax(label,axis=1))/label.shape[0] if j % 50 == 0: t = time.time() - start start = time.time() ACCs.append(acc.cpu().numpy()) print(j,t,'ACC: ',acc) #繪圖 x = np.linspace(0,len(ACCs),len(ACCs)) plt.plot(x,ACCs)
準(zhǔn)確率變化圖如下:
3 注意事項(xiàng)
需要注意的是,pytorch的tensor基于numpy的array,它們是共享內(nèi)存的。也就是說(shuō),如果你把tensor直接插入一個(gè)列表,當(dāng)你修改這個(gè)tensor時(shí),列表中的這個(gè)tensor也會(huì)被修改;更容易被忽略的是,即使你用tensor.detach.numpy(),先將tensor轉(zhuǎn)換為array類型,再插入列表,當(dāng)你修改原本的tensor時(shí),列表中的這個(gè)array也依然會(huì)被修改。所以如果我們只是想保存tensor的值而不是整個(gè)對(duì)象,就要使用np.array(tensor)將tensor的值復(fù)制出來(lái)。
以上就是如何使用Pytorch搭建模型的詳細(xì)內(nèi)容,更多關(guān)于Pytorch搭建模型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python 判斷一組數(shù)據(jù)是否符合正態(tài)分布
這篇文章主要介紹了python 如何判斷一組數(shù)據(jù)是否符合正態(tài)分布,幫助大家更好的利用python分析數(shù)據(jù),感興趣的朋友可以了解下2020-09-09python實(shí)現(xiàn)的希爾排序算法實(shí)例
這篇文章主要介紹了python實(shí)現(xiàn)的希爾排序算法,實(shí)例分析了基于Python實(shí)現(xiàn)希爾排序的相關(guān)技巧,需要的朋友可以參考下2015-07-07python實(shí)現(xiàn)簡(jiǎn)單爬蟲(chóng)功能的示例
本文主要是介紹python實(shí)現(xiàn)簡(jiǎn)單爬蟲(chóng)功能的示例,主要實(shí)現(xiàn)了把我們想要的圖片爬蟲(chóng)到本地的一個(gè)示例,有需要的朋友可以了解一下。2016-10-10pandas 數(shù)據(jù)索引與選取的實(shí)現(xiàn)方法
這篇文章主要介紹了pandas 數(shù)據(jù)索引與選取的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06python使用urllib2提交http post請(qǐng)求的方法
這篇文章主要介紹了python使用urllib2提交http post請(qǐng)求的方法,涉及Python使用urllib2模塊的相關(guān)技巧,需要的朋友可以參考下2015-05-05python生成13位或16位時(shí)間戳以及反向解析時(shí)間戳的實(shí)例
這篇文章主要介紹了python生成13位或16位時(shí)間戳以及反向解析時(shí)間戳的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03Python使用正則匹配實(shí)現(xiàn)抓圖代碼分享
本文給大家分享的是個(gè)人的第一個(gè)作品,使用Python正則匹配實(shí)現(xiàn)抓圖代碼,非常的簡(jiǎn)單實(shí)用,推薦給大家,小伙伴們可以自由擴(kuò)展下。2015-04-04