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











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. 使用 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 % 结束检查点存在判定
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. 使用 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
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
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)