上一篇 | 下一篇 |
---|---|
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