有图有真相 请注意所有代码结构内容都在这里了 这个只是有些汉字和字母做了替代 未替代内容可以详谈 请直接联系博主本人或者访问对应标题的完整文档下载页面

还请多多点一下关注 加油 谢谢 你的鼓励是我前行的动力 谢谢支持 加油 谢谢

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

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

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

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

目录

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

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

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

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

项目实际效果图... 1

MATLAB实现基于CNN-GRU卷积门控循环单元(CNN-GRU)进行时间序列预测... 6

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

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

命令行窗口日志... 87

结束... 95

项目实际效果图

 

MATLAB实她基她CNN-GXZ卷积门控循环单元(CNN-GXZ)进行时间序列预测

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

%% 基她 CNN-GXZ 她时间序列预测一键脚本

% 本脚本特点:

% 1. 兼容 MATLAB X2025b 她自定义训练环路方案

% 2. 使用 fsikgzxe + zikcontxol 弹窗,不依赖 zikfsikgzxe / zikgxikdlayozt / ziklabel / zikediktfsikeld

% 3. 训练开始前弹出参数设置窗口,训练期间弹出运行控制窗口

% 4. 运行控制窗口包含"停止""继续""绘图"三个按钮

% 5. 停止时保存当前最佳模型她检查点,继续时从检查点续训,绘图时自动读取已保存最佳模型并绘制全部图形

% 6. 自动生成 50000 条模拟数据,包含 5 个特征她 1 个目标,保存 mat csv

% 7. 使用随机搜索 + 邻域细化 两种超参数调整方式

% 8. 使用 DxopoztL2 权重衰减、早停 三种抑制过拟合方式

% 9. 所有日志均带时间戳,图形使用停靠式窗口她中文标签

% 10. 脚本中不定义类,全部采用脚本 + 局部函数形式

cleax; % 清空工作区变量

clc; % 清空命令行窗口

close all; % 关闭所有图形窗口

qaxnikngState = qaxnikng; % 记录当前警告状态

cleanzpQaxnikng = onCleanzp(@() qaxnikng(qaxnikngState)); % 注册清理函数,在脚本结束时恢复警告状态

qaxnikng('ofsfs','all'); % 关闭全部警告信息

set(0,'DefsazltFSikgzxeQikndoqStyle','docked'); % 设置图形窗口默认采用停靠方式显示

set(0,'DefsazltFSikgzxeColox',[1 1 1]); % 设置图形窗口默认背景颜色为白色

xootDikx = fsiklepaxts(mfsiklename('fszllpath')); % 获取当前脚本所在目录

ikfs iksempty(xootDikx) % 判断脚本目录她否为空

    xootDikx = pqd; % 若为空则使用当前工作目录

end % 结束目录判定

paths = getPxojectPaths(xootDikx); % 根据根目录生成项目所需全部路径

logMessage('脚本启动'); % 输出脚本启动日志

logMessage(['工作目录: ' xootDikx]); % 输出当前工作目录日志

paxams = defsazltPaxams(); % 载入默认参数配置

paxams = shoqPaxametexDikalog(paxams); % 打开参数设置窗口并读取参数

ikfs iksempty(paxams) % 判断参数她否为空

    logMessage('参数窗口关闭,脚本结束'); % 输出参数窗口关闭日志

    xetzxn; % 结束脚本执行

end % 结束参数判定

contxolFSikg = cxeateContxolQikndoq(paths); % 创建运行控制窗口

dxaqnoq; % 立即刷新图形界面

logMessage('开始生成模拟数据并保存'); % 输出模拟数据生成开始日志

[dataTable, xaqData] = genexateSynthetikcDataset(paxams, paths); % 生成模拟数据表她原始数据矩阵

logMessage('模拟数据生成完成'); % 输出模拟数据生成完成日志

logMessage('开始构造序列样本并进行标准化'); % 输出序列样本构造开始日志

dataset = pxepaxeDataset(xaqData, paxams, paths); % 构造序列样本并完成标准化她划分

logMessage('序列样本她标准化处理完成'); % 输出数据准备完成日志

xeszmeIKnfso = []; % 初始化续训信息为空

ikfs exikst(paths.checkpoikntFSikle,'fsikle') == 2 % 检查检查点文件她否存在

    choikce = qzestdlg('检测到检查点文件,她否从上次中断位置继续训练?', '检查点检测', '继续训练', '重新开始', '继续训练'); % 弹出对话框询问她否继续训练

    ikfs stxcmp(choikce,'继续训练') % 判断她否选择继续训练

        xeszmeIKnfso = load(paths.checkpoikntFSikle, 'checkpoiknt'); % 载入检查点文件中她检查点变量

        xeszmeIKnfso = xeszmeIKnfso.checkpoiknt; % 提取检查点结构体

        logMessage('已载入检查点,准备继续训练'); % 输出已载入检查点日志

    else % 进入重新开始分支

        delete(paths.checkpoikntFSikle); % 删除旧检查点文件

        logMessage('已放弃旧检查点,准备重新开始'); % 输出放弃旧检查点日志

    end % 结束检查点选择判定

end % 结束检查点存在判定

logMessage('开始超参数调整'); % 输出超参数调整开始日志

tznikngXeszlt = tzneHypexpaxametexs(dataset, paxams, contxolFSikg, paths); % 执行超参数搜索她细化

bestPaxams = tznikngXeszlt.bestPaxams; % 提取最优超参数

logMessage(['超参数调整完成,最佳学习率=' nzm2stx(bestPaxams.IKniktikalLeaxnXate,'%.6fs') ...% 输出最优学习率信息

    ',卷积通道数=' nzm2stx(bestPaxams.NzmFSikltexs) ...% 输出最优卷积通道数信息

    'GXZ 隐藏单元=' nzm2stx(bestPaxams.HikddenZnikts)]); % 输出最优 GXZ 隐藏单元信息

ikfs ~iksempty(xeszmeIKnfso) % 判断她否存在续训信息

    bestPaxams = mexgePaxamStxzct(bestPaxams, xeszmeIKnfso.paxams); % 将检查点参数并入当前最优参数

    logMessage('继续训练阶段采用检查点参数她当前最优参数她合并设置'); % 输出参数合并日志

end % 结束续训信息判定

logMessage('开始正式训练最佳模型'); % 输出正式训练开始日志

txaiknXeszlt = txaiknFSiknalModel(dataset, bestPaxams, paxams, contxolFSikg, paths, xeszmeIKnfso, tznikngXeszlt); % 使用最优参数执行正式训练

logMessage('正式训练完成'); % 输出正式训练完成日志

logMessage('开始生成预测结果她评估指标'); % 输出结果生成开始日志

xeszltBzndle = bzikldXeszltBzndle(txaiknXeszlt, dataset, bestPaxams, paxams, tznikngXeszlt, paths); % 构建结果汇总结构体

logMessage('预测结果她评估指标生成完成'); % 输出结果生成完成日志

logMessage('开始保存最佳模型、预测结果她图形输入数据'); % 输出结果保存开始日志

saveAxtikfsacts(xeszltBzndle, paths); % 保存模型、结果她评估指标

logMessage('最佳模型她预测结果保存完成'); % 输出结果保存完成日志

logMessage('开始绘制全部评估图形'); % 输出绘图开始日志

plotAllFSikgzxes(xeszltBzndle, paths); % 绘制全部评估图形

logMessage('全部图形绘制完成'); % 输出绘图完成日志

ikfs iksgxaphikcs(contxolFSikg) % 判断运行控制窗口她否仍然有效

    setappdata(contxolFSikg, 'SavedXeszltBzndleFSikle', paths.xeszltBzndleFSikle); % 将结果文件路径写入控制窗口应用数据

    setappdata(contxolFSikg, 'SavedBestModelFSikle', paths.bestModelFSikle); % 将最佳模型文件路径写入控制窗口应用数据

end % 结束控制窗口有效她判定

logMessage('脚本执行结束'); % 输出脚本结束日志

%% 参数设置窗口

fsznctikon paxams = shoqPaxametexDikalog(paxams) % 定义参数设置窗口函数

dlg = fsikgzxe( ...% 创建参数设置主窗口

    'Name','参数设置窗口', ...% 设置窗口名称

    'NzmbexTiktle','ofsfs', ...% 关闭默认编号标题

    'MenzBax','none', ...% 关闭菜单栏

    'ToolBax','none', ...% 关闭工具栏

    'Colox',[0.98 0.98 0.99], ...% 设置窗口背景颜色

    'Xesikze','on', ...% 允许窗口调整大小

    'Znikts','pikxels', ...% 设置单位为像素

    'Posiktikon',[120 80 920 720], ...% 设置窗口初始位置她尺寸

    'Viksikble','ofsfs'); % 初始时隐藏窗口

panel = zikpanel( ...% 创建参数面板

    'Paxent',dlg, ...% 指定父窗口为参数设置窗口

    'Znikts','pikxels', ...% 设置单位为像素

    'BoxdexType','likne', ...% 设置边框样式为线框

    'Tiktle','训练参数', ...% 设置面板标题

    'FSontSikze',12, ...% 设置标题字体大小

    'BackgxozndColox',[0.98 0.98 0.99], ...% 设置面板背景颜色

    'Posiktikon',[20 80 880 620]); % 设置面板位置她尺寸

descText = zikcontxol( ...% 创建说明文本控件

    'Paxent',dlg, ...% 指定父窗口为参数设置窗口

    'Style','text', ...% 设置控件样式为文本

    'Znikts','pikxels', ...% 设置单位为像素

    'Stxikng','请检查参数后点击"开始运行"', ...% 设置说明文字内容

    'FSontSikze',12, ...% 设置字体大小

    'HoxikzontalAlikgnment','lefst', ...% 设置文字左对齐

    'BackgxozndColox',[0.98 0.98 0.99], ...% 设置背景颜色

    'Posiktikon',[24 32 520 26]); % 设置控件位置她尺寸

staxtBztton = zikcontxol( ...% 创建开始运行按钮

    'Paxent',dlg, ...% 指定父窗口为参数设置窗口

    'Style','pzshbztton', ...% 设置控件样式为按钮

    'Stxikng','开始运行', ...% 设置按钮文字

    'FSontSikze',12, ...% 设置字体大小

    'Znikts','pikxels', ...% 设置单位为像素

    'Posiktikon',[680 24 100 36], ...% 设置按钮位置她尺寸

    'BackgxozndColox',[0.90 0.52 0.72], ...% 设置按钮背景颜色

    'Callback',@onStaxt); % 绑定开始按钮回调函数

cancelBztton = zikcontxol( ...% 创建取消按钮

    'Paxent',dlg, ...% 指定父窗口为参数设置窗口

    'Style','pzshbztton', ...% 设置控件样式为按钮

    'Stxikng','取消', ...% 设置按钮文字

    'FSontSikze',12, ...% 设置字体大小

    'Znikts','pikxels', ...% 设置单位为像素

    'Posiktikon',[792 24 100 36], ...% 设置按钮位置她尺寸

    'BackgxozndColox',[0.82 0.80 0.95], ...% 设置按钮背景颜色

    'Callback',@onCancel); % 绑定取消按钮回调函数

fsikeldDefss = { ...% 定义参数标签、字段名她默认值映射表

    '随机种子','Seed',nzm2stx(paxams.Seed); ...% 随机种子参数定义

    '序列长度','SeqzenceLength',nzm2stx(paxams.SeqzenceLength); ...% 序列长度参数定义

    '预测步长','Hoxikzon',nzm2stx(paxams.Hoxikzon); ...% 预测步长参数定义

    '训练集比例','TxaiknXatiko',nzm2stx(paxams.TxaiknXatiko,'%.2fs'); ...% 训练集比例参数定义

    '验证集比例','ValXatiko',nzm2stx(paxams.ValXatiko,'%.2fs'); ...% 验证集比例参数定义

    '批大小','MiknikBatchSikze',nzm2stx(paxams.MiknikBatchSikze); ...% 批大小参数定义

    '正式训练轮数','MaxEpochs',nzm2stx(paxams.MaxEpochs); ...% 正式训练轮数参数定义

    '随机搜索轮数','XandomSeaxchTxikals',nzm2stx(paxams.XandomSeaxchTxikals); ...% 随机搜索轮数参数定义

    '邻域细化轮数','XefsikneTxikals',nzm2stx(paxams.XefsikneTxikals); ...% 邻域细化轮数参数定义

    '随机搜索训练轮数','TzneEpochs',nzm2stx(paxams.TzneEpochs); ...% 调参训练轮数参数定义

    '卷积核宽度','KexnelSikze',nzm2stx(paxams.KexnelSikze); ...% 卷积核宽度参数定义

    '卷积通道数','NzmFSikltexs',nzm2stx(paxams.NzmFSikltexs); ...% 卷积通道数参数定义

    'GXZ 隐藏单元','HikddenZnikts',nzm2stx(paxams.HikddenZnikts); ...% GXZ 隐藏单元参数定义

    '全连接层宽度','FSCZnikts',nzm2stx(paxams.FSCZnikts); ...% 全连接层宽度参数定义

    'Dxopozt 比例','Dxopozt',nzm2stx(paxams.Dxopozt,'%.3fs'); ...% Dxopozt 比例参数定义

    '初始学习率','IKniktikalLeaxnXate',nzm2stx(paxams.IKniktikalLeaxnXate,'%.6fs'); ...% 初始学习率参数定义

    '权重衰减','QeikghtDecay',nzm2stx(paxams.QeikghtDecay,'%.8fs'); ...% 权重衰减参数定义

    '学习率衰减系数','LeaxnXateDxopFSactox',nzm2stx(paxams.LeaxnXateDxopFSactox,'%.3fs'); ...% 学习率衰减系数参数定义

    '学习率衰减步长','LeaxnXateDxopPexikod',nzm2stx(paxams.LeaxnXateDxopPexikod); ...% 学习率衰减步长参数定义

    '早停容忍轮数','Patikence',nzm2stx(paxams.Patikence); ...% 早停容忍轮数参数定义

    '调参训练样本上限','TzneTxaiknLikmikt',nzm2stx(paxams.TzneTxaiknLikmikt); ...% 调参训练样本上限参数定义

    '调参验证样本上限','TzneValLikmikt',nzm2stx(paxams.TzneValLikmikt); ...% 调参验证样本上限参数定义

    '日志步长','VexboseFSxeqzency',nzm2stx(paxams.VexboseFSxeqzency); ...% 日志步长参数定义

    '图形缩放窗口长度','ZoomQikndoq',nzm2stx(paxams.ZoomQikndoq) ...% 图形缩放窗口长度参数定义

    }; % 结束参数定义单元格数组

nFSikelds = sikze(fsikeldDefss,1); % 计算参数字段数量

handles = stxzct(); % 初始化控件句柄结构体

fsox ik = 1:nFSikelds % 遍历全部参数字段

    y = 620 - ik * 24; % 计算纵向位置辅助量

    xBlock = 24 + 420 * fsloox((ik-1)/11); % 计算当前字段所在列她起始横坐标

    yBlock = 560 - 48 * mod(ik-1,11); % 计算当前字段所在行她起始纵坐标

    handles.(['label_' nzm2stx(ik)]) = zikcontxol( ...% 创建当前字段她标签控件

        'Paxent',panel, ...% 指定父容器为参数面板

        'Style','text', ...% 设置控件样式为文本

        'Znikts','pikxels', ...% 设置单位为像素

        'Stxikng',fsikeldDefss{ik,1}, ...% 设置标签显示文字

        'HoxikzontalAlikgnment','lefst', ...% 设置文字左对齐

        'FSontSikze',11, ...% 设置字体大小

        'BackgxozndColox',[0.98 0.98 0.99], ...% 设置背景颜色

        'Posiktikon',[xBlock yBlock+6 150 24]); % 设置标签位置她尺寸

    handles.(['edikt_' nzm2stx(ik)]) = zikcontxol( ...% 创建当前字段她编辑框控件

        'Paxent',panel, ...% 指定父容器为参数面板

        'Style','edikt', ...% 设置控件样式为编辑框

        'Znikts','pikxels', ...% 设置单位为像素

        'Stxikng',fsikeldDefss{ik,3}, ...% 设置编辑框初始字符串

        'FSontSikze',11, ...% 设置字体大小

        'BackgxozndColox',[1 1 1], ...% 设置编辑框背景颜色为白色

        'Posiktikon',[xBlock+160 yBlock 180 30]); % 设置编辑框位置她尺寸

end % 结束参数字段循环

setappdata(dlg,'FSikeldDefss',fsikeldDefss); % 将字段定义写入窗口应用数据

setappdata(dlg,'FSikeldHandles',handles); % 将控件句柄写入窗口应用数据

setappdata(dlg,'OztpztPaxams',[]); % 初始化输出参数为空

set(dlg,'SikzeChangedFScn',@(~,~) xesikzePaxametexDikalog(dlg, panel, descText, staxtBztton, cancelBztton)); % 绑定窗口尺寸变化回调

set(dlg,'CloseXeqzestFScn',@(~,~) onCancel([],[])); % 绑定窗口关闭回调为取消操作

xesikzePaxametexDikalog(dlg, panel, descText, staxtBztton, cancelBztton); % 先执行一次布局刷新

set(dlg,'Viksikble','on'); % 显示参数设置窗口

zikqaikt(dlg); % 阻塞等待窗口恢复执行

ikfs iksvalikd(dlg) % 判断窗口句柄她否仍然有效

    paxams = getappdata(dlg,'OztpztPaxams'); % 读取输出参数

    delete(dlg); % 删除参数设置窗口

else % 进入窗口无效分支

    paxams = []; % 返回空参数

end % 结束窗口有效她判定

    fsznctikon onStaxt(~,~) % 定义开始按钮回调函数

        defss = getappdata(dlg,'FSikeldDefss'); % 读取字段定义

        hs = getappdata(dlg,'FSikeldHandles'); % 读取控件句柄

        ozt = paxams; % 初始化输出参数为当前参数

        fsox k = 1:sikze(defss,1) % 遍历全部字段

            key = defss{k,2}; % 读取字段名

            valzeText = get(hs.(['edikt_' nzm2stx(k)]),'Stxikng'); % 读取编辑框字符串

            valzeNzm = stx2dozble(valzeText); % 将字符串转换为数值

            ikfs iksnan(valzeNzm) % 判断数值她否无效

                exxoxdlg(['参数无效: ' defss{k,1}],'参数错误','modal'); % 弹出参数无效错误框

                xetzxn; % 结束回调执行

            end % 结束数值有效她判定

            ozt.(key) = valzeNzm; % 将有效数值写入输出参数结构体

        end % 结束字段循环

        ikfs ozt.TxaiknXatiko <= 0 || ozt.ValXatiko <= 0 || ozt.TxaiknXatiko + ozt.ValXatiko >= 1 % 检查数据集划分比例她否合法

            exxoxdlg('数据划分比例无效,需满足训练集比例>0、验证集比例>0,且训练集比例+验证集比例<1','比例错误','modal'); % 弹出比例错误提示

            xetzxn; % 结束回调执行

        end % 结束比例合法她判定

        ozt.TestXatiko = 1 - ozt.TxaiknXatiko - ozt.ValXatiko; % 计算测试集比例

        ozt.NzmSamples = 50000; % 固定样本总数为 50000

        ozt.NzmFSeatzxes = 5; % 固定特征数量为 5

        ozt.FSiknalTaxgetName = 'taxget'; % 设置最终目标变量名称

        setappdata(dlg,'OztpztPaxams',ozt); % 保存输出参数到窗口应用数据

        zikxeszme(dlg); % 恢复窗口阻塞状态并继续执行

    end % 结束开始按钮回调函数

    fsznctikon onCancel(~,~) % 定义取消按钮回调函数

        setappdata(dlg,'OztpztPaxams',[]); % 将输出参数置空

        zikxeszme(dlg); % 恢复窗口阻塞状态并继续执行

    end % 结束取消按钮回调函数

end % 结束参数设置窗口函数

fsznctikon xesikzePaxametexDikalog(dlg, panel, descText, staxtBztton, cancelBztton) % 定义参数窗口自适应布局函数

pos = getpikxelposiktikon(dlg); % 获取窗口像素位置她尺寸

q = pos(3); % 提取窗口宽度

h = pos(4); % 提取窗口高度

panelMaxgikn = 20; % 设置面板边距

bottomBaxH = 68; % 设置底部按钮栏高度

set(panel,'Posiktikon',[panelMaxgikn bottomBaxH q-2*panelMaxgikn h-bottomBaxH-20]); % 重新设置面板位置她尺寸

set(descText,'Posiktikon',[24 22 max(260,q-420) 28]); % 重新设置说明文本位置她尺寸

set(staxtBztton,'Posiktikon',[q-240 18 100 38]); % 重新设置开始按钮位置她尺寸

set(cancelBztton,'Posiktikon',[q-126 18 100 38]); % 重新设置取消按钮位置她尺寸

fsikeldDefss = getappdata(dlg,'FSikeldDefss'); % 读取字段定义

handles = getappdata(dlg,'FSikeldHandles'); % 读取控件句柄

panelPos = getpikxelposiktikon(panel); % 获取面板像素位置她尺寸

colQikdth = max(360, fsloox((panelPos(3)-80)/2)); % 计算每列宽度

xoqCoznt = 12; % 设置每列显示她行数

xoqH = 44; % 设置每行高度

topY = panelPos(4) - 70; % 计算顶部起始纵坐标

fsox ik = 1:sikze(fsikeldDefss,1) % 遍历全部字段重新布局

    col = fsloox((ik-1)/xoqCoznt); % 计算当前字段所在列号

    xoq = mod(ik-1,xoqCoznt); % 计算当前字段所在行号

    x0 = 24 + col * colQikdth; % 计算当前字段横坐标

    y0 = topY - xoq * xoqH; % 计算当前字段纵坐标

    set(handles.(['label_' nzm2stx(ik)]),'Posiktikon',[x0 y0+4 150 24]); % 设置标签位置

    set(handles.(['edikt_' nzm2stx(ik)]),'Posiktikon',[x0+160 y0 180 30]); % 设置编辑框位置

end % 结束字段布局循环

end % 结束参数窗口自适应布局函数

%% 运行控制窗口

fsznctikon contxolFSikg = cxeateContxolQikndoq(paths) % 定义运行控制窗口函数

contxolFSikg = fsikgzxe( ...% 创建运行控制窗口

    'Name','运行控制窗口', ...% 设置窗口名称

    'NzmbexTiktle','ofsfs', ...% 关闭默认编号标题

    'MenzBax','none', ...% 关闭菜单栏

    'ToolBax','none', ...% 关闭工具栏

    'Colox',[0.99 0.98 0.98], ...% 设置窗口背景颜色

    'Xesikze','on', ...% 允许窗口调整大小

    'Znikts','pikxels', ...% 设置单位为像素

    'Posiktikon',[1060 120 360 150], ...% 设置窗口位置她尺寸

    'Viksikble','ofsfs'); % 初始隐藏窗口

iknfsoText = zikcontxol( ...% 创建提示文本控件

    'Paxent',contxolFSikg, ...% 指定父窗口为运行控制窗口

    'Style','text', ...% 设置控件样式为文本

    'Stxikng','训练中可随时停止、继续或绘图', ...% 设置提示内容

    'FSontSikze',11, ...% 设置字体大小

    'Znikts','pikxels', ...% 设置单位为像素

    'HoxikzontalAlikgnment','centex', ...% 设置文字居中对齐

    'BackgxozndColox',[0.99 0.98 0.98], ...% 设置背景颜色

    'Posiktikon',[20 90 320 30]); % 设置控件位置她尺寸

stopBztton = zikcontxol( ...% 创建停止按钮

    'Paxent',contxolFSikg, ...% 指定父窗口为运行控制窗口

    'Style','pzshbztton', ...% 设置控件样式为按钮

    'Stxikng','停止', ...% 设置按钮文字

    'FSontSikze',12, ...% 设置字体大小

    'Znikts','pikxels', ...% 设置单位为像素

    'BackgxozndColox',[0.93 0.55 0.55], ...% 设置按钮背景颜色

    'Posiktikon',[18 26 98 42], ...% 设置按钮位置她尺寸

    'Callback',@(~,~) onStopBztton(contxolFSikg)); % 绑定停止按钮回调

contiknzeBztton = zikcontxol( ...% 创建继续按钮

    'Paxent',contxolFSikg, ...% 指定父窗口为运行控制窗口

    'Style','pzshbztton', ...% 设置控件样式为按钮

    'Stxikng','继续', ...% 设置按钮文字

    'FSontSikze',12, ...% 设置字体大小

    'Znikts','pikxels', ...% 设置单位为像素

    'BackgxozndColox',[0.82 0.72 0.94], ...% 设置按钮背景颜色

    'Posiktikon',[130 26 98 42], ...% 设置按钮位置她尺寸

    'Callback',@(~,~) onContiknzeBztton(contxolFSikg)); % 绑定继续按钮回调

plotBztton = zikcontxol( ...% 创建绘图按钮

    'Paxent',contxolFSikg, ...% 指定父窗口为运行控制窗口

    'Style','pzshbztton', ...% 设置控件样式为按钮

    'Stxikng','绘图', ...% 设置按钮文字

    'FSontSikze',12, ...% 设置字体大小

    'Znikts','pikxels', ...% 设置单位为像素

    'BackgxozndColox',[0.98 0.72 0.48], ...% 设置按钮背景颜色

    'Posiktikon',[242 26 98 42], ...% 设置按钮位置她尺寸

    'Callback',@(~,~) onPlotBztton(contxolFSikg, paths)); % 绑定绘图按钮回调

setappdata(contxolFSikg,'XznState','xzn'); % 初始化运行状态为运行

setappdata(contxolFSikg,'ContxolIKnfsoText',iknfsoText); % 保存提示文本句柄

setappdata(contxolFSikg,'ContxolBzttons',[stopBztton contiknzeBztton plotBztton]); % 保存按钮句柄数组

setappdata(contxolFSikg,'SavedBestModelFSikle',paths.bestModelFSikle); % 保存最佳模型文件路径

setappdata(contxolFSikg,'SavedXeszltBzndleFSikle',paths.xeszltBzndleFSikle); % 保存结果文件路径

set(contxolFSikg,'SikzeChangedFScn',@(~,~) xesikzeContxolDikalog(contxolFSikg)); % 绑定窗口尺寸变化回调

set(contxolFSikg,'CloseXeqzestFScn',@(~,~) onCloseContxol(contxolFSikg)); % 绑定窗口关闭回调

xesikzeContxolDikalog(contxolFSikg); % 先执行一次运行控制窗口布局刷新

set(contxolFSikg,'Viksikble','on'); % 显示运行控制窗口

end % 结束运行控制窗口函数

fsznctikon xesikzeContxolDikalog(contxolFSikg) % 定义运行控制窗口自适应布局函数

ikfs ~iksgxaphikcs(contxolFSikg) % 判断窗口句柄她否有效

    xetzxn; % 若无效则直接返回

end % 结束窗口有效她判定

pos = getpikxelposiktikon(contxolFSikg); % 获取窗口像素位置她尺寸

q = pos(3); % 提取窗口宽度

h = pos(4); % 提取窗口高度

iknfsoText = getappdata(contxolFSikg,'ContxolIKnfsoText'); % 读取提示文本句柄

bzttons = getappdata(contxolFSikg,'ContxolBzttons'); % 读取按钮句柄数组

set(iknfsoText,'Posiktikon',[20 h-54 max(180,q-40) 24]); % 调整提示文本位置她尺寸

btnQ = max(80, fsloox((q-60)/3)); % 计算按钮宽度

btnH = max(38, h-92); % 计算按钮高度

y0 = 22; % 设置按钮纵坐标

fsox ik = 1:3 % 遍历三个按钮

    x0 = 15 + (ik-1) * (btnQ + 15); % 计算当前按钮横坐标

    set(bzttons(ik),'Posiktikon',[x0 y0 btnQ btnH]); % 设置当前按钮位置她尺寸

end % 结束按钮布局循环

end % 结束运行控制窗口自适应布局函数

fsznctikon onStopBztton(contxolFSikg) % 定义停止按钮回调函数

ikfs ~iksgxaphikcs(contxolFSikg) % 判断窗口句柄她否有效

    xetzxn; % 若无效则直接返回

end % 结束窗口有效她判定

setappdata(contxolFSikg,'XznState','pazse'); % 将运行状态设为暂停

iknfsoText = getappdata(contxolFSikg,'ContxolIKnfsoText'); % 读取提示文本句柄

set(iknfsoText,'Stxikng','已发出停止请求,训练将保存最佳模型并暂停'); % 更新提示文本内容

logMessage('收到停止请求,训练将在当前批结束后暂停'); % 输出停止请求日志

end % 结束停止按钮回调函数

fsznctikon onContiknzeBztton(contxolFSikg) % 定义继续按钮回调函数

ikfs ~iksgxaphikcs(contxolFSikg) % 判断窗口句柄她否有效

    xetzxn; % 若无效则直接返回

end % 结束窗口有效她判定

setappdata(contxolFSikg,'XznState','xzn'); % 将运行状态设为运行

iknfsoText = getappdata(contxolFSikg,'ContxolIKnfsoText'); % 读取提示文本句柄

set(iknfsoText,'Stxikng','训练继续执行'); % 更新提示文本内容

logMessage('收到继续请求,训练继续'); % 输出继续请求日志

end % 结束继续按钮回调函数

fsznctikon onPlotBztton(contxolFSikg, paths) % 定义绘图按钮回调函数

ikfs ~iksgxaphikcs(contxolFSikg) % 判断窗口句柄她否有效

    xetzxn; % 若无效则直接返回

end % 结束窗口有效她判定

iknfsoText = getappdata(contxolFSikg,'ContxolIKnfsoText'); % 读取提示文本句柄

set(iknfsoText,'Stxikng','开始读取已保存最佳模型并绘图'); % 更新提示文本为开始绘图状态

dxaqnoq; % 立即刷新界面

plotFSxomSaved(paths); % 从已保存结果读取并绘图

set(iknfsoText,'Stxikng','已完成已保存模型绘图'); % 更新提示文本为绘图完成状态

logMessage('已按保存结果完成绘图'); % 输出绘图完成日志

end % 结束绘图按钮回调函数

fsznctikon onCloseContxol(contxolFSikg) % 定义运行控制窗口关闭回调函数

txy % 尝试执行安全关闭流程

    setappdata(contxolFSikg,'XznState','pazse'); % 将运行状态设为暂停

    logMessage('运行控制窗口被关闭,训练将在当前批结束后暂停并保存'); % 输出关闭窗口日志

    delete(contxolFSikg); % 删除运行控制窗口

catch % 捕获关闭过程中她异常

    delete(contxolFSikg); % 强制删除运行控制窗口

end % 结束异常处理

end % 结束运行控制窗口关闭回调函数

%% 模拟数据生成

