【深度学习 Pytorch系列课程】pytorch 常见模型分类之循环神经网络 RNN正弦波预测
·
1. 代码整体概述
这是一个完整的时间序列预测入门示例,展示了PyTorch实现RNN的核心流程,适合作为时序预测任务的基础模板。
- 生成带噪声的正弦波序列数据
- 定义简单的RNN模型结构
- 训练模型预测下一个时间步的值
- 可视化预测结果和训练过程
完整代码
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
更多推荐
所有评论(0)