
最近后台收到不少留言都在问时间序列预测到底该用 LSTM 还是 Transformer。这确实是个好问题也是目前论文和工业落地里最容易纠结的地方。这次我们把这两个模型放在一起核心关注点放在三件事模型原理的通俗化拆解、PyTorch 代码怎么一步步复现以及同一份数据上如何公平对比效果。文章会比较长建议直接收藏写代码和跑实验的时候对照着看。这篇文章不是简单搬运论文公式而是按照“论文精读 代码复现 实验验证”的思路来组织。你不需要提前精通数学推导只要会 Python 基础跟着代码走一遍就能把 LSTM 和 Transformer 跑在同一个时间序列数据集上看到它们的预测效果差异。最后我会给出一套通用验证流程方便你迁移到自己的业务数据上。1. 核心能力速览对比项LSTMTransformer模型类型循环神经网络RNN变体自注意力机制Self-Attention核心思想门控机制 记忆单元全局注意力 位置编码擅长场景中短序列、依赖关系较强的局部模式长序列、全局依赖、并行训练训练速度串行计算训练偏慢并行计算训练效率高显存占用相对较低注意力矩阵随序列长度平方增长显存偏高序列长度扩展性一般长序列有梯度问题优秀但需处理注意力复杂度代码复现难度较低中等需理解多头注意力和位置编码推理时延较低视序列长度而定长序列更高是否支持批量任务支持支持适合读者刚入门、想快速跑通时序预测有基础、想解决长序列依赖问题从模型结构来看LSTM 是“按时间一步步往后看”Transformer 是“一次性看完整个序列再找关键信息”。这个本质差异决定了它们在不同数据类型上的表现。实际项目中数据量、序列长度、计算资源和业务解释性需求都会影响最终选择。2. 适用场景与使用边界2.1 适合谁用机器学习初学者LSTM 和 Transformer 是当前时间序列预测领域最常被问到的两个模型搞清楚它们的原理和代码实现后续再看其他变体模型会轻松很多。论文复现需求的同学很多论文会把这两个模型作为 baseline代码复现是跑实验的第一步。工业场景工程师如果涉及销量预测、流量预测、设备指标预测这两个模型是很好的起点模型。考研/面试复习人群Transformer 和 LSTM 都是高频考点动手实现一遍比死记公式更牢固。2.2 能解决什么问题单变量时间序列预测例如预测未来 24 小时的温度。多变量时间序列预测例如根据多个传感器数据预测设备剩余寿命。回归类预测任务例如预测连续数值而非分类标签。长序列建模Transformer 在这类任务上优势明显。2.3 不适合什么场景特征关系极简单、用线性回归就能解决的任务不需要强行上深度模型。训练数据极少例如只有几百条样本神经网络容易过拟合。对可解释性要求极高的金融风控场景纯黑盒预测风险较高。实时流式预测但硬件资源受限LSTM 可以跑Transformer 长序列推理可能撑不住。2.4 合规与安全边界代码复现和实验测试必须在自己的环境或公开数据集上进行。使用任何第三方数据前确认数据来源合法、不涉及个人隐私和商业机密。涉及真实业务预测时模型输出只作为辅助参考不做全自动决策。3. 学习路线与环境准备3.1 你需要具备的基础Python 基础语法函数、类、列表推导式。PyTorch 基础张量操作、nn.Module、DataLoader。简单机器学习概念训练集/测试集划分、损失函数、优化器。不需要数学功底非常扎实但建议了解“梯度下降”的基本含义知道模型是“通过损失函数反向传播更新权重”即可。3.2 环境列表推荐环境配置以实际机器为准环境项推荐配置备注操作系统Windows 10/11、Ubuntu 20.04两种系统均可Python3.9 或 3.10建议用 conda 创建独立环境PyTorch2.xCPU 版本或 CUDA 版本均可CUDA可选若无 NVIDIA 显卡直接用 CPU 版开发工具PyCharm、VS Code、Jupyter Notebook推荐 Notebook 做逐步调试磁盘空间至少 5GB包含数据和依赖包显卡要求无硬性要求有 NVIDIA 显卡训练更快纯 CPU 也能跑小数据3.3 创建虚拟环境conda create -n ts_forecast python3.10 conda activate ts_forecast pip install torch numpy pandas matplotlib scikit-learn没有 conda 的话直接用 python 自带的 venv 也可以python -m venv ts_forecast source ts_forecast/bin/activate # Windows 下是 ts_forecast\Scripts\activate pip install torch numpy pandas matplotlib scikit-learn依赖安装时间取决于网络环境安装完成后可以用下面的命令验证python -c import torch; print(torch.__version__) python -c import pandas; print(pandas.__version__)能正常打印版本号环境就准备好了。4. 数据准备与训练流程搭建4.1 数据来源这里使用公开的 Air Passengers 数据集作为示例。这个数据集包含 1949 到 1960 年每月国际航班乘客数共 144 条数据是时间序列预测最常用的入门数据集。如果你的网络环境下载不便也可以直接构造一个简单的正弦波加噪声的数据集来完成代码验证逻辑是一样的。4.2 加载数据与可视化import pandas as pd import numpy as np import matplotlib.pyplot as plt # 读取数据 df pd.read_csv(AirPassengers.csv, parse_dates[Month], index_colMonth) data df[Passengers].values.astype(np.float32) # 可视化 plt.figure(figsize(10, 4)) plt.plot(data) plt.title(Air Passengers Monthly Data) plt.xlabel(Time) plt.ylabel(Passengers) plt.show()从可视化结果可以直观看到数据存在明显的趋势和季节性周期适合用来验证 LSTM 和 Transformer 对周期模式的捕捉能力。4.3 构造滑窗样本时间序列预测常用“滑动窗口”方式构造样本用过去input_window个时间点的数据预测未来output_window个时间点的数据。def create_sequences(data, input_window, output_window): X, y [], [] for i in range(len(data) - input_window - output_window 1): X.append(data[i : i input_window]) y.append(data[i input_window : i input_window output_window]) return np.array(X), np.array(y) input_window 24 # 用过去 24 个月 output_window 6 # 预测未来 6 个月 X, y create_sequences(data, input_window, output_window) # 划分训练集和测试集 split_ratio 0.8 split_idx int(len(X) * split_ratio) X_train, X_test X[:split_idx], X[split_idx:] y_train, y_test y[:split_idx], y[split_idx:] print(f训练集样本数: {X_train.shape[0]}, 测试集样本数: {X_test.shape[0]})4.4 数据标准化神经网络对数据尺度敏感建议在训练前做标准化。这里用训练集的均值和标准差来转换测试集避免数据泄漏。from sklearn.preprocessing import StandardScaler scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train.reshape(-1, input_window)).reshape(-1, input_window, 1) X_test_scaled scaler.transform(X_test.reshape(-1, input_window)).reshape(-1, input_window, 1) # 注意y 也需要缩放用同一个 scaler 的均值和标准差 y_mean scaler.mean_ y_std scaler.scale_ # 保存训练数据用于后续训练 print(fX_train_scaled shape: {X_train_scaled.shape}) print(fy_train shape: {y_train.shape})这里有一个小细节y的标准化需要使用与X同一组均值和标准差否则还原预测值时会不一致。5. LSTM 模型原理精读与代码复现5.1 LSTM 核心概念LSTMLong Short-Term Memory通过三个门控机制控制信息流动遗忘门决定上一时刻的记忆细胞中有多少信息需要丢弃。输入门决定当前候选状态中有多少新信息写入记忆细胞。输出门决定当前记忆细胞输出给隐藏状态的信息。相比普通 RNNLSTM 的梯度可以沿着记忆细胞传递更远所以它对中长序列的依赖建模更稳定。这也是 LSTM 在时间序列预测中能长期作为 baseline 的原因。5.2 PyTorch 实现 LSTM 预测模型下面是最基础的 LSTM 回归模型定义。num_layers表示堆叠的 LSTM 层数hidden_size表示隐藏单元数量。import torch import torch.nn as nn class LSTMForecast(nn.Module): def __init__(self, input_size1, hidden_size64, num_layers2, output_size6): super(LSTMForecast, self).__init__() self.lstm nn.LSTM( input_sizeinput_size, hidden_sizehidden_size, num_layersnum_layers, batch_firstTrue ) self.regressor nn.Linear(hidden_size, output_size) def forward(self, x): # x shape: (batch, input_window, input_size) out, _ self.lstm(x) # 取最后一个时间步的隐藏状态 last_out out[:, -1, :] y_pred self.regressor(last_out) return y_pred训练时输入x的形状是(batch_size, input_window, 1)输出形状是(batch_size, output_window)。代码简洁关键点就是batch_firstTrue让输入变成(batch, seq_len, features)这一步对初学者非常友好。5.3 训练循环def train_model(model, X_train, y_train, epochs100, lr0.001): optimizer torch.optim.Adam(model.parameters(), lrlr) loss_fn nn.MSELoss() model.train() X_tensor torch.tensor(X_train, dtypetorch.float32) y_tensor torch.tensor(y_train, dtypetorch.float32) for epoch in range(epochs): optimizer.zero_grad() y_pred model(X_tensor) loss loss_fn(y_pred, y_tensor) loss.backward() optimizer.step() if (epoch 1) % 20 0: print(fEpoch {epoch1}/{epochs}, Loss: {loss.item():.6f})model_lstm LSTMForecast(input_size1, hidden_size64, num_layers2, output_sizeoutput_window) train_model(model_lstm, X_train_scaled, y_train, epochs100, lr0.001)不过这里有一个需要注意的地方上面直接对整个训练集做梯度更新数据量小的时候能跑通但数据量大的时候应该用DataLoader配合Mini-batch训练否则内存和显存都会吃紧。后面会补充分批训练版本。5.4 分批训练版本from torch.utils.data import TensorDataset, DataLoader dataset TensorDataset( torch.tensor(X_train_scaled, dtypetorch.float32), torch.tensor(y_train, dtypetorch.float32) ) dataloader DataLoader(dataset, batch_size16, shuffleTrue) def train_model_dataloader(model, dataloader, epochs100, lr0.001): optimizer torch.optim.Adam(model.parameters(), lrlr) loss_fn nn.MSELoss() model.train() for epoch in range(epochs): total_loss 0.0 for X_batch, y_batch in dataloader: optimizer.zero_grad() y_pred model(X_batch) loss loss_fn(y_pred, y_batch) loss.backward() optimizer.step() total_loss loss.item() if (epoch 1) % 20 0: print(fEpoch {epoch1}/{epochs}, Loss: {total_loss / len(dataloader):.6f})6. Transformer 模型原理精读与代码复现6.1 Transformer 核心概念Transformer 不再依赖循环结构而是完全基于自注意力机制。核心组件包括自注意力每个位置都能直接和序列中所有其他位置计算相关性获取全局依赖。多头注意力把注意力计算拆分到多个子空间让模型关注不同维度的关系。位置编码因为注意力机制本身不感知顺序需要给每个位置加上位置信息。前馈网络对每个位置的表示做非线性变换。在时间序列预测中Transformer 可以把整段历史数据传入编码器再由解码器输出未来值。由于它不按时间步串行计算训练时可以并行序列越长优势越明显。6.2 位置编码实现import math def positional_encoding(seq_len, d_model): pe torch.zeros(seq_len, d_model) position torch.arange(0, seq_len, dtypetorch.float32).unsqueeze(1) div_term torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)) pe[:, 0::2] torch.sin(position * div_term) pe[:, 1::2] torch.cos(position * div_term) return pe.unsqueeze(0) # shape: (1, seq_len, d_model)位置编码的作用是给模型提供时间顺序信息。原始 Transformer 用固定三角函数编码后来的改进模型也有可学习位置编码效果因数据集而异。6.3 PyTorch 实现 Transformer 预测模型class TransformerForecast(nn.Module): def __init__(self, input_size1, d_model64, nhead4, num_encoder_layers2, output_size6, dropout0.1): super(TransformerForecast, self).__init__() self.input_proj nn.Linear(input_size, d_model) self.pos_encoder nn.Parameter(positional_encoding(5000, d_model), requires_gradTrue) encoder_layer nn.TransformerEncoderLayer( d_modeld_model, nheadnhead, dim_feedforward128, dropoutdropout, batch_firstTrue ) self.transformer_encoder nn.TransformerEncoder(encoder_layer, num_layersnum_encoder_layers) self.regressor nn.Linear(d_model, output_size) def forward(self, x): # x shape: (batch, seq_len, input_size) x self.input_proj(x) seq_len x.size(1) x x self.pos_encoder[:, :seq_len, :] out self.transformer_encoder(x) out out[:, -1, :] # 取最后一个位置 y_pred self.regressor(out) return y_pred需要留意的是positional_encoding(5000, d_model)里的 5000 只是预设的最大序列长度。如果实际序列超过这个长度需要重新生成位置编码或改成可学习的nn.Parameter初始化。实际使用中可以直接传入一个足够大的值或者动态生成。6.4 训练 Transformermodel_transformer TransformerForecast( input_size1, d_model64, nhead4, num_encoder_layers2, output_sizeoutput_window ) train_model_dataloader(model_transformer, dataloader, epochs100, lr0.001)从代码角度来看Transformer 的模型定义本身并不复杂真正复杂的是理解注意力机制为什么能替代 RNN 完成序列建模。如果第一次接触建议先把nn.TransformerEncoderLayer拆开看了解self_attn、linear1、linear2、norm1、norm2这些子模块各自的作用。7. 效果评估与结果对比7.1 评估函数使用 RMSE 作为评估指标同时把预测值还原到原始数据尺度。def evaluate(model, X_test_scaled, y_test, scaler, output_std): model.eval() X_tensor torch.tensor(X_test_scaled, dtypetorch.float32) with torch.no_grad(): y_pred_scaled model(X_tensor).numpy() # 还原预测值 y_pred y_pred_scaled * output_std scaler.mean_ # 注意这里的还原方式 # 计算 RMSE rmse np.sqrt(np.mean((y_pred - y_test) ** 2)) return y_pred, rmse还原时有个容易出错的地方如果训练时对 X 和 y 用了同一个StandardScaler那么还原 y 时应该使用该 scaler 的mean_和scale_。但如果 X 和 y 的取值范围差异较大更稳妥的做法是分别对 X 和 y 创建独立的 scaler。7.2 测试集预测效果输出from sklearn.metrics import mean_squared_error # LSTM 评估 y_pred_lstm, rmse_lstm evaluate(model_lstm, X_test_scaled, y_test, scaler, y_std) print(fLSTM RMSE: {rmse_lstm:.4f}) # Transformer 评估 y_pred_transformer, rmse_transformer evaluate(model_transformer, X_test_scaled, y_test, scaler, y_std) print(fTransformer RMSE: {rmse_transformer:.4f})结果可视化把测试集的真实值、LSTM 预测值、Transformer 预测值画在同一张图里能非常直观地看到两个模型对趋势和周期波动的拟合程度。plt.figure(figsize(12, 5)) plt.plot(y_test, labelTrue, linewidth2) plt.plot(y_pred_lstm, labelLSTM Predictions) plt.plot(y_pred_transformer, labelTransformer Predictions) plt.legend() plt.title(Test Set Predictions Comparison) plt.show()7.3 不同超参数的影响超参数影响经验值input_window窗口越长模型能看到的上下文越多24、48、72hidden_size隐藏维度越大拟合能力越强但更容易过拟合32、64、128num_layers层数越多模型越深但不一定更准1、2、3d_modelTransformer 的嵌入维度32、64、128nhead注意力头数需要能被 d_model 整除2、4、8batch_size影响训练稳定性和显存占用8、16、32epochs训练轮数过多会过拟合50、100、200从实际测试反馈来看LSTM 在数据量小、序列长度 30 以内时训练快且效果稳定。Transformer 的全局注意力在序列长度较长时优势更明显但需要更多数据来拟合训练时间也更长。8. 资源占用与性能观察8.1 显存占用Transformer 的注意力计算复杂度是 O(n²)n 是序列长度。序列长度从 24 增加到 96显存占用可能明显上升。LSTM 的显存占用主要取决于隐藏层维度和层数与序列长度的关系更温和。建议在训练时通过nvidia-smi观察显存占用变化nvidia-smi -l 1这条命令每秒刷新一次 GPU 使用情况可以看到训练过程中的显存峰值和利用率。8.2 CPU 与 GPU 训练差异小数据集几百到几千条样本CPU 和 GPU 差距不明显。大数据集和长序列场景GPU 的并行计算优势会被放大。没有 NVIDIA GPU 时建议缩小模型规模用 CPU 跑通代码验证逻辑即可。如果你用的是 Apple Silicon 芯片可以尝试pip install torch python -c import torch; print(torch.backends.mps.is_available())输出True说明可以使用 MPS 加速。8.3 降低资源占用的方法减小input_window。减小batch_size。降低hidden_size或d_model。使用混合精度训练。使用梯度累积模拟更大的 batch。在训练代码中加入梯度累积可以降低单个 batch 的显存峰值又不损失太大精度accumulation_steps 4 optimizer.zero_grad() for i, (X_batch, y_batch) in enumerate(dataloader): y_pred model(X_batch) loss loss_fn(y_pred, y_batch) loss loss / accumulation_steps loss.backward() if (i 1) % accumulation_steps 0: optimizer.step() optimizer.zero_grad()9. 常见问题与排查方法问题现象可能原因排查方式解决方案训练 Loss 不下降学习率太大或太小打印每个 epoch 的 Loss尝试 lr0.01、0.001、0.0001预测结果全是一条水平线模型输出被平均化可能输出窗口太长检查最后几层网络输出减小 output_window 或增加模型容量数据标准化后预测值无法还原对 X 和 y 使用了不同 scaler或还原方式错误打印 y_mean 和 y_std统一 scaler或分别定义 y_scalerGPU 显存不足序列太长、batch 太大或模型太大查看显存占用减小 batch_size、缩短输入窗口、加梯度累积模型训练很慢使用了 CPU 且数据集偏大查看 CPU 占用减小数据量或使用 GPU训练集效果很好测试集效果差过拟合对比训练集和测试集 Loss增加 dropout、减小模型、加入正则化Transformer 训练不稳定学习率偏高或位置编码未正确添加观察初始 Loss 是否波动降低 lr、增加 warmup 训练策略Attention 维度不匹配nhead 无法整除 d_model查看报错信息让 d_model % nhead 0数据集有缺失值导致报错数据中存在 NaN检查数据描述用前向填充或插值处理缺失值这里重点说两个高频问题第一个是“预测值整体偏移”通常是标准化还原写错了第二个是“LSTM 比 Transformer 效果好很多”很多时候不是模型本身的问题而是因为数据量太小、序列不够长Transformer 的全局建模优势没有发挥空间。判断一个模型好不好一定要在多个数据集和多个超参数下对比不要只看一次运行的结果。10. 最佳实践与使用建议10.1 代码组织建议建议按模块划分文件方便后续扩展到其他模型ts_project/ ├── data/ │ └── AirPassengers.csv ├── src/ │ ├── dataset.py # 数据加载和窗口构造 │ ├── models.py # LSTM 和 Transformer 定义 │ ├── train.py # 训练和验证逻辑 │ └── evaluate.py # 评估函数 ├── checkpoints/ │ ├── lstm_best.pt │ └── transformer_best.pt ├── outputs/ │ ├── lstm_predictions.csv │ └── transformer_predictions.csv └── README.md10.2 模型保存与加载# 保存 torch.save(model_lstm.state_dict(), checkpoints/lstm_best.pt) # 加载 model_lstm.load_state_dict(torch.load(checkpoints/lstm_best.pt)) model_lstm.eval()10.3 实验记录每次跑实验都要记录数据集名称和样本量。输入窗口和输出窗口。模型结构参数。学习率、batch_size、epochs。最终 RMSE。训练耗时。没有实验记录的模型对比没有任何说服力。建议用wandb或简单的 CSV 文件记录方便回溯。10.4 使用建议第一次跑通时先把input_window12、output_window1这样问题最简单能快速验证代码正确性。再逐步增加窗口长度、隐藏层维度观察训练 Loss 和测试集 RMSE 的变化。如果模型在测试集上表现不佳先检查数据和标准化逻辑再考虑调整模型结构。做真实业务预测时先处理异常值和缺失值再做窗口化。涉及版权或私密数据时使用前必须确认数据来源合法。11. 总结与下一步从原理到代码LSTM 和 Transformer 在时间序列预测上其实是两种完全不同的建模思路。LSTM 靠循环结构逐步传递信息适合中短序列和局部依赖明显的场景代码简单、调试容易Transformer 靠自注意力机制建模全局依赖适合长序列和数据量较大的场景但训练时需要更注意显存和超参设置。这篇文章最值得直接上手的部分是第 4、5、6 节中的代码框架。建议你先用 Air Passengers 数据集跑通流程然后把create_sequences和evaluate两个函数直接迁移到自己的数据上。最容易踩的坑是数据标准化还原错误其次是超参数设置。注意看预测值是否出现“平移偏移”一旦出现优先检查还原逻辑。后续可以继续扩展的方向包括把 LSTM 和 Transformer 混合使用例如用 LSTM 提取局部特征再输入 Transformer引入注意力机制的可解释性分析尝试最新的 PatchTST、Informer 等改进模型把模型导出成 ONNX 部署到生产环境。希望这篇 LSTM 和 Transformer 时间序列预测模型的精读与复现文章能帮你省下找代码的时间顺手把原理也一并理清。