一、案例背景
本案例通過PyTorch的nn.RNN
構建單隱藏層RNN模型,重點展示RNN對變長序列數據的處理能力(序列長度從1變為20),幫助理解RNN的輸入輸出邏輯。
二、核心代碼與結構拆解
def dm_rnn_for_sequencelen():# 1. 定義RNN模型rnn = nn.RNN(5, 6, 1) # input_size=5, hidden_size=6, num_layers=1# 2. 準備輸入數據input = torch.randn(20, 3, 5) # 序列長度=20,批次大小=3,輸入維度=5# 3. 初始化隱狀態h0 = torch.randn(1, 3, 6) # 層數×方向=1,批次大小=3,隱藏層維度=6# 4. 前向傳播output, hn = rnn(input, h0)# 輸出結果print('output形狀--->', output.shape) # torch.Size([20, 3, 6])print('hn形狀--->', hn.shape) # torch.Size([1, 3, 6])print('模型結構--->', rnn) # RNN(5, 6)
三、關鍵參數詳解
1. 模型定義參數(nn.RNN
)
參數 | 含義 | 本案例取值 | 說明 |
---|---|---|---|
input_size | 輸入特征維度 | 5 | 每個時間步的輸入向量維度(如單詞的 embedding 維度) |
hidden_size | 隱藏層輸出維度 | 6 | 每個時間步的隱狀態向量維度 |
num_layers | 隱藏層層數 | 1 | 單隱藏層結構,簡化計算 |
2. 輸入數據格式(input
)
- 形狀:
[sequence_length, batch_size, input_size]
- 本案例:
[20, 3, 5]
20
:序列長度(sequence_length),每個樣本包含20個時間步(如一句話有20個單詞);3
:批次大小(batch_size),一次并行處理3個樣本;5
:輸入特征維度,與模型定義的input_size
一致。
3. 初始隱狀態(h0
)
- 形狀:
[num_layers × num_directions, batch_size, hidden_size]
- 本案例:
[1, 3, 6]
1
:num_layers × num_directions
(1層+單向RNN);3
:與輸入的batch_size
一致,每個樣本對應一個初始隱狀態;6
:與模型定義的hidden_size
一致,初始隱狀態的維度。
四、輸出結果解析
1. output
(所有時間步的隱藏層輸出)
- 形狀:
[sequence_length, batch_size, hidden_size]
- 本案例:
[20, 3, 6]
- 包含每個時間步、每個樣本的隱藏層輸出(20個時間步×3個樣本×6維向量);
- 體現RNN對序列的“逐步處理”特性,保留所有中間結果。
2. hn
(最后一個時間步的隱狀態)
- 形狀:
[num_layers × num_directions, batch_size, hidden_size]
- 本案例:
[1, 3, 6]
- 僅包含最后一個時間步(第20步)、每個樣本的隱狀態;
- 因單隱藏層,
hn
與output
的最后一個時間步結果完全一致。
五、核心結論:RNN對變長序列的適應性
- 序列長度可靈活變化:只要輸入特征維度(
input_size
)和批次大小(batch_size
)不變,RNN可處理任意長度的序列(如示例1中長度=1,本案例中長度=20)。 - 輸出形狀隨序列長度調整:
output
的第一個維度始終等于輸入序列長度,體現RNN對時序數據的動態處理能力。
六、類比理解
將RNN比作“逐字閱讀的處理器”:
- 輸入:3篇文章(
batch_size=3
),每篇20個單詞(sequence_length=20
),每個單詞用5維向量表示(input_size=5
); - 處理過程:每讀一個單詞(時間步),結合上一步的記憶(隱狀態),更新當前記憶(6維向量,
hidden_size=6
); - 輸出:
output
是每讀一個單詞時的記憶記錄,hn
是讀完最后一個單詞的最終記憶。