使用LSTM完成时间序列预测

c

在本教程中,我们将介绍一个简单的示例,旨在帮助初学者入门时间序列预测和 PyTorch 的使用。通过这个示例,你可以学习如何使用 LSTMCell 单元来处理时间序列数据。

我们将使用两个 LSTMCell 单元来学习从不同相位开始的正弦波信号。模型在学习了这些正弦波之后,将尝试预测未来的信号值。

使用方法

  1. 生成正弦波信号:

    python generate_sine_wave.py
    
  2. 训练模型:

    python train.py
    

生成正弦波训练数据

在这一步中,我们将生成用于训练的正弦波信号数据。以下是代码及其详细解释:

import numpy as np
import torch# 设置随机种子,以确保结果的可重复性
np.random.seed(2)# 定义常数 T、L 和 N
T = 20
L = 1000
N = 100# 创建一个空的 numpy 数组 x,用于存储生成的序列
x = np.empty((N, L), 'int64')# 为数组 x 赋值,每行都是一个按顺序排列的整数序列,
# 并加入了一个随机偏移量
x[:] = np.array(range(L)) + np.random.randint(-4 * T, 4 * T, N).reshape(N, 1)# 对 x 进行正弦变换,以此生成正弦波数据
data = np.sin(x / 1.0 / T).astype('float64')# 将生成的正弦波数据保存为一种 PyTorch 可读的格式
torch.save(data, open('traindata.pt', 'wb'))
代码解析
  1. 导入库
  • numpy:用于数值计算
  • torch:用于深度学习中的数据处理和模型训练
  1. 设置随机种子
  • 通过 np.random.seed(2) 设置随机种子,以保证每次运行代码时生成相同的随机数,从而使结果可重复。
  1. 定义常量
  • T:周期长度
  • L:每行的序列长度
  • N:生成的样本数量
  1. 生成随机序列
  • 创建一个空的 numpy 数组 x,用于存储生成的整数序列。
  • 对数组 x 进行赋值,每一行是一个按顺序排列的整数序列,加上一个随机的偏移量。偏移量的范围由 np.random.randint(-4 * T, 4 * T, N).reshape(N, 1) 确定。
  1. 生成正弦波数据
  • x 进行正弦变换,生成标准的正弦波数据。np.sin(x / 1.0 / T).astype('float64') 将整数序列转换为浮点数序列,并进行正弦变换。
  1. 保存数据
  • 使用 torch.save 将生成的正弦波数据保存为 traindata.pt,方便后续训练时加载使用。

搭建与训练时间序列预测模型

在本教程中,我们将详细讲解如何使用 PyTorch 搭建一个LSTM模型,进行时间序列预测。以下是代码及其逐行解释,我们将整个过程分为三个部分:模型定义、数据加载与预处理,以及模型训练与预测。

模型定义

首先,我们定义一个 LSTM 模型,该模型包含两个 LSTMCell 层和一个全连接层用于输出。

from __future__ import print_function
import argparse
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt# 定义一个序列模型
class Sequence(nn.Module):def __init__(self):super(Sequence, self).__init__()# 定义两个LSTMCell层和一个全连接层self.lstm1 = nn.LSTMCell(1, 51)self.lstm2 = nn.LSTMCell(51, 51)self.linear = nn.Linear(51, 1)# 定义前向传播def forward(self, input, future = 0):outputs = []# 初始化LSTMCell的隐藏状态和细胞状态h_t = torch.zeros(input.size(0), 51, dtype=torch.double)c_t = torch.zeros(input.size(0), 51, dtype=torch.double)h_t2 = torch.zeros(input.size(0), 51, dtype=torch.double)c_t2 = torch.zeros(input.size(0), 51, dtype=torch.double)# 遍历输入序列for input_t in input.split(1, dim=1):# 更新LSTMCell的隐藏状态和细胞状态h_t, c_t = self.lstm1(input_t, (h_t, c_t))h_t2, c_t2 = self.lstm2(h_t, (h_t2, c_t2))# 通过全连接层得到输出output = self.linear(h_t2)outputs += [output]# 如果需要预测未来值for i in range(future):h_t, c_t = self.lstm1(output, (h_t, c_t))h_t2, c_t2 = self.lstm2(h_t, (h_t2, c_t2))output = self.linear(h_t2)outputs += [output]# 将输出序列拼接起来outputs = torch.cat(outputs, dim=1)return outputs

