
简介本资源面向深度学习入门与进阶学习者提供一套基于CNN-LSTM的多输入单输出回归预测完整实现适用于时间序列分析、序列建模等场景。模型将卷积神经网络提取局部特征的能力与长短期记忆网络的时序记忆机制相结合对复杂序列数据的预测效果通常优于单一模型并配套R2、MAE、MSE、RMSE、MAPE等评价指标的计算逻辑便于读者系统评估模型性能。压缩包共9个文件约1.23MB包含2个m脚本文件主程序与指标计算函数、1个xlsx数据文件、1个docx说明文档、1个txt注释及4张png结果图覆盖模型定义、训练验证、指标计算与可视化全流程。目前已有367人学习下载适合希望掌握CNN与LSTM融合建模、理解回归评价体系并动手复现完整实验的读者参考。1. 多输入单输出的 CNN-LSTM 回归模型从数据到 R2 的完整落地路径做设备寿命预测或工艺参数软测量的朋友多半遇到过这种局面手头有振动、温度、电流三路时序信号想预测下一时刻的刀具磨损量或产品强度输出只有一个连续值。这就是典型的多输入单输出回归问题。纯 LSTM 能记住长程依赖却容易在局部突变点上抓不住波形里的短时模式纯 CNN 擅长提局部特征却对时序先后顺序不敏感。把两者串起来用 CNN 先做一维卷积抽特征、LSTM 再吃特征序列做回归是这类任务里比较稳的常见做法。这份资源给的就是这样一套 CNN-LSTM 回归预测的完整实现评价指标覆盖 R2、MAE、MSE、RMSE 和 M 系列误差适合已经会用 Python 跑通基础神经网络、但卡在「多路输入怎么拼、指标怎么算、结果怎么复现」这一步的从业者。2. 网络结构拆解CNN 提特征、LSTM 记时序为什么这么串2.1 多输入单输出的数据形状约定多输入不是指多个模型而是指特征维度上有多个通道。假设你有 3 路传感器每路取过去 24 个时间步那么单条样本的形状是(时间步24, 通道数3)。喂给网络时通常再扩一维成(batch, 24, 3)。单输出意味着最后全连接层只有一个神经元不加 softmax直接输出连续值。这个形状约定必须先定死否则后面卷积核、池化、LSTM 的输入维度全对不上这是新手最容易翻车的地方。常见做法是把数据整理成三维数组samples × timesteps × features。标签整理成二维samples × 1。训练前用滑动窗口切分窗口大小就是 timesteps步长决定样本重叠程度。步长取 1 样本最多但相邻样本高度相关步长取窗口一半是折中。2.2 CNN 一维卷积层的作用与参数一维卷积在时间轴上滑动提取的是局部波形模式比如某个尖峰、某段上升沿。它比 LSTM 快因为卷积是并行计算的。典型配置是两层 Conv1D 加池化from tensorflow.keras import layers, models model models.Sequential([ # 第一层卷积64个卷积核核大小3输入形状(24,3) layers.Conv1D(filters64, kernel_size3, activationrelu, paddingsame, input_shape(24, 3)), layers.MaxPooling1D(pool_size2), # 时间步 24 - 12 # 第二层卷积32个卷积核进一步抽特征 layers.Conv1D(filters32, kernel_size3, activationrelu, paddingsame), layers.MaxPooling1D(pool_size2), # 时间步 12 - 6 layers.LSTM(50, return_sequencesFalse), # 只取最后时刻输出 layers.Dense(1) # 单输出回归 ]) model.compile(optimizeradam, lossmse, metrics[mae])filters是卷积核数量决定提取多少种局部模式第一层给大一点64抓丰富特征第二层减半32做压缩。kernel_size3表示每次看 3 个连续时间步太小抓不到趋势太大参数量涨。paddingsame保证卷积后时间步不变方便接池化。池化把时间步减半降低 LSTM 的计算量。return_sequencesFalse让 LSTM 只输出最后一个时间步的隐状态直接对接单值输出。如果设成 True后面还得再接 Flatten 或池化多此一举。2.3 LSTM 层与输出层的衔接LSTM 接收的是卷积池化后的特征序列形状(batch, 6, 32)。50 个隐藏单元意味着隐状态是 50 维向量这个数不是越大越好太小欠拟合太大训练慢且容易过拟合。经验上从 32 到 128 之间试配合早停。输出层Dense(1)不加激活函数因为回归要的是线性输出加了 sigmoid 或 tanh 会把预测值压到固定区间除非你先把标签归一化到那个区间。提示如果标签量纲差异大比如强度 0~1000训练前务必做标准化否则 MSE 会被大数值主导梯度更新失衡。3. 训练流程与评价指标R2、MAE、MSE、RMSE 怎么算才不误导3.1 数据切分与标准化顺序标准化必须只用训练集的均值和方差再套用到验证集和测试集。如果先对全量数据标准化再切分测试集的统计信息就泄漏进了训练过程R2 会虚高上线就崩。这是血泪经验很多人第一次跑出 0.99 的 R2 还高兴其实是泄漏。import numpy as np from sklearn.preprocessing import StandardScaler # X: (样本数, 24, 3) y: (样本数, 1) n len(X) train_end int(n * 0.7) val_end int(n * 0.85) X_train, y_train X[:train_end], y[:train_end] X_val, y_val X[train_end:val_end], y[train_end:val_end] X_test, y_test X[val_end:], y[val_end:] # 按特征维度标准化把(样本,时间步,特征)拉平成(样本*时间步,特征) scaler_X StandardScaler().fit(X_train.reshape(-1, X_train.shape[-1])) X_train scaler_X.transform(X_train.reshape(-1, 3)).reshape(X_train.shape) X_val scaler_X.transform(X_val.reshape(-1, 3)).reshape(X_val.shape) X_test scaler_X.transform(X_test.reshape(-1, 3)).reshape(X_test.shape) scaler_y StandardScaler().fit(y_train) y_train scaler_y.transform(y_train) y_val scaler_y.transform(y_val) y_test scaler_y.transform(y_test)reshape(-1, 3)把时间步维度合并进样本维度让 StandardScaler 对每个特征通道单独算均值方差。变换完再 reshape 回三维。标签也单独标准化预测完再用scaler_y.inverse_transform还原回原始量纲否则算出来的 MAE 没有物理意义。3.2 训练回调与早停from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau callbacks [ EarlyStopping(monitorval_loss, patience15, restore_best_weightsTrue), ReduceLROnPlateau(monitorval_loss, factor0.5, patience7, min_lr1e-6) ] history model.fit(X_train, y_train, validation_data(X_val, y_val), epochs200, batch_size32, callbackscallbacks, verbose1)patience15表示验证损失连续 15 轮不降就停restore_best_weightsTrue回滚到最优轮次的权重这是后悔药。ReduceLROnPlateau在损失停滞时把学习率减半帮助跳出局部极小。batch_size32是常见起点样本少就降到 16 或 8。3.3 五个评价指标的代码实现from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error y_pred model.predict(X_test) y_pred_inv scaler_y.inverse_transform(y_pred) y_test_inv scaler_y.inverse_transform(y_test) r2 r2_score(y_test_inv, y_pred_inv) mae mean_absolute_error(y_test_inv, y_pred_inv) mse mean_squared_error(y_test_inv, y_pred_inv) rmse np.sqrt(mse) # M系列平均绝对百分比误差MAPE与对称MAPE mape np.mean(np.abs((y_test_inv - y_pred_inv) / y_test_inv)) * 100 smape np.mean(2 * np.abs(y_pred_inv - y_test_inv) / (np.abs(y_test_inv) np.abs(y_pred_inv))) * 100 print(fR2{r2:.4f} MAE{mae:.4f} MSE{mse:.4f} RMSE{rmse:.4f} MAPE{mape:.2f}% SMAPE{smape:.2f}%)R2 越接近 1 越好但要注意它在测试集上的含义是「模型解释了多大比例的方差」如果测试集本身波动小R2 会偏低不代表模型差。MAE 和 RMSE 单位跟标签一致RMSE 对大误差更敏感MAE 更稳健。MAPE 是百分比误差但标签接近 0 时会爆炸这时候用 SMAPE 更稳。这几个指标要一起看单看一个容易被误导。指标含义对异常值敏感度适用场景R2解释方差比例中整体拟合优度MAE平均绝对误差低误差有物理量纲MSE均方误差高训练损失函数RMSE均方根误差高与大误差相关的任务MAPE/SMAPE百分比误差中跨量纲对比4. 避坑与排查多输入单输出回归里最容易翻车的五件事4.1 现象R2 高得离谱但预测曲线平移原因标准化时用了全量数据的统计量测试集信息泄漏。解决严格按 3.1 的顺序scaler 只在训练集 fit验证和测试只 transform。检查方法是把测试集预测值画出来如果整体形状对但有个固定偏移多半是标签还原时用了错误的 scaler。4.2 现象训练损失降但验证损失震荡上升原因过拟合或者 batch_size 太小导致梯度噪声大。解决先加 DropoutLSTM 后加layers.Dropout(0.2)再降 LSTM 单元数最后才考虑加数据。如果验证损失是锯齿状把 batch_size 提到 64 试试。4.3 现象LSTM 输入报维度错误原因Conv1D 后接了return_sequencesTrue的 LSTM输出还是三维直接接 Dense 会报错。解决要么 LSTM 设return_sequencesFalse要么后面加layers.Flatten()。多输入场景下还要确认 Conv1D 的input_shape是(timesteps, features)不是(features, timesteps)写反了卷积就在特征轴上滑结果毫无意义。4.4 现象MAPE 算出 inf 或超大值原因测试标签里有接近 0 的值除法爆炸。解决改用 SMAPE或者给分母加一个极小常数1e-8。更稳妥的做法是回归任务优先看 MAE 和 RMSE百分比误差只在标签远离 0 时用。4.5 现象每次训练结果差异大R2 在 0.7 到 0.95 之间跳原因权重随机初始化、数据切分随机、没有固定随机种子。解决在脚本开头固定np.random.seed(42)和tf.random.set_seed(42)数据切分用固定索引而不是train_test_split的随机模式。如果固定种子后仍波动大说明样本量不足考虑交叉验证取平均。5. 进阶技巧用滑动窗口预测与残差分析验证模型真实能力训练完拿到 R2 只是第一步真正判断模型能不能用得看它在连续时间上的表现。我一般会把测试集按时间顺序拼回一条完整序列用滑动窗口逐点预测画出预测值和真实值的对比曲线再画残差图。如果残差在某个时间段系统性偏正或偏负说明模型没学到那个工况得回去检查那段数据是不是分布不同。import matplotlib.pyplot as plt # 逐点滚动预测每次用真实历史窗口预测下一点 preds [] window X_test[0:1] # 初始窗口 for i in range(len(X_test)): p model.predict(X_test[i:i1], verbose0) preds.append(p[0, 0]) preds scaler_y.inverse_transform(np.array(preds).reshape(-1, 1)) truth scaler_y.inverse_transform(y_test) residual truth - preds plt.figure(figsize(12, 4)) plt.subplot(1, 2, 1) plt.plot(truth, labeltrue) plt.plot(preds, labelpred) plt.legend() plt.subplot(1, 2, 2) plt.plot(residual) plt.axhline(0, colorr, linestyle--) plt.title(residual) plt.show()这段代码里model.predict每次只喂一个样本虽然慢但能模拟上线时的逐点推理。残差图如果围绕 0 均匀分布说明模型没有系统性偏差如果残差有周期性说明 LSTM 没记住那个周期的模式可以加大时间窗口或增加 LSTM 单元。另一个技巧是把 CNN 部分的输出单独拿出来做 t-SNE 可视化看不同工况的样本有没有被分开分不开就说明卷积特征区分度不够得加层或加核。注意逐点预测时不要用预测值去构造下一步的输入窗口那样误差会累积评估结果偏悲观。评估阶段始终用真实历史构造窗口。从那以后我每次跑完回归模型都强制走一遍「残差图 分段 R2」的检查光看一个全局 R2 根本不知道模型在哪个区间失效。希望帮到你。本文还有配套的精品资源点击获取