学习过程中用到LSTM(简单版),记录下对这个网络的理解。
首先是数据的问题。如果数据是按照时间顺序获取的,那就按顺序输入就行。
每一行是一个时刻采集到的6个数据。一共168个时刻。168*6
当我们只输入一条数据时,整个网络的结构,此时可以看作是一个普通的网络后面再接一个全连接层(如下图)
这里有几点需要明确一下。输入数据需要转化为三维(涉及到一个步数的问题),LSTM层输出的也是三维,lstm层输出的三维需要转化为二维接入全连接层,再把输出的二维转化为三维。
下面是代码
class LstmRNN(nn.Module): """ Parameters: - input_size: 特征大小 - hidden_size: 隐藏神经元数 - output_size: 输出的神经元数 - num_layers: 隐藏层数,一般为1 """ def __init__(self, input_size, hidden_size, output_size, num_layers=1): super().__init__() self.lstm = nn.LSTM(input_size, hidden_size, num_layers) ### input_size输入特征维度 hidden_size 隐藏层维度 num_layers lstm的隐藏层数 self.linear1 = nn.Linear(hidden_size, output_size) # 全连接层 def forward(self, _x): x, _ = self.lstm(_x) #_x是输入的数据,需要转化为三维。 _x is input, size (seq_len, batch, input_size)即 总的时间长度,每个批次大小,输入特征大小 s, b, h = x.shape # x是lstm的输出结果,转化为二维。 # x is output, size (seq_len, batch, hidden_size)即 总的时间长度,批次大小 隐藏层神经元个数 x = x.view(s * b, h) ## 把x转换为二维(s*b,h) 这里是为后面连接一个全连接层做准备 x = self.linear1(x) ## 把lstm的输出结果输入进最后的全连接层得到结果 x = x.view(s, b, -1) ## 把最后全连接层输出的结果转化为三维 return x
接下来是读入数据,我用的pandas
if __name__ == '__main__': # checking if GPU is available device = torch.device("cpu") if (torch.cuda.is_available()): device = torch.device("cuda:0") print('Training on GPU.') else: print('No GPU available, training on CPU.') ## 读入数据集和标签集并进行归一化。 # data_x = np.array(pd.read_csv('特征集/特征-6.csv', header=None,skiprows=1)).astype('float32') data_x = pd.read_csv('特征集/特征-6.csv') data_x=np.array((data_x)).astype(('float32')) # 转化数据类型 data_x = (data_x- data_x.min()) / (data_x.max() - data_x.min()) ## 归一化data_y = pd.read_csv('特征集/soh-6.csv') # 这里是标签集的操作 和数据集一样 data_y = np.array((data_y)).astype(('float32')) data_y = (data_y - data_y.min()) / (data_y.max() - data_y.min()) data_len = len(data_x) ## 获取总的时间维度,即数据集的条数 168 t = np.linspace(0, data_len-1, data_len) ## 生成一个序列号 train_data_ratio = 0.6 # 为了把数据集拆分,这里设置一个数字 train_data_len = int(data_len * train_data_ratio) train_x = data_x[:train_data_len] ##切分数据集,这里取前134个作为训练集 train_y = data_y[:train_data_len] ## 训练集的标签 t_for_training = t[:train_data_len] ## 训练集的序列号 test_x = data_x[train_data_len:] ## 这里是 测试集 test_y = data_y[train_data_len:] t_for_testing = t[train_data_len:]
接下来是数据的转化
INPUT_FEATURES_NUM = 6 ## 特征个数是6 OUTPUT_FEATURES_NUM = 1 ## 把训练集和训练的标签转化为3维 train_x_tensor = train_x.reshape(-1, 1, INPUT_FEATURES_NUM) # set batch size to 1 train_y_tensor = train_y.reshape(-1, 1, OUTPUT_FEATURES_NUM) # set batch size to 1 # transfer data to pytorch tensor train_x_tensor = torch.from_numpy(train_x_tensor) ## 把数组改为张量 train_y_tensor = torch.from_numpy(train_y_tensor) lstm_model = LstmRNN(INPUT_FEATURES_NUM, 20, output_size=OUTPUT_FEATURES_NUM, num_layers=1) ## 调用我们的lstm类 并传入参数criterion = nn.L1Loss() ## 损失函数 optimizer = torch.optim.Adam(lstm_model.parameters(), lr=1e-2) ## 梯度下降法 max_epochs = 3000 ## 训练次数
接下来是训练
train_x_tensor = train_x_tensor.to(device) ## 训练数据加载到CPU上 for epoch in range(max_epochs): output = lstm_model(train_x_tensor).to(device) ## 把我们的模型也加载到CPU loss = criterion(output, train_y_tensor) ## 计算损失 optimizer.zero_grad() ## 梯度下降 loss.backward() optimizer.step()pred_y_for_train = lstm_model(train_x_tensor).to(device) ## 训练数据的预测值 即从lstm网络中输出的是三维 pred_y_for_train = pred_y_for_train.view(-1, OUTPUT_FEATURES_NUM).data.numpy()## 把预测的值从三维转化为二维lstm_model = lstm_model.eval() ## 我们的训练已经完毕,权重W B都已得到,接下来进行预测,不需要梯度的计算test_x_tensor = test_x.reshape(-1, 1,INPUT_FEATURES_NUM) ##测试集转化为三维,并转化为张量,加载到cpu上 test_x_tensor = torch.from_numpy(test_x_tensor) test_x_tensor = test_x_tensor.to(device)pred_y_for_test = lstm_model(test_x_tensor).to(device) ## 测试集的预测值,转化为二维 pred_y_for_test = pred_y_for_test.view(-1, OUTPUT_FEATURES_NUM).data.numpy()loss = criterion(torch.from_numpy(pred_y_for_test), torch.from_numpy(test_y)) ## 计算损失print("test loss:", loss.item()) #输出损失
如果想画图可以自己添加画图的程序。