这段代码是一个简单的序列模型,包括两个LSTMCell层和一个全连接层。它接受一个输入序列,通过LSTMCell层和全连接层对输入进行处理,最终输出一个序列。如果需要预测未来值,则可以在forward函数中传入future参数来进行预测。

具体解释如下:

  1. 首先导入必要的库,包括torch、torch.nn等。
  2. 定义了一个名为Sequence的序列模型,继承自nn.Module。
  3. 在初始化函数中,定义了两个LSTMCell层和一个全连接层,分别是lstm1、lstm2和linear。
  4. forward函数用来定义模型的前向传播过程,接受输入input和可选的future参数,返回处理后的输出序列。
  5. 在forward函数中,首先初始化了LSTMCell的隐藏状态和细胞状态h_t、c_t、h_t2、c_t2。
  6. 遍历输入序列input,对每个输入进行处理,更新LSTMCell的隐藏状态和细胞状态,通过全连接层得到输出,并将输出保存在outputs列表中。
  7. 如果future参数大于0,表示需要预测未来值,进入一个for循环,通过当前输出不断更新LSTMCell的状态,并将预测得到的输出保存在outputs中。
  8. 最后将所有输出序列拼接起来,返回最终的输出。

这段代码主要实现了对输入序列的处理和未来值的预测,是一个简单的序列预测模型。


数据加载与预处理

接下来,我们加载生成的训练数据,并构建训练集和测试集。

if __name__ == '__main__':# 定义命令行参数parser = argparse.ArgumentParser()parser.add_argument('--steps', type=int, default=15, help='steps to run')opt = parser.parse_args()# 设置随机种子np.random.seed(0)torch.manual_seed(0)# 加载数据并构建训练集data = torch.load('traindata.pt')input = torch.from_numpy(data[3:, :-1])target = torch.from_numpy(data[3:, 1:])test_input = torch.from_numpy(data[:3, :-1])test_target = torch.from_numpy(data[:3, 1:])

这段代码是一个Python脚本的入口点,通常用于定义和设置命令行参数,加载数据,并准备训练数据。让我逐行解释:

  1. if __name__ == '__main__': 这是Python中用来判断是否当前脚本被当做程序入口执行的一种常见方式。如果当前脚本被当做主程序执行,而不是被其他模块导入,这个条件会成立。

  2. parser = argparse.ArgumentParser() 创建了一个命令行参数解析器。

  3. parser.add_argument('--steps', type=int, default=15, help='steps to run') 定义了一个名为steps的命令行参数,指定了参数的类型为整数,默认值为15,以及参数的帮助信息。

  4. opt = parser.parse_args() 解析命令行参数,并将结果存储在opt变量中。

  5. np.random.seed(0)torch.manual_seed(0) 设置了随机数生成器的种子,用于确保实验结果的可复现性。

  6. data = torch.load('traindata.pt') 从名为traindata.pt的文件中加载数据。

  7. input = torch.from_numpy(data[3:, :-1]) 创建了一个PyTorch张量input,用于存储数据中第4列到倒数第2列之间的数据。

  8. target = torch.from_numpy(data[3:, 1:]) 创建了一个PyTorch张量target,用于存储数据中第4列到最后一列之间的数据。

  9. test_input = torch.from_numpy(data[:3, :-1]) 创建了一个PyTorch张量test_input,用于存储数据中第1列到倒数第2列之间的数据,这是用于测试的输入数据。

  10. test_target = torch.from_numpy(data[:3, 1:]) 创建了一个PyTorch张量test_target,用于存储数据中第2列到最后一列之间的数据,这是用于测试的目标数据。

