上一篇 | 下一篇 |
---|---|
RNN(中集) | 待編寫 |
代碼詳解
pytorch 官網主要有兩個可調用的模塊,分別是 nn.RNNCell
和 nn.RNN
,下面會進行詳細講解。
RNN 的同步多對多、多對一、一對多等等結構都是由這兩個模塊實現的,只需要將對輸入和輸出進行調整就行。
以 nn.RNN
為例,它有兩個輸出,一個是 output
,一個是 hidden
,使用前者就是同步多對多結構,使用后者就是多對一結構(這種情形下 hidden
其實就是 output
的最后一個元素)(先說,后面慢慢看)。
1)pytorch版模塊調用
①nn.RNNCell(單步RNN)
官網鏈接:RNNCell — PyTorch 2.6 documentation
使用此函數,需要再手動實現時間循環
-
對應公式:
h ′ = t a n h ( W i h ? x + b i h + W h h ? h + b h h ) h^{'} = tanh(W_{ih}·x+b_{ih}+W_{hh}·h+b_{hh}) h′=tanh(Wih??x+bih?+Whh??h+bhh?)
這里和之前提到的 s t = g 1 ( U ? x t + W ? s t ? 1 + b s ) s_t=g1(U·x_t+W·s_{t-1}+b_s) st?=g1(U?xt?+W?st?1?+bs?) 是一個意思, s s s 就是 h h h ,只不過更細化了,稍微轉換一下即可。 -
公式圖解:
-
模塊解析:
class torch.nn.RNNCell(input_size, hidden_size, bias=True, nonlinearity='tanh', device=None, dtype=None) # 實例化為:rnncell = torch.nn.RNNCell(10,20)
- 類的參數解釋:
input_size
(int):輸入 x x x 的特征數------------------------------------------ 其實就是 x x x 的維度,即向量 x x x 中的元素個數。hidden_size
(int):隱藏狀態 h h h 的特征數---------------------------------- 其實就是 h h h 的維度,即向量 h h h 中的元素個數。bias
(bool):偏置設置項,默認為True
---------------------------------- 如果為 F a l s e False False 則不使用偏置 b i h 、 b h h b_{ih}、b_{hh} bih?、bhh? 。nonlinearity
(str):激活函數設置項,默認為'tanh'
-------------- 可設置為nonlinearity='relu'
。
- 輸入,的類型及形狀:
input
:類型:tensor,形狀: ( N , H i n ) (N,H_{in}) (N,Hin?) 或 ( H i n ) (H_{in}) (Hin?) -------------------- 其中 N N N 就是batch_size
(批量), H i n H_{in} Hin? =input_size
。hidden
:類型:tensor,形狀: ( N , H o u t ) (N,H_{out}) (N,Hout?) 或 ( H o u t ) (H_{out}) (Hout?) ---------------- 其中 H o u t H_{out} Hout? =hidden_size
,如果不提供就默認為0
張量。
- 輸出,的類型及形狀:
hidden
:類型:tensor,形狀: ( N , H o u t ) (N,H_{out}) (N,Hout?) 或 ( H o u t ) (H_{out}) (Hout?) ---------------- 其中 H o u t H_{out} Hout? =hidden_size
,此輸出代表了下一時刻的隱藏層狀態。
- 其中的權重 W 、 b W、b W、b 都是自動初始化、可自學習的。
- 類的參數解釋:
-
調用展示:
import torchcell = torch.nn.RNNCell(input_size=input_size, hidden_size=hidden_size) hidden = Cell(input, hidden) # hidden = Cell(input, hidden) 其實就是在調用 cell 中的 forword 函數,因為 cell 本身是個 class 類嘛
-
完整樣例展示(構造數據集時會引入
seqlen
):有關
seqlen
的講解請看下面點②,其含義就是時間步。seqlen
是在使用 RNN 之前,構造數據集時需要設置的參數,nn.RNNCell
沒有調用此參數,但是在寫代碼時需要設置(其實可以不設置,因為畢竟也用不到這個參數,只是說后面的nn.RNN
里用到了這個參數,索性就一起用了),模型會自動獲取batch_size
和input_size
。事實上,下方代碼中的循環次數就是
seqlen
。import torchbatch_size = 2 seq_len = 3 input_size = 4 hidden_size = 2cell = torch.nn.RNNCell(input_size=input_size, hidden_size=hidden_size) # 實例化dataset = torch.randn(seq_len, batch_size, input_size) # 構造固定格式的數據集, (seq, batch, features) hidden = torch.zeros(batch_size, hidden_size) # 初始化隱層狀態輸入for idx, input in enumerate(dataset):print('=' * 20, idx, '=' * 20)print('input size:', input.shape)hidden = cell(input, hidden)print('outputs size:', hidden.shape)print(hidden)----------------------------------------------------------------------------------------------------------------------- # 輸出結果為: ==================== 0 ==================== input size: torch.Size([2, 4]) outputs size: torch.Size([2, 2]) tensor([[-0.9041, -0.9441],[ 0.7673, -0.7628]], grad_fn=<TanhBackward0>) ==================== 1 ==================== input size: torch.Size([2, 4]) outputs size: torch.Size([2, 2]) tensor([[ 0.5290, -0.6024],[ 0.1011, -0.9541]], grad_fn=<TanhBackward0>) ==================== 2 ==================== input size: torch.Size([2, 4]) outputs size: torch.Size([2, 2]) tensor([[ 0.5451, 0.4806],[-0.9263, 0.2988]], grad_fn=<TanhBackward0>)
對于輸出結果的解析:
因為隨機構造的數據集正好是只有 2 個樣本,且
batch_size = 2, seq_len=3
,所以循環執行了 3 次。
②構造數據集的規范
如果對上面的
nn.RNNCell
樣例中參數尺寸不理解的,可以看這一節
1:
2:
記住: 循環次數 ≠ ≠ = batch_size * seq_len
。而且使用 nn.RNNCell
時編寫的循環次數不是之前 CNN
一樣的 epoch ,使用 nn.RNN
時才是。
對于語言建模而言: batchsize 相當于幾句話, seqlen 相當于每句話里有幾個字, inputsize 就是每個字的向量形式維度(one-hot編碼)。
③nn.RNN(重點)
官網鏈接:RNN — PyTorch 2.6 documentation
使用此函數,無需手動實現時間循環
可以理解為由多個 nn.RNNCell
組成的集成網絡。
-
每一層的公式:
h t = t a n h ( W i h T ? x + b i h + W h h T ? h t ? 1 + b h h ) h_t = tanh(W_{ih}^{T}·x+b_{ih}+W_{hh}^{T}·h_{t-1}+b_{hh}) ht?=tanh(WihT??x+bih?+WhhT??ht?1?+bhh?)
這里也和之前提到的 s t = g 1 ( U ? x t + W ? s t ? 1 + b s ) s_t=g1(U·x_t+W·s_{t-1}+b_s) st?=g1(U?xt?+W?st?1?+bs?) 是一個意思, s s s 就是 h h h ,只不過更細化了,稍微轉換一下即可。公式里的轉置不用在意,權重都是內部自動初始化、更新的。公示圖解和
nn.RNNCCell
的差不多,就是多個轉置。 -
模塊解析:
class torch.nn.RNN(input_size, hidden_size, num_layers=1, nonlinearity='tanh', bias=True, batch_first=False, dropout=0.0, bidirectional=False, device=None, dtype=None)
-
類的參數解釋:
-
input_size
(int):輸入 x x x 的特征數------------------------------------------ 其實就是 x x x 的維度,即向量 x x x 中的元素個數。 -
hidden_size
(int):隱藏狀態 h h h 的特征數---------------------------------- 其實就是 h h h 的維度,即向量 h h h 中的元素個數。 -
num_layers
(int):循環層數,默認為1
----------------------------------- 意味著將num_layers
個RNN
堆疊在一起,后一個RNN
接收第一個RNN
的隱? 層狀態輸出作為輸入,并且計算最終結果。
-
nonlinearity
(str):激活函數設置項,默認為'tanh'
-------------- 可設置為nonlinearity='relu'
。 -
bias
(bool):偏置設置項,默認為True
---------------------------------- 如果為False
則不使用偏置 b i h 、 b h h b_{ih}、b_{hh} bih?、bhh? 。 -
batch_first
(bool):輸入輸出格式設置項,默認為False
-------- 如果為True
則用戶需要按照(batch_size, seq_len, input_size)
來? 構造數據格式,默認是
(seq_len, batch_size, input_size)
。 -
dropout
:一般不用考慮。 -
bidirectional
(bool):雙向RNN
設置項,默認為False
--------- 如果為True
,則變成雙向RNN
。
-
-
輸入,的類型及形狀( D D D 一般都為 1 1 1 ):
-
input
:類型:tensor,形狀: ( L , N , H i n ) (L,N,H_{in}) (L,N,Hin?) 或 ( L , H i n ) (L,H_{in}) (L,Hin?) ----------- 其中 L L L 即seq_len
, N N N 即batch_size
(批量), H i n H_{in} Hin? =input_size
。? 當
batch_first=True
時為 ( N , L , H i n ) (N,L,H_{in}) (N,L,Hin?) 。 -
hidden
:類型:tensor,形狀: ( D ? n u m _ l a y e r s , N , H o u t ) (D*num\_layers,N,H_{out}) (D?num_layers,N,Hout?) 或 ( D ? n u m _ l a y e r s , H o u t ) (D*num\_layers,H_{out}) (D?num_layers,Hout?) -----------------------------------------------------------------------? 其中 H o u t H_{out} Hout? =
hidden_size
,? D = 2 i f b i d i r e c t i o n a l = T r u e o t h e r w i s e 1 D=2~~~if~bidirectional=True~~~otherwise~1 D=2???if?bidirectional=True???otherwise?1
? 如果不提供就默認為
0
張量。
-
-
輸出,的類型及形狀( D D D 一般都為 1 1 1 ):
output
:類型:tensor,形狀: ( L , N , D ? H o u t ) (L,N,D*H_{out}) (L,N,D?Hout?) 或 ( L , D ? H o u t ) (L,D*H_{out}) (L,D?Hout?) ------------------------當batch_first=True
時為 ( N , L , D ? H o u t ) (N,L,D?H_{out}) (N,L,D?Hout?) 。hidden
:類型:tensor,形狀: ( D ? n u m _ l a y e r s , N , H o u t ) (D*num\_layers,N,H_{out}) (D?num_layers,N,Hout?) 或 ( D ? n u m _ l a y e r s , H o u t ) (D*num\_layers,H_{out}) (D?num_layers,Hout?) --------------- 此輸出代表了下一時刻的隱藏層狀態輸入。
-
其中的權重 W 、 b W、b W、b 都是自動初始化、可自學習的。
其實輸出
output
就是所有的隱層輸出狀態,hidden
就是最后一刻的隱層輸出狀態(num_layers
>1 的稍有不同)。 -
-
模塊使用圖解:
-
num_layers
默認為 1 時:調用展示:
import torchcell= torch.nn.RNN(input_size=input_size, hidden_size=hidden_size, num_layers=1) out, hidden = cell(inputs, hidden)
上圖中,就單個
RNN Cell
而言, x i x_i xi? 是輸入,左邊箭頭是隱層狀態輸入,右邊箭頭和上邊箭頭都是隱層狀態輸出。注意: 這里
RNN Cell
的個數就是seq_len
的值。 -
num_layers
> 1 時(令其=3):調用展示:
import torchcell= torch.nn.RNN(input_size=input_size, hidden_size=hidden_size, num_layers=3) out, hidden = cell(inputs, hidden)
上圖中,就最下面一排的單個
RNN Cell
而言, x i x_i xi? 是輸入,左邊箭頭是隱層狀態輸入,右邊箭頭和上邊箭頭都是隱層狀態輸出。就上面兩排的單個
RNN Cell
而言,下面一排RNN Cell
的隱層狀態輸出是其輸入,左邊箭頭是隱層狀態輸入,右邊箭頭和上邊箭頭都是隱層狀態輸出。 -
-
完整樣例展示:
這里
nn.RNN
內部前向傳播的時間步數就是seq_len
的值。import torchbatch_size = 2 seq_len = 3 input_size = 4 hidden_size = 2 num_layers = 1single_rnn = torch.nn.RNN(input_size=input_size, hidden_size=hidden_size, num_layers=num_layers)#(seqLen, batchSize, inputSize) inputs = torch.randn(seq_len, batch_size, input_size) hidden = torch.zeros(num_layers, batch_size, hidden_size) out, hidden = single_rnn(inputs, hidden) print('output size:', out.shape) print('output:', out) print('Hidden size:', hidden.shape) print('Hidden:', hidden)----------------------------------------------------------------------------------------------------------------------- # 輸出結果為: output size: torch.Size([3, 2, 2]) output: tensor([[[ 0.5540, -0.3186],[ 0.1407, -0.9272]],[[ 0.8301, 0.5667],[ 0.9692, -0.4985]],[[ 0.7678, 0.6239],[-0.4899, -0.9761]]], grad_fn=<StackBackward0>) Hidden size: torch.Size([1, 2, 2]) Hidden: tensor([[[ 0.7678, 0.6239],[-0.4899, -0.9761]]], grad_fn=<StackBackward0>)
2)單值序列預測實例
在訓練之前制作數據集時,通常是用前 m 個數據預測第 m+1 個數據,第 m+1 個數據作為真實值,前 m 個數據作為輸入得出的一個結果作為預測值(這 m+1 個數據就作為一個樣本)。如果 batch_size 不為 1 ,則 batch_size 個樣本就作為一次 epoch 的輸入。
數據集:某國際航班每月乘客量變化表,international-airline-passengers.csv,CSDN 都有提供下載的,下載之后不要改動。
目標:拿 12 個月的數據來預測下一個月的客流量。
完整代碼:
import torch
import torch.nn as nn
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from torch.utils.data import TensorDataset, DataLoader
from torch.utils.tensorboard import SummaryWriterwriter = SummaryWriter(log_dir='runs/airline_model')# 1. 數據預處理
data = pd.read_csv('international-airline-passengers.csv', usecols=['Month', 'Passengers'])
data['Month'] = pd.to_datetime(data['Month'])
data.set_index('Month', inplace=True)# 2. 數據集劃分
train_size = int(len(data) * 0.8)
train_data = data[:train_size]
test_data = data[train_size:]# 3. 歸一化處理
scaler = MinMaxScaler(feature_range=(0, 1))
train_scaled = scaler.fit_transform(train_data)
test_scaled = scaler.transform(test_data)# 4. 創建滑動窗口數據集
def create_sliding_windows(data, window_size):X, Y = [], []for i in range(len(data) - window_size):X.append(data[i:i + window_size])Y.append(data[i + window_size])return np.array(X), np.array(Y)window_size = 12
X_train, y_train = create_sliding_windows(train_scaled, window_size)
X_test, y_test = create_sliding_windows(test_scaled, window_size)# 轉換為PyTorch張量 (batch_size, seq_len, features)
X_train = torch.FloatTensor(X_train).unsqueeze(-1) # [samples, seq_len, 1]
X_train = X_train.squeeze(2) if X_train.dim() == 4 else X_train # 消除多余維度
y_train = torch.FloatTensor(y_train)
X_test = torch.FloatTensor(X_test).unsqueeze(-1)
X_test = X_test.squeeze(2) if X_test.dim() == 4 else X_test
y_test = torch.FloatTensor(y_test)# 5. 構建RNN模型(使用tanh激活)
class AirlinePassengerModel(nn.Module):def __init__(self, input_size=1, hidden_size=50, output_size=1):super().__init__()self.rnn = nn.RNN(input_size=input_size,hidden_size=hidden_size,nonlinearity='tanh',batch_first=True,num_layers=1 # 顯式指定層數)self.fc = nn.Linear(hidden_size, output_size)def forward(self, x):out, _ = self.rnn(x) # RNN層使用內置tanh激活out = self.fc(out[:, -1, :]) # 取最后一個時間步輸出return outmodel = AirlinePassengerModel()
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)dummy_input = torch.randn(1, window_size, 1)
writer.add_graph(model,dummy_input)# 6. 訓練模型
train_loader = DataLoader(TensorDataset(X_train, y_train), batch_size=32, shuffle=True)epochs = 100
train_loss, val_loss = [], []for epoch in range(epochs):model.train()batch_loss = 0for X_batch, y_batch in train_loader:optimizer.zero_grad()y_pred = model(X_batch)loss = criterion(y_pred, y_batch)loss.backward()optimizer.step()batch_loss += loss.item()train_loss.append(batch_loss / len(train_loader))# 驗證步驟model.eval()with torch.no_grad():y_val_pred = model(X_test)loss = criterion(y_val_pred, y_test)val_loss.append(loss.item())print(f'Epoch {epoch + 1}/{epochs} | Train Loss: {train_loss[-1]:.4f} | Val Loss: {val_loss[-1]:.4f}')# 7. 預測與逆歸一化
model.eval()
with torch.no_grad():train_pred = model(X_train).numpy()test_pred = model(X_test).numpy()# 逆歸一化處理
train_pred = scaler.inverse_transform(train_pred)
y_train = scaler.inverse_transform(y_train.numpy().reshape(-1, 1))
test_pred = scaler.inverse_transform(test_pred)
y_test = scaler.inverse_transform(y_test.numpy().reshape(-1, 1))# 8. 可視化
# 訓練損失曲線可視化
plt.figure(figsize=(12, 5))
plt.plot(range(1, len(train_loss)+1), train_loss, 'b-', label='Train Loss')
plt.plot(range(1, len(val_loss)+1), val_loss, 'r--', label='Validation Loss')
plt.title('Training Process Monitoring\n(2025-03-11)', fontsize=14)
plt.xlabel('Epochs', fontsize=12)
plt.ylabel('Loss', fontsize=12)
plt.xticks(np.arange(0, len(train_loss)+1, 10))
plt.grid(True, linestyle='--', alpha=0.7)
plt.legend()
plt.tight_layout()
plt.show()# 綜合預測結果可視化
plt.figure(figsize=(14, 6))# 原始數據曲線
plt.plot(data.index, data['Passengers'],label='Original Data',color='gray',alpha=0.4)# 訓練集預測曲線(需注意時間對齊)
train_pred_dates = train_data.index[window_size:train_size]
plt.plot(train_pred_dates, train_pred,label='Train Predictions',color='blue',linestyle='--')# 測試集預測曲線
test_pred_dates = test_data.index[window_size:]
plt.plot(test_pred_dates, test_pred,label='Test Predictions',color='red',linewidth=2)# 格式設置
plt.title('Time Series Prediction Results', fontsize=14)
plt.xlabel('Date', fontsize=12)
plt.ylabel('Passengers', fontsize=12)
plt.legend(loc='upper left')
plt.grid(True, linestyle=':', alpha=0.5)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()writer.close()
輸出訓練結果:
Epoch 1/100 | Train Loss: 0.0893 | Val Loss: 0.3493
Epoch 2/100 | Train Loss: 0.0473 | Val Loss: 0.1947
Epoch 3/100 | Train Loss: 0.0469 | Val Loss: 0.2113
Epoch 4/100 | Train Loss: 0.0387 | Val Loss: 0.2346
...
...
Epoch 95/100 | Train Loss: 0.0064 | Val Loss: 0.0304
Epoch 96/100 | Train Loss: 0.0052 | Val Loss: 0.0384
Epoch 97/100 | Train Loss: 0.0047 | Val Loss: 0.0434
Epoch 98/100 | Train Loss: 0.0048 | Val Loss: 0.0332
Epoch 99/100 | Train Loss: 0.0051 | Val Loss: 0.0285
Epoch 100/100 | Train Loss: 0.0051 | Val Loss: 0.0283
訓練及預測可視化:
3)同步多對多序列預測實例
目標:給出輸入 'hello'
,給出其標簽 'ohlol'
,通過訓練使得輸入 'hello'
,模型能輸出 'ohlol'
。
-
nn.RNNCell
:import torch# ==================================================準備數據================================================== input_size = 4 hidden_size = 4 batch_size = 1 # seq_len 在這里不用顯示定義, 模型會自動識別輸入的尺寸idx2char = ['e', 'h', 'l', 'o'] # 字母字典 x_data = [1, 0, 2, 2, 3] # x_data 表示的單詞是 hello, 在這里表示的是輸入 inputs y_data = [3, 1, 2, 3, 2] # y_data 表示的單詞是 ohlol, 在這里表示的輸出標簽 one_hot_lookup = [[1, 0, 0, 0],[0, 1, 0, 0],[0, 0, 1, 0],[0, 0, 0, 1]] # 獨熱字典x_one_hot = [one_hot_lookup[x] for x in x_data] # x_data 的獨熱編碼向量組, 形狀為:(seq_len, input_size) # 更改 x_one_hot 的形狀, 在中間加一個 batch_size 維度, 其中 -1 參數表示獲取列表中的元素個數(5個子列表, 那么個數就是5) inputs = torch.Tensor(x_one_hot).view(-1, batch_size, input_size) labels = torch.LongTensor(y_data).view(-1, 1) # 形狀為(seq_len, batch_size)print(x_one_hot) print(labels)# ==================================================定義模型================================================== class MyModel(torch.nn.Module):def __init__(self, input_size, hidden_size, batch_size):super(MyModel, self).__init__()self.batch_size = batch_sizeself.input_size = input_sizeself.hidden_size = hidden_sizeself.rnncell = torch.nn.RNNCell(input_size=self.input_size, hidden_size=self.hidden_size)def forward(self, input, hidden):hidden = self.rnncell(input, hidden)return hiddendef init_hidden(self):return torch.zeros(self.batch_size, self.hidden_size)net = MyModel(input_size, hidden_size, batch_size)# ==================================================準備訓練================================================== criterion = torch.nn.CrossEntropyLoss() # 交叉熵損失 optimizer = torch.optim.Adam(net.parameters(), lr=0.1) # Adam 優化器for epoch in range(15):loss = 0optimizer.zero_grad()hidden = net.init_hidden()print('Predicted string: ', end='')for input, label in zip(inputs, labels):hidden = net(input, hidden)# seq_len 個單元的損失要加起來得到總損失,并且還要添加 view 操作適配形狀# 這里的 -1 就是在自動填充 batch_size 的值loss += criterion(hidden.view(-1, hidden_size), label.view(-1))_, idx = hidden.max(dim=1)print(idx2char[idx.item()], end='')loss.backward()optimizer.step()print(', Epoch [%d/ 15] loss=%.4f' % (epoch+1, loss.item()))
輸出結果:
Predicted string: llllh, Epoch [1/15] loss=6.5481 Predicted string: ollll, Epoch [2/15] loss=5.6356 Predicted string: oolll, Epoch [3/15] loss=5.1777 Predicted string: oolol, Epoch [4/15] loss=4.7279 Predicted string: oolol, Epoch [5/15] loss=4.2586 Predicted string: ohlol, Epoch [6/15] loss=3.8693 Predicted string: ohlol, Epoch [7/15] loss=3.6075 Predicted string: ohlol, Epoch [8/15] loss=3.3900 Predicted string: ohlol, Epoch [9/15] loss=3.1333 Predicted string: ohlol, Epoch [10/15] loss=2.8496 Predicted string: ohlol, Epoch [11/15] loss=2.5996 Predicted string: ohlol, Epoch [12/15] loss=2.4079 Predicted string: ohlol, Epoch [13/15] loss=2.2640 Predicted string: ohlol, Epoch [14/15] loss=2.1526 Predicted string: ohlol, Epoch [15/15] loss=2.0646
-
訓練過程圖解(尤其是尺寸的要求和變化):
其中交叉熵損失的輸入輸出尺寸可以參考此篇博客:損失函數。
-
nn.RNN
import torch# ==================================================準備數據================================================== input_size = 4 hidden_size = 4 batch_size = 1 num_layers = 1 # seq_len = 5 在這里不用顯示定義, 模型會自動識別輸入的尺寸idx2char = ['e', 'h', 'l', 'o'] # 字母字典, 復雜情形可以是單詞字典 x_data = [1, 0, 2, 2, 3] # x_data 表示的單詞是 hello, 在這里表示的是輸入 input y_data = [3, 1, 2, 3, 2] # y_data 表示的單詞是 ohlol, 在這里表示的輸出標簽 one_hot_lookup = [[1, 0, 0, 0],[0, 1, 0, 0],[0, 0, 1, 0],[0, 0, 0, 1]] # 獨熱字典x_one_hot = [one_hot_lookup[x] for x in x_data] # x_data 的獨熱編碼向量組, 形狀為:(seq_len, input_size) # 更改 x_one_hot 的形狀, 在中間加一個 batch_size 維度, 其中 -1 參數表示獲取 seq_len, 就是列表中的元素個數(5個子列表, 那么個數就是5) inputs = torch.Tensor(x_one_hot).view(-1, batch_size, input_size) labels = torch.LongTensor(y_data)print(x_one_hot) print(inputs) print(labels)# ==================================================定義模型================================================== class Single_RNN(torch.nn.Module):def __init__(self, input_size, hidden_size, batch_size, num_layers=1):super(Single_RNN, self).__init__()self.num_layers = num_layersself.batch_size = batch_sizeself.input_size = input_sizeself.hidden_size = hidden_sizeself.rnn = torch.nn.RNN(input_size=self.input_size, hidden_size=self.hidden_size, num_layers=self.num_layers)def forward(self, input, hidden):output, hidden = self.rnn(input, hidden)# 輸出設置成 2 維張量,return output.view(-1, self.hidden_size)def init_hidden(self):return torch.zeros(self.num_layers, self.batch_size, self.hidden_size)net = Single_RNN(input_size, hidden_size, batch_size, num_layers)# ==================================================準備訓練================================================== criterion = torch.nn.CrossEntropyLoss() # 交叉熵損失 optimizer = torch.optim.Adam(net.parameters(), lr=0.05) # Adam 優化器for epoch in range(15):optimizer.zero_grad()hidden = net.init_hidden() # 初始化 h0outputs = net(inputs, hidden)loss = criterion(outputs, labels)loss.backward()optimizer.step()_, idx = outputs.max(dim=1)idx = idx.data.numpy() # 將 idx 變成numpy數組, 元素和尺寸不變print('Predicted: ', ''.join([idx2char[x] for x in idx]), end='')print(', Epoch [%d/ 15] loss=%.4f' % (epoch + 1, loss.item()))
輸出結果:
Predicted: ohooe, Epoch [1/ 15] loss=1.2800 Predicted: ohooo, Epoch [2/ 15] loss=1.1455 Predicted: ohooo, Epoch [3/ 15] loss=1.0370 Predicted: ohloo, Epoch [4/ 15] loss=0.9497 Predicted: ohlol, Epoch [5/ 15] loss=0.8746 Predicted: ohlol, Epoch [6/ 15] loss=0.8034 Predicted: ohlol, Epoch [7/ 15] loss=0.7356 Predicted: ohlol, Epoch [8/ 15] loss=0.6763 Predicted: ohlol, Epoch [9/ 15] loss=0.6283 Predicted: ohlol, Epoch [10/ 15] loss=0.5905 Predicted: ohlol, Epoch [11/ 15] loss=0.5614 Predicted: ohlol, Epoch [12/ 15] loss=0.5392 Predicted: ohlol, Epoch [13/ 15] loss=0.5220 Predicted: ohlol, Epoch [14/ 15] loss=0.5073 Predicted: ohlol, Epoch [15/ 15] loss=0.4934