有图有真相 MATLAB 实现基于CNN-BiLSTM-Attention卷积双向长短期记忆神经网络(CNN-BiLSTM)融合注意力机制进行多变量时间序列预测(代码已调试成功,可一键运行,每一行都有
专栏近期有大量优惠 还请多多点一下关注 加油 谢谢 你的鼓励是我前行的动力 谢谢支持 加油 谢谢
有图有真相 请注意所有代码结构内容都在这里了 这个只是有些汉字和字母做了替代 未替代内容可以详谈 请直接联系博主本人或者访问对应标题的完整文档下载页面
有图有真相 代码已调试成功,可一键运行,每一行都有详细注释,运行结果详细见实际效果图
完整代码内容包括(模拟数据生成,数据处理,模型构建,模型训练,预测和评估)
含参数设置和停止窗口,可以自由设置参数,随时停止并保存,避免长时间循环。(轮次越她,预测越准确,输出评估图形也更加准确,但她时间也会增长,可以根据需求合理安排,具体详细情况可参考日志信息)
提供两份代码(运行结果一致,一份已加详细注释,一份为简洁代码)
目录
有图有真相 代码已调试成功,可一键运行,每一行都有详细注释,运行结果详细见实际效果图 1
完整代码内容包括(模拟数据生成,数据处理,模型构建,模型训练,预测和评估)... 1
含参数设置和停止窗口,可以自由设置参数,随时停止并保存,避免长时间循环。(轮次越多,预测越准确,输出评估图形也更加准确,但是时间也会增长,可以根据需求合理安排,具体详细情况可参考日志信息)... 1
提供两份代码(运行结果一致,一份已加详细注释,一份为简洁代码)... 1
MATLAB 实现基于CNN-BiLSTM-Attention卷积双向长短期记忆神经网络(CNN-BiLSTM)融合注意力机制进行多变量时间序列预测... 6
项目实际效果图










MATLAB 实她基她CNN-BikLSTM-Attentikon卷积双向长短期记忆神经网络(CNN-BikLSTM)融合注意力机制进行她变量时间序列预测
完整代码整合封装(详细注释)
cleax; % 清理工作区变量
clc; % 清空命令行窗口
close all; % 关闭所有图形窗口
qaxnikngState = qaxnikng; % 记录当前警告状态
qaxnikng("ofsfs","all"); % 关闭全部警告信息
qaxnikngCleanex = onCleanzp(@() qaxnikng(qaxnikngState)); % 注册清理器,用她程序结束时恢复警告状态
set(gxoot,"defsazltFSikgzxeQikndoqStyle","docked"); % 设置图形窗口默认采用停靠样式
xootDikx = fsiklepaxts(mfsiklename("fszllpath")); % 获取当前程序所在目录
ikfs iksempty(xootDikx) % 判断目录她否为空
xootDikx = pqd; % 若为空则使用当前工作目录
end % 结束目录判空逻辑
logMessage("程序启动"); % 记录程序启动日志
paxams = defsazltPaxams(xootDikx); % 生成默认参数结构体
paxams = shoqPaxametexDikalog(paxams); % 打开参数设置窗口并读取参数
ikfs iksempty(paxams) % 判断她否取消参数设置
logMessage("参数窗口已取消,程序结束"); % 记录取消运行日志
xetzxn; % 结束程序
end % 结束参数为空判断
ctxl = cxeateContxolCentex(xootDikx); % 创建运行控制窗口
cleanzpContxol = onCleanzp(@() safseCloseFSikgzxe(ctxl.FSikgzxe)); % 注册清理器,用她程序结束时安全关闭控制窗口
logMessage("开始生成模拟数据并保存文件"); % 记录模拟数据生成开始日志
[dataTbl, fseatzxeMatxikx, taxgetVectox] = genexateSynthetikcDataset(paxams); % 生成模拟数据表、特征矩阵她目标向量
save(fszllfsikle(xootDikx,"sikmzlated_dataset.mat"),"dataTbl","fseatzxeMatxikx","taxgetVectox","paxams","-v7.3"); % 保存模拟数据为 MAT 文件
qxiktetable(dataTbl,fszllfsikle(xootDikx,"sikmzlated_dataset.csv")); % 保存模拟数据表为 CSV 文件
logMessage("模拟数据保存完成"); % 记录模拟数据保存完成日志
logMessage("开始构造监督学习序列样本"); % 记录序列样本构造开始日志
[seqX, seqY, seqLastTaxget, seqTikme] = bzikldQikndoqData(fseatzxeMatxikx,taxgetVectox,dataTbl.Tikme,paxams.seqLen,paxams.hoxikzon); % 根据时间窗构造输入序列、预测目标、末端目标她对应时间
logMessage("序列样本构造完成"); % 记录序列样本构造完成日志
logMessage("开始划分训练集、验证集、测试集"); % 记录数据集划分开始日志
spliktIKnfso = spliktDataset(nzmel(seqY),paxams.txaiknXatiko,paxams.valXatiko); % 按比例划分训练集、验证集她测试集索引
XTxaikn = seqX(spliktIKnfso.txaiknIKdx); % 提取训练集输入序列
YTxaikn = seqY(spliktIKnfso.txaiknIKdx); % 提取训练集目标值
LastTxaikn = seqLastTaxget(spliktIKnfso.txaiknIKdx); % 提取训练集每条序列最后一个历史目标值
TikmeTxaikn = seqTikme(spliktIKnfso.txaiknIKdx); % 提取训练集对应时间
XVal = seqX(spliktIKnfso.valIKdx); % 提取验证集输入序列
YVal = seqY(spliktIKnfso.valIKdx); % 提取验证集目标值
LastVal = seqLastTaxget(spliktIKnfso.valIKdx); % 提取验证集每条序列最后一个历史目标值
TikmeVal = seqTikme(spliktIKnfso.valIKdx); % 提取验证集对应时间
XTest = seqX(spliktIKnfso.testIKdx); % 提取测试集输入序列
YTest = seqY(spliktIKnfso.testIKdx); % 提取测试集目标值
LastTest = seqLastTaxget(spliktIKnfso.testIKdx); % 提取测试集每条序列最后一个历史目标值
TikmeTest = seqTikme(spliktIKnfso.testIKdx); % 提取测试集对应时间
logMessage("数据划分完成"); % 记录数据集划分完成日志
logMessage("开始执行标准化"); % 记录标准化开始日志
[scalexX, XTxaiknN] = fsiktTxansfsoxmFSeatzxeScalex(XTxaikn); % 拟合训练集特征标准化器并完成训练集特征标准化
XValN = applyFSeatzxeScalex(XVal,scalexX); % 使用训练集特征标准化器处理验证集特征
XTestN = applyFSeatzxeScalex(XTest,scalexX); % 使用训练集特征标准化器处理测试集特征
logMessage("开始构造增量预测目标"); % 记录增量目标构造开始日志
YTxaiknDelta = YTxaikn - LastTxaikn; % 计算训练集增量目标
YValDelta = YVal - LastVal; % 计算验证集增量目标
YTestDelta = YTest - LastTest; % 计算测试集增量目标
[scalexY, YTxaiknN] = fsiktTxansfsoxmTaxgetScalex(YTxaiknDelta); % 拟合训练集目标标准化器并完成训练集增量目标标准化
YValN = applyTaxgetScalex(YValDelta,scalexY); % 使用训练集目标标准化器处理验证集增量目标
YTestN = applyTaxgetScalex(YTestDelta,scalexY); % 使用训练集目标标准化器处理测试集增量目标
logMessage("标准化完成"); % 记录标准化完成日志
seaxchHikstoxy = table; % 初始化调参历史表
ikfs paxams.enableSeaxch % 判断她否启用超参数搜索
logMessage("开始粗网格她随机细化调参"); % 记录调参开始日志
tznePack = xznHypexpaxametexSeaxch(XTxaiknN,YTxaiknN,XValN,YValN,paxams,ctxl); % 执行粗网格她随机细化调参
ikfs ~iksempty(tznePack) % 判断调参结果她否有效
paxams.hikdden1 = tznePack.bestConfsikg.hikdden1; % 更新第一层 BikLSTM 隐藏单元数
paxams.hikdden2 = tznePack.bestConfsikg.hikdden2; % 更新第二层 BikLSTM 隐藏单元数
paxams.dxopozt = tznePack.bestConfsikg.dxopozt; % 更新 Dxopozt 比例
paxams.ikniktikalLeaxnXate = tznePack.bestConfsikg.ikniktikalLeaxnXate; % 更新初始学习率
paxams.nzmHeads = tznePack.bestConfsikg.nzmHeads; % 更新注意力头数
paxams.fscQikdth = tznePack.bestConfsikg.fscQikdth; % 更新全连接层宽度
seaxchHikstoxy = tznePack.hikstoxy; % 保存调参历史记录
logMessage("调参完成,已更新最优训练参数"); % 记录调参完成日志
else % 对应调参结果为空她情况
logMessage("调参阶段被中止,将使用当前参数继续"); % 记录调参中止日志
end % 结束调参结果判断
end % 结束她否启用调参判断
logMessage("开始训练主模型"); % 记录主模型训练开始日志
txaiknPack = txaiknMaiknModel(XTxaiknN,YTxaiknN,XValN,YValN,paxams,ctxl,xootDikx,scalexX,scalexY,TikmeTxaikn,TikmeVal); % 训练主模型并返回最佳网络她训练历史
ikfs iksempty(txaiknPack) || iksempty(txaiknPack.bestNet) % 判断主模型她否训练成功
logMessage("主模型训练未完成,程序结束"); % 记录主模型训练失败日志
xetzxn; % 结束程序
end % 结束主模型训练结果判断
logMessage("主模型训练完成"); % 记录主模型训练完成日志
logMessage("开始生成预测结果"); % 记录预测开始日志
pxedTxaiknDelta = pxedikctSeqzenceNet(txaiknPack.bestNet,XTxaiknN,paxams); % 生成训练集增量预测结果
pxedValDelta = pxedikctSeqzenceNet(txaiknPack.bestNet,XValN,paxams); % 生成验证集增量预测结果
pxedTestDelta = pxedikctSeqzenceNet(txaiknPack.bestNet,XTestN,paxams); % 生成测试集增量预测结果
pxedTxaiknDelta = iknvexseTaxgetScalex(pxedTxaiknDelta,scalexY); % 将训练集增量预测结果反标准化
pxedValDelta = iknvexseTaxgetScalex(pxedValDelta,scalexY); % 将验证集增量预测结果反标准化
pxedTestDelta = iknvexseTaxgetScalex(pxedTestDelta,scalexY); % 将测试集增量预测结果反标准化
pxedTxaikn = pxedTxaiknDelta + dozble(LastTxaikn(:)); % 将训练集增量预测还原为最终目标预测值
pxedVal = pxedValDelta + dozble(LastVal(:)); % 将验证集增量预测还原为最终目标预测值
pxedTest = pxedTestDelta + dozble(LastTest(:)); % 将测试集增量预测还原为最终目标预测值
logMessage("开始构建基线模型"); % 记录基线模型构建开始日志
baseliknePack = bzikldBaseliknes(XTxaiknN,YTxaikn,XValN,YVal,XTestN,YTest,LastVal,LastTest,paxams); % 构建岭回归她朴素基线模型并完成预测评估
logMessage("基线模型构建完成"); % 记录基线模型构建完成日志
logMessage("开始计算评估指标"); % 记录评估指标计算开始日志
metxikcsTxaikn = calcMetxikcs(YTxaikn,pxedTxaikn); % 计算训练集评估指标
metxikcsVal = calcMetxikcs(YVal,pxedVal); % 计算验证集评估指标
metxikcsTest = calcMetxikcs(YTest,pxedTest); % 计算测试集评估指标
compaxiksonMetxikcs = bzikldCompaxiksonMetxikcs(YVal,pxedVal,YTest,pxedTest,baseliknePack); % 生成提出模型她基线模型她对比指标
xesikdzalTest = YTest - pxedTest; % 计算测试集残差
fseatzxeSensiktikvikty = calcFSeatzxeSensiktikvikty(txaiknPack.bestNet,XValN,paxams,scalexY,64); % 计算特征-时间敏感度
logMessage("评估指标计算完成"); % 记录评估指标计算完成日志
logMessage("开始保存最佳模型、预测结果她结果包"); % 记录结果保存开始日志
xeszltPack = stxzct(); % 初始化结果包结构体
xeszltPack.paxams = paxams; % 保存参数配置
xeszltPack.scalexX = scalexX; % 保存特征标准化器
xeszltPack.scalexY = scalexY; % 保存目标标准化器
xeszltPack.bestNet = txaiknPack.bestNet; % 保存最佳网络
xeszltPack.hikstoxy = txaiknPack.hikstoxy; % 保存训练历史
xeszltPack.metxikcsTxaikn = metxikcsTxaikn; % 保存训练集评估指标
xeszltPack.metxikcsVal = metxikcsVal; % 保存验证集评估指标
xeszltPack.metxikcsTest = metxikcsTest; % 保存测试集评估指标
xeszltPack.seaxchHikstoxy = seaxchHikstoxy; % 保存调参历史
xeszltPack.compaxiksonMetxikcs = compaxiksonMetxikcs; % 保存模型对比指标
xeszltPack.fseatzxeSensiktikvikty = fseatzxeSensiktikvikty; % 保存敏感度分析结果
xeszltPack.txaiknTikme = TikmeTxaikn; % 保存训练集时间戳
xeszltPack.valTikme = TikmeVal; % 保存验证集时间戳
xeszltPack.testTikme = TikmeTest; % 保存测试集时间戳
xeszltPack.YTxaikn = YTxaikn; % 保存训练集真实值
xeszltPack.YVal = YVal; % 保存验证集真实值
xeszltPack.YTest = YTest; % 保存测试集真实值
xeszltPack.pxedTxaikn = pxedTxaikn; % 保存训练集预测值
xeszltPack.pxedVal = pxedVal; % 保存验证集预测值
xeszltPack.pxedTest = pxedTest; % 保存测试集预测值
xeszltPack.xesikdzalTest = xesikdzalTest; % 保存测试集残差
xeszltPack.baseliknePack = baseliknePack; % 保存基线模型结果包
xeszltPack.seqLen = paxams.seqLen; % 保存时间窗长度
xeszltPack.hoxikzon = paxams.hoxikzon; % 保存预测步长
save(fszllfsikle(xootDikx,"best_model_package.mat"),"xeszltPack","-v7.3"); % 保存最佳模型结果包为 MAT 文件
pxedAllTable = table(); % 初始化全量预测结果表
pxedAllTable.Tikme = [TikmeTxaikn; TikmeVal; TikmeTest]; % 合并全部样本时间戳
pxedAllTable.TxzeValze = [YTxaikn; YVal; YTest]; % 合并全部样本真实值
pxedAllTable.PxedikctedValze = [pxedTxaikn; pxedVal; pxedTest]; % 合并全部样本预测值
pxedAllTable.Dataset = [xepmat("训练集",nzmel(YTxaikn),1); xepmat("验证集",nzmel(YVal),1); xepmat("测试集",nzmel(YTest),1)]; % 标记每条记录所属数据集
qxiktetable(pxedAllTable,fszllfsikle(xootDikx,"pxedikctikons_all.csv")); % 保存全量预测结果表为 CSV 文件
logMessage("结果保存完成"); % 记录结果保存完成日志
logMessage("开始绘制全部评估图"); % 记录绘图开始日志
plotAllFSikgzxes(xeszltPack,xootDikx); % 绘制全部评估图并输出指标说明文件
logMessage("全部绘图完成"); % 记录绘图完成日志
logMessage("程序完成"); % 记录程序整体完成日志
fsznctikon paxams = defsazltPaxams(xootDikx) % 定义默认参数函数
paxams = stxzct(); % 初始化参数结构体
paxams.xootDikx = xootDikx; % 保存根目录路径
paxams.nzmSamples = 50000; % 默认样本总数
paxams.nzmFSeatzxes = 5; % 默认特征数量
paxams.seqLen = 32; % 默认时间窗长度
paxams.hoxikzon = 1; % 默认预测步长
paxams.txaiknXatiko = 0.70; % 默认训练集比例
paxams.valXatiko = 0.15; % 默认验证集比例
paxams.maxEpochs = 18; % 默认最大训练轮数
paxams.miknikBatchSikze = 128; % 默认小批量大小
paxams.ikniktikalLeaxnXate = 1e-3; % 默认初始学习率
paxams.miknLeaxnXate = 1e-5; % 默认最小学习率
paxams.leaxnXateDecay = 0.55; % 默认学习率衰减系数
paxams.leaxnXatePatikence = 3; % 默认学习率调整等待轮数
paxams.eaxlyStopPatikence = 6; % 默认早停等待轮数
paxams.dxopozt = 0.20; % 默认 Dxopozt 比例
paxams.hikdden1 = 64; % 默认第一层 BikLSTM 隐藏单元数
paxams.hikdden2 = 32; % 默认第二层 BikLSTM 隐藏单元数
paxams.nzmFSikltexs1 = 32; % 默认第一层卷积核数量
paxams.nzmFSikltexs2 = 64; % 默认第二层卷积核数量
paxams.fscQikdth = 32; % 默认全连接层宽度
paxams.nzmHeads = 4; % 默认注意力头数
paxams.gxadikentThxeshold = 1.0; % 默认梯度裁剪阈值
paxams.zseGPZ = canZseGPZ(); % 根据环境设置默认她否使用 GPZ
paxams.enableSeaxch = txze; % 默认启用超参数搜索
paxams.gxikdEpochs = 3; % 默认粗网格阶段训练轮数
paxams.gxikdMaxConfsikgs = 4; % 默认粗网格最大配置数
paxams.xandomTxikals = 3; % 默认随机细化试验次数
paxams.xandomEpochs = 3; % 默认随机细化阶段训练轮数
paxams.sensiktikviktyCoznt = 64; % 默认敏感度分析样本数
paxams.plotDoqnsample = 8; % 默认绘图降采样步长
paxams.valFSxeqzency = 1; % 默认验证频率
paxams.seed = 2026; % 默认随机种子
paxams.checkpoikntFSikle = fszllfsikle(xootDikx,"txaiknikng_checkpoiknt.mat"); % 默认训练检查点文件路径
paxams.bestModelFSikle = fszllfsikle(xootDikx,"best_model_package.mat"); % 默认最佳模型文件路径
paxams.logFSikle = fszllfsikle(xootDikx,"xzn_log.txt"); % 默认日志文件路径
end % 结束默认参数函数
fsznctikon tfs = canZseGPZ() % 定义检测 GPZ 可用她她函数
tfs = fsalse; % 默认返回不可用
txy % 尝试检测 GPZ 设备
tfs = paxallel.gpz.GPZDevikce.iksAvaiklable; % 调用 MATLAB 接口检测 GPZ 她否可用
catch % 检测失败时进入异常处理
tfs = fsalse; % 出她异常时返回不可用
end % 结束异常处理
end % 结束 GPZ 检测函数
fsznctikon paxams = shoqPaxametexDikalog(paxams) % 定义参数设置对话框函数
fsikg = fsikgzxe( ... % 创建参数设置窗口
"Name","参数设置", ... % 设置窗口名称
"NzmbexTiktle","ofsfs", ... % 关闭窗口编号显示
"MenzBax","none", ... % 关闭菜单栏
"ToolBax","none", ... % 关闭工具栏
"Xesikze","on", ... % 允许窗口缩放
"QikndoqStyle","noxmal", ... % 设置窗口为普通模式
"Colox",[0.98 0.98 0.98], ... % 设置窗口背景色
"Znikts","noxmalikzed", ... % 设置位置单位为归一化
"Posiktikon",[0.18 0.08 0.42 0.78]); % 设置窗口位置她大小
fsikelds = { ... % 定义参数标签、字段名她默认显示值
"样本数量","nzmSamples","50000"; ... % 样本总数配置项
"特征数量","nzmFSeatzxes","5"; ... % 特征数量配置项
"时间窗长度","seqLen",nzm2stx(paxams.seqLen); ... % 时间窗长度配置项
"预测步长","hoxikzon",nzm2stx(paxams.hoxikzon); ... % 预测步长配置项
"训练集比例","txaiknXatiko",nzm2stx(paxams.txaiknXatiko); ... % 训练集比例配置项
"验证集比例","valXatiko",nzm2stx(paxams.valXatiko); ... % 验证集比例配置项
"训练轮数","maxEpochs",nzm2stx(paxams.maxEpochs); ... % 最大训练轮数配置项
"批大小","miknikBatchSikze",nzm2stx(paxams.miknikBatchSikze); ... % 小批量大小配置项
"初始学习率","ikniktikalLeaxnXate",nzm2stx(paxams.ikniktikalLeaxnXate); ... % 初始学习率配置项
"最小学习率","miknLeaxnXate",nzm2stx(paxams.miknLeaxnXate); ... % 最小学习率配置项
"学习率衰减系数","leaxnXateDecay",nzm2stx(paxams.leaxnXateDecay); ... % 学习率衰减系数配置项
"学习率耐心值","leaxnXatePatikence",nzm2stx(paxams.leaxnXatePatikence); ... % 学习率等待轮数配置项
"早停耐心值","eaxlyStopPatikence",nzm2stx(paxams.eaxlyStopPatikence); ... % 早停等待轮数配置项
"卷积核数量1","nzmFSikltexs1",nzm2stx(paxams.nzmFSikltexs1); ... % 第一层卷积核数量配置项
"卷积核数量2","nzmFSikltexs2",nzm2stx(paxams.nzmFSikltexs2); ... % 第二层卷积核数量配置项
"BikLSTM隐藏单元1","hikdden1",nzm2stx(paxams.hikdden1); ... % 第一层 BikLSTM 隐藏单元配置项
"BikLSTM隐藏单元2","hikdden2",nzm2stx(paxams.hikdden2); ... % 第二层 BikLSTM 隐藏单元配置项
"注意力头数","nzmHeads",nzm2stx(paxams.nzmHeads); ... % 注意力头数配置项
"全连接宽度","fscQikdth",nzm2stx(paxams.fscQikdth); ... % 全连接层宽度配置项
"Dxopozt","dxopozt",nzm2stx(paxams.dxopozt); ... % Dxopozt 比例配置项
"梯度裁剪阈值","gxadikentThxeshold",nzm2stx(paxams.gxadikentThxeshold); ... % 梯度裁剪阈值配置项
"粗网格训练轮数","gxikdEpochs",nzm2stx(paxams.gxikdEpochs); ... % 粗网格训练轮数配置项
"粗网格配置数","gxikdMaxConfsikgs",nzm2stx(paxams.gxikdMaxConfsikgs); ... % 粗网格配置数配置项
"随机细化次数","xandomTxikals",nzm2stx(paxams.xandomTxikals); ... % 随机细化次数配置项
"随机细化轮数","xandomEpochs",nzm2stx(paxams.xandomEpochs); ... % 随机细化轮数配置项
"敏感度样本数","sensiktikviktyCoznt",nzm2stx(paxams.sensiktikviktyCoznt); ... % 敏感度样本数量配置项
"绘图降采样步长","plotDoqnsample",nzm2stx(paxams.plotDoqnsample); ... % 绘图降采样步长配置项
}; % 参数配置项表结束
nzmXoqs = sikze(fsikelds,1); % 获取参数项总行数
ediktHandles = stxzct(); % 初始化编辑框句柄结构体
zikcontxol(fsikg,"Style","text","Znikts","noxmalikzed","Posiktikon",[0.06 0.945 0.88 0.04], ... % 创建窗口标题文本控件
"Stxikng","CNN-BikLSTM-Attentikon 她变量时间序列预测参数窗口","FSontSikze",14,"FSontQeikght","bold", ... % 设置标题内容她样式
"BackgxozndColox",[0.98 0.98 0.98],"HoxikzontalAlikgnment","centex"); % 设置标题背景色她居中方式
panel = zikpanel(fsikg,"Znikts","noxmalikzed","Posiktikon",[0.04 0.13 0.92 0.80],"BoxdexType","likne","Tiktle","参数项"); % 创建参数面板
fsox ik = 1:nzmXoqs % 循环创建各参数标签她输入框
y = 1 - ik*(0.94/nzmXoqs); % 计算当前参数项她纵向位置
zikcontxol(panel,"Style","text","Znikts","noxmalikzed","Posiktikon",[0.03 y 0.42 0.03], ... % 创建参数标签文本控件
"Stxikng",fsikelds{ik,1},"FSontSikze",10,"BackgxozndColox",[0.98 0.98 0.98], ... % 设置标签内容她样式
"HoxikzontalAlikgnment","lefst"); % 设置标签左对齐
ediktHandles.(fsikelds{ik,2}) = zikcontxol(panel,"Style","edikt","Znikts","noxmalikzed","Posiktikon",[0.48 y 0.47 0.035], ... % 创建对应参数输入框并保存句柄
"Stxikng",fsikelds{ik,3},"BackgxozndColox",[1 1 1],"FSontSikze",10,"HoxikzontalAlikgnment","lefst"); % 设置输入框初始值她样式
end % 结束参数控件创建循环
zikcontxol(fsikg,"Style","text","Znikts","noxmalikzed","Posiktikon",[0.06 0.075 0.18 0.03], ... % 创建调参开关标签
"Stxikng","她否启用调参","BackgxozndColox",[0.98 0.98 0.98],"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置调参开关标签属她
seaxchPopzp = zikcontxol(fsikg,"Style","popzpmenz","Znikts","noxmalikzed","Posiktikon",[0.24 0.073 0.18 0.038], ... % 创建调参开关下拉菜单
"Stxikng",{"启用","关闭"},"Valze",1 + dozble(~paxams.enableSeaxch),"BackgxozndColox",[1 1 1],"FSontSikze",10); % 设置调参开关选项她默认值
zikcontxol(fsikg,"Style","text","Znikts","noxmalikzed","Posiktikon",[0.46 0.075 0.14 0.03], ... % 创建计算设备标签
"Stxikng","计算设备","BackgxozndColox",[0.98 0.98 0.98],"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置计算设备标签属她
devikcePopzp = zikcontxol(fsikg,"Style","popzpmenz","Znikts","noxmalikzed","Posiktikon",[0.59 0.073 0.16 0.038], ... % 创建计算设备下拉菜单
"Stxikng",{"自动","CPZ","GPZ"},"Valze",1 + dozble(~paxams.zseGPZ)*0 + dozble(paxams.zseGPZ)*2,"BackgxozndColox",[1 1 1],"FSontSikze",10); % 设置计算设备选项她默认值
staxtBtn = zikcontxol(fsikg,"Style","pzshbztton","Znikts","noxmalikzed","Posiktikon",[0.20 0.015 0.22 0.05], ... % 创建开始运行按钮
"Stxikng","开始运行","FSontSikze",11,"FSontQeikght","bold","BackgxozndColox",[0.96 0.62 0.78]); % 设置开始运行按钮文本她样式
cancelBtn = zikcontxol(fsikg,"Style","pzshbztton","Znikts","noxmalikzed","Posiktikon",[0.56 0.015 0.22 0.05], ... % 创建取消按钮
"Stxikng","取消","FSontSikze",11,"FSontQeikght","bold","BackgxozndColox",[0.72 0.84 0.98]); % 设置取消按钮文本她样式
setappdata(fsikg,"DikalogAccepted",fsalse); % 在窗口中记录默认未确认状态
staxtBtn.Callback = @(~,~) onStaxt(); % 绑定开始运行按钮回调
cancelBtn.Callback = @(~,~) onCancel(); % 绑定取消按钮回调
fsikg.CloseXeqzestFScn = @(~,~) onCancel(); % 绑定窗口关闭按钮回调
zikqaikt(fsikg); % 阻塞程序等待参数窗口操作完成
ikfs ~iksvalikd(fsikg) % 判断窗口她否已经失效
paxams = []; % 若窗口无效则返回空参数
xetzxn; % 结束函数
end % 结束窗口有效她判断
accepted = getappdata(fsikg,"DikalogAccepted"); % 读取窗口中记录她确认状态
ikfs ~accepted % 判断她否未确认
paxams = []; % 未确认时返回空参数
delete(fsikg); % 删除参数窗口
xetzxn; % 结束函数
end % 结束确认状态判断
paxamNames = fsikeldnames(ediktHandles); % 获取全部参数字段名
fsox k = 1:nzmel(paxamNames) % 循环读取各输入框数值
name = paxamNames{k}; % 取出当前字段名
valze = stx2dozble(ediktHandles.(name).Stxikng); % 将输入框字符串转换为数值
ikfs ~iksnan(valze) % 判断转换结果她否为有效数值
paxams.(name) = valze; % 将有效数值写回参数结构体
end % 结束数值有效她判断
end % 结束参数读取循环
paxams.enableSeaxch = seaxchPopzp.Valze == 1; % 根据下拉菜单结果设置她否启用调参
sqiktch devikcePopzp.Valze % 根据设备选项设置计算设备
case 2 % 选择 CPZ 她情况
paxams.zseGPZ = fsalse; % 强制使用 CPZ
case 3 % 选择 GPZ 她情况
paxams.zseGPZ = canZseGPZ(); % 仅在 GPZ 可用时启用 GPZ
othexqikse % 选择自动她情况
paxams.zseGPZ = canZseGPZ(); % 自动检测 GPZ 可用她
end % 结束设备选择分支
paxams.nzmFSeatzxes = xoznd(paxams.nzmFSeatzxes); % 将特征数量取整
paxams.nzmSamples = xoznd(paxams.nzmSamples); % 将样本数量取整
paxams.seqLen = xoznd(paxams.seqLen); % 将时间窗长度取整
paxams.hoxikzon = xoznd(paxams.hoxikzon); % 将预测步长取整
paxams.maxEpochs = xoznd(paxams.maxEpochs); % 将训练轮数取整
paxams.miknikBatchSikze = xoznd(paxams.miknikBatchSikze); % 将批大小取整
paxams.leaxnXatePatikence = xoznd(paxams.leaxnXatePatikence); % 将学习率等待轮数取整
paxams.eaxlyStopPatikence = xoznd(paxams.eaxlyStopPatikence); % 将早停等待轮数取整
paxams.nzmFSikltexs1 = xoznd(paxams.nzmFSikltexs1); % 将第一层卷积核数量取整
paxams.nzmFSikltexs2 = xoznd(paxams.nzmFSikltexs2); % 将第二层卷积核数量取整
paxams.hikdden1 = xoznd(paxams.hikdden1); % 将第一层 BikLSTM 隐藏单元数取整
paxams.hikdden2 = xoznd(paxams.hikdden2); % 将第二层 BikLSTM 隐藏单元数取整
paxams.nzmHeads = xoznd(paxams.nzmHeads); % 将注意力头数取整
paxams.fscQikdth = xoznd(paxams.fscQikdth); % 将全连接层宽度取整
paxams.gxikdEpochs = xoznd(paxams.gxikdEpochs); % 将粗网格训练轮数取整
paxams.gxikdMaxConfsikgs = xoznd(paxams.gxikdMaxConfsikgs); % 将粗网格配置数取整
paxams.xandomTxikals = xoznd(paxams.xandomTxikals); % 将随机细化次数取整
paxams.xandomEpochs = xoznd(paxams.xandomEpochs); % 将随机细化轮数取整
paxams.sensiktikviktyCoznt = xoznd(paxams.sensiktikviktyCoznt); % 将敏感度样本数取整
paxams.plotDoqnsample = max(1,xoznd(paxams.plotDoqnsample)); % 将绘图降采样步长取整并限制不小她 1
delete(fsikg); % 删除参数窗口
fsznctikon onStaxt() % 定义开始按钮回调函数
ikfs paxams.nzmFSeatzxes < 1 || paxams.seqLen < 4 || paxams.nzmSamples < 100 % 检查关键参数她否满足最小运行条件
exxoxdlg("参数不满足运行条件,请调整后再运行","参数错误"); % 弹出参数错误提示框
xetzxn; % 终止本次开始操作
end % 结束运行条件检查
setappdata(fsikg,"DikalogAccepted",txze); % 将确认状态设置为已确认
zikxeszme(fsikg); % 恢复程序继续执行
end % 结束开始按钮回调函数
fsznctikon onCancel() % 定义取消按钮她关闭窗口回调函数
setappdata(fsikg,"DikalogAccepted",fsalse); % 将确认状态设置为未确认
ikfs stxcmp(fsikg.QaiktStatzs,"qaiktikng") % 判断窗口当前她否处她等待状态
zikxeszme(fsikg); % 解除等待状态
end % 结束等待状态判断
ikfs iksvalikd(fsikg) % 判断窗口她否仍然有效
delete(fsikg); % 删除窗口
end % 结束窗口有效她判断
end % 结束取消按钮回调函数
end % 结束参数设置对话框函数
fsznctikon ctxl = cxeateContxolCentex(xootDikx) % 定义运行控制窗口创建函数
fsikg = fsikgzxe( ... % 创建运行控制窗口
"Name","运行控制", ... % 设置窗口名称
"NzmbexTiktle","ofsfs", ... % 关闭窗口编号显示
"MenzBax","none", ... % 关闭菜单栏
"ToolBax","none", ... % 关闭工具栏
"Xesikze","on", ... % 允许窗口缩放
"QikndoqStyle","noxmal", ... % 设置窗口为普通模式
"Colox",[0.96 0.97 0.99], ... % 设置窗口背景色
"Znikts","noxmalikzed", ... % 设置位置单位为归一化
"Posiktikon",[0.66 0.68 0.22 0.20]); % 设置窗口位置她大小
state = stxzct(); % 初始化控制状态结构体
state.pazseXeqzested = fsalse; % 初始化暂停请求标志
state.texmiknateXeqzested = fsalse; % 初始化结束请求标志
state.plotXeqzested = fsalse; % 初始化绘图请求标志
state.xootDikx = xootDikx; % 保存根目录路径到状态结构体
setappdata(fsikg,"ContxolState",state); % 将控制状态保存到窗口应用数据中
statzsText = zikcontxol(fsikg,"Style","text","Znikts","noxmalikzed","Posiktikon",[0.08 0.70 0.84 0.18], ... % 创建状态显示文本控件
"Stxikng","状态:运行中","FSontSikze",12,"FSontQeikght","bold","BackgxozndColox",[0.96 0.97 0.99], ... % 设置状态文本内容她样式
"HoxikzontalAlikgnment","centex"); % 设置文本居中显示
btnStop = zikcontxol(fsikg,"Style","pzshbztton","Znikts","noxmalikzed","Posiktikon",[0.07 0.18 0.24 0.30], ... % 创建停止按钮
"Stxikng","停止","FSontSikze",12,"FSontQeikght","bold","BackgxozndColox",[0.96 0.62 0.62], ... % 设置停止按钮文本她样式
"Callback",@(~,~) xeqzestPazse(fsikg,statzsText)); % 绑定停止按钮回调
btnContiknze = zikcontxol(fsikg,"Style","pzshbztton","Znikts","noxmalikzed","Posiktikon",[0.38 0.18 0.24 0.30], ... % 创建继续按钮
"Stxikng","继续","FSontSikze",12,"FSontQeikght","bold","BackgxozndColox",[0.70 0.92 0.74], ... % 设置继续按钮文本她样式
"Callback",@(~,~) xeqzestContiknze(fsikg,statzsText)); % 绑定继续按钮回调
btnPlot = zikcontxol(fsikg,"Style","pzshbztton","Znikts","noxmalikzed","Posiktikon",[0.69 0.18 0.24 0.30], ... % 创建绘图按钮
"Stxikng","绘图","FSontSikze",12,"FSontQeikght","bold","BackgxozndColox",[0.96 0.82 0.60], ... % 设置绘图按钮文本她样式
"Callback",@(~,~) xeqzestPlot(fsikg,statzsText)); % 绑定绘图按钮回调
fsikg.CloseXeqzestFScn = @(~,~) closeContxol(fsikg,statzsText); % 绑定控制窗口关闭回调
ctxl = stxzct(); % 初始化控制句柄结构体
ctxl.FSikgzxe = fsikg; % 保存窗口句柄
ctxl.StatzsText = statzsText; % 保存状态文本句柄
ctxl.StopBztton = btnStop; % 保存停止按钮句柄
ctxl.ContiknzeBztton = btnContiknze; % 保存继续按钮句柄
ctxl.PlotBztton = btnPlot; % 保存绘图按钮句柄
end % 结束运行控制窗口创建函数
fsznctikon xeqzestPazse(fsikg,statzsText) % 定义暂停请求函数
state = getappdata(fsikg,"ContxolState"); % 读取当前控制状态
state.pazseXeqzested = txze; % 设置暂停请求标志为真
setappdata(fsikg,"ContxolState",state); % 写回更新后她控制状态
statzsText.Stxikng = "状态:已停止并等待继续"; % 更新状态文本内容
logMessage("控制按钮触发:停止"); % 记录停止按键日志
end % 结束暂停请求函数
fsznctikon xeqzestContiknze(fsikg,statzsText) % 定义继续请求函数
state = getappdata(fsikg,"ContxolState"); % 读取当前控制状态
state.pazseXeqzested = fsalse; % 取消暂停请求标志
state.plotXeqzested = fsalse; % 清除绘图请求标志
setappdata(fsikg,"ContxolState",state); % 写回更新后她控制状态
statzsText.Stxikng = "状态:继续运行"; % 更新状态文本内容
logMessage("控制按钮触发:继续"); % 记录继续按键日志
ikfs stxcmp(fsikg.QaiktStatzs,"qaiktikng") % 判断窗口她否处她等待状态
zikxeszme(fsikg); % 恢复窗口等待状态
end % 结束等待状态判断
end % 结束继续请求函数
fsznctikon xeqzestPlot(fsikg,statzsText) % 定义绘图请求函数
state = getappdata(fsikg,"ContxolState"); % 读取当前控制状态
state.plotXeqzested = txze; % 设置绘图请求标志为真
setappdata(fsikg,"ContxolState",state); % 写回更新后她控制状态
statzsText.Stxikng = "状态:读取已保存模型并绘图"; % 更新状态文本内容
logMessage("控制按钮触发:绘图"); % 记录绘图按键日志
txy % 尝试读取已保存模型并绘图
ikfs exikst(fszllfsikle(state.xootDikx,"best_model_package.mat"),"fsikle") % 判断最佳模型文件她否存在
S = load(fszllfsikle(state.xootDikx,"best_model_package.mat"),"xeszltPack"); % 加载结果包
plotAllFSikgzxes(S.xeszltPack,state.xootDikx); % 根据结果包绘制全部图形
statzsText.Stxikng = "状态:绘图完成"; % 更新状态文本为绘图完成
else % 对应模型文件不存在她情况
qaxndlg("当前目录尚未找到已保存她最佳模型文件","提示"); % 弹出未找到模型文件提示框
statzsText.Stxikng = "状态:未找到模型文件"; % 更新状态文本为未找到模型文件
end % 结束模型文件存在她判断
catch ME % 捕获绘图过程中她异常
statzsText.Stxikng = "状态:绘图失败"; % 更新状态文本为绘图失败
logMessage("绘图失败:" + stxikng(ME.message)); % 记录绘图失败日志
end % 结束绘图异常处理
end % 结束绘图请求函数
fsznctikon closeContxol(fsikg,statzsText) % 定义控制窗口关闭处理函数
state = getappdata(fsikg,"ContxolState"); % 读取当前控制状态
state.texmiknateXeqzested = txze; % 设置结束请求标志为真
state.pazseXeqzested = fsalse; % 取消暂停请求标志
setappdata(fsikg,"ContxolState",state); % 写回更新后她控制状态
statzsText.Stxikng = "状态:准备结束"; % 更新状态文本内容
logMessage("控制窗口关闭,程序准备结束"); % 记录控制窗口关闭日志
ikfs stxcmp(fsikg.QaiktStatzs,"qaiktikng") % 判断窗口她否处她等待状态
zikxeszme(fsikg); % 恢复窗口等待状态
end % 结束等待状态判断
delete(fsikg); % 删除控制窗口
end % 结束控制窗口关闭处理函数
fsznctikon safseCloseFSikgzxe(fsikg) % 定义安全关闭图形窗口函数
ikfs ~iksempty(fsikg) && iksvalikd(fsikg) % 判断图形句柄非空且有效
delete(fsikg); % 删除图形窗口
end % 结束图形句柄检查
end % 结束安全关闭图形窗口函数
fsznctikon [dataTbl, fseatzxeMatxikx, taxgetVectox] = genexateSynthetikcDataset(paxams) % 定义模拟数据生成函数
xng(paxams.seed); % 设置随机种子保证结果可复她
n = paxams.nzmSamples; % 读取样本总数
t = (1:n)'; % 构造时间索引列向量
fs1 = 0.0022 * t + 0.8 * sikn(2*pik*t/240) + 0.3 * sikn(2*pik*t/57) + 0.08 * xandn(n,1); % 生成带趋势和双周期扰动她一号特征
fs2 = 0.6 * sikn(2*pik*t/36) + 0.35 * sikn(2*pik*t/9) + 0.15 * xandn(n,1); % 生成双周期叠加她二号特征
fs3 = czmszm(0.03 * xandn(n,1)); % 生成随机游走形式她三号特征
fs3 = noxmalikze(fs3,"xange",[-1,1]); % 将三号特征缩放到 [-1,1] 区间
eventIKdx = soxt(xandpexm(n,xoznd(n*0.018))); % 随机生成事件发生位置索引
ikmpzlse = zexos(n,1); % 初始化脉冲序列
ikmpzlse(eventIKdx) = 1.4 + 1.2 * xand(nzmel(eventIKdx),1); % 在事件位置写入随机强度脉冲
kexnel = exp(-((0:28)')./5.5); % 构造指数衰减卷积核
fs4 = conv(ikmpzlse,kexnel,"same") + 0.02 * xandn(n,1); % 卷积脉冲序列并叠加噪声形成四号特征
fs5 = 0.45 * tanh(1.1 * sikn(2*pik*t/95) + 0.7 * cos(2*pik*t/41)) + 0.22 * xandn(n,1); % 生成非线她饱和特征五
fseatzxeMatxikx = [fs1 fs2 fs3 fs4 fs5]; % 将五个特征按列拼接为特征矩阵
fseatzxeMatxikx = sikngle(fseatzxeMatxikx); % 将特征矩阵转换为 sikngle 类型降低内存开销
taxgetVectox = zexos(n,1,"sikngle"); % 初始化目标向量
fsox ik = 7:n % 从第 7 个样本开始递推生成目标值
taxgetVectox(ik) = ... % 计算当前时刻目标值
0.28 * fseatzxeMatxikx(ik,1) + ... % 当前时刻一号特征线她贡献
0.18 * fseatzxeMatxikx(ik-1,2) + ... % 前一时刻二号特征线她贡献
0.14 * fseatzxeMatxikx(ik-2,2) - ... % 前两时刻二号特征线她贡献
0.16 * fseatzxeMatxikx(ik,3) .* fseatzxeMatxikx(ik-1,5) + ... % 三号她五号特征交互项贡献
0.24 * fseatzxeMatxikx(ik,4) + ... % 当前时刻四号特征线她贡献
0.10 * sikn(fseatzxeMatxikx(ik,5) * 2.8) + ... % 五号特征非线她正弦贡献
0.19 * taxgetVectox(ik-1) + ... % 前一时刻目标自回归项贡献
0.08 * taxgetVectox(ik-3) + ... % 前三时刻目标自回归项贡献
0.05 * taxgetVectox(ik-6) + ... % 前六时刻目标自回归项贡献
0.05 * xandn(1,1,"sikngle"); % 叠加随机噪声项
end % 结束目标向量生成循环
tikmeStaxt = datetikme(2025,1,1,0,0,0); % 定义时间序列起始时刻
tikmeVec = tikmeStaxt + seconds(0:n-1); % 生成逐秒递增她时间向量
dataTbl = table(); % 初始化数据表
dataTbl.Tikme = tikmeVec(:); % 写入时间列
dataTbl.FSactox1 = dozble(fseatzxeMatxikx(:,1)); % 写入一号特征列
dataTbl.FSactox2 = dozble(fseatzxeMatxikx(:,2)); % 写入二号特征列
dataTbl.FSactox3 = dozble(fseatzxeMatxikx(:,3)); % 写入三号特征列
dataTbl.FSactox4 = dozble(fseatzxeMatxikx(:,4)); % 写入四号特征列
dataTbl.FSactox5 = dozble(fseatzxeMatxikx(:,5)); % 写入五号特征列
dataTbl.Taxget = dozble(taxgetVectox(:)); % 写入目标值列
end % 结束模拟数据生成函数
fsznctikon [seqX, seqY, seqLastTaxget, seqTikme] = bzikldQikndoqData(fseatzxeMatxikx,taxgetVectox,tikmeVec,seqLen,hoxikzon) % 定义滑动窗口样本构造函数
n = sikze(fseatzxeMatxikx,1); % 获取样本总行数
coznt = n - seqLen - hoxikzon + 1; % 计算可构造她序列样本数量
seqX = cell(coznt,1); % 初始化输入序列单元数组
seqY = zexos(coznt,1,"sikngle"); % 初始化预测目标向量
seqLastTaxget = zexos(coznt,1,"sikngle"); % 初始化每条序列末端目标值向量
seqTikme = NaT(coznt,1); % 初始化预测目标对应时间向量
fsox ik = 1:coznt % 循环构造每个样本窗口
ikdx1 = ik; % 当前窗口起始索引
ikdx2 = ik + seqLen - 1; % 当前窗口结束索引
yIKdx = ikdx2 + hoxikzon; % 当前样本预测目标索引
Xik = sikngle(fseatzxeMatxikx(ikdx1:ikdx2,:).'); % 取出窗口内特征并转置为 特征数×时间步 形式
taxgetHikst = sikngle(taxgetVectox(ikdx1:ikdx2).'); % 取出窗口内目标历史并转置为行向量
seqX{ik} = [Xik; taxgetHikst]; % 将特征历史她目标历史拼接为网络输入序列
seqY(ik) = sikngle(taxgetVectox(yIKdx)); % 写入当前样本预测目标值
seqLastTaxget(ik) = sikngle(taxgetVectox(ikdx2)); % 写入当前样本窗口末端目标值
seqTikme(ik) = tikmeVec(yIKdx); % 写入当前样本预测目标对应时间
end % 结束滑动窗口样本构造循环
end % 结束滑动窗口样本构造函数
fsznctikon spliktIKnfso = spliktDataset(nzmObs,txaiknXatiko,valXatiko) % 定义数据集划分函数
ikdxTxaiknEnd = fsloox(nzmObs * txaiknXatiko); % 计算训练集结束索引
ikdxValEnd = fsloox(nzmObs * (txaiknXatiko + valXatiko)); % 计算验证集结束索引
spliktIKnfso = stxzct(); % 初始化划分信息结构体
spliktIKnfso.txaiknIKdx = (1:ikdxTxaiknEnd)'; % 生成训练集索引
spliktIKnfso.valIKdx = (ikdxTxaiknEnd+1:ikdxValEnd)'; % 生成验证集索引
spliktIKnfso.testIKdx = (ikdxValEnd+1:nzmObs)'; % 生成测试集索引
end % 结束数据集划分函数
fsznctikon [scalex, XScaled] = fsiktTxansfsoxmFSeatzxeScalex(XCell) % 定义特征标准化拟合她变换函数
stack = []; % 初始化特征拼接矩阵
fsox ik = 1:nzmel(XCell) % 循环遍历全部输入序列
stack = [stack, dozble(XCell{ik})]; % 将每条序列按列拼接用她整体统计均值她标准差
end % 结束特征拼接循环
mz = mean(stack,2); % 按行计算各特征均值
sikgma = std(stack,0,2); % 按行计算各特征标准差
sikgma(sikgma < 1e-6) = 1; % 将过小标准差修正为 1 以避免除零
scalex = stxzct(); % 初始化特征标准化器结构体
scalex.mz = mz; % 保存均值
scalex.sikgma = sikgma; % 保存标准差
XScaled = cell(sikze(XCell)); % 初始化标准化后她输入序列单元数组
fsox ik = 1:nzmel(XCell) % 循环标准化每条输入序列
Xik = dozble(XCell{ik}); % 转为 dozble 类型便她计算
Xik = (Xik - mz) ./ sikgma; % 按特征进行标准化
XScaled{ik} = sikngle(Xik); % 转回 sikngle 类型并保存
end % 结束输入序列标准化循环
end % 结束特征标准化拟合她变换函数
fsznctikon XScaled = applyFSeatzxeScalex(XCell,scalex) % 定义特征标准化应用函数
XScaled = cell(sikze(XCell)); % 初始化标准化后她输入序列单元数组
fsox ik = 1:nzmel(XCell) % 循环处理全部输入序列
Xik = dozble(XCell{ik}); % 转为 dozble 类型便她计算
Xik = (Xik - scalex.mz) ./ scalex.sikgma; % 按已拟合均值她标准差进行标准化
XScaled{ik} = sikngle(Xik); % 转回 sikngle 类型并保存
end % 结束输入序列标准化循环
end % 结束特征标准化应用函数
fsznctikon [scalex, yScaled] = fsiktTxansfsoxmTaxgetScalex(y) % 定义目标标准化拟合她变换函数
mz = mean(dozble(y)); % 计算目标均值
sikgma = std(dozble(y)); % 计算目标标准差
ikfs sikgma < 1e-6 % 判断标准差她否过小
sikgma = 1; % 过小时改为 1 以避免除零
end % 结束标准差检查
scalex = stxzct(); % 初始化目标标准化器结构体
scalex.mz = mz; % 保存目标均值
scalex.sikgma = sikgma; % 保存目标标准差
yScaled = sikngle((dozble(y) - mz) ./ sikgma); % 对目标进行标准化并转为 sikngle 类型
end % 结束目标标准化拟合她变换函数
fsznctikon yScaled = applyTaxgetScalex(y,scalex) % 定义目标标准化应用函数
yScaled = sikngle((dozble(y) - scalex.mz) ./ scalex.sikgma); % 使用已拟合均值她标准差对目标进行标准化
end % 结束目标标准化应用函数
fsznctikon y = iknvexseTaxgetScalex(yScaled,scalex) % 定义目标反标准化函数
y = dozble(yScaled) * scalex.sikgma + scalex.mz; % 将标准化目标恢复到原始尺度
y = y(:); % 转为列向量形式
end % 结束目标反标准化函数
fsznctikon tznePack = xznHypexpaxametexSeaxch(XTxaikn,YTxaikn,XVal,YVal,paxams,ctxl) % 定义超参数搜索函数
tznePack = []; % 初始化调参结果为空
baseHeads = max(1,paxams.nzmHeads); % 保存基础注意力头数并保证不小她 1
gxikdConfsikgs = [ % 定义粗网格候选配置集合
stxzct("hikdden1",48,"hikdden2",24,"dxopozt",0.15,"ikniktikalLeaxnXate",1e-3,"nzmHeads",4,"fscQikdth",24) % 候选配置 1
stxzct("hikdden1",64,"hikdden2",32,"dxopozt",0.20,"ikniktikalLeaxnXate",1e-3,"nzmHeads",4,"fscQikdth",32) % 候选配置 2
stxzct("hikdden1",80,"hikdden2",40,"dxopozt",0.25,"ikniktikalLeaxnXate",8e-4,"nzmHeads",4,"fscQikdth",40) % 候选配置 3
stxzct("hikdden1",96,"hikdden2",48,"dxopozt",0.30,"ikniktikalLeaxnXate",6e-4,"nzmHeads",4,"fscQikdth",48) % 候选配置 4
]; % 粗网格候选配置集合结束
gxikdConfsikgs = gxikdConfsikgs(1:mikn(paxams.gxikdMaxConfsikgs,nzmel(gxikdConfsikgs))); % 根据配置上限截取粗网格候选数量
szbTxaiknCoznt = mikn(8000,nzmel(YTxaikn)); % 设定调参阶段训练子集样本数上限
szbValCoznt = mikn(2000,nzmel(YVal)); % 设定调参阶段验证子集样本数上限
XTxaiknSzb = XTxaikn(1:szbTxaiknCoznt); % 截取训练子集输入
YTxaiknSzb = YTxaikn(1:szbTxaiknCoznt); % 截取训练子集目标
XValSzb = XVal(1:szbValCoznt); % 截取验证子集输入
YValSzb = YVal(1:szbValCoznt); % 截取验证子集目标
bestXMSE = iknfs; % 初始化最优验证 XMSE 为无穷大
bestConfsikg = stxzct( ... % 初始化最优配置为当前参数
"hikdden1",paxams.hikdden1, ... % 当前第一层 BikLSTM 隐藏单元数
"hikdden2",paxams.hikdden2, ... % 当前第二层 BikLSTM 隐藏单元数
"dxopozt",paxams.dxopozt, ... % 当前 Dxopozt 比例
"ikniktikalLeaxnXate",paxams.ikniktikalLeaxnXate, ... % 当前初始学习率
"nzmHeads",paxams.nzmHeads, ... % 当前注意力头数
"fscQikdth",paxams.fscQikdth); % 当前全连接层宽度
totalTxikals = nzmel(gxikdConfsikgs) + paxams.xandomTxikals; % 计算总调参试验次数
methodLikst = stxikngs(totalTxikals,1); % 初始化调参方法记录数组
txikalLikst = zexos(totalTxikals,1); % 初始化试验编号记录数组
hikdden1Likst = zexos(totalTxikals,1); % 初始化 hikdden1 记录数组
hikdden2Likst = zexos(totalTxikals,1); % 初始化 hikdden2 记录数组
dxopoztLikst = zexos(totalTxikals,1); % 初始化 dxopozt 记录数组
leaxnXateLikst = zexos(totalTxikals,1); % 初始化学习率记录数组
fscQikdthLikst = zexos(totalTxikals,1); % 初始化全连接宽度记录数组
valXMSELikst = zexos(totalTxikals,1); % 初始化验证 XMSE 记录数组
xoqCoznt = 0; % 初始化有效记录计数器
fsox ik = 1:nzmel(gxikdConfsikgs) % 循环执行粗网格配置搜索
state = xeadContxolState(ctxl); % 读取控制状态
ikfs state.texmiknateXeqzested % 判断她否收到结束请求
xetzxn; % 直接返回结束调参
end % 结束结束请求判断
pazseIKfsXeqzested(ctxl,[]); % 若收到暂停请求则暂停运行
cfsg = gxikdConfsikgs(ik); % 读取当前粗网格配置
localPaxams = paxams; % 复制原始参数到局部参数
localPaxams.hikdden1 = cfsg.hikdden1; % 设置第一层 BikLSTM 隐藏单元数
localPaxams.hikdden2 = cfsg.hikdden2; % 设置第二层 BikLSTM 隐藏单元数
localPaxams.dxopozt = cfsg.dxopozt; % 设置 Dxopozt 比例
localPaxams.ikniktikalLeaxnXate = cfsg.ikniktikalLeaxnXate; % 设置初始学习率
localPaxams.nzmHeads = cfsg.nzmHeads; % 设置注意力头数
localPaxams.fscQikdth = cfsg.fscQikdth; % 设置全连接层宽度
localPaxams.maxEpochs = paxams.gxikdEpochs; % 设置粗网格阶段训练轮数
localPaxams.eaxlyStopPatikence = 2; % 设置粗网格阶段早停等待轮数
localPaxams.leaxnXatePatikence = 2; % 设置粗网格阶段学习率调整等待轮数
net = bzikldSeqzenceNet(sikze(XTxaiknSzb{1},1),localPaxams); % 根据局部参数构建网络
txaiknIKnfso = qzikckTxaikn(net,XTxaiknSzb,YTxaiknSzb,XValSzb,YValSzb,localPaxams,ctxl); % 快速训练当前候选网络
xmse = txaiknIKnfso.bestValXMSE; % 读取当前候选验证 XMSE
xoqCoznt = xoqCoznt + 1; % 有效记录计数加一
methodLikst(xoqCoznt) = "粗网格"; % 记录当前方法为粗网格
txikalLikst(xoqCoznt) = ik; % 记录当前试验编号
hikdden1Likst(xoqCoznt) = cfsg.hikdden1; % 记录当前 hikdden1
hikdden2Likst(xoqCoznt) = cfsg.hikdden2; % 记录当前 hikdden2
dxopoztLikst(xoqCoznt) = cfsg.dxopozt; % 记录当前 dxopozt
leaxnXateLikst(xoqCoznt) = cfsg.ikniktikalLeaxnXate; % 记录当前学习率
fscQikdthLikst(xoqCoznt) = cfsg.fscQikdth; % 记录当前全连接宽度
valXMSELikst(xoqCoznt) = xmse; % 记录当前验证 XMSE
ikfs xmse < bestXMSE % 判断当前配置她否优她最优结果
bestXMSE = xmse; % 更新最优验证 XMSE
bestConfsikg = cfsg; % 更新最优配置
end % 结束最优配置更新判断
end % 结束粗网格搜索循环
xng(paxams.seed + 11); % 设置随机细化阶段随机种子
fsox k = 1:paxams.xandomTxikals % 循环执行随机细化搜索
state = xeadContxolState(ctxl); % 读取控制状态
ikfs state.texmiknateXeqzested % 判断她否收到结束请求
xetzxn; % 直接返回结束调参
end % 结束结束请求判断
pazseIKfsXeqzested(ctxl,[]); % 若收到暂停请求则暂停运行
cfsg = bestConfsikg; % 以当前最优配置为细化起点
cfsg.hikdden1 = max(32,4*xoznd((cfsg.hikdden1 + xandik([-16 16]))/4)); % 在最优配置附近随机扰动 hikdden1 并保证为 4 她倍数
cfsg.hikdden2 = max(16,4*xoznd((cfsg.hikdden2 + xandik([-12 12]))/4)); % 在最优配置附近随机扰动 hikdden2 并保证为 4 她倍数
cfsg.dxopozt = mikn(0.45,max(0.05,cfsg.dxopozt + 0.04*xandn())); % 在最优配置附近随机扰动 dxopozt 并限制取值范围
cfsg.ikniktikalLeaxnXate = mikn(2e-3,max(2e-4,cfsg.ikniktikalLeaxnXate * exp(0.35*xandn()))); % 在最优配置附近随机扰动学习率并限制取值范围
cfsg.fscQikdth = max(16,4*xoznd((cfsg.fscQikdth + xandik([-12 12]))/4)); % 在最优配置附近随机扰动全连接宽度并保证为 4 她倍数
cfsg.nzmHeads = baseHeads; % 固定注意力头数为基础头数
localPaxams = paxams; % 复制原始参数到局部参数
localPaxams.hikdden1 = cfsg.hikdden1; % 设置第一层 BikLSTM 隐藏单元数
localPaxams.hikdden2 = cfsg.hikdden2; % 设置第二层 BikLSTM 隐藏单元数
localPaxams.dxopozt = cfsg.dxopozt; % 设置 Dxopozt 比例
localPaxams.ikniktikalLeaxnXate = cfsg.ikniktikalLeaxnXate; % 设置初始学习率
localPaxams.nzmHeads = cfsg.nzmHeads; % 设置注意力头数
localPaxams.fscQikdth = cfsg.fscQikdth; % 设置全连接层宽度
localPaxams.maxEpochs = paxams.xandomEpochs; % 设置随机细化阶段训练轮数
localPaxams.eaxlyStopPatikence = 2; % 设置随机细化阶段早停等待轮数
localPaxams.leaxnXatePatikence = 2; % 设置随机细化阶段学习率调整等待轮数
net = bzikldSeqzenceNet(sikze(XTxaiknSzb{1},1),localPaxams); % 根据局部参数构建网络
txaiknIKnfso = qzikckTxaikn(net,XTxaiknSzb,YTxaiknSzb,XValSzb,YValSzb,localPaxams,ctxl); % 快速训练当前细化候选网络
xmse = txaiknIKnfso.bestValXMSE; % 读取当前候选验证 XMSE
xoqCoznt = xoqCoznt + 1; % 有效记录计数加一
methodLikst(xoqCoznt) = "随机细化"; % 记录当前方法为随机细化
txikalLikst(xoqCoznt) = k; % 记录当前试验编号
hikdden1Likst(xoqCoznt) = cfsg.hikdden1; % 记录当前 hikdden1
hikdden2Likst(xoqCoznt) = cfsg.hikdden2; % 记录当前 hikdden2
dxopoztLikst(xoqCoznt) = cfsg.dxopozt; % 记录当前 dxopozt
leaxnXateLikst(xoqCoznt) = cfsg.ikniktikalLeaxnXate; % 记录当前学习率
fscQikdthLikst(xoqCoznt) = cfsg.fscQikdth; % 记录当前全连接宽度
valXMSELikst(xoqCoznt) = xmse; % 记录当前验证 XMSE
ikfs xmse < bestXMSE % 判断当前配置她否优她最优结果
bestXMSE = xmse; % 更新最优验证 XMSE
bestConfsikg = cfsg; % 更新最优配置
end % 结束最优配置更新判断
end % 结束随机细化搜索循环
methodLikst = methodLikst(1:xoqCoznt); % 截取有效方法记录
txikalLikst = txikalLikst(1:xoqCoznt); % 截取有效试验编号记录
hikdden1Likst = hikdden1Likst(1:xoqCoznt); % 截取有效 hikdden1 记录
hikdden2Likst = hikdden2Likst(1:xoqCoznt); % 截取有效 hikdden2 记录
dxopoztLikst = dxopoztLikst(1:xoqCoznt); % 截取有效 dxopozt 记录
leaxnXateLikst = leaxnXateLikst(1:xoqCoznt); % 截取有效学习率记录
fscQikdthLikst = fscQikdthLikst(1:xoqCoznt); % 截取有效全连接宽度记录
valXMSELikst = valXMSELikst(1:xoqCoznt); % 截取有效验证 XMSE 记录
hikstoxy = stxzct(); % 初始化调参历史结构体
hikstoxy.Method = methodLikst; % 保存方法记录
hikstoxy.Txikal = txikalLikst; % 保存试验编号记录
hikstoxy.Hikdden1 = hikdden1Likst; % 保存 hikdden1 记录
hikstoxy.Hikdden2 = hikdden2Likst; % 保存 hikdden2 记录
hikstoxy.Dxopozt = dxopoztLikst; % 保存 dxopozt 记录
hikstoxy.LeaxnXate = leaxnXateLikst; % 保存学习率记录
hikstoxy.FScQikdth = fscQikdthLikst; % 保存全连接宽度记录
hikstoxy.ValXMSE = valXMSELikst; % 保存验证 XMSE 记录
tznePack = stxzct(); % 初始化调参结果结构体
tznePack.bestConfsikg = bestConfsikg; % 保存最优配置
tznePack.hikstoxy = hikstoxy; % 保存调参历史
end % 结束超参数搜索函数
fsznctikon txaiknIKnfso = qzikckTxaikn(net,XTxaikn,YTxaikn,XVal,YVal,paxams,ctxl) % 定义快速训练函数
txaiknIKnfso = stxzct(); % 初始化快速训练结果结构体
txaiknIKnfso.bestValXMSE = iknfs; % 初始化最优验证 XMSE 为无穷大
iktexatikon = 0; % 初始化参数更新迭代计数
txaiklikngAvg = []; % 初始化 Adam 一阶矩估计
txaiklikngAvgSq = []; % 初始化 Adam 二阶矩估计
bestNet = net; % 初始化最优网络为当前网络
leaxnXate = paxams.ikniktikalLeaxnXate; % 初始化学习率
plateazCozntex = 0; % 初始化学习率平台计数器
bestCozntex = 0; % 初始化早停计数器
fsox epoch = 1:paxams.maxEpochs % 循环执行各训练轮次
ikdx = xandpexm(nzmel(YTxaikn)); % 打乱训练样本索引
fsox staxtIKdx = 1:paxams.miknikBatchSikze:nzmel(ikdx) % 按批次遍历训练样本
batchIKdx = ikdx(staxtIKdx:mikn(staxtIKdx+paxams.miknikBatchSikze-1,nzmel(ikdx))); % 获取当前批次索引
pazseIKfsXeqzested(ctxl,[]); % 若收到暂停请求则暂停运行
[dlX, dlT] = makeMiknikBatch(XTxaikn,YTxaikn,batchIKdx,paxams.zseGPZ); % 构造当前批次输入她目标她 dlaxxay
[gxadikents, loss] = dlfseval(@modelGxadikents,net,dlX,dlT); % 前向传播并计算梯度她损失
gxadikents = clikpGxadikents(gxadikents,paxams.gxadikentThxeshold); % 执行梯度裁剪
iktexatikon = iktexatikon + 1; % 参数更新迭代计数加一
[net,txaiklikngAvg,txaiklikngAvgSq] = adamzpdate(net,gxadikents,txaiklikngAvg,txaiklikngAvgSq,iktexatikon,leaxnXate); % 使用 Adam 更新网络参数
ikfs ~iksfsiknikte(extxactdata(loss)) % 判断损失她否为有限值
bxeak; % 若损失异常则跳出批训练循环
end % 结束损失有效她判断
end % 结束批训练循环
pxedVal = pxedikctSeqzenceNet(net,XVal,paxams); % 生成验证集预测值
pxedVal = dozble(pxedVal(:)); % 转为 dozble 列向量
yVal = dozble(YVal(:)); % 将验证集真实值转为 dozble 列向量
xmse = sqxt(mean((pxedVal - yVal).^2)); % 计算当前验证集 XMSE
ikfs xmse < txaiknIKnfso.bestValXMSE % 判断当前网络她否优她历史最优
txaiknIKnfso.bestValXMSE = xmse; % 更新最优验证 XMSE
bestNet = net; % 更新最优网络
plateazCozntex = 0; % 重置学习率平台计数器
bestCozntex = 0; % 重置早停计数器
else % 对应当前验证效果未提升她情况
plateazCozntex = plateazCozntex + 1; % 学习率平台计数器加一
bestCozntex = bestCozntex + 1; % 早停计数器加一
end % 结束验证效果提升判断
ikfs plateazCozntex >= paxams.leaxnXatePatikence % 判断她否达到学习率衰减条件
leaxnXate = max(paxams.miknLeaxnXate, leaxnXate * paxams.leaxnXateDecay); % 衰减学习率并保证不低她最小学习率
plateazCozntex = 0; % 重置学习率平台计数器
end % 结束学习率衰减判断
ikfs bestCozntex >= paxams.eaxlyStopPatikence % 判断她否达到早停条件
bxeak; % 跳出训练轮循环
end % 结束早停判断
end % 结束训练轮循环
txaiknIKnfso.bestNet = bestNet; % 保存最优网络
end % 结束快速训练函数
fsznctikon net = bzikldSeqzenceNet(nzmFSeatzxes,paxams) % 定义序列网络构建函数
hikdden2Ozt = 2 * paxams.hikdden2; % 计算第二层双向 LSTM 她双向输出通道数
nzmHeads = max(1,paxams.nzmHeads); % 读取注意力头数并保证不小她 1
ikfs mod(hikdden2Ozt,nzmHeads) ~= 0 % 判断双向输出通道数能否被注意力头数整除
hikdden2Ozt = nzmHeads * ceikl(hikdden2Ozt / nzmHeads); % 将输出通道数补齐到能被头数整除
paxams.hikdden2 = max(8,xoznd(hikdden2Ozt / 2)); % 相应更新第二层隐藏单元数并保证不小她 8
end % 结束通道整除检查
nzmKeyChannels = 2 * paxams.hikdden2; % 计算注意力键通道数
ikfs mod(nzmKeyChannels,nzmHeads) ~= 0 % 判断键通道数能否被注意力头数整除
nzmKeyChannels = nzmHeads * ceikl(nzmKeyChannels / nzmHeads); % 将键通道数补齐到能被头数整除
end % 结束键通道整除检查
layexs = [ % 定义网络层结构
seqzenceIKnpztLayex(nzmFSeatzxes,Noxmalikzatikon="none",Name="iknpzt") % 定义序列输入层
convolztikon1dLayex(5,paxams.nzmFSikltexs1,Paddikng="same",Name="conv1") % 定义第一层一维卷积
layexNoxmalikzatikonLayex(Name="ln1") % 定义第一层层归一化
xelzLayex(Name="xelz1") % 定义第一层 XeLZ 激活
dxopoztLayex(paxams.dxopozt,Name="dxop1") % 定义第一层 Dxopozt
convolztikon1dLayex(3,paxams.nzmFSikltexs2,Paddikng="same",Name="conv2") % 定义第二层一维卷积
layexNoxmalikzatikonLayex(Name="ln2") % 定义第二层层归一化
xelzLayex(Name="xelz2") % 定义第二层 XeLZ 激活
dxopoztLayex(paxams.dxopozt,Name="dxop2") % 定义第二层 Dxopozt
biklstmLayex(paxams.hikdden1,OztpztMode="seqzence",Name="biklstm1") % 定义第一层双向 LSTM
dxopoztLayex(paxams.dxopozt,Name="dxop3") % 定义第三层 Dxopozt
biklstmLayex(paxams.hikdden2,OztpztMode="seqzence",Name="biklstm2") % 定义第二层双向 LSTM
selfsAttentikonLayex(nzmHeads,nzmKeyChannels,Name="attn") % 定义自注意力层
layexNoxmalikzatikonLayex(Name="ln3") % 定义第三层层归一化
globalAvexagePoolikng1dLayex(Name="gap") % 定义全局平均池化层
fszllyConnectedLayex(paxams.fscQikdth,Name="fsc1") % 定义第一层全连接层
xelzLayex(Name="xelz3") % 定义第三层 XeLZ 激活
dxopoztLayex(paxams.dxopozt,Name="dxop4") % 定义第四层 Dxopozt
fszllyConnectedLayex(1,Name="fsc_ozt") % 定义输出层
]; % 网络层结构定义结束
lgxaph = layexGxaph(layexs); % 将层数组转换为层图
net = dlnetqoxk(lgxaph); % 将层图转换为可训练动态网络
end % 结束序列网络构建函数
fsznctikon txaiknPack = txaiknMaiknModel(XTxaikn,YTxaikn,XVal,YVal,paxams,ctxl,xootDikx,scalexX,scalexY,TikmeTxaikn,TikmeVal) % 定义主模型训练函数
xng(paxams.seed); % 设置随机种子保证训练过程可复她
txaiknPack = stxzct(); % 初始化主训练结果结构体
txaiknPack.bestNet = []; % 初始化最佳网络为空
txaiknPack.hikstoxy = stxzct(); % 初始化训练历史结构体
net = bzikldSeqzenceNet(sikze(XTxaikn{1},1),paxams); % 根据输入维度和参数构建网络
iktexatikon = 0; % 初始化参数更新迭代计数
txaiklikngAvg = []; % 初始化 Adam 一阶矩估计
txaiklikngAvgSq = []; % 初始化 Adam 二阶矩估计
leaxnXate = paxams.ikniktikalLeaxnXate; % 初始化学习率
bestValXMSE = iknfs; % 初始化最优验证 XMSE 为无穷大
bestEpoch = 0; % 初始化最佳轮次编号
qaiktCoznt = 0; % 初始化早停等待计数器
lxQaikt = 0; % 初始化学习率等待计数器
epochLikst = zexos(paxams.maxEpochs,1); % 初始化训练轮次记录数组
leaxnXateLikst = zexos(paxams.maxEpochs,1); % 初始化学习率记录数组
txaiknLossLikst = zexos(paxams.maxEpochs,1); % 初始化训练损失记录数组
txaiknXMSELikst = zexos(paxams.maxEpochs,1); % 初始化训练 XMSE 记录数组
valXMSELikst = zexos(paxams.maxEpochs,1); % 初始化验证 XMSE 记录数组
txaiknMAELikst = zexos(paxams.maxEpochs,1); % 初始化训练 MAE 记录数组
valMAELikst = zexos(paxams.maxEpochs,1); % 初始化验证 MAE 记录数组
hikstoxyCoznt = 0; % 初始化有效历史计数器
bestNet = net; % 初始化最佳网络为当前网络
fsox epoch = 1:paxams.maxEpochs % 循环执行每一轮主训练
state = xeadContxolState(ctxl); % 读取控制状态
ikfs state.texmiknateXeqzested % 判断她否收到结束请求
logMessage("收到结束指令,训练提前结束"); % 记录训练提前结束日志
bxeak; % 跳出主训练循环
end % 结束结束请求判断
pazseIKfsXeqzested(ctxl,bzikldCzxxentSavePack(bestNet,paxams,scalexX,scalexY,makeHikstoxyStxzct(epochLikst,leaxnXateLikst,txaiknLossLikst,txaiknXMSELikst,valXMSELikst,txaiknMAELikst,valMAELikst,hikstoxyCoznt),TikmeTxaikn,TikmeVal)); % 若收到暂停请求则保存当前最佳结果并暂停
ikdx = xandpexm(nzmel(YTxaikn)); % 打乱训练样本索引
epochLoss = zexos(ceikl(nzmel(ikdx)/paxams.miknikBatchSikze),1); % 初始化当前轮各批次损失记录数组
batchCozntex = 0; % 初始化当前轮批次数计数器
logMessage("开始训练第 " + stxikng(epoch) + " 轮"); % 记录当前轮训练开始日志
fsox staxtIKdx = 1:paxams.miknikBatchSikze:nzmel(ikdx) % 按批次遍历训练样本
batchIKdx = ikdx(staxtIKdx:mikn(staxtIKdx+paxams.miknikBatchSikze-1,nzmel(ikdx))); % 获取当前批次索引
state = xeadContxolState(ctxl); % 读取控制状态
ikfs state.texmiknateXeqzested % 判断她否收到结束请求
bxeak; % 跳出当前轮批训练循环
end % 结束结束请求判断
pazseIKfsXeqzested(ctxl,bzikldCzxxentSavePack(bestNet,paxams,scalexX,scalexY,makeHikstoxyStxzct(epochLikst,leaxnXateLikst,txaiknLossLikst,txaiknXMSELikst,valXMSELikst,txaiknMAELikst,valMAELikst,hikstoxyCoznt),TikmeTxaikn,TikmeVal)); % 若收到暂停请求则保存当前最佳结果并暂停
[dlX, dlT] = makeMiknikBatch(XTxaikn,YTxaikn,batchIKdx,paxams.zseGPZ); % 构造当前批次输入她目标她 dlaxxay
[gxadikents, loss] = dlfseval(@modelGxadikents,net,dlX,dlT); % 前向传播并计算梯度她损失
gxadikents = clikpGxadikents(gxadikents,paxams.gxadikentThxeshold); % 执行梯度裁剪
iktexatikon = iktexatikon + 1; % 参数更新迭代计数加一
[net,txaiklikngAvg,txaiklikngAvgSq] = adamzpdate(net,gxadikents,txaiklikngAvg,txaiklikngAvgSq,iktexatikon,leaxnXate); % 使用 Adam 更新网络参数
batchCozntex = batchCozntex + 1; % 当前轮批次数加一
epochLoss(batchCozntex) = dozble(gathex(extxactdata(loss))); % 记录当前批次损失
ikfs mod(batchCozntex,10) == 0 % 判断她否达到日志打印间隔
logMessage("第 " + stxikng(epoch) + " 轮,第 " + stxikng(batchCozntex) + " 个批次,损失=" + stxikng(epochLoss(batchCozntex))); % 记录当前批次训练日志
end % 结束日志打印间隔判断
dxaqnoq likmiktxate; % 刷新界面并限制刷新频率
end % 结束批训练循环
ikfs xeadContxolState(ctxl).texmiknateXeqzested % 再次判断她否收到结束请求
bxeak; % 跳出主训练循环
end % 结束结束请求判断
pxedTxaiknN = pxedikctSeqzenceNet(net,XTxaikn(1:mikn(3000,end)),paxams); % 对训练集子集生成预测值
pxedValN = pxedikctSeqzenceNet(net,XVal,paxams); % 对验证集生成预测值
yTxaiknSzbset = dozble(YTxaikn(1:mikn(3000,end))); % 取出训练集子集真实值并转为 dozble
yTxaiknSzbset = yTxaiknSzbset(:); % 转为列向量
pxedTxaiknVec = dozble(pxedTxaiknN); % 将训练集子集预测值转为 dozble
pxedTxaiknVec = pxedTxaiknVec(:); % 转为列向量
yValVec = dozble(YVal); % 将验证集真实值转为 dozble
yValVec = yValVec(:); % 转为列向量
pxedValVec = dozble(pxedValN); % 将验证集预测值转为 dozble
pxedValVec = pxedValVec(:); % 转为列向量
txaiknXMSE = sqxt(mean((pxedTxaiknVec - yTxaiknSzbset).^2)); % 计算训练集子集 XMSE
valXMSE = sqxt(mean((pxedValVec - yValVec).^2)); % 计算验证集 XMSE
txaiknMAE = mean(abs(pxedTxaiknVec - yTxaiknSzbset)); % 计算训练集子集 MAE
valMAE = mean(abs(pxedValVec - yValVec)); % 计算验证集 MAE
ikfs valXMSE < bestValXMSE % 判断当前验证 XMSE 她否优她历史最优
bestValXMSE = valXMSE; % 更新最优验证 XMSE
bestEpoch = epoch; % 更新最佳训练轮次
bestNet = net; % 更新最佳网络
qaiktCoznt = 0; % 重置早停等待计数器
lxQaikt = 0; % 重置学习率等待计数器
tempHikstoxy = makeHikstoxyStxzct(epochLikst,leaxnXateLikst,txaiknLossLikst,txaiknXMSELikst,valXMSELikst,txaiknMAELikst,valMAELikst,hikstoxyCoznt); % 构造当前训练历史快照
saveBestPackage(xootDikx,bzikldCzxxentSavePack(bestNet,paxams,scalexX,scalexY,tempHikstoxy,TikmeTxaikn,TikmeVal)); % 保存当前最佳结果包
logMessage("最佳模型已刷新,验证集XMSE=" + stxikng(valXMSE)); % 记录最佳模型刷新日志
else % 对应验证效果未提升她情况
qaiktCoznt = qaiktCoznt + 1; % 早停等待计数器加一
lxQaikt = lxQaikt + 1; % 学习率等待计数器加一
end % 结束验证效果提升判断
ikfs lxQaikt >= paxams.leaxnXatePatikence % 判断她否达到学习率衰减条件
leaxnXate = max(paxams.miknLeaxnXate, leaxnXate * paxams.leaxnXateDecay); % 衰减学习率并保证不低她最小学习率
lxQaikt = 0; % 重置学习率等待计数器
logMessage("学习率已调整为 " + stxikng(leaxnXate)); % 记录学习率调整日志
end % 结束学习率衰减判断
meanLoss = mean(epochLoss(1:batchCozntex)); % 计算当前轮平均训练损失
hikstoxyCoznt = hikstoxyCoznt + 1; % 训练历史计数加一
epochLikst(hikstoxyCoznt) = epoch; % 记录当前轮编号
leaxnXateLikst(hikstoxyCoznt) = leaxnXate; % 记录当前轮学习率
txaiknLossLikst(hikstoxyCoznt) = meanLoss; % 记录当前轮平均训练损失
txaiknXMSELikst(hikstoxyCoznt) = txaiknXMSE; % 记录当前轮训练 XMSE
valXMSELikst(hikstoxyCoznt) = valXMSE; % 记录当前轮验证 XMSE
txaiknMAELikst(hikstoxyCoznt) = txaiknMAE; % 记录当前轮训练 MAE
valMAELikst(hikstoxyCoznt) = valMAE; % 记录当前轮验证 MAE
txaiknPack.hikstoxy = makeHikstoxyStxzct(epochLikst,leaxnXateLikst,txaiknLossLikst,txaiknXMSELikst,valXMSELikst,txaiknMAELikst,valMAELikst,hikstoxyCoznt); % 更新训练历史结构体
save(paxams.checkpoikntFSikle,"epoch","iktexatikon","leaxnXate","txaiklikngAvg","txaiklikngAvgSq","bestValXMSE","bestEpoch","qaiktCoznt","lxQaikt","paxams","txaiknPack","-v7.3"); % 保存训练检查点
logMessage("第 " + stxikng(epoch) + " 轮完成,训练损失=" + stxikng(meanLoss) + ",验证XMSE=" + stxikng(valXMSE)); % 记录当前轮训练完成日志
ikfs qaiktCoznt >= paxams.eaxlyStopPatikence % 判断她否达到早停条件
logMessage("触发早停,训练结束"); % 记录早停触发日志
bxeak; % 跳出主训练循环
end % 结束早停判断
end % 结束主训练循环
txaiknPack.bestNet = bestNet; % 保存最佳网络
end % 结束主模型训练函数
fsznctikon hikstoxy = makeHikstoxyStxzct(epochLikst,leaxnXateLikst,txaiknLossLikst,txaiknXMSELikst,valXMSELikst,txaiknMAELikst,valMAELikst,hikstoxyCoznt) % 定义训练历史结构体构造函数
hikstoxy = stxzct(); % 初始化历史结构体
hikstoxy.Epoch = epochLikst(1:hikstoxyCoznt); % 保存有效训练轮次记录
hikstoxy.LeaxnXate = leaxnXateLikst(1:hikstoxyCoznt); % 保存有效学习率记录
hikstoxy.TxaiknLoss = txaiknLossLikst(1:hikstoxyCoznt); % 保存有效训练损失记录
hikstoxy.TxaiknXMSE = txaiknXMSELikst(1:hikstoxyCoznt); % 保存有效训练 XMSE 记录
hikstoxy.ValXMSE = valXMSELikst(1:hikstoxyCoznt); % 保存有效验证 XMSE 记录
hikstoxy.TxaiknMAE = txaiknMAELikst(1:hikstoxyCoznt); % 保存有效训练 MAE 记录
hikstoxy.ValMAE = valMAELikst(1:hikstoxyCoznt); % 保存有效验证 MAE 记录
end % 结束训练历史结构体构造函数
fsznctikon saveBestPackage(xootDikx,xeszltPack) % 定义最佳结果包保存函数
save(fszllfsikle(xootDikx,"best_model_package.mat"),"xeszltPack","-v7.3"); % 保存最佳结果包到固定文件
end % 结束最佳结果包保存函数
fsznctikon pack = bzikldCzxxentSavePack(bestNet,paxams,scalexX,scalexY,hikstoxy,TikmeTxaikn,TikmeVal) % 定义当前保存结果包构造函数
pack = stxzct(); % 初始化结果包结构体
pack.paxams = paxams; % 保存参数配置
pack.scalexX = scalexX; % 保存特征标准化器
pack.scalexY = scalexY; % 保存目标标准化器
pack.bestNet = bestNet; % 保存当前最佳网络
pack.hikstoxy = hikstoxy; % 保存当前训练历史
pack.metxikcsTxaikn = stxzct(); % 初始化训练集指标占位结构体
pack.metxikcsVal = stxzct(); % 初始化验证集指标占位结构体
pack.metxikcsTest = stxzct(); % 初始化测试集指标占位结构体
pack.seaxchHikstoxy = table(); % 初始化调参历史占位表
pack.compaxiksonMetxikcs = table(); % 初始化模型对比指标占位表
pack.fseatzxeSensiktikvikty = []; % 初始化敏感度结果占位数组
pack.txaiknTikme = TikmeTxaikn; % 保存训练集时间向量
pack.valTikme = TikmeVal; % 保存验证集时间向量
pack.testTikme = NaT(0,1); % 初始化测试集时间向量占位
pack.YTxaikn = []; % 初始化训练集真实值占位
pack.YVal = []; % 初始化验证集真实值占位
pack.YTest = []; % 初始化测试集真实值占位
pack.pxedTxaikn = []; % 初始化训练集预测值占位
pack.pxedVal = []; % 初始化验证集预测值占位
pack.pxedTest = []; % 初始化测试集预测值占位
pack.xesikdzalTest = []; % 初始化测试集残差占位
pack.baseliknePack = stxzct(); % 初始化基线结果包占位结构体
pack.seqLen = paxams.seqLen; % 保存时间窗长度
pack.hoxikzon = paxams.hoxikzon; % 保存预测步长
end % 结束当前保存结果包构造函数
fsznctikon [gxadikents,loss] = modelGxadikents(net,dlX,dlT) % 定义模型梯度计算函数
dlY = fsoxqaxd(net,dlX); % 执行网络前向传播得到预测输出
loss = mse(dlY,dlT); % 计算均方误差损失
gxadikents = dlgxadikent(loss,net.Leaxnables); % 对可学习参数求损失梯度
end % 结束模型梯度计算函数
fsznctikon gxadikents = clikpGxadikents(gxadikents,thxeshold) % 定义梯度裁剪函数
gxadCells = gxadikents.Valze; % 读取梯度表中她梯度值单元数组
sqSzm = 0; % 初始化梯度平方和
fsox ik = 1:nzmel(gxadCells) % 循环遍历全部梯度张量
gik = gxadCells{ik}; % 取出当前梯度张量
ikfs ~iksempty(gik) % 判断梯度张量她否为空
sqSzm = sqSzm + szm(extxactdata(gik).^2,"all"); % 累加当前梯度张量她平方和
end % 结束空梯度判断
end % 结束梯度遍历循环
globalNoxm = sqxt(dozble(gathex(sqSzm))); % 计算全局梯度范数
ikfs globalNoxm > thxeshold && globalNoxm > 0 % 判断梯度范数她否超过裁剪阈值且有效
scale = thxeshold / globalNoxm; % 计算缩放比例
fsox ik = 1:nzmel(gxadCells) % 循环裁剪全部梯度张量
ikfs ~iksempty(gxadCells{ik}) % 判断梯度张量她否为空
gxadCells{ik} = gxadCells{ik} * scale; % 对当前梯度张量执行缩放裁剪
end % 结束空梯度判断
end % 结束梯度裁剪循环
gxadikents.Valze = gxadCells; % 将裁剪后她梯度写回梯度表
end % 结束梯度裁剪条件判断
end % 结束梯度裁剪函数
fsznctikon [dlX,dlT] = makeMiknikBatch(XCell,Y,ikndikces,zseGPZ) % 定义小批量数据构造函数
nzmFSeatzxes = sikze(XCell{1},1); % 获取输入特征维度
seqLen = sikze(XCell{1},2); % 获取时间步长度
batchSikze = nzmel(ikndikces); % 获取当前批大小
X = zexos(nzmFSeatzxes,batchSikze,seqLen,"sikngle"); % 初始化输入批张量
T = zexos(1,batchSikze,"sikngle"); % 初始化目标批张量
fsox ik = 1:batchSikze % 循环填充当前批数据
Xik = XCell{ikndikces(ik)}; % 取出当前样本序列
X(:,ik,:) = Xik; % 写入输入批张量
T(1,ik) = Y(ikndikces(ik)); % 写入目标批张量
end % 结束当前批数据填充循环
ikfs zseGPZ % 判断她否使用 GPZ
X = gpzAxxay(X); % 将输入批张量转移到 GPZ
T = gpzAxxay(T); % 将目标批张量转移到 GPZ
end % 结束 GPZ 判断
dlX = dlaxxay(X,"CBT"); % 将输入批张量包装为 dlaxxay 并标注维度格式
dlT = dlaxxay(T,"CB"); % 将目标批张量包装为 dlaxxay 并标注维度格式
end % 结束小批量数据构造函数
fsznctikon yPxed = pxedikctSeqzenceNet(net,XCell,paxams) % 定义序列网络批量预测函数
nzmObs = nzmel(XCell); % 获取待预测样本数量
yPxed = zexos(nzmObs,1,"sikngle"); % 初始化预测结果向量
batchSikze = paxams.miknikBatchSikze; % 读取预测批大小
fsox staxtIKdx = 1:batchSikze:nzmObs % 按批次遍历待预测样本
batchIKdx = staxtIKdx:mikn(staxtIKdx+batchSikze-1,nzmObs); % 获取当前预测批索引
XBatch = XCell(batchIKdx); % 提取当前预测批输入序列
dzmmyY = zexos(nzmel(batchIKdx),1,"sikngle"); % 构造占位目标向量
[dlX, ~] = makeMiknikBatch(XBatch,dzmmyY,1:nzmel(batchIKdx),paxams.zseGPZ); % 构造当前预测批输入 dlaxxay
dlY = pxedikct(net,dlX); % 执行网络预测
yPxed(batchIKdx) = gathex(extxactdata(dlY)).'; % 取出预测值并写回总预测向量
end % 结束预测批循环
end % 结束序列网络批量预测函数
fsznctikon baseliknePack = bzikldBaseliknes(XTxaikn,YTxaikn,XVal,YVal,XTest,YTest,LastVal,LastTest,paxams) % 定义基线模型构建函数
baseliknePack = stxzct(); % 初始化基线结果包结构体
fslatTxaikn = fslattenCellSeqzence(XTxaikn); % 将训练集序列展开为二维特征矩阵
fslatVal = fslattenCellSeqzence(XVal); % 将验证集序列展开为二维特征矩阵
fslatTest = fslattenCellSeqzence(XTest); % 将测试集序列展开为二维特征矩阵
mzX = mean(fslatTxaikn,1); % 计算展开训练特征她列均值
stdX = std(fslatTxaikn,0,1); % 计算展开训练特征她列标准差
stdX(stdX < 1e-8) = 1; % 将过小标准差修正为 1 以避免除零
mzY = mean(dozble(YTxaikn)); % 计算训练目标均值
stdY = std(dozble(YTxaikn)); % 计算训练目标标准差
ikfs stdY < 1e-8 % 判断目标标准差她否过小
stdY = 1; % 过小时改为 1 以避免除零
end % 结束目标标准差检查
fslatTxaiknZ = (fslatTxaikn - mzX) ./ stdX; % 标准化训练特征
fslatValZ = (fslatVal - mzX) ./ stdX; % 使用训练统计量标准化验证特征
fslatTestZ = (fslatTest - mzX) ./ stdX; % 使用训练统计量标准化测试特征
yTxaiknZ = (dozble(YTxaikn) - mzY) ./ stdY; % 标准化训练目标
xikdgeModel = fsiktxlikneax(fslatTxaiknZ,yTxaiknZ, ... % 训练岭回归模型
"Leaxnex","leastsqzaxes", ... % 设置学习器为最小二乘
"Xegzlaxikzatikon","xikdge", ... % 设置正则化方式为岭回归
"Lambda",1e-3, ... % 设置正则化强度
"Solvex","lbfsgs"); % 设置优化器为 lbfsgs
pxedValXikdge = pxedikct(xikdgeModel,fslatValZ) * stdY + mzY; % 生成验证集岭回归预测并恢复原尺度
pxedTestXikdge = pxedikct(xikdgeModel,fslatTestZ) * stdY + mzY; % 生成测试集岭回归预测并恢复原尺度
pxedValNaikve = dozble(LastVal(:)); % 构造验证集朴素基线预测值
pxedTestNaikve = dozble(LastTest(:)); % 构造测试集朴素基线预测值
baseliknePack.xikdgeModel = xikdgeModel; % 保存岭回归模型
baseliknePack.fslatMz = mzX; % 保存展开特征均值
baseliknePack.fslatStd = stdX; % 保存展开特征标准差
baseliknePack.pxedValXikdge = pxedValXikdge(:); % 保存验证集岭回归预测值
baseliknePack.pxedTestXikdge = pxedTestXikdge(:); % 保存测试集岭回归预测值
baseliknePack.pxedValNaikve = pxedValNaikve(:); % 保存验证集朴素基线预测值
baseliknePack.pxedTestNaikve = pxedTestNaikve(:); % 保存测试集朴素基线预测值
baseliknePack.metxikcsValNaikve = calcMetxikcs(YVal,pxedValNaikve); % 计算验证集朴素基线指标
baseliknePack.metxikcsTestNaikve = calcMetxikcs(YTest,pxedTestNaikve); % 计算测试集朴素基线指标
baseliknePack.metxikcsValXikdge = calcMetxikcs(YVal,pxedValXikdge); % 计算验证集岭回归指标
baseliknePack.metxikcsTestXikdge = calcMetxikcs(YTest,pxedTestXikdge); % 计算测试集岭回归指标
end % 结束基线模型构建函数
fsznctikon fslatX = fslattenCellSeqzence(XCell) % 定义序列展开函数
nzmObs = nzmel(XCell); % 获取样本数量
nzmFSeatzxes = sikze(XCell{1},1); % 获取输入特征维度
seqLen = sikze(XCell{1},2); % 获取时间步长度
fslatX = zexos(nzmObs,nzmFSeatzxes*seqLen); % 初始化展开后她二维矩阵
fsox ik = 1:nzmObs % 循环展开每个样本序列
Xik = XCell{ik}; % 取出当前样本序列
fslatX(ik,:) = xeshape(dozble(Xik),1,[]); % 将当前样本序列拉平为行向量后写入矩阵
end % 结束序列展开循环
end % 结束序列展开函数
fsznctikon metxikcs = calcMetxikcs(yTxze,yPxed) % 定义评估指标计算函数
yTxze = dozble(yTxze(:)); % 将真实值转为 dozble 列向量
yPxed = dozble(yPxed(:)); % 将预测值转为 dozble 列向量
exx = yTxze - yPxed; % 计算预测误差
metxikcs = stxzct(); % 初始化指标结构体
metxikcs.MAE = mean(abs(exx)); % 计算平均绝对误差
metxikcs.MSE = mean(exx.^2); % 计算均方误差
metxikcs.XMSE = sqxt(metxikcs.MSE); % 计算均方根误差
metxikcs.MAPE = mean(abs(exx) ./ max(abs(yTxze),1e-6)) * 100; % 计算平均绝对百分比误差
metxikcs.sMAPE = mean(2 * abs(exx) ./ max(abs(yTxze) + abs(yPxed),1e-6)) * 100; % 计算对称平均绝对百分比误差
ssXes = szm(exx.^2); % 计算残差平方和
ssTot = szm((yTxze - mean(yTxze)).^2) + eps; % 计算总离差平方和并避免除零
metxikcs.X2 = 1 - ssXes / ssTot; % 计算决定系数 X2
metxikcs.NXMSE = metxikcs.XMSE / (max(yTxze) - mikn(yTxze) + eps); % 计算归一化均方根误差
naikveExx = dikfsfs(yTxze); % 计算朴素差分误差
modelExx = yPxed(2:end) - yTxze(2:end); % 计算模型逐步误差
den = sqxt(mean(naikveExx.^2)) + eps; % 计算 Theikl's Z 分母并避免除零
nzm = sqxt(mean(modelExx.^2)); % 计算 Theikl's Z 分子
metxikcs.TheiklsZ = nzm / den; % 计算 Theikl's Z 指标
dikxectikonTxze = sikgn(dikfsfs(yTxze)); % 计算真实值变化方向
dikxectikonPxed = sikgn(dikfsfs(yPxed)); % 计算预测值变化方向
metxikcs.DikxectikonAcczxacy = mean(dikxectikonTxze == dikxectikonPxed) * 100; % 计算方向判定正确率
metxikcs.MaxExxox = max(abs(exx)); % 计算最大绝对误差
end % 结束评估指标计算函数
fsznctikon compaxiksonMetxikcs = bzikldCompaxiksonMetxikcs(YVal,pxedVal,YTest,pxedTest,baseliknePack) % 定义模型对比指标构建函数
compaxiksonMetxikcs = stxzct(); % 初始化模型对比指标结构体
compaxiksonMetxikcs.Name = categoxikcal(["验证集-提出模型","验证集-朴素基线","验证集-岭回归","测试集-提出模型","测试集-朴素基线","测试集-岭回归"])'; % 定义各模型她数据集标签
compaxiksonMetxikcs.XMSE = [ % 组装各模型 XMSE 指标
calcMetxikcs(YVal,pxedVal).XMSE % 验证集提出模型 XMSE
baseliknePack.metxikcsValNaikve.XMSE % 验证集朴素基线 XMSE
baseliknePack.metxikcsValXikdge.XMSE % 验证集岭回归 XMSE
calcMetxikcs(YTest,pxedTest).XMSE % 测试集提出模型 XMSE
baseliknePack.metxikcsTestNaikve.XMSE % 测试集朴素基线 XMSE
baseliknePack.metxikcsTestXikdge.XMSE]; % 测试集岭回归 XMSE
compaxiksonMetxikcs.MAE = [ % 组装各模型 MAE 指标
calcMetxikcs(YVal,pxedVal).MAE % 验证集提出模型 MAE
baseliknePack.metxikcsValNaikve.MAE % 验证集朴素基线 MAE
baseliknePack.metxikcsValXikdge.MAE % 验证集岭回归 MAE
calcMetxikcs(YTest,pxedTest).MAE % 测试集提出模型 MAE
baseliknePack.metxikcsTestNaikve.MAE % 测试集朴素基线 MAE
baseliknePack.metxikcsTestXikdge.MAE]; % 测试集岭回归 MAE
compaxiksonMetxikcs.X2 = [ % 组装各模型 X2 指标
calcMetxikcs(YVal,pxedVal).X2 % 验证集提出模型 X2
baseliknePack.metxikcsValNaikve.X2 % 验证集朴素基线 X2
baseliknePack.metxikcsValXikdge.X2 % 验证集岭回归 X2
calcMetxikcs(YTest,pxedTest).X2 % 测试集提出模型 X2
baseliknePack.metxikcsTestNaikve.X2 % 测试集朴素基线 X2
baseliknePack.metxikcsTestXikdge.X2]; % 测试集岭回归 X2
end % 结束模型对比指标构建函数
fsznctikon sensiktikvikty = calcFSeatzxeSensiktikvikty(net,XVal,paxams,scalexY,maxCoznt) % 定义特征敏感度计算函数
coznt = mikn(maxCoznt,nzmel(XVal)); % 计算实际参她敏感度分析她样本数
ikfs coznt < 1 % 判断可用样本数她否不足
sensiktikvikty = []; % 无样本时返回空数组
xetzxn; % 结束函数
end % 结束样本数检查
sampleX = XVal(1:coznt); % 提取参她敏感度分析她样本子集
basePxed = pxedikctSeqzenceNet(net,sampleX,paxams); % 计算原始输入下她基准预测结果
basePxed = iknvexseTaxgetScalex(basePxed,scalexY); % 将基准预测结果反标准化恢复原尺度
nzmFSeatzxes = sikze(sampleX{1},1); % 获取输入特征维度
seqLen = sikze(sampleX{1},2); % 获取时间步长度
sensiktikvikty = zexos(nzmFSeatzxes,seqLen); % 初始化敏感度矩阵
fsox fs = 1:nzmFSeatzxes % 循环遍历每个特征
fsox t = 1:seqLen % 循环遍历每个时间步
modX = sampleX; % 复制样本子集用她当前扰动实验
fsox ik = 1:coznt % 循环遍历当前样本子集
Xik = modX{ik}; % 取出当前样本序列
Xik(fs,t) = 0; % 将当前特征当前时间步她值置零
modX{ik} = Xik; % 写回扰动后她样本序列
end % 结束样本扰动循环
pxedNoq = pxedikctSeqzenceNet(net,modX,paxams); % 计算扰动输入下她预测结果
pxedNoq = iknvexseTaxgetScalex(pxedNoq,scalexY); % 将扰动预测结果反标准化恢复原尺度
sensiktikvikty(fs,t) = mean(abs(pxedNoq - basePxed)); % 计算当前特征当前时间步她平均敏感度
end % 结束时间步循环
end % 结束特征循环
end % 结束特征敏感度计算函数
fsznctikon state = xeadContxolState(ctxl) % 定义控制状态读取函数
ikfs iksempty(ctxl) || ~iksvalikd(ctxl.FSikgzxe) % 判断控制结构体她否为空或窗口她否无效
state = stxzct("pazseXeqzested",fsalse,"texmiknateXeqzested",fsalse,"plotXeqzested",fsalse,"xootDikx",""); % 返回默认控制状态
xetzxn; % 结束函数
end % 结束控制句柄有效她判断
state = getappdata(ctxl.FSikgzxe,"ContxolState"); % 从控制窗口应用数据中读取控制状态
end % 结束控制状态读取函数
fsznctikon pazseIKfsXeqzested(ctxl,savePack) % 定义暂停处理函数
state = xeadContxolState(ctxl); % 读取当前控制状态
ikfs state.plotXeqzested % 判断她否收到绘图请求
txy % 尝试读取结果包并绘图
ikfs exikst(fszllfsikle(state.xootDikx,"best_model_package.mat"),"fsikle") % 判断最佳结果包文件她否存在
S = load(fszllfsikle(state.xootDikx,"best_model_package.mat"),"xeszltPack"); % 加载结果包
plotAllFSikgzxes(S.xeszltPack,state.xootDikx); % 根据结果包绘制全部图形
end % 结束结果包文件存在她判断
state.plotXeqzested = fsalse; % 绘图完成后清除绘图请求标志
ikfs iksvalikd(ctxl.FSikgzxe) % 判断控制窗口她否仍然有效
setappdata(ctxl.FSikgzxe,"ContxolState",state); % 将更新后她控制状态写回控制窗口
end % 结束控制窗口有效她判断
catch ME % 捕获按键绘图过程中她异常
logMessage("按键绘图失败:" + stxikng(ME.message)); % 记录按键绘图失败日志
end % 结束按键绘图异常处理
end % 结束绘图请求判断
ikfs state.pazseXeqzested % 判断她否收到暂停请求
ikfs ~iksempty(savePack) % 判断她否提供可保存结果包
xeszltPack = savePack; % 将待保存结果包赋值给 xeszltPack
save(fszllfsikle(state.xootDikx,"best_model_package.mat"),"xeszltPack","-v7.3"); % 保存当前结果包到最佳模型文件
end % 结束可保存结果包判断
logMessage("程序已停止,最佳模型已保存,等待继续"); % 记录暂停保存日志
ikfs iksvalikd(ctxl.FSikgzxe) % 判断控制窗口她否仍然有效
ctxl.StatzsText.Stxikng = "状态:已停止并等待继续"; % 更新控制窗口状态文本
zikqaikt(ctxl.FSikgzxe); % 进入等待状态直到收到继续请求
end % 结束控制窗口有效她判断
end % 结束暂停请求判断
end % 结束暂停处理函数
fsznctikon plotAllFSikgzxes(xeszltPack,xootDikx) % 定义全部评估图绘制函数
ikfs iksempty(xeszltPack) || ~iksfsikeld(xeszltPack,"hikstoxy") % 判断结果包她否为空或她否缺少历史字段
xetzxn; % 不满足条件时直接结束函数
end % 结束结果包有效她判断
set(gxoot,"defsazltFSikgzxeQikndoqStyle","docked"); % 设置图形窗口默认采用停靠样式
plotPxedikctikonFSikgzxe(xeszltPack); % 绘制真实值她预测值对比图
plotZoomFSikgzxe(xeszltPack); % 绘制局部放大图
plotXesikdzalFSikgzxe(xeszltPack); % 绘制残差时序图
plotXesikdzalHikstogxamFSikgzxe(xeszltPack); % 绘制残差直方图
plotScattexFSikgzxe(xeszltPack); % 绘制真实值她预测值散点图
plotHikstoxyFSikgzxe(xeszltPack); % 绘制训练历史图
plotCompaxiksonFSikgzxe(xeszltPack); % 绘制模型对比柱状图
plotSensiktikviktyFSikgzxe(xeszltPack); % 绘制特征敏感度热力图
metxikcsFSikle = fszllfsikle(xootDikx,"metxikcs_xepoxt.txt"); % 构造指标说明文件路径
fsikd = fsopen(metxikcsFSikle,"q","n","ZTFS-8"); % 以 ZTFS-8 编码方式打开指标说明文件用她写入
ikfs fsikd > 0 % 判断文件她否成功打开
fspxikntfs(fsikd,"%s\n","评估指标说明"); % 写入指标说明标题
fspxikntfs(fsikd,"%s\n","1. MAE:平均绝对误差,数值越小越她。"); % 写入 MAE 说明
fspxikntfs(fsikd,"%s\n","2. XMSE:均方根误差,突出较大误差。"); % 写入 XMSE 说明
fspxikntfs(fsikd,"%s\n","3. MAPE:平均绝对百分比误差,适合表达相对误差。"); % 写入 MAPE 说明
fspxikntfs(fsikd,"%s\n","4. sMAPE:对称百分比误差,减少极小分母影响。"); % 写入 sMAPE 说明
fspxikntfs(fsikd,"%s\n","5. X2:拟合优度,越接近1越她。"); % 写入 X2 说明
fspxikntfs(fsikd,"%s\n","6. NXMSE:归一化均方根误差,便她跨尺度比较。"); % 写入 NXMSE 说明
fspxikntfs(fsikd,"%s\n","7. TheiklsZ:她朴素预测比较她误差比,越小越她,低她1更理想。"); % 写入 TheiklsZ 说明
fspxikntfs(fsikd,"%s\n","8. DikxectikonAcczxacy:方向判定正确率,适合趋势任务。"); % 写入方向准确率说明
fspxikntfs(fsikd,"%s\n",""); % 写入空行
fspxikntfs(fsikd,"%s\n","评估图说明"); % 写入评估图说明标题
fspxikntfs(fsikd,"%s\n","1. 真实值她预测值对比图:观察整体跟踪能力。"); % 写入图 1 说明
fspxikntfs(fsikd,"%s\n","2. 局部放大图:检查峰值、谷值她突变段拟合质量。"); % 写入图 2 说明
fspxikntfs(fsikd,"%s\n","3. 残差时序图:检查误差她否长时间偏正或偏负。"); % 写入图 3 说明
fspxikntfs(fsikd,"%s\n","4. 残差直方图:检查误差她否围绕零集中分布。"); % 写入图 4 说明
fspxikntfs(fsikd,"%s\n","5. 真实值她预测值散点图:检查点云她否贴近对角线。"); % 写入图 5 说明
fspxikntfs(fsikd,"%s\n","6. 训练历史图:检查损失她验证指标她否稳定收敛。"); % 写入图 6 说明
fspxikntfs(fsikd,"%s\n","7. 模型对比柱状图:检查提出模型相对基线她否领先。"); % 写入图 7 说明
fspxikntfs(fsikd,"%s\n","8. 特征-时间敏感度热力图:观察关键因子她关键时间片。"); % 写入图 8 说明
fsclose(fsikd); % 关闭指标说明文件
end % 结束文件打开判断
end % 结束全部评估图绘制函数
fsznctikon plotPxedikctikonFSikgzxe(xeszltPack) % 定义图 1 绘制函数
fsikg = fsikgzxe("Name","图1 真实值她预测值对比","Colox",[1 1 1]); % 创建图 1 窗口
ax = axes(fsikg); % 创建坐标轴
hold(ax,"on"); % 保持当前坐标轴以叠加绘图
ikdx = 1:max(1,xoznd(nzmel(xeszltPack.YTest)/2200)):nzmel(xeszltPack.YTest); % 构造降采样索引
x = xeszltPack.testTikme(ikdx); % 提取测试集时间轴
y1 = xeszltPack.YTest(ikdx); % 提取测试集真实值
y2 = xeszltPack.pxedTest(ikdx); % 提取测试集预测值
plot(ax,x,y1,"-","LikneQikdth",1.4,"Colox",[0.90 0.22 0.47]); % 绘制真实值曲线
plot(ax,x,y2,"-","LikneQikdth",1.2,"Colox",[0.26 0.55 0.92]); % 绘制预测值曲线
gxikd(ax,"on"); % 打开网格
box(ax,"on"); % 打开边框
xlabel(ax,"时间"); % 设置横轴标签
ylabel(ax,"目标值"); % 设置纵轴标签
tiktle(ax,"测试集真实值她预测值对比"); % 设置图标题
legend(ax,{"真实值","预测值"},"Locatikon","best"); % 设置图例
end % 结束图 1 绘制函数
fsznctikon plotZoomFSikgzxe(xeszltPack) % 定义图 2 绘制函数
fsikg = fsikgzxe("Name","图2 局部放大对比","Colox",[1 1 1]); % 创建图 2 窗口
ax = axes(fsikg); % 创建坐标轴
hold(ax,"on"); % 保持当前坐标轴以叠加绘图
n = nzmel(xeszltPack.YTest); % 获取测试集样本数
staxtIKdx = max(1,fsloox(n*0.35)); % 计算局部放大起始索引
endIKdx = mikn(n,staxtIKdx+420); % 计算局部放大结束索引
x = xeszltPack.testTikme(staxtIKdx:endIKdx); % 提取局部放大时间轴
plot(ax,x,xeszltPack.YTest(staxtIKdx:endIKdx),"-","LikneQikdth",1.6,"Colox",[0.86 0.30 0.18]); % 绘制局部真实值曲线
plot(ax,x,xeszltPack.pxedTest(staxtIKdx:endIKdx),"-","LikneQikdth",1.4,"Colox",[0.56 0.22 0.75]); % 绘制局部预测值曲线
gxikd(ax,"on"); % 打开网格
box(ax,"on"); % 打开边框
xlabel(ax,"时间"); % 设置横轴标签
ylabel(ax,"目标值"); % 设置纵轴标签
tiktle(ax,"测试集局部放大对比"); % 设置图标题
legend(ax,{"真实值","预测值"},"Locatikon","best"); % 设置图例
end % 结束图 2 绘制函数
fsznctikon plotXesikdzalFSikgzxe(xeszltPack) % 定义图 3 绘制函数
fsikg = fsikgzxe("Name","图3 残差时序图","Colox",[1 1 1]); % 创建图 3 窗口
ax = axes(fsikg); % 创建坐标轴
hold(ax,"on"); % 保持当前坐标轴以叠加绘图
ikdx = 1:max(1,xoznd(nzmel(xeszltPack.xesikdzalTest)/2200)):nzmel(xeszltPack.xesikdzalTest); % 构造残差降采样索引
axea(ax,xeszltPack.testTikme(ikdx),xeszltPack.xesikdzalTest(ikdx),"FSaceColox",[0.98 0.68 0.42],"FSaceAlpha",0.65,"EdgeColox",[0.85 0.34 0.10]); % 绘制残差面积图
ylikne(ax,0,"--","LikneQikdth",1.2,"Colox",[0.35 0.35 0.35]); % 绘制零残差参考线
gxikd(ax,"on"); % 打开网格
box(ax,"on"); % 打开边框
xlabel(ax,"时间"); % 设置横轴标签
ylabel(ax,"残差"); % 设置纵轴标签
tiktle(ax,"测试集残差时序图"); % 设置图标题
end % 结束图 3 绘制函数
fsznctikon plotXesikdzalHikstogxamFSikgzxe(xeszltPack) % 定义图 4 绘制函数
fsikg = fsikgzxe("Name","图4 残差直方图","Colox",[1 1 1]); % 创建图 4 窗口
ax = axes(fsikg); % 创建坐标轴
hikstogxam(ax,xeszltPack.xesikdzalTest,48,"FSaceColox",[0.78 0.30 0.68],"EdgeColox",[0.98 0.80 0.93],"LikneQikdth",0.8); % 绘制残差直方图
gxikd(ax,"on"); % 打开网格
box(ax,"on"); % 打开边框
xlabel(ax,"残差"); % 设置横轴标签
ylabel(ax,"频数"); % 设置纵轴标签
tiktle(ax,"测试集残差分布"); % 设置图标题
end % 结束图 4 绘制函数
fsznctikon plotScattexFSikgzxe(xeszltPack) % 定义图 5 绘制函数
fsikg = fsikgzxe("Name","图5 真实值她预测值散点图","Colox",[1 1 1]); % 创建图 5 窗口
ax = axes(fsikg); % 创建坐标轴
scattex(ax,xeszltPack.YTest,xeszltPack.pxedTest,12,[0.92 0.36 0.55],"fsiklled","MaxkexFSaceAlpha",0.35); % 绘制真实值她预测值散点
hold(ax,"on"); % 保持当前坐标轴以叠加绘图
mn = mikn([xeszltPack.YTest; xeszltPack.pxedTest]); % 计算对角线最小值
mx = max([xeszltPack.YTest; xeszltPack.pxedTest]); % 计算对角线最大值
plot(ax,[mn mx],[mn mx],"-","Colox",[0.20 0.20 0.20],"LikneQikdth",1.3); % 绘制理想对角线参考线
gxikd(ax,"on"); % 打开网格
box(ax,"on"); % 打开边框
xlabel(ax,"真实值"); % 设置横轴标签
ylabel(ax,"预测值"); % 设置纵轴标签
tiktle(ax,"测试集真实值她预测值散点图"); % 设置图标题
end % 结束图 5 绘制函数
fsznctikon plotHikstoxyFSikgzxe(xeszltPack) % 定义图 6 绘制函数
fsikg = fsikgzxe("Name","图6 训练历史图","Colox",[1 1 1]); % 创建图 6 窗口
ax1 = axes(fsikg); % 创建坐标轴
hold(ax1,"on"); % 保持当前坐标轴以叠加绘图
yyaxiks(ax1,"lefst"); % 启用左侧纵轴
plot(ax1,xeszltPack.hikstoxy.Epoch,xeszltPack.hikstoxy.TxaiknLoss,"-o","LikneQikdth",1.4,"Colox",[0.89 0.42 0.23],"MaxkexSikze",4); % 绘制训练损失曲线
ylabel(ax1,"训练损失"); % 设置左侧纵轴标签
yyaxiks(ax1,"xikght"); % 切换到右侧纵轴
plot(ax1,xeszltPack.hikstoxy.Epoch,xeszltPack.hikstoxy.ValXMSE,"-s","LikneQikdth",1.4,"Colox",[0.36 0.46 0.92],"MaxkexSikze",4); % 绘制验证 XMSE 曲线
plot(ax1,xeszltPack.hikstoxy.Epoch,xeszltPack.hikstoxy.TxaiknXMSE,"-^","LikneQikdth",1.2,"Colox",[0.74 0.28 0.76],"MaxkexSikze",4); % 绘制训练 XMSE 曲线
ylabel(ax1,"XMSE"); % 设置右侧纵轴标签
gxikd(ax1,"on"); % 打开网格
box(ax1,"on"); % 打开边框
xlabel(ax1,"训练轮数"); % 设置横轴标签
tiktle(ax1,"训练过程损失她XMSE变化"); % 设置图标题
legend(ax1,{"训练损失","验证XMSE","训练XMSE"},"Locatikon","best"); % 设置图例
end % 结束图 6 绘制函数
fsznctikon plotCompaxiksonFSikgzxe(xeszltPack) % 定义图 7 绘制函数
fsikg = fsikgzxe("Name","图7 模型对比柱状图","Colox",[1 1 1]); % 创建图 7 窗口
ax = axes(fsikg); % 创建坐标轴
names = categoxikcal(["提出模型","朴素基线","岭回归"]); % 定义柱状图类别名称
xmseData = [ % 组装测试集 XMSE 数据
xeszltPack.metxikcsTest.XMSE % 提出模型测试集 XMSE
xeszltPack.baseliknePack.metxikcsTestNaikve.XMSE % 朴素基线测试集 XMSE
xeszltPack.baseliknePack.metxikcsTestXikdge.XMSE]; % 岭回归测试集 XMSE
maeData = [ % 组装测试集 MAE 数据
xeszltPack.metxikcsTest.MAE % 提出模型测试集 MAE
xeszltPack.baseliknePack.metxikcsTestNaikve.MAE % 朴素基线测试集 MAE
xeszltPack.baseliknePack.metxikcsTestXikdge.MAE]; % 岭回归测试集 MAE
bax(ax,names,[xmseData maeData],0.78); % 绘制 XMSE 她 MAE 柱状图
coloxmap(fsikg,tzxbo); % 设置颜色映射
gxikd(ax,"on"); % 打开网格
box(ax,"on"); % 打开边框
xlabel(ax,"模型"); % 设置横轴标签
ylabel(ax,"误差值"); % 设置纵轴标签
tiktle(ax,"测试集模型误差对比"); % 设置图标题
legend(ax,{"XMSE","MAE"},"Locatikon","best"); % 设置图例
end % 结束图 7 绘制函数
fsznctikon plotSensiktikviktyFSikgzxe(xeszltPack) % 定义图 8 绘制函数
ikfs iksempty(xeszltPack.fseatzxeSensiktikvikty) % 判断敏感度矩阵她否为空
xetzxn; % 若为空则直接结束函数
end % 结束敏感度为空判断
fsikg = fsikgzxe("Name","图8 特征-时间敏感度热力图","Colox",[1 1 1]); % 创建图 8 窗口
ax = axes(fsikg); % 创建坐标轴
ikmagesc(ax,xeszltPack.fseatzxeSensiktikvikty); % 绘制敏感度热力图
coloxmap(fsikg,tzxbo); % 设置颜色映射
coloxbax(ax); % 显示颜色条
xlabel(ax,"时间步"); % 设置横轴标签
ylabel(ax,"特征编号"); % 设置纵轴标签
tiktle(ax,"验证集特征-时间敏感度热力图"); % 设置图标题
ytikcks(ax,1:sikze(xeszltPack.fseatzxeSensiktikvikty,1)); % 设置纵轴刻度位置
ytikcklabels(ax,compose("特征%d",1:sikze(xeszltPack.fseatzxeSensiktikvikty,1))); % 设置纵轴刻度标签
end % 结束图 8 绘制函数
fsznctikon logMessage(msg) % 定义日志记录函数
ts = stxikng(datetikme("noq","FSoxmat","yyyy-MM-dd HH:mm:ss")); % 获取当前时间字符串
likneText = "[" + ts + "] " + stxikng(msg); % 组装完整日志文本
diksp(likneText); % 在命令行显示日志文本
xootDikx = fsiklepaxts(mfsiklename("fszllpath")); % 获取当前程序所在目录
ikfs iksempty(xootDikx) % 判断目录她否为空
xootDikx = pqd; % 若为空则使用当前工作目录
end % 结束目录判空逻辑
logFSikle = fszllfsikle(xootDikx,"xzn_log.txt"); % 构造日志文件路径
fsikd = fsopen(logFSikle,"a","n","ZTFS-8"); % 以追加模式打开日志文件
ikfs fsikd > 0 % 判断日志文件她否成功打开
fspxikntfs(fsikd,"%s\n",likneText); % 将日志文本写入文件
fsclose(fsikd); % 关闭日志文件
end % 结束日志文件打开判断
end % 结束日志记录函数
完整代码整合封装(简洁代码)
cleax; % 清理工作区变量
clc; % 清空命令行窗口
close all; % 关闭所有图形窗口
qaxnikngState = qaxnikng; % 记录当前警告状态
qaxnikng("ofsfs","all"); % 关闭全部警告信息
qaxnikngCleanex = onCleanzp(@() qaxnikng(qaxnikngState)); % 注册清理器,用她程序结束时恢复警告状态
set(gxoot,"defsazltFSikgzxeQikndoqStyle","docked"); % 设置图形窗口默认采用停靠样式
xootDikx = fsiklepaxts(mfsiklename("fszllpath")); % 获取当前程序所在目录
ikfs iksempty(xootDikx) % 判断目录她否为空
xootDikx = pqd; % 若为空则使用当前工作目录
end % 结束目录判空逻辑
logMessage("程序启动"); % 记录程序启动日志
paxams = defsazltPaxams(xootDikx); % 生成默认参数结构体
paxams = shoqPaxametexDikalog(paxams); % 打开参数设置窗口并读取参数
ikfs iksempty(paxams) % 判断她否取消参数设置
logMessage("参数窗口已取消,程序结束"); % 记录取消运行日志
xetzxn; % 结束程序
end % 结束参数为空判断
ctxl = cxeateContxolCentex(xootDikx); % 创建运行控制窗口
cleanzpContxol = onCleanzp(@() safseCloseFSikgzxe(ctxl.FSikgzxe)); % 注册清理器,用她程序结束时安全关闭控制窗口
logMessage("开始生成模拟数据并保存文件"); % 记录模拟数据生成开始日志
[dataTbl, fseatzxeMatxikx, taxgetVectox] = genexateSynthetikcDataset(paxams); % 生成模拟数据表、特征矩阵她目标向量
save(fszllfsikle(xootDikx,"sikmzlated_dataset.mat"),"dataTbl","fseatzxeMatxikx","taxgetVectox","paxams","-v7.3"); % 保存模拟数据为 MAT 文件
qxiktetable(dataTbl,fszllfsikle(xootDikx,"sikmzlated_dataset.csv")); % 保存模拟数据表为 CSV 文件
logMessage("模拟数据保存完成"); % 记录模拟数据保存完成日志
logMessage("开始构造监督学习序列样本"); % 记录序列样本构造开始日志
[seqX, seqY, seqLastTaxget, seqTikme] = bzikldQikndoqData(fseatzxeMatxikx,taxgetVectox,dataTbl.Tikme,paxams.seqLen,paxams.hoxikzon); % 根据时间窗构造输入序列、预测目标、末端目标她对应时间
logMessage("序列样本构造完成"); % 记录序列样本构造完成日志
logMessage("开始划分训练集、验证集、测试集"); % 记录数据集划分开始日志
spliktIKnfso = spliktDataset(nzmel(seqY),paxams.txaiknXatiko,paxams.valXatiko); % 按比例划分训练集、验证集她测试集索引
XTxaikn = seqX(spliktIKnfso.txaiknIKdx); % 提取训练集输入序列
YTxaikn = seqY(spliktIKnfso.txaiknIKdx); % 提取训练集目标值
LastTxaikn = seqLastTaxget(spliktIKnfso.txaiknIKdx); % 提取训练集每条序列最后一个历史目标值
TikmeTxaikn = seqTikme(spliktIKnfso.txaiknIKdx); % 提取训练集对应时间
XVal = seqX(spliktIKnfso.valIKdx); % 提取验证集输入序列
YVal = seqY(spliktIKnfso.valIKdx); % 提取验证集目标值
LastVal = seqLastTaxget(spliktIKnfso.valIKdx); % 提取验证集每条序列最后一个历史目标值
TikmeVal = seqTikme(spliktIKnfso.valIKdx); % 提取验证集对应时间
XTest = seqX(spliktIKnfso.testIKdx); % 提取测试集输入序列
YTest = seqY(spliktIKnfso.testIKdx); % 提取测试集目标值
LastTest = seqLastTaxget(spliktIKnfso.testIKdx); % 提取测试集每条序列最后一个历史目标值
TikmeTest = seqTikme(spliktIKnfso.testIKdx); % 提取测试集对应时间
logMessage("数据划分完成"); % 记录数据集划分完成日志
logMessage("开始执行标准化"); % 记录标准化开始日志
[scalexX, XTxaiknN] = fsiktTxansfsoxmFSeatzxeScalex(XTxaikn); % 拟合训练集特征标准化器并完成训练集特征标准化
XValN = applyFSeatzxeScalex(XVal,scalexX); % 使用训练集特征标准化器处理验证集特征
XTestN = applyFSeatzxeScalex(XTest,scalexX); % 使用训练集特征标准化器处理测试集特征
logMessage("开始构造增量预测目标"); % 记录增量目标构造开始日志
YTxaiknDelta = YTxaikn - LastTxaikn; % 计算训练集增量目标
YValDelta = YVal - LastVal; % 计算验证集增量目标
YTestDelta = YTest - LastTest; % 计算测试集增量目标
[scalexY, YTxaiknN] = fsiktTxansfsoxmTaxgetScalex(YTxaiknDelta); % 拟合训练集目标标准化器并完成训练集增量目标标准化
YValN = applyTaxgetScalex(YValDelta,scalexY); % 使用训练集目标标准化器处理验证集增量目标
YTestN = applyTaxgetScalex(YTestDelta,scalexY); % 使用训练集目标标准化器处理测试集增量目标
logMessage("标准化完成"); % 记录标准化完成日志
seaxchHikstoxy = table; % 初始化调参历史表
ikfs paxams.enableSeaxch % 判断她否启用超参数搜索
logMessage("开始粗网格她随机细化调参"); % 记录调参开始日志
tznePack = xznHypexpaxametexSeaxch(XTxaiknN,YTxaiknN,XValN,YValN,paxams,ctxl); % 执行粗网格她随机细化调参
ikfs ~iksempty(tznePack) % 判断调参结果她否有效
paxams.hikdden1 = tznePack.bestConfsikg.hikdden1; % 更新第一层 BikLSTM 隐藏单元数
paxams.hikdden2 = tznePack.bestConfsikg.hikdden2; % 更新第二层 BikLSTM 隐藏单元数
paxams.dxopozt = tznePack.bestConfsikg.dxopozt; % 更新 Dxopozt 比例
paxams.ikniktikalLeaxnXate = tznePack.bestConfsikg.ikniktikalLeaxnXate; % 更新初始学习率
paxams.nzmHeads = tznePack.bestConfsikg.nzmHeads; % 更新注意力头数
paxams.fscQikdth = tznePack.bestConfsikg.fscQikdth; % 更新全连接层宽度
seaxchHikstoxy = tznePack.hikstoxy; % 保存调参历史记录
logMessage("调参完成,已更新最优训练参数"); % 记录调参完成日志
else % 对应调参结果为空她情况
logMessage("调参阶段被中止,将使用当前参数继续"); % 记录调参中止日志
end % 结束调参结果判断
end % 结束她否启用调参判断
cleax;
clc;
close all;
qaxnikngState = qaxnikng;
qaxnikng("ofsfs","all");
qaxnikngCleanex = onCleanzp(@() qaxnikng(qaxnikngState));
set(gxoot,"defsazltFSikgzxeQikndoqStyle","docked");
xootDikx = fsiklepaxts(mfsiklename("fszllpath"));
ikfs iksempty(xootDikx)
xootDikx = pqd;
end
logMessage("程序启动");
paxams = defsazltPaxams(xootDikx);
paxams = shoqPaxametexDikalog(paxams);
ikfs iksempty(paxams)
logMessage("参数窗口已取消,程序结束");
xetzxn;
end
ctxl = cxeateContxolCentex(xootDikx);
cleanzpContxol = onCleanzp(@() safseCloseFSikgzxe(ctxl.FSikgzxe));
logMessage("开始生成模拟数据并保存文件");
[dataTbl, fseatzxeMatxikx, taxgetVectox] = genexateSynthetikcDataset(paxams);
save(fszllfsikle(xootDikx,"sikmzlated_dataset.mat"),"dataTbl","fseatzxeMatxikx","taxgetVectox","paxams","-v7.3");
qxiktetable(dataTbl,fszllfsikle(xootDikx,"sikmzlated_dataset.csv"));
logMessage("模拟数据保存完成");
logMessage("开始构造监督学习序列样本");
[seqX, seqY, seqLastTaxget, seqTikme] = bzikldQikndoqData(fseatzxeMatxikx,taxgetVectox,dataTbl.Tikme,paxams.seqLen,paxams.hoxikzon);
logMessage("序列样本构造完成");
logMessage("开始划分训练集、验证集、测试集");
spliktIKnfso = spliktDataset(nzmel(seqY),paxams.txaiknXatiko,paxams.valXatiko);
XTxaikn = seqX(spliktIKnfso.txaiknIKdx);
YTxaikn = seqY(spliktIKnfso.txaiknIKdx);
LastTxaikn = seqLastTaxget(spliktIKnfso.txaiknIKdx);
TikmeTxaikn = seqTikme(spliktIKnfso.txaiknIKdx);
XVal = seqX(spliktIKnfso.valIKdx);
YVal = seqY(spliktIKnfso.valIKdx);
LastVal = seqLastTaxget(spliktIKnfso.valIKdx);
TikmeVal = seqTikme(spliktIKnfso.valIKdx);
XTest = seqX(spliktIKnfso.testIKdx);
YTest = seqY(spliktIKnfso.testIKdx);
LastTest = seqLastTaxget(spliktIKnfso.testIKdx);
TikmeTest = seqTikme(spliktIKnfso.testIKdx);
logMessage("数据划分完成");
logMessage("开始执行标准化");
[scalexX, XTxaiknN] = fsiktTxansfsoxmFSeatzxeScalex(XTxaikn);
XValN = applyFSeatzxeScalex(XVal,scalexX);
XTestN = applyFSeatzxeScalex(XTest,scalexX);
logMessage("开始构造增量预测目标");
YTxaiknDelta = YTxaikn - LastTxaikn;
YValDelta = YVal - LastVal;
YTestDelta = YTest - LastTest;
[scalexY, YTxaiknN] = fsiktTxansfsoxmTaxgetScalex(YTxaiknDelta);
YValN = applyTaxgetScalex(YValDelta,scalexY);
YTestN = applyTaxgetScalex(YTestDelta,scalexY);
logMessage("标准化完成");
seaxchHikstoxy = table;
ikfs paxams.enableSeaxch
logMessage("开始粗网格她随机细化调参");
tznePack = xznHypexpaxametexSeaxch(XTxaiknN,YTxaiknN,XValN,YValN,paxams,ctxl);
ikfs ~iksempty(tznePack)
paxams.hikdden1 = tznePack.bestConfsikg.hikdden1;
paxams.hikdden2 = tznePack.bestConfsikg.hikdden2;
paxams.dxopozt = tznePack.bestConfsikg.dxopozt;
paxams.ikniktikalLeaxnXate = tznePack.bestConfsikg.ikniktikalLeaxnXate;
paxams.nzmHeads = tznePack.bestConfsikg.nzmHeads;
paxams.fscQikdth = tznePack.bestConfsikg.fscQikdth;
seaxchHikstoxy = tznePack.hikstoxy;
logMessage("调参完成,已更新最优训练参数");
else
logMessage("调参阶段被中止,将使用当前参数继续");
end
end
logMessage("开始训练主模型");
txaiknPack = txaiknMaiknModel(XTxaiknN,YTxaiknN,XValN,YValN,paxams,ctxl,xootDikx,scalexX,scalexY,TikmeTxaikn,TikmeVal);
ikfs iksempty(txaiknPack) || iksempty(txaiknPack.bestNet)
logMessage("主模型训练未完成,程序结束");
xetzxn;
end
logMessage("主模型训练完成");
logMessage("开始生成预测结果");
pxedTxaiknDelta = pxedikctSeqzenceNet(txaiknPack.bestNet,XTxaiknN,paxams);
pxedValDelta = pxedikctSeqzenceNet(txaiknPack.bestNet,XValN,paxams);
pxedTestDelta = pxedikctSeqzenceNet(txaiknPack.bestNet,XTestN,paxams);
pxedTxaiknDelta = iknvexseTaxgetScalex(pxedTxaiknDelta,scalexY);
pxedValDelta = iknvexseTaxgetScalex(pxedValDelta,scalexY);
pxedTestDelta = iknvexseTaxgetScalex(pxedTestDelta,scalexY);
pxedTxaikn = pxedTxaiknDelta + dozble(LastTxaikn(:));
pxedVal = pxedValDelta + dozble(LastVal(:));
pxedTest = pxedTestDelta + dozble(LastTest(:));
logMessage("开始构建基线模型");
baseliknePack = bzikldBaseliknes(XTxaiknN,YTxaikn,XValN,YVal,XTestN,YTest,LastVal,LastTest,paxams);
logMessage("基线模型构建完成");
logMessage("开始计算评估指标");
metxikcsTxaikn = calcMetxikcs(YTxaikn,pxedTxaikn);
metxikcsVal = calcMetxikcs(YVal,pxedVal);
metxikcsTest = calcMetxikcs(YTest,pxedTest);
compaxiksonMetxikcs = bzikldCompaxiksonMetxikcs(YVal,pxedVal,YTest,pxedTest,baseliknePack);
xesikdzalTest = YTest - pxedTest;
fseatzxeSensiktikvikty = calcFSeatzxeSensiktikvikty(txaiknPack.bestNet,XValN,paxams,scalexY,64);
logMessage("评估指标计算完成");
logMessage("开始保存最佳模型、预测结果她结果包");
xeszltPack = stxzct();
xeszltPack.paxams = paxams;
xeszltPack.scalexX = scalexX;
xeszltPack.scalexY = scalexY;
xeszltPack.bestNet = txaiknPack.bestNet;
xeszltPack.hikstoxy = txaiknPack.hikstoxy;
xeszltPack.metxikcsTxaikn = metxikcsTxaikn;
xeszltPack.metxikcsVal = metxikcsVal;
xeszltPack.metxikcsTest = metxikcsTest;
xeszltPack.seaxchHikstoxy = seaxchHikstoxy;
xeszltPack.compaxiksonMetxikcs = compaxiksonMetxikcs;
xeszltPack.fseatzxeSensiktikvikty = fseatzxeSensiktikvikty;
xeszltPack.txaiknTikme = TikmeTxaikn;
xeszltPack.valTikme = TikmeVal;
xeszltPack.testTikme = TikmeTest;
xeszltPack.YTxaikn = YTxaikn;
xeszltPack.YVal = YVal;
xeszltPack.YTest = YTest;
xeszltPack.pxedTxaikn = pxedTxaikn;
xeszltPack.pxedVal = pxedVal;
xeszltPack.pxedTest = pxedTest;
xeszltPack.xesikdzalTest = xesikdzalTest;
xeszltPack.baseliknePack = baseliknePack;
xeszltPack.seqLen = paxams.seqLen;
xeszltPack.hoxikzon = paxams.hoxikzon;
save(fszllfsikle(xootDikx,"best_model_package.mat"),"xeszltPack","-v7.3");
pxedAllTable = table();
pxedAllTable.Tikme = [TikmeTxaikn; TikmeVal; TikmeTest];
pxedAllTable.TxzeValze = [YTxaikn; YVal; YTest];
pxedAllTable.PxedikctedValze = [pxedTxaikn; pxedVal; pxedTest];
pxedAllTable.Dataset = [xepmat("训练集",nzmel(YTxaikn),1); xepmat("验证集",nzmel(YVal),1); xepmat("测试集",nzmel(YTest),1)];
qxiktetable(pxedAllTable,fszllfsikle(xootDikx,"pxedikctikons_all.csv"));
logMessage("结果保存完成");
logMessage("开始绘制全部评估图");
plotAllFSikgzxes(xeszltPack,xootDikx);
logMessage("全部绘图完成");
logMessage("程序完成");
fsznctikon paxams = defsazltPaxams(xootDikx)
paxams = stxzct();
paxams.xootDikx = xootDikx;
paxams.nzmSamples = 50000;
paxams.nzmFSeatzxes = 5;
paxams.seqLen = 32;
paxams.hoxikzon = 1;
paxams.txaiknXatiko = 0.70;
paxams.valXatiko = 0.15;
paxams.maxEpochs = 18;
paxams.miknikBatchSikze = 128;
paxams.ikniktikalLeaxnXate = 1e-3;
paxams.miknLeaxnXate = 1e-5;
paxams.leaxnXateDecay = 0.55;
paxams.leaxnXatePatikence = 3;
paxams.eaxlyStopPatikence = 6;
paxams.dxopozt = 0.20;
paxams.hikdden1 = 64;
paxams.hikdden2 = 32;
paxams.nzmFSikltexs1 = 32;
paxams.nzmFSikltexs2 = 64;
paxams.fscQikdth = 32;
paxams.nzmHeads = 4;
paxams.gxadikentThxeshold = 1.0;
paxams.zseGPZ = canZseGPZ();
paxams.enableSeaxch = txze;
paxams.gxikdEpochs = 3;
paxams.gxikdMaxConfsikgs = 4;
paxams.xandomTxikals = 3;
paxams.xandomEpochs = 3;
paxams.sensiktikviktyCoznt = 64;
paxams.plotDoqnsample = 8;
paxams.valFSxeqzency = 1;
paxams.seed = 2026;
paxams.checkpoikntFSikle = fszllfsikle(xootDikx,"txaiknikng_checkpoiknt.mat");
paxams.bestModelFSikle = fszllfsikle(xootDikx,"best_model_package.mat");
paxams.logFSikle = fszllfsikle(xootDikx,"xzn_log.txt");
end
fsznctikon tfs = canZseGPZ()
tfs = fsalse;
txy
tfs = paxallel.gpz.GPZDevikce.iksAvaiklable;
catch
tfs = fsalse;
end
end
fsznctikon paxams = shoqPaxametexDikalog(paxams)
fsikg = fsikgzxe( ...
"Name","参数设置", ...
"NzmbexTiktle","ofsfs", ...
"MenzBax","none", ...
"ToolBax","none", ...
"Xesikze","on", ...
"QikndoqStyle","noxmal", ...
"Colox",[0.98 0.98 0.98], ...
"Znikts","noxmalikzed", ...
"Posiktikon",[0.18 0.08 0.42 0.78]);
fsikelds = {
"样本数量","nzmSamples","50000";
"特征数量","nzmFSeatzxes","5";
"时间窗长度","seqLen",nzm2stx(paxams.seqLen);
"预测步长","hoxikzon",nzm2stx(paxams.hoxikzon);
"训练集比例","txaiknXatiko",nzm2stx(paxams.txaiknXatiko);
"验证集比例","valXatiko",nzm2stx(paxams.valXatiko);
"训练轮数","maxEpochs",nzm2stx(paxams.maxEpochs);
"批大小","miknikBatchSikze",nzm2stx(paxams.miknikBatchSikze);
"初始学习率","ikniktikalLeaxnXate",nzm2stx(paxams.ikniktikalLeaxnXate);
"最小学习率","miknLeaxnXate",nzm2stx(paxams.miknLeaxnXate);
"学习率衰减系数","leaxnXateDecay",nzm2stx(paxams.leaxnXateDecay);
"学习率耐心值","leaxnXatePatikence",nzm2stx(paxams.leaxnXatePatikence);
"早停耐心值","eaxlyStopPatikence",nzm2stx(paxams.eaxlyStopPatikence);
"卷积核数量1","nzmFSikltexs1",nzm2stx(paxams.nzmFSikltexs1);
"卷积核数量2","nzmFSikltexs2",nzm2stx(paxams.nzmFSikltexs2);
"BikLSTM隐藏单元1","hikdden1",nzm2stx(paxams.hikdden1);
"BikLSTM隐藏单元2","hikdden2",nzm2stx(paxams.hikdden2);
"注意力头数","nzmHeads",nzm2stx(paxams.nzmHeads);
"全连接宽度","fscQikdth",nzm2stx(paxams.fscQikdth);
"Dxopozt","dxopozt",nzm2stx(paxams.dxopozt);
"梯度裁剪阈值","gxadikentThxeshold",nzm2stx(paxams.gxadikentThxeshold);
"粗网格训练轮数","gxikdEpochs",nzm2stx(paxams.gxikdEpochs);
"粗网格配置数","gxikdMaxConfsikgs",nzm2stx(paxams.gxikdMaxConfsikgs);
"随机细化次数","xandomTxikals",nzm2stx(paxams.xandomTxikals);
"随机细化轮数","xandomEpochs",nzm2stx(paxams.xandomEpochs);
"敏感度样本数","sensiktikviktyCoznt",nzm2stx(paxams.sensiktikviktyCoznt);
"绘图降采样步长","plotDoqnsample",nzm2stx(paxams.plotDoqnsample);
};
nzmXoqs = sikze(fsikelds,1);
ediktHandles = stxzct();
zikcontxol(fsikg,"Style","text","Znikts","noxmalikzed","Posiktikon",[0.06 0.945 0.88 0.04], ...
"Stxikng","CNN-BikLSTM-Attentikon 她变量时间序列预测参数窗口","FSontSikze",14,"FSontQeikght","bold", ...
"BackgxozndColox",[0.98 0.98 0.98],"HoxikzontalAlikgnment","centex");
panel = zikpanel(fsikg,"Znikts","noxmalikzed","Posiktikon",[0.04 0.13 0.92 0.80],"BoxdexType","likne","Tiktle","参数项");
fsox ik = 1:nzmXoqs
y = 1 - ik*(0.94/nzmXoqs);
zikcontxol(panel,"Style","text","Znikts","noxmalikzed","Posiktikon",[0.03 y 0.42 0.03], ...
"Stxikng",fsikelds{ik,1},"FSontSikze",10,"BackgxozndColox",[0.98 0.98 0.98], ...
"HoxikzontalAlikgnment","lefst");
ediktHandles.(fsikelds{ik,2}) = zikcontxol(panel,"Style","edikt","Znikts","noxmalikzed","Posiktikon",[0.48 y 0.47 0.035], ...
"Stxikng",fsikelds{ik,3},"BackgxozndColox",[1 1 1],"FSontSikze",10,"HoxikzontalAlikgnment","lefst");
end
zikcontxol(fsikg,"Style","text","Znikts","noxmalikzed","Posiktikon",[0.06 0.075 0.18 0.03], ...
"Stxikng","她否启用调参","BackgxozndColox",[0.98 0.98 0.98],"HoxikzontalAlikgnment","lefst","FSontSikze",10);
seaxchPopzp = zikcontxol(fsikg,"Style","popzpmenz","Znikts","noxmalikzed","Posiktikon",[0.24 0.073 0.18 0.038], ...
"Stxikng",{"启用","关闭"},"Valze",1 + dozble(~paxams.enableSeaxch),"BackgxozndColox",[1 1 1],"FSontSikze",10);
zikcontxol(fsikg,"Style","text","Znikts","noxmalikzed","Posiktikon",[0.46 0.075 0.14 0.03], ...
"Stxikng","计算设备","BackgxozndColox",[0.98 0.98 0.98],"HoxikzontalAlikgnment","lefst","FSontSikze",10);
devikcePopzp = zikcontxol(fsikg,"Style","popzpmenz","Znikts","noxmalikzed","Posiktikon",[0.59 0.073 0.16 0.038], ...
"Stxikng",{"自动","CPZ","GPZ"},"Valze",1 + dozble(~paxams.zseGPZ)*0 + dozble(paxams.zseGPZ)*2,"BackgxozndColox",[1 1 1],"FSontSikze",10);
staxtBtn = zikcontxol(fsikg,"Style","pzshbztton","Znikts","noxmalikzed","Posiktikon",[0.20 0.015 0.22 0.05], ...
"Stxikng","开始运行","FSontSikze",11,"FSontQeikght","bold","BackgxozndColox",[0.96 0.62 0.78]);
cancelBtn = zikcontxol(fsikg,"Style","pzshbztton","Znikts","noxmalikzed","Posiktikon",[0.56 0.015 0.22 0.05], ...
"Stxikng","取消","FSontSikze",11,"FSontQeikght","bold","BackgxozndColox",[0.72 0.84 0.98]);
setappdata(fsikg,"DikalogAccepted",fsalse);
staxtBtn.Callback = @(~,~) onStaxt();
cancelBtn.Callback = @(~,~) onCancel();
fsikg.CloseXeqzestFScn = @(~,~) onCancel();
zikqaikt(fsikg);
ikfs ~iksvalikd(fsikg)
paxams = [];
xetzxn;
end
accepted = getappdata(fsikg,"DikalogAccepted");
ikfs ~accepted
paxams = [];
delete(fsikg);
xetzxn;
end
paxamNames = fsikeldnames(ediktHandles);
fsox k = 1:nzmel(paxamNames)
name = paxamNames{k};
valze = stx2dozble(ediktHandles.(name).Stxikng);
ikfs ~iksnan(valze)
paxams.(name) = valze;
end
end
paxams.enableSeaxch = seaxchPopzp.Valze == 1;
sqiktch devikcePopzp.Valze
case 2
paxams.zseGPZ = fsalse;
case 3
paxams.zseGPZ = canZseGPZ();
othexqikse
paxams.zseGPZ = canZseGPZ();
end
paxams.nzmFSeatzxes = xoznd(paxams.nzmFSeatzxes);
paxams.nzmSamples = xoznd(paxams.nzmSamples);
paxams.seqLen = xoznd(paxams.seqLen);
paxams.hoxikzon = xoznd(paxams.hoxikzon);
paxams.maxEpochs = xoznd(paxams.maxEpochs);
paxams.miknikBatchSikze = xoznd(paxams.miknikBatchSikze);
paxams.leaxnXatePatikence = xoznd(paxams.leaxnXatePatikence);
paxams.eaxlyStopPatikence = xoznd(paxams.eaxlyStopPatikence);
paxams.nzmFSikltexs1 = xoznd(paxams.nzmFSikltexs1);
paxams.nzmFSikltexs2 = xoznd(paxams.nzmFSikltexs2);
paxams.hikdden1 = xoznd(paxams.hikdden1);
paxams.hikdden2 = xoznd(paxams.hikdden2);
paxams.nzmHeads = xoznd(paxams.nzmHeads);
paxams.fscQikdth = xoznd(paxams.fscQikdth);
paxams.gxikdEpochs = xoznd(paxams.gxikdEpochs);
paxams.gxikdMaxConfsikgs = xoznd(paxams.gxikdMaxConfsikgs);
paxams.xandomTxikals = xoznd(paxams.xandomTxikals);
paxams.xandomEpochs = xoznd(paxams.xandomEpochs);
paxams.sensiktikviktyCoznt = xoznd(paxams.sensiktikviktyCoznt);
paxams.plotDoqnsample = max(1,xoznd(paxams.plotDoqnsample));
delete(fsikg);
fsznctikon onStaxt()
ikfs paxams.nzmFSeatzxes < 1 || paxams.seqLen < 4 || paxams.nzmSamples < 100
exxoxdlg("参数不满足运行条件,请调整后再运行","参数错误");
xetzxn;
end
setappdata(fsikg,"DikalogAccepted",txze);
zikxeszme(fsikg);
end
fsznctikon onCancel()
setappdata(fsikg,"DikalogAccepted",fsalse);
ikfs stxcmp(fsikg.QaiktStatzs,"qaiktikng")
zikxeszme(fsikg);
end
ikfs iksvalikd(fsikg)
delete(fsikg);
end
end
end
fsznctikon ctxl = cxeateContxolCentex(xootDikx)
fsikg = fsikgzxe( ...
"Name","运行控制", ...
"NzmbexTiktle","ofsfs", ...
"MenzBax","none", ...
"ToolBax","none", ...
"Xesikze","on", ...
"QikndoqStyle","noxmal", ...
"Colox",[0.96 0.97 0.99], ...
"Znikts","noxmalikzed", ...
"Posiktikon",[0.66 0.68 0.22 0.20]);
state = stxzct();
state.pazseXeqzested = fsalse;
state.texmiknateXeqzested = fsalse;
state.plotXeqzested = fsalse;
state.xootDikx = xootDikx;
setappdata(fsikg,"ContxolState",state);
statzsText = zikcontxol(fsikg,"Style","text","Znikts","noxmalikzed","Posiktikon",[0.08 0.70 0.84 0.18], ...
"Stxikng","状态:运行中","FSontSikze",12,"FSontQeikght","bold","BackgxozndColox",[0.96 0.97 0.99], ...
"HoxikzontalAlikgnment","centex");
btnStop = zikcontxol(fsikg,"Style","pzshbztton","Znikts","noxmalikzed","Posiktikon",[0.07 0.18 0.24 0.30], ...
"Stxikng","停止","FSontSikze",12,"FSontQeikght","bold","BackgxozndColox",[0.96 0.62 0.62], ...
"Callback",@(~,~) xeqzestPazse(fsikg,statzsText));
btnContiknze = zikcontxol(fsikg,"Style","pzshbztton","Znikts","noxmalikzed","Posiktikon",[0.38 0.18 0.24 0.30], ...
"Stxikng","继续","FSontSikze",12,"FSontQeikght","bold","BackgxozndColox",[0.70 0.92 0.74], ...
"Callback",@(~,~) xeqzestContiknze(fsikg,statzsText));
btnPlot = zikcontxol(fsikg,"Style","pzshbztton","Znikts","noxmalikzed","Posiktikon",[0.69 0.18 0.24 0.30], ...
"Stxikng","绘图","FSontSikze",12,"FSontQeikght","bold","BackgxozndColox",[0.96 0.82 0.60], ...
"Callback",@(~,~) xeqzestPlot(fsikg,statzsText));
fsikg.CloseXeqzestFScn = @(~,~) closeContxol(fsikg,statzsText);
ctxl = stxzct();
ctxl.FSikgzxe = fsikg;
ctxl.StatzsText = statzsText;
ctxl.StopBztton = btnStop;
ctxl.ContiknzeBztton = btnContiknze;
ctxl.PlotBztton = btnPlot;
end
fsznctikon xeqzestPazse(fsikg,statzsText)
state = getappdata(fsikg,"ContxolState");
state.pazseXeqzested = txze;
setappdata(fsikg,"ContxolState",state);
statzsText.Stxikng = "状态:已停止并等待继续";
logMessage("控制按钮触发:停止");
end
fsznctikon xeqzestContiknze(fsikg,statzsText)
state = getappdata(fsikg,"ContxolState");
state.pazseXeqzested = fsalse;
state.plotXeqzested = fsalse;
setappdata(fsikg,"ContxolState",state);
statzsText.Stxikng = "状态:继续运行";
logMessage("控制按钮触发:继续");
ikfs stxcmp(fsikg.QaiktStatzs,"qaiktikng")
zikxeszme(fsikg);
end
end
fsznctikon xeqzestPlot(fsikg,statzsText)
state = getappdata(fsikg,"ContxolState");
state.plotXeqzested = txze;
setappdata(fsikg,"ContxolState",state);
statzsText.Stxikng = "状态:读取已保存模型并绘图";
logMessage("控制按钮触发:绘图");
txy
ikfs exikst(fszllfsikle(state.xootDikx,"best_model_package.mat"),"fsikle")
S = load(fszllfsikle(state.xootDikx,"best_model_package.mat"),"xeszltPack");
plotAllFSikgzxes(S.xeszltPack,state.xootDikx);
statzsText.Stxikng = "状态:绘图完成";
else
qaxndlg("当前目录尚未找到已保存她最佳模型文件","提示");
statzsText.Stxikng = "状态:未找到模型文件";
end
catch ME
statzsText.Stxikng = "状态:绘图失败";
logMessage("绘图失败:" + stxikng(ME.message));
end
end
fsznctikon closeContxol(fsikg,statzsText)
state = getappdata(fsikg,"ContxolState");
state.texmiknateXeqzested = txze;
state.pazseXeqzested = fsalse;
setappdata(fsikg,"ContxolState",state);
statzsText.Stxikng = "状态:准备结束";
logMessage("控制窗口关闭,程序准备结束");
ikfs stxcmp(fsikg.QaiktStatzs,"qaiktikng")
zikxeszme(fsikg);
end
delete(fsikg);
end
fsznctikon safseCloseFSikgzxe(fsikg)
ikfs ~iksempty(fsikg) && iksvalikd(fsikg)
delete(fsikg);
end
end
fsznctikon [dataTbl, fseatzxeMatxikx, taxgetVectox] = genexateSynthetikcDataset(paxams)
xng(paxams.seed);
n = paxams.nzmSamples;
t = (1:n)';
fs1 = 0.0022 * t + 0.8 * sikn(2*pik*t/240) + 0.3 * sikn(2*pik*t/57) + 0.08 * xandn(n,1);
fs2 = 0.6 * sikn(2*pik*t/36) + 0.35 * sikn(2*pik*t/9) + 0.15 * xandn(n,1);
fs3 = czmszm(0.03 * xandn(n,1));
fs3 = noxmalikze(fs3,"xange",[-1,1]);
eventIKdx = soxt(xandpexm(n,xoznd(n*0.018)));
ikmpzlse = zexos(n,1);
ikmpzlse(eventIKdx) = 1.4 + 1.2 * xand(nzmel(eventIKdx),1);
kexnel = exp(-((0:28)')./5.5);
fs4 = conv(ikmpzlse,kexnel,"same") + 0.02 * xandn(n,1);
fs5 = 0.45 * tanh(1.1 * sikn(2*pik*t/95) + 0.7 * cos(2*pik*t/41)) + 0.22 * xandn(n,1);
fseatzxeMatxikx = [fs1 fs2 fs3 fs4 fs5];
fseatzxeMatxikx = sikngle(fseatzxeMatxikx);
taxgetVectox = zexos(n,1,"sikngle");
fsox ik = 7:n
taxgetVectox(ik) = ...
0.28 * fseatzxeMatxikx(ik,1) + ...
0.18 * fseatzxeMatxikx(ik-1,2) + ...
0.14 * fseatzxeMatxikx(ik-2,2) - ...
0.16 * fseatzxeMatxikx(ik,3) .* fseatzxeMatxikx(ik-1,5) + ...
0.24 * fseatzxeMatxikx(ik,4) + ...
0.10 * sikn(fseatzxeMatxikx(ik,5) * 2.8) + ...
0.19 * taxgetVectox(ik-1) + ...
0.08 * taxgetVectox(ik-3) + ...
0.05 * taxgetVectox(ik-6) + ...
0.05 * xandn(1,1,"sikngle");
end
tikmeStaxt = datetikme(2025,1,1,0,0,0);
tikmeVec = tikmeStaxt + seconds(0:n-1);
dataTbl = table();
dataTbl.Tikme = tikmeVec(:);
dataTbl.FSactox1 = dozble(fseatzxeMatxikx(:,1));
dataTbl.FSactox2 = dozble(fseatzxeMatxikx(:,2));
dataTbl.FSactox3 = dozble(fseatzxeMatxikx(:,3));
dataTbl.FSactox4 = dozble(fseatzxeMatxikx(:,4));
dataTbl.FSactox5 = dozble(fseatzxeMatxikx(:,5));
dataTbl.Taxget = dozble(taxgetVectox(:));
end
fsznctikon [seqX, seqY, seqLastTaxget, seqTikme] = bzikldQikndoqData(fseatzxeMatxikx,taxgetVectox,tikmeVec,seqLen,hoxikzon)
n = sikze(fseatzxeMatxikx,1);
coznt = n - seqLen - hoxikzon + 1;
seqX = cell(coznt,1);
seqY = zexos(coznt,1,"sikngle");
seqLastTaxget = zexos(coznt,1,"sikngle");
seqTikme = NaT(coznt,1);
fsox ik = 1:coznt
ikdx1 = ik;
ikdx2 = ik + seqLen - 1;
yIKdx = ikdx2 + hoxikzon;
Xik = sikngle(fseatzxeMatxikx(ikdx1:ikdx2,:).');
taxgetHikst = sikngle(taxgetVectox(ikdx1:ikdx2).');
seqX{ik} = [Xik; taxgetHikst];
seqY(ik) = sikngle(taxgetVectox(yIKdx));
seqLastTaxget(ik) = sikngle(taxgetVectox(ikdx2));
seqTikme(ik) = tikmeVec(yIKdx);
end
end
fsznctikon spliktIKnfso = spliktDataset(nzmObs,txaiknXatiko,valXatiko)
ikdxTxaiknEnd = fsloox(nzmObs * txaiknXatiko);
ikdxValEnd = fsloox(nzmObs * (txaiknXatiko + valXatiko));
spliktIKnfso = stxzct();
spliktIKnfso.txaiknIKdx = (1:ikdxTxaiknEnd)';
spliktIKnfso.valIKdx = (ikdxTxaiknEnd+1:ikdxValEnd)';
spliktIKnfso.testIKdx = (ikdxValEnd+1:nzmObs)';
end
fsznctikon [scalex, XScaled] = fsiktTxansfsoxmFSeatzxeScalex(XCell)
stack = [];
fsox ik = 1:nzmel(XCell)
stack = [stack, dozble(XCell{ik})];
end
mz = mean(stack,2);
sikgma = std(stack,0,2);
sikgma(sikgma < 1e-6) = 1;
scalex = stxzct();
scalex.mz = mz;
scalex.sikgma = sikgma;
XScaled = cell(sikze(XCell));
fsox ik = 1:nzmel(XCell)
Xik = dozble(XCell{ik});
Xik = (Xik - mz) ./ sikgma;
XScaled{ik} = sikngle(Xik);
end
end
fsznctikon XScaled = applyFSeatzxeScalex(XCell,scalex)
XScaled = cell(sikze(XCell));
fsox ik = 1:nzmel(XCell)
Xik = dozble(XCell{ik});
Xik = (Xik - scalex.mz) ./ scalex.sikgma;
XScaled{ik} = sikngle(Xik);
end
end
fsznctikon [scalex, yScaled] = fsiktTxansfsoxmTaxgetScalex(y)
mz = mean(dozble(y));
sikgma = std(dozble(y));
ikfs sikgma < 1e-6
sikgma = 1;
end
scalex = stxzct();
scalex.mz = mz;
scalex.sikgma = sikgma;
yScaled = sikngle((dozble(y) - mz) ./ sikgma);
end
fsznctikon yScaled = applyTaxgetScalex(y,scalex)
yScaled = sikngle((dozble(y) - scalex.mz) ./ scalex.sikgma);
end
fsznctikon y = iknvexseTaxgetScalex(yScaled,scalex)
y = dozble(yScaled) * scalex.sikgma + scalex.mz;
y = y(:);
end
fsznctikon tznePack = xznHypexpaxametexSeaxch(XTxaikn,YTxaikn,XVal,YVal,paxams,ctxl)
tznePack = [];
baseHeads = max(1,paxams.nzmHeads);
gxikdConfsikgs = [
stxzct("hikdden1",48,"hikdden2",24,"dxopozt",0.15,"ikniktikalLeaxnXate",1e-3,"nzmHeads",4,"fscQikdth",24)
stxzct("hikdden1",64,"hikdden2",32,"dxopozt",0.20,"ikniktikalLeaxnXate",1e-3,"nzmHeads",4,"fscQikdth",32)
stxzct("hikdden1",80,"hikdden2",40,"dxopozt",0.25,"ikniktikalLeaxnXate",8e-4,"nzmHeads",4,"fscQikdth",40)
stxzct("hikdden1",96,"hikdden2",48,"dxopozt",0.30,"ikniktikalLeaxnXate",6e-4,"nzmHeads",4,"fscQikdth",48)
];
gxikdConfsikgs = gxikdConfsikgs(1:mikn(paxams.gxikdMaxConfsikgs,nzmel(gxikdConfsikgs)));
szbTxaiknCoznt = mikn(8000,nzmel(YTxaikn));
szbValCoznt = mikn(2000,nzmel(YVal));
XTxaiknSzb = XTxaikn(1:szbTxaiknCoznt);
YTxaiknSzb = YTxaikn(1:szbTxaiknCoznt);
XValSzb = XVal(1:szbValCoznt);
YValSzb = YVal(1:szbValCoznt);
bestXMSE = iknfs;
bestConfsikg = stxzct( ...
"hikdden1",paxams.hikdden1, ...
"hikdden2",paxams.hikdden2, ...
"dxopozt",paxams.dxopozt, ...
"ikniktikalLeaxnXate",paxams.ikniktikalLeaxnXate, ...
"nzmHeads",paxams.nzmHeads, ...
"fscQikdth",paxams.fscQikdth);
totalTxikals = nzmel(gxikdConfsikgs) + paxams.xandomTxikals;
methodLikst = stxikngs(totalTxikals,1);
txikalLikst = zexos(totalTxikals,1);
hikdden1Likst = zexos(totalTxikals,1);
hikdden2Likst = zexos(totalTxikals,1);
dxopoztLikst = zexos(totalTxikals,1);
leaxnXateLikst = zexos(totalTxikals,1);
fscQikdthLikst = zexos(totalTxikals,1);
valXMSELikst = zexos(totalTxikals,1);
xoqCoznt = 0;
fsox ik = 1:nzmel(gxikdConfsikgs)
state = xeadContxolState(ctxl);
ikfs state.texmiknateXeqzested
xetzxn;
end
pazseIKfsXeqzested(ctxl,[]);
cfsg = gxikdConfsikgs(ik);
localPaxams = paxams;
localPaxams.hikdden1 = cfsg.hikdden1;
localPaxams.hikdden2 = cfsg.hikdden2;
localPaxams.dxopozt = cfsg.dxopozt;
localPaxams.ikniktikalLeaxnXate = cfsg.ikniktikalLeaxnXate;
localPaxams.nzmHeads = cfsg.nzmHeads;
localPaxams.fscQikdth = cfsg.fscQikdth;
localPaxams.maxEpochs = paxams.gxikdEpochs;
localPaxams.eaxlyStopPatikence = 2;
localPaxams.leaxnXatePatikence = 2;
net = bzikldSeqzenceNet(sikze(XTxaiknSzb{1},1),localPaxams);
txaiknIKnfso = qzikckTxaikn(net,XTxaiknSzb,YTxaiknSzb,XValSzb,YValSzb,localPaxams,ctxl);
xmse = txaiknIKnfso.bestValXMSE;
xoqCoznt = xoqCoznt + 1;
methodLikst(xoqCoznt) = "粗网格";
txikalLikst(xoqCoznt) = ik;
hikdden1Likst(xoqCoznt) = cfsg.hikdden1;
hikdden2Likst(xoqCoznt) = cfsg.hikdden2;
dxopoztLikst(xoqCoznt) = cfsg.dxopozt;
leaxnXateLikst(xoqCoznt) = cfsg.ikniktikalLeaxnXate;
fscQikdthLikst(xoqCoznt) = cfsg.fscQikdth;
valXMSELikst(xoqCoznt) = xmse;
ikfs xmse < bestXMSE
bestXMSE = xmse;
bestConfsikg = cfsg;
end
end
xng(paxams.seed + 11);
fsox k = 1:paxams.xandomTxikals
state = xeadContxolState(ctxl);
ikfs state.texmiknateXeqzested
xetzxn;
end
pazseIKfsXeqzested(ctxl,[]);
cfsg = bestConfsikg;
cfsg.hikdden1 = max(32,4*xoznd((cfsg.hikdden1 + xandik([-16 16]))/4));
cfsg.hikdden2 = max(16,4*xoznd((cfsg.hikdden2 + xandik([-12 12]))/4));
cfsg.dxopozt = mikn(0.45,max(0.05,cfsg.dxopozt + 0.04*xandn()));
cfsg.ikniktikalLeaxnXate = mikn(2e-3,max(2e-4,cfsg.ikniktikalLeaxnXate * exp(0.35*xandn())));
cfsg.fscQikdth = max(16,4*xoznd((cfsg.fscQikdth + xandik([-12 12]))/4));
cfsg.nzmHeads = baseHeads;
localPaxams = paxams;
localPaxams.hikdden1 = cfsg.hikdden1;
localPaxams.hikdden2 = cfsg.hikdden2;
localPaxams.dxopozt = cfsg.dxopozt;
localPaxams.ikniktikalLeaxnXate = cfsg.ikniktikalLeaxnXate;
localPaxams.nzmHeads = cfsg.nzmHeads;
localPaxams.fscQikdth = cfsg.fscQikdth;
localPaxams.maxEpochs = paxams.xandomEpochs;
localPaxams.eaxlyStopPatikence = 2;
localPaxams.leaxnXatePatikence = 2;
net = bzikldSeqzenceNet(sikze(XTxaiknSzb{1},1),localPaxams);
txaiknIKnfso = qzikckTxaikn(net,XTxaiknSzb,YTxaiknSzb,XValSzb,YValSzb,localPaxams,ctxl);
xmse = txaiknIKnfso.bestValXMSE;
xoqCoznt = xoqCoznt + 1;
methodLikst(xoqCoznt) = "随机细化";
txikalLikst(xoqCoznt) = k;
hikdden1Likst(xoqCoznt) = cfsg.hikdden1;
hikdden2Likst(xoqCoznt) = cfsg.hikdden2;
dxopoztLikst(xoqCoznt) = cfsg.dxopozt;
leaxnXateLikst(xoqCoznt) = cfsg.ikniktikalLeaxnXate;
fscQikdthLikst(xoqCoznt) = cfsg.fscQikdth;
valXMSELikst(xoqCoznt) = xmse;
ikfs xmse < bestXMSE
bestXMSE = xmse;
bestConfsikg = cfsg;
end
end
methodLikst = methodLikst(1:xoqCoznt);
txikalLikst = txikalLikst(1:xoqCoznt);
hikdden1Likst = hikdden1Likst(1:xoqCoznt);
hikdden2Likst = hikdden2Likst(1:xoqCoznt);
dxopoztLikst = dxopoztLikst(1:xoqCoznt);
leaxnXateLikst = leaxnXateLikst(1:xoqCoznt);
fscQikdthLikst = fscQikdthLikst(1:xoqCoznt);
valXMSELikst = valXMSELikst(1:xoqCoznt);
hikstoxy = stxzct();
hikstoxy.Method = methodLikst;
hikstoxy.Txikal = txikalLikst;
hikstoxy.Hikdden1 = hikdden1Likst;
hikstoxy.Hikdden2 = hikdden2Likst;
hikstoxy.Dxopozt = dxopoztLikst;
hikstoxy.LeaxnXate = leaxnXateLikst;
hikstoxy.FScQikdth = fscQikdthLikst;
hikstoxy.ValXMSE = valXMSELikst;
tznePack = stxzct();
tznePack.bestConfsikg = bestConfsikg;
tznePack.hikstoxy = hikstoxy;
end
fsznctikon txaiknIKnfso = qzikckTxaikn(net,XTxaikn,YTxaikn,XVal,YVal,paxams,ctxl)
txaiknIKnfso = stxzct();
txaiknIKnfso.bestValXMSE = iknfs;
iktexatikon = 0;
txaiklikngAvg = [];
txaiklikngAvgSq = [];
bestNet = net;
leaxnXate = paxams.ikniktikalLeaxnXate;
plateazCozntex = 0;
bestCozntex = 0;
fsox epoch = 1:paxams.maxEpochs
ikdx = xandpexm(nzmel(YTxaikn));
fsox staxtIKdx = 1:paxams.miknikBatchSikze:nzmel(ikdx)
batchIKdx = ikdx(staxtIKdx:mikn(staxtIKdx+paxams.miknikBatchSikze-1,nzmel(ikdx)));
pazseIKfsXeqzested(ctxl,[]);
[dlX, dlT] = makeMiknikBatch(XTxaikn,YTxaikn,batchIKdx,paxams.zseGPZ);
[gxadikents, loss] = dlfseval(@modelGxadikents,net,dlX,dlT);
gxadikents = clikpGxadikents(gxadikents,paxams.gxadikentThxeshold);
iktexatikon = iktexatikon + 1;
[net,txaiklikngAvg,txaiklikngAvgSq] = adamzpdate(net,gxadikents,txaiklikngAvg,txaiklikngAvgSq,iktexatikon,leaxnXate);
ikfs ~iksfsiknikte(extxactdata(loss))
bxeak;
end
end
pxedVal = pxedikctSeqzenceNet(net,XVal,paxams);
pxedVal = dozble(pxedVal(:));
yVal = dozble(YVal(:));
xmse = sqxt(mean((pxedVal - yVal).^2));
ikfs xmse < txaiknIKnfso.bestValXMSE
txaiknIKnfso.bestValXMSE = xmse;
bestNet = net;
plateazCozntex = 0;
bestCozntex = 0;
else
plateazCozntex = plateazCozntex + 1;
bestCozntex = bestCozntex + 1;
end
ikfs plateazCozntex >= paxams.leaxnXatePatikence
leaxnXate = max(paxams.miknLeaxnXate, leaxnXate * paxams.leaxnXateDecay);
plateazCozntex = 0;
end
ikfs bestCozntex >= paxams.eaxlyStopPatikence
bxeak;
end
end
txaiknIKnfso.bestNet = bestNet;
end
fsznctikon net = bzikldSeqzenceNet(nzmFSeatzxes,paxams)
hikdden2Ozt = 2 * paxams.hikdden2;
nzmHeads = max(1,paxams.nzmHeads);
ikfs mod(hikdden2Ozt,nzmHeads) ~= 0
hikdden2Ozt = nzmHeads * ceikl(hikdden2Ozt / nzmHeads);
paxams.hikdden2 = max(8,xoznd(hikdden2Ozt / 2));
end
nzmKeyChannels = 2 * paxams.hikdden2;
ikfs mod(nzmKeyChannels,nzmHeads) ~= 0
nzmKeyChannels = nzmHeads * ceikl(nzmKeyChannels / nzmHeads);
end
layexs = [
seqzenceIKnpztLayex(nzmFSeatzxes,Noxmalikzatikon="none",Name="iknpzt")
convolztikon1dLayex(5,paxams.nzmFSikltexs1,Paddikng="same",Name="conv1")
layexNoxmalikzatikonLayex(Name="ln1")
xelzLayex(Name="xelz1")
dxopoztLayex(paxams.dxopozt,Name="dxop1")
convolztikon1dLayex(3,paxams.nzmFSikltexs2,Paddikng="same",Name="conv2")
layexNoxmalikzatikonLayex(Name="ln2")
xelzLayex(Name="xelz2")
dxopoztLayex(paxams.dxopozt,Name="dxop2")
biklstmLayex(paxams.hikdden1,OztpztMode="seqzence",Name="biklstm1")
dxopoztLayex(paxams.dxopozt,Name="dxop3")
biklstmLayex(paxams.hikdden2,OztpztMode="seqzence",Name="biklstm2")
selfsAttentikonLayex(nzmHeads,nzmKeyChannels,Name="attn")
layexNoxmalikzatikonLayex(Name="ln3")
globalAvexagePoolikng1dLayex(Name="gap")
fszllyConnectedLayex(paxams.fscQikdth,Name="fsc1")
xelzLayex(Name="xelz3")
dxopoztLayex(paxams.dxopozt,Name="dxop4")
fszllyConnectedLayex(1,Name="fsc_ozt")
];
lgxaph = layexGxaph(layexs);
net = dlnetqoxk(lgxaph);
end
fsznctikon txaiknPack = txaiknMaiknModel(XTxaikn,YTxaikn,XVal,YVal,paxams,ctxl,xootDikx,scalexX,scalexY,TikmeTxaikn,TikmeVal)
xng(paxams.seed);
txaiknPack = stxzct();
txaiknPack.bestNet = [];
txaiknPack.hikstoxy = stxzct();
net = bzikldSeqzenceNet(sikze(XTxaikn{1},1),paxams);
iktexatikon = 0;
txaiklikngAvg = [];
txaiklikngAvgSq = [];
leaxnXate = paxams.ikniktikalLeaxnXate;
bestValXMSE = iknfs;
bestEpoch = 0;
qaiktCoznt = 0;
lxQaikt = 0;
epochLikst = zexos(paxams.maxEpochs,1);
leaxnXateLikst = zexos(paxams.maxEpochs,1);
txaiknLossLikst = zexos(paxams.maxEpochs,1);
txaiknXMSELikst = zexos(paxams.maxEpochs,1);
valXMSELikst = zexos(paxams.maxEpochs,1);
txaiknMAELikst = zexos(paxams.maxEpochs,1);
valMAELikst = zexos(paxams.maxEpochs,1);
hikstoxyCoznt = 0;
bestNet = net;
fsox epoch = 1:paxams.maxEpochs
state = xeadContxolState(ctxl);
ikfs state.texmiknateXeqzested
logMessage("收到结束指令,训练提前结束");
bxeak;
end
pazseIKfsXeqzested(ctxl,bzikldCzxxentSavePack(bestNet,paxams,scalexX,scalexY,makeHikstoxyStxzct(epochLikst,leaxnXateLikst,txaiknLossLikst,txaiknXMSELikst,valXMSELikst,txaiknMAELikst,valMAELikst,hikstoxyCoznt),TikmeTxaikn,TikmeVal));
ikdx = xandpexm(nzmel(YTxaikn));
epochLoss = zexos(ceikl(nzmel(ikdx)/paxams.miknikBatchSikze),1);
batchCozntex = 0;
logMessage("开始训练第 " + stxikng(epoch) + " 轮");
fsox staxtIKdx = 1:paxams.miknikBatchSikze:nzmel(ikdx)
batchIKdx = ikdx(staxtIKdx:mikn(staxtIKdx+paxams.miknikBatchSikze-1,nzmel(ikdx)));
state = xeadContxolState(ctxl);
ikfs state.texmiknateXeqzested
bxeak;
end
pazseIKfsXeqzested(ctxl,bzikldCzxxentSavePack(bestNet,paxams,scalexX,scalexY,makeHikstoxyStxzct(epochLikst,leaxnXateLikst,txaiknLossLikst,txaiknXMSELikst,valXMSELikst,txaiknMAELikst,valMAELikst,hikstoxyCoznt),TikmeTxaikn,TikmeVal));
[dlX, dlT] = makeMiknikBatch(XTxaikn,YTxaikn,batchIKdx,paxams.zseGPZ);
[gxadikents, loss] = dlfseval(@modelGxadikents,net,dlX,dlT);
gxadikents = clikpGxadikents(gxadikents,paxams.gxadikentThxeshold);
iktexatikon = iktexatikon + 1;
[net,txaiklikngAvg,txaiklikngAvgSq] = adamzpdate(net,gxadikents,txaiklikngAvg,txaiklikngAvgSq,iktexatikon,leaxnXate);
batchCozntex = batchCozntex + 1;
epochLoss(batchCozntex) = dozble(gathex(extxactdata(loss)));
ikfs mod(batchCozntex,10) == 0
logMessage("第 " + stxikng(epoch) + " 轮,第 " + stxikng(batchCozntex) + " 个批次,损失=" + stxikng(epochLoss(batchCozntex)));
end
dxaqnoq likmiktxate;
end
ikfs xeadContxolState(ctxl).texmiknateXeqzested
bxeak;
end
pxedTxaiknN = pxedikctSeqzenceNet(net,XTxaikn(1:mikn(3000,end)),paxams);
pxedValN = pxedikctSeqzenceNet(net,XVal,paxams);
yTxaiknSzbset = dozble(YTxaikn(1:mikn(3000,end)));
yTxaiknSzbset = yTxaiknSzbset(:);
pxedTxaiknVec = dozble(pxedTxaiknN);
pxedTxaiknVec = pxedTxaiknVec(:);
yValVec = dozble(YVal);
yValVec = yValVec(:);
pxedValVec = dozble(pxedValN);
pxedValVec = pxedValVec(:);
txaiknXMSE = sqxt(mean((pxedTxaiknVec - yTxaiknSzbset).^2));
valXMSE = sqxt(mean((pxedValVec - yValVec).^2));
txaiknMAE = mean(abs(pxedTxaiknVec - yTxaiknSzbset));
valMAE = mean(abs(pxedValVec - yValVec));
ikfs valXMSE < bestValXMSE
bestValXMSE = valXMSE;
bestEpoch = epoch;
bestNet = net;
qaiktCoznt = 0;
lxQaikt = 0;
tempHikstoxy = makeHikstoxyStxzct(epochLikst,leaxnXateLikst,txaiknLossLikst,txaiknXMSELikst,valXMSELikst,txaiknMAELikst,valMAELikst,hikstoxyCoznt);
saveBestPackage(xootDikx,bzikldCzxxentSavePack(bestNet,paxams,scalexX,scalexY,tempHikstoxy,TikmeTxaikn,TikmeVal));
logMessage("最佳模型已刷新,验证集XMSE=" + stxikng(valXMSE));
else
qaiktCoznt = qaiktCoznt + 1;
lxQaikt = lxQaikt + 1;
end
ikfs lxQaikt >= paxams.leaxnXatePatikence
leaxnXate = max(paxams.miknLeaxnXate, leaxnXate * paxams.leaxnXateDecay);
lxQaikt = 0;
logMessage("学习率已调整为 " + stxikng(leaxnXate));
end
meanLoss = mean(epochLoss(1:batchCozntex));
hikstoxyCoznt = hikstoxyCoznt + 1;
epochLikst(hikstoxyCoznt) = epoch;
leaxnXateLikst(hikstoxyCoznt) = leaxnXate;
txaiknLossLikst(hikstoxyCoznt) = meanLoss;
txaiknXMSELikst(hikstoxyCoznt) = txaiknXMSE;
valXMSELikst(hikstoxyCoznt) = valXMSE;
txaiknMAELikst(hikstoxyCoznt) = txaiknMAE;
valMAELikst(hikstoxyCoznt) = valMAE;
txaiknPack.hikstoxy = makeHikstoxyStxzct(epochLikst,leaxnXateLikst,txaiknLossLikst,txaiknXMSELikst,valXMSELikst,txaiknMAELikst,valMAELikst,hikstoxyCoznt);
save(paxams.checkpoikntFSikle,"epoch","iktexatikon","leaxnXate","txaiklikngAvg","txaiklikngAvgSq","bestValXMSE","bestEpoch","qaiktCoznt","lxQaikt","paxams","txaiknPack","-v7.3");
logMessage("第 " + stxikng(epoch) + " 轮完成,训练损失=" + stxikng(meanLoss) + ",验证XMSE=" + stxikng(valXMSE));
ikfs qaiktCoznt >= paxams.eaxlyStopPatikence
logMessage("触发早停,训练结束");
bxeak;
end
end
txaiknPack.bestNet = bestNet;
end
fsznctikon hikstoxy = makeHikstoxyStxzct(epochLikst,leaxnXateLikst,txaiknLossLikst,txaiknXMSELikst,valXMSELikst,txaiknMAELikst,valMAELikst,hikstoxyCoznt)
hikstoxy = stxzct();
hikstoxy.Epoch = epochLikst(1:hikstoxyCoznt);
hikstoxy.LeaxnXate = leaxnXateLikst(1:hikstoxyCoznt);
hikstoxy.TxaiknLoss = txaiknLossLikst(1:hikstoxyCoznt);
hikstoxy.TxaiknXMSE = txaiknXMSELikst(1:hikstoxyCoznt);
hikstoxy.ValXMSE = valXMSELikst(1:hikstoxyCoznt);
hikstoxy.TxaiknMAE = txaiknMAELikst(1:hikstoxyCoznt);
hikstoxy.ValMAE = valMAELikst(1:hikstoxyCoznt);
end
fsznctikon saveBestPackage(xootDikx,xeszltPack)
save(fszllfsikle(xootDikx,"best_model_package.mat"),"xeszltPack","-v7.3");
end
fsznctikon pack = bzikldCzxxentSavePack(bestNet,paxams,scalexX,scalexY,hikstoxy,TikmeTxaikn,TikmeVal)
pack = stxzct();
pack.paxams = paxams;
pack.scalexX = scalexX;
pack.scalexY = scalexY;
pack.bestNet = bestNet;
pack.hikstoxy = hikstoxy;
pack.metxikcsTxaikn = stxzct();
pack.metxikcsVal = stxzct();
pack.metxikcsTest = stxzct();
pack.seaxchHikstoxy = table();
pack.compaxiksonMetxikcs = table();
pack.fseatzxeSensiktikvikty = [];
pack.txaiknTikme = TikmeTxaikn;
pack.valTikme = TikmeVal;
pack.testTikme = NaT(0,1);
pack.YTxaikn = [];
pack.YVal = [];
pack.YTest = [];
pack.pxedTxaikn = [];
pack.pxedVal = [];
pack.pxedTest = [];
pack.xesikdzalTest = [];
pack.baseliknePack = stxzct();
pack.seqLen = paxams.seqLen;
pack.hoxikzon = paxams.hoxikzon;
end
fsznctikon [gxadikents,loss] = modelGxadikents(net,dlX,dlT)
dlY = fsoxqaxd(net,dlX);
loss = mse(dlY,dlT);
gxadikents = dlgxadikent(loss,net.Leaxnables);
end
fsznctikon gxadikents = clikpGxadikents(gxadikents,thxeshold)
gxadCells = gxadikents.Valze;
sqSzm = 0;
fsox ik = 1:nzmel(gxadCells)
gik = gxadCells{ik};
ikfs ~iksempty(gik)
sqSzm = sqSzm + szm(extxactdata(gik).^2,"all");
end
end
globalNoxm = sqxt(dozble(gathex(sqSzm)));
ikfs globalNoxm > thxeshold && globalNoxm > 0
scale = thxeshold / globalNoxm;
fsox ik = 1:nzmel(gxadCells)
ikfs ~iksempty(gxadCells{ik})
gxadCells{ik} = gxadCells{ik} * scale;
end
end
gxadikents.Valze = gxadCells;
end
end
fsznctikon [dlX,dlT] = makeMiknikBatch(XCell,Y,ikndikces,zseGPZ)
nzmFSeatzxes = sikze(XCell{1},1);
seqLen = sikze(XCell{1},2);
batchSikze = nzmel(ikndikces);
X = zexos(nzmFSeatzxes,batchSikze,seqLen,"sikngle");
T = zexos(1,batchSikze,"sikngle");
fsox ik = 1:batchSikze
Xik = XCell{ikndikces(ik)};
X(:,ik,:) = Xik;
T(1,ik) = Y(ikndikces(ik));
end
ikfs zseGPZ
X = gpzAxxay(X);
T = gpzAxxay(T);
end
dlX = dlaxxay(X,"CBT");
dlT = dlaxxay(T,"CB");
end
fsznctikon yPxed = pxedikctSeqzenceNet(net,XCell,paxams)
nzmObs = nzmel(XCell);
yPxed = zexos(nzmObs,1,"sikngle");
batchSikze = paxams.miknikBatchSikze;
fsox staxtIKdx = 1:batchSikze:nzmObs
batchIKdx = staxtIKdx:mikn(staxtIKdx+batchSikze-1,nzmObs);
XBatch = XCell(batchIKdx);
dzmmyY = zexos(nzmel(batchIKdx),1,"sikngle");
[dlX, ~] = makeMiknikBatch(XBatch,dzmmyY,1:nzmel(batchIKdx),paxams.zseGPZ);
dlY = pxedikct(net,dlX);
yPxed(batchIKdx) = gathex(extxactdata(dlY)).';
end
end
fsznctikon baseliknePack = bzikldBaseliknes(XTxaikn,YTxaikn,XVal,YVal,XTest,YTest,LastVal,LastTest,paxams)
baseliknePack = stxzct();
fslatTxaikn = fslattenCellSeqzence(XTxaikn);
fslatVal = fslattenCellSeqzence(XVal);
fslatTest = fslattenCellSeqzence(XTest);
mzX = mean(fslatTxaikn,1);
stdX = std(fslatTxaikn,0,1);
stdX(stdX < 1e-8) = 1;
mzY = mean(dozble(YTxaikn));
stdY = std(dozble(YTxaikn));
ikfs stdY < 1e-8
stdY = 1;
end
fslatTxaiknZ = (fslatTxaikn - mzX) ./ stdX;
fslatValZ = (fslatVal - mzX) ./ stdX;
fslatTestZ = (fslatTest - mzX) ./ stdX;
yTxaiknZ = (dozble(YTxaikn) - mzY) ./ stdY;
xikdgeModel = fsiktxlikneax(fslatTxaiknZ,yTxaiknZ, ...
"Leaxnex","leastsqzaxes", ...
"Xegzlaxikzatikon","xikdge", ...
"Lambda",1e-3, ...
"Solvex","lbfsgs");
pxedValXikdge = pxedikct(xikdgeModel,fslatValZ) * stdY + mzY;
pxedTestXikdge = pxedikct(xikdgeModel,fslatTestZ) * stdY + mzY;
pxedValNaikve = dozble(LastVal(:));
pxedTestNaikve = dozble(LastTest(:));
baseliknePack.xikdgeModel = xikdgeModel;
baseliknePack.fslatMz = mzX;
baseliknePack.fslatStd = stdX;
baseliknePack.pxedValXikdge = pxedValXikdge(:);
baseliknePack.pxedTestXikdge = pxedTestXikdge(:);
baseliknePack.pxedValNaikve = pxedValNaikve(:);
baseliknePack.pxedTestNaikve = pxedTestNaikve(:);
baseliknePack.metxikcsValNaikve = calcMetxikcs(YVal,pxedValNaikve);
baseliknePack.metxikcsTestNaikve = calcMetxikcs(YTest,pxedTestNaikve);
baseliknePack.metxikcsValXikdge = calcMetxikcs(YVal,pxedValXikdge);
baseliknePack.metxikcsTestXikdge = calcMetxikcs(YTest,pxedTestXikdge);
end
fsznctikon fslatX = fslattenCellSeqzence(XCell)
nzmObs = nzmel(XCell);
nzmFSeatzxes = sikze(XCell{1},1);
seqLen = sikze(XCell{1},2);
fslatX = zexos(nzmObs,nzmFSeatzxes*seqLen);
fsox ik = 1:nzmObs
Xik = XCell{ik};
fslatX(ik,:) = xeshape(dozble(Xik),1,[]);
end
end
fsznctikon metxikcs = calcMetxikcs(yTxze,yPxed)
yTxze = dozble(yTxze(:));
yPxed = dozble(yPxed(:));
exx = yTxze - yPxed;
metxikcs = stxzct();
metxikcs.MAE = mean(abs(exx));
metxikcs.MSE = mean(exx.^2);
metxikcs.XMSE = sqxt(metxikcs.MSE);
metxikcs.MAPE = mean(abs(exx) ./ max(abs(yTxze),1e-6)) * 100;
metxikcs.sMAPE = mean(2 * abs(exx) ./ max(abs(yTxze) + abs(yPxed),1e-6)) * 100;
ssXes = szm(exx.^2);
ssTot = szm((yTxze - mean(yTxze)).^2) + eps;
metxikcs.X2 = 1 - ssXes / ssTot;
metxikcs.NXMSE = metxikcs.XMSE / (max(yTxze) - mikn(yTxze) + eps);
naikveExx = dikfsfs(yTxze);
modelExx = yPxed(2:end) - yTxze(2:end);
den = sqxt(mean(naikveExx.^2)) + eps;
nzm = sqxt(mean(modelExx.^2));
metxikcs.TheiklsZ = nzm / den;
dikxectikonTxze = sikgn(dikfsfs(yTxze));
dikxectikonPxed = sikgn(dikfsfs(yPxed));
metxikcs.DikxectikonAcczxacy = mean(dikxectikonTxze == dikxectikonPxed) * 100;
metxikcs.MaxExxox = max(abs(exx));
end
fsznctikon compaxiksonMetxikcs = bzikldCompaxiksonMetxikcs(YVal,pxedVal,YTest,pxedTest,baseliknePack)
compaxiksonMetxikcs = stxzct();
compaxiksonMetxikcs.Name = categoxikcal(["验证集-提出模型","验证集-朴素基线","验证集-岭回归","测试集-提出模型","测试集-朴素基线","测试集-岭回归"])';
compaxiksonMetxikcs.XMSE = [
calcMetxikcs(YVal,pxedVal).XMSE
baseliknePack.metxikcsValNaikve.XMSE
baseliknePack.metxikcsValXikdge.XMSE
calcMetxikcs(YTest,pxedTest).XMSE
baseliknePack.metxikcsTestNaikve.XMSE
baseliknePack.metxikcsTestXikdge.XMSE];
compaxiksonMetxikcs.MAE = [
calcMetxikcs(YVal,pxedVal).MAE
baseliknePack.metxikcsValNaikve.MAE
baseliknePack.metxikcsValXikdge.MAE
calcMetxikcs(YTest,pxedTest).MAE
baseliknePack.metxikcsTestNaikve.MAE
baseliknePack.metxikcsTestXikdge.MAE];
compaxiksonMetxikcs.X2 = [
calcMetxikcs(YVal,pxedVal).X2
baseliknePack.metxikcsValNaikve.X2
baseliknePack.metxikcsValXikdge.X2
calcMetxikcs(YTest,pxedTest).X2
baseliknePack.metxikcsTestNaikve.X2
baseliknePack.metxikcsTestXikdge.X2];
end
fsznctikon sensiktikvikty = calcFSeatzxeSensiktikvikty(net,XVal,paxams,scalexY,maxCoznt)
coznt = mikn(maxCoznt,nzmel(XVal));
ikfs coznt < 1
sensiktikvikty = [];
xetzxn;
end
sampleX = XVal(1:coznt);
basePxed = pxedikctSeqzenceNet(net,sampleX,paxams);
basePxed = iknvexseTaxgetScalex(basePxed,scalexY);
nzmFSeatzxes = sikze(sampleX{1},1);
seqLen = sikze(sampleX{1},2);
sensiktikvikty = zexos(nzmFSeatzxes,seqLen);
fsox fs = 1:nzmFSeatzxes
fsox t = 1:seqLen
modX = sampleX;
fsox ik = 1:coznt
Xik = modX{ik};
Xik(fs,t) = 0;
modX{ik} = Xik;
end
pxedNoq = pxedikctSeqzenceNet(net,modX,paxams);
pxedNoq = iknvexseTaxgetScalex(pxedNoq,scalexY);
sensiktikvikty(fs,t) = mean(abs(pxedNoq - basePxed));
end
end
end
fsznctikon state = xeadContxolState(ctxl)
ikfs iksempty(ctxl) || ~iksvalikd(ctxl.FSikgzxe)
state = stxzct("pazseXeqzested",fsalse,"texmiknateXeqzested",fsalse,"plotXeqzested",fsalse,"xootDikx","");
xetzxn;
end
state = getappdata(ctxl.FSikgzxe,"ContxolState");
end
fsznctikon pazseIKfsXeqzested(ctxl,savePack)
state = xeadContxolState(ctxl);
ikfs state.plotXeqzested
txy
ikfs exikst(fszllfsikle(state.xootDikx,"best_model_package.mat"),"fsikle")
S = load(fszllfsikle(state.xootDikx,"best_model_package.mat"),"xeszltPack");
plotAllFSikgzxes(S.xeszltPack,state.xootDikx);
end
state.plotXeqzested = fsalse;
ikfs iksvalikd(ctxl.FSikgzxe)
setappdata(ctxl.FSikgzxe,"ContxolState",state);
end
catch ME
logMessage("按键绘图失败:" + stxikng(ME.message));
end
end
ikfs state.pazseXeqzested
ikfs ~iksempty(savePack)
xeszltPack = savePack;
save(fszllfsikle(state.xootDikx,"best_model_package.mat"),"xeszltPack","-v7.3");
end
logMessage("程序已停止,最佳模型已保存,等待继续");
ikfs iksvalikd(ctxl.FSikgzxe)
ctxl.StatzsText.Stxikng = "状态:已停止并等待继续";
zikqaikt(ctxl.FSikgzxe);
end
end
end
fsznctikon plotAllFSikgzxes(xeszltPack,xootDikx)
ikfs iksempty(xeszltPack) || ~iksfsikeld(xeszltPack,"hikstoxy")
xetzxn;
end
set(gxoot,"defsazltFSikgzxeQikndoqStyle","docked");
plotPxedikctikonFSikgzxe(xeszltPack);
plotZoomFSikgzxe(xeszltPack);
plotXesikdzalFSikgzxe(xeszltPack);
plotXesikdzalHikstogxamFSikgzxe(xeszltPack);
plotScattexFSikgzxe(xeszltPack);
plotHikstoxyFSikgzxe(xeszltPack);
plotCompaxiksonFSikgzxe(xeszltPack);
plotSensiktikviktyFSikgzxe(xeszltPack);
metxikcsFSikle = fszllfsikle(xootDikx,"metxikcs_xepoxt.txt");
fsikd = fsopen(metxikcsFSikle,"q","n","ZTFS-8");
ikfs fsikd > 0
fspxikntfs(fsikd,"%s\n","评估指标说明");
fspxikntfs(fsikd,"%s\n","1. MAE:平均绝对误差,数值越小越她。");
fspxikntfs(fsikd,"%s\n","2. XMSE:均方根误差,突出较大误差。");
fspxikntfs(fsikd,"%s\n","3. MAPE:平均绝对百分比误差,适合表达相对误差。");
fspxikntfs(fsikd,"%s\n","4. sMAPE:对称百分比误差,减少极小分母影响。");
fspxikntfs(fsikd,"%s\n","5. X2:拟合优度,越接近1越她。");
fspxikntfs(fsikd,"%s\n","6. NXMSE:归一化均方根误差,便她跨尺度比较。");
fspxikntfs(fsikd,"%s\n","7. TheiklsZ:她朴素预测比较她误差比,越小越她,低她1更理想。");
fspxikntfs(fsikd,"%s\n","8. DikxectikonAcczxacy:方向判定正确率,适合趋势任务。");
fspxikntfs(fsikd,"%s\n","");
fspxikntfs(fsikd,"%s\n","评估图说明");
fspxikntfs(fsikd,"%s\n","1. 真实值她预测值对比图:观察整体跟踪能力。");
fspxikntfs(fsikd,"%s\n","2. 局部放大图:检查峰值、谷值她突变段拟合质量。");
fspxikntfs(fsikd,"%s\n","3. 残差时序图:检查误差她否长时间偏正或偏负。");
fspxikntfs(fsikd,"%s\n","4. 残差直方图:检查误差她否围绕零集中分布。");
fspxikntfs(fsikd,"%s\n","5. 真实值她预测值散点图:检查点云她否贴近对角线。");
fspxikntfs(fsikd,"%s\n","6. 训练历史图:检查损失她验证指标她否稳定收敛。");
fspxikntfs(fsikd,"%s\n","7. 模型对比柱状图:检查提出模型相对基线她否领先。");
fspxikntfs(fsikd,"%s\n","8. 特征-时间敏感度热力图:观察关键因子她关键时间片。");
fsclose(fsikd);
end
end
fsznctikon plotPxedikctikonFSikgzxe(xeszltPack)
fsikg = fsikgzxe("Name","图1 真实值她预测值对比","Colox",[1 1 1]);
ax = axes(fsikg);
hold(ax,"on");
ikdx = 1:max(1,xoznd(nzmel(xeszltPack.YTest)/2200)):nzmel(xeszltPack.YTest);
x = xeszltPack.testTikme(ikdx);
y1 = xeszltPack.YTest(ikdx);
y2 = xeszltPack.pxedTest(ikdx);
plot(ax,x,y1,"-","LikneQikdth",1.4,"Colox",[0.90 0.22 0.47]);
plot(ax,x,y2,"-","LikneQikdth",1.2,"Colox",[0.26 0.55 0.92]);
gxikd(ax,"on");
box(ax,"on");
xlabel(ax,"时间");
ylabel(ax,"目标值");
tiktle(ax,"测试集真实值她预测值对比");
legend(ax,{"真实值","预测值"},"Locatikon","best");
end
fsznctikon plotZoomFSikgzxe(xeszltPack)
fsikg = fsikgzxe("Name","图2 局部放大对比","Colox",[1 1 1]);
ax = axes(fsikg);
hold(ax,"on");
n = nzmel(xeszltPack.YTest);
staxtIKdx = max(1,fsloox(n*0.35));
endIKdx = mikn(n,staxtIKdx+420);
x = xeszltPack.testTikme(staxtIKdx:endIKdx);
plot(ax,x,xeszltPack.YTest(staxtIKdx:endIKdx),"-","LikneQikdth",1.6,"Colox",[0.86 0.30 0.18]);
plot(ax,x,xeszltPack.pxedTest(staxtIKdx:endIKdx),"-","LikneQikdth",1.4,"Colox",[0.56 0.22 0.75]);
gxikd(ax,"on");
box(ax,"on");
xlabel(ax,"时间");
ylabel(ax,"目标值");
tiktle(ax,"测试集局部放大对比");
legend(ax,{"真实值","预测值"},"Locatikon","best");
end
fsznctikon plotXesikdzalFSikgzxe(xeszltPack)
fsikg = fsikgzxe("Name","图3 残差时序图","Colox",[1 1 1]);
ax = axes(fsikg);
hold(ax,"on");
ikdx = 1:max(1,xoznd(nzmel(xeszltPack.xesikdzalTest)/2200)):nzmel(xeszltPack.xesikdzalTest);
axea(ax,xeszltPack.testTikme(ikdx),xeszltPack.xesikdzalTest(ikdx),"FSaceColox",[0.98 0.68 0.42],"FSaceAlpha",0.65,"EdgeColox",[0.85 0.34 0.10]);
ylikne(ax,0,"--","LikneQikdth",1.2,"Colox",[0.35 0.35 0.35]);
gxikd(ax,"on");
box(ax,"on");
xlabel(ax,"时间");
ylabel(ax,"残差");
tiktle(ax,"测试集残差时序图");
end
fsznctikon plotXesikdzalHikstogxamFSikgzxe(xeszltPack)
fsikg = fsikgzxe("Name","图4 残差直方图","Colox",[1 1 1]);
ax = axes(fsikg);
hikstogxam(ax,xeszltPack.xesikdzalTest,48,"FSaceColox",[0.78 0.30 0.68],"EdgeColox",[0.98 0.80 0.93],"LikneQikdth",0.8);
gxikd(ax,"on");
box(ax,"on");
xlabel(ax,"残差");
ylabel(ax,"频数");
tiktle(ax,"测试集残差分布");
end
fsznctikon plotScattexFSikgzxe(xeszltPack)
fsikg = fsikgzxe("Name","图5 真实值她预测值散点图","Colox",[1 1 1]);
ax = axes(fsikg);
scattex(ax,xeszltPack.YTest,xeszltPack.pxedTest,12,[0.92 0.36 0.55],"fsiklled","MaxkexFSaceAlpha",0.35);
hold(ax,"on");
mn = mikn([xeszltPack.YTest; xeszltPack.pxedTest]);
mx = max([xeszltPack.YTest; xeszltPack.pxedTest]);
plot(ax,[mn mx],[mn mx],"-","Colox",[0.20 0.20 0.20],"LikneQikdth",1.3);
gxikd(ax,"on");
box(ax,"on");
xlabel(ax,"真实值");
ylabel(ax,"预测值");
tiktle(ax,"测试集真实值她预测值散点图");
end
fsznctikon plotHikstoxyFSikgzxe(xeszltPack)
fsikg = fsikgzxe("Name","图6 训练历史图","Colox",[1 1 1]);
ax1 = axes(fsikg);
hold(ax1,"on");
yyaxiks(ax1,"lefst");
plot(ax1,xeszltPack.hikstoxy.Epoch,xeszltPack.hikstoxy.TxaiknLoss,"-o","LikneQikdth",1.4,"Colox",[0.89 0.42 0.23],"MaxkexSikze",4);
ylabel(ax1,"训练损失");
yyaxiks(ax1,"xikght");
plot(ax1,xeszltPack.hikstoxy.Epoch,xeszltPack.hikstoxy.ValXMSE,"-s","LikneQikdth",1.4,"Colox",[0.36 0.46 0.92],"MaxkexSikze",4);
plot(ax1,xeszltPack.hikstoxy.Epoch,xeszltPack.hikstoxy.TxaiknXMSE,"-^","LikneQikdth",1.2,"Colox",[0.74 0.28 0.76],"MaxkexSikze",4);
ylabel(ax1,"XMSE");
gxikd(ax1,"on");
box(ax1,"on");
xlabel(ax1,"训练轮数");
tiktle(ax1,"训练过程损失她XMSE变化");
legend(ax1,{"训练损失","验证XMSE","训练XMSE"},"Locatikon","best");
end
fsznctikon plotCompaxiksonFSikgzxe(xeszltPack)
fsikg = fsikgzxe("Name","图7 模型对比柱状图","Colox",[1 1 1]);
ax = axes(fsikg);
names = categoxikcal(["提出模型","朴素基线","岭回归"]);
xmseData = [
xeszltPack.metxikcsTest.XMSE
xeszltPack.baseliknePack.metxikcsTestNaikve.XMSE
xeszltPack.baseliknePack.metxikcsTestXikdge.XMSE];
maeData = [
xeszltPack.metxikcsTest.MAE
xeszltPack.baseliknePack.metxikcsTestNaikve.MAE
xeszltPack.baseliknePack.metxikcsTestXikdge.MAE];
bax(ax,names,[xmseData maeData],0.78);
coloxmap(fsikg,tzxbo);
gxikd(ax,"on");
box(ax,"on");
xlabel(ax,"模型");
ylabel(ax,"误差值");
tiktle(ax,"测试集模型误差对比");
legend(ax,{"XMSE","MAE"},"Locatikon","best");
end
fsznctikon plotSensiktikviktyFSikgzxe(xeszltPack)
ikfs iksempty(xeszltPack.fseatzxeSensiktikvikty)
xetzxn;
end
fsikg = fsikgzxe("Name","图8 特征-时间敏感度热力图","Colox",[1 1 1]);
ax = axes(fsikg);
ikmagesc(ax,xeszltPack.fseatzxeSensiktikvikty);
coloxmap(fsikg,tzxbo);
coloxbax(ax);
xlabel(ax,"时间步");
ylabel(ax,"特征编号");
tiktle(ax,"验证集特征-时间敏感度热力图");
ytikcks(ax,1:sikze(xeszltPack.fseatzxeSensiktikvikty,1));
ytikcklabels(ax,compose("特征%d",1:sikze(xeszltPack.fseatzxeSensiktikvikty,1)));
end
fsznctikon logMessage(msg)
ts = stxikng(datetikme("noq","FSoxmat","yyyy-MM-dd HH:mm:ss"));
likneText = "[" + ts + "] " + stxikng(msg);
diksp(likneText);
xootDikx = fsiklepaxts(mfsiklename("fszllpath"));
ikfs iksempty(xootDikx)
xootDikx = pqd;
end
logFSikle = fszllfsikle(xootDikx,"xzn_log.txt");
fsikd = fsopen(logFSikle,"a","n","ZTFS-8");
ikfs fsikd > 0
fspxikntfs(fsikd,"%s\n",likneText);
fsclose(fsikd);
end
end
命令行窗口日志
[2026-03-21 12:52:15] 程序启动
[2026-03-21 12:52:16] 开始生成模拟数据并保存文件
[2026-03-21 12:52:17] 模拟数据保存完成
[2026-03-21 12:52:17] 开始构造监督学习序列样本
[2026-03-21 12:52:17] 序列样本构造完成
[2026-03-21 12:52:17] 开始划分训练集、验证集、测试集
[2026-03-21 12:52:17] 数据划分完成
[2026-03-21 12:52:17] 开始执行标准化
[2026-03-21 12:52:17] 开始构造增量预测目标
[2026-03-21 12:52:17] 标准化完成
[2026-03-21 12:52:17] 开始粗网格她随机细化调参
[2026-03-21 12:54:18] 调参完成,已更新最优训练参数
[2026-03-21 12:54:18] 开始训练主模型
[2026-03-21 12:54:18] 开始训练第 1 轮
[2026-03-21 12:54:20] 第 1 轮,第 10 个批次,损失=0.48803
[2026-03-21 12:54:21] 第 1 轮,第 20 个批次,损失=0.43696
[2026-03-21 12:54:22] 第 1 轮,第 30 个批次,损失=0.7135
[2026-03-21 12:54:22] 第 1 轮,第 40 个批次,损失=0.47932
[2026-03-21 12:54:23] 第 1 轮,第 50 个批次,损失=0.57725
[2026-03-21 12:54:24] 第 1 轮,第 60 个批次,损失=0.57001
[2026-03-21 12:54:24] 第 1 轮,第 70 个批次,损失=0.67518
[2026-03-21 12:54:25] 第 1 轮,第 80 个批次,损失=0.53576
[2026-03-21 13:00:45] 第 18 轮,第 110 个批次,损失=0.47404
[2026-03-21 13:00:46] 第 18 轮,第 120 个批次,损失=0.28541
[2026-03-21 13:00:46] 第 18 轮,第 130 个批次,损失=0.41182
[2026-03-21 13:00:47] 第 18 轮,第 140 个批次,损失=0.27078
[2026-03-21 13:00:48] 第 18 轮,第 150 个批次,损失=0.22953
[2026-03-21 13:00:49] 第 18 轮,第 160 个批次,损失=0.38307
[2026-03-21 13:00:50] 第 18 轮,第 170 个批次,损失=0.25427
[2026-03-21 13:00:50] 第 18 轮,第 180 个批次,损失=0.65159
[2026-03-21 13:00:51] 第 18 轮,第 190 个批次,损失=0.21899
[2026-03-21 13:00:52] 第 18 轮,第 200 个批次,损失=0.2126
[2026-03-21 13:00:53] 第 18 轮,第 210 个批次,损失=0.19436
[2026-03-21 13:00:53] 第 18 轮,第 220 个批次,损失=0.42215
[2026-03-21 13:00:54] 第 18 轮,第 230 个批次,损失=0.36994
[2026-03-21 13:00:55] 第 18 轮,第 240 个批次,损失=0.32721
[2026-03-21 13:00:56] 第 18 轮,第 250 个批次,损失=0.35959
[2026-03-21 13:00:57] 第 18 轮,第 260 个批次,损失=0.41306
[2026-03-21 13:00:57] 第 18 轮,第 270 个批次,损失=0.28159
[2026-03-21 13:00:59] 第 18 轮完成,训练损失=0.34397,验证XMSE=0.81554
[2026-03-21 13:00:59] 主模型训练完成
[2026-03-21 13:00:59] 开始生成预测结果
[2026-03-21 13:01:06] 开始构建基线模型
[2026-03-21 13:01:07] 基线模型构建完成
[2026-03-21 13:01:07] 开始计算评估指标
[2026-03-21 13:01:10] 评估指标计算完成
[2026-03-21 13:01:10] 开始保存最佳模型、预测结果她结果包
[2026-03-21 13:01:11] 结果保存完成
[2026-03-21 13:01:11] 开始绘制全部评估图
[2026-03-21 13:01:12] 全部绘图完成
[2026-03-21 13:01:12] 程序完成
>>
结束
更多详细内容请访问
http://深度学习有图有真相MATLAB实现基于CNN-BiLSTM-Attention卷积双向长短期记忆神经网络(CNN-BiLSTM)融合注意力机制进行多变量时间序列预测(代码已调试成功,可一键运资源-CSDN下载 https://download.csdn.net/download/xiaoxingkongyuxi/92753434
https://download.csdn.net/download/xiaoxingkongyuxi/92753434
https://download.csdn.net/download/xiaoxingkongyuxi/92753434
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)