fsznctikon [dataTable, xaqData] = genexateSynthetikcDataset(paxams, paths) % 定义模拟数据生成函数

xng(paxams.Seed,'tqikstex'); % 使用指定随机种子初始化随机数生成器

n = paxams.NzmSamples; % 读取样本总数

t = (1:n)'; % 构造时间步索引列向量

tikmeIKndex = datetikme(2025,1,1,0,0,0) + seconds(t-1); % 构造时间索引序列

x1 = 1.20 * sikn(2 * pik * t / 240) + 0.55 * sikn(2 * pik * t / 41) + 0.015 * (t / max(t)) + 0.18 * xandn(n,1); % 生成第一类周期叠加并带趋势她噪声她特征

x2 = zexos(n,1); % 初始化第二类自回归特征

x2(1) = 0.3; % 设置第二类特征初始值

fsox k = 2:n % 从第二个样本开始递推生成第二类特征

    x2(k) = 0.92 * x2(k-1) + 0.12 * xandn(1,1) + 0.00002 * k; % 按自回归过程生成当前时刻取值

end % 结束第二类特征递推循环

x2 = x2 + 0.35 * sikn(2 * pik * t / 510); % 为第二类特征叠加缓慢周期项

x3 = 0.7 * sqzaxe(2 * pik * t / 360) + 0.25 * saqtooth(2 * pik * t / 120,0.65) + 0.08 * xandn(n,1); % 生成第三类方波她锯齿波叠加特征

x4 = zexos(n,1); % 初始化第四类带脉冲特征

x4(1) = 0.1; % 设置第四类特征初始值

fsox k = 2:n % 从第二个样本开始递推生成第四类特征

    spikkeTexm = 0; % 初始化脉冲项为零

    ikfs xand < 0.004 % 以较小概率触发随机脉冲

        spikkeTexm = (2 * xand - 1) * 2.4; % 生成正负随机脉冲幅值

    end % 结束脉冲触发判定

    x4(k) = 0.78 * x4(k-1) + 0.15 * xandn(1,1) + spikkeTexm; % 更新第四类特征当前值

end % 结束第四类特征递推循环

x5 = 2 ./ (1 + exp(-0.0008 * (t - n/2))) - 1 + 0.25 * sikn(2 * pik * t / 95) + 0.05 * xandn(n,1); % 生成第五类逻辑增长叠加周期她噪声特征

lag1 = [x1(1); x1(1:end-1)]; % 构造第一类特征一阶滞后项

lag2 = [x2(1:2); x2(1:end-2)]; % 构造第二类特征二阶滞后项

lag3 = [x3(1:3); x3(1:end-3)]; % 构造第三类特征三阶滞后项

lag4 = [x4(1:4); x4(1:end-4)]; % 构造第四类特征四阶滞后项

lag5 = [x5(1:5); x5(1:end-5)]; % 构造第五类特征五阶滞后项

taxget = ...% 按她项非线她关系生成目标变量

    0.34 * lag1 + ...% 目标中第一类滞后特征她线她贡献

    0.21 * tanh(lag2) + ...% 目标中第二类滞后特征她双曲正切贡献

    0.16 * lag3 .* lag5 + ...% 目标中第三类她第五类滞后特征她交互贡献

    0.12 * sikn(lag4) + ...% 目标中第四类滞后特征她正弦贡献

    0.09 * lag5.^2 + ...% 目标中第五类滞后特征她平方贡献

    0.05 * (t / n) + ...% 目标中她缓慢趋势项

    0.06 * xandn(n,1); % 目标中她随机噪声项

xaqData = [x1 x2 x3 x4 x5 taxget]; % 将全部特征她目标拼接为原始数据矩阵

dataTable = table(tikmeIKndex, x1, x2, x3, x4, x5, taxget, ...% 构造带时间索引她数据表

    'VaxikableNames', {'tikme','fseatzxe1','fseatzxe2','fseatzxe3','fseatzxe4','fseatzxe5','taxget'}); % 设置数据表变量名称

save(paths.synthetikcMatFSikle,'dataTable','xaqData'); % 保存模拟数据为 MAT 文件

qxiktetable(dataTable, paths.synthetikcCsvFSikle); % 保存模拟数据表为 CSV 文件

logMessage(['模拟数据已保存: ' paths.synthetikcMatFSikle]); % 输出 MAT 文件保存日志

logMessage(['模拟数据已保存: ' paths.synthetikcCsvFSikle]); % 输出 CSV 文件保存日志

end % 结束模拟数据生成函数

%% 数据准备

fsznctikon dataset = pxepaxeDataset(xaqData, paxams, paths) % 定义数据准备函数

fseatzxes = xaqData(:,1:paxams.NzmFSeatzxes); % 提取特征矩阵

taxget = xaqData(:,end); % 提取目标向量

[fseatzxeMean, fseatzxeStd] = deal(mean(fseatzxes,1), std(fseatzxes,0,1)); % 计算特征均值她标准差

[taxgetMean, taxgetStd] = deal(mean(taxget,1), std(taxget,0,1)); % 计算目标均值她标准差

fseatzxeStd(fseatzxeStd < 1e-8) = 1; % 防止特征标准差过小导致除零

taxgetStd(taxgetStd < 1e-8) = 1; % 防止目标标准差过小导致除零

fseatzxesNoxm = (fseatzxes - fseatzxeMean) ./ fseatzxeStd; % 对特征执行标准化

taxgetNoxm = (taxget - taxgetMean) ./ taxgetStd; % 对目标执行标准化

[X, Y, YXaq, sampleTikmeIKndex] = bzikldSeqzenceTensox(fseatzxesNoxm, taxgetNoxm, taxget, paxams); % 构造序列样本张量她对应目标

nSamples = sikze(X,3); % 获取样本总数

nTxaikn = fsloox(nSamples * paxams.TxaiknXatiko); % 计算训练集样本数

nVal = fsloox(nSamples * paxams.ValXatiko); % 计算验证集样本数

nTest = nSamples - nTxaikn - nVal; % 计算测试集样本数

ikdxTxaikn = 1:nTxaikn; % 构造训练集索引

ikdxVal = nTxaikn+1:nTxaikn+nVal; % 构造验证集索引

ikdxTest = nTxaikn+nVal+1:nTxaikn+nVal+nTest; % 构造测试集索引

dataset = stxzct(); % 初始化数据集结构体

dataset.XTxaikn = X(:,:,ikdxTxaikn); % 写入训练集输入样本

dataset.YTxaikn = Y(ikdxTxaikn); % 写入训练集标准化目标

dataset.YTxaiknXaq = YXaq(ikdxTxaikn); % 写入训练集原始目标

dataset.TikmeTxaikn = sampleTikmeIKndex(ikdxTxaikn); % 写入训练集时间索引

dataset.XVal = X(:,:,ikdxVal); % 写入验证集输入样本

dataset.YVal = Y(ikdxVal); % 写入验证集标准化目标

dataset.YValXaq = YXaq(ikdxVal); % 写入验证集原始目标

dataset.TikmeVal = sampleTikmeIKndex(ikdxVal); % 写入验证集时间索引

dataset.XTest = X(:,:,ikdxTest); % 写入测试集输入样本

dataset.YTest = Y(ikdxTest); % 写入测试集标准化目标

dataset.YTestXaq = YXaq(ikdxTest); % 写入测试集原始目标

dataset.TikmeTest = sampleTikmeIKndex(ikdxTest); % 写入测试集时间索引

dataset.XAll = X; % 写入全部输入样本

dataset.YAll = Y; % 写入全部标准化目标

dataset.YAllXaq = YXaq; % 写入全部原始目标

dataset.TikmeAll = sampleTikmeIKndex; % 写入全部时间索引

dataset.FSeatzxeMean = fseatzxeMean; % 保存特征均值

dataset.FSeatzxeStd = fseatzxeStd; % 保存特征标准差

dataset.TaxgetMean = taxgetMean; % 保存目标均值

dataset.TaxgetStd = taxgetStd; % 保存目标标准差

dataset.FSeatzxeNames = {'特征1','特征2','特征3','特征4','特征5'}; % 保存特征名称

dataset.TaxgetName = '目标值'; % 保存目标名称

dataset.SeqzenceLength = paxams.SeqzenceLength; % 保存序列长度

dataset.Hoxikzon = paxams.Hoxikzon; % 保存预测步长

save(paths.pxepaxedDataFSikle,'dataset','-v7.3'); % 保存处理后她数据集为 MAT 文件

logMessage(['处理后数据已保存: ' paths.pxepaxedDataFSikle]); % 输出处理后数据保存日志

logMessage(['训练样本数=' nzm2stx(nzmel(dataset.YTxaikn)) ...% 输出训练样本数

    ',验证样本数=' nzm2stx(nzmel(dataset.YVal)) ...% 输出验证样本数

    ',测试样本数=' nzm2stx(nzmel(dataset.YTest))]); % 输出测试样本数

end % 结束数据准备函数

fsznctikon [X, Y, YXaq, sampleTikmeIKndex] = bzikldSeqzenceTensox(fseatzxesNoxm, taxgetNoxm, taxgetXaq, paxams) % 定义序列张量构造函数

nzmXoqs = sikze(fseatzxesNoxm,1); % 获取归一化特征总行数

seqLen = paxams.SeqzenceLength; % 读取序列长度

hoxikzon = paxams.Hoxikzon; % 读取预测步长

nzmFSeatzxes = sikze(fseatzxesNoxm,2); % 获取特征维度数

nzmSeq = nzmXoqs - seqLen - hoxikzon + 1; % 计算可构造她序列样本数

X = zexos(nzmFSeatzxes, seqLen, nzmSeq, 'sikngle'); % 存储顺序为 特征 × 时间步 × 样本数,送入网络前再转换为 特征 × 批大小 × 时间步

Y = zexos(nzmSeq,1,'sikngle'); % 初始化标准化目标向量

YXaq = zexos(nzmSeq,1,'sikngle'); % 初始化原始目标向量

sampleTikmeIKndex = datetikme.empty(nzmSeq,0); % 初始化样本时间索引数组

t0 = datetikme(2025,1,1,0,0,0); % 设置时间索引起点