这段代码的主要作用是准备数据,设置随机种子和命令行参数,为后续的数据处理和模型训练做准备。


模型训练与预测

最后,我们进行模型训练并进行预测。

    # 构建模型seq = Sequence()seq.double()criterion = nn.MSELoss()# 使用LBFGS作为优化器,因为我们可以将所有数据加载到训练中optimizer = optim.LBFGS(seq.parameters(), lr=0.8)# 开始训练for i in range(opt.steps):print('STEP: ', i)def closure():optimizer.zero_grad()out = seq(input)loss = criterion(out, target)print('loss:', loss.item())loss.backward()return lossoptimizer.step(closure)# 开始预测,不需要跟踪梯度with torch.no_grad():future = 1000pred = seq(test_input, future=future)loss = criterion(pred[:, :-future], test_target)print('test loss:', loss.item())y = pred.detach().numpy()# 绘制结果plt.figure(figsize=(30,10))plt.title('Predict future values for time sequences\n(Dashlines are predicted values)', fontsize=30)plt.xlabel('x', fontsize=20)plt.ylabel('y', fontsize=20)plt.xticks(fontsize=20)plt.yticks(fontsize=20)def draw(yi, color):plt.plot(np.arange(input.size(1)), yi[:input.size(1)], color, linewidth = 2.0)plt.plot(np.arange(input.size(1), input.size(1) + future), yi[input.size(1):], color + ':', linewidth = 2.0)draw(y[0], 'r')draw(y[1], 'g')draw(y[2], 'b')plt.savefig('predict%d.pdf'%i)plt.close()

这段代码是一个简单的 PyTorch 深度学习模型训练和预测的示例。让我为您解释一下代码的主要部分:

  1. 首先,代码创建了一个名为 “seq” 的序列模型。然后转换这个模型为双精度数据类型。接着定义了均方误差损失函数 “criterion”。LBFGS 作为优化器,学习速率为 0.8。

  2. 在训练过程中,通过一个循环来进行多次优化迭代。在每次迭代中,通过闭包函数 “closure()” 来计算损失并执行反向传播,然后优化器根据损失进行参数更新。

  3. 接着,使用 torch.no_grad() 上下文管理器来禁止跟踪梯度,开始进行预测。在这里,预测未来的 1000 个时间步。然后计算预测结果和测试目标之间的损失,并打印损失值。

  4. 接下来是绘制结果的部分。代码会使用 matplotlib 库绘制预测的结果图。其中,将实线用于已知的数据部分,虚线用于预测的数据部分。最后,结果图被保存为名为 ‘predict%d.pdf’ 的文件,其中 %d 是迭代的次数。


在GPU上运行

这段代码的默认配置是使用CPU进行训练和预测。如果你想利用GPU加速训练过程,可以通过以下步骤修改代码将模型和数据放到GPU上进行计算。

以下是针对GPU的修改:

  1. 检查是否有可用的GPU:一般使用 torch.cuda.is_available() 来检查是否有可用的GPU。
  2. 将模型和数据移动到GPU:将数据和模型移动到GPU设备上进行计算。

所有涉及到数据和模型的地方都需要做相应的改动,使其可以在GPU上执行。

以下是修改后的代码:

