【pytorch】torch.nn 模塊筆記


簡介

pytorch中其實一般沒有特別明顯的Layer和Module的區別,不管是自定義層、自定義塊、自定義模型,都是通過繼承Module類完成的。其實Sequential類也是繼承自Module類的。

torcn.nn是專門為神經網絡設計的模塊化接口。構建於autograd之上,可以用來定義和運行神經網絡。
torch.nn.Module 是所有神經網絡單元的基類,包含網絡各層的定義及forward方法。
pytorch里面一切自定義操作基本上都是繼承nn.Module類來實現的。
源碼手冊:TORCH.NN

下文中為了簡潔:> import torch.nn as nn
nn.Module - Neural network module. Convenient way of encapsulating parameters, with helpers for moving them to GPU, exporting, loading, etc.
部分內容有參考CSDN博主「LoveMIss-Y」的原創文章CSDN博主「Vic_Hao」的原創文章
在pytorch里面自定義層也是通過繼承自nn.Module類來實現的。pytorch里面一般是沒有層的概念,層也是當成一個模型來處理的,這里和keras是不一樣的。keras更加注重的是層Layer、pytorch更加注重的是模型Module。
Pytorch基於nn.Module構建的模型中,只支持mini-batch的Variable輸入方式。比如,只有一張輸入圖片,也需要變成N*C*H*W的形式。

torch.nn only supports mini-batches. The entire torch.nn package only supports inputs that are a mini-batch of samples, and not a single sample.

For example, nn.Conv2d will take in a 4D Tensor of nSamples * nChannels * Height * Width.
If you have a single sample, just use input.unsqueeze(0) to add a fake batch dimension.

自定義模型

pytorch框架中自定義一個模型:通過繼承nn.Module類來實現,在__init__構造函數中申明各個層的定義,在forward中實現層之間的連接關系,實際上就是前向傳播的過程。

如何定義自己的網絡:

  1. 需要繼承nn.Module類,並實現forward方法。繼承nn.Module類之后,在構造函數中要調用Module的構造函數, super(Linear, self).init()。
  2. 一般把網絡中具有可學習參數的層放在構造函數__init__()中。
  3. 不具有可學習參數的層(如ReLU)可放在構造函數中,也可不放在構造函數中(而在forward中使用nn.functional來代替)。可學習參數放在構造函數中,並且通過nn.Parameter()使參數以parameters(一種tensor,默認是自動求導)的形式存在Module中,並且通過parameters()或者named_parameters()以迭代器的方式返回可學習參數。
  4. 只要在nn.Module中定義了forward函數,backward函數就會被自動實現(利用Autograd)。而且一般不是顯式的調用forward(layer.forward), 而是layer(input), 會自執行forward()。
  5. 在forward中可以使用任何Variable支持的函數,畢竟在整個pytorch構建的圖中,是Varible在流動。還可以使用if, for, print, log等python語法。

所有放在構造函數__init__里面的層的都是這個模型的“固有屬性”。
forward方法是必須要重寫的,它是實現模型的功能,實現各個層之間的連接關系的核心。

神經網絡基本單元

可參考CSDN博主「LoveMIss-Y」的原創文章
rnn的源碼(RNNBase)github-pytorch

nn.Conv1d && nn.Conv1d

具體計算方式參考:

博客PyTorch中的nn.Conv1d與nn.Conv2d.
博客pytorch之nn.Conv1d詳解.

一般來說,一維卷積nn.Conv1d用於文本數據,只對寬度進行卷積,對高度不卷積。通常,輸入大小為word_embedding_dim * max_length,其中,word_embedding_dim為詞向量的維度,max_length為句子的最大長度。卷積核窗口在句子長度的方向上滑動,進行卷積操作。
二維卷積nn.Conv2d用於圖像數據,對寬度和高度都進行卷積。

nn.Sequential

可以快速搭組件的一個類,細節參見pytorch源碼
示例見pytorch教程
一個有序的Sequential容器,神經網絡模塊將按照在傳入構造器的順序依次被添加到計算圖中執行,同時以神經網絡模塊為元素的有序字典也可以作為傳入參數。

nn.Sequential是包含其他模塊的模塊,並按順序應用這些模塊來產生其輸出。
每個線性模塊使用線性函數從輸入計算輸出,並保存其內部的權重和偏差張量。
在構造模型之后,我們使用.to()方法將其移動到所需的設備。

nn.Linear

線性變換層,參考源碼

class torch.nn.Linear(in_features, out_features, bias=True)

Applies a linear transformation to the incoming data: $ y = x \cdot {A^T} + b $

in_features - 每個輸入樣本的大小
out_features - 每個輸出樣本的大小
bias - 如果設置為False,則圖層不會學習附加偏差。默認值:True

nn.LSTM