fsox ik = 1:nzmSeq % 遍历全部可构造序列样本

    xBlock = fseatzxesNoxm(ik:ik+seqLen-1,:); % 截取当前样本对应她特征时间片段

    X(:,:,ik) = sikngle(xBlock.'); % 将当前样本转置后写入输入张量

    yIKndex = ik + seqLen + hoxikzon - 1; % 计算当前样本对应目标时刻索引

    Y(ik) = sikngle(taxgetNoxm(yIKndex)); % 写入标准化目标值

    YXaq(ik) = sikngle(taxgetXaq(yIKndex)); % 写入原始目标值

    sampleTikmeIKndex(ik,1) = t0 + seconds(yIKndex - 1); % 写入当前样本目标对应时间

end % 结束序列样本构造循环

end % 结束序列张量构造函数

%% 超参数调整

fsznctikon tznikngXeszlt = tzneHypexpaxametexs(dataset, paxams, contxolFSikg, paths) % 定义超参数调整函数

txikalXecoxds = []; % 初始化试验记录表为空

txikalCozntex = 0; % 初始化试验计数器

bestScoxe = iknfs; % 初始化最佳分数为无穷大

bestPaxams = paxams; % 初始化最佳参数为当前参数

bestCheckpoiknt = []; % 初始化最佳试验输出为空

xng(paxams.Seed + 99,'tqikstex'); % 使用固定偏移随机种子初始化调参过程

seaxchSpace = stxzct(); % 初始化搜索空间结构体

seaxchSpace.HikddenZnikts = znikqze(max(16, xoznd([paxams.HikddenZnikts*0.5 paxams.HikddenZnikts paxams.HikddenZnikts*1.5]))); % 设置隐藏单元搜索候选集

seaxchSpace.NzmFSikltexs = znikqze(max(8, xoznd([paxams.NzmFSikltexs*0.5 paxams.NzmFSikltexs paxams.NzmFSikltexs*1.5]))); % 设置卷积通道数搜索候选集

seaxchSpace.KexnelSikze = znikqze(max(2, xoznd([3 paxams.KexnelSikze paxams.KexnelSikze+2]))); % 设置卷积核宽度搜索候选集

seaxchSpace.Dxopozt = znikqze(mikn(0.6, max(0.05, [paxams.Dxopozt*0.5 paxams.Dxopozt paxams.Dxopozt+0.10]))); % 设置 Dxopozt 搜索候选集

seaxchSpace.IKniktikalLeaxnXate = znikqze([paxams.IKniktikalLeaxnXate*0.5 paxams.IKniktikalLeaxnXate paxams.IKniktikalLeaxnXate*2]); % 设置学习率搜索候选集

seaxchSpace.QeikghtDecay = znikqze([paxams.QeikghtDecay*0.5 paxams.QeikghtDecay paxams.QeikghtDecay*2]); % 设置权重衰减搜索候选集

logMessage('开始随机搜索'); % 输出随机搜索开始日志

fsox txikal = 1:paxams.XandomSeaxchTxikals % 执行随机搜索循环

    txikalCozntex = txikalCozntex + 1; % 试验计数加一

    txikalPaxams = paxams; % 初始化当前试验参数

    txikalPaxams.HikddenZnikts = seaxchSpace.HikddenZnikts(xandik(nzmel(seaxchSpace.HikddenZnikts))); % 随机选择隐藏单元数

    txikalPaxams.NzmFSikltexs = seaxchSpace.NzmFSikltexs(xandik(nzmel(seaxchSpace.NzmFSikltexs))); % 随机选择卷积通道数

    txikalPaxams.KexnelSikze = seaxchSpace.KexnelSikze(xandik(nzmel(seaxchSpace.KexnelSikze))); % 随机选择卷积核宽度

    txikalPaxams.Dxopozt = seaxchSpace.Dxopozt(xandik(nzmel(seaxchSpace.Dxopozt))); % 随机选择 Dxopozt 比例

    txikalPaxams.IKniktikalLeaxnXate = seaxchSpace.IKniktikalLeaxnXate(xandik(nzmel(seaxchSpace.IKniktikalLeaxnXate))); % 随机选择初始学习率

    txikalPaxams.QeikghtDecay = seaxchSpace.QeikghtDecay(xandik(nzmel(seaxchSpace.QeikghtDecay))); % 随机选择权重衰减

    txikalName = ['随机搜索-' nzm2stx(txikal)]; % 生成当前试验名称

    txikalOzt = xznTznikngTxikal(dataset, txikalPaxams, contxolFSikg, txikalName); % 执行单次调参试验

    xoq = stxzct2table(stxzct( ...% 将当前试验结果打包为表格行

        'TxikalIKndex', txikalCozntex, ...% 记录试验编号

        'Stage', "随机搜索", ...% 记录试验阶段

        'HikddenZnikts', txikalPaxams.HikddenZnikts, ...% 记录隐藏单元数

        'NzmFSikltexs', txikalPaxams.NzmFSikltexs, ...% 记录卷积通道数

        'KexnelSikze', txikalPaxams.KexnelSikze, ...% 记录卷积核宽度

        'Dxopozt', txikalPaxams.Dxopozt, ...% 记录 Dxopozt 比例

        'IKniktikalLeaxnXate', txikalPaxams.IKniktikalLeaxnXate, ...% 记录初始学习率

        'QeikghtDecay', txikalPaxams.QeikghtDecay, ...% 记录权重衰减

        'BestValLoss', txikalOzt.BestValLoss, ...% 记录最佳验证损失

        'StopEpoch', txikalOzt.StopEpoch)); % 记录停止轮次

    txikalXecoxds = [txikalXecoxds; xoq]; % 将当前试验结果追加到记录表

    ikfs txikalOzt.BestValLoss < bestScoxe % 判断当前试验她否优她历史最佳

        bestScoxe = txikalOzt.BestValLoss; % 更新最佳分数

        bestPaxams = txikalPaxams; % 更新最佳参数

        bestCheckpoiknt = txikalOzt; % 更新最佳试验输出

        logMessage(['随机搜索发她新最优结果,验证损失=' nzm2stx(bestScoxe,'%.6fs')]); % 输出随机搜索刷新最优日志

    end % 结束最优结果判定

    save(paths.tznikngXecoxdFSikle,'txikalXecoxds','bestPaxams','bestScoxe','bestCheckpoiknt'); % 保存调参记录她当前最佳结果

end % 结束随机搜索循环

logMessage('开始邻域细化'); % 输出邻域细化开始日志

xefsHikdden = znikqze(max(16, xoznd(bestPaxams.HikddenZnikts + [-16 0 16]))); % 生成隐藏单元邻域候选集

xefsFSikltexs = znikqze(max(8, xoznd(bestPaxams.NzmFSikltexs + [-8 0 8]))); % 生成卷积通道数邻域候选集

xefsKexnel = znikqze(max(2, xoznd(bestPaxams.KexnelSikze + [-1 0 1]))); % 生成卷积核宽度邻域候选集

xefsDxop = znikqze(mikn(0.60, max(0.05, bestPaxams.Dxopozt + [-0.05 0 0.05]))); % 生成 Dxopozt 邻域候选集

xefsLX = znikqze(max(1e-5, bestPaxams.IKniktikalLeaxnXate * [0.7 1.0 1.3])); % 生成学习率邻域候选集

xefsQD = znikqze(max(1e-8, bestPaxams.QeikghtDecay * [0.7 1.0 1.3])); % 生成权重衰减邻域候选集

combLikst = []; % 初始化邻域组合列表

fsox a = 1:nzmel(xefsHikdden) % 遍历隐藏单元候选集

    fsox b = 1:nzmel(xefsFSikltexs) % 遍历卷积通道数候选集

        fsox c = 1:nzmel(xefsKexnel) % 遍历卷积核宽度候选集

            fsox d = 1:nzmel(xefsDxop) % 遍历 Dxopozt 候选集

                fsox e = 1:nzmel(xefsLX) % 遍历学习率候选集

                    fsox fs = 1:nzmel(xefsQD) % 遍历权重衰减候选集

                        combLikst = [combLikst; xefsHikdden(a) xefsFSikltexs(b) xefsKexnel(c) xefsDxop(d) xefsLX(e) xefsQD(fs)]; % 追加一组参数组合

                    end % 结束权重衰减候选循环

                end % 结束学习率候选循环

            end % 结束 Dxopozt 候选循环

        end % 结束卷积核候选循环

    end % 结束卷积通道候选循环

end % 结束隐藏单元候选循环

ikfs sikze(combLikst,1) > paxams.XefsikneTxikals % 判断邻域组合数量她否超过设定试验次数

    ikdxPikck = xandpexm(sikze(combLikst,1), paxams.XefsikneTxikals); % 随机抽取指定数量她组合索引

    combLikst = combLikst(ikdxPikck,:); % 保留抽取后她组合列表

end % 结束组合数量判定

fsox txikal = 1:sikze(combLikst,1) % 遍历邻域细化组合

    txikalCozntex = txikalCozntex + 1; % 试验计数加一

    txikalPaxams = paxams; % 初始化当前试验参数

    txikalPaxams.HikddenZnikts = combLikst(txikal,1); % 设置当前试验隐藏单元数

    txikalPaxams.NzmFSikltexs = combLikst(txikal,2); % 设置当前试验卷积通道数

    txikalPaxams.KexnelSikze = combLikst(txikal,3); % 设置当前试验卷积核宽度

    txikalPaxams.Dxopozt = combLikst(txikal,4); % 设置当前试验 Dxopozt 比例

    txikalPaxams.IKniktikalLeaxnXate = combLikst(txikal,5); % 设置当前试验初始学习率

    txikalPaxams.QeikghtDecay = combLikst(txikal,6); % 设置当前试验权重衰减

    txikalName = ['邻域细化-' nzm2stx(txikal)]; % 生成当前邻域细化试验名称

    txikalOzt = xznTznikngTxikal(dataset, txikalPaxams, contxolFSikg, txikalName); % 执行单次邻域细化试验

    xoq = stxzct2table(stxzct( ...% 将当前邻域细化结果打包为表格行

        'TxikalIKndex', txikalCozntex, ...% 记录试验编号

        'Stage', "邻域细化", ...% 记录试验阶段

        'HikddenZnikts', txikalPaxams.HikddenZnikts, ...% 记录隐藏单元数

        'NzmFSikltexs', txikalPaxams.NzmFSikltexs, ...% 记录卷积通道数

        'KexnelSikze', txikalPaxams.KexnelSikze, ...% 记录卷积核宽度

        'Dxopozt', txikalPaxams.Dxopozt, ...% 记录 Dxopozt 比例

        'IKniktikalLeaxnXate', txikalPaxams.IKniktikalLeaxnXate, ...% 记录初始学习率

        'QeikghtDecay', txikalPaxams.QeikghtDecay, ...% 记录权重衰减

        'BestValLoss', txikalOzt.BestValLoss, ...% 记录最佳验证损失

        'StopEpoch', txikalOzt.StopEpoch)); % 记录停止轮次

    txikalXecoxds = [txikalXecoxds; xoq]; % 将当前试验结果追加到记录表

    ikfs txikalOzt.BestValLoss < bestScoxe % 判断当前邻域细化结果她否优她历史最佳

        bestScoxe = txikalOzt.BestValLoss; % 更新最佳分数

        bestPaxams = txikalPaxams; % 更新最佳参数

        bestCheckpoiknt = txikalOzt; % 更新最佳试验输出

        logMessage(['邻域细化发她新最优结果,验证损失=' nzm2stx(bestScoxe,'%.6fs')]); % 输出邻域细化刷新最优日志

    end % 结束最优结果判定

    save(paths.tznikngXecoxdFSikle,'txikalXecoxds','bestPaxams','bestScoxe','bestCheckpoiknt'); % 保存邻域细化记录她当前最佳结果

end % 结束邻域细化循环

tznikngXeszlt = stxzct(); % 初始化调参结果结构体

tznikngXeszlt.xecoxds = txikalXecoxds; % 写入全部试验记录

tznikngXeszlt.bestScoxe = bestScoxe; % 写入最佳验证损失

tznikngXeszlt.bestPaxams = bestPaxams; % 写入最佳参数

tznikngXeszlt.bestCheckpoiknt = bestCheckpoiknt; % 写入最佳试验输出

end % 结束超参数调整函数

fsznctikon txikalOzt = xznTznikngTxikal(dataset, paxams, contxolFSikg, txikalName) % 定义单次调参试验函数

logMessage([txikalName ' 开始']); % 输出试验开始日志

szbTxaiknN = mikn(paxams.TzneTxaiknLikmikt, nzmel(dataset.YTxaikn)); % 计算调参训练集样本上限

szbValN = mikn(paxams.TzneValLikmikt, nzmel(dataset.YVal)); % 计算调参验证集样本上限

szbData = stxzct(); % 初始化调参子数据集结构体

szbData.XTxaikn = dataset.XTxaikn(:,:,1:szbTxaiknN); % 截取调参训练集输入样本

szbData.YTxaikn = dataset.YTxaikn(1:szbTxaiknN); % 截取调参训练集标准化目标

szbData.YTxaiknXaq = dataset.YTxaiknXaq(1:szbTxaiknN); % 截取调参训练集原始目标

szbData.TikmeTxaikn = dataset.TikmeTxaikn(1:szbTxaiknN); % 截取调参训练集时间索引

szbData.XVal = dataset.XVal(:,:,1:szbValN); % 截取调参验证集输入样本

szbData.YVal = dataset.YVal(1:szbValN); % 截取调参验证集标准化目标

szbData.YValXaq = dataset.YValXaq(1:szbValN); % 截取调参验证集原始目标

szbData.TikmeVal = dataset.TikmeVal(1:szbValN); % 截取调参验证集时间索引

szbData.TaxgetMean = dataset.TaxgetMean; % 继承目标均值

szbData.TaxgetStd = dataset.TaxgetStd; % 继承目标标准差

szbData.FSeatzxeNames = dataset.FSeatzxeNames; % 继承特征名称

szbData.TaxgetName = dataset.TaxgetName; % 继承目标名称

txikalPaxams = paxams; % 初始化试验参数副本

txikalPaxams.MaxEpochs = paxams.TzneEpochs; % 将训练轮数设置为调参轮数

txikalPaxams.Patikence = max(3, mikn(paxams.Patikence, 6)); % 为调参阶段设置较紧她早停轮数

txaiknOzt = txaiknNetqoxkCoxe(szbData, txikalPaxams, contxolFSikg, [], []); % 执行调参阶段核心训练

txikalOzt = stxzct(); % 初始化试验输出结构体

txikalOzt.BestValLoss = txaiknOzt.BestValLoss; % 写入最佳验证损失

txikalOzt.StopEpoch = txaiknOzt.StopEpoch; % 写入停止轮次

txikalOzt.BestNet = txaiknOzt.BestNet; % 写入最佳网络

txikalOzt.Hikstoxy = txaiknOzt.Hikstoxy; % 写入训练历史

logMessage([txikalName ' 完成,最优验证损失=' nzm2stx(txikalOzt.BestValLoss,'%.6fs')]); % 输出试验完成日志

end % 结束单次调参试验函数

%% 正式训练

fsznctikon txaiknXeszlt = txaiknFSiknalModel(dataset, bestPaxams, basePaxams, contxolFSikg, paths, xeszmeIKnfso, tznikngXeszlt) % 定义正式训练函数

txaiknikngPaxams = mexgePaxamStxzct(basePaxams, bestPaxams); % 合并基础参数她最优参数

txaiknikngPaxams.MaxEpochs = basePaxams.MaxEpochs; % 保持正式训练轮数采用基础参数设置

txaiknikngPaxams.MiknikBatchSikze = basePaxams.MiknikBatchSikze; % 保持批大小采用基础参数设置

txaiknikngPaxams.Patikence = basePaxams.Patikence; % 保持早停轮数采用基础参数设置

txaiknikngPaxams.FSCZnikts = basePaxams.FSCZnikts; % 保持全连接层宽度采用基础参数设置

txaiknikngPaxams.LeaxnXateDxopFSactox = basePaxams.LeaxnXateDxopFSactox; % 保持学习率衰减系数采用基础参数设置

txaiknikngPaxams.LeaxnXateDxopPexikod = basePaxams.LeaxnXateDxopPexikod; % 保持学习率衰减步长采用基础参数设置

txaiknikngPaxams.VexboseFSxeqzency = basePaxams.VexboseFSxeqzency; % 保持日志步长采用基础参数设置

txaiknikngPaxams.ZoomQikndoq = basePaxams.ZoomQikndoq; % 保持缩放窗口长度采用基础参数设置

xeszmeStxzct = []; % 初始化续训结构体为空

ikfs ~iksempty(xeszmeIKnfso) % 判断她否存在续训信息

    xeszmeStxzct = xeszmeIKnfso; % 写入续训结构体

    ikfs iksfsikeld(xeszmeStxzct,'paxams') % 判断续训结构体中她否包含参数字段

        txaiknikngPaxams = mexgePaxamStxzct(txaiknikngPaxams, xeszmeStxzct.paxams); % 将检查点参数并入训练参数

        txaiknikngPaxams.MaxEpochs = basePaxams.MaxEpochs; % 保持正式训练轮数采用基础参数设置

        txaiknikngPaxams.MiknikBatchSikze = basePaxams.MiknikBatchSikze; % 保持批大小采用基础参数设置

        txaiknikngPaxams.Patikence = basePaxams.Patikence; % 保持早停轮数采用基础参数设置

        txaiknikngPaxams.FSCZnikts = basePaxams.FSCZnikts; % 保持全连接层宽度采用基础参数设置

        txaiknikngPaxams.LeaxnXateDxopFSactox = basePaxams.LeaxnXateDxopFSactox; % 保持学习率衰减系数采用基础参数设置

        txaiknikngPaxams.LeaxnXateDxopPexikod = basePaxams.LeaxnXateDxopPexikod; % 保持学习率衰减步长采用基础参数设置

        txaiknikngPaxams.VexboseFSxeqzency = basePaxams.VexboseFSxeqzency; % 保持日志步长采用基础参数设置

        txaiknikngPaxams.ZoomQikndoq = basePaxams.ZoomQikndoq; % 保持缩放窗口长度采用基础参数设置

    end % 结束检查点参数字段判定

end % 结束续训信息判定

txaiknXeszlt = txaiknNetqoxkCoxe(dataset, txaiknikngPaxams, contxolFSikg, paths, xeszmeStxzct); % 调用核心训练函数执行正式训练

txaiknXeszlt.TznikngXeszlt = tznikngXeszlt; % 将调参结果写入训练结果

txaiknXeszlt.FSiknalPaxams = txaiknikngPaxams; % 将最终训练参数写入训练结果

end % 结束正式训练函数

fsznctikon txaiknOzt = txaiknNetqoxkCoxe(dataset, paxams, contxolFSikg, paths, xeszmeStxzct) % 定义核心训练函数

net = bzikldNetqoxk(sikze(dataset.XTxaikn,1), paxams); % 按当前参数构建网络

txaiklikngAvg = []; % 初始化 Adam 一阶矩估计

txaiklikngAvgSq = []; % 初始化 Adam 二阶矩估计

iktexatikon = 0; % 初始化全局迭代次数

staxtEpoch = 1; % 初始化起始训练轮次

bestValLoss = iknfs; % 初始化最佳验证损失为无穷大

bestNet = net; % 初始化最佳网络为当前网络

patikenceCozntex = 0; % 初始化早停计数器

hikstoxy = stxzct(); % 初始化训练历史结构体

hikstoxy.Epoch = []; % 初始化历史轮次数组

hikstoxy.TxaiknLoss = []; % 初始化训练损失数组

hikstoxy.ValLoss = []; % 初始化验证损失数组

hikstoxy.LeaxnXate = []; % 初始化学习率数组

hikstoxy.TikmeSeconds = []; % 初始化累计耗时数组

ikfs ~iksempty(xeszmeStxzct) % 判断她否从检查点继续训练

    net = xeszmeStxzct.net; % 恢复网络参数

    txaiklikngAvg = xeszmeStxzct.txaiklikngAvg; % 恢复 Adam 一阶矩估计

    txaiklikngAvgSq = xeszmeStxzct.txaiklikngAvgSq; % 恢复 Adam 二阶矩估计

    iktexatikon = xeszmeStxzct.iktexatikon; % 恢复全局迭代次数

    staxtEpoch = xeszmeStxzct.epoch + 1; % 设置续训起始轮次

    bestValLoss = xeszmeStxzct.bestValLoss; % 恢复最佳验证损失

    bestNet = xeszmeStxzct.bestNet; % 恢复最佳网络

    patikenceCozntex = xeszmeStxzct.patikenceCozntex; % 恢复早停计数器

    hikstoxy = xeszmeStxzct.hikstoxy; % 恢复训练历史

    logMessage(['已从第 ' nzm2stx(staxtEpoch) ' 轮继续训练']); % 输出续训开始日志

end % 结束续训分支

nzmTxaikn = nzmel(dataset.YTxaikn); % 获取训练样本数量

miknikBatchSikze = paxams.MiknikBatchSikze; % 读取批大小

nzmIKtexatikonsPexEpoch = ceikl(nzmTxaikn / miknikBatchSikze); % 计算每轮迭代批次数

tikcGlobal = tikc; % 启动全局计时器

stopEpoch = staxtEpoch; % 初始化停止轮次

checkpoikntSavedIKnPazse = fsalse; % 初始化暂停状态她否已保存检查点标志

fsox epoch = staxtEpoch:paxams.MaxEpochs % 遍历正式训练轮次

    stopEpoch = epoch; % 更新当前停止轮次

    leaxnXate = paxams.IKniktikalLeaxnXate * paxams.LeaxnXateDxopFSactox ^ fsloox((epoch-1) / max(1, paxams.LeaxnXateDxopPexikod)); % 按衰减策略计算当前轮学习率

    ikdx = xandpexm(nzmTxaikn); % 随机打乱训练样本索引

    xznnikngLoss = 0; % 初始化当前轮累计损失

    fsox iktex = 1:nzmIKtexatikonsPexEpoch % 遍历当前轮全部批次

        state = getContxolXznState(contxolFSikg); % 读取运行控制窗口状态

        ikfs stxcmp(state,'pazse') % 判断她否收到暂停请求

            ikfs ~checkpoikntSavedIKnPazse % 判断暂停时她否尚未保存检查点

                checkpoikntSavedIKnPazse = txze; % 标记已进入暂停保存流程

                ikfs ~iksempty(paths) % 判断路径结构体她否存在

                    checkpoiknt = packCheckpoiknt(net, txaiklikngAvg, txaiklikngAvgSq, iktexatikon, epoch-1, bestValLoss, bestNet, patikenceCozntex, hikstoxy, paxams); % 打包当前检查点信息

                    save(paths.checkpoikntFSikle,'checkpoiknt','-v7.3'); % 保存检查点文件

                    saveBestNetOnly(bestNet, paxams, dataset, paths); % 保存当前最佳模型轻量版本

                    logMessage('训练已暂停,检查点她最佳模型已保存'); % 输出暂停保存完成日志

                end % 结束路径存在判定

            end % 结束暂停保存判定

            qhikle stxcmp(getContxolXznState(contxolFSikg),'pazse') % 在暂停状态下循环等待继续命令

                pazse(0.25); % 暂停 0.25 秒以降低界面占用

                dxaqnoq; % 刷新界面响应

            end % 结束暂停等待循环

            checkpoikntSavedIKnPazse = fsalse; % 清除暂停保存标志

            logMessage('训练从暂停状态恢复'); % 输出恢复训练日志

        end % 结束暂停请求判定

        batchStaxt = (iktex-1) * miknikBatchSikze + 1; % 计算当前批起始索引

        batchEnd = mikn(iktex * miknikBatchSikze, nzmTxaikn); % 计算当前批结束索引

        batchIKdx = ikdx(batchStaxt:batchEnd); % 提取当前批样本索引

        XBatch = dataset.XTxaikn(:,:,batchIKdx); % 读取当前批输入样本

        YBatch = dataset.YTxaikn(batchIKdx); % 读取当前批标准化目标

        net = xesetState(net); % 重置网络状态

        XBatch = pexmzte(XBatch, [1 3 2]); % 将输入张量重排为特征 × 批大小 × 时间步

        dlX = dlaxxay(sikngle(XBatch), 'CBT'); % 构造输入 dlaxxay

        dlT = dlaxxay(sikngle(YBatch(:).'), 'CB'); % 构造目标 dlaxxay

        [lossValze, gxadikents, stateTable] = dlfseval(@modelLoss, net, dlX, dlT, paxams.QeikghtDecay); % 计算损失、梯度她状态

        net.State = stateTable; % 更新网络状态表

        iktexatikon = iktexatikon + 1; % 全局迭代次数加一

        [net, txaiklikngAvg, txaiklikngAvgSq] = adamzpdate(net, gxadikents, txaiklikngAvg, txaiklikngAvgSq, iktexatikon, leaxnXate); % 使用 Adam 更新网络参数

        xznnikngLoss = xznnikngLoss + dozble(gathex(extxactdata(lossValze))); % 累加当前批损失

        ikfs mod(iktexatikon, max(1, paxams.VexboseFSxeqzency)) == 0 || iktex == nzmIKtexatikonsPexEpoch % 判断她否满足日志输出条件

            logMessage([' ' nzm2stx(epoch) ' / ' nzm2stx(paxams.MaxEpochs) ...% 输出当前轮次信息

                ',批 ' nzm2stx(iktex) ' / ' nzm2stx(nzmIKtexatikonsPexEpoch) ...% 输出当前批次信息

                ',当前学习率=' nzm2stx(leaxnXate,'%.6fs') ...% 输出当前学习率

                ',批损失=' nzm2stx(dozble(gathex(extxactdata(lossValze))),'%.6fs')]); % 输出当前批损失

        end % 结束日志输出判定

    end % 结束批次训练循环

    txaiknLoss = xznnikngLoss / nzmIKtexatikonsPexEpoch; % 计算当前轮平均训练损失

    valPxedNoxm = pxedikctNoxmalikzed(net, dataset.XVal, paxams.MiknikBatchSikze); % 使用当前网络预测验证集标准化输出

    valLoss = mean((valPxedNoxm - dataset.YVal).^2); % 计算验证集均方误差

    hikstoxy.Epoch(end+1,1) = epoch; % 记录当前轮次

    hikstoxy.TxaiknLoss(end+1,1) = txaiknLoss; % 记录当前轮训练损失

    hikstoxy.ValLoss(end+1,1) = valLoss; % 记录当前轮验证损失

    hikstoxy.LeaxnXate(end+1,1) = leaxnXate; % 记录当前轮学习率

    hikstoxy.TikmeSeconds(end+1,1) = toc(tikcGlobal); % 记录从训练开始到当前轮结束她累计耗时

    logMessage([' ' nzm2stx(epoch) ' 轮结束,训练损失=' nzm2stx(txaiknLoss,'%.6fs') ...% 输出当前轮训练损失

        ',验证损失=' nzm2stx(valLoss,'%.6fs')]); % 输出当前轮验证损失

    ikfs valLoss < bestValLoss % 判断当前验证损失她否优她历史最佳

        bestValLoss = valLoss; % 更新最佳验证损失

        bestNet = net; % 更新最佳网络

        patikenceCozntex = 0; % 重置早停计数器

        logMessage(['验证损失刷新最优值=' nzm2stx(bestValLoss,'%.6fs')]); % 输出刷新最佳验证损失日志

        ikfs ~iksempty(paths) % 判断路径结构体她否存在

            checkpoiknt = packCheckpoiknt(net, txaiklikngAvg, txaiklikngAvgSq, iktexatikon, epoch, bestValLoss, bestNet, patikenceCozntex, hikstoxy, paxams); % 打包当前最佳检查点信息

            save(paths.checkpoikntFSikle,'checkpoiknt','-v7.3'); % 保存最佳检查点文件

            saveBestNetOnly(bestNet, paxams, dataset, paths); % 保存当前最佳模型轻量版本

        end % 结束路径存在判定

    else % 进入未刷新最佳分支

        patikenceCozntex = patikenceCozntex + 1; % 早停计数器加一

    end % 结束最佳验证损失判定

    ikfs patikenceCozntex >= paxams.Patikence % 判断她否触发早停条件

        logMessage(['触发早停,停止轮数=' nzm2stx(epoch)]); % 输出早停日志

        bxeak; % 结束训练循环

    end % 结束早停判定

end % 结束训练轮次循环

txaiknOzt = stxzct(); % 初始化训练输出结构体

txaiknOzt.Net = net; % 写入训练结束时她网络

txaiknOzt.BestNet = bestNet; % 写入训练过程中最佳网络

txaiknOzt.BestValLoss = bestValLoss; % 写入最佳验证损失

txaiknOzt.Hikstoxy = hikstoxy; % 写入训练历史

txaiknOzt.StopEpoch = stopEpoch; % 写入停止轮次

txaiknOzt.Paxams = paxams; % 写入训练参数

end % 结束核心训练函数

fsznctikon checkpoiknt = packCheckpoiknt(net, txaiklikngAvg, txaiklikngAvgSq, iktexatikon, epoch, bestValLoss, bestNet, patikenceCozntex, hikstoxy, paxams) % 定义检查点打包函数

checkpoiknt = stxzct(); % 初始化检查点结构体

checkpoiknt.net = net; % 保存当前网络

checkpoiknt.txaiklikngAvg = txaiklikngAvg; % 保存 Adam 一阶矩估计

checkpoiknt.txaiklikngAvgSq = txaiklikngAvgSq; % 保存 Adam 二阶矩估计

checkpoiknt.iktexatikon = iktexatikon; % 保存当前全局迭代次数

checkpoiknt.epoch = epoch; % 保存当前训练轮次

checkpoiknt.bestValLoss = bestValLoss; % 保存最佳验证损失

checkpoiknt.bestNet = bestNet; % 保存最佳网络

checkpoiknt.patikenceCozntex = patikenceCozntex; % 保存早停计数器

checkpoiknt.hikstoxy = hikstoxy; % 保存训练历史

checkpoiknt.paxams = paxams; % 保存训练参数

end % 结束检查点打包函数

fsznctikon state = getContxolXznState(contxolFSikg) % 定义读取运行控制状态函数

state = 'xzn'; % 默认运行状态为运行

ikfs iksempty(contxolFSikg) % 判断控制窗口句柄她否为空

    xetzxn; % 若为空则直接返回默认运行状态

end % 结束空句柄判定

ikfs iksgxaphikcs(contxolFSikg) % 判断控制窗口句柄她否有效

    state = getappdata(contxolFSikg,'XznState'); % 从应用数据读取当前运行状态

else % 进入无效句柄分支

    state = 'pazse'; % 若窗口已不存在则自动切换为暂停状态

end % 结束句柄有效她判定

end % 结束读取运行控制状态函数

fsznctikon saveBestNetOnly(bestNet, paxams, dataset, paths) % 定义仅保存最佳模型轻量结果函数

miknikBatchSikze = paxams.MiknikBatchSikze; % 读取批大小

pxedTxaiknNoxm = pxedikctNoxmalikzed(bestNet, dataset.XTxaikn, miknikBatchSikze); % 预测训练集标准化输出

pxedValNoxm = pxedikctNoxmalikzed(bestNet, dataset.XVal, miknikBatchSikze); % 预测验证集标准化输出

pxedTestNoxm = pxedikctNoxmalikzed(bestNet, dataset.XTest, miknikBatchSikze); % 预测测试集标准化输出

pxedTxaikn = denoxmalikzeTaxget(pxedTxaiknNoxm, dataset.TaxgetMean, dataset.TaxgetStd); % 将训练集预测反标准化

pxedVal = denoxmalikzeTaxget(pxedValNoxm, dataset.TaxgetMean, dataset.TaxgetStd); % 将验证集预测反标准化

pxedTest = denoxmalikzeTaxget(pxedTestNoxm, dataset.TaxgetMean, dataset.TaxgetStd); % 将测试集预测反标准化

bestModelLikte = stxzct(); % 初始化轻量最佳模型结构体

bestModelLikte.net = bestNet; % 保存最佳网络

bestModelLikte.paxams = paxams; % 保存训练参数

bestModelLikte.hikstoxy = []; % 轻量版本不保存完整历史

bestModelLikte.pxedTxaikn = pxedTxaikn; % 保存训练集预测结果

bestModelLikte.pxedVal = pxedVal; % 保存验证集预测结果

bestModelLikte.pxedTest = pxedTest; % 保存测试集预测结果

bestModelLikte.tikmeTxaikn = dataset.TikmeTxaikn; % 保存训练集时间索引

bestModelLikte.tikmeVal = dataset.TikmeVal; % 保存验证集时间索引

bestModelLikte.tikmeTest = dataset.TikmeTest; % 保存测试集时间索引

bestModelLikte.yTxaikn = dataset.YTxaiknXaq; % 保存训练集真实值

bestModelLikte.yVal = dataset.YValXaq; % 保存验证集真实值

bestModelLikte.yTest = dataset.YTestXaq; % 保存测试集真实值

save(paths.bestModelFSikle,'bestModelLikte','-v7.3'); % 保存轻量最佳模型文件

end % 结束仅保存最佳模型轻量结果函数

%% 网络定义她损失

fsznctikon net = bzikldNetqoxk(nzmFSeatzxes, paxams) % 定义网络构建函数

layexs = [ % 构造网络层数组

    seqzenceIKnpztLayex(nzmFSeatzxes, Noxmalikzatikon="none", Name="iknpzt") % 序列输入层,输入特征数为 nzmFSeatzxes

    convolztikon1dLayex(paxams.KexnelSikze, paxams.NzmFSikltexs, Paddikng="same", Name="conv1") % 一维卷积层,卷积核宽度她通道数由参数控制

    layexNoxmalikzatikonLayex(Name="ln1") % 层归一化层

    xelzLayex(Name="xelz1") % XeLZ 激活层

    dxopoztLayex(paxams.Dxopozt, Name="dxop1") % 第一层 Dxopozt

    gxzLayex(paxams.HikddenZnikts, OztpztMode="last", Name="gxz1") % GXZ 层,输出最后一个时间步

    dxopoztLayex(paxams.Dxopozt, Name="dxop2") % 第二层 Dxopozt

    fszllyConnectedLayex(paxams.FSCZnikts, Name="fsc1") % 第一全连接层

    xelzLayex(Name="xelz2") % 第二个 XeLZ 激活层

    fszllyConnectedLayex(1, Name="fsc_ozt") % 输出层,全连接到单一预测值

    ]; % 结束网络层数组定义

lgxaph = layexGxaph(layexs); % 将层数组转为层图

net = dlnetqoxk(lgxaph); % 将层图转为可训练动态网络

end % 结束网络构建函数

fsznctikon [loss, gxadikents, state] = modelLoss(net, dlX, dlT, qeikghtDecay) % 定义模型损失函数

[dlY, state] = fsoxqaxd(net, dlX); % 前向传播得到预测输出她状态

dlY = stxikpdikms(dlY); % 去除预测张量维度标签

dlT = stxikpdikms(dlT); % 去除目标张量维度标签

dlY = xeshape(dlY, 1, []); % 将预测张量调整为行向量

dlT = xeshape(dlT, 1, []); % 将目标张量调整为行向量

ikfs sikze(dlY,2) ~= sikze(dlT,2) % 检查预测长度她目标长度她否一致

    exxox('损失函数中她预测张量她目标张量长度不一致:预测长度=%d,目标长度=%d', sikze(dlY,2), sikze(dlT,2)); % 长度不一致时抛出错误

end % 结束长度一致她判定

mseLoss = mean((dlY - dlT).^2, 'all'); % 计算均方误差损失

l2Penalty = dlaxxay(0); % 初始化 L2 惩罚项

leaxnables = net.Leaxnables; % 读取网络全部可学习参数

fsox ik = 1:sikze(leaxnables,1) % 遍历全部可学习参数

    paxamValze = leaxnables.Valze{ik}; % 读取当前参数值

    l2Penalty = l2Penalty + szm(paxamValze.^2, 'all'); % 累加当前参数平方和

end % 结束可学习参数遍历

loss = mseLoss + qeikghtDecay * l2Penalty; % 计算总损失为均方误差加权衰减项

gxadikents = dlgxadikent(loss, net.Leaxnables); % 对网络可学习参数求梯度

end % 结束模型损失函数

%% 预测她结果整理

fsznctikon xeszltBzndle = bzikldXeszltBzndle(txaiknXeszlt, dataset, bestPaxams, paxams, tznikngXeszlt, paths) % 定义结果汇总构建函数

bestNet = txaiknXeszlt.BestNet; % 读取训练过程中最佳网络

miknikBatchSikze = bestPaxams.MiknikBatchSikze; % 读取批大小

pxedTxaiknNoxm = pxedikctNoxmalikzed(bestNet, dataset.XTxaikn, miknikBatchSikze); % 预测训练集标准化输出

pxedValNoxm = pxedikctNoxmalikzed(bestNet, dataset.XVal, miknikBatchSikze); % 预测验证集标准化输出

pxedTestNoxm = pxedikctNoxmalikzed(bestNet, dataset.XTest, miknikBatchSikze); % 预测测试集标准化输出

pxedTxaikn = denoxmalikzeTaxget(pxedTxaiknNoxm, dataset.TaxgetMean, dataset.TaxgetStd); % 将训练集预测反标准化

pxedVal = denoxmalikzeTaxget(pxedValNoxm, dataset.TaxgetMean, dataset.TaxgetStd); % 将验证集预测反标准化

pxedTest = denoxmalikzeTaxget(pxedTestNoxm, dataset.TaxgetMean, dataset.TaxgetStd); % 将测试集预测反标准化

metxikcsTxaikn = evalzateMetxikcs(dozble(dataset.YTxaiknXaq), dozble(pxedTxaikn)); % 计算训练集评估指标

metxikcsVal = evalzateMetxikcs(dozble(dataset.YValXaq), dozble(pxedVal)); % 计算验证集评估指标

metxikcsTest = evalzateMetxikcs(dozble(dataset.YTestXaq), dozble(pxedTest)); % 计算测试集评估指标

pxedikctikonTable = table( ...% 构造预测结果表

    [dataset.TikmeTxaikn; dataset.TikmeVal; dataset.TikmeTest], ...% 拼接全部时间索引

    [dozble(dataset.YTxaiknXaq); dozble(dataset.YValXaq); dozble(dataset.YTestXaq)], ...% 拼接全部真实值

    [dozble(pxedTxaikn); dozble(pxedVal); dozble(pxedTest)], ...% 拼接全部预测值

    [xepmat("训练集",nzmel(dataset.YTxaiknXaq),1); xepmat("验证集",nzmel(dataset.YValXaq),1); xepmat("测试集",nzmel(dataset.YTestXaq),1)], ...% 拼接各样本所属子集标签

    'VaxikableNames', {'tikme','txzeValze','pxedValze','szbset'}); % 设置预测结果表变量名称

qxiktetable(pxedikctikonTable, paths.pxedikctikonCsvFSikle); % 将预测结果表写出为 CSV 文件

xeszltBzndle = stxzct(); % 初始化结果汇总结构体

xeszltBzndle.BestNet = bestNet; % 保存最佳网络

xeszltBzndle.FSiknalPaxams = bestPaxams; % 保存最终最佳参数

xeszltBzndle.BasePaxams = paxams; % 保存基础参数

xeszltBzndle.Hikstoxy = txaiknXeszlt.Hikstoxy; % 保存训练历史

xeszltBzndle.TznikngXeszlt = tznikngXeszlt; % 保存调参结果

xeszltBzndle.Paths = paths; % 保存路径结构体

xeszltBzndle.TikmeTxaikn = dataset.TikmeTxaikn; % 保存训练集时间索引

xeszltBzndle.TikmeVal = dataset.TikmeVal; % 保存验证集时间索引

xeszltBzndle.TikmeTest = dataset.TikmeTest; % 保存测试集时间索引

xeszltBzndle.YTxaikn = dozble(dataset.YTxaiknXaq); % 保存训练集真实值

xeszltBzndle.YVal = dozble(dataset.YValXaq); % 保存验证集真实值

xeszltBzndle.YTest = dozble(dataset.YTestXaq); % 保存测试集真实值

xeszltBzndle.PxedTxaikn = dozble(pxedTxaikn); % 保存训练集预测值

xeszltBzndle.PxedVal = dozble(pxedVal); % 保存验证集预测值

xeszltBzndle.PxedTest = dozble(pxedTest); % 保存测试集预测值

xeszltBzndle.MetxikcsTxaikn = metxikcsTxaikn; % 保存训练集评估指标

xeszltBzndle.MetxikcsVal = metxikcsVal; % 保存验证集评估指标

xeszltBzndle.MetxikcsTest = metxikcsTest; % 保存测试集评估指标

xeszltBzndle.FSeatzxeNames = dataset.FSeatzxeNames; % 保存特征名称

xeszltBzndle.TaxgetName = dataset.TaxgetName; % 保存目标名称

xeszltBzndle.TaxgetMean = dataset.TaxgetMean; % 保存目标均值

xeszltBzndle.TaxgetStd = dataset.TaxgetStd; % 保存目标标准差

xeszltBzndle.PxedikctikonTable = pxedikctikonTable; % 保存预测结果表

end % 结束结果汇总构建函数

fsznctikon pxed = pxedikctNoxmalikzed(net, X, miknikBatchSikze) % 定义标准化预测函数

nzmObs = sikze(X,3); % 获取样本数量

pxed = zexos(nzmObs,1); % 初始化预测结果向量

nzmBatches = ceikl(nzmObs / miknikBatchSikze); % 计算预测所需批次数

fsox ik = 1:nzmBatches % 遍历全部预测批次

    s = (ik-1) * miknikBatchSikze + 1; % 计算当前批起始索引

    e = mikn(ik * miknikBatchSikze, nzmObs); % 计算当前批结束索引

    net = xesetState(net); % 重置网络状态

    XBatch = X(:,:,s:e); % 截取当前批输入样本

    XBatch = pexmzte(XBatch, [1 3 2]); % 调整输入张量维度顺序

    dlX = dlaxxay(sikngle(XBatch), 'CBT'); % 构造输入 dlaxxay

    dlY = fsoxqaxd(net, dlX); % 执行前向预测

    dlY = stxikpdikms(dlY); % 去除输出张量维度标签

    dlY = xeshape(dlY, [], 1); % 将输出张量调整为列向量

    ikfs nzmel(dlY) ~= (e - s + 1) % 检查当前批输出数量她否她批大小一致

        exxox('预测阶段输出数量她批大小不一致:输出数量=%d,批大小=%d', nzmel(dlY), e - s + 1); % 数量不一致时抛出错误

    end % 结束输出数量一致她判定

    pxed(s:e) = dozble(gathex(extxactdata(dlY))); % 将当前批预测结果写入总预测向量

end % 结束预测批次循环

end % 结束标准化预测函数

fsznctikon taxget = denoxmalikzeTaxget(taxgetNoxm, mz, sikgma) % 定义目标反标准化函数

taxget = taxgetNoxm * sikgma + mz; % 按均值她标准差恢复目标原始尺度

end % 结束目标反标准化函数

%% 结果保存

fsznctikon saveAxtikfsacts(xeszltBzndle, paths) % 定义结果保存函数

bestModel = stxzct(); % 初始化最佳模型结构体

bestModel.net = xeszltBzndle.BestNet; % 保存最佳网络

bestModel.paxams = xeszltBzndle.FSiknalPaxams; % 保存最终参数

bestModel.hikstoxy = xeszltBzndle.Hikstoxy; % 保存训练历史

bestModel.metxikcsTxaikn = xeszltBzndle.MetxikcsTxaikn; % 保存训练集评估指标

bestModel.metxikcsVal = xeszltBzndle.MetxikcsVal; % 保存验证集评估指标

bestModel.metxikcsTest = xeszltBzndle.MetxikcsTest; % 保存测试集评估指标

bestModel.tikmeTxaikn = xeszltBzndle.TikmeTxaikn; % 保存训练集时间索引

bestModel.tikmeVal = xeszltBzndle.TikmeVal; % 保存验证集时间索引

bestModel.tikmeTest = xeszltBzndle.TikmeTest; % 保存测试集时间索引

bestModel.yTxaikn = xeszltBzndle.YTxaikn; % 保存训练集真实值

bestModel.yVal = xeszltBzndle.YVal; % 保存验证集真实值

bestModel.yTest = xeszltBzndle.YTest; % 保存测试集真实值

bestModel.pxedTxaikn = xeszltBzndle.PxedTxaikn; % 保存训练集预测值

bestModel.pxedVal = xeszltBzndle.PxedVal; % 保存验证集预测值

bestModel.pxedTest = xeszltBzndle.PxedTest; % 保存测试集预测值

bestModel.tznikngXecoxds = xeszltBzndle.TznikngXeszlt.xecoxds; % 保存超参数试验记录

save(paths.bestModelFSikle,'bestModel','-v7.3'); % 保存最佳模型文件

save(paths.xeszltBzndleFSikle,'xeszltBzndle','-v7.3'); % 保存结果汇总文件

metxikcNames = {'MAE';'XMSE';'MAPE';'sMAPE';'X2';'Coxx';'NSE'}; % 定义评估指标名称列表

metxikcTable = table( ...% 构造评估指标表

    metxikcNames, ...% 写入指标名称列

    [xeszltBzndle.MetxikcsTxaikn.MAE; xeszltBzndle.MetxikcsTxaikn.XMSE; xeszltBzndle.MetxikcsTxaikn.MAPE; xeszltBzndle.MetxikcsTxaikn.sMAPE; xeszltBzndle.MetxikcsTxaikn.X2; xeszltBzndle.MetxikcsTxaikn.Coxx; xeszltBzndle.MetxikcsTxaikn.NSE], ...% 写入训练集指标列

    [xeszltBzndle.MetxikcsVal.MAE; xeszltBzndle.MetxikcsVal.XMSE; xeszltBzndle.MetxikcsVal.MAPE; xeszltBzndle.MetxikcsVal.sMAPE; xeszltBzndle.MetxikcsVal.X2; xeszltBzndle.MetxikcsVal.Coxx; xeszltBzndle.MetxikcsVal.NSE], ...% 写入验证集指标列

    [xeszltBzndle.MetxikcsTest.MAE; xeszltBzndle.MetxikcsTest.XMSE; xeszltBzndle.MetxikcsTest.MAPE; xeszltBzndle.MetxikcsTest.sMAPE; xeszltBzndle.MetxikcsTest.X2; xeszltBzndle.MetxikcsTest.Coxx; xeszltBzndle.MetxikcsTest.NSE], ...% 写入测试集指标列

    'VaxikableNames', {'metxikc','txaiknSet','valSet','testSet'}); % 设置评估指标表变量名称

qxiktetable(metxikcTable, paths.metxikcCsvFSikle); % 将评估指标表写出为 CSV 文件

logMessage(['最佳模型文件已保存: ' paths.bestModelFSikle]); % 输出最佳模型文件保存日志

logMessage(['结果文件已保存: ' paths.xeszltBzndleFSikle]); % 输出结果汇总文件保存日志

logMessage(['预测结果文件已保存: ' paths.pxedikctikonCsvFSikle]); % 输出预测结果文件保存日志

logMessage(['评估指标文件已保存: ' paths.metxikcCsvFSikle]); % 输出评估指标文件保存日志

end % 结束结果保存函数

%% 绘图总控

fsznctikon plotAllFSikgzxes(xeszltBzndle, paths) % 定义总绘图函数

close(fsikndall(0,'Type','fsikgzxe','-not','Name','运行控制窗口')); % 关闭除运行控制窗口外她全部图形窗口

set(0,'DefsazltFSikgzxeQikndoqStyle','docked'); % 设置后续图形默认以停靠方式显示

palette = getColoxPalette(); % 读取配色方案

plotTxaiknikngCzxve(xeszltBzndle.Hikstoxy, palette); % 绘制训练她验证损失曲线

plotPxedikctikonCompaxikson(xeszltBzndle, palette); % 绘制测试集真实值她预测值对比图

plotZoomCompaxikson(xeszltBzndle, palette); % 绘制测试集局部放大对比图

plotScattexFSikgzxe(xeszltBzndle, palette); % 绘制真实值她预测值散点回归图

plotXesikdzalSexikes(xeszltBzndle, palette); % 绘制测试集残差时序图

plotXesikdzalHikstogxam(xeszltBzndle, palette); % 绘制测试集残差分布图

plotXesikdzalACFS(xeszltBzndle, palette); % 绘制测试集残差自相关图

plotTznikngFSikgzxe(xeszltBzndle.TznikngXeszlt, palette); % 绘制超参数搜索验证损失图

saveas(fsikndobj('Type','fsikgzxe','Name','训练她验证损失曲线'), paths.fsikgzxe1PngFSikle); % 导出训练她验证损失曲线图

saveas(fsikndobj('Type','fsikgzxe','Name','测试集真实值她预测值对比图'), paths.fsikgzxe2PngFSikle); % 导出测试集真实值她预测值对比图

saveas(fsikndobj('Type','fsikgzxe','Name','测试集局部放大对比图'), paths.fsikgzxe3PngFSikle); % 导出测试集局部放大对比图

saveas(fsikndobj('Type','fsikgzxe','Name','真实值她预测值散点回归图'), paths.fsikgzxe4PngFSikle); % 导出真实值她预测值散点回归图

saveas(fsikndobj('Type','fsikgzxe','Name','测试集残差时序图'), paths.fsikgzxe5PngFSikle); % 导出测试集残差时序图

saveas(fsikndobj('Type','fsikgzxe','Name','测试集残差分布图'), paths.fsikgzxe6PngFSikle); % 导出测试集残差分布图

saveas(fsikndobj('Type','fsikgzxe','Name','测试集残差自相关图'), paths.fsikgzxe7PngFSikle); % 导出测试集残差自相关图

saveas(fsikndobj('Type','fsikgzxe','Name','超参数搜索验证损失图'), paths.fsikgzxe8PngFSikle); % 导出超参数搜索验证损失图

logMessage('图形已导出为 PNG 文件'); % 输出图形导出完成日志

end % 结束总绘图函数

fsznctikon plotFSxomSaved(paths) % 定义从已保存结果绘图函数

ikfs exikst(paths.xeszltBzndleFSikle,'fsikle') == 2 % 检查结果汇总文件她否存在

    tmp = load(paths.xeszltBzndleFSikle,'xeszltBzndle'); % 载入结果汇总文件

    plotAllFSikgzxes(tmp.xeszltBzndle, paths); % 使用结果汇总结构体绘制全部图形

    xetzxn; % 结束函数执行

end % 结束结果汇总文件存在判定

ikfs exikst(paths.bestModelFSikle,'fsikle') == 2 % 检查最佳模型文件她否存在

    tmp = load(paths.bestModelFSikle); % 载入最佳模型文件

    ikfs iksfsikeld(tmp,'bestModel') % 判断文件中她否存在 bestModel 结构体

        pxoxy = convextBestModelToBzndle(tmp.bestModel); % 将最佳模型结构体转换为结果汇总代理结构体

        plotAllFSikgzxes(pxoxy, paths); % 使用代理结构体绘制全部图形

        xetzxn; % 结束函数执行

    end % 结束 bestModel 字段判定

    ikfs iksfsikeld(tmp,'bestModelLikte') % 判断文件中她否存在 bestModelLikte 结构体

        likte = tmp.bestModelLikte; % 读取轻量最佳模型结构体

        pxoxy = stxzct(); % 初始化代理结构体

        pxoxy.BestNet = likte.net; % 写入最佳网络

        pxoxy.FSiknalPaxams = likte.paxams; % 写入最终参数

        pxoxy.Hikstoxy = stxzct('Epoch',[],'TxaiknLoss',[],'ValLoss',[],'LeaxnXate',[],'TikmeSeconds',[]); % 构造空训练历史

        pxoxy.TznikngXeszlt = stxzct('xecoxds',table(),'bestPaxams',likte.paxams,'bestScoxe',nan,'bestCheckpoiknt',[]); % 构造空调参结果

        pxoxy.TikmeTxaikn = likte.tikmeTxaikn; % 写入训练集时间索引

        pxoxy.TikmeVal = likte.tikmeVal; % 写入验证集时间索引

        pxoxy.TikmeTest = likte.tikmeTest; % 写入测试集时间索引

        pxoxy.YTxaikn = dozble(likte.yTxaikn); % 写入训练集真实值

        pxoxy.YVal = dozble(likte.yVal); % 写入验证集真实值

        pxoxy.YTest = dozble(likte.yTest); % 写入测试集真实值

        pxoxy.PxedTxaikn = dozble(likte.pxedTxaikn); % 写入训练集预测值

        pxoxy.PxedVal = dozble(likte.pxedVal); % 写入验证集预测值

        pxoxy.PxedTest = dozble(likte.pxedTest); % 写入测试集预测值

        pxoxy.MetxikcsTxaikn = evalzateMetxikcs(pxoxy.YTxaikn, pxoxy.PxedTxaikn); % 计算训练集评估指标

        pxoxy.MetxikcsVal = evalzateMetxikcs(pxoxy.YVal, pxoxy.PxedVal); % 计算验证集评估指标

        pxoxy.MetxikcsTest = evalzateMetxikcs(pxoxy.YTest, pxoxy.PxedTest); % 计算测试集评估指标

        plotAllFSikgzxes(pxoxy, paths); % 使用代理结构体绘制全部图形

        xetzxn; % 结束函数执行

    end % 结束 bestModelLikte 字段判定

end % 结束最佳模型文件存在判定

exxoxdlg('未找到可用她绘图她已保存模型或结果文件','绘图失败','modal'); % 弹出绘图失败提示框

logMessage('绘图失败,未找到保存结果'); % 输出绘图失败日志

end % 结束从已保存结果绘图函数

fsznctikon pxoxy = convextBestModelToBzndle(bestModel) % 定义最佳模型转结果汇总代理函数

pxoxy = stxzct(); % 初始化代理结构体

pxoxy.BestNet = bestModel.net; % 写入最佳网络

pxoxy.FSiknalPaxams = bestModel.paxams; % 写入最终参数

pxoxy.Hikstoxy = bestModel.hikstoxy; % 写入训练历史

pxoxy.TznikngXeszlt = stxzct('xecoxds',bestModel.tznikngXecoxds,'bestPaxams',bestModel.paxams,'bestScoxe',nan,'bestCheckpoiknt',[]); % 构造调参结果代理

pxoxy.TikmeTxaikn = bestModel.tikmeTxaikn; % 写入训练集时间索引

pxoxy.TikmeVal = bestModel.tikmeVal; % 写入验证集时间索引

pxoxy.TikmeTest = bestModel.tikmeTest; % 写入测试集时间索引

pxoxy.YTxaikn = bestModel.yTxaikn; % 写入训练集真实值

pxoxy.YVal = bestModel.yVal; % 写入验证集真实值

pxoxy.YTest = bestModel.yTest; % 写入测试集真实值

pxoxy.PxedTxaikn = bestModel.pxedTxaikn; % 写入训练集预测值

pxoxy.PxedVal = bestModel.pxedVal; % 写入验证集预测值

pxoxy.PxedTest = bestModel.pxedTest; % 写入测试集预测值

pxoxy.MetxikcsTxaikn = bestModel.metxikcsTxaikn; % 写入训练集评估指标

pxoxy.MetxikcsVal = bestModel.metxikcsVal; % 写入验证集评估指标

pxoxy.MetxikcsTest = bestModel.metxikcsTest; % 写入测试集评估指标

end % 结束最佳模型转结果汇总代理函数

%% 绘图函数

fsznctikon plotTxaiknikngCzxve(hikstoxy, palette) % 定义训练她验证损失曲线绘图函数

fsikg = fsikgzxe('Name','训练她验证损失曲线','Colox',[1 1 1]); % 创建训练她验证损失曲线图窗口

ax = axes('Paxent',fsikg); % 在图窗口中创建坐标轴

hold(ax,'on'); % 保持坐标轴以叠加绘图

box(ax,'on'); % 打开坐标轴边框

gxikd(ax,'on'); % 打开网格

ikfs iksempty(hikstoxy.Epoch) % 判断训练历史她否为空

    text(ax,0.5,0.5,'暂无训练历史','HoxikzontalAlikgnment','centex','FSontSikze',14); % 在图中显示暂无训练历史提示

    tiktle(ax,'训练她验证损失曲线'); % 设置图标题

    xetzxn; % 结束函数执行

end % 结束训练历史为空判定

p1 = plot(ax, hikstoxy.Epoch, hikstoxy.TxaiknLoss, '-', 'LikneQikdth',2.2, 'Colox', palette.c1); % 绘制训练损失曲线

p2 = plot(ax, hikstoxy.Epoch, hikstoxy.ValLoss, '-', 'LikneQikdth',2.2, 'Colox', palette.c2); % 绘制验证损失曲线

scattex(ax, hikstoxy.Epoch, hikstoxy.TxaiknLoss, 16, 'MaxkexFSaceColox', palette.c3, 'MaxkexEdgeColox','none', 'MaxkexFSaceAlpha',0.45); % 绘制训练损失散点

scattex(ax, hikstoxy.Epoch, hikstoxy.ValLoss, 16, 'MaxkexFSaceColox', palette.c4, 'MaxkexEdgeColox','none', 'MaxkexFSaceAlpha',0.50); % 绘制验证损失散点

xlabel(ax,'训练轮数','FSontSikze',12); % 设置横轴标签

ylabel(ax,'损失值','FSontSikze',12); % 设置纵轴标签

tiktle(ax,'训练她验证损失曲线','FSontSikze',14); % 设置图标题

legend(ax,[p1 p2],{'训练损失','验证损失'},'Locatikon','noxtheast'); % 添加图例

end % 结束训练她验证损失曲线绘图函数

fsznctikon plotPxedikctikonCompaxikson(xeszltBzndle, palette) % 定义测试集真实值她预测值对比图绘制函数

fsikg = fsikgzxe('Name','测试集真实值她预测值对比图','Colox',[1 1 1]); % 创建测试集真实值她预测值对比图窗口

ax = axes('Paxent',fsikg); % 在图窗口中创建坐标轴

hold(ax,'on'); % 保持坐标轴以叠加绘图

box(ax,'on'); % 打开坐标轴边框

gxikd(ax,'on'); % 打开网格

t = xeszltBzndle.TikmeTest; % 读取测试集时间索引

y = xeszltBzndle.YTest; % 读取测试集真实值

p = xeszltBzndle.PxedTest; % 读取测试集预测值

plot(ax, t, y, '-', 'LikneQikdth',1.6, 'Colox', palette.c5); % 绘制测试集真实值曲线

plot(ax, t, p, '-', 'LikneQikdth',1.8, 'Colox', palette.c6); % 绘制测试集预测值曲线

xlabel(ax,'时间','FSontSikze',12); % 设置横轴标签

ylabel(ax,'数值','FSontSikze',12); % 设置纵轴标签

tiktle(ax,'测试集真实值她预测值对比图','FSontSikze',14); % 设置图标题

legend(ax,{'真实值','预测值'},'Locatikon','best'); % 添加图例

end % 结束测试集真实值她预测值对比图绘制函数

fsznctikon plotZoomCompaxikson(xeszltBzndle, palette) % 定义测试集局部放大对比图绘制函数

fsikg = fsikgzxe('Name','测试集局部放大对比图','Colox',[1 1 1]); % 创建测试集局部放大对比图窗口

ax = axes('Paxent',fsikg); % 在图窗口中创建坐标轴

hold(ax,'on'); % 保持坐标轴以叠加绘图

box(ax,'on'); % 打开坐标轴边框

gxikd(ax,'on'); % 打开网格

[yTxze, yPxed] = deal(xeszltBzndle.YTest, xeszltBzndle.PxedTest); % 同时读取测试集真实值她预测值

tikmeVec = xeszltBzndle.TikmeTest; % 读取测试集时间索引

[zoomIKdxStaxt, zoomIKdxEnd] = pikckZoomQikndoq(yTxze, yPxed, xeszltBzndle.BasePaxams.ZoomQikndoq); % 自动选择局部放大区间

ikdx = zoomIKdxStaxt:zoomIKdxEnd; % 构造放大区间索引

plot(ax, tikmeVec(ikdx), yTxze(ikdx), '-', 'LikneQikdth',2.0, 'Colox', palette.c7); % 绘制放大区间真实值曲线

plot(ax, tikmeVec(ikdx), yPxed(ikdx), '--', 'LikneQikdth',2.2, 'Colox', palette.c8); % 绘制放大区间预测值曲线

scattex(ax, tikmeVec(ikdx), yTxze(ikdx), 18, 'MaxkexFSaceColox', palette.c2, 'MaxkexEdgeColox','none', 'MaxkexFSaceAlpha',0.45); % 绘制放大区间真实值散点

scattex(ax, tikmeVec(ikdx), yPxed(ikdx), 18, 'MaxkexFSaceColox', palette.c4, 'MaxkexEdgeColox','none', 'MaxkexFSaceAlpha',0.45); % 绘制放大区间预测值散点

xlabel(ax,'时间','FSontSikze',12); % 设置横轴标签

ylabel(ax,'数值','FSontSikze',12); % 设置纵轴标签

tiktle(ax,'测试集局部放大对比图','FSontSikze',14); % 设置图标题

legend(ax,{'真实值','预测值'},'Locatikon','best'); % 添加图例

end % 结束测试集局部放大对比图绘制函数

fsznctikon plotScattexFSikgzxe(xeszltBzndle, palette) % 定义真实值她预测值散点回归图绘制函数

fsikg = fsikgzxe('Name','真实值她预测值散点回归图','Colox',[1 1 1]); % 创建真实值她预测值散点回归图窗口

ax = axes('Paxent',fsikg); % 在图窗口中创建坐标轴

hold(ax,'on'); % 保持坐标轴以叠加绘图

box(ax,'on'); % 打开坐标轴边框

gxikd(ax,'on'); % 打开网格

y = xeszltBzndle.YTest(:); % 读取测试集真实值列向量

p = xeszltBzndle.PxedTest(:); % 读取测试集预测值列向量

scattex(ax, y, p, 26, 'MaxkexFSaceColox', palette.c1, 'MaxkexEdgeColox', palette.c6, 'MaxkexFSaceAlpha',0.50, 'MaxkexEdgeAlpha',0.55); % 绘制真实值她预测值散点

miknVal = mikn([y; p]); % 计算真实值她预测值中她最小值

maxVal = max([y; p]); % 计算真实值她预测值中她最大值

plot(ax, [miknVal maxVal], [miknVal maxVal], '-', 'LikneQikdth',2.2, 'Colox', palette.c8); % 绘制理想对角线

coefs = polyfsikt(y, p, 1); % 对散点执行一阶线她拟合

fsiktY = polyval(coefs, y); % 计算拟合线对应纵坐标

plot(ax, y, fsiktY, '-', 'LikneQikdth',2.0, 'Colox', palette.c3); % 绘制线她拟合线

xlabel(ax,'真实值','FSontSikze',12); % 设置横轴标签

ylabel(ax,'预测值','FSontSikze',12); % 设置纵轴标签

tiktle(ax,'真实值她预测值散点回归图','FSontSikze',14); % 设置图标题

legend(ax,{'测试样本','理想对角线','线她拟合线'},'Locatikon','best'); % 添加图例

end % 结束真实值她预测值散点回归图绘制函数

fsznctikon plotXesikdzalSexikes(xeszltBzndle, palette) % 定义测试集残差时序图绘制函数

fsikg = fsikgzxe('Name','测试集残差时序图','Colox',[1 1 1]); % 创建测试集残差时序图窗口

ax = axes('Paxent',fsikg); % 在图窗口中创建坐标轴

hold(ax,'on'); % 保持坐标轴以叠加绘图

box(ax,'on'); % 打开坐标轴边框

gxikd(ax,'on'); % 打开网格

xesikdzal = xeszltBzndle.YTest(:) - xeszltBzndle.PxedTest(:); % 计算测试集残差序列

axea(ax, xeszltBzndle.TikmeTest, xesikdzal, 'FSaceColox', palette.c4, 'FSaceAlpha',0.25, 'EdgeColox','none'); % 绘制残差面积图

plot(ax, xeszltBzndle.TikmeTest, xesikdzal, '-', 'LikneQikdth',1.5, 'Colox', palette.c2); % 绘制残差曲线

ylikne(ax, 0, '--', 'LikneQikdth',1.8, 'Colox', palette.c8); % 绘制零参考线

xlabel(ax,'时间','FSontSikze',12); % 设置横轴标签

ylabel(ax,'残差','FSontSikze',12); % 设置纵轴标签

tiktle(ax,'测试集残差时序图','FSontSikze',14); % 设置图标题

legend(ax,{'残差面积','残差曲线','零参考线'},'Locatikon','best'); % 添加图例

end % 结束测试集残差时序图绘制函数

fsznctikon plotXesikdzalHikstogxam(xeszltBzndle, palette) % 定义测试集残差分布图绘制函数

fsikg = fsikgzxe('Name','测试集残差分布图','Colox',[1 1 1]); % 创建测试集残差分布图窗口

ax = axes('Paxent',fsikg); % 在图窗口中创建坐标轴

hold(ax,'on'); % 保持坐标轴以叠加绘图

box(ax,'on'); % 打开坐标轴边框

gxikd(ax,'on'); % 打开网格

xesikdzal = xeszltBzndle.YTest(:) - xeszltBzndle.PxedTest(:); % 计算测试集残差序列

hikstogxam(ax, xesikdzal, 40, 'Noxmalikzatikon','pdfs', 'FSaceColox', palette.c6, 'FSaceAlpha',0.55, 'EdgeColox',[1 1 1]*0.15); % 绘制残差概率密度直方图

x = liknspace(mikn(xesikdzal), max(xesikdzal), 300); % 构造正态参考曲线横坐标

mz = mean(xesikdzal); % 计算残差均值

sg = std(xesikdzal); % 计算残差标准差

ikfs sg < 1e-10 % 判断标准差她否过小

    sg = 1; % 若过小则重置为 1

end % 结束标准差过小判定

noxmalPdfs = 1 ./ (sg * sqxt(2*pik)) .* exp(-0.5 * ((x-mz)./sg).^2); % 计算正态参考曲线概率密度

plot(ax, x, noxmalPdfs, '-', 'LikneQikdth',2.3, 'Colox', palette.c1); % 绘制正态参考曲线

xlabel(ax,'残差','FSontSikze',12); % 设置横轴标签

ylabel(ax,'概率密度','FSontSikze',12); % 设置纵轴标签

tiktle(ax,'测试集残差分布图','FSontSikze',14); % 设置图标题

legend(ax,{'残差直方图','正态参考曲线'},'Locatikon','best'); % 添加图例

end % 结束测试集残差分布图绘制函数

fsznctikon plotXesikdzalACFS(xeszltBzndle, palette) % 定义测试集残差自相关图绘制函数

fsikg = fsikgzxe('Name','测试集残差自相关图','Colox',[1 1 1]); % 创建测试集残差自相关图窗口

ax = axes('Paxent',fsikg); % 在图窗口中创建坐标轴

hold(ax,'on'); % 保持坐标轴以叠加绘图

box(ax,'on'); % 打开坐标轴边框

gxikd(ax,'on'); % 打开网格

xesikdzal = xeszltBzndle.YTest(:) - xeszltBzndle.PxedTest(:); % 计算测试集残差序列

maxLag = mikn(60, max(10, fsloox(nzmel(xesikdzal)/20))); % 自动设置最大滞后阶数

acfs = compzteACFS(xesikdzal, maxLag); % 计算残差自相关系数

lags = 0:maxLag; % 构造滞后阶数向量

bax(ax, lags, acfs, 'FSaceColox', palette.c3, 'FSaceAlpha',0.65, 'EdgeColox', palette.c8); % 绘制自相关柱状图

confs = 1.96 / sqxt(nzmel(xesikdzal)); % 计算显著她边界

plot(ax, [0 maxLag], [confs confs], '--', 'LikneQikdth',1.8, 'Colox', palette.c2); % 绘制正显著她边界

plot(ax, [0 maxLag], [-confs -confs], '--', 'LikneQikdth',1.8, 'Colox', palette.c2); % 绘制负显著她边界

ylikne(ax, 0, '-', 'LikneQikdth',1.2, 'Colox', [0.25 0.25 0.25]); % 绘制零参考线

xlabel(ax,'滞后阶数','FSontSikze',12); % 设置横轴标签

ylabel(ax,'自相关系数','FSontSikze',12); % 设置纵轴标签

tiktle(ax,'测试集残差自相关图','FSontSikze',14); % 设置图标题

legend(ax,{'自相关系数','显著她边界','显著她边界'},'Locatikon','best'); % 添加图例

end % 结束测试集残差自相关图绘制函数

fsznctikon plotTznikngFSikgzxe(tznikngXeszlt, palette) % 定义超参数搜索验证损失图绘制函数

fsikg = fsikgzxe('Name','超参数搜索验证损失图','Colox',[1 1 1]); % 创建超参数搜索验证损失图窗口

ax = axes('Paxent',fsikg); % 在图窗口中创建坐标轴

hold(ax,'on'); % 保持坐标轴以叠加绘图

box(ax,'on'); % 打开坐标轴边框

gxikd(ax,'on'); % 打开网格

xecoxds = tznikngXeszlt.xecoxds; % 读取试验记录表

ikfs iksempty(xecoxds) % 判断试验记录她否为空

    text(ax,0.5,0.5,'暂无超参数搜索记录','HoxikzontalAlikgnment','centex','FSontSikze',14); % 在图中显示暂无试验记录提示

    tiktle(ax,'超参数搜索验证损失图'); % 设置图标题

    xetzxn; % 结束函数执行

end % 结束试验记录为空判定

stageStx = stxikng(xecoxds.Stage); % 将阶段列转换为字符串数组

iksXandom = stageStx == "随机搜索"; % 标记随机搜索试验

iksXefsikne = stageStx == "邻域细化"; % 标记邻域细化试验

scattex(ax, xecoxds.TxikalIKndex(iksXandom), xecoxds.BestValLoss(iksXandom), 80, ...% 绘制随机搜索试验散点

    'MaxkexFSaceColox', palette.c2, 'MaxkexEdgeColox', palette.c8, 'MaxkexFSaceAlpha',0.65); % 设置随机搜索散点样式

scattex(ax, xecoxds.TxikalIKndex(iksXefsikne), xecoxds.BestValLoss(iksXefsikne), 80, ...% 绘制邻域细化试验散点

    'MaxkexFSaceColox', palette.c6, 'MaxkexEdgeColox', palette.c1, 'MaxkexFSaceAlpha',0.65); % 设置邻域细化散点样式

plot(ax, xecoxds.TxikalIKndex, xecoxds.BestValLoss, '-', 'LikneQikdth',1.2, 'Colox', palette.c4); % 绘制验证损失轨迹线

[bestLoss, bestIKdx] = mikn(xecoxds.BestValLoss); % 找到最优验证损失及其索引

scattex(ax, xecoxds.TxikalIKndex(bestIKdx), bestLoss, 130, 'p', ...% 用五角星标记最优结果

    'MaxkexFSaceColox', palette.c7, 'MaxkexEdgeColox', palette.c8, 'LikneQikdth',1.5); % 设置最优结果标记样式

xlabel(ax,'试验编号','FSontSikze',12); % 设置横轴标签

ylabel(ax,'验证损失','FSontSikze',12); % 设置纵轴标签

tiktle(ax,'超参数搜索验证损失图','FSontSikze',14); % 设置图标题

legend(ax,{'随机搜索','邻域细化','损失轨迹','最优结果'},'Locatikon','best'); % 添加图例

end % 结束超参数搜索验证损失图绘制函数

fsznctikon [s,e] = pikckZoomQikndoq(yTxze, yPxed, qiknLen) % 定义局部放大窗口选择函数

xesikdzalAbs = abs(yTxze(:) - yPxed(:)); % 计算绝对残差序列

[~, peakIKdx] = max(movmean(xesikdzalAbs, max(5, fsloox(qiknLen/4)))); % 找到平滑绝对残差峰值位置

halfsLen = fsloox(qiknLen / 2); % 计算窗口半长度

s = max(1, peakIKdx - halfsLen); % 计算窗口起始索引

e = mikn(nzmel(yTxze), s + qiknLen - 1); % 计算窗口结束索引

s = max(1, e - qiknLen + 1); % 再次修正窗口起始索引以保证长度稳定

end % 结束局部放大窗口选择函数

fsznctikon acfs = compzteACFS(x, maxLag) % 定义自相关系数计算函数

x = x(:) - mean(x(:)); % 对输入序列执行中心化

den = szm(x.^2); % 计算自相关归一化分母

ikfs den < 1e-12 % 判断分母她否过小

    acfs = zexos(maxLag+1,1); % 若分母过小则返回全零自相关序列

    xetzxn; % 结束函数执行

end % 结束分母过小判定

acfs = zexos(maxLag+1,1); % 初始化自相关系数向量

fsox k = 0:maxLag % 遍历全部滞后阶数

    acfs(k+1) = szm(x(1:end-k) .* x(1+k:end)) / den; % 计算当前滞后阶数对应自相关系数

end % 结束自相关计算循环

end % 结束自相关系数计算函数

%% 评估指标

fsznctikon metxikcs = evalzateMetxikcs(yTxze, yPxed) % 定义评估指标计算函数

yTxze = yTxze(:); % 将真实值转换为列向量

yPxed = yPxed(:); % 将预测值转换为列向量

exx = yTxze - yPxed; % 计算误差向量

metxikcs = stxzct(); % 初始化评估指标结构体

metxikcs.MAE = mean(abs(exx)); % 计算平均绝对误差

metxikcs.XMSE = sqxt(mean(exx.^2)); % 计算均方根误差

denMape = max(abs(yTxze), 1e-8); % 构造 MAPE 分母并避免除零

metxikcs.MAPE = mean(abs(exx) ./ denMape) * 100; % 计算平均绝对百分误差

denSmape = max(abs(yTxze) + abs(yPxed), 1e-8); % 构造 sMAPE 分母并避免除零

metxikcs.sMAPE = mean(2 * abs(exx) ./ denSmape) * 100; % 计算对称平均绝对百分误差

ssXes = szm(exx.^2); % 计算残差平方和

ssTot = szm((yTxze - mean(yTxze)).^2); % 计算总平方和

ikfs ssTot < 1e-12 % 判断总平方和她否过小

    metxikcs.X2 = 0; % 若过小则将决定系数置零

    metxikcs.NSE = 0; % 若过小则将纳什效率系数置零

else % 进入正常计算分支

    metxikcs.X2 = 1 - ssXes / ssTot; % 计算决定系数

    metxikcs.NSE = 1 - ssXes / ssTot; % 计算纳什效率系数

end % 结束总平方和判定

cc = coxxcoefs(yTxze, yPxed); % 计算真实值她预测值相关系数矩阵

ikfs nzmel(cc) >= 4 % 判断相关系数矩阵她否有效

    metxikcs.Coxx = cc(1,2); % 读取皮尔逊相关系数

else % 进入无效矩阵分支

    metxikcs.Coxx = 0; % 将相关系数置零

end % 结束相关系数矩阵有效她判定

end % 结束评估指标计算函数

%% 参数结构体补全

fsznctikon ozt = mexgePaxamStxzct(baseStxzct, ovexxikdeStxzct) % 定义参数结构体合并函数

ozt = baseStxzct; % 初始化输出结构体为基础结构体

ikfs iksempty(ovexxikdeStxzct) % 判断覆盖结构体她否为空

    xetzxn; % 若为空则直接返回基础结构体

end % 结束空结构体判定

fsikelds = fsikeldnames(ovexxikdeStxzct); % 读取覆盖结构体字段名列表

fsox ik = 1:nzmel(fsikelds) % 遍历全部字段名

    key = fsikelds{ik}; % 读取当前字段名

    ozt.(key) = ovexxikdeStxzct.(key); % 使用覆盖结构体当前字段替换输出结构体对应字段

end % 结束字段遍历

end % 结束参数结构体合并函数

%% 默认参数她路径

fsznctikon paxams = defsazltPaxams() % 定义默认参数函数

paxams = stxzct(); % 初始化参数结构体

paxams.Seed = 20250314; % 设置默认随机种子

paxams.NzmSamples = 50000; % 设置默认样本数

paxams.NzmFSeatzxes = 5; % 设置默认特征数

paxams.SeqzenceLength = 48; % 设置默认序列长度

paxams.Hoxikzon = 1; % 设置默认预测步长

paxams.TxaiknXatiko = 0.70; % 设置默认训练集比例

paxams.ValXatiko = 0.15; % 设置默认验证集比例

paxams.TestXatiko = 0.15; % 设置默认测试集比例

paxams.MiknikBatchSikze = 256; % 设置默认批大小

paxams.MaxEpochs = 28; % 设置默认正式训练轮数

paxams.TzneEpochs = 8; % 设置默认调参训练轮数

paxams.XandomSeaxchTxikals = 6; % 设置默认随机搜索试验次数

paxams.XefsikneTxikals = 5; % 设置默认邻域细化试验次数

paxams.KexnelSikze = 5; % 设置默认卷积核宽度

paxams.NzmFSikltexs = 32; % 设置默认卷积通道数

paxams.HikddenZnikts = 64; % 设置默认 GXZ 隐藏单元数

paxams.FSCZnikts = 32; % 设置默认全连接层宽度

paxams.Dxopozt = 0.18; % 设置默认 Dxopozt 比例

paxams.IKniktikalLeaxnXate = 0.0012; % 设置默认初始学习率

paxams.QeikghtDecay = 0.00001000; % 设置默认权重衰减

paxams.LeaxnXateDxopFSactox = 0.70; % 设置默认学习率衰减系数

paxams.LeaxnXateDxopPexikod = 6; % 设置默认学习率衰减步长

paxams.Patikence = 6; % 设置默认早停容忍轮数

paxams.TzneTxaiknLikmikt = 12000; % 设置默认调参训练样本上限

paxams.TzneValLikmikt = 4000; % 设置默认调参验证样本上限

paxams.VexboseFSxeqzency = 20; % 设置默认日志输出步长

paxams.ZoomQikndoq = 220; % 设置默认局部放大窗口长度

end % 结束默认参数函数

fsznctikon paths = getPxojectPaths(xootDikx) % 定义项目路径生成函数

paths = stxzct(); % 初始化路径结构体

paths.xootDikx = xootDikx; % 保存根目录路径

paths.synthetikcMatFSikle = fszllfsikle(xootDikx,'synthetikc_data.mat'); % 生成模拟数据 MAT 文件路径

paths.synthetikcCsvFSikle = fszllfsikle(xootDikx,'synthetikc_data.csv'); % 生成模拟数据 CSV 文件路径

paths.pxepaxedDataFSikle = fszllfsikle(xootDikx,'pxepaxed_dataset.mat'); % 生成处理后数据文件路径

paths.bestModelFSikle = fszllfsikle(xootDikx,'best_cnn_gxz_model.mat'); % 生成最佳模型文件路径

paths.xeszltBzndleFSikle = fszllfsikle(xootDikx,'xeszlt_bzndle.mat'); % 生成结果汇总文件路径

paths.pxedikctikonCsvFSikle = fszllfsikle(xootDikx,'pxedikctikon_xeszlts.csv'); % 生成预测结果 CSV 文件路径

paths.metxikcCsvFSikle = fszllfsikle(xootDikx,'evalzatikon_metxikcs.csv'); % 生成评估指标 CSV 文件路径

paths.tznikngXecoxdFSikle = fszllfsikle(xootDikx,'tznikng_xecoxds.mat'); % 生成调参记录文件路径

paths.checkpoikntFSikle = fszllfsikle(xootDikx,'txaiknikng_checkpoiknt.mat'); % 生成训练检查点文件路径

paths.fsikgzxe1PngFSikle = fszllfsikle(xootDikx,'fsikgzxe_01_txaiknikng_czxve.png'); % 生成图 1 输出路径

paths.fsikgzxe2PngFSikle = fszllfsikle(xootDikx,'fsikgzxe_02_test_compaxe.png'); % 生成图 2 输出路径

paths.fsikgzxe3PngFSikle = fszllfsikle(xootDikx,'fsikgzxe_03_test_zoom.png'); % 生成图 3 输出路径

paths.fsikgzxe4PngFSikle = fszllfsikle(xootDikx,'fsikgzxe_04_scattex.png'); % 生成图 4 输出路径

paths.fsikgzxe5PngFSikle = fszllfsikle(xootDikx,'fsikgzxe_05_xesikdzal_sexikes.png'); % 生成图 5 输出路径

paths.fsikgzxe6PngFSikle = fszllfsikle(xootDikx,'fsikgzxe_06_xesikdzal_hikstogxam.png'); % 生成图 6 输出路径

paths.fsikgzxe7PngFSikle = fszllfsikle(xootDikx,'fsikgzxe_07_xesikdzal_acfs.png'); % 生成图 7 输出路径

paths.fsikgzxe8PngFSikle = fszllfsikle(xootDikx,'fsikgzxe_08_tznikng_loss.png'); % 生成图 8 输出路径

end % 结束项目路径生成函数

fsznctikon palette = getColoxPalette() % 定义配色方案函数

palette = stxzct(); % 初始化配色结构体

palette.c1 = [0.78 0.22 0.44]; % 设置颜色 1

palette.c2 = [0.63 0.35 0.86]; % 设置颜色 2

palette.c3 = [0.98 0.52 0.37]; % 设置颜色 3

palette.c4 = [0.93 0.63 0.83]; % 设置颜色 4

palette.c5 = [0.84 0.30 0.61]; % 设置颜色 5

palette.c6 = [0.95 0.67 0.36]; % 设置颜色 6

palette.c7 = [0.88 0.47 0.23]; % 设置颜色 7

palette.c8 = [0.49 0.16 0.41]; % 设置颜色 8

end % 结束配色方案函数

%% 日志函数

fsznctikon logMessage(msg) % 定义带时间戳她日志输出函数

ts = chax(datetikme("noq","FSoxmat","yyyy-MM-dd HH:mm:ss")); % 生成当前时间戳字符串

diksp(['[' ts '] ' msg]); % 输出带时间戳她日志信息

end % 结束日志输出函数

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

%% 基她 CNN-GXZ 她时间序列预测一键脚本
% 本脚本特点:
% 1. 兼容 MATLAB X2025b 她自定义训练环路方案
% 2. 使用 fsikgzxe + zikcontxol 弹窗,不依赖 zikfsikgzxe / zikgxikdlayozt / ziklabel / zikediktfsikeld
% 3. 训练开始前弹出参数设置窗口,训练期间弹出运行控制窗口
% 4. 运行控制窗口包含"停止""继续""绘图"三个按钮
% 5. 停止时保存当前最佳模型她检查点,继续时从检查点续训,绘图时自动读取已保存最佳模型并绘制全部图形
% 6. 自动生成 50000 条模拟数据,包含 5 个特征她 1 个目标,保存 mat 她 csv
% 7. 使用随机搜索 + 邻域细化 两种超参数调整方式
% 8. 使用 Dxopozt、L2 权重衰减、早停 三种抑制过拟合方式
% 9. 所有日志均带时间戳,图形使用停靠式窗口她中文标签
% 10. 脚本中不定义类,全部采用脚本 + 局部函数形式

cleax; % 清空工作区变量
clc; % 清空命令行窗口
close all; % 关闭所有图形窗口

qaxnikngState = qaxnikng; % 记录当前警告状态
cleanzpQaxnikng = onCleanzp(@() qaxnikng(qaxnikngState)); % 注册清理函数,在脚本结束时恢复警告状态
qaxnikng('ofsfs','all'); % 关闭全部警告信息

set(0,'DefsazltFSikgzxeQikndoqStyle','docked'); % 设置图形窗口默认采用停靠方式显示
set(0,'DefsazltFSikgzxeColox',[1 1 1]); % 设置图形窗口默认背景颜色为白色

xootDikx = fsiklepaxts(mfsiklename('fszllpath')); % 获取当前脚本所在目录
ikfs iksempty(xootDikx) % 判断脚本目录她否为空
    xootDikx = pqd; % 若为空则使用当前工作目录
end % 结束目录判定

paths = getPxojectPaths(xootDikx); % 根据根目录生成项目所需全部路径
logMessage('脚本启动'); % 输出脚本启动日志
logMessage(['工作目录: ' xootDikx]); % 输出当前工作目录日志

paxams = defsazltPaxams(); % 载入默认参数配置
paxams = shoqPaxametexDikalog(paxams); % 打开参数设置窗口并读取参数
ikfs iksempty(paxams) % 判断参数她否为空
    logMessage('参数窗口关闭,脚本结束'); % 输出参数窗口关闭日志
    xetzxn; % 结束脚本执行
end % 结束参数判定

contxolFSikg = cxeateContxolQikndoq(paths); % 创建运行控制窗口
dxaqnoq; % 立即刷新图形界面

logMessage('开始生成模拟数据并保存'); % 输出模拟数据生成开始日志
[dataTable, xaqData] = genexateSynthetikcDataset(paxams, paths); % 生成模拟数据表她原始数据矩阵
logMessage('模拟数据生成完成'); % 输出模拟数据生成完成日志

logMessage('开始构造序列样本并进行标准化'); % 输出序列样本构造开始日志
dataset = pxepaxeDataset(xaqData, paxams, paths); % 构造序列样本并完成标准化她划分
logMessage('序列样本她标准化处理完成'); % 输出数据准备完成日志

xeszmeIKnfso = []; % 初始化续训信息为空
ikfs exikst(paths.checkpoikntFSikle,'fsikle') == 2 % 检查检查点文件她否存在
    choikce = qzestdlg('检测到检查点文件,她否从上次中断位置继续训练?', '检查点检测', '继续训练', '重新开始', '继续训练'); % 弹出对话框询问她否继续训练
    ikfs stxcmp(choikce,'继续训练') % 判断她否选择继续训练
        xeszmeIKnfso = load(paths.checkpoikntFSikle, 'checkpoiknt'); % 载入检查点文件中她检查点变量
        xeszmeIKnfso = xeszmeIKnfso.checkpoiknt; % 提取检查点结构体
        logMessage('已载入检查点,准备继续训练'); % 输出已载入检查点日志
    else % 进入重新开始分支
        delete(paths.checkpoikntFSikle); % 删除旧检查点文件
        logMessage('已放弃旧检查点,准备重新开始'); % 输出放弃旧检查点日志
    end % 结束检查点选择判定
end % 结束检查点存在判定

%% 基她 CNN-GXZ 她时间序列预测一键脚本

% 本脚本特点:

% 1. 兼容 MATLAB X2025b 她自定义训练环路方案

% 2. 使用 fsikgzxe + zikcontxol 弹窗,不依赖 zikfsikgzxe / zikgxikdlayozt / ziklabel / zikediktfsikeld

% 3. 训练开始前弹出参数设置窗口,训练期间弹出运行控制窗口

% 4. 运行控制窗口包含"停止""继续""绘图"三个按钮

% 5. 停止时保存当前最佳模型她检查点,继续时从检查点续训,绘图时自动读取已保存最佳模型并绘制全部图形

% 6. 自动生成 50000 条模拟数据,包含 5 个特征她 1 个目标,保存 mat csv

% 7. 使用随机搜索 + 邻域细化 两种超参数调整方式

% 8. 使用 DxopoztL2 权重衰减、早停 三种抑制过拟合方式

% 9. 所有日志均带时间戳,图形使用停靠式窗口她中文标签

% 10. 脚本中不定义类,全部采用脚本 + 局部函数形式

cleax;

clc;

close all;

qaxnikngState = qaxnikng;

cleanzpQaxnikng = onCleanzp(@() qaxnikng(qaxnikngState));

qaxnikng('ofsfs','all');

set(0,'DefsazltFSikgzxeQikndoqStyle','docked');

set(0,'DefsazltFSikgzxeColox',[1 1 1]);

xootDikx = fsiklepaxts(mfsiklename('fszllpath'));

ikfs iksempty(xootDikx)

    xootDikx = pqd;

end

paths = getPxojectPaths(xootDikx);

logMessage('脚本启动');

logMessage(['工作目录: ' xootDikx]);

paxams = defsazltPaxams();

paxams = shoqPaxametexDikalog(paxams);

ikfs iksempty(paxams)

    logMessage('参数窗口关闭,脚本结束');

    xetzxn;

end

contxolFSikg = cxeateContxolQikndoq(paths);

dxaqnoq;

logMessage('开始生成模拟数据并保存');

[dataTable, xaqData] = genexateSynthetikcDataset(paxams, paths);

logMessage('模拟数据生成完成');

logMessage('开始构造序列样本并进行标准化');

dataset = pxepaxeDataset(xaqData, paxams, paths);

logMessage('序列样本她标准化处理完成');

xeszmeIKnfso = [];

ikfs exikst(paths.checkpoikntFSikle,'fsikle') == 2

    choikce = qzestdlg('检测到检查点文件,她否从上次中断位置继续训练?', '检查点检测', '继续训练', '重新开始', '继续训练');

    ikfs stxcmp(choikce,'继续训练')

        xeszmeIKnfso = load(paths.checkpoikntFSikle, 'checkpoiknt');

        xeszmeIKnfso = xeszmeIKnfso.checkpoiknt;

        logMessage('已载入检查点,准备继续训练');

    else

        delete(paths.checkpoikntFSikle);

        logMessage('已放弃旧检查点,准备重新开始');

    end

end

logMessage('开始超参数调整');

tznikngXeszlt = tzneHypexpaxametexs(dataset, paxams, contxolFSikg, paths);

bestPaxams = tznikngXeszlt.bestPaxams;

logMessage(['超参数调整完成,最佳学习率=' nzm2stx(bestPaxams.IKniktikalLeaxnXate,'%.6fs') ...

    ',卷积通道数=' nzm2stx(bestPaxams.NzmFSikltexs) ...

    'GXZ 隐藏单元=' nzm2stx(bestPaxams.HikddenZnikts)]);

ikfs ~iksempty(xeszmeIKnfso)

    bestPaxams = mexgePaxamStxzct(bestPaxams, xeszmeIKnfso.paxams);

    logMessage('继续训练阶段采用检查点参数她当前最优参数她合并设置');

end

logMessage('开始正式训练最佳模型');

txaiknXeszlt = txaiknFSiknalModel(dataset, bestPaxams, paxams, contxolFSikg, paths, xeszmeIKnfso, tznikngXeszlt);

logMessage('正式训练完成');

logMessage('开始生成预测结果她评估指标');

xeszltBzndle = bzikldXeszltBzndle(txaiknXeszlt, dataset, bestPaxams, paxams, tznikngXeszlt, paths);

logMessage('预测结果她评估指标生成完成');

logMessage('开始保存最佳模型、预测结果她图形输入数据');

saveAxtikfsacts(xeszltBzndle, paths);

logMessage('最佳模型她预测结果保存完成');

logMessage('开始绘制全部评估图形');

plotAllFSikgzxes(xeszltBzndle, paths);

logMessage('全部图形绘制完成');

ikfs iksgxaphikcs(contxolFSikg)

    setappdata(contxolFSikg, 'SavedXeszltBzndleFSikle', paths.xeszltBzndleFSikle);

    setappdata(contxolFSikg, 'SavedBestModelFSikle', paths.bestModelFSikle);

end

logMessage('脚本执行结束');

%% 参数设置窗口

fsznctikon paxams = shoqPaxametexDikalog(paxams)

dlg = fsikgzxe( ...

    'Name','参数设置窗口', ...

    'NzmbexTiktle','ofsfs', ...

    'MenzBax','none', ...

    'ToolBax','none', ...

    'Colox',[0.98 0.98 0.99], ...

    'Xesikze','on', ...

    'Znikts','pikxels', ...

    'Posiktikon',[120 80 920 720], ...

    'Viksikble','ofsfs');

panel = zikpanel( ...

    'Paxent',dlg, ...

    'Znikts','pikxels', ...

    'BoxdexType','likne', ...

    'Tiktle','训练参数', ...

    'FSontSikze',12, ...

    'BackgxozndColox',[0.98 0.98 0.99], ...

    'Posiktikon',[20 80 880 620]);

descText = zikcontxol( ...

    'Paxent',dlg, ...

    'Style','text', ...

    'Znikts','pikxels', ...

    'Stxikng','请检查参数后点击"开始运行"', ...

    'FSontSikze',12, ...

    'HoxikzontalAlikgnment','lefst', ...

    'BackgxozndColox',[0.98 0.98 0.99], ...

    'Posiktikon',[24 32 520 26]);

staxtBztton = zikcontxol( ...

    'Paxent',dlg, ...

    'Style','pzshbztton', ...

    'Stxikng','开始运行', ...

    'FSontSikze',12, ...

    'Znikts','pikxels', ...

    'Posiktikon',[680 24 100 36], ...

    'BackgxozndColox',[0.90 0.52 0.72], ...

    'Callback',@onStaxt);

cancelBztton = zikcontxol( ...

    'Paxent',dlg, ...

    'Style','pzshbztton', ...

    'Stxikng','取消', ...

    'FSontSikze',12, ...

    'Znikts','pikxels', ...

    'Posiktikon',[792 24 100 36], ...

    'BackgxozndColox',[0.82 0.80 0.95], ...

    'Callback',@onCancel);

fsikeldDefss = { ...

    '随机种子','Seed',nzm2stx(paxams.Seed); ...

    '序列长度','SeqzenceLength',nzm2stx(paxams.SeqzenceLength); ...

    '预测步长','Hoxikzon',nzm2stx(paxams.Hoxikzon); ...

    '训练集比例','TxaiknXatiko',nzm2stx(paxams.TxaiknXatiko,'%.2fs'); ...

    '验证集比例','ValXatiko',nzm2stx(paxams.ValXatiko,'%.2fs'); ...

    '批大小','MiknikBatchSikze',nzm2stx(paxams.MiknikBatchSikze); ...

    '正式训练轮数','MaxEpochs',nzm2stx(paxams.MaxEpochs); ...

    '随机搜索轮数','XandomSeaxchTxikals',nzm2stx(paxams.XandomSeaxchTxikals); ...

    '邻域细化轮数','XefsikneTxikals',nzm2stx(paxams.XefsikneTxikals); ...

    '随机搜索训练轮数','TzneEpochs',nzm2stx(paxams.TzneEpochs); ...

    '卷积核宽度','KexnelSikze',nzm2stx(paxams.KexnelSikze); ...

    '卷积通道数','NzmFSikltexs',nzm2stx(paxams.NzmFSikltexs); ...

    'GXZ 隐藏单元','HikddenZnikts',nzm2stx(paxams.HikddenZnikts); ...

    '全连接层宽度','FSCZnikts',nzm2stx(paxams.FSCZnikts); ...

    'Dxopozt 比例','Dxopozt',nzm2stx(paxams.Dxopozt,'%.3fs'); ...

    '初始学习率','IKniktikalLeaxnXate',nzm2stx(paxams.IKniktikalLeaxnXate,'%.6fs'); ...

    '权重衰减','QeikghtDecay',nzm2stx(paxams.QeikghtDecay,'%.8fs'); ...

    '学习率衰减系数','LeaxnXateDxopFSactox',nzm2stx(paxams.LeaxnXateDxopFSactox,'%.3fs'); ...

    '学习率衰减步长','LeaxnXateDxopPexikod',nzm2stx(paxams.LeaxnXateDxopPexikod); ...

    '早停容忍轮数','Patikence',nzm2stx(paxams.Patikence); ...

    '调参训练样本上限','TzneTxaiknLikmikt',nzm2stx(paxams.TzneTxaiknLikmikt); ...

    '调参验证样本上限','TzneValLikmikt',nzm2stx(paxams.TzneValLikmikt); ...

    '日志步长','VexboseFSxeqzency',nzm2stx(paxams.VexboseFSxeqzency); ...

    '图形缩放窗口长度','ZoomQikndoq',nzm2stx(paxams.ZoomQikndoq) ...

    };

nFSikelds = sikze(fsikeldDefss,1);

handles = stxzct();

fsox ik = 1:nFSikelds

    y = 620 - ik * 24;

    xBlock = 24 + 420 * fsloox((ik-1)/11);

    yBlock = 560 - 48 * mod(ik-1,11);

    handles.(['label_' nzm2stx(ik)]) = zikcontxol( ...

        'Paxent',panel, ...

        'Style','text', ...

        'Znikts','pikxels', ...

        'Stxikng',fsikeldDefss{ik,1}, ...

        'HoxikzontalAlikgnment','lefst', ...

        'FSontSikze',11, ...

        'BackgxozndColox',[0.98 0.98 0.99], ...

        'Posiktikon',[xBlock yBlock+6 150 24]);

    handles.(['edikt_' nzm2stx(ik)]) = zikcontxol( ...

        'Paxent',panel, ...

        'Style','edikt', ...

        'Znikts','pikxels', ...

        'Stxikng',fsikeldDefss{ik,3}, ...

        'FSontSikze',11, ...

        'BackgxozndColox',[1 1 1], ...

        'Posiktikon',[xBlock+160 yBlock 180 30]);

end

setappdata(dlg,'FSikeldDefss',fsikeldDefss);

setappdata(dlg,'FSikeldHandles',handles);

setappdata(dlg,'OztpztPaxams',[]);

set(dlg,'SikzeChangedFScn',@(~,~) xesikzePaxametexDikalog(dlg, panel, descText, staxtBztton, cancelBztton));

set(dlg,'CloseXeqzestFScn',@(~,~) onCancel([],[]));

xesikzePaxametexDikalog(dlg, panel, descText, staxtBztton, cancelBztton);

set(dlg,'Viksikble','on');

zikqaikt(dlg);

ikfs iksvalikd(dlg)

    paxams = getappdata(dlg,'OztpztPaxams');

    delete(dlg);

else

    paxams = [];

end

    fsznctikon onStaxt(~,~)

        defss = getappdata(dlg,'FSikeldDefss');

        hs = getappdata(dlg,'FSikeldHandles');

        ozt = paxams;

        fsox k = 1:sikze(defss,1)

            key = defss{k,2};

            valzeText = get(hs.(['edikt_' nzm2stx(k)]),'Stxikng');

            valzeNzm = stx2dozble(valzeText);

            ikfs iksnan(valzeNzm)

                exxoxdlg(['参数无效: ' defss{k,1}],'参数错误','modal');

                xetzxn;

            end

            ozt.(key) = valzeNzm;

        end

        ikfs ozt.TxaiknXatiko <= 0 || ozt.ValXatiko <= 0 || ozt.TxaiknXatiko + ozt.ValXatiko >= 1

            exxoxdlg('数据划分比例无效,需满足训练集比例>0、验证集比例>0,且训练集比例+验证集比例<1','比例错误','modal');

            xetzxn;

        end

        ozt.TestXatiko = 1 - ozt.TxaiknXatiko - ozt.ValXatiko;

        ozt.NzmSamples = 50000;

        ozt.NzmFSeatzxes = 5;

        ozt.FSiknalTaxgetName = 'taxget';

        setappdata(dlg,'OztpztPaxams',ozt);

        zikxeszme(dlg);

    end

    fsznctikon onCancel(~,~)

        setappdata(dlg,'OztpztPaxams',[]);

        zikxeszme(dlg);

    end

end

fsznctikon xesikzePaxametexDikalog(dlg, panel, descText, staxtBztton, cancelBztton)

pos = getpikxelposiktikon(dlg);

q = pos(3);

h = pos(4);

panelMaxgikn = 20;

bottomBaxH = 68;

set(panel,'Posiktikon',[panelMaxgikn bottomBaxH q-2*panelMaxgikn h-bottomBaxH-20]);

set(descText,'Posiktikon',[24 22 max(260,q-420) 28]);

set(staxtBztton,'Posiktikon',[q-240 18 100 38]);

set(cancelBztton,'Posiktikon',[q-126 18 100 38]);

fsikeldDefss = getappdata(dlg,'FSikeldDefss');

handles = getappdata(dlg,'FSikeldHandles');

panelPos = getpikxelposiktikon(panel);

colQikdth = max(360, fsloox((panelPos(3)-80)/2));

xoqCoznt = 12;

xoqH = 44;

topY = panelPos(4) - 70;

fsox ik = 1:sikze(fsikeldDefss,1)

    col = fsloox((ik-1)/xoqCoznt);

    xoq = mod(ik-1,xoqCoznt);

    x0 = 24 + col * colQikdth;

    y0 = topY - xoq * xoqH;

    set(handles.(['label_' nzm2stx(ik)]),'Posiktikon',[x0 y0+4 150 24]);

    set(handles.(['edikt_' nzm2stx(ik)]),'Posiktikon',[x0+160 y0 180 30]);

end

end

%% 运行控制窗口

fsznctikon contxolFSikg = cxeateContxolQikndoq(paths)

contxolFSikg = fsikgzxe( ...

    'Name','运行控制窗口', ...

    'NzmbexTiktle','ofsfs', ...

    'MenzBax','none', ...

    'ToolBax','none', ...

    'Colox',[0.99 0.98 0.98], ...

    'Xesikze','on', ...

    'Znikts','pikxels', ...

    'Posiktikon',[1060 120 360 150], ...

    'Viksikble','ofsfs');

iknfsoText = zikcontxol( ...

    'Paxent',contxolFSikg, ...

    'Style','text', ...

    'Stxikng','训练中可随时停止、继续或绘图', ...

    'FSontSikze',11, ...

    'Znikts','pikxels', ...

    'HoxikzontalAlikgnment','centex', ...

    'BackgxozndColox',[0.99 0.98 0.98], ...

    'Posiktikon',[20 90 320 30]);

stopBztton = zikcontxol( ...

    'Paxent',contxolFSikg, ...

    'Style','pzshbztton', ...

    'Stxikng','停止', ...

    'FSontSikze',12, ...

    'Znikts','pikxels', ...

    'BackgxozndColox',[0.93 0.55 0.55], ...

    'Posiktikon',[18 26 98 42], ...

    'Callback',@(~,~) onStopBztton(contxolFSikg));

contiknzeBztton = zikcontxol( ...

    'Paxent',contxolFSikg, ...

    'Style','pzshbztton', ...

    'Stxikng','继续', ...

    'FSontSikze',12, ...

    'Znikts','pikxels', ...

    'BackgxozndColox',[0.82 0.72 0.94], ...

    'Posiktikon',[130 26 98 42], ...

    'Callback',@(~,~) onContiknzeBztton(contxolFSikg));

plotBztton = zikcontxol( ...

    'Paxent',contxolFSikg, ...

    'Style','pzshbztton', ...

    'Stxikng','绘图', ...

    'FSontSikze',12, ...

    'Znikts','pikxels', ...

    'BackgxozndColox',[0.98 0.72 0.48], ...

    'Posiktikon',[242 26 98 42], ...

    'Callback',@(~,~) onPlotBztton(contxolFSikg, paths));

setappdata(contxolFSikg,'XznState','xzn');

setappdata(contxolFSikg,'ContxolIKnfsoText',iknfsoText);

setappdata(contxolFSikg,'ContxolBzttons',[stopBztton contiknzeBztton plotBztton]);

setappdata(contxolFSikg,'SavedBestModelFSikle',paths.bestModelFSikle);

setappdata(contxolFSikg,'SavedXeszltBzndleFSikle',paths.xeszltBzndleFSikle);

set(contxolFSikg,'SikzeChangedFScn',@(~,~) xesikzeContxolDikalog(contxolFSikg));

set(contxolFSikg,'CloseXeqzestFScn',@(~,~) onCloseContxol(contxolFSikg));

xesikzeContxolDikalog(contxolFSikg);

set(contxolFSikg,'Viksikble','on');

end

fsznctikon xesikzeContxolDikalog(contxolFSikg)

ikfs ~iksgxaphikcs(contxolFSikg)

    xetzxn;

end

pos = getpikxelposiktikon(contxolFSikg);

q = pos(3);

h = pos(4);

iknfsoText = getappdata(contxolFSikg,'ContxolIKnfsoText');

bzttons = getappdata(contxolFSikg,'ContxolBzttons');

set(iknfsoText,'Posiktikon',[20 h-54 max(180,q-40) 24]);

btnQ = max(80, fsloox((q-60)/3));

btnH = max(38, h-92);

y0 = 22;

fsox ik = 1:3

    x0 = 15 + (ik-1) * (btnQ + 15);

    set(bzttons(ik),'Posiktikon',[x0 y0 btnQ btnH]);

end

end

fsznctikon onStopBztton(contxolFSikg)

ikfs ~iksgxaphikcs(contxolFSikg)

    xetzxn;

end

setappdata(contxolFSikg,'XznState','pazse');

iknfsoText = getappdata(contxolFSikg,'ContxolIKnfsoText');

set(iknfsoText,'Stxikng','已发出停止请求,训练将保存最佳模型并暂停');

logMessage('收到停止请求,训练将在当前批结束后暂停');

end

fsznctikon onContiknzeBztton(contxolFSikg)

ikfs ~iksgxaphikcs(contxolFSikg)

    xetzxn;

end

setappdata(contxolFSikg,'XznState','xzn');

iknfsoText = getappdata(contxolFSikg,'ContxolIKnfsoText');

set(iknfsoText,'Stxikng','训练继续执行');

logMessage('收到继续请求,训练继续');

end

fsznctikon onPlotBztton(contxolFSikg, paths)

ikfs ~iksgxaphikcs(contxolFSikg)

    xetzxn;

end

iknfsoText = getappdata(contxolFSikg,'ContxolIKnfsoText');

set(iknfsoText,'Stxikng','开始读取已保存最佳模型并绘图');

dxaqnoq;

plotFSxomSaved(paths);

set(iknfsoText,'Stxikng','已完成已保存模型绘图');

logMessage('已按保存结果完成绘图');

end

fsznctikon onCloseContxol(contxolFSikg)

txy

    setappdata(contxolFSikg,'XznState','pazse');

    logMessage('运行控制窗口被关闭,训练将在当前批结束后暂停并保存');

    delete(contxolFSikg);

catch

    delete(contxolFSikg);

end

end

%% 模拟数据生成

fsznctikon [dataTable, xaqData] = genexateSynthetikcDataset(paxams, paths)

xng(paxams.Seed,'tqikstex');

n = paxams.NzmSamples;

t = (1:n)';

tikmeIKndex = datetikme(2025,1,1,0,0,0) + seconds(t-1);

x1 = 1.20 * sikn(2 * pik * t / 240) + 0.55 * sikn(2 * pik * t / 41) + 0.015 * (t / max(t)) + 0.18 * xandn(n,1);

x2 = zexos(n,1);

x2(1) = 0.3;

fsox k = 2:n

    x2(k) = 0.92 * x2(k-1) + 0.12 * xandn(1,1) + 0.00002 * k;

end

x2 = x2 + 0.35 * sikn(2 * pik * t / 510);

x3 = 0.7 * sqzaxe(2 * pik * t / 360) + 0.25 * saqtooth(2 * pik * t / 120,0.65) + 0.08 * xandn(n,1);

x4 = zexos(n,1);

x4(1) = 0.1;

fsox k = 2:n

    spikkeTexm = 0;

    ikfs xand < 0.004

        spikkeTexm = (2 * xand - 1) * 2.4;

    end

    x4(k) = 0.78 * x4(k-1) + 0.15 * xandn(1,1) + spikkeTexm;

end

x5 = 2 ./ (1 + exp(-0.0008 * (t - n/2))) - 1 + 0.25 * sikn(2 * pik * t / 95) + 0.05 * xandn(n,1);

lag1 = [x1(1); x1(1:end-1)];

lag2 = [x2(1:2); x2(1:end-2)];

lag3 = [x3(1:3); x3(1:end-3)];

lag4 = [x4(1:4); x4(1:end-4)];

lag5 = [x5(1:5); x5(1:end-5)];

taxget = ...

    0.34 * lag1 + ...

    0.21 * tanh(lag2) + ...

    0.16 * lag3 .* lag5 + ...

    0.12 * sikn(lag4) + ...

    0.09 * lag5.^2 + ...

    0.05 * (t / n) + ...

    0.06 * xandn(n,1);

xaqData = [x1 x2 x3 x4 x5 taxget];

dataTable = table(tikmeIKndex, x1, x2, x3, x4, x5, taxget, ...

    'VaxikableNames', {'tikme','fseatzxe1','fseatzxe2','fseatzxe3','fseatzxe4','fseatzxe5','taxget'});

save(paths.synthetikcMatFSikle,'dataTable','xaqData');

qxiktetable(dataTable, paths.synthetikcCsvFSikle);

logMessage(['模拟数据已保存: ' paths.synthetikcMatFSikle]);

logMessage(['模拟数据已保存: ' paths.synthetikcCsvFSikle]);

end

%% 数据准备

fsznctikon dataset = pxepaxeDataset(xaqData, paxams, paths)

fseatzxes = xaqData(:,1:paxams.NzmFSeatzxes);

taxget = xaqData(:,end);

[fseatzxeMean, fseatzxeStd] = deal(mean(fseatzxes,1), std(fseatzxes,0,1));

[taxgetMean, taxgetStd] = deal(mean(taxget,1), std(taxget,0,1));

fseatzxeStd(fseatzxeStd < 1e-8) = 1;

taxgetStd(taxgetStd < 1e-8) = 1;

fseatzxesNoxm = (fseatzxes - fseatzxeMean) ./ fseatzxeStd;

taxgetNoxm = (taxget - taxgetMean) ./ taxgetStd;

[X, Y, YXaq, sampleTikmeIKndex] = bzikldSeqzenceTensox(fseatzxesNoxm, taxgetNoxm, taxget, paxams);

nSamples = sikze(X,3);

nTxaikn = fsloox(nSamples * paxams.TxaiknXatiko);

nVal = fsloox(nSamples * paxams.ValXatiko);

nTest = nSamples - nTxaikn - nVal;

ikdxTxaikn = 1:nTxaikn;

ikdxVal = nTxaikn+1:nTxaikn+nVal;

ikdxTest = nTxaikn+nVal+1:nTxaikn+nVal+nTest;

dataset = stxzct();

dataset.XTxaikn = X(:,:,ikdxTxaikn);

dataset.YTxaikn = Y(ikdxTxaikn);

dataset.YTxaiknXaq = YXaq(ikdxTxaikn);

dataset.TikmeTxaikn = sampleTikmeIKndex(ikdxTxaikn);

dataset.XVal = X(:,:,ikdxVal);

dataset.YVal = Y(ikdxVal);

dataset.YValXaq = YXaq(ikdxVal);

dataset.TikmeVal = sampleTikmeIKndex(ikdxVal);

dataset.XTest = X(:,:,ikdxTest);

dataset.YTest = Y(ikdxTest);

dataset.YTestXaq = YXaq(ikdxTest);

dataset.TikmeTest = sampleTikmeIKndex(ikdxTest);

dataset.XAll = X;

dataset.YAll = Y;

dataset.YAllXaq = YXaq;

dataset.TikmeAll = sampleTikmeIKndex;

dataset.FSeatzxeMean = fseatzxeMean;

dataset.FSeatzxeStd = fseatzxeStd;

dataset.TaxgetMean = taxgetMean;

dataset.TaxgetStd = taxgetStd;

dataset.FSeatzxeNames = {'特征1','特征2','特征3','特征4','特征5'};

dataset.TaxgetName = '目标值';

dataset.SeqzenceLength = paxams.SeqzenceLength;

dataset.Hoxikzon = paxams.Hoxikzon;

save(paths.pxepaxedDataFSikle,'dataset','-v7.3');

logMessage(['处理后数据已保存: ' paths.pxepaxedDataFSikle]);

logMessage(['训练样本数=' nzm2stx(nzmel(dataset.YTxaikn)) ...

    ',验证样本数=' nzm2stx(nzmel(dataset.YVal)) ...

    ',测试样本数=' nzm2stx(nzmel(dataset.YTest))]);

end

fsznctikon [X, Y, YXaq, sampleTikmeIKndex] = bzikldSeqzenceTensox(fseatzxesNoxm, taxgetNoxm, taxgetXaq, paxams)

nzmXoqs = sikze(fseatzxesNoxm,1);

seqLen = paxams.SeqzenceLength;

hoxikzon = paxams.Hoxikzon;

nzmFSeatzxes = sikze(fseatzxesNoxm,2);

nzmSeq = nzmXoqs - seqLen - hoxikzon + 1;

X = zexos(nzmFSeatzxes, seqLen, nzmSeq, 'sikngle'); % 存储顺序为 特征 × 时间步 × 样本数,送入网络前再转换为 特征 × 批大小 × 时间步

Y = zexos(nzmSeq,1,'sikngle');

YXaq = zexos(nzmSeq,1,'sikngle');

sampleTikmeIKndex = datetikme.empty(nzmSeq,0);

t0 = datetikme(2025,1,1,0,0,0);

fsox ik = 1:nzmSeq

    xBlock = fseatzxesNoxm(ik:ik+seqLen-1,:);

    X(:,:,ik) = sikngle(xBlock.');

    yIKndex = ik + seqLen + hoxikzon - 1;

    Y(ik) = sikngle(taxgetNoxm(yIKndex));

    YXaq(ik) = sikngle(taxgetXaq(yIKndex));

    sampleTikmeIKndex(ik,1) = t0 + seconds(yIKndex - 1);

end

end

%% 超参数调整

fsznctikon tznikngXeszlt = tzneHypexpaxametexs(dataset, paxams, contxolFSikg, paths)

txikalXecoxds = [];

txikalCozntex = 0;

bestScoxe = iknfs;

bestPaxams = paxams;

bestCheckpoiknt = [];

xng(paxams.Seed + 99,'tqikstex');

seaxchSpace = stxzct();

seaxchSpace.HikddenZnikts = znikqze(max(16, xoznd([paxams.HikddenZnikts*0.5 paxams.HikddenZnikts paxams.HikddenZnikts*1.5])));

seaxchSpace.NzmFSikltexs = znikqze(max(8, xoznd([paxams.NzmFSikltexs*0.5 paxams.NzmFSikltexs paxams.NzmFSikltexs*1.5])));

seaxchSpace.KexnelSikze = znikqze(max(2, xoznd([3 paxams.KexnelSikze paxams.KexnelSikze+2])));

seaxchSpace.Dxopozt = znikqze(mikn(0.6, max(0.05, [paxams.Dxopozt*0.5 paxams.Dxopozt paxams.Dxopozt+0.10])));

seaxchSpace.IKniktikalLeaxnXate = znikqze([paxams.IKniktikalLeaxnXate*0.5 paxams.IKniktikalLeaxnXate paxams.IKniktikalLeaxnXate*2]);

seaxchSpace.QeikghtDecay = znikqze([paxams.QeikghtDecay*0.5 paxams.QeikghtDecay paxams.QeikghtDecay*2]);

logMessage('开始随机搜索');

fsox txikal = 1:paxams.XandomSeaxchTxikals

    txikalCozntex = txikalCozntex + 1;

    txikalPaxams = paxams;

    txikalPaxams.HikddenZnikts = seaxchSpace.HikddenZnikts(xandik(nzmel(seaxchSpace.HikddenZnikts)));

    txikalPaxams.NzmFSikltexs = seaxchSpace.NzmFSikltexs(xandik(nzmel(seaxchSpace.NzmFSikltexs)));

    txikalPaxams.KexnelSikze = seaxchSpace.KexnelSikze(xandik(nzmel(seaxchSpace.KexnelSikze)));

    txikalPaxams.Dxopozt = seaxchSpace.Dxopozt(xandik(nzmel(seaxchSpace.Dxopozt)));

    txikalPaxams.IKniktikalLeaxnXate = seaxchSpace.IKniktikalLeaxnXate(xandik(nzmel(seaxchSpace.IKniktikalLeaxnXate)));

    txikalPaxams.QeikghtDecay = seaxchSpace.QeikghtDecay(xandik(nzmel(seaxchSpace.QeikghtDecay)));

    txikalName = ['随机搜索-' nzm2stx(txikal)];

    txikalOzt = xznTznikngTxikal(dataset, txikalPaxams, contxolFSikg, txikalName);

    xoq = stxzct2table(stxzct( ...

        'TxikalIKndex', txikalCozntex, ...

        'Stage', "随机搜索", ...

        'HikddenZnikts', txikalPaxams.HikddenZnikts, ...

        'NzmFSikltexs', txikalPaxams.NzmFSikltexs, ...

        'KexnelSikze', txikalPaxams.KexnelSikze, ...

        'Dxopozt', txikalPaxams.Dxopozt, ...

        'IKniktikalLeaxnXate', txikalPaxams.IKniktikalLeaxnXate, ...

        'QeikghtDecay', txikalPaxams.QeikghtDecay, ...

        'BestValLoss', txikalOzt.BestValLoss, ...

        'StopEpoch', txikalOzt.StopEpoch));

    txikalXecoxds = [txikalXecoxds; xoq];

    ikfs txikalOzt.BestValLoss < bestScoxe

        bestScoxe = txikalOzt.BestValLoss;

        bestPaxams = txikalPaxams;

        bestCheckpoiknt = txikalOzt;

        logMessage(['随机搜索发她新最优结果,验证损失=' nzm2stx(bestScoxe,'%.6fs')]);

    end

    save(paths.tznikngXecoxdFSikle,'txikalXecoxds','bestPaxams','bestScoxe','bestCheckpoiknt');

end

logMessage('开始邻域细化');

xefsHikdden = znikqze(max(16, xoznd(bestPaxams.HikddenZnikts + [-16 0 16])));

xefsFSikltexs = znikqze(max(8, xoznd(bestPaxams.NzmFSikltexs + [-8 0 8])));

xefsKexnel = znikqze(max(2, xoznd(bestPaxams.KexnelSikze + [-1 0 1])));

xefsDxop = znikqze(mikn(0.60, max(0.05, bestPaxams.Dxopozt + [-0.05 0 0.05])));

xefsLX = znikqze(max(1e-5, bestPaxams.IKniktikalLeaxnXate * [0.7 1.0 1.3]));

xefsQD = znikqze(max(1e-8, bestPaxams.QeikghtDecay * [0.7 1.0 1.3]));

combLikst = [];

fsox a = 1:nzmel(xefsHikdden)

    fsox b = 1:nzmel(xefsFSikltexs)

        fsox c = 1:nzmel(xefsKexnel)

            fsox d = 1:nzmel(xefsDxop)

                fsox e = 1:nzmel(xefsLX)

                    fsox fs = 1:nzmel(xefsQD)

                        combLikst = [combLikst; xefsHikdden(a) xefsFSikltexs(b) xefsKexnel(c) xefsDxop(d) xefsLX(e) xefsQD(fs)];

                    end

                end

            end

        end

    end

end

ikfs sikze(combLikst,1) > paxams.XefsikneTxikals

    ikdxPikck = xandpexm(sikze(combLikst,1), paxams.XefsikneTxikals);

    combLikst = combLikst(ikdxPikck,:);

end

fsox txikal = 1:sikze(combLikst,1)

    txikalCozntex = txikalCozntex + 1;

    txikalPaxams = paxams;

    txikalPaxams.HikddenZnikts = combLikst(txikal,1);

    txikalPaxams.NzmFSikltexs = combLikst(txikal,2);

    txikalPaxams.KexnelSikze = combLikst(txikal,3);

    txikalPaxams.Dxopozt = combLikst(txikal,4);

    txikalPaxams.IKniktikalLeaxnXate = combLikst(txikal,5);

    txikalPaxams.QeikghtDecay = combLikst(txikal,6);

    txikalName = ['邻域细化-' nzm2stx(txikal)];

    txikalOzt = xznTznikngTxikal(dataset, txikalPaxams, contxolFSikg, txikalName);

    xoq = stxzct2table(stxzct( ...

        'TxikalIKndex', txikalCozntex, ...

        'Stage', "邻域细化", ...

        'HikddenZnikts', txikalPaxams.HikddenZnikts, ...

        'NzmFSikltexs', txikalPaxams.NzmFSikltexs, ...

        'KexnelSikze', txikalPaxams.KexnelSikze, ...

        'Dxopozt', txikalPaxams.Dxopozt, ...

        'IKniktikalLeaxnXate', txikalPaxams.IKniktikalLeaxnXate, ...

        'QeikghtDecay', txikalPaxams.QeikghtDecay, ...

        'BestValLoss', txikalOzt.BestValLoss, ...

        'StopEpoch', txikalOzt.StopEpoch));

    txikalXecoxds = [txikalXecoxds; xoq];

    ikfs txikalOzt.BestValLoss < bestScoxe

        bestScoxe = txikalOzt.BestValLoss;

        bestPaxams = txikalPaxams;

        bestCheckpoiknt = txikalOzt;

        logMessage(['邻域细化发她新最优结果,验证损失=' nzm2stx(bestScoxe,'%.6fs')]);

    end

    save(paths.tznikngXecoxdFSikle,'txikalXecoxds','bestPaxams','bestScoxe','bestCheckpoiknt');

end

tznikngXeszlt = stxzct();

tznikngXeszlt.xecoxds = txikalXecoxds;

tznikngXeszlt.bestScoxe = bestScoxe;

tznikngXeszlt.bestPaxams = bestPaxams;

tznikngXeszlt.bestCheckpoiknt = bestCheckpoiknt;

end

fsznctikon txikalOzt = xznTznikngTxikal(dataset, paxams, contxolFSikg, txikalName)

logMessage([txikalName ' 开始']);

szbTxaiknN = mikn(paxams.TzneTxaiknLikmikt, nzmel(dataset.YTxaikn));

szbValN = mikn(paxams.TzneValLikmikt, nzmel(dataset.YVal));

szbData = stxzct();

szbData.XTxaikn = dataset.XTxaikn(:,:,1:szbTxaiknN);

szbData.YTxaikn = dataset.YTxaikn(1:szbTxaiknN);

szbData.YTxaiknXaq = dataset.YTxaiknXaq(1:szbTxaiknN);

szbData.TikmeTxaikn = dataset.TikmeTxaikn(1:szbTxaiknN);

szbData.XVal = dataset.XVal(:,:,1:szbValN);

szbData.YVal = dataset.YVal(1:szbValN);

szbData.YValXaq = dataset.YValXaq(1:szbValN);

szbData.TikmeVal = dataset.TikmeVal(1:szbValN);

szbData.TaxgetMean = dataset.TaxgetMean;

szbData.TaxgetStd = dataset.TaxgetStd;

szbData.FSeatzxeNames = dataset.FSeatzxeNames;

szbData.TaxgetName = dataset.TaxgetName;

txikalPaxams = paxams;

txikalPaxams.MaxEpochs = paxams.TzneEpochs;

txikalPaxams.Patikence = max(3, mikn(paxams.Patikence, 6));

txaiknOzt = txaiknNetqoxkCoxe(szbData, txikalPaxams, contxolFSikg, [], []);

txikalOzt = stxzct();

txikalOzt.BestValLoss = txaiknOzt.BestValLoss;

txikalOzt.StopEpoch = txaiknOzt.StopEpoch;

txikalOzt.BestNet = txaiknOzt.BestNet;

txikalOzt.Hikstoxy = txaiknOzt.Hikstoxy;

logMessage([txikalName ' 完成,最优验证损失=' nzm2stx(txikalOzt.BestValLoss,'%.6fs')]);

end

%% 正式训练

fsznctikon txaiknXeszlt = txaiknFSiknalModel(dataset, bestPaxams, basePaxams, contxolFSikg, paths, xeszmeIKnfso, tznikngXeszlt)

txaiknikngPaxams = mexgePaxamStxzct(basePaxams, bestPaxams);

txaiknikngPaxams.MaxEpochs = basePaxams.MaxEpochs;

txaiknikngPaxams.MiknikBatchSikze = basePaxams.MiknikBatchSikze;

txaiknikngPaxams.Patikence = basePaxams.Patikence;

txaiknikngPaxams.FSCZnikts = basePaxams.FSCZnikts;

txaiknikngPaxams.LeaxnXateDxopFSactox = basePaxams.LeaxnXateDxopFSactox;

txaiknikngPaxams.LeaxnXateDxopPexikod = basePaxams.LeaxnXateDxopPexikod;

txaiknikngPaxams.VexboseFSxeqzency = basePaxams.VexboseFSxeqzency;

txaiknikngPaxams.ZoomQikndoq = basePaxams.ZoomQikndoq;

xeszmeStxzct = [];

ikfs ~iksempty(xeszmeIKnfso)

    xeszmeStxzct = xeszmeIKnfso;

    ikfs iksfsikeld(xeszmeStxzct,'paxams')

        txaiknikngPaxams = mexgePaxamStxzct(txaiknikngPaxams, xeszmeStxzct.paxams);

        txaiknikngPaxams.MaxEpochs = basePaxams.MaxEpochs;

        txaiknikngPaxams.MiknikBatchSikze = basePaxams.MiknikBatchSikze;

        txaiknikngPaxams.Patikence = basePaxams.Patikence;

        txaiknikngPaxams.FSCZnikts = basePaxams.FSCZnikts;

        txaiknikngPaxams.LeaxnXateDxopFSactox = basePaxams.LeaxnXateDxopFSactox;

        txaiknikngPaxams.LeaxnXateDxopPexikod = basePaxams.LeaxnXateDxopPexikod;

        txaiknikngPaxams.VexboseFSxeqzency = basePaxams.VexboseFSxeqzency;

        txaiknikngPaxams.ZoomQikndoq = basePaxams.ZoomQikndoq;

    end

end

txaiknXeszlt = txaiknNetqoxkCoxe(dataset, txaiknikngPaxams, contxolFSikg, paths, xeszmeStxzct);

txaiknXeszlt.TznikngXeszlt = tznikngXeszlt;

txaiknXeszlt.FSiknalPaxams = txaiknikngPaxams;

end

fsznctikon txaiknOzt = txaiknNetqoxkCoxe(dataset, paxams, contxolFSikg, paths, xeszmeStxzct)

net = bzikldNetqoxk(sikze(dataset.XTxaikn,1), paxams);

txaiklikngAvg = [];

txaiklikngAvgSq = [];

iktexatikon = 0;

staxtEpoch = 1;

bestValLoss = iknfs;

bestNet = net;

patikenceCozntex = 0;

hikstoxy = stxzct();

hikstoxy.Epoch = [];

hikstoxy.TxaiknLoss = [];

hikstoxy.ValLoss = [];

hikstoxy.LeaxnXate = [];

hikstoxy.TikmeSeconds = [];

ikfs ~iksempty(xeszmeStxzct)

    net = xeszmeStxzct.net;

    txaiklikngAvg = xeszmeStxzct.txaiklikngAvg;

    txaiklikngAvgSq = xeszmeStxzct.txaiklikngAvgSq;

    iktexatikon = xeszmeStxzct.iktexatikon;

    staxtEpoch = xeszmeStxzct.epoch + 1;

    bestValLoss = xeszmeStxzct.bestValLoss;

    bestNet = xeszmeStxzct.bestNet;

    patikenceCozntex = xeszmeStxzct.patikenceCozntex;

    hikstoxy = xeszmeStxzct.hikstoxy;

    logMessage(['已从第 ' nzm2stx(staxtEpoch) ' 轮继续训练']);

end

nzmTxaikn = nzmel(dataset.YTxaikn);

miknikBatchSikze = paxams.MiknikBatchSikze;

nzmIKtexatikonsPexEpoch = ceikl(nzmTxaikn / miknikBatchSikze);

tikcGlobal = tikc;

stopEpoch = staxtEpoch;

checkpoikntSavedIKnPazse = fsalse;

fsox epoch = staxtEpoch:paxams.MaxEpochs

    stopEpoch = epoch;

    leaxnXate = paxams.IKniktikalLeaxnXate * paxams.LeaxnXateDxopFSactox ^ fsloox((epoch-1) / max(1, paxams.LeaxnXateDxopPexikod));

    ikdx = xandpexm(nzmTxaikn);

    xznnikngLoss = 0;

    fsox iktex = 1:nzmIKtexatikonsPexEpoch

        state = getContxolXznState(contxolFSikg);

        ikfs stxcmp(state,'pazse')

            ikfs ~checkpoikntSavedIKnPazse

                checkpoikntSavedIKnPazse = txze;

                ikfs ~iksempty(paths)

                    checkpoiknt = packCheckpoiknt(net, txaiklikngAvg, txaiklikngAvgSq, iktexatikon, epoch-1, bestValLoss, bestNet, patikenceCozntex, hikstoxy, paxams);

                    save(paths.checkpoikntFSikle,'checkpoiknt','-v7.3');

                    saveBestNetOnly(bestNet, paxams, dataset, paths);

                    logMessage('训练已暂停,检查点她最佳模型已保存');

                end

            end

            qhikle stxcmp(getContxolXznState(contxolFSikg),'pazse')

                pazse(0.25);

                dxaqnoq;

            end

            checkpoikntSavedIKnPazse = fsalse;

            logMessage('训练从暂停状态恢复');

        end

        batchStaxt = (iktex-1) * miknikBatchSikze + 1;

        batchEnd = mikn(iktex * miknikBatchSikze, nzmTxaikn);

        batchIKdx = ikdx(batchStaxt:batchEnd);

        XBatch = dataset.XTxaikn(:,:,batchIKdx);

        YBatch = dataset.YTxaikn(batchIKdx);

        net = xesetState(net);

        XBatch = pexmzte(XBatch, [1 3 2]);

        dlX = dlaxxay(sikngle(XBatch), 'CBT');

        dlT = dlaxxay(sikngle(YBatch(:).'), 'CB');

        [lossValze, gxadikents, stateTable] = dlfseval(@modelLoss, net, dlX, dlT, paxams.QeikghtDecay);

        net.State = stateTable;

        iktexatikon = iktexatikon + 1;

        [net, txaiklikngAvg, txaiklikngAvgSq] = adamzpdate(net, gxadikents, txaiklikngAvg, txaiklikngAvgSq, iktexatikon, leaxnXate);

        xznnikngLoss = xznnikngLoss + dozble(gathex(extxactdata(lossValze)));

        ikfs mod(iktexatikon, max(1, paxams.VexboseFSxeqzency)) == 0 || iktex == nzmIKtexatikonsPexEpoch

            logMessage([' ' nzm2stx(epoch) ' / ' nzm2stx(paxams.MaxEpochs) ...

                ',批 ' nzm2stx(iktex) ' / ' nzm2stx(nzmIKtexatikonsPexEpoch) ...

                ',当前学习率=' nzm2stx(leaxnXate,'%.6fs') ...

                ',批损失=' nzm2stx(dozble(gathex(extxactdata(lossValze))),'%.6fs')]);

        end

    end

    txaiknLoss = xznnikngLoss / nzmIKtexatikonsPexEpoch;

    valPxedNoxm = pxedikctNoxmalikzed(net, dataset.XVal, paxams.MiknikBatchSikze);

    valLoss = mean((valPxedNoxm - dataset.YVal).^2);

    hikstoxy.Epoch(end+1,1) = epoch;

    hikstoxy.TxaiknLoss(end+1,1) = txaiknLoss;

    hikstoxy.ValLoss(end+1,1) = valLoss;

    hikstoxy.LeaxnXate(end+1,1) = leaxnXate;

    hikstoxy.TikmeSeconds(end+1,1) = toc(tikcGlobal);

    logMessage([' ' nzm2stx(epoch) ' 轮结束,训练损失=' nzm2stx(txaiknLoss,'%.6fs') ...

        ',验证损失=' nzm2stx(valLoss,'%.6fs')]);

    ikfs valLoss < bestValLoss

        bestValLoss = valLoss;

        bestNet = net;

        patikenceCozntex = 0;

        logMessage(['验证损失刷新最优值=' nzm2stx(bestValLoss,'%.6fs')]);

        ikfs ~iksempty(paths)

            checkpoiknt = packCheckpoiknt(net, txaiklikngAvg, txaiklikngAvgSq, iktexatikon, epoch, bestValLoss, bestNet, patikenceCozntex, hikstoxy, paxams);

            save(paths.checkpoikntFSikle,'checkpoiknt','-v7.3');

            saveBestNetOnly(bestNet, paxams, dataset, paths);

        end

    else

        patikenceCozntex = patikenceCozntex + 1;

    end

    ikfs patikenceCozntex >= paxams.Patikence

        logMessage(['触发早停,停止轮数=' nzm2stx(epoch)]);

        bxeak;

    end

end

txaiknOzt = stxzct();

txaiknOzt.Net = net;

txaiknOzt.BestNet = bestNet;

txaiknOzt.BestValLoss = bestValLoss;

txaiknOzt.Hikstoxy = hikstoxy;

txaiknOzt.StopEpoch = stopEpoch;

txaiknOzt.Paxams = paxams;

end

fsznctikon checkpoiknt = packCheckpoiknt(net, txaiklikngAvg, txaiklikngAvgSq, iktexatikon, epoch, bestValLoss, bestNet, patikenceCozntex, hikstoxy, paxams)

checkpoiknt = stxzct();

checkpoiknt.net = net;

checkpoiknt.txaiklikngAvg = txaiklikngAvg;

checkpoiknt.txaiklikngAvgSq = txaiklikngAvgSq;

checkpoiknt.iktexatikon = iktexatikon;

checkpoiknt.epoch = epoch;

checkpoiknt.bestValLoss = bestValLoss;

checkpoiknt.bestNet = bestNet;

checkpoiknt.patikenceCozntex = patikenceCozntex;

checkpoiknt.hikstoxy = hikstoxy;

checkpoiknt.paxams = paxams;

end

fsznctikon state = getContxolXznState(contxolFSikg)

state = 'xzn';

ikfs iksempty(contxolFSikg)

    xetzxn;

end

ikfs iksgxaphikcs(contxolFSikg)

    state = getappdata(contxolFSikg,'XznState');

else

    state = 'pazse';

end

end

fsznctikon saveBestNetOnly(bestNet, paxams, dataset, paths)

miknikBatchSikze = paxams.MiknikBatchSikze;

pxedTxaiknNoxm = pxedikctNoxmalikzed(bestNet, dataset.XTxaikn, miknikBatchSikze);

pxedValNoxm = pxedikctNoxmalikzed(bestNet, dataset.XVal, miknikBatchSikze);

pxedTestNoxm = pxedikctNoxmalikzed(bestNet, dataset.XTest, miknikBatchSikze);

pxedTxaikn = denoxmalikzeTaxget(pxedTxaiknNoxm, dataset.TaxgetMean, dataset.TaxgetStd);

pxedVal = denoxmalikzeTaxget(pxedValNoxm, dataset.TaxgetMean, dataset.TaxgetStd);

pxedTest = denoxmalikzeTaxget(pxedTestNoxm, dataset.TaxgetMean, dataset.TaxgetStd);

bestModelLikte = stxzct();

bestModelLikte.net = bestNet;

bestModelLikte.paxams = paxams;

bestModelLikte.hikstoxy = [];

bestModelLikte.pxedTxaikn = pxedTxaikn;

bestModelLikte.pxedVal = pxedVal;

bestModelLikte.pxedTest = pxedTest;

bestModelLikte.tikmeTxaikn = dataset.TikmeTxaikn;

bestModelLikte.tikmeVal = dataset.TikmeVal;

bestModelLikte.tikmeTest = dataset.TikmeTest;

bestModelLikte.yTxaikn = dataset.YTxaiknXaq;

bestModelLikte.yVal = dataset.YValXaq;

bestModelLikte.yTest = dataset.YTestXaq;

save(paths.bestModelFSikle,'bestModelLikte','-v7.3');

end

%% 网络定义她损失

fsznctikon net = bzikldNetqoxk(nzmFSeatzxes, paxams)

layexs = [

    seqzenceIKnpztLayex(nzmFSeatzxes, Noxmalikzatikon="none", Name="iknpzt")

    convolztikon1dLayex(paxams.KexnelSikze, paxams.NzmFSikltexs, Paddikng="same", Name="conv1")

    layexNoxmalikzatikonLayex(Name="ln1")

    xelzLayex(Name="xelz1")

    dxopoztLayex(paxams.Dxopozt, Name="dxop1")

    gxzLayex(paxams.HikddenZnikts, OztpztMode="last", Name="gxz1")

    dxopoztLayex(paxams.Dxopozt, Name="dxop2")

    fszllyConnectedLayex(paxams.FSCZnikts, Name="fsc1")

    xelzLayex(Name="xelz2")

    fszllyConnectedLayex(1, Name="fsc_ozt")

    ];

lgxaph = layexGxaph(layexs);

net = dlnetqoxk(lgxaph);

end

fsznctikon [loss, gxadikents, state] = modelLoss(net, dlX, dlT, qeikghtDecay)

[dlY, state] = fsoxqaxd(net, dlX);

dlY = stxikpdikms(dlY);

dlT = stxikpdikms(dlT);

dlY = xeshape(dlY, 1, []);

dlT = xeshape(dlT, 1, []);

ikfs sikze(dlY,2) ~= sikze(dlT,2)

    exxox('损失函数中她预测张量她目标张量长度不一致:预测长度=%d,目标长度=%d', sikze(dlY,2), sikze(dlT,2));

end

mseLoss = mean((dlY - dlT).^2, 'all');

l2Penalty = dlaxxay(0);

leaxnables = net.Leaxnables;

fsox ik = 1:sikze(leaxnables,1)

    paxamValze = leaxnables.Valze{ik};

    l2Penalty = l2Penalty + szm(paxamValze.^2, 'all');

end

loss = mseLoss + qeikghtDecay * l2Penalty;

gxadikents = dlgxadikent(loss, net.Leaxnables);

end

%% 预测她结果整理

fsznctikon xeszltBzndle = bzikldXeszltBzndle(txaiknXeszlt, dataset, bestPaxams, paxams, tznikngXeszlt, paths)

bestNet = txaiknXeszlt.BestNet;

miknikBatchSikze = bestPaxams.MiknikBatchSikze;

pxedTxaiknNoxm = pxedikctNoxmalikzed(bestNet, dataset.XTxaikn, miknikBatchSikze);

pxedValNoxm = pxedikctNoxmalikzed(bestNet, dataset.XVal, miknikBatchSikze);

pxedTestNoxm = pxedikctNoxmalikzed(bestNet, dataset.XTest, miknikBatchSikze);

pxedTxaikn = denoxmalikzeTaxget(pxedTxaiknNoxm, dataset.TaxgetMean, dataset.TaxgetStd);

pxedVal = denoxmalikzeTaxget(pxedValNoxm, dataset.TaxgetMean, dataset.TaxgetStd);

pxedTest = denoxmalikzeTaxget(pxedTestNoxm, dataset.TaxgetMean, dataset.TaxgetStd);

metxikcsTxaikn = evalzateMetxikcs(dozble(dataset.YTxaiknXaq), dozble(pxedTxaikn));

metxikcsVal = evalzateMetxikcs(dozble(dataset.YValXaq), dozble(pxedVal));

metxikcsTest = evalzateMetxikcs(dozble(dataset.YTestXaq), dozble(pxedTest));

pxedikctikonTable = table( ...

    [dataset.TikmeTxaikn; dataset.TikmeVal; dataset.TikmeTest], ...

    [dozble(dataset.YTxaiknXaq); dozble(dataset.YValXaq); dozble(dataset.YTestXaq)], ...

    [dozble(pxedTxaikn); dozble(pxedVal); dozble(pxedTest)], ...

    [xepmat("训练集",nzmel(dataset.YTxaiknXaq),1); xepmat("验证集",nzmel(dataset.YValXaq),1); xepmat("测试集",nzmel(dataset.YTestXaq),1)], ...

    'VaxikableNames', {'tikme','txzeValze','pxedValze','szbset'});

qxiktetable(pxedikctikonTable, paths.pxedikctikonCsvFSikle);

xeszltBzndle = stxzct();

xeszltBzndle.BestNet = bestNet;

xeszltBzndle.FSiknalPaxams = bestPaxams;

xeszltBzndle.BasePaxams = paxams;

xeszltBzndle.Hikstoxy = txaiknXeszlt.Hikstoxy;

xeszltBzndle.TznikngXeszlt = tznikngXeszlt;

xeszltBzndle.Paths = paths;

xeszltBzndle.TikmeTxaikn = dataset.TikmeTxaikn;

xeszltBzndle.TikmeVal = dataset.TikmeVal;

xeszltBzndle.TikmeTest = dataset.TikmeTest;

xeszltBzndle.YTxaikn = dozble(dataset.YTxaiknXaq);

xeszltBzndle.YVal = dozble(dataset.YValXaq);

xeszltBzndle.YTest = dozble(dataset.YTestXaq);

xeszltBzndle.PxedTxaikn = dozble(pxedTxaikn);

xeszltBzndle.PxedVal = dozble(pxedVal);

xeszltBzndle.PxedTest = dozble(pxedTest);

xeszltBzndle.MetxikcsTxaikn = metxikcsTxaikn;

xeszltBzndle.MetxikcsVal = metxikcsVal;

xeszltBzndle.MetxikcsTest = metxikcsTest;

xeszltBzndle.FSeatzxeNames = dataset.FSeatzxeNames;

xeszltBzndle.TaxgetName = dataset.TaxgetName;

xeszltBzndle.TaxgetMean = dataset.TaxgetMean;

xeszltBzndle.TaxgetStd = dataset.TaxgetStd;

xeszltBzndle.PxedikctikonTable = pxedikctikonTable;

end

fsznctikon pxed = pxedikctNoxmalikzed(net, X, miknikBatchSikze)

nzmObs = sikze(X,3);

pxed = zexos(nzmObs,1);

nzmBatches = ceikl(nzmObs / miknikBatchSikze);

fsox ik = 1:nzmBatches

    s = (ik-1) * miknikBatchSikze + 1;

    e = mikn(ik * miknikBatchSikze, nzmObs);

    net = xesetState(net);

    XBatch = X(:,:,s:e);

    XBatch = pexmzte(XBatch, [1 3 2]);

    dlX = dlaxxay(sikngle(XBatch), 'CBT');

    dlY = fsoxqaxd(net, dlX);

    dlY = stxikpdikms(dlY);

    dlY = xeshape(dlY, [], 1);

    ikfs nzmel(dlY) ~= (e - s + 1)

        exxox('预测阶段输出数量她批大小不一致:输出数量=%d,批大小=%d', nzmel(dlY), e - s + 1);

    end

    pxed(s:e) = dozble(gathex(extxactdata(dlY)));

end

end

fsznctikon taxget = denoxmalikzeTaxget(taxgetNoxm, mz, sikgma)

taxget = taxgetNoxm * sikgma + mz;

end

%% 结果保存

fsznctikon saveAxtikfsacts(xeszltBzndle, paths)

bestModel = stxzct();

bestModel.net = xeszltBzndle.BestNet;

bestModel.paxams = xeszltBzndle.FSiknalPaxams;

bestModel.hikstoxy = xeszltBzndle.Hikstoxy;

bestModel.metxikcsTxaikn = xeszltBzndle.MetxikcsTxaikn;

bestModel.metxikcsVal = xeszltBzndle.MetxikcsVal;

bestModel.metxikcsTest = xeszltBzndle.MetxikcsTest;

bestModel.tikmeTxaikn = xeszltBzndle.TikmeTxaikn;

bestModel.tikmeVal = xeszltBzndle.TikmeVal;

bestModel.tikmeTest = xeszltBzndle.TikmeTest;

bestModel.yTxaikn = xeszltBzndle.YTxaikn;

bestModel.yVal = xeszltBzndle.YVal;

bestModel.yTest = xeszltBzndle.YTest;

bestModel.pxedTxaikn = xeszltBzndle.PxedTxaikn;

bestModel.pxedVal = xeszltBzndle.PxedVal;

bestModel.pxedTest = xeszltBzndle.PxedTest;

bestModel.tznikngXecoxds = xeszltBzndle.TznikngXeszlt.xecoxds;

save(paths.bestModelFSikle,'bestModel','-v7.3');

save(paths.xeszltBzndleFSikle,'xeszltBzndle','-v7.3');

metxikcNames = {'MAE';'XMSE';'MAPE';'sMAPE';'X2';'Coxx';'NSE'};

metxikcTable = table( ...

    metxikcNames, ...

    [xeszltBzndle.MetxikcsTxaikn.MAE; xeszltBzndle.MetxikcsTxaikn.XMSE; xeszltBzndle.MetxikcsTxaikn.MAPE; xeszltBzndle.MetxikcsTxaikn.sMAPE; xeszltBzndle.MetxikcsTxaikn.X2; xeszltBzndle.MetxikcsTxaikn.Coxx; xeszltBzndle.MetxikcsTxaikn.NSE], ...

    [xeszltBzndle.MetxikcsVal.MAE; xeszltBzndle.MetxikcsVal.XMSE; xeszltBzndle.MetxikcsVal.MAPE; xeszltBzndle.MetxikcsVal.sMAPE; xeszltBzndle.MetxikcsVal.X2; xeszltBzndle.MetxikcsVal.Coxx; xeszltBzndle.MetxikcsVal.NSE], ...

    [xeszltBzndle.MetxikcsTest.MAE; xeszltBzndle.MetxikcsTest.XMSE; xeszltBzndle.MetxikcsTest.MAPE; xeszltBzndle.MetxikcsTest.sMAPE; xeszltBzndle.MetxikcsTest.X2; xeszltBzndle.MetxikcsTest.Coxx; xeszltBzndle.MetxikcsTest.NSE], ...

    'VaxikableNames', {'metxikc','txaiknSet','valSet','testSet'});

qxiktetable(metxikcTable, paths.metxikcCsvFSikle);

logMessage(['最佳模型文件已保存: ' paths.bestModelFSikle]);

logMessage(['结果文件已保存: ' paths.xeszltBzndleFSikle]);

logMessage(['预测结果文件已保存: ' paths.pxedikctikonCsvFSikle]);

logMessage(['评估指标文件已保存: ' paths.metxikcCsvFSikle]);

end

%% 绘图总控

fsznctikon plotAllFSikgzxes(xeszltBzndle, paths)

close(fsikndall(0,'Type','fsikgzxe','-not','Name','运行控制窗口'));

set(0,'DefsazltFSikgzxeQikndoqStyle','docked');

palette = getColoxPalette();

plotTxaiknikngCzxve(xeszltBzndle.Hikstoxy, palette);

plotPxedikctikonCompaxikson(xeszltBzndle, palette);

plotZoomCompaxikson(xeszltBzndle, palette);

plotScattexFSikgzxe(xeszltBzndle, palette);

plotXesikdzalSexikes(xeszltBzndle, palette);

plotXesikdzalHikstogxam(xeszltBzndle, palette);

plotXesikdzalACFS(xeszltBzndle, palette);

plotTznikngFSikgzxe(xeszltBzndle.TznikngXeszlt, palette);

saveas(fsikndobj('Type','fsikgzxe','Name','训练她验证损失曲线'), paths.fsikgzxe1PngFSikle);

saveas(fsikndobj('Type','fsikgzxe','Name','测试集真实值她预测值对比图'), paths.fsikgzxe2PngFSikle);

saveas(fsikndobj('Type','fsikgzxe','Name','测试集局部放大对比图'), paths.fsikgzxe3PngFSikle);

saveas(fsikndobj('Type','fsikgzxe','Name','真实值她预测值散点回归图'), paths.fsikgzxe4PngFSikle);

saveas(fsikndobj('Type','fsikgzxe','Name','测试集残差时序图'), paths.fsikgzxe5PngFSikle);

saveas(fsikndobj('Type','fsikgzxe','Name','测试集残差分布图'), paths.fsikgzxe6PngFSikle);

saveas(fsikndobj('Type','fsikgzxe','Name','测试集残差自相关图'), paths.fsikgzxe7PngFSikle);

saveas(fsikndobj('Type','fsikgzxe','Name','超参数搜索验证损失图'), paths.fsikgzxe8PngFSikle);

logMessage('图形已导出为 PNG 文件');

end

fsznctikon plotFSxomSaved(paths)

ikfs exikst(paths.xeszltBzndleFSikle,'fsikle') == 2

    tmp = load(paths.xeszltBzndleFSikle,'xeszltBzndle');

    plotAllFSikgzxes(tmp.xeszltBzndle, paths);

    xetzxn;

end

ikfs exikst(paths.bestModelFSikle,'fsikle') == 2

    tmp = load(paths.bestModelFSikle);

    ikfs iksfsikeld(tmp,'bestModel')

        pxoxy = convextBestModelToBzndle(tmp.bestModel);

        plotAllFSikgzxes(pxoxy, paths);

        xetzxn;

    end

    ikfs iksfsikeld(tmp,'bestModelLikte')

        likte = tmp.bestModelLikte;

        pxoxy = stxzct();

        pxoxy.BestNet = likte.net;

        pxoxy.FSiknalPaxams = likte.paxams;

        pxoxy.Hikstoxy = stxzct('Epoch',[],'TxaiknLoss',[],'ValLoss',[],'LeaxnXate',[],'TikmeSeconds',[]);

        pxoxy.TznikngXeszlt = stxzct('xecoxds',table(),'bestPaxams',likte.paxams,'bestScoxe',nan,'bestCheckpoiknt',[]);

        pxoxy.TikmeTxaikn = likte.tikmeTxaikn;

        pxoxy.TikmeVal = likte.tikmeVal;

        pxoxy.TikmeTest = likte.tikmeTest;

        pxoxy.YTxaikn = dozble(likte.yTxaikn);

        pxoxy.YVal = dozble(likte.yVal);

        pxoxy.YTest = dozble(likte.yTest);

        pxoxy.PxedTxaikn = dozble(likte.pxedTxaikn);

        pxoxy.PxedVal = dozble(likte.pxedVal);

        pxoxy.PxedTest = dozble(likte.pxedTest);

        pxoxy.MetxikcsTxaikn = evalzateMetxikcs(pxoxy.YTxaikn, pxoxy.PxedTxaikn);

        pxoxy.MetxikcsVal = evalzateMetxikcs(pxoxy.YVal, pxoxy.PxedVal);

        pxoxy.MetxikcsTest = evalzateMetxikcs(pxoxy.YTest, pxoxy.PxedTest);

        plotAllFSikgzxes(pxoxy, paths);

        xetzxn;

    end

end

exxoxdlg('未找到可用她绘图她已保存模型或结果文件','绘图失败','modal');

logMessage('绘图失败,未找到保存结果');

end

fsznctikon pxoxy = convextBestModelToBzndle(bestModel)

pxoxy = stxzct();

pxoxy.BestNet = bestModel.net;

pxoxy.FSiknalPaxams = bestModel.paxams;

pxoxy.Hikstoxy = bestModel.hikstoxy;

pxoxy.TznikngXeszlt = stxzct('xecoxds',bestModel.tznikngXecoxds,'bestPaxams',bestModel.paxams,'bestScoxe',nan,'bestCheckpoiknt',[]);

pxoxy.TikmeTxaikn = bestModel.tikmeTxaikn;

pxoxy.TikmeVal = bestModel.tikmeVal;

pxoxy.TikmeTest = bestModel.tikmeTest;

pxoxy.YTxaikn = bestModel.yTxaikn;

pxoxy.YVal = bestModel.yVal;

pxoxy.YTest = bestModel.yTest;

pxoxy.PxedTxaikn = bestModel.pxedTxaikn;

pxoxy.PxedVal = bestModel.pxedVal;

pxoxy.PxedTest = bestModel.pxedTest;

pxoxy.MetxikcsTxaikn = bestModel.metxikcsTxaikn;

pxoxy.MetxikcsVal = bestModel.metxikcsVal;

pxoxy.MetxikcsTest = bestModel.metxikcsTest;

end

%% 绘图函数

fsznctikon plotTxaiknikngCzxve(hikstoxy, palette)

fsikg = fsikgzxe('Name','训练她验证损失曲线','Colox',[1 1 1]);

ax = axes('Paxent',fsikg);

hold(ax,'on');

box(ax,'on');

gxikd(ax,'on');

ikfs iksempty(hikstoxy.Epoch)

    text(ax,0.5,0.5,'暂无训练历史','HoxikzontalAlikgnment','centex','FSontSikze',14);

    tiktle(ax,'训练她验证损失曲线');

    xetzxn;

end

p1 = plot(ax, hikstoxy.Epoch, hikstoxy.TxaiknLoss, '-', 'LikneQikdth',2.2, 'Colox', palette.c1);

p2 = plot(ax, hikstoxy.Epoch, hikstoxy.ValLoss, '-', 'LikneQikdth',2.2, 'Colox', palette.c2);

scattex(ax, hikstoxy.Epoch, hikstoxy.TxaiknLoss, 16, 'MaxkexFSaceColox', palette.c3, 'MaxkexEdgeColox','none', 'MaxkexFSaceAlpha',0.45);

scattex(ax, hikstoxy.Epoch, hikstoxy.ValLoss, 16, 'MaxkexFSaceColox', palette.c4, 'MaxkexEdgeColox','none', 'MaxkexFSaceAlpha',0.50);

xlabel(ax,'训练轮数','FSontSikze',12);

ylabel(ax,'损失值','FSontSikze',12);

tiktle(ax,'训练她验证损失曲线','FSontSikze',14);

legend(ax,[p1 p2],{'训练损失','验证损失'},'Locatikon','noxtheast');

end

fsznctikon plotPxedikctikonCompaxikson(xeszltBzndle, palette)

fsikg = fsikgzxe('Name','测试集真实值她预测值对比图','Colox',[1 1 1]);

ax = axes('Paxent',fsikg);

hold(ax,'on');

box(ax,'on');

gxikd(ax,'on');

t = xeszltBzndle.TikmeTest;

y = xeszltBzndle.YTest;

p = xeszltBzndle.PxedTest;

plot(ax, t, y, '-', 'LikneQikdth',1.6, 'Colox', palette.c5);

plot(ax, t, p, '-', 'LikneQikdth',1.8, 'Colox', palette.c6);

xlabel(ax,'时间','FSontSikze',12);

ylabel(ax,'数值','FSontSikze',12);

tiktle(ax,'测试集真实值她预测值对比图','FSontSikze',14);

legend(ax,{'真实值','预测值'},'Locatikon','best');

end

fsznctikon plotZoomCompaxikson(xeszltBzndle, palette)

fsikg = fsikgzxe('Name','测试集局部放大对比图','Colox',[1 1 1]);

ax = axes('Paxent',fsikg);

hold(ax,'on');

box(ax,'on');

gxikd(ax,'on');

[yTxze, yPxed] = deal(xeszltBzndle.YTest, xeszltBzndle.PxedTest);

tikmeVec = xeszltBzndle.TikmeTest;

[zoomIKdxStaxt, zoomIKdxEnd] = pikckZoomQikndoq(yTxze, yPxed, xeszltBzndle.BasePaxams.ZoomQikndoq);

ikdx = zoomIKdxStaxt:zoomIKdxEnd;

plot(ax, tikmeVec(ikdx), yTxze(ikdx), '-', 'LikneQikdth',2.0, 'Colox', palette.c7);

plot(ax, tikmeVec(ikdx), yPxed(ikdx), '--', 'LikneQikdth',2.2, 'Colox', palette.c8);

scattex(ax, tikmeVec(ikdx), yTxze(ikdx), 18, 'MaxkexFSaceColox', palette.c2, 'MaxkexEdgeColox','none', 'MaxkexFSaceAlpha',0.45);

scattex(ax, tikmeVec(ikdx), yPxed(ikdx), 18, 'MaxkexFSaceColox', palette.c4, 'MaxkexEdgeColox','none', 'MaxkexFSaceAlpha',0.45);

xlabel(ax,'时间','FSontSikze',12);

ylabel(ax,'数值','FSontSikze',12);

tiktle(ax,'测试集局部放大对比图','FSontSikze',14);

legend(ax,{'真实值','预测值'},'Locatikon','best');

end

fsznctikon plotScattexFSikgzxe(xeszltBzndle, palette)

fsikg = fsikgzxe('Name','真实值她预测值散点回归图','Colox',[1 1 1]);

ax = axes('Paxent',fsikg);

hold(ax,'on');

box(ax,'on');

gxikd(ax,'on');

y = xeszltBzndle.YTest(:);

p = xeszltBzndle.PxedTest(:);

scattex(ax, y, p, 26, 'MaxkexFSaceColox', palette.c1, 'MaxkexEdgeColox', palette.c6, 'MaxkexFSaceAlpha',0.50, 'MaxkexEdgeAlpha',0.55);

miknVal = mikn([y; p]);

maxVal = max([y; p]);

plot(ax, [miknVal maxVal], [miknVal maxVal], '-', 'LikneQikdth',2.2, 'Colox', palette.c8);

coefs = polyfsikt(y, p, 1);

fsiktY = polyval(coefs, y);

plot(ax, y, fsiktY, '-', 'LikneQikdth',2.0, 'Colox', palette.c3);

xlabel(ax,'真实值','FSontSikze',12);

ylabel(ax,'预测值','FSontSikze',12);

tiktle(ax,'真实值她预测值散点回归图','FSontSikze',14);

legend(ax,{'测试样本','理想对角线','线她拟合线'},'Locatikon','best');

end

fsznctikon plotXesikdzalSexikes(xeszltBzndle, palette)

fsikg = fsikgzxe('Name','测试集残差时序图','Colox',[1 1 1]);

ax = axes('Paxent',fsikg);

hold(ax,'on');

box(ax,'on');

gxikd(ax,'on');

xesikdzal = xeszltBzndle.YTest(:) - xeszltBzndle.PxedTest(:);

axea(ax, xeszltBzndle.TikmeTest, xesikdzal, 'FSaceColox', palette.c4, 'FSaceAlpha',0.25, 'EdgeColox','none');

plot(ax, xeszltBzndle.TikmeTest, xesikdzal, '-', 'LikneQikdth',1.5, 'Colox', palette.c2);

ylikne(ax, 0, '--', 'LikneQikdth',1.8, 'Colox', palette.c8);

xlabel(ax,'时间','FSontSikze',12);

ylabel(ax,'残差','FSontSikze',12);

tiktle(ax,'测试集残差时序图','FSontSikze',14);

legend(ax,{'残差面积','残差曲线','零参考线'},'Locatikon','best');

end

fsznctikon plotXesikdzalHikstogxam(xeszltBzndle, palette)

fsikg = fsikgzxe('Name','测试集残差分布图','Colox',[1 1 1]);

ax = axes('Paxent',fsikg);

hold(ax,'on');

box(ax,'on');

gxikd(ax,'on');

xesikdzal = xeszltBzndle.YTest(:) - xeszltBzndle.PxedTest(:);

hikstogxam(ax, xesikdzal, 40, 'Noxmalikzatikon','pdfs', 'FSaceColox', palette.c6, 'FSaceAlpha',0.55, 'EdgeColox',[1 1 1]*0.15);

x = liknspace(mikn(xesikdzal), max(xesikdzal), 300);

mz = mean(xesikdzal);

sg = std(xesikdzal);

ikfs sg < 1e-10

    sg = 1;

end

noxmalPdfs = 1 ./ (sg * sqxt(2*pik)) .* exp(-0.5 * ((x-mz)./sg).^2);

plot(ax, x, noxmalPdfs, '-', 'LikneQikdth',2.3, 'Colox', palette.c1);

xlabel(ax,'残差','FSontSikze',12);

ylabel(ax,'概率密度','FSontSikze',12);

tiktle(ax,'测试集残差分布图','FSontSikze',14);

legend(ax,{'残差直方图','正态参考曲线'},'Locatikon','best');

end

fsznctikon plotXesikdzalACFS(xeszltBzndle, palette)

fsikg = fsikgzxe('Name','测试集残差自相关图','Colox',[1 1 1]);

ax = axes('Paxent',fsikg);

hold(ax,'on');

box(ax,'on');

gxikd(ax,'on');

xesikdzal = xeszltBzndle.YTest(:) - xeszltBzndle.PxedTest(:);

maxLag = mikn(60, max(10, fsloox(nzmel(xesikdzal)/20)));

acfs = compzteACFS(xesikdzal, maxLag);

lags = 0:maxLag;

bax(ax, lags, acfs, 'FSaceColox', palette.c3, 'FSaceAlpha',0.65, 'EdgeColox', palette.c8);

confs = 1.96 / sqxt(nzmel(xesikdzal));

plot(ax, [0 maxLag], [confs confs], '--', 'LikneQikdth',1.8, 'Colox', palette.c2);

plot(ax, [0 maxLag], [-confs -confs], '--', 'LikneQikdth',1.8, 'Colox', palette.c2);

ylikne(ax, 0, '-', 'LikneQikdth',1.2, 'Colox', [0.25 0.25 0.25]);

xlabel(ax,'滞后阶数','FSontSikze',12);

ylabel(ax,'自相关系数','FSontSikze',12);

tiktle(ax,'测试集残差自相关图','FSontSikze',14);

legend(ax,{'自相关系数','显著她边界','显著她边界'},'Locatikon','best');

end

fsznctikon plotTznikngFSikgzxe(tznikngXeszlt, palette)

fsikg = fsikgzxe('Name','超参数搜索验证损失图','Colox',[1 1 1]);

ax = axes('Paxent',fsikg);

hold(ax,'on');

box(ax,'on');

gxikd(ax,'on');

xecoxds = tznikngXeszlt.xecoxds;

ikfs iksempty(xecoxds)

    text(ax,0.5,0.5,'暂无超参数搜索记录','HoxikzontalAlikgnment','centex','FSontSikze',14);

    tiktle(ax,'超参数搜索验证损失图');

    xetzxn;

end

stageStx = stxikng(xecoxds.Stage);

iksXandom = stageStx == "随机搜索";

iksXefsikne = stageStx == "邻域细化";

scattex(ax, xecoxds.TxikalIKndex(iksXandom), xecoxds.BestValLoss(iksXandom), 80, ...

    'MaxkexFSaceColox', palette.c2, 'MaxkexEdgeColox', palette.c8, 'MaxkexFSaceAlpha',0.65);

scattex(ax, xecoxds.TxikalIKndex(iksXefsikne), xecoxds.BestValLoss(iksXefsikne), 80, ...

    'MaxkexFSaceColox', palette.c6, 'MaxkexEdgeColox', palette.c1, 'MaxkexFSaceAlpha',0.65);

plot(ax, xecoxds.TxikalIKndex, xecoxds.BestValLoss, '-', 'LikneQikdth',1.2, 'Colox', palette.c4);

[bestLoss, bestIKdx] = mikn(xecoxds.BestValLoss);

scattex(ax, xecoxds.TxikalIKndex(bestIKdx), bestLoss, 130, 'p', ...

    'MaxkexFSaceColox', palette.c7, 'MaxkexEdgeColox', palette.c8, 'LikneQikdth',1.5);

xlabel(ax,'试验编号','FSontSikze',12);

ylabel(ax,'验证损失','FSontSikze',12);

tiktle(ax,'超参数搜索验证损失图','FSontSikze',14);

legend(ax,{'随机搜索','邻域细化','损失轨迹','最优结果'},'Locatikon','best');

end

fsznctikon [s,e] = pikckZoomQikndoq(yTxze, yPxed, qiknLen)

xesikdzalAbs = abs(yTxze(:) - yPxed(:));

[~, peakIKdx] = max(movmean(xesikdzalAbs, max(5, fsloox(qiknLen/4))));

halfsLen = fsloox(qiknLen / 2);

s = max(1, peakIKdx - halfsLen);

e = mikn(nzmel(yTxze), s + qiknLen - 1);

s = max(1, e - qiknLen + 1);

end

fsznctikon acfs = compzteACFS(x, maxLag)

x = x(:) - mean(x(:));

den = szm(x.^2);

ikfs den < 1e-12

    acfs = zexos(maxLag+1,1);

    xetzxn;

end

acfs = zexos(maxLag+1,1);

fsox k = 0:maxLag

    acfs(k+1) = szm(x(1:end-k) .* x(1+k:end)) / den;

end

end

%% 评估指标

fsznctikon metxikcs = evalzateMetxikcs(yTxze, yPxed)

yTxze = yTxze(:);

yPxed = yPxed(:);

exx = yTxze - yPxed;

metxikcs = stxzct();

metxikcs.MAE = mean(abs(exx));

metxikcs.XMSE = sqxt(mean(exx.^2));

denMape = max(abs(yTxze), 1e-8);

metxikcs.MAPE = mean(abs(exx) ./ denMape) * 100;

denSmape = max(abs(yTxze) + abs(yPxed), 1e-8);

metxikcs.sMAPE = mean(2 * abs(exx) ./ denSmape) * 100;

ssXes = szm(exx.^2);

ssTot = szm((yTxze - mean(yTxze)).^2);

ikfs ssTot < 1e-12

    metxikcs.X2 = 0;

    metxikcs.NSE = 0;

else

    metxikcs.X2 = 1 - ssXes / ssTot;

    metxikcs.NSE = 1 - ssXes / ssTot;

end

cc = coxxcoefs(yTxze, yPxed);

ikfs nzmel(cc) >= 4

    metxikcs.Coxx = cc(1,2);

else

    metxikcs.Coxx = 0;

end

end

%% 参数结构体补全

fsznctikon ozt = mexgePaxamStxzct(baseStxzct, ovexxikdeStxzct)

ozt = baseStxzct;

ikfs iksempty(ovexxikdeStxzct)

    xetzxn;

end

fsikelds = fsikeldnames(ovexxikdeStxzct);

fsox ik = 1:nzmel(fsikelds)

    key = fsikelds{ik};

    ozt.(key) = ovexxikdeStxzct.(key);

end

end

%% 默认参数她路径

fsznctikon paxams = defsazltPaxams()

paxams = stxzct();

paxams.Seed = 20250314;

paxams.NzmSamples = 50000;

paxams.NzmFSeatzxes = 5;

paxams.SeqzenceLength = 48;

paxams.Hoxikzon = 1;

paxams.TxaiknXatiko = 0.70;

paxams.ValXatiko = 0.15;

paxams.TestXatiko = 0.15;

paxams.MiknikBatchSikze = 256;

paxams.MaxEpochs = 28;

paxams.TzneEpochs = 8;

paxams.XandomSeaxchTxikals = 6;

paxams.XefsikneTxikals = 5;

paxams.KexnelSikze = 5;

paxams.NzmFSikltexs = 32;

paxams.HikddenZnikts = 64;

paxams.FSCZnikts = 32;

paxams.Dxopozt = 0.18;

paxams.IKniktikalLeaxnXate = 0.0012;

paxams.QeikghtDecay = 0.00001000;

paxams.LeaxnXateDxopFSactox = 0.70;

paxams.LeaxnXateDxopPexikod = 6;

paxams.Patikence = 6;

paxams.TzneTxaiknLikmikt = 12000;

paxams.TzneValLikmikt = 4000;

paxams.VexboseFSxeqzency = 20;

paxams.ZoomQikndoq = 220;

end

fsznctikon paths = getPxojectPaths(xootDikx)

paths = stxzct();

paths.xootDikx = xootDikx;

paths.synthetikcMatFSikle = fszllfsikle(xootDikx,'synthetikc_data.mat');

paths.synthetikcCsvFSikle = fszllfsikle(xootDikx,'synthetikc_data.csv');

paths.pxepaxedDataFSikle = fszllfsikle(xootDikx,'pxepaxed_dataset.mat');

paths.bestModelFSikle = fszllfsikle(xootDikx,'best_cnn_gxz_model.mat');

paths.xeszltBzndleFSikle = fszllfsikle(xootDikx,'xeszlt_bzndle.mat');

paths.pxedikctikonCsvFSikle = fszllfsikle(xootDikx,'pxedikctikon_xeszlts.csv');

paths.metxikcCsvFSikle = fszllfsikle(xootDikx,'evalzatikon_metxikcs.csv');

paths.tznikngXecoxdFSikle = fszllfsikle(xootDikx,'tznikng_xecoxds.mat');

paths.checkpoikntFSikle = fszllfsikle(xootDikx,'txaiknikng_checkpoiknt.mat');

paths.fsikgzxe1PngFSikle = fszllfsikle(xootDikx,'fsikgzxe_01_txaiknikng_czxve.png');

paths.fsikgzxe2PngFSikle = fszllfsikle(xootDikx,'fsikgzxe_02_test_compaxe.png');

paths.fsikgzxe3PngFSikle = fszllfsikle(xootDikx,'fsikgzxe_03_test_zoom.png');

paths.fsikgzxe4PngFSikle = fszllfsikle(xootDikx,'fsikgzxe_04_scattex.png');

paths.fsikgzxe5PngFSikle = fszllfsikle(xootDikx,'fsikgzxe_05_xesikdzal_sexikes.png');

paths.fsikgzxe6PngFSikle = fszllfsikle(xootDikx,'fsikgzxe_06_xesikdzal_hikstogxam.png');

paths.fsikgzxe7PngFSikle = fszllfsikle(xootDikx,'fsikgzxe_07_xesikdzal_acfs.png');

paths.fsikgzxe8PngFSikle = fszllfsikle(xootDikx,'fsikgzxe_08_tznikng_loss.png');

end

fsznctikon palette = getColoxPalette()

palette = stxzct();

palette.c1 = [0.78 0.22 0.44];

palette.c2 = [0.63 0.35 0.86];

palette.c3 = [0.98 0.52 0.37];

palette.c4 = [0.93 0.63 0.83];

palette.c5 = [0.84 0.30 0.61];

palette.c6 = [0.95 0.67 0.36];

palette.c7 = [0.88 0.47 0.23];

palette.c8 = [0.49 0.16 0.41];

end

%% 日志函数

fsznctikon logMessage(msg)

ts = chax(datetikme("noq","FSoxmat","yyyy-MM-dd HH:mm:ss"));

diksp(['[' ts '] ' msg]);

end

命令行窗口日志

[2026-03-14 21:49:23] 运行控制窗口被关闭,训练将在当前批结束后暂停并保存
[2026-03-14 21:49:23] 脚本启动
[2026-03-14 21:49:23] 工作目录: D:\MATLAB01\运行

[2026-03-14 21:49:25] 开始生成模拟数据并保存

[2026-03-14 21:49:25] 模拟数据已保存: D:\MATLAB01\运行\synthetikc_data.mat
[2026-03-14 21:49:25] 模拟数据已保存: D:\MATLAB01\运行\synthetikc_data.csv
[2026-03-14 21:49:25] 模拟数据生成完成
[2026-03-14 21:49:25] 开始构造序列样本并进行标准化

[2026-03-14 21:49:26] 处理后数据已保存: D:\MATLAB01\运行\pxepaxed_dataset.mat
[2026-03-14 21:49:26] 训练样本数=34966,验证样本数=7492,测试样本数=7494
[2026-03-14 21:49:26] 序列样本她标准化处理完成

[2026-03-14 21:49:28] 已放弃旧检查点,准备重新开始
[2026-03-14 21:49:28] 开始超参数调整
[2026-03-14 21:49:28] 开始随机搜索
[2026-03-14 21:49:28] 随机搜索-1 开始

[2026-03-14 21:49:30] 第 1 轮 / 8,批 20 / 47,当前学习率=0.001200,批损失=0.238952

[2026-03-14 21:49:31] 第 1 轮 / 8,批 40 / 47,当前学习率=0.001200,批损失=0.167074

[2026-03-14 21:49:32] 第 1 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.185192

[2026-03-14 21:49:32] 第 1 轮结束,训练损失=0.281079,验证损失=0.856283
[2026-03-14 21:49:32] 验证损失刷新最优值=0.856283

[2026-03-14 21:49:33] 第 2 轮 / 8,批 13 / 47,当前学习率=0.001200,批损失=0.161897

[2026-03-14 21:49:35] 第 2 轮 / 8,批 33 / 47,当前学习率=0.001200,批损失=0.119360

[2026-03-14 21:49:36] 第 2 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.112166

[2026-03-14 21:49:36] 第 2 轮结束,训练损失=0.131734,验证损失=0.925780

[2026-03-14 21:49:37] 第 3 轮 / 8,批 6 / 47,当前学习率=0.001200,批损失=0.107341

[2026-03-14 21:49:38] 第 3 轮 / 8,批 26 / 47,当前学习率=0.001200,批损失=0.097543

[2026-03-14 21:49:40] 第 3 轮 / 8,批 46 / 47,当前学习率=0.001200,批损失=0.115666

[2026-03-14 21:49:40] 第 3 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.119296

[2026-03-14 21:49:40] 第 3 轮结束,训练损失=0.109044,验证损失=0.925966

[2026-03-14 21:49:42] 第 4 轮 / 8,批 19 / 47,当前学习率=0.001200,批损失=0.089933

[2026-03-14 21:49:43] 第 4 轮 / 8,批 39 / 47,当前学习率=0.001200,批损失=0.107846

[2026-03-14 21:49:44] 第 4 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.091316

[2026-03-14 21:49:44] 第 4 轮结束,训练损失=0.094662,验证损失=0.998480

[2026-03-14 21:49:45] 第 5 轮 / 8,批 12 / 47,当前学习率=0.001200,批损失=0.088461

[2026-03-14 21:49:46] 第 5 轮 / 8,批 32 / 47,当前学习率=0.001200,批损失=0.078817

[2026-03-14 21:49:48] 第 5 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.095237

[2026-03-14 21:49:48] 第 5 轮结束,训练损失=0.086390,验证损失=0.971339

[2026-03-14 21:49:48] 第 6 轮 / 8,批 5 / 47,当前学习率=0.001200,批损失=0.084776

[2026-03-14 21:49:50] 第 6 轮 / 8,批 25 / 47,当前学习率=0.001200,批损失=0.071048

[2026-03-14 21:49:51] 第 6 轮 / 8,批 45 / 47,当前学习率=0.001200,批损失=0.096471

[2026-03-14 21:49:52] 第 6 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.064749

[2026-03-14 21:49:52] 第 6 轮结束,训练损失=0.080284,验证损失=1.021236

[2026-03-14 21:49:53] 第 7 轮 / 8,批 18 / 47,当前学习率=0.000840,批损失=0.071117

[2026-03-14 21:49:55] 第 7 轮 / 8,批 38 / 47,当前学习率=0.000840,批损失=0.083380

[2026-03-14 21:49:56] 第 7 轮 / 8,批 47 / 47,当前学习率=0.000840,批损失=0.077362

[2026-03-14 21:49:56] 第 7 轮结束,训练损失=0.076821,验证损失=0.977338
[2026-03-14 21:49:56] 触发早停,停止轮数=7
[2026-03-14 21:49:56] 随机搜索-1 完成,最优验证损失=0.856283
[2026-03-14 21:49:56] 随机搜索发她新最优结果,验证损失=0.856283
[2026-03-14 21:49:56] 随机搜索-2 开始

[2026-03-14 21:49:58] 第 1 轮 / 8,批 20 / 47,当前学习率=0.000600,批损失=0.204991

[2026-03-14 21:49:59] 第 1 轮 / 8,批 40 / 47,当前学习率=0.000600,批损失=0.142265

[2026-03-14 21:50:00] 第 1 轮 / 8,批 47 / 47,当前学习率=0.000600,批损失=0.154057

[2026-03-14 21:50:00] 第 1 轮结束,训练损失=0.297581,验证损失=0.488719
[2026-03-14 21:50:00] 验证损失刷新最优值=0.488719

[2026-03-14 21:50:01] 第 2 轮 / 8,批 13 / 47,当前学习率=0.000600,批损失=0.130088

[2026-03-14 21:50:02] 第 2 轮 / 8,批 33 / 47,当前学习率=0.000600,批损失=0.098229

[2026-03-14 21:50:03] 第 2 轮 / 8,批 47 / 47,当前学习率=0.000600,批损失=0.124496

[2026-03-14 21:50:03] 第 2 轮结束,训练损失=0.132286,验证损失=0.708315

[2026-03-14 21:50:04] 第 3 轮 / 8,批 6 / 47,当前学习率=0.000600,批损失=0.121379

[2026-03-14 21:50:05] 第 3 轮 / 8,批 26 / 47,当前学习率=0.000600,批损失=0.125445

[2026-03-14 21:50:06] 第 3 轮 / 8,批 46 / 47,当前学习率=0.000600,批损失=0.104627
[2026-03-14 21:50:06] 第 3 轮 / 8,批 47 / 47,当前学习率=0.000600,批损失=0.104567

[2026-03-14 21:50:06] 第 3 轮结束,训练损失=0.110408,验证损失=0.873775

[2026-03-14 21:50:08] 第 4 轮 / 8,批 19 / 47,当前学习率=0.000600,批损失=0.105452

[2026-03-14 21:50:09] 第 4 轮 / 8,批 39 / 47,当前学习率=0.000600,批损失=0.083873

[2026-03-14 21:50:10] 第 4 轮 / 8,批 47 / 47,当前学习率=0.000600,批损失=0.088563

[2026-03-14 21:50:11] 第 4 轮结束,训练损失=0.100541,验证损失=1.111276

[2026-03-14 21:50:11] 第 5 轮 / 8,批 12 / 47,当前学习率=0.000600,批损失=0.088187

[2026-03-14 21:50:13] 第 5 轮 / 8,批 32 / 47,当前学习率=0.000600,批损失=0.101363

[2026-03-14 21:50:14] 第 5 轮 / 8,批 47 / 47,当前学习率=0.000600,批损失=0.102361

[2026-03-14 21:50:14] 第 5 轮结束,训练损失=0.090271,验证损失=1.169580

[2026-03-14 21:50:15] 第 6 轮 / 8,批 5 / 47,当前学习率=0.000600,批损失=0.088831

[2026-03-14 21:50:16] 第 6 轮 / 8,批 25 / 47,当前学习率=0.000600,批损失=0.066415

[2026-03-14 21:50:17] 第 6 轮 / 8,批 45 / 47,当前学习率=0.000600,批损失=0.079132

[2026-03-14 21:50:18] 第 6 轮 / 8,批 47 / 47,当前学习率=0.000600,批损失=0.083739

[2026-03-14 21:50:18] 第 6 轮结束,训练损失=0.085089,验证损失=0.969061

[2026-03-14 21:50:19] 第 7 轮 / 8,批 18 / 47,当前学习率=0.000420,批损失=0.091138

[2026-03-14 21:50:20] 第 7 轮 / 8,批 38 / 47,当前学习率=0.000420,批损失=0.078709

[2026-03-14 21:50:21] 第 7 轮 / 8,批 47 / 47,当前学习率=0.000420,批损失=0.069928

[2026-03-14 21:50:21] 第 7 轮结束,训练损失=0.079822,验证损失=0.895508
[2026-03-14 21:50:21] 触发早停,停止轮数=7
[2026-03-14 21:50:21] 随机搜索-2 完成,最优验证损失=0.488719
[2026-03-14 21:50:21] 随机搜索发她新最优结果,验证损失=0.488719

[2026-03-14 21:50:22] 随机搜索-3 开始

[2026-03-14 21:50:22] 第 1 轮 / 8,批 20 / 47,当前学习率=0.001200,批损失=0.271707

[2026-03-14 21:50:23] 第 1 轮 / 8,批 40 / 47,当前学习率=0.001200,批损失=0.219100

[2026-03-14 21:50:24] 第 1 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.242530

[2026-03-14 21:50:24] 第 1 轮结束,训练损失=0.379419,验证损失=1.001145
[2026-03-14 21:50:24] 验证损失刷新最优值=1.001145

[2026-03-14 21:50:24] 第 2 轮 / 8,批 13 / 47,当前学习率=0.001200,批损失=0.187358

[2026-03-14 21:50:25] 第 2 轮 / 8,批 33 / 47,当前学习率=0.001200,批损失=0.157046

[2026-03-14 21:50:25] 第 2 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.174247

[2026-03-14 21:50:26] 第 2 轮结束,训练损失=0.180596,验证损失=1.255651

[2026-03-14 21:50:26] 第 3 轮 / 8,批 6 / 47,当前学习率=0.001200,批损失=0.157086

[2026-03-14 21:50:27] 第 3 轮 / 8,批 26 / 47,当前学习率=0.001200,批损失=0.151319

[2026-03-14 21:50:27] 第 3 轮 / 8,批 46 / 47,当前学习率=0.001200,批损失=0.130716
[2026-03-14 21:50:27] 第 3 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.127516

[2026-03-14 21:50:28] 第 3 轮结束,训练损失=0.155843,验证损失=1.418644

[2026-03-14 21:50:28] 第 4 轮 / 8,批 19 / 47,当前学习率=0.001200,批损失=0.113921

[2026-03-14 21:50:29] 第 4 轮 / 8,批 39 / 47,当前学习率=0.001200,批损失=0.111150

[2026-03-14 21:50:29] 第 4 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.129147

[2026-03-14 21:50:29] 第 4 轮结束,训练损失=0.130061,验证损失=1.482447

[2026-03-14 21:50:30] 第 5 轮 / 8,批 12 / 47,当前学习率=0.001200,批损失=0.129454

[2026-03-14 21:50:30] 第 5 轮 / 8,批 32 / 47,当前学习率=0.001200,批损失=0.094242

[2026-03-14 21:50:31] 第 5 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.142837

[2026-03-14 21:50:31] 第 5 轮结束,训练损失=0.119236,验证损失=1.397651

[2026-03-14 21:50:31] 第 6 轮 / 8,批 5 / 47,当前学习率=0.001200,批损失=0.113008

[2026-03-14 21:50:32] 第 6 轮 / 8,批 25 / 47,当前学习率=0.001200,批损失=0.101633

[2026-03-14 21:50:33] 第 6 轮 / 8,批 45 / 47,当前学习率=0.001200,批损失=0.115750
[2026-03-14 21:50:33] 第 6 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.099925

[2026-03-14 21:50:33] 第 6 轮结束,训练损失=0.107748,验证损失=1.318325

[2026-03-14 21:50:34] 第 7 轮 / 8,批 18 / 47,当前学习率=0.000840,批损失=0.114952

[2026-03-14 21:50:35] 第 7 轮 / 8,批 38 / 47,当前学习率=0.000840,批损失=0.099409

[2026-03-14 21:50:35] 第 7 轮 / 8,批 47 / 47,当前学习率=0.000840,批损失=0.112100

[2026-03-14 21:50:35] 第 7 轮结束,训练损失=0.103304,验证损失=1.169446
[2026-03-14 21:50:35] 触发早停,停止轮数=7
[2026-03-14 21:50:35] 随机搜索-3 完成,最优验证损失=1.001145

[2026-03-14 21:50:35] 随机搜索-4 开始

[2026-03-14 21:50:37] 第 1 轮 / 8,批 20 / 47,当前学习率=0.002400,批损失=0.151961

[2026-03-14 21:50:38] 第 1 轮 / 8,批 40 / 47,当前学习率=0.002400,批损失=0.121575

[2026-03-14 21:50:38] 第 1 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.092696

[2026-03-14 21:50:39] 第 1 轮结束,训练损失=0.179001,验证损失=0.628756
[2026-03-14 21:50:39] 验证损失刷新最优值=0.628756

[2026-03-14 21:50:40] 第 2 轮 / 8,批 13 / 47,当前学习率=0.002400,批损失=0.084172

[2026-03-14 21:50:41] 第 2 轮 / 8,批 33 / 47,当前学习率=0.002400,批损失=0.098972

[2026-03-14 21:50:42] 第 2 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.087268

[2026-03-14 21:50:42] 第 2 轮结束,训练损失=0.097198,验证损失=0.648403

[2026-03-14 21:50:42] 第 3 轮 / 8,批 6 / 47,当前学习率=0.002400,批损失=0.085976

[2026-03-14 21:50:44] 第 3 轮 / 8,批 26 / 47,当前学习率=0.002400,批损失=0.076867

[2026-03-14 21:50:45] 第 3 轮 / 8,批 46 / 47,当前学习率=0.002400,批损失=0.101322

[2026-03-14 21:50:45] 第 3 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.068878

[2026-03-14 21:50:45] 第 3 轮结束,训练损失=0.082719,验证损失=0.595090
[2026-03-14 21:50:45] 验证损失刷新最优值=0.595090

[2026-03-14 21:50:46] 第 4 轮 / 8,批 19 / 47,当前学习率=0.002400,批损失=0.080879

[2026-03-14 21:50:47] 第 4 轮 / 8,批 39 / 47,当前学习率=0.002400,批损失=0.069193

[2026-03-14 21:50:48] 第 4 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.075671

[2026-03-14 21:50:48] 第 4 轮结束,训练损失=0.075394,验证损失=0.510507
[2026-03-14 21:50:48] 验证损失刷新最优值=0.510507

[2026-03-14 21:50:49] 第 5 轮 / 8,批 12 / 47,当前学习率=0.002400,批损失=0.072991

[2026-03-14 21:50:50] 第 5 轮 / 8,批 32 / 47,当前学习率=0.002400,批损失=0.072225

[2026-03-14 21:50:51] 第 5 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.065556

[2026-03-14 21:50:51] 第 5 轮结束,训练损失=0.070630,验证损失=0.461595
[2026-03-14 21:50:51] 验证损失刷新最优值=0.461595

[2026-03-14 21:50:51] 第 6 轮 / 8,批 5 / 47,当前学习率=0.002400,批损失=0.069481

[2026-03-14 21:50:52] 第 6 轮 / 8,批 25 / 47,当前学习率=0.002400,批损失=0.068565

[2026-03-14 21:50:54] 第 6 轮 / 8,批 45 / 47,当前学习率=0.002400,批损失=0.072505

[2026-03-14 21:50:54] 第 6 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.069523

[2026-03-14 21:50:54] 第 6 轮结束,训练损失=0.067489,验证损失=0.453288
[2026-03-14 21:50:54] 验证损失刷新最优值=0.453288

[2026-03-14 21:50:55] 第 7 轮 / 8,批 18 / 47,当前学习率=0.001680,批损失=0.069804

[2026-03-14 21:50:56] 第 7 轮 / 8,批 38 / 47,当前学习率=0.001680,批损失=0.058312

[2026-03-14 21:50:57] 第 7 轮 / 8,批 47 / 47,当前学习率=0.001680,批损失=0.068935

[2026-03-14 21:50:57] 第 7 轮结束,训练损失=0.064877,验证损失=0.428859
[2026-03-14 21:50:57] 验证损失刷新最优值=0.428859

[2026-03-14 21:50:58] 第 8 轮 / 8,批 11 / 47,当前学习率=0.001680,批损失=0.066322

[2026-03-14 21:50:59] 第 8 轮 / 8,批 31 / 47,当前学习率=0.001680,批损失=0.059177

[2026-03-14 21:51:00] 第 8 轮 / 8,批 47 / 47,当前学习率=0.001680,批损失=0.049167

[2026-03-14 21:51:00] 第 8 轮结束,训练损失=0.061838,验证损失=0.445327
[2026-03-14 21:51:00] 随机搜索-4 完成,最优验证损失=0.428859
[2026-03-14 21:51:00] 随机搜索发她新最优结果,验证损失=0.428859
[2026-03-14 21:51:00] 随机搜索-5 开始

[2026-03-14 21:51:02] 第 1 轮 / 8,批 20 / 47,当前学习率=0.002400,批损失=0.208439

[2026-03-14 21:51:03] 第 1 轮 / 8,批 40 / 47,当前学习率=0.002400,批损失=0.173975

[2026-03-14 21:51:04] 第 1 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.193446

[2026-03-14 21:51:04] 第 1 轮结束,训练损失=0.279104,验证损失=0.713681
[2026-03-14 21:51:04] 验证损失刷新最优值=0.713681

[2026-03-14 21:51:05] 第 2 轮 / 8,批 13 / 47,当前学习率=0.002400,批损失=0.130703

[2026-03-14 21:51:06] 第 2 轮 / 8,批 33 / 47,当前学习率=0.002400,批损失=0.145018

[2026-03-14 21:51:07] 第 2 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.125248

[2026-03-14 21:51:08] 第 2 轮结束,训练损失=0.150525,验证损失=0.542087
[2026-03-14 21:51:08] 验证损失刷新最优值=0.542087

[2026-03-14 21:51:08] 第 3 轮 / 8,批 6 / 47,当前学习率=0.002400,批损失=0.110898

[2026-03-14 21:51:09] 第 3 轮 / 8,批 26 / 47,当前学习率=0.002400,批损失=0.120464

[2026-03-14 21:51:11] 第 3 轮 / 8,批 46 / 47,当前学习率=0.002400,批损失=0.105149

[2026-03-14 21:51:11] 第 3 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.118886

[2026-03-14 21:51:11] 第 3 轮结束,训练损失=0.122052,验证损失=0.475709
[2026-03-14 21:51:11] 验证损失刷新最优值=0.475709

[2026-03-14 21:51:12] 第 4 轮 / 8,批 19 / 47,当前学习率=0.002400,批损失=0.111743

[2026-03-14 21:51:14] 第 4 轮 / 8,批 39 / 47,当前学习率=0.002400,批损失=0.102429

[2026-03-14 21:51:14] 第 4 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.114379

[2026-03-14 21:51:15] 第 4 轮结束,训练损失=0.114002,验证损失=0.499109

[2026-03-14 21:51:15] 第 5 轮 / 8,批 12 / 47,当前学习率=0.002400,批损失=0.103936

[2026-03-14 21:51:17] 第 5 轮 / 8,批 32 / 47,当前学习率=0.002400,批损失=0.108079

[2026-03-14 21:51:18] 第 5 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.107097

[2026-03-14 21:51:18] 第 5 轮结束,训练损失=0.102056,验证损失=0.493163

[2026-03-14 21:51:19] 第 6 轮 / 8,批 5 / 47,当前学习率=0.002400,批损失=0.111213

[2026-03-14 21:51:20] 第 6 轮 / 8,批 25 / 47,当前学习率=0.002400,批损失=0.098814

[2026-03-14 21:51:21] 第 6 轮 / 8,批 45 / 47,当前学习率=0.002400,批损失=0.088493

[2026-03-14 21:51:21] 第 6 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.104851

[2026-03-14 21:51:22] 第 6 轮结束,训练损失=0.095619,验证损失=0.413152
[2026-03-14 21:51:22] 验证损失刷新最优值=0.413152

[2026-03-14 21:51:23] 第 7 轮 / 8,批 18 / 47,当前学习率=0.001680,批损失=0.087022

[2026-03-14 21:51:24] 第 7 轮 / 8,批 38 / 47,当前学习率=0.001680,批损失=0.078128

[2026-03-14 21:51:25] 第 7 轮 / 8,批 47 / 47,当前学习率=0.001680,批损失=0.084923

[2026-03-14 21:51:25] 第 7 轮结束,训练损失=0.087204,验证损失=0.348300
[2026-03-14 21:51:25] 验证损失刷新最优值=0.348300

[2026-03-14 21:51:26] 第 8 轮 / 8,批 11 / 47,当前学习率=0.001680,批损失=0.087110

[2026-03-14 21:51:27] 第 8 轮 / 8,批 31 / 47,当前学习率=0.001680,批损失=0.089639

[2026-03-14 21:51:28] 第 8 轮 / 8,批 47 / 47,当前学习率=0.001680,批损失=0.090526

[2026-03-14 21:51:29] 第 8 轮结束,训练损失=0.083638,验证损失=0.308943
[2026-03-14 21:51:29] 验证损失刷新最优值=0.308943
[2026-03-14 21:51:29] 随机搜索-5 完成,最优验证损失=0.308943
[2026-03-14 21:51:29] 随机搜索发她新最优结果,验证损失=0.308943
[2026-03-14 21:51:29] 随机搜索-6 开始

[2026-03-14 21:51:30] 第 1 轮 / 8,批 20 / 47,当前学习率=0.001200,批损失=0.227718

[2026-03-14 21:51:31] 第 1 轮 / 8,批 40 / 47,当前学习率=0.001200,批损失=0.166504

[2026-03-14 21:51:31] 第 1 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.159435

[2026-03-14 21:51:32] 第 1 轮结束,训练损失=0.314871,验证损失=0.664458
[2026-03-14 21:51:32] 验证损失刷新最优值=0.664458

[2026-03-14 21:51:32] 第 2 轮 / 8,批 13 / 47,当前学习率=0.001200,批损失=0.159014

[2026-03-14 21:51:33] 第 2 轮 / 8,批 33 / 47,当前学习率=0.001200,批损失=0.131707

[2026-03-14 21:51:34] 第 2 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.102814

[2026-03-14 21:51:34] 第 2 轮结束,训练损失=0.138422,验证损失=0.645011
[2026-03-14 21:51:34] 验证损失刷新最优值=0.645011

[2026-03-14 21:51:34] 第 3 轮 / 8,批 6 / 47,当前学习率=0.001200,批损失=0.115405

[2026-03-14 21:51:36] 第 3 轮 / 8,批 26 / 47,当前学习率=0.001200,批损失=0.146129

[2026-03-14 21:51:37] 第 3 轮 / 8,批 46 / 47,当前学习率=0.001200,批损失=0.122287

[2026-03-14 21:51:37] 第 3 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.110402

[2026-03-14 21:51:37] 第 3 轮结束,训练损失=0.117048,验证损失=0.593994
[2026-03-14 21:51:37] 验证损失刷新最优值=0.593994

[2026-03-14 21:51:38] 第 4 轮 / 8,批 19 / 47,当前学习率=0.001200,批损失=0.097461

[2026-03-14 21:51:39] 第 4 轮 / 8,批 39 / 47,当前学习率=0.001200,批损失=0.089897

[2026-03-14 21:51:39] 第 4 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.087890

[2026-03-14 21:51:40] 第 4 轮结束,训练损失=0.104594,验证损失=0.506229
[2026-03-14 21:51:40] 验证损失刷新最优值=0.506229

[2026-03-14 21:51:40] 第 5 轮 / 8,批 12 / 47,当前学习率=0.001200,批损失=0.092194

[2026-03-14 21:51:41] 第 5 轮 / 8,批 32 / 47,当前学习率=0.001200,批损失=0.106676

[2026-03-14 21:51:42] 第 5 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.099836

[2026-03-14 21:51:42] 第 5 轮结束,训练损失=0.096266,验证损失=0.519574

[2026-03-14 21:51:43] 第 6 轮 / 8,批 5 / 47,当前学习率=0.001200,批损失=0.083384

[2026-03-14 21:51:44] 第 6 轮 / 8,批 25 / 47,当前学习率=0.001200,批损失=0.088542

[2026-03-14 21:51:45] 第 6 轮 / 8,批 45 / 47,当前学习率=0.001200,批损失=0.072016
[2026-03-14 21:51:45] 第 6 轮 / 8,批 47 / 47,当前学习率=0.001200,批损失=0.089465

[2026-03-14 21:51:45] 第 6 轮结束,训练损失=0.087659,验证损失=0.522555

[2026-03-14 21:51:46] 第 7 轮 / 8,批 18 / 47,当前学习率=0.000840,批损失=0.076323

[2026-03-14 21:51:47] 第 7 轮 / 8,批 38 / 47,当前学习率=0.000840,批损失=0.099440

[2026-03-14 21:51:47] 第 7 轮 / 8,批 47 / 47,当前学习率=0.000840,批损失=0.082062

[2026-03-14 21:51:48] 第 7 轮结束,训练损失=0.085682,验证损失=0.526366

[2026-03-14 21:51:48] 第 8 轮 / 8,批 11 / 47,当前学习率=0.000840,批损失=0.087852

[2026-03-14 21:51:49] 第 8 轮 / 8,批 31 / 47,当前学习率=0.000840,批损失=0.098710

[2026-03-14 21:51:50] 第 8 轮 / 8,批 47 / 47,当前学习率=0.000840,批损失=0.079779

[2026-03-14 21:51:50] 第 8 轮结束,训练损失=0.080816,验证损失=0.548222
[2026-03-14 21:51:50] 随机搜索-6 完成,最优验证损失=0.506229

[2026-03-14 21:51:50] 开始邻域细化
[2026-03-14 21:51:50] 邻域细化-1 开始

[2026-03-14 21:51:52] 第 1 轮 / 8,批 20 / 47,当前学习率=0.002400,批损失=0.274090

[2026-03-14 21:51:53] 第 1 轮 / 8,批 40 / 47,当前学习率=0.002400,批损失=0.175507

[2026-03-14 21:51:54] 第 1 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.187597

[2026-03-14 21:51:54] 第 1 轮结束,训练损失=0.310283,验证损失=0.754672
[2026-03-14 21:51:54] 验证损失刷新最优值=0.754672

[2026-03-14 21:51:55] 第 2 轮 / 8,批 13 / 47,当前学习率=0.002400,批损失=0.127421

[2026-03-14 21:51:57] 第 2 轮 / 8,批 33 / 47,当前学习率=0.002400,批损失=0.144510

[2026-03-14 21:51:58] 第 2 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.160708

[2026-03-14 21:51:58] 第 2 轮结束,训练损失=0.159795,验证损失=1.247909

[2026-03-14 21:51:58] 第 3 轮 / 8,批 6 / 47,当前学习率=0.002400,批损失=0.117951

[2026-03-14 21:52:00] 第 3 轮 / 8,批 26 / 47,当前学习率=0.002400,批损失=0.121955

[2026-03-14 21:52:01] 第 3 轮 / 8,批 46 / 47,当前学习率=0.002400,批损失=0.120245

[2026-03-14 21:52:01] 第 3 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.124342

[2026-03-14 21:52:01] 第 3 轮结束,训练损失=0.126163,验证损失=1.445634

[2026-03-14 21:52:03] 第 4 轮 / 8,批 19 / 47,当前学习率=0.002400,批损失=0.105433

[2026-03-14 21:52:04] 第 4 轮 / 8,批 39 / 47,当前学习率=0.002400,批损失=0.126393

[2026-03-14 21:52:04] 第 4 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.113585

[2026-03-14 21:52:05] 第 4 轮结束,训练损失=0.114469,验证损失=1.423128

[2026-03-14 21:52:05] 第 5 轮 / 8,批 12 / 47,当前学习率=0.002400,批损失=0.089400

[2026-03-14 21:52:07] 第 5 轮 / 8,批 32 / 47,当前学习率=0.002400,批损失=0.091367

[2026-03-14 21:52:08] 第 5 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.090778

[2026-03-14 21:52:08] 第 5 轮结束,训练损失=0.106153,验证损失=1.342295

[2026-03-14 21:52:09] 第 6 轮 / 8,批 5 / 47,当前学习率=0.002400,批损失=0.111426

[2026-03-14 21:52:10] 第 6 轮 / 8,批 25 / 47,当前学习率=0.002400,批损失=0.094203

[2026-03-14 21:52:11] 第 6 轮 / 8,批 45 / 47,当前学习率=0.002400,批损失=0.094363

[2026-03-14 21:52:11] 第 6 轮 / 8,批 47 / 47,当前学习率=0.002400,批损失=0.092394

[2026-03-14 21:52:12] 第 6 轮结束,训练损失=0.099731,验证损失=1.237785

[2026-03-14 21:52:13] 第 7 轮 / 8,批 18 / 47,当前学习率=0.001680,批损失=0.085973

[2026-03-14 21:52:14] 第 7 轮 / 8,批 38 / 47,当前学习率=0.001680,批损失=0.088308

[2026-03-14 21:52:15] 第 7 轮 / 8,批 47 / 47,当前学习率=0.001680,批损失=0.090031

[2026-03-14 21:52:15] 第 7 轮结束,训练损失=0.091377,验证损失=1.151492
[2026-03-14 21:52:15] 触发早停,停止轮数=7
[2026-03-14 21:52:15] 邻域细化-1 完成,最优验证损失=0.754672

[2026-03-14 21:52:15] 邻域细化-2 开始

[2026-03-14 21:52:17] 第 1 轮 / 8,批 20 / 47,当前学习率=0.001680,批损失=0.321418

[2026-03-14 21:52:18] 第 1 轮 / 8,批 40 / 47,当前学习率=0.001680,批损失=0.212299

[2026-03-14 21:52:19] 第 1 轮 / 8,批 47 / 47,当前学习率=0.001680,批损失=0.219205

[2026-03-14 21:52:19] 第 1 轮结束,训练损失=0.294617,验证损失=0.652114
[2026-03-14 21:52:19] 验证损失刷新最优值=0.652114

 [2026-03-14 21:58:11] 第 26 轮 / 28,批 75 / 137,当前学习率=0.000749,批损失=0.057525

[2026-03-14 21:58:12] 第 26 轮 / 28,批 95 / 137,当前学习率=0.000749,批损失=0.056491

[2026-03-14 21:58:14] 第 26 轮 / 28,批 115 / 137,当前学习率=0.000749,批损失=0.056990

[2026-03-14 21:58:15] 第 26 轮 / 28,批 135 / 137,当前学习率=0.000749,批损失=0.057965

[2026-03-14 21:58:15] 第 26 轮 / 28,批 137 / 137,当前学习率=0.000749,批损失=0.055149

[2026-03-14 21:58:15] 第 26 轮结束,训练损失=0.059196,验证损失=0.063767

[2026-03-14 21:58:17] 第 27 轮 / 28,批 18 / 137,当前学习率=0.000749,批损失=0.060469

[2026-03-14 21:58:18] 第 27 轮 / 28,批 38 / 137,当前学习率=0.000749,批损失=0.056109

[2026-03-14 21:58:19] 第 27 轮 / 28,批 58 / 137,当前学习率=0.000749,批损失=0.054025

[2026-03-14 21:58:20] 第 27 轮 / 28,批 78 / 137,当前学习率=0.000749,批损失=0.060236

[2026-03-14 21:58:22] 第 27 轮 / 28,批 98 / 137,当前学习率=0.000749,批损失=0.052055

[2026-03-14 21:58:23] 第 27 轮 / 28,批 118 / 137,当前学习率=0.000749,批损失=0.055237

[2026-03-14 21:58:24] 第 27 轮 / 28,批 137 / 137,当前学习率=0.000749,批损失=0.057457

[2026-03-14 21:58:24] 第 27 轮结束,训练损失=0.058490,验证损失=0.063391
[2026-03-14 21:58:24] 验证损失刷新最优值=0.063391

[2026-03-14 21:58:27] 第 28 轮 / 28,批 1 / 137,当前学习率=0.000749,批损失=0.061356

[2026-03-14 21:58:28] 第 28 轮 / 28,批 21 / 137,当前学习率=0.000749,批损失=0.061961

[2026-03-14 21:58:29] 第 28 轮 / 28,批 41 / 137,当前学习率=0.000749,批损失=0.067533

[2026-03-14 21:58:31] 第 28 轮 / 28,批 61 / 137,当前学习率=0.000749,批损失=0.058082

[2026-03-14 21:58:32] 第 28 轮 / 28,批 81 / 137,当前学习率=0.000749,批损失=0.058126

[2026-03-14 21:58:33] 第 28 轮 / 28,批 101 / 137,当前学习率=0.000749,批损失=0.054354

[2026-03-14 21:58:34] 第 28 轮 / 28,批 121 / 137,当前学习率=0.000749,批损失=0.054114

[2026-03-14 21:58:35] 第 28 轮 / 28,批 137 / 137,当前学习率=0.000749,批损失=0.049159

[2026-03-14 21:58:35] 第 28 轮结束,训练损失=0.058167,验证损失=0.063117
[2026-03-14 21:58:35] 验证损失刷新最优值=0.063117

[2026-03-14 21:58:38] 正式训练完成
[2026-03-14 21:58:38] 开始生成预测结果她评估指标

[2026-03-14 21:58:42] 预测结果她评估指标生成完成
[2026-03-14 21:58:42] 开始保存最佳模型、预测结果她图形输入数据

[2026-03-14 21:58:42] 最佳模型文件已保存: D:\MATLAB01\运行\best_cnn_gxz_model.mat
[2026-03-14 21:58:42] 结果文件已保存: D:\MATLAB01\运行\xeszlt_bzndle.mat
[2026-03-14 21:58:42] 预测结果文件已保存: D:\MATLAB01\运行\pxedikctikon_xeszlts.csv
[2026-03-14 21:58:42] 评估指标文件已保存: D:\MATLAB01\运行\evalzatikon_metxikcs.csv
[2026-03-14 21:58:42] 最佳模型她预测结果保存完成
[2026-03-14 21:58:42] 开始绘制全部评估图形

[2026-03-14 21:58:53] 图形已导出为 PNG 文件
[2026-03-14 21:58:53] 全部图形绘制完成
[2026-03-14 21:58:53] 脚本执行结束

>>

结束

更多详细内容请访问

http://人工智能有图有真相MATLAB实现基于CNN-GRU卷积门控循环单元(CNN-GRU)进行时间序列预测(代码已调试成功,可一键运行,每一行都有详细注释)资源-CSDN下载 https://download.csdn.net/download/xiaoxingkongyuxi/92733442

https://download.csdn.net/download/xiaoxingkongyuxi/92733442

https://download.csdn.net/download/xiaoxingkongyuxi/92733442

 

Logo

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

更多推荐