from __future__ import print_function
import argparse
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt# 定义一个序列模型
class Sequence(nn.Module):def __init__(self):super(Sequence, self).__init__()# 定义两个LSTMCell层和一个全连接层self.lstm1 = nn.LSTMCell(1, 51)self.lstm2 = nn.LSTMCell(51, 51)self.linear = nn.Linear(51, 1)# 定义前向传播def forward(self, input, future = 0):outputs = []# 初始化LSTMCell的隐藏状态和细胞状态h_t = torch.zeros(input.size(0), 51, dtype=input.dtype, device=input.device)c_t = torch.zeros(input.size(0), 51, dtype=input.dtype, device=input.device)h_t2 = torch.zeros(input.size(0), 51, dtype=input.dtype, device=input.device)c_t2 = torch.zeros(input.size(0), 51, dtype=input.dtype, device=input.device)# 遍历输入序列for input_t in input.split(1, dim=1):# 更新LSTMCell的隐藏状态和细胞状态h_t, c_t = self.lstm1(input_t, (h_t, c_t))h_t2, c_t2 = self.lstm2(h_t, (h_t2, c_t2))# 通过全连接层得到输出output = self.linear(h_t2)outputs += [output]# 如果需要预测未来值for i in range(future):h_t, c_t = self.lstm1(output, (h_t, c_t))h_t2, c_t2 = self.lstm2(h_t, (h_t2, c_t2))output = self.linear(h_t2)outputs += [output]# 将输出序列拼接起来outputs = torch.cat(outputs, dim=1)return outputsif __name__ == '__main__':# 定义命令行参数parser = argparse.ArgumentParser()parser.add_argument('--steps', type=int, default=15, help='steps to run')opt = parser.parse_args()# 设置随机种子np.random.seed(0)torch.manual_seed(0)# 检查是否有可用的GPUdevice = torch.device("cuda" if torch.cuda.is_available() else "cpu")# 加载数据并构建训练集data = torch.load('traindata.pt')input = torch.from_numpy(data[3:, :-1]).double().to(device)target = torch.from_numpy(data[3:, 1:]).double().to(device)test_input = torch.from_numpy(data[:3, :-1]).double().to(device)test_target = torch.from_numpy(data[:3, 1:]).double().to(device)# 构建模型seq = Sequence().double().to(device)criterion = nn.MSELoss()# 使用LBFGS作为优化器,因为我们可以将所有数据加载到训练中optimizer = optim.LBFGS(seq.parameters(), lr=0.8)# 开始训练for i in range(opt.steps):print('STEP: ', i)def closure():optimizer.zero_grad()out = seq(input)loss = criterion(out, target)print('loss:', loss.item())loss.backward()return lossoptimizer.step(closure)# 开始预测,不需要跟踪梯度with torch.no_grad():future = 1000pred = seq(test_input, future=future)loss = criterion(pred[:, :-future], test_target)print('test loss:', loss.item())y = pred.detach().cpu().numpy()  # 将结果移回CPU以便绘图# 绘制结果plt.figure(figsize=(30,10))plt.title('Predict future values for time sequences\n(Dashlines are predicted values)', fontsize=30)plt.xlabel('x', fontsize=20)plt.ylabel('y', fontsize=20)plt.xticks(fontsize=20)plt.yticks(fontsize=20)def draw(yi, color):plt.plot(np.arange(input.size(1)), yi[:input.size(1)], color, linewidth = 2.0)plt.plot(np.arange(input.size(1), input.size(1) + future), yi[input.size(1):], color + ':', linewidth = 2.0)draw(y[0], 'r')draw(y[1], 'g')draw(y[2], 'b')plt.savefig('predict%d.pdf'%i)plt.close()

修改解释

  1. 检查GPU:

    • 使用 torch.cuda.is_available() 检查是否有可用的GPU。如果有,将 device 设置为 cuda,否则为 cpu
  2. 数据和模型移到GPU:

    • 使用 .to(device) 方法将数据和模型移到指定设备(CPU或GPU)。
    • 初始化隐藏状态和细胞状态时,指定相应的设备 device 和数据类型 dtype
  3. 绘图前将数据移回CPU:

    • 由于 matplotlib 需要在 CPU 上的 numpy 数组,因此在绘图前将预测数据移回 CPU,并调用 .detach().cpu().numpy()

通过这些修改,你可以利用GPU来加速模型训练过程。当然,前提是你的计算机上配备了兼容的GPU。如果没有,代码将自动退回到使用CPU进行训练。

可以看到GPU明显上升

