ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

MATLAB搭建DNN实现多输入多输出回归预测实战

MATLAB搭建DNN实现多输入多输出回归预测实战 简介MATLAB实现DNN深度神经网络/全连接神经网络多输入多输出预测的完整源码与配套数据包面向需要构建多特征输入、多变量输出预测模型的研究者、学生与工程师适用于回归拟合、时序预测及工业数据建模等场景。模型输入10个特征、输出3个变量运行环境要求MATLAB2018b及以上并已针对程序乱码问题给出处理办法。包内共8个文件包括1个m主程序、1个xlsx数据集、1个docx结果说明文档以及5个png预测结果图压缩包仅1.44MB文件类型分工明确便于快速定位源码、数据与可视化结果。目前已有1784人学习下载资源提供可直接运行的建模流程和详细输出图可帮助理解DNN网络结构设计、训练超参数选择与多输出回归任务的关键步骤适合作为课程设计、毕业设计或工程项目的实验模板。1. 多输入多输出预测MATLAB 里 DNN 解决的是什么问题DNN 做多输入多输出MIMO预测就是用深度前馈神经网络拟合多维度输入到多个目标输出的映射。相比对每个输出单独建 BP 网络共享隐藏层能利用输出间相关性参数更少数据利用更充分这是 MIMO 建模最实在的收益。MATLAB 里实现这件事用 Deep Learning Toolbox 就够featureInputLayer、fullyConnectedLayer、regressionLayer 配合 trainNetwork 形成闭环。决定一份完整源码能否迁移到你的数据上的不是网络有多深而是数据矩阵怎么摆、归一化参数在哪里算、预测结果怎么还原。下面按从数据到评估的完整链路讲读者是想用 MATLAB 跑通 MIMO 预测的工程师以及做过单输出回归、想确认多输出场景差异的人。代码用 Deep Learning Toolbox 常用接口版本差异会单独标出。2. 训练数据构造与归一化DNN 多输出建模的第一道坎2.1 输入输出矩阵怎么摆行样本、列维度的约定trainNetwork 对数值型回归数据的约定与 sklearn 一致输入 X 是 n×d 矩阵每一行是一个样本目标 Y 是 n×m 矩阵每一行对应同一个样本的 m 个输出值。这个约定和 MATLAB 里很多传统工具箱相反——比如 mapminmax 是按行做映射的这会直接影响后面的转置操作。读取数据用 readmatrixR2019a 之后引入旧版本可以用 xlsread但 readmatrix 对纯数值表格更省心自动跳过文本表头data readmatrix(mimo_dataset.xlsx); % 每行一个样本假设无表头 X data(:, 1:8); % 前 8 列输入特征 Y data(:, 9:12); % 后 4 列输出目标 fprintf(样本数%d, 输入维度%d, 输出维度%d\n, ... size(X,1), size(X,2), size(Y,2));参数说明第一处 readmatrix 返回的 data 是 double 矩阵如果文件里混有字符串列data 会被读成 cell 或直接报错所以读完之后立刻用 size 核对维度是关键一步。特征列数和输出列数必须与后面 featureInputLayer(8) 和 fullyConnectedLayer(4) 的声明一致这个数字错了训练阶段会直接报输入尺寸不匹配。DNN 对脏数据的容忍度比树模型低很多NaN 和 Inf 会在反向传播时把梯度变成 NaN。清洗代码要同时在输入和输出两侧做逐行检查并且用同一个掩码删除保证 X 和 Y 行数始终对应badX any(isnan(X) | isinf(X), 2); % 输入侧任一列有脏值即标记 badY any(isnan(Y) | isinf(Y), 2); % 输出侧同样处理 mask badX | badY; X(mask, :) []; Y(mask, :) []; fprintf(清洗后样本数%d\n, size(X,1));逻辑说明isnan(X) 和 isinf(X) 返回与 X 同尺寸的逻辑矩阵any(...,2) 把逐列的标记按行压缩成一个 n×1 逻辑向量。先算好 mask 再同时删除两侧避免先删 X 导致行号错位。这一步在真实数据上几乎必然用到不要指望读进来的 Excel 是干净的。2.2 mapminmax 归一化的正确用法训练集算参数其余数据只做映射DNN 的权重初始化与梯度更新都对输入尺度敏感。特征量纲差几个数量级时不归一化直接训练损失曲线会在高位长时间不动。MATLAB 里最常用的线性归一化函数是 mapminmax但它有个容易踩的坑mapminmax 按行操作。要对一个 n×d 矩阵逐列归一化必须先把矩阵转置成 d×n映射完再转回来[Xtr_n, psX] mapminmax(Xtr, 0, 1); % 对每行(每个特征)独立映射到 [0,1] Xtr_n Xtr_n; % 转回 n×d [Ytr_n, psY] mapminmax(Ytr, 0, 1); Ytr_n Ytr_n; Xte_n mapminmax(apply, Xte, psX); % 测试集只用 apply不重新算参数 Yte_n mapminmax(apply, Yte, psY);参数说明mapminmax 的第二个参数 0 和 1 表示目标区间默认是 [-1,1]。对以 relu 为隐藏层激活的网络[0,1] 更自然如果输出层用线性激活[-1,1] 也没有问题。psX、psY 是结构体保存了每个特征的最小值、最大值和映射公式reverse 还原时必须用到它们。这里最关键的是后面两句测试集必须用训练集算出来的 psX、psY 去做 apply任何情况下都不要在测试集上重新估计归一化参数。测试集一旦参与最小值和最大值的统计等于把测试集的信息泄漏进了训练流程评估出的指标会比实际部署时乐观。这是多输入多输出预测里最隐蔽、也最常见的错误。归一化方法的选择没有绝对标准主要看数据形态方法映射结果适用场景离群值影响mapminmax(x,0,1)[0,1]relu 为主的网络离群值被压到 0/1 边界mapminmax(x,-1,1)[-1,1]输出无界回归同上zscore 标准化均值 0、方差 1特征含极端值影响较小如果数据里存在明显的极端离群点mapminmax 会把正常样本压缩到很窄的区间此时改用 zscore 更稳mu mean(Xtr); sg std(Xtr); Xtr_n (Xtr - mu) ./ sg。zscore 也需要用训练集的均值方差去映射测试集逻辑与 mapminmax 完全一致。2.3 训练测试切分时间序列用顺序块独立样本才随机切分方式取决于数据的生成过程。截面采样数据样本间近似独立可以随机切分并用 cvpartition 做留出验证rng(0); % 固定随机种子保证结果可复现 cv cvpartition(size(X,1), HoldOut, 0.2); idxTe test(cv); Xtr X(~idxTe,:); Ytr Y(~idxTe,:); Xte X(idxTe,:); Yte Y(idxTe,:);如果是按时间顺序采集的数据设备运行记录、负荷曲线、能耗序列随机切分会把时间上相邻的样本同时塞进训练集和测试集模型等于提前见过未来评估出的 R² 虚高部署后立刻失效。时间序列场景必须用顺序切分前 80% 训练、后 20% 测试numTrain floor(size(X,1) * 0.8); Xtr X(1:numTrain,:); Ytr Y(1:numTrain,:); Xte X(numTrain1:end,:); Yte Y(numTrain1:end,:);额外提醒如果数据是多个工况的分段时间序列拼接而成顺序切分仍然会跨工况泄漏。正确的做法是先定位工况边界按工况块整体划分而不是按行号划。这一步没有现成函数但直接决定后续所有指标的可信度值得单独写脚本处理。3. 用 featureInputLayer 与 regressionLayer 搭 DNN 多输出回归网络3.1 为什么不是搭 m 个单输出网络多输出预测最朴素的做法是对每个输出单独训练一个 DNNm 个输出就 m 个模型。思路直白但如果输出之间相关——比如同时预测温度、湿度和功耗三者强耦合——m 个模型会重复学习同一批特征参数总量成倍上涨小样本下每个模型分到的数据更少过拟合风险更高。共享隐藏层的 MIMO 网络把 m 个输出放进同一个前向传播输入先经过若干全连接层提取公共特征最后一个全连接层直接产出 m 个值。中间层的特征表示同时被 m 个输出监督训出来的表示更鲁棒。判断输出是否适合共享网络的方法是算相关系数矩阵相关性明显大于 0经验上 0.3 以上用共享网络收益明显输出之间接近独立甚至负相关时共享层互相干扰才考虑分组建模。这里用的是 DNN 而非图神经网络原因在于表格特征之间没有显式的图拓扑。如果输入是图像或时序谱图MATLAB 里的做法要换成卷积神经网络CNN用 convolution2dLayer 堆叠本文的 DNN 针对的是结构化表格特征。3.2 隐藏层宽度、深度与激活函数的选择DNN 在 MATLAB 里的深是相对传统 BP 网络feedforwardnet通常一两层而言的。表格类回归任务一般 2 到 4 个隐藏层足够再深在小样本上几乎必然过拟合。宽度遵循递减原则第一层取输入维度的 4 到 8 倍后面逐层减半输出层对齐输出维度。激活函数的选择有明确倾向隐藏层用 relu 是默认计算简单且梯度不会在正区间饱和tanh 在浅层网络也可以用但堆到 3 层以上时梯度消失风险明显上升sigmoid 不要用在隐藏层它不是概率输出梯度饱和问题最严重。输出层不加任何激活函数让最后一个全连接层直接输出实数这正是回归任务的标准做法regressionLayer 只负责计算损失不会套非线性。训练中发现损失卡在高位不动、很多神经元输出恒为 0 时说明出现了 relu 死亡可以把部分隐藏层换成 leakyreluLayer。新版 MATLAB 还提供了一些更复杂的激活层但表格回归场景收益不明显不值得为此增加兼容性风险。3.3 完整网络定义layers 数组逐层说明下面是一个可复现的最小网络对应 8 维输入、4 维输出layers [ featureInputLayer(8, Normalization, none, Name, in) fullyConnectedLayer(64, Name, fc1) reluLayer(Name, relu1) fullyConnectedLayer(32, Name, fc2) reluLayer(Name, relu2) fullyConnectedLayer(16, Name, fc3) reluLayer(Name, relu3) fullyConnectedLayer(4, Name, fc_out) regressionLayer(Name, loss) ];逐层说明featureInputLayer 声明输入维度为 8Normalization 设为 none 是因为数据已经显式归一化过再开内置标准化会做重复工作fc1 把 8 维映射到 64 维参数数为 8×6464576fc2 为 64×32322080fc3 为 32×1616528输出层 16×4468整个网络约 3252 个可训练参数。这个量级在表格数据里属于轻量网络训练快也方便定位问题。regressionLayer 的作用是计算均方误差损失。注意 MIMO 回归不需要 m 个损失头regressionLayer 会把最后一层输出的 m 个维度与目标矩阵逐元素比较统一算一个标量损失这是 trainNetwork 处理多输出的原生方式。各层在工程上的角色和要点层作用关键参数featureInputLayer声明输入维度inputSize 必须等于 X 列数fullyConnectedLayer线性变换加偏置OutputSize 决定该层宽度reluLayer引入非线性无参数dropoutLayer(0.2)训练时随机丢弃神经元防过拟合丢弃概率一般 0.1~0.5regressionLayer计算 MSE 损失无参数如果四个输出属性差异很大归一化已经把各列拉到同一尺度损失函数对每个输出的权重是均等的。业务上更看重某个输出时需要在归一化后对该列额外加权trainNetwork 没有内置选项要改用 dlnetwork 加自定义训练循环dlgradient、dlfeval 组合。这是进阶路径先不要碰。判断标准很直接共享表示、输出同尺度用 trainNetwork输出异质性强、需要差异化 loss 项再上 dlnetwork。4. trainingOptions 调参与损失曲线判读让 DNN 真正收敛4.1 多输出回归最容易见效的四个训练参数网络定义好之后训练是否收敛几乎全由 trainingOptions 决定。下面是适合表格回归的起始配置options trainingOptions(adam, ... InitialLearnRate, 0.001, ... MaxEpochs, 300, ... MiniBatchSize, 32, ... L2Regularization, 0.0001, ... ValidationData, {Xval_n, Yval_n}, ... ValidationFrequency, 20, ... ValidationPatience, 20, ... Plots, training-progress, ... Verbose, true); net trainNetwork(Xtr_n, Ytr_n, layers, options);参数含义与调整方向参数起始值说明与调整solveradam自适应矩估计表格回归首选sgdm 收敛慢但调好后精度可能略高InitialLearnRate0.001adam 默认值损失震荡不降减半下降过慢加倍MiniBatchSize32样本几千到几万时 32/64 都合理batch 越小梯度噪声越大、泛化通常更好L2Regularization0.0001权重衰减防过拟合多输出共享层参数较多可以加大到 0.001ValidationPatience20连续 20 次验证不改善即早停默认是 Inf不显式设置等于没有早停ValidationFrequency 的单位是迭代次数而不是 epoch。样本 5000、batch 32 时一个 epoch 约 156 次迭代验证频率 20 相当于每轮验证七八次密度合理。样本量小时把频率调低例如 10避免验证本身拖慢训练。ValidationData 的数据也必须经过与训练集相同的归一化映射Xval_n 必须是 apply 后的结果不能拿原始值传进去。提示ValidationPatience 的默认值是 Inf。不显式设置的话验证损失再差也不会触发早停最终返回的是训练到 MaxEpochs 的模型而不是验证最优的模型。4.2 从训练进度图判断欠拟合、过拟合还是学不动打开 Plots 的 training-progress 后窗口显示训练损失和验证损失两条曲线。判断按顺序排查训练损失和验证损失都在高位平着不动是欠拟合或学习率过小。0.001 的学习率已经不低如果 100 轮损失几乎不变先考虑网络容量不够把第一个隐藏层从 64 加到 128或加一层。第二检查归一化是否做对确认没有把测试集参数混进来。最后才怀疑初始化trainNetwork 的内部默认初始化一般不用动。训练损失降得很低、验证损失在某个 epoch 后反弹向上是典型过拟合。对策按顺序试把 L2Regularization 从 0.0001 加到 0.001再减小网络宽度最后加 dropout。dropout 层接在 relu 后面训练时随机丢弃 20% 的神经元layers [ featureInputLayer(8, Normalization, none, Name, in) fullyConnectedLayer(64, Name, fc1) reluLayer(Name, relu1) dropoutLayer(0.2, Name, drop1) fullyConnectedLayer(32, Name, fc2) reluLayer(Name, relu2) fullyConnectedLayer(4, Name, fc_out) regressionLayer(Name, loss) ];dropoutLayer 的入参是丢弃概率0.2 表示随机丢弃 20%。它对不同 MATLAB 版本的层兼容性有细微差异R2020a 之后在 fullyConnected 序列里使用没问题如果报层连接错误检查是否把 dropout 放到了 featureInputLayer 后面dropout 应该跟在激活层之后。训练损失和验证损失都在下降但速度很慢是典型的学得动但学不快。把 InitialLearnRate 提到 0.003 或 0.005同时把 MiniBatchSize 降到 16往往比加深网络有效。多输出场景还有一种独特现象训练损失一直在降但验证集上某几个输出表现始终差。这通常是共享层被占主导的输出带偏了处理办法是对该输出的归一化列单独做权重放大或者把主导输出拼进输入特征后一种方式简单且经常有效。4.3 NaN、不收敛与验证集失效的排错顺序损失曲线出现 NaN 是 DNN 回归最常见的事故。按顺序排查第一检查归一化后的数据是否含 NaN 或 Infmapminmax 对含 Inf 的列会直接产生 NaN清洗不彻底时训练第一轮就崩第二把 InitialLearnRate 降到 0.0001 试一次学习率过大会导致梯度爆炸这是 NaN 的第二大来源第三检查输出列是否有接近常数的列这类列没有有效梯度剔除后再训。验证集失效的表现是 ValidationData 传进去后进度图不出现验证曲线。常见原因是验证集行数与训练集不一致或者验证集里含 NaNtrainNetwork 对验证数据的要求与训练数据完全一致数值矩阵、行数对应、无缺失。另一个隐蔽问题是验证集切分与训练集时间重叠验证曲线贴着训练曲线走看似完美实际是泄漏。调参坚持一次只动一个旋钮的原则并记录每组参数在验证集上的 RMSE 总和。MATLAB 没有针对 trainNetwork 的内置网格搜索用 experiment manager 或手工循环枚举学习率与网络宽度就够不要为了调参引入不必要的复杂度。5. 预测、还原与评估多输出结果怎么算分才公平5.1 predict 输出与 mapminmax reverse 的还原顺序训练完成后用 predict 对测试集做前向推理。predict 返回一个与 Yte 同尺寸的矩阵行对应样本、列对应输出维度顺序与训练时的目标矩阵完全一致。YPred_n predict(net, Xte_n); % 先还原预测值再回算到原始物理单位 YPred mapminmax(reverse, YPred_n, psY); Yte_raw mapminmax(reverse, Yte_n, psY);还原时有三个容易出错的位置。第一必须用训练时保存的 psY不能在测试集上重新估计第二mapminmax(reverse, ...) 同样按行操作先转置再转回来第三还原必须在计算误差之前完成在归一化空间算 RMSE 得到的是无量纲值不反映真实误差而且各列还原系数不同归一化空间的指标排序与真实空间可能不一致误导调参方向。如果只需要部分输出列可以索引 YPred_n(:, 2:3) 再还原psY 依然有效因为 psY 记录了每个输出列独立的映射参数取子列不影响对应关系。5.2 逐列计算 RMSE、MAE、R² 并检查时间错位多输出评估的第一原则是逐列算、再汇总不要直接算整个矩阵的 RMSE。输出列即使归一化后尺度一致还原到物理单位后差异也很大一个大尺度输出会淹没小尺度输出的误差rmse sqrt(mean((Yte_raw - YPred).^2, 1)); mae mean(abs(Yte_raw - YPred), 1); ss sum((Yte_raw - mean(Yte_raw,1)).^2, 1); r2 1 - sum((Yte_raw - YPred).^2, 1) ./ ss; for i 1:size(Yte_raw,2) fprintf(输出%d: RMSE%.4f, MAE%.4f, R2%.4f\n, i, rmse(i), mae(i), r2(i)); end % 每个输出画散点预测值对真实值对角线为理想线 figure; for i 1:size(Yte_raw,2) subplot(2, 2, i); scatter(Yte_raw(:,i), YPred(:,i), 12, filled); hold on; lim [min(Yte_raw(:,i)), max(Yte_raw(:,i))]; plot(lim, lim, r--, LineWidth, 1); xlabel(真实值); ylabel(预测值); title(sprintf(输出 %d: R^2 %.3f, i, r2(i))); endR² 的公式里用到每个输出自己的均值逐列计算天然正确。subplot(2,2,i) 的布局假设输出是 4 列输出数不同时改成 ceil(m/2) 与 2 的组合即可。如果输出是时间序列散点图看不出相位滞后务必把真实值和预测值画在同一张时间轴图上检查是否存在明显的错位——这是时间序列 MIMO 预测里最常被跳过的验证步骤。最后一个实用技巧验证共享网络是否真的利用到了多输出间的相关信息。把输出层从 fullyConnectedLayer(4) 改成 fullyConnectedLayer(1)分别对每个输出单独训练一遍比较各输出的验证 RMSE。共享网络在大多数输出上显著更优说明公共特征提取有效如果反而更差说明输出间干扰大于共享收益回到前面的分组建模思路。这个对照实验只需改一行代码却是判断 MIMO 架构是否值得保留的最快方法。本文还有配套的精品资源点击获取
返回列表