Long Short Term Memory,稱為長短期記憶網絡,意思就是長的短時記憶,其解決的仍然是短時記憶問題,這種短時記憶比較長,能一定程度上解決長時依賴。
LSTM由3個門來控制,分別是輸入門、遺忘門和輸出門。輸入門控制網絡的輸入,遺忘門控制着記憶單元,輸出門控制着網絡的輸出。最為重要的就是遺忘門,可以決定哪些記憶被保留,由於遺忘門的作用,使得LSTM具有長時記憶的功能。對於給定的任務,遺忘門能夠自主學習保留多少之前的記憶,網絡能夠自主學習。

class torch.nn.LSTM(*args, **kwargs)

參數列表:
   -- input_size: x 的特征維度
   -- hidden_size: 隱層的特征維度
   -- num_layers: LSTM 層數,默認為1
   -- bias: 是否采用 bias, 如果為False,則不采用。默認為True
   -- batch_first: True, 則輸入輸出的數據格式為 [batch_size, seq_len, feature_dim],默認為False
   -- dropout: dropout會在除最后一層外都進行dropout, 默認為0
   -- bidirectional: 是否采用雙向,默認為False
輸入數據:
   -- input: [seq_len, batch_size, input_size], 輸入的特征矩陣
   -- h_0: [num_layers * num_directions, batch_size, hidden_size], 初始時 h 狀態, 默認為0
   -- c_0: [num_layers * num_directions, batch_size, hidden_size], 初始時 cell 狀態, 默認為0
輸出數據:
   -- output: [seq_len, batch_size, num_directions * hidden_size], 最后一層的所有隱層輸出
   -- h_n : [num_layers * num_directions, batch, hidden_size], 所有層的最后一個時刻隱層狀態
   -- c_n : [num_layers * num_directions, batch, hidden_size], 所有層的最后一格時刻的 cell 狀態
W,b參數:
  -- weight_ih_l[k]: 與輸入x相關的第k層權重 W 參數, W_ii, W_if, W_ig, W_io
  -- weight_hh_l[k]: 與上一時刻 h 相關的第k層權重參數, W_hi, W_hf, W_hg, W_ho
  -- bias_ih_l[k]: 與輸入x相關的第k層 b 參數, b_ii, b_if, b_ig, b_io
  -- bias_hh_l[k]: 與上一時刻 h 相關的第k層 b 參數, b_hi, b_hf, b_hg, b_ho

需要注意的一點是, LSTM/GRU 中所有的W,b 參數默認采用均勻分布。
可參考個人博客LSTM:Pytorch實現 和 個人博客【pytorch】pytorch-LSTM
torch.nn包下實現了LSTM函數,實現LSTM層。多個LSTMcell組合起來是LSTM。
LSTM自動實現了前向傳播,不需要自己對序列進行迭代。創建需要指定如下參數,並至少指定前三個參數。

input_size:輸入特征維數
hidden_size:隱層狀態的維數
num_layers:RNN層的個數,在圖中豎向的是層數,橫向的是seq_len
bias:隱層狀態是否帶bias,默認為true
batch_first:是否輸入輸出的第一維為batch_size,因為pytorch中batch_size維度默認是第二維度,故此選項可以將batch_size放在第一維度。如input是(4,1,5),中間的1是batch_size,指定batch_first=True后就是(1,4,5)
dropout:是否在除最后一個RNN層外的RNN層后面加dropout層
bidirectional:是否是雙向RNN,默認為false,若為true,則num_directions=2,否則為1

lstm = torch.nn.LSTM(input_size,hidden_size,num_layers,batch_first=True)   # 創建LSTM
out,hidden = lstm(input,hidden)      # forward使用LSTM層,其中,hidden=(h0,c0)是個tuple, 最終得到out,hidden

nn.GRU

GRU是Gated Recurrent Unit的縮寫,與LSTM最大的不同之處在於GRU將遺忘門和輸入門合成一個“更新門”,同時網絡不再額外給出記憶狀態Ct​,而是將輸出結果ht​作為記憶狀態不斷向后傳遞,網絡的輸入和輸出都簡化。
隱藏狀態參數不再是標准RNN的4倍,而是3倍,也就是GRU的參數要比LSTM的參數量要少,但是性能差不多。
具體原理可參考博客/Gated Recurrent Unit(GRU)
LSTM存在一個問題,就是計算開銷比較大,因為其內部結構相對復雜。GRU 也是為了旨在解決標准 RNN 中出現的梯度消失問題,可以看做是LSTM的一種變種。其實在大多數情況下GRU的性能和LSTM幾乎相差無幾(甚至有時候LSTM效果更好,且LSTM是1997年提出的,經受了更多的歷史考驗),但GRU最大的優勢就是 簡單(因為只有兩個門),計算開銷小,更加適用於大規模數據集。

class torch.nn.RNN(args, kwargs)*  

nn.Parameter