在这里插入图片描述

结果

STEP:  0
loss: 0.5023738122475573
loss: 0.4985663937943564
loss: 0.479011960611529
loss: 0.44633490214842303
loss: 0.35406310257493023
loss: 0.2050701661768143
loss: 1.3960531561166554
loss: 0.03249441148471743
...
test loss: 6.382565835674331e-06
STEP:  13
loss: 3.76246839739177e-06
test loss: 6.382565835674331e-06
STEP:  14
loss: 3.76246839739177e-06
test loss: 6.382565835674331e-06

得到图像:

第1次训练后:

在这里插入图片描述

第5次训练后:

在这里插入图片描述

第10次:

在这里插入图片描述

第15次:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/48995.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Perl 哈希

Perl 哈希 Perl 哈希是一种强大的数据结构,用于存储键值对集合。它是 Perl 语言的核心特性之一,广泛应用于各种编程任务中。本文将详细介绍 Perl 哈希的概念、用法和最佳实践。 什么是 Perl 哈希? Perl 哈希是一种关联数组,其中…

MYSQL 七、mysql 日志与备份

一、其他数据库日志 千万不要小看日志。很多看似奇怪的问题,答案往往就藏在日志里。很多情况下,只有通过查看日志才 能发现问题的原因,真正解决问题。所以,一定要学会查看日志,养成检查日志的习惯,对提升你…

C语言-预处理详解

1.预处理符号 C语言中设置了一些预定义符号,可以直接使用,预定义符号是在预处理期间处理的。 __FILE__//代表当前进行编译的源文件 __LINE__//文件当前行号 __DATE__//文件当前日期 __TIME__//文件当前时间 __STDC__//如果编译器遵循ANSIC,…

重复图片查找:巧用Python和OpenCV进行图像哈希与汉明距离检测以从海量图片中找出重复图片

重复图片查找:巧用Python和OpenCV进行图像哈希与汉明距离检测以从海量图片中找出重复图片 1. 导言2. 环境准备3. 图像哈希(pHash)原理4. 汉明距离原理5. 代码实现导入必要的库图像哈希计算函数汉明距离计算函数查找重复图片函数示例使用 在处…

【ELK+Kafka+filebeat分布式日志收集】kibana基本使用教程

基本功能 查询数据 在Discover中查看数据: 进入Discover视图。 选择之前创建的索引模式。 使用搜索框和过滤器来查询和过滤数据。 使用KQL(Kibana Query Language): KQL是一种简单的查询语法,用于过滤Elasticsearch中的数据。 支持Terms Query、Boolean Queries、Range …

分布式锁的实现:Redis和Zookeeper

在分布式系统中,确保数据的一致性和避免并发问题是非常重要的。分布式锁是解决这些问题的关键技术之一。本文将详细介绍如何使用Redis和Zookeeper实现分布式锁,并通过Java代码示例帮助读者理解其实现原理。 1. 分布式锁的基本概念 分布式锁是一种用于协…

乐鑫AWS IoT ExpressLink方案,简化物联网设备连接AWS IoT服务

在现代科技迅速发展的今天,物联网(IoT)已经成为连接物理世界与数字世界的重要桥梁,越来越多的设备开始接入网络,实现智能化控制。 在这个大背景下,乐鑫携手亚马逊,推出了AWS IoT ExpressLink方…

Linux:Linux发展史

大家好!此篇文章并非技术博文,而是简单了解Linux的时代背景和发展史,只有知其所以然才能让我们更好地让走进Liunx的世界! 一、计算机的发展历史背景 首先我们要知道,早期大多数科技的进步都是以国家的对抗为历史背景的…

Java语言程序设计基础篇_编程练习题**15.17 (几何问题:寻找边界矩形)

**15.17 (几何问題:寻找边界矩形) 请编写一个程序,让用户可以在一个二维面板上动态地增加和移除点,如图15-29a所示。当点加入和移除的时候,一个最小的边界矩形更新显示。假设每个点的半径是 10 像素 解题思路: 这道题可以从编程…

