對于RNN的理解
import torch
import torch.nn as nn
import torch.nn.functional as F# 手動實現一個簡單的RNN
class RNN(nn.Module):def __init__(self, input_size, hidden_size, output_size):super(RNN, self).__init__()# 定義權重矩陣和偏置項self.hidden_size = hidden_sizeself.W_xh = nn.Parameter(torch.randn(input_size, hidden_size)) # 輸入到隱藏層的權重#
#注:
input_size = 4
hidden_size = 3
W_xh = torch.randn(input_size, hidden_size)
生成的 W_xh 會是一個形狀為 (4, 3) 的張量,可能是這樣的(數字是隨機生成的):
tensor([[ 0.2973, -1.1254, 0.7172],
[ 0.0983, 0.2856, -0.4586],
[-0.0105, 0.2317, 0.2716],
[ 1.0431, -1.3894, -0.1525]])
這個張量有 4 行 3 列。
self.W_hh = nn.Parameter(torch.randn(hidden_size, hidden_size)) # 隱藏層到隱藏層的權重self.b_h = nn.Parameter(torch.zeros(hidden_size)) # 隱藏層偏置self.W_hy = nn.Parameter(torch.randn(hidden_size, output_size)) # 隱藏層到輸出層的權重self.b_y = nn.Parameter(torch.zeros(output_size)) # 輸出層偏置def forward(self, x):# 初始化隱藏狀態為0h_t = torch.zeros(x.size(0), self.hidden_size) # 初始隱藏狀態 [[5]]
注:
x 是輸入數據,形狀是 (3, 5, 4),其中:
3 是批量大小(batch_size),即我們一次性輸入網絡的樣本數是 3。
5 是序列長度(seq_len),每個樣本有 5 個時間步。
4 是每個時間步的輸入特征數量。
self.hidden_size 假設是 6,表示隱藏層的維度是 6。
x.size(0) 獲取輸入張量 x 的第一個維度的大小,也就是批量大小 3。
torch.zeros(3, 6) 會創建一個形狀為 (3, 6) 的張量,表示有 3 個樣本,每個樣本有 6 個隱藏狀態神經元(即隱狀態的維度是 6)。所有的元素都初始化為 0。
# 遍歷時間步,逐個處理輸入序列for t in range(x.size(1)): # x.size(1) 是序列長度x_t = x[:, t, :] # 獲取當前時間步的輸入 (batch_size, input_size)
`
注:x = torch.tensor([[[0.1, 0.2, 0.3, 0.4], # 第 0 時間步的輸入 (第一個樣本)
[0.5, 0.6, 0.7, 0.8], # 第 1 時間步的輸入 (第一個樣本)
[0.9, 1.0, 1.1, 1.2]], # 第 2 時間步的輸入 (第一個樣本)
[[1.3, 1.4, 1.5, 1.6], # 第 0 時間步的輸入 (第二個樣本)
[1.7, 1.8, 1.9, 2.0], # 第 1 時間步的輸入 (第二個樣本)
[2.1, 2.2, 2.3, 2.4]]]) # 第 2 時間步的輸入 (第二個樣本)
第一次循環 t=0:
x_t = x[:, 0, :]
x[:, 0, :] 會提取出所有樣本在第 0 時間步的輸入:
第一個樣本在第 0 時間步的輸入是 [0.1, 0.2, 0.3, 0.4]。
第二個樣本在第 0 時間步的輸入是 [1.3, 1.4, 1.5, 1.6]。
因此,x_t 的值是:
tensor([[0.1, 0.2, 0.3, 0.4],
[1.3, 1.4, 1.5, 1.6]])
# 更新隱藏狀態:h_t = tanh(W_xh * x_t + W_hh * h_t + b_h)h_t = torch.tanh(x_t @ self.W_xh + h_t @ self.W_hh + self.b_h) # [[4]]
`
注:1. 計算 x_t @ W_xh
x_t @ W_xh 是輸入 x_t 和權重矩陣 W_xh 的矩陣乘法。我們有 2 個樣本,每個樣本有 3 個輸入特征,權重矩陣 W_xh 的形狀是 (3, 4),所以乘法的結果是一個形狀為 (2, 4) 的張量,即每個樣本的隱藏狀態更新的部分。
對于第一個樣本:
[0.5, 0.6, 0.7] @ [[0.1, 0.2, -0.1, 0.4],
[0.3, 0.5, 0.2, -0.2],
[0.7, -0.1, 0.3, 0.5]]
我們可以計算它的結果:
= [0.5 * 0.1 + 0.6 * 0.3 + 0.7 * 0.7,
0.5 * 0.2 + 0.6 * 0.5 + 0.7 * (-0.1),
0.5 * -0.1 + 0.6 * 0.2 + 0.7 * 0.3,
0.5 * 0.4 + 0.6 * (-0.2) + 0.7 * 0.5]
= [0.05 + 0.18 + 0.49,
0.1 + 0.3 - 0.07,
-0.05 + 0.12 + 0.21,
0.2 - 0.12 + 0.35]
= [0.72, 0.33, 0.28, 0.43]
對于第二個樣本:
[1.0, 1.2, 1.3] @ [[0.1, 0.2, -0.1, 0.4],
[0.3, 0.5, 0.2, -0.2],
[0.7, -0.1, 0.3, 0.5]]
計算結果:
= [1.0 * 0.1 + 1.2 * 0.3 + 1.3 * 0.7,
1.0 * 0.2 + 1.2 * 0.5 + 1.3 * (-0.1),
1.0 * -0.1 + 1.2 * 0.2 + 1.3 * 0.3,
1.0 * 0.4 + 1.2 * (-0.2) + 1.3 * 0.5]
= [0.1 + 0.36 + 0.91,
0.2 + 0.6 - 0.13,
-0.1 + 0.24 + 0.39,
0.4 - 0.24 + 0.65]
= [1.37, 0.67, 0.53, 0.81]
因此,x_t @ W_xh 的結果是:
tensor([[0.72, 0.33, 0.28, 0.43],
[1.37, 0.67, 0.53, 0.81]])
x_t @ self.W_xh:
x_t 是當前時間步的輸入,形狀是 (batch_size, input_size)。
self.W_xh 是輸入到隱藏層的權重矩陣,形狀是 (input_size, hidden_size)。
h_t @ self.W_hh:
h_t 是前一時間步的隱藏狀態,形狀是 (batch_size, hidden_size)。
self.W_hh 是隱藏層到隱藏層的權重矩陣,形狀是 (hidden_size, hidden_size)。
# 最后一個時間步的隱藏狀態通過全連接層得到輸出y_t = h_t @ self.W_hy + self.b_y # 輸出層return y_t
超參數設置
input_size = 10 # 輸入特征維度
hidden_size = 20 # 隱藏層維度
output_size = 5 # 輸出類別數
seq_length = 5 # 序列長度
batch_size = 3 # 批量大小
實例化模型
model = RNN(input_size, hidden_size, output_size)
打印模型結構
print(model)
創建隨機輸入數據 (batch_size, seq_length, input_size)
x = torch.randn(batch_size, seq_length, input_size)
前向傳播
output = model(x)
print(“Output shape:”, output.shape) # 輸出形狀應為 (batch_size, output_size)