【小白学PyTorch】6.模型的构建访问遍历存储(附代码)
<<小白學(xué)PyTorch>>
小白學(xué)PyTorch | 5 torchvision預(yù)訓(xùn)練模型與數(shù)據(jù)集全覽
小白學(xué)PyTorch | 4 構(gòu)建模型三要素與權(quán)重初始化
小白學(xué)PyTorch | 3 淺談Dataset和Dataloader
小白學(xué)PyTorch | 2 淺談?dòng)?xùn)練集驗(yàn)證集和測(cè)試集
小白學(xué)PyTorch | 1 搭建一個(gè)超簡(jiǎn)單的網(wǎng)絡(luò)
小白學(xué)PyTorch | 動(dòng)態(tài)圖與靜態(tài)圖的淺顯理解
文章目錄:
1 模型構(gòu)建函數(shù)
1.1 add_module
1.2 ModuleList
1.3 Sequential
1.4 小總結(jié)
2 遍歷模型結(jié)構(gòu)
2.1 modules()
2.2 named_modules()
2.3 parameters()
3 保存與載入
本文是對(duì)一些函數(shù)的學(xué)習(xí)。函數(shù)主要包括下面四個(gè)方便:
模型構(gòu)建的函數(shù):add_module,add_module,add_module
訪問(wèn)子模塊:add_module,add_module,add_module,add_module
網(wǎng)絡(luò)遍歷:add_module,add_module
模型的保存與加載:add_module,add_module,add_module
1 模型構(gòu)建函數(shù)
torch.nn.Module是所有網(wǎng)絡(luò)的基類,在PyTorch實(shí)現(xiàn)模型的類中都要繼承這個(gè)類(這個(gè)在之前的課程中已經(jīng)提到)。在構(gòu)建Module中,Module是一個(gè)包含其他的Module的,類似于,你可以先定義一個(gè)小的網(wǎng)絡(luò)模塊,然后把這個(gè)小模塊作為另外一個(gè)網(wǎng)絡(luò)的組件。因此網(wǎng)絡(luò)結(jié)構(gòu)是呈現(xiàn)樹狀結(jié)構(gòu)。
我們先簡(jiǎn)單定義一個(gè)網(wǎng)絡(luò):
import?torch.nn?as?nn import?torch? class?MyNet(nn.Module):def?__init__(self):super(MyNet,self).__init__()self.conv1?=?nn.Conv2d(3,64,3)self.conv2?=?nn.Conv2d(64,64,3)def?forward(self,x):x?=?self.conv1(x)x?=?self.conv2(x)return?x net?=?MyNet() print(net)輸出結(jié)果:MyNet中有兩個(gè)屬性conv1和conv2是兩個(gè)卷積層,在正向傳播forward的過(guò)程中,依次調(diào)用這兩個(gè)卷積層實(shí)現(xiàn)網(wǎng)絡(luò)的功能。
1.1 add_module
這種是最常見(jiàn)的定義網(wǎng)絡(luò)的功能,在有些項(xiàng)目中,會(huì)看到這樣的方法add_module。我們用這個(gè)方法來(lái)重寫上面的網(wǎng)絡(luò):
class?MyNet(nn.Module):def?__init__(self):super(MyNet,self).__init__()self.add_module('conv1',nn.Conv2d(3,64,3))self.add_module('conv2',nn.Conv2d(64,64,3))def?forward(self,x):x?=?self.conv1(x)x?=?self.conv2(x)return?x其實(shí)add_module(name,layer)和self.name=layer實(shí)現(xiàn)了相同的功能,個(gè)人感覺(jué)也許是因?yàn)閍dd_module可以使用字符串來(lái)定義變量名字,所以可以放在循環(huán)中?反正這個(gè)先了解熟悉熟悉。
上面的兩種方法都是一層一層的添加layer,如果網(wǎng)絡(luò)復(fù)雜的話,那就需要寫很多重復(fù)的代碼了。因此接下來(lái)來(lái)講解一下網(wǎng)絡(luò)模塊的構(gòu)建,torch.nn.ModuleList和torch.nn.Sequential
1.2 ModuleList
ModuleList按照字面意思是用list的形式保存網(wǎng)絡(luò)層的。這樣就可以先將網(wǎng)絡(luò)需要的layer構(gòu)建好,保存到一個(gè)list,然后通過(guò)ModuleList方法添加到網(wǎng)絡(luò)中.
class?MyNet(nn.Module):def?__init__(self):super(MyNet,self).__init__()self.linears?=?nn.ModuleList([nn.Linear(10,10)?for?i?in?range(5)])def?forward(self,x):for?l?in?self.linears:x?=?l(x)return?x net?=?MyNet() print(net)輸出結(jié)果是:
這個(gè)ModuleList主要是用在讀取config文件來(lái)構(gòu)建網(wǎng)絡(luò)模型中的,下面用VGG模型的構(gòu)建為例子:
vgg_cfg?=?[64,?64,?'M',?128,?128,?'M',?256,?256,?256,?'C',?512,?512,?512,?'M',512,?512,?512,?'M']def?vgg(cfg,?i,?batch_norm=False):layers?=?[]in_channels?=?ifor?v?in?cfg:if?v?==?'M':layers?+=?[nn.MaxPool2d(kernel_size=2,?stride=2)]elif?v?==?'C':layers?+=?[nn.MaxPool2d(kernel_size=2,?stride=2,?ceil_mode=True)]else:conv2d?=?nn.Conv2d(in_channels,?v,?kernel_size=3,?padding=1)if?batch_norm:layers?+=?[conv2d,?nn.BatchNorm2d(v),?nn.ReLU(inplace=True)]else:layers?+=?[conv2d,?nn.ReLU(inplace=True)]in_channels?=?vreturn?layersclass?Model1(nn.Module):def?__init__(self):super(Model1,self).__init__()self.vgg?=?nn.ModuleList(vgg(vgg_cfg,3))def?forward(self,x):for?l?in?self.vgg:x?=?l(x) m1?=?Model1() print(m1)先讀取網(wǎng)絡(luò)結(jié)構(gòu)的配置文件vgg_cfg然后根據(jù)這個(gè)文件創(chuàng)建對(duì)應(yīng)的Layer list,然后使用ModuleList添加到網(wǎng)絡(luò)中,這樣可以快速創(chuàng)建不同的網(wǎng)絡(luò)(用上面為例子的話,可以通過(guò)修改配置文件,然后快速修改網(wǎng)絡(luò)結(jié)構(gòu) )
1.3 Sequential
在一些自己做的小項(xiàng)目中,Sequential其實(shí)用的更為頻繁。依然重寫最初最簡(jiǎn)單的例子:
class?MyNet(nn.Module):def?__init__(self):super(MyNet,self).__init__()self.conv?=?nn.Sequential(nn.Conv2d(3,64,3),nn.Conv2d(64,64,3))def?forward(self,x):x?=?self.conv(x)return?x net?=?MyNet() print(net)運(yùn)行結(jié)果:
觀察細(xì)致的朋友可以發(fā)現(xiàn)這個(gè)問(wèn)題,Seqential內(nèi)的網(wǎng)絡(luò)層是默認(rèn)用數(shù)字進(jìn)行標(biāo)號(hào)的,而一開始我們使用self.conv1和self.conv2的時(shí)候,使用conv1和conv2作為標(biāo)號(hào)的。
我們?nèi)绾涡薷腟equential中網(wǎng)絡(luò)層的名稱呢?這里需要使用到collections.OrderedDict有序字典。Sequential是支持有序字典構(gòu)建的。
from?collections?import?OrderedDict? class?MyNet(nn.Module):def?__init__(self):super(MyNet,self).__init__()self.conv?=?nn.Sequential(OrderedDict([('conv1',nn.Conv2d(3,64,3)),('conv2',nn.Conv2d(64,64,3))]))def?forward(self,x):x?=?self.conv(x)return?x net?=?MyNet() print(net)輸出結(jié)果:
1.4 小總結(jié)
單獨(dú)增加一個(gè)網(wǎng)絡(luò)層或者子模塊,可以用add_module或者直接賦予屬性;
ModuleList可以將一個(gè)Module的List增加到網(wǎng)絡(luò)中,自由度較高。
Sequential按照順序產(chǎn)生一個(gè)Module模塊。這里推薦習(xí)慣使用OrderedDict的方法進(jìn)行構(gòu)建。對(duì)網(wǎng)絡(luò)層加上規(guī)范的名稱,這樣有助于后續(xù)查找與遍歷
2 遍歷模型結(jié)構(gòu)
本章節(jié)使用下面的方法進(jìn)行遍歷之前提到的Module。(個(gè)人理解,Module是多個(gè)layer的合并,但是一個(gè)layer可以說(shuō)成Module。 ) 先定義一個(gè)網(wǎng)絡(luò)吧,隨便寫一個(gè):
import?torch.nn?as?nn import?torch? from?collections?import?OrderedDict class?MyNet(nn.Module):def?__init__(self):super(MyNet,self).__init__()self.conv1?=?nn.Conv2d(in_channels=3,out_channels=64,kernel_size=3)self.conv2?=?nn.Conv2d(64,64,3)self.maxpool1?=?nn.MaxPool2d(2,2)self.features?=?nn.Sequential(OrderedDict([('conv3',?nn.Conv2d(64,128,3)),('conv4',?nn.Conv2d(128,128,3)),('relu1',?nn.ReLU())]))def?forward(self,x):x?=?self.conv1(x)x?=?self.conv2(x)x?=?self.maxpool1(x)x?=?self.features(x)return?x net?=?MyNet() print(net)輸出結(jié)果是:
2.1 modules()
在第四課中初始化模型各個(gè)層的參數(shù)的時(shí)候,用到了這個(gè)方法,現(xiàn)在我們?cè)賮?lái)理解一下:
for?idx,m?in?enumerate(net.modules()):print(idx,"-",m)運(yùn)行結(jié)果:
上面那個(gè)網(wǎng)絡(luò)構(gòu)建的時(shí)候用到了Sequential,所以網(wǎng)絡(luò)中其實(shí)是嵌套了一個(gè)小的Module,這就是之前提到的樹狀結(jié)構(gòu),然后上面便利的時(shí)候也是樹狀結(jié)構(gòu)的便利過(guò)程,可以看出來(lái)應(yīng)該是一個(gè)深度遍歷的過(guò)程。
首先第一個(gè)輸出的是最大的那個(gè)Module,也就是整個(gè)網(wǎng)絡(luò),0-Model整個(gè)網(wǎng)絡(luò)模塊;
1-2-3-4是網(wǎng)絡(luò)的四個(gè)子模塊,4-Sequential中間仍然包含子模塊
5-6-7是模塊4-Sequential的子模塊。
【總結(jié)】
modules()是遞歸的返回網(wǎng)絡(luò)的各個(gè)module(深度遍歷),從最頂層直到最后的葉子的module。
2.2 named_modules()
named_modules()和module()類似,只是同時(shí)返回name和module。
for?idx,(name,m)?in?enumerate(net.named_modules()):print(idx,"-",name)輸出結(jié)果:
2.3 parameters()
for?p?in?net.parameters():print(type(p.data),p.size())運(yùn)行結(jié)果:
輸出的是四個(gè)卷積層的權(quán)重矩陣參數(shù)和偏置參數(shù)。值得一提的是,對(duì)網(wǎng)絡(luò)進(jìn)行訓(xùn)練時(shí)需要將parameters()作為優(yōu)化器optimizer的參數(shù)。
optimizer?=?torch.optim.SGD(net.parameters(),lr?=?0.001,momentum=0.9)總之呢,這個(gè)parameters()是返回網(wǎng)絡(luò)所有的參數(shù),主要用在給optimizer優(yōu)化器用的。而要對(duì)網(wǎng)絡(luò)的某一層的參數(shù)做處理的時(shí)候,一般還是使用named_parameters()方便一些。
for?idx,(name,m)?in?enumerate(net.named_parameters()):print(idx,"-",name,m.size())輸出結(jié)果:
【小擴(kuò)展】
我個(gè)人有時(shí)會(huì)使用下面的方法來(lái)獲取參數(shù):
for?idx,(name,m)?in?enumerate(net.named_modules()):if?isinstance(m,nn.Conv2d):print(m.weight.shape)print(m.bias.shape)先判斷是否是卷積層,然后獲取其參數(shù),輸出結(jié)果:
3 保存與載入
PyTorch使用torch.save和torch.load方法來(lái)保存和加載網(wǎng)絡(luò),而且網(wǎng)絡(luò)結(jié)構(gòu)和參數(shù)可以分開的保存和加載。
torch.save(model,'model.pth')?#?保存 model?=?torch.load("model.pth")?#?加載pytorch中網(wǎng)絡(luò)結(jié)構(gòu)和模型參數(shù)是可以分開保存的。上面的方法是兩者同時(shí)保存到了.pth文件中,當(dāng)然,你也可以僅僅保存網(wǎng)絡(luò)的參數(shù)來(lái)減小存儲(chǔ)文件的大小。注意:如果你僅僅保存模型參數(shù),那么在載入的時(shí)候,是需要通過(guò)運(yùn)行代碼來(lái)初始化模型的結(jié)構(gòu)的。
torch.save(model.state_dict(),"model.pth")?#?保存參數(shù) model?=?MyNet()?#?代碼中創(chuàng)建網(wǎng)絡(luò)結(jié)構(gòu) params?=?torch.load("model.pth")?#?加載參數(shù) model.load_state_dict(params)?#?應(yīng)用到網(wǎng)絡(luò)結(jié)構(gòu)中至此,我們今天已經(jīng)學(xué)習(xí)了不少的內(nèi)容,大家對(duì)PyTorch的掌握更近一步了呢~
- END -往期精彩回顧適合初學(xué)者入門人工智能的路線及資料下載機(jī)器學(xué)習(xí)及深度學(xué)習(xí)筆記等資料打印機(jī)器學(xué)習(xí)在線手冊(cè)深度學(xué)習(xí)筆記專輯《統(tǒng)計(jì)學(xué)習(xí)方法》的代碼復(fù)現(xiàn)專輯 AI基礎(chǔ)下載機(jī)器學(xué)習(xí)的數(shù)學(xué)基礎(chǔ)專輯獲取一折本站知識(shí)星球優(yōu)惠券,復(fù)制鏈接直接打開:https://t.zsxq.com/662nyZF本站qq群1003271085。加入微信群請(qǐng)掃碼進(jìn)群(如果是博士或者準(zhǔn)備讀博士請(qǐng)說(shuō)明):總結(jié)
以上是生活随笔為你收集整理的【小白学PyTorch】6.模型的构建访问遍历存储(附代码)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【学术相关】你只看到了200万年薪的招聘
- 下一篇: 彻底掌握机器学习的6个主流模型,是什么水