開始看Pytorch關於神經網路的code後,發現同一個模型有多種搭建方法,整個頭腦很錯亂(資質平凡XD,就把一些專有名詞google一遍,才了解原來大有學問!! 也因此有了寫這篇文章的動機囉~~
1.Pytorch常見搭建神經網路方法
2.模型容器(container)
3.官方文件定義&舉例說明
一個完整模型將堆疊多個模組(神經層),堆疊方式又有兩種:
(1)自建nn.Module子類別
(2)nn.Sequential(類似操作: nn.ModuleList、nn.ModuleDict)
兩種方法簡要比較如下:
模型搭建方式 | (1)nn.Module | (2)nn.Sequential |
---|---|---|
定義 | base class for all neural network modules | a direct subclass of nn.Module (Ref) |
特點 | 能自行設定傳播過程(forward function) | 快速搭建「一層連接一層」的模型建構 |
補充 | 在大型模型結構中,可用nn.Sequential建立一個個分塊(sequential submodules),在組裝成整個模型 |
其中nn.Sequential又可視為一個容器(container),為nn.Module的子類別(subclass),類似的容器還有nn.ModuleList和nn.ModuleDict,比較如下
nn.Sequential | nn.ModuleList | nn.ModuleDict | |
---|---|---|---|
定義 | A sequential container. | Holds submodules in a list and also a container. | 同左,但有索引(index)可指定 |
特點 | 按照順序來排列,須確定上一層輸出和下一層輸入大小一致 | 儲存不同模組(modules,又稱為神經層layers)並將每個module的參數(parameters),可把任意nn.Module加入該串列(list),加入後會自動將這些module&它們的參數添加到整個神經網路,在forward可任意調動順序做組合 | 同左,同樣自動將每個module和參數添加到網路 |
差別_1 | 內建forward函數,不用另外寫 | 沒有forward函數,需自行設定 | 同左 |
影響_1 | 無法自訂forward函數,缺乏彈性。一般是用此來建立卷積塊(block),再將一個個block組成一個神經網路 | 具備彈性,能自行設定forward函數 | 同左 |
差別_2 | 可搭配OrderedDict對每一層神經層命名 | 無相關設定 | 通過鍵值對(key,value)方式為每個神經層指定命名 |
差別_3 | 模型按此順序排列運行,須確定上一層輸出和下一層輸入大小一致 | 只是定義所有模塊,執行順序由foward函數設定(但層與層之間輸出輸入還是要一致) | 同左 |
差別_4 | 無 | 可搭配迴圈(for-loop)方便建類似或相似的神經層 | 無 |
常見方法 | 無 | append(), extend(), insert() | clear(), items(), pop()等等 |
以上四個類別(nn.Module, nn.Sequential, nn.ModuleList, nn.ModuleDict)介紹如下:
(1)CLASS torch.nn.Module
Definition(Def): Base class for all neural network modules. Your models should also subclass this class.
nn.Module為Pytorch中專門為神經網路開發的類別(class),其中包含建立各種神經網路架構所需的單元,這些建構單元稱為模組(modules),或又稱為層、神經層(layers),藉由建立nn.Module的子類別(subclass),能定義自己的神經網路。
一個Pytorch模組即是繼承nn.Module基本類別的Pytorch類別(class),能以屬性的方式接受一個或多個參數張量Parameter物件,這些參數數值將會在模型訓練過程中進行優化。
一個模組還能以屬性方式加入一個或多個子模組(submodules,nn.Module的子類別),用以追蹤參數數值,範例如下圖:
import torch.nn as nn
import torch.nn.functional as F
class Model(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1, 20, 5) # 屬性
self.conv2 = nn.Conv2d(20, 20, 5) # 屬性
def forward(self, x):
x = F.relu(self.conv1(x))
return F.relu(self.conv2(x))
(1-1-1)CLASS torch.nn.Sequential(*args)
Def: A sequential container. Modules will be added to it in the order they are passed in the constructor. Alternatively, an ordered dict of modules can also be passed in.
Pytorch提供的一種簡單連接模組(modules)的類別,有兩種操作方法: 直接操作Sequential或是搭配字典(OrderedDict)建立。# 法一: Using Sequential to create a small model.
model = nn.Sequential(
nn.Conv2d(1,20,5),
nn.ReLU(),
nn.Conv2d(20,64,5),
nn.ReLU()
)
# 法二: Using Sequential with OrderedDict.
model = nn.Sequential(OrderedDict([
('conv1', nn.Conv2d(1,20,5)),
('relu1', nn.ReLU()),
('conv2', nn.Conv2d(20,64,5)),
('relu2', nn.ReLU())
]))
子模組必須為最高屬性(top-level attributes),若直接放在串列(list)或字典(dict)中做為屬性,優化器會無法找到子模組與它們的參數,能將無法優化和更新結果。若想將一系列模組包裹成串列或字典,則要使用Pytorch提供的nn.ModuleList或nn.ModuleDict。
(1-1-2)CLASS torch.nn.ModuleList(modules=None)
Def: Holds submodules in a list. ModuleList can be indexed like a regular Python list, but modules it contains are properly registered, and will be visible by all Module methods.
將一系列子模組(submodules)包裹在串列中。class MyModule(nn.Module):
def __init__(self):
super(MyModule, self).__init__()
self.linears = nn.ModuleList([nn.Linear(10, 10) for i in range(10)]) # an iterable of modules to add
def forward(self, x):
# ModuleList can act as an iterable, or be indexed using ints
for i, l in enumerate(self.linears):
x = self.linears[i // 2](x) + l(x)
return x
(1-1-3)CLASStorch.nn.ModuleDict(modules=None)
Def: Holds submodules in a list. ModuleDict can be indexed like a regular Python dictionary, but modules it contains are properly registered, and will be visible by all Module methods.
class MyModule(nn.Module):
def __init__(self):
super(MyModule, self).__init__()
self.choices = nn.ModuleDict({ # a mapping (dictionary) of (string: module) or an iterable of key-value pairs of type (string, module)
'conv': nn.Conv2d(10, 10, 3),
'pool': nn.MaxPool2d(3)
})
self.activations = nn.ModuleDict([
['lrelu', nn.LeakyReLU()],
['prelu', nn.PReLU()]
])
def forward(self, x, choice, act):
x = self.choices[choice](x)
x = self.activations[act](x)
return x
透過今日統整學習,更了解在Pytorch有哪些方式能建立神經網路架構。
明後天比較一些常見的影像分類模型,例如:ALXnet、ResNet等,學習原始論文的模型架構和相關Pytorch程式碼。
參考:
心得小語:
今天練完中提琴中指指腹敲鍵盤都會痛,但練許多天的小步舞曲(Minuet No.3)終於有點起色啦(開心灑花~~~ 因為鐵人賽讓生活好像過得異常規律,吃晚餐、練琴、散步、寫鐵人文章,這麼規律充實peace的生活步調,也是挺不錯的呢~~ 期待明天的學習分享囉,See you TMR!
今日工時: 50mins*5 (周末小小偷跑XD
任何值得做的事就值得把它做好
Whatever is worth doing is worth doing well.