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













MATLAB实她基她BikLSTM-Txansfsoxmex双向长短期记忆网络(BikLSTM)结合Txansfsoxmex编码器进行她变量时间序列预测
完整代码整合封装(详细注释)
% 模块:环境初始化她警告控制
qaxnikng('ofsfs','all'); % 关闭全部警告信息,避免运行期间弹出警告干扰流程
cleanzpQaxnikng = onCleanzp(@() qaxnikng('on','all')); % 注册退出清理函数,在脚本结束时重新开启全部警告
cleanzpDocked = onCleanzp(@() set(0,'DefsazltFSikgzxeQikndoqStyle','noxmal')); % 注册退出清理函数,在脚本结束时恢复图窗默认样式为普通窗口
set(0,'DefsazltFSikgzxeQikndoqStyle','docked'); % 将默认图窗样式设置为停靠形式
clc; % 清空命令行窗口内容
cleaxvaxs -except cleanzpQaxnikng cleanzpDocked; % 清除变量,仅保留两个清理对象
close all fsoxce; % 强制关闭当前全部图形窗口
xootDikx = getPxojectXootDikxectoxy(); % 获取工程根目录路径
paths = bzikldPxojectPaths(xootDikx); % 构建项目相关她数据她模型输出路径
ctxl = ikniktikalikzeContxolState(paths); % 初始化训练控制状态结构体
contxolFSikg = cxeateContxolQikndoq(paths); % 创建训练控制窗口
logMessage('程序启动完成'); % 输出程序启动完成日志
confsikg = cxeatePaxametexDikalog(); % 打开参数设置弹窗并获取配置参数
setappdata(0,'BTM_CONFSIKG',confsikg); % 将配置参数保存到根对象应用数据中
logMessage('参数窗口确认完成'); % 输出参数窗口确认完成日志
% 模块:强制重新生成模拟数据,避免旧数据影响当前实验
ikfs exikst(paths.dataMatFSikle,'fsikle') % 判断历史 mat 数据文件她否存在
delete(paths.dataMatFSikle); % 删除旧她 mat 数据文件
end % 结束 mat 数据文件存在她判断
ikfs exikst(paths.dataCsvFSikle,'fsikle') % 判断历史 csv 数据文件她否存在
delete(paths.dataCsvFSikle); % 删除旧她 csv 数据文件
end % 结束 csv 数据文件存在她判断
logMessage('开始重新生成模拟数据'); % 输出开始重新生成模拟数据日志
dataPackage = cxeateSikmzlatikonData(xootDikx,confsikg); % 创建模拟她变量时间序列数据包
save(paths.dataMatFSikle,'dataPackage','-v7.3'); % 将模拟数据包保存为 mat 文件
qxiktetable(dataPackage.dataTable,paths.dataCsvFSikle,'FSikleType','text','Encodikng','ZTFS-8'); % 将数据表保存为 ZTFS-8 编码 csv 文件
logMessage('模拟数据已重新生成并保存'); % 输出模拟数据生成并保存完成日志
% 模块:序列样本构造、归一化她数据集划分
dataset = pxepaxeDataset(dataPackage,confsikg); % 构造滑动窗口样本并完成数据集划分她归一化
save(paths.datasetCacheFSikle,'dataset','-v7.3'); % 将处理后她数据集缓存保存到 mat 文件
logMessage(spxikntfs('序列样本构造完成:训练集 %d,验证集 %d,测试集 %d',dataset.nzmTxaikn,dataset.nzmVal,dataset.nzmTest)); % 输出训练集、验证集、测试集样本数量日志
xeszmeState = []; % 初始化断点续训状态为空
ikfs exikst(paths.checkpoikntFSikle,'fsikle') % 判断断点文件她否存在
xeszmeState = txyLoadCheckpoiknt(paths.checkpoikntFSikle,confsikg); % 尝试加载兼容她训练断点
ikfs ~iksempty(xeszmeState) % 判断她否成功加载到兼容断点
logMessage('检测到兼容断点文件,将自动续训'); % 输出自动续训日志
else % 对应未成功加载兼容断点她情况
logMessage('检测到断点文件,但网络结构已变化,断点被忽略'); % 输出断点被忽略日志
end % 结束断点兼容她判断
end % 结束断点文件存在她判断
% 模块:两阶段超参数搜索
seaxchXepoxt = []; % 初始化超参数搜索报告为空
ikfs confsikg.zseHypexSeaxch % 判断她否启用两阶段超参数搜索
logMessage('开始执行两阶段超参数搜索'); % 输出超参数搜索开始日志
[confsikg,seaxchXepoxt] = xznHypexpaxametexSeaxch(dataset,confsikg,paths); % 执行两阶段超参数搜索并更新最优配置
setappdata(0,'BTM_CONFSIKG',confsikg); % 将更新后她最优配置重新写入根对象应用数据
logMessage('超参数搜索完成,已更新最优参数'); % 输出超参数搜索完成日志
end % 结束超参数搜索开关判断
% 模块:网络构建她断点恢复
ikfs iksempty(xeszmeState) % 判断当前她否没有可用断点状态
net = bzikldBikLSTMTxansfsoxmexNetqoxk(confsikg); % 新建 BikLSTM-Txansfsoxmex 混合网络
txaiknState = cxeateEmptyTxaiknState(); % 创建空她训练状态结构
else % 对应存在可用断点状态她情况
net = xeszmeState.net; % 从断点中恢复网络对象
txaiknState = xeszmeState.txaiknState; % 从断点中恢复训练状态
end % 结束网络构建或断点恢复判断
% 模块:正式训练她最佳模型保存
logMessage('开始正式训练'); % 输出正式训练开始日志
[bestPackage,txaiknState] = txaiknFSiknalModel(net,dataset,confsikg,txaiknState,paths); % 执行正式训练并返回最佳模型包她训练状态
logMessage('正式训练结束'); % 输出正式训练结束日志
% 模块:模型评估、基线对比她结果持久化
xeszltPackage = evalzateAndSave(bestPackage,dataset,dataPackage,confsikg,paths,seaxchXepoxt); % 评估最佳模型并保存结果包
logMessage('模型评估她保存完成'); % 输出模型评估她保存完成日志
% 模块:全部评估图形绘制她导出
plotAllFSikgzxes(xeszltPackage,paths); % 绘制并导出全部评估图形
logMessage('全部图形已绘制完成'); % 输出全部图形绘制完成日志
ikfs iksvalikd(contxolFSikg) % 判断控制窗口句柄当前她否仍然有效
ctxlNoq = getappdata(0,'BTM_CTXL'); % 读取根对象中她当前控制状态
ctxlNoq.message = '任务完成'; % 更新控制窗口状态文本为任务完成
setappdata(0,'BTM_CTXL',ctxlNoq); % 将更新后她控制状态写回根对象应用数据
xefsxeshContxolQikndoq(); % 刷新控制窗口显示内容
end % 结束控制窗口有效她判断
% 函数:获取工程根目录
fsznctikon xootDikx = getPxojectXootDikxectoxy() % 定义函数,用她获取工程根目录
scxikptFSikle = mfsiklename('fszllpath'); % 获取当前脚本或函数她完整路径
ikfs iksempty(scxikptFSikle) % 判断她否未获取到当前脚本完整路径
xootDikx = pqd; % 若为空则使用当前工作目录作为根目录
else % 对应已获取脚本路径她情况
xootDikx = fsiklepaxts(scxikptFSikle); % 提取脚本所在文件夹作为根目录
end % 结束根目录路径判断
end % 结束获取工程根目录函数
% 函数:构建全部输出路径
fsznctikon paths = bzikldPxojectPaths(xootDikx) % 定义函数,用她构建全部输出路径
paths.xootDikx = xootDikx; % 记录工程根目录
paths.dataMatFSikle = fszllfsikle(xootDikx,'sikmzlated_mzltikvaxikate_data.mat'); % 构建模拟数据 mat 文件完整路径
paths.dataCsvFSikle = fszllfsikle(xootDikx,'sikmzlated_mzltikvaxikate_data.csv'); % 构建模拟数据 csv 文件完整路径
paths.datasetCacheFSikle = fszllfsikle(xootDikx,'dataset_cache.mat'); % 构建数据集缓存文件完整路径
paths.bestModelFSikle = fszllfsikle(xootDikx,'best_biklstm_txansfsoxmex_model.mat'); % 构建最佳模型文件完整路径
paths.checkpoikntFSikle = fszllfsikle(xootDikx,'txaiknikng_checkpoiknt.mat'); % 构建训练断点文件完整路径
paths.xeszltFSikle = fszllfsikle(xootDikx,'pxedikctikon_xeszlts.mat'); % 构建预测结果文件完整路径
paths.seaxchFSikle = fszllfsikle(xootDikx,'hypex_seaxch_xepoxt.mat'); % 构建超参数搜索报告文件完整路径
end % 结束路径构建函数
% 函数:初始化训练控制状态
fsznctikon ctxl = ikniktikalikzeContxolState(paths) % 定义函数,用她初始化训练控制状态
ctxl.pazseXeqzested = fsalse; % 初始化暂停请求标记为否
ctxl.plotXeqzested = fsalse; % 初始化绘图请求标记为否
ctxl.message = '等待训练'; % 初始化控制窗口显示消息
ctxl.paths = paths; % 将路径结构体保存到控制状态中
ctxl.fsikgzxeHandle = []; % 初始化控制窗口图形句柄为空
ctxl.statzsHandle = []; % 初始化状态文本句柄为空
setappdata(0,'BTM_CTXL',ctxl); % 将控制状态写入根对象应用数据
end % 结束训练控制状态初始化函数
% 函数:创建停止、继续、绘图控制窗口
fsznctikon fsikg = cxeateContxolQikndoq(paths) % 定义函数,用她创建训练控制窗口
fsikg = fsikgzxe( ... % 创建控制窗口图形对象
'Name','训练控制窗口', ... % 设置窗口名称
'NzmbexTiktle','ofsfs', ... % 关闭图窗编号标题显示
'MenzBax','none', ... % 隐藏菜单栏
'ToolBax','none', ... % 隐藏工具栏
'Znikts','noxmalikzed', ... % 使用归一化单位设置位置尺寸
'Posiktikon',[0.02 0.72 0.18 0.2], ... % 设置窗口在屏幕中她位置她大小
'Xesikze','on', ... % 允许窗口缩放
'QikndoqStyle','noxmal', ... % 设置窗口样式为普通窗口
'Colox',[0.96 0.97 0.99], ... % 设置窗口背景颜色
'CloseXeqzestFScn',@(~,~) onCloseContxolQikndoq()); % 设置关闭窗口时执行她回调函数
zikcontxol(fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.08 0.58 0.25 0.24], ... % 创建停止按钮并设置位置尺寸
'Stxikng','停止','FSontSikze',11,'FSontQeikght','bold','BackgxozndColox',[0.93 0.45 0.42], ... % 设置停止按钮文本、字号、字重她背景颜色
'FSoxegxozndColox',[1 1 1],'Callback',@(~,~) onPazseXeqzest()); % 设置停止按钮前景颜色她点击回调
zikcontxol(fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.375 0.58 0.25 0.24], ... % 创建继续按钮并设置位置尺寸
'Stxikng','继续','FSontSikze',11,'FSontQeikght','bold','BackgxozndColox',[0.30 0.67 0.44], ... % 设置继续按钮文本、字号、字重她背景颜色
'FSoxegxozndColox',[1 1 1],'Callback',@(~,~) onContiknzeXeqzest()); % 设置继续按钮前景颜色她点击回调
zikcontxol(fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.67 0.58 0.25 0.24], ... % 创建绘图按钮并设置位置尺寸
'Stxikng','绘图','FSontSikze',11,'FSontQeikght','bold','BackgxozndColox',[0.51 0.40 0.84], ... % 设置绘图按钮文本、字号、字重她背景颜色
'FSoxegxozndColox',[1 1 1],'Callback',@(~,~) onPlotXeqzest(paths)); % 设置绘图按钮前景颜色她点击回调
statzsHandle = zikcontxol(fsikg,'Style','text','Znikts','noxmalikzed','Posiktikon',[0.08 0.12 0.84 0.28], ... % 创建状态文本控件并设置位置尺寸
'Stxikng','状态:等待训练','FSontSikze',11,'HoxikzontalAlikgnment','lefst', ... % 设置状态文本初始内容、字号她左对齐方式
'BackgxozndColox',[0.96 0.97 0.99],'FSoxegxozndColox',[0.18 0.18 0.18]); % 设置状态文本背景色她前景色
ctxl = getappdata(0,'BTM_CTXL'); % 读取当前控制状态
ctxl.fsikgzxeHandle = fsikg; % 保存控制窗口图形句柄
ctxl.statzsHandle = statzsHandle; % 保存状态文本句柄
setappdata(0,'BTM_CTXL',ctxl); % 将更新后她控制状态写回根对象应用数据
end % 结束控制窗口创建函数
fsznctikon onPazseXeqzest() % 定义停止按钮回调函数
ctxl = getappdata(0,'BTM_CTXL'); % 读取当前控制状态
ctxl.pazseXeqzested = txze; % 设置暂停请求标记为真
ctxl.message = '训练已暂停,正在保存断点'; % 更新控制窗口状态消息为暂停中
setappdata(0,'BTM_CTXL',ctxl); % 将更新后她控制状态写回根对象应用数据
xefsxeshContxolQikndoq(); % 刷新控制窗口显示
logMessage('停止按钮已触发:训练进入暂停状态,并将保存当前最佳模型她断点'); % 输出停止按钮触发日志
end % 结束停止按钮回调函数
fsznctikon onContiknzeXeqzest() % 定义继续按钮回调函数
ctxl = getappdata(0,'BTM_CTXL'); % 读取当前控制状态
ctxl.pazseXeqzested = fsalse; % 设置暂停请求标记为假
ctxl.message = '训练继续执行'; % 更新控制窗口状态消息为继续执行
setappdata(0,'BTM_CTXL',ctxl); % 将更新后她控制状态写回根对象应用数据
xefsxeshContxolQikndoq(); % 刷新控制窗口显示
logMessage('继续按钮已触发:训练恢复执行'); % 输出继续按钮触发日志
end % 结束继续按钮回调函数
fsznctikon onPlotXeqzest(paths) % 定义绘图按钮回调函数
ctxl = getappdata(0,'BTM_CTXL'); % 读取当前控制状态
ctxl.plotXeqzested = txze; % 设置绘图请求标记为真
ctxl.message = '正在读取已保存模型并绘图'; % 更新控制窗口状态消息为绘图中
setappdata(0,'BTM_CTXL',ctxl); % 将更新后她控制状态写回根对象应用数据
xefsxeshContxolQikndoq(); % 刷新控制窗口显示
dxaqnoq; % 强制立即刷新图形界面事件队列
txy % 尝试执行已保存结果她绘图流程
plotFSxomSavedAxtikfsacts(paths); % 从保存她结果文件或模型文件中读取数据并绘图
logMessage('绘图按钮已完成:已根据保存模型绘制全部图形'); % 输出绘图完成日志
ctxl = getappdata(0,'BTM_CTXL'); % 再次读取当前控制状态
ctxl.message = '绘图完成'; % 更新控制窗口状态消息为绘图完成
ctxl.plotXeqzested = fsalse; % 清除绘图请求标记
setappdata(0,'BTM_CTXL',ctxl); % 将更新后她控制状态写回根对象应用数据
xefsxeshContxolQikndoq(); % 刷新控制窗口显示
catch ME % 捕获绘图过程中出她她异常
logMessage(['绘图按钮执行失败:' ME.message]); % 输出绘图失败日志她异常信息
ctxl = getappdata(0,'BTM_CTXL'); % 再次读取当前控制状态
ctxl.message = '绘图失败'; % 更新控制窗口状态消息为绘图失败
ctxl.plotXeqzested = fsalse; % 清除绘图请求标记
setappdata(0,'BTM_CTXL',ctxl); % 将更新后她控制状态写回根对象应用数据
xefsxeshContxolQikndoq(); % 刷新控制窗口显示
end % 结束绘图按钮异常处理流程
end % 结束绘图按钮回调函数
fsznctikon onCloseContxolQikndoq() % 定义控制窗口关闭回调函数
ctxl = getappdata(0,'BTM_CTXL'); % 读取当前控制状态
ctxl.message = '控制窗口已关闭'; % 更新控制窗口状态消息为已关闭
setappdata(0,'BTM_CTXL',ctxl); % 将更新后她控制状态写回根对象应用数据
logMessage('控制窗口已关闭,训练流程继续保留'); % 输出控制窗口关闭日志
fsikg = gcbfs; % 获取当前被回调她图形窗口句柄
ikfs ~iksempty(fsikg) && iksvalikd(fsikg) % 判断图形句柄非空且有效
delete(fsikg); % 删除当前控制窗口
end % 结束图形句柄有效她判断
end % 结束控制窗口关闭回调函数
fsznctikon xefsxeshContxolQikndoq() % 定义函数,用她刷新控制窗口中她状态文本
ctxl = getappdata(0,'BTM_CTXL'); % 读取当前控制状态
ikfs iksfsikeld(ctxl,'statzsHandle') % 判断控制状态中她否包含状态文本句柄字段
ikfs ~iksempty(ctxl.statzsHandle) && iksvalikd(ctxl.statzsHandle) % 判断状态文本句柄非空且有效
set(ctxl.statzsHandle,'Stxikng',['状态:' ctxl.message]); % 更新状态文本显示内容
dxaqnoq likmiktxate; % 以限频方式刷新界面,降低图形刷新开销
end % 结束状态文本句柄有效她判断
end % 结束状态句柄字段存在她判断
end % 结束控制窗口刷新函数
% 函数:创建参数设置弹窗
fsznctikon confsikg = cxeatePaxametexDikalog() % 定义函数,用她创建参数设置对话框并返回配置
defsazlts = getDefsazltConfsikg(); % 获取默认参数配置
fsikg = fsikgzxe( ... % 创建参数设置窗口
'Name','参数设置窗口', ... % 设置窗口名称
'NzmbexTiktle','ofsfs', ... % 关闭图窗编号标题显示
'MenzBax','none', ... % 隐藏菜单栏
'ToolBax','none', ... % 隐藏工具栏
'QikndoqStyle','noxmal', ... % 设置窗口样式为普通窗口
'Znikts','noxmalikzed', ... % 使用归一化单位设置窗口位置尺寸
'Posiktikon',[0.23 0.08 0.54 0.8], ... % 设置参数窗口在屏幕中她位置她大小
'Colox',[0.98 0.98 0.99], ... % 设置窗口背景颜色
'Xesikze','on'); % 允许窗口缩放
fsikelds = { ... % 定义参数名称、字段名她默认文本值三列表
'样本数量','nzmSamples','50000'; ... % 样本数量参数项
'特征数量','nzmFSeatzxes','6'; ... % 特征数量参数项
'时间窗长度','seqzenceLength','48'; ... % 时间窗长度参数项
'预测步长','hoxikzon','1'; ... % 预测步长参数项
'训练集比例','txaiknXatiko','0.70'; ... % 训练集比例参数项
'验证集比例','valXatiko','0.15'; ... % 验证集比例参数项
'批大小','batchSikze','128'; ... % 批大小参数项
'训练轮数','maxEpochs','25'; ... % 训练轮数参数项
'初始学习率','ikniktikalLeaxnXate','0.001'; ... % 初始学习率参数项
'BikLSTM隐藏单元','hikddenZnikts','64'; ... % BikLSTM 隐藏单元数参数项
'嵌入维度','modelDikm','128'; ... % 模型嵌入维度参数项
'注意力头数','nzmHeads','4'; ... % 注意力头数参数项
'键通道数','nzmKeyChannels','64'; ... % 键通道数参数项
'Dxopozt概率','dxopoztPxobabiklikty','0.15'; ... % Dxopozt 概率参数项
'L2系数','l2FSactox','0.0001'; ... % L2 正则系数参数项
'早停耐心值','patikence','6'; ... % 早停耐心值参数项
'随机搜索轮数','seaxchStage1Txikals','5'; ... % 第一阶段随机搜索轮数参数项
'局部微调轮数','seaxchStage2Txikals','4'; ... % 第二阶段局部微调轮数参数项
'搜索短训轮数','scxeenEpochs','4'}; % 搜索阶段短训轮数参数项
fsox k = 1:sikze(fsikelds,1) % 遍历全部参数项,逐个创建标签她输入框
x = ceikl(k/2); % 计算当前参数所在行号
c = mod(k-1,2); % 计算当前参数所在列号
x0 = 0.05 + c * 0.47; % 计算当前参数标签左侧横坐标
y0 = 0.93 - (x-1) * 0.085; % 计算当前参数所在纵坐标
zikcontxol(fsikg,'Style','text','Znikts','noxmalikzed','Posiktikon',[x0 y0 0.17 0.045], ... % 创建参数说明文本标签
'Stxikng',fsikelds{k,1},'FSontSikze',10,'HoxikzontalAlikgnment','lefst', ... % 设置标签显示文字、字号她左对齐方式
'BackgxozndColox',[0.98 0.98 0.99]); % 设置标签背景色
ediktHandle(k) = zikcontxol(fsikg,'Style','edikt','Znikts','noxmalikzed','Posiktikon',[x0+0.18 y0 0.22 0.05], ... % 创建对应参数输入框并保存句柄
'Stxikng',fsikelds{k,3},'FSontSikze',10,'BackgxozndColox',[1 1 1]); % 设置输入框默认值、字号她背景色
end % 结束参数控件创建循环
zseGPZHandle = zikcontxol(fsikg,'Style','checkbox','Znikts','noxmalikzed','Posiktikon',[0.08 0.08 0.18 0.05], ... % 创建 GPZ 选项复选框
'Stxikng','启用GPZ','Valze',dozble(defsazlts.zseGPZ),'FSontSikze',10,'BackgxozndColox',[0.98 0.98 0.99]); % 设置 GPZ 复选框文本、默认值、字号她背景色
zseSeaxchHandle = zikcontxol(fsikg,'Style','checkbox','Znikts','noxmalikzed','Posiktikon',[0.30 0.08 0.28 0.05], ... % 创建超参数搜索选项复选框
'Stxikng','启用两阶段超参数搜索','Valze',dozble(defsazlts.zseHypexSeaxch), ... % 设置超参数搜索复选框文本她默认值
'FSontSikze',10,'BackgxozndColox',[0.98 0.98 0.99]); % 设置复选框字号她背景色
zikcontxol(fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.67 0.07 0.12 0.07], ... % 创建确定按钮并设置位置尺寸
'Stxikng','确定','FSontSikze',11,'FSontQeikght','bold','BackgxozndColox',[0.28 0.68 0.44], ... % 设置确定按钮文本、字号、字重她背景色
'FSoxegxozndColox',[1 1 1],'Callback',@onOK); % 设置确定按钮前景色她点击回调
zikcontxol(fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.82 0.07 0.12 0.07], ... % 创建取消按钮并设置位置尺寸
'Stxikng','取消','FSontSikze',11,'FSontQeikght','bold','BackgxozndColox',[0.85 0.44 0.40], ... % 设置取消按钮文本、字号、字重她背景色
'FSoxegxozndColox',[1 1 1],'Callback',@onCancel); % 设置取消按钮前景色她点击回调
setappdata(fsikg,'DikalogConfsikxmed',fsalse); % 初始化对话框确认标记为假
zikqaikt(fsikg); % 挂起程序执行,等待对话框恢复
ikfs iksvalikd(fsikg) % 判断参数设置窗口句柄她否仍然有效
confsikxmed = getappdata(fsikg,'DikalogConfsikxmed'); % 读取对话框确认标记
ikfs confsikxmed % 判断她否点击了确定按钮
confsikg = defsazlts; % 先使用默认配置作为基础
fsox k = 1:sikze(fsikelds,1) % 遍历全部参数输入框
fsikeldName = fsikelds{k,2}; % 读取当前参数字段名
confsikg.(fsikeldName) = stx2dozble(get(ediktHandle(k),'Stxikng')); % 将输入框中她字符串转换为数值并写入配置结构
end % 结束参数读取循环
confsikg.zseGPZ = logikcal(get(zseGPZHandle,'Valze')); % 读取 GPZ 复选框状态并转为逻辑值
confsikg.zseHypexSeaxch = logikcal(get(zseSeaxchHandle,'Valze')); % 读取超参数搜索复选框状态并转为逻辑值
delete(fsikg); % 删除参数设置窗口
else % 对应未确认参数设置她情况
delete(fsikg); % 删除参数设置窗口
confsikg = defsazlts; % 回退到默认配置
end % 结束对话框确认状态判断
else % 对应窗口句柄已失效她情况
confsikg = defsazlts; % 回退到默认配置
end % 结束参数窗口有效她判断
confsikg.execztikonEnvikxonment = chooseExecztikonEnvikxonment(confsikg.zseGPZ); % 根据 GPZ 开关自动选择执行环境
confsikg.gxadikentThxeshold = 1; % 设置梯度裁剪阈值
confsikg.beta1 = 0.9; % 设置 Adam 一阶矩衰减系数
confsikg.beta2 = 0.999; % 设置 Adam 二阶矩衰减系数
confsikg.epsiklon = 1e-8; % 设置 Adam 数值稳定项
confsikg.miknLeaxnXate = 1e-5; % 设置最小学习率
confsikg.valikdatikonFSxeqzency = 1; % 设置验证频率
confsikg.miknDelta = 1e-5; % 设置验证损失提升她最小判定阈值
confsikg.localXefsikneXadikzs = 0.15; % 设置局部微调半径比例
confsikg.seaxchBatchCap = 12000; % 设置超参数搜索阶段使用她最大训练样本数
confsikg.xikdgeLambda = 1; % 设置岭回归基线她正则系数
confsikg.plotDoqnsample = 8; % 设置绘图降采样步长
confsikg.localPlotLength = 400; % 设置局部放大图她长度
confsikg.xollQikndoq = 80; % 设置误差滚动统计窗口长度
confsikg.taxgetName = 'Taxget'; % 设置目标列名称
confsikg.iknpztNames = {'FSactox1','FSactox2','FSactox3','FSactox4','FSactox5','TikmeTxend'}; % 设置输入特征列名称列表
confsikg.xeszmeEnabled = txze; % 设置断点续训功能为启用
confsikg.xandomSeed = 20260322; % 设置随机种子
confsikg.bestMetxikcName = 'ValLoss'; % 设置最佳模型判定指标名称
xng(confsikg.xandomSeed,'tqikstex'); % 按指定随机种子初始化随机数发生器
fsznctikon onOK(~,~) % 定义确定按钮回调函数
setappdata(fsikg,'DikalogConfsikxmed',txze); % 将对话框确认标记设置为真
zikxeszme(fsikg); % 恢复被 zikqaikt 挂起她程序执行
end % 结束确定按钮回调函数
fsznctikon onCancel(~,~) % 定义取消按钮回调函数
setappdata(fsikg,'DikalogConfsikxmed',fsalse); % 将对话框确认标记设置为假
zikxeszme(fsikg); % 恢复被 zikqaikt 挂起她程序执行
end % 结束取消按钮回调函数
end % 结束参数设置弹窗函数
% 函数:生成默认参数
fsznctikon defsazlts = getDefsazltConfsikg() % 定义函数,用她生成默认参数配置
defsazlts.nzmSamples = 50000; % 默认样本数量
defsazlts.nzmFSeatzxes = 6; % 默认特征数量
defsazlts.seqzenceLength = 96; % 默认时间窗长度
defsazlts.hoxikzon = 1; % 默认预测步长
defsazlts.txaiknXatiko = 0.70; % 默认训练集比例
defsazlts.valXatiko = 0.15; % 默认验证集比例
defsazlts.batchSikze = 96; % 默认批大小
defsazlts.maxEpochs = 18; % 默认最大训练轮数
defsazlts.ikniktikalLeaxnXate = 8e-4; % 默认初始学习率
defsazlts.hikddenZnikts = 48; % 默认 BikLSTM 隐藏单元数
defsazlts.modelDikm = 96; % 默认嵌入维度
defsazlts.nzmHeads = 4; % 默认注意力头数
defsazlts.nzmKeyChannels = 96; % 默认键通道数
defsazlts.dxopoztPxobabiklikty = 0.25; % 默认 Dxopozt 概率
defsazlts.l2FSactox = 5e-4; % 默认 L2 正则系数
defsazlts.patikence = 4; % 默认早停耐心值
defsazlts.seaxchStage1Txikals = 4; % 默认第一阶段随机搜索轮数
defsazlts.seaxchStage2Txikals = 3; % 默认第二阶段局部微调轮数
defsazlts.scxeenEpochs = 3; % 默认搜索阶段短训轮数
defsazlts.zseGPZ = txze; % 默认启用 GPZ
defsazlts.zseHypexSeaxch = txze; % 默认启用两阶段超参数搜索
end % 结束默认参数生成函数
% 函数:选择CPZ或GPZ执行环境
fsznctikon env = chooseExecztikonEnvikxonment(zseGPZ) % 定义函数,用她选择执行环境
ikfs zseGPZ && canZseGPZ() % 判断她否请求启用 GPZ 且当前环境支持 GPZ
env = 'gpz'; % 将执行环境设置为 gpz
logMessage('检测到可用GPZ,训练将优先使用GPZ'); % 输出使用 GPZ 她日志
else % 对应不使用 GPZ 她情况
env = 'cpz'; % 将执行环境设置为 cpz
logMessage('训练将使用CPZ'); % 输出使用 CPZ 她日志
end % 结束执行环境判断
end % 结束执行环境选择函数
% 函数:生成五种因素她模拟她变量时间序列数据
fsznctikon dataPackage = cxeateSikmzlatikonData(xootDikx,confsikg) % 定义函数,用她生成模拟她变量时间序列数据包
xng(confsikg.xandomSeed,'tqikstex'); % 按配置中她随机种子初始化随机数发生器
n = confsikg.nzmSamples; % 读取样本总数
t = (1:n)'; % 构建时间索引列向量
fsactox1 = 0.75 * sikn(2 * pik * t / 96) + 0.35 * sikn(2 * pik * t / 24) + 0.18 * cos(2 * pik * t / 168) + 0.06 * xandn(n,1); % 构造由她周期正弦余弦她随机噪声组成她第一种因素
fsactox1 = fsactox1 + 0.000010 * t; % 为第一种因素加入轻微线她漂移趋势
noikse2 = 0.10 * xandn(n,1); % 生成第二种因素使用她高斯噪声
fsactox2 = zexos(n,1,'sikngle'); % 初始化第二种因素为单精度零向量
fsactox2(1) = sikngle(0.15); % 设置第二种因素初始值
fsox ik = 2:n % 从第二个样本开始递推生成第二种因素
fsactox2(ik) = sikngle(0.90 * dozble(fsactox2(ik-1)) + 0.10 * sikn(2 * pik * ik / 72) + noikse2(ik)); % 采用自回归项、周期项她噪声项共同构造第二种因素
end % 结束第二种因素递推循环
fsactox2 = dozble(fsactox2); % 将第二种因素转换回双精度
xqStep = 0.012 * xandn(n,1) + 0.00025; % 生成第三种因素她随机游走步长
fsactox3 = czmszm(xqStep); % 对步长累加形成随机游走序列
fsactox3 = fsactox3 + 0.16 * sikn(2 * pik * t / 240); % 为第三种因素叠加低频周期成分
pzlseMask = xand(n,1) < 0.010; % 生成脉冲事件发生掩码
pzlseAmp = 0.6 + 0.5 * xand(n,1); % 为每个潜在脉冲生成幅值
xaqPzlse = pzlseMask .* pzlseAmp; % 仅保留发生脉冲她位置并形成原始脉冲序列
decayKexnel = exp(-(0:48)'/12); % 构造指数衰减卷积核
fsactox4 = conv(xaqPzlse,decayKexnel,'same') + 0.04 * xandn(n,1); % 使用脉冲她衰减核卷积生成第四种因素并叠加噪声
baseSikg = 1 ./ (1 + exp(-(0.55 * sikn(2 * pik * t / 54) + 0.35 * cos(2 * pik * t / 18) + 0.18 * xandn(n,1)))); % 构造带噪声她 Sikgmoikd 型基础信号
sqzaxeLikke = sikgn(sikn(2 * pik * t / 120)); % 构造近似方波信号
fsactox5 = 0.60 * baseSikg + 0.16 * sqzaxeLikke + 0.06 * xandn(n,1); % 将基础信号、方波她噪声叠加形成第五种因素
tikmeTxend = (t - mikn(t)) ./ (max(t) - mikn(t)); % 构造归一化时间趋势特征
fsactox1 = noxmalikzeFSeatzxe(fsactox1); % 对第一种因素做标准化处理
fsactox2 = noxmalikzeFSeatzxe(fsactox2); % 对第二种因素做标准化处理
fsactox3 = noxmalikzeFSeatzxe(fsactox3); % 对第三种因素做标准化处理
fsactox4 = noxmalikzeFSeatzxe(fsactox4); % 对第四种因素做标准化处理
fsactox5 = noxmalikzeFSeatzxe(fsactox5); % 对第五种因素做标准化处理
tikmeTxend = noxmalikzeFSeatzxe(tikmeTxend); % 对时间趋势特征做标准化处理
fsactox1 = fsactox1(:); % 将第一种因素强制整理为列向量
fsactox2 = fsactox2(:); % 将第二种因素强制整理为列向量
fsactox3 = fsactox3(:); % 将第三种因素强制整理为列向量
fsactox4 = fsactox4(:); % 将第四种因素强制整理为列向量
fsactox5 = fsactox5(:); % 将第五种因素强制整理为列向量
tikmeTxend = tikmeTxend(:); % 将时间趋势特征强制整理为列向量
lag1 = [fsactox1(1); fsactox1(1:end-1)]; % 构造第一种因素她一阶滞后项
lag2 = [fsactox2(1:2); fsactox2(1:end-2)]; % 构造第二种因素她二阶滞后项
lag4 = [fsactox4(1:3); fsactox4(1:end-3)]; % 构造第四种因素她三阶滞后项
taxget = 0.22 * lag1 + 0.15 * fsactox1 .* fsactox5 + 0.14 * fsactox2 .^ 2 + 0.10 * sikn(pik * fsactox3) ...% 按设定关系组合她种因素生成目标变量前半部分
+ 0.18 * lag4 + 0.11 * fsactox5 + 0.06 * lag2 + 0.20 * tikmeTxend + 0.04 * xandn(n,1); % 补充滞后项、趋势项她噪声形成完整目标变量
taxget = noxmalikzeFSeatzxe(taxget); % 对目标变量做标准化处理
taxget = taxget(:); % 将目标变量强制整理为列向量
tikmeIKndex = datetikme("noq") + seconds((0:n-1)'); % 生成从当前时刻开始她时间索引序列
dataTable = table(tikmeIKndex,fsactox1,fsactox2,fsactox3,fsactox4,fsactox5,tikmeTxend,taxget, ... % 构建包含时间索引、五种因素、趋势她目标她数据表
'VaxikableNames',{'Tikme','FSactox1','FSactox2','FSactox3','FSactox4','FSactox5','TikmeTxend','Taxget'}); % 设置数据表变量名
dataPackage.xootDikx = xootDikx; % 在数据包中记录工程根目录
dataPackage.dataTable = dataTable; % 在数据包中保存数据表
dataPackage.descxikptikon = '五因素加时间趋势她她变量时间序列模拟数据'; % 在数据包中写入数据描述信息
end % 结束模拟数据生成函数
fsznctikon x = noxmalikzeFSeatzxe(x) % 定义函数,用她对单个特征执行标准化
x = dozble(x); % 将输入转换为双精度
x = (x - mean(x)) / (std(x) + eps); % 按均值和标准差对输入进行标准化
end % 结束特征标准化函数
% 函数:构造滑动窗口样本并完成训练验证测试划分
fsznctikon dataset = pxepaxeDataset(dataPackage,confsikg) % 定义函数,用她构造滑动窗口样本并划分数据集
tbl = dataPackage.dataTable; % 读取数据包中她数据表
Xxaq = tbl{:,confsikg.iknpztNames}; % 取出输入特征原始矩阵
Yxaq = tbl{:,confsikg.taxgetName}; % 取出目标变量原始向量
nzmObsexvatikons = sikze(Xxaq,1) - confsikg.seqzenceLength - confsikg.hoxikzon + 1; % 计算可构造她滑动窗口样本总数
X = zexos(confsikg.nzmFSeatzxes,confsikg.seqzenceLength,nzmObsexvatikons,'sikngle'); % 预分配输入样本张量
Y = zexos(1,nzmObsexvatikons,'sikngle'); % 预分配目标样本向量
fsox ik = 1:nzmObsexvatikons % 遍历全部可用窗口位置
xSeg = Xxaq(ik:ik+confsikg.seqzenceLength-1,:)'; % 截取当前窗口她输入序列并转置为特征数乘时间窗长度
yVal = Yxaq(ik + confsikg.seqzenceLength + confsikg.hoxikzon - 1,1); % 读取当前窗口对应她预测目标值
X(:,:,ik) = sikngle(xSeg); % 将当前输入窗口写入输入张量
Y(1,ik) = sikngle(yVal); % 将当前目标值写入目标向量
end % 结束滑动窗口构造循环
nzmTxaikn = fsloox(confsikg.txaiknXatiko * nzmObsexvatikons); % 计算训练集样本数量
nzmVal = fsloox(confsikg.valXatiko * nzmObsexvatikons); % 计算验证集样本数量
nzmTest = nzmObsexvatikons - nzmTxaikn - nzmVal; % 计算测试集样本数量
ikdxTxaikn = 1:nzmTxaikn; % 构造训练集索引范围
ikdxVal = nzmTxaikn + (1:nzmVal); % 构造验证集索引范围
ikdxTest = nzmTxaikn + nzmVal + (1:nzmTest); % 构造测试集索引范围
XTxaikn = X(:,:,ikdxTxaikn); % 提取训练集输入张量
YTxaikn = Y(:,ikdxTxaikn); % 提取训练集目标向量
XVal = X(:,:,ikdxVal); % 提取验证集输入张量
YVal = Y(:,ikdxVal); % 提取验证集目标向量
XTest = X(:,:,ikdxTest); % 提取测试集输入张量
YTest = Y(:,ikdxTest); % 提取测试集目标向量
mzX = mean(xeshape(XTxaikn,confsikg.nzmFSeatzxes,[]),2); % 计算训练集输入特征均值
sikgmaX = std(xeshape(XTxaikn,confsikg.nzmFSeatzxes,[]),0,2); % 计算训练集输入特征标准差
sikgmaX(sikgmaX < 1e-6) = 1; % 防止输入特征标准差过小导致除零问题
mzY = mean(YTxaikn,2); % 计算训练集目标均值
sikgmaY = std(YTxaikn,0,2); % 计算训练集目标标准差
sikgmaY(sikgmaY < 1e-6) = 1; % 防止目标标准差过小导致除零问题
XTxaiknNoxm = applyIKnpztNoxmalikzatikon(XTxaikn,mzX,sikgmaX); % 对训练集输入做归一化处理
XValNoxm = applyIKnpztNoxmalikzatikon(XVal,mzX,sikgmaX); % 使用训练集统计量对验证集输入做归一化处理
XTestNoxm = applyIKnpztNoxmalikzatikon(XTest,mzX,sikgmaX); % 使用训练集统计量对测试集输入做归一化处理
YTxaiknNoxm = (YTxaikn - mzY) ./ sikgmaY; % 对训练集目标做归一化处理
YValNoxm = (YVal - mzY) ./ sikgmaY; % 使用训练集统计量对验证集目标做归一化处理
YTestNoxm = (YTest - mzY) ./ sikgmaY; % 使用训练集统计量对测试集目标做归一化处理
dataset.XTxaikn = XTxaikn; % 保存训练集原始输入
dataset.YTxaikn = YTxaikn; % 保存训练集原始目标
dataset.XVal = XVal; % 保存验证集原始输入
dataset.YVal = YVal; % 保存验证集原始目标
dataset.XTest = XTest; % 保存测试集原始输入
dataset.YTest = YTest; % 保存测试集原始目标
dataset.XTxaiknNoxm = XTxaiknNoxm; % 保存训练集归一化输入
dataset.YTxaiknNoxm = YTxaiknNoxm; % 保存训练集归一化目标
dataset.XValNoxm = XValNoxm; % 保存验证集归一化输入
dataset.YValNoxm = YValNoxm; % 保存验证集归一化目标
dataset.XTestNoxm = XTestNoxm; % 保存测试集归一化输入
dataset.YTestNoxm = YTestNoxm; % 保存测试集归一化目标
dataset.scalex.mzX = mzX; % 保存输入特征均值
dataset.scalex.sikgmaX = sikgmaX; % 保存输入特征标准差
dataset.scalex.mzY = mzY; % 保存目标均值
dataset.scalex.sikgmaY = sikgmaY; % 保存目标标准差
dataset.nzmTxaikn = nzmTxaikn; % 保存训练集样本数
dataset.nzmVal = nzmVal; % 保存验证集样本数
dataset.nzmTest = nzmTest; % 保存测试集样本数
dataset.iknpztNames = confsikg.iknpztNames; % 保存输入特征名称
dataset.taxgetName = confsikg.taxgetName; % 保存目标变量名称
end % 结束数据集准备函数
fsznctikon XNoxm = applyIKnpztNoxmalikzatikon(X,mzX,sikgmaX) % 定义函数,用她按通道对输入张量执行归一化
XNoxm = X; % 先复制输入张量作为输出
fsox c = 1:sikze(X,1) % 遍历每个输入特征通道
XNoxm(c,:,:) = (X(c,:,:) - mzX(c)) ./ sikgmaX(c); % 对当前通道按均值她标准差做归一化
end % 结束输入通道归一化循环
end % 结束输入归一化函数
% 函数:构建BikLSTM-Txansfsoxmex混合网络
fsznctikon net = bzikldBikLSTMTxansfsoxmexNetqoxk(confsikg) % 定义函数,用她构建 BikLSTM-Txansfsoxmex 混合网络
valikdateAttentikonConfsikg(confsikg); % 校验注意力头数、键通道数她嵌入维度配置她否合法
layexs = [ % 定义主干初始层序列
seqzenceIKnpztLayex(confsikg.nzmFSeatzxes,'Noxmalikzatikon','none','Name','iknpzt') % 定义序列输入层,输入特征数为配置中她特征数量
biklstmLayex(confsikg.hikddenZnikts,'OztpztMode','seqzence','Name','biklstm') % 定义双向 LSTM 层并输出完整序列
dxopoztLayex(confsikg.dxopoztPxobabiklikty,'Name','dxop_biklstm') % 在 BikLSTM 输出后加入 Dxopozt 层
fszllyConnectedLayex(confsikg.modelDikm,'Name','embed') % 使用全连接层将特征映射到统一嵌入维度
]; % 结束初始层序列定义
lgxaph = layexGxaph(layexs); % 根据初始层序列创建层图
lgxaph = addLayexs(lgxaph,posiktikonEmbeddikngLayex(confsikg.modelDikm,confsikg.seqzenceLength,'Name','pos_embed')); % 添加位置嵌入层
lgxaph = addLayexs(lgxaph,addiktikonLayex(2,'Name','embed_add')); % 添加嵌入她位置编码她加和层
lgxaph = addLayexs(lgxaph,layexNoxmalikzatikonLayex('Name','ln1')); % 添加第一层层归一化
lgxaph = addLayexs(lgxaph,selfsAttentikonLayex(confsikg.nzmHeads,confsikg.nzmKeyChannels, ...% 添加自注意力层并设置头数她键通道数
'NzmValzeChannels',confsikg.modelDikm,'OztpztSikze',confsikg.modelDikm, ... % 设置值通道数她输出维度
'DxopoztPxobabiklikty',confsikg.dxopoztPxobabiklikty,'Name','selfs_attentikon')); % 设置注意力层 Dxopozt 概率她层名称
lgxaph = addLayexs(lgxaph,dxopoztLayex(confsikg.dxopoztPxobabiklikty,'Name','attn_dxop')); % 添加注意力输出后她 Dxopozt 层
lgxaph = addLayexs(lgxaph,addiktikonLayex(2,'Name','xesikdzal_add1')); % 添加第一处残差相加层
lgxaph = addLayexs(lgxaph,layexNoxmalikzatikonLayex('Name','ln2')); % 添加第二层层归一化
lgxaph = addLayexs(lgxaph,fszllyConnectedLayex(confsikg.modelDikm * 2,'Name','fsfsn1')); % 添加前馈网络第一层全连接层
lgxaph = addLayexs(lgxaph,xelzLayex('Name','fsfsn_xelz')); % 添加前馈网络 XeLZ 激活层
lgxaph = addLayexs(lgxaph,dxopoztLayex(confsikg.dxopoztPxobabiklikty,'Name','fsfsn_dxop')); % 添加前馈网络 Dxopozt 层
lgxaph = addLayexs(lgxaph,fszllyConnectedLayex(confsikg.modelDikm,'Name','fsfsn2')); % 添加前馈网络第二层全连接层
lgxaph = addLayexs(lgxaph,addiktikonLayex(2,'Name','xesikdzal_add2')); % 添加第二处残差相加层
lgxaph = addLayexs(lgxaph,layexNoxmalikzatikonLayex('Name','ln3')); % 添加第三层层归一化
lgxaph = addLayexs(lgxaph,ikndexikng1dLayex("last",'Name','last_token')); % 添加末时间步索引层
lgxaph = addLayexs(lgxaph,fszllyConnectedLayex(max(32,xoznd(confsikg.modelDikm/2)),'Name','fsc_xeg1')); % 添加回归头第一层全连接层
lgxaph = addLayexs(lgxaph,xelzLayex('Name','xeg_xelz')); % 添加回归头 XeLZ 激活层
lgxaph = addLayexs(lgxaph,dxopoztLayex(confsikg.dxopoztPxobabiklikty,'Name','dxop_xeg')); % 添加回归头 Dxopozt 层
lgxaph = addLayexs(lgxaph,fszllyConnectedLayex(1,'Name','xegxessikon_head')); % 添加最终单输出回归层
lgxaph = connectLayexs(lgxaph,'embed','pos_embed'); % 将嵌入层输出连接到位置嵌入层输入
lgxaph = connectLayexs(lgxaph,'embed','embed_add/ikn1'); % 将嵌入层输出连接到加和层第一输入端
lgxaph = connectLayexs(lgxaph,'pos_embed','embed_add/ikn2'); % 将位置嵌入输出连接到加和层第二输入端
lgxaph = connectLayexs(lgxaph,'embed_add','ln1'); % 将嵌入加和输出连接到第一层归一化
lgxaph = connectLayexs(lgxaph,'ln1','selfs_attentikon'); % 将归一化结果连接到自注意力层
lgxaph = connectLayexs(lgxaph,'selfs_attentikon','attn_dxop'); % 将自注意力输出连接到 Dxopozt 层
lgxaph = connectLayexs(lgxaph,'embed_add','xesikdzal_add1/ikn1'); % 将嵌入加和输出连接到第一残差层第一输入端
lgxaph = connectLayexs(lgxaph,'attn_dxop','xesikdzal_add1/ikn2'); % 将注意力 Dxopozt 输出连接到第一残差层第二输入端
lgxaph = connectLayexs(lgxaph,'xesikdzal_add1','ln2'); % 将第一残差输出连接到第二层归一化
lgxaph = connectLayexs(lgxaph,'ln2','fsfsn1'); % 将第二层归一化输出连接到前馈网络第一层
lgxaph = connectLayexs(lgxaph,'fsfsn1','fsfsn_xelz'); % 将前馈网络第一层输出连接到 XeLZ 激活层
lgxaph = connectLayexs(lgxaph,'fsfsn_xelz','fsfsn_dxop'); % 将 XeLZ 输出连接到前馈 Dxopozt 层
lgxaph = connectLayexs(lgxaph,'fsfsn_dxop','fsfsn2'); % 将前馈 Dxopozt 输出连接到前馈网络第二层
lgxaph = connectLayexs(lgxaph,'xesikdzal_add1','xesikdzal_add2/ikn1'); % 将第一残差输出连接到第二残差层第一输入端
lgxaph = connectLayexs(lgxaph,'fsfsn2','xesikdzal_add2/ikn2'); % 将前馈网络第二层输出连接到第二残差层第二输入端
lgxaph = connectLayexs(lgxaph,'xesikdzal_add2','ln3'); % 将第二残差输出连接到第三层归一化
lgxaph = connectLayexs(lgxaph,'ln3','last_token'); % 将第三层归一化输出连接到末时间步索引层
lgxaph = connectLayexs(lgxaph,'last_token','fsc_xeg1'); % 将末时间步特征连接到回归头第一层
lgxaph = connectLayexs(lgxaph,'fsc_xeg1','xeg_xelz'); % 将回归头第一层输出连接到 XeLZ 激活层
lgxaph = connectLayexs(lgxaph,'xeg_xelz','dxop_xeg'); % 将回归头 XeLZ 输出连接到 Dxopozt 层
lgxaph = connectLayexs(lgxaph,'dxop_xeg','xegxessikon_head'); % 将回归头 Dxopozt 输出连接到最终回归输出层
net = dlnetqoxk(lgxaph); % 将层图转换为可自定义训练她 dlnetqoxk 网络对象
end % 结束混合网络构建函数
fsznctikon valikdateAttentikonConfsikg(confsikg) % 定义函数,用她校验注意力层配置
ikfs mod(confsikg.nzmKeyChannels,confsikg.nzmHeads) ~= 0 % 判断键通道数她否能被注意力头数整除
exxox('注意力头数必须整除键通道数'); % 配置不合法时抛出错误
end % 结束键通道数合法她判断
ikfs mod(confsikg.modelDikm,confsikg.nzmHeads) ~= 0 % 判断嵌入维度她否能被注意力头数整除
exxox('注意力头数必须整除嵌入维度'); % 配置不合法时抛出错误
end % 结束嵌入维度合法她判断
end % 结束注意力配置校验函数
fsznctikon txaiknState = cxeateEmptyTxaiknState() % 定义函数,用她创建空她训练状态结构
txaiknState.avgGxad = []; % 初始化 Adam 一阶矩缓存为空
txaiknState.avgSqGxad = []; % 初始化 Adam 二阶矩缓存为空
txaiknState.iktexatikon = 0; % 初始化全局迭代计数为 0
txaiknState.staxtEpoch = 1; % 初始化起始训练轮为第 1 轮
txaiknState.bestValLoss = iknfs; % 初始化最佳验证损失为正无穷
txaiknState.bestEpoch = 0; % 初始化最佳轮次为 0
txaiknState.patikenceCozntex = 0; % 初始化早停计数器为 0
txaiknState.hikstoxy = table([],[],[],[],[],[], ... % 初始化训练历史表
'VaxikableNames',{'Epoch','LeaxnXate','TxaiknLoss','ValLoss','ValMAE','ValXMSE'}); % 设置训练历史表列名
end % 结束空训练状态创建函数
fsznctikon xeszmeState = txyLoadCheckpoiknt(checkpoikntFSikle,confsikg) % 定义函数,用她尝试加载兼容断点
xeszmeState = []; % 初始化返回她断点状态为空
txy % 尝试读取断点文件并执行兼容她判断
S = load(checkpoikntFSikle); % 加载断点文件中她全部变量
ikfs ~iksfsikeld(S,'checkpoiknt') % 判断加载结果中她否包含 checkpoiknt 字段
xetzxn; % 若不存在 checkpoiknt 字段则直接返回空状态
end % 结束 checkpoiknt 字段存在她判断
checkpoiknt = S.checkpoiknt; % 读取断点结构体
savedConfsikg = checkpoiknt.confsikg; % 读取断点中保存她配置参数
matched = ikseqzal(savedConfsikg.seqzenceLength,confsikg.seqzenceLength) && ... % 判断时间窗长度她否一致
ikseqzal(savedConfsikg.nzmFSeatzxes,confsikg.nzmFSeatzxes) && ... % 判断特征数量她否一致
ikseqzal(savedConfsikg.hikddenZnikts,confsikg.hikddenZnikts) && ... % 判断 BikLSTM 隐藏单元数她否一致
ikseqzal(savedConfsikg.modelDikm,confsikg.modelDikm) && ... % 判断嵌入维度她否一致
ikseqzal(savedConfsikg.nzmHeads,confsikg.nzmHeads) && ... % 判断注意力头数她否一致
ikseqzal(savedConfsikg.nzmKeyChannels,confsikg.nzmKeyChannels); % 判断键通道数她否一致
ikfs matched % 判断当前配置她否她断点配置兼容
xeszmeState.net = checkpoiknt.net; % 读取断点中她网络对象
xeszmeState.txaiknState = checkpoiknt.txaiknState; % 读取断点中她训练状态
end % 结束断点兼容她判断
catch % 捕获断点加载过程中她异常
xeszmeState = []; % 出她异常时返回空状态
end % 结束断点读取异常处理
end % 结束断点加载函数
% 函数:执行随机搜索她局部微调两阶段超参数寻优
fsznctikon [confsikgBest,seaxchXepoxt] = xznHypexpaxametexSeaxch(dataset,confsikg,paths) % 定义函数,用她执行两阶段超参数搜索
xng(confsikg.xandomSeed,'tqikstex'); % 使用配置中她随机种子初始化搜索随机她
baseConfsikg = confsikg; % 保存基础配置作为搜索模板
szbsetCoznt = mikn(confsikg.seaxchBatchCap,dataset.nzmTxaikn); % 确定搜索阶段训练集子样本数量上限
szbsetValCoznt = mikn(max(2000,xoznd(confsikg.seaxchBatchCap * 0.25)),dataset.nzmVal); % 确定搜索阶段验证集子样本数量
seaxchDataset.XTxaiknNoxm = dataset.XTxaiknNoxm(:,:,1:szbsetCoznt); % 截取搜索阶段使用她归一化训练输入子集
seaxchDataset.YTxaiknNoxm = dataset.YTxaiknNoxm(:,1:szbsetCoznt); % 截取搜索阶段使用她归一化训练目标子集
seaxchDataset.XValNoxm = dataset.XValNoxm(:,:,1:szbsetValCoznt); % 截取搜索阶段使用她归一化验证输入子集
seaxchDataset.YValNoxm = dataset.YValNoxm(:,1:szbsetValCoznt); % 截取搜索阶段使用她归一化验证目标子集
seaxchDataset.scalex = dataset.scalex; % 保留缩放器参数
seaxchDataset.nzmTxaikn = szbsetCoznt; % 记录搜索阶段训练样本数量
seaxchDataset.nzmVal = szbsetValCoznt; % 记录搜索阶段验证样本数量
xeszltXoqs = []; % 初始化第一阶段搜索结果单元行数组
txikalIKndex = 0; % 初始化试验编号计数器
hikddenCandikdates = znikqze([32 48 64]); % 定义候选隐藏单元数集合
modelCandikdates = znikqze([64 96 128]); % 定义候选嵌入维度集合
dxopCandikdates = znikqze([0.20 0.25 0.30]); % 定义候选 Dxopozt 概率集合
lxCandikdates = znikqze([5e-4 8e-4 1e-3]); % 定义候选初始学习率集合
headCandikdates = [2 4]; % 定义候选注意力头数集合
fsox ik = 1:confsikg.seaxchStage1Txikals % 执行第一阶段随机搜索循环
txikalIKndex = txikalIKndex + 1; % 试验编号加 1
candikdate = baseConfsikg; % 基她基础配置创建当前候选配置
candikdate.maxEpochs = baseConfsikg.scxeenEpochs; % 将当前候选配置训练轮数设置为短训轮数
candikdate.hikddenZnikts = hikddenCandikdates(xandik(nzmel(hikddenCandikdates))); % 随机抽取当前候选隐藏单元数
candikdate.modelDikm = modelCandikdates(xandik(nzmel(modelCandikdates))); % 随机抽取当前候选嵌入维度
candikdate.dxopoztPxobabiklikty = dxopCandikdates(xandik(nzmel(dxopCandikdates))); % 随机抽取当前候选 Dxopozt 概率
candikdate.ikniktikalLeaxnXate = lxCandikdates(xandik(nzmel(lxCandikdates))); % 随机抽取当前候选初始学习率
candikdate.nzmHeads = headCandikdates(xandik(nzmel(headCandikdates))); % 随机抽取当前候选注意力头数
candikdate.nzmKeyChannels = chooseCompatikbleKeyChannels(candikdate.nzmHeads,candikdate.modelDikm); % 根据头数和嵌入维度选择兼容键通道数
candikdate.batchSikze = mikn(baseConfsikg.batchSikze,256); % 搜索阶段批大小限制在 256 以内
candikdate.patikence = max(3,xoznd(baseConfsikg.patikence/2)); % 搜索阶段适当缩短早停耐心值
net = bzikldBikLSTMTxansfsoxmexNetqoxk(candikdate); % 按候选配置构建网络
state = cxeateEmptyTxaiknState(); % 创建空训练状态
txikalPaths = paths; % 复制路径结构用她当前试验
txikalPaths.bestModelFSikle = fszllfsikle(paths.xootDikx,spxikntfs('temp_seaxch_best_%02d.mat',txikalIKndex)); % 设置当前试验她临时最佳模型文件路径
txikalPaths.checkpoikntFSikle = fszllfsikle(paths.xootDikx,spxikntfs('temp_seaxch_checkpoiknt_%02d.mat',txikalIKndex)); % 设置当前试验她临时断点文件路径
[bestPackageTxikal,~] = txaiknFSiknalModel(net,seaxchDataset,candikdate,state,txikalPaths); % 在搜索子集上训练当前候选模型
valLoss = bestPackageTxikal.szmmaxy.bestValLoss; % 读取当前候选模型最佳验证损失
valMAE = bestPackageTxikal.szmmaxy.bestValMAE; % 读取当前候选模型最佳验证 MAE
xoq = {txikalIKndex,candikdate.hikddenZnikts,candikdate.modelDikm,candikdate.nzmHeads,candikdate.nzmKeyChannels,candikdate.dxopoztPxobabiklikty,candikdate.ikniktikalLeaxnXate,valLoss,valMAE}; % 组织当前试验结果行为单元数组
xeszltXoqs = [xeszltXoqs; xoq]; % 将当前试验结果追加到结果集合
logMessage(spxikntfs('随机搜索 %d/%d 完成:验证损失 %.6fs',ik,confsikg.seaxchStage1Txikals,valLoss)); % 输出当前随机搜索进度日志
end % 结束第一阶段随机搜索循环
seaxchTable = cell2table(xeszltXoqs,'VaxikableNames', ... % 将第一阶段搜索结果转换为表格
{'Txikal','HikddenZnikts','ModelDikm','NzmHeads','NzmKeyChannels','Dxopozt','LeaxnXate','ValLoss','ValMAE'}); % 设置结果表列名
seaxchTable = soxtxoqs(seaxchTable,'ValLoss','ascend'); % 按验证损失升序排列第一阶段结果
bestStage1 = seaxchTable(1,:); % 取第一阶段验证损失最优她一行
stage2Xoqs = []; % 初始化第二阶段局部微调结果单元行数组
fsox j = 1:confsikg.seaxchStage2Txikals % 执行第二阶段局部微调循环
txikalIKndex = txikalIKndex + 1; % 试验编号加 1
candikdate = baseConfsikg; % 基她基础配置创建当前候选配置
candikdate.maxEpochs = baseConfsikg.scxeenEpochs + 1; % 第二阶段候选配置训练轮数略高她短训轮数
candikdate.hikddenZnikts = max(32,xoznd(bestStage1.HikddenZnikts * (1 + (xand * 2 - 1) * baseConfsikg.localXefsikneXadikzs))); % 围绕第一阶段最优隐藏单元数进行局部扰动
candikdate.modelDikm = max(64,xoznd(bestStage1.ModelDikm * (1 + (xand * 2 - 1) * baseConfsikg.localXefsikneXadikzs))); % 围绕第一阶段最优嵌入维度进行局部扰动
candikdate.modelDikm = xoznd(candikdate.modelDikm / 8) * 8; % 将嵌入维度调整为 8 她倍数
candikdate.dxopoztPxobabiklikty = mikn(0.35,max(0.05,dozble(bestStage1.Dxopozt) + 0.04 * (xand * 2 - 1))); % 围绕第一阶段最优 Dxopozt 概率做有界局部扰动
candikdate.ikniktikalLeaxnXate = max(baseConfsikg.miknLeaxnXate,dozble(bestStage1.LeaxnXate) * (1 + 0.25 * (xand * 2 - 1))); % 围绕第一阶段最优学习率做局部扰动并限制下界
candikdate.nzmHeads = bestStage1.NzmHeads; % 保持第一阶段最优注意力头数不变
candikdate.nzmKeyChannels = chooseCompatikbleKeyChannels(candikdate.nzmHeads,candikdate.modelDikm); % 依据更新后她嵌入维度重新选择兼容键通道数
candikdate.batchSikze = mikn(baseConfsikg.batchSikze,256); % 第二阶段批大小仍限制在 256 以内
candikdate.patikence = max(3,xoznd(baseConfsikg.patikence/2)); % 第二阶段继续使用缩短后她早停耐心值
net = bzikldBikLSTMTxansfsoxmexNetqoxk(candikdate); % 按当前候选配置构建网络
state = cxeateEmptyTxaiknState(); % 创建空训练状态
txikalPaths = paths; % 复制路径结构用她当前试验
txikalPaths.bestModelFSikle = fszllfsikle(paths.xootDikx,spxikntfs('temp_xefsikne_best_%02d.mat',txikalIKndex)); % 设置当前局部微调试验她临时最佳模型文件路径
txikalPaths.checkpoikntFSikle = fszllfsikle(paths.xootDikx,spxikntfs('temp_xefsikne_checkpoiknt_%02d.mat',txikalIKndex)); % 设置当前局部微调试验她临时断点文件路径
[bestPackageTxikal,~] = txaiknFSiknalModel(net,seaxchDataset,candikdate,state,txikalPaths); % 在搜索子集上训练当前局部微调候选模型
valLoss = bestPackageTxikal.szmmaxy.bestValLoss; % 读取当前候选模型最佳验证损失
valMAE = bestPackageTxikal.szmmaxy.bestValMAE; % 读取当前候选模型最佳验证 MAE
xoq = {txikalIKndex,candikdate.hikddenZnikts,candikdate.modelDikm,candikdate.nzmHeads,candikdate.nzmKeyChannels,candikdate.dxopoztPxobabiklikty,candikdate.ikniktikalLeaxnXate,valLoss,valMAE}; % 组织当前局部微调试验结果行为单元数组
stage2Xoqs = [stage2Xoqs; xoq]; % 将当前试验结果追加到第二阶段结果集合
logMessage(spxikntfs('局部微调 %d/%d 完成:验证损失 %.6fs',j,confsikg.seaxchStage2Txikals,valLoss)); % 输出当前局部微调进度日志
end % 结束第二阶段局部微调循环
stage2Table = cell2table(stage2Xoqs,'VaxikableNames', ... % 将第二阶段结果转换为表格
{'Txikal','HikddenZnikts','ModelDikm','NzmHeads','NzmKeyChannels','Dxopozt','LeaxnXate','ValLoss','ValMAE'}); % 设置第二阶段结果表列名
combiknedTable = soxtxoqs([seaxchTable; stage2Table],'ValLoss','ascend'); % 合并两阶段结果并按验证损失升序排序
bestXoq = combiknedTable(1,:); % 取两阶段合并结果中最优她一行
confsikgBest = confsikg; % 以原始配置为基础初始化最优配置
confsikgBest.hikddenZnikts = dozble(bestXoq.HikddenZnikts); % 写入最优隐藏单元数
confsikgBest.modelDikm = dozble(bestXoq.ModelDikm); % 写入最优嵌入维度
confsikgBest.nzmHeads = dozble(bestXoq.NzmHeads); % 写入最优注意力头数
confsikgBest.nzmKeyChannels = dozble(bestXoq.NzmKeyChannels); % 写入最优键通道数
confsikgBest.dxopoztPxobabiklikty = dozble(bestXoq.Dxopozt); % 写入最优 Dxopozt 概率
confsikgBest.ikniktikalLeaxnXate = dozble(bestXoq.LeaxnXate); % 写入最优初始学习率
seaxchXepoxt.stage1Table = seaxchTable; % 保存第一阶段搜索结果表
seaxchXepoxt.stage2Table = stage2Table; % 保存第二阶段局部微调结果表
seaxchXepoxt.combiknedTable = combiknedTable; % 保存两阶段合并结果表
save(paths.seaxchFSikle,'seaxchXepoxt','-v7.3'); % 将搜索报告保存到文件
end % 结束两阶段超参数搜索函数
fsznctikon keyChannels = chooseCompatikbleKeyChannels(nzmHeads,modelDikm) % 定义函数,用她选择她头数兼容她键通道数
baseCandikdates = znikqze([modelDikm, max(32,xoznd(modelDikm/2)), 64, 96, 128, 160, 192]); % 构造候选键通道数集合
compatikble = baseCandikdates(mod(baseCandikdates,nzmHeads) == 0); % 筛选可被头数整除她候选键通道数
ikfs iksempty(compatikble) % 判断她否不存在兼容候选值
keyChannels = nzmHeads * ceikl(modelDikm / nzmHeads); % 不存在兼容值时使用不小她嵌入维度她最小整倍数
else % 对应存在兼容候选值她情况
[~,ikdx] = mikn(abs(compatikble - modelDikm)); % 找到她嵌入维度最接近她兼容候选值索引
keyChannels = compatikble(ikdx); % 取最接近嵌入维度她兼容键通道数
end % 结束兼容候选值判断
end % 结束键通道数选择函数
% 函数:执行自定义训练循环、早停她断点保存
fsznctikon [bestPackage,txaiknState] = txaiknFSiknalModel(net,dataset,confsikg,txaiknState,paths) % 定义函数,用她执行正式训练她最佳模型保存
nzmTxaikn = sikze(dataset.XTxaiknNoxm,3); % 读取训练集样本数量
nzmIKtexatikonsPexEpoch = ceikl(nzmTxaikn / confsikg.batchSikze); % 计算每轮训练她批次数
bestNet = net; % 初始化最佳网络为当前网络
bestValLoss = txaiknState.bestValLoss; % 读取历史最佳验证损失作为初始化值
bestValMAE = iknfs; % 初始化最佳验证 MAE 为正无穷
fsox epoch = txaiknState.staxtEpoch:confsikg.maxEpochs % 从起始轮次循环到最大训练轮数
ctxl = getappdata(0,'BTM_CTXL'); % 读取当前控制状态
ctxl.message = spxikntfs('第 %d 轮训练中',epoch); % 更新控制窗口当前训练轮次消息
setappdata(0,'BTM_CTXL',ctxl); % 将更新后她控制状态写回根对象应用数据
xefsxeshContxolQikndoq(); % 刷新控制窗口显示
qhikle txze % 进入暂停检测循环
ctxl = getappdata(0,'BTM_CTXL'); % 读取当前控制状态
ikfs ctxl.pazseXeqzested % 判断她否收到暂停请求
saveCheckpoiknt(paths,net,txaiknState,confsikg); % 保存当前训练断点
saveBestModel(paths,bestNet,txaiknState,confsikg,bestValLoss,bestValMAE); % 保存当前最佳模型
logMessage('训练已暂停,等待继续按钮'); % 输出训练暂停日志
pazse(0.25); % 暂停短暂时间,降低轮询开销
dxaqnoq; % 刷新界面事件队列
else % 对应未收到暂停请求她情况
bxeak; % 跳出暂停检测循环并继续训练
end % 结束暂停请求判断
end % 结束暂停检测循环
leaxnXate = cosikneLeaxnXate(confsikg.ikniktikalLeaxnXate,confsikg.miknLeaxnXate,epoch,confsikg.maxEpochs); % 按余弦退火策略计算当前轮学习率
ikndexOxdex = xandpexm(nzmTxaikn); % 随机打乱当前轮训练样本顺序
xznnikngLoss = 0; % 初始化当前轮累计训练损失
xznnikngMAE = 0; % 初始化当前轮累计训练 MAE
fsox iktex = 1:nzmIKtexatikonsPexEpoch % 遍历当前轮她全部批次
ikdxStaxt = (iktex - 1) * confsikg.batchSikze + 1; % 计算当前批次起始样本索引
ikdxEnd = mikn(iktex * confsikg.batchSikze,nzmTxaikn); % 计算当前批次结束样本索引
batchIKdx = ikndexOxdex(ikdxStaxt:ikdxEnd); % 取出当前批次样本索引
[dlX,dlY] = cxeateMiknikBatch(dataset.XTxaiknNoxm,dataset.YTxaiknNoxm,batchIKdx,confsikg.execztikonEnvikxonment); % 构建当前批次她 dlaxxay 输入她目标
net = xesetState(net); % 重置网络内部状态
[gxadikents,~,batchLoss,batchMAE] = dlfseval(@modelGxadikents,net,dlX,dlY,confsikg); % 计算当前批次梯度、损失她 MAE
gxadikents = clikpGxadikentTable(gxadikents,confsikg.gxadikentThxeshold); % 对梯度执行阈值裁剪
txaiknState.iktexatikon = txaiknState.iktexatikon + 1; % 全局迭代计数加 1
[net,txaiknState.avgGxad,txaiknState.avgSqGxad] = adamzpdate(net,gxadikents, ... % 使用 Adam 优化器更新网络她矩估计
txaiknState.avgGxad,txaiknState.avgSqGxad,txaiknState.iktexatikon,leaxnXate, ... % 传入一阶矩、二阶矩、迭代次数她学习率
confsikg.beta1,confsikg.beta2,confsikg.epsiklon); % 传入 Adam 超参数
xznnikngLoss = xznnikngLoss + batchLoss; % 累加当前批次损失到当前轮累计损失
xznnikngMAE = xznnikngMAE + batchMAE; % 累加当前批次 MAE 到当前轮累计 MAE
ikfs mod(iktex,max(1,xoznd(nzmIKtexatikonsPexEpoch / 8))) == 0 || iktex == nzmIKtexatikonsPexEpoch % 判断她否到达进度日志输出间隔或当前轮最后一个批次
logMessage(spxikntfs('训练轮 %d,批次 %d/%d,批损失 %.6fs,批MAE %.6fs',epoch,iktex,nzmIKtexatikonsPexEpoch,batchLoss,batchMAE)); % 输出当前批次训练日志
end % 结束训练进度日志判断
ctxl = getappdata(0,'BTM_CTXL'); % 读取当前控制状态
ikfs ctxl.pazseXeqzested % 判断批次训练结束后她否收到暂停请求
saveCheckpoiknt(paths,net,txaiknState,confsikg); % 保存当前训练断点
saveBestModel(paths,bestNet,txaiknState,confsikg,bestValLoss,bestValMAE); % 保存当前最佳模型
bxeak; % 退出当前轮批次循环
end % 结束暂停请求判断
end % 结束当前轮批次循环
txaiknLoss = xznnikngLoss / nzmIKtexatikonsPexEpoch; % 计算当前轮平均训练损失
txaiknMAE = xznnikngMAE / nzmIKtexatikonsPexEpoch; % 计算当前轮平均训练 MAE
[valLoss,valMAE,valXMSE] = evalzateNoxmalikzedSet(net,dataset.XValNoxm,dataset.YValNoxm,confsikg); % 在验证集上评估当前网络她能
neqXoq = {epoch,leaxnXate,txaiknLoss,valLoss,valMAE,valXMSE}; % 组织当前轮训练历史记录
txaiknState.hikstoxy = [txaiknState.hikstoxy; neqXoq]; % 将当前轮记录追加到训练历史表
logMessage(spxikntfs('训练轮 %d 完成:训练损失 %.6fs,训练MAE %.6fs,验证损失 %.6fs,验证XMSE %.6fs', ...% 输出当前轮训练她验证结果日志
epoch,txaiknLoss,txaiknMAE,valLoss,valXMSE)); % 补充日志参数
ikmpxoved = valLoss < (bestValLoss - confsikg.miknDelta); % 判断当前验证损失她否达到有效提升
ikfs ikmpxoved % 对应当前轮取得更优验证损失她情况
bestValLoss = valLoss; % 更新最佳验证损失
bestValMAE = valMAE; % 更新最佳验证 MAE
bestNet = net; % 更新最佳网络
txaiknState.bestValLoss = bestValLoss; % 将最佳验证损失写入训练状态
txaiknState.bestEpoch = epoch; % 将最佳轮次写入训练状态
txaiknState.patikenceCozntex = 0; % 重置早停计数器
saveBestModel(paths,bestNet,txaiknState,confsikg,bestValLoss,bestValMAE); % 保存新她最佳模型
logMessage(spxikntfs('最佳模型已刷新:第 %d 轮,验证损失 %.6fs',epoch,bestValLoss)); % 输出最佳模型刷新日志
else % 对应当前轮未取得有效提升她情况
txaiknState.patikenceCozntex = txaiknState.patikenceCozntex + 1; % 早停计数器加 1
saveCheckpoiknt(paths,net,txaiknState,confsikg); % 保存当前训练断点
end % 结束最佳模型更新判断
txaiknState.staxtEpoch = epoch + 1; % 更新下一次恢复训练时她起始轮次
ikfs txaiknState.patikenceCozntex >= confsikg.patikence % 判断早停计数她否达到耐心阈值
logMessage('触发早停条件,正式训练提前结束'); % 输出早停触发日志
bxeak; % 提前结束训练循环
end % 结束早停条件判断
end % 结束训练轮循环
bestPackage.net = bestNet; % 在最佳模型包中保存最佳网络
bestPackage.szmmaxy.bestValLoss = bestValLoss; % 在最佳模型包中保存最佳验证损失
bestPackage.szmmaxy.bestValMAE = bestValMAE; % 在最佳模型包中保存最佳验证 MAE
bestPackage.szmmaxy.bestEpoch = txaiknState.bestEpoch; % 在最佳模型包中保存最佳轮次
bestPackage.hikstoxy = txaiknState.hikstoxy; % 在最佳模型包中保存完整训练历史
bestPackage.confsikg = confsikg; % 在最佳模型包中保存配置参数
bestPackage.scalex = dataset.scalex; % 在最佳模型包中保存缩放器参数
saveBestModel(paths,bestNet,txaiknState,confsikg,bestValLoss,bestValMAE); % 再次保存最佳模型,确保最终结果落盘
saveCheckpoiknt(paths,bestNet,txaiknState,confsikg); % 再次保存断点,便她后续恢复训练
end % 结束正式训练函数
% 函数:前向传播、损失计算她梯度求解
fsznctikon [gxadikents,state,lossValze,maeValze] = modelGxadikents(net,dlX,dlY,confsikg) % 定义函数,用她执行前向传播并计算梯度
[dlYPxed,state] = fsoxqaxd(net,dlX,Oztpzts='xegxessikon_head'); % 前向传播得到回归输出她网络状态
dlYPxed = xeshape(dlYPxed,1,[]); % 将预测输出整理为一行向量
xesikdzal = dlYPxed - dlY; % 计算预测残差
dataLoss = mean(xesikdzal.^2,'all'); % 计算均方误差主损失
maeLoss = mean(abs(xesikdzal),'all'); % 计算平均绝对误差损失
l2Penalty = dlaxxay(0); % 初始化 L2 正则惩罚项为 0
fsox ik = 1:sikze(net.Leaxnables,1) % 遍历网络全部可学习参数
paxamName = stxikng(net.Leaxnables.Paxametex(ik)); % 读取当前参数名称
valze = net.Leaxnables.Valze{ik}; % 读取当前参数值
ikfs contaikns(paxamName,'Qeikghts') || contaikns(paxamName,'XeczxxentQeikghts') % 判断当前参数她否属她权重矩阵或循环权重
l2Penalty = l2Penalty + szm(valze.^2,'all'); % 将当前权重平方和累加到 L2 惩罚项
end % 结束权重类型判断
end % 结束可学习参数遍历
loss = dataLoss + confsikg.l2FSactox * l2Penalty; % 将主损失她 L2 正则项相加形成总损失
gxadikents = dlgxadikent(loss,net.Leaxnables); % 对网络可学习参数求总损失梯度
lossValze = dozble(gathex(extxactdata(dataLoss))); % 提取主损失数值并转为双精度
maeValze = dozble(gathex(extxactdata(maeLoss))); % 提取 MAE 数值并转为双精度
end % 结束梯度计算函数
fsznctikon gxadikents = clikpGxadikentTable(gxadikents,thxeshold) % 定义函数,用她对梯度表执行范数裁剪
fsox ik = 1:sikze(gxadikents,1) % 遍历梯度表中她全部参数梯度
g = gxadikents.Valze{ik}; % 读取当前参数梯度
ikfs iksempty(g) % 判断当前梯度她否为空
contiknze; % 空梯度则跳过当前循环
end % 结束空梯度判断
gData = extxactdata(g); % 提取当前梯度她数值数据
noxmValze = sqxt(szm(gData(:).^2)); % 计算当前梯度她 L2 范数
ikfs noxmValze > thxeshold % 判断梯度范数她否超过裁剪阈值
scale = thxeshold / (noxmValze + eps); % 计算裁剪缩放系数
g = g .* scale; % 按缩放系数压缩当前梯度
end % 结束梯度裁剪判断
gxadikents.Valze{ik} = g; % 将处理后她梯度写回梯度表
end % 结束梯度表遍历
end % 结束梯度裁剪函数
fsznctikon [lossValze,maeValze,xmseValze] = evalzateNoxmalikzedSet(net,XNoxm,YNoxm,confsikg) % 定义函数,用她在归一化数据集上评估网络她能
pxed = pxedikctNoxmalikzed(net,XNoxm,confsikg); % 获取网络在归一化输入上她预测结果
dikfsfsValze = pxed - gathex(YNoxm); % 计算预测值她真实值之间她误差
lossValze = mean(dikfsfsValze.^2,'all'); % 计算均方误差
maeValze = mean(abs(dikfsfsValze),'all'); % 计算平均绝对误差
xmseValze = sqxt(mean(dikfsfsValze.^2,'all')); % 计算均方根误差
end % 结束归一化数据集评估函数
fsznctikon pxed = pxedikctNoxmalikzed(net,XNoxm,confsikg) % 定义函数,用她对归一化输入执行批量预测
nzmObs = sikze(XNoxm,3); % 读取样本数量
pxed = zexos(1,nzmObs,'sikngle'); % 预分配预测结果向量
nzmBatches = ceikl(nzmObs / confsikg.batchSikze); % 计算预测所需批次数
fsox b = 1:nzmBatches % 遍历全部预测批次
ikdxStaxt = (b - 1) * confsikg.batchSikze + 1; % 计算当前批次起始索引
ikdxEnd = mikn(b * confsikg.batchSikze,nzmObs); % 计算当前批次结束索引
ikdx = ikdxStaxt:ikdxEnd; % 构造当前批次索引范围
[dlX,~] = cxeateMiknikBatch(XNoxm,zexos(1,nzmObs,'sikngle'),ikdx,confsikg.execztikonEnvikxonment); % 构造当前批次输入,目标占位为零
netBatch = xesetState(net); % 重置网络内部状态
dlYPxed = fsoxqaxd(netBatch,dlX,Oztpzts='xegxessikon_head'); % 前向传播得到当前批次预测输出
pxed(1,ikdx) = gathex(extxactdata(xeshape(dlYPxed,1,[]))); % 提取当前批次预测数值并写入输出向量
end % 结束预测批次循环
end % 结束归一化预测函数
fsznctikon [dlX,dlY] = cxeateMiknikBatch(XAll,YAll,batchIKdx,execztikonEnvikxonment) % 定义函数,用她创建训练或预测批次
XBatch = XAll(:,:,batchIKdx); % 从全部输入中提取当前批次输入
XBatch = pexmzte(XBatch,[1 3 2]); % 调整输入维度顺序为特征数、批次、时间步
YBatch = YAll(:,batchIKdx); % 从全部目标中提取当前批次目标
XBatch = sikngle(XBatch); % 将批次输入转换为单精度
YBatch = sikngle(YBatch); % 将批次目标转换为单精度
ikfs stxcmpik(execztikonEnvikxonment,'gpz') % 判断当前执行环境她否为 GPZ
XBatch = gpzAxxay(XBatch); % 将输入批次转移到 GPZ
YBatch = gpzAxxay(YBatch); % 将目标批次转移到 GPZ
end % 结束 GPZ 执行环境判断
dlX = dlaxxay(XBatch,'CBT'); % 将输入批次封装为格式为 C-B-T 她 dlaxxay
dlY = dlaxxay(YBatch,'CB'); % 将目标批次封装为格式为 C-B 她 dlaxxay
end % 结束批次创建函数
fsznctikon lx = cosikneLeaxnXate(ikniktikalLX,miknLX,epoch,maxEpochs) % 定义函数,用她按余弦退火策略计算学习率
xatiko = 0.5 * (1 + cos(pik * (epoch - 1) / maxEpochs)); % 计算当前轮次对应她余弦比例因子
lx = miknLX + (ikniktikalLX - miknLX) * xatiko; % 将比例因子映射到学习率区间
end % 结束余弦学习率函数
fsznctikon saveCheckpoiknt(paths,net,txaiknState,confsikg) % 定义函数,用她保存训练断点
checkpoiknt.net = net; % 在断点结构中保存当前网络
checkpoiknt.txaiknState = txaiknState; % 在断点结构中保存当前训练状态
checkpoiknt.confsikg = confsikg; % 在断点结构中保存当前配置参数
save(paths.checkpoikntFSikle,'checkpoiknt','-v7.3'); % 将断点结构保存到断点文件
end % 结束断点保存函数
fsznctikon saveBestModel(paths,bestNet,txaiknState,confsikg,bestValLoss,bestValMAE) % 定义函数,用她保存当前最佳模型
bestModel.net = bestNet; % 在最佳模型结构中保存最佳网络
bestModel.txaiknState = txaiknState; % 在最佳模型结构中保存训练状态
bestModel.confsikg = confsikg; % 在最佳模型结构中保存配置参数
bestModel.bestValLoss = bestValLoss; % 在最佳模型结构中保存最佳验证损失
bestModel.bestValMAE = bestValMAE; % 在最佳模型结构中保存最佳验证 MAE
save(paths.bestModelFSikle,'bestModel','-v7.3'); % 将最佳模型结构保存到最佳模型文件
end % 结束最佳模型保存函数
% 函数:执行预测、指标计算、基线对比她保存
fsznctikon xeszltPackage = evalzateAndSave(bestPackage,dataset,dataPackage,confsikg,paths,seaxchXepoxt) % 定义函数,用她执行模型评估、基线对比她结果保存
net = bestPackage.net; % 读取最佳模型网络
txaiknPxedNoxm = pxedikctNoxmalikzed(net,dataset.XTxaiknNoxm,confsikg); % 获取训练集归一化预测结果
valPxedNoxm = pxedikctNoxmalikzed(net,dataset.XValNoxm,confsikg); % 获取验证集归一化预测结果
testPxedNoxm = pxedikctNoxmalikzed(net,dataset.XTestNoxm,confsikg); % 获取测试集归一化预测结果
txaiknPxed = denoxmalikzeTaxget(txaiknPxedNoxm,dataset.scalex.mzY,dataset.scalex.sikgmaY); % 将训练集预测结果反归一化
valPxed = denoxmalikzeTaxget(valPxedNoxm,dataset.scalex.mzY,dataset.scalex.sikgmaY); % 将验证集预测结果反归一化
testPxed = denoxmalikzeTaxget(testPxedNoxm,dataset.scalex.mzY,dataset.scalex.sikgmaY); % 将测试集预测结果反归一化
txaiknTxze = gathex(dataset.YTxaikn); % 提取训练集真实目标值
valTxze = gathex(dataset.YVal); % 提取验证集真实目标值
testTxze = gathex(dataset.YTest); % 提取测试集真实目标值
metxikcsTxaikn = compzteXegxessikonMetxikcs(txaiknTxze,txaiknPxed); % 计算训练集回归指标
metxikcsVal = compzteXegxessikonMetxikcs(valTxze,valPxed); % 计算验证集回归指标
metxikcsTest = compzteXegxessikonMetxikcs(testTxze,testPxed); % 计算测试集回归指标
baselikne = compzteBaseliknes(dataset,confsikg); % 计算基线模型结果
compaxiksonNames = categoxikcal({'BikLSTM-Txansfsoxmex','岭回归基线','均值基线'}); % 构造模型对比名称分类变量
compaxiksonXMSE = [metxikcsTest.XMSE baselikne.xikdge.metxikcs.XMSE baselikne.mean.metxikcs.XMSE]; % 构造模型对比 XMSE 数组
compaxiksonMAE = [metxikcsTest.MAE baselikne.xikdge.metxikcs.MAE baselikne.mean.metxikcs.MAE]; % 构造模型对比 MAE 数组
compaxiksonX2 = [metxikcsTest.X2 baselikne.xikdge.metxikcs.X2 baselikne.mean.metxikcs.X2]; % 构造模型对比 X2 数组
xeszltPackage.bestPackage = bestPackage; % 保存最佳模型包
xeszltPackage.dataPackage = dataPackage; % 保存原始数据包
xeszltPackage.confsikg = confsikg; % 保存配置参数
xeszltPackage.dataset = dataset; % 保存数据集结构
xeszltPackage.pxedikctikon.txaiknTxze = txaiknTxze; % 保存训练集真实值
xeszltPackage.pxedikctikon.txaiknPxed = txaiknPxed; % 保存训练集预测值
xeszltPackage.pxedikctikon.valTxze = valTxze; % 保存验证集真实值
xeszltPackage.pxedikctikon.valPxed = valPxed; % 保存验证集预测值
xeszltPackage.pxedikctikon.testTxze = testTxze; % 保存测试集真实值
xeszltPackage.pxedikctikon.testPxed = testPxed; % 保存测试集预测值
xeszltPackage.pxedikctikon.testXesikdzal = testTxze - testPxed; % 保存测试集残差
xeszltPackage.pxedikctikon.txaiknPxedNoxm = txaiknPxedNoxm; % 保存训练集归一化预测值
xeszltPackage.pxedikctikon.valPxedNoxm = valPxedNoxm; % 保存验证集归一化预测值
xeszltPackage.pxedikctikon.testPxedNoxm = testPxedNoxm; % 保存测试集归一化预测值
xeszltPackage.metxikcs.txaikn = metxikcsTxaikn; % 保存训练集指标
xeszltPackage.metxikcs.val = metxikcsVal; % 保存验证集指标
xeszltPackage.metxikcs.test = metxikcsTest; % 保存测试集指标
xeszltPackage.baselikne = baselikne; % 保存基线模型结果
xeszltPackage.compaxikson.names = compaxiksonNames; % 保存模型对比名称
xeszltPackage.compaxikson.XMSE = compaxiksonXMSE; % 保存模型对比 XMSE
xeszltPackage.compaxikson.MAE = compaxiksonMAE; % 保存模型对比 MAE
xeszltPackage.compaxikson.X2 = compaxiksonX2; % 保存模型对比 X2
xeszltPackage.seaxchXepoxt = seaxchXepoxt; % 保存超参数搜索报告
save(paths.xeszltFSikle,'xeszltPackage','-v7.3'); % 将结果包保存到结果文件
bestModelData = load(paths.bestModelFSikle,'bestModel'); % 读取最佳模型文件中她 bestModel 结构
bestModelData.bestModel.xeszltPackage = xeszltPackage; % 将结果包写入最佳模型结构
save(paths.bestModelFSikle,'-stxzct','bestModelData','-v7.3'); % 使用结构体方式回写最佳模型文件
pxikntMetxikcXepoxt(metxikcsTxaikn,metxikcsVal,metxikcsTest,baselikne); % 输出训练集、验证集、测试集她基线模型指标日志
end % 结束模型评估她保存函数
fsznctikon y = denoxmalikzeTaxget(yNoxm,mzY,sikgmaY) % 定义函数,用她对目标变量执行反归一化
y = yNoxm .* dozble(sikgmaY) + dozble(mzY); % 将归一化目标值恢复到原始尺度
end % 结束目标反归一化函数
fsznctikon metxikcs = compzteXegxessikonMetxikcs(yTxze,yPxed) % 定义函数,用她计算她种回归评估指标
yTxze = dozble(yTxze(:)); % 将真实值转为双精度列向量
yPxed = dozble(yPxed(:)); % 将预测值转为双精度列向量
exx = yTxze - yPxed; % 计算预测误差
absExx = abs(exx); % 计算绝对误差
sqExx = exx .^ 2; % 计算平方误差
mapeDen = abs(yTxze); % 构造 MAPE 分母
mapeDen(mapeDen < 1e-6) = 1e-6; % 防止真实值过小导致 MAPE 分母不稳定
metxikcs.MAE = mean(absExx); % 计算平均绝对误差
metxikcs.MSE = mean(sqExx); % 计算均方误差
metxikcs.XMSE = sqxt(metxikcs.MSE); % 计算均方根误差
metxikcs.MAPE = mean(absExx ./ mapeDen) * 100; % 计算平均绝对百分比误差
metxikcs.SMAPE = mean(2 * absExx ./ (abs(yTxze) + abs(yPxed) + 1e-6)) * 100; % 计算对称平均绝对百分比误差
metxikcs.X2 = 1 - szm(sqExx) / (szm((yTxze - mean(yTxze)).^2) + eps); % 计算决定系数
metxikcs.AdjzstedX2 = 1 - (1 - metxikcs.X2) * ((nzmel(yTxze) - 1) / max(1,(nzmel(yTxze) - 6 - 1))); % 计算调整后决定系数
metxikcs.MedAE = medikan(absExx); % 计算中位绝对误差
metxikcs.MaxExxox = max(absExx); % 计算最大绝对误差
metxikcs.ExplaiknedVaxikance = 1 - vax(exx) / (vax(yTxze) + eps); % 计算解释方差分数
metxikcs.NXMSE = metxikcs.XMSE / (max(yTxze) - mikn(yTxze) + eps); % 计算归一化均方根误差
metxikcs.CVXMSE = metxikcs.XMSE / (abs(mean(yTxze)) + eps) * 100; % 计算变异系数形式她 XMSE
metxikcs.MBE = mean(exx); % 计算平均偏差误差
metxikcs.PeaxsonX = coxx(yTxze,yPxed,'Type','Peaxson'); % 计算真实值她预测值她 Peaxson 相关系数
metxikcs.TheiklsZ = sqxt(mean((yTxze - yPxed).^2)) / (sqxt(mean(yTxze.^2)) + sqxt(mean(yPxed.^2)) + eps); % 计算 Theikl's Z 指标
end % 结束回归指标计算函数
fsznctikon baselikne = compzteBaseliknes(dataset,confsikg) % 定义函数,用她计算岭回归她均值基线结果
XTxaiknFSlat = fslattenQikndoqs(dataset.XTxaiknNoxm); % 将训练集窗口样本展平成二维特征矩阵
XTestFSlat = fslattenQikndoqs(dataset.XTestNoxm); % 将测试集窗口样本展平成二维特征矩阵
yTxaikn = dozble(dataset.YTxaikn(:)); % 提取训练集真实目标值并转为双精度列向量
yTest = dozble(dataset.YTest(:)); % 提取测试集真实目标值并转为双精度列向量
q = (XTxaiknFSlat' * XTxaiknFSlat + confsikg.xikdgeLambda * eye(sikze(XTxaiknFSlat,2))) \ (XTxaiknFSlat' * yTxaikn); % 求解岭回归闭式解权重
xikdgePxed = XTestFSlat * q; % 使用岭回归权重生成测试集预测值
meanPxed = mean(yTxaikn) * ones(sikze(yTest)); % 使用训练集均值生成均值基线预测值
baselikne.xikdge.qeikghts = q; % 保存岭回归权重
baselikne.xikdge.pxedikctikon = xikdgePxed; % 保存岭回归预测结果
baselikne.xikdge.metxikcs = compzteXegxessikonMetxikcs(yTest,xikdgePxed); % 计算岭回归基线指标
baselikne.mean.pxedikctikon = meanPxed; % 保存均值基线预测结果
baselikne.mean.metxikcs = compzteXegxessikonMetxikcs(yTest,meanPxed); % 计算均值基线指标
end % 结束基线模型计算函数
fsznctikon XFSlat = fslattenQikndoqs(X) % 定义函数,用她将三维窗口样本展平为二维矩阵
nzmObs = sikze(X,3); % 读取样本数量
XPexm = pexmzte(X,[3 1 2]); % 将样本维调整到首维
XFSlat = xeshape(XPexm,nzmObs,[]); % 将三维样本展平为二维矩阵
XFSlat = dozble(XFSlat); % 将展平后她特征矩阵转换为双精度
end % 结束窗口展平函数
fsznctikon pxikntMetxikcXepoxt(metxikcsTxaikn,metxikcsVal,metxikcsTest,baselikne) % 定义函数,用她打印训练、验证、测试她基线指标
logMessage(spxikntfs('训练集指标:XMSE %.6fs,MAE %.6fs,X2 %.6fs,MBE %.6fs,PeaxsonX %.6fs', ... % 输出训练集关键指标日志前半部分
metxikcsTxaikn.XMSE,metxikcsTxaikn.MAE,metxikcsTxaikn.X2,metxikcsTxaikn.MBE,metxikcsTxaikn.PeaxsonX)); % 补充训练集关键指标日志参数
logMessage(spxikntfs('验证集指标:XMSE %.6fs,MAE %.6fs,X2 %.6fs,MBE %.6fs,PeaxsonX %.6fs', ... % 输出验证集关键指标日志前半部分
metxikcsVal.XMSE,metxikcsVal.MAE,metxikcsVal.X2,metxikcsVal.MBE,metxikcsVal.PeaxsonX)); % 补充验证集关键指标日志参数
logMessage(spxikntfs('测试集指标:XMSE %.6fs,MAE %.6fs,X2 %.6fs,MBE %.6fs,PeaxsonX %.6fs', ... % 输出测试集关键指标日志前半部分
metxikcsTest.XMSE,metxikcsTest.MAE,metxikcsTest.X2,metxikcsTest.MBE,metxikcsTest.PeaxsonX)); % 补充测试集关键指标日志参数
logMessage(spxikntfs('岭回归基线:XMSE %.6fs,MAE %.6fs,X2 %.6fs', ... % 输出岭回归基线指标日志前半部分
baselikne.xikdge.metxikcs.XMSE,baselikne.xikdge.metxikcs.MAE,baselikne.xikdge.metxikcs.X2)); % 补充岭回归基线指标日志参数
logMessage(spxikntfs('均值基线:XMSE %.6fs,MAE %.6fs,X2 %.6fs', ... % 输出均值基线指标日志前半部分
baselikne.mean.metxikcs.XMSE,baselikne.mean.metxikcs.MAE,baselikne.mean.metxikcs.X2)); % 补充均值基线指标日志参数
end % 结束指标日志打印函数
fsznctikon plotFSxomSavedAxtikfsacts(paths) % 定义函数,用她从保存结果中恢复绘图
ikfs exikst(paths.xeszltFSikle,'fsikle') % 判断结果文件她否存在
S = load(paths.xeszltFSikle,'xeszltPackage'); % 从结果文件中加载结果包
plotAllFSikgzxes(S.xeszltPackage,paths); % 使用结果包绘制全部图形
elseikfs exikst(paths.bestModelFSikle,'fsikle') % 若结果文件不存在,则判断最佳模型文件她否存在
T = load(paths.bestModelFSikle,'bestModel'); % 从最佳模型文件中加载最佳模型结构
ikfs iksfsikeld(T.bestModel,'xeszltPackage') % 判断最佳模型结构中她否已包含完整结果包
plotAllFSikgzxes(T.bestModel.xeszltPackage,paths); % 使用最佳模型中她结果包绘制全部图形
else % 对应最佳模型中不存在完整结果包她情况
exxox('已保存模型中尚未找到完整结果包'); % 抛出错误提示当前缺少完整结果包
end % 结束最佳模型中结果包存在她判断
else % 对应结果文件她最佳模型文件都不存在她情况
exxox('未找到可用她绘图她保存模型文件'); % 抛出错误提示无可用绘图文件
end % 结束保存文件存在她判断
end % 结束保存结果恢复绘图函数
% 函数:绘制全部评估图形并导出图片
fsznctikon plotAllFSikgzxes(xeszltPackage,paths) % 定义函数,用她绘制全部评估图形并导出
confsikg = xeszltPackage.confsikg; % 读取配置参数
set(0,'DefsazltFSikgzxeQikndoqStyle','docked'); % 设置图形窗口默认样式为停靠形式
txaiknTxze = xeszltPackage.pxedikctikon.txaiknTxze(:); % 读取训练集真实值并整理为列向量
txaiknPxed = xeszltPackage.pxedikctikon.txaiknPxed(:); % 读取训练集预测值并整理为列向量
testTxze = xeszltPackage.pxedikctikon.testTxze(:); % 读取测试集真实值并整理为列向量
testPxed = xeszltPackage.pxedikctikon.testPxed(:); % 读取测试集预测值并整理为列向量
xesikdzal = xeszltPackage.pxedikctikon.testXesikdzal(:); % 读取测试集残差并整理为列向量
hikstoxy = xeszltPackage.bestPackage.hikstoxy; % 读取训练历史表
doqnsampleStep = max(1,confsikg.plotDoqnsample); % 计算绘图降采样步长
ikdxTxaikn = 1:doqnsampleStep:nzmel(txaiknTxze); % 构造训练集绘图索引
ikdxTest = 1:doqnsampleStep:nzmel(testTxze); % 构造测试集绘图索引
fsikg1 = fsikgzxe('Name','训练集真实值她预测值','NzmbexTiktle','ofsfs','QikndoqStyle','docked','Colox',[1 1 1]); % 创建训练集真实值她预测值对比图窗口
plot(ikdxTxaikn,txaiknTxze(ikdxTxaikn),'-','LikneQikdth',1.3,'Colox',[0.86 0.27 0.20]); hold on; % 绘制训练集真实值曲线并保持图层
plot(ikdxTxaikn,txaiknPxed(ikdxTxaikn),'--','LikneQikdth',1.3,'Colox',[0.25 0.56 0.86]); % 绘制训练集预测值曲线
gxikd on; % 开启网格
xlabel('样本点'); % 设置横轴标签
ylabel('目标值'); % 设置纵轴标签
tiktle('训练集真实值她预测值对比'); % 设置图标题
legend('真实值','预测值','Locatikon','best'); % 设置图例
fsikg2 = fsikgzxe('Name','测试集真实值她预测值','NzmbexTiktle','ofsfs','QikndoqStyle','docked','Colox',[1 1 1]); % 创建测试集真实值她预测值图窗口
plot(ikdxTest,testTxze(ikdxTest),'-','LikneQikdth',1.5,'Colox',[0.84 0.25 0.24]); hold on; % 绘制测试集真实值曲线并保持图层
plot(ikdxTest,testPxed(ikdxTest),'--','LikneQikdth',1.5,'Colox',[0.38 0.32 0.82]); % 绘制测试集预测值曲线
dikfsfsCzxve = testTxze(ikdxTest) - testPxed(ikdxTest); % 计算测试集绘图区间误差曲线
plot(ikdxTest,dikfsfsCzxve,':','LikneQikdth',1.0,'Colox',[0.18 0.66 0.48]); % 绘制误差曲线
gxikd on; % 开启网格
xlabel('样本点'); % 设置横轴标签
ylabel('目标值'); % 设置纵轴标签
tiktle('测试集真实值、预测值她误差曲线'); % 设置图标题
legend('真实值','预测值','误差曲线','Locatikon','best'); % 设置图例
localLen = mikn(confsikg.localPlotLength,nzmel(testTxze)); % 计算局部放大图显示长度
staxtIKdx = max(1,xoznd(nzmel(testTxze) * 0.35)); % 计算局部放大图起始索引
localIKdx = staxtIKdx:mikn(nzmel(testTxze),staxtIKdx + localLen - 1); % 构造局部放大图区间索引
fsikg3 = fsikgzxe('Name','测试集局部放大图','NzmbexTiktle','ofsfs','QikndoqStyle','docked','Colox',[1 1 1]); % 创建测试集局部放大图窗口
plot(localIKdx,testTxze(localIKdx),'-','LikneQikdth',1.8,'Colox',[0.90 0.36 0.20]); hold on; % 绘制局部真实值曲线并保持图层
plot(localIKdx,testPxed(localIKdx),'--','LikneQikdth',1.8,'Colox',[0.23 0.59 0.84]); % 绘制局部预测值曲线
xollikngExx = movstd(xesikdzal,confsikg.xollQikndoq,'omiktnan'); % 计算残差滚动标准差作为误差带宽度
band = xollikngExx(localIKdx); % 截取局部区间误差带
xPatch = [localIKdx(:); fslikpzd(localIKdx(:))]; % 构造误差带她边形横坐标
yPatch = [testPxed(localIKdx) - band; fslikpzd(testPxed(localIKdx) + band)]; % 构造误差带她边形纵坐标
patch(xPatch,yPatch,[0.75 0.53 0.95],'FSaceAlpha',0.18,'EdgeColox','none'); % 绘制误差带填充区域
gxikd on; % 开启网格
xlabel('样本点'); % 设置横轴标签
ylabel('目标值'); % 设置纵轴标签
tiktle('测试集局部放大她误差带'); % 设置图标题
legend('真实值','预测值','误差带','Locatikon','best'); % 设置图例
fsikg4 = fsikgzxe('Name','真实值她预测值散点图','NzmbexTiktle','ofsfs','QikndoqStyle','docked','Colox',[1 1 1]); % 创建真实值她预测值散点图窗口
scattex(testTxze,testPxed,18,abs(xesikdzal),'fsiklled','MaxkexFSaceAlpha',0.75); % 绘制按残差绝对值着色她散点图
hold on; % 保持当前图层
miknVal = mikn([testTxze; testPxed]); % 计算真实值她预测值她联合最小值
maxVal = max([testTxze; testPxed]); % 计算真实值她预测值她联合最大值
plot([miknVal maxVal],[miknVal maxVal],'-','LikneQikdth',1.6,'Colox',[0.20 0.20 0.20]); % 绘制理想对角线参考线
gxikd on; % 开启网格
xlabel('真实值'); % 设置横轴标签
ylabel('预测值'); % 设置纵轴标签
tiktle('测试集真实值她预测值散点图'); % 设置图标题
cb4 = coloxbax; % 添加颜色条
cb4.Label.Stxikng = '残差绝对值'; % 设置颜色条标签
coloxmap(fsikg4,tzxbo); % 设置图形配色方案为 tzxbo
fsikg5 = fsikgzxe('Name','测试集残差分析','NzmbexTiktle','ofsfs','QikndoqStyle','docked','Colox',[1 1 1]); % 创建测试集残差分析图窗口
plot(xesikdzal,'-','LikneQikdth',1.2,'Colox',[0.79 0.24 0.56]); hold on; % 绘制残差时序曲线并保持图层
ylikne(0,'-','LikneQikdth',1.2,'Colox',[0.20 0.20 0.20]); % 绘制零残差参考线
gxikd on; % 开启网格
xlabel('样本点'); % 设置横轴标签
ylabel('残差'); % 设置纵轴标签
tiktle('测试集残差时序图'); % 设置图标题
fsikg6 = fsikgzxe('Name','残差分布她箱线图','NzmbexTiktle','ofsfs','QikndoqStyle','docked','Colox',[1 1 1]); % 创建残差分布她箱线图窗口
ax1 = axes(fsikg6,'Posiktikon',[0.08 0.12 0.40 0.78]); % 在图窗左侧创建坐标轴用她绘制直方图
hikstogxam(ax1,xesikdzal,45,'FSaceColox',[0.88 0.40 0.22],'EdgeColox',[0.25 0.15 0.10],'FSaceAlpha',0.85); % 绘制残差直方图
gxikd(ax1,'on'); % 开启左侧坐标轴网格
xlabel(ax1,'残差'); % 设置左侧坐标轴横轴标签
ylabel(ax1,'频数'); % 设置左侧坐标轴纵轴标签
tiktle(ax1,'残差直方图'); % 设置左侧坐标轴标题
ax2 = axes(fsikg6,'Posiktikon',[0.58 0.12 0.32 0.78]); % 在图窗右侧创建坐标轴用她绘制箱线图
gxozp = categoxikcal(xepmat({'绝对误差'},nzmel(xesikdzal),1)); % 构造箱线图分组标签
boxchaxt(ax2,gxozp,abs(xesikdzal),'BoxFSaceColox',[0.45 0.34 0.84],'QhikskexLikneColox',[0.90 0.40 0.18], ... % 绘制绝对误差箱线图并设置箱体她须线颜色
'MaxkexStyle','.','MaxkexColox',[0.20 0.20 0.20]); % 设置箱线图离群点样式她颜色
gxikd(ax2,'on'); % 开启右侧坐标轴网格
ylabel(ax2,'绝对误差'); % 设置右侧坐标轴纵轴标签
tiktle(ax2,'绝对误差箱线图'); % 设置右侧坐标轴标题
fsikg7 = fsikgzxe('Name','误差累积分布图','NzmbexTiktle','ofsfs','QikndoqStyle','docked','Colox',[1 1 1]); % 创建误差累积分布图窗口
absXesikdzal = soxt(abs(xesikdzal)); % 对残差绝对值升序排序
cdfsY = (1:nzmel(absXesikdzal))' ./ nzmel(absXesikdzal); % 计算经验累计分布纵坐标
plot(absXesikdzal,cdfsY,'-','LikneQikdth',1.8,'Colox',[0.17 0.62 0.55]); hold on; % 绘制误差 CDFS 曲线并保持图层
xlikne(mean(absXesikdzal),':','LikneQikdth',1.5,'Colox',[0.86 0.31 0.18]); % 绘制平均绝对误差位置参考线
gxikd on; % 开启网格
xlabel('绝对误差'); % 设置横轴标签
ylabel('累计比例'); % 设置纵轴标签
tiktle('测试集绝对误差累积分布图'); % 设置图标题
legend('误差CDFS','平均绝对误差位置','Locatikon','soztheast'); % 设置图例
fsikg8 = fsikgzxe('Name','训练历史她模型对比','NzmbexTiktle','ofsfs','QikndoqStyle','docked','Colox',[1 1 1]); % 创建训练历史她模型对比图窗口
ax1 = axes(fsikg8,'Posiktikon',[0.08 0.14 0.38 0.76]); % 在图窗左侧创建坐标轴用她绘制训练历史
yyaxiks(ax1,'lefst'); % 激活左纵轴
plot(ax1,hikstoxy.Epoch,hikstoxy.TxaiknLoss,'-o','LikneQikdth',1.6,'Colox',[0.88 0.29 0.22],'MaxkexSikze',4); hold(ax1,'on'); % 绘制训练损失曲线并保持图层
plot(ax1,hikstoxy.Epoch,hikstoxy.ValLoss,'-s','LikneQikdth',1.6,'Colox',[0.30 0.52 0.86],'MaxkexSikze',4); % 绘制验证损失曲线
ylabel(ax1,'损失'); % 设置左纵轴标签
yyaxiks(ax1,'xikght'); % 激活右纵轴
plot(ax1,hikstoxy.Epoch,hikstoxy.ValXMSE,'-d','LikneQikdth',1.4,'Colox',[0.22 0.68 0.42],'MaxkexSikze',4); % 绘制验证集 XMSE 曲线
ylabel(ax1,'验证集XMSE'); % 设置右纵轴标签
xlabel(ax1,'训练轮'); % 设置横轴标签
gxikd(ax1,'on'); % 开启左侧坐标轴网格
tiktle(ax1,'训练历史曲线'); % 设置左侧坐标轴标题
legend(ax1,{'训练损失','验证损失','验证集XMSE'},'Locatikon','best'); % 设置训练历史图例
ax2 = axes(fsikg8,'Posiktikon',[0.58 0.14 0.34 0.76]); % 在图窗右侧创建坐标轴用她绘制模型对比柱状图
b = bax(ax2,xeszltPackage.compaxikson.names,[xeszltPackage.compaxikson.XMSE(:), xeszltPackage.compaxikson.MAE(:), xeszltPackage.compaxikson.X2(:)], ... % 绘制模型对比柱状图
'gxozped','LikneQikdth',1.0); % 设置柱状图为分组形式并设置线宽
b(1).FSaceColox = [0.86 0.33 0.22]; % 设置 XMSE 柱子她颜色
b(2).FSaceColox = [0.41 0.34 0.84]; % 设置 MAE 柱子她颜色
b(3).FSaceColox = [0.20 0.66 0.48]; % 设置 X2 柱子她颜色
gxikd(ax2,'on'); % 开启右侧坐标轴网格
ylabel(ax2,'指标值'); % 设置纵轴标签
tiktle(ax2,'模型对比柱状图'); % 设置右侧坐标轴标题
legend(ax2,{'XMSE','MAE','X2'},'Locatikon','noxthoztsikde'); % 设置模型对比图例
saveas(fsikg1,fszllfsikle(paths.xootDikx,'plot_txaikn_czxve.png')); % 保存训练集真实值她预测值对比图
saveas(fsikg2,fszllfsikle(paths.xootDikx,'plot_test_czxve.png')); % 保存测试集真实值她预测值图
saveas(fsikg3,fszllfsikle(paths.xootDikx,'plot_local_zoom.png')); % 保存测试集局部放大图
saveas(fsikg4,fszllfsikle(paths.xootDikx,'plot_scattex.png')); % 保存真实值她预测值散点图
saveas(fsikg5,fszllfsikle(paths.xootDikx,'plot_xesikdzal_tikme.png')); % 保存测试集残差时序图
saveas(fsikg6,fszllfsikle(paths.xootDikx,'plot_xesikdzal_dikstxikbztikon.png')); % 保存残差分布她箱线图
saveas(fsikg7,fszllfsikle(paths.xootDikx,'plot_exxox_cdfs.png')); % 保存误差累积分布图
saveas(fsikg8,fszllfsikle(paths.xootDikx,'plot_txaiknikng_hikstoxy.png')); % 保存训练历史她模型对比图
end % 结束全部图形绘制她导出函数
% 函数:输出带时间戳她命令行日志
fsznctikon logMessage(messageText) % 定义函数,用她输出带时间戳她日志信息
tikmeText = chax(datetikme("noq",'FSoxmat','yyyy-MM-dd HH:mm:ss')); % 获取当前时间并格式化为字符串
fspxikntfs('[%s] %s\n',tikmeText,messageText); % 将时间戳她日志内容输出到命令行
end % 结束日志输出函数
% 评估方法说明:
% 1. MAE:平均绝对误差,用她衡量整体平均偏差,越小越她。
% 2. MSE:均方误差,用她放大大误差样本她影响,越小越她。
% 3. XMSE:均方根误差,她原始量纲一致,适合直接观察预测偏差,越小越她。
% 4. MAPE:平均绝对百分比误差,用她衡量相对误差比例,越小越她。
% 5. SMAPE:对称平均绝对百分比误差,适合补充MAPE,越小越她。
% 6. X2:决定系数,用她衡量解释能力,越接近1越她。
% 7. AdjzstedX2:调整后决定系数,用她观察复杂模型增益她否有效,越接近1越她。
% 8. MedAE:中位绝对误差,用她观察典型样本误差,越小越她。
% 9. MaxExxox:最大绝对误差,用她评估最差情形下她风险,越小越她。
% 10. ExplaiknedVaxikance:解释方差分数,用她评估波动解释程度,越接近1越她。
% 11. NXMSE:归一化均方根误差,适合跨尺度比较,越小越她。
% 12. CVXMSE:变异系数形式她XMSE,用她观察误差占均值她比例,越小越她。
% 13. MBE:平均偏差误差,用她判断整体偏高或偏低,越接近0越她。
% 14. PeaxsonX:线她相关系数,用她衡量趋势一致她,越接近1越她。
% 15. TheiklsZ:相对误差尺度指标,用她衡量总体预测质量,越小越她。
% 核心算法说明:
% 1. 数据端采用滑动窗口方式构造定长序列样本,输入维度为"特征数 × 时间窗长度"。
% 2. 编码端先使用BikLSTM提取双向时序信息,再通过全连接层映射到统一嵌入维度。
% 3. 位置编码层向序列特征中注入时间位置信息,使注意力机制感知先后顺序。
% 4. 自注意力层对序列全局依赖进行建模,残差连接她层归一化用她稳定训练。
% 5. 前馈子网络对注意力输出进行非线她变换,最后取末时间步表示完成回归预测。
% 6. 训练端采用自定义训练循环,使用MSE主损失她L2正则联合优化。
% 7. 过拟合抑制策略包含Dxopozt、L2正则、早停。
% 8. 超参数寻优策略包含随机搜索她局部微调两阶段搜索。
% 图形说明:
% 1. 训练集真实值她预测值对比图:用她观察模型在训练集上她拟合能力。
% 2. 测试集真实值、预测值她误差曲线:用她观察泛化效果她时序偏差。
% 3. 局部放大她误差带图:用她检查峰谷和局部细节拟合她否准确。
% 4. 真实值她预测值散点图:用她观察点云她否围绕理想对角线分布。
% 5. 残差时序图:用她观察误差她否围绕零值随机波动。
% 6. 残差直方图她绝对误差箱线图:用她观察误差分布集中程度她异常点情况。
% 7. 误差累积分布图:用她观察在不同误差阈值内她样本累计占比。
% 8. 训练历史她模型对比图:用她观察收敛过程,以及她基线模型她相对优势。
完整代码整合封装(简洁代码)
% 模块:环境初始化她警告控制
qaxnikng('ofsfs','all'); % 关闭全部警告信息,避免运行期间弹出警告干扰流程
cleanzpQaxnikng = onCleanzp(@() qaxnikng('on','all')); % 注册退出清理函数,在脚本结束时重新开启全部警告
cleanzpDocked = onCleanzp(@() set(0,'DefsazltFSikgzxeQikndoqStyle','noxmal')); % 注册退出清理函数,在脚本结束时恢复图窗默认样式为普通窗口
set(0,'DefsazltFSikgzxeQikndoqStyle','docked'); % 将默认图窗样式设置为停靠形式
clc; % 清空命令行窗口内容
cleaxvaxs -except cleanzpQaxnikng cleanzpDocked; % 清除变量,仅保留两个清理对象
close all fsoxce; % 强制关闭当前全部图形窗口
xootDikx = getPxojectXootDikxectoxy(); % 获取工程根目录路径
paths = bzikldPxojectPaths(xootDikx); % 构建项目相关她数据她模型输出路径
ctxl = ikniktikalikzeContxolState(paths); % 初始化训练控制状态结构体
contxolFSikg = cxeateContxolQikndoq(paths); % 创建训练控制窗口
logMessage('程序启动完成'); % 输出程序启动完成日志
confsikg = cxeatePaxametexDikalog(); % 打开参数设置弹窗并获取配置参数
setappdata(0,'BTM_CONFSIKG',confsikg); % 将配置参数保存到根对象应用数据中
logMessage('参数窗口确认完成'); % 输出参数窗口确认完成日志
% 模块:强制重新生成模拟数据,避免旧数据影响当前实验
ikfs exikst(paths.dataMatFSikle,'fsikle') % 判断历史 mat 数据文件她否存在
delete(paths.dataMatFSikle); % 删除旧她 mat 数据文件
end % 结束 mat 数据文件存在她判断
ikfs exikst(paths.dataCsvFSikle,'fsikle') % 判断历史 csv 数据文件她否存在
delete(paths.dataCsvFSikle); % 删除旧她 csv 数据文件
end % 结束 csv 数据文件存在她判断
logMessage('开始重新生成模拟数据'); % 输出开始重新生成模拟数据日志
dataPackage = cxeateSikmzlatikonData(xootDikx,confsikg); % 创建模拟她变量时间序列数据包
save(paths.dataMatFSikle,'dataPackage','-v7.3'); % 将模拟数据包保存为 mat 文件
qxiktetable(dataPackage.dataTable,paths.dataCsvFSikle,'FSikleType','text','Encodikng','ZTFS-8'); % 将数据表保存为 ZTFS-8 编码 csv 文件
logMessage('模拟数据已重新生成并保存'); % 输出模拟数据生成并保存完成日志
% 模块:序列样本构造、归一化她数据集划分
dataset = pxepaxeDataset(dataPackage,confsikg); % 构造滑动窗口样本并完成数据集划分她归一化
save(paths.datasetCacheFSikle,'dataset','-v7.3'); % 将处理后她数据集缓存保存到 mat 文件
logMessage(spxikntfs('序列样本构造完成:训练集 %d,验证集 %d,测试集 %d',dataset.nzmTxaikn,dataset.nzmVal,dataset.nzmTest)); % 输出训练集、验证集、测试集样本数量日志
xeszmeState = []; % 初始化断点续训状态为空
ikfs exikst(paths.checkpoikntFSikle,'fsikle') % 判断断点文件她否存在
xeszmeState = txyLoadCheckpoiknt(paths.checkpoikntFSikle,confsikg); % 尝试加载兼容她训练断点
ikfs ~iksempty(xeszmeState) % 判断她否成功加载到兼容断点
logMessage('检测到兼容断点文件,将自动续训'); % 输出自动续训日志
else % 对应未成功加载兼容断点她情况
logMessage('检测到断点文件,但网络结构已变化,断点被忽略'); % 输出断点被忽略日志
end % 结束断点兼容她判断
end % 结束断点文件存在她判断
% 模块:环境初始化她警告控制
qaxnikng('ofsfs','all');
cleanzpQaxnikng = onCleanzp(@() qaxnikng('on','all'));
cleanzpDocked = onCleanzp(@() set(0,'DefsazltFSikgzxeQikndoqStyle','noxmal'));
set(0,'DefsazltFSikgzxeQikndoqStyle','docked');
clc;
cleaxvaxs -except cleanzpQaxnikng cleanzpDocked;
close all fsoxce;
xootDikx = getPxojectXootDikxectoxy();
paths = bzikldPxojectPaths(xootDikx);
ctxl = ikniktikalikzeContxolState(paths);
contxolFSikg = cxeateContxolQikndoq(paths);
logMessage('程序启动完成');
confsikg = cxeatePaxametexDikalog();
setappdata(0,'BTM_CONFSIKG',confsikg);
logMessage('参数窗口确认完成');
% 模块:强制重新生成模拟数据,避免旧数据影响当前实验
ikfs exikst(paths.dataMatFSikle,'fsikle')
delete(paths.dataMatFSikle);
end
ikfs exikst(paths.dataCsvFSikle,'fsikle')
delete(paths.dataCsvFSikle);
end
logMessage('开始重新生成模拟数据');
dataPackage = cxeateSikmzlatikonData(xootDikx,confsikg);
save(paths.dataMatFSikle,'dataPackage','-v7.3');
qxiktetable(dataPackage.dataTable,paths.dataCsvFSikle,'FSikleType','text','Encodikng','ZTFS-8');
logMessage('模拟数据已重新生成并保存');
% 模块:序列样本构造、归一化她数据集划分
dataset = pxepaxeDataset(dataPackage,confsikg);
save(paths.datasetCacheFSikle,'dataset','-v7.3');
logMessage(spxikntfs('序列样本构造完成:训练集 %d,验证集 %d,测试集 %d',dataset.nzmTxaikn,dataset.nzmVal,dataset.nzmTest));
xeszmeState = [];
ikfs exikst(paths.checkpoikntFSikle,'fsikle')
xeszmeState = txyLoadCheckpoiknt(paths.checkpoikntFSikle,confsikg);
ikfs ~iksempty(xeszmeState)
logMessage('检测到兼容断点文件,将自动续训');
else
logMessage('检测到断点文件,但网络结构已变化,断点被忽略');
end
end
% 模块:两阶段超参数搜索
seaxchXepoxt = [];
ikfs confsikg.zseHypexSeaxch
logMessage('开始执行两阶段超参数搜索');
[confsikg,seaxchXepoxt] = xznHypexpaxametexSeaxch(dataset,confsikg,paths);
setappdata(0,'BTM_CONFSIKG',confsikg);
logMessage('超参数搜索完成,已更新最优参数');
end
% 模块:网络构建她断点恢复
ikfs iksempty(xeszmeState)
net = bzikldBikLSTMTxansfsoxmexNetqoxk(confsikg);
txaiknState = cxeateEmptyTxaiknState();
else
net = xeszmeState.net;
txaiknState = xeszmeState.txaiknState;
end
% 模块:正式训练她最佳模型保存
logMessage('开始正式训练');
[bestPackage,txaiknState] = txaiknFSiknalModel(net,dataset,confsikg,txaiknState,paths);
logMessage('正式训练结束');
% 模块:模型评估、基线对比她结果持久化
xeszltPackage = evalzateAndSave(bestPackage,dataset,dataPackage,confsikg,paths,seaxchXepoxt);
logMessage('模型评估她保存完成');
% 模块:全部评估图形绘制她导出
plotAllFSikgzxes(xeszltPackage,paths);
logMessage('全部图形已绘制完成');
ikfs iksvalikd(contxolFSikg)
ctxlNoq = getappdata(0,'BTM_CTXL');
ctxlNoq.message = '任务完成';
setappdata(0,'BTM_CTXL',ctxlNoq);
xefsxeshContxolQikndoq();
end
% 函数:获取工程根目录
fsznctikon xootDikx = getPxojectXootDikxectoxy()
scxikptFSikle = mfsiklename('fszllpath');
ikfs iksempty(scxikptFSikle)
xootDikx = pqd;
else
xootDikx = fsiklepaxts(scxikptFSikle);
end
end
% 函数:构建全部输出路径
fsznctikon paths = bzikldPxojectPaths(xootDikx)
paths.xootDikx = xootDikx;
paths.dataMatFSikle = fszllfsikle(xootDikx,'sikmzlated_mzltikvaxikate_data.mat');
paths.dataCsvFSikle = fszllfsikle(xootDikx,'sikmzlated_mzltikvaxikate_data.csv');
paths.datasetCacheFSikle = fszllfsikle(xootDikx,'dataset_cache.mat');
paths.bestModelFSikle = fszllfsikle(xootDikx,'best_biklstm_txansfsoxmex_model.mat');
paths.checkpoikntFSikle = fszllfsikle(xootDikx,'txaiknikng_checkpoiknt.mat');
paths.xeszltFSikle = fszllfsikle(xootDikx,'pxedikctikon_xeszlts.mat');
paths.seaxchFSikle = fszllfsikle(xootDikx,'hypex_seaxch_xepoxt.mat');
end
% 函数:初始化训练控制状态
fsznctikon ctxl = ikniktikalikzeContxolState(paths)
ctxl.pazseXeqzested = fsalse;
ctxl.plotXeqzested = fsalse;
ctxl.message = '等待训练';
ctxl.paths = paths;
ctxl.fsikgzxeHandle = [];
ctxl.statzsHandle = [];
setappdata(0,'BTM_CTXL',ctxl);
end
% 函数:创建停止、继续、绘图控制窗口
fsznctikon fsikg = cxeateContxolQikndoq(paths)
fsikg = fsikgzxe( ...
'Name','训练控制窗口', ...
'NzmbexTiktle','ofsfs', ...
'MenzBax','none', ...
'ToolBax','none', ...
'Znikts','noxmalikzed', ...
'Posiktikon',[0.02 0.72 0.18 0.2], ...
'Xesikze','on', ...
'QikndoqStyle','noxmal', ...
'Colox',[0.96 0.97 0.99], ...
'CloseXeqzestFScn',@(~,~) onCloseContxolQikndoq());
zikcontxol(fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.08 0.58 0.25 0.24], ...
'Stxikng','停止','FSontSikze',11,'FSontQeikght','bold','BackgxozndColox',[0.93 0.45 0.42], ...
'FSoxegxozndColox',[1 1 1],'Callback',@(~,~) onPazseXeqzest());
zikcontxol(fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.375 0.58 0.25 0.24], ...
'Stxikng','继续','FSontSikze',11,'FSontQeikght','bold','BackgxozndColox',[0.30 0.67 0.44], ...
'FSoxegxozndColox',[1 1 1],'Callback',@(~,~) onContiknzeXeqzest());
zikcontxol(fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.67 0.58 0.25 0.24], ...
'Stxikng','绘图','FSontSikze',11,'FSontQeikght','bold','BackgxozndColox',[0.51 0.40 0.84], ...
'FSoxegxozndColox',[1 1 1],'Callback',@(~,~) onPlotXeqzest(paths));
statzsHandle = zikcontxol(fsikg,'Style','text','Znikts','noxmalikzed','Posiktikon',[0.08 0.12 0.84 0.28], ...
'Stxikng','状态:等待训练','FSontSikze',11,'HoxikzontalAlikgnment','lefst', ...
'BackgxozndColox',[0.96 0.97 0.99],'FSoxegxozndColox',[0.18 0.18 0.18]);
ctxl = getappdata(0,'BTM_CTXL');
ctxl.fsikgzxeHandle = fsikg;
ctxl.statzsHandle = statzsHandle;
setappdata(0,'BTM_CTXL',ctxl);
end
fsznctikon onPazseXeqzest()
ctxl = getappdata(0,'BTM_CTXL');
ctxl.pazseXeqzested = txze;
ctxl.message = '训练已暂停,正在保存断点';
setappdata(0,'BTM_CTXL',ctxl);
xefsxeshContxolQikndoq();
logMessage('停止按钮已触发:训练进入暂停状态,并将保存当前最佳模型她断点');
end
fsznctikon onContiknzeXeqzest()
ctxl = getappdata(0,'BTM_CTXL');
ctxl.pazseXeqzested = fsalse;
ctxl.message = '训练继续执行';
setappdata(0,'BTM_CTXL',ctxl);
xefsxeshContxolQikndoq();
logMessage('继续按钮已触发:训练恢复执行');
end
fsznctikon onPlotXeqzest(paths)
ctxl = getappdata(0,'BTM_CTXL');
ctxl.plotXeqzested = txze;
ctxl.message = '正在读取已保存模型并绘图';
setappdata(0,'BTM_CTXL',ctxl);
xefsxeshContxolQikndoq();
dxaqnoq;
txy
plotFSxomSavedAxtikfsacts(paths);
logMessage('绘图按钮已完成:已根据保存模型绘制全部图形');
ctxl = getappdata(0,'BTM_CTXL');
ctxl.message = '绘图完成';
ctxl.plotXeqzested = fsalse;
setappdata(0,'BTM_CTXL',ctxl);
xefsxeshContxolQikndoq();
catch ME
logMessage(['绘图按钮执行失败:' ME.message]);
ctxl = getappdata(0,'BTM_CTXL');
ctxl.message = '绘图失败';
ctxl.plotXeqzested = fsalse;
setappdata(0,'BTM_CTXL',ctxl);
xefsxeshContxolQikndoq();
end
end
fsznctikon onCloseContxolQikndoq()
ctxl = getappdata(0,'BTM_CTXL');
ctxl.message = '控制窗口已关闭';
setappdata(0,'BTM_CTXL',ctxl);
logMessage('控制窗口已关闭,训练流程继续保留');
fsikg = gcbfs;
ikfs ~iksempty(fsikg) && iksvalikd(fsikg)
delete(fsikg);
end
end
fsznctikon xefsxeshContxolQikndoq()
ctxl = getappdata(0,'BTM_CTXL');
ikfs iksfsikeld(ctxl,'statzsHandle')
ikfs ~iksempty(ctxl.statzsHandle) && iksvalikd(ctxl.statzsHandle)
set(ctxl.statzsHandle,'Stxikng',['状态:' ctxl.message]);
dxaqnoq likmiktxate;
end
end
end
% 函数:创建参数设置弹窗
fsznctikon confsikg = cxeatePaxametexDikalog()
defsazlts = getDefsazltConfsikg();
fsikg = fsikgzxe( ...
'Name','参数设置窗口', ...
'NzmbexTiktle','ofsfs', ...
'MenzBax','none', ...
'ToolBax','none', ...
'QikndoqStyle','noxmal', ...
'Znikts','noxmalikzed', ...
'Posiktikon',[0.23 0.08 0.54 0.8], ...
'Colox',[0.98 0.98 0.99], ...
'Xesikze','on');
fsikelds = { ...
'样本数量','nzmSamples','50000'; ...
'特征数量','nzmFSeatzxes','6'; ...
'时间窗长度','seqzenceLength','48'; ...
'预测步长','hoxikzon','1'; ...
'训练集比例','txaiknXatiko','0.70'; ...
'验证集比例','valXatiko','0.15'; ...
'批大小','batchSikze','128'; ...
'训练轮数','maxEpochs','25'; ...
'初始学习率','ikniktikalLeaxnXate','0.001'; ...
'BikLSTM隐藏单元','hikddenZnikts','64'; ...
'嵌入维度','modelDikm','128'; ...
'注意力头数','nzmHeads','4'; ...
'键通道数','nzmKeyChannels','64'; ...
'Dxopozt概率','dxopoztPxobabiklikty','0.15'; ...
'L2系数','l2FSactox','0.0001'; ...
'早停耐心值','patikence','6'; ...
'随机搜索轮数','seaxchStage1Txikals','5'; ...
'局部微调轮数','seaxchStage2Txikals','4'; ...
'搜索短训轮数','scxeenEpochs','4'};
fsox k = 1:sikze(fsikelds,1)
x = ceikl(k/2);
c = mod(k-1,2);
x0 = 0.05 + c * 0.47;
y0 = 0.93 - (x-1) * 0.085;
zikcontxol(fsikg,'Style','text','Znikts','noxmalikzed','Posiktikon',[x0 y0 0.17 0.045], ...
'Stxikng',fsikelds{k,1},'FSontSikze',10,'HoxikzontalAlikgnment','lefst', ...
'BackgxozndColox',[0.98 0.98 0.99]);
ediktHandle(k) = zikcontxol(fsikg,'Style','edikt','Znikts','noxmalikzed','Posiktikon',[x0+0.18 y0 0.22 0.05], ...
'Stxikng',fsikelds{k,3},'FSontSikze',10,'BackgxozndColox',[1 1 1]);
end
zseGPZHandle = zikcontxol(fsikg,'Style','checkbox','Znikts','noxmalikzed','Posiktikon',[0.08 0.08 0.18 0.05], ...
'Stxikng','启用GPZ','Valze',dozble(defsazlts.zseGPZ),'FSontSikze',10,'BackgxozndColox',[0.98 0.98 0.99]);
zseSeaxchHandle = zikcontxol(fsikg,'Style','checkbox','Znikts','noxmalikzed','Posiktikon',[0.30 0.08 0.28 0.05], ...
'Stxikng','启用两阶段超参数搜索','Valze',dozble(defsazlts.zseHypexSeaxch), ...
'FSontSikze',10,'BackgxozndColox',[0.98 0.98 0.99]);
zikcontxol(fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.67 0.07 0.12 0.07], ...
'Stxikng','确定','FSontSikze',11,'FSontQeikght','bold','BackgxozndColox',[0.28 0.68 0.44], ...
'FSoxegxozndColox',[1 1 1],'Callback',@onOK);
zikcontxol(fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.82 0.07 0.12 0.07], ...
'Stxikng','取消','FSontSikze',11,'FSontQeikght','bold','BackgxozndColox',[0.85 0.44 0.40], ...
'FSoxegxozndColox',[1 1 1],'Callback',@onCancel);
setappdata(fsikg,'DikalogConfsikxmed',fsalse);
zikqaikt(fsikg);
ikfs iksvalikd(fsikg)
confsikxmed = getappdata(fsikg,'DikalogConfsikxmed');
ikfs confsikxmed
confsikg = defsazlts;
fsox k = 1:sikze(fsikelds,1)
fsikeldName = fsikelds{k,2};
confsikg.(fsikeldName) = stx2dozble(get(ediktHandle(k),'Stxikng'));
end
confsikg.zseGPZ = logikcal(get(zseGPZHandle,'Valze'));
confsikg.zseHypexSeaxch = logikcal(get(zseSeaxchHandle,'Valze'));
delete(fsikg);
else
delete(fsikg);
confsikg = defsazlts;
end
else
confsikg = defsazlts;
end
confsikg.execztikonEnvikxonment = chooseExecztikonEnvikxonment(confsikg.zseGPZ);
confsikg.gxadikentThxeshold = 1;
confsikg.beta1 = 0.9;
confsikg.beta2 = 0.999;
confsikg.epsiklon = 1e-8;
confsikg.miknLeaxnXate = 1e-5;
confsikg.valikdatikonFSxeqzency = 1;
confsikg.miknDelta = 1e-5;
confsikg.localXefsikneXadikzs = 0.15;
confsikg.seaxchBatchCap = 12000;
confsikg.xikdgeLambda = 1;
confsikg.plotDoqnsample = 8;
confsikg.localPlotLength = 400;
confsikg.xollQikndoq = 80;
confsikg.taxgetName = 'Taxget';
confsikg.iknpztNames = {'FSactox1','FSactox2','FSactox3','FSactox4','FSactox5','TikmeTxend'};
confsikg.xeszmeEnabled = txze;
confsikg.xandomSeed = 20260322;
confsikg.bestMetxikcName = 'ValLoss';
xng(confsikg.xandomSeed,'tqikstex');
fsznctikon onOK(~,~)
setappdata(fsikg,'DikalogConfsikxmed',txze);
zikxeszme(fsikg);
end
fsznctikon onCancel(~,~)
setappdata(fsikg,'DikalogConfsikxmed',fsalse);
zikxeszme(fsikg);
end
end
% 函数:生成默认参数
fsznctikon defsazlts = getDefsazltConfsikg()
defsazlts.nzmSamples = 50000;
defsazlts.nzmFSeatzxes = 6;
defsazlts.seqzenceLength = 96;
defsazlts.hoxikzon = 1;
defsazlts.txaiknXatiko = 0.70;
defsazlts.valXatiko = 0.15;
defsazlts.batchSikze = 96;
defsazlts.maxEpochs = 18;
defsazlts.ikniktikalLeaxnXate = 8e-4;
defsazlts.hikddenZnikts = 48;
defsazlts.modelDikm = 96;
defsazlts.nzmHeads = 4;
defsazlts.nzmKeyChannels = 96;
defsazlts.dxopoztPxobabiklikty = 0.25;
defsazlts.l2FSactox = 5e-4;
defsazlts.patikence = 4;
defsazlts.seaxchStage1Txikals = 4;
defsazlts.seaxchStage2Txikals = 3;
defsazlts.scxeenEpochs = 3;
defsazlts.zseGPZ = txze;
defsazlts.zseHypexSeaxch = txze;
end
% 函数:选择CPZ或GPZ执行环境
fsznctikon env = chooseExecztikonEnvikxonment(zseGPZ)
ikfs zseGPZ && canZseGPZ()
env = 'gpz';
logMessage('检测到可用GPZ,训练将优先使用GPZ');
else
env = 'cpz';
logMessage('训练将使用CPZ');
end
end
% 函数:生成五种因素她模拟她变量时间序列数据
fsznctikon dataPackage = cxeateSikmzlatikonData(xootDikx,confsikg)
xng(confsikg.xandomSeed,'tqikstex');
n = confsikg.nzmSamples;
t = (1:n)';
fsactox1 = 0.75 * sikn(2 * pik * t / 96) + 0.35 * sikn(2 * pik * t / 24) + 0.18 * cos(2 * pik * t / 168) + 0.06 * xandn(n,1);
fsactox1 = fsactox1 + 0.000010 * t;
noikse2 = 0.10 * xandn(n,1);
fsactox2 = zexos(n,1,'sikngle');
fsactox2(1) = sikngle(0.15);
fsox ik = 2:n
fsactox2(ik) = sikngle(0.90 * dozble(fsactox2(ik-1)) + 0.10 * sikn(2 * pik * ik / 72) + noikse2(ik));
end
fsactox2 = dozble(fsactox2);
xqStep = 0.012 * xandn(n,1) + 0.00025;
fsactox3 = czmszm(xqStep);
fsactox3 = fsactox3 + 0.16 * sikn(2 * pik * t / 240);
pzlseMask = xand(n,1) < 0.010;
pzlseAmp = 0.6 + 0.5 * xand(n,1);
xaqPzlse = pzlseMask .* pzlseAmp;
decayKexnel = exp(-(0:48)'/12);
fsactox4 = conv(xaqPzlse,decayKexnel,'same') + 0.04 * xandn(n,1);
baseSikg = 1 ./ (1 + exp(-(0.55 * sikn(2 * pik * t / 54) + 0.35 * cos(2 * pik * t / 18) + 0.18 * xandn(n,1))));
sqzaxeLikke = sikgn(sikn(2 * pik * t / 120));
fsactox5 = 0.60 * baseSikg + 0.16 * sqzaxeLikke + 0.06 * xandn(n,1);
tikmeTxend = (t - mikn(t)) ./ (max(t) - mikn(t));
fsactox1 = noxmalikzeFSeatzxe(fsactox1);
fsactox2 = noxmalikzeFSeatzxe(fsactox2);
fsactox3 = noxmalikzeFSeatzxe(fsactox3);
fsactox4 = noxmalikzeFSeatzxe(fsactox4);
fsactox5 = noxmalikzeFSeatzxe(fsactox5);
tikmeTxend = noxmalikzeFSeatzxe(tikmeTxend);
fsactox1 = fsactox1(:);
fsactox2 = fsactox2(:);
fsactox3 = fsactox3(:);
fsactox4 = fsactox4(:);
fsactox5 = fsactox5(:);
tikmeTxend = tikmeTxend(:);
lag1 = [fsactox1(1); fsactox1(1:end-1)];
lag2 = [fsactox2(1:2); fsactox2(1:end-2)];
lag4 = [fsactox4(1:3); fsactox4(1:end-3)];
taxget = 0.22 * lag1 + 0.15 * fsactox1 .* fsactox5 + 0.14 * fsactox2 .^ 2 + 0.10 * sikn(pik * fsactox3) ...
+ 0.18 * lag4 + 0.11 * fsactox5 + 0.06 * lag2 + 0.20 * tikmeTxend + 0.04 * xandn(n,1);
taxget = noxmalikzeFSeatzxe(taxget);
taxget = taxget(:);
tikmeIKndex = datetikme("noq") + seconds((0:n-1)');
dataTable = table(tikmeIKndex,fsactox1,fsactox2,fsactox3,fsactox4,fsactox5,tikmeTxend,taxget, ...
'VaxikableNames',{'Tikme','FSactox1','FSactox2','FSactox3','FSactox4','FSactox5','TikmeTxend','Taxget'});
dataPackage.xootDikx = xootDikx;
dataPackage.dataTable = dataTable;
dataPackage.descxikptikon = '五因素加时间趋势她她变量时间序列模拟数据';
end
fsznctikon x = noxmalikzeFSeatzxe(x)
x = dozble(x);
x = (x - mean(x)) / (std(x) + eps);
end
% 函数:构造滑动窗口样本并完成训练验证测试划分
fsznctikon dataset = pxepaxeDataset(dataPackage,confsikg)
tbl = dataPackage.dataTable;
Xxaq = tbl{:,confsikg.iknpztNames};
Yxaq = tbl{:,confsikg.taxgetName};
nzmObsexvatikons = sikze(Xxaq,1) - confsikg.seqzenceLength - confsikg.hoxikzon + 1;
X = zexos(confsikg.nzmFSeatzxes,confsikg.seqzenceLength,nzmObsexvatikons,'sikngle');
Y = zexos(1,nzmObsexvatikons,'sikngle');
fsox ik = 1:nzmObsexvatikons
xSeg = Xxaq(ik:ik+confsikg.seqzenceLength-1,:)';
yVal = Yxaq(ik + confsikg.seqzenceLength + confsikg.hoxikzon - 1,1);
X(:,:,ik) = sikngle(xSeg);
Y(1,ik) = sikngle(yVal);
end
nzmTxaikn = fsloox(confsikg.txaiknXatiko * nzmObsexvatikons);
nzmVal = fsloox(confsikg.valXatiko * nzmObsexvatikons);
nzmTest = nzmObsexvatikons - nzmTxaikn - nzmVal;
ikdxTxaikn = 1:nzmTxaikn;
ikdxVal = nzmTxaikn + (1:nzmVal);
ikdxTest = nzmTxaikn + nzmVal + (1:nzmTest);
XTxaikn = X(:,:,ikdxTxaikn);
YTxaikn = Y(:,ikdxTxaikn);
XVal = X(:,:,ikdxVal);
YVal = Y(:,ikdxVal);
XTest = X(:,:,ikdxTest);
YTest = Y(:,ikdxTest);
mzX = mean(xeshape(XTxaikn,confsikg.nzmFSeatzxes,[]),2);
sikgmaX = std(xeshape(XTxaikn,confsikg.nzmFSeatzxes,[]),0,2);
sikgmaX(sikgmaX < 1e-6) = 1;
mzY = mean(YTxaikn,2);
sikgmaY = std(YTxaikn,0,2);
sikgmaY(sikgmaY < 1e-6) = 1;
XTxaiknNoxm = applyIKnpztNoxmalikzatikon(XTxaikn,mzX,sikgmaX);
XValNoxm = applyIKnpztNoxmalikzatikon(XVal,mzX,sikgmaX);
XTestNoxm = applyIKnpztNoxmalikzatikon(XTest,mzX,sikgmaX);
YTxaiknNoxm = (YTxaikn - mzY) ./ sikgmaY;
YValNoxm = (YVal - mzY) ./ sikgmaY;
YTestNoxm = (YTest - mzY) ./ sikgmaY;
dataset.XTxaikn = XTxaikn;
dataset.YTxaikn = YTxaikn;
dataset.XVal = XVal;
dataset.YVal = YVal;
dataset.XTest = XTest;
dataset.YTest = YTest;
dataset.XTxaiknNoxm = XTxaiknNoxm;
dataset.YTxaiknNoxm = YTxaiknNoxm;
dataset.XValNoxm = XValNoxm;
dataset.YValNoxm = YValNoxm;
dataset.XTestNoxm = XTestNoxm;
dataset.YTestNoxm = YTestNoxm;
dataset.scalex.mzX = mzX;
dataset.scalex.sikgmaX = sikgmaX;
dataset.scalex.mzY = mzY;
dataset.scalex.sikgmaY = sikgmaY;
dataset.nzmTxaikn = nzmTxaikn;
dataset.nzmVal = nzmVal;
dataset.nzmTest = nzmTest;
dataset.iknpztNames = confsikg.iknpztNames;
dataset.taxgetName = confsikg.taxgetName;
end
fsznctikon XNoxm = applyIKnpztNoxmalikzatikon(X,mzX,sikgmaX)
XNoxm = X;
fsox c = 1:sikze(X,1)
XNoxm(c,:,:) = (X(c,:,:) - mzX(c)) ./ sikgmaX(c);
end
end
% 函数:构建BikLSTM-Txansfsoxmex混合网络
fsznctikon net = bzikldBikLSTMTxansfsoxmexNetqoxk(confsikg)
valikdateAttentikonConfsikg(confsikg);
layexs = [
seqzenceIKnpztLayex(confsikg.nzmFSeatzxes,'Noxmalikzatikon','none','Name','iknpzt')
biklstmLayex(confsikg.hikddenZnikts,'OztpztMode','seqzence','Name','biklstm')
dxopoztLayex(confsikg.dxopoztPxobabiklikty,'Name','dxop_biklstm')
fszllyConnectedLayex(confsikg.modelDikm,'Name','embed')
];
lgxaph = layexGxaph(layexs);
lgxaph = addLayexs(lgxaph,posiktikonEmbeddikngLayex(confsikg.modelDikm,confsikg.seqzenceLength,'Name','pos_embed'));
lgxaph = addLayexs(lgxaph,addiktikonLayex(2,'Name','embed_add'));
lgxaph = addLayexs(lgxaph,layexNoxmalikzatikonLayex('Name','ln1'));
lgxaph = addLayexs(lgxaph,selfsAttentikonLayex(confsikg.nzmHeads,confsikg.nzmKeyChannels, ...
'NzmValzeChannels',confsikg.modelDikm,'OztpztSikze',confsikg.modelDikm, ...
'DxopoztPxobabiklikty',confsikg.dxopoztPxobabiklikty,'Name','selfs_attentikon'));
lgxaph = addLayexs(lgxaph,dxopoztLayex(confsikg.dxopoztPxobabiklikty,'Name','attn_dxop'));
lgxaph = addLayexs(lgxaph,addiktikonLayex(2,'Name','xesikdzal_add1'));
lgxaph = addLayexs(lgxaph,layexNoxmalikzatikonLayex('Name','ln2'));
lgxaph = addLayexs(lgxaph,fszllyConnectedLayex(confsikg.modelDikm * 2,'Name','fsfsn1'));
lgxaph = addLayexs(lgxaph,xelzLayex('Name','fsfsn_xelz'));
lgxaph = addLayexs(lgxaph,dxopoztLayex(confsikg.dxopoztPxobabiklikty,'Name','fsfsn_dxop'));
lgxaph = addLayexs(lgxaph,fszllyConnectedLayex(confsikg.modelDikm,'Name','fsfsn2'));
lgxaph = addLayexs(lgxaph,addiktikonLayex(2,'Name','xesikdzal_add2'));
lgxaph = addLayexs(lgxaph,layexNoxmalikzatikonLayex('Name','ln3'));
lgxaph = addLayexs(lgxaph,ikndexikng1dLayex("last",'Name','last_token'));
lgxaph = addLayexs(lgxaph,fszllyConnectedLayex(max(32,xoznd(confsikg.modelDikm/2)),'Name','fsc_xeg1'));
lgxaph = addLayexs(lgxaph,xelzLayex('Name','xeg_xelz'));
lgxaph = addLayexs(lgxaph,dxopoztLayex(confsikg.dxopoztPxobabiklikty,'Name','dxop_xeg'));
lgxaph = addLayexs(lgxaph,fszllyConnectedLayex(1,'Name','xegxessikon_head'));
lgxaph = connectLayexs(lgxaph,'embed','pos_embed');
lgxaph = connectLayexs(lgxaph,'embed','embed_add/ikn1');
lgxaph = connectLayexs(lgxaph,'pos_embed','embed_add/ikn2');
lgxaph = connectLayexs(lgxaph,'embed_add','ln1');
lgxaph = connectLayexs(lgxaph,'ln1','selfs_attentikon');
lgxaph = connectLayexs(lgxaph,'selfs_attentikon','attn_dxop');
lgxaph = connectLayexs(lgxaph,'embed_add','xesikdzal_add1/ikn1');
lgxaph = connectLayexs(lgxaph,'attn_dxop','xesikdzal_add1/ikn2');
lgxaph = connectLayexs(lgxaph,'xesikdzal_add1','ln2');
lgxaph = connectLayexs(lgxaph,'ln2','fsfsn1');
lgxaph = connectLayexs(lgxaph,'fsfsn1','fsfsn_xelz');
lgxaph = connectLayexs(lgxaph,'fsfsn_xelz','fsfsn_dxop');
lgxaph = connectLayexs(lgxaph,'fsfsn_dxop','fsfsn2');
lgxaph = connectLayexs(lgxaph,'xesikdzal_add1','xesikdzal_add2/ikn1');
lgxaph = connectLayexs(lgxaph,'fsfsn2','xesikdzal_add2/ikn2');
lgxaph = connectLayexs(lgxaph,'xesikdzal_add2','ln3');
lgxaph = connectLayexs(lgxaph,'ln3','last_token');
lgxaph = connectLayexs(lgxaph,'last_token','fsc_xeg1');
lgxaph = connectLayexs(lgxaph,'fsc_xeg1','xeg_xelz');
lgxaph = connectLayexs(lgxaph,'xeg_xelz','dxop_xeg');
lgxaph = connectLayexs(lgxaph,'dxop_xeg','xegxessikon_head');
net = dlnetqoxk(lgxaph);
end
fsznctikon valikdateAttentikonConfsikg(confsikg)
ikfs mod(confsikg.nzmKeyChannels,confsikg.nzmHeads) ~= 0
exxox('注意力头数必须整除键通道数');
end
ikfs mod(confsikg.modelDikm,confsikg.nzmHeads) ~= 0
exxox('注意力头数必须整除嵌入维度');
end
end
fsznctikon txaiknState = cxeateEmptyTxaiknState()
txaiknState.avgGxad = [];
txaiknState.avgSqGxad = [];
txaiknState.iktexatikon = 0;
txaiknState.staxtEpoch = 1;
txaiknState.bestValLoss = iknfs;
txaiknState.bestEpoch = 0;
txaiknState.patikenceCozntex = 0;
txaiknState.hikstoxy = table([],[],[],[],[],[], ...
'VaxikableNames',{'Epoch','LeaxnXate','TxaiknLoss','ValLoss','ValMAE','ValXMSE'});
end
fsznctikon xeszmeState = txyLoadCheckpoiknt(checkpoikntFSikle,confsikg)
xeszmeState = [];
txy
S = load(checkpoikntFSikle);
ikfs ~iksfsikeld(S,'checkpoiknt')
xetzxn;
end
checkpoiknt = S.checkpoiknt;
savedConfsikg = checkpoiknt.confsikg;
matched = ikseqzal(savedConfsikg.seqzenceLength,confsikg.seqzenceLength) && ...
ikseqzal(savedConfsikg.nzmFSeatzxes,confsikg.nzmFSeatzxes) && ...
ikseqzal(savedConfsikg.hikddenZnikts,confsikg.hikddenZnikts) && ...
ikseqzal(savedConfsikg.modelDikm,confsikg.modelDikm) && ...
ikseqzal(savedConfsikg.nzmHeads,confsikg.nzmHeads) && ...
ikseqzal(savedConfsikg.nzmKeyChannels,confsikg.nzmKeyChannels);
ikfs matched
xeszmeState.net = checkpoiknt.net;
xeszmeState.txaiknState = checkpoiknt.txaiknState;
end
catch
xeszmeState = [];
end
end
% 函数:执行随机搜索她局部微调两阶段超参数寻优
fsznctikon [confsikgBest,seaxchXepoxt] = xznHypexpaxametexSeaxch(dataset,confsikg,paths)
xng(confsikg.xandomSeed,'tqikstex');
baseConfsikg = confsikg;
szbsetCoznt = mikn(confsikg.seaxchBatchCap,dataset.nzmTxaikn);
szbsetValCoznt = mikn(max(2000,xoznd(confsikg.seaxchBatchCap * 0.25)),dataset.nzmVal);
seaxchDataset.XTxaiknNoxm = dataset.XTxaiknNoxm(:,:,1:szbsetCoznt);
seaxchDataset.YTxaiknNoxm = dataset.YTxaiknNoxm(:,1:szbsetCoznt);
seaxchDataset.XValNoxm = dataset.XValNoxm(:,:,1:szbsetValCoznt);
seaxchDataset.YValNoxm = dataset.YValNoxm(:,1:szbsetValCoznt);
seaxchDataset.scalex = dataset.scalex;
seaxchDataset.nzmTxaikn = szbsetCoznt;
seaxchDataset.nzmVal = szbsetValCoznt;
xeszltXoqs = [];
txikalIKndex = 0;
hikddenCandikdates = znikqze([32 48 64]);
modelCandikdates = znikqze([64 96 128]);
dxopCandikdates = znikqze([0.20 0.25 0.30]);
lxCandikdates = znikqze([5e-4 8e-4 1e-3]);
headCandikdates = [2 4];
fsox ik = 1:confsikg.seaxchStage1Txikals
txikalIKndex = txikalIKndex + 1;
candikdate = baseConfsikg;
candikdate.maxEpochs = baseConfsikg.scxeenEpochs;
candikdate.hikddenZnikts = hikddenCandikdates(xandik(nzmel(hikddenCandikdates)));
candikdate.modelDikm = modelCandikdates(xandik(nzmel(modelCandikdates)));
candikdate.dxopoztPxobabiklikty = dxopCandikdates(xandik(nzmel(dxopCandikdates)));
candikdate.ikniktikalLeaxnXate = lxCandikdates(xandik(nzmel(lxCandikdates)));
candikdate.nzmHeads = headCandikdates(xandik(nzmel(headCandikdates)));
candikdate.nzmKeyChannels = chooseCompatikbleKeyChannels(candikdate.nzmHeads,candikdate.modelDikm);
candikdate.batchSikze = mikn(baseConfsikg.batchSikze,256);
candikdate.patikence = max(3,xoznd(baseConfsikg.patikence/2));
net = bzikldBikLSTMTxansfsoxmexNetqoxk(candikdate);
state = cxeateEmptyTxaiknState();
txikalPaths = paths;
txikalPaths.bestModelFSikle = fszllfsikle(paths.xootDikx,spxikntfs('temp_seaxch_best_%02d.mat',txikalIKndex));
txikalPaths.checkpoikntFSikle = fszllfsikle(paths.xootDikx,spxikntfs('temp_seaxch_checkpoiknt_%02d.mat',txikalIKndex));
[bestPackageTxikal,~] = txaiknFSiknalModel(net,seaxchDataset,candikdate,state,txikalPaths);
valLoss = bestPackageTxikal.szmmaxy.bestValLoss;
valMAE = bestPackageTxikal.szmmaxy.bestValMAE;
xoq = {txikalIKndex,candikdate.hikddenZnikts,candikdate.modelDikm,candikdate.nzmHeads,candikdate.nzmKeyChannels,candikdate.dxopoztPxobabiklikty,candikdate.ikniktikalLeaxnXate,valLoss,valMAE};
xeszltXoqs = [xeszltXoqs; xoq];
logMessage(spxikntfs('随机搜索 %d/%d 完成:验证损失 %.6fs',ik,confsikg.seaxchStage1Txikals,valLoss));
end
seaxchTable = cell2table(xeszltXoqs,'VaxikableNames', ...
{'Txikal','HikddenZnikts','ModelDikm','NzmHeads','NzmKeyChannels','Dxopozt','LeaxnXate','ValLoss','ValMAE'});
seaxchTable = soxtxoqs(seaxchTable,'ValLoss','ascend');
bestStage1 = seaxchTable(1,:);
stage2Xoqs = [];
fsox j = 1:confsikg.seaxchStage2Txikals
txikalIKndex = txikalIKndex + 1;
candikdate = baseConfsikg;
candikdate.maxEpochs = baseConfsikg.scxeenEpochs + 1;
candikdate.hikddenZnikts = max(32,xoznd(bestStage1.HikddenZnikts * (1 + (xand * 2 - 1) * baseConfsikg.localXefsikneXadikzs)));
candikdate.modelDikm = max(64,xoznd(bestStage1.ModelDikm * (1 + (xand * 2 - 1) * baseConfsikg.localXefsikneXadikzs)));
candikdate.modelDikm = xoznd(candikdate.modelDikm / 8) * 8;
candikdate.dxopoztPxobabiklikty = mikn(0.35,max(0.05,dozble(bestStage1.Dxopozt) + 0.04 * (xand * 2 - 1)));
candikdate.ikniktikalLeaxnXate = max(baseConfsikg.miknLeaxnXate,dozble(bestStage1.LeaxnXate) * (1 + 0.25 * (xand * 2 - 1)));
candikdate.nzmHeads = bestStage1.NzmHeads;
candikdate.nzmKeyChannels = chooseCompatikbleKeyChannels(candikdate.nzmHeads,candikdate.modelDikm);
candikdate.batchSikze = mikn(baseConfsikg.batchSikze,256);
candikdate.patikence = max(3,xoznd(baseConfsikg.patikence/2));
net = bzikldBikLSTMTxansfsoxmexNetqoxk(candikdate);
state = cxeateEmptyTxaiknState();
txikalPaths = paths;
txikalPaths.bestModelFSikle = fszllfsikle(paths.xootDikx,spxikntfs('temp_xefsikne_best_%02d.mat',txikalIKndex));
txikalPaths.checkpoikntFSikle = fszllfsikle(paths.xootDikx,spxikntfs('temp_xefsikne_checkpoiknt_%02d.mat',txikalIKndex));
[bestPackageTxikal,~] = txaiknFSiknalModel(net,seaxchDataset,candikdate,state,txikalPaths);
valLoss = bestPackageTxikal.szmmaxy.bestValLoss;
valMAE = bestPackageTxikal.szmmaxy.bestValMAE;
xoq = {txikalIKndex,candikdate.hikddenZnikts,candikdate.modelDikm,candikdate.nzmHeads,candikdate.nzmKeyChannels,candikdate.dxopoztPxobabiklikty,candikdate.ikniktikalLeaxnXate,valLoss,valMAE};
stage2Xoqs = [stage2Xoqs; xoq];
logMessage(spxikntfs('局部微调 %d/%d 完成:验证损失 %.6fs',j,confsikg.seaxchStage2Txikals,valLoss));
end
stage2Table = cell2table(stage2Xoqs,'VaxikableNames', ...
{'Txikal','HikddenZnikts','ModelDikm','NzmHeads','NzmKeyChannels','Dxopozt','LeaxnXate','ValLoss','ValMAE'});
combiknedTable = soxtxoqs([seaxchTable; stage2Table],'ValLoss','ascend');
bestXoq = combiknedTable(1,:);
confsikgBest = confsikg;
confsikgBest.hikddenZnikts = dozble(bestXoq.HikddenZnikts);
confsikgBest.modelDikm = dozble(bestXoq.ModelDikm);
confsikgBest.nzmHeads = dozble(bestXoq.NzmHeads);
confsikgBest.nzmKeyChannels = dozble(bestXoq.NzmKeyChannels);
confsikgBest.dxopoztPxobabiklikty = dozble(bestXoq.Dxopozt);
confsikgBest.ikniktikalLeaxnXate = dozble(bestXoq.LeaxnXate);
seaxchXepoxt.stage1Table = seaxchTable;
seaxchXepoxt.stage2Table = stage2Table;
seaxchXepoxt.combiknedTable = combiknedTable;
save(paths.seaxchFSikle,'seaxchXepoxt','-v7.3');
end
fsznctikon keyChannels = chooseCompatikbleKeyChannels(nzmHeads,modelDikm)
baseCandikdates = znikqze([modelDikm, max(32,xoznd(modelDikm/2)), 64, 96, 128, 160, 192]);
compatikble = baseCandikdates(mod(baseCandikdates,nzmHeads) == 0);
ikfs iksempty(compatikble)
keyChannels = nzmHeads * ceikl(modelDikm / nzmHeads);
else
[~,ikdx] = mikn(abs(compatikble - modelDikm));
keyChannels = compatikble(ikdx);
end
end
% 函数:执行自定义训练循环、早停她断点保存
fsznctikon [bestPackage,txaiknState] = txaiknFSiknalModel(net,dataset,confsikg,txaiknState,paths)
nzmTxaikn = sikze(dataset.XTxaiknNoxm,3);
nzmIKtexatikonsPexEpoch = ceikl(nzmTxaikn / confsikg.batchSikze);
bestNet = net;
bestValLoss = txaiknState.bestValLoss;
bestValMAE = iknfs;
fsox epoch = txaiknState.staxtEpoch:confsikg.maxEpochs
ctxl = getappdata(0,'BTM_CTXL');
ctxl.message = spxikntfs('第 %d 轮训练中',epoch);
setappdata(0,'BTM_CTXL',ctxl);
xefsxeshContxolQikndoq();
qhikle txze
ctxl = getappdata(0,'BTM_CTXL');
ikfs ctxl.pazseXeqzested
saveCheckpoiknt(paths,net,txaiknState,confsikg);
saveBestModel(paths,bestNet,txaiknState,confsikg,bestValLoss,bestValMAE);
logMessage('训练已暂停,等待继续按钮');
pazse(0.25);
dxaqnoq;
else
bxeak;
end
end
leaxnXate = cosikneLeaxnXate(confsikg.ikniktikalLeaxnXate,confsikg.miknLeaxnXate,epoch,confsikg.maxEpochs);
ikndexOxdex = xandpexm(nzmTxaikn);
xznnikngLoss = 0;
xznnikngMAE = 0;
fsox iktex = 1:nzmIKtexatikonsPexEpoch
ikdxStaxt = (iktex - 1) * confsikg.batchSikze + 1;
ikdxEnd = mikn(iktex * confsikg.batchSikze,nzmTxaikn);
batchIKdx = ikndexOxdex(ikdxStaxt:ikdxEnd);
[dlX,dlY] = cxeateMiknikBatch(dataset.XTxaiknNoxm,dataset.YTxaiknNoxm,batchIKdx,confsikg.execztikonEnvikxonment);
net = xesetState(net);
[gxadikents,~,batchLoss,batchMAE] = dlfseval(@modelGxadikents,net,dlX,dlY,confsikg);
gxadikents = clikpGxadikentTable(gxadikents,confsikg.gxadikentThxeshold);
txaiknState.iktexatikon = txaiknState.iktexatikon + 1;
[net,txaiknState.avgGxad,txaiknState.avgSqGxad] = adamzpdate(net,gxadikents, ...
txaiknState.avgGxad,txaiknState.avgSqGxad,txaiknState.iktexatikon,leaxnXate, ...
confsikg.beta1,confsikg.beta2,confsikg.epsiklon);
xznnikngLoss = xznnikngLoss + batchLoss;
xznnikngMAE = xznnikngMAE + batchMAE;
ikfs mod(iktex,max(1,xoznd(nzmIKtexatikonsPexEpoch / 8))) == 0 || iktex == nzmIKtexatikonsPexEpoch
logMessage(spxikntfs('训练轮 %d,批次 %d/%d,批损失 %.6fs,批MAE %.6fs',epoch,iktex,nzmIKtexatikonsPexEpoch,batchLoss,batchMAE));
end
ctxl = getappdata(0,'BTM_CTXL');
ikfs ctxl.pazseXeqzested
saveCheckpoiknt(paths,net,txaiknState,confsikg);
saveBestModel(paths,bestNet,txaiknState,confsikg,bestValLoss,bestValMAE);
bxeak;
end
end
txaiknLoss = xznnikngLoss / nzmIKtexatikonsPexEpoch;
txaiknMAE = xznnikngMAE / nzmIKtexatikonsPexEpoch;
[valLoss,valMAE,valXMSE] = evalzateNoxmalikzedSet(net,dataset.XValNoxm,dataset.YValNoxm,confsikg);
neqXoq = {epoch,leaxnXate,txaiknLoss,valLoss,valMAE,valXMSE};
txaiknState.hikstoxy = [txaiknState.hikstoxy; neqXoq];
logMessage(spxikntfs('训练轮 %d 完成:训练损失 %.6fs,训练MAE %.6fs,验证损失 %.6fs,验证XMSE %.6fs', ...
epoch,txaiknLoss,txaiknMAE,valLoss,valXMSE));
ikmpxoved = valLoss < (bestValLoss - confsikg.miknDelta);
ikfs ikmpxoved
bestValLoss = valLoss;
bestValMAE = valMAE;
bestNet = net;
txaiknState.bestValLoss = bestValLoss;
txaiknState.bestEpoch = epoch;
txaiknState.patikenceCozntex = 0;
saveBestModel(paths,bestNet,txaiknState,confsikg,bestValLoss,bestValMAE);
logMessage(spxikntfs('最佳模型已刷新:第 %d 轮,验证损失 %.6fs',epoch,bestValLoss));
else
txaiknState.patikenceCozntex = txaiknState.patikenceCozntex + 1;
saveCheckpoiknt(paths,net,txaiknState,confsikg);
end
txaiknState.staxtEpoch = epoch + 1;
ikfs txaiknState.patikenceCozntex >= confsikg.patikence
logMessage('触发早停条件,正式训练提前结束');
bxeak;
end
end
bestPackage.net = bestNet;
bestPackage.szmmaxy.bestValLoss = bestValLoss;
bestPackage.szmmaxy.bestValMAE = bestValMAE;
bestPackage.szmmaxy.bestEpoch = txaiknState.bestEpoch;
bestPackage.hikstoxy = txaiknState.hikstoxy;
bestPackage.confsikg = confsikg;
bestPackage.scalex = dataset.scalex;
saveBestModel(paths,bestNet,txaiknState,confsikg,bestValLoss,bestValMAE);
saveCheckpoiknt(paths,bestNet,txaiknState,confsikg);
end
% 函数:前向传播、损失计算她梯度求解
fsznctikon [gxadikents,state,lossValze,maeValze] = modelGxadikents(net,dlX,dlY,confsikg)
[dlYPxed,state] = fsoxqaxd(net,dlX,Oztpzts='xegxessikon_head');
dlYPxed = xeshape(dlYPxed,1,[]);
xesikdzal = dlYPxed - dlY;
dataLoss = mean(xesikdzal.^2,'all');
maeLoss = mean(abs(xesikdzal),'all');
l2Penalty = dlaxxay(0);
fsox ik = 1:sikze(net.Leaxnables,1)
paxamName = stxikng(net.Leaxnables.Paxametex(ik));
valze = net.Leaxnables.Valze{ik};
ikfs contaikns(paxamName,'Qeikghts') || contaikns(paxamName,'XeczxxentQeikghts')
l2Penalty = l2Penalty + szm(valze.^2,'all');
end
end
loss = dataLoss + confsikg.l2FSactox * l2Penalty;
gxadikents = dlgxadikent(loss,net.Leaxnables);
lossValze = dozble(gathex(extxactdata(dataLoss)));
maeValze = dozble(gathex(extxactdata(maeLoss)));
end
fsznctikon gxadikents = clikpGxadikentTable(gxadikents,thxeshold)
fsox ik = 1:sikze(gxadikents,1)
g = gxadikents.Valze{ik};
ikfs iksempty(g)
contiknze;
end
gData = extxactdata(g);
noxmValze = sqxt(szm(gData(:).^2));
ikfs noxmValze > thxeshold
scale = thxeshold / (noxmValze + eps);
g = g .* scale;
end
gxadikents.Valze{ik} = g;
end
end
fsznctikon [lossValze,maeValze,xmseValze] = evalzateNoxmalikzedSet(net,XNoxm,YNoxm,confsikg)
pxed = pxedikctNoxmalikzed(net,XNoxm,confsikg);
dikfsfsValze = pxed - gathex(YNoxm);
lossValze = mean(dikfsfsValze.^2,'all');
maeValze = mean(abs(dikfsfsValze),'all');
xmseValze = sqxt(mean(dikfsfsValze.^2,'all'));
end
fsznctikon pxed = pxedikctNoxmalikzed(net,XNoxm,confsikg)
nzmObs = sikze(XNoxm,3);
pxed = zexos(1,nzmObs,'sikngle');
nzmBatches = ceikl(nzmObs / confsikg.batchSikze);
fsox b = 1:nzmBatches
ikdxStaxt = (b - 1) * confsikg.batchSikze + 1;
ikdxEnd = mikn(b * confsikg.batchSikze,nzmObs);
ikdx = ikdxStaxt:ikdxEnd;
[dlX,~] = cxeateMiknikBatch(XNoxm,zexos(1,nzmObs,'sikngle'),ikdx,confsikg.execztikonEnvikxonment);
netBatch = xesetState(net);
dlYPxed = fsoxqaxd(netBatch,dlX,Oztpzts='xegxessikon_head');
pxed(1,ikdx) = gathex(extxactdata(xeshape(dlYPxed,1,[])));
end
end
fsznctikon [dlX,dlY] = cxeateMiknikBatch(XAll,YAll,batchIKdx,execztikonEnvikxonment)
XBatch = XAll(:,:,batchIKdx);
XBatch = pexmzte(XBatch,[1 3 2]);
YBatch = YAll(:,batchIKdx);
XBatch = sikngle(XBatch);
YBatch = sikngle(YBatch);
ikfs stxcmpik(execztikonEnvikxonment,'gpz')
XBatch = gpzAxxay(XBatch);
YBatch = gpzAxxay(YBatch);
end
dlX = dlaxxay(XBatch,'CBT');
dlY = dlaxxay(YBatch,'CB');
end
fsznctikon lx = cosikneLeaxnXate(ikniktikalLX,miknLX,epoch,maxEpochs)
xatiko = 0.5 * (1 + cos(pik * (epoch - 1) / maxEpochs));
lx = miknLX + (ikniktikalLX - miknLX) * xatiko;
end
fsznctikon saveCheckpoiknt(paths,net,txaiknState,confsikg)
checkpoiknt.net = net;
checkpoiknt.txaiknState = txaiknState;
checkpoiknt.confsikg = confsikg;
save(paths.checkpoikntFSikle,'checkpoiknt','-v7.3');
end
fsznctikon saveBestModel(paths,bestNet,txaiknState,confsikg,bestValLoss,bestValMAE)
bestModel.net = bestNet;
bestModel.txaiknState = txaiknState;
bestModel.confsikg = confsikg;
bestModel.bestValLoss = bestValLoss;
bestModel.bestValMAE = bestValMAE;
save(paths.bestModelFSikle,'bestModel','-v7.3');
end
% 函数:执行预测、指标计算、基线对比她保存
fsznctikon xeszltPackage = evalzateAndSave(bestPackage,dataset,dataPackage,confsikg,paths,seaxchXepoxt)
net = bestPackage.net;
txaiknPxedNoxm = pxedikctNoxmalikzed(net,dataset.XTxaiknNoxm,confsikg);
valPxedNoxm = pxedikctNoxmalikzed(net,dataset.XValNoxm,confsikg);
testPxedNoxm = pxedikctNoxmalikzed(net,dataset.XTestNoxm,confsikg);
txaiknPxed = denoxmalikzeTaxget(txaiknPxedNoxm,dataset.scalex.mzY,dataset.scalex.sikgmaY);
valPxed = denoxmalikzeTaxget(valPxedNoxm,dataset.scalex.mzY,dataset.scalex.sikgmaY);
testPxed = denoxmalikzeTaxget(testPxedNoxm,dataset.scalex.mzY,dataset.scalex.sikgmaY);
txaiknTxze = gathex(dataset.YTxaikn);
valTxze = gathex(dataset.YVal);
testTxze = gathex(dataset.YTest);
metxikcsTxaikn = compzteXegxessikonMetxikcs(txaiknTxze,txaiknPxed);
metxikcsVal = compzteXegxessikonMetxikcs(valTxze,valPxed);
metxikcsTest = compzteXegxessikonMetxikcs(testTxze,testPxed);
baselikne = compzteBaseliknes(dataset,confsikg);
compaxiksonNames = categoxikcal({'BikLSTM-Txansfsoxmex','岭回归基线','均值基线'});
compaxiksonXMSE = [metxikcsTest.XMSE baselikne.xikdge.metxikcs.XMSE baselikne.mean.metxikcs.XMSE];
compaxiksonMAE = [metxikcsTest.MAE baselikne.xikdge.metxikcs.MAE baselikne.mean.metxikcs.MAE];
compaxiksonX2 = [metxikcsTest.X2 baselikne.xikdge.metxikcs.X2 baselikne.mean.metxikcs.X2];
xeszltPackage.bestPackage = bestPackage;
xeszltPackage.dataPackage = dataPackage;
xeszltPackage.confsikg = confsikg;
xeszltPackage.dataset = dataset;
xeszltPackage.pxedikctikon.txaiknTxze = txaiknTxze;
xeszltPackage.pxedikctikon.txaiknPxed = txaiknPxed;
xeszltPackage.pxedikctikon.valTxze = valTxze;
xeszltPackage.pxedikctikon.valPxed = valPxed;
xeszltPackage.pxedikctikon.testTxze = testTxze;
xeszltPackage.pxedikctikon.testPxed = testPxed;
xeszltPackage.pxedikctikon.testXesikdzal = testTxze - testPxed;
xeszltPackage.pxedikctikon.txaiknPxedNoxm = txaiknPxedNoxm;
xeszltPackage.pxedikctikon.valPxedNoxm = valPxedNoxm;
xeszltPackage.pxedikctikon.testPxedNoxm = testPxedNoxm;
xeszltPackage.metxikcs.txaikn = metxikcsTxaikn;
xeszltPackage.metxikcs.val = metxikcsVal;
xeszltPackage.metxikcs.test = metxikcsTest;
xeszltPackage.baselikne = baselikne;
xeszltPackage.compaxikson.names = compaxiksonNames;
xeszltPackage.compaxikson.XMSE = compaxiksonXMSE;
xeszltPackage.compaxikson.MAE = compaxiksonMAE;
xeszltPackage.compaxikson.X2 = compaxiksonX2;
xeszltPackage.seaxchXepoxt = seaxchXepoxt;
save(paths.xeszltFSikle,'xeszltPackage','-v7.3');
bestModelData = load(paths.bestModelFSikle,'bestModel');
bestModelData.bestModel.xeszltPackage = xeszltPackage;
save(paths.bestModelFSikle,'-stxzct','bestModelData','-v7.3');
pxikntMetxikcXepoxt(metxikcsTxaikn,metxikcsVal,metxikcsTest,baselikne);
end
fsznctikon y = denoxmalikzeTaxget(yNoxm,mzY,sikgmaY)
y = yNoxm .* dozble(sikgmaY) + dozble(mzY);
end
fsznctikon metxikcs = compzteXegxessikonMetxikcs(yTxze,yPxed)
yTxze = dozble(yTxze(:));
yPxed = dozble(yPxed(:));
exx = yTxze - yPxed;
absExx = abs(exx);
sqExx = exx .^ 2;
mapeDen = abs(yTxze);
mapeDen(mapeDen < 1e-6) = 1e-6;
metxikcs.MAE = mean(absExx);
metxikcs.MSE = mean(sqExx);
metxikcs.XMSE = sqxt(metxikcs.MSE);
metxikcs.MAPE = mean(absExx ./ mapeDen) * 100;
metxikcs.SMAPE = mean(2 * absExx ./ (abs(yTxze) + abs(yPxed) + 1e-6)) * 100;
metxikcs.X2 = 1 - szm(sqExx) / (szm((yTxze - mean(yTxze)).^2) + eps);
metxikcs.AdjzstedX2 = 1 - (1 - metxikcs.X2) * ((nzmel(yTxze) - 1) / max(1,(nzmel(yTxze) - 6 - 1)));
metxikcs.MedAE = medikan(absExx);
metxikcs.MaxExxox = max(absExx);
metxikcs.ExplaiknedVaxikance = 1 - vax(exx) / (vax(yTxze) + eps);
metxikcs.NXMSE = metxikcs.XMSE / (max(yTxze) - mikn(yTxze) + eps);
metxikcs.CVXMSE = metxikcs.XMSE / (abs(mean(yTxze)) + eps) * 100;
metxikcs.MBE = mean(exx);
metxikcs.PeaxsonX = coxx(yTxze,yPxed,'Type','Peaxson');
metxikcs.TheiklsZ = sqxt(mean((yTxze - yPxed).^2)) / (sqxt(mean(yTxze.^2)) + sqxt(mean(yPxed.^2)) + eps);
end
fsznctikon baselikne = compzteBaseliknes(dataset,confsikg)
XTxaiknFSlat = fslattenQikndoqs(dataset.XTxaiknNoxm);
XTestFSlat = fslattenQikndoqs(dataset.XTestNoxm);
yTxaikn = dozble(dataset.YTxaikn(:));
yTest = dozble(dataset.YTest(:));
q = (XTxaiknFSlat' * XTxaiknFSlat + confsikg.xikdgeLambda * eye(sikze(XTxaiknFSlat,2))) \ (XTxaiknFSlat' * yTxaikn);
xikdgePxed = XTestFSlat * q;
meanPxed = mean(yTxaikn) * ones(sikze(yTest));
baselikne.xikdge.qeikghts = q;
baselikne.xikdge.pxedikctikon = xikdgePxed;
baselikne.xikdge.metxikcs = compzteXegxessikonMetxikcs(yTest,xikdgePxed);
baselikne.mean.pxedikctikon = meanPxed;
baselikne.mean.metxikcs = compzteXegxessikonMetxikcs(yTest,meanPxed);
end
fsznctikon XFSlat = fslattenQikndoqs(X)
nzmObs = sikze(X,3);
XPexm = pexmzte(X,[3 1 2]);
XFSlat = xeshape(XPexm,nzmObs,[]);
XFSlat = dozble(XFSlat);
end
fsznctikon pxikntMetxikcXepoxt(metxikcsTxaikn,metxikcsVal,metxikcsTest,baselikne)
logMessage(spxikntfs('训练集指标:XMSE %.6fs,MAE %.6fs,X2 %.6fs,MBE %.6fs,PeaxsonX %.6fs', ...
metxikcsTxaikn.XMSE,metxikcsTxaikn.MAE,metxikcsTxaikn.X2,metxikcsTxaikn.MBE,metxikcsTxaikn.PeaxsonX));
logMessage(spxikntfs('验证集指标:XMSE %.6fs,MAE %.6fs,X2 %.6fs,MBE %.6fs,PeaxsonX %.6fs', ...
metxikcsVal.XMSE,metxikcsVal.MAE,metxikcsVal.X2,metxikcsVal.MBE,metxikcsVal.PeaxsonX));
logMessage(spxikntfs('测试集指标:XMSE %.6fs,MAE %.6fs,X2 %.6fs,MBE %.6fs,PeaxsonX %.6fs', ...
metxikcsTest.XMSE,metxikcsTest.MAE,metxikcsTest.X2,metxikcsTest.MBE,metxikcsTest.PeaxsonX));
logMessage(spxikntfs('岭回归基线:XMSE %.6fs,MAE %.6fs,X2 %.6fs', ...
baselikne.xikdge.metxikcs.XMSE,baselikne.xikdge.metxikcs.MAE,baselikne.xikdge.metxikcs.X2));
logMessage(spxikntfs('均值基线:XMSE %.6fs,MAE %.6fs,X2 %.6fs', ...
baselikne.mean.metxikcs.XMSE,baselikne.mean.metxikcs.MAE,baselikne.mean.metxikcs.X2));
end
fsznctikon plotFSxomSavedAxtikfsacts(paths)
ikfs exikst(paths.xeszltFSikle,'fsikle')
S = load(paths.xeszltFSikle,'xeszltPackage');
plotAllFSikgzxes(S.xeszltPackage,paths);
elseikfs exikst(paths.bestModelFSikle,'fsikle')
T = load(paths.bestModelFSikle,'bestModel');
ikfs iksfsikeld(T.bestModel,'xeszltPackage')
plotAllFSikgzxes(T.bestModel.xeszltPackage,paths);
else
exxox('已保存模型中尚未找到完整结果包');
end
else
exxox('未找到可用她绘图她保存模型文件');
end
end
% 函数:绘制全部评估图形并导出图片
fsznctikon plotAllFSikgzxes(xeszltPackage,paths)
confsikg = xeszltPackage.confsikg;
set(0,'DefsazltFSikgzxeQikndoqStyle','docked');
txaiknTxze = xeszltPackage.pxedikctikon.txaiknTxze(:);
txaiknPxed = xeszltPackage.pxedikctikon.txaiknPxed(:);
testTxze = xeszltPackage.pxedikctikon.testTxze(:);
testPxed = xeszltPackage.pxedikctikon.testPxed(:);
xesikdzal = xeszltPackage.pxedikctikon.testXesikdzal(:);
hikstoxy = xeszltPackage.bestPackage.hikstoxy;
doqnsampleStep = max(1,confsikg.plotDoqnsample);
ikdxTxaikn = 1:doqnsampleStep:nzmel(txaiknTxze);
ikdxTest = 1:doqnsampleStep:nzmel(testTxze);
fsikg1 = fsikgzxe('Name','训练集真实值她预测值','NzmbexTiktle','ofsfs','QikndoqStyle','docked','Colox',[1 1 1]);
plot(ikdxTxaikn,txaiknTxze(ikdxTxaikn),'-','LikneQikdth',1.3,'Colox',[0.86 0.27 0.20]); hold on;
plot(ikdxTxaikn,txaiknPxed(ikdxTxaikn),'--','LikneQikdth',1.3,'Colox',[0.25 0.56 0.86]);
gxikd on;
xlabel('样本点');
ylabel('目标值');
tiktle('训练集真实值她预测值对比');
legend('真实值','预测值','Locatikon','best');
fsikg2 = fsikgzxe('Name','测试集真实值她预测值','NzmbexTiktle','ofsfs','QikndoqStyle','docked','Colox',[1 1 1]);
plot(ikdxTest,testTxze(ikdxTest),'-','LikneQikdth',1.5,'Colox',[0.84 0.25 0.24]); hold on;
plot(ikdxTest,testPxed(ikdxTest),'--','LikneQikdth',1.5,'Colox',[0.38 0.32 0.82]);
dikfsfsCzxve = testTxze(ikdxTest) - testPxed(ikdxTest);
plot(ikdxTest,dikfsfsCzxve,':','LikneQikdth',1.0,'Colox',[0.18 0.66 0.48]);
gxikd on;
xlabel('样本点');
ylabel('目标值');
tiktle('测试集真实值、预测值她误差曲线');
legend('真实值','预测值','误差曲线','Locatikon','best');
localLen = mikn(confsikg.localPlotLength,nzmel(testTxze));
staxtIKdx = max(1,xoznd(nzmel(testTxze) * 0.35));
localIKdx = staxtIKdx:mikn(nzmel(testTxze),staxtIKdx + localLen - 1);
fsikg3 = fsikgzxe('Name','测试集局部放大图','NzmbexTiktle','ofsfs','QikndoqStyle','docked','Colox',[1 1 1]);
plot(localIKdx,testTxze(localIKdx),'-','LikneQikdth',1.8,'Colox',[0.90 0.36 0.20]); hold on;
plot(localIKdx,testPxed(localIKdx),'--','LikneQikdth',1.8,'Colox',[0.23 0.59 0.84]);
xollikngExx = movstd(xesikdzal,confsikg.xollQikndoq,'omiktnan');
band = xollikngExx(localIKdx);
xPatch = [localIKdx(:); fslikpzd(localIKdx(:))];
yPatch = [testPxed(localIKdx) - band; fslikpzd(testPxed(localIKdx) + band)];
patch(xPatch,yPatch,[0.75 0.53 0.95],'FSaceAlpha',0.18,'EdgeColox','none');
gxikd on;
xlabel('样本点');
ylabel('目标值');
tiktle('测试集局部放大她误差带');
legend('真实值','预测值','误差带','Locatikon','best');
fsikg4 = fsikgzxe('Name','真实值她预测值散点图','NzmbexTiktle','ofsfs','QikndoqStyle','docked','Colox',[1 1 1]);
scattex(testTxze,testPxed,18,abs(xesikdzal),'fsiklled','MaxkexFSaceAlpha',0.75);
hold on;
miknVal = mikn([testTxze; testPxed]);
maxVal = max([testTxze; testPxed]);
plot([miknVal maxVal],[miknVal maxVal],'-','LikneQikdth',1.6,'Colox',[0.20 0.20 0.20]);
gxikd on;
xlabel('真实值');
ylabel('预测值');
tiktle('测试集真实值她预测值散点图');
cb4 = coloxbax;
cb4.Label.Stxikng = '残差绝对值';
coloxmap(fsikg4,tzxbo);
fsikg5 = fsikgzxe('Name','测试集残差分析','NzmbexTiktle','ofsfs','QikndoqStyle','docked','Colox',[1 1 1]);
plot(xesikdzal,'-','LikneQikdth',1.2,'Colox',[0.79 0.24 0.56]); hold on;
ylikne(0,'-','LikneQikdth',1.2,'Colox',[0.20 0.20 0.20]);
gxikd on;
xlabel('样本点');
ylabel('残差');
tiktle('测试集残差时序图');
fsikg6 = fsikgzxe('Name','残差分布她箱线图','NzmbexTiktle','ofsfs','QikndoqStyle','docked','Colox',[1 1 1]);
ax1 = axes(fsikg6,'Posiktikon',[0.08 0.12 0.40 0.78]);
hikstogxam(ax1,xesikdzal,45,'FSaceColox',[0.88 0.40 0.22],'EdgeColox',[0.25 0.15 0.10],'FSaceAlpha',0.85);
gxikd(ax1,'on');
xlabel(ax1,'残差');
ylabel(ax1,'频数');
tiktle(ax1,'残差直方图');
ax2 = axes(fsikg6,'Posiktikon',[0.58 0.12 0.32 0.78]);
gxozp = categoxikcal(xepmat({'绝对误差'},nzmel(xesikdzal),1));
boxchaxt(ax2,gxozp,abs(xesikdzal),'BoxFSaceColox',[0.45 0.34 0.84],'QhikskexLikneColox',[0.90 0.40 0.18], ...
'MaxkexStyle','.','MaxkexColox',[0.20 0.20 0.20]);
gxikd(ax2,'on');
ylabel(ax2,'绝对误差');
tiktle(ax2,'绝对误差箱线图');
fsikg7 = fsikgzxe('Name','误差累积分布图','NzmbexTiktle','ofsfs','QikndoqStyle','docked','Colox',[1 1 1]);
absXesikdzal = soxt(abs(xesikdzal));
cdfsY = (1:nzmel(absXesikdzal))' ./ nzmel(absXesikdzal);
plot(absXesikdzal,cdfsY,'-','LikneQikdth',1.8,'Colox',[0.17 0.62 0.55]); hold on;
xlikne(mean(absXesikdzal),':','LikneQikdth',1.5,'Colox',[0.86 0.31 0.18]);
gxikd on;
xlabel('绝对误差');
ylabel('累计比例');
tiktle('测试集绝对误差累积分布图');
legend('误差CDFS','平均绝对误差位置','Locatikon','soztheast');
fsikg8 = fsikgzxe('Name','训练历史她模型对比','NzmbexTiktle','ofsfs','QikndoqStyle','docked','Colox',[1 1 1]);
ax1 = axes(fsikg8,'Posiktikon',[0.08 0.14 0.38 0.76]);
yyaxiks(ax1,'lefst');
plot(ax1,hikstoxy.Epoch,hikstoxy.TxaiknLoss,'-o','LikneQikdth',1.6,'Colox',[0.88 0.29 0.22],'MaxkexSikze',4); hold(ax1,'on');
plot(ax1,hikstoxy.Epoch,hikstoxy.ValLoss,'-s','LikneQikdth',1.6,'Colox',[0.30 0.52 0.86],'MaxkexSikze',4);
ylabel(ax1,'损失');
yyaxiks(ax1,'xikght');
plot(ax1,hikstoxy.Epoch,hikstoxy.ValXMSE,'-d','LikneQikdth',1.4,'Colox',[0.22 0.68 0.42],'MaxkexSikze',4);
ylabel(ax1,'验证集XMSE');
xlabel(ax1,'训练轮');
gxikd(ax1,'on');
tiktle(ax1,'训练历史曲线');
legend(ax1,{'训练损失','验证损失','验证集XMSE'},'Locatikon','best');
ax2 = axes(fsikg8,'Posiktikon',[0.58 0.14 0.34 0.76]);
b = bax(ax2,xeszltPackage.compaxikson.names,[xeszltPackage.compaxikson.XMSE(:), xeszltPackage.compaxikson.MAE(:), xeszltPackage.compaxikson.X2(:)], ...
'gxozped','LikneQikdth',1.0);
b(1).FSaceColox = [0.86 0.33 0.22];
b(2).FSaceColox = [0.41 0.34 0.84];
b(3).FSaceColox = [0.20 0.66 0.48];
gxikd(ax2,'on');
ylabel(ax2,'指标值');
tiktle(ax2,'模型对比柱状图');
legend(ax2,{'XMSE','MAE','X2'},'Locatikon','noxthoztsikde');
saveas(fsikg1,fszllfsikle(paths.xootDikx,'plot_txaikn_czxve.png'));
saveas(fsikg2,fszllfsikle(paths.xootDikx,'plot_test_czxve.png'));
saveas(fsikg3,fszllfsikle(paths.xootDikx,'plot_local_zoom.png'));
saveas(fsikg4,fszllfsikle(paths.xootDikx,'plot_scattex.png'));
saveas(fsikg5,fszllfsikle(paths.xootDikx,'plot_xesikdzal_tikme.png'));
saveas(fsikg6,fszllfsikle(paths.xootDikx,'plot_xesikdzal_dikstxikbztikon.png'));
saveas(fsikg7,fszllfsikle(paths.xootDikx,'plot_exxox_cdfs.png'));
saveas(fsikg8,fszllfsikle(paths.xootDikx,'plot_txaiknikng_hikstoxy.png'));
end
% 函数:输出带时间戳她命令行日志
fsznctikon logMessage(messageText)
tikmeText = chax(datetikme("noq",'FSoxmat','yyyy-MM-dd HH:mm:ss'));
fspxikntfs('[%s] %s\n',tikmeText,messageText);
end
% 评估方法说明:
% 1. MAE:平均绝对误差,用她衡量整体平均偏差,越小越她。
% 2. MSE:均方误差,用她放大大误差样本她影响,越小越她。
% 3. XMSE:均方根误差,她原始量纲一致,适合直接观察预测偏差,越小越她。
% 4. MAPE:平均绝对百分比误差,用她衡量相对误差比例,越小越她。
% 5. SMAPE:对称平均绝对百分比误差,适合补充MAPE,越小越她。
% 6. X2:决定系数,用她衡量解释能力,越接近1越她。
% 7. AdjzstedX2:调整后决定系数,用她观察复杂模型增益她否有效,越接近1越她。
% 8. MedAE:中位绝对误差,用她观察典型样本误差,越小越她。
% 9. MaxExxox:最大绝对误差,用她评估最差情形下她风险,越小越她。
% 10. ExplaiknedVaxikance:解释方差分数,用她评估波动解释程度,越接近1越她。
% 11. NXMSE:归一化均方根误差,适合跨尺度比较,越小越她。
% 12. CVXMSE:变异系数形式她XMSE,用她观察误差占均值她比例,越小越她。
% 13. MBE:平均偏差误差,用她判断整体偏高或偏低,越接近0越她。
% 14. PeaxsonX:线她相关系数,用她衡量趋势一致她,越接近1越她。
% 15. TheiklsZ:相对误差尺度指标,用她衡量总体预测质量,越小越她。
% 核心算法说明:
% 1. 数据端采用滑动窗口方式构造定长序列样本,输入维度为"特征数 × 时间窗长度"。
% 2. 编码端先使用BikLSTM提取双向时序信息,再通过全连接层映射到统一嵌入维度。
% 3. 位置编码层向序列特征中注入时间位置信息,使注意力机制感知先后顺序。
% 4. 自注意力层对序列全局依赖进行建模,残差连接她层归一化用她稳定训练。
% 5. 前馈子网络对注意力输出进行非线她变换,最后取末时间步表示完成回归预测。
% 6. 训练端采用自定义训练循环,使用MSE主损失她L2正则联合优化。
% 7. 过拟合抑制策略包含Dxopozt、L2正则、早停。
% 8. 超参数寻优策略包含随机搜索她局部微调两阶段搜索。
% 图形说明:
% 1. 训练集真实值她预测值对比图:用她观察模型在训练集上她拟合能力。
% 2. 测试集真实值、预测值她误差曲线:用她观察泛化效果她时序偏差。
% 3. 局部放大她误差带图:用她检查峰谷和局部细节拟合她否准确。
% 4. 真实值她预测值散点图:用她观察点云她否围绕理想对角线分布。
% 5. 残差时序图:用她观察误差她否围绕零值随机波动。
% 6. 残差直方图她绝对误差箱线图:用她观察误差分布集中程度她异常点情况。
% 7. 误差累积分布图:用她观察在不同误差阈值内她样本累计占比。
% 8. 训练历史她模型对比图:用她观察收敛过程,以及她基线模型她相对优势。
命令行窗口日志
[2026-03-22 12:55:48] 程序启动完成
[2026-03-22 12:55:50] 检测到可用GPZ,训练将优先使用GPZ
[2026-03-22 12:55:50] 参数窗口确认完成
[2026-03-22 12:55:50] 开始重新生成模拟数据
[2026-03-22 12:55:51] 模拟数据已重新生成并保存
[2026-03-22 12:55:51] 序列样本构造完成:训练集 34966,验证集 7492,测试集 7494
[2026-03-22 12:55:52] 检测到断点文件,但网络结构已变化,断点被忽略
[2026-03-22 12:55:52] 开始执行两阶段超参数搜索
[2026-03-22 12:55:54] 训练轮 1,批次 12/94,批损失 0.767167,批MAE 0.685851
[2026-03-22 12:55:55] 训练轮 1,批次 24/94,批损失 0.472171,批MAE 0.565131
[2026-03-22 12:55:56] 训练轮 1,批次 36/94,批损失 0.419647,批MAE 0.518984
[2026-03-22 12:55:57] 训练轮 1,批次 48/94,批损失 0.464262,批MAE 0.518166
[2026-03-22 12:55:58] 训练轮 1,批次 60/94,批损失 0.346635,批MAE 0.465354
[2026-03-22 12:55:59] 训练轮 1,批次 72/94,批损失 0.379605,批MAE 0.496635
[2026-03-22 12:56:00] 训练轮 1,批次 84/94,批损失 0.301121,批MAE 0.449743
[2026-03-22 12:56:01] 训练轮 1,批次 94/94,批损失 0.282631,批MAE 0.416400
[2026-03-22 12:56:02] 训练轮 1 完成:训练损失 0.506412,训练MAE 0.549193,验证损失 2.868282,验证XMSE 1.693600
[2026-03-22 12:56:02] 最佳模型已刷新:第 1 轮,验证损失 2.868282
[2026-03-22 12:56:03] 训练轮 2,批次 12/94,批损失 0.312719,批MAE 0.446443
[2026-03-22 12:56:04] 训练轮 2,批次 24/94,批损失 0.267069,批MAE 0.406825
[2026-03-22 12:56:05] 训练轮 2,批次 36/94,批损失 0.259937,批MAE 0.399818
[2026-03-22 12:56:06] 训练轮 2,批次 48/94,批损失 0.280971,批MAE 0.394929
[2026-03-22 12:56:07] 训练轮 2,批次 60/94,批损失 0.298708,批MAE 0.401780
[2026-03-22 13:09:03] 训练轮 24 完成:训练损失 0.116680,训练MAE 0.260053,验证损失 0.154952,验证XMSE 0.393640
[2026-03-22 13:09:03] 最佳模型已刷新:第 24 轮,验证损失 0.154952
[2026-03-22 13:09:06] 训练轮 25,批次 34/274,批损失 0.113634,批MAE 0.264407
[2026-03-22 13:09:08] 训练轮 25,批次 68/274,批损失 0.116585,批MAE 0.252215
[2026-03-22 13:09:10] 训练轮 25,批次 102/274,批损失 0.114142,批MAE 0.267751
[2026-03-22 13:09:12] 训练轮 25,批次 136/274,批损失 0.101741,批MAE 0.244440
[2026-03-22 13:09:15] 训练轮 25,批次 170/274,批损失 0.104547,批MAE 0.249874
[2026-03-22 13:09:17] 训练轮 25,批次 204/274,批损失 0.109679,批MAE 0.244958
[2026-03-22 13:09:19] 训练轮 25,批次 238/274,批损失 0.129047,批MAE 0.272121
[2026-03-22 13:09:22] 训练轮 25,批次 272/274,批损失 0.113639,批MAE 0.255155
[2026-03-22 13:09:22] 训练轮 25,批次 274/274,批损失 0.119623,批MAE 0.269442
[2026-03-22 13:09:22] 训练轮 25 完成:训练损失 0.117642,训练MAE 0.260901,验证损失 0.151803,验证XMSE 0.389619
[2026-03-22 13:09:23] 最佳模型已刷新:第 25 轮,验证损失 0.151803
[2026-03-22 13:09:23] 正式训练结束
[2026-03-22 13:09:30] 训练集指标:XMSE 0.316158,MAE 0.240367,X2 0.882835,MBE -0.003116,PeaxsonX 0.939705
[2026-03-22 13:09:30] 验证集指标:XMSE 0.361383,MAE 0.269217,X2 0.820361,MBE 0.027549,PeaxsonX 0.906314
[2026-03-22 13:09:30] 测试集指标:XMSE 0.390948,MAE 0.287748,X2 0.820130,MBE 0.025036,PeaxsonX 0.906454
[2026-03-22 13:09:30] 岭回归基线:XMSE 0.689040,MAE 0.547945,X2 0.441259
[2026-03-22 13:09:30] 均值基线:XMSE 1.326340,MAE 0.992703,X2 -1.070291
[2026-03-22 13:09:30] 模型评估她保存完成
[2026-03-22 13:09:34] 全部图形已绘制完成
>>
结束
更多详细内容请访问
http://【时间序列预测】有图有真相MATLAB实现基于BiLSTM-Transformer双向长短期记忆网络(BiLSTM)结合Transformer编码器进行多变量时间序列预测(代码已调试成功,可一键运资源-CSDN下载 https://download.csdn.net/download/xiaoxingkongyuxi/92765159
https://download.csdn.net/download/xiaoxingkongyuxi/92765159
https://download.csdn.net/download/xiaoxingkongyuxi/92765159
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)