1. 代码整体概述

这是一个完整的时间序列预测入门示例,展示了PyTorch实现RNN的核心流程,适合作为时序预测任务的基础模板。

  1. 生成带噪声的正弦波序列数据
  2. 定义简单的RNN模型结构
  3. 训练模型预测下一个时间步的值
  4. 可视化预测结果和训练过程

完整代码

import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt
import os
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"

def add_gaussian_noise(tensor, mean=0.0, std=0.1):
    noise = torch.normal(mean, std, tensor.size())
    return tensor + noise

# 1. 生成正弦波序列数据
def generate_sine_wave(seq_length=10, num_samples=1000):
    x = torch.linspace(0, 10, num_samples)  # 生成时间点
    y = torch.sin(x) # 生成正弦波
    y = add_gaussian_noise(y)# + 噪音

    # 创建输入-输出序列 (使用前seq_length个点预测下一个点)
    X, Y = [], []
    for i in range(len(y) - seq_length):
        X.append(y[i:i + seq_length].unsqueeze(-1))  # 输入序列 [seq_length, 1]
        Y.append(y[i + seq_length])  # 输出值 (下一个点)

    return torch.stack(X), torch.tensor(Y).unsqueeze(-1)


# 参数设置
seq_length = 20  # 输入序列长度
input_size = 1  # 输入特征维度 (正弦波是单变量)
hidden_size = 32  # RNN隐藏层维度
output_size = 1  # 输出维度
num_epochs = 100  # 训练轮数
batch_size = 64  # 批大小

# 生成数据
X, Y = generate_sine_wave(seq_length, num_samples=1000)

print(X.shape)

print(Y.shape)


# 2. 定义最简单的RNN模型
class SimpleRNN(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(SimpleRNN, self).__init__()
        self.rnn = nn.RNN(
            input_size=input_size,
            hidden_size=hidden_size,
            batch_first=True  # 输入格式为 [batch, seq, feature]
        )
        self.fc = nn.Linear(hidden_size, output_size)  # 输出层

    def forward(self, x):
        # 初始化隐藏状态 (全零)
        h0 = torch.zeros(1, x.size(0), hidden_size)

        # RNN前向传播
        # out: 所有时间步的输出 [batch, seq_len, hidden_size]
        # hn: 最后一个时间步的隐藏状态 [1, batch, hidden_size]
        out, hn = self.rnn(x, h0)

        # 只取最后一个时间步的输出
        out = self.fc(out[:, -1, :])
        return out


# 3. 初始化模型和优化器
model = SimpleRNN(input_size, hidden_size, output_size)
criterion = nn.MSELoss()  # 回归任务用均方误差损失
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

# 4. 训练模型
losses = []
for epoch in range(num_epochs):
    model.train()
    optimizer.zero_grad()

    # 前向传播
    outputs = model(X)
    loss = criterion(outputs, Y)

    # 反向传播
    loss.backward()
    optimizer.step()

    losses.append(loss.item())
    if (epoch + 1) % 10 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.6f}')

# 5. 预测结果可视化
model.eval()
with torch.no_grad():
    predictions = model(X)

# 绘制结果
plt.figure(figsize=(12, 6))
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
# 禁用 Unicode 负号(使用 ASCII 短横线)
plt.rcParams['axes.unicode_minus'] = False

plt.plot(Y.numpy(), 'b-', label='真实值', alpha=0.6)
plt.plot(predictions.numpy(), 'r--', label='预测值', linewidth=2)
plt.title('正弦波序列预测结果')
plt.xlabel('时间步')
plt.ylabel('振幅')
plt.legend()
plt.grid(True)
plt.show()

# 绘制损失曲线
plt.figure(figsize=(10, 4))
plt.plot(losses)
plt.title('训练损失变化')
plt.xlabel('训练轮次')
plt.ylabel('MSE损失')
plt.grid(True)
plt.show()

2. 关键代码解析

2.1 数据准备部分

def generate_sine_wave(seq_length=10, num_samples=1000):
    # 生成基础正弦波
    x = torch.linspace(0, 10, num_samples)
    y = torch.sin(x)
    
    # 添加高斯噪声
    y = add_gaussian_noise(y)
    
    # 创建时间序列样本
    X, Y = [], []
    for i in range(len(y) - seq_length):
        X.append(y[i:i + seq_length].unsqueeze(-1))  # 输入序列
        Y.append(y[i + seq_length])  # 输出值 (下一个点)
    
    return torch.stack(X), torch.tensor(Y).unsqueeze(-1)
  • 功能:生成带噪声的正弦波序列数据
  • 输入参数:
    • seq_length:输入序列长度
    • num_samples:总样本点数
  • 关键技术:
    • 使用torch.linspace创建均匀分布的时间点
    • 添加高斯噪声增强模型鲁棒性
    • 滑动窗口创建输入-输出对
    • unsqueeze(-1)增加特征维度(1D→2D)
    • torch.stack组合样本为批量张量

2.2 模型定义

class SimpleRNN(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super().__init__()
        self.rnn = nn.RNN(input_size, hidden_size, batch_first=True)
        self.fc = nn.Linear(hidden_size, output_size)
    
    def forward(self, x):
        h0 = torch.zeros(1, x.size(0), hidden_size)
        out, hn = self.rnn(x, h0)
        return self.fc(out[:, -1, :])
  • 结构组成:
    • RNN层:处理序列数据
    • 全连接层:将RNN输出映射为预测值
  • 关键技术:
    • batch_first=True:输入格式为(batch, seq, feature)
    • 隐藏状态初始化为全零
    • out[:, -1, :]只取最后一个时间步的输出

2.3 模型训练

model = SimpleRNN(input_size, hidden_size, output_size)
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

for epoch in range(num_epochs):
    optimizer.zero_grad()
    outputs = model(X)
    loss = criterion(outputs, Y)
    loss.backward()
    optimizer.step()
  • 训练配置:
    • 损失函数:均方误差(MSE),适合回归任务
    • 优化器:Adam,学习率0.001
  • 训练过程:
    • 每个epoch前清零梯度
    • 前向传播计算损失
    • 反向传播更新权重

2.4 结果可视化

# 预测结果对比
plt.plot(Y.numpy(), 'b-', label='真实值')
plt.plot(predictions.numpy(), 'r--', label='预测值')

# 训练损失曲线
plt.plot(losses)
plt.title('训练损失变化')
  • 图表1:真实值与预测值对比
  • 图表2:训练损失变化曲线
  • 中文支持:
    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['axes.unicode_minus'] = False
    
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