PyTorch学习笔记(1)nn.Sequential、nn.Conv2d、nn.BatchNorm2d、nn.ReLU和nn.MaxPool2d
文章目錄
- 一、nn.Sequential
- 二、nn.Conv2d
- 三、nn.BatchNorm2d
- 四、nn.ReLU
- 五、nn.MaxPool2d
一、nn.Sequential
torch.nn.Sequential是一個Sequential容器,模塊將按照構造函數中傳遞的順序添加到模塊中。
使用方式:
官方給出案例(上面所提的方式1 和 方式2的列子):
# Sequential使用實例model = nn.Sequential(nn.Conv2d(1,20,5),nn.ReLU(),nn.Conv2d(20,64,5),nn.ReLU())# 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())]))以上兩種形式為一致。一種自動命名,一種指定名字。
驗證:
需要在pytorch環境下運行。
先添加:
打印模型輸出:
print(model) --------------------------------------------------------- Sequential((0): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))(1): ReLU()(2): Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))(3): ReLU() )使用torch.nn.Sequential可以快速的搭建一個神經網絡
為比較,先用普通方法搭建一個神經網絡來對比
class Net(torch.nn.Module):def __init__(self, n_feature, n_hidden, n_output):super(Net, self).__init__()self.hidden = torch.nn.Linear(n_feature, n_hidden)self.predict = torch.nn.Linear(n_hidden, n_output)def forward(self, x):x = F.relu(self.hidden(x))x = self.predict(x)return xnet1 = Net(1, 10, 1)上面class繼承了一個torch中的神經網絡結構, 然后對其進行了修改;
接下來我們來使用torch.nn.Sequential來快速搭建一個神經網絡。
打印輸出上面2個神經網絡數據,查看區別:
print(net1) --------------------------------------------------------- Net ((hidden): Linear (1 -> 10)(predict): Linear (10 -> 1) ) --------------------------------------------------------- print(net2) --------------------------------------------------------- Sequential ((0): Linear (1 -> 10)(1): ReLU ()(2): Linear (10 -> 1) ) ---------------------------------------------------------我們可以發現,使用torch.nn.Sequential會自動加入激勵函數, 但是 net1 中, 激勵函數實際上是在 forward() 功能中才被調用的.
torch.nn.Sequential與torch.nn.Module區別與選擇
- 使用torch.nn.Module,我們可以根據自己的需求改變傳播過程,如RNN等
- 如果你需要快速構建或者不需要過多的過程,直接使用torch.nn.Sequential即可。
- nn.Sequentialt使對于加入其中的子模塊在forward中可以通過循環實現調用
- Module 里面也可以使用 Sequential,同時 Module 非常靈活
二、nn.Conv2d
源自:https://pytorch.org/docs/1.2.0/nn.html#conv2d
nn.Conv2d是二維卷積方法,相對應的還有一維卷積方法nn.Conv1d,常用于文本數據的處理,而nn.Conv2d一般用于二維圖像。
接口定義:
參數解釋:
- in_channels(int):輸入圖像的channel(通道數),例如,RGB圖像通道數為3
- out_channels(int): 輸出圖像(特征層)的channel
- kernel_size(int or tuple):kernel(卷積核)的大小,kennel_size=5,意味著卷積大小(5,5)/5×5,kennel_size=(2,3),意味著卷積大小(2,3)/2×3 ,即非正方形卷積
- stride(int or tuple,optional): 卷積的步長,默認為1,stride=2,意味著步長上下左右掃描皆為2, stride=(2,3),左右掃描步長為2、上下為3
- padding(int or tuple,optional):四周pad的大小,默認為0,在卷積之前補0,四周都補0,
- dilation(int or tuple,optional): kernel元素間的距離,默認為1(dilation翻譯為擴張,有時候也稱為“空洞”1)
- groups(int ,optional):將原始輸入channel劃分成的組數,默認為1
- bias(bool,optional):如果是True,則輸出的bias可學,默認為True。卷積后是否加偏移量
- padding_mode:默認為“zeros”,填充0
channel:通道數。
一般的RGB圖片,channels 數量是 3 (紅、綠、藍);而單色/灰度圖片,channels 數量是 1。
channels 一般分為三種:
dilation:空洞卷積,控制 kernel 點之間的空間距離,實際在上采樣上有利用(在FCN、U-net等網絡結構中),看下圖有助于理解
groups:分組卷積
Convolution 層的參數中有一個group參數,其意思是將對應的輸入通道與輸出通道數進行分組, 默認值為1, 也就是說默認輸出輸入的所有通道各為一組。
比如:輸入數據大小為90x100x100x32,通道數32,要經過一個3x3x48的卷積,group默認是1,就是全連接的卷積層。
如果group是2,那么對應要將輸入的32個通道分成2個16的通道,將輸出的48個通道分成2個24的通道。對輸出的2個24的通道,第一個24通道與輸入的第一個16通道進行全卷積,第二個24通道與輸入的第二個16通道進行全卷積。
極端情況下,輸入輸出通道數相同,比如為24,group大小也為24,那么每個輸出卷積核,只與輸入的對應的通道進行卷積。
三、nn.BatchNorm2d
源自:https://pytorch.org/docs/1.2.0/nn.html#batchnorm2d
BatchNorm(批規范化)主要是為了加速神經網絡的收斂過程以及提高訓練過程中的穩定性。通常用于解決多層神經網絡中間層的協方差偏移(Internal Covariate Shift)問題,類似于網絡輸入進行零均值化和方差歸一化的操作,不過是在中間層的輸入中操作而已。使一批(Batch)feature map滿足均值為0,方差為1的分布規律。這樣不僅數據分布一致,而且避免發生梯度消失。
接口定義:
參數解釋:
- num_features: 一般輸入參數為batch_size num_features (height*width),即為其中特征的數量,為輸入BN層的通道數;
- eps: 分母中添加的一個值,目的是為了計算的穩定性,默認為:1e-05,避免分母為0;為公式中的ε\ ε\,?ε
- momentum:動態均值和動態方差所使用的動量。默認為0.1。一個用于運行過程中均值和方差的一個估計參數(我的理解是一個穩定系數,類似于SGD中的momentum的系數);
- affine: 當設為true時,會給定可以學習的系數矩陣γ\ γ\,?γ和β\ β\,?β。布爾值,當設為true,給該層添加可學習的仿射變換參數。
- track_running_stats:布爾值,當設為true,記錄訓練過程中的均值和方差;
公式:
y=γ×(x?E[x]Var[x]+ε)+β\ y=γ×({x-E[x] \over \sqrt{Var[x]+ε} \quad })+β\, ?y=γ×(Var[x]+ε?x?E[x]?)+β
(γ\ γ\,?γ 和β\ β\,?β在反向傳播過程中訓練得到,是對像素在BN的基礎上進行的調整,具體數值是模型學習出來的,初始化γ=1\ γ=1\,?γ=1用來調整方差, β=0\ β=0\,?β=0用來調整均值。
用于抵消部分標準化帶來的影響,因為有時候可能標準化了不好,這個時候這兩個變量就有足夠的彈性來學習修整這種標準化了。)
在訓練時,該層計算每次輸入的均值和方差,進行移動平均。移動平均momentum 默認的動量值為0.1
在驗證時,訓練求得的均值和方差將用于標準化驗證數據。
參數詳解:
在BN操作中,最重要的無非是這四個式子:
- 輸入:B=(x1,x2,...,xm)\ Β = (x_1,x_2,...,x_m )\,?B=(x1?,x2?,...,xm?),為m個樣本組成的一個batch數據
- 輸出:需要學習到的是γ\ γ\,?γ和β\ β\,?β,在框架中一般表述成weight和bias
更新過程:
注意到這里的最后一步也稱之為仿射(affine),引入這一步的目的主要是設計一個通道,使得輸出output至少能夠回到輸入input的狀態(當 γ=1\ γ=1\,?γ=1, β=0\ β=0\,?β=0時)使得BN的引入至少不至于降低模型的表現,這是深度網絡設計的一個套路。
一般來說pytorch中的模型都是繼承nn.Module類的,都有一個屬性trainning指定是否是訓練狀態,訓練狀態與否將會影響到某些層的參數是否是固定的,比如BN層或者Dropout層。通常用model.train()指定當前模型model為訓練狀態,model.eval()指定當前模型為測試/驗證狀態。
同時,BN的API中有幾個參數需要比較關心的,一個是affine指定是否需要仿射,還有個是track_running_stats指定是否跟蹤當前batch的統計特性。容易出現問題也正好是這三個參數:trainning,affine,track_running_stats。
- 其中的affine指定是否需要仿射,也就是是否需要上面算式的第四個,如果affine=False,則 γ=1\ γ=1\,?γ=1, β=0\ β=0\,?β=0,并且不能學習被更新。一般都會設置成affine=True
- trainning和track_running_stats,track_running_stats=True表示跟蹤整個訓練過程中的batch的統計特性,得到方差和均值,而不只是僅僅依賴與當前輸入的batch的統計特性。相反的,如果track_running_stats=False那么就只是計算當前輸入的batch的統計特性中的均值和方差了。當在推理階段的時候,如果track_running_stats=False,此時如果batch_size比較小,那么其統計特性就會和全局統計特性有著較大偏差,可能導致糟糕的效果。
神經網絡中有各種歸一化算法:Batch Normalization (BN)、Layer Normalization (LN)、Instance Normalization (IN)、Group Normalization (GN)。
從公式看它們都差不多:無非是減去均值,除以標準差,再施以線性映射。
y=γ(x?μ(x)σ(x))+β\ y=γ({x-μ(x) \overσ (x)})+β\, ?y=γ(σ(x)x?μ(x)?)+β這些歸一化算法的主要區別在于操作的 feature map 維度不同。
- BatchNorm(BN):batch方向做歸一化,算NHW的均值,對小batchsize效果不好;BN主要缺點是對batchsize的大小比較敏感,由于每次計算均值和方差是在一個batch上,所以如果batchsize太小,則計算的均值、方差不足以代表整個數據分布
- LayerNorm (LN):channel方向做歸一化,算CHW的均值,主要對RNN作用明顯;
- InstanceNorm(IN):一個channel內做歸一化,算H*W的均值,用在風格化遷移;因為在圖像風格化中,生成結果主要依賴于某個圖像實例,所以對整個batch歸一化不適合圖像風格化中,因而對HW做歸一化。可以加速模型收斂,并且保持每個圖像實例之間的獨立。
- GroupNorm(GN):將channel方向分group,然后每個group內做歸一化,算(C//G)HW的均值;這樣與batchsize無關,不受其約束。
- SwitchableNorm是將BN、LN、IN結合,賦予權重,讓網絡自己去學習歸一化層應該使用什么方法。
Batch Normalization (BN) 是最早出現的,也通常是效果最好的歸一化方式。feature map:x∈RN×C×H×W.\ x∈R^{N×C×H×W} \,.?x∈RN×C×H×W.包含 N 個樣本,每個樣本通道數為 C,高為 H,寬為 W。對其求均值和方差時,將在 N、H、W上操作,而保留通道 C 的維度。
具體來說,就是把第1個樣本的第1個通道,加上第2個樣本第1個通道 … 加上第 N 個樣本第1個通道,求平均,得到通道 1 的均值(注意是除以 N×H×W 而不是單純除以 N,最后得到的是一個代表這個 batch 第1個通道平均值的數字,而不是一個 H×W 的矩陣)。求通道 1 的方差也是同理。對所有通道都施加一遍這個操作,就得到了所有通道的均值和方差。具體公式為:
這里有個特別好的比喻,便于理解:
如果把x∈RN×C×H×W.\ x∈R^{N×C×H×W} \,.?x∈RN×C×H×W.類比為一摞書,這摞書總共有 N 本,每本有 C 頁,每頁有 H 行,每行 W 個字符。BN 求均值時,相當于把這些書按頁碼一一對應地加起來(例如第1本書第36頁,第2本書第36頁…),再除以每個頁碼下的字符總數:N×H×W.\ N×H×W \,.?N×H×W.,因此可以把 BN 看成求“平均書”的操作(注意這個“平均書”每頁只有一個字),求標準差時也是同理。
詳細區別和參數細節建議參考:知乎,CSDN。
四、nn.ReLU
源自:https://pytorch.org/docs/1.2.0/nn.html#relu
nn.ReLU() 是封裝好的類,繼承nn.Module
接口定義:
參數定義:
inplace: can optionally do the operation in=plase. Default: False
inplace:默認為false(選擇是否進行覆蓋運算,意思是:是否將得到的值計算得到的值覆蓋之前的值)
inplace=True,會改變輸入數據,inplace=False,不會改變輸入數據,只會產生新的輸出
注:產生的計算結果不會有影響。利用in-place計算可以節省內(顯)存,同時還可以省去反復申請和釋放內存的時間。但是會對原變量覆蓋,只要不帶來錯誤就用。
對于ReLU非線性激勵函數,其公式為:
ReLU(x)=max(0,x)\ ReLU(x)=max(0, x)\,?ReLU(x)=max(0,x)
nn.ReLU() 與 F.relu()的區別
nn.ReLU() :
F.relu():
import torch.nn.functional as F ''' out = F.relu(input)其實這兩種方法都是使用relu激活,只是使用的場景不一樣,F.relu()是函數調用,一般使用在foreward函數里。而nn.ReLU()是模塊調用,一般在定義網絡層的時候使用,作為一個層結構,必須添加到nn.Module容器中才能使用。
1.為什么引入非線性激勵函數?
如果不適用激勵函數,那么在這種情況下每一層的輸出都是上層輸入的線性函數,很容易驗證,無論你神經網絡有多少層,輸出都是輸入的線性組合,與沒有隱藏層效果相當,這種情況就是最原始的感知機(perceptron)了。正因為上面的原因,我們決定引入非線性函數作為激勵函數,這樣深層神經網絡就有意義了,不再是輸入的線性組合,可以逼近任意函數,最早的想法是用sigmoid函數或者tanh函數,輸出有界,很容易充當下一層的輸入
2.為什么引入Relu?
其實,relu函數的作用就是增加了神經網絡各層之間的非線性關系,否則,如果沒有激活函數,層與層之間是簡單的線性關系,每層都相當于矩陣相乘,這樣怎么能夠完成我們需要神經網絡完成的復雜任務,
五、nn.MaxPool2d
源自:https://pytorch.org/docs/1.2.0/nn.html#torch.nn.MaxPool2d
接口定義:
class torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)參數定義:
- kernel_size(int or tuple):取最大值(max pooling)的窗口大小,如果是一個值單int,高度和寬度都使用相同的值;如果是tuple兩個整數,第一個是height ,第二個是height 。(最大池化的方法就是取這個窗口覆蓋元素中的最大值。)
- stride(int or tuple, optional):窗口移動的步長。默認值為kernel_size(上一個參數我們確定了滑動窗口的大小,現在我們來確定這個窗口如何進行滑動。如果不指定這個參數,那么默認步長跟最大池化窗口大小一致。如果指定了參數,那么將按照我們指定的參數進行滑動。)
- padding (int or tuple, optional):輸入的每一條邊補充0的層數
- dilation (int or tuple, optional):控制窗口中元素步長的參數
- return_indices:如果為True,會返回輸出最大值的位置索引,對于上采樣(torch.nn.MaxUnpool2d)操作會有幫助。
- ceil_mode: 如果等于True,計算輸出信號大小的時候,會使用向上取整,代替默認的向下取整的操作。(關于 ceil_mode 的詳解:建議參考CSDN)
如果padding 不是0,會在輸入的每一邊添加相應數目0,如padding=1,則在每一邊分別補0,其實最后的結果補出來是bias
最大池化的方法示意圖:
總結
以上是生活随笔為你收集整理的PyTorch学习笔记(1)nn.Sequential、nn.Conv2d、nn.BatchNorm2d、nn.ReLU和nn.MaxPool2d的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: XTU OJ 1397 Patchoul
- 下一篇: 我们能做出量子计算机却至今摸不透量子力学