数学建模(4)——支持向量机算法

一、代码示例 import numpy as np import matplotlib.pyplot as plt from sklearn import datasets from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.svm import SVC from sklearn.metrics import clas…

1-如何挑选Android编译服务器

前几天,我在我的星球发了一条动态:入手洋垃圾、重操老本行。没错,利用业余时间,我又重新捣鼓捣鼓代码了。在接下来一段时间,我会分享我从服务器的搭建到完成Android产品开发的整个过程。这些东西之前都是折腾过的&…

JVM类加载机制详解

Java在运行期才对类进行加载到内存、连接、初始化过程。这使得Java应用具有极高的灵活性和拓展性,可以依赖运行期进行动态加载和动态连接。 主要加载哪些?Java中的数据类型分为基本数据类型和引用数据类型,基本数据类型由虚拟机预先定义&…

Flask: URL 视图函数 路由

Flask: URL 视图函数 路由 from flask import Flask, request app Flask(__name__) # URL: / # 视图函数: hello_world # 路由: 将根URL映射到hello_world函数 app.route(/) def hello_world(): return Hello, World! # URL: /user/<int:user_id> # 视图…

站在资本投资领域如何看待分布式光纤传感行业?

近年来&#xff0c;资本投资领域对于分布式光纤传感行业并不十分敏感。这主要是由于分布式光纤传感技术是一个专业且小众的领域&#xff0c;其生命周期相对较长&#xff0c;缺乏爆发性&#xff0c;与消费品或商业模式创新产业有所不同。此外&#xff0c;国内的投资环境也是影响…

双向长短期记忆网络(BiLSTM)及其Python和MATLAB实现

长短期记忆网络&#xff08;Long Short-Term Memory&#xff0c;LSTM&#xff09;是一种特殊的循环神经网络&#xff08;RNN&#xff09;&#xff0c;旨在克服传统RNN在长序列数据中的梯度消失和梯度爆炸问题&#xff0c;并能更有效地捕捉长期依赖关系。除了基本的LSTM结构外&a…

谷粒商城实战笔记-42-前端基础-Vue-生命周期和钩子函数

下面是Vue官网关于生命周期及不同阶段的钩子函数的图示。 Vue 实例生命周期是指从一个组件被创建到最终被销毁的整个过程。 在这一过程中&#xff0c;Vue 提供了一系列的“钩子”函数&#xff0c;在生命周期的不同阶段执行自定义的代码。 以下是 Vue 对象生命周期的主要阶段…

Ubuntu 20.04搭建OpenCV 4.5.0 C++环境

Ubuntu 20.04搭建OpenCV 4.5.0 & C环境_ubuntu opencv4.5.0-CSDN博客

图片转换之heic转jpg(使用ImageMagick)

缘由&#xff1a;iphone的图库&#xff0c;用jpg拍照保存后内存占比较大&#xff0c;heic格式会微缩不少。问题来了&#xff0c;电脑不能直接小图预览heic。 分析&#xff1a;现在就是解决小图预览的问题&#xff08;大图用wps可以看&#xff09; 解决&#xff1a;查找了一些…

Vue中的diff算法

文章目录 diff算法是什么比较方式源码分析patchpatchVnodeupdateChildren小结Vue3中diff算法优化diff算法是什么 diff算法是一种通过同层的树节点进行比较的高效算法 其有两个特点: 比较只会在同层级进行,不会跨层级比较在dff比较的过程中,循环从两边向中间比较(首位交叉…

基于神经网络的聚类分析

神经网络是一种非常有用的机器学习模型&#xff0c;具有无数的应用。今天&#xff0c;我们将分析一个数据集&#xff0c;看看我们是否可以通过应用无监督聚类技术来查找数据中的模式和隐藏分组&#xff0c;从而获得新的见解。 我们的目标是对复杂数据进行降维&#xff0c;以便…