最近做了利用RNN实现一个回归预测问题的小项目,在这里总结一下,方便下次使用。
代码参考莫烦python——RNN 循环神经网络 (回归):
- https://ptorch.com/docs/4/pytorch-video-RNN-regression/
- https://morvanzhou.github.io/tutorials/machine-learning/torch/4-03-RNN-regression/
0. 构建数据集
我们的任务目的是用sin函数预测cos函数,因此首先构造数据集。这里我们用MATLAB构造数据集,并导出至csv文件。其中input为幅值1,频率5Hz的正弦信号。相应output是input求导之后的结果。
数据格式为:
t | input | output |
---|---|---|
… | … | … |
1. 数据集导入
利用torch自带的Dataset和Dataloader类,导入训练数据。
导入数据集的自定义Dataset类:
import numpy as np
from torch.utils.data import Dataset
# 导入数据集的类
class MyDataset(Dataset):
def __init__(self, csv_file):
self.lines = open(csv_file).readlines()
def __getitem__(self, index):
# 获取索引对应位置的一条数据
cur_line = self.lines[index].split(',')
sin_input = np.float32(cur_line[1].strip())
cos_output = np.float32(cur_line[2].strip())
return sin_input, cos_output
def __len__(self):
return len(self.lines) # MyDataSet的行数
DataLoader按照batch进行分割:
# batch size
batch_size_train = 20
filename = './data/data.csv'
dataset_train = MyDataset(filename)
train_loader = DataLoader(dataset_train, batch_size=batch_size_train, shuffle=False, drop_last=True)
其中shuffle为是否打乱顺序,drop_last为按照batch分割数据后如果最后一组不够分了是否舍弃。
2. 构建RNN网络结构
定义网络结构如下:
from torch import nn
class Rnn(nn.Module):
def __init__(self, input_num=1, hidden_num=64, layer_num=1, output_num=1, seq_len=20):
super(Rnn, self).__init__()
self.hidden_num = hidden_num
self.output_num = output_num
self.seq_len = seq_len # 序列长度
self.rnn = nn.RNN(
input_size=input_num,
hidden_size=hidden_num,
num_layers=layer_num,
nonlinearity='relu',
batch_first=True # 输入(batch, seq, feature)
)
self.Out = nn.Linear(hidden_num, output_num)
def forward(self, u, h_state):
"""
:param u: input输入
:param h_state: 循环神经网络状态量
:return: outs, h_state_next
"""
r_out, h_state_next = self.rnn(u, h_state)
r_out_reshaped = r_out.view(-1, self.hidden_num) # to 2D data
outs = self.Out(r_out_reshaped)
outs = outs.view(-1, self.seq_len, self.output_num) # to 3D data
return outs, h_state_next
其中:input_num对应输入数据的维度, hidden_num对应每个隐含层的维度, layer_num对应隐含层数目, output_num对应输出数据的维度, seq_len对应每个序列的长度(与上面导入数据的batch_size一致)。
关于forward中的数据维度转换可以输出一下对应的维度观察数据形式,这里我都调好了,不再具体说了。输入和输出都是3维的,因为batch_first=True,所以格式均为(batch, seq, feature)
。
导入模型、优化器:
rnn = Rnn(seq_len=batch_size_train).to(device)
optimizer = torch.optim.SGD(rnn.parameters(), lr=0.001, momentum=0.8) # SGD
# scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=500, gamma=0.1) # Learning Rate Decay
criterion = nn.MSELoss()