201204-通過一個A4紙張掃描的例子通俗理解PyTorch中LSTM的引數定義

GuokLiu發表於2020-12-05
  • 講解
import torch
from torch import nn
import torch.nn.functional as F

# 【第1步】 掃描器引數設定   
batch = 10          # 一次同時掃描的紙張數
batchFirst = True   # 將bacth設定成input的第一個維度,與CNN等傳統NN保持一致
a4_width = 21       # 掃描器每一個時間步step掃描到的特徵
a4_height = 29      # 掃描器掃描完總共需要的時間步steps,即 seq_len
hidden_size = 210   # 輸入特徵:A4紙(21cm * 29 steps);輸出特徵:Jpeg照片(210 dpi * 29 steps); 深度特徵提取的維度,任意數值
num_layers = 5     # 重複掃描的次數:將第一次掃描好的Jpeg檔案列印出來(1dpi=1cm),繼續掃描,重複之前的步驟 
bidirectL = False   # 是否同時雙面掃描;並將兩次掃描的結果在同一個Step上進行橫向堆疊
bidirectN  = 2 if bidirectL == True else 1 # 記錄掃描方式: 只是單面掃描:1; 同時雙面掃描:2

# 【第2步】 待掃描紙張引數設定
# 每次掃描10張紙:batch = 10:
# 從上到下,掃描完一張紙總的時間步:seq_len = 29
# 從左到右:每秒一次掃描的寬度:input_size = 21
input = torch.randn(batch, a4_height, a4_width) # (batch, seq_len, input_size)

# 【第3步】 掃描器結構效能設定,不需要考慮seq_len,針對同一個batch內不同seq_len要提前做好資料預處理
# input_size =21, hidden_size = 210, num_layers = 2, batch_first: 同CNN邏輯結構,bidirectional:同時掃描
rnn = nn.LSTM(a4_width, hidden_size, num_layers, batch_first = batchFirst, bidirectional=bidirectL)  

# 【第4步】 掃描器掃描偏好設定,如果不設定,預設初始狀態全部為零
h0 = torch.randn(num_layers*bidirectN, batch, hidden_size) # num_layers * num_directions, batch, hidden_siz
c0 = torch.randn(num_layers*bidirectN, batch, hidden_size) # num_layers * num_directions, batch, hidden_siz

# 【第5步】輸出掃描結果
# - 如果bacth在第二維度:(seq_len, batch, num_directions * hidden_size)
# - 如果batch在第一維度:(batch, seq_len, num_directions * hidden_size)
output, (hn, cn) = rnn(input, (h0, c0)) 
print('output: {}; \nhn: {}; \ncn: {}.'.format(output.shape,hn.shape, cn.shape))

# output: torch.Size([10, 29, 210]); 
# hn: torch.Size([5, 10, 210]); 
# cn: torch.Size([5, 10, 210]).

# [第6步] 編輯並選擇Jpeg影像的全部或區域性
# - 如果需要全部掃描好的影像,則選擇output[:, :,:], 隨後reshape堆疊
# - 如果只需要掃面影像最下面,則選擇output[:,-1,:], 通過index索引
edit = 'last' # or all
select =  output[:,-1,:] if edit == 'last' else output[:,:,:]
print('Select: {}'.format(select.shape))

# [第7步] 對映‘編輯選擇好的Jpeg’作為邏輯值,輸出歸一化後的效能指標
map = nn.Linear(210,10)
logits  = map(select)
final = F.log_softmax(logits, dim=1)
print('Final: {}'.format(final.shape))

針對同一個batch內不同seq_len要提前做好資料預處理

  • 輸出

output: torch.Size([10, 29, 210]);
hn: torch.Size([5, 10, 210]);
cn: torch.Size([5, 10, 210]).
Select: torch.Size([10, 210])
Final: torch.Size([10, 10])

  • 理解雙向堆疊
    在這裡插入圖片描述

  • 理解如何利用所有時間步的全部隱藏特徵
    在這裡插入圖片描述

  • 理解如何利用最後時間步的高層隱藏特徵
    在這裡插入圖片描述
    在這裡插入圖片描述

  • 如何理解dropout
    在這裡插入圖片描述

  • 如何理解序列對齊
    在這裡插入圖片描述
    在這裡插入圖片描述

  • LSTM的多種應用模式
    在這裡插入圖片描述

  • Demo下面程式碼供參考,引數可調整

class LSTM(nn.Module):
    def __init__(self):
        super(LSTM,self).__init__()
        self.LSTM1 = nn.LSTM(21,210,batch_first=True,dropout=0.15,num_layers=2)
        self.LSTM2 = nn.LSTM(210,64,batch_first=True,dropout=0.15,num_layers=2)
        self.LSTM3 = nn.LSTM(64,32,batch_first=True)
        self.Logits = nn.Linear(32,10)
        
    def forward(self,x):
        x = x.view(-1,29,21) # input of shape (batch, seq_len, input_size):
        out,(h_n,c_n) = self.LSTM1(x)
        out,(h_n,c_n) = self.LSTM2(out)
        out,(h_n,c_n) = self.LSTM3(out)
        logits = self.Logits(out[:,-1,:]) # Only select the final feature
        output = F.log_softmax(logits, dim=1)
        return output

相關文章