尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

CNN-LSTM多输入单输出回归预测MATLAB源码实战解析

CNN-LSTM多输入单输出回归预测MATLAB源码实战解析 简介这是一套基于MATLAB的CNN-LSTM多输入单输出回归预测完整项目面向需要开展时间序列或多元特征回归建模的深度学习初学者与科研人员。项目将卷积神经网络的局部特征提取能力与长短期记忆网络对序列长期依赖的建模优势相结合并附带可直接运行的训练脚本与预处理后的数据。压缩包共5个文件包含1个m脚本、2个mat数据文件、1个预测结果docx文档和1张模型结构png示意图整体约208KB结构清晰。其中m脚本定义CNN与LSTM串联的MISO网络结构mat文件对应训练集与测试集docx呈现预测对比与R^2等指标png便于快速理解数据流动过程。该资源已有11373人学习适合希望快速复现并深入理解CNN-LSTM回归流程的读者可兼顾代码实践与理论对照。1. CNN-LSTM 多输入单输出回归预测这份 MATLAB 源码包拿来就能复现做回归预测的工程师多半遇到过这种尴尬原始数据里特征有十来个目标却只有一个连续值比如设备剩余寿命或未来半小时的电力负荷。CNN-LSTM 多输入单输出回归预测就是为这个场景准备的它用 CNN 提取多输入通道里的局部特征用 LSTM 记录时间依赖最后回归层输出单个目标值。普通 BP 网络拟合这种带时序依赖的数据预测曲线总慢半拍纯 LSTM 又抓不住局部模式。这套资源是完整的 MATLAB 源码加配套数据数据导入、滑窗构造、网络定义、训练、指标计算全链路打通改改路径和参数就能在自己数据集上复现。适合课程设计、毕业设计或接横向课题要快速出预测结果的人。下面按实际拆包的顺序把数据格式约定、网络结构、训练参数和最容易踩的坑逐章展开。2. 数据组织和网络选型滑窗维度、特征行与卷积LSTM 的分工动手跑 trainNetwork 之前最值得先搞明白的是这份源码里数据是怎么组织的。多输入单输出意味着输入是多个特征的时间序列输出是一个标量而 MATLAB 的 sequenceInputLayer 对数据格式有严格约定不满足它的维度要求训练第一步就会报错。这一章先把数据格式和网络分工讲透后面复现才不会卡在维度问题上。2.1 CNN 与 LSTM 的分工为什么组合比单模型稳这套资源里的网络主结构是 sequenceInputLayer → convolution1dLayer → relu → lstmLayer → fullyConnected → regressionLayer。卷积核长度为 3在时间维上滑动每个卷积核相当于一个局部模式检测器它看的是相邻三个时间步里多个输入特征的组合情况。多输入场景下特征之间往往有耦合关系比如温度爬升的同时振动幅值也在变大这种跨通道的局部模式正是 CNN 擅长的。LSTM 接在卷积后面把卷积输出的特征序列按时间顺序编码门控机制决定哪些历史信息要保留到当前时刻。回归任务输出只有一个数所以 LSTM 用 OutputModelast只取最后一个时间步的隐状态接全连接层再接 regressionLayer 做标量输出。为什么组合比单模型稳这里有两层原因。第一纯 LSTM 会把原始特征通道平等看待输入特征一多小样本下很容易过拟合CNN 先做局部融合相当于给 LSTM 降维序列长度不变但每个时间步的特征表达更紧凑。第二纯一维 CNN 的感受野固定跨几十个时间步的长期依赖只能靠堆卷积层数层数一深小样本根本训不动LSTM 天然能跨时间步传递信息。两者串联收敛难度和精度通常比单用其中一种要好这也是这个源码包选择组合结构而不是单模型的原因。2.2 滑窗构造把数据表变成 cell 数组源码里的原始数据是一张矩阵表每行是一个采样时刻每列是一个变量最后一列是目标变量。要把这种表格变成监督学习的样本就得做滑窗用过去 winSize 个时刻的特征预测当前时刻的目标值。窗口之间允许重叠这正是时序预测构造样本的常见做法不会造成数据泄漏因为每个样本的过去都严格早于它的当前。function [X, Y] makeWindows(data, featCols, targetCol, winSize) % data : 按时间排序的原始矩阵每行一个采样时刻 % featCols : 输入特征所在列号例如 1:size(data,2)-1 % targetCol : 目标变量所在列号通常是最后一列 % winSize : 滑窗长度即用过去 winSize 个时刻预测当前时刻 n size(data, 1) - winSize 1; X cell(n, 1); Y zeros(n, 1); for i 1:n X{i} data(i:iwinSize-1, featCols); % 转置成 [特征数, 时间步] Y(i) data(iwinSize-1, targetCol); % 窗口末端时刻的目标值 end end逻辑说明窗口从第 i 行取到第 iwinSize-1 行目标值 Y(i) 取窗口最后一个时刻的真实值含义是用这 winSize 个历史时刻预测最后一个时刻。这段代码里最容易出错的是转置cell 内每个矩阵要求行数是特征数、列数是时间步原始数据是时间步在行方向所以必须转置。参数说明featCols 决定输入通道数targetCol 单独拎出来不进特征矩阵这样输入输出的口径就是多输入单输出。winSize 是最敏感的超参数后面参数表里会细说。用 cell 数组而不是三维 double 数组是 sequenceInputLayer 的接口约定因为理论上各样本序列长度可以不同cell 是这类输入的通用容器。2.3 关键参数表初始值选定依据参数推荐初值说明winSize10~20窗口越长看到的依赖越久但小样本下过长会引入噪声建议从 12 试起numFilters64卷积核数量等价于提取的特征通道数输入特征少可降到 32filterSize3卷积核在时间维的长度取 3 或 5小样本用 3 更稳hiddenSize64LSTM 隐单元数单输出回归不需要太大64 够用OutputModelast多输入单输出必须用 last用 sequence 会输出每个时间步导致维度对不上InitialLearnRate0.005训练发散就降到 0.001稳定再逐级调回MaxEpochs120小样本 120 轮左右足够重点是观察 loss 曲线是否收敛MiniBatchSize64样本量少可减到 32主要看内存占用注意convolution1dLayer 从 R2020a 开始提供更早的 MATLAB 版本没有这个层需要升级或把卷积部分改成全连接替代。调参在很多人那里是玄学我的习惯是每次只动一个变量记录指标变化而不是同时改三个参数然后猜是谁的功劳。winSize 优先调其次 numFilters 和 hiddenSize最后才动学习率。3. 完整复现流程数据预处理、网络搭建与训练跑通这一章按资源里的主脚本顺序走读数据、造窗口、切训练测试、归一化、定义网络、训练、预测。每一步都对应一段可复用代码后面换成你自己的数据集时只需要改文件路径和列号。3.1 数据加载、滑窗与训练集划分clearvars; close all; clc; % 读取数据假设每行是一个采样时刻最后一列是目标变量 data readmatrix(data.xlsx); featCols 1:size(data, 2)-1; % 前 N-1 列作为输入特征 targetCol size(data, 2); % 最后一列作为目标 winSize 12; [X, Y] makeWindows(data, featCols, targetCol, winSize); % 时间序列按顺序切分前 80% 训练后 20% 测试 numTrain round(0.8 * length(X)); XTrain X(1:numTrain); YTrain Y(1:numTrain); XTest X(numTrain1:end); YTest Y(numTrain1:end); % 目标值归一化到 [0,1]ps 保存 min/max反归一化必须复用 [YNorm, ps] mapminmax(YTrain, 0, 1); YTrain YNorm;逻辑说明readmatrix 对 xlsx 和 csv 都友好省去处理 sheet 索引的麻烦。时序数据划分必须按顺序切不能随机打乱否则测试集里会出现未来样本教过去样本的伪高精度。mapminmax 把训练目标归一到 [0,1]ps 结构体里存的是训练集的 min 和缩放区间。参数说明mapminmax 要求输入是一行所以 YTrain 先转置输出再转置回来。ps 是后面反归一化唯一合法的依据测试集不能用自己另算的 min/max那属于数据泄漏。划分比例 0.8 是默认经验值样本量很小时可以提到 0.85但测试集至少要留 30 个以上样本否则指标波动太大没参考价值。3.2 搭建 CNN-LSTM 网络与训练选项numFeatures length(featCols); layers [ sequenceInputLayer(numFeatures, Normalization, zscore) convolution1dLayer(3, 64, Padding, same) reluLayer lstmLayer(64, OutputMode, last) fullyConnectedLayer(32) reluLayer fullyConnectedLayer(1) regressionLayer ]; options trainingOptions(adam, ... MaxEpochs, 120, ... InitialLearnRate, 0.005, ... MiniBatchSize, 64, ... GradientThreshold, 1, ... Shuffle, every-epoch, ... Verbose, true, ... VerboseFrequency, 20, ... Plots, training-progress);逻辑说明sequenceInputLayer 的 Normalization 设为 zscore在层内按每个特征通道自动标准化输入侧就不用手动归一化。convolution1dLayer 的 Padding 设为 same保证卷积后时间步数量不变否则 LSTM 收到的时间序列会变短。LSTM 后面先接一个 32 维全连接做特征压缩再接 1 维输出和回归层这是回归任务的常规收尾方式。参数说明GradientThreshold 设 1 是防梯度爆炸的后悔药CNN-LSTM 偶尔会出现 loss 突然跳到 NaN有这个阈值兜底会稳很多。Shuffle 每轮洗牌能缓解小样本的过拟合但洗牌发生在样本之间不会破坏时序样本内部的时间顺序。VerboseFrequency 20 表示每 20 轮打印一次 loss配合训练进度图观察收敛。3.3 训练、预测与反归一化net trainNetwork(XTrain, YTrain, layers, options); % predict 返回的是归一化后的预测值需要还原到原始量纲 YPredNorm predict(net, XTest); YPred mapminmax(reverse, YPredNorm, ps); % 初步看误差量级正式指标评估在下一章 fprintf(平均误差: %.4f\n, mean(abs(YPred - YTest)));逻辑说明trainNetwork 把定义好的层数组和训练选项一起吃进去返回训练好的 network 对象。predict 对 cell 数组输入逐样本预测输出是列向量。mapminmax 的 reverse 方向要求输入是一行所以先转置再还原输出后再转置回列向量这个转置顺序经常被漏掉漏一次量纲就全错了。参数说明fprintf 只是摸底验证模型好坏不能只看平均误差要结合 RMSE 和 R² 一起判断这是下一章的内容。4. 多输入单输出的效果评估指标计算与预测曲线可视化模型训完只看 loss 曲线不算完回归预测要回答的是预测值和真实值差多少、趋势对不对。这份资源里配套的评估脚本把四个常用指标和两张图放在一起一次跑完省得手动翻工作区。4.1 四项回归指标RMSE、MAE、MAPE、R²YTest YTest(:); % 统一成列向量避免隐式转置出错 YPred YPred(:); rmse sqrt(mean((YPred - YTest).^2)); mae mean(abs(YPred - YTest)); mape mean(abs((YPred - YTest) ./ YTest)) * 100; ssRes sum((YTest - YPred).^2); ssTot sum((YTest - mean(YTest)).^2); r2 1 - ssRes / ssTot; fprintf(RMSE %.4f\nMAE %.4f\nMAPE %.2f%%\nR2 %.4f\n, ... rmse, mae, mape, r2);逻辑说明四个指标各有侧重RMSE 对大误差敏感个别离谱预测会被平方放大MAE 是平均绝对误差量纲直观工程汇报常用MAPE 是百分比误差适合业务方理解但目标值接近 0 的时候数值会爆炸遇到这种情况直接弃用R² 衡量模型相对直接用均值预测的改进程度。参数说明R² 的计算里 ssTot 是真实值与均值的平方和ssRes 是残差平方和。R² 接近 1 说明解释力强为负说明模型比朴素均值预测还差这时候别怀疑代码先回去看数据组织。指标判断标准使用场景RMSE越小越好单位与目标一致暴露大误差样本MAE越小越好工程汇报主指标MAPE目标接近 0 时禁用业务侧沟通R²越接近 1 越好负值说明模型无效模型横向对比4.2 可视化预测曲线、真实曲线与残差figure(Color, w); plot(YTest, b-, LineWidth, 1.2); hold on; plot(YPred, r--, LineWidth, 1.2); legend(真实值, 预测值, Location, best); xlabel(测试样本序号); ylabel(目标值); title(CNN-LSTM 多输入单输出回归预测结果); grid on; figure(Color, w); plot(YTest - YPred, k-, LineWidth, 1); yline(0, r--); xlabel(测试样本序号); ylabel(残差); title(预测残差分布); grid on;逻辑说明第一张图把真实值和预测值画在同一条时间轴上重点看两件事曲线贴合程度和峰值位置是否滞后。如果预测曲线整体形态对但峰值总是晚一步说明模型对突变的响应偏慢常见原因是滑窗太短或卷积核太小。残差图里残差围绕 0 上下波动是正常形态说明没有系统性偏差。参数说明残差如果出现连续一段全正、一段全负说明模型对某个时间段的变化没学到要去检查训练集里这个时段的样本是否过少或者特征在这个时段本来就不敏感。两张图建议直接 exportgraphics 存成 png 留档写报告或交差时都要用到。5. 避坑与常见问题维度报错、NaN 与预测平线这部分是拆包和复现过程中反复出现的五类问题每条都按现象、原因、解决记录。多数问题不是网络结构错了而是数据格式或参数习惯的问题提前知道能省一整天排查时间。5.1 trainNetwork 报错Invalid input data for sequence input现象训练一开始就报 Invalid input data for sequence input错误指向 sequenceInputLayer。原因X 的 cell 数组里矩阵维度不对。MATLAB 要求每个 cell 元素是 [特征数, 时间步]很多人从表格直接读进来是 [时间步, 特征数]忘了转置另一种情况是部分 cell 里元素类型是整型卷积层要求 single 或 double。解决在 makeWindows 里转置并统一类型X{i} double(data(i:iwinSize-1, featCols))。改完先用 size(X{1}) 检查维度确认第一位是特征数再跑训练。5.2 loss 变成 NaN 或训练曲线震荡现象loss 曲线前几轮正常某一步突然跳到 NaN之后全部是 NaN或者曲线上下震荡完全不收敛。原因学习率过大导致梯度爆炸CNN-LSTM 对学习率比纯全连接敏感得多另一个常见原因是输入数据里有 NaN或者某列全程是同一个常数min-max 归一化时分母为 0。解决InitialLearnRate 从 0.005 降到 0.001同时把 GradientThreshold 设为 1 兜底用 isnan(sum(data)) 和 unique(data(:, col)) 逐列扫一遍原始数据把非法值和常数列处理掉。5.3 预测结果是一条平线几乎等于均值现象测试集预测曲线是一条水平直线数值接近训练集均值MAE 巨大曲线图完全无意义。原因三个可能叠加。一是滑窗长度太短模型根本看不到有效依赖二是网络容量不够卷积核太少加隐单元太少学不动三是目标归一化后分布被压太窄个别异常点把 min-max 区间拉大正常值全挤在 0.1 附近模型输出趋向保守。解决把 winSize 从 12 加到 20numFilters 和 hiddenSize 各提一倍试跑归一化改用 zscore或者先剔除明显异常点再 min-max。平线问题基本都能靠前两个动作解决。5.4 旧版 MATLAB 找不到 convolution1dLayer现象脚本跑到 layers 定义时报 Unrecognized function or variable convolution1dLayer。原因convolution1dLayer 是 R2020a 才引入的层老版本没有这个接口。这不是代码问题是环境版本问题。解决升级到 R2020a 以上2023b 及更新版本默认支持不方便升级就把卷积部分替换成 fullyConnectedLayer 加 reshape 的组合效果打折扣但能跑通整条链路。提示如果你在用较新的 MATLAB还报找不到层优先检查 Deep Learning Toolbox 是否安装完整trainNetwork 依赖这个工具箱。5.5 指标虚高归一化参数泄漏现象测试集指标好得离谱R² 0.99预测曲线和真实值几乎完全重叠但换一份数据立刻崩。原因反归一化时 ps 是拿全部数据算的等于模型评估时偷看了测试集的 min/max 信息这叫数据泄漏。源码包里如果顺序写反先 normalize 后 split就会出现这个问题。解决严格按 split 再 normalize 的顺序执行ps 只从 YTrain 计算测试集预测结果反归一化复用同一个 ps。检查方法很简单看 ps.xmin 和 ps.xmax 是否等于测试集的最小最大值如果相等则说明泄漏了。6. 进阶滚动多步预测与模型可信度验证单步预测在测试集上指标好看很多时候是因为每一步都用了真实历史值。工程上更常见的问题是只用历史真实值起步到底能往外推几步这就是滚动多步预测。6.1 滚动多步预测把预测值回填到窗口末端滚动预测的前提是把目标列本身也放进输入特征里否则预测值没有位置回填到窗口。做法是每次预测完把窗口最旧的一列丢掉把新预测值放进窗口末端的目标行再继续预测下一步。% 前提targetCol 已经包含在 featCols 里否则无法回填 targetRow find(featCols targetCol); rollingInput XTest{1}; % [numFeat, winSize] numSteps 20; preds zeros(numSteps, 1); for k 1:numSteps preds(k) predict(net, {rollingInput}); newCol rollingInput(:, end); % 复制最新一列 newCol(targetRow) preds(k); % 用预测值覆盖目标行 rollingInput [rollingInput(:, 2:end), newCol]; end逻辑说明滚动步数越长误差在反馈回路里累积越明显这是正常现象不是模型坏了。其他特征行在没有新观测时沿用上一时刻的值这是工程里常见的近似处理。滚动预测的价值在于暴露模型真实的时序泛化能力单步预测指标好看完全不能证明这一点。验证模型可不可信我一般加两个对照。第一是朴素基线直接用上一个时刻的真实值当预测如果 CNN-LSTM 的 RMSE 压不过这根基线说明模型没学到比惯性外推更多的东西。第二是滚动步数递增测试分别外推 5、10、20 步误差应该平滑增长如果 10 步误差突然暴涨通常是被回填方式坑了某个特征行没有正确更新。以前我刚开始用这套源码时也翻过车把测试集一起丢进 mapminmax指标好看到以为模型神了对照基线才发现是数据泄漏造成的假象。从那以后我每次做回归预测都强制自己先走一遍基线对照、归一化只用训练集、滚动步数递增验证三道检查再谈指标。希望帮到你。本文还有配套的精品资源点击获取
返回列表