
简介这份资源提供了一套基于1D CNN与LSTM组合结构的高速公路短时交通流预测完整Python实现面向具备一定深度学习基础、关注智能交通与时空序列建模的开发者与研究人员可用于学习如何同时提取交通流的空间特征与时间特征。压缩包共21个文件约31MB包含7个py脚本、6个h5模型权重、4个json模型结构配置、2张png结构示意图及说明文档覆盖数据预处理、模型训练、超参数搜索与多模型对比等环节。数据侧包含车站各站点一个半小时内的交通流txt记录并给出采集、归一化与时间顺序处理流程脚本cnn_lstm_param.py支持超参数搜索运行前需安装hyperas。目前已有5334人学习下载读者可据此复现CNNLSTM预测流程理解模型保存与对比思路并借助目录结构快速定位训练、评估与调参代码适合作为交通流预测课题的实践参考。1. 高速流量预测的 LCTFP 模型一份能直接跑的 Python 代码包高速路网的短时流量预测难在既要抓空间上的车道耦合又要抓时间上的周期依赖。单用 LSTM 容易漏掉相邻检测器之间的相互影响单用 CNN 又抓不住时序上的滞后效应。LCTFP 这份代码包走的是 1D CNN LSTM 的串行组合路线先用一维卷积在时间窗口上提取局部空间特征再把特征序列喂给 LSTM 学时间依赖最后接全连接层输出未来时段的流量值。包里带了 PeMS 数据集、预处理脚本、三套对比模型CNN、LSTM、CNN-LSTM以及训练好的权重文件适合做交通流预测的毕设、课程设计或者想拿真实路网数据练手 CNN 与 LSTM 组合建模的 Python 开发者。下面按「数据怎么进、模型怎么搭、参数怎么调、坑在哪」的顺序拆一遍。2. 数据管道拆解从 PEMS.zip 到可训练的时序张量2.1 原始数据长什么样为什么不能直接喂模型PeMS 是加州高速路网检测器采集的交通数据包里PEMS.zip解压后是一批按检测器、按时间戳组织的流量记录。原始数据有三个绕不开的问题不同检测器的采样周期不完全对齐、流量值量纲差异大、缺失值以各种形式混在记录里。直接把这些记录堆成矩阵丢进网络梯度会被大量级样本带偏收敛基本靠运气。data_preprocess.py干的就是把这些脏数据整理成模型能吃的形状。常见做法是先把每个检测器的时间序列按统一时间粒度重采样再做归一化最后滑窗切成(样本数, 时间步长, 特征数)的三维张量。这个形状是 1D CNN 和 LSTM 都能直接接收的格式也是后面所有模型共享的输入。2.2 预处理脚本的关键步骤与参数# data_preprocess.py 核心逻辑按包内结构整理 import numpy as np import pandas as pd def load_and_clean(path): df pd.read_csv(path) # 缺失值用前向填充交通流短时连续性强插值比均值填充更合理 df df.fillna(methodffill).fillna(methodbfill) return df def normalize(data): # 最大最小归一化把流量压到 [0,1]避免量纲主导梯度 return (data - data.min()) / (data.max() - data.min() 1e-8) def make_windows(series, step12, horizon1): X, y [], [] for i in range(len(series) - step - horizon 1): X.append(series[i:istep]) y.append(series[istep:istephorizon]) return np.array(X), np.array(y)step12表示用过去 12 个时间步预测未来horizon1表示预测下一个时间步。这两个参数直接决定样本量和预测难度step 太小模型看不到周期太大则样本数骤减。归一化用 min-max 而不是 z-score是因为流量分布右偏min-max 对极值更稳。填充用前向后向组合比直接丢缺失行保留更多有效样本。2.3 训练集与验证集的切分方式时序数据不能随机打乱切分否则会把未来信息泄漏进训练集。包里input_data.py按时间顺序切分前 80% 做训练、后 20% 做验证。这个比例不是硬规定数据量大可以调到 90/10数据少就 70/30。切分后要检查验证集的流量分布是否和训练集接近如果验证集全落在高峰段评估指标会失真。提示切分前先画一遍整条序列的流量曲线确认没有大段缺失或异常跳变否则后面调参全是白费功夫。3. CNN-LSTM 模型搭建1D 卷积怎么接 LSTM3.1 为什么是 1D CNN 而不是 2D交通流是典型的一维时序信号1D 卷积核在时间轴上滑动提取的是局部时段内的变化模式比如早高峰的爬升段、午间的平稳段。2D 卷积适合图像那种空间二维结构用在时序上反而引入无意义的维度。cnn_lstm_final.py里卷积层用Conv1D卷积核沿时间方向滑动这一步的输出是一组特征图每个特征图代表某种局部时间模式的响应强度。3.2 模型结构逐层说明# cnn_lstm_final.py 模型主体按包内结构整理 from tensorflow.keras import layers, models def build_cnn_lstm(step, feat): model models.Sequential() # 第一层 1D 卷积64 个卷积核核宽 3提取局部时间特征 model.add(layers.Conv1D(filters64, kernel_size3, activationrelu, input_shape(step, feat), paddingsame)) model.add(layers.MaxPooling1D(pool_size2)) # 第二层卷积加深特征提取 model.add(layers.Conv1D(filters32, kernel_size3, activationrelu, paddingsame)) # LSTM 学时间依赖50 个隐藏单元 model.add(layers.LSTM(50, return_sequencesFalse)) model.add(layers.Dropout(0.2)) model.add(layers.Dense(1)) model.compile(optimizeradam, lossmse) return modelfilters64是第一层卷积核数量核越多特征越丰富但计算量上升kernel_size3表示每次看 3 个连续时间步这个值一般取 3 到 5太大就失去局部性。paddingsame保证卷积后时间维度不变方便接池化。MaxPooling1D(pool_size2)把时间步减半降低 LSTM 的输入长度减少计算量。LSTM 的return_sequencesFalse表示只取最后一个时间步的输出因为这里做的是单点预测而不是序列到序列。Dropout(0.2)防过拟合数据量小可以调到 0.3。3.3 训练脚本与回调配置# 训练入口按包内结构整理 from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint model build_cnn_lstm(step12, feat1) callbacks [ EarlyStopping(monitorval_loss, patience10, restore_best_weightsTrue), ModelCheckpoint(Model/cnn_lstm_best.h5, monitorval_loss, save_best_onlyTrue) ] history model.fit(X_train, y_train, validation_data(X_val, y_val), epochs100, batch_size64, callbackscallbacks)EarlyStopping的patience10表示验证损失连续 10 轮不降就停避免无效训练。restore_best_weightsTrue是关键它保证训练结束后模型回到验证损失最低的那一版而不是最后一版。batch_size64是常见起点显存够可以加到 128数据少就降到 32。ModelCheckpoint把最优权重存成cnn_lstm_best.h5后面compare.py做模型对比时直接加载这个文件。4. 超参数搜索与三模型对比cnn_lstm_param.py 怎么用4.1 hyperas 超参数搜索的接入方式cnn_lstm_param.py依赖 hyperas它是对 hyperopt 的封装能在 Keras 模型上做随机搜索或贝叶斯搜索。安装方式是pip install hyperas hyperopt。脚本里把卷积核数量、LSTM 单元数、学习率等写成搜索空间跑一轮会尝试多组组合并返回验证损失最低的那组。# cnn_lstm_param.py 搜索空间片段按包内结构整理 from hyperas.distributions import choice, uniform def create_model(X_train, Y_train, X_test, Y_test): model models.Sequential() model.add(layers.Conv1D(filters{{choice([32, 64, 128])}}, kernel_size{{choice([3, 5])}}, activationrelu, input_shape(step, feat))) model.add(layers.LSTM({{choice([32, 50, 100])}})) model.add(layers.Dense(1)) model.compile(optimizer{{choice([adam, rmsprop])}}, lossmse) # ... 训练与评估搜索空间不要开太大filters三档、kernel_size两档、LSTM三档组合起来已经 18 种每种跑一遍训练时间不短。常见做法是先粗搜一轮缩小范围再在最优附近细搜。搜索过程中每次试验都重新初始化权重所以结果有随机性建议对同一组配置跑 2 到 3 次取平均。4.2 compare.py 的对比逻辑与指标解读compare.py加载Model/目录下的cnn.h5、lstm.h5、cnn_lstm_best.h5在同一验证集上算指标。包里images/threemodels.png就是三模型对比图。对比时要注意三个模型必须用同一份验证数据、同一个归一化参数否则指标不可比。常见指标是 MAE、RMSE、MAPE交通流预测里 MAPE 对低流量时段敏感容易虚高建议以 MAE 为主、RMSE 为辅。模型结构特点适用场景CNN只提局部时间特征流量平稳、周期弱的短时预测LSTM只学时间依赖单检测器、无空间耦合的场景CNN-LSTM先卷积再 LSTM多检测器、有明显时空耦合的路网4.3 训练结果文件怎么读Model/目录下有两类文件.h5是权重.json是模型结构。cnn_lstm_final.json配cnn_lstm_final.h5可以完整还原模型cnn_lstm_best.h5是早停保存的最优权重。加载时先读 json 建结构再 load_weights不要直接用load_model读 json那是两种不同格式。sae.py和sae.json、sae.h5是包里附带的另一个自编码器相关脚本和主预测流程独立想跑得单独看它的输入要求。5. 避坑与排查跑这份代码最容易翻车的五个地方5.1 现象训练损失不降一直卡在高位原因通常是归一化没做对或者输入张量形状和模型期望的不一致。Conv1D要求输入是(batch, steps, channels)如果预处理出来是(batch, channels, steps)卷积会在错误维度上滑动学不到东西。解决在input_data.py里打印X_train.shape确认第二维是时间步、第三维是特征数不对就np.transpose调过来。5.2 现象验证损失震荡剧烈指标忽好忽坏原因一般是 batch_size 太小或学习率偏高。交通流数据噪声大小 batch 会让梯度方向抖动。解决把 batch_size 从 32 提到 64 或 128学习率从默认 0.001 降到 0.0005再观察几个 epoch。如果还震荡检查验证集切分是否混入了异常段。5.3 现象hyperas 搜索报错找不到 hyperopt原因hyperas 依赖 hyperopt但两者版本不匹配时会报导入错误。解决先pip install hyperopt再pip install hyperas不要只装 hyperas。如果还报错检查 Python 版本hyperopt 对较新的 Python 版本支持有滞后必要时用 3.8 到 3.10 的环境。5.4 现象加载 .h5 权重报形状不匹配原因模型结构 json 和权重文件不是同一次训练产出的或者中途改过网络层。解决确认cnn_lstm_final.json和cnn_lstm_final.h5是配套的cnn_lstm_best.h5只配cnn_lstm.json的结构。改过网络层后必须重新训练不能复用旧权重。5.5 现象预测值全落在同一水平线原因模型退化成只输出均值通常是 LSTM 层数太多或 Dropout 太高导致欠拟合。解决先减一层 LSTM把 Dropout 从 0.3 降到 0.1再跑一轮。如果还是平的检查标签 y 是不是被错误地归一化成了常数。6. 进阶技巧把单点预测改成多步预测并验证单点预测只输出下一个时间步实际调度更关心未来一段时间的流量走势。把Dense(1)改成Dense(horizon)同时把make_windows里的horizon从 1 调到 3 或 6就能一次输出未来多个时间步。改完后损失函数仍是 MSE但评估要按每个预测步分别算 MAE因为越远的步越难预测混在一起算会掩盖问题。# 多步预测改造要点 model.add(layers.Dense(horizon)) # horizon3 表示预测未来 3 个时间步 # 评估时按步拆开 for h in range(horizon): mae_h np.mean(np.abs(pred[:, h] - true[:, h])) print(fstep {h1} MAE: {mae_h:.4f})验证多步预测是否可信有个简单办法把预测出的第一步再喂回输入窗口滚动生成后续步和直接多输出对比。如果滚动预测误差累积很快说明模型对自身输出的鲁棒性不够这时候要么加噪声训练要么改用 seq2seq 结构。我一般会在改完结构后先跑一遍compare.py确认 CNN-LSTM 仍然优于单模型再去看多步结果。从那以后每次动网络层我都强制先跑一遍三模型对比确认没有退化才继续调。希望帮到你。本文还有配套的精品资源点击获取