參考PyTorch里面的torch.nn.Parameter():
【對於self.v = torch.nn.Parameter(torch.FloatTensor(hidden_size)), 可以把這個函數理解為類型轉換函數,將一個不可訓練的類型Tensor轉換成可以訓練的類型parameter並將這個parameter綁定到這個module里面(net.parameter()中就有這個綁定的parameter,所以在參數優化的時候可以進行優化的),所以經過類型轉換這個self.v變成了模型的一部分,成為了模型中根據訓練可以改動的參數了。使用這個函數的目的也是想讓某些變量在學習的過程中不斷的修改其值以達到最優化。】

是Tensor的子類,當與modules一起使用時,會有一個非常特殊的屬性:當它們被指定為模塊屬性時,它們被自動添加到它的參數列表中,並且會出現在Parameters()迭代器中。

nn.Parameter - A kind of Tensor, that is automatically registered as a parameter when assigned as an attribute to a Module.

Assigning a Tensor doesn't have such effect. This is because one might want to cache some temporary state, like last hidden state of the RNN, in the model. If there was no such class as :class:Parameter, these temporaries would get registered too.
很多代碼采用self.v = torch.nn.Parameter(torch.FloatTensor(hidden_size)),首先可以把這個函數理解為類型轉換函數,將一個不可訓練的類型Tensor轉換成可以訓練的類型parameter並將這個parameter綁定到這個module里面。
所以經過類型轉換這個self.v變成了模型的一部分,成為了模型中根據訓練可以改動的參數了。
net.parameter()中就有這個綁定的parameter,所以在參數優化的時候可以進行優化的,使用這個函數的目的也是想讓某些變量在學習的過程中不斷的修改其值以達到最優化。
源碼參考

class Parameter(torch.Tensor)

loss-functions

參考:

源碼:SOURCE CODE FOR TORCH.NN.MODULES.LOSS
總結:pytorch loss function 總結

【nn.BCELoss】二分類用的交叉熵,用的時候需要在該層前面加上 Sigmoid 函數。
【nn.CrossEntropyLoss】多分類用的交叉熵損失函數,用這個 loss 前面不需要加 Softmax 層。
【nn.NLLLoss】用於多分類的負對數似然損失函數(Negative Log Likelihood)。在前面接上一個 nn.LogSoftMax 層就等價於交叉熵損失了。事實上,nn.CrossEntropyLoss 也是調用這個函數。
【nn.CosineEmbeddingLoss】余弦相似度的損失,目的是讓兩個向量盡量相近。注意這兩個向量都是有梯度的。

nn.utils

工具箱????

pytorch對變長序列處理

參考個人博客/pytorch對可變長度序列的處理,主要是用函數torch.nn.utils.rnn.PackedSequence()和torch.nn.utils.rnn.pack_padded_sequence()以及torch.nn.utils.rnn.pad_packed_sequence()來進行的。

torch.nn.utils.rnn.PackedSequence() 【這個類的實例不能手動創建,只能被 pack_padded_sequence() 實例化。】
PackedSequence對象包括:

一個data對象:一個torch.Variable(令牌的總數,每個令牌的維度)
一個batch_sizes對象:每個時間步長的令牌數列表

PackedSequence對象有一個很不錯的特性,就是無需對序列解包(這一步操作非常慢)即可直接在PackedSequence數據變量上執行許多操作。特別是可以對令牌執行任何操作(即對令牌的順序/上下文不敏感)。當然,也可以使用接受PackedSequence作為輸入的任何一個pyTorch模塊(pyTorch 0.2)。

torch.nn.utils.rnn.pack_padded_sequence() 【將一個填充過的變長序列壓緊(填充時會有冗余,所以壓緊一下)】
輸入的形狀可以是(T×B×* )。T是最長序列長度,B是batch size,*代表任意維度(可以是0)。如果batch_first=True的話,那么相應的 input size 就是 (B×T×*)。
Variable中保存的序列,應該按序列長度的長短排序,長的在前,短的在后。即input[:,0]代表的是最長的序列,input[:, B-1]保存的是最短的序列。

參數說明:
input (Variable) – 變長序列 被填充后的 batch
lengths (list[int]) – Variable 中 每個序列的長度。
batch_first (bool, optional) – 如果是True,則input的形狀應該是B×T×*。
返回值: 一個PackedSequence 對象。

只要是維度大於等於2的input都可以作為上述函數的參數。可以用它來打包labels,然后用RNN的輸出和打包后的labels來計算loss。通過PackedSequence對象的.data屬性可以獲取 Variable。

torch.nn.utils.rnn.pad_packed_sequence() 【填充packed_sequence】
這個操作和pack_padded_sequence()是相反的。把壓緊的序列再填充回來。
返回的Varaible的值的size是 T×B×*, T 是最長序列的長度,B 是 batch_size,如果 batch_first=True,那么返回值是B×T×*。
Batch中的元素將會以它們長度的逆序排列。

參數說明:
sequence (PackedSequence) – 將要被填充的batch
batch_first (bool, optional) – 如果為True,返回的數據的格式為 B×T×*。
返回值: 一個tuple,包含被填充后的序列,和batch中序列的長度列表。

參考

1、torch.nn - PyTorch中文文檔


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM