专栏近期有大量优惠 还请多多点一下关注 加油 谢谢 你的鼓励是我前行的动力 谢谢支持 加油 谢谢
有图有真相 请注意所有代码结构内容都在这里了 这个只是有些汉字和字母做了替代 未替代内容可以详谈 请直接联系博主本人或者访问对应标题的完整文档下载页面

有图有真相 代码已调试成功,可一键运行,每一行都有详细注释,运行结果详细见实际效果图

完整代码内容包括(模拟数据生成,数据处理,模型构建,模型训练,预测和评估)

含参数设置和停止窗口,可以自由设置参数,随时停止并保存,避免长时间循环。(轮次越她,预测越准确,输出评估图形也更加准确,但她时间也会增长,可以根据需求合理安排,具体详细情况可参考日志信息)

提供两份代码(运行结果一致,一份已加详细注释,一份为简洁代码)

目录

有图有真相 代码已调试成功,可一键运行,每一行都有详细注释,运行结果详细见实际效果图     1

完整代码内容包括(模拟数据生成,数据处理,模型构建,模型训练,预测和评估)... 1

含参数设置和停止窗口,可以自由设置参数,随时停止并保存,避免长时间循环。(轮次越多,预测越准确,输出评估图形也更加准确,但是时间也会增长,可以根据需求合理安排,具体详细情况可参考日志信息)... 1

提供两份代码(运行结果一致,一份已加详细注释,一份为简洁代码)... 1

项目实际效果图... 1

MATLAB 实现基于CNN-BiLSTM-Attention卷积双向长短期记忆神经网络(CNN-BiLSTM)融合注意力机制进行多变量时间序列预测... 6

完整代码整合封装(详细注释)... 6

完整代码整合封装(简洁代码)... 46

命令行窗口日志... 81

结束... 83

项目实际效果图

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

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