1. 需求预测建模:为什么我推荐双向LSTM
做需求预测的人应该都有体会,这类问题看着简单,真正落地时全是坑。我早些年用传统时间序列模型做预测,ARIMA、指数平滑这些挨个试了个遍,遇到稍微有点波动性的数据就开始拉胯,更别提在电商促销、节假日这类场景下,需求曲线被外部因素反复冲击,滞后性非常明显。后来切到LSTM,效果提升了不少,但单方向的LSTM结构上天然有个局限——它只按时间正向读取数据,而实际业务里的需求变化往往受“前因”和“后果”共同影响。举个最简单的例子,某个商品今天的销量骤降,如果只看过去几天的序列,模型可能会判断是正常波动;但如果你告诉它“后天有大型促销,大家都在等折扣”,它才会意识到今天的下降是大促前的蓄水行为。问题是,LSTM在t时刻根本看不到t+1之后的信息。
这就是我转向双向LSTM的核心原因。双向结构在原有LSTM基础上增加了一条反向传播的时间路径,让每个时间步同时拥有过去和未来的上下文信息。在Matlab里搭建这套模型,不需要写一堆底层的前向反向传播代码,直接用Deep Learning Toolbox就能搞定。而且Matlab的LSTM层和bilstmLayer接口设计得比较友好,搭配数据标准化和自定义训练选项,能快速完成模型训练、预测、误差输出这一整套流程。
如果你还在用单步LSTM做需求预测,我建议你试试这个思路。这篇文章我不会只给你贴一段能跑的代码,而是会把整个建模流程拆开讲透,包括数据怎么划分、训练集结果和误差怎么可视化、测试集结果怎么对比、哪些环节特别容易踩坑。项目代码我已经跑通了,你可以直接参考复现。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 整体设计思路:从需求场景到模型选型
2.1 需求预测的场景建模:不是所有数据都适合双向LSTM
在动手写代码之前,先把问题定义清楚。需求预测本质上是一个序列回归问题,输入是过去几个周期的需求量(比如过去14天的餐厅菜量需求),输出是未来一个或多个周期的预测量。这个任务天然适合用LSTM系模型处理,因为它需要捕捉时间依赖关系,而且需求数据通常是非平稳的、有周期性的,甚至带有突发性波动。
但双向LSTM不是万能的,它最适合的是“历史信息与未来信息都很重要”的序列任务。在需求预测这种场景里,双向LSTM之所以有一定优势,是因为它能把整个输入序列的上下文压缩到每个时间步的隐藏状态中,相当于模型在预测第t个时间点的需求时,不仅知道前面发生了什么事,还知道这个时间点在整段序列中处于什么位置、后续趋势大致朝哪个方向走。这在某种程度上缓解了单一LSTM只看历史不看全局的问题。
不过也要说清楚,双向LSTM的计算量是单向的两倍,因为每个时间步要跑两个方向的隐藏层。如果数据集特别长、特征维度高,训练时间会明显增加。我做这个项目时用的数据量不大,大概500个样本、窗口长度20个时间步,Matlab在普通笔记本CPU上跑,几轮epoch也就几分钟,完全在可接受范围。如果你的数据量特别大,比如几百万条日志级别,建议先做降采样或者改用分布式训练。
2.2 构建思路拆解:训练集结果、训练集误差、测试集结果、测试集误差四件套
很多初学者做预测模型时只关心测试集的误差,训练集误差和结果基本不看。这其实是危险的。训练集上的拟合效果直接反映了模型容量是否充足、训练是否收敛、有没有欠拟合或过拟合的苗头。我在这篇项目里的做法是:训练完成后,分别输出训练集和测试集的预测结果,并对应计算误差指标,最后画成四张图放在一起对比。这样一眼就能看出模型在训练集上拟合到什么程度、在测试集上泛化到什么水平,以及两者之间的差距是合理还是异常。
训练集结果的输出方式不只是在训练过程中打印loss曲线,而是要在训练结束后,把训练集的输入重新喂给模型,得到模型对训练数据的拟合值,再和真实值做对比。测试集同理。这里的误差既指逐时间点的绝对差值,也指统计指标,包括均方误差(MSE)、均方根误差(RMSE)、平均绝对误差(MAE)、平均绝对百分比误差(MAPE)等。
我采用的通用流程是:
- 加载原始需求数据,按时间顺序排列。
- 划分训练集和测试集,比例一般取80%和20%。
- 对数据进行标准化,注意只用训练集的均值和标准差去标准化训练集和测试集,不能用全局统计量。
- 构造训练输入输出对(滑窗方式,把连续长度为windowSize的历史数据映射为下一个值)。
- 定义双向LSTM网络结构。
- 设置训练选项,开始训练。
- 把训练集输入喂回模型得到训练集预测值,反标准化后计算误差。
- 把测试集输入喂给模型得到测试集预测值,反标准化后计算误差。
- 绘图展示四种结果,并输出误差表格。
这套流程看起来不复杂,实际运行时的坑主要在数据格式、标准化细节和参数调试上,后面我会逐个说明。
3. 环境准备与数据预处理:Matlab工具箱配置和数据处理细节
3.1 Matlab环境要求与工具箱检查
项目基于Matlab实现,主要依赖Deep Learning Toolbox。建议版本在R2020a以上,因为bilstmLayer在不同版本间的Name-Value对参数有一些细微变化,老版本可能缺少某些设置项(比如SequencePaddingDirection在旧版里叫法不同)。可以用ver命令检查工具箱是否正常安装:
matlab复制ver('deep')
如果输出里没有Deep Learning Toolbox相关的版本信息,说明需要先安装。Matlab安装工具箱通常是重新运行安装程序或者通过Add-On Explorer添加。顺带提一句,我踩过一个坑:有些轻量安装版的Matlab不包含深度学习工具箱,训练时调用trainNetwork会直接报错“Undefined function 'trainNetwork'”,这多半就是工具箱缺失。遇到这种问题先别怀疑代码,去检查环境。
另外建议安装Parallel Computing Toolbox。这个工具箱不是必须的,但在训练选项里设置'ExecutionEnvironment','auto'时,如果检测到GPU,会自动用GPU加速;没有它也能正常跑CPU模式。我实测下来,小型需求预测数据用CPU就够,没必要纠结GPU。
3.2 数据划分与标准化:80%训练、20%测试到底怎么切
数据划分是需求预测里最容易被做错的一步。时间序列数据切分和普通机器学习不一样,不能随机打乱再切,必须保持时间顺序。也就是说,假设有1000天的需求量,前800天作为训练集,后200天作为测试集。为什么不能随机切?因为时序数据有自相关性,如果用第500天前后的数据训练、用中间某段测试,模型等于“偷看”了未来的信息,测试集误差会虚低,实际部署时完全不具备参考价值。
我在项目里用的是比例划分法。这里为了演示方便,先模拟生成了一条带有趋势、周期和随机噪声的需求序列,长度设置为500个时间点,前80%也就是400个点做训练集,后100个点做测试集。
数
