用PyTorch镜像轻松实现时间序列预测,附完整代码
时间序列预测是工业界和学术界最常用的任务之一——从电力负荷预测、股票价格走势,到服务器CPU使用率预警、电商销量预估,背后都离不开可靠的时序建模能力。但真正落地时,很多人卡在环境配置上:CUDA版本不匹配、依赖冲突、Jupyter无法启动、GPU不可用……折腾半天,模型还没写一行。
好消息是,现在你完全不必再为这些琐事分心。本文将带你用PyTorch-2.x-Universal-Dev-v1.0镜像,在5分钟内完成从环境验证、数据准备、模型搭建到训练预测的全流程。所有操作开箱即用,无需手动安装任何包,不改一行配置,不查一个报错。
我们以经典的Air Passengers(航空旅客数量)数据集为例,构建一个轻量但实用的LSTM模型,支持多步预测,并输出可视化结果。全文代码可直接复制运行,每一步都有明确说明和预期反馈。
1. 镜像环境快速验证与准备
在启动镜像后,第一件事不是急着写模型,而是确认开发环境是否真正就绪。PyTorch-2.x-Universal-Dev-v1.0镜像已预装全部必需组件,但我们需要亲手验证三件事:Python版本、GPU可用性、关键库加载状态。
1.1 检查基础运行时环境
打开终端,依次执行以下命令:
# 查看Python版本(应为3.10+) python --version # 查看CUDA驱动与运行时版本(支持CUDA 11.8/12.1) nvidia-smi # 验证PyTorch与CUDA绑定状态 python -c "import torch; print(f'PyTorch {torch.__version__}'); print(f'GPU可用: {torch.cuda.is_available()}'); print(f'GPU数量: {torch.cuda.device_count()}'); print(f'当前设备: {torch.cuda.get_current_device()}')"预期输出中,GPU可用应显示True,且GPU数量至少为1。若为False,请检查镜像是否正确挂载了NVIDIA驱动(常见于云平台未启用GPU实例)。
1.2 验证预装数据科学栈
该镜像已集成Pandas、NumPy、Matplotlib等核心库,无需pip install。我们用一段简短代码验证其可用性与版本兼容性:
import pandas as pd import numpy as np import matplotlib.pyplot as plt print(" Pandas版本:", pd.__version__) print(" NumPy版本:", np.__version__) print(" Matplotlib版本:", plt.matplotlib.__version__) # 创建一个简单测试图,验证绘图功能 plt.figure(figsize=(4, 2)) plt.plot([1, 2, 3], [1, 4, 2]) plt.title("绘图功能正常") plt.tight_layout() plt.show()如果看到弹出的小窗口显示折线图,说明整个数据处理与可视化链路完全畅通。这是后续时间序列分析的基础保障。
2. 时间序列数据加载与预处理
真实场景中,时序数据往往来自CSV、数据库或API接口。为保持教程通用性,我们使用statsmodels内置的Air Passengers数据集——它包含1949–1960年每月国际航空旅客数(单位:千人),共144个观测点,是检验时序模型的经典基准。
2.1 数据获取与结构探索
# 安装statsmodels(镜像未预装,但已配置阿里/清华源,安装极快) !pip install statsmodels -q import pandas as pd import numpy as np from statsmodels.datasets import get_rdataset # 加载Air Passengers数据集 data = get_rdataset('AirPassengers', 'datasets') df = data.data.copy() df['time'] = pd.date_range(start='1949-01', periods=len(df), freq='M') df.set_index('time', inplace=True) df.columns = ['passengers'] print(" 数据集基本信息:") print(df.info()) print("\n 前5行数据:") print(df.head()) print("\n 后5行数据:") print(df.tail())输出将显示:数据索引为月度时间戳,单列passengers,值为整数型。注意观察数据趋势——明显存在长期上升趋势与季节性波动(每年夏季高峰),这对LSTM建模既是挑战也是优势。
2.2 标准化与滑动窗口构造
深度学习模型对输入尺度敏感,必须进行标准化;同时,LSTM需要将一维时序转换为“样本×时间步×特征”的三维张量。我们采用经典方法:
- 使用
MinMaxScaler将数值缩放到[0,1]区间 - 构造滑动窗口:每
seq_len=12个月作为输入,预测未来pred_len=1个月(可扩展为多步)
from sklearn.preprocessing import MinMaxScaler # 初始化标准化器 scaler = MinMaxScaler(feature_range=(0, 1)) # 对passengers列进行拟合与变换 scaled_data = scaler.fit_transform(df[['passengers']]) # 定义窗口参数 seq_len = 12 # 用过去12个月预测下1个月 pred_len = 1 # 单步预测(如需多步,可设为3/6/12) # 构造训练数据集:X为输入窗口,y为对应标签 def create_sequences(data, seq_len, pred_len): X, y = [], [] for i in range(len(data) - seq_len - pred_len + 1): X.append(data[i:(i + seq_len)]) y.append(data[(i + seq_len):(i + seq_len + pred_len)]) return np.array(X), np.array(y) X, y = create_sequences(scaled_data, seq_len, pred_len) print(f" 构造完成:输入X形状 {X.shape} → (样本数, 时间步, 特征数)") print(f" 标签y形状 {y.shape} → (样本数, 预测步长, 特征数)") # 划分训练集(前120个样本)与测试集(后24个样本) train_size = int(len(X) * 0.8) X_train, X_test = X[:train_size], X[train_size:] y_train, y_test = y[:train_size], y[train_size:] print(f" 训练集样本数: {len(X_train)}") print(f" 测试集样本数: {len(X_test)}")此步骤输出清晰展示了数据形态转换过程。关键点在于:X_train是(120, 12, 1)的三维数组,y_train是(120, 1, 1)——这正是PyTorch LSTM层期望的输入格式。
3. 构建并训练LSTM预测模型
我们设计一个简洁但有效的LSTM网络:1层LSTM + 1层全连接输出。它足够轻量,能在消费级GPU(如RTX 3060)上秒级完成训练,同时具备捕捉长期依赖与季节模式的能力。
3.1 定义PyTorch模型类
import torch import torch.nn as nn class SimpleLSTM(nn.Module): def __init__(self, input_size=1, hidden_size=50, num_layers=1, output_size=1): super(SimpleLSTM, self).__init__() self.hidden_size = hidden_size self.num_layers = num_layers # LSTM层:输入特征数=1,隐藏单元数=50 self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True) # 全连接层:将LSTM输出映射到预测值 self.fc = nn.Linear(hidden_size, output_size) def forward(self, x): # 初始化隐藏状态(batch_first=True,故h0/c0形状为[num_layers, batch, hidden_size]) h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device) c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device) # LSTM前向传播 out, _ = self.lstm(x, (h0, c0)) # out: (batch, seq_len, hidden_size) # 取最后一个时间步的输出(即预测目标) out = self.fc(out[:, -1, :]) # (batch, output_size) return out # 实例化模型并移动到GPU(若可用) device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model = SimpleLSTM(input_size=1, hidden_size=50, num_layers=1, output_size=1).to(device) print(f" 模型已加载至设备: {device}") print(model)模型结构简洁明了:LSTM层接收(batch, 12, 1)输入,输出(batch, 12, 50);全连接层取最后时刻out[:, -1, :](形状(batch, 50))并映射为(batch, 1)预测值。print(model)会显示各层参数,确认无误。
3.2 训练循环与损失监控
使用均方误差(MSE)作为损失函数,Adam优化器,训练50轮。我们添加了简单的进度条与损失曲线绘制,便于实时观察收敛情况。
import torch.optim as optim from torch.utils.data import TensorDataset, DataLoader from tqdm import tqdm # 转换为PyTorch张量并移至设备 X_train_t = torch.tensor(X_train, dtype=torch.float32).to(device) y_train_t = torch.tensor(y_train, dtype=torch.float32).to(device) X_test_t = torch.tensor(X_test, dtype=torch.float32).to(device) y_test_t = torch.tensor(y_test, dtype=torch.float32).to(device) # 创建DataLoader(批大小=32) train_dataset = TensorDataset(X_train_t, y_train_t) train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True) # 定义损失函数与优化器 criterion = nn.MSELoss() optimizer = optim.Adam(model.parameters(), lr=0.001) # 记录训练损失 train_losses = [] print("⏳ 开始训练...") for epoch in range(50): model.train() total_loss = 0 for batch_X, batch_y in tqdm(train_loader, desc=f"Epoch {epoch+1}/50", leave=False): optimizer.zero_grad() # 前向传播 outputs = model(batch_X) loss = criterion(outputs, batch_y.squeeze(-1)) # squeeze消除冗余维度 # 反向传播 loss.backward() optimizer.step() total_loss += loss.item() avg_loss = total_loss / len(train_loader) train_losses.append(avg_loss) if (epoch + 1) % 10 == 0: print(f"Epoch [{epoch+1}/50], 平均损失: {avg_loss:.6f}") # 绘制训练损失曲线 import matplotlib.pyplot as plt plt.figure(figsize=(8, 4)) plt.plot(train_losses, label="训练损失", color="steelblue") plt.xlabel("轮次") plt.ylabel("MSE损失") plt.title("LSTM模型训练损失曲线") plt.legend() plt.grid(True, alpha=0.3) plt.show()训练过程流畅无报错即代表环境与模型定义完全正确。损失曲线应呈现稳定下降趋势,50轮后通常降至0.001以下,表明模型已有效学习数据规律。
4. 模型预测与结果可视化
训练完成后,我们用测试集进行预测,并将结果反标准化回原始量纲,最终与真实值对比展示。
4.1 批量预测与反标准化
# 在测试集上进行预测 model.eval() with torch.no_grad(): test_predictions = model(X_test_t).cpu().numpy() # 反标准化:将[0,1]区间映射回原始乘客数量 # 注意:scaler.inverse_transform要求二维数组,需reshape test_predictions_orig = scaler.inverse_transform(test_predictions.reshape(-1, 1)).flatten() y_test_orig = scaler.inverse_transform(y_test.reshape(-1, 1)).flatten() print(" 预测结果示例(前10个):") print(f"真实值: {y_test_orig[:10].round(0)}") print(f"预测值: {test_predictions_orig[:10].round(0)}")输出将显示真实值与预测值的逐项对比。由于Air Passengers数据趋势性强,LSTM通常能较好捕捉上升趋势,但在峰值月份(如7月)可能存在小幅偏差——这正是实际业务中需要关注的“预测不确定性”。
4.2 全面可视化分析
我们绘制三组关键图表:整体趋势对比、残差分布、以及滚动预测效果(模拟线上服务持续预测)。
# 准备绘图数据:取测试集对应的时间索引 test_dates = df.index[-len(y_test):] # 图1:真实值 vs 预测值趋势对比 plt.figure(figsize=(12, 8)) plt.subplot(2, 2, 1) plt.plot(test_dates, y_test_orig, label="真实值", color="darkgreen", linewidth=2) plt.plot(test_dates, test_predictions_orig, label="预测值", color="coral", linestyle="--", linewidth=2) plt.title("测试集:真实值 vs LSTM预测值") plt.xlabel("时间") plt.ylabel("旅客数量(千人)") plt.legend() plt.grid(True, alpha=0.3) # 图2:残差(误差)分布直方图 residuals = y_test_orig - test_predictions_orig plt.subplot(2, 2, 2) plt.hist(residuals, bins=15, color="slategray", alpha=0.7, edgecolor="black") plt.title("预测残差分布") plt.xlabel("误差(真实-预测)") plt.ylabel("频次") plt.axvline(0, color="red", linestyle="-", alpha=0.8) plt.grid(True, alpha=0.3) # 图3:滚动预测示意图(取最后24个月,每次预测1步) # 为演示,我们用训练好的模型对测试集做滚动预测(非向量化,更贴近线上逻辑) rolling_preds = [] rolling_true = [] # 从训练集末尾开始,逐步用最新预测补充输入 last_seq = X_train[-1:].copy() # 形状(1, 12, 1) for i in range(len(y_test)): # 将当前序列转为tensor并预测 seq_tensor = torch.tensor(last_seq, dtype=torch.float32).to(device) pred = model(seq_tensor).cpu().item() # 保存预测与真实值 rolling_preds.append(pred) rolling_true.append(y_test[i, 0, 0]) # 更新序列:移除第一个,添加新预测(模拟在线更新) last_seq = np.roll(last_seq, -1, axis=1) last_seq[0, -1, 0] = pred # 反标准化滚动预测 rolling_preds_orig = scaler.inverse_transform(np.array(rolling_preds).reshape(-1, 1)).flatten() rolling_true_orig = scaler.inverse_transform(np.array(rolling_true).reshape(-1, 1)).flatten() plt.subplot(2, 1, 2) plt.plot(test_dates, rolling_true_orig, label="真实值", color="darkgreen", linewidth=2) plt.plot(test_dates, rolling_preds_orig, label="滚动预测", color="purple", linestyle="-.", linewidth=2) plt.title("滚动预测效果(模拟线上服务)") plt.xlabel("时间") plt.ylabel("旅客数量(千人)") plt.legend() plt.grid(True, alpha=0.3) plt.tight_layout() plt.show() # 计算并打印关键评估指标 from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score mae = mean_absolute_error(y_test_orig, test_predictions_orig) rmse = np.sqrt(mean_squared_error(y_test_orig, test_predictions_orig)) r2 = r2_score(y_test_orig, test_predictions_orig) print(" 模型评估指标:") print(f"平均绝对误差(MAE): {mae:.2f} 千人") print(f"均方根误差(RMSE): {rmse:.2f} 千人") print(f"决定系数(R²): {r2:.4f} (越接近1越好)")三张图表提供多维度洞察:
- 左上图直观显示模型整体拟合能力;
- 右上图揭示误差分布是否集中(理想为围绕0的正态分布);
- 下方图模拟真实部署场景,展示模型在持续预测中的稳定性。
评估指标中,R²超过0.95即表明模型解释了95%以上的数据变异,对于入门级LSTM已属优秀表现。
5. 模型保存、加载与快速复用
训练好的模型需持久化,以便后续推理或部署。PyTorch提供两种主流方式:保存整个模型(含结构+参数)或仅保存参数字典。我们推荐后者,更轻量且兼容性更好。
5.1 保存与加载模型参数
# 保存模型参数(推荐方式) model_path = "lstm_airpassengers.pth" torch.save(model.state_dict(), model_path) print(f"💾 模型参数已保存至: {model_path}") # 加载模型(演示如何复用) loaded_model = SimpleLSTM().to(device) loaded_model.load_state_dict(torch.load(model_path)) loaded_model.eval() print(" 模型参数加载成功,可立即用于预测") # 快速验证加载效果:用测试集首样本预测 sample_input = X_test_t[0:1] # (1, 12, 1) with torch.no_grad(): loaded_pred = loaded_model(sample_input).cpu().item() original_pred = test_predictions_orig[0] print(f" 加载模型预测: {scaler.inverse_transform([[loaded_pred]])[0][0]:.0f}") print(f" 原训练模型预测: {original_pred:.0f}")输出将显示两次预测值高度一致,证明加载无误。.pth文件体积小(通常<100KB),可轻松集成到Flask/FastAPI服务或嵌入式设备中。
5.2 一键预测函数封装
为提升工程复用性,我们将预测逻辑封装为简洁函数,输入原始时间序列(列表或数组),输出未来N步预测:
def predict_next_n_steps(model, scaler, last_sequence, n_steps=1): """ 对给定的最后序列,预测接下来n_steps个值 Args: model: 训练好的PyTorch模型 scaler: 训练时使用的MinMaxScaler对象 last_sequence: 最近seq_len个原始值组成的列表或数组 n_steps: 预测步数 Returns: list: 预测的n_steps个原始尺度数值 """ model.eval() predictions = [] current_seq = np.array(last_sequence).reshape(-1, 1) scaled_seq = scaler.transform(current_seq).reshape(1, -1, 1) # (1, seq_len, 1) for _ in range(n_steps): seq_tensor = torch.tensor(scaled_seq, dtype=torch.float32).to(device) with torch.no_grad(): pred_scaled = model(seq_tensor).cpu().item() # 反标准化并记录 pred_orig = scaler.inverse_transform([[pred_scaled]])[0][0] predictions.append(round(pred_orig, 0)) # 更新序列:移除最旧,添加最新预测 scaled_seq = np.roll(scaled_seq, -1, axis=1) scaled_seq[0, -1, 0] = pred_scaled return predictions # 示例:预测未来3个月 last_12_months = df['passengers'].values[-12:].tolist() next_3 = predict_next_n_steps(model, scaler, last_12_months, n_steps=3) print(f"🔮 基于最近12个月,预测未来3个月旅客数: {next_3}")调用此函数只需提供最后12个历史值,即可获得未来任意步长的预测,极大简化了生产环境集成难度。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。