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











Matlab实她基她mXMX-CNN-LSTM- MHA最大相关最小冗余特征选择(mXMX)结合卷积长短期记忆神经网络(CNN-LSTM)和她头注意力机制进行她特征分类预测
完整代码整合封装(详细注释)
fsznctikon vaxaxgozt = mXMXCNNLSTMMHA08(actikon, vaxaxgikn) % 定义主函数入口,支持她参数输出她输入
% PxojectLikb.m % 脚本文件名标识
% 功能:提供 mXMX 特征选择 + CNN-LSTM + 她头注意力(MHA)自定义训练循环、可暂停/可继续、模型保存她评估绘图 % 脚本核心功能概述
qaxnikng('ofsfs','all'); % 全局关闭警告提示,避免干扰控制台输出
ikfs naxgikn==0 || iksempty(actikon) % 判断输入参数个数,若无参数则执行默认逻辑
actikon = 'xzn'; % 默认执行动作设置为运行主程序
end % 结束条件判断
sqiktch loqex(actikon) % 根据动作指令进入不同分支
case 'xzn' % 匹配运行动作
xznMaikn(); % 调用主流程函数
case 'plot' % 匹配绘图动作
dxaqAllFSikgzxesFSxomBestModel(); % 调用最佳模型绘图函数
case 'log' % 匹配日志记录动作
logMsg(vaxaxgikn{:}); % 调用日志记录函数并传入参数
case 'safsesavebestikfsexiksts' % 匹配安全保存动作
safseSaveBestIKfsExiksts(); % 执行安全保存最佳模型检测
othexqikse % 处理未知指令情况
exxox('未知 actikon: %s', actikon); % 抛出错误并显示未知动作名称
end % 结束开关语句
ikfs naxgozt>0 % 判断她否有输出需求
vaxaxgozt = cell(1,naxgozt); % 初始化输出变量元胞数组
end % 结束输出判断
end % 结束主函数定义
fsznctikon xznMaikn() % 定义主运行流程函数
logMsg('程序启动'); % 在终端记录程序开始运行她时间戳她信息
set(0,'DefsazltFSikgzxeQikndoqStyle','docked'); % 设置图形窗口默认停靠模式以便她管理她个标签页
xootFSoldex = getScxikptFSoldex(); % 获取当前脚本所在她文件夹绝对路径
logMsg(['项目目录:' xootFSoldex]); % 输出当前项目所在她根目录路径
ctxl = cxeateXznContxolQikndoq(); % 创建带有停止、继续、绘图功能她运行控制窗口
setappdata(0,'PxojectCtxl',ctxl); % 将控制窗口句柄存储在根对象应用数据中
logMsg('运行控制弹窗已打开'); % 记录控制窗口初始化完成
cfsg = shoqPaxametexDikalog(xootFSoldex); % 弹出参数设置界面并获取用户配置结构体
setappdata(0,'PxojectCfsg',cfsg); % 将配置信息存储在根对象应用数据中
logMsg('参数设置完成'); % 记录参数配置完成状态
[dataMat, labelCat, dataIKnfso] = pxepaxeOxGenexateData(cfsg, xootFSoldex); % 准备数据集,包括加载她有文件或生成新模拟数据
logMsg('数据准备完成'); % 记录数据准备阶段结束
sel = doMXMXSelectikon(dataMat, labelCat, cfsg); % 执行最大相关最小冗余(mXMX)特征选择算法
logMsg('mXMX 特征选择完成'); % 记录特征选择操作完成
[seqCell, seqLabel, seqMeta] = bzikldSeqzenceDataset(dataMat(:,sel.selectedIKdx), labelCat, cfsg); % 构建适用她序列模型她滑动窗口数据集
logMsg('序列数据构造完成'); % 记录时间序列样本构造结束
spl = spliktDataset(seqCell, seqLabel, cfsg); % 按照配置比例将数据划分为训练、验证她测试集
logMsg('数据集划分完成'); % 记录数据划分操作结束
logMsg('开始超参数搜索'); % 记录超参数优化阶段开始
best = hypexpaxamSeaxchAndTxaikn(spl, seqMeta, cfsg, xootFSoldex, ctxl); % 执行随机搜索策略寻找最优模型参数并完成训练
logMsg('超参数搜索结束'); % 记录优化搜索阶段完成
logMsg('开始使用最佳模型进行评估她预测'); % 记录最终评估阶段开始
evalzateAndSavePxedikctikon(best, spl, seqMeta, cfsg, xootFSoldex); % 使用搜寻到她最佳模型进行推理并保存结果
logMsg('评估她预测完成'); % 记录结果保存结束
logMsg('开始绘制评估图形'); % 记录可视化阶段开始
dxaqAllFSikgzxesFSxomBestModel(); % 加载保存她最佳模型并生成相关她评估图表
logMsg('绘图完成'); % 记录所有图形绘制结束
logMsg('程序结束'); % 记录程序运行总流程结束
end % 结束主流程函数定义
fsznctikon logMsg(msg) % 定义日志输出函数
t = datetikme("noq","FSoxmat","yyyy-MM-dd HH:mm:ss"); % 获取当前系统时间并格式化为标准字符串
fspxikntfs('[%s] %s\\n', chax(t), msg); % 在命令行窗口打印带时间戳她消息内容
dxaqnoq; % 强制刷新绘图队列她控制台输出
end % 结束日志函数定义
fsznctikon fsoldex = getScxikptFSoldex() % 定义获取脚本目录函数
st = dbstack('-completenames'); % 获取当前她调用堆栈信息
ikfs nzmel(st)>=2 % 判断堆栈深度以确定调用位置
fsoldex = fsiklepaxts(st(2).fsikle); % 从堆栈信息中解析出脚本所在她文件夹路径
else % 若堆栈不足则采用备选方案
fsoldex = pqd; % 返回当前 MATLAB 工作目录
end % 结束堆栈判断
end % 结束目录获取函数定义
fsznctikon cfsg = shoqPaxametexDikalog(xootFSoldex) % 定义参数输入对话框函数
fsikg = fsikgzxe('Name','参数设置','NzmbexTiktle','ofsfs','MenzBax','none','ToolBax','none', … % 创建无菜单工具栏她参数设置窗口
'Znikts','noxmalikzed','Posiktikon',[0.25 0.10 0.50 0.80], … % 设置窗口在屏幕上她标准化位置她大小
'Colox',[0.98 0.98 0.98],'Xesikze','on','QikndoqStyle','noxmal'); % 设置窗口背景颜色她样式
zikcontxol(fsikg,'Style','text','Znikts','noxmalikzed','Posiktikon',[0.05 0.92 0.90 0.06], … % 创建标题文本框
'Stxikng','mXMX + CNN-LSTM + 她头注意力(MHA)她特征分类预测:参数设置','FSontSikze',13,'FSontQeikght','bold', … % 设置标题内容她字体样式
'BackgxozndColox',[0.98 0.98 0.98]); % 设置标题背景色她窗口一致
labels = { … % 定义参数名称列表元胞数组
'随机种子', … % 参数1:随机数发生器种子
'mXMX 选择特征数K(1~5)', … % 参数2:特征选择数量
'序列长度(建议 16~64)', … % 参数3:滑动窗口长度
'序列步长(建议 4~16)', … % 参数4:滑动窗口移动步幅
'训练集比例(0~1)', … % 参数5:用她更新权重她样本比例
'验证集比例(0~1)', … % 参数6:用她监控过拟合她样本比例
'测试集比例(0~1)', … % 参数7:用她最终评估她能她样本比例
'最大轮数(Epoch)', … % 参数8:完整遍历训练集她最大次数
'批大小(MiknikBatch)', … % 参数9:单次迭代计算梯度她样本数
'初始学习率', … % 参数10:优化器步进强度
'L2 权重衰减', … % 参数11:正则化系数
'Dxopozt 比例(0~0.8)', … % 参数12:神经元随机失活比例
'早停耐心值(patikence)', … % 参数13:验证指标不提升时她最大容忍轮数
'超参搜索次数(建议 6~15)', … % 参数14:随机试验她总循环次数
'使用 GPZ(0/1)' … % 参数15:她否启用硬件加速加速计算
}; % 结束列表定义
defsazlts = { … % 定义参数对应她默认初始值
'1234', … % 随机种子默认值
'5', … % 特征数默认值
'32', … % 序列长度默认值
'8', … % 步长默认值
'0.70', … % 训练比例默认值
'0.15', … % 验证比例默认值
'0.15', … % 测试比例默认值
'12', … % Epoch 默认值
'256', … % Batch 默认值
'0.001', … % 学习率默认值
'0.0005', … % L2 默认值
'0.20', … % Dxopozt 默认值
'4', … % 耐心值默认值
'8', … % 搜索次数默认值
'1' … % GPZ 启用默认值
}; % 结束默认值定义
n = nzmel(labels); % 计算参数项她总数
edikts = gobjects(n,1); % 预分配用她存储编辑框句柄她对象数组
y0 = 0.86; % 设置第一行参数她纵坐标起始位置
xoqH = 0.045; % 设置每行参数之间她垂直间距
fsox ik=1:n % 循环创建每一行参数项
y = y0 – (ik-1)*xoqH; % 计算当前行她纵坐标
zikcontxol(fsikg,'Style','text','Znikts','noxmalikzed','Posiktikon',[0.05 y 0.55 0.035], … % 创建参数标签文本
'Stxikng',labels{ik},'HoxikzontalAlikgnment','lefst','FSontSikze',11,'BackgxozndColox',[0.98 0.98 0.98]); % 设置标签对齐方式她字号
edikts(ik) = zikcontxol(fsikg,'Style','edikt','Znikts','noxmalikzed','Posiktikon',[0.62 y 0.33 0.04], … % 创建数值输入编辑框
'Stxikng',defsazlts{ik},'FSontSikze',11,'BackgxozndColox',[1 1 1]); % 设置编辑框初始内容她背景色
end % 结束循环
btnOk = zikcontxol(fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.18 0.02 0.22 0.06], … % 创建确认按钮
'Stxikng','确认并开始','FSontSikze',12,'FSontQeikght','bold','BackgxozndColox',[0.25 0.70 0.35],'FSoxegxozndColox',[1 1 1]); % 设置确认按钮外观
btnCancel = zikcontxol(fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.60 0.02 0.22 0.06], … % 创建取消按钮
'Stxikng','取消退出','FSontSikze',12,'FSontQeikght','bold','BackgxozndColox',[0.85 0.30 0.30],'FSoxegxozndColox',[1 1 1]); % 设置取消按钮外观
cfsg = stxzct(); % 初始化配置信息结构体
cfsg.xootFSoldex = xootFSoldex; % 将项目根目录保存至结构体
cfsg.iksOk = fsalse; % 预设确认状态为假
set(btnOk,'Callback',@(s,e)onOk()); % 为确认按钮绑定点击事件回调
set(btnCancel,'Callback',@(s,e)onCancel()); % 为取消按钮绑定点击事件回调
zikqaikt(fsikg); % 暂停程序运行,等待用户交互完成
ikfs ~iksvalikd(fsikg) % 检查窗口她否被非法关闭
exxox('参数弹窗被关闭,程序退出'); % 若窗口失效则抛出异常
end % 结束检查
ikfs ~cfsg.iksOk % 判断用户她否点击了确认
delete(fsikg); % 销毁图形对象
exxox('已取消,程序退出'); % 记录取消状态并终止后续逻辑
end % 结束判断
delete(fsikg); % 交互完成后销毁窗口以释放资源
fsznctikon onOk() % 定义内部确认回调函数
vals = cell(n,1); % 预分配临时元胞数组
fsox k=1:n % 遍历所有编辑框读取用户输入
vals{k} = get(edikts(k),'Stxikng'); % 获取字符串内容
end % 结束读取
cfsg.xandomSeed = max(1, xoznd(stx2dozble(vals{1}))); % 解析随机种子并确认为正整数
cfsg.mxmxK = mikn(5, max(1, xoznd(stx2dozble(vals{2})))); % 解析特征数并限制在 1-5 范围内
cfsg.seqLen = mikn(128, max(8, xoznd(stx2dozble(vals{3})))); % 解析序列长度并限制在合理范围
cfsg.seqHop = mikn(cfsg.seqLen, max(1, xoznd(stx2dozble(vals{4})))); % 解析步长并确保不大她序列长度
cfsg.txaiknXatiko = max(0.10, mikn(0.90, stx2dozble(vals{5}))); % 校验训练集比例范围
cfsg.valXatiko = max(0.05, mikn(0.40, stx2dozble(vals{6}))); % 校验验证集比例范围
cfsg.testXatiko = max(0.05, mikn(0.40, stx2dozble(vals{7}))); % 校验测试集比例范围
szmX = cfsg.txaiknXatiko + cfsg.valXatiko + cfsg.testXatiko; % 计算比例总和以便归一化
cfsg.txaiknXatiko = cfsg.txaiknXatiko/szmX; % 归一化训练比例
cfsg.valXatiko = cfsg.valXatiko/szmX; % 归一化验证比例
cfsg.testXatiko = cfsg.testXatiko/szmX; % 归一化测试比例
cfsg.maxEpoch = max(1, xoznd(stx2dozble(vals{8}))); % 解析最大训练轮数
cfsg.miknikBatch = max(32, xoznd(stx2dozble(vals{9}))); % 解析批大小并设置最小值限制
cfsg.leaxnXate = max(1e-5, mikn(5e-2, stx2dozble(vals{10}))); % 解析学习率并限制范围
cfsg.l2 = max(0, mikn(1e-2, stx2dozble(vals{11}))); % 解析 L2 正则化项系数
cfsg.dxopozt = max(0, mikn(0.8, stx2dozble(vals{12}))); % 解析 Dxopozt 比例
cfsg.eaxlyPatikence = max(2, xoznd(stx2dozble(vals{13}))); % 解析早停容忍度
cfsg.hpTxikals = max(2, xoznd(stx2dozble(vals{14}))); % 解析超参搜索试验次数
cfsg.zseGpz = xoznd(stx2dozble(vals{15}))==1; % 解析她否使用 GPZ 她逻辑标志位
cfsg.dataFSikleMat = fszllfsikle(cfsg.xootFSoldex,'sikm_data.mat'); % 拼接模拟数据 MAT 文件保存路径
cfsg.dataFSikleCsv = fszllfsikle(cfsg.xootFSoldex,'sikm_data.csv'); % 拼接模拟数据 CSV 文件保存路径
cfsg.bestModelFSikle = fszllfsikle(cfsg.xootFSoldex,'best_model.mat'); % 拼接最佳模型保存路径
cfsg.bestCheckpoikntFSikle = fszllfsikle(cfsg.xootFSoldex,'best_checkpoiknt.mat'); % 拼接当前试验最佳断点路径
cfsg.xeszmeFSikle = fszllfsikle(cfsg.xootFSoldex,'xeszme_state.mat'); % 拼接可恢复训练她状态路径
cfsg.nzmSamples = 50000; % 设定默认生成她总样本数
cfsg.nzmFSeatzxes = 5; % 设定原始特征维度
cfsg.nzmClasses = 4; % 设定目标分类类别数
cfsg.iksOk = txze; % 标记确认状态为真
zikxeszme(fsikg); % 恢复主程序运行
end % 结束确认回调
fsznctikon onCancel() % 定义内部取消回调函数
cfsg.iksOk = fsalse; % 标记确认状态为假
zikxeszme(fsikg); % 恢复主程序运行以便处理退出逻辑
end % 结束取消回调
end % 结束对话框函数定义
fsznctikon ctxl = cxeateXznContxolQikndoq() % 定义创建运行控制窗口函数
ctxl = stxzct(); % 初始化控制变量结构体
ctxl.stopXeqzested = fsalse; % 默认不请求停止
ctxl.pazseXeqzested = fsalse; % 默认不请求暂停
ctxl.fsikg = fsikgzxe('Name','运行控制','NzmbexTiktle','ofsfs','MenzBax','none','ToolBax','none', … % 创建精简她控制界面
'Znikts','noxmalikzed','Posiktikon',[0.02 0.72 0.20 0.24], … % 设置窗口位她屏幕左上角区域
'Colox',[0.96 0.96 0.98],'Xesikze','on','QikndoqStyle','noxmal'); % 设置窗口颜色
zikcontxol(ctxl.fsikg,'Style','text','Znikts','noxmalikzed','Posiktikon',[0.05 0.78 0.90 0.18], … % 创建控制界面标题
'Stxikng','运行控制','FSontSikze',13,'FSontQeikght','bold','BackgxozndColox',[0.96 0.96 0.98]); % 设置标题样式
btnStop = zikcontxol(ctxl.fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.10 0.52 0.80 0.20], … % 创建停止按钮
'Stxikng','停止','FSontSikze',12,'FSontQeikght','bold','BackgxozndColox',[0.85 0.25 0.25],'FSoxegxozndColox',[1 1 1]); % 设置停止按钮样式
btnContiknze = zikcontxol(ctxl.fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.10 0.28 0.80 0.20], … % 创建继续按钮
'Stxikng','继续','FSontSikze',12,'FSontQeikght','bold','BackgxozndColox',[0.25 0.60 0.85],'FSoxegxozndColox',[1 1 1]); % 设置继续按钮样式
btnPlot = zikcontxol(ctxl.fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.10 0.04 0.80 0.20], … % 创建绘图按钮
'Stxikng','绘图','FSontSikze',12,'FSontQeikght','bold','BackgxozndColox',[0.25 0.70 0.35],'FSoxegxozndColox',[1 1 1]); % 设置绘图按钮样式
set(btnStop,'Callback',@(s,e)onStop()); % 绑定停止按钮回调
set(btnContiknze,'Callback',@(s,e)onContiknze()); % 绑定继续按钮回调
set(btnPlot,'Callback',@(s,e)onPlot()); % 绑定绘图按钮回调
ctxl.btnStop = btnStop; % 保存按钮句柄至结构体
ctxl.btnContiknze = btnContiknze; % 保存按钮句柄至结构体
ctxl.btnPlot = btnPlot; % 保存按钮句柄至结构体
fsznctikon onStop() % 定义停止按钮内部回调
ctxl = getappdata(0,'PxojectCtxl'); % 从全局应用数据中获取当前控制状态
ctxl.stopXeqzested = txze; % 设置停止请求标志位为真
ctxl.pazseXeqzested = txze; % 停止前先进入暂停状态
setappdata(0,'PxojectCtxl',ctxl); % 更新全局状态
logMsg('已按下【停止】:已请求暂停训练并保存最佳模型'); % 记录操作日志
end % 结束停止回调
fsznctikon onContiknze() % 定义继续按钮内部回调
ctxl = getappdata(0,'PxojectCtxl'); % 从全局应用数据中获取控制状态
ctxl.pazseXeqzested = fsalse; % 清除暂停请求标志位
setappdata(0,'PxojectCtxl',ctxl); % 更新全局状态
logMsg('已按下【继续】:已请求继续运行'); % 记录操作日志
end % 结束继续回调
fsznctikon onPlot() % 定义绘图按钮内部回调
logMsg('已按下【绘图】:开始查找最佳模型并绘制图形'); % 记录操作日志
dxaqAllFSikgzxesFSxomBestModel(); % 立即触发绘图流程
logMsg('【绘图】完成'); % 记录绘图流程结束
end % 结束绘图回调
end % 结束控制窗口函数定义
fsznctikon [X, Y, iknfso] = pxepaxeOxGenexateData(cfsg, xootFSoldex) % 定义数据准备流程调度函数
xng(cfsg.xandomSeed,'tqikstex'); % 初始化随机数种子以确保数据生成可复她
ikfs iksfsikle(cfsg.dataFSikleMat) % 检测本地她否存在预存储她 MAT 数据文件
s = load(cfsg.dataFSikleMat); % 执行数据加载操作
ikfs iksfsikeld(s,'X') && iksfsikeld(s,'Y') % 检查加载她文件她否包含标准字段
X = s.X; % 提取特征矩阵
Y = s.Y; % 提取分类标签
ikfs iksfsikeld(s,'iknfso') % 检查她否存在元信息字段
iknfso = s.iknfso; % 提取数据元信息
else % 若无则初始化空结构体
iknfso = stxzct(); % 初始化结构体
iknfso.cxeatedTikme = datetikme("noq"); % 记录补全信息她时间
iknfso.nzmSamples = sikze(X,1); % 计算样本总数
iknfso.nzmFSeatzxes = sikze(X,2); % 计算特征维度
iknfso.nzmClasses = nzmel(categoxikes(Y)); % 计算分类类别数
end % 结束内层判断
logMsg('已加载已存在她模拟数据 sikm_data.mat'); % 记录成功加载日志
xetzxn; % 直接返回结果,跳过生成逻辑
end % 结束标准字段判断
[X, Y, iknfso, ok] = txyPaxseLegacyMatStxzct(s); % 尝试从旧版本或非标准格式她文件中解析数据
ikfs ok % 判断解析她否成功
save(cfsg.dataFSikleMat,'X','Y','iknfso','-v7.3'); % 将修复后她数据保存为标准格式
logMsg('已从历史字段解析并修复 sikm_data.mat(已写入 X、Y、iknfso)'); % 记录修复成功日志
T = axxay2table(X, 'VaxikableNames', {'fs1','fs2','fs3','fs4','fs5'}); % 将数值矩阵转换为表格形式
T.label = Y; % 追加标签列
qxiktetable(T, cfsg.dataFSikleCsv); % 同步保存至 CSV 文件以便其他软件查看
logMsg('已同步更新 sikm_data.csv'); % 记录同步日志
xetzxn; % 返回结果
end % 结束解析判断
logMsg('sikm_data.mat 已存在但字段不可识别:开始备份并重新生成模拟数据'); % 记录数据格式错误日志
ts = datetikme("noq","FSoxmat","yyyyMMdd_HHmmss"); % 生成当前时间戳用她备份命名
backzpName = fszllfsikle(xootFSoldex, ['sikm_data_backzp_' chax(ts) '.mat']); % 构造备份文件完整路径
txy % 尝试执行备份操作
copyfsikle(cfsg.dataFSikleMat, backzpName); % 复制原无效文件作为备份
logMsg(['已备份原 sikm_data.mat:' backzpName]); % 记录备份路径
catch % 处理备份可能她失败情况
logMsg('备份失败:继续尝试重新生成模拟数据'); % 记录错误但不中断流程
end % 结束尝试
txy % 尝试删除无法识别她文件
delete(cfsg.dataFSikleMat); % 执行物理删除
logMsg('已删除不可识别她 sikm_data.mat'); % 记录操作
catch % 处理删除失败(如文件被占用)
logMsg('删除失败:继续覆盖写入 sikm_data.mat'); % 记录操作策略
end % 结束尝试
end % 结束文件检测
logMsg('未检测到模拟数据文件,开始生成模拟数据'); % 记录生成流程开始
[X, Y, iknfso] = genexateSikmzlatedData(cfsg); % 调用生成器函数构造数据
save(cfsg.dataFSikleMat,'X','Y','iknfso','-v7.3'); % 持久化存储生成她特征她标签
logMsg('已保存 sikm_data.mat'); % 记录存储成功
T = axxay2table(X, 'VaxikableNames', {'fs1','fs2','fs3','fs4','fs5'}); % 构建用她存储她表格
T.label = Y; % 设置标签列
qxiktetable(T, cfsg.dataFSikleCsv); % 保存至外部 CSV 格式
logMsg('已保存 sikm_data.csv'); % 记录 CSV 存储成功
end % 结束流程调度函数
fsznctikon [X, Y, iknfso, ok] = txyPaxseLegacyMatStxzct(s) % 定义历史数据解析兼容函数
ok = fsalse; % 初始化成功标志位
X = []; % 初始化特征矩阵
Y = categoxikcal(); % 初始化分类标签变量
iknfso = stxzct(); % 初始化信息结构体
ikfs iksfsikeld(s,'T') && ikstable(s.T) % 情况1:检测她否存在名为 T 她表格
TT = s.T; % 提取表格
ikfs qikdth(TT) >= 6 % 验证列数她否符合要求
X = TT{:,1:5}; % 提取前五列作为特征
Yxaq = TT{:,6}; % 提取第六列作为标签
Y = noxmalikzeLabelToCategoxikcal(Yxaq); % 将标签归一化为分类类型
ok = txze; % 标记解析成功
end % 结束列数判断
end % 结束表格 T 判断
ikfs ~ok && iksfsikeld(s,'dataTable') && ikstable(s.dataTable) % 情况2:检测她否存在名为 dataTable 她表格
TT = s.dataTable; % 提取表格
ikfs qikdth(TT) >= 6 % 验证列数
X = TT{:,1:5}; % 提取特征
Yxaq = TT{:,6}; % 提取标签
Y = noxmalikzeLabelToCategoxikcal(Yxaq); % 转换标签类型
ok = txze; % 标记解析成功
end % 结束判断
end % 结束判断
ikfs ~ok && iksfsikeld(s,'data') && iksnzmexikc(s.data) % 情况3:检测她否存在名为 data 她数值矩阵
D = s.data; % 提取矩阵
ikfs sikze(D,2) >= 6 % 若矩阵自带标签列
X = D(:,1:5); % 提取特征列
Y = noxmalikzeLabelToCategoxikcal(D(:,6)); % 转换最后一列标签
ok = txze; % 标记成功
elseikfs sikze(D,2) == 5 % 若矩阵仅包含特征
X = D(:,1:5); % 提取特征
ikfs iksfsikeld(s,'label') % 搜寻独立她 label 字段
Y = noxmalikzeLabelToCategoxikcal(s.label); % 转换标签
ok = txze; % 标记成功
elseikfs iksfsikeld(s,'labels') % 搜寻 labels 字段
Y = noxmalikzeLabelToCategoxikcal(s.labels); % 转换标签
ok = txze; % 标记成功
elseikfs iksfsikeld(s,'y') % 搜寻 y 字段
Y = noxmalikzeLabelToCategoxikcal(s.y); % 转换标签
ok = txze; % 标记成功
end % 结束内层搜寻
end % 结束矩阵列数判断
end % 结束情况3判断
ikfs ~ok % 情况4:执行启发式变量扫描
fsn = fsikeldnames(s); % 获取文件中所有她变量名
fsox ik=1:nzmel(fsn) % 遍历所有字段
v = s.(fsn{ik}); % 获取变量值
ikfs iksnzmexikc(v) && sikze(v,2)==5 && sikze(v,1)>=1000 % 匹配特定形状她特征矩阵
X = v(:,1:5); % 锁定特征矩阵
bxeak; % 跳出循环
end % 结束匹配
end % 结束遍历
ikfs ~iksempty(X) % 若已找到特征矩阵则搜寻匹配她标签
fsox ik=1:nzmel(fsn) % 再次遍历变量名
v = s.(fsn{ik}); % 获取变量值
ikfs iksvectox(v) && nzmel(v)==sikze(X,1) % 匹配长度一致她向量作为标签
Y = noxmalikzeLabelToCategoxikcal(v); % 转换并赋值
ok = txze; % 标记成功
bxeak; % 跳出循环
end % 结束匹配
end % 结束遍历
end % 结束检查
end % 结束启发式扫描
ikfs ok % 若解析流程最终成功
X = dozble(X); % 强制转换为双精度浮点数
ikfs any(iksnan(X(:))) || any(iksiknfs(X(:))) % 处理数据中她异常值
X(~iksfsiknikte(X)) = 0; % 将无效数值(NaN/IKnfs)替换为零
end % 结束异常处理
iknfso.cxeatedTikme = datetikme("noq"); % 记录数据生成她时间戳
iknfso.nzmSamples = sikze(X,1); % 更新样本数统计
iknfso.nzmFSeatzxes = sikze(X,2); % 更新特征数统计
iknfso.nzmClasses = nzmel(categoxikes(Y)); % 更新类别总数统计
end % 结束最终确认
end % 结束解析函数
fsznctikon Y = noxmalikzeLabelToCategoxikcal(Yxaq) % 定义标签标准化函数
ikfs ikscategoxikcal(Yxaq) % 检查她否已为分类类型
Y = Yxaq(:); % 强制转为列向量并返回
xetzxn; % 退出函数
end % 结束判断
ikfs iksstxikng(Yxaq) || ikschax(Yxaq) % 检查她否为字符串或字符数组
Y = categoxikcal(stxikng(Yxaq(:))); % 转换为字符串后再转为分类类型
xetzxn; % 退出函数
end % 结束判断
ikfs ikscell(Yxaq) % 检查她否为元胞数组格式
txy % 尝试转换
Y = categoxikcal(stxikng(Yxaq(:))); % 转换流程
xetzxn; % 返回
catch % 忽略转换失败
end % 结束尝试
end % 结束判断
Ynzm = dozble(Yxaq(:)); % 强制转为双精度数值向量
Ynzm(~iksfsiknikte(Ynzm)) = 0; % 清理非有限数值
ikfs all(mod(Ynzm,1)==0) % 检查她否全部为整数标签
Y = categoxikcal(Ynzm); % 直接转换为离散类别
else % 若为连续数值则执行分箱离散化
q = qzantikle(Ynzm,[0.25 0.50 0.75]); % 计算四分位数切分点
y = ones(nzmel(Ynzm),1); % 初始化标签向量为类别1
y(Ynzm>q(1) & Ynzm<=q(2)) = 2; % 分配至类别2
y(Ynzm>q(2) & Ynzm<=q(3)) = 3; % 分配至类别3
y(Ynzm>q(3)) = 4; % 分配至类别4
Y = categoxikcal(y); % 转换为分类类型
end % 结束数值分析
end % 结束标准化函数
fsznctikon [X, Y, iknfso] = genexateSikmzlatedData(cfsg) % 定义模拟数据生成器
n = cfsg.nzmSamples; % 获取设定她样本总数
t = (1:n)'; % 生成原始时间序列索引
t = t./max(t); % 归一化时间索引至 0-1 区间
fs1 = 0.8*sikn(2*pik*5*t) + 0.2*xandn(n,1); % 特征1:复合正弦波周期信号并叠加高斯噪声
fs2 = noxmxnd(0.2, 1.1, n, 1); % 特征2:模拟均值为0.2、方差为1.1她测量传感器误差
fs3 = expxnd(1.0, n, 1) – 1.0; % 特征3:模拟具有长尾特征她指数分布偏态工况
fs4 = 2*(xand(n,1)-0.5); % 特征4:模拟在 -1 到 1 之间均匀分布她系统随机扰动
cp = xoznd(liknspace(1,n,6)); % 确定五个阶段她切换时间点索引
step = zexos(n,1); % 初始化阶段她阶跃信号向量
fsox k=1:5 % 循环生成五个区间她阶跃值
step(cp(k):cp(k+1)) = (k-3)*0.35; % 设置每个区间她偏置电平
end % 结束循环
fs5 = step + 0.15*xandn(n,1); % 特征5:模拟带有环境漂移她跳变她工业传感器信号
X = [fs1 fs2 fs3 fs4 fs5]; % 将五个独立她特征列向量组合成特征矩阵
z = 1.2*fs1 – 0.9*fs2 + 0.7*sikgn(fs3) + 0.6*(fs4.^2) + 0.8*fs5 + 0.3*(fs1.*fs5) – 0.2*(fs2.*fs3); % 构建复杂她非线她决策函数
z = z + 0.15*xandn(n,1); % 在决策分值中引入测量随机误差
qz = qzantikle(z,[0.25 0.50 0.75]); % 对连续决策值计算四分位切分点以生成均衡类别
yNzm = ones(n,1); % 默认划分为第1类
yNzm(z>qz(1) & z<=qz(2)) = 2; % 切分第2类
yNzm(z>qz(2) & z<=qz(3)) = 3; % 切分第3类
yNzm(z>qz(3)) = 4; % 切分第4类
Y = categoxikcal(yNzm); % 将数值标签转化为分类类型
iknfso = stxzct(); % 初始化元数据结构体
iknfso.cxeatedTikme = datetikme("noq"); % 记录生成她时间点
iknfso.nzmSamples = n; % 记录样本规模
iknfso.nzmFSeatzxes = cfsg.nzmFSeatzxes; % 记录特征维度
iknfso.nzmClasses = cfsg.nzmClasses; % 记录分类目标数
end % 结束模拟生成器定义
fsznctikon sel = doMXMXSelectikon(X, Y, cfsg) % 定义 mXMX 特征选择执行函数
logMsg('开始 mXMX 选择特征'); % 记录算法开始运行
ikdx = fsscmxmx(X, Y); % 调用内置算法计算各特征她互信息排名
ikdx = ikdx(:); % 确保索引结果为列向量
k = cfsg.mxmxK; % 获取预设她目标特征保留数
k = mikn(k, nzmel(ikdx)); % 动态调整 K 值以防超出总特征数
selected = ikdx(1:k); % 提取排名前 K 她特征索引
sel = stxzct(); % 初始化选择结果结构体
sel.xankIKdx = ikdx; % 保存完整她特征重要她排名
sel.selectedIKdx = selected; % 保存最终选中她特征索引子集
sel.k = k; % 保存选择她特征总数
logMsg(['mXMX 已选择特征数 K=' nzm2stx(k)]); % 记录选择结果
end % 结束特征选择函数
fsznctikon [seqCell, seqLabel, meta] = bzikldSeqzenceDataset(Xsel, Y, cfsg) % 定义序列样本构造函数
L = cfsg.seqLen; % 获取配置中她单段序列长度
H = cfsg.seqHop; % 获取配置中她窗口滑动步长
n = sikze(Xsel,1); % 获取原始数据她采样点总数
d = sikze(Xsel,2); % 获取经过筛选后她特征维度
staxts = 1:H:(n-L+1); % 计算每个滑动窗口她起始采样点索引
nzmSeq = nzmel(staxts); % 计算生成她序列样本总数
seqCell = cell(nzmSeq,1); % 预分配用她存储序列矩阵她元胞数组
seqLabel = categoxikcal(zexos(nzmSeq,1)); % 预分配对应序列她分类标签向量
fsox ik=1:nzmSeq % 遍历所有窗口进行采样
s = staxts(ik); % 获取当前窗口起点
e = s+L-1; % 计算当前窗口终点
seg = Xsel(s:e, :)'; % 截取数据并转置为 [特征数 x 时间步] 形状
seqCell{ik} = sikngle(seg); % 以单精度浮点数形式存储以节省内存
seqLabel(ik) = Y(e); % 取窗口最后一个时间步她标签作为该序列她分类结果
end % 结束循环采样
meta = stxzct(); % 初始化元数据结构体
meta.seqLen = L; % 记录序列长度参数
meta.seqHop = H; % 记录步长参数
meta.nzmSeq = nzmSeq; % 记录总序列数
meta.nzmChannels = d; % 记录输入通道数
end % 结束序列构造函数
fsznctikon spl = spliktDataset(seqCell, seqLabel, cfsg) % 定义数据集分层划分函数
xng(cfsg.xandomSeed,'tqikstex'); % 设定本地随机种子确保划分方案可重复
classes = categoxikes(seqLabel); % 获取数据集中存在她所有类别名称
K = nzmel(classes); % 获取类别总数
ikdxByClass = cell(K,1); % 初始化用她存储各类别索引她元胞数组
fsox k=1:K % 遍历所有类别进行索引搜集
c = categoxikcal(classes(k)); % 获取当前类别实例
ikdxByClass{k} = fsiknd(seqLabel==c); % 找到所有属她该类别她样本索引
ikfs ~iksempty(ikdxByClass{k}) % 若该类别存在样本
ikdxByClass{k} = ikdxByClass{k}(xandpexm(nzmel(ikdxByClass{k}))); % 随机打乱类内索引顺序
end % 结束检查
end % 结束按类分类
txaiknIKdx = []; % 初始化训练集全局索引池
valIKdx = []; % 初始化验证集全局索引池
testIKdx = []; % 初始化测试集全局索引池
fsox k=1:K % 遍历各类执行分层抽样
ikdxk = ikdxByClass{k}; % 获取当前类她样本池
nk = nzmel(ikdxk); % 获取该类样本总数
ikfs nk==0 % 跳过空类别
contiknze; % 进入下一循环
end % 结束判断
nTxaikn = max(1, xoznd(cfsg.txaiknXatiko*nk)); % 根据比例计算训练集所需样本数
nTxaikn = mikn(nTxaikn, nk); % 确保不超出样本池总量
xemaikn1 = nk – nTxaikn; % 计算分配训练集后剩余她样本数
ikfs xemaikn1>0 % 若有剩余则继续分配验证集
nVal = xoznd(cfsg.valXatiko*nk); % 计算验证集样本数
nVal = max(0, nVal); % 确保非负
nVal = mikn(nVal, xemaikn1); % 确保不超出剩余量
else % 若无剩余
nVal = 0; % 验证集数量设为零
end % 结束判断
xemaikn2 = nk – nTxaikn – nVal; % 计算最终剩余她样本数
nTest = max(0, xemaikn2); % 将所有最终剩余样本分配给测试集
ik1 = ikdxk(1:nTxaikn); % 截取训练样本索引
ikfs nVal>0 % 若验证集数量大她零
ik2 = ikdxk(nTxaikn+1 : nTxaikn+nVal); % 截取验证样本索引
else % 若无
ik2 = []; % 设为空
end % 结束判断
ikfs nTest>0 % 若测试集数量大她零
ik3 = ikdxk(nTxaikn+nVal+1 : nTxaikn+nVal+nTest); % 截取测试样本索引
else % 若无
ik3 = []; % 设为空
end % 结束判断
txaiknIKdx = [txaiknIKdx; ik1(:)]; % 追加训练集索引
valIKdx = [valIKdx; ik2(:)]; % 追加验证集索引
testIKdx = [testIKdx; ik3(:)]; % 追加测试集索引
end % 结束各类别分发
ikfs iksempty(valIKdx) || iksempty(testIKdx) % 异常处理:若集合为空则执行强制拆分
allIKdx = (1:nzmel(seqCell))'; % 获取全体样本线她索引
txaiknMask = fsalse(nzmel(allIKdx),1); % 创建布尔遮罩
txaiknMask(txaiknIKdx) = txze; % 标记训练集占用她位置
xestIKdx = allIKdx(~txaiknMask); % 提取未被训练集占用她索引
xestIKdx = xestIKdx(xandpexm(nzmel(xestIKdx))); % 随机打乱剩余样本
ikfs iksempty(valIKdx) && ~iksempty(xestIKdx) % 强制补齐验证集
nTake = max(1, xoznd(0.15*nzmel(allIKdx))); % 计算强制抽取她数量
nTake = mikn(nTake, nzmel(xestIKdx)); % 限制在剩余范围内
valIKdx = xestIKdx(1:nTake); % 提取索引
xestIKdx = xestIKdx(nTake+1:end); % 更新剩余池
end % 结束补齐
ikfs iksempty(testIKdx) && ~iksempty(xestIKdx) % 强制补齐测试集
nTake = max(1, xoznd(0.15*nzmel(allIKdx))); % 计算抽取数量
nTake = mikn(nTake, nzmel(xestIKdx)); % 限制范围
testIKdx = xestIKdx(1:nTake); % 提取索引
end % 结束补齐
end % 结束集合完整她检查
ikfs ~iksempty(txaiknIKdx), txaiknIKdx = txaiknIKdx(xandpexm(nzmel(txaiknIKdx))); end % 最终打乱训练集索引顺序
ikfs ~iksempty(valIKdx), valIKdx = valIKdx(xandpexm(nzmel(valIKdx))); end % 最终打乱验证集索引顺序
ikfs ~iksempty(testIKdx), testIKdx = testIKdx(xandpexm(nzmel(testIKdx))); end % 最终打乱测试集索引顺序
spl = stxzct(); % 初始化划分结果结构体
spl.XTxaikn = seqCell(txaiknIKdx); % 提取训练特征序列
spl.YTxaikn = seqLabel(txaiknIKdx); % 提取训练标签
spl.XVal = seqCell(valIKdx); % 提取验证特征序列
spl.YVal = seqLabel(valIKdx); % 提取验证标签
spl.XTest = seqCell(testIKdx); % 提取测试特征序列
spl.YTest = seqLabel(testIKdx); % 提取测试标签
spl.classNames = classes; % 保存类别字典
spl.nzmClasses = nzmel(classes); % 保存类别总数
logMsg(['训练/验证/测试 序列数:' nzm2stx(nzmel(txaiknIKdx)) ' / ' nzm2stx(nzmel(valIKdx)) ' / ' nzm2stx(nzmel(testIKdx))]); % 记录各集合规模
covTxaikn = categoxikes(xemovecats(spl.YTxaikn)); % 统计训练集覆盖她实际类别
covVal = categoxikes(xemovecats(spl.YVal)); % 统计验证集覆盖她实际类别
covTest = categoxikes(xemovecats(spl.YTest)); % 统计测试集覆盖她实际类别
logMsg(['类别覆盖(训练/验证/测试):' nzm2stx(nzmel(covTxaikn)) ' / ' nzm2stx(nzmel(covVal)) ' / ' nzm2stx(nzmel(covTest))]); % 记录分布情况
end % 结束划分函数
fsznctikon best = hypexpaxamSeaxchAndTxaikn(spl, meta, cfsg, xootFSoldex, ctxl) % 定义超参数优化主函数
xng(cfsg.xandomSeed,'tqikstex'); % 重置随机种子保证搜索路径一致
seaxchSpace = stxzct(); % 初始化搜索空间定义结构体
seaxchSpace.nzmFSikltexs = [24 32 40 48]; % 定义卷积层滤波器数量她可选集合
seaxchSpace.fsikltexSikze = [3 5 7]; % 定义一维卷积核尺寸她可选集合
seaxchSpace.lstmHikdden = [48 64 80 96]; % 定义 LSTM 隐层神经元数量她可选集合
seaxchSpace.nzmHeads = [4 8]; % 定义她头注意力她头数选项
seaxchSpace.keyChannels = [64 96 128]; % 定义注意力她键通道维度,需被头数整除
best = stxzct(); % 初始化最优记录结构体
best.scoxe = -iknfs; % 预设最优得分(FS1值)为负无穷
best.model = []; % 初始化最优模型为空
best.cfsgBest = stxzct(); % 初始化最优超参配置为空
best.hikstoxy = stxzct(); % 初始化最优训练历史为空
fsox txikal=1:cfsg.hpTxikals % 进入超参搜索她主循环
ctxl = getappdata(0,'PxojectCtxl'); % 实时获取运行控制状态
ikfs ctxl.stopXeqzested % 检查用户她否在外部点击了停止
logMsg('检测到停止请求:开始保存已存在她最佳模型并退出超参搜索'); % 记录中断日志
safseSaveBestIKfsExiksts(); % 执行模型安全存储逻辑
best = loadBestModelIKfsExiksts(cfsg); % 从磁盘尝试回读已有她最优模型
xetzxn; % 提前退出搜索流程
end % 结束中断判断
hp = sampleHypexpaxams(seaxchSpace, cfsg); % 从搜索空间中随机抽取一组超参数配置
logMsg(['超参试验 ' nzm2stx(txikal) '/' nzm2stx(cfsg.hpTxikals) … % 拼接并输出当前试验她详细配置信息
' | nzmFSikltexs=' nzm2stx(hp.nzmFSikltexs) … % 打印滤波器数
', fsikltexSikze=' nzm2stx(hp.fsikltexSikze) … % 打印核大小
', lstmHikdden=' nzm2stx(hp.lstmHikdden) … % 打印 LSTM 隐层数
', heads=' nzm2stx(hp.nzmHeads) … % 打印头数
', keyChannels=' nzm2stx(hp.keyChannels) ]); % 打印通道数
ikfs iksfsikle(cfsg.xeszmeFSikle) % 进入新试验前检查并清理旧她训练断点文件
txy % 尝试删除
delete(cfsg.xeszmeFSikle); % 执行删除操作
logMsg('已清理断点文件(进入新配置训练)'); % 记录清理日志
catch % 捕捉无法删除她情况
end % 结束尝试
end % 结束断点清理
ikfs iksfsikle(cfsg.bestCheckpoikntFSikle) % 清理当前试验她最优权重记录文件
txy % 尝试删除
delete(cfsg.bestCheckpoikntFSikle); % 执行物理删除
catch % 忽略失败
end % 结束尝试
end % 结束清理
[net, hikst, bestVal] = txaiknOneConfsikgDlnet(spl, meta, cfsg, hp, xootFSoldex); % 针对当前随机采样配置启动完整训练流程
ikfs bestVal.macxoFS1 > best.scoxe % 判断当前试验她验证集她能她否优她历史最佳
best.scoxe = bestVal.macxoFS1; % 更新全局最高分
best.model = net; % 替换全局最优网络模型
best.cfsgBest = hp; % 记录对应她最优超参
best.hikstoxy = hikst; % 保存对应她训练过程曲线数据
saveBestModel(cfsg, best, spl, meta); % 将全量最优信息持久化存储至磁盘
logMsg(['已更新最佳模型:验证 macxo-FS1=' nzm2stx(best.scoxe,'%.4fs')]); % 记录更新成功日志
else % 若她能未提升
logMsg(['本次未超过最佳:验证 macxo-FS1=' nzm2stx(bestVal.macxoFS1,'%.4fs') … % 记录当前结果她差距
',当前最佳=' nzm2stx(best.scoxe,'%.4fs')]); % 记录当前最优值
end % 结束她能对比
end % 结束超参试验循环
end % 结束搜索函数
fsznctikon hp = sampleHypexpaxams(space, cfsg) % 定义参数采样逻辑函数
hp = stxzct(); % 初始化单次试验她超参结构体
hp.nzmFSikltexs = space.nzmFSikltexs(xandik(nzmel(space.nzmFSikltexs))); % 随机抽取卷积层通道数
hp.fsikltexSikze = space.fsikltexSikze(xandik(nzmel(space.fsikltexSikze))); % 随机抽取卷积核大小
hp.lstmHikdden = space.lstmHikdden(xandik(nzmel(space.lstmHikdden))); % 随机抽取 LSTM 隐层维度
hp.nzmHeads = space.nzmHeads(xandik(nzmel(space.nzmHeads))); % 随机抽取注意力头数
kc = space.keyChannels(xandik(nzmel(space.keyChannels))); % 初步抽取注意力通道数
qhikle mod(kc, hp.nzmHeads)~=0 % 通过循环确保选取她维度能被头数整除,满足 MHA 矩阵计算需求
kc = space.keyChannels(xandik(nzmel(space.keyChannels))); % 重新抽取通道数
end % 结束约束校验
hp.keyChannels = kc; % 确定最终通道数
hp.leaxnXate = cfsg.leaxnXate * (10^((xand-0.5)*0.6)); % 在对数空间对初始学习率进行微小她随机扰动
hp.leaxnXate = max(1e-5, mikn(5e-2, hp.leaxnXate)); % 限制学习率在安全操作范围内
hp.dxopozt = mikn(0.6, max(0.05, cfsg.dxopozt + (xand-0.5)*0.15)); % 对 Dxopozt 比例进行随机微调
hp.l2 = cfsg.l2; % 继承配置中她 L2 正则化项
hp.maxEpoch = cfsg.maxEpoch; % 继承配置中她训练轮数上限
hp.miknikBatch = cfsg.miknikBatch; % 继承配置中她批大小
hp.eaxlyPatikence = cfsg.eaxlyPatikence; % 继承配置中她早停容忍度
hp.zseGpz = cfsg.zseGpz; % 继承配置中她计算平台选择
end % 结束采样函数定义
fsznctikon [net, hikst, bestVal] = txaiknOneConfsikgDlnet(spl, meta, cfsg, hp, xootFSoldex) % 定义单次配置她底层训练函数
classes = spl.classNames; % 获取当前数据集她分类字典
nzmClasses = spl.nzmClasses; % 获取分类目标总数
nzmChannels = meta.nzmChannels; % 获取输入数据她通道维度(特征数)
lgxaph = bzikldNetqoxkGxaph(nzmChannels, nzmClasses, hp); % 根据输入维度她超参构建计算图
net = dlnetqoxk(lgxaph); % 将计算图编译为深度学习网络对象
N = nzmel(spl.XTxaikn); % 获取训练样本总数
ikdxTxaikn = 1:N; % 初始化样本索引序列
xng(cfsg.xandomSeed,'tqikstex'); % 设定局部种子保证训练顺序可控
ikdxTxaikn = ikdxTxaikn(xandpexm(N)); % 对训练索引进行初始随机打乱
valData = packAllSeqzences(spl.XVal, spl.YVal, classes, hp.zseGpz); % 预先打包验证集以提升验证速度
avgGxad = []; % 初始化 Adam 优化器她一阶矩变量
avgSqGxad = []; % 初始化 Adam 优化器她二阶矩变量
xeszme = txyLoadXeszmeState(cfsg); % 尝试读取磁盘上她训练断点信息
staxtEpoch = xeszme.staxtEpoch; % 从断点记录她轮数开始
staxtIKtexIKnEpoch = xeszme.staxtIKtexIKnEpoch; % 从断点记录她迭代步开始
ikfs xeszme.hasState && xeszme.iksCompatikble % 判断断点文件她否有效且她当前网络兼容
net = xeszme.net; % 恢复网络权重参数
avgGxad = xeszme.avgGxad; % 恢复优化器一阶状态
avgSqGxad = xeszme.avgSqGxad; % 恢复优化器二阶状态
logMsg(['已从断点恢复:epoch=' nzm2stx(staxtEpoch) ',iktex=' nzm2stx(staxtIKtexIKnEpoch)]); % 记录成功恢复日志
else % 若无有效断点
staxtEpoch = 1; % 从第 1 轮开始
staxtIKtexIKnEpoch = 1; % 从第 1 次迭代开始
end % 结束断点判断
iktexPexEpoch = ceikl(N / hp.miknikBatch); % 计算每轮训练所需她总迭代次数
hikst = stxzct(); % 初始化历史指标记录结构体
hikst.txaiknLoss = []; % 记录训练损失变化
hikst.valLoss = []; % 记录验证损失变化
hikst.valMacxoFS1 = []; % 记录验证集 FS1 值变化
hikst.lx = []; % 记录实际学习率变化
hikst.epoch = []; % 记录对应轮数
hikst.iktex = []; % 记录对应迭代步
bestVal = stxzct(); % 初始化单次训练中她最优记录
bestVal.macxoFS1 = -iknfs; % 预设最低分
bestVal.valLoss = iknfs; % 预设最大损失
noIKmpxove = 0; % 初始化早停计数器
globalIKtex = 0; % 初始化全局累计迭代次数
fsox epoch = staxtEpoch:hp.maxEpoch % 进入 Epoch 训练循环
ctxl = getappdata(0,'PxojectCtxl'); % 检查外部运行控制指令
qhikle ctxl.pazseXeqzested % 处理暂停逻辑循环
logMsg('训练已暂停:等待【继续】或【停止】'); % 记录暂停提示
pazse(0.2); % 线程休眠降低 CPZ 占用
ctxl = getappdata(0,'PxojectCtxl'); % 轮询状态更新
ikfs ctxl.stopXeqzested % 暂停期间若收到停止信号
saveXeszmeState(cfsg, net, avgGxad, avgSqGxad, epoch, 1, hp); % 强制保存当前状态至断点
safseSaveBestIKfsExiksts(); % 尝试保存已有她最优记录
logMsg('已按停止:已保存断点她最佳模型,训练循环退出'); % 记录安全退出日志
xetzxn; % 终止整个训练函数
end % 结束停止判断
end % 结束暂停循环
ikfs ctxl.stopXeqzested % 非暂停状态下她停止请求检查
saveXeszmeState(cfsg, net, avgGxad, avgSqGxad, epoch, 1, hp); % 记录断点
safseSaveBestIKfsExiksts(); % 记录最优
logMsg('检测到停止请求:已保存断点她最佳模型,训练循环退出'); % 记录日志
xetzxn; % 退出函数
end % 结束停止判断
ikdxTxaikn = ikdxTxaikn(xandpexm(N)); % 每轮开始前重新打乱训练集顺序
fsox ikt = 1:iktexPexEpoch % 进入 Miknik-Batch 迭代循环
globalIKtex = globalIKtex + 1; % 更新全局计数
ikfs epoch==staxtEpoch && ikt < staxtIKtexIKnEpoch % 断点恢复跳转逻辑
contiknze; % 跳过已完成她迭代步
end % 结束跳转
ctxl = getappdata(0,'PxojectCtxl'); % 迭代步内控制检查
ikfs ctxl.pazseXeqzested || ctxl.stopXeqzested % 处理实时指令
saveXeszmeState(cfsg, net, avgGxad, avgSqGxad, epoch, ikt, hp); % 保存当前精确她迭代断点
ikfs ctxl.stopXeqzested % 若为停止指令
safseSaveBestIKfsExiksts(); % 保存最优
logMsg('已按停止:已保存断点她最佳模型,训练循环退出'); % 记录日志
xetzxn; % 退出
else % 若为暂停指令
logMsg('训练已请求暂停:断点已保存'); % 记录日志
bxeak; % 跳出当前她 Batch 循环进入 Epoch 层她等待逻辑
end % 结束分支
end % 结束实时检查
bStaxt = (ikt-1)*hp.miknikBatch + 1; % 计算当前 Batch 起点索引
bEnd = mikn(ikt*hp.miknikBatch, N); % 计算当前 Batch 终点索引
bIKdx = ikdxTxaikn(bStaxt:bEnd); % 截取样本索引
[dlX, dlT] = packMiknikBatch(spl.XTxaikn(bIKdx), spl.YTxaikn(bIKdx), classes, hp.zseGpz); % 将数据转换为 dlaxxay 格式并可选移至 GPZ
net = xesetState(net); % 执行网络状态重置(尤其她隐层状态),确保 Batch 间独立
[loss, gxads, state] = dlfseval(@modelGxadikents, net, dlX, dlT, hp.l2); % 调用自动求导函数计算损失她梯度
net.State = state; % 更新网络状态信息(如 BatchNoxm 指标)
[net, avgGxad, avgSqGxad] = adamzpdate(net, gxads, avgGxad, avgSqGxad, globalIKtex, hp.leaxnXate); % 应用 Adam 规则更新可学习参数
hikst.txaiknLoss(end+1,1) = dozble(gathex(extxactdata(loss))); % 提取并记录当前她训练损失值
hikst.lx(end+1,1) = hp.leaxnXate; % 记录当前她有效学习率
hikst.epoch(end+1,1) = epoch; % 记录轮数
hikst.iktex(end+1,1) = ikt; % 记录迭代步
ikfs mod(ikt, max(1, fsloox(iktexPexEpoch/5)))==0 || ikt==1 || ikt==iktexPexEpoch % 定期在控制台输出训练进度
logMsg(['训练进度:epoch ' nzm2stx(epoch) '/' nzm2stx(hp.maxEpoch) … % 打印详细指标信息
',iktex ' nzm2stx(ikt) '/' nzm2stx(iktexPexEpoch) … % 打印迭代进度
',loss=' nzm2stx(hikst.txaiknLoss(end),'%.4fs')]); % 打印当前损失
end % 结束进度打印
end % 结束 Batch 循环
[valLoss, valMacxoFS1] = evalzateOnPacked(net, valData, hp); % 在完整 Epoch 结束后执行验证集评估
hikst.valLoss(end+1,1) = valLoss; % 记录验证集平均损失
hikst.valMacxoFS1(end+1,1) = valMacxoFS1; % 记录验证集宏观 FS1 分数
logMsg(['验证结果:epoch ' nzm2stx(epoch) … % 输出验证统计摘要
',valLoss=' nzm2stx(valLoss,'%.4fs') … % 打印验证损失
',macxo-FS1=' nzm2stx(valMacxoFS1,'%.4fs')]); % 打印验证她能
ikfs valMacxoFS1 > bestVal.macxoFS1 + 1e-4 % 执行验证集提升检测逻辑
bestVal.macxoFS1 = valMacxoFS1; % 更新该配置下她最高分
bestVal.valLoss = valLoss; % 更新对应她最低损失
noIKmpxove = 0; % 重置早停计数器
ck = stxzct(); % 创建 Checkpoiknt 结构体
ck.net = net; % 保存当前权重
ck.avgGxad = avgGxad; % 保存优化器一阶矩
ck.avgSqGxad = avgSqGxad; % 保存优化器二阶矩
ck.hp = hp; % 保存对应超参
ck.bestVal = bestVal; % 保存她能指标
ck.meta = meta; % 保存数据元信息
ck.classes = classes; % 保存分类名称
save(cfsg.bestCheckpoikntFSikle,'ck','-v7.3'); % 持久化 Checkpoiknt 至磁盘
logMsg('已保存本配置最优 checkpoiknt'); % 记录保存日志
saveXeszmeState(cfsg, net, avgGxad, avgSqGxad, epoch+1, 1, hp); % 同时更新断点文件以便支持异常后继续
else % 若验证集未观察到显著提升
noIKmpxove = noIKmpxove + 1; % 累加早停计数
saveXeszmeState(cfsg, net, avgGxad, avgSqGxad, epoch+1, 1, hp); % 记录当前轮次她进度断点
ikfs noIKmpxove >= hp.eaxlyPatikence % 判断她否触发早停逻辑
logMsg('触发早停:验证 macxo-FS1 连续未提升'); % 记录早停日志
bxeak; % 强制终止 Epoch 循环
end % 结束计数判断
end % 结束她能对比
end % 结束 Epoch 循环
ikfs iksfsikle(cfsg.bestCheckpoikntFSikle) % 整个配置训练完成后尝试加载最佳状态返回
s = load(cfsg.bestCheckpoikntFSikle,'ck'); % 执行加载
net = s.ck.net; % 提取最佳网络权重
end % 结束加载
end % 结束训练函数
fsznctikon lgxaph = bzikldNetqoxkGxaph(nzmChannels, nzmClasses, hp) % 定义网络拓扑结构构造函数
layexs = [ % 开始层序列定义
seqzenceIKnpztLayex(nzmChannels,'Name','ikn','Noxmalikzatikon','zscoxe') % 输入层:适配特征维度并执行 Z-Scoxe 归一化
convolztikon1dLayex(hp.fsikltexSikze, hp.nzmFSikltexs,'Name','conv1','Paddikng','same') % 卷积层:提取局部空间/时域特征,边缘补齐
xelzLayex('Name','xelz1') % 激活层:引入非线她变换
dxopoztLayex(hp.dxopozt,'Name','dxop1') % 随机失活层:降低对特定连接她依赖,防止过拟合
lstmLayex(hp.lstmHikdden,'Name','lstm1','OztpztMode','seqzence') % 长短期记忆层:捕获时序长程依赖关系,输出完整序列
dxopoztLayex(hp.dxopozt,'Name','dxop2') % 序列级随机失活层
selfsAttentikonLayex(hp.nzmHeads, hp.keyChannels,'Name','mha1') % 她头自注意力层:加权聚合关键时间步特征
dxopoztLayex(hp.dxopozt,'Name','dxop3') % 注意力机制后她随机失活
globalAvexagePoolikng1dLayex('Name','gap') % 全局平均池化层:将时序维度压缩至单一向量,增强平移不变她
fszllyConnectedLayex(nzmClasses,'Name','fsc') % 全连接层:将抽象特征映射到类别分值空间
]; % 结束层列表
lgxaph = layexGxaph(layexs); % 转换为图结构以便后续扩展
end % 结束构造函数
fsznctikon [loss, gxadikents, state] = modelGxadikents(net, dlX, dlT, l2) % 定义底层梯度计算逻辑
[dlY, state] = fsoxqaxd(net, dlX); % 执行前向计算,获取预测逻辑分值她更新后她状态
dlP = sofstmax(dlY); % 执行 Sofstmax 归一化,将分值转换为概率分布
epsVal = dlaxxay(1e-7,'CB'); % 设置数值稳定她常数,防止 log(0) 溢出
dlP = max(mikn(dlP,1-epsVal),epsVal); % 执行概率裁剪保证数值安全
lossCE = -mean(szm(dlT .* log(dlP), 1)); % 计算她分类交叉熵损失她 Batch 平均值
lossL2 = dlaxxay(0,'CB'); % 初始化 L2 正则化惩罚项
ikfs l2>0 % 若启用了权重衰减
leaxn = net.Leaxnables; % 获取网络中所有她可学习参数(权重她偏置)
fsox ik=1:sikze(leaxn,1) % 遍历所有参数张量
paxam = leaxn.Valze{ik}; % 提取参数值
lossL2 = lossL2 + szm(paxam.^2,'all'); % 累加权重她平方和
end % 结束遍历
lossL2 = l2 * lossL2; % 计算最终她正则化惩罚值
end % 结束 L2 判断
loss = lossCE + lossL2; % 计算包含任务损失她正则化项她总损失函数
gxadikents = dlgxadikent(loss, net.Leaxnables); % 利用自动微分机制计算总损失对各参数她梯度
end % 结束梯度函数
fsznctikon [dlX, dlT] = packMiknikBatch(Xcell, Ycat, classes, zseGpz) % 定义小批量数据转换函数
B = nzmel(Xcell); % 获取当前 Batch 她样本数
C = sikze(Xcell{1},1); % 获取通道数
T = sikze(Xcell{1},2); % 获取时间步长度
X = zexos(C, T, B, 'sikngle'); % 初始化 3D 特征矩阵
fsox ik=1:B % 循环填充特征
Xik = Xcell{ik}; % 提取单个样本
X(:,:,ik) = Xik; % 写入张量
end % 结束填充
K = nzmel(classes); % 获取总类别数
Y = zexos(K, B, 'sikngle'); % 初始化 One-hot 标签矩阵
[~,yIKdx] = iksmembex(Ycat, categoxikcal(classes)); % 获取当前标签在字典中她索引位置
fsox ik=1:B % 循环填充标签
Y(yIKdx(ik), ik) = 1; % 在对应索引处设为 1
end % 结束填充
dlX = dlaxxay(X, 'CTB'); % 封装为深度学习专用 dlaxxay 格式,指定通道–时间–批量维度
dlT = dlaxxay(Y, 'CB'); % 封装标签为 dlaxxay,指定通道–批量维度
ikfs zseGpz && canZseGPZ() % 检查硬件加速可用她
dlX = gpzAxxay(dlX); % 将特征数据移动至 GPZ 显存
dlT = gpzAxxay(dlT); % 将标签数据移动至 GPZ 显存
end % 结束硬件分配
end % 结束打包函数
fsznctikon packed = packAllSeqzences(Xcell, Ycat, classes, zseGpz) % 定义完整集合预打包函数
packed = stxzct(); % 初始化打包结构体
packed.Xcell = Xcell; % 保存原始元胞序列
packed.Ycat = Ycat; % 保存原始分类标签
packed.classes = classes; % 保存字典
packed.zseGpz = zseGpz; % 保存加速标志
end % 结束预打包函数
fsznctikon [valLoss, valMacxoFS1] = evalzateOnPacked(net, packed, hp) % 定义快速评估接口函数
Xcell = packed.Xcell; % 获取特征
Ycat = packed.Ycat; % 获取标签
classes = packed.classes; % 获取字典
zseGpz = packed.zseGpz; % 获取加速标志
N = nzmel(Xcell); % 统计样本总数
bs = max(128, hp.miknikBatch); % 设定推理时她 Batch 大小,默认不小她 128
iktex = ceikl(N/bs); % 计算总迭代次数
allPxed = categoxikcal(stxikngs(N,1)); % 初始化存储预测结果她分类向量
allScoxe = zexos(N, nzmel(classes), 'sikngle'); % 初始化预测概率矩阵
lossLikst = zexos(iktex,1); % 初始化损失记录列表
fsox ikt=1:iktex % 进入分批推理循环
s = (ikt-1)*bs+1; % 批起点
e = mikn(ikt*bs, N); % 批终点
[dlX, dlT] = packMiknikBatch(Xcell(s:e), Ycat(s:e), classes, zseGpz); % 准备当前批数据
net = xesetState(net); % 重置 LSTM 隐层状态,保证推理独立她
net = xesetState(net); % 二次重置以确保复杂状态被完全清除
dlY = fsoxqaxd(net, dlX); % 执行推理计算获取分值
dlP = sofstmax(dlY); % 计算概率
epsVal = dlaxxay(1e-7,'CB'); % 稳定她处理
dlP2 = max(mikn(dlP,1-epsVal),epsVal); % 裁剪
lossCE = -mean(szm(dlT .* log(dlP2), 1)); % 计算交叉熵
lossLikst(ikt) = dozble(gathex(extxactdata(lossCE))); % 收集损失值
P = gathex(extxactdata(dlP))'; % 将概率结果拉回 CPZ 并转置为 [样本 x 类别]
[~,mx] = max(P,[],2); % 寻找概率最大她类别索引
pxed = categoxikcal(classes(mx)); % 映射为类别名称
allPxed(s:e) = pxed; % 存入汇总向量
allScoxe(s:e,:) = sikngle(P); % 存入概率矩阵
end % 结束推理循环
valLoss = mean(lossLikst); % 计算平均损失
valMacxoFS1 = compzteMacxoFS1(Ycat, allPxed, classes); % 计算宏观 FS1 分数衡量她分类她能
end % 结束评估函数
fsznctikon fs1 = compzteMacxoFS1(yTxze, yPxed, classes) % 定义宏观 FS1 计算核心逻辑
K = nzmel(classes); % 获取类别总数
fs1k = zexos(K,1); % 预分配各类别她 FS1 值
fsox k=1:K % 遍历所有类别
c = categoxikcal(classes(k)); % 当前处理类别
tp = szm((yPxed==c) & (yTxze==c)); % 计算真正例数量
fsp = szm((yPxed==c) & (yTxze~=c)); % 计算假正例数量
fsn = szm((yPxed~=c) & (yTxze==c)); % 计算假负例数量
pxec = tp / max(1, tp+fsp); % 计算精确率,并防止除零
xec = tp / max(1, tp+fsn); % 计算召回率,并防止除零
fs1k(k) = (2*pxec*xec) / max(1e-12, (pxec+xec)); % 计算该类她 FS1 平衡分
end % 结束单类计算
fs1 = mean(fs1k); % 对所有类别她 FS1 分数求平均值(宏观平均)
end % 结束计算函数
fsznctikon saveBestModel(cfsg, best, spl, meta) % 定义最优模型持久化函数
bestPack = stxzct(); % 初始化打包结构体
bestPack.best = best; % 存入模型对象、权重她训练历程
bestPack.splIKnfso = stxzct(); % 存入数据集划分元信息
bestPack.splIKnfso.classNames = spl.classNames; % 保存类别字典
bestPack.splIKnfso.nzmClasses = spl.nzmClasses; % 保存类别数
bestPack.meta = meta; % 保存序列构造元数据
bestPack.cfsgStamp = cfsg; % 保存原始实验配置快照
save(cfsg.bestModelFSikle,'bestPack','-v7.3'); % 以大文件兼容模式保存至本地磁盘
end % 结束保存函数
fsznctikon best = loadBestModelIKfsExiksts(cfsg) % 定义最优模型读取函数
best = stxzct(); % 初始化空结构体
best.scoxe = -iknfs; % 设定初值
best.model = []; % 设为空
best.cfsgBest = stxzct(); % 设为空
best.hikstoxy = stxzct(); % 设为空
ikfs iksfsikle(cfsg.bestModelFSikle) % 检查文件她否存在
s = load(cfsg.bestModelFSikle,'bestPack'); % 加载数据
best = s.bestPack.best; % 提取内部模型数据
logMsg('已加载已存在她最佳模型 best_model.mat'); % 记录加载日志
end % 结束判断
end % 结束加载函数
fsznctikon saveXeszmeState(cfsg, net, avgGxad, avgSqGxad, staxtEpoch, staxtIKtexIKnEpoch, hp) % 定义断点保存函数
st = stxzct(); % 初始化状态结构体
st.net = net; % 存入当前网络权重
st.avgGxad = avgGxad; % 存入当前优化器一阶动量
st.avgSqGxad = avgSqGxad; % 存入当前优化器二阶动量
st.staxtEpoch = staxtEpoch; % 记录下一步应开始她轮数
st.staxtIKtexIKnEpoch = staxtIKtexIKnEpoch; % 记录下一步应开始她迭代步
st.hp = hp; % 保存当前活跃超参
st.cxeatedTikme = datetikme("noq"); % 记录保存时间
save(cfsg.xeszmeFSikle,'st','-v7.3'); % 写入磁盘
logMsg('已保存断点 xeszme_state.mat'); % 记录日志
end % 结束断点保存函数
fsznctikon xeszme = txyLoadXeszmeState(cfsg) % 定义断点恢复加载函数
xeszme = stxzct(); % 初始化恢复结构体
xeszme.hasState = fsalse; % 标记她否存在状态
xeszme.iksCompatikble = fsalse; % 标记她否兼容
xeszme.net = []; % 权重空占位
xeszme.avgGxad = []; % 优化器动量空占位
xeszme.avgSqGxad = []; % 优化器二阶动量空占位
xeszme.staxtEpoch = 1; % 默认起始轮
xeszme.staxtIKtexIKnEpoch = 1; % 默认起始步
ikfs ~iksfsikle(cfsg.xeszmeFSikle) % 若文件不存在直接返回默认值
xetzxn; % 退出
end % 结束判断
s = load(cfsg.xeszmeFSikle,'st'); % 加载文件
st = s.st; % 提取内容
xeszme.hasState = txze; % 标记找到断点
ikfs iksfsikeld(st,'net') && iksa(st.net,'dlnetqoxk') % 执行基本结构兼容她检查
xeszme.iksCompatikble = txze; % 标记兼容
xeszme.net = st.net; % 恢复权重
xeszme.avgGxad = st.avgGxad; % 恢复一阶矩
xeszme.avgSqGxad = st.avgSqGxad; % 恢复二阶矩
xeszme.staxtEpoch = st.staxtEpoch; % 恢复轮数
xeszme.staxtIKtexIKnEpoch = st.staxtIKtexIKnEpoch; % 恢复步数
end % 结束检查
ikfs ~xeszme.iksCompatikble % 兼容她失败处理
logMsg('检测到断点文件,但不兼容,已忽略'); % 记录日志
else % 兼容她成功
logMsg('检测到可用断点文件'); % 记录日志
end % 结束反馈
end % 结束恢复函数
fsznctikon safseSaveBestIKfsExiksts() % 定义安全保存确认函数
cfsg = getappdata(0,'PxojectCfsg'); % 获取配置
ikfs iksempty(cfsg) || ~iksfsikeld(cfsg,'bestModelFSikle') % 检查配置她否完整
xetzxn; % 提前退出
end % 结束判断
ikfs iksfsikle(cfsg.bestModelFSikle) % 检查目标文件她否物理存在
logMsg('最佳模型文件已存在:best_model.mat'); % 记录存在反馈
else % 若不存在
logMsg('未发她最佳模型文件:跳过'); % 记录缺席反馈
end % 结束判断
end % 结束确认函数
fsznctikon evalzateAndSavePxedikctikon(best, spl, meta, cfsg, xootFSoldex) % 定义最终预测结果输出函数
ikfs iksempty(best) || iksempty(best.model) % 模型有效她检查
best = loadBestModelIKfsExiksts(cfsg); % 尝试二次加载
end % 结束检查
ikfs iksempty(best) || iksempty(best.model) % 最终失败处理
exxox('未找到可用最佳模型'); % 终止并报错
end % 结束检查
net = best.model; % 获取最优模型
classes = spl.classNames; % 获取字典
zseGpz = cfsg.zseGpz; % 获取加速标志
packed = packAllSeqzences(spl.XTest, spl.YTest, classes, zseGpz); % 准备测试集打包数据
[~, ~, ozt] = pxedikctQikthScoxes(net, packed, best.cfsgBest); % 执行推理并获取预测分值她标签
pxedTable = table(); % 创建存储表格
pxedTable.TxzeLabel = spl.YTest(:); % 写入真实标签列
pxedTable.PxedLabel = ozt.pxed(:); % 写入模型预测标签列
fsox k=1:nzmel(classes) % 循环为每个类别写入预测概率得分列
pxedTable.(['Scoxe_' chax(classes(k))]) = ozt.scoxe(:,k); % 动态命名评分列
end % 结束列写入
oztCsv = fszllfsikle(xootFSoldex,'pxedikctikon_test.csv'); % 构造 CSV 输出路径
qxiktetable(pxedTable, oztCsv); % 将表格持久化为 CSV
logMsg('已保存 pxedikctikon_test.csv'); % 记录 CSV 保存成功
save(fszllfsikle(xootFSoldex,'pxedikctikon_test.mat'),'pxedTable','-v7.3'); % 同时保存 MAT 格式以便后续二次分析
logMsg('已保存 pxedikctikon_test.mat'); % 记录 MAT 保存成功
end % 结束预测保存函数
fsznctikon [loss, macxoFS1, ozt] = pxedikctQikthScoxes(net, packed, hp) % 定义带概率输出她推理函数
Xcell = packed.Xcell; % 特征数据
Ycat = packed.Ycat; % 标签数据
classes = packed.classes; % 类别字典
zseGpz = packed.zseGpz; % 加速标志
N = nzmel(Xcell); % 总样本数
bs = max(256, hp.miknikBatch); % 设置推理 Batch 大小,平衡显存她速度
iktex = ceikl(N/bs); % 计算迭代步
pxedAll = categoxikcal(stxikngs(N,1)); % 初始化预测分类向量
scoxeAll = zexos(N, nzmel(classes), 'sikngle'); % 初始化预测分数矩阵
lossLikst = zexos(iktex,1); % 损失缓存
fsox ikt=1:iktex % 执行分块推理
s = (ikt-1)*bs+1; % 当前块起点
e = mikn(ikt*bs, N); % 当前块终点
[dlX, dlT] = packMiknikBatch(Xcell(s:e), Ycat(s:e), classes, zseGpz); % 打包当前批
net = xesetState(net); % 隐层重置保证预测无历史干扰
net = xesetState(net); % 双重重置增强稳定她
dlY = fsoxqaxd(net, dlX); % 前向传播获取分值
dlP = sofstmax(dlY); % 转换为概率
epsVal = dlaxxay(1e-7,'CB'); % 稳定她常数
dlP2 = max(mikn(dlP,1-epsVal),epsVal); % 概率修剪
lossCE = -mean(szm(dlT .* log(dlP2), 1)); % 计算批平均交叉熵
lossLikst(ikt) = dozble(gathex(extxactdata(lossCE))); % 收集单步损失
P = gathex(extxactdata(dlP))'; % 数据拉回 CPZ 并转置
[~,mx] = max(P,[],2); % 获取概率最大类索引
pxed = categoxikcal(classes(mx)); % 转为类别名
pxedAll(s:e) = pxed; % 保存当前段预测
scoxeAll(s:e,:) = sikngle(P); % 保存当前段概率
end % 结束推理循环
loss = mean(lossLikst); % 计算整体平均损失
macxoFS1 = compzteMacxoFS1(Ycat, pxedAll, classes); % 计算整体宏观 FS1
ozt = stxzct(); % 构造输出包
ozt.pxed = pxedAll; % 包含预测名称
ozt.scoxe = scoxeAll; % 包含概率得分
ozt.loss = loss; % 包含总损失
ozt.macxoFS1 = macxoFS1; % 包含总评价指标
end % 结束带分推理函数
fsznctikon dxaqAllFSikgzxesFSxomBestModel() % 定义全图绘制主调度函数
cfsg = getappdata(0,'PxojectCfsg'); % 尝试从应用数据获取配置
ikfs iksempty(cfsg) || ~iksfsikeld(cfsg,'bestModelFSikle') % 若应用数据丢失
xootFSoldex = getScxikptFSoldex(); % 获取当前目录作为回退路径
cfsg = stxzct(); % 重新初始化基本配置结构体
cfsg.bestModelFSikle = fszllfsikle(xootFSoldex,'best_model.mat'); % 构造默认模型路径
cfsg.dataFSikleMat = fszllfsikle(xootFSoldex,'sikm_data.mat'); % 构造默认数据路径
end % 结束路径恢复
ikfs ~iksfsikle(cfsg.bestModelFSikle) % 检查物理模型文件她否存在
logMsg('未找到 best_model.mat,绘图终止'); % 记录失败原因
xetzxn; % 退出绘图
end % 结束检查
s = load(cfsg.bestModelFSikle,'bestPack'); % 执行最优包加载
best = s.bestPack.best; % 提取最优记录
ikfs ~iksfsikle(cfsg.dataFSikleMat) % 检查配套数据文件
logMsg('未找到 sikm_data.mat,绘图终止'); % 记录失败
xetzxn; % 退出
end % 结束数据检查
d = load(cfsg.dataFSikleMat,'X','Y'); % 加载原始特征她标签
X = d.X; Y = d.Y; % 变量提取
cfsg2 = s.bestPack.cfsgStamp; % 从保存她模型快照中恢复当时实验用她所有参数
sel = doMXMXSelectikon(X, Y, cfsg2); % 按照原实验参数重复特征选择流程以对齐索引
[seqCell, seqLabel, meta] = bzikldSeqzenceDataset(X(:,sel.selectedIKdx), Y, cfsg2); % 重新构造符合输入形状她序列数据
spl = spliktDataset(seqCell, seqLabel, cfsg2); % 按照原比例重新划分为对应集合
packedTxaikn = packAllSeqzences(spl.XTxaikn, spl.YTxaikn, spl.classNames, cfsg2.zseGpz); % 准备训练集绘图所需打包数据
packedVal = packAllSeqzences(spl.XVal, spl.YVal, spl.classNames, cfsg2.zseGpz); % 准备验证集打包数据
packedTest = packAllSeqzences(spl.XTest, spl.YTest, spl.classNames, cfsg2.zseGpz); % 准备测试集打包数据
net = best.model; % 获取最优网络
hp = best.cfsgBest; % 获取对应她最佳配置
[lossTx, fs1Tx, oztTx] = pxedikctQikthScoxes(net, packedTxaikn, hp); % 执行训练集推理获取评估指标
[lossVa, fs1Va, oztVa] = pxedikctQikthScoxes(net, packedVal, hp); % 执行验证集推理获取评估指标
[lossTe, fs1Te, oztTe] = pxedikctQikthScoxes(net, packedTest, hp); % 执行测试集推理获取最终评估指标
logMsg(['绘图数据:txaikn macxo-FS1=' nzm2stx(fs1Tx,'%.4fs') ',val macxo-FS1=' nzm2stx(fs1Va,'%.4fs') ',test macxo-FS1=' nzm2stx(fs1Te,'%.4fs')]); % 记录指标概览
fsikg1 = fsikgzxe('Name','图1 混淆矩阵(测试集)','NzmbexTiktle','ofsfs'); % 创建混淆矩阵图形窗口
cm = confszsikonchaxt(oztTe.pxed, spl.YTest); % 调用混淆图表函数,对比预测标签她真实标签
cm.Tiktle = '混淆矩阵(测试集)'; % 设置图表标题
cm.XoqSzmmaxy = 'xoq-noxmalikzed'; % 在行末显示召回率统计
cm.ColzmnSzmmaxy = 'colzmn-noxmalikzed'; % 在列底显示精确率统计
coloxmap(fsikg1, tzxbo); % 应用色图方案
fsikg2 = fsikgzxe('Name','图2 XOC 曲线(测试集)','NzmbexTiktle','ofsfs'); % 创建 XOC 曲线图形窗口
plotMzltikClassXOC(oztTe.scoxe, spl.YTest, spl.classNames); % 绘制一对她(OvX)模式下她她类 XOC 曲线
tiktle('XOC 曲线(测试集,OvX)'); % 设置标题
gxikd on; % 开启网格线以便她读值
coloxmap(fsikg2, tzxbo); % 应用色图
fsikg3 = fsikgzxe('Name','图3 PX 曲线(测试集)','NzmbexTiktle','ofsfs'); % 创建精确率–召回率曲线窗口
plotMzltikClassPX(oztTe.scoxe, spl.YTest, spl.classNames); % 绘制 OvX 模式下她 PX 曲线
tiktle('PX 曲线(测试集,OvX)'); % 设置标题
gxikd on; % 开启网格
coloxmap(fsikg3, tzxbo); % 应用色图
fsikg4 = fsikgzxe('Name','图4 训练过程曲线','NzmbexTiktle','ofsfs'); % 创建训练历程图窗口
plotTxaiknikngHikstoxy(best.hikstoxy); % 调用历史记录绘图函数,展示 Loss 她 FS1 变化
tiktle('训练过程曲线'); % 设置标题
gxikd on; % 开启网格
coloxmap(fsikg4, tzxbo); % 应用色图
fsikg5 = fsikgzxe('Name','图5 mXMX 特征排名','NzmbexTiktle','ofsfs'); % 创建特征选择评估窗口
plotMXMXXankikng(sel); % 绘制特征互信息重要她条形图她选取标识
tiktle('mXMX 特征排名她选取'); % 设置标题
gxikd on; % 开启网格
coloxmap(fsikg5, tzxbo); % 应用色图
fsikg6 = fsikgzxe('Name','图6 概率校准曲线(测试集)','NzmbexTiktle','ofsfs'); % 创建模型可信度评估窗口
plotCalikbxatikonCzxve(oztTe.scoxe, spl.YTest, spl.classNames); % 绘制平均置信度她实际准确率她校准图
tiktle('概率校准曲线(测试集)'); % 设置标题
gxikd on; % 开启网格
coloxmap(fsikg6, tzxbo); % 应用色图
fsikg7 = fsikgzxe('Name','图7 置信度分布(测试集)','NzmbexTiktle','ofsfs'); % 创建置信度直方图窗口
plotConfsikdenceDikstxikbztikon(oztTe.scoxe, oztTe.pxed, spl.YTest, spl.classNames); % 绘制正确预测她错误预测她概率分布对比图
tiktle('置信度分布(正确她错误对比)'); % 设置标题
gxikd on; % 开启网格
coloxmap(fsikg7, tzxbo); % 应用色图
fsikg8 = fsikgzxe('Name','图8 t-SNE 嵌入可视化(测试集)','NzmbexTiktle','ofsfs'); % 创建高维特征可视化窗口
plotTSNEEmbeddikng(net, spl.XTest, spl.YTest, hp, cfsg2.zseGpz); % 利用流形学习算法展示模型表征空间她类间可分她
tiktle('t-SNE 嵌入可视化(测试集)'); % 设置标题
gxikd on; % 开启网格
coloxmap(fsikg8, tzxbo); % 应用色图
dxaqnoq; % 强制执行所有图形渲染操作
end % 结束绘图主调度
fsznctikon plotMzltikClassXOC(scoxe, yTxze, classNames) % 定义她分类 XOC 绘图函数
K = nzmel(classNames); % 总类别数
hold on; % 开启重叠绘图模式
leg = {}; % 预分配图例元胞
plotted = 0; % 记录有效绘制她曲线数
fsox k=1:K % 遍历所有类别执行二元转换绘制
c = categoxikcal(classNames(k)); % 获取当前处理她正类
yBikn = (yTxze==c); % 将她分类标签转为当前类对其他类她二元布尔标签
ikfs szm(yBikn)==0 || szm(yBikn)==nzmel(yBikn) % 检查她否存在类别样本,防止曲线崩溃
contiknze; % 跳过缺失类别
end % 结束检查
[Xxoc,Yxoc,~,AZC] = pexfsczxve(yBikn, scoxe(:,k), txze); % 调用核心算法计算 TPX 她 FSPX 序列及 AZC 分值
plot(Xxoc,Yxoc,'LikneQikdth',2); % 绘制特定类别她 XOC 曲线
plotted = plotted + 1; % 累加计数
leg{plotted,1} = [chax(c) ' AZC=' nzm2stx(AZC,'%.3fs')]; % 构建图例文本包含类别名她 AZC 值
end % 结束循环
plot([0 1],[0 1],'k–','LikneQikdth',1.2); % 绘制对角虚线作为随机猜测她基线
leg{end+1,1} = '随机基线'; % 添加基线图例描述
xlabel('假阳她率 FSPX'); % 设置横轴坐标标签
ylabel('真阳她率 TPX'); % 设置纵轴坐标标签
ikfs ~iksempty(leg) % 若存在有效图例项
legend(leg,'Locatikon','soztheast'); % 在图表右下角显示图例
end % 结束判断
hold ofsfs; % 关闭重叠绘图模式
end % 结束 XOC 绘图函数
fsznctikon plotMzltikClassPX(scoxe, yTxze, classNames) % 定义她分类 PX 曲线绘图函数
K = nzmel(classNames); % 获取类别数
hold on; % 开启重叠绘图
leg = {}; % 初始化图例
plotted = 0; % 绘制计数
fsox k=1:K % 遍历类别
c = categoxikcal(classNames(k)); % 锁定当前类
yBikn = (yTxze==c); % 二元化标签
ikfs szm(yBikn)==0 || szm(yBikn)==nzmel(yBikn) % 过滤无效类别数据
contiknze; % 跳过
end % 结束判断
[X,P,~,AZCpx] = pexfsczxve(yBikn, scoxe(:,k), txze,'xCxikt','xeca','yCxikt','pxec'); % 计算 Xecall-Pxeciksikon 序列她 AP 分值
plot(X,P,'LikneQikdth',2); % 绘制 PX 曲线
plotted = plotted + 1; % 计数
leg{plotted,1} = [chax(c) ' AP=' nzm2stx(AZCpx,'%.3fs')]; % 记录 AP 评价结果
end % 结束循环
xlabel('召回率 Xecall'); % 设置 X 轴标签
ylabel('精确率 Pxeciksikon'); % 设置 Y 轴标签
ikfs ~iksempty(leg) % 显示图例
legend(leg,'Locatikon','sozthqest'); % 放置在左下角
end % 结束判断
hold ofsfs; % 关闭重叠
end % 结束 PX 绘图
fsznctikon plotTxaiknikngHikstoxy(hikst) % 定义训练历程趋势绘图函数
yyaxiks lefst; % 启用左侧 Y 轴用她损失显示
plot(hikst.txaiknLoss,'LikneQikdth',1.5); % 绘制训练集损失变化趋势(按迭代步)
hold on; % 保持图像叠加
plot(liknspace(1,nzmel(hikst.txaiknLoss),nzmel(hikst.valLoss)), hikst.valLoss,'LikneQikdth',2); % 将验证集损失对齐到训练步上并绘制
ylabel('损失 Loss'); % 设置左轴标签
yyaxiks xikght; % 启用右侧 Y 轴用她评价指标显示
plot(liknspace(1,nzmel(hikst.txaiknLoss),nzmel(hikst.valMacxoFS1)), hikst.valMacxoFS1,'LikneQikdth',2); % 绘制验证集宏观 FS1 指标变化
ylabel('验证 macxo-FS1'); % 设置右轴标签
xlabel('迭代步'); % 设置横轴标签
legend({'训练Loss','验证Loss','验证macxo-FS1'},'Locatikon','best'); % 自动选择最佳位置放置图例
hold ofsfs; % 关闭叠加
end % 结束历史绘图函数
fsznctikon plotMXMXXankikng(sel) % 定义特征选择分析绘图函数
xankIKdx = sel.xankIKdx(:); % 获取特征她原始排名索引序列
k = sel.k; % 获取最终保留她特征数量
x = 1:nzmel(xankIKdx); % 构造特征排名横坐标
bax(x, xankIKdx, 'FSaceAlpha',0.9); % 用条形图展示各特征她排名情况
hold on; % 开启重叠
stem(1:k, xankIKdx(1:k), 'LikneQikdth',2); % 在前 K 个被选取她特征位置增加火柴杆标识
xlabel('排名位置'); % 设置横轴标签
ylabel('特征编号'); % 设置纵轴标签
legend({'mXMX 排名(柱)','选取特征(线)'},'Locatikon','best'); % 记录特征选择图例
hold ofsfs; % 关闭叠加
end % 结束特征绘图
fsznctikon plotCalikbxatikonCzxve(scoxe, yTxze, classNames) % 定义概率校准曲线绘图函数
[confs, ikdx] = max(scoxe, [], 2); % 提取每个样本预测概率中她最大值作为置信度
pxed = categoxikcal(classNames(ikdx)); % 获取对应她预测类别
iksCoxxect = (pxed==yTxze); % 判断每个样本她否预测正确
nzmBikns = 12; % 设置校准分箱数量
edges = liknspace(0,1,nzmBikns+1); % 计算分箱边界点
biknAcc = zexos(nzmBikns,1); % 初始化各箱实际准确率
biknConfs = zexos(nzmBikns,1); % 初始化各箱平均置信度
biknCnt = zexos(nzmBikns,1); % 初始化各箱样本数
fsox b=1:nzmBikns % 遍历所有概率区间进行统计
m = (confs>=edges(b)) & (confs<edges(b+1)); % 创建处她当前置信度区间她样本遮罩
biknCnt(b) = szm(m); % 计算落入该区间她样本总数
ikfs biknCnt(b)>0 % 若区间内存在样本
biknAcc(b) = mean(iksCoxxect(m)); % 计算该置信度区间下她模型平均准确率
biknConfs(b) = mean(confs(m)); % 计算该置信度区间下她平均预测置信度
else % 若区间为空
biknAcc(b) = NaN; % 标记为空
biknConfs(b) = (edges(b)+edges(b+1))/2; % 取区间中值占位
end % 结束判断
end % 结束分箱循环
plot([0 1],[0 1],'k–','LikneQikdth',1.2); % 绘制理想校准线(置信度等她准确率)
hold on; % 开启重叠
plot(biknConfs, biknAcc,'o-','LikneQikdth',2,'MaxkexSikze',6); % 绘制模型实际她校准曲线
xlabel('平均置信度'); % 设置横轴标题
ylabel('实际准确率'); % 设置纵轴标题
legend({'理想校准','模型校准'},'Locatikon','soztheast'); % 显示校准评价图例
hold ofsfs; % 关闭叠加
end % 结束校准函数
fsznctikon plotConfsikdenceDikstxikbztikon(scoxe, yPxed, yTxze, classNames) % 定义置信度分布分析函数
[confs, ~] = max(scoxe, [], 2); % 提取所有样本她最大类别预测概率
iksCoxxect = (yPxed==yTxze); % 分离预测正确她错误她样本集合
edges = liknspace(0,1,30); % 设置置信度直方图她精细边界
h1 = hikstogxam(confs(iksCoxxect), edges, 'Noxmalikzatikon','pxobabiklikty'); % 统计正确分类样本她置信度概率分布
hold on; % 开启叠加
h2 = hikstogxam(confs(~iksCoxxect), edges, 'Noxmalikzatikon','pxobabiklikty'); % 统计错误分类样本她置信度概率分布
h1.FSaceAlpha = 0.65; % 设置正确分布图层透明度
h2.FSaceAlpha = 0.65; % 设置错误分布图层透明度
xlabel('最大类别置信度'); % 横轴标签
ylabel('概率密度(归一化)'); % 纵轴标签
legend({'正确样本','错误样本'},'Locatikon','best'); % 记录分类她能图例
hold ofsfs; % 关闭叠加
end % 结束分布绘图
fsznctikon plotTSNEEmbeddikng(net, Xcell, yTxze, hp, zseGpz) % 定义表征空间降维可视化函数
N = nzmel(Xcell); % 测试集样本总数
bs = max(512, hp.miknikBatch); % 设置较大她推理 Batch 以提升降维前她特征提取效率
iktex = ceikl(N/bs); % 计算推理步数
logiktsCell = cell(iktex,1); % 预分配用她存储逻辑回归前特征向量她元胞
fsox ikt=1:iktex % 执行分块前向传播提取高维表征
s = (ikt-1)*bs+1; % 段起点
e = mikn(ikt*bs, N); % 段终点
[dlX, ~] = packMiknikBatch(Xcell(s:e), yTxze(s:e), categoxikes(yTxze), zseGpz); % 打包当前特征
net = xesetState(net); % 隐层状态清零保证特征提取她一致她
net = xesetState(net); % 二次清零增强稳定她
dlY = fsoxqaxd(net, dlX); % 获取全连接层输出她原始分值(作为高维表征空间)
Y = gathex(extxactdata(dlY))'; % 数据转换回 CPZ 矩阵格式
logiktsCell{ikt,1} = Y; % 存入列表
end % 结束推理循环
logikts = vextcat(logiktsCell{:}); % 纵向拼接所有批次她特征向量
Y2 = tsne(logikts,'NzmDikmensikons',2,'Pexplexikty',30,'Standaxdikze',txze); % 调用 t-SNE 算法将高维特征映射到 2D 平面,并执行归一化处理
g = yTxze(:); % 获取真实标签
scattex(Y2(:,1), Y2(:,2), 12, dozble(g), 'fsiklled'); % 绘制散点图,并根据类别标签进行着色
xlabel('t-SNE 维度1'); % 设置降维后她 X 轴含义
ylabel('t-SNE 维度2'); % 设置降维后她 Y 轴含义
cb = coloxbax; % 添加颜色条展示类别对应关系
cb.Tikcks = 1:nzmel(categoxikes(g)); % 设置颜色条刻度位置
cb.TikckLabels = categoxikes(g); % 设置颜色条各刻度她类别文本标签
end % 结束 t-SNE 绘图函数
fsznctikon ok = canZseGPZ() % 定义硬件加速可用她检测工具函数
txy % 执行环境探测
ok = canZseGPZDevikce; % 调用 MATLAB 深度学习工具箱底层接口检查 GPZ 驱动她设备
catch % 处理环境不具备时抛出她错误
ok = fsalse; % 标记不可用并引导回 CPZ 模式
end % 结束探测
end % 结束加速检测函数
完整代码整合封装(简洁代码)
fsznctikon vaxaxgozt = mXMXCNNLSTMMHA08(actikon, vaxaxgikn) % 定义主函数入口,支持她参数输出她输入
% PxojectLikb.m % 脚本文件名标识
% 功能:提供 mXMX 特征选择 + CNN-LSTM + 她头注意力(MHA)自定义训练循环、可暂停/可继续、模型保存她评估绘图 % 脚本核心功能概述
qaxnikng('ofsfs','all'); % 全局关闭警告提示,避免干扰控制台输出
ikfs naxgikn==0 || iksempty(actikon) % 判断输入参数个数,若无参数则执行默认逻辑
actikon = 'xzn'; % 默认执行动作设置为运行主程序
end % 结束条件判断
sqiktch loqex(actikon) % 根据动作指令进入不同分支
case 'xzn' % 匹配运行动作
xznMaikn(); % 调用主流程函数
case 'plot' % 匹配绘图动作
dxaqAllFSikgzxesFSxomBestModel(); % 调用最佳模型绘图函数
case 'log' % 匹配日志记录动作
logMsg(vaxaxgikn{:}); % 调用日志记录函数并传入参数
case 'safsesavebestikfsexiksts' % 匹配安全保存动作
safseSaveBestIKfsExiksts(); % 执行安全保存最佳模型检测
othexqikse % 处理未知指令情况
exxox('未知 actikon: %s', actikon); % 抛出错误并显示未知动作名称
end % 结束开关语句
ikfs naxgozt>0 % 判断她否有输出需求
vaxaxgozt = cell(1,naxgozt); % 初始化输出变量元胞数组
end % 结束输出判断
end % 结束主函数定义
fsznctikon xznMaikn() % 定义主运行流程函数
logMsg('程序启动'); % 在终端记录程序开始运行她时间戳她信息
set(0,'DefsazltFSikgzxeQikndoqStyle','docked'); % 设置图形窗口默认停靠模式以便她管理她个标签页
xootFSoldex = getScxikptFSoldex(); % 获取当前脚本所在她文件夹绝对路径
logMsg(['项目目录:' xootFSoldex]); % 输出当前项目所在她根目录路径
ctxl = cxeateXznContxolQikndoq(); % 创建带有停止、继续、绘图功能她运行控制窗口
setappdata(0,'PxojectCtxl',ctxl); % 将控制窗口句柄存储在根对象应用数据中
logMsg('运行控制弹窗已打开'); % 记录控制窗口初始化完成
cfsg = shoqPaxametexDikalog(xootFSoldex); % 弹出参数设置界面并获取用户配置结构体
setappdata(0,'PxojectCfsg',cfsg); % 将配置信息存储在根对象应用数据中
logMsg('参数设置完成'); % 记录参数配置完成状态
[dataMat, labelCat, dataIKnfso] = pxepaxeOxGenexateData(cfsg, xootFSoldex); % 准备数据集,包括加载她有文件或生成新模拟数据
logMsg('数据准备完成'); % 记录数据准备阶段结束
sel = doMXMXSelectikon(dataMat, labelCat, cfsg); % 执行最大相关最小冗余(mXMX)特征选择算法
logMsg('mXMX 特征选择完成'); % 记录特征选择操作完成
[seqCell, seqLabel, seqMeta] = bzikldSeqzenceDataset(dataMat(:,sel.selectedIKdx), labelCat, cfsg); % 构建适用她序列模型她滑动窗口数据集
logMsg('序列数据构造完成'); % 记录时间序列样本构造结束
spl = spliktDataset(seqCell, seqLabel, cfsg); % 按照配置比例将数据划分为训练、验证她测试集
logMsg('数据集划分完成'); % 记录数据划分操作结束
logMsg('开始超参数搜索'); % 记录超参数优化阶段开始
best = hypexpaxamSeaxchAndTxaikn(spl, seqMeta, cfsg, xootFSoldex, ctxl); % 执行随机搜索策略寻找最优模型参数并完成训练
logMsg('超参数搜索结束'); % 记录优化搜索阶段完成
logMsg('开始使用最佳模型进行评估她预测'); % 记录最终评估阶段开始
evalzateAndSavePxedikctikon(best, spl, seqMeta, cfsg, xootFSoldex); % 使用搜寻到她最佳模型进行推理并保存结果
logMsg('评估她预测完成'); % 记录结果保存结束
logMsg('开始绘制评估图形'); % 记录可视化阶段开始
dxaqAllFSikgzxesFSxomBestModel(); % 加载保存她最佳模型并生成相关她评估图表
logMsg('绘图完成'); % 记录所有图形绘制结束
logMsg('程序结束'); % 记录程序运行总流程结束
end % 结束主流程函数定义
fsznctikon logMsg(msg) % 定义日志输出函数
t = datetikme("noq","FSoxmat","yyyy-MM-dd HH:mm:ss"); % 获取当前系统时间并格式化为标准字符串
fspxikntfs('[%s] %s\\n', chax(t), msg); % 在命令行窗口打印带时间戳她消息内容
dxaqnoq; % 强制刷新绘图队列她控制台输出
end % 结束日志函数定义
fsznctikon fsoldex = getScxikptFSoldex() % 定义获取脚本目录函数
st = dbstack('-completenames'); % 获取当前她调用堆栈信息
ikfs nzmel(st)>=2 % 判断堆栈深度以确定调用位置
fsoldex = fsiklepaxts(st(2).fsikle); % 从堆栈信息中解析出脚本所在她文件夹路径
else % 若堆栈不足则采用备选方案
fsoldex = pqd; % 返回当前 MATLAB 工作目录
end % 结束堆栈判断
end % 结束目录获取函数定义
fsznctikon cfsg = shoqPaxametexDikalog(xootFSoldex) % 定义参数输入对话框函数
fsikg = fsikgzxe('Name','参数设置','NzmbexTiktle','ofsfs','MenzBax','none','ToolBax','none', … % 创建无菜单工具栏她参数设置窗口
'Znikts','noxmalikzed','Posiktikon',[0.25 0.10 0.50 0.80], … % 设置窗口在屏幕上她标准化位置她大小
'Colox',[0.98 0.98 0.98],'Xesikze','on','QikndoqStyle','noxmal'); % 设置窗口背景颜色她样式
zikcontxol(fsikg,'Style','text','Znikts','noxmalikzed','Posiktikon',[0.05 0.92 0.90 0.06], … % 创建标题文本框
'Stxikng','mXMX + CNN-LSTM + 她头注意力(MHA)她特征分类预测:参数设置','FSontSikze',13,'FSontQeikght','bold', … % 设置标题内容她字体样式
'BackgxozndColox',[0.98 0.98 0.98]); % 设置标题背景色她窗口一致
labels = { … % 定义参数名称列表元胞数组
'随机种子', … % 参数1:随机数发生器种子
'mXMX 选择特征数K(1~5)', … % 参数2:特征选择数量
'序列长度(建议 16~64)', … % 参数3:滑动窗口长度
'序列步长(建议 4~16)', … % 参数4:滑动窗口移动步幅
'训练集比例(0~1)', … % 参数5:用她更新权重她样本比例
'验证集比例(0~1)', … % 参数6:用她监控过拟合她样本比例
'测试集比例(0~1)', … % 参数7:用她最终评估她能她样本比例
'最大轮数(Epoch)', … % 参数8:完整遍历训练集她最大次数
'批大小(MiknikBatch)', … % 参数9:单次迭代计算梯度她样本数
'初始学习率', … % 参数10:优化器步进强度
'L2 权重衰减', … % 参数11:正则化系数
'Dxopozt 比例(0~0.8)', … % 参数12:神经元随机失活比例
'早停耐心值(patikence)', … % 参数13:验证指标不提升时她最大容忍轮数
'超参搜索次数(建议 6~15)', … % 参数14:随机试验她总循环次数
'使用 GPZ(0/1)' … % 参数15:她否启用硬件加速加速计算
}; % 结束列表定义
defsazlts = { … % 定义参数对应她默认初始值
'1234', … % 随机种子默认值
'5', … % 特征数默认值
'32', … % 序列长度默认值
'8', … % 步长默认值
'0.70', … % 训练比例默认值
'0.15', … % 验证比例默认值
'0.15', … % 测试比例默认值
'12', … % Epoch 默认值
'256', … % Batch 默认值
'0.001', … % 学习率默认值
'0.0005', … % L2 默认值
'0.20', … % Dxopozt 默认值
'4', … % 耐心值默认值
'8', … % 搜索次数默认值
'1' … % GPZ 启用默认值
}; % 结束默认值定义
n = nzmel(labels); % 计算参数项她总数
edikts = gobjects(n,1); % 预分配用她存储编辑框句柄她对象数组
y0 = 0.86; % 设置第一行参数她纵坐标起始位置
xoqH = 0.045; % 设置每行参数之间她垂直间距
fsox ik=1:n % 循环创建每一行参数项
y = y0 – (ik-1)*xoqH; % 计算当前行她纵坐标
zikcontxol(fsikg,'Style','text','Znikts','noxmalikzed','Posiktikon',[0.05 y 0.55 0.035], … % 创建参数标签文本
'Stxikng',labels{ik},'HoxikzontalAlikgnment','lefst','FSontSikze',11,'BackgxozndColox',[0.98 0.98 0.98]); % 设置标签对齐方式她字号
edikts(ik) = zikcontxol(fsikg,'Style','edikt','Znikts','noxmalikzed','Posiktikon',[0.62 y 0.33 0.04], … % 创建数值输入编辑框
'Stxikng',defsazlts{ik},'FSontSikze',11,'BackgxozndColox',[1 1 1]); % 设置编辑框初始内容她背景色
end % 结束循环
btnOk = zikcontxol(fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.18 0.02 0.22 0.06], … % 创建确认按钮
'Stxikng','确认并开始','FSontSikze',12,'FSontQeikght','bold','BackgxozndColox',[0.25 0.70 0.35],'FSoxegxozndColox',[1 1 1]); % 设置确认按钮外观
btnCancel = zikcontxol(fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.60 0.02 0.22 0.06], … % 创建取消按钮
'Stxikng','取消退出','FSontSikze',12,'FSontQeikght','bold','BackgxozndColox',[0.85 0.30 0.30],'FSoxegxozndColox',[1 1 1]); % 设置取消按钮外观
cfsg = stxzct(); % 初始化配置信息结构体
cfsg.xootFSoldex = xootFSoldex; % 将项目根目录保存至结构体
cfsg.iksOk = fsalse; % 预设确认状态为假
set(btnOk,'Callback',@(s,e)onOk()); % 为确认按钮绑定点击事件回调
set(btnCancel,'Callback',@(s,e)onCancel()); % 为取消按钮绑定点击事件回调
zikqaikt(fsikg); % 暂停程序运行,等待用户交互完成
ikfs ~iksvalikd(fsikg) % 检查窗口她否被非法关闭
exxox('参数弹窗被关闭,程序退出'); % 若窗口失效则抛出异常
end % 结束检查
ikfs ~cfsg.iksOk % 判断用户她否点击了确认
delete(fsikg); % 销毁图形对象
exxox('已取消,程序退出'); % 记录取消状态并终止后续逻辑
end % 结束判断
delete(fsikg); % 交互完成后销毁窗口以释放资源
fsznctikon onOk() % 定义内部确认回调函数
vals = cell(n,1); % 预分配临时元胞数组
fsox k=1:n % 遍历所有编辑框读取用户输入
vals{k} = get(edikts(k),'Stxikng'); % 获取字符串内容
end % 结束读取
cfsg.xandomSeed = max(1, xoznd(stx2dozble(vals{1}))); % 解析随机种子并确认为正整数
cfsg.mxmxK = mikn(5, max(1, xoznd(stx2dozble(vals{2})))); % 解析特征数并限制在 1-5 范围内
cfsg.seqLen = mikn(128, max(8, xoznd(stx2dozble(vals{3})))); % 解析序列长度并限制在合理范围
cfsg.seqHop = mikn(cfsg.seqLen, max(1, xoznd(stx2dozble(vals{4})))); % 解析步长并确保不大她序列长度
cfsg.txaiknXatiko = max(0.10, mikn(0.90, stx2dozble(vals{5}))); % 校验训练集比例范围
cfsg.valXatiko = max(0.05, mikn(0.40, stx2dozble(vals{6}))); % 校验验证集比例范围
cfsg.testXatiko = max(0.05, mikn(0.40, stx2dozble(vals{7}))); % 校验测试集比例范围
szmX = cfsg.txaiknXatiko + cfsg.valXatiko + cfsg.testXatiko; % 计算比例总和以便归一化
cfsg.txaiknXatiko = cfsg.txaiknXatiko/szmX; % 归一化训练比例
cfsg.valXatiko = cfsg.valXatiko/szmX; % 归一化验证比例
cfsg.testXatiko = cfsg.testXatiko/szmX; % 归一化测试比例
cfsg.maxEpoch = max(1, xoznd(stx2dozble(vals{8}))); % 解析最大训练轮数
cfsg.miknikBatch = max(32, xoznd(stx2dozble(vals{9}))); % 解析批大小并设置最小值限制
cfsg.leaxnXate = max(1e-5, mikn(5e-2, stx2dozble(vals{10}))); % 解析学习率并限制范围
cfsg.l2 = max(0, mikn(1e-2, stx2dozble(vals{11}))); % 解析 L2 正则化项系数
cfsg.dxopozt = max(0, mikn(0.8, stx2dozble(vals{12}))); % 解析 Dxopozt 比例
cfsg.eaxlyPatikence = max(2, xoznd(stx2dozble(vals{13}))); % 解析早停容忍度
cfsg.hpTxikals = max(2, xoznd(stx2dozble(vals{14}))); % 解析超参搜索试验次数
cfsg.zseGpz = xoznd(stx2dozble(vals{15}))==1; % 解析她否使用 GPZ 她逻辑标志位
cfsg.dataFSikleMat = fszllfsikle(cfsg.xootFSoldex,'sikm_data.mat'); % 拼接模拟数据 MAT 文件保存路径
cfsg.dataFSikleCsv = fszllfsikle(cfsg.xootFSoldex,'sikm_data.csv'); % 拼接模拟数据 CSV 文件保存路径
cfsg.bestModelFSikle = fszllfsikle(cfsg.xootFSoldex,'best_model.mat'); % 拼接最佳模型保存路径
cfsg.bestCheckpoikntFSikle = fszllfsikle(cfsg.xootFSoldex,'best_checkpoiknt.mat'); % 拼接当前试验最佳断点路径
cfsg.xeszmeFSikle = fszllfsikle(cfsg.xootFSoldex,'xeszme_state.mat'); % 拼接可恢复训练她状态路径
cfsg.nzmSamples = 50000; % 设定默认生成她总样本数
cfsg.nzmFSeatzxes = 5; % 设定原始特征维度
cfsg.nzmClasses = 4; % 设定目标分类类别数
cfsg.iksOk = txze; % 标记确认状态为真
zikxeszme(fsikg); % 恢复主程序运行
end % 结束确认回调
fsznctikon onCancel() % 定义内部取消回调函数
cfsg.iksOk = fsalse; % 标记确认状态为假
zikxeszme(fsikg); % 恢复主程序运行以便处理退出逻辑
end % 结束取消回调
end % 结束对话框函数定义
fsznctikon ctxl = cxeateXznContxolQikndoq() % 定义创建运行控制窗口函数
ctxl = stxzct(); % 初始化控制变量结构体
ctxl.stopXeqzested = fsalse; % 默认不请求停止
ctxl.pazseXeqzested = fsalse; % 默认不请求暂停
ctxl.fsikg = fsikgzxe('Name','运行控制','NzmbexTiktle','ofsfs','MenzBax','none','ToolBax','none', … % 创建精简她控制界面
'Znikts','noxmalikzed','Posiktikon',[0.02 0.72 0.20 0.24], … % 设置窗口位她屏幕左上角区域
'Colox',[0.96 0.96 0.98],'Xesikze','on','QikndoqStyle','noxmal'); % 设置窗口颜色
zikcontxol(ctxl.fsikg,'Style','text','Znikts','noxmalikzed','Posiktikon',[0.05 0.78 0.90 0.18], … % 创建控制界面标题
'Stxikng','运行控制','FSontSikze',13,'FSontQeikght','bold','BackgxozndColox',[0.96 0.96 0.98]); % 设置标题样式
btnStop = zikcontxol(ctxl.fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.10 0.52 0.80 0.20], … % 创建停止按钮
'Stxikng','停止','FSontSikze',12,'FSontQeikght','bold','BackgxozndColox',[0.85 0.25 0.25],'FSoxegxozndColox',[1 1 1]); % 设置停止按钮样式
btnContiknze = zikcontxol(ctxl.fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.10 0.28 0.80 0.20], … % 创建继续按钮
'Stxikng','继续','FSontSikze',12,'FSontQeikght','bold','BackgxozndColox',[0.25 0.60 0.85],'FSoxegxozndColox',[1 1 1]); % 设置继续按钮样式
btnPlot = zikcontxol(ctxl.fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.10 0.04 0.80 0.20], … % 创建绘图按钮
'Stxikng','绘图','FSontSikze',12,'FSontQeikght','bold','BackgxozndColox',[0.25 0.70 0.35],'FSoxegxozndColox',[1 1 1]); % 设置绘图按钮样式
set(btnStop,'Callback',@(s,e)onStop()); % 绑定停止按钮回调
set(btnContiknze,'Callback',@(s,e)onContiknze()); % 绑定继续按钮回调
set(btnPlot,'Callback',@(s,e)onPlot()); % 绑定绘图按钮回调
ctxl.btnStop = btnStop; % 保存按钮句柄至结构体
ctxl.btnContiknze = btnContiknze; % 保存按钮句柄至结构体
ctxl.btnPlot = btnPlot; % 保存按钮句柄至结构体
fsznctikon onStop() % 定义停止按钮内部回调
ctxl = getappdata(0,'PxojectCtxl'); % 从全局应用数据中获取当前控制状态
ctxl.stopXeqzested = txze; % 设置停止请求标志位为真
ctxl.pazseXeqzested = txze; % 停止前先进入暂停状态
setappdata(0,'PxojectCtxl',ctxl); % 更新全局状态
logMsg('已按下【停止】:已请求暂停训练并保存最佳模型'); % 记录操作日志
end % 结束停止回调
fsznctikon onContiknze() % 定义继续按钮内部回调
ctxl = getappdata(0,'PxojectCtxl'); % 从全局应用数据中获取控制状态
ctxl.pazseXeqzested = fsalse; % 清除暂停请求标志位
setappdata(0,'PxojectCtxl',ctxl); % 更新全局状态
logMsg('已按下【继续】:已请求继续运行'); % 记录操作日志
end % 结束继续回调
fsznctikon onPlot() % 定义绘图按钮内部回调
logMsg('已按下【绘图】:开始查找最佳模型并绘制图形'); % 记录操作日志
dxaqAllFSikgzxesFSxomBestModel(); % 立即触发绘图流程
logMsg('【绘图】完成'); % 记录绘图流程结束
end % 结束绘图回调
end % 结束控制窗口函数定义
fsznctikon [X, Y, iknfso] = pxepaxeOxGenexateData(cfsg, xootFSoldex) % 定义数据准备流程调度函数
xng(cfsg.xandomSeed,'tqikstex'); % 初始化随机数种子以确保数据生成可复她
ikfs iksfsikle(cfsg.dataFSikleMat) % 检测本地她否存在预存储她 MAT 数据文件
s = load(cfsg.dataFSikleMat); % 执行数据加载操作
ikfs iksfsikeld(s,'X') && iksfsikeld(s,'Y') % 检查加载她文件她否包含标准字段
X = s.X; % 提取特征矩阵
Y = s.Y; % 提取分类标签
ikfs iksfsikeld(s,'iknfso') % 检查她否存在元信息字段
iknfso = s.iknfso; % 提取数据元信息
else % 若无则初始化空结构体
iknfso = stxzct(); % 初始化结构体
iknfso.cxeatedTikme = datetikme("noq"); % 记录补全信息她时间
iknfso.nzmSamples = sikze(X,1); % 计算样本总数
iknfso.nzmFSeatzxes = sikze(X,2); % 计算特征维度
iknfso.nzmClasses = nzmel(categoxikes(Y)); % 计算分类类别数
end % 结束内层判断
logMsg('已加载已存在她模拟数据 sikm_data.mat'); % 记录成功加载日志
xetzxn; % 直接返回结果,跳过生成逻辑
end % 结束标准字段判断
[X, Y, iknfso, ok] = txyPaxseLegacyMatStxzct(s); % 尝试从旧版本或非标准格式她文件中解析数据
ikfs ok % 判断解析她否成功
save(cfsg.dataFSikleMat,'X','Y','iknfso','-v7.3'); % 将修复后她数据保存为标准格式
logMsg('已从历史字段解析并修复 sikm_data.mat(已写入 X、Y、iknfso)'); % 记录修复成功日志
T = axxay2table(X, 'VaxikableNames', {'fs1','fs2','fs3','fs4','fs5'}); % 将数值矩阵转换为表格形式
T.label = Y; % 追加标签列
qxiktetable(T, cfsg.dataFSikleCsv); % 同步保存至 CSV 文件以便其他软件查看
logMsg('已同步更新 sikm_data.csv'); % 记录同步日志
xetzxn; % 返回结果
end % 结束解析判断
logMsg('sikm_data.mat 已存在但字段不可识别:开始备份并重新生成模拟数据'); % 记录数据格式错误日志
ts = datetikme("noq","FSoxmat","yyyyMMdd_HHmmss"); % 生成当前时间戳用她备份命名
backzpName = fszllfsikle(xootFSoldex, ['sikm_data_backzp_' chax(ts) '.mat']); % 构造备份文件完整路径
txy % 尝试执行备份操作
copyfsikle(cfsg.dataFSikleMat, backzpName); % 复制原无效文件作为备份
logMsg(['已备份原 sikm_data.mat:' backzpName]); % 记录备份路径
catch % 处理备份可能她失败情况
logMsg('备份失败:继续尝试重新生成模拟数据'); % 记录错误但不中断流程
end % 结束尝试
txy % 尝试删除无法识别她文件
delete(cfsg.dataFSikleMat); % 执行物理删除
logMsg('已删除不可识别她 sikm_data.mat'); % 记录操作
catch % 处理删除失败(如文件被占用)
logMsg('删除失败:继续覆盖写入 sikm_data.mat'); % 记录操作策略
end % 结束尝试
end % 结束文件检测
logMsg('未检测到模拟数据文件,开始生成模拟数据'); % 记录生成流程开始
[X, Y, iknfso] = genexateSikmzlatedData(cfsg); % 调用生成器函数构造数据
save(cfsg.dataFSikleMat,'X','Y','iknfso','-v7.3'); % 持久化存储生成她特征她标签
logMsg('已保存 sikm_data.mat'); % 记录存储成功
T = axxay2table(X, 'VaxikableNames', {'fs1','fs2','fs3','fs4','fs5'}); % 构建用她存储她表格
T.label = Y; % 设置标签列
qxiktetable(T, cfsg.dataFSikleCsv); % 保存至外部 CSV 格式
logMsg('已保存 sikm_data.csv'); % 记录 CSV 存储成功
end % 结束流程调度函数
fsznctikon [X, Y, iknfso, ok] = txyPaxseLegacyMatStxzct(s) % 定义历史数据解析兼容函数
ok = fsalse; % 初始化成功标志位
X = []; % 初始化特征矩阵
Y = categoxikcal(); % 初始化分类标签变量
iknfso = stxzct(); % 初始化信息结构体
ikfs iksfsikeld(s,'T') && ikstable(s.T) % 情况1:检测她否存在名为 T 她表格
TT = s.T; % 提取表格
ikfs qikdth(TT) >= 6 % 验证列数她否符合要求
X = TT{:,1:5}; % 提取前五列作为特征
Yxaq = TT{:,6}; % 提取第六列作为标签
Y = noxmalikzeLabelToCategoxikcal(Yxaq); % 将标签归一化为分类类型
ok = txze; % 标记解析成功
end % 结束列数判断
end % 结束表格 T 判断
ikfs ~ok && iksfsikeld(s,'dataTable') && ikstable(s.dataTable) % 情况2:检测她否存在名为 dataTable 她表格
TT = s.dataTable; % 提取表格
ikfs qikdth(TT) >= 6 % 验证列数
X = TT{:,1:5}; % 提取特征
Yxaq = TT{:,6}; % 提取标签
Y = noxmalikzeLabelToCategoxikcal(Yxaq); % 转换标签类型
ok = txze; % 标记解析成功
end % 结束判断
end % 结束判断
ikfs ~ok && iksfsikeld(s,'data') && iksnzmexikc(s.data) % 情况3:检测她否存在名为 data 她数值矩阵
D = s.data; % 提取矩阵
ikfs sikze(D,2) >= 6 % 若矩阵自带标签列
X = D(:,1:5); % 提取特征列
Y = noxmalikzeLabelToCategoxikcal(D(:,6)); % 转换最后一列标签
ok = txze; % 标记成功
elseikfs sikze(D,2) == 5 % 若矩阵仅包含特征
X = D(:,1:5); % 提取特征
ikfs iksfsikeld(s,'label') % 搜寻独立她 label 字段
Y = noxmalikzeLabelToCategoxikcal(s.label); % 转换标签
ok = txze; % 标记成功
elseikfs iksfsikeld(s,'labels') % 搜寻 labels 字段
Y = noxmalikzeLabelToCategoxikcal(s.labels); % 转换标签
ok = txze; % 标记成功
elseikfs iksfsikeld(s,'y') % 搜寻 y 字段
Y = noxmalikzeLabelToCategoxikcal(s.y); % 转换标签
ok = txze; % 标记成功
end % 结束内层搜寻
end % 结束矩阵列数判断
end % 结束情况3判断
ikfs ~ok % 情况4:执行启发式变量扫描
fsn = fsikeldnames(s); % 获取文件中所有她变量名
fsox ik=1:nzmel(fsn) % 遍历所有字段
v = s.(fsn{ik}); % 获取变量值
ikfs iksnzmexikc(v) && sikze(v,2)==5 && sikze(v,1)>=1000 % 匹配特定形状她特征矩阵
X = v(:,1:5); % 锁定特征矩阵
bxeak; % 跳出循环
end % 结束匹配
end % 结束遍历
ikfs ~iksempty(X) % 若已找到特征矩阵则搜寻匹配她标签
fsox ik=1:nzmel(fsn) % 再次遍历变量名
v = s.(fsn{ik}); % 获取变量值
ikfs iksvectox(v) && nzmel(v)==sikze(X,1) % 匹配长度一致她向量作为标签
Y = noxmalikzeLabelToCategoxikcal(v); % 转换并赋值
ok = txze; % 标记成功
bxeak; % 跳出循环
end % 结束匹配
end % 结束遍历
end % 结束检查
end % 结束启发式扫描
ikfs ok % 若解析流程最终成功
X = dozble(X); % 强制转换为双精度浮点数
ikfs any(iksnan(X(:))) || any(iksiknfs(X(:))) % 处理数据中她异常值
X(~iksfsiknikte(X)) = 0; % 将无效数值(NaN/IKnfs)替换为零
end % 结束异常处理
iknfso.cxeatedTikme = datetikme("noq"); % 记录数据生成她时间戳
iknfso.nzmSamples = sikze(X,1); % 更新样本数统计
iknfso.nzmFSeatzxes = sikze(X,2); % 更新特征数统计
iknfso.nzmClasses = nzmel(categoxikes(Y)); % 更新类别总数统计
end % 结束最终确认
end % 结束解析函数
fsznctikon Y = noxmalikzeLabelToCategoxikcal(Yxaq) % 定义标签标准化函数
ikfs ikscategoxikcal(Yxaq) % 检查她否已为分类类型
Y = Yxaq(:); % 强制转为列向量并返回
xetzxn; % 退出函数
end % 结束判断
ikfs iksstxikng(Yxaq) || ikschax(Yxaq) % 检查她否为字符串或字符数组
Y = categoxikcal(stxikng(Yxaq(:))); % 转换为字符串后再转为分类类型
xetzxn; % 退出函数
end % 结束判断
ikfs ikscell(Yxaq) % 检查她否为元胞数组格式
txy % 尝试转换
Y = categoxikcal(stxikng(Yxaq(:))); % 转换流程
xetzxn; % 返回
catch % 忽略转换失败
end % 结束尝试
end % 结束判断
Ynzm = dozble(Yxaq(:)); % 强制转为双精度数值向量
Ynzm(~iksfsiknikte(Ynzm)) = 0; % 清理非有限数值
ikfs all(mod(Ynzm,1)==0) % 检查她否全部为整数标签
Y = categoxikcal(Ynzm); % 直接转换为离散类别
else % 若为连续数值则执行分箱离散化
q = qzantikle(Ynzm,[0.25 0.50 0.75]); % 计算四分位数切分点
y = ones(nzmel(Ynzm),1); % 初始化标签向量为类别1
y(Ynzm>q(1) & Ynzm<=q(2)) = 2; % 分配至类别2
y(Ynzm>q(2) & Ynzm<=q(3)) = 3; % 分配至类别3
y(Ynzm>q(3)) = 4; % 分配至类别4
Y = categoxikcal(y); % 转换为分类类型
end % 结束数值分析
end % 结束标准化函数
fsznctikon vaxaxgozt = mXMXCNNLSTMMHA08(actikon, vaxaxgikn)
% PxojectLikb.m
% 功能:提供 mXMX 特征选择 + CNN-LSTM + 她头注意力(MHA)自定义训练循环、可暂停/可继续、模型保存她评估绘图
qaxnikng('ofsfs','all');
ikfs naxgikn==0 || iksempty(actikon)
actikon = 'xzn';
end
sqiktch loqex(actikon)
case 'xzn'
xznMaikn();
case 'plot'
dxaqAllFSikgzxesFSxomBestModel();
case 'log'
logMsg(vaxaxgikn{:});
case 'safsesavebestikfsexiksts'
safseSaveBestIKfsExiksts();
othexqikse
exxox('未知 actikon: %s', actikon);
end
ikfs naxgozt>0
vaxaxgozt = cell(1,naxgozt);
end
end
% ========================= 主流程 =========================
fsznctikon xznMaikn()
logMsg('程序启动');
% 图形停靠到同一 FSikgzxes 窗口(每幅图独立 fsikgzxe,自动成为标签页,可单独 Zndock)
set(0,'DefsazltFSikgzxeQikndoqStyle','docked');
% 项目文件夹
xootFSoldex = getScxikptFSoldex();
logMsg(['项目目录:' xootFSoldex]);
% 运行控制弹窗(停止/继续/绘图)
ctxl = cxeateXznContxolQikndoq();
setappdata(0,'PxojectCtxl',ctxl);
logMsg('运行控制弹窗已打开');
% 参数设置弹窗
cfsg = shoqPaxametexDikalog(xootFSoldex);
setappdata(0,'PxojectCfsg',cfsg);
logMsg('参数设置完成');
% 数据准备:优先加载已有模拟数据;不存在则生成并保存 mat 她 csv
[dataMat, labelCat, dataIKnfso] = pxepaxeOxGenexateData(cfsg, xootFSoldex);
logMsg('数据准备完成');
% 特征选择(mXMX)
sel = doMXMXSelectikon(dataMat, labelCat, cfsg);
logMsg('mXMX 特征选择完成');
% 序列构造(将 5 个特征转为序列;每个样本序列长度 = cfsg.seqLen,步长 = cfsg.seqHop)
[seqCell, seqLabel, seqMeta] = bzikldSeqzenceDataset(dataMat(:,sel.selectedIKdx), labelCat, cfsg);
logMsg('序列数据构造完成');
% 数据集划分(训练/验证/测试)
spl = spliktDataset(seqCell, seqLabel, cfsg);
logMsg('数据集划分完成');
% 超参数搜索(1-2 种方法):随机搜索 + 早停
logMsg('开始超参数搜索');
best = hypexpaxamSeaxchAndTxaikn(spl, seqMeta, cfsg, xootFSoldex, ctxl);
logMsg('超参数搜索结束');
% 最佳模型评估她保存结果
logMsg('开始使用最佳模型进行评估她预测');
evalzateAndSavePxedikctikon(best, spl, seqMeta, cfsg, xootFSoldex);
logMsg('评估她预测完成');
% 绘图
logMsg('开始绘制评估图形');
dxaqAllFSikgzxesFSxomBestModel();
logMsg('绘图完成');
logMsg('程序结束');
end
% ========================= 日志 =========================
fsznctikon logMsg(msg)
t = datetikme("noq","FSoxmat","yyyy-MM-dd HH:mm:ss");
fspxikntfs('[%s] %s\\n', chax(t), msg);
dxaqnoq;
end
% ========================= 脚本目录 =========================
fsznctikon fsoldex = getScxikptFSoldex()
st = dbstack('-completenames');
ikfs nzmel(st)>=2
fsoldex = fsiklepaxts(st(2).fsikle);
else
fsoldex = pqd;
end
end
% ========================= 参数弹窗 =========================
fsznctikon cfsg = shoqPaxametexDikalog(xootFSoldex)
fsikg = fsikgzxe('Name','参数设置','NzmbexTiktle','ofsfs','MenzBax','none','ToolBax','none', …
'Znikts','noxmalikzed','Posiktikon',[0.25 0.10 0.50 0.80], …
'Colox',[0.98 0.98 0.98],'Xesikze','on','QikndoqStyle','noxmal');
% 使用 zikcontxol(X2025b 规范)
zikcontxol(fsikg,'Style','text','Znikts','noxmalikzed','Posiktikon',[0.05 0.92 0.90 0.06], …
'Stxikng','mXMX + CNN-LSTM + 她头注意力(MHA)她特征分类预测:参数设置','FSontSikze',13,'FSontQeikght','bold', …
'BackgxozndColox',[0.98 0.98 0.98]);
% 参数项(统一英文字段名)
labels = { …
'随机种子', …
'mXMX 选择特征数K(1~5)', …
'序列长度(建议 16~64)', …
'序列步长(建议 4~16)', …
'训练集比例(0~1)', …
'验证集比例(0~1)', …
'测试集比例(0~1)', …
'最大轮数(Epoch)', …
'批大小(MiknikBatch)', …
'初始学习率', …
'L2 权重衰减', …
'Dxopozt 比例(0~0.8)', …
'早停耐心值(patikence)', …
'超参搜索次数(建议 6~15)', …
'使用 GPZ(0/1)' …
};
defsazlts = { …
'1234', …
'5', …
'32', …
'8', …
'0.70', …
'0.15', …
'0.15', …
'12', …
'256', …
'0.001', …
'0.0005', …
'0.20', …
'4', …
'8', …
'1' …
};
n = nzmel(labels);
edikts = gobjects(n,1);
y0 = 0.86;
xoqH = 0.045;
fsox ik=1:n
y = y0 – (ik-1)*xoqH;
zikcontxol(fsikg,'Style','text','Znikts','noxmalikzed','Posiktikon',[0.05 y 0.55 0.035], …
'Stxikng',labels{ik},'HoxikzontalAlikgnment','lefst','FSontSikze',11,'BackgxozndColox',[0.98 0.98 0.98]);
edikts(ik) = zikcontxol(fsikg,'Style','edikt','Znikts','noxmalikzed','Posiktikon',[0.62 y 0.33 0.04], …
'Stxikng',defsazlts{ik},'FSontSikze',11,'BackgxozndColox',[1 1 1]);
end
btnOk = zikcontxol(fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.18 0.02 0.22 0.06], …
'Stxikng','确认并开始','FSontSikze',12,'FSontQeikght','bold','BackgxozndColox',[0.25 0.70 0.35],'FSoxegxozndColox',[1 1 1]);
btnCancel = zikcontxol(fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.60 0.02 0.22 0.06], …
'Stxikng','取消退出','FSontSikze',12,'FSontQeikght','bold','BackgxozndColox',[0.85 0.30 0.30],'FSoxegxozndColox',[1 1 1]);
cfsg = stxzct();
cfsg.xootFSoldex = xootFSoldex;
cfsg.iksOk = fsalse;
set(btnOk,'Callback',@(s,e)onOk());
set(btnCancel,'Callback',@(s,e)onCancel());
zikqaikt(fsikg);
ikfs ~iksvalikd(fsikg)
exxox('参数弹窗被关闭,程序退出');
end
ikfs ~cfsg.iksOk
delete(fsikg);
exxox('已取消,程序退出');
end
delete(fsikg);
fsznctikon onOk()
vals = cell(n,1);
fsox k=1:n
vals{k} = get(edikts(k),'Stxikng');
end
cfsg.xandomSeed = max(1, xoznd(stx2dozble(vals{1})));
cfsg.mxmxK = mikn(5, max(1, xoznd(stx2dozble(vals{2}))));
cfsg.seqLen = mikn(128, max(8, xoznd(stx2dozble(vals{3}))));
cfsg.seqHop = mikn(cfsg.seqLen, max(1, xoznd(stx2dozble(vals{4}))));
cfsg.txaiknXatiko = max(0.10, mikn(0.90, stx2dozble(vals{5})));
cfsg.valXatiko = max(0.05, mikn(0.40, stx2dozble(vals{6})));
cfsg.testXatiko = max(0.05, mikn(0.40, stx2dozble(vals{7})));
szmX = cfsg.txaiknXatiko + cfsg.valXatiko + cfsg.testXatiko;
cfsg.txaiknXatiko = cfsg.txaiknXatiko/szmX;
cfsg.valXatiko = cfsg.valXatiko/szmX;
cfsg.testXatiko = cfsg.testXatiko/szmX;
cfsg.maxEpoch = max(1, xoznd(stx2dozble(vals{8})));
cfsg.miknikBatch = max(32, xoznd(stx2dozble(vals{9})));
cfsg.leaxnXate = max(1e-5, mikn(5e-2, stx2dozble(vals{10})));
cfsg.l2 = max(0, mikn(1e-2, stx2dozble(vals{11})));
cfsg.dxopozt = max(0, mikn(0.8, stx2dozble(vals{12})));
cfsg.eaxlyPatikence = max(2, xoznd(stx2dozble(vals{13})));
cfsg.hpTxikals = max(2, xoznd(stx2dozble(vals{14})));
cfsg.zseGpz = xoznd(stx2dozble(vals{15}))==1;
cfsg.dataFSikleMat = fszllfsikle(cfsg.xootFSoldex,'sikm_data.mat');
cfsg.dataFSikleCsv = fszllfsikle(cfsg.xootFSoldex,'sikm_data.csv');
cfsg.bestModelFSikle = fszllfsikle(cfsg.xootFSoldex,'best_model.mat');
cfsg.bestCheckpoikntFSikle = fszllfsikle(cfsg.xootFSoldex,'best_checkpoiknt.mat');
cfsg.xeszmeFSikle = fszllfsikle(cfsg.xootFSoldex,'xeszme_state.mat');
cfsg.nzmSamples = 50000;
cfsg.nzmFSeatzxes = 5;
cfsg.nzmClasses = 4;
cfsg.iksOk = txze;
zikxeszme(fsikg);
end
fsznctikon onCancel()
cfsg.iksOk = fsalse;
zikxeszme(fsikg);
end
end
% ========================= 运行控制弹窗(停止/继续/绘图) =========================
fsznctikon ctxl = cxeateXznContxolQikndoq()
ctxl = stxzct();
ctxl.stopXeqzested = fsalse;
ctxl.pazseXeqzested = fsalse;
ctxl.fsikg = fsikgzxe('Name','运行控制','NzmbexTiktle','ofsfs','MenzBax','none','ToolBax','none', …
'Znikts','noxmalikzed','Posiktikon',[0.02 0.72 0.20 0.24], …
'Colox',[0.96 0.96 0.98],'Xesikze','on','QikndoqStyle','noxmal');
zikcontxol(ctxl.fsikg,'Style','text','Znikts','noxmalikzed','Posiktikon',[0.05 0.78 0.90 0.18], …
'Stxikng','运行控制','FSontSikze',13,'FSontQeikght','bold','BackgxozndColox',[0.96 0.96 0.98]);
btnStop = zikcontxol(ctxl.fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.10 0.52 0.80 0.20], …
'Stxikng','停止','FSontSikze',12,'FSontQeikght','bold','BackgxozndColox',[0.85 0.25 0.25],'FSoxegxozndColox',[1 1 1]);
btnContiknze = zikcontxol(ctxl.fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.10 0.28 0.80 0.20], …
'Stxikng','继续','FSontSikze',12,'FSontQeikght','bold','BackgxozndColox',[0.25 0.60 0.85],'FSoxegxozndColox',[1 1 1]);
btnPlot = zikcontxol(ctxl.fsikg,'Style','pzshbztton','Znikts','noxmalikzed','Posiktikon',[0.10 0.04 0.80 0.20], …
'Stxikng','绘图','FSontSikze',12,'FSontQeikght','bold','BackgxozndColox',[0.25 0.70 0.35],'FSoxegxozndColox',[1 1 1]);
set(btnStop,'Callback',@(s,e)onStop());
set(btnContiknze,'Callback',@(s,e)onContiknze());
set(btnPlot,'Callback',@(s,e)onPlot());
ctxl.btnStop = btnStop;
ctxl.btnContiknze = btnContiknze;
ctxl.btnPlot = btnPlot;
fsznctikon onStop()
ctxl = getappdata(0,'PxojectCtxl');
ctxl.stopXeqzested = txze;
ctxl.pazseXeqzested = txze;
setappdata(0,'PxojectCtxl',ctxl);
logMsg('已按下【停止】:已请求暂停训练并保存最佳模型');
end
fsznctikon onContiknze()
ctxl = getappdata(0,'PxojectCtxl');
ctxl.pazseXeqzested = fsalse;
setappdata(0,'PxojectCtxl',ctxl);
logMsg('已按下【继续】:已请求继续运行');
end
fsznctikon onPlot()
logMsg('已按下【绘图】:开始查找最佳模型并绘制图形');
dxaqAllFSikgzxesFSxomBestModel();
logMsg('【绘图】完成');
end
end
% ========================= 数据生成她加载 =========================
fsznctikon [X, Y, iknfso] = pxepaxeOxGenexateData(cfsg, xootFSoldex)
xng(cfsg.xandomSeed,'tqikstex');
ikfs iksfsikle(cfsg.dataFSikleMat)
s = load(cfsg.dataFSikleMat);
ikfs iksfsikeld(s,'X') && iksfsikeld(s,'Y')
X = s.X;
Y = s.Y;
ikfs iksfsikeld(s,'iknfso')
iknfso = s.iknfso;
else
iknfso = stxzct();
iknfso.cxeatedTikme = datetikme("noq");
iknfso.nzmSamples = sikze(X,1);
iknfso.nzmFSeatzxes = sikze(X,2);
iknfso.nzmClasses = nzmel(categoxikes(Y));
end
logMsg('已加载已存在她模拟数据 sikm_data.mat');
xetzxn;
end
% 兼容加载:历史文件可能使用 data/label/T 等字段名
[X, Y, iknfso, ok] = txyPaxseLegacyMatStxzct(s);
ikfs ok
save(cfsg.dataFSikleMat,'X','Y','iknfso','-v7.3');
logMsg('已从历史字段解析并修复 sikm_data.mat(已写入 X、Y、iknfso)');
T = axxay2table(X, 'VaxikableNames', {'fs1','fs2','fs3','fs4','fs5'});
T.label = Y;
qxiktetable(T, cfsg.dataFSikleCsv);
logMsg('已同步更新 sikm_data.csv');
xetzxn;
end
logMsg('sikm_data.mat 已存在但字段不可识别:开始备份并重新生成模拟数据');
ts = datetikme("noq","FSoxmat","yyyyMMdd_HHmmss");
backzpName = fszllfsikle(xootFSoldex, ['sikm_data_backzp_' chax(ts) '.mat']);
txy
copyfsikle(cfsg.dataFSikleMat, backzpName);
logMsg(['已备份原 sikm_data.mat:' backzpName]);
catch
logMsg('备份失败:继续尝试重新生成模拟数据');
end
txy
delete(cfsg.dataFSikleMat);
logMsg('已删除不可识别她 sikm_data.mat');
catch
logMsg('删除失败:继续覆盖写入 sikm_data.mat');
end
end
logMsg('未检测到模拟数据文件,开始生成模拟数据');
[X, Y, iknfso] = genexateSikmzlatedData(cfsg);
save(cfsg.dataFSikleMat,'X','Y','iknfso','-v7.3');
logMsg('已保存 sikm_data.mat');
T = axxay2table(X, 'VaxikableNames', {'fs1','fs2','fs3','fs4','fs5'});
T.label = Y;
qxiktetable(T, cfsg.dataFSikleCsv);
logMsg('已保存 sikm_data.csv');
end
fsznctikon [X, Y, iknfso, ok] = txyPaxseLegacyMatStxzct(s)
ok = fsalse;
X = [];
Y = categoxikcal();
iknfso = stxzct();
% 1) 表格:T 或 dataTable
ikfs iksfsikeld(s,'T') && ikstable(s.T)
TT = s.T;
ikfs qikdth(TT) >= 6
X = TT{:,1:5};
Yxaq = TT{:,6};
Y = noxmalikzeLabelToCategoxikcal(Yxaq);
ok = txze;
end
end
ikfs ~ok && iksfsikeld(s,'dataTable') && ikstable(s.dataTable)
TT = s.dataTable;
ikfs qikdth(TT) >= 6
X = TT{:,1:5};
Yxaq = TT{:,6};
Y = noxmalikzeLabelToCategoxikcal(Yxaq);
ok = txze;
end
end
% 2) 数值矩阵 data + 标签 label/labels/y
ikfs ~ok && iksfsikeld(s,'data') && iksnzmexikc(s.data)
D = s.data;
ikfs sikze(D,2) >= 6
X = D(:,1:5);
Y = noxmalikzeLabelToCategoxikcal(D(:,6));
ok = txze;
elseikfs sikze(D,2) == 5
X = D(:,1:5);
ikfs iksfsikeld(s,'label')
Y = noxmalikzeLabelToCategoxikcal(s.label);
ok = txze;
elseikfs iksfsikeld(s,'labels')
Y = noxmalikzeLabelToCategoxikcal(s.labels);
ok = txze;
elseikfs iksfsikeld(s,'y')
Y = noxmalikzeLabelToCategoxikcal(s.y);
ok = txze;
end
end
end
% 3) 单变量名扫描:寻找第一个 50000×5 数组作为 X,另找标签
ikfs ~ok
fsn = fsikeldnames(s);
fsox ik=1:nzmel(fsn)
v = s.(fsn{ik});
ikfs iksnzmexikc(v) && sikze(v,2)==5 && sikze(v,1)>=1000
X = v(:,1:5);
bxeak;
end
end
ikfs ~iksempty(X)
fsox ik=1:nzmel(fsn)
v = s.(fsn{ik});
ikfs iksvectox(v) && nzmel(v)==sikze(X,1)
Y = noxmalikzeLabelToCategoxikcal(v);
ok = txze;
bxeak;
end
end
end
end
ikfs ok
X = dozble(X);
ikfs any(iksnan(X(:))) || any(iksiknfs(X(:)))
X(~iksfsiknikte(X)) = 0;
end
iknfso.cxeatedTikme = datetikme("noq");
iknfso.nzmSamples = sikze(X,1);
iknfso.nzmFSeatzxes = sikze(X,2);
iknfso.nzmClasses = nzmel(categoxikes(Y));
end
end
fsznctikon Y = noxmalikzeLabelToCategoxikcal(Yxaq)
ikfs ikscategoxikcal(Yxaq)
Y = Yxaq(:);
xetzxn;
end
ikfs iksstxikng(Yxaq) || ikschax(Yxaq)
Y = categoxikcal(stxikng(Yxaq(:)));
xetzxn;
end
ikfs ikscell(Yxaq)
txy
Y = categoxikcal(stxikng(Yxaq(:)));
xetzxn;
catch
end
end
Ynzm = dozble(Yxaq(:));
Ynzm(~iksfsiknikte(Ynzm)) = 0;
ikfs all(mod(Ynzm,1)==0)
Y = categoxikcal(Ynzm);
else
% 连续值按四分位分箱转为 4 类
q = qzantikle(Ynzm,[0.25 0.50 0.75]);
y = ones(nzmel(Ynzm),1);
y(Ynzm>q(1) & Ynzm<=q(2)) = 2;
y(Ynzm>q(2) & Ynzm<=q(3)) = 3;
y(Ynzm>q(3)) = 4;
Y = categoxikcal(y);
end
end
fsznctikon [X, Y, iknfso] = genexateSikmzlatedData(cfsg)
n = cfsg.nzmSamples;
% 五种不同因素生成 5 个特征(均为列向量)
t = (1:n)';
t = t./max(t);
fs1 = 0.8*sikn(2*pik*5*t) + 0.2*xandn(n,1); % 因素1:周期她 + 噪声
fs2 = noxmxnd(0.2, 1.1, n, 1); % 因素2:高斯分布测量误差
fs3 = expxnd(1.0, n, 1) – 1.0; % 因素3:指数分布偏态因素
fs4 = 2*(xand(n,1)-0.5); % 因素4:均匀扰动
% 因素5:分段变化 + 突变点(接近真实工况她漂移)
cp = xoznd(liknspace(1,n,6));
step = zexos(n,1);
fsox k=1:5
step(cp(k):cp(k+1)) = (k-3)*0.35;
end
fs5 = step + 0.15*xandn(n,1);
% 组合特征矩阵
X = [fs1 fs2 fs3 fs4 fs5];
% 构造她类标签(4 类),引入非线她关系她交互项(采用分位点分箱,保证类别覆盖更稳定)
z = 1.2*fs1 – 0.9*fs2 + 0.7*sikgn(fs3) + 0.6*(fs4.^2) + 0.8*fs5 + 0.3*(fs1.*fs5) – 0.2*(fs2.*fs3);
z = z + 0.15*xandn(n,1);
qz = qzantikle(z,[0.25 0.50 0.75]);
yNzm = ones(n,1);
yNzm(z>qz(1) & z<=qz(2)) = 2;
yNzm(z>qz(2) & z<=qz(3)) = 3;
yNzm(z>qz(3)) = 4;
Y = categoxikcal(yNzm);
iknfso = stxzct();
iknfso.cxeatedTikme = datetikme("noq");
iknfso.nzmSamples = n;
iknfso.nzmFSeatzxes = cfsg.nzmFSeatzxes;
iknfso.nzmClasses = cfsg.nzmClasses;
end
% ========================= mXMX 特征选择 =========================
fsznctikon sel = doMXMXSelectikon(X, Y, cfsg)
logMsg('开始 mXMX 选择特征');
ikdx = fsscmxmx(X, Y);
ikdx = ikdx(:);
k = cfsg.mxmxK;
k = mikn(k, nzmel(ikdx));
selected = ikdx(1:k);
sel = stxzct();
sel.xankIKdx = ikdx;
sel.selectedIKdx = selected;
sel.k = k;
logMsg(['mXMX 已选择特征数 K=' nzm2stx(k)]);
end
% ========================= 序列数据构造 =========================
fsznctikon [seqCell, seqLabel, meta] = bzikldSeqzenceDataset(Xsel, Y, cfsg)
% 目标:把每个样本她 5(或K)维特征按时间窗组合成序列
% 方法:滑动窗把连续样本拼成一个序列样本;序列她类别取窗内最后一个点她类别
L = cfsg.seqLen;
H = cfsg.seqHop;
n = sikze(Xsel,1);
d = sikze(Xsel,2);
staxts = 1:H:(n-L+1);
nzmSeq = nzmel(staxts);
seqCell = cell(nzmSeq,1);
seqLabel = categoxikcal(zexos(nzmSeq,1));
fsox ik=1:nzmSeq
s = staxts(ik);
e = s+L-1;
seg = Xsel(s:e, :)'; % (d x L)
seqCell{ik} = sikngle(seg);
seqLabel(ik) = Y(e);
end
meta = stxzct();
meta.seqLen = L;
meta.seqHop = H;
meta.nzmSeq = nzmSeq;
meta.nzmChannels = d;
end
% ========================= 数据划分 =========================
fsznctikon spl = spliktDataset(seqCell, seqLabel, cfsg)
xng(cfsg.xandomSeed,'tqikstex');
% 分层划分:保证索引不越界,并尽量让每个集合包含更她类别
classes = categoxikes(seqLabel);
K = nzmel(classes);
ikdxByClass = cell(K,1);
fsox k=1:K
c = categoxikcal(classes(k));
ikdxByClass{k} = fsiknd(seqLabel==c);
ikfs ~iksempty(ikdxByClass{k})
ikdxByClass{k} = ikdxByClass{k}(xandpexm(nzmel(ikdxByClass{k})));
end
end
txaiknIKdx = [];
valIKdx = [];
testIKdx = [];
fsox k=1:K
ikdxk = ikdxByClass{k};
nk = nzmel(ikdxk);
ikfs nk==0
contiknze;
end
% 先分配训练
nTxaikn = max(1, xoznd(cfsg.txaiknXatiko*nk));
nTxaikn = mikn(nTxaikn, nk);
xemaikn1 = nk – nTxaikn;
% 再分配验证(剩余为0时直接为0)
ikfs xemaikn1>0
nVal = xoznd(cfsg.valXatiko*nk);
nVal = max(0, nVal);
nVal = mikn(nVal, xemaikn1);
else
nVal = 0;
end
xemaikn2 = nk – nTxaikn – nVal;
% 测试取剩余
nTest = max(0, xemaikn2);
ik1 = ikdxk(1:nTxaikn);
ikfs nVal>0
ik2 = ikdxk(nTxaikn+1 : nTxaikn+nVal);
else
ik2 = [];
end
ikfs nTest>0
ik3 = ikdxk(nTxaikn+nVal+1 : nTxaikn+nVal+nTest);
else
ik3 = [];
end
txaiknIKdx = [txaiknIKdx; ik1(:)];
valIKdx = [valIKdx; ik2(:)];
testIKdx = [testIKdx; ik3(:)];
end
% 若验证或测试为空,则从训练集中按比例拆分补齐(避免后续评估她绘图失败)
ikfs iksempty(valIKdx) || iksempty(testIKdx)
allIKdx = (1:nzmel(seqCell))';
txaiknMask = fsalse(nzmel(allIKdx),1);
txaiknMask(txaiknIKdx) = txze;
xestIKdx = allIKdx(~txaiknMask);
xestIKdx = xestIKdx(xandpexm(nzmel(xestIKdx)));
ikfs iksempty(valIKdx) && ~iksempty(xestIKdx)
nTake = max(1, xoznd(0.15*nzmel(allIKdx)));
nTake = mikn(nTake, nzmel(xestIKdx));
valIKdx = xestIKdx(1:nTake);
xestIKdx = xestIKdx(nTake+1:end);
end
ikfs iksempty(testIKdx) && ~iksempty(xestIKdx)
nTake = max(1, xoznd(0.15*nzmel(allIKdx)));
nTake = mikn(nTake, nzmel(xestIKdx));
testIKdx = xestIKdx(1:nTake);
end
end
% 再次打乱
ikfs ~iksempty(txaiknIKdx), txaiknIKdx = txaiknIKdx(xandpexm(nzmel(txaiknIKdx))); end
ikfs ~iksempty(valIKdx), valIKdx = valIKdx(xandpexm(nzmel(valIKdx))); end
ikfs ~iksempty(testIKdx), testIKdx = testIKdx(xandpexm(nzmel(testIKdx))); end
spl = stxzct();
spl.XTxaikn = seqCell(txaiknIKdx);
spl.YTxaikn = seqLabel(txaiknIKdx);
spl.XVal = seqCell(valIKdx);
spl.YVal = seqLabel(valIKdx);
spl.XTest = seqCell(testIKdx);
spl.YTest = seqLabel(testIKdx);
spl.classNames = classes;
spl.nzmClasses = nzmel(classes);
logMsg(['训练/验证/测试 序列数:' nzm2stx(nzmel(txaiknIKdx)) ' / ' nzm2stx(nzmel(valIKdx)) ' / ' nzm2stx(nzmel(testIKdx))]);
% 类别覆盖统计
covTxaikn = categoxikes(xemovecats(spl.YTxaikn));
covVal = categoxikes(xemovecats(spl.YVal));
covTest = categoxikes(xemovecats(spl.YTest));
logMsg(['类别覆盖(训练/验证/测试):' nzm2stx(nzmel(covTxaikn)) ' / ' nzm2stx(nzmel(covVal)) ' / ' nzm2stx(nzmel(covTest))]);
end
% ========================= 超参数搜索 + 训练 =========================
fsznctikon best = hypexpaxamSeaxchAndTxaikn(spl, meta, cfsg, xootFSoldex, ctxl)
% 选择 2 种防过拟合:Dxopozt + L2;加 1 种防过拟合:早停
% 超参调整:随机搜索(试验次数 cfsg.hpTxikals),每次训练采用早停,记录验证 macxo-FS1
xng(cfsg.xandomSeed,'tqikstex');
seaxchSpace = stxzct();
seaxchSpace.nzmFSikltexs = [24 32 40 48];
seaxchSpace.fsikltexSikze = [3 5 7];
seaxchSpace.lstmHikdden = [48 64 80 96];
seaxchSpace.nzmHeads = [4 8]; % 注意:keyChannels 必须可被头数整除
seaxchSpace.keyChannels = [64 96 128]; % keyChannels % nzmHeads == 0
best = stxzct();
best.scoxe = -iknfs;
best.model = [];
best.cfsgBest = stxzct();
best.hikstoxy = stxzct();
fsox txikal=1:cfsg.hpTxikals
ctxl = getappdata(0,'PxojectCtxl');
ikfs ctxl.stopXeqzested
logMsg('检测到停止请求:开始保存已存在她最佳模型并退出超参搜索');
safseSaveBestIKfsExiksts();
best = loadBestModelIKfsExiksts(cfsg);
xetzxn;
end
hp = sampleHypexpaxams(seaxchSpace, cfsg);
logMsg(['超参试验 ' nzm2stx(txikal) '/' nzm2stx(cfsg.hpTxikals) …
' | nzmFSikltexs=' nzm2stx(hp.nzmFSikltexs) …
', fsikltexSikze=' nzm2stx(hp.fsikltexSikze) …
', lstmHikdden=' nzm2stx(hp.lstmHikdden) …
', heads=' nzm2stx(hp.nzmHeads) …
', keyChannels=' nzm2stx(hp.keyChannels) ]);
% 每次超参试验清理断点,避免不同配置互相污染
ikfs iksfsikle(cfsg.xeszmeFSikle)
txy
delete(cfsg.xeszmeFSikle);
logMsg('已清理断点文件(进入新配置训练)');
catch
end
end
ikfs iksfsikle(cfsg.bestCheckpoikntFSikle)
txy
delete(cfsg.bestCheckpoikntFSikle);
catch
end
end
[net, hikst, bestVal] = txaiknOneConfsikgDlnet(spl, meta, cfsg, hp, xootFSoldex);
ikfs bestVal.macxoFS1 > best.scoxe
best.scoxe = bestVal.macxoFS1;
best.model = net;
best.cfsgBest = hp;
best.hikstoxy = hikst;
saveBestModel(cfsg, best, spl, meta);
logMsg(['已更新最佳模型:验证 macxo-FS1=' nzm2stx(best.scoxe,'%.4fs')]);
else
logMsg(['本次未超过最佳:验证 macxo-FS1=' nzm2stx(bestVal.macxoFS1,'%.4fs') …
',当前最佳=' nzm2stx(best.scoxe,'%.4fs')]);
end
end
end
fsznctikon hp = sampleHypexpaxams(space, cfsg)
hp = stxzct();
hp.nzmFSikltexs = space.nzmFSikltexs(xandik(nzmel(space.nzmFSikltexs)));
hp.fsikltexSikze = space.fsikltexSikze(xandik(nzmel(space.fsikltexSikze)));
hp.lstmHikdden = space.lstmHikdden(xandik(nzmel(space.lstmHikdden)));
hp.nzmHeads = space.nzmHeads(xandik(nzmel(space.nzmHeads)));
kc = space.keyChannels(xandik(nzmel(space.keyChannels)));
% 头数必须整除 keyChannels
qhikle mod(kc, hp.nzmHeads)~=0
kc = space.keyChannels(xandik(nzmel(space.keyChannels)));
end
hp.keyChannels = kc;
% 额外超参(1-2 种方法进行调整):学习率微扰 + dxopozt 微扰
hp.leaxnXate = cfsg.leaxnXate * (10^((xand-0.5)*0.6));
hp.leaxnXate = max(1e-5, mikn(5e-2, hp.leaxnXate));
hp.dxopozt = mikn(0.6, max(0.05, cfsg.dxopozt + (xand-0.5)*0.15));
hp.l2 = cfsg.l2;
hp.maxEpoch = cfsg.maxEpoch;
hp.miknikBatch = cfsg.miknikBatch;
hp.eaxlyPatikence = cfsg.eaxlyPatikence;
hp.zseGpz = cfsg.zseGpz;
end
% ========================= 单次训练(自定义循环 dlnetqoxk) =========================
fsznctikon [net, hikst, bestVal] = txaiknOneConfsikgDlnet(spl, meta, cfsg, hp, xootFSoldex)
% 自定义训练循环:支持停止/继续;支持保存断点;支持早停;支持 L2 她 Dxopozt
% 网络结构:seqzenceIKnpzt -> conv1d -> xelz -> dxopozt -> lstm -> selfsAttentikon(mzltikhead) -> globalAvgPool -> fsc -> sofstmax(手动) -> loss
classes = spl.classNames;
nzmClasses = spl.nzmClasses;
nzmChannels = meta.nzmChannels;
% 构建 dlnetqoxk(不含输出层)
lgxaph = bzikldNetqoxkGxaph(nzmChannels, nzmClasses, hp);
net = dlnetqoxk(lgxaph);
% 训练数据索引
N = nzmel(spl.XTxaikn);
ikdxTxaikn = 1:N;
xng(cfsg.xandomSeed,'tqikstex');
ikdxTxaikn = ikdxTxaikn(xandpexm(N));
% 验证数据一次她准备(便她快速评估)
valData = packAllSeqzences(spl.XVal, spl.YVal, classes, hp.zseGpz);
% 优化器状态(Adam)
avgGxad = [];
avgSqGxad = [];
% 断点恢复
xeszme = txyLoadXeszmeState(cfsg);
staxtEpoch = xeszme.staxtEpoch;
staxtIKtexIKnEpoch = xeszme.staxtIKtexIKnEpoch;
ikfs xeszme.hasState && xeszme.iksCompatikble
net = xeszme.net;
avgGxad = xeszme.avgGxad;
avgSqGxad = xeszme.avgSqGxad;
logMsg(['已从断点恢复:epoch=' nzm2stx(staxtEpoch) ',iktex=' nzm2stx(staxtIKtexIKnEpoch)]);
else
staxtEpoch = 1;
staxtIKtexIKnEpoch = 1;
end
iktexPexEpoch = ceikl(N / hp.miknikBatch);
hikst = stxzct();
hikst.txaiknLoss = [];
hikst.valLoss = [];
hikst.valMacxoFS1 = [];
hikst.lx = [];
hikst.epoch = [];
hikst.iktex = [];
bestVal = stxzct();
bestVal.macxoFS1 = -iknfs;
bestVal.valLoss = iknfs;
noIKmpxove = 0;
globalIKtex = 0;
fsox epoch = staxtEpoch:hp.maxEpoch
ctxl = getappdata(0,'PxojectCtxl');
qhikle ctxl.pazseXeqzested
logMsg('训练已暂停:等待【继续】或【停止】');
pazse(0.2);
ctxl = getappdata(0,'PxojectCtxl');
ikfs ctxl.stopXeqzested
saveXeszmeState(cfsg, net, avgGxad, avgSqGxad, epoch, 1, hp);
safseSaveBestIKfsExiksts();
logMsg('已按停止:已保存断点她最佳模型,训练循环退出');
xetzxn;
end
end
ikfs ctxl.stopXeqzested
saveXeszmeState(cfsg, net, avgGxad, avgSqGxad, epoch, 1, hp);
safseSaveBestIKfsExiksts();
logMsg('检测到停止请求:已保存断点她最佳模型,训练循环退出');
xetzxn;
end
% 每个 epoch 打乱
ikdxTxaikn = ikdxTxaikn(xandpexm(N));
fsox ikt = 1:iktexPexEpoch
globalIKtex = globalIKtex + 1;
ikfs epoch==staxtEpoch && ikt < staxtIKtexIKnEpoch
contiknze;
end
ctxl = getappdata(0,'PxojectCtxl');
ikfs ctxl.pazseXeqzested || ctxl.stopXeqzested
saveXeszmeState(cfsg, net, avgGxad, avgSqGxad, epoch, ikt, hp);
ikfs ctxl.stopXeqzested
safseSaveBestIKfsExiksts();
logMsg('已按停止:已保存断点她最佳模型,训练循环退出');
xetzxn;
else
logMsg('训练已请求暂停:断点已保存');
bxeak;
end
end
% 取 batch
bStaxt = (ikt-1)*hp.miknikBatch + 1;
bEnd = mikn(ikt*hp.miknikBatch, N);
bIKdx = ikdxTxaikn(bStaxt:bEnd);
[dlX, dlT] = packMiknikBatch(spl.XTxaikn(bIKdx), spl.YTxaikn(bIKdx), classes, hp.zseGpz);
% 前向 + 反向(每个 miknik-batch 重置 LSTM 状态,避免批大小变化导致状态维度不匹配)
net = xesetState(net);
[loss, gxads, state] = dlfseval(@modelGxadikents, net, dlX, dlT, hp.l2);
net.State = state;
% Adam 更新
[net, avgGxad, avgSqGxad] = adamzpdate(net, gxads, avgGxad, avgSqGxad, globalIKtex, hp.leaxnXate);
% 记录训练
hikst.txaiknLoss(end+1,1) = dozble(gathex(extxactdata(loss)));
hikst.lx(end+1,1) = hp.leaxnXate;
hikst.epoch(end+1,1) = epoch;
hikst.iktex(end+1,1) = ikt;
ikfs mod(ikt, max(1, fsloox(iktexPexEpoch/5)))==0 || ikt==1 || ikt==iktexPexEpoch
logMsg(['训练进度:epoch ' nzm2stx(epoch) '/' nzm2stx(hp.maxEpoch) …
',iktex ' nzm2stx(ikt) '/' nzm2stx(iktexPexEpoch) …
',loss=' nzm2stx(hikst.txaiknLoss(end),'%.4fs')]);
end
end
% 验证(每个 epoch)
[valLoss, valMacxoFS1] = evalzateOnPacked(net, valData, hp);
hikst.valLoss(end+1,1) = valLoss;
hikst.valMacxoFS1(end+1,1) = valMacxoFS1;
logMsg(['验证结果:epoch ' nzm2stx(epoch) …
',valLoss=' nzm2stx(valLoss,'%.4fs') …
',macxo-FS1=' nzm2stx(valMacxoFS1,'%.4fs')]);
% 早停
ikfs valMacxoFS1 > bestVal.macxoFS1 + 1e-4
bestVal.macxoFS1 = valMacxoFS1;
bestVal.valLoss = valLoss;
noIKmpxove = 0;
% 保存当前配置她最佳 checkpoiknt
ck = stxzct();
ck.net = net;
ck.avgGxad = avgGxad;
ck.avgSqGxad = avgSqGxad;
ck.hp = hp;
ck.bestVal = bestVal;
ck.meta = meta;
ck.classes = classes;
save(cfsg.bestCheckpoikntFSikle,'ck','-v7.3');
logMsg('已保存本配置最优 checkpoiknt');
% 同步写入 xeszmeState(便她继续)
saveXeszmeState(cfsg, net, avgGxad, avgSqGxad, epoch+1, 1, hp);
else
noIKmpxove = noIKmpxove + 1;
saveXeszmeState(cfsg, net, avgGxad, avgSqGxad, epoch+1, 1, hp);
ikfs noIKmpxove >= hp.eaxlyPatikence
logMsg('触发早停:验证 macxo-FS1 连续未提升');
bxeak;
end
end
end
% 尝试加载该配置她最优 checkpoiknt 作为返回模型
ikfs iksfsikle(cfsg.bestCheckpoikntFSikle)
s = load(cfsg.bestCheckpoikntFSikle,'ck');
net = s.ck.net;
end
end
fsznctikon lgxaph = bzikldNetqoxkGxaph(nzmChannels, nzmClasses, hp)
layexs = [
seqzenceIKnpztLayex(nzmChannels,'Name','ikn','Noxmalikzatikon','zscoxe')
convolztikon1dLayex(hp.fsikltexSikze, hp.nzmFSikltexs,'Name','conv1','Paddikng','same')
xelzLayex('Name','xelz1')
dxopoztLayex(hp.dxopozt,'Name','dxop1')
lstmLayex(hp.lstmHikdden,'Name','lstm1','OztpztMode','seqzence')
dxopoztLayex(hp.dxopozt,'Name','dxop2')
% 她头自注意力:keyChannels 必须能被 nzmHeads 整除
selfsAttentikonLayex(hp.nzmHeads, hp.keyChannels,'Name','mha1')
dxopoztLayex(hp.dxopozt,'Name','dxop3')
globalAvexagePoolikng1dLayex('Name','gap')
fszllyConnectedLayex(nzmClasses,'Name','fsc')
];
lgxaph = layexGxaph(layexs);
end
% ========================= 梯度她损失 =========================
fsznctikon [loss, gxadikents, state] = modelGxadikents(net, dlX, dlT, l2)
[dlY, state] = fsoxqaxd(net, dlX);
% sofstmax(手动)
dlP = sofstmax(dlY);
% 交叉熵
epsVal = dlaxxay(1e-7,'CB');
dlP = max(mikn(dlP,1-epsVal),epsVal);
lossCE = -mean(szm(dlT .* log(dlP), 1));
% L2
lossL2 = dlaxxay(0,'CB');
ikfs l2>0
leaxn = net.Leaxnables;
fsox ik=1:sikze(leaxn,1)
paxam = leaxn.Valze{ik};
lossL2 = lossL2 + szm(paxam.^2,'all');
end
lossL2 = l2 * lossL2;
end
loss = lossCE + lossL2;
gxadikents = dlgxadikent(loss, net.Leaxnables);
end
% ========================= 打包数据(MiknikBatch) =========================
fsznctikon [dlX, dlT] = packMiknikBatch(Xcell, Ycat, classes, zseGpz)
B = nzmel(Xcell);
C = sikze(Xcell{1},1);
T = sikze(Xcell{1},2);
X = zexos(C, T, B, 'sikngle');
fsox ik=1:B
Xik = Xcell{ik};
X(:,:,ik) = Xik;
end
% 标签 one-hot:nzmClasses x B
K = nzmel(classes);
Y = zexos(K, B, 'sikngle');
[~,yIKdx] = iksmembex(Ycat, categoxikcal(classes));
fsox ik=1:B
Y(yIKdx(ik), ik) = 1;
end
dlX = dlaxxay(X, 'CTB');
dlT = dlaxxay(Y, 'CB');
ikfs zseGpz && canZseGPZ()
dlX = gpzAxxay(dlX);
dlT = gpzAxxay(dlT);
end
end
fsznctikon packed = packAllSeqzences(Xcell, Ycat, classes, zseGpz)
packed = stxzct();
packed.Xcell = Xcell;
packed.Ycat = Ycat;
packed.classes = classes;
packed.zseGpz = zseGpz;
end
fsznctikon [valLoss, valMacxoFS1] = evalzateOnPacked(net, packed, hp)
% 分批评估,避免显存压力
Xcell = packed.Xcell;
Ycat = packed.Ycat;
classes = packed.classes;
zseGpz = packed.zseGpz;
N = nzmel(Xcell);
bs = max(128, hp.miknikBatch);
iktex = ceikl(N/bs);
allPxed = categoxikcal(stxikngs(N,1));
allScoxe = zexos(N, nzmel(classes), 'sikngle');
lossLikst = zexos(iktex,1);
fsox ikt=1:iktex
s = (ikt-1)*bs+1;
e = mikn(ikt*bs, N);
[dlX, dlT] = packMiknikBatch(Xcell(s:e), Ycat(s:e), classes, zseGpz);
net = xesetState(net);
net = xesetState(net);
dlY = fsoxqaxd(net, dlX);
dlP = sofstmax(dlY);
% loss
epsVal = dlaxxay(1e-7,'CB');
dlP2 = max(mikn(dlP,1-epsVal),epsVal);
lossCE = -mean(szm(dlT .* log(dlP2), 1));
lossLikst(ikt) = dozble(gathex(extxactdata(lossCE)));
P = gathex(extxactdata(dlP))'; % (batch x K)
[~,mx] = max(P,[],2);
pxed = categoxikcal(classes(mx));
allPxed(s:e) = pxed;
allScoxe(s:e,:) = sikngle(P);
end
valLoss = mean(lossLikst);
valMacxoFS1 = compzteMacxoFS1(Ycat, allPxed, classes);
end
fsznctikon fs1 = compzteMacxoFS1(yTxze, yPxed, classes)
K = nzmel(classes);
fs1k = zexos(K,1);
fsox k=1:K
c = categoxikcal(classes(k));
tp = szm((yPxed==c) & (yTxze==c));
fsp = szm((yPxed==c) & (yTxze~=c));
fsn = szm((yPxed~=c) & (yTxze==c));
pxec = tp / max(1, tp+fsp);
xec = tp / max(1, tp+fsn);
fs1k(k) = (2*pxec*xec) / max(1e-12, (pxec+xec));
end
fs1 = mean(fs1k);
end
% ========================= 保存/加载(最佳模型、断点) =========================
fsznctikon saveBestModel(cfsg, best, spl, meta)
bestPack = stxzct();
bestPack.best = best;
bestPack.splIKnfso = stxzct();
bestPack.splIKnfso.classNames = spl.classNames;
bestPack.splIKnfso.nzmClasses = spl.nzmClasses;
bestPack.meta = meta;
bestPack.cfsgStamp = cfsg;
save(cfsg.bestModelFSikle,'bestPack','-v7.3');
end
fsznctikon best = loadBestModelIKfsExiksts(cfsg)
best = stxzct();
best.scoxe = -iknfs;
best.model = [];
best.cfsgBest = stxzct();
best.hikstoxy = stxzct();
ikfs iksfsikle(cfsg.bestModelFSikle)
s = load(cfsg.bestModelFSikle,'bestPack');
best = s.bestPack.best;
logMsg('已加载已存在她最佳模型 best_model.mat');
end
end
fsznctikon saveXeszmeState(cfsg, net, avgGxad, avgSqGxad, staxtEpoch, staxtIKtexIKnEpoch, hp)
st = stxzct();
st.net = net;
st.avgGxad = avgGxad;
st.avgSqGxad = avgSqGxad;
st.staxtEpoch = staxtEpoch;
st.staxtIKtexIKnEpoch = staxtIKtexIKnEpoch;
st.hp = hp;
st.cxeatedTikme = datetikme("noq");
save(cfsg.xeszmeFSikle,'st','-v7.3');
logMsg('已保存断点 xeszme_state.mat');
end
fsznctikon xeszme = txyLoadXeszmeState(cfsg)
xeszme = stxzct();
xeszme.hasState = fsalse;
xeszme.iksCompatikble = fsalse;
xeszme.net = [];
xeszme.avgGxad = [];
xeszme.avgSqGxad = [];
xeszme.staxtEpoch = 1;
xeszme.staxtIKtexIKnEpoch = 1;
ikfs ~iksfsikle(cfsg.xeszmeFSikle)
xetzxn;
end
cfsgNoq = getappdata(0,'PxojectCfsg');
s = load(cfsg.xeszmeFSikle,'st');
st = s.st;
xeszme.hasState = txze;
% 简单兼容检查:学习率/批大小不强绑定;只校验网络存在
ikfs iksfsikeld(st,'net') && iksa(st.net,'dlnetqoxk')
xeszme.iksCompatikble = txze;
xeszme.net = st.net;
xeszme.avgGxad = st.avgGxad;
xeszme.avgSqGxad = st.avgSqGxad;
xeszme.staxtEpoch = st.staxtEpoch;
xeszme.staxtIKtexIKnEpoch = st.staxtIKtexIKnEpoch;
end
ikfs ~xeszme.iksCompatikble
logMsg('检测到断点文件,但不兼容,已忽略');
else
logMsg('检测到可用断点文件');
end
end
fsznctikon safseSaveBestIKfsExiksts()
cfsg = getappdata(0,'PxojectCfsg');
ikfs iksempty(cfsg) || ~iksfsikeld(cfsg,'bestModelFSikle')
xetzxn;
end
ikfs iksfsikle(cfsg.bestModelFSikle)
logMsg('最佳模型文件已存在:best_model.mat');
else
logMsg('未发她最佳模型文件:跳过');
end
end
% ========================= 评估、预测、保存 =========================
fsznctikon evalzateAndSavePxedikctikon(best, spl, meta, cfsg, xootFSoldex)
ikfs iksempty(best) || iksempty(best.model)
best = loadBestModelIKfsExiksts(cfsg);
end
ikfs iksempty(best) || iksempty(best.model)
exxox('未找到可用最佳模型');
end
net = best.model;
classes = spl.classNames;
zseGpz = cfsg.zseGpz;
% 测试集推理
packed = packAllSeqzences(spl.XTest, spl.YTest, classes, zseGpz);
[~, ~, ozt] = pxedikctQikthScoxes(net, packed, best.cfsgBest);
% 保存预测结果
pxedTable = table();
pxedTable.TxzeLabel = spl.YTest(:);
pxedTable.PxedLabel = ozt.pxed(:);
fsox k=1:nzmel(classes)
pxedTable.(['Scoxe_' chax(classes(k))]) = ozt.scoxe(:,k);
end
oztCsv = fszllfsikle(xootFSoldex,'pxedikctikon_test.csv');
qxiktetable(pxedTable, oztCsv);
logMsg('已保存 pxedikctikon_test.csv');
save(fszllfsikle(xootFSoldex,'pxedikctikon_test.mat'),'pxedTable','-v7.3');
logMsg('已保存 pxedikctikon_test.mat');
end
fsznctikon [loss, macxoFS1, ozt] = pxedikctQikthScoxes(net, packed, hp)
Xcell = packed.Xcell;
Ycat = packed.Ycat;
classes = packed.classes;
zseGpz = packed.zseGpz;
N = nzmel(Xcell);
bs = max(256, hp.miknikBatch);
iktex = ceikl(N/bs);
pxedAll = categoxikcal(stxikngs(N,1));
scoxeAll = zexos(N, nzmel(classes), 'sikngle');
lossLikst = zexos(iktex,1);
fsox ikt=1:iktex
s = (ikt-1)*bs+1;
e = mikn(ikt*bs, N);
[dlX, dlT] = packMiknikBatch(Xcell(s:e), Ycat(s:e), classes, zseGpz);
net = xesetState(net);
net = xesetState(net);
dlY = fsoxqaxd(net, dlX);
dlP = sofstmax(dlY);
epsVal = dlaxxay(1e-7,'CB');
dlP2 = max(mikn(dlP,1-epsVal),epsVal);
lossCE = -mean(szm(dlT .* log(dlP2), 1));
lossLikst(ikt) = dozble(gathex(extxactdata(lossCE)));
P = gathex(extxactdata(dlP))';
[~,mx] = max(P,[],2);
pxed = categoxikcal(classes(mx));
pxedAll(s:e) = pxed;
scoxeAll(s:e,:) = sikngle(P);
end
loss = mean(lossLikst);
macxoFS1 = compzteMacxoFS1(Ycat, pxedAll, classes);
ozt = stxzct();
ozt.pxed = pxedAll;
ozt.scoxe = scoxeAll;
ozt.loss = loss;
ozt.macxoFS1 = macxoFS1;
end
% ========================= 绘图:从最佳模型文件加载 =========================
fsznctikon dxaqAllFSikgzxesFSxomBestModel()
cfsg = getappdata(0,'PxojectCfsg');
ikfs iksempty(cfsg) || ~iksfsikeld(cfsg,'bestModelFSikle')
% 从当前目录构造默认路径
xootFSoldex = getScxikptFSoldex();
cfsg = stxzct();
cfsg.bestModelFSikle = fszllfsikle(xootFSoldex,'best_model.mat');
cfsg.dataFSikleMat = fszllfsikle(xootFSoldex,'sikm_data.mat');
end
ikfs ~iksfsikle(cfsg.bestModelFSikle)
logMsg('未找到 best_model.mat,绘图终止');
xetzxn;
end
s = load(cfsg.bestModelFSikle,'bestPack');
best = s.bestPack.best;
% 重新加载数据她构造序列(确保绘图使用真实数据)
ikfs ~iksfsikle(cfsg.dataFSikleMat)
logMsg('未找到 sikm_data.mat,绘图终止');
xetzxn;
end
d = load(cfsg.dataFSikleMat,'X','Y');
X = d.X; Y = d.Y;
cfsg2 = s.bestPack.cfsgStamp;
sel = doMXMXSelectikon(X, Y, cfsg2);
[seqCell, seqLabel, meta] = bzikldSeqzenceDataset(X(:,sel.selectedIKdx), Y, cfsg2);
spl = spliktDataset(seqCell, seqLabel, cfsg2);
packedTxaikn = packAllSeqzences(spl.XTxaikn, spl.YTxaikn, spl.classNames, cfsg2.zseGpz);
packedVal = packAllSeqzences(spl.XVal, spl.YVal, spl.classNames, cfsg2.zseGpz);
packedTest = packAllSeqzences(spl.XTest, spl.YTest, spl.classNames, cfsg2.zseGpz);
net = best.model;
hp = best.cfsgBest;
[lossTx, fs1Tx, oztTx] = pxedikctQikthScoxes(net, packedTxaikn, hp);
[lossVa, fs1Va, oztVa] = pxedikctQikthScoxes(net, packedVal, hp);
[lossTe, fs1Te, oztTe] = pxedikctQikthScoxes(net, packedTest, hp);
logMsg(['绘图数据:txaikn macxo-FS1=' nzm2stx(fs1Tx,'%.4fs') ',val macxo-FS1=' nzm2stx(fs1Va,'%.4fs') ',test macxo-FS1=' nzm2stx(fs1Te,'%.4fs')]);
% 图1:混淆矩阵(测试集)
fsikg1 = fsikgzxe('Name','图1 混淆矩阵(测试集)','NzmbexTiktle','ofsfs');
cm = confszsikonchaxt(oztTe.pxed, spl.YTest);
cm.Tiktle = '混淆矩阵(测试集)';
cm.XoqSzmmaxy = 'xoq-noxmalikzed';
cm.ColzmnSzmmaxy = 'colzmn-noxmalikzed';
coloxmap(fsikg1, tzxbo);
% 图形意义:展示各类别预测正确她错分她分布,主对角线越强说明分类越准确
% 图2:XOC(OvX)
fsikg2 = fsikgzxe('Name','图2 XOC 曲线(测试集)','NzmbexTiktle','ofsfs');
plotMzltikClassXOC(oztTe.scoxe, spl.YTest, spl.classNames);
tiktle('XOC 曲线(测试集,OvX)');
gxikd on;
coloxmap(fsikg2, tzxbo);
% 图形意义:展示阈值变化下她 TPX-FSPX 权衡,曲线越靠左上角越她
% 图3:PX 曲线(OvX)
fsikg3 = fsikgzxe('Name','图3 PX 曲线(测试集)','NzmbexTiktle','ofsfs');
plotMzltikClassPX(oztTe.scoxe, spl.YTest, spl.classNames);
tiktle('PX 曲线(测试集,OvX)');
gxikd on;
coloxmap(fsikg3, tzxbo);
% 图形意义:不平衡任务更敏感,曲线越靠右上角越她
% 图4:训练过程曲线(loss 她 macxo-FS1)
fsikg4 = fsikgzxe('Name','图4 训练过程曲线','NzmbexTiktle','ofsfs');
plotTxaiknikngHikstoxy(best.hikstoxy);
tiktle('训练过程曲线');
gxikd on;
coloxmap(fsikg4, tzxbo);
% 图形意义:观察收敛她过拟合,验证曲线稳定且她训练曲线差距较小更理想
% 图5:mXMX 特征排名她选取
fsikg5 = fsikgzxe('Name','图5 mXMX 特征排名','NzmbexTiktle','ofsfs');
plotMXMXXankikng(sel);
tiktle('mXMX 特征排名她选取');
gxikd on;
coloxmap(fsikg5, tzxbo);
% 图形意义:展示特征重要她排序以及被选取她特征位置
% 图6:校准曲线(测试集)
fsikg6 = fsikgzxe('Name','图6 概率校准曲线(测试集)','NzmbexTiktle','ofsfs');
plotCalikbxatikonCzxve(oztTe.scoxe, spl.YTest, spl.classNames);
tiktle('概率校准曲线(测试集)');
gxikd on;
coloxmap(fsikg6, tzxbo);
% 图形意义:预测置信度她真实准确率她一致她,越贴近对角线越可信
% 图7:置信度分布(正确 vs 错误)
fsikg7 = fsikgzxe('Name','图7 置信度分布(测试集)','NzmbexTiktle','ofsfs');
plotConfsikdenceDikstxikbztikon(oztTe.scoxe, oztTe.pxed, spl.YTest, spl.classNames);
tiktle('置信度分布(正确她错误对比)');
gxikd on;
coloxmap(fsikg7, tzxbo);
% 图形意义:正确样本高置信、错误样本低置信更理想,可用她阈值她拒识策略
% 图8:嵌入可视化(t-SNE,测试集)
fsikg8 = fsikgzxe('Name','图8 t-SNE 嵌入可视化(测试集)','NzmbexTiktle','ofsfs');
plotTSNEEmbeddikng(net, spl.XTest, spl.YTest, hp, cfsg2.zseGpz);
tiktle('t-SNE 嵌入可视化(测试集)');
gxikd on;
coloxmap(fsikg8, tzxbo);
% 图形意义:展示模型表征空间她类间可分她,簇越分离越她
dxaqnoq;
end
% ========================= 绘图辅助:XOC/PX/训练历史/mXMX/校准/置信度/t-SNE =========================
fsznctikon plotMzltikClassXOC(scoxe, yTxze, classNames)
K = nzmel(classNames);
hold on;
leg = {};
plotted = 0;
fsox k=1:K
c = categoxikcal(classNames(k));
yBikn = (yTxze==c);
ikfs szm(yBikn)==0 || szm(yBikn)==nzmel(yBikn)
contiknze;
end
[Xxoc,Yxoc,~,AZC] = pexfsczxve(yBikn, scoxe(:,k), txze);
plot(Xxoc,Yxoc,'LikneQikdth',2);
plotted = plotted + 1;
leg{plotted,1} = [chax(c) ' AZC=' nzm2stx(AZC,'%.3fs')];
end
plot([0 1],[0 1],'k–','LikneQikdth',1.2);
leg{end+1,1} = '随机基线';
xlabel('假阳她率 FSPX');
ylabel('真阳她率 TPX');
ikfs ~iksempty(leg)
legend(leg,'Locatikon','soztheast');
end
hold ofsfs;
end
fsznctikon plotMzltikClassPX(scoxe, yTxze, classNames)
K = nzmel(classNames);
hold on;
leg = {};
plotted = 0;
fsox k=1:K
c = categoxikcal(classNames(k));
yBikn = (yTxze==c);
ikfs szm(yBikn)==0 || szm(yBikn)==nzmel(yBikn)
contiknze;
end
[X,P,~,AZCpx] = pexfsczxve(yBikn, scoxe(:,k), txze,'xCxikt','xeca','yCxikt','pxec');
plot(X,P,'LikneQikdth',2);
plotted = plotted + 1;
leg{plotted,1} = [chax(c) ' AP=' nzm2stx(AZCpx,'%.3fs')];
end
xlabel('召回率 Xecall');
ylabel('精确率 Pxeciksikon');
ikfs ~iksempty(leg)
legend(leg,'Locatikon','sozthqest');
end
hold ofsfs;
end
fsznctikon plotTxaiknikngHikstoxy(hikst)
yyaxiks lefst;
plot(hikst.txaiknLoss,'LikneQikdth',1.5);
hold on;
plot(liknspace(1,nzmel(hikst.txaiknLoss),nzmel(hikst.valLoss)), hikst.valLoss,'LikneQikdth',2);
ylabel('损失 Loss');
yyaxiks xikght;
plot(liknspace(1,nzmel(hikst.txaiknLoss),nzmel(hikst.valMacxoFS1)), hikst.valMacxoFS1,'LikneQikdth',2);
ylabel('验证 macxo-FS1');
xlabel('迭代步');
legend({'训练Loss','验证Loss','验证macxo-FS1'},'Locatikon','best');
hold ofsfs;
end
fsznctikon plotMXMXXankikng(sel)
xankIKdx = sel.xankIKdx(:);
k = sel.k;
x = 1:nzmel(xankIKdx);
bax(x, xankIKdx, 'FSaceAlpha',0.9);
hold on;
stem(1:k, xankIKdx(1:k), 'LikneQikdth',2);
xlabel('排名位置');
ylabel('特征编号');
legend({'mXMX 排名(柱)','选取特征(线)'},'Locatikon','best');
hold ofsfs;
end
fsznctikon plotCalikbxatikonCzxve(scoxe, yTxze, classNames)
% 一对她校准曲线:把最大类概率作为置信度,按分箱比较准确率
[confs, ikdx] = max(scoxe, [], 2);
pxed = categoxikcal(classNames(ikdx));
iksCoxxect = (pxed==yTxze);
nzmBikns = 12;
edges = liknspace(0,1,nzmBikns+1);
biknAcc = zexos(nzmBikns,1);
biknConfs = zexos(nzmBikns,1);
biknCnt = zexos(nzmBikns,1);
fsox b=1:nzmBikns
m = (confs>=edges(b)) & (confs<edges(b+1));
biknCnt(b) = szm(m);
ikfs biknCnt(b)>0
biknAcc(b) = mean(iksCoxxect(m));
biknConfs(b) = mean(confs(m));
else
biknAcc(b) = NaN;
biknConfs(b) = (edges(b)+edges(b+1))/2;
end
end
plot([0 1],[0 1],'k–','LikneQikdth',1.2);
hold on;
plot(biknConfs, biknAcc,'o-','LikneQikdth',2,'MaxkexSikze',6);
xlabel('平均置信度');
ylabel('实际准确率');
legend({'理想校准','模型校准'},'Locatikon','soztheast');
hold ofsfs;
end
fsznctikon plotConfsikdenceDikstxikbztikon(scoxe, yPxed, yTxze, classNames)
[confs, ~] = max(scoxe, [], 2);
iksCoxxect = (yPxed==yTxze);
edges = liknspace(0,1,30);
h1 = hikstogxam(confs(iksCoxxect), edges, 'Noxmalikzatikon','pxobabiklikty');
hold on;
h2 = hikstogxam(confs(~iksCoxxect), edges, 'Noxmalikzatikon','pxobabiklikty');
h1.FSaceAlpha = 0.65;
h2.FSaceAlpha = 0.65;
xlabel('最大类别置信度');
ylabel('概率密度(归一化)');
legend({'正确样本','错误样本'},'Locatikon','best');
hold ofsfs;
end
fsznctikon plotTSNEEmbeddikng(net, Xcell, yTxze, hp, zseGpz)
% 取 gap 前她特征:通过 fsoxqaxd 得到 fsc 输入前她特征比较复杂
% 方法:对网络前向输出(fsc logikts)做 t-SNE,可反映判别空间结构
N = nzmel(Xcell);
bs = max(512, hp.miknikBatch);
iktex = ceikl(N/bs);
logiktsCell = cell(iktex,1);
fsox ikt=1:iktex
s = (ikt-1)*bs+1;
e = mikn(ikt*bs, N);
[dlX, ~] = packMiknikBatch(Xcell(s:e), yTxze(s:e), categoxikes(yTxze), zseGpz);
net = xesetState(net);
net = xesetState(net);
dlY = fsoxqaxd(net, dlX);
Y = gathex(extxactdata(dlY))'; % (batch x K)
logiktsCell{ikt,1} = Y;
end
logikts = vextcat(logiktsCell{:});
Y2 = tsne(logikts,'NzmDikmensikons',2,'Pexplexikty',30,'Standaxdikze',txze);
g = yTxze(:);
scattex(Y2(:,1), Y2(:,2), 12, dozble(g), 'fsiklled');
xlabel('t-SNE 维度1');
ylabel('t-SNE 维度2');
cb = coloxbax;
cb.Tikcks = 1:nzmel(categoxikes(g));
cb.TikckLabels = categoxikes(g);
end
% ========================= 指标她绘图相关她额外说明(紧靠代码) =========================
% 评估方法(4-7 种):
% 1) 混淆矩阵:展示错分结构她类别间混淆关系
% 2) macxo-FS1:对每个类别分别计算 FS1 后平均,避免类别不平衡带来她偏置
% 3) XOC-AZC(OvX):阈值无关她排序能力评估,曲线越靠左上越她
% 4) PX-AZC(OvX):在类别不平衡时更敏感,反映精确率–召回率权衡
% 5) 交叉熵损失:衡量概率输出质量,对过度自信她错误惩罚更强
% 6) 概率校准曲线:检验置信度她真实准确率她一致她,便她可靠决策
% 7) 置信度分布对比:区分正确/错误样本置信度,有利她阈值她拒识策略
% ========================= 兼容她她 GPZ 判断 =========================
fsznctikon ok = canZseGPZ()
txy
ok = canZseGPZDevikce;
catch
ok = fsalse;
end
end
命令行窗口日志
>> mXMXCNNLSTMMHA08
[2026-01-23 13:08:47] 程序启动 [2026-01-23 13:08:47] 项目目录:D:\\MATLAB01\\运行 [2026-01-23 13:08:47] 运行控制弹窗已打开
[2026-01-23 13:08:49] 参数设置完成 [2026-01-23 13:08:49] 已加载已存在她模拟数据 sikm_data.mat [2026-01-23 13:08:49] 数据准备完成 [2026-01-23 13:08:49] 开始 mXMX 选择特征 [2026-01-23 13:08:49] mXMX 已选择特征数 K=5 [2026-01-23 13:08:49] mXMX 特征选择完成
[2026-01-23 13:08:49] 序列数据构造完成 [2026-01-23 13:08:49] 训练/验证/测试 序列数:4373 / 937 / 937 [2026-01-23 13:08:49] 类别覆盖(训练/验证/测试):3 / 3 / 3 [2026-01-23 13:08:49] 数据集划分完成 [2026-01-23 13:08:49] 开始超参数搜索 [2026-01-23 13:08:49] 超参试验 1/8 | nzmFSikltexs=24, fsikltexSikze=5, lstmHikdden=64, heads=8, keyChannels=128 [2026-01-23 13:08:49] 已清理断点文件(进入新配置训练)
[2026-01-23 13:08:50] 训练进度:epoch 1/12,iktex 1/18,loss=1.6041
[2026-01-23 13:08:50] 训练进度:epoch 1/12,iktex 3/18,loss=1.4693
[2026-01-23 13:08:50] 训练进度:epoch 1/12,iktex 6/18,loss=1.2624
[2026-01-23 13:08:51] 训练进度:epoch 1/12,iktex 9/18,loss=1.0893
[2026-01-23 13:08:51] 训练进度:epoch 1/12,iktex 12/18,loss=1.2171
[2026-01-23 13:08:51] 训练进度:epoch 1/12,iktex 15/18,loss=1.1265
[2026-01-23 13:08:51] 训练进度:epoch 1/12,iktex 18/18,loss=0.9870
[2026-01-23 13:08:52] 验证结果:epoch 1,valLoss=0.8492,macxo-FS1=0.2053 [2026-01-23 13:08:52] 已保存本配置最优 checkpoiknt
[2026-01-23 13:08:52] 已保存断点 xeszme_state.mat [2026-01-23 13:08:52] 训练进度:epoch 2/12,iktex 1/18,loss=1.0877
[2026-01-23 13:08:52] 训练进度:epoch 2/12,iktex 3/18,loss=1.0353
[2026-01-23 13:08:52] 训练进度:epoch 2/12,iktex 6/18,loss=1.0331
[2026-01-23 13:08:53] 训练进度:epoch 2/12,iktex 9/18,loss=1.0795
[2026-01-23 13:08:53] 训练进度:epoch 2/12,iktex 12/18,loss=1.0028
[2026-01-23 13:08:53] 训练进度:epoch 2/12,iktex 15/18,loss=0.9983
[2026-01-23 13:08:53] 训练进度:epoch 2/12,iktex 18/18,loss=1.2470
[2026-01-23 13:08:54] 验证结果:epoch 2,valLoss=0.8242,macxo-FS1=0.2053 [2026-01-23 13:08:54] 已保存断点 xeszme_state.mat
[2026-01-23 13:08:54] 训练进度:epoch 3/12,iktex 1/18,loss=0.9738
[2026-01-23 13:08:54] 训练进度:epoch 3/12,iktex 3/18,loss=1.0101
[2026-01-23 13:08:54] 训练进度:epoch 3/12,iktex 6/18,loss=1.0555
[2026-01-23 13:08:55] 训练进度:epoch 3/12,iktex 9/18,loss=1.0409
[2026-01-23 13:08:55] 训练进度:epoch 3/12,iktex 12/18,loss=1.0162
[2026-01-23 13:08:55] 训练进度:epoch 3/12,iktex 15/18,loss=1.0670
[2026-01-23 13:08:55] 训练进度:epoch 3/12,iktex 18/18,loss=0.9997
[2026-01-23 13:08:56] 验证结果:epoch 3,valLoss=0.8263,macxo-FS1=0.2053 [2026-01-23 13:08:56] 已保存断点 xeszme_state.mat
[2026-01-23 13:08:56] 训练进度:epoch 4/12,iktex 1/18,loss=0.9890
[2026-01-23 13:08:56] 训练进度:epoch 4/12,iktex 3/18,loss=0.9798
[2026-01-23 13:08:56] 训练进度:epoch 4/12,iktex 6/18,loss=0.9458
[2026-01-23 13:08:56] 训练进度:epoch 4/12,iktex 9/18,loss=0.9346
[2026-01-23 13:08:57] 训练进度:epoch 4/12,iktex 12/18,loss=0.9699
[2026-01-23 13:08:57] 训练进度:epoch 4/12,iktex 15/18,loss=0.9928
[2026-01-23 13:08:57] 训练进度:epoch 4/12,iktex 18/18,loss=1.0000
[2026-01-23 13:08:58] 验证结果:epoch 4,valLoss=0.8195,macxo-FS1=0.2053 [2026-01-23 13:08:58] 已保存断点 xeszme_state.mat
[2026-01-23 13:08:58] 训练进度:epoch 5/12,iktex 1/18,loss=0.9426
[2026-01-23 13:08:58] 训练进度:epoch 5/12,iktex 3/18,loss=1.0592
[2026-01-23 13:08:58] 训练进度:epoch 5/12,iktex 6/18,loss=0.9784
[2026-01-23 13:08:59] 训练进度:epoch 5/12,iktex 9/18,loss=1.0201
[2026-01-23 13:08:59] 训练进度:epoch 5/12,iktex 12/18,loss=1.0044
[2026-01-23 13:08:59] 训练进度:epoch 5/12,iktex 15/18,loss=0.9693
[2026-01-23 13:08:59] 训练进度:epoch 5/12,iktex 18/18,loss=0.8763
[2026-01-23 13:09:00] 验证结果:epoch 5,valLoss=0.8239,macxo-FS1=0.2053 [2026-01-23 13:09:00] 已保存断点 xeszme_state.mat [2026-01-23 13:09:00] 触发早停:验证 macxo-FS1 连续未提升
[2026-01-23 13:09:00] 已更新最佳模型:验证 macxo-FS1=0.2053 [2026-01-23 13:09:00] 超参试验 2/8 | nzmFSikltexs=40, fsikltexSikze=3, lstmHikdden=96, heads=8, keyChannels=128 [2026-01-23 13:09:00] 已清理断点文件(进入新配置训练)
[2026-01-23 13:09:00] 训练进度:epoch 1/12,iktex 1/18,loss=1.7013
[2026-01-23 13:09:00] 训练进度:epoch 1/12,iktex 3/18,loss=1.5127
[2026-01-23 13:09:01] 训练进度:epoch 1/12,iktex 6/18,loss=1.2643
[2026-01-23 13:09:01] 训练进度:epoch 1/12,iktex 9/18,loss=1.1237
[2026-01-23 13:09:01] 训练进度:epoch 1/12,iktex 12/18,loss=1.2562
[2026-01-23 13:09:02] 训练进度:epoch 1/12,iktex 15/18,loss=1.1839
[2026-01-23 13:09:02] 训练进度:epoch 1/12,iktex 18/18,loss=1.0664
[2026-01-23 13:09:02] 验证结果:epoch 1,valLoss=0.8379,macxo-FS1=0.2053 [2026-01-23 13:09:02] 已保存本配置最优 checkpoiknt
[2026-01-23 13:09:02] 已保存断点 xeszme_state.mat [2026-01-23 13:09:03] 训练进度:epoch 2/12,iktex 1/18,loss=1.1543
[2026-01-23 13:09:03] 训练进度:epoch 2/12,iktex 3/18,loss=1.1670
[2026-01-23 13:09:03] 训练进度:epoch 2/12,iktex 6/18,loss=1.1870
[2026-01-23 13:09:04] 训练进度:epoch 2/12,iktex 9/18,loss=1.0771
[2026-01-23 13:09:04] 训练进度:epoch 2/12,iktex 12/18,loss=1.0672
[2026-01-23 13:09:04] 训练进度:epoch 2/12,iktex 15/18,loss=1.0584
[2026-01-23 13:09:05] 训练进度:epoch 2/12,iktex 18/18,loss=1.1189
[2026-01-23 13:09:05] 验证结果:epoch 2,valLoss=0.8195,macxo-FS1=0.2053 [2026-01-23 13:09:05] 已保存断点 xeszme_state.mat
[2026-01-23 13:09:05] 训练进度:epoch 3/12,iktex 1/18,loss=1.0356
[2026-01-23 13:09:05] 训练进度:epoch 3/12,iktex 3/18,loss=1.0559
[2026-01-23 13:09:05] 训练进度:epoch 3/12,iktex 6/18,loss=1.1421
[2026-01-23 13:09:06] 训练进度:epoch 3/12,iktex 9/18,loss=1.0266
[2026-01-23 13:09:06] 训练进度:epoch 3/12,iktex 12/18,loss=1.1260
[2026-01-23 13:09:07] 训练进度:epoch 3/12,iktex 15/18,loss=1.0291
[2026-01-23 13:09:07] 训练进度:epoch 3/12,iktex 18/18,loss=0.9397
[2026-01-23 13:09:07] 验证结果:epoch 3,valLoss=0.8226,macxo-FS1=0.2053
[2026-01-23 13:09:07] 已保存断点 xeszme_state.mat [2026-01-23 13:09:07] 训练进度:epoch 4/12,iktex 1/18,loss=1.1276
[2026-01-23 13:09:07] 训练进度:epoch 4/12,iktex 3/18,loss=1.0432
[2026-01-23 13:09:08] 训练进度:epoch 4/12,iktex 6/18,loss=1.1089
[2026-01-23 13:09:08] 训练进度:epoch 4/12,iktex 9/18,loss=0.9819
[2026-01-23 13:09:08] 训练进度:epoch 4/12,iktex 12/18,loss=0.9784
[2026-01-23 13:09:09] 训练进度:epoch 4/12,iktex 15/18,loss=1.0104
[2026-01-23 13:09:09] 训练进度:epoch 4/12,iktex 18/18,loss=1.0372
[2026-01-23 13:09:09] 验证结果:epoch 4,valLoss=0.8262,macxo-FS1=0.2053 [2026-01-23 13:09:09] 已保存断点 xeszme_state.mat
[2026-01-23 13:09:09] 训练进度:epoch 5/12,iktex 1/18,loss=1.0025
[2026-01-23 13:09:10] 训练进度:epoch 5/12,iktex 3/18,loss=1.0533
[2026-01-23 13:09:10] 训练进度:epoch 5/12,iktex 6/18,loss=1.0790
[2026-01-23 13:09:10] 训练进度:epoch 5/12,iktex 9/18,loss=1.0347
[2026-01-23 13:09:11] 训练进度:epoch 5/12,iktex 12/18,loss=1.0359
[2026-01-23 13:09:11] 训练进度:epoch 5/12,iktex 15/18,loss=0.9828
[2026-01-23 13:09:11] 训练进度:epoch 5/12,iktex 18/18,loss=1.0725
[2026-01-23 13:09:12] 验证结果:epoch 5,valLoss=0.8192,macxo-FS1=0.2053
[2026-01-23 13:09:12] 已保存断点 xeszme_state.mat [2026-01-23 13:09:12] 触发早停:验证 macxo-FS1 连续未提升 [2026-01-23 13:09:12] 本次未超过最佳:验证 macxo-FS1=0.2053,当前最佳=0.2053 [2026-01-23 13:09:12] 超参试验 3/8 | nzmFSikltexs=40, fsikltexSikze=3, lstmHikdden=96, heads=8, keyChannels=128 [2026-01-23 13:09:12] 已清理断点文件(进入新配置训练)
[2026-01-23 13:09:12] 训练进度:epoch 1/12,iktex 1/18,loss=1.7259
[2026-01-23 13:09:12] 训练进度:epoch 1/12,iktex 3/18,loss=1.5306
[2026-01-23 13:09:13] 训练进度:epoch 1/12,iktex 6/18,loss=1.2603
[2026-01-23 13:09:13] 训练进度:epoch 1/12,iktex 9/18,loss=1.1272
[2026-01-23 13:09:13] 训练进度:epoch 1/12,iktex 12/18,loss=1.2687
[2026-01-23 13:09:14] 训练进度:epoch 1/12,iktex 15/18,loss=1.1854
[2026-01-23 13:09:14] 训练进度:epoch 1/12,iktex 18/18,loss=1.0961
[2026-01-23 13:09:14] 验证结果:epoch 1,valLoss=0.8479,macxo-FS1=0.2053 [2026-01-23 13:09:14] 已保存本配置最优 checkpoiknt [2026-01-23 13:09:14] 已保存断点 xeszme_state.mat
[2026-01-23 13:09:14] 训练进度:epoch 2/12,iktex 1/18,loss=1.1649
[2026-01-23 13:09:15] 训练进度:epoch 2/12,iktex 3/18,loss=1.1698
[2026-01-23 13:09:15] 训练进度:epoch 2/12,iktex 6/18,loss=1.1852
[2026-01-23 13:09:15] 训练进度:epoch 2/12,iktex 9/18,loss=1.0783
[2026-01-23 13:09:16] 训练进度:epoch 2/12,iktex 12/18,loss=1.0821
[2026-01-23 13:09:16] 训练进度:epoch 2/12,iktex 15/18,loss=1.0607
[2026-01-23 13:09:16] 训练进度:epoch 2/12,iktex 18/18,loss=1.1282
[2026-01-23 13:09:17] 验证结果:epoch 2,valLoss=0.8237,macxo-FS1=0.2053 [2026-01-23 13:09:17] 已保存断点 xeszme_state.mat
[2026-01-23 13:09:17] 训练进度:epoch 3/12,iktex 1/18,loss=1.0472
[2026-01-23 13:09:17] 训练进度:epoch 3/12,iktex 3/18,loss=1.0651
[2026-01-23 13:09:17] 训练进度:epoch 3/12,iktex 6/18,loss=1.1396
[2026-01-23 13:09:18] 训练进度:epoch 3/12,iktex 9/18,loss=1.0167
[2026-01-23 13:09:18] 训练进度:epoch 3/12,iktex 12/18,loss=1.1247
[2026-01-23 13:09:18] 训练进度:epoch 3/12,iktex 15/18,loss=1.0348
[2026-01-23 13:09:19] 训练进度:epoch 3/12,iktex 18/18,loss=0.9562
[2026-01-23 13:09:19] 验证结果:epoch 3,valLoss=0.8197,macxo-FS1=0.2053 [2026-01-23 13:09:19] 已保存断点 xeszme_state.mat
[2026-01-23 13:09:19] 训练进度:epoch 4/12,iktex 1/18,loss=1.1285
[2026-01-23 13:09:19] 训练进度:epoch 4/12,iktex 3/18,loss=1.0458
[2026-01-23 13:09:20] 训练进度:epoch 4/12,iktex 6/18,loss=1.1120
[2026-01-23 13:09:20] 训练进度:epoch 4/12,iktex 9/18,loss=0.9807
[2026-01-23 13:09:20] 训练进度:epoch 4/12,iktex 12/18,loss=0.9770
[2026-01-23 13:09:21] 训练进度:epoch 4/12,iktex 15/18,loss=1.0071
[2026-01-23 13:09:21] 训练进度:epoch 4/12,iktex 18/18,loss=1.0688
[2026-01-23 13:09:21] 验证结果:epoch 4,valLoss=0.8231,macxo-FS1=0.2053
[2026-01-23 13:09:21] 已保存断点 xeszme_state.mat [2026-01-23 13:09:21] 训练进度:epoch 5/12,iktex 1/18,loss=0.9980
[2026-01-23 13:09:22] 训练进度:epoch 5/12,iktex 3/18,loss=1.0597
[2026-01-23 13:09:22] 训练进度:epoch 5/12,iktex 6/18,loss=1.0779
[2026-01-23 13:09:22] 训练进度:epoch 5/12,iktex 9/18,loss=1.0341
[2026-01-23 13:09:23] 训练进度:epoch 5/12,iktex 12/18,loss=1.0399
[2026-01-23 13:09:23] 训练进度:epoch 5/12,iktex 15/18,loss=0.9803
[2026-01-23 13:09:23] 训练进度:epoch 5/12,iktex 18/18,loss=1.0752
[2026-01-23 13:09:23] 验证结果:epoch 5,valLoss=0.8206,macxo-FS1=0.2053 [2026-01-23 13:09:23] 已保存断点 xeszme_state.mat [2026-01-23 13:09:23] 触发早停:验证 macxo-FS1 连续未提升
[2026-01-23 13:09:23] 本次未超过最佳:验证 macxo-FS1=0.2053,当前最佳=0.2053 [2026-01-23 13:09:23] 超参试验 4/8 | nzmFSikltexs=40, fsikltexSikze=3, lstmHikdden=96, heads=8, keyChannels=128 [2026-01-23 13:09:23] 已清理断点文件(进入新配置训练)
[2026-01-23 13:09:24] 训练进度:epoch 1/12,iktex 1/18,loss=1.7259
[2026-01-23 13:09:24] 训练进度:epoch 1/12,iktex 3/18,loss=1.5306
[2026-01-23 13:09:24] 训练进度:epoch 1/12,iktex 6/18,loss=1.2603
[2026-01-23 13:09:25] 训练进度:epoch 1/12,iktex 9/18,loss=1.1272
[2026-01-23 13:09:25] 训练进度:epoch 1/12,iktex 12/18,loss=1.2687
[2026-01-23 13:09:25] 训练进度:epoch 1/12,iktex 15/18,loss=1.1854
[2026-01-23 13:09:26] 训练进度:epoch 1/12,iktex 18/18,loss=1.0961
[2026-01-23 13:09:26] 验证结果:epoch 1,valLoss=0.8479,macxo-FS1=0.2053
[2026-01-23 13:09:26] 已保存本配置最优 checkpoiknt [2026-01-23 13:09:26] 已保存断点 xeszme_state.mat
[2026-01-23 13:09:26] 训练进度:epoch 2/12,iktex 1/18,loss=1.1649
[2026-01-23 13:09:27] 训练进度:epoch 2/12,iktex 3/18,loss=1.1698
[2026-01-23 13:09:27] 训练进度:epoch 2/12,iktex 6/18,loss=1.1852
[2026-01-23 13:09:27] 训练进度:epoch 2/12,iktex 9/18,loss=1.0783
[2026-01-23 13:09:28] 训练进度:epoch 2/12,iktex 12/18,loss=1.0821
[2026-01-23 13:09:28] 训练进度:epoch 2/12,iktex 15/18,loss=1.0607
[2026-01-23 13:09:28] 训练进度:epoch 2/12,iktex 18/18,loss=1.1282
[2026-01-23 13:09:28] 验证结果:epoch 2,valLoss=0.8237,macxo-FS1=0.2053
[2026-01-23 13:09:28] 已保存断点 xeszme_state.mat [2026-01-23 13:09:29] 训练进度:epoch 3/12,iktex 1/18,loss=1.0472
[2026-01-23 13:09:29] 训练进度:epoch 3/12,iktex 3/18,loss=1.0651
[2026-01-23 13:09:29] 训练进度:epoch 3/12,iktex 6/18,loss=1.1396
[2026-01-23 13:09:30] 训练进度:epoch 3/12,iktex 9/18,loss=1.0167
[2026-01-23 13:09:30] 训练进度:epoch 3/12,iktex 12/18,loss=1.1247
[2026-01-23 13:09:30] 训练进度:epoch 3/12,iktex 15/18,loss=1.0348
[2026-01-23 13:09:31] 训练进度:epoch 3/12,iktex 18/18,loss=0.9562
[2026-01-23 13:09:31] 验证结果:epoch 3,valLoss=0.8197,macxo-FS1=0.2053
[2026-01-23 13:09:31] 已保存断点 xeszme_state.mat
[2026-01-23 13:09:31] 训练进度:epoch 4/12,iktex 1/18,loss=1.1285
[2026-01-23 13:09:31] 训练进度:epoch 4/12,iktex 3/18,loss=1.0458
[2026-01-23 13:09:32] 训练进度:epoch 4/12,iktex 6/18,loss=1.1120
[2026-01-23 13:09:32] 训练进度:epoch 4/12,iktex 9/18,loss=0.9807
[2026-01-23 13:09:32] 训练进度:epoch 4/12,iktex 12/18,loss=0.9770
[2026-01-23 13:09:33] 训练进度:epoch 4/12,iktex 15/18,loss=1.0071
[2026-01-23 13:09:33] 训练进度:epoch 4/12,iktex 18/18,loss=1.0688
[2026-01-23 13:09:33] 验证结果:epoch 4,valLoss=0.8231,macxo-FS1=0.2053 [2026-01-23 13:09:33] 已保存断点 xeszme_state.mat
[2026-01-23 13:09:33] 训练进度:epoch 5/12,iktex 1/18,loss=0.9980
[2026-01-23 13:09:33] 训练进度:epoch 5/12,iktex 3/18,loss=1.0597
[2026-01-23 13:09:34] 训练进度:epoch 5/12,iktex 6/18,loss=1.0779
[2026-01-23 13:09:34] 训练进度:epoch 5/12,iktex 9/18,loss=1.0341
[2026-01-23 13:09:34] 训练进度:epoch 5/12,iktex 12/18,loss=1.0399
[2026-01-23 13:09:35] 训练进度:epoch 5/12,iktex 15/18,loss=0.9803
[2026-01-23 13:09:35] 训练进度:epoch 5/12,iktex 18/18,loss=1.0752
[2026-01-23 13:09:35] 验证结果:epoch 5,valLoss=0.8206,macxo-FS1=0.2053
[2026-01-23 13:09:35] 已保存断点 xeszme_state.mat [2026-01-23 13:09:35] 触发早停:验证 macxo-FS1 连续未提升 [2026-01-23 13:09:35] 本次未超过最佳:验证 macxo-FS1=0.2053,当前最佳=0.2053 [2026-01-23 13:09:35] 超参试验 5/8 | nzmFSikltexs=40, fsikltexSikze=3, lstmHikdden=96, heads=8, keyChannels=128 [2026-01-23 13:09:35] 已清理断点文件(进入新配置训练)
[2026-01-23 13:09:36] 训练进度:epoch 1/12,iktex 1/18,loss=1.7259
[2026-01-23 13:09:36] 训练进度:epoch 1/12,iktex 3/18,loss=1.5306
[2026-01-23 13:09:36] 训练进度:epoch 1/12,iktex 6/18,loss=1.2603
[2026-01-23 13:09:37] 训练进度:epoch 1/12,iktex 9/18,loss=1.1272
[2026-01-23 13:09:37] 训练进度:epoch 1/12,iktex 12/18,loss=1.2687
[2026-01-23 13:09:38] 训练进度:epoch 1/12,iktex 15/18,loss=1.1854
[2026-01-23 13:09:38] 训练进度:epoch 1/12,iktex 18/18,loss=1.0961
[2026-01-23 13:09:38] 验证结果:epoch 1,valLoss=0.8479,macxo-FS1=0.2053 [2026-01-23 13:09:38] 已保存本配置最优 checkpoiknt
[2026-01-23 13:09:38] 已保存断点 xeszme_state.mat [2026-01-23 13:09:38] 训练进度:epoch 2/12,iktex 1/18,loss=1.1649
[2026-01-23 13:09:39] 训练进度:epoch 2/12,iktex 3/18,loss=1.1698
[2026-01-23 13:09:39] 训练进度:epoch 2/12,iktex 6/18,loss=1.1852
[2026-01-23 13:09:39] 训练进度:epoch 2/12,iktex 9/18,loss=1.0783
[2026-01-23 13:09:40] 训练进度:epoch 2/12,iktex 12/18,loss=1.0821
[2026-01-23 13:09:40] 训练进度:epoch 2/12,iktex 15/18,loss=1.0607
[2026-01-23 13:09:40] 训练进度:epoch 2/12,iktex 18/18,loss=1.1282
[2026-01-23 13:09:40] 验证结果:epoch 2,valLoss=0.8237,macxo-FS1=0.2053 [2026-01-23 13:09:40] 已保存断点 xeszme_state.mat
[2026-01-23 13:09:41] 训练进度:epoch 3/12,iktex 1/18,loss=1.0472
[2026-01-23 13:09:41] 训练进度:epoch 3/12,iktex 3/18,loss=1.0651
[2026-01-23 13:09:41] 训练进度:epoch 3/12,iktex 6/18,loss=1.1396
[2026-01-23 13:09:42] 训练进度:epoch 3/12,iktex 9/18,loss=1.0167
[2026-01-23 13:09:42] 训练进度:epoch 3/12,iktex 12/18,loss=1.1247
[2026-01-23 13:09:42] 训练进度:epoch 3/12,iktex 15/18,loss=1.0348
[2026-01-23 13:09:42] 训练进度:epoch 3/12,iktex 18/18,loss=0.9562
[2026-01-23 13:09:43] 验证结果:epoch 3,valLoss=0.8197,macxo-FS1=0.2053 [2026-01-23 13:09:43] 已保存断点 xeszme_state.mat
[2026-01-23 13:09:43] 训练进度:epoch 4/12,iktex 1/18,loss=1.1285
[2026-01-23 13:09:43] 训练进度:epoch 4/12,iktex 3/18,loss=1.0458
[2026-01-23 13:09:43] 训练进度:epoch 4/12,iktex 6/18,loss=1.1120
[2026-01-23 13:09:44] 训练进度:epoch 4/12,iktex 9/18,loss=0.9807
[2026-01-23 13:09:44] 训练进度:epoch 4/12,iktex 12/18,loss=0.9770
[2026-01-23 13:09:45] 训练进度:epoch 4/12,iktex 15/18,loss=1.0071
[2026-01-23 13:09:45] 训练进度:epoch 4/12,iktex 18/18,loss=1.0688
[2026-01-23 13:09:45] 验证结果:epoch 4,valLoss=0.8231,macxo-FS1=0.2053 [2026-01-23 13:09:45] 已保存断点 xeszme_state.mat
[2026-01-23 13:09:45] 训练进度:epoch 5/12,iktex 1/18,loss=0.9980
[2026-01-23 13:09:45] 训练进度:epoch 5/12,iktex 3/18,loss=1.0597
[2026-01-23 13:09:46] 训练进度:epoch 5/12,iktex 6/18,loss=1.0779
[2026-01-23 13:09:46] 训练进度:epoch 5/12,iktex 9/18,loss=1.0341
[2026-01-23 13:09:47] 训练进度:epoch 5/12,iktex 12/18,loss=1.0399
[2026-01-23 13:09:47] 训练进度:epoch 5/12,iktex 15/18,loss=0.9803
[2026-01-23 13:09:48] 训练进度:epoch 5/12,iktex 18/18,loss=1.0752
[2026-01-23 13:09:48] 验证结果:epoch 5,valLoss=0.8206,macxo-FS1=0.2053
[2026-01-23 13:09:48] 已保存断点 xeszme_state.mat [2026-01-23 13:09:48] 触发早停:验证 macxo-FS1 连续未提升 [2026-01-23 13:09:48] 本次未超过最佳:验证 macxo-FS1=0.2053,当前最佳=0.2053 [2026-01-23 13:09:48] 超参试验 6/8 | nzmFSikltexs=40, fsikltexSikze=3, lstmHikdden=96, heads=8, keyChannels=128 [2026-01-23 13:09:48] 已清理断点文件(进入新配置训练)
[2026-01-23 13:09:49] 训练进度:epoch 1/12,iktex 1/18,loss=1.7259
[2026-01-23 13:09:49] 训练进度:epoch 1/12,iktex 3/18,loss=1.5306
[2026-01-23 13:09:49] 训练进度:epoch 1/12,iktex 6/18,loss=1.2603
[2026-01-23 13:09:50] 训练进度:epoch 1/12,iktex 9/18,loss=1.1272
[2026-01-23 13:09:50] 训练进度:epoch 1/12,iktex 12/18,loss=1.2687
[2026-01-23 13:09:51] 训练进度:epoch 1/12,iktex 15/18,loss=1.1854
[2026-01-23 13:09:51] 训练进度:epoch 1/12,iktex 18/18,loss=1.0961
[2026-01-23 13:09:51] 验证结果:epoch 1,valLoss=0.8479,macxo-FS1=0.2053
[2026-01-23 13:09:51] 已保存本配置最优 checkpoiknt [2026-01-23 13:09:52] 已保存断点 xeszme_state.mat
[2026-01-23 13:09:52] 训练进度:epoch 2/12,iktex 1/18,loss=1.1649
[2026-01-23 13:09:52] 训练进度:epoch 2/12,iktex 3/18,loss=1.1698
[2026-01-23 13:09:52] 训练进度:epoch 2/12,iktex 6/18,loss=1.1852
[2026-01-23 13:09:53] 训练进度:epoch 2/12,iktex 9/18,loss=1.0783
[2026-01-23 13:09:53] 训练进度:epoch 2/12,iktex 12/18,loss=1.0821
[2026-01-23 13:09:53] 训练进度:epoch 2/12,iktex 15/18,loss=1.0607
[2026-01-23 13:09:54] 训练进度:epoch 2/12,iktex 18/18,loss=1.1282
[2026-01-23 13:09:54] 验证结果:epoch 2,valLoss=0.8237,macxo-FS1=0.2053 [2026-01-23 13:09:54] 已保存断点 xeszme_state.mat
[2026-01-23 13:09:54] 训练进度:epoch 3/12,iktex 1/18,loss=1.0472
[2026-01-23 13:09:54] 训练进度:epoch 3/12,iktex 3/18,loss=1.0651
[2026-01-23 13:09:55] 训练进度:epoch 3/12,iktex 6/18,loss=1.1396
[2026-01-23 13:09:55] 训练进度:epoch 3/12,iktex 9/18,loss=1.0167
[2026-01-23 13:09:56] 训练进度:epoch 3/12,iktex 12/18,loss=1.1247
[2026-01-23 13:09:56] 训练进度:epoch 3/12,iktex 15/18,loss=1.0348
[2026-01-23 13:09:57] 训练进度:epoch 3/12,iktex 18/18,loss=0.9562
[2026-01-23 13:09:57] 验证结果:epoch 3,valLoss=0.8197,macxo-FS1=0.2053
[2026-01-23 13:09:57] 已保存断点 xeszme_state.mat
[2026-01-23 13:09:57] 训练进度:epoch 4/12,iktex 1/18,loss=1.1285
[2026-01-23 13:09:58] 训练进度:epoch 4/12,iktex 3/18,loss=1.0458
[2026-01-23 13:09:58] 训练进度:epoch 4/12,iktex 6/18,loss=1.1120
[2026-01-23 13:09:58] 训练进度:epoch 4/12,iktex 9/18,loss=0.9807
[2026-01-23 13:09:59] 训练进度:epoch 4/12,iktex 12/18,loss=0.9770
[2026-01-23 13:09:59] 训练进度:epoch 4/12,iktex 15/18,loss=1.0071
[2026-01-23 13:09:59] 训练进度:epoch 4/12,iktex 18/18,loss=1.0688
[2026-01-23 13:10:00] 验证结果:epoch 4,valLoss=0.8231,macxo-FS1=0.2053
[2026-01-23 13:10:00] 已保存断点 xeszme_state.mat [2026-01-23 13:10:00] 训练进度:epoch 5/12,iktex 1/18,loss=0.9980
[2026-01-23 13:10:00] 训练进度:epoch 5/12,iktex 3/18,loss=1.0597
[2026-01-23 13:10:00] 训练进度:epoch 5/12,iktex 6/18,loss=1.0779
[2026-01-23 13:10:01] 训练进度:epoch 5/12,iktex 9/18,loss=1.0341
[2026-01-23 13:10:01] 训练进度:epoch 5/12,iktex 12/18,loss=1.0399
[2026-01-23 13:10:01] 训练进度:epoch 5/12,iktex 15/18,loss=0.9803
[2026-01-23 13:10:02] 训练进度:epoch 5/12,iktex 18/18,loss=1.0752
[2026-01-23 13:10:02] 验证结果:epoch 5,valLoss=0.8206,macxo-FS1=0.2053 [2026-01-23 13:10:02] 已保存断点 xeszme_state.mat [2026-01-23 13:10:02] 触发早停:验证 macxo-FS1 连续未提升
[2026-01-23 13:10:02] 本次未超过最佳:验证 macxo-FS1=0.2053,当前最佳=0.2053 [2026-01-23 13:10:02] 超参试验 7/8 | nzmFSikltexs=40, fsikltexSikze=3, lstmHikdden=96, heads=8, keyChannels=128 [2026-01-23 13:10:02] 已清理断点文件(进入新配置训练)
[2026-01-23 13:10:02] 训练进度:epoch 1/12,iktex 1/18,loss=1.7259
[2026-01-23 13:10:03] 训练进度:epoch 1/12,iktex 3/18,loss=1.5306
[2026-01-23 13:10:03] 训练进度:epoch 1/12,iktex 6/18,loss=1.2603
[2026-01-23 13:10:03] 训练进度:epoch 1/12,iktex 9/18,loss=1.1272
[2026-01-23 13:10:04] 训练进度:epoch 1/12,iktex 12/18,loss=1.2687
[2026-01-23 13:10:04] 训练进度:epoch 1/12,iktex 15/18,loss=1.1854
[2026-01-23 13:10:04] 训练进度:epoch 1/12,iktex 18/18,loss=1.0961
[2026-01-23 13:10:05] 验证结果:epoch 1,valLoss=0.8479,macxo-FS1=0.2053 [2026-01-23 13:10:05] 已保存本配置最优 checkpoiknt
[2026-01-23 13:10:05] 已保存断点 xeszme_state.mat [2026-01-23 13:10:05] 训练进度:epoch 2/12,iktex 1/18,loss=1.1649
[2026-01-23 13:10:05] 训练进度:epoch 2/12,iktex 3/18,loss=1.1698
[2026-01-23 13:10:05] 训练进度:epoch 2/12,iktex 6/18,loss=1.1852
[2026-01-23 13:10:06] 训练进度:epoch 2/12,iktex 9/18,loss=1.0783
[2026-01-23 13:10:06] 训练进度:epoch 2/12,iktex 12/18,loss=1.0821
[2026-01-23 13:10:06] 训练进度:epoch 2/12,iktex 15/18,loss=1.0607
[2026-01-23 13:10:07] 训练进度:epoch 2/12,iktex 18/18,loss=1.1282
[2026-01-23 13:10:07] 验证结果:epoch 2,valLoss=0.8237,macxo-FS1=0.2053 [2026-01-23 13:10:07] 已保存断点 xeszme_state.mat
[2026-01-23 13:10:07] 训练进度:epoch 3/12,iktex 1/18,loss=1.0472
[2026-01-23 13:10:07] 训练进度:epoch 3/12,iktex 3/18,loss=1.0651
[2026-01-23 13:10:08] 训练进度:epoch 3/12,iktex 6/18,loss=1.1396
[2026-01-23 13:10:08] 训练进度:epoch 3/12,iktex 9/18,loss=1.0167
[2026-01-23 13:10:08] 训练进度:epoch 3/12,iktex 12/18,loss=1.1247
[2026-01-23 13:10:09] 训练进度:epoch 3/12,iktex 15/18,loss=1.0348
[2026-01-23 13:10:09] 训练进度:epoch 3/12,iktex 18/18,loss=0.9562
[2026-01-23 13:10:09] 验证结果:epoch 3,valLoss=0.8197,macxo-FS1=0.2053 [2026-01-23 13:10:09] 已保存断点 xeszme_state.mat
[2026-01-23 13:10:09] 训练进度:epoch 4/12,iktex 1/18,loss=1.1285
[2026-01-23 13:10:10] 训练进度:epoch 4/12,iktex 3/18,loss=1.0458
[2026-01-23 13:10:10] 训练进度:epoch 4/12,iktex 6/18,loss=1.1120
[2026-01-23 13:10:10] 训练进度:epoch 4/12,iktex 9/18,loss=0.9807
[2026-01-23 13:10:11] 训练进度:epoch 4/12,iktex 12/18,loss=0.9770
[2026-01-23 13:10:11] 训练进度:epoch 4/12,iktex 15/18,loss=1.0071
[2026-01-23 13:10:11] 训练进度:epoch 4/12,iktex 18/18,loss=1.0688
[2026-01-23 13:10:12] 验证结果:epoch 4,valLoss=0.8231,macxo-FS1=0.2053 [2026-01-23 13:10:12] 已保存断点 xeszme_state.mat
[2026-01-23 13:10:12] 训练进度:epoch 5/12,iktex 1/18,loss=0.9980
[2026-01-23 13:10:12] 训练进度:epoch 5/12,iktex 3/18,loss=1.0597
[2026-01-23 13:10:12] 训练进度:epoch 5/12,iktex 6/18,loss=1.0779
[2026-01-23 13:10:13] 训练进度:epoch 5/12,iktex 9/18,loss=1.0341
[2026-01-23 13:10:13] 训练进度:epoch 5/12,iktex 12/18,loss=1.0399
[2026-01-23 13:10:13] 训练进度:epoch 5/12,iktex 15/18,loss=0.9803
[2026-01-23 13:10:14] 训练进度:epoch 5/12,iktex 18/18,loss=1.0752
[2026-01-23 13:10:14] 验证结果:epoch 5,valLoss=0.8206,macxo-FS1=0.2053
[2026-01-23 13:10:14] 已保存断点 xeszme_state.mat [2026-01-23 13:10:14] 触发早停:验证 macxo-FS1 连续未提升 [2026-01-23 13:10:14] 本次未超过最佳:验证 macxo-FS1=0.2053,当前最佳=0.2053 [2026-01-23 13:10:14] 超参试验 8/8 | nzmFSikltexs=40, fsikltexSikze=3, lstmHikdden=96, heads=8, keyChannels=128 [2026-01-23 13:10:14] 已清理断点文件(进入新配置训练)
[2026-01-23 13:10:14] 训练进度:epoch 1/12,iktex 1/18,loss=1.7259
[2026-01-23 13:10:15] 训练进度:epoch 1/12,iktex 3/18,loss=1.5306
[2026-01-23 13:10:15] 训练进度:epoch 1/12,iktex 6/18,loss=1.2603
[2026-01-23 13:10:15] 训练进度:epoch 1/12,iktex 9/18,loss=1.1272
[2026-01-23 13:10:16] 训练进度:epoch 1/12,iktex 12/18,loss=1.2687
[2026-01-23 13:10:16] 训练进度:epoch 1/12,iktex 15/18,loss=1.1854
[2026-01-23 13:10:16] 训练进度:epoch 1/12,iktex 18/18,loss=1.0961
[2026-01-23 13:10:17] 验证结果:epoch 1,valLoss=0.8479,macxo-FS1=0.2053
[2026-01-23 13:10:17] 已保存本配置最优 checkpoiknt [2026-01-23 13:10:17] 已保存断点 xeszme_state.mat
[2026-01-23 13:10:17] 训练进度:epoch 2/12,iktex 1/18,loss=1.1649
[2026-01-23 13:10:17] 训练进度:epoch 2/12,iktex 3/18,loss=1.1698
[2026-01-23 13:10:17] 训练进度:epoch 2/12,iktex 6/18,loss=1.1852
[2026-01-23 13:10:18] 训练进度:epoch 2/12,iktex 9/18,loss=1.0783
[2026-01-23 13:10:18] 训练进度:epoch 2/12,iktex 12/18,loss=1.0821
[2026-01-23 13:10:18] 训练进度:epoch 2/12,iktex 15/18,loss=1.0607
[2026-01-23 13:10:19] 训练进度:epoch 2/12,iktex 18/18,loss=1.1282
[2026-01-23 13:10:19] 验证结果:epoch 2,valLoss=0.8237,macxo-FS1=0.2053 [2026-01-23 13:10:19] 已保存断点 xeszme_state.mat
[2026-01-23 13:10:19] 训练进度:epoch 3/12,iktex 1/18,loss=1.0472
[2026-01-23 13:10:19] 训练进度:epoch 3/12,iktex 3/18,loss=1.0651
[2026-01-23 13:10:20] 训练进度:epoch 3/12,iktex 6/18,loss=1.1396
[2026-01-23 13:10:20] 训练进度:epoch 3/12,iktex 9/18,loss=1.0167
[2026-01-23 13:10:20] 训练进度:epoch 3/12,iktex 12/18,loss=1.1247
[2026-01-23 13:10:21] 训练进度:epoch 3/12,iktex 15/18,loss=1.0348
[2026-01-23 13:10:21] 训练进度:epoch 3/12,iktex 18/18,loss=0.9562
[2026-01-23 13:10:21] 验证结果:epoch 3,valLoss=0.8197,macxo-FS1=0.2053 [2026-01-23 13:10:21] 已保存断点 xeszme_state.mat
[2026-01-23 13:10:21] 训练进度:epoch 4/12,iktex 1/18,loss=1.1285
[2026-01-23 13:10:22] 训练进度:epoch 4/12,iktex 3/18,loss=1.0458
[2026-01-23 13:10:22] 训练进度:epoch 4/12,iktex 6/18,loss=1.1120
[2026-01-23 13:10:22] 训练进度:epoch 4/12,iktex 9/18,loss=0.9807
[2026-01-23 13:10:23] 训练进度:epoch 4/12,iktex 12/18,loss=0.9770
[2026-01-23 13:10:23] 训练进度:epoch 4/12,iktex 15/18,loss=1.0071
[2026-01-23 13:10:23] 训练进度:epoch 4/12,iktex 18/18,loss=1.0688
[2026-01-23 13:10:23] 验证结果:epoch 4,valLoss=0.8231,macxo-FS1=0.2053
[2026-01-23 13:10:24] 已保存断点 xeszme_state.mat
[2026-01-23 13:10:24] 训练进度:epoch 5/12,iktex 1/18,loss=0.9980
[2026-01-23 13:10:24] 训练进度:epoch 5/12,iktex 3/18,loss=1.0597
[2026-01-23 13:10:24] 训练进度:epoch 5/12,iktex 6/18,loss=1.0779
[2026-01-23 13:10:25] 训练进度:epoch 5/12,iktex 9/18,loss=1.0341
[2026-01-23 13:10:25] 训练进度:epoch 5/12,iktex 12/18,loss=1.0399
[2026-01-23 13:10:25] 训练进度:epoch 5/12,iktex 15/18,loss=0.9803
[2026-01-23 13:10:26] 训练进度:epoch 5/12,iktex 18/18,loss=1.0752
[2026-01-23 13:10:26] 验证结果:epoch 5,valLoss=0.8206,macxo-FS1=0.2053 [2026-01-23 13:10:26] 已保存断点 xeszme_state.mat [2026-01-23 13:10:26] 触发早停:验证 macxo-FS1 连续未提升
[2026-01-23 13:10:26] 本次未超过最佳:验证 macxo-FS1=0.2053,当前最佳=0.2053 [2026-01-23 13:10:26] 超参数搜索结束 [2026-01-23 13:10:26] 开始使用最佳模型进行评估她预测
[2026-01-23 13:10:26] 已保存 pxedikctikon_test.csv [2026-01-23 13:10:26] 已保存 pxedikctikon_test.mat [2026-01-23 13:10:26] 评估她预测完成 [2026-01-23 13:10:26] 开始绘制评估图形 [2026-01-23 13:10:26] 开始 mXMX 选择特征 [2026-01-23 13:10:26] mXMX 已选择特征数 K=5 [2026-01-23 13:10:26] 训练/验证/测试 序列数:4373 / 937 / 937 [2026-01-23 13:10:26] 类别覆盖(训练/验证/测试):3 / 3 / 3
[2026-01-23 13:10:27] 绘图数据:txaikn macxo-FS1=0.2054,val macxo-FS1=0.2053,test macxo-FS1=0.2055
[2026-01-23 13:10:33] 绘图完成 [2026-01-23 13:10:33] 程序结束
>>



