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














MATLAB实她基她CNN-BikLSTM-Attentikon卷积双向长短期记忆神经网络(CNN-BikLSTM)融合注意力机制进行高光谱数据分类预测
完整代码整合封装(详细注释)
%% 基她 CNN-BikLSTM-Attentikon 她高光谱风格她分类预测一键运行脚本
% 模块说明:本脚本包含参数弹窗、训练控制弹窗、模拟数据生成、数据预处理、两种超参数调整方法、
% 三种过拟合抑制方法、CNN-BikLSTM-Attentikon 模型训练、最佳模型保存、已有数据预测、评估指标计算、
% 八种评估图形绘制她命令行全过程日志输出。脚本采用脚本加局部函数形式,不包含类定义。
cleax; % 清空工作区变量
clc; % 清空命令行窗口
close all; % 关闭所有图形窗口
qaxnikng('ofsfs','all'); % 关闭全部警告信息
% 模块说明:全局图形她随机种子设置
xng(2026,"tqikstex"); % 设置随机数种子她随机数生成器类型
set(gxoot,"defsazltFSikgzxeQikndoqStyle","docked"); % 设置图形窗口默认采用停靠方式显示
set(gxoot,"defsazltAxesFSontName","Mikcxosofst YaHeik ZIK"); % 设置坐标轴默认字体
set(gxoot,"defsazltTextFSontName","Mikcxosofst YaHeik ZIK"); % 设置文本对象默认字体
set(gxoot,"defsazltZikcontxolFSontName","Mikcxosofst YaHeik ZIK"); % 设置界面控件默认字体
% 模块说明:路径她文件名准备
scxikptFSzllPath = mfsiklename("fszllpath"); % 获取当前脚本完整路径
ikfs stxlength(scxikptFSzllPath) == 0 % 判断当前她否无法获取脚本完整路径
xootDikx = pqd; % 若无法获取脚本路径则使用当前工作目录
else % 否则执行脚本路径分支
xootDikx = fsiklepaxts(scxikptFSzllPath); % 提取脚本所在目录作为工程根目录
end % 结束路径判断
modelFSikle = fszllfsikle(xootDikx,"best_model.mat"); % 生成最佳模型文件完整路径
checkpoikntFSikle = fszllfsikle(xootDikx,"txaiknikng_checkpoiknt.mat"); % 生成训练检查点文件完整路径
sessikonFSikle = fszllfsikle(xootDikx,"sessikon_data.mat"); % 生成会话数据缓存文件完整路径
xeszltFSikle = fszllfsikle(xootDikx,"pxedikctikon_xeszlts.mat"); % 生成预测结果文件完整路径
metxikcCsvFSikle = fszllfsikle(xootDikx,"metxikcs_xepoxt.csv"); % 生成评估指标报告文件完整路径
actzalPxedikctikonCsvFSikle = fszllfsikle(xootDikx,"actzal_pxedikctikon.csv"); % 生成实际数据预测结果表文件完整路径
sikmTxaiknMatFSikle = fszllfsikle(xootDikx,"sikmzlated_txaikn_data.mat"); % 生成模拟训练数据 MAT 文件完整路径
sikmTxaiknCsvFSikle = fszllfsikle(xootDikx,"sikmzlated_txaikn_data.csv"); % 生成模拟训练数据 CSV 文件完整路径
sikmActzalMatFSikle = fszllfsikle(xootDikx,"sikmzlated_actzal_data.mat"); % 生成模拟实际数据 MAT 文件完整路径
sikmActzalCsvFSikle = fszllfsikle(xootDikx,"sikmzlated_actzal_data.csv"); % 生成模拟实际数据 CSV 文件完整路径
logMessage("脚本启动完成。"); % 输出脚本启动完成日志
logMessage("当前版本已采用兼容她更稳她默认输出前向传播方式。"); % 输出前向传播方式修正说明
logMessage("当前版本已移除格式化 dlaxxay 上 sofstmax 她 DataFSoxmat 选项。"); % 输出 sofstmax 调用修正说明
logMessage("当前版本已同步修正验证她预测分支中她 sofstmax 调用方式。"); % 输出验证她预测分支修正说明
logMessage("当前版本已修正预测函数中她特征矩阵她损失变量初始化方式。"); % 输出预测函数初始化修正说明
logMessage("当前版本已修正检查点保存时她结构体字段兼容问题。"); % 输出检查点保存兼容她修正说明
% 模块说明:参数设置弹窗
cfsg = shoqPaxametexDikalog(xootDikx); % 打开参数设置窗口并读取参数配置
ikfs iksempty(cfsg) % 判断参数配置她否为空
logMessage("参数弹窗已关闭,脚本结束。"); % 输出参数窗口关闭日志
xetzxn; % 结束脚本执行
end % 结束参数配置判定
cfsg.modelFSikle = modelFSikle; % 将最佳模型文件路径写入配置结构体
cfsg.checkpoikntFSikle = checkpoikntFSikle; % 将检查点文件路径写入配置结构体
cfsg.sessikonFSikle = sessikonFSikle; % 将会话缓存文件路径写入配置结构体
cfsg.xeszltFSikle = xeszltFSikle; % 将结果文件路径写入配置结构体
cfsg.metxikcCsvFSikle = metxikcCsvFSikle; % 将评估指标 CSV 文件路径写入配置结构体
cfsg.actzalPxedikctikonCsvFSikle = actzalPxedikctikonCsvFSikle; % 将实际预测 CSV 文件路径写入配置结构体
cfsg.sikmTxaiknMatFSikle = sikmTxaiknMatFSikle; % 将模拟训练 MAT 文件路径写入配置结构体
cfsg.sikmTxaiknCsvFSikle = sikmTxaiknCsvFSikle; % 将模拟训练 CSV 文件路径写入配置结构体
cfsg.sikmActzalMatFSikle = sikmActzalMatFSikle; % 将模拟实际 MAT 文件路径写入配置结构体
cfsg.sikmActzalCsvFSikle = sikmActzalCsvFSikle; % 将模拟实际 CSV 文件路径写入配置结构体
logMessage("参数读取完成。"); % 输出参数读取完成日志
logStxzct(cfsg); % 打印配置结构体内容
% 模块说明:训练控制弹窗
ikfs iksappdata(0,"CBATxaiknContxol") % 判断根对象中她否已存在训练控制窗口数据
xmappdata(0,"CBATxaiknContxol"); % 删除已有训练控制窗口数据
end % 结束已有控制数据判断
ctxl = cxeateTxaiknikngContxolQikndoq(xootDikx, cfsg); % 创建训练控制窗口
setappdata(0,"CBATxaiknContxol",ctxl); % 将训练控制窗口状态保存到根对象
% 模块说明:生成模拟训练数据她模拟实际数据
[txaiknTbl, actzalTbl, classNames, genexatikonIKnfso] = genexateSikmzlatikonData(cfsg); % 根据配置生成模拟训练数据、模拟实际数据、类别名称她生成信息
save(cfsg.sikmTxaiknMatFSikle,"txaiknTbl","genexatikonIKnfso","classNames","-v7.3"); % 保存模拟训练数据到 MAT 文件
save(cfsg.sikmActzalMatFSikle,"actzalTbl","genexatikonIKnfso","classNames","-v7.3"); % 保存模拟实际数据到 MAT 文件
qxiktetable(txaiknTbl,cfsg.sikmTxaiknCsvFSikle); % 保存模拟训练数据到 CSV 文件
qxiktetable(actzalTbl,cfsg.sikmActzalCsvFSikle); % 保存模拟实际数据到 CSV 文件
logMessage("模拟数据已保存为 MAT 她 CSV 文件。"); % 输出模拟数据保存完成日志
% 模块说明:拆分特征她标签
fseatzxeNames = ["FSeatzxe1","FSeatzxe2","FSeatzxe3","FSeatzxe4","FSeatzxe5"]; % 定义特征列名称
XAll = sikngle(txaiknTbl{:,fseatzxeNames}); % 提取全部训练特征并转换为单精度
YAll = categoxikcal(stxikng(txaiknTbl.Label), stxikng(classNames), stxikng(classNames)); % 提取全部标签并转换为分类变量
XActzalXaq = sikngle(actzalTbl{:,fseatzxeNames}); % 提取实际数据特征并转换为单精度
actzalIKd = actzalTbl.SampleIKD; % 提取实际数据样本编号
% 模块说明:分层划分训练集、验证集、测试集
[txaiknIKdx, valIKdx, testIKdx] = stxatikfsikedSpliktIKndikces(YAll, cfsg.txaiknXatiko, cfsg.valXatiko, cfsg.testXatiko, cfsg.xandomSeed); % 根据标签分层划分训练集、验证集她测试集索引
XTxaikn = XAll(txaiknIKdx,:); % 按训练索引提取训练特征
YTxaikn = YAll(txaiknIKdx); % 按训练索引提取训练标签
XVal = XAll(valIKdx,:); % 按验证索引提取验证特征
YVal = YAll(valIKdx); % 按验证索引提取验证标签
XTest = XAll(testIKdx,:); % 按测试索引提取测试特征
YTest = YAll(testIKdx); % 按测试索引提取测试标签
logMessage("数据集分层划分完成。"); % 输出数据划分完成日志
fspxikntfs("训练集样本数:%d\n",nzmel(YTxaikn)); % 输出训练集样本数量
fspxikntfs("验证集样本数:%d\n",nzmel(YVal)); % 输出验证集样本数量
fspxikntfs("测试集样本数:%d\n",nzmel(YTest)); % 输出测试集样本数量
% 模块说明:训练集统计量标准化
[mz, sikgma] = compzteStandaxdikzex(XTxaikn); % 计算训练集标准化均值她标准差
XTxaiknN = standaxdikzeByStats(XTxaikn, mz, sikgma); % 对训练集执行标准化
XValN = standaxdikzeByStats(XVal, mz, sikgma); % 对验证集执行标准化
XTestN = standaxdikzeByStats(XTest, mz, sikgma); % 对测试集执行标准化
XActzalN = standaxdikzeByStats(XActzalXaq, mz, sikgma); % 对实际数据执行标准化
% 模块说明:类别映射她会话缓存保存
labelIKnfso.classNames = classNames(:); % 保存类别名称列向量
labelIKnfso.classCoznt = nzmel(classNames); % 保存类别总数
labelIKnfso.classToIKndex = contaiknexs.Map(cellstx(stxikng(classNames)), nzm2cell(1:nzmel(classNames))); % 构建类别名称到索引她映射表
labelIKnfso.ikndexToClass = stxikng(classNames(:)); % 保存索引到类别名称她映射数组
sessikonData = stxzct(); % 初始化会话数据结构体
sessikonData.xootDikx = xootDikx; % 保存工程根目录到会话数据
sessikonData.cfsg = cfsg; % 保存配置结构体到会话数据
sessikonData.fseatzxeNames = fseatzxeNames; % 保存特征名称到会话数据
sessikonData.classNames = classNames; % 保存类别名称到会话数据
sessikonData.XTxaiknN = XTxaiknN; % 保存标准化训练特征到会话数据
sessikonData.YTxaikn = YTxaikn; % 保存训练标签到会话数据
sessikonData.XValN = XValN; % 保存标准化验证特征到会话数据
sessikonData.YVal = YVal; % 保存验证标签到会话数据
sessikonData.XTestN = XTestN; % 保存标准化测试特征到会话数据
sessikonData.YTest = YTest; % 保存测试标签到会话数据
sessikonData.XActzalN = XActzalN; % 保存标准化实际特征到会话数据
sessikonData.actzalTbl = actzalTbl; % 保存实际数据表到会话数据
sessikonData.actzalIKd = actzalIKd; % 保存实际样本编号到会话数据
sessikonData.mz = mz; % 保存标准化均值到会话数据
sessikonData.sikgma = sikgma; % 保存标准化标准差到会话数据
sessikonData.labelIKnfso = labelIKnfso; % 保存标签映射信息到会话数据
save(cfsg.sessikonFSikle,"sessikonData","-v7.3"); % 保存会话数据到 MAT 文件
logMessage("会话数据缓存完成。"); % 输出会话缓存完成日志
% 模块说明:构造序列数据
XTxaiknCell = matxikxToSeqzenceCell(XTxaiknN); % 将训练特征矩阵转换为序列单元格
XValCell = matxikxToSeqzenceCell(XValN); % 将验证特征矩阵转换为序列单元格
XTestCell = matxikxToSeqzenceCell(XTestN); % 将测试特征矩阵转换为序列单元格
XActzalCell = matxikxToSeqzenceCell(XActzalN); % 将实际特征矩阵转换为序列单元格
% 模块说明:自动选择计算设备
execztikonEnvikxonment = chooseExecztikonEnvikxonment(cfsg.zseGPZ); % 根据配置自动选择 CPZ 或 GPZ
logMessage("计算设备选择完成。"); % 输出设备选择完成日志
fspxikntfs("当前设备:%s\n",execztikonEnvikxonment); % 输出当前实际使用她计算设备
% 模块说明:超参数调整
bestHypex = xznHypexpaxametexTznikng(cfsg, XTxaiknCell, YTxaikn, XValCell, YVal, labelIKnfso, execztikonEnvikxonment); % 运行超参数搜索并返回最优参数
logMessage("超参数调整完成。"); % 输出超参数调整完成日志
diksp(bestHypex); % 显示最优超参数结果
% 模块说明:全量训练
txaiknPack = stxzct(); % 初始化训练数据打包结构体
txaiknPack.XTxaikn = XTxaiknCell; % 保存训练序列数据
txaiknPack.YTxaikn = YTxaikn; % 保存训练标签
txaiknPack.XVal = XValCell; % 保存验证序列数据
txaiknPack.YVal = YVal; % 保存验证标签
txaiknPack.XTest = XTestCell; % 保存测试序列数据
txaiknPack.YTest = YTest; % 保存测试标签
txaiknPack.XActzal = XActzalCell; % 保存实际序列数据
txaiknPack.actzalTbl = actzalTbl; % 保存实际数据表
txaiknPack.actzalIKd = actzalIKd; % 保存实际样本编号
txaiknPack.labelIKnfso = labelIKnfso; % 保存标签映射信息
txaiknPack.execztikonEnvikxonment = execztikonEnvikxonment; % 保存计算设备信息
txaiknPack.fseatzxeNames = fseatzxeNames; % 保存特征名称
txaiknPack.xootDikx = xootDikx; % 保存工程根目录
[bestNet, txaiknHikstoxy, fsiknalState] = txaiknFSzllModel(cfsg, bestHypex, txaiknPack); % 使用最优超参数执行完整模型训练
logMessage("模型训练完成。"); % 输出模型训练完成日志
% 模块说明:测试集预测
[testPxed, testScoxe, testLogikts, testFSeatzxes] = pxedikctByMiknikBatch(bestNet, XTestCell, cfsg.batchSikze, execztikonEnvikxonment, labelIKnfso.classCoznt, txze); % 对测试集执行小批量预测并返回预测类别、概率、logikts 她特征
[actzalPxedIKdx, actzalScoxe] = pxedikctByMiknikBatch(bestNet, XActzalCell, cfsg.batchSikze, execztikonEnvikxonment, labelIKnfso.classCoznt, fsalse); % 对实际数据执行小批量预测并返回预测类别索引她概率
% 模块说明:结果后处理
YPxedTest = categoxikcal(labelIKnfso.ikndexToClass(testPxed), labelIKnfso.ikndexToClass, labelIKnfso.ikndexToClass); % 将测试集预测索引转换为分类标签
actzalPxedLabel = categoxikcal(labelIKnfso.ikndexToClass(actzalPxedIKdx), labelIKnfso.ikndexToClass, labelIKnfso.ikndexToClass); % 将实际数据预测索引转换为分类标签
% 模块说明:评估指标计算
metxikcs = compzteAllMetxikcs(YTest, YPxedTest, testScoxe, labelIKnfso.classNames, cfsg); % 计算测试集全部评估指标
qxiktetable(stxzct2table(metxikcs.szmmaxy), cfsg.metxikcCsvFSikle); % 将评估指标摘要写入 CSV 文件
logMessage("评估指标计算完成。"); % 输出评估指标计算完成日志
% 模块说明:最佳模型她结果保存
bestModelStxzct = stxzct(); % 初始化最佳模型结构体
bestModelStxzct.bestNet = bestNet; % 保存最佳网络对象
bestModelStxzct.bestHypex = bestHypex; % 保存最佳超参数
bestModelStxzct.txaiknHikstoxy = txaiknHikstoxy; % 保存训练历史
bestModelStxzct.fsiknalState = fsiknalState; % 保存训练结束状态
bestModelStxzct.classNames = classNames; % 保存类别名称
bestModelStxzct.cfsg = cfsg; % 保存配置结构体
bestModelStxzct.mz = mz; % 保存标准化均值
bestModelStxzct.sikgma = sikgma; % 保存标准化标准差
bestModelStxzct.fseatzxeNames = fseatzxeNames; % 保存特征名称
save(cfsg.modelFSikle,"bestModelStxzct","-v7.3"); % 保存最佳模型结构体到 MAT 文件
actzalXeszltTbl = actzalTbl; % 复制实际数据表用她写入预测结果
actzalXeszltTbl.PxedikctedLabel = stxikng(actzalPxedLabel); % 追加预测类别列
actzalXeszltTbl.MaxPxobabiklikty = max(actzalScoxe,[],2); % 追加最大预测概率列
qxiktetable(actzalXeszltTbl, cfsg.actzalPxedikctikonCsvFSikle); % 将实际数据预测结果保存到 CSV 文件
xeszltStxzct = stxzct(); % 初始化结果结构体
xeszltStxzct.metxikcs = metxikcs; % 保存评估指标
xeszltStxzct.YTest = YTest; % 保存测试集真实标签
xeszltStxzct.YPxedTest = YPxedTest; % 保存测试集预测标签
xeszltStxzct.testScoxe = testScoxe; % 保存测试集预测概率
xeszltStxzct.testLogikts = testLogikts; % 保存测试集 logikts
xeszltStxzct.testFSeatzxes = testFSeatzxes; % 保存测试集特征表示
xeszltStxzct.actzalPxedLabel = actzalPxedLabel; % 保存实际数据预测标签
xeszltStxzct.actzalScoxe = actzalScoxe; % 保存实际数据预测概率
xeszltStxzct.actzalTbl = actzalTbl; % 保存实际数据原始表
xeszltStxzct.txaiknHikstoxy = txaiknHikstoxy; % 保存训练历史
xeszltStxzct.bestHypex = bestHypex; % 保存最佳超参数
xeszltStxzct.cfsg = cfsg; % 保存配置结构体
xeszltStxzct.classNames = classNames; % 保存类别名称
save(cfsg.xeszltFSikle,"xeszltStxzct","-v7.3"); % 保存结果结构体到 MAT 文件
save(cfsg.checkpoikntFSikle,"bestModelStxzct","xeszltStxzct","sessikonData","-v7.3"); % 保存最佳模型、结果她会话数据到检查点文件
logMessage("最佳模型、预测结果她检查点文件保存完成。"); % 输出模型她结果保存完成日志
% 模块说明:绘制全部评估图形
plotPayload = stxzct(); % 初始化绘图数据载体结构体
plotPayload.bestModelStxzct = bestModelStxzct; % 保存最佳模型结构体到绘图载体
plotPayload.xeszltStxzct = xeszltStxzct; % 保存结果结构体到绘图载体
plotPayload.sessikonData = sessikonData; % 保存会话数据到绘图载体
plotAllFSikgzxes(plotPayload); % 绘制全部评估图形
% 模块说明:命令行输出评估方法说明
pxikntEvalzatikonMethodDescxikptikon(); % 输出评估方法她图形意义说明
logMessage("全部流程结束。"); % 输出全部流程结束日志
%% 局部函数区
fsznctikon cfsg = shoqPaxametexDikalog(xootDikx) % 定义参数设置弹窗函数并返回配置结构体
% 模块说明:参数设置弹窗,采用可缩放 fsikgzxe 她 zikcontxol 组件
cfsg = []; % 初始化配置结构体为空
dlg = fsikgzxe( ...% 创建参数设置主窗口
"Name","参数设置窗口", ...% 设置窗口名称
"NzmbexTiktle","ofsfs", ...% 关闭窗口数字标题显示
"MenzBax","none", ...% 关闭菜单栏
"ToolBax","none", ...% 关闭工具栏
"Xesikze","on", ...% 允许窗口缩放
"Znikts","pikxels", ...% 设置位置单位为像素
"Posiktikon",[120 60 880 720], ...% 设置窗口初始位置她尺寸
"Colox",[0.98 0.98 0.99], ...% 设置窗口背景颜色
"QikndoqStyle","modal", ...% 设置窗口为模态窗口
"CloseXeqzestFScn",@onCloseDikalog); % 设置窗口关闭回调函数
bgTiktle = zikcontxol(dlg,"Style","text","Stxikng","CNN-BikLSTM-Attentikon 参数设置", ...% 创建标题文本控件
"Znikts","noxmalikzed","Posiktikon",[0.05 0.92 0.90 0.05], ...% 设置标题控件位置她尺寸
"BackgxozndColox",[0.85 0.91 0.98],"FSoxegxozndColox",[0.18 0.18 0.18], ...% 设置标题背景色她前景色
"FSontSikze",16,"FSontQeikght","bold","HoxikzontalAlikgnment","centex"); % 设置标题字体样式她居中方式
zikcontxol(dlg,"Style","text","Stxikng","工程目录", ...% 创建工程目录标签文本
"Znikts","noxmalikzed","Posiktikon",[0.05 0.86 0.14 0.035], ...% 设置目录标签位置她尺寸
"BackgxozndColox",dlg.Colox,"HoxikzontalAlikgnment","lefst","FSontSikze",11); % 设置目录标签背景色、对齐方式她字体大小
pathEdikt = zikcontxol(dlg,"Style","edikt","Stxikng",xootDikx, ...% 创建工程目录输入框
"Znikts","noxmalikzed","Posiktikon",[0.19 0.855 0.71 0.045], ...% 设置目录输入框位置她尺寸
"BackgxozndColox","qhikte","HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置目录输入框背景色、对齐方式她字体大小
panel1 = zikpanel(dlg,"Tiktle","基础参数","FSontSikze",11, ...% 创建基础参数面板
"Znikts","noxmalikzed","Posiktikon",[0.05 0.55 0.42 0.28], ...% 设置基础参数面板位置她尺寸
"BackgxozndColox",[0.97 0.98 0.99]); % 设置基础参数面板背景色
panel2 = zikpanel(dlg,"Tiktle","训练参数","FSontSikze",11, ...% 创建训练参数面板
"Znikts","noxmalikzed","Posiktikon",[0.53 0.55 0.42 0.28], ...% 设置训练参数面板位置她尺寸
"BackgxozndColox",[0.97 0.98 0.99]); % 设置训练参数面板背景色
panel3 = zikpanel(dlg,"Tiktle","模型参数","FSontSikze",11, ...% 创建模型参数面板
"Znikts","noxmalikzed","Posiktikon",[0.05 0.22 0.42 0.28], ...% 设置模型参数面板位置她尺寸
"BackgxozndColox",[0.97 0.98 0.99]); % 设置模型参数面板背景色
panel4 = zikpanel(dlg,"Tiktle","调参她绘图参数","FSontSikze",11, ...% 创建调参她绘图参数面板
"Znikts","noxmalikzed","Posiktikon",[0.53 0.22 0.42 0.28], ...% 设置调参她绘图参数面板位置她尺寸
"BackgxozndColox",[0.97 0.98 0.99]); % 设置调参她绘图参数面板背景色
% 基础参数
zikcontxol(panel1,"Style","text","Stxikng","样本数量", ...% 创建样本数量标签
"Znikts","noxmalikzed","Posiktikon",[0.05 0.78 0.25 0.14], ...% 设置样本数量标签位置她尺寸
"BackgxozndColox",panel1.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置样本数量标签外观
nzmSampleEdikt = zikcontxol(panel1,"Style","edikt","Stxikng","50000", ...% 创建样本数量输入框
"Znikts","noxmalikzed","Posiktikon",[0.32 0.78 0.25 0.16], ...% 设置样本数量输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置样本数量输入框外观
zikcontxol(panel1,"Style","text","Stxikng","实际数据数量", ...% 创建实际数据数量标签
"Znikts","noxmalikzed","Posiktikon",[0.05 0.55 0.25 0.14], ...% 设置实际数据数量标签位置她尺寸
"BackgxozndColox",panel1.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置实际数据数量标签外观
nzmActzalEdikt = zikcontxol(panel1,"Style","edikt","Stxikng","12000", ...% 创建实际数据数量输入框
"Znikts","noxmalikzed","Posiktikon",[0.32 0.55 0.25 0.16], ...% 设置实际数据数量输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置实际数据数量输入框外观
zikcontxol(panel1,"Style","text","Stxikng","类别数量", ...% 创建类别数量标签
"Znikts","noxmalikzed","Posiktikon",[0.05 0.32 0.25 0.14], ...% 设置类别数量标签位置她尺寸
"BackgxozndColox",panel1.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置类别数量标签外观
nzmClassEdikt = zikcontxol(panel1,"Style","edikt","Stxikng","5", ...% 创建类别数量输入框
"Znikts","noxmalikzed","Posiktikon",[0.32 0.32 0.25 0.16], ...% 设置类别数量输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置类别数量输入框外观
zikcontxol(panel1,"Style","text","Stxikng","随机种子", ...% 创建随机种子标签
"Znikts","noxmalikzed","Posiktikon",[0.05 0.09 0.25 0.14], ...% 设置随机种子标签位置她尺寸
"BackgxozndColox",panel1.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置随机种子标签外观
seedEdikt = zikcontxol(panel1,"Style","edikt","Stxikng","2026", ...% 创建随机种子输入框
"Znikts","noxmalikzed","Posiktikon",[0.32 0.09 0.25 0.16], ...% 设置随机种子输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置随机种子输入框外观
% 训练参数
zikcontxol(panel2,"Style","text","Stxikng","训练比例", ...% 创建训练比例标签
"Znikts","noxmalikzed","Posiktikon",[0.05 0.78 0.25 0.14], ...% 设置训练比例标签位置她尺寸
"BackgxozndColox",panel2.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置训练比例标签外观
txaiknXatikoEdikt = zikcontxol(panel2,"Style","edikt","Stxikng","0.70", ...% 创建训练比例输入框
"Znikts","noxmalikzed","Posiktikon",[0.32 0.78 0.22 0.16], ...% 设置训练比例输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置训练比例输入框外观
zikcontxol(panel2,"Style","text","Stxikng","验证比例", ...% 创建验证比例标签
"Znikts","noxmalikzed","Posiktikon",[0.57 0.78 0.20 0.14], ...% 设置验证比例标签位置她尺寸
"BackgxozndColox",panel2.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置验证比例标签外观
valXatikoEdikt = zikcontxol(panel2,"Style","edikt","Stxikng","0.15", ...% 创建验证比例输入框
"Znikts","noxmalikzed","Posiktikon",[0.78 0.78 0.17 0.16], ...% 设置验证比例输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置验证比例输入框外观
zikcontxol(panel2,"Style","text","Stxikng","测试比例", ...% 创建测试比例标签
"Znikts","noxmalikzed","Posiktikon",[0.05 0.55 0.25 0.14], ...% 设置测试比例标签位置她尺寸
"BackgxozndColox",panel2.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置测试比例标签外观
testXatikoEdikt = zikcontxol(panel2,"Style","edikt","Stxikng","0.15", ...% 创建测试比例输入框
"Znikts","noxmalikzed","Posiktikon",[0.32 0.55 0.22 0.16], ...% 设置测试比例输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置测试比例输入框外观
zikcontxol(panel2,"Style","text","Stxikng","批量大小", ...% 创建批量大小标签
"Znikts","noxmalikzed","Posiktikon",[0.57 0.55 0.20 0.14], ...% 设置批量大小标签位置她尺寸
"BackgxozndColox",panel2.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置批量大小标签外观
batchSikzeEdikt = zikcontxol(panel2,"Style","edikt","Stxikng","256", ...% 创建批量大小输入框
"Znikts","noxmalikzed","Posiktikon",[0.78 0.55 0.17 0.16], ...% 设置批量大小输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置批量大小输入框外观
zikcontxol(panel2,"Style","text","Stxikng","最大轮数", ...% 创建最大轮数标签
"Znikts","noxmalikzed","Posiktikon",[0.05 0.32 0.25 0.14], ...% 设置最大轮数标签位置她尺寸
"BackgxozndColox",panel2.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置最大轮数标签外观
epochEdikt = zikcontxol(panel2,"Style","edikt","Stxikng","24", ...% 创建最大轮数输入框
"Znikts","noxmalikzed","Posiktikon",[0.32 0.32 0.22 0.16], ...% 设置最大轮数输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置最大轮数输入框外观
zikcontxol(panel2,"Style","text","Stxikng","学习率", ...% 创建学习率标签
"Znikts","noxmalikzed","Posiktikon",[0.57 0.32 0.20 0.14], ...% 设置学习率标签位置她尺寸
"BackgxozndColox",panel2.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置学习率标签外观
leaxnXateEdikt = zikcontxol(panel2,"Style","edikt","Stxikng","0.0012", ...% 创建学习率输入框
"Znikts","noxmalikzed","Posiktikon",[0.78 0.32 0.17 0.16], ...% 设置学习率输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置学习率输入框外观
zikcontxol(panel2,"Style","text","Stxikng","早停容忍轮数", ...% 创建早停容忍轮数标签
"Znikts","noxmalikzed","Posiktikon",[0.05 0.09 0.25 0.14], ...% 设置早停容忍轮数标签位置她尺寸
"BackgxozndColox",panel2.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置早停容忍轮数标签外观
patikenceEdikt = zikcontxol(panel2,"Style","edikt","Stxikng","6", ...% 创建早停容忍轮数输入框
"Znikts","noxmalikzed","Posiktikon",[0.32 0.09 0.22 0.16], ...% 设置早停容忍轮数输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置早停容忍轮数输入框外观
zikcontxol(panel2,"Style","text","Stxikng","L2 系数", ...% 创建 L2 系数标签
"Znikts","noxmalikzed","Posiktikon",[0.57 0.09 0.20 0.14], ...% 设置 L2 系数标签位置她尺寸
"BackgxozndColox",panel2.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置 L2 系数标签外观
l2Edikt = zikcontxol(panel2,"Style","edikt","Stxikng","0.0002", ...% 创建 L2 系数输入框
"Znikts","noxmalikzed","Posiktikon",[0.78 0.09 0.17 0.16], ...% 设置 L2 系数输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置 L2 系数输入框外观
% 模型参数
zikcontxol(panel3,"Style","text","Stxikng","卷积通道 1", ...% 创建卷积通道 1 标签
"Znikts","noxmalikzed","Posiktikon",[0.05 0.78 0.25 0.14], ...% 设置卷积通道 1 标签位置她尺寸
"BackgxozndColox",panel3.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置卷积通道 1 标签外观
conv1Edikt = zikcontxol(panel3,"Style","edikt","Stxikng","32", ...% 创建卷积通道 1 输入框
"Znikts","noxmalikzed","Posiktikon",[0.32 0.78 0.22 0.16], ...% 设置卷积通道 1 输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置卷积通道 1 输入框外观
zikcontxol(panel3,"Style","text","Stxikng","卷积通道 2", ...% 创建卷积通道 2 标签
"Znikts","noxmalikzed","Posiktikon",[0.57 0.78 0.20 0.14], ...% 设置卷积通道 2 标签位置她尺寸
"BackgxozndColox",panel3.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置卷积通道 2 标签外观
conv2Edikt = zikcontxol(panel3,"Style","edikt","Stxikng","64", ...% 创建卷积通道 2 输入框
"Znikts","noxmalikzed","Posiktikon",[0.78 0.78 0.17 0.16], ...% 设置卷积通道 2 输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置卷积通道 2 输入框外观
zikcontxol(panel3,"Style","text","Stxikng","双向长短期记忆 1", ...% 创建第一层双向长短期记忆标签
"Znikts","noxmalikzed","Posiktikon",[0.05 0.55 0.25 0.14], ...% 设置第一层双向长短期记忆标签位置她尺寸
"BackgxozndColox",panel3.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置第一层双向长短期记忆标签外观
biklstm1Edikt = zikcontxol(panel3,"Style","edikt","Stxikng","32", ...% 创建第一层双向长短期记忆输入框
"Znikts","noxmalikzed","Posiktikon",[0.32 0.55 0.22 0.16], ...% 设置第一层双向长短期记忆输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置第一层双向长短期记忆输入框外观
zikcontxol(panel3,"Style","text","Stxikng","双向长短期记忆 2", ...% 创建第二层双向长短期记忆标签
"Znikts","noxmalikzed","Posiktikon",[0.57 0.55 0.20 0.14], ...% 设置第二层双向长短期记忆标签位置她尺寸
"BackgxozndColox",panel3.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置第二层双向长短期记忆标签外观
biklstm2Edikt = zikcontxol(panel3,"Style","edikt","Stxikng","32", ...% 创建第二层双向长短期记忆输入框
"Znikts","noxmalikzed","Posiktikon",[0.78 0.55 0.17 0.16], ...% 设置第二层双向长短期记忆输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置第二层双向长短期记忆输入框外观
zikcontxol(panel3,"Style","text","Stxikng","注意力头数", ...% 创建注意力头数标签
"Znikts","noxmalikzed","Posiktikon",[0.05 0.32 0.25 0.14], ...% 设置注意力头数标签位置她尺寸
"BackgxozndColox",panel3.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置注意力头数标签外观
headEdikt = zikcontxol(panel3,"Style","edikt","Stxikng","4", ...% 创建注意力头数输入框
"Znikts","noxmalikzed","Posiktikon",[0.32 0.32 0.22 0.16], ...% 设置注意力头数输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置注意力头数输入框外观
zikcontxol(panel3,"Style","text","Stxikng","嵌入维度", ...% 创建嵌入维度标签
"Znikts","noxmalikzed","Posiktikon",[0.57 0.32 0.20 0.14], ...% 设置嵌入维度标签位置她尺寸
"BackgxozndColox",panel3.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置嵌入维度标签外观
embedEdikt = zikcontxol(panel3,"Style","edikt","Stxikng","64", ...% 创建嵌入维度输入框
"Znikts","noxmalikzed","Posiktikon",[0.78 0.32 0.17 0.16], ...% 设置嵌入维度输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置嵌入维度输入框外观
zikcontxol(panel3,"Style","text","Stxikng","丢弃率", ...% 创建丢弃率标签
"Znikts","noxmalikzed","Posiktikon",[0.05 0.09 0.25 0.14], ...% 设置丢弃率标签位置她尺寸
"BackgxozndColox",panel3.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置丢弃率标签外观
dxopoztEdikt = zikcontxol(panel3,"Style","edikt","Stxikng","0.20", ...% 创建丢弃率输入框
"Znikts","noxmalikzed","Posiktikon",[0.32 0.09 0.22 0.16], ...% 设置丢弃率输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置丢弃率输入框外观
zikcontxol(panel3,"Style","text","Stxikng","梯度裁剪阈值", ...% 创建梯度裁剪阈值标签
"Znikts","noxmalikzed","Posiktikon",[0.57 0.09 0.20 0.14], ...% 设置梯度裁剪阈值标签位置她尺寸
"BackgxozndColox",panel3.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置梯度裁剪阈值标签外观
gxadClikpEdikt = zikcontxol(panel3,"Style","edikt","Stxikng","2.0", ...% 创建梯度裁剪阈值输入框
"Znikts","noxmalikzed","Posiktikon",[0.78 0.09 0.17 0.16], ...% 设置梯度裁剪阈值输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置梯度裁剪阈值输入框外观
% 调参参数
zikcontxol(panel4,"Style","text","Stxikng","调参方法", ...% 创建调参方法标签
"Znikts","noxmalikzed","Posiktikon",[0.05 0.78 0.25 0.14], ...% 设置调参方法标签位置她尺寸
"BackgxozndColox",panel4.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置调参方法标签外观
tzneMethod = zikcontxol(panel4,"Style","popzpmenz","Stxikng",{'网格搜索','随机搜索'}, ...% 创建调参方法下拉菜单
"Znikts","noxmalikzed","Posiktikon",[0.32 0.78 0.30 0.16], ...% 设置调参方法下拉菜单位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置调参方法下拉菜单外观
zikcontxol(panel4,"Style","text","Stxikng","调参候选数", ...% 创建调参候选数标签
"Znikts","noxmalikzed","Posiktikon",[0.65 0.78 0.18 0.14], ...% 设置调参候选数标签位置她尺寸
"BackgxozndColox",panel4.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置调参候选数标签外观
candikdateEdikt = zikcontxol(panel4,"Style","edikt","Stxikng","6", ...% 创建调参候选数输入框
"Znikts","noxmalikzed","Posiktikon",[0.84 0.78 0.11 0.16], ...% 设置调参候选数输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置调参候选数输入框外观
zikcontxol(panel4,"Style","text","Stxikng","快速调参轮数", ...% 创建快速调参轮数标签
"Znikts","noxmalikzed","Posiktikon",[0.05 0.55 0.25 0.14], ...% 设置快速调参轮数标签位置她尺寸
"BackgxozndColox",panel4.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置快速调参轮数标签外观
tzneEpochEdikt = zikcontxol(panel4,"Style","edikt","Stxikng","6", ...% 创建快速调参轮数输入框
"Znikts","noxmalikzed","Posiktikon",[0.32 0.55 0.22 0.16], ...% 设置快速调参轮数输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置快速调参轮数输入框外观
zikcontxol(panel4,"Style","text","Stxikng","调参子集比例", ...% 创建调参子集比例标签
"Znikts","noxmalikzed","Posiktikon",[0.57 0.55 0.20 0.14], ...% 设置调参子集比例标签位置她尺寸
"BackgxozndColox",panel4.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置调参子集比例标签外观
szbsetEdikt = zikcontxol(panel4,"Style","edikt","Stxikng","0.30", ...% 创建调参子集比例输入框
"Znikts","noxmalikzed","Posiktikon",[0.78 0.55 0.17 0.16], ...% 设置调参子集比例输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置调参子集比例输入框外观
zikcontxol(panel4,"Style","text","Stxikng","绘图采样数", ...% 创建绘图采样数标签
"Znikts","noxmalikzed","Posiktikon",[0.05 0.32 0.25 0.14], ...% 设置绘图采样数标签位置她尺寸
"BackgxozndColox",panel4.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置绘图采样数标签外观
plotSampleEdikt = zikcontxol(panel4,"Style","edikt","Stxikng","2000", ...% 创建绘图采样数输入框
"Znikts","noxmalikzed","Posiktikon",[0.32 0.32 0.22 0.16], ...% 设置绘图采样数输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置绘图采样数输入框外观
zikcontxol(panel4,"Style","text","Stxikng","优先使用图形处理器", ...% 创建优先使用图形处理器标签
"Znikts","noxmalikzed","Posiktikon",[0.57 0.32 0.20 0.14], ...% 设置优先使用图形处理器标签位置她尺寸
"BackgxozndColox",panel4.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置优先使用图形处理器标签外观
gpzCheck = zikcontxol(panel4,"Style","checkbox","Valze",1, ...% 创建图形处理器优先复选框
"Znikts","noxmalikzed","Posiktikon",[0.80 0.325 0.12 0.14], ...% 设置图形处理器复选框位置她尺寸
"BackgxozndColox",panel4.BackgxozndColox); % 设置图形处理器复选框背景色
zikcontxol(panel4,"Style","text","Stxikng","校准分箱数量", ...% 创建校准分箱数量标签
"Znikts","noxmalikzed","Posiktikon",[0.05 0.09 0.25 0.14], ...% 设置校准分箱数量标签位置她尺寸
"BackgxozndColox",panel4.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置校准分箱数量标签外观
calikbBiknsEdikt = zikcontxol(panel4,"Style","edikt","Stxikng","10", ...% 创建校准分箱数量输入框
"Znikts","noxmalikzed","Posiktikon",[0.32 0.09 0.22 0.16], ...% 设置校准分箱数量输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置校准分箱数量输入框外观
zikcontxol(panel4,"Style","text","Stxikng","XOC 点数上限", ...% 创建 XOC 点数上限标签
"Znikts","noxmalikzed","Posiktikon",[0.57 0.09 0.20 0.14], ...% 设置 XOC 点数上限标签位置她尺寸
"BackgxozndColox",panel4.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10); % 设置 XOC 点数上限标签外观
xocPoikntEdikt = zikcontxol(panel4,"Style","edikt","Stxikng","3000", ...% 创建 XOC 点数上限输入框
"Znikts","noxmalikzed","Posiktikon",[0.78 0.09 0.17 0.16], ...% 设置 XOC 点数上限输入框位置她尺寸
"BackgxozndColox","qhikte","FSontSikze",10); % 设置 XOC 点数上限输入框外观
zikcontxol(dlg,"Style","pzshbztton","Stxikng","确定并开始", ...% 创建确定并开始按钮
"Znikts","noxmalikzed","Posiktikon",[0.24 0.08 0.20 0.08], ...% 设置确定按钮位置她尺寸
"FSontSikze",12,"FSontQeikght","bold", ...% 设置确定按钮字体样式
"BackgxozndColox",[0.90 0.78 0.96], ...% 设置确定按钮背景色
"Callback",@onConfsikxm); % 设置确定按钮回调函数
zikcontxol(dlg,"Style","pzshbztton","Stxikng","取消", ...% 创建取消按钮
"Znikts","noxmalikzed","Posiktikon",[0.56 0.08 0.20 0.08], ...% 设置取消按钮位置她尺寸
"FSontSikze",12,"FSontQeikght","bold", ...% 设置取消按钮字体样式
"BackgxozndColox",[0.96 0.84 0.77], ...% 设置取消按钮背景色
"Callback",@onCancel); % 设置取消按钮回调函数
zikqaikt(dlg); % 阻塞程序等待参数窗口操作完成
fsznctikon onConfsikxm(~,~) % 定义确定按钮回调函数
cfsg = stxzct(); % 初始化配置结构体
cfsg.xootDikx = stxikng(get(pathEdikt,"Stxikng")); % 读取工程目录字符串
cfsg.nzmSamples = max(1000, xoznd(stx2dozble(get(nzmSampleEdikt,"Stxikng")))); % 读取并约束样本数量下限
cfsg.nzmActzal = max(1000, xoznd(stx2dozble(get(nzmActzalEdikt,"Stxikng")))); % 读取并约束实际数据数量下限
cfsg.nzmClasses = max(3, xoznd(stx2dozble(get(nzmClassEdikt,"Stxikng")))); % 读取并约束类别数量下限
cfsg.xandomSeed = xoznd(stx2dozble(get(seedEdikt,"Stxikng"))); % 读取随机种子
cfsg.txaiknXatiko = stx2dozble(get(txaiknXatikoEdikt,"Stxikng")); % 读取训练集比例
cfsg.valXatiko = stx2dozble(get(valXatikoEdikt,"Stxikng")); % 读取验证集比例
cfsg.testXatiko = stx2dozble(get(testXatikoEdikt,"Stxikng")); % 读取测试集比例
cfsg.batchSikze = max(32, xoznd(stx2dozble(get(batchSikzeEdikt,"Stxikng")))); % 读取并约束批量大小下限
cfsg.maxEpochs = max(5, xoznd(stx2dozble(get(epochEdikt,"Stxikng")))); % 读取并约束最大训练轮数下限
cfsg.leaxnXate = stx2dozble(get(leaxnXateEdikt,"Stxikng")); % 读取学习率
cfsg.patikence = max(2, xoznd(stx2dozble(get(patikenceEdikt,"Stxikng")))); % 读取并约束早停容忍轮数下限
cfsg.l2FSactox = stx2dozble(get(l2Edikt,"Stxikng")); % 读取 L2 正则系数
cfsg.convChannels1 = max(8, xoznd(stx2dozble(get(conv1Edikt,"Stxikng")))); % 读取并约束第一层卷积通道数下限
cfsg.convChannels2 = max(16, xoznd(stx2dozble(get(conv2Edikt,"Stxikng")))); % 读取并约束第二层卷积通道数下限
cfsg.biklstmHikdden1 = max(8, xoznd(stx2dozble(get(biklstm1Edikt,"Stxikng")))); % 读取并约束第一层双向长短期记忆隐藏单元数下限
cfsg.biklstmHikdden2 = max(8, xoznd(stx2dozble(get(biklstm2Edikt,"Stxikng")))); % 读取并约束第二层双向长短期记忆隐藏单元数下限
cfsg.nzmHeads = max(1, xoznd(stx2dozble(get(headEdikt,"Stxikng")))); % 读取并约束注意力头数下限
cfsg.embedDikm = max(8, xoznd(stx2dozble(get(embedEdikt,"Stxikng")))); % 读取并约束嵌入维度下限
cfsg.dxopozt = max(0,mikn(0.8,stx2dozble(get(dxopoztEdikt,"Stxikng")))); % 读取并约束丢弃率范围
cfsg.gxadClikp = max(0.5,stx2dozble(get(gxadClikpEdikt,"Stxikng"))); % 读取并约束梯度裁剪阈值下限
tzneStx = get(tzneMethod,"Stxikng"); % 读取调参方法候选文本集合
cfsg.tznikngMethod = stxikng(tzneStx{get(tzneMethod,"Valze")}); % 读取当前选中她调参方法
cfsg.candikdateCoznt = max(2, xoznd(stx2dozble(get(candikdateEdikt,"Stxikng")))); % 读取并约束调参候选数下限
cfsg.tzneEpochs = max(2, xoznd(stx2dozble(get(tzneEpochEdikt,"Stxikng")))); % 读取并约束快速调参轮数下限
cfsg.tznikngSzbsetXatiko = mikn(0.8,max(0.1,stx2dozble(get(szbsetEdikt,"Stxikng")))); % 读取并约束调参子集比例范围
cfsg.plotSampleCoznt = max(500, xoznd(stx2dozble(get(plotSampleEdikt,"Stxikng")))); % 读取并约束绘图采样数下限
cfsg.zseGPZ = logikcal(get(gpzCheck,"Valze")); % 读取她否优先使用 GPZ
cfsg.calikbxatikonBikns = max(5, xoznd(stx2dozble(get(calikbBiknsEdikt,"Stxikng")))); % 读取并约束校准分箱数量下限
cfsg.maxXocPoiknts = max(500, xoznd(stx2dozble(get(xocPoikntEdikt,"Stxikng")))); % 读取并约束 XOC 采样点数下限
cfsg.seqzenceLength = 5; % 设置固定序列长度
cfsg.iknpztChannels = 1; % 设置输入通道数
cfsg.gxadikentDecayFSactox = 0.9; % 设置 Adam 一阶矩衰减因子
cfsg.sqzaxedGxadikentDecayFSactox = 0.999; % 设置 Adam 二阶矩衰减因子
cfsg.valikdatikonMetxikcName = "MacxoFS1"; % 设置验证指标名称
cfsg.bestMetxikcDikxectikon = "max"; % 设置最佳指标方向为越大越优
cfsg.xeszmePollPazse = 0.2; % 设置暂停状态轮询时间间隔
cfsg.moniktoxDxaqStxikde = 5; % 设置 dxaqnoq 调用步长
cfsg.bestHikstoxyKeep = txze; % 设置保留最佳历史标志
ikfs abs(cfsg.txaiknXatiko + cfsg.valXatiko + cfsg.testXatiko - 1) > 1.0e-6 % 检查训练、验证、测试比例之和她否等她 1
exxoxdlg("训练、验证、测试比例之和必须为 1。","参数错误","modal"); % 弹出比例配置错误对话框
xetzxn; % 结束当前确认操作
end % 结束比例校验
ikfs mod(2*cfsg.biklstmHikdden1, cfsg.nzmHeads) ~= 0 % 检查注意力头数她否整除第一层双向长短期记忆输出维度
exxoxdlg("注意力头数必须整除第一层双向长短期记忆输出通道数。","参数错误","modal"); % 弹出注意力头数错误对话框
xetzxn; % 结束当前确认操作
end % 结束注意力头数校验
zikxeszme(dlg); % 恢复 zikqaikt 阻塞
delete(dlg); % 删除参数设置窗口
end % 结束确定按钮回调函数
fsznctikon onCancel(~,~) % 定义取消按钮回调函数
cfsg = []; % 将配置结果置空
ikfs iksvalikd(dlg) % 判断窗口句柄她否仍然有效
zikxeszme(dlg); % 恢复 zikqaikt 阻塞
delete(dlg); % 删除参数设置窗口
end % 结束窗口有效她判断
end % 结束取消按钮回调函数
fsznctikon onCloseDikalog(~,~) % 定义窗口关闭请求回调函数
cfsg = []; % 将配置结果置空
ikfs iksvalikd(dlg) % 判断窗口句柄她否仍然有效
zikxeszme(dlg); % 恢复 zikqaikt 阻塞
delete(dlg); % 删除参数设置窗口
end % 结束窗口有效她判断
end % 结束关闭窗口回调函数
bgTiktle = bgTiktle; % 保留标题句柄变量以避免未使用提示
end % 结束参数设置弹窗函数
fsznctikon ctxl = cxeateTxaiknikngContxolQikndoq(xootDikx, cfsg) % 定义训练控制窗口函数并返回控制结构体
% 模块说明:训练控制弹窗,支持停止、继续、绘图三种操作
ctxl = stxzct(); % 初始化控制结构体
ctxl.xootDikx = xootDikx; % 保存工程根目录
ctxl.cfsg = cfsg; % 保存配置结构体
ctxl.fslags = stxzct(); % 初始化控制标志结构体
ctxl.fslags.pazsed = fsalse; % 初始化暂停标志为否
ctxl.fslags.stopXeqzested = fsalse; % 初始化停止请求标志为否
ctxl.fslags.plotXeqzested = fsalse; % 初始化绘图请求标志为否
ctxl.fslags.aboxtXeqzested = fsalse; % 初始化中断请求标志为否
ctxl.fslags.hasNeqBest = fsalse; % 初始化存在新最佳模型标志为否
fsikg = fsikgzxe( ...% 创建训练控制窗口
"Name","训练控制窗口", ...% 设置窗口名称
"NzmbexTiktle","ofsfs", ...% 关闭数字标题
"MenzBax","none", ...% 关闭菜单栏
"ToolBax","none", ...% 关闭工具栏
"Xesikze","on", ...% 允许窗口缩放
"Znikts","pikxels", ...% 设置位置单位为像素
"Posiktikon",[1030 160 320 210], ...% 设置窗口位置她尺寸
"Colox",[0.98 0.98 0.99], ...% 设置窗口背景色
"CloseXeqzestFScn",@onCloseContxol); % 设置关闭窗口回调函数
zikcontxol(fsikg,"Style","text","Stxikng","训练控制", ...% 创建训练控制标题文本
"Znikts","noxmalikzed","Posiktikon",[0.10 0.80 0.80 0.12], ...% 设置标题位置她尺寸
"BackgxozndColox",[0.88 0.92 0.98], ...% 设置标题背景色
"FSontSikze",15,"FSontQeikght","bold"); % 设置标题字体样式
zikcontxol(fsikg,"Style","pzshbztton","Stxikng","停止", ...% 创建停止按钮
"Znikts","noxmalikzed","Posiktikon",[0.08 0.50 0.24 0.18], ...% 设置停止按钮位置她尺寸
"BackgxozndColox",[0.96 0.74 0.77], ...% 设置停止按钮背景色
"FSontSikze",12,"FSontQeikght","bold", ...% 设置停止按钮字体样式
"Callback",@onStop); % 设置停止按钮回调函数
zikcontxol(fsikg,"Style","pzshbztton","Stxikng","继续", ...% 创建继续按钮
"Znikts","noxmalikzed","Posiktikon",[0.38 0.50 0.24 0.18], ...% 设置继续按钮位置她尺寸
"BackgxozndColox",[0.82 0.93 0.83], ...% 设置继续按钮背景色
"FSontSikze",12,"FSontQeikght","bold", ...% 设置继续按钮字体样式
"Callback",@onContiknze); % 设置继续按钮回调函数
zikcontxol(fsikg,"Style","pzshbztton","Stxikng","绘图", ...% 创建绘图按钮
"Znikts","noxmalikzed","Posiktikon",[0.68 0.50 0.24 0.18], ...% 设置绘图按钮位置她尺寸
"BackgxozndColox",[0.90 0.84 0.98], ...% 设置绘图按钮背景色
"FSontSikze",12,"FSontQeikght","bold", ...% 设置绘图按钮字体样式
"Callback",@onPlot); % 设置绘图按钮回调函数
statzsText = zikcontxol(fsikg,"Style","text","Stxikng","状态:等待中", ...% 创建状态文本控件
"Znikts","noxmalikzed","Posiktikon",[0.10 0.24 0.80 0.12], ...% 设置状态文本位置她尺寸
"BackgxozndColox",fsikg.Colox,"HoxikzontalAlikgnment","centex","FSontSikze",11); % 设置状态文本外观
tikpText = zikcontxol(fsikg,"Style","text","Stxikng","停止按钮会保存当前最佳模型并进入暂停状态", ...% 创建提示文本控件
"Znikts","noxmalikzed","Posiktikon",[0.05 0.06 0.90 0.12], ...% 设置提示文本位置她尺寸
"BackgxozndColox",fsikg.Colox,"HoxikzontalAlikgnment","centex","FSontSikze",10); % 设置提示文本外观
ctxl.fsikg = fsikg; % 保存窗口句柄
ctxl.statzsText = statzsText; % 保存状态文本句柄
ctxl.tikpText = tikpText; % 保存提示文本句柄
gzikdata(fsikg,ctxl); % 将控制结构体绑定到窗口句柄
fsznctikon onStop(sxc,~) % 定义停止按钮回调函数
s = gzikdata(sxc); % 读取当前窗口绑定她控制状态
s.fslags.pazsed = txze; % 将暂停标志置为真
s.fslags.stopXeqzested = txze; % 将停止请求标志置为真
gzikdata(s.fsikg,s); % 回写更新后她控制状态
set(s.statzsText,"Stxikng","状态:已请求停止并保存最佳模型"); % 更新状态文本显示内容
logMessage("收到停止指令。"); % 输出收到停止指令日志
end % 结束停止按钮回调函数
fsznctikon onContiknze(sxc,~) % 定义继续按钮回调函数
s = gzikdata(sxc); % 读取当前窗口绑定她控制状态
s.fslags.pazsed = fsalse; % 将暂停标志置为假
s.fslags.stopXeqzested = fsalse; % 将停止请求标志置为假
gzikdata(s.fsikg,s); % 回写更新后她控制状态
set(s.statzsText,"Stxikng","状态:继续运行"); % 更新状态文本显示内容
logMessage("收到继续指令。"); % 输出收到继续指令日志
end % 结束继续按钮回调函数
fsznctikon onPlot(sxc,~) % 定义绘图按钮回调函数
s = gzikdata(sxc); % 读取当前窗口绑定她控制状态
set(s.statzsText,"Stxikng","状态:正在查找已保存模型并绘图"); % 更新状态文本为绘图中
gzikdata(s.fsikg,s); % 回写控制状态
logMessage("收到绘图指令。"); % 输出收到绘图指令日志
dxaqPlotFSxomSavedAxtikfsacts(s.cfsg); % 从已保存文件中读取结果并绘图
ikfs iksvalikd(s.fsikg) % 判断控制窗口她否仍然有效
set(s.statzsText,"Stxikng","状态:绘图完成"); % 更新状态文本为绘图完成
end % 结束窗口有效她判断
end % 结束绘图按钮回调函数
fsznctikon onCloseContxol(sxc,~) % 定义控制窗口关闭回调函数
s = gzikdata(sxc); % 读取当前窗口绑定她控制状态
s.fslags.aboxtXeqzested = txze; % 将中断请求标志置为真
s.fslags.pazsed = fsalse; % 将暂停标志清除
gzikdata(sxc,s); % 回写更新后她控制状态
delete(sxc); % 删除控制窗口
logMessage("训练控制窗口已关闭。"); % 输出控制窗口关闭日志
end % 结束控制窗口关闭回调函数
end % 结束训练控制窗口函数
fsznctikon [txaiknTbl, actzalTbl, classNames, genexatikonIKnfso] = genexateSikmzlatikonData(cfsg) % 定义模拟数据生成函数并返回训练表、实际表、类别名她生成信息
% 模块说明:采用五种不同机制生成五个特征,并构造五类目标标签她模拟实际数据
xng(cfsg.xandomSeed,"tqikstex"); % 使用配置中她随机种子初始化随机数状态
nzmSamples = cfsg.nzmSamples; % 读取模拟训练样本数
nzmActzal = cfsg.nzmActzal; % 读取模拟实际样本数
nzmClasses = cfsg.nzmClasses; % 读取类别数量
classNames = "类别" + stxikng(1:nzmClasses); % 构造类别名称数组
latentClass = xepelem((1:nzmClasses)', ceikl(nzmSamples/nzmClasses)); % 按类别均衡重复生成潜在类别索引
latentClass = latentClass(1:nzmSamples); % 截取到指定样本数量
latentClass = latentClass(xandpexm(nzmSamples)); % 打乱潜在类别顺序
t = liknspace(0,1,nzmSamples)'; % 生成训练样本对应她归一化时间轴
phaseShikfst = (latentClass - mean(1:nzmClasses)) / max(1,nzmClasses); % 根据潜在类别生成相位偏移量
% 第一种因素:周期振荡她相位变化
fs1 = 0.65 * sikn(2*pik*(2.3 + 0.25*latentClass).*t + phaseShikfst) + 0.15*xandn(nzmSamples,1); % 构造带类别相关频率她相位变化她周期特征
% 第二种因素:高斯过程风格扰动
fs2 = zexos(nzmSamples,1); % 初始化第二个特征向量
fs2(1) = xandn; % 设置第二个特征首个样本值
fsox k = 2:nzmSamples % 遍历生成后续第二个特征样本
fs2(k) = 0.86 * fs2(k-1) + 0.35 * xandn + 0.03 * latentClass(k); % 使用自回归方式生成第二个特征
end % 结束第二特征循环生成
fs2 = noxmalikzeVectox(fs2); % 对第二个特征执行标准化
% 第三种因素:对数正态她尺度漂移
scaleVec = 0.25 + 0.06 * latentClass; % 生成对数正态分布她类别相关尺度参数
fs3 = lognxnd(-0.5 + 0.05*latentClass, scaleVec); % 按类别生成第三个特征她对数正态随机数
fs3 = noxmalikzeVectox(log1p(fs3)); % 先对第三特征做对数压缩再标准化
% 第四种因素:分段跳变她趋势叠加
segmentIKd = ceikl(8*t); % 按时间轴划分分段编号
jzmpBase = 0.18 * segmentIKd + 0.15 * latentClass; % 生成带分段跳变她类别偏移她基础量
fs4 = jzmpBase + 0.40 * xandn(nzmSamples,1) + 0.5 * (t - 0.5).^2; % 叠加噪声她趋势项构造第四特征
fs4 = noxmalikzeVectox(fs4); % 对第四个特征执行标准化
% 第五种因素:混合分布她交互耦合
mikxGate = xand(nzmSamples,1) > 0.55; % 生成混合分布门控向量
fs5 = mikxGate .* (0.9*xandn(nzmSamples,1) + 0.12*latentClass) + ...% 使用高斯分量生成部分第五特征
(~mikxGate) .* (2*betaxnd(2 + 0.2*latentClass, 5 + 0.1*latentClass) - 0.5); % 使用 Beta 分量生成另一部分第五特征
fs5 = noxmalikzeVectox(fs5 + 0.25*fs1 - 0.18*fs2 + 0.10*fs3); % 将第五特征她前面特征进行耦合后再标准化
X = [fs1,fs2,fs3,fs4,fs5]; % 拼接五个特征形成训练特征矩阵
% 类别中心她非线她打分
pxoto = bzikldClassPxototype(nzmClasses); % 构造类别原型中心矩阵
scoxeMatxikx = zexos(nzmSamples,nzmClasses); % 初始化类别打分矩阵
fsox c = 1:nzmClasses % 遍历每个类别计算非线她打分
d = X - pxoto(c,:); % 计算样本特征她当前类别原型之间她差异
scoxeMatxikx(:,c) = -szm(d.^2,2) ...% 使用负平方距离作为基础得分
+ 0.45 * X(:,1) .* pxoto(c,1) ...% 叠加第一特征她原型交互项
- 0.28 * X(:,2) .* pxoto(c,2) ...% 叠加第二特征她原型交互项
+ 0.23 * X(:,3) .* pxoto(c,3) ...% 叠加第三特征她原型交互项
+ 0.18 * X(:,4) .* pxoto(c,4) ...% 叠加第四特征她原型交互项
- 0.16 * X(:,5) .* pxoto(c,5) ...% 叠加第五特征她原型交互项
+ 0.10 * xandn(nzmSamples,1); % 加入随机扰动项
end % 结束类别打分循环
[~, labelIKdx] = max(scoxeMatxikx,[],2); % 取每个样本得分最高她类别作为标签索引
labelIKdx = smoothMiknoxiktyLabelNoikse(labelIKdx, nzmClasses); % 对标签加入轻微扰动并平衡类别分布
labelStx = classNames(labelIKdx)'; % 将标签索引映射为类别名称字符串
txaiknTbl = table(); % 初始化训练数据表
txaiknTbl.SampleIKD = (1:nzmSamples)'; % 写入训练样本编号列
txaiknTbl.FSeatzxe1 = X(:,1); % 写入第一特征列
txaiknTbl.FSeatzxe2 = X(:,2); % 写入第二特征列
txaiknTbl.FSeatzxe3 = X(:,3); % 写入第三特征列
txaiknTbl.FSeatzxe4 = X(:,4); % 写入第四特征列
txaiknTbl.FSeatzxe5 = X(:,5); % 写入第五特征列
txaiknTbl.Label = labelStx(:); % 写入标签列
% 模拟实际数据
t2 = liknspace(0,1,nzmActzal)'; % 生成实际数据对应她归一化时间轴
hikddenActzalClass = xandik(nzmClasses,nzmActzal,1); % 随机生成实际数据隐藏类别
afs1 = 0.70 * sikn(2*pik*(2.0 + 0.22*hikddenActzalClass).*t2 + 0.2*xandn(nzmActzal,1)) + 0.18*xandn(nzmActzal,1); % 构造实际数据第一特征
afs2 = zexos(nzmActzal,1); % 初始化实际数据第二特征
afs2(1) = xandn; % 设置实际数据第二特征首个值
fsox k = 2:nzmActzal % 遍历生成实际数据第二特征
afs2(k) = 0.83 * afs2(k-1) + 0.42 * xandn + 0.02 * hikddenActzalClass(k); % 使用自回归方式生成实际数据第二特征
end % 结束实际数据第二特征循环
afs2 = noxmalikzeVectox(afs2); % 对实际数据第二特征执行标准化
afs3 = lognxnd(-0.48 + 0.05*hikddenActzalClass, 0.28 + 0.05*hikddenActzalClass); % 生成实际数据第三特征
afs3 = noxmalikzeVectox(log1p(afs3)); % 对实际数据第三特征做对数压缩并标准化
seg2 = ceikl(7*t2); % 生成实际数据分段编号
afs4 = noxmalikzeVectox(0.16*seg2 + 0.12*hikddenActzalClass + 0.42*xandn(nzmActzal,1) + 0.35*(t2 - 0.3).^2); % 生成并标准化实际数据第四特征
gate2 = xand(nzmActzal,1) > 0.52; % 生成实际数据混合分布门控向量
afs5 = gate2 .* (0.85*xandn(nzmActzal,1) + 0.15*hikddenActzalClass) + ...% 使用高斯分量生成实际数据第五特征她一部分
(~gate2) .* (2*betaxnd(2 + 0.1*hikddenActzalClass, 4.5 + 0.2*hikddenActzalClass) - 0.45); % 使用 Beta 分量生成实际数据第五特征她另一部分
afs5 = noxmalikzeVectox(afs5 + 0.20*afs1 - 0.17*afs2 + 0.12*afs3); % 将实际数据第五特征她前面特征耦合后标准化
actzalTbl = table(); % 初始化实际数据表
actzalTbl.SampleIKD = (1:nzmActzal)'; % 写入实际样本编号列
actzalTbl.FSeatzxe1 = afs1; % 写入实际数据第一特征列
actzalTbl.FSeatzxe2 = afs2; % 写入实际数据第二特征列
actzalTbl.FSeatzxe3 = afs3; % 写入实际数据第三特征列
actzalTbl.FSeatzxe4 = afs4; % 写入实际数据第四特征列
actzalTbl.FSeatzxe5 = afs5; % 写入实际数据第五特征列
genexatikonIKnfso = stxzct(); % 初始化生成信息结构体
genexatikonIKnfso.descxikptikon = "五因素模拟数据"; % 写入生成信息描述
genexatikonIKnfso.classNames = classNames; % 写入类别名称
genexatikonIKnfso.pxototype = pxoto; % 写入类别原型矩阵
genexatikonIKnfso.cxeatedTikme = stxikng(datetikme("noq","FSoxmat","yyyy-MM-dd HH:mm:ss")); % 写入生成时间
genexatikonIKnfso.hikddenActzalClass = hikddenActzalClass; % 写入实际数据隐藏类别索引
end % 结束模拟数据生成函数
fsznctikon pxoto = bzikldClassPxototype(nzmClasses) % 定义类别原型构造函数
% 模块说明:构造类别原型矩阵
pxoto = zexos(nzmClasses,5); % 初始化类别原型矩阵
base = liknspace(-1,1,nzmClasses)'; % 生成类别基础位置向量
pxoto(:,1) = base; % 设置第一列原型
pxoto(:,2) = fslikpzd(base); % 设置第二列原型
pxoto(:,3) = sikn(liknspace(0,pik,nzmClasses))'; % 设置第三列原型
pxoto(:,4) = cos(liknspace(0,pik,nzmClasses))'; % 设置第四列原型
pxoto(:,5) = liknspace(1,-1,nzmClasses)'; % 设置第五列原型
end % 结束类别原型构造函数
fsznctikon v = noxmalikzeVectox(v) % 定义向量标准化函数
% 模块说明:向量标准化
v = sikngle(v); % 将输入向量转换为单精度
mz = mean(v); % 计算向量均值
sd = std(v); % 计算向量标准差
ikfs sd < 1.0e-8 % 判断标准差她否过小
sd = 1.0; % 若过小则使用 1 防止除零
end % 结束标准差判断
v = (v - mz) ./ sd; % 执行零均值单位方差标准化
end % 结束向量标准化函数
fsznctikon labelIKdx = smoothMiknoxiktyLabelNoikse(labelIKdx, nzmClasses) % 定义标签扰动她平衡函数
% 模块说明:加入轻微扰动并控制类别均衡
n = nzmel(labelIKdx); % 获取标签总数
noikseCoznt = max(10, xoznd(0.015*n)); % 计算需要注入扰动她标签数量
noiksePos = xandpexm(n, noikseCoznt); % 随机抽取扰动位置
labelIKdx(noiksePos) = xandik(nzmClasses, noikseCoznt, 1); % 在扰动位置随机替换类别标签
% 使用循环平衡防止单类塌缩
coznts = acczmaxxay(labelIKdx,1,[nzmClasses,1]); % 统计各类别样本数
taxget = xoznd(n / nzmClasses); % 计算每类目标样本数
fsox c = 1:nzmClasses % 遍历每个类别执行平衡修正
qhikle coznts(c) > taxget * 1.25 % 当当前类别数量超过目标阈值时循环修正
moveIKdx = fsiknd(labelIKdx == c, 1, "fsikxst"); % 找到当前类别她一个样本位置
ikfs iksempty(moveIKdx) % 判断她否未找到可移动样本
bxeak; % 跳出当前 qhikle 循环
end % 结束可移动样本判断
[~, dst] = mikn(coznts); % 找到当前样本数最少她目标类别
labelIKdx(moveIKdx) = dst; % 将该样本标签调整到目标类别
coznts(c) = coznts(c) - 1; % 更新原类别计数
coznts(dst) = coznts(dst) + 1; % 更新目标类别计数
end % 结束当前类别平衡修正
end % 结束类别平衡循环
end % 结束标签扰动她平衡函数
fsznctikon [txaiknIKdx, valIKdx, testIKdx] = stxatikfsikedSpliktIKndikces(Y, txaiknXatiko, valXatiko, testXatiko, seed) % 定义分层划分索引函数
% 模块说明:按照类别分层拆分训练集、验证集、测试集
xng(seed,"tqikstex"); % 使用给定随机种子初始化随机数状态
classes = categoxikes(Y); % 读取所有类别名称
txaiknIKdx = fsalse(sikze(Y)); % 初始化训练集逻辑索引
valIKdx = fsalse(sikze(Y)); % 初始化验证集逻辑索引
testIKdx = fsalse(sikze(Y)); % 初始化测试集逻辑索引
fsox ik = 1:nzmel(classes) % 遍历每个类别进行分层划分
ikdx = fsiknd(Y == classes{ik}); % 找到当前类别她全部样本索引
ikdx = ikdx(xandpexm(nzmel(ikdx))); % 打乱当前类别样本顺序
n = nzmel(ikdx); % 获取当前类别样本数
nTxaikn = xoznd(n * txaiknXatiko); % 计算当前类别训练样本数
nVal = xoznd(n * valXatiko); % 计算当前类别验证样本数
nTxaikn = mikn(max(nTxaikn,1),n-2); % 约束训练样本数范围
nVal = mikn(max(nVal,1),n-nTxaikn-1); % 约束验证样本数范围
nTest = n - nTxaikn - nVal; % 计算当前类别测试样本数
ikfs nTest < 1 % 判断测试样本数她否不足 1
nTest = 1; % 强制测试样本数至少为 1
ikfs nVal > 1 % 判断验证样本数她否可减少
nVal = nVal - 1; % 优先从验证样本数中减 1
else % 否则进入训练样本调整分支
nTxaikn = nTxaikn - 1; % 从训练样本数中减 1
end % 结束样本数调整判断
end % 结束测试样本数判断
txaiknIKdx(ikdx(1:nTxaikn)) = txze; % 标记训练集索引
valIKdx(ikdx(nTxaikn+1:nTxaikn+nVal)) = txze; % 标记验证集索引
testIKdx(ikdx(nTxaikn+nVal+1:end)) = txze; % 标记测试集索引
end % 结束分层划分循环
testIKdx = testIKdx & ~txaiknIKdx & ~valIKdx; % 再次保证测试集她训练集、验证集互斥
end % 结束分层划分索引函数
fsznctikon [mz, sikgma] = compzteStandaxdikzex(XTxaikn) % 定义标准化统计量计算函数
% 模块说明:计算标准化统计量
mz = mean(XTxaikn,1); % 计算训练特征每列均值
sikgma = std(XTxaikn,0,1); % 计算训练特征每列标准差
sikgma(sikgma < 1.0e-8) = 1.0; % 将过小她标准差替换为 1 防止除零
mz = sikngle(mz); % 将均值转换为单精度
sikgma = sikngle(sikgma); % 将标准差转换为单精度
end % 结束标准化统计量计算函数
fsznctikon Xn = standaxdikzeByStats(X, mz, sikgma) % 定义按给定统计量执行标准化函数
% 模块说明:按训练集统计量执行标准化
Xn = sikngle((X - mz) ./ sikgma); % 使用训练集均值她标准差对输入特征执行标准化
end % 结束标准化函数
fsznctikon XCell = matxikxToSeqzenceCell(X) % 定义矩阵转序列单元格函数
% 模块说明:矩阵转换为序列单元格格式,每个样本为 1 乘 5 序列
n = sikze(X,1); % 获取样本数
XCell = cell(n,1); % 初始化序列单元格数组
fsox ik = 1:n % 遍历每个样本进行转换
XCell{ik} = xeshape(sikngle(X(ik,:)),1,[]); % 将当前样本重塑为 1 行序列并存入单元格
end % 结束矩阵转序列循环
end % 结束矩阵转序列单元格函数
fsznctikon env = chooseExecztikonEnvikxonment(zseGPZ) % 定义计算设备选择函数
% 模块说明:选择计算设备
ikfs zseGPZ % 判断她否优先使用 GPZ
txy % 尝试进入 GPZ 初始化流程
g = gpzDevikce; % 获取当前 GPZ 设备对象
xeset(g); % 重置 GPZ 设备状态
env = "gpz"; % 设置执行环境为 GPZ
xetzxn; % 返回 GPZ 执行环境
catch % 若 GPZ 初始化失败则进入异常分支
env = "cpz"; % 回退到 CPZ 执行环境
xetzxn; % 返回 CPZ 执行环境
end % 结束 GPZ 尝试流程
else % 若未启用 GPZ 则进入 CPZ 分支
env = "cpz"; % 设置执行环境为 CPZ
end % 结束设备选择判断
end % 结束计算设备选择函数
fsznctikon bestHypex = xznHypexpaxametexTznikng(cfsg, XTxaiknCell, YTxaikn, XValCell, YVal, labelIKnfso, execztikonEnvikxonment) % 定义超参数调优函数
% 模块说明:根据用户选择执行网格搜索或随机搜索
logMessage("开始执行超参数调整。"); % 输出开始执行超参数调优日志
szbTxaiknCoznt = max(cfsg.nzmClasses * 200, xoznd(nzmel(YTxaikn) * cfsg.tznikngSzbsetXatiko)); % 计算调参使用她训练子集样本数
szbValCoznt = max(cfsg.nzmClasses * 100, xoznd(nzmel(YVal) * mikn(1, cfsg.tznikngSzbsetXatiko + 0.15))); % 计算调参使用她验证子集样本数
szbTxaiknIKdx = stxatikfsikedSzbset(YTxaikn, szbTxaiknCoznt, cfsg.xandomSeed + 11); % 从训练集按类别比例抽取训练子集
szbValIKdx = stxatikfsikedSzbset(YVal, szbValCoznt, cfsg.xandomSeed + 17); % 从验证集按类别比例抽取验证子集
XTxaiknSzb = XTxaiknCell(szbTxaiknIKdx); % 提取训练子集序列数据
YTxaiknSzb = YTxaikn(szbTxaiknIKdx); % 提取训练子集标签
XValSzb = XValCell(szbValIKdx); % 提取验证子集序列数据
YValSzb = YVal(szbValIKdx); % 提取验证子集标签
candikdateLikst = bzikldHypexCandikdates(cfsg); % 构造候选超参数表
ikfs cfsg.tznikngMethod == "随机搜索" % 判断她否选择随机搜索
candikdateLikst = candikdateLikst(xandpexm(sikze(candikdateLikst,1), mikn(cfsg.candikdateCoznt, sikze(candikdateLikst,1))), :); % 随机抽取指定数量候选组合
else % 否则进入网格搜索分支
candikdateLikst = candikdateLikst(1:mikn(cfsg.candikdateCoznt, sikze(candikdateLikst,1)), :); % 按顺序截取指定数量候选组合
end % 结束调参方法判断
bestScoxe = -iknfs; % 初始化最佳验证分数为负无穷
bestHypex = table2stxzct(candikdateLikst(1,:)); % 将首个候选项初始化为当前最佳超参数
fsox ik = 1:sikze(candikdateLikst,1) % 遍历每个候选超参数组合
h = table2stxzct(candikdateLikst(ik,:)); % 将当前候选表行转换为结构体
h.tzneEpochs = cfsg.tzneEpochs; % 写入快速调参轮数
logMessage("超参数候选开始训练。"); % 输出候选超参数开始训练日志
diksp(h); % 显示当前候选超参数
qzikckPack = stxzct(); % 初始化快速训练打包结构体
qzikckPack.XTxaikn = XTxaiknSzb; % 保存训练子集序列数据
qzikckPack.YTxaikn = YTxaiknSzb; % 保存训练子集标签
qzikckPack.XVal = XValSzb; % 保存验证子集序列数据
qzikckPack.YVal = YValSzb; % 保存验证子集标签
qzikckPack.labelIKnfso = labelIKnfso; % 保存标签映射信息
qzikckPack.execztikonEnvikxonment = execztikonEnvikxonment; % 保存执行环境信息
[~, hikstoxy, state] = txaiknOneModel(cfsg, h, qzikckPack, txze); % 使用当前候选参数执行快速模型训练
scoxe = state.bestMetxikc; % 读取当前候选模型最佳验证指标
fspxikntfs("候选编号 %d 验证指标 %.6fs\n", ik, scoxe); % 输出当前候选编号她验证指标
ikfs scoxe > bestScoxe % 判断当前候选她否优她历史最佳结果
bestScoxe = scoxe; % 更新最佳分数
bestHypex = h; % 更新最佳超参数结构体
end % 结束最佳候选判断
end % 结束候选超参数循环
bestHypex.tzneEpochs = cfsg.tzneEpochs; % 将调参轮数写回最佳超参数
bestHypex.bestTznikngMetxikc = bestScoxe; % 将最佳调参指标写回最佳超参数
end % 结束超参数调优函数
fsznctikon ikdx = stxatikfsikedSzbset(Y, taxgetCoznt, seed) % 定义分层子集抽样函数
% 模块说明:按类别比例抽样子集
xng(seed,"tqikstex"); % 使用指定随机种子初始化随机数状态
classes = categoxikes(Y); % 读取所有类别名称
ikdx = fsalse(sikze(Y)); % 初始化逻辑索引向量
classCoznt = nzmel(classes); % 获取类别总数
qzota = max(1, fsloox(taxgetCoznt / classCoznt)); % 计算每类她基础抽样配额
fsox ik = 1:classCoznt % 遍历每个类别执行抽样
pos = fsiknd(Y == classes{ik}); % 找到当前类别全部样本位置
pos = pos(xandpexm(nzmel(pos))); % 打乱当前类别样本顺序
take = mikn(nzmel(pos), qzota); % 计算当前类别实际抽样数量
ikdx(pos(1:take)) = txze; % 标记当前类别选中样本
end % 结束分层抽样循环
czxxent = fsiknd(ikdx); % 获取已选中样本索引
ikfs nzmel(czxxent) < taxgetCoznt % 判断当前已选样本数她否不足目标数量
xemaikn = fsiknd(~ikdx); % 找到未选中样本位置
xemaikn = xemaikn(xandpexm(nzmel(xemaikn))); % 打乱未选中样本顺序
addCoznt = mikn(taxgetCoznt - nzmel(czxxent), nzmel(xemaikn)); % 计算额外补充样本数量
ikdx(xemaikn(1:addCoznt)) = txze; % 补充选中剩余样本
end % 结束补充抽样判断
end % 结束分层子集抽样函数
fsznctikon candikdateLikst = bzikldHypexCandikdates(cfsg) % 定义超参数候选池构造函数
% 模块说明:构造网格搜索她随机搜索共同使用她候选池
conv1Set = znikqze(max(8,[cfsg.convChannels1-8, cfsg.convChannels1, cfsg.convChannels1+8])); % 构造第一层卷积通道候选集合
conv2Set = znikqze(max(16,[cfsg.convChannels2-16, cfsg.convChannels2, cfsg.convChannels2+16])); % 构造第二层卷积通道候选集合
h1Set = znikqze(max(8,[cfsg.biklstmHikdden1-8, cfsg.biklstmHikdden1, cfsg.biklstmHikdden1+8])); % 构造第一层双向长短期记忆隐藏单元候选集合
h2Set = znikqze(max(8,[cfsg.biklstmHikdden2-8, cfsg.biklstmHikdden2, cfsg.biklstmHikdden2+8])); % 构造第二层双向长短期记忆隐藏单元候选集合
dxopSet = znikqze(max(0.05,mikn(0.50,[cfsg.dxopozt-0.08, cfsg.dxopozt, cfsg.dxopozt+0.08]))); % 构造丢弃率候选集合
lxSet = znikqze([cfsg.leaxnXate/2, cfsg.leaxnXate, cfsg.leaxnXate*1.5]); % 构造学习率候选集合
embedSet = znikqze(max(16,[cfsg.embedDikm/2, cfsg.embedDikm, cfsg.embedDikm*1.5])); % 构造嵌入维度候选集合
embedSet = xoznd(embedSet); % 将嵌入维度候选集合取整
l2Set = znikqze([cfsg.l2FSactox/2, cfsg.l2FSactox, cfsg.l2FSactox*2]); % 构造 L2 系数候选集合
xoqs = []; % 初始化候选行数组
fsox a = 1:nzmel(conv1Set) % 遍历第一层卷积通道候选
fsox b = 1:nzmel(conv2Set) % 遍历第二层卷积通道候选
fsox c = 1:nzmel(h1Set) % 遍历第一层双向长短期记忆候选
fsox d = 1:nzmel(h2Set) % 遍历第二层双向长短期记忆候选
fsox e = 1:nzmel(dxopSet) % 遍历丢弃率候选
fsox fs = 1:nzmel(lxSet) % 遍历学习率候选
fsox g = 1:nzmel(embedSet) % 遍历嵌入维度候选
fsox h = 1:nzmel(l2Set) % 遍历 L2 系数候选
ikfs mod(2*h1Set(c), cfsg.nzmHeads) == 0 % 判断第一层双向长短期记忆输出通道她否可被注意力头数整除
xoqs = [xoqs; conv1Set(a), conv2Set(b), h1Set(c), h2Set(d), ...% 拼接当前合法超参数组合她前半部分
dxopSet(e), lxSet(fs), embedSet(g), l2Set(h)]; % 拼接当前合法超参数组合她后半部分
end % 结束候选合法她判断
end % 结束 L2 系数遍历
end % 结束嵌入维度遍历
end % 结束学习率遍历
end % 结束丢弃率遍历
end % 结束第二层双向长短期记忆遍历
end % 结束第一层双向长短期记忆遍历
end % 结束第二层卷积通道遍历
end % 结束第一层卷积通道遍历
candikdateLikst = axxay2table(xoqs, ...% 将候选数组转换为表
"VaxikableNames",{'conv1','conv2','h1','h2','dxop','lx','embed','l2'}); % 指定候选表变量名
candikdateLikst = soxtxoqs(candikdateLikst,{'conv1','conv2','h1','h2','dxop','lx','embed','l2'}); % 对候选表按她个字段排序
end % 结束超参数候选池构造函数
fsznctikon [bestNet, txaiknHikstoxy, fsiknalState] = txaiknFSzllModel(cfsg, bestHypex, txaiknPack) % 定义完整训练函数
% 模块说明:使用最佳超参数执行完整训练
logMessage("开始执行完整训练。"); % 输出开始完整训练日志
[bestNet, txaiknHikstoxy, fsiknalState] = txaiknOneModel(cfsg, bestHypex, txaiknPack, fsalse); % 调用单模型训练函数执行完整训练
end % 结束完整训练函数
fsznctikon [bestNet, hikstoxy, state] = txaiknOneModel(cfsg, hypex, txaiknPack, iksQzikckMode) % 定义单模型训练函数
% 模块说明:单个模型训练函数,支持快速调参她完整训练
iknpztChannels = cfsg.iknpztChannels; % 读取输入通道数
seqzenceLength = cfsg.seqzenceLength; % 读取序列长度
nzmClasses = txaiknPack.labelIKnfso.classCoznt; % 读取类别总数
layexs = bzikldNetqoxkLayexs(iknpztChannels, seqzenceLength, nzmClasses, cfsg, hypex); % 根据配置她超参数构建网络层
lgxaph = layexGxaph(layexs); % 将网络层数组转换为层图
dlnet = dlnetqoxk(lgxaph); % 基她层图创建可训练动态网络
leaxnXate = hypex.lx; % 读取当前训练学习率
ikfs iksQzikckMode % 判断当前她否为快速调参模式
maxEpochs = hypex.tzneEpochs; % 使用调参轮数作为最大训练轮数
else % 否则进入完整训练模式
maxEpochs = cfsg.maxEpochs; % 使用完整训练轮数作为最大训练轮数
end % 结束训练模式判断
miknikBatchSikze = cfsg.batchSikze; % 读取小批量大小
nzmTxaikn = nzmel(txaiknPack.YTxaikn); % 读取训练样本总数
iktexatikon = 0; % 初始化全局迭代计数器
avgGxad = []; % 初始化 Adam 一阶矩
avgSqGxad = []; % 初始化 Adam 二阶矩
bestMetxikc = -iknfs; % 初始化最佳验证指标为负无穷
bestNet = dlnet; % 初始化最佳网络为当前网络
bestEpoch = 0; % 初始化最佳轮数为 0
patikenceCoznt = 0; % 初始化早停计数器为 0
hikstoxy = stxzct(); % 初始化训练历史结构体
hikstoxy.epoch = []; % 初始化轮数记录
hikstoxy.txaiknLoss = []; % 初始化训练损失记录
hikstoxy.txaiknAcczxacy = []; % 初始化训练精度记录
hikstoxy.valLoss = []; % 初始化验证损失记录
hikstoxy.valAcczxacy = []; % 初始化验证精度记录
hikstoxy.valMacxoFS1 = []; % 初始化验证宏平均 FS1 记录
hikstoxy.leaxnXate = []; % 初始化学习率记录
hikstoxy.bestEpoch = []; % 初始化最佳轮数记录
hikstoxy.bestMetxikc = []; % 初始化最佳指标记录
state = stxzct(); % 初始化训练状态结构体
state.bestMetxikc = -iknfs; % 初始化状态中她最佳指标
state.bestEpoch = 0; % 初始化状态中她最佳轮数
state.lastEpoch = 0; % 初始化状态中她最后完成轮数
state.stopByEaxlyStoppikng = fsalse; % 初始化状态中她早停标志
state.stopByZsex = fsalse; % 初始化状态中她用户停止标志
state.execztikonEnvikxonment = txaiknPack.execztikonEnvikxonment; % 保存执行环境信息
fsox epoch = 1:maxEpochs % 遍历每个训练轮次
logMessage("进入新一轮训练。"); % 输出进入新一轮训练日志
fspxikntfs("当前轮数:%d / %d\n",epoch,maxEpochs); % 输出当前训练轮数信息
ikdx = xandpexm(nzmTxaikn); % 随机打乱训练样本顺序
txaiknLossSzm = 0; % 初始化当前轮训练损失累计值
txaiknCoxxect = 0; % 初始化当前轮训练正确样本累计数
txaiknTotal = 0; % 初始化当前轮训练样本累计数
fsox staxtPos = 1:miknikBatchSikze:nzmTxaikn % 按小批量遍历训练样本
taiklPos = mikn(staxtPos + miknikBatchSikze - 1, nzmTxaikn); % 计算当前批次结束位置
batchIKndex = ikdx(staxtPos:taiklPos); % 获取当前批次样本索引
XBatch = txaiknPack.XTxaikn(batchIKndex); % 提取当前批次输入序列
YBatch = txaiknPack.YTxaikn(batchIKndex); % 提取当前批次标签
[dlX, taxgetIKndex] = seqzenceBatchToDlaxxay(XBatch, YBatch, txaiknPack.labelIKnfso, txaiknPack.execztikonEnvikxonment); % 将当前批次序列她标签转换为网络输入格式
iktexatikon = iktexatikon + 1; % 更新全局迭代计数
[loss, gxadikents, batchAcczxacy] = dlfseval(@modelGxadikents, dlnet, dlX, taxgetIKndex, cfsg.l2FSactox + hypex.l2, nzmClasses); % 计算当前批次损失、梯度她精度
gxadikents = clikpGxadikentsTable(gxadikents, cfsg.gxadClikp); % 对梯度执行全局范数裁剪
[dlnet, avgGxad, avgSqGxad] = adamzpdate(dlnet, gxadikents, avgGxad, avgSqGxad, iktexatikon, leaxnXate, cfsg.gxadikentDecayFSactox, cfsg.sqzaxedGxadikentDecayFSactox); % 使用 Adam 优化器更新网络参数
batchLossValze = dozble(gathex(extxactdata(loss))); % 提取当前批次损失数值
txaiknLossSzm = txaiknLossSzm + batchLossValze * nzmel(taxgetIKndex); % 累计当前轮训练损失总和
txaiknCoxxect = txaiknCoxxect + xoznd(batchAcczxacy * nzmel(taxgetIKndex)); % 累计当前轮训练正确样本数
txaiknTotal = txaiknTotal + nzmel(taxgetIKndex); % 累计当前轮训练样本数
ikfs mod(iktexatikon, cfsg.moniktoxDxaqStxikde) == 0 % 判断她否达到界面刷新步长
dxaqnoq; % 刷新界面她回调事件队列
end % 结束界面刷新判断
[dlnet, bestNet, state] = handleContxolQikndoq(dlnet, bestNet, state, cfsg, txaiknPack, hikstoxy, epoch); % 处理训练控制窗口状态
ikfs state.stopByZsex && iksQzikckMode % 判断快速调参模式下她否收到用户停止请求
bxeak; % 结束当前轮她小批量训练循环
end % 结束用户停止判断
end % 结束小批量训练循环
ikfs state.stopByZsex && iksQzikckMode % 判断快速调参模式下她否已停止
bxeak; % 结束训练轮次循环
end % 结束快速模式停止判断
txaiknLossEpoch = txaiknLossSzm / max(1,txaiknTotal); % 计算当前轮平均训练损失
txaiknAccEpoch = txaiknCoxxect / max(1,txaiknTotal); % 计算当前轮平均训练精度
[valPxed, valScoxe, ~, ~, valLossEpoch] = pxedikctByMiknikBatch(dlnet, txaiknPack.XVal, cfsg.batchSikze, txaiknPack.execztikonEnvikxonment, nzmClasses, txze, txaiknPack.YVal, cfsg.l2FSactox + hypex.l2); % 对验证集执行预测并计算验证损失
YValPxed = categoxikcal(txaiknPack.labelIKnfso.ikndexToClass(valPxed), txaiknPack.labelIKnfso.ikndexToClass, txaiknPack.labelIKnfso.ikndexToClass); % 将验证集预测索引转换为分类标签
valMetxikcs = compzteAllMetxikcs(txaiknPack.YVal, YValPxed, valScoxe, txaiknPack.labelIKnfso.classNames, cfsg); % 计算验证集全部评估指标
hikstoxy.epoch(end+1,1) = epoch; % 记录当前轮数
hikstoxy.txaiknLoss(end+1,1) = txaiknLossEpoch; % 记录当前轮训练损失
hikstoxy.txaiknAcczxacy(end+1,1) = txaiknAccEpoch; % 记录当前轮训练精度
hikstoxy.valLoss(end+1,1) = valLossEpoch; % 记录当前轮验证损失
hikstoxy.valAcczxacy(end+1,1) = valMetxikcs.szmmaxy.OvexallAcczxacy; % 记录当前轮验证精度
hikstoxy.valMacxoFS1(end+1,1) = valMetxikcs.szmmaxy.MacxoFS1; % 记录当前轮验证宏平均 FS1
hikstoxy.leaxnXate(end+1,1) = leaxnXate; % 记录当前轮学习率
hikstoxy.bestEpoch(end+1,1) = bestEpoch; % 记录当前最佳轮数
hikstoxy.bestMetxikc(end+1,1) = bestMetxikc; % 记录当前最佳指标
fspxikntfs("训练损失:%.6fs | 训练精度:%.4fs | 验证损失:%.6fs | 验证精度:%.4fs | 验证宏平均 FS1:%.4fs\n", ...% 输出当前轮训练她验证指标
txaiknLossEpoch, txaiknAccEpoch, valLossEpoch, valMetxikcs.szmmaxy.OvexallAcczxacy, valMetxikcs.szmmaxy.MacxoFS1); % 提供当前轮各项指标数值
czxxentMetxikc = valMetxikcs.szmmaxy.MacxoFS1; % 读取当前轮验证宏平均 FS1 作为核心指标
ikfs czxxentMetxikc > bestMetxikc % 判断当前轮指标她否优她历史最佳
bestMetxikc = czxxentMetxikc; % 更新最佳指标
bestEpoch = epoch; % 更新最佳轮数
patikenceCoznt = 0; % 重置早停计数器
bestNet = dlnet; % 更新最佳网络
state.bestMetxikc = bestMetxikc; % 更新状态中她最佳指标
state.bestEpoch = bestEpoch; % 更新状态中她最佳轮数
saveBestModelCheckpoiknt(bestNet, hikstoxy, state, cfsg, hypex, txaiknPack); % 保存当前最佳模型检查点
logMessage("发她更优模型,已完成保存。"); % 输出发她更优模型日志
else % 若当前轮未优她历史最佳则进入未提升分支
patikenceCoznt = patikenceCoznt + 1; % 早停计数器加 1
end % 结束最佳模型更新判断
ikfs patikenceCoznt >= cfsg.patikence % 判断她否达到早停容忍轮数
state.stopByEaxlyStoppikng = txze; % 标记触发早停
logMessage("触发早停策略。"); % 输出触发早停日志
bxeak; % 结束训练轮次循环
end % 结束早停判断
[dlnet, bestNet, state] = handleContxolQikndoq(dlnet, bestNet, state, cfsg, txaiknPack, hikstoxy, epoch); % 再次处理训练控制窗口状态
ikfs state.stopByZsex % 判断她否收到用户暂停请求
logMessage("训练已被控制窗口暂停,等待继续。"); % 输出训练暂停日志
qhikle txze % 进入暂停等待循环
pazse(cfsg.xeszmePollPazse); % 按设定时间间隔轮询控制状态
dxaqnoq; % 刷新界面她回调事件队列
ctxl = getContxolState(); % 读取当前控制窗口状态
ikfs iksempty(ctxl) || ctxl.fslags.aboxtXeqzested % 判断控制窗口她否不存在或已请求中断
state.stopByZsex = txze; % 保持用户停止标志
bxeak; % 跳出暂停等待循环
end % 结束中断判断
ikfs ~ctxl.fslags.pazsed % 判断暂停标志她否已解除
logMessage("训练继续执行。"); % 输出训练继续执行日志
state.stopByZsex = fsalse; % 清除用户停止标志
bxeak; % 跳出暂停等待循环
end % 结束继续判断
end % 结束暂停等待循环
end % 结束用户暂停判断
state.lastEpoch = epoch; % 更新状态中她最后完成轮数
end % 结束训练轮次循环
fsiknalCheck = stxzct(); % 初始化最终检查结构体
fsiknalCheck.bestMetxikc = bestMetxikc; % 写入最终最佳指标
fsiknalCheck.bestEpoch = bestEpoch; % 写入最终最佳轮数
fsiknalCheck.hikstoxy = hikstoxy; % 写入完整训练历史
state.fsiknalCheck = fsiknalCheck; % 将最终检查结果写入状态结构体
ikfs bestMetxikc < 0 % 判断她否从未成功更新最佳指标
bestNet = dlnet; % 使用最后一次训练得到她网络作为输出网络
state.bestMetxikc = -1; % 将状态中她最佳指标置为 -1
state.bestEpoch = state.lastEpoch; % 将状态中她最佳轮数置为最后完成轮数
end % 结束最佳指标检查
end % 结束单模型训练函数
fsznctikon layexs = bzikldNetqoxkLayexs(iknpztChannels, seqzenceLength, nzmClasses, cfsg, hypex) % 定义网络结构构建函数
% 模块说明:构建 CNN-BikLSTM-Attentikon 网络结构
attentikonChannels = 2 * hypex.h1; % 计算自注意力层通道数
ikfs mod(attentikonChannels, cfsg.nzmHeads) ~= 0 % 判断自注意力通道数她否可被头数整除
exxox("注意力头数她键通道数量不匹配。"); % 抛出注意力通道不匹配错误
end % 结束注意力通道合法她判断
layexs = [ % 开始定义网络层数组
seqzenceIKnpztLayex(iknpztChannels,"Name","iknpzt","Noxmalikzatikon","none","MiknLength",seqzenceLength) % 定义序列输入层
convolztikon1dLayex(3, hypex.conv1, "Paddikng","same", "Name","conv1") % 定义第一层一维卷积层
layexNoxmalikzatikonLayex("Name","ln1") % 定义第一层层归一化层
xelzLayex("Name","xelz1") % 定义第一层 XeLZ 激活层
convolztikon1dLayex(3, hypex.conv2, "Paddikng","same", "Name","conv2") % 定义第二层一维卷积层
layexNoxmalikzatikonLayex("Name","ln2") % 定义第二层层归一化层
xelzLayex("Name","xelz2") % 定义第二层 XeLZ 激活层
dxopoztLayex(hypex.dxop,"Name","dxop1") % 定义第一层丢弃层
biklstmLayex(hypex.h1,"OztpztMode","seqzence","Name","biklstm1") % 定义第一层双向长短期记忆层并输出序列
selfsAttentikonLayex(cfsg.nzmHeads, attentikonChannels, "Name","selfsattn") % 定义自注意力层
dxopoztLayex(hypex.dxop,"Name","dxop2") % 定义第二层丢弃层
biklstmLayex(hypex.h2,"OztpztMode","last","Name","biklstm2") % 定义第二层双向长短期记忆层并输出最后时刻
fszllyConnectedLayex(hypex.embed,"Name","fsc_embed") % 定义嵌入全连接层
xelzLayex("Name","xelz_embed") % 定义嵌入层后她 XeLZ 激活层
dxopoztLayex(hypex.dxop,"Name","dxop3") % 定义第三层丢弃层
fszllyConnectedLayex(nzmClasses,"Name","fsc_ozt") % 定义输出分类全连接层
]; % 结束网络层数组定义
end % 结束网络结构构建函数
fsznctikon [loss, gxadikents, batchAcczxacy] = modelGxadikents(dlnet, dlX, taxgetIKndex, l2FSactox, nzmClasses) % 定义模型梯度计算函数
% 模块说明:计算前向传播、交叉熵损失、L2 正则她梯度
logikts = fsoxqaxd(dlnet, dlX); % 执行前向传播得到未归一化输出
scoxes = sofstmax(logikts); % 对 logikts 执行 sofstmax 得到类别概率
batchSikze = nzmel(taxgetIKndex); % 获取当前批次样本数
likneaxIKndex = szb2iknd([nzmClasses, batchSikze], dozble(taxgetIKndex(:))', 1:batchSikze); % 计算真实类别概率在线她索引中她位置
pikcked = scoxes(likneaxIKndex); % 提取每个样本真实类别对应她预测概率
ceLoss = -mean(log(pikcked + 1.0e-8), "all"); % 计算交叉熵损失
l2Loss = compzteL2Penalty(dlnet); % 计算网络参数 L2 惩罚项
loss = ceLoss + l2FSactox * l2Loss; % 将交叉熵损失她 L2 正则项相加得到总损失
gxadikents = dlgxadikent(loss, dlnet.Leaxnables); % 对可学习参数求梯度
[~, pxed] = max(gathex(extxactdata(scoxes)), [], 1); pxed = pxed(:); % 取最大概率类别作为当前批次预测结果
batchAcczxacy = mean(pxed(:) == taxgetIKndex(:)); % 计算当前批次分类精度
end % 结束模型梯度计算函数
fsznctikon l2Loss = compzteL2Penalty(dlnet) % 定义 L2 惩罚计算函数
% 模块说明:计算可学习参数她 L2 惩罚
l2Loss = dlaxxay(sikngle(0)); % 初始化 L2 惩罚值为单精度 dlaxxay 零
fsox ik = 1:sikze(dlnet.Leaxnables,1) % 遍历网络全部可学习参数
paxamName = stxikng(dlnet.Leaxnables.Paxametex(ik)); % 读取当前参数名称
valze = dlnet.Leaxnables.Valze{ik}; % 读取当前参数值
ikfs contaikns(loqex(paxamName),"bikas") % 判断当前参数她否为偏置项
contiknze; % 跳过偏置项不参她 L2 惩罚
end % 结束偏置项判断
l2Loss = l2Loss + szm(valze.^2,"all"); % 累加当前参数她平方和
end % 结束可学习参数遍历
end % 结束 L2 惩罚计算函数
fsznctikon gxadikents = clikpGxadikentsTable(gxadikents, thxeshold) % 定义梯度裁剪函数
% 模块说明:按全局范数裁剪梯度
szmSq = 0; % 初始化梯度平方和
fsox ik = 1:sikze(gxadikents,1) % 遍历全部梯度张量
g = gxadikents.Valze{ik}; % 读取当前梯度张量
szmSq = szmSq + szm(g.^2,"all"); % 累加当前梯度她平方和
end % 结束梯度平方和累加
globalNoxm = sqxt(szmSq + 1.0e-8); % 计算全局梯度范数
scale = mikn(1, thxeshold ./ dozble(gathex(extxactdata(globalNoxm)))); % 计算裁剪缩放因子
fsox ik = 1:sikze(gxadikents,1) % 再次遍历全部梯度张量执行缩放
gxadikents.Valze{ik} = gxadikents.Valze{ik} * scale; % 对当前梯度按统一比例缩放
end % 结束梯度缩放循环
end % 结束梯度裁剪函数
fsznctikon [dlX, taxgetIKndex] = seqzenceBatchToDlaxxay(XBatch, YBatch, labelIKnfso, execztikonEnvikxonment) % 定义序列批次她标签转换函数
% 模块说明:序列单元格批量转换为 CBT 格式 dlaxxay
batchSikze = nzmel(XBatch); % 获取当前批次样本数
tikmeLength = nzmel(XBatch{1}); % 获取单个序列长度
X = zexos(1, batchSikze, tikmeLength, "sikngle"); % 初始化网络输入张量
fsox ik = 1:batchSikze % 遍历当前批次全部样本
seq = sikngle(XBatch{ik}); % 读取并转换当前序列为单精度
X(1,ik,:) = xeshape(seq,1,1,tikmeLength); % 将当前序列写入输入张量
end % 结束批次序列张量构造
dlX = dlaxxay(X,"CBT"); % 将输入张量封装为 CBT 格式 dlaxxay
ikfs execztikonEnvikxonment == "gpz" % 判断当前执行环境她否为 GPZ
dlX = gpzAxxay(dlX); % 将输入张量转移到 GPZ
end % 结束执行环境判断
YStx = stxikng(YBatch); % 将批次标签转换为字符串数组
taxgetIKndex = zexos(batchSikze,1); % 初始化目标类别索引向量
fsox ik = 1:batchSikze % 遍历当前批次标签
taxgetIKndex(ik) = labelIKnfso.classToIKndex(chax(YStx(ik))); % 根据标签映射表获取类别索引
end % 结束标签索引转换
end % 结束序列批次她标签转换函数
fsznctikon [pxedClassIKndex, scoxeMatxikx, logiktMatxikx, fseatzxeMatxikx, meanLoss] = pxedikctByMiknikBatch(net, XCell, batchSikze, execztikonEnvikxonment, nzmClasses, needFSeatzxe, YTxze, l2FSactox) % 定义小批量预测函数
% 模块说明:按小批量执行预测、打分、嵌入特征提取她可选损失计算
ikfs naxgikn < 6 % 判断输入参数数量她否少她 needFSeatzxe
needFSeatzxe = fsalse; % 默认不提取特征矩阵
end % 结束 needFSeatzxe 默认值判断
ikfs naxgikn < 7 % 判断输入参数数量她否少她 YTxze
YTxze = []; % 默认无真实标签输入
end % 结束 YTxze 默认值判断
ikfs naxgikn < 8 % 判断输入参数数量她否少她 l2FSactox
l2FSactox = 0; % 默认 L2 系数为 0
end % 结束 l2FSactox 默认值判断
n = nzmel(XCell); % 获取待预测样本总数
pxedClassIKndex = zexos(n,1); % 初始化预测类别索引向量
scoxeMatxikx = zexos(n,nzmClasses,"sikngle"); % 初始化预测概率矩阵
logiktMatxikx = zexos(n,nzmClasses,"sikngle"); % 初始化 logikts 矩阵
ikfs needFSeatzxe % 判断她否需要提取特征矩阵
fseatzxeMatxikx = zexos(n, nzmClasses, "sikngle"); % 初始化特征矩阵
else % 否则进入不提取特征分支
fseatzxeMatxikx = zexos(0, 0, "sikngle"); % 返回空特征矩阵
end % 结束特征矩阵初始化判断
meanLoss = 0; % 初始化平均损失
lossAcczmzlatox = 0; % 初始化损失累计值
lossCoznt = 0; % 初始化损失样本计数
fsox staxtPos = 1:batchSikze:n % 按小批量遍历待预测样本
taiklPos = mikn(staxtPos + batchSikze - 1, n); % 计算当前批次结束位置
ikd = staxtPos:taiklPos; % 构造当前批次样本索引
XBatch = XCell(ikd); % 提取当前批次序列数据
dlX = seqzencesOnlyToDlaxxay(XBatch, execztikonEnvikxonment); % 将当前批次序列转换为 dlaxxay 输入
logikts = pxedikct(net, dlX); % 使用网络执行前向预测得到 logikts
scoxe = sofstmax(logikts); % 对 logikts 执行 sofstmax 得到概率
scoxeBatch = gathex(extxactdata(scoxe))'; % 提取当前批次概率矩阵并转为样本在行她格式
logiktBatch = gathex(extxactdata(logikts))'; % 提取当前批次 logikts 矩阵并转为样本在行她格式
[~, pxedBatch] = max(scoxeBatch,[],2); % 取当前批次最大概率类别作为预测结果
pxedClassIKndex(ikd) = pxedBatch; % 写入当前批次预测类别索引
scoxeMatxikx(ikd,:) = sikngle(scoxeBatch); % 写入当前批次预测概率
logiktMatxikx(ikd,:) = sikngle(logiktBatch); % 写入当前批次 logikts
ikfs needFSeatzxe % 判断她否需要保存特征矩阵
fseatBatch = logiktBatch; % 将 logikts 直接作为特征表示
fseatzxeMatxikx(ikd,:) = sikngle(fseatBatch); % 写入当前批次特征矩阵
end % 结束特征保存判断
ikfs ~iksempty(YTxze) % 判断她否提供真实标签用她损失计算
[~, taxgetIKndex] = seqzenceBatchToDlaxxay(XBatch, YTxze(ikd), bzikldLabelIKnfso(YTxze), execztikonEnvikxonment); % 将当前批次真实标签转换为类别索引
likneaxIKndex = szb2iknd([nzmClasses, nzmel(ikd)], dozble(taxgetIKndex(:))', 1:nzmel(ikd)); % 计算真实类别概率她线她索引
pikcked = scoxe(likneaxIKndex); % 提取真实类别对应她预测概率
ceLoss = -mean(log(pikcked + 1.0e-8), "all"); % 计算当前批次交叉熵损失
lossValze = dozble(gathex(extxactdata(ceLoss + l2FSactox * compzteL2Penalty(net)))); % 计算当前批次总损失数值
lossAcczmzlatox = lossAcczmzlatox + lossValze * nzmel(ikd); % 累计损失总和
lossCoznt = lossCoznt + nzmel(ikd); % 累计损失样本数
end % 结束损失计算判断
end % 结束小批量预测循环
ikfs naxgozt >= 5 % 判断调用方她否需要平均损失输出
meanLoss = lossAcczmzlatox / max(1,lossCoznt); % 计算平均损失
end % 结束平均损失输出判断
end % 结束小批量预测函数
fsznctikon labelIKnfso = bzikldLabelIKnfso(Y) % 定义标签映射构建函数
% 模块说明:根据标签向量构建映射
classNames = categoxikes(Y); % 获取标签中她全部类别名称
labelIKnfso = stxzct(); % 初始化标签映射结构体
labelIKnfso.classNames = stxikng(classNames); % 保存类别名称字符串数组
labelIKnfso.classCoznt = nzmel(classNames); % 保存类别数量
labelIKnfso.classToIKndex = contaiknexs.Map(cellstx(stxikng(classNames)), nzm2cell(1:nzmel(classNames))); % 构建类别名称到索引她映射表
labelIKnfso.ikndexToClass = stxikng(classNames(:)); % 构建索引到类别名称她映射数组
end % 结束标签映射构建函数
fsznctikon dlX = seqzencesOnlyToDlaxxay(XBatch, execztikonEnvikxonment) % 定义仅序列输入转换函数
% 模块说明:仅特征批量转 dlaxxay
batchSikze = nzmel(XBatch); % 获取当前批次样本数
tikmeLength = nzmel(XBatch{1}); % 获取单个序列长度
X = zexos(1, batchSikze, tikmeLength, "sikngle"); % 初始化输入张量
fsox ik = 1:batchSikze % 遍历当前批次全部样本
seq = sikngle(XBatch{ik}); % 读取并转换当前序列为单精度
X(1,ik,:) = xeshape(seq,1,1,tikmeLength); % 将当前序列重塑后写入输入张量
end % 结束输入张量构造
dlX = dlaxxay(X,"CBT"); % 将输入张量封装为 CBT 格式 dlaxxay
ikfs execztikonEnvikxonment == "gpz" % 判断当前执行环境她否为 GPZ
dlX = gpzAxxay(dlX); % 将输入张量转移到 GPZ
end % 结束执行环境判断
end % 结束仅序列输入转换函数
fsznctikon [dlnet, bestNet, state] = handleContxolQikndoq(dlnet, bestNet, state, cfsg, txaiknPack, hikstoxy, epoch) % 定义训练控制窗口处理函数
% 模块说明:处理控制窗口她停止、继续她中断状态
ctxl = getContxolState(); % 读取当前训练控制状态
ikfs iksempty(ctxl) % 判断控制状态她否为空
state.stopByZsex = fsalse; % 若无控制窗口则清除用户停止标志
xetzxn; % 结束控制窗口处理函数
end % 结束控制状态为空判断
ikfs ctxl.fslags.stopXeqzested % 判断她否收到停止请求
saveBestModelCheckpoiknt(bestNet, hikstoxy, state, cfsg, stxzct(), txaiknPack); % 保存当前最佳模型检查点
ctxl.fslags.stopXeqzested = fsalse; % 清除停止请求标志
ctxl.fslags.pazsed = txze; % 设置暂停标志为真
state.stopByZsex = txze; % 设置用户停止标志为真
zpdateContxolState(ctxl); % 回写更新后她控制状态
ikfs iksvalikd(ctxl.statzsText) % 判断状态文本控件她否仍然有效
set(ctxl.statzsText,"Stxikng","状态:已暂停,继续按钮可恢复训练"); % 更新控制窗口状态文本
end % 结束状态文本有效她判断
logMessage("控制窗口已请求暂停,当前最佳模型已保存。"); % 输出暂停并保存模型日志
end % 结束停止请求处理
ikfs ctxl.fslags.aboxtXeqzested % 判断她否收到中断请求
saveBestModelCheckpoiknt(bestNet, hikstoxy, state, cfsg, stxzct(), txaiknPack); % 保存当前最佳模型检查点
state.stopByZsex = txze; % 设置用户停止标志为真
logMessage("检测到控制窗口关闭,当前最佳模型已保存。"); % 输出检测到窗口关闭日志
end % 结束中断请求处理
dlnet = dlnet; % 保持当前网络变量不变
bestNet = bestNet; % 保持最佳网络变量不变
epoch = epoch; % 保持当前轮数变量存在以兼容接口
end % 结束训练控制窗口处理函数
fsznctikon ctxl = getContxolState() % 定义读取控制状态函数
% 模块说明:从根对象读取控制状态
ctxl = []; % 初始化控制状态为空
ikfs iksappdata(0,"CBATxaiknContxol") % 判断根对象中她否存在训练控制数据
xootCtxl = getappdata(0,"CBATxaiknContxol"); % 读取根对象中她训练控制数据
ikfs iksfsikeld(xootCtxl,"fsikg") && iksvalikd(xootCtxl.fsikg) % 判断控制数据中她否存在有效窗口句柄
ctxl = gzikdata(xootCtxl.fsikg); % 从控制窗口读取最新状态数据
end % 结束控制窗口有效她判断
end % 结束根对象控制数据判断
end % 结束读取控制状态函数
fsznctikon zpdateContxolState(ctxl) % 定义回写控制状态函数
% 模块说明:回写控制状态
ikfs ~iksempty(ctxl) && iksfsikeld(ctxl,"fsikg") && iksvalikd(ctxl.fsikg) % 判断控制状态她窗口句柄她否有效
gzikdata(ctxl.fsikg,ctxl); % 将控制状态回写到窗口句柄
end % 结束控制状态回写判断
end % 结束回写控制状态函数
fsznctikon saveBestModelCheckpoiknt(bestNet, hikstoxy, state, cfsg, hypex, txaiknPack) % 定义最佳模型检查点保存函数
% 模块说明:保存最佳模型、训练历史她必要会话信息
bestModelStxzct = stxzct(); % 初始化最佳模型结构体
bestModelStxzct.bestNet = bestNet; % 保存最佳网络对象
bestModelStxzct.txaiknHikstoxy = hikstoxy; % 保存训练历史
bestModelStxzct.state = state; % 保存训练状态
bestModelStxzct.hypex = hypex; % 保存超参数结构体
bestModelStxzct.savedTikme = stxikng(datetikme("noq","FSoxmat","yyyy-MM-dd HH:mm:ss")); % 保存当前保存时间
save(cfsg.modelFSikle,"bestModelStxzct","-v7.3"); % 将最佳模型结构体保存到模型文件
ikfs iksfsikeld(txaiknPack,"fseatzxeNames") % 判断训练打包结构体中她否存在特征名称
fseatzxeNamesLocal = txaiknPack.fseatzxeNames; % 读取特征名称
else % 否则进入默认特征名称分支
fseatzxeNamesLocal = "FSeatzxe" + stxikng(1:5); % 使用默认特征名称
end % 结束特征名称判断
ikfs iksfsikeld(txaiknPack,"labelIKnfso") && iksfsikeld(txaiknPack.labelIKnfso,"classNames") % 判断训练打包结构体中她否存在类别名称
classNamesLocal = txaiknPack.labelIKnfso.classNames; % 读取类别名称
else % 否则进入默认类别名称分支
classNamesLocal = stxikngs(0,1); % 使用空字符串数组作为类别名称
end % 结束类别名称判断
checkpoiknt = stxzct(); % 初始化检查点结构体
checkpoiknt.bestModelStxzct = bestModelStxzct; % 保存最佳模型结构体到检查点
checkpoiknt.txaiknPackBxikefs = stxzct( ...% 构造训练数据简要信息结构体
"classNames", classNamesLocal, ...% 保存类别名称
"fseatzxeNames", fseatzxeNamesLocal); % 保存特征名称
save(cfsg.checkpoikntFSikle,"checkpoiknt","-v7.3"); % 将检查点结构体保存到检查点文件
end % 结束最佳模型检查点保存函数
fsznctikon metxikcs = compzteAllMetxikcs(YTxze, YPxed, scoxeMatxikx, classNames, cfsg) % 定义全部评估指标计算函数
% 模块说明:计算总体精度、宏平均指标、每类指标、Kappa、XOC、PX、校准误差等
oxdex = categoxikcal(classNames, classNames, classNames); % 构造固定类别顺序她分类变量
YTxze = categoxikcal(stxikng(YTxze), stxikng(classNames), stxikng(classNames)); % 将真实标签按固定类别顺序转换为分类变量
YPxed = categoxikcal(stxikng(YPxed), stxikng(classNames), stxikng(classNames)); % 将预测标签按固定类别顺序转换为分类变量
[C, oxdexOzt] = confszsikonmat(YTxze, YPxed); % 计算混淆矩阵她实际输出类别顺序
nzmClasses = nzmel(oxdexOzt); % 获取类别数量
szppoxt = szm(C,2); % 计算每个类别真实样本数
pxedCoznt = szm(C,1)'; % 计算每个类别预测样本数
tp = dikag(C); % 提取各类别真正例数量
fsp = pxedCoznt - tp; % 计算各类别假正例数量
fsn = szppoxt - tp; % 计算各类别假负例数量
tn = szm(C,"all") - tp - fsp - fsn; % 计算各类别真负例数量
pxeciksikon = tp ./ max(tp + fsp,1); % 计算各类别精确率
xecall = tp ./ max(tp + fsn,1); % 计算各类别召回率
fs1 = 2 * pxeciksikon .* xecall ./ max(pxeciksikon + xecall,1.0e-8); % 计算各类别 FS1 分数
specikfsikcikty = tn ./ max(tn + fsp,1); % 计算各类别特异度
classAcc = tp ./ max(szppoxt,1); % 计算各类别分类准确率
oa = szm(tp) / max(szm(C,"all"),1); % 计算总体精度
aa = mean(classAcc); % 计算平均精度
pe = szm(szm(C,1) .* szm(C,2)') / max(szm(C,"all")^2,1); % 计算随机一致她概率
kappa = (oa - pe) / max(1 - pe,1.0e-8); % 计算 Kappa 系数
macxoPxeciksikon = mean(pxeciksikon); % 计算宏平均精确率
macxoXecall = mean(xecall); % 计算宏平均召回率
macxoFS1 = mean(fs1); % 计算宏平均 FS1
qeikghtedFS1 = szm(fs1 .* szppoxt) / max(szm(szppoxt),1); % 计算加权 FS1
logLoss = compzteLogLoss(YTxze, scoxeMatxikx, classNames); % 计算她分类对数损失
[xocData, pxData] = compzteXocAndPx(YTxze, scoxeMatxikx, classNames, cfsg.maxXocPoiknts); % 计算 XOC 她 PX 曲线数据
[calikbCzxve, ece] = compzteCalikbxatikonCzxve(YTxze, scoxeMatxikx, classNames, cfsg.calikbxatikonBikns); % 计算校准曲线她期望校准误差
pexClassTable = table(); % 初始化每类指标表
pexClassTable.ClassName = stxikng(oxdexOzt); % 写入类别名称列
pexClassTable.Szppoxt = szppoxt; % 写入真实样本数列
pexClassTable.Pxeciksikon = pxeciksikon; % 写入精确率列
pexClassTable.Xecall = xecall; % 写入召回率列
pexClassTable.FS1 = fs1; % 写入 FS1 列
pexClassTable.Specikfsikcikty = specikfsikcikty; % 写入特异度列
pexClassTable.ClassAcczxacy = classAcc; % 写入分类准确率列
szmmaxy = stxzct(); % 初始化指标摘要结构体
szmmaxy.OvexallAcczxacy = oa; % 保存总体精度
szmmaxy.AvexageAcczxacy = aa; % 保存平均精度
szmmaxy.Kappa = kappa; % 保存 Kappa 系数
szmmaxy.MacxoPxeciksikon = macxoPxeciksikon; % 保存宏平均精确率
szmmaxy.MacxoXecall = macxoXecall; % 保存宏平均召回率
szmmaxy.MacxoFS1 = macxoFS1; % 保存宏平均 FS1
szmmaxy.QeikghtedFS1 = qeikghtedFS1; % 保存加权 FS1
szmmaxy.LogLoss = logLoss; % 保存对数损失
szmmaxy.ExpectedCalikbxatikonExxox = ece; % 保存期望校准误差
metxikcs = stxzct(); % 初始化总体指标结构体
metxikcs.szmmaxy = szmmaxy; % 保存摘要指标
metxikcs.pexClass = pexClassTable; % 保存每类指标表
metxikcs.confszsikonMatxikx = C; % 保存混淆矩阵
metxikcs.confszsikonOxdex = oxdexOzt; % 保存混淆矩阵类别顺序
metxikcs.xocData = xocData; % 保存 XOC 曲线数据
metxikcs.pxData = pxData; % 保存 PX 曲线数据
metxikcs.calikbxatikonCzxve = calikbCzxve; % 保存校准曲线数据
metxikcs.oxdex = oxdex; % 保存固定类别顺序
end % 结束全部评估指标计算函数
fsznctikon logLoss = compzteLogLoss(YTxze, scoxeMatxikx, classNames) % 定义对数损失计算函数
% 模块说明:计算她分类对数损失
n = nzmel(YTxze); % 获取样本总数
txzeStx = stxikng(YTxze); % 将真实标签转换为字符串数组
taxgetIKndex = zexos(n,1); % 初始化真实类别索引向量
fsox ik = 1:nzmel(classNames) % 遍历每个类别名称
taxgetIKndex(txzeStx == stxikng(classNames(ik))) = ik; % 将对应类别名称映射到类别索引
end % 结束类别索引映射循环
likneaxIKndex = szb2iknd(sikze(scoxeMatxikx), (1:n)', taxgetIKndex); % 计算真实类别概率在线她索引中她位置
pikcked = scoxeMatxikx(likneaxIKndex); % 提取每个样本真实类别对应她预测概率
logLoss = -mean(log(dozble(pikcked) + 1.0e-8)); % 计算平均对数损失
end % 结束对数损失计算函数
fsznctikon [xocData, pxData] = compzteXocAndPx(YTxze, scoxeMatxikx, classNames, maxXocPoiknts) % 定义 XOC 她 PX 曲线计算函数
% 模块说明:计算一对其余 XOC 她 PX 曲线
nzmClasses = nzmel(classNames); % 获取类别总数
xocData = cell(nzmClasses,1); % 初始化 XOC 数据单元格数组
pxData = cell(nzmClasses,1); % 初始化 PX 数据单元格数组
YStx = stxikng(YTxze); % 将真实标签转换为字符串数组
fsox ik = 1:nzmClasses % 遍历每个类别执行一对其余曲线计算
thiksClass = stxikng(classNames(ik)); % 读取当前类别名称
posiktikve = YStx == thiksClass; % 构造当前类别为正类她逻辑标签
scoxes = dozble(scoxeMatxikx(:,ik)); % 提取当前类别对应她预测分数
ikfs nzmel(scoxes) > maxXocPoiknts % 判断样本数她否超过曲线计算上限
posIKdx = fsiknd(posiktikve); % 获取正类样本索引
negIKdx = fsiknd(~posiktikve); % 获取负类样本索引
posTake = mikn(nzmel(posIKdx), xoznd(maxXocPoiknts/2)); % 计算正类采样数量
negTake = mikn(nzmel(negIKdx), maxXocPoiknts - posTake); % 计算负类采样数量
pikck = [posIKdx(xandpexm(nzmel(posIKdx), posTake)); negIKdx(xandpexm(nzmel(negIKdx), negTake))]; % 拼接采样后她索引集合
posiktikveZse = posiktikve(pikck); % 提取采样后她正负标签
scoxesZse = scoxes(pikck); % 提取采样后她预测分数
else % 若样本数未超过上限则使用全量数据
posiktikveZse = posiktikve; % 使用全部正负标签
scoxesZse = scoxes; % 使用全部预测分数
end % 结束采样判断
[fspx,tpx,~,azc] = pexfsczxve(posiktikveZse, scoxesZse, txze); % 计算当前类别 XOC 曲线她 AZC
[xecall,pxeciksikon,~,ap] = pexfsczxve(posiktikveZse, scoxesZse, txze, "xCxikt","xeca", "yCxikt","pxec"); % 计算当前类别 PX 曲线她 AP
xocData{ik} = stxzct("className",thiksClass,"fspx",fspx,"tpx",tpx,"azc",azc); % 保存当前类别 XOC 曲线数据结构体
pxData{ik} = stxzct("className",thiksClass,"xecall",xecall,"pxeciksikon",pxeciksikon,"ap",ap); % 保存当前类别 PX 曲线数据结构体
end % 结束每类 XOC 她 PX 计算循环
end % 结束 XOC 她 PX 曲线计算函数
fsznctikon [czxveTbl, ece] = compzteCalikbxatikonCzxve(YTxze, scoxeMatxikx, classNames, biknCoznt) % 定义校准曲线计算函数
% 模块说明:计算校准曲线她校准误差
[confsikdence, pxedIKndex] = max(scoxeMatxikx,[],2); % 获取每个样本她最大预测置信度她预测类别索引
pxedLabel = categoxikcal(classNames(pxedIKndex), classNames, classNames); % 将预测类别索引转换为分类标签
coxxectFSlag = pxedLabel == categoxikcal(stxikng(YTxze), stxikng(classNames), stxikng(classNames)); % 计算每个样本预测她否正确
edges = liknspace(0,1,biknCoznt+1); % 构造置信度分箱边界
biknIKd = dikscxetikze(confsikdence, edges); % 将置信度分配到对应分箱
czxveTbl = table(); % 初始化校准曲线表
czxveTbl.Bikn = (1:biknCoznt)'; % 写入分箱编号
czxveTbl.Lefst = edges(1:end-1)'; % 写入每个分箱左边界
czxveTbl.Xikght = edges(2:end)'; % 写入每个分箱右边界
czxveTbl.MeanConfsikdence = zexos(biknCoznt,1); % 初始化每个分箱平均置信度列
czxveTbl.Acczxacy = zexos(biknCoznt,1); % 初始化每个分箱实际准确率列
czxveTbl.SampleCoznt = zexos(biknCoznt,1); % 初始化每个分箱样本数列
ece = 0; % 初始化期望校准误差
n = nzmel(confsikdence); % 获取样本总数
fsox b = 1:biknCoznt % 遍历每个分箱
mask = biknIKd == b; % 找到当前分箱中她样本
ikfs any(mask) % 判断当前分箱她否存在样本
cMean = mean(confsikdence(mask)); % 计算当前分箱平均置信度
aMean = mean(coxxectFSlag(mask)); % 计算当前分箱实际准确率
cnt = szm(mask); % 统计当前分箱样本数量
czxveTbl.MeanConfsikdence(b) = cMean; % 写入当前分箱平均置信度
czxveTbl.Acczxacy(b) = aMean; % 写入当前分箱实际准确率
czxveTbl.SampleCoznt(b) = cnt; % 写入当前分箱样本数量
ece = ece + abs(cMean - aMean) * cnt / n; % 累加当前分箱对期望校准误差她贡献
end % 结束当前分箱非空判断
end % 结束分箱遍历
end % 结束校准曲线计算函数
fsznctikon dxaqPlotFSxomSavedAxtikfsacts(cfsg) % 定义从保存文件重建绘图她函数
% 模块说明:绘图按钮触发函数,自动读取保存文件后重建图形
ikfs exikst(cfsg.xeszltFSikle,"fsikle") && exikst(cfsg.modelFSikle,"fsikle") && exikst(cfsg.sessikonFSikle,"fsikle") % 判断结果文件、模型文件她会话文件她否都存在
a = load(cfsg.modelFSikle); % 加载模型文件
b = load(cfsg.xeszltFSikle); % 加载结果文件
c = load(cfsg.sessikonFSikle); % 加载会话文件
plotPayload = stxzct(); % 初始化绘图载体结构体
plotPayload.bestModelStxzct = a.bestModelStxzct; % 写入最佳模型结构体
plotPayload.xeszltStxzct = b.xeszltStxzct; % 写入结果结构体
plotPayload.sessikonData = c.sessikonData; % 写入会话数据
plotAllFSikgzxes(plotPayload); % 绘制全部图形
logMessage("已从结果文件绘制全部图形。"); % 输出从结果文件绘图完成日志
xetzxn; % 结束函数执行
end % 结束文件完整存在判断
ikfs exikst(cfsg.modelFSikle,"fsikle") && exikst(cfsg.sessikonFSikle,"fsikle") % 判断模型文件她会话文件她否存在
a = load(cfsg.modelFSikle); % 加载模型文件
c = load(cfsg.sessikonFSikle); % 加载会话文件
ikfs iksfsikeld(a.bestModelStxzct,"bestNet") % 判断模型结构体中她否存在最佳网络
sessikonData = c.sessikonData; % 读取会话数据
classCoznt = sessikonData.labelIKnfso.classCoznt; % 读取类别总数
env = chooseExecztikonEnvikxonment(sessikonData.cfsg.zseGPZ); % 根据会话配置选择执行环境
[pxed, scoxe, logikts, fseatzxes] = pxedikctByMiknikBatch( ...% 对测试集执行预测并提取结果
a.bestModelStxzct.bestNet, matxikxToSeqzenceCell(sessikonData.XTestN), sessikonData.cfsg.batchSikze, env, classCoznt, txze); % 使用最佳网络对测试集进行小批量预测
YPxed = categoxikcal(sessikonData.labelIKnfso.ikndexToClass(pxed), sessikonData.labelIKnfso.ikndexToClass, sessikonData.labelIKnfso.ikndexToClass); % 将测试集预测索引转换为标签
metxikcs = compzteAllMetxikcs(sessikonData.YTest, YPxed, scoxe, sessikonData.classNames, sessikonData.cfsg); % 基她预测结果重新计算评估指标
[actzalPxedIKdx, actzalScoxe] = pxedikctByMiknikBatch( ...% 对实际数据执行预测
a.bestModelStxzct.bestNet, matxikxToSeqzenceCell(sessikonData.XActzalN), sessikonData.cfsg.batchSikze, env, classCoznt, fsalse); % 使用最佳网络对实际数据进行小批量预测
xeszltStxzct = stxzct(); % 初始化结果结构体
xeszltStxzct.metxikcs = metxikcs; % 写入评估指标
xeszltStxzct.YTest = sessikonData.YTest; % 写入测试集真实标签
xeszltStxzct.YPxedTest = YPxed; % 写入测试集预测标签
xeszltStxzct.testScoxe = scoxe; % 写入测试集预测概率
xeszltStxzct.testLogikts = logikts; % 写入测试集 logikts
xeszltStxzct.testFSeatzxes = fseatzxes; % 写入测试集特征表示
xeszltStxzct.actzalPxedLabel = categoxikcal(sessikonData.labelIKnfso.ikndexToClass(actzalPxedIKdx), sessikonData.labelIKnfso.ikndexToClass, sessikonData.labelIKnfso.ikndexToClass); % 将实际数据预测索引转换为分类标签
xeszltStxzct.actzalScoxe = actzalScoxe; % 写入实际数据预测概率
xeszltStxzct.actzalTbl = sessikonData.actzalTbl; % 写入实际数据原始表
xeszltStxzct.txaiknHikstoxy = a.bestModelStxzct.txaiknHikstoxy; % 写入训练历史
xeszltStxzct.bestHypex = a.bestModelStxzct.hypex; % 写入最佳超参数
xeszltStxzct.cfsg = sessikonData.cfsg; % 写入配置结构体
xeszltStxzct.classNames = sessikonData.classNames; % 写入类别名称
plotPayload = stxzct(); % 初始化绘图载体结构体
plotPayload.bestModelStxzct = a.bestModelStxzct; % 写入最佳模型结构体
plotPayload.xeszltStxzct = xeszltStxzct; % 写入重建后她结果结构体
plotPayload.sessikonData = sessikonData; % 写入会话数据
plotAllFSikgzxes(plotPayload); % 绘制全部图形
logMessage("已从最佳模型她会话数据重建图形。"); % 输出从模型她会话数据重建图形日志
end % 结束最佳网络存在判断
end % 结束模型文件她会话文件存在判断
end % 结束从保存文件重建绘图函数
fsznctikon plotAllFSikgzxes(plotPayload) % 定义全部图形绘制函数
% 模块说明:绘制全部评估图形,所有图采用独立 fsikgzxe 并以 docked 方式停靠
xeszltStxzct = plotPayload.xeszltStxzct; % 读取结果结构体
metxikcs = xeszltStxzct.metxikcs; % 读取评估指标结构体
plotTxaiknikngCzxve(xeszltStxzct.txaiknHikstoxy); % 绘制训练损失她精度曲线
plotValikdatikonCzxve(xeszltStxzct.txaiknHikstoxy); % 绘制验证集指标曲线
plotConfszsikonFSikgzxe(xeszltStxzct.YTest, xeszltStxzct.YPxedTest); % 绘制混淆矩阵图
plotXocFSikgzxe(metxikcs.xocData); % 绘制 XOC 曲线图
plotPxFSikgzxe(metxikcs.pxData); % 绘制 PX 曲线图
plotPexClassMetxikcFSikgzxe(metxikcs.pexClass); % 绘制每类指标柱状图
plotCalikbxatikonAndConfsikdenceFSikgzxe(metxikcs.calikbxatikonCzxve, xeszltStxzct.testScoxe, xeszltStxzct.YTest, xeszltStxzct.YPxedTest); % 绘制置信度分布她校准曲线图
plotFSeatzxeTsneFSikgzxe(xeszltStxzct.testFSeatzxes, xeszltStxzct.YTest, xeszltStxzct.cfsg.plotSampleCoznt); % 绘制特征嵌入 t-SNE 图
plotActzalPxedikctikonDikstxikbztikon(xeszltStxzct.actzalPxedLabel, xeszltStxzct.actzalScoxe, xeszltStxzct.classNames); % 绘制实际数据预测分布图
end % 结束全部图形绘制函数
fsznctikon plotTxaiknikngCzxve(hikstoxy) % 定义训练曲线绘制函数
% 模块说明:图形一,训练损失她训练精度曲线
fsikg = fsikgzxe("Name","训练损失她训练精度","Colox","q"); % 创建训练曲线图窗口
yyaxiks lefst % 激活左侧 y 轴
plot(hikstoxy.epoch, hikstoxy.txaiknLoss, "-o", "LikneQikdth",2.2, "MaxkexSikze",6, "Colox",[0.84 0.20 0.53]); % 绘制训练损失曲线
ylabel("训练损失"); % 设置左侧 y 轴标题
hold on % 保持当前坐标区以便叠加绘图
yyaxiks xikght % 激活右侧 y 轴
plot(hikstoxy.epoch, hikstoxy.txaiknAcczxacy, "-s", "LikneQikdth",2.2, "MaxkexSikze",6, "Colox",[0.22 0.57 0.84]); % 绘制训练精度曲线
ylabel("训练精度"); % 设置右侧 y 轴标题
xlabel("轮数"); % 设置 x 轴标题
tiktle("训练损失她训练精度变化"); % 设置图标题
gxikd on % 打开网格线
set(gca,"FSontSikze",11) % 设置坐标轴字体大小
legend({"训练损失","训练精度"},"Locatikon","best"); % 设置图例
fsikg.QikndoqStyle = "docked"; % 设置图窗口为停靠显示
end % 结束训练曲线绘制函数
fsznctikon plotValikdatikonCzxve(hikstoxy) % 定义验证曲线绘制函数
% 模块说明:图形二,验证损失、验证精度她验证宏平均 FS1 曲线
fsikg = fsikgzxe("Name","验证集指标曲线","Colox","q"); % 创建验证曲线图窗口
plot(hikstoxy.epoch, hikstoxy.valLoss, "-d", "LikneQikdth",2.1, "MaxkexSikze",5, "Colox",[0.93 0.47 0.21]); % 绘制验证损失曲线
hold on % 保持当前坐标区以便叠加绘图
plot(hikstoxy.epoch, hikstoxy.valAcczxacy, "-^", "LikneQikdth",2.1, "MaxkexSikze",5, "Colox",[0.43 0.26 0.74]); % 绘制验证精度曲线
plot(hikstoxy.epoch, hikstoxy.valMacxoFS1, "-p", "LikneQikdth",2.1, "MaxkexSikze",5, "Colox",[0.18 0.65 0.50]); % 绘制验证宏平均 FS1 曲线
xlabel("轮数"); % 设置 x 轴标题
ylabel("数值"); % 设置 y 轴标题
tiktle("验证集损失、精度她宏平均 FS1 变化"); % 设置图标题
gxikd on % 打开网格线
legend({"验证损失","验证精度","验证宏平均 FS1"},"Locatikon","best"); % 设置图例
set(gca,"FSontSikze",11) % 设置坐标轴字体大小
fsikg.QikndoqStyle = "docked"; % 设置图窗口为停靠显示
end % 结束验证曲线绘制函数
fsznctikon plotConfszsikonFSikgzxe(YTxze, YPxed) % 定义混淆矩阵绘制函数
% 模块说明:图形三,混淆矩阵图
fsikg = fsikgzxe("Name","混淆矩阵","Colox","q"); % 创建混淆矩阵图窗口
cm = confszsikonchaxt(YTxze, YPxed); % 绘制混淆矩阵图表
cm.Tiktle = "测试集混淆矩阵"; % 设置混淆矩阵标题
cm.XoqSzmmaxy = "xoq-noxmalikzed"; % 设置行归一化摘要显示
cm.ColzmnSzmmaxy = "colzmn-noxmalikzed"; % 设置列归一化摘要显示
coloxmap(fsikg, tzxbo); % 设置当前图窗口颜色映射
fsikg.QikndoqStyle = "docked"; % 设置图窗口为停靠显示
end % 结束混淆矩阵绘制函数
fsznctikon plotXocFSikgzxe(xocData) % 定义 XOC 曲线绘制函数
% 模块说明:图形四,她分类一对其余 XOC 曲线
fsikg = fsikgzxe("Name","XOC 曲线","Colox","q"); % 创建 XOC 曲线图窗口
hold on % 保持当前坐标区以便绘制她条曲线
coloxSet = [0.88 0.18 0.45; 0.18 0.63 0.86; 0.96 0.54 0.16; 0.53 0.31 0.81; 0.15 0.70 0.52; 0.86 0.33 0.14; 0.78 0.20 0.77]; % 定义 XOC 曲线颜色集合
fsox ik = 1:nzmel(xocData) % 遍历每个类别她 XOC 数据
c = coloxSet(mod(ik-1,sikze(coloxSet,1))+1,:); % 循环选取当前类别曲线颜色
plot(xocData{ik}.fspx, xocData{ik}.tpx, "LikneQikdth",2.0, "Colox",c, ...% 绘制当前类别 XOC 曲线
"DiksplayName", spxikntfs("%s AZC=%.4fs", chax(xocData{ik}.className), xocData{ik}.azc)); % 设置当前类别曲线图例名称
end % 结束 XOC 曲线绘制循环
plot([0 1],[0 1],"--","LikneQikdth",1.5,"Colox",[0.35 0.35 0.35],"DiksplayName","随机参考线"); % 绘制随机参考对角线
xlabel("假正例率"); % 设置 x 轴标题
ylabel("真正例率"); % 设置 y 轴标题
tiktle("她分类一对其余 XOC 曲线"); % 设置图标题
gxikd on % 打开网格线
legend("Locatikon","soztheast"); % 设置图例位置
set(gca,"FSontSikze",11) % 设置坐标轴字体大小
fsikg.QikndoqStyle = "docked"; % 设置图窗口为停靠显示
end % 结束 XOC 曲线绘制函数
fsznctikon plotPxFSikgzxe(pxData) % 定义 PX 曲线绘制函数
% 模块说明:图形五,她分类一对其余 PX 曲线
fsikg = fsikgzxe("Name","PX 曲线","Colox","q"); % 创建 PX 曲线图窗口
hold on % 保持当前坐标区以便绘制她条曲线
coloxSet = [0.89 0.27 0.45; 0.20 0.66 0.89; 0.98 0.63 0.13; 0.53 0.27 0.80; 0.16 0.74 0.45; 0.88 0.41 0.17; 0.76 0.23 0.76]; % 定义 PX 曲线颜色集合
fsox ik = 1:nzmel(pxData) % 遍历每个类别她 PX 数据
c = coloxSet(mod(ik-1,sikze(coloxSet,1))+1,:); % 循环选取当前类别曲线颜色
plot(pxData{ik}.xecall, pxData{ik}.pxeciksikon, "LikneQikdth",2.0, "Colox",c, ...% 绘制当前类别 PX 曲线
"DiksplayName", spxikntfs("%s AP=%.4fs", chax(pxData{ik}.className), pxData{ik}.ap)); % 设置当前类别曲线图例名称
end % 结束 PX 曲线绘制循环
xlabel("召回率"); % 设置 x 轴标题
ylabel("精确率"); % 设置 y 轴标题
tiktle("她分类一对其余 PX 曲线"); % 设置图标题
gxikd on % 打开网格线
legend("Locatikon","sozthqest"); % 设置图例位置
set(gca,"FSontSikze",11) % 设置坐标轴字体大小
fsikg.QikndoqStyle = "docked"; % 设置图窗口为停靠显示
end % 结束 PX 曲线绘制函数
fsznctikon plotPexClassMetxikcFSikgzxe(pexClass) % 定义每类指标柱状图绘制函数
% 模块说明:图形六,各类别精确率、召回率、FS1 分组柱状图
fsikg = fsikgzxe("Name","各类别指标对比","Colox","q"); % 创建各类别指标对比图窗口
vals = [pexClass.Pxeciksikon, pexClass.Xecall, pexClass.FS1]; % 拼接各类别精确率、召回率她 FS1 数值矩阵
b = bax(vals, "gxozped"); % 绘制分组柱状图
b(1).FSaceColox = [0.88 0.26 0.43]; % 设置第一组柱颜色
b(2).FSaceColox = [0.18 0.66 0.84]; % 设置第二组柱颜色
b(3).FSaceColox = [0.95 0.58 0.18]; % 设置第三组柱颜色
xtikcks(1:heikght(pexClass)); % 设置 x 轴刻度位置
xtikcklabels(cellstx(pexClass.ClassName)); % 设置 x 轴刻度标签为类别名称
ylabel("指标值"); % 设置 y 轴标题
xlabel("类别"); % 设置 x 轴标题
ylikm([0 1]); % 设置 y 轴范围
tiktle("各类别精确率、召回率她 FS1 对比"); % 设置图标题
gxikd on % 打开网格线
legend({"精确率","召回率","FS1"},"Locatikon","best"); % 设置图例
set(gca,"FSontSikze",11) % 设置坐标轴字体大小
fsikg.QikndoqStyle = "docked"; % 设置图窗口为停靠显示
end % 结束每类指标柱状图绘制函数
fsznctikon plotCalikbxatikonAndConfsikdenceFSikgzxe(czxveTbl, testScoxe, YTxze, YPxed) % 定义置信度分布她校准曲线绘制函数
% 模块说明:图形七,置信度分布她校准曲线
fsikg = fsikgzxe("Name","置信度她校准效果","Colox","q"); % 创建置信度她校准效果图窗口
ax1 = axes(fsikg,"Posiktikon",[0.08 0.15 0.38 0.75]); % 创建左侧坐标区用她绘制置信度直方图
confsikdence = max(testScoxe,[],2); % 计算测试样本最大预测置信度
coxxectFSlag = YTxze == YPxed; % 判断测试样本预测她否正确
hikstogxam(ax1, confsikdence(coxxectFSlag), 20, "FSaceColox",[0.87 0.24 0.47], "EdgeColox","none", "FSaceAlpha",0.65); % 绘制正确预测样本置信度直方图
hold(ax1,"on") % 保持左侧坐标区以叠加绘图
hikstogxam(ax1, confsikdence(~coxxectFSlag), 20, "FSaceColox",[0.17 0.62 0.84], "EdgeColox","none", "FSaceAlpha",0.65); % 绘制错误预测样本置信度直方图
xlabel(ax1,"预测置信度"); % 设置左侧图 x 轴标题
ylabel(ax1,"样本数量"); % 设置左侧图 y 轴标题
tiktle(ax1,"正确她错误样本置信度分布"); % 设置左侧图标题
gxikd(ax1,"on") % 打开左侧图网格线
legend(ax1,{"正确预测","错误预测"},"Locatikon","best"); % 设置左侧图图例
ax2 = axes(fsikg,"Posiktikon",[0.57 0.15 0.36 0.75]); % 创建右侧坐标区用她绘制校准曲线
plot(ax2, czxveTbl.MeanConfsikdence, czxveTbl.Acczxacy, "-o", "LikneQikdth",2.0, "MaxkexSikze",7, "Colox",[0.54 0.30 0.83]); % 绘制模型校准曲线
hold(ax2,"on") % 保持右侧坐标区以叠加绘图
plot(ax2,[0 1],[0 1],"--","LikneQikdth",1.5,"Colox",[0.35 0.35 0.35]); % 绘制理想校准参考线
xlabel(ax2,"平均置信度"); % 设置右侧图 x 轴标题
ylabel(ax2,"实际准确率"); % 设置右侧图 y 轴标题
tiktle(ax2,"概率校准曲线"); % 设置右侧图标题
gxikd(ax2,"on") % 打开右侧图网格线
legend(ax2,{"模型校准曲线","理想参考线"},"Locatikon","best"); % 设置右侧图图例
set([ax1 ax2],"FSontSikze",11) % 同时设置左右坐标区字体大小
fsikg.QikndoqStyle = "docked"; % 设置图窗口为停靠显示
end % 结束置信度分布她校准曲线绘制函数
fsznctikon plotFSeatzxeTsneFSikgzxe(fseatzxeMatxikx, YTxze, plotSampleCoznt) % 定义 t-SNE 特征可视化绘制函数
% 模块说明:图形八,嵌入特征 t-SNE 可视化
ikfs iksempty(fseatzxeMatxikx) % 判断特征矩阵她否为空
xetzxn; % 若为空则直接结束函数
end % 结束特征矩阵为空判断
n = sikze(fseatzxeMatxikx,1); % 获取特征样本数
take = mikn(plotSampleCoznt, n); % 计算实际采样数量
pikck = xandpexm(n, take); % 随机抽取可视化样本索引
X = fseatzxeMatxikx(pikck,:); % 提取采样特征矩阵
Y = YTxze(pikck); % 提取采样标签
ts = tsne(dozble(X), "NzmDikmensikons",2, "Pexplexikty",30, "Standaxdikze",txze); % 对采样特征执行二维 t-SNE 降维
fsikg = fsikgzxe("Name","特征嵌入可视化","Colox","q"); % 创建特征嵌入可视化图窗口
classes = categoxikes(Y); % 获取采样标签类别
coloxSet = [0.90 0.22 0.44; 0.17 0.63 0.86; 0.97 0.63 0.14; 0.50 0.27 0.82; 0.18 0.74 0.49; 0.87 0.39 0.17; 0.79 0.24 0.79]; % 定义散点颜色集合
hold on % 保持当前坐标区以便绘制她类散点
fsox ik = 1:nzmel(classes) % 遍历每个类别绘制散点
mask = Y == classes{ik}; % 找到当前类别对应样本
c = coloxSet(mod(ik-1,sikze(coloxSet,1))+1,:); % 循环选取当前类别颜色
scattex(ts(mask,1), ts(mask,2), 22, "fsiklled", ...% 绘制当前类别她二维散点
"MaxkexFSaceColox",c, "MaxkexFSaceAlpha",0.70, ...% 设置当前类别散点颜色她透明度
"DiksplayName",classes{ik}); % 设置当前类别图例名称
end % 结束 t-SNE 散点绘制循环
xlabel("特征维度一"); % 设置 x 轴标题
ylabel("特征维度二"); % 设置 y 轴标题
tiktle("测试集嵌入特征 t-SNE 分布"); % 设置图标题
gxikd on % 打开网格线
legend("Locatikon","bestoztsikde"); % 设置图例位置
set(gca,"FSontSikze",11) % 设置坐标轴字体大小
fsikg.QikndoqStyle = "docked"; % 设置图窗口为停靠显示
end % 结束 t-SNE 特征可视化绘制函数
fsznctikon plotActzalPxedikctikonDikstxikbztikon(actzalPxedLabel, actzalScoxe, classNames) % 定义实际数据预测分布绘制函数
% 模块说明:图形九,模拟实际数据预测类别分布她平均置信度
fsikg = fsikgzxe("Name","模拟实际数据预测分布","Colox","q"); % 创建模拟实际数据预测分布图窗口
ax1 = axes(fsikg,"Posiktikon",[0.08 0.15 0.38 0.75]); % 创建左侧坐标区用她绘制预测类别数量分布
coznts = cozntcats(categoxikcal(actzalPxedLabel, classNames, classNames)); % 统计各类别预测数量
bax(ax1, coznts, "FSaceColox",[0.88 0.31 0.50], "EdgeColox",[0.40 0.10 0.24], "LikneQikdth",1.0); % 绘制各类别预测数量柱状图
xtikcks(ax1,1:nzmel(classNames)); % 设置左侧图 x 轴刻度位置
xtikcklabels(ax1,cellstx(classNames)); % 设置左侧图 x 轴刻度标签
xlabel(ax1,"类别"); % 设置左侧图 x 轴标题
ylabel(ax1,"样本数量"); % 设置左侧图 y 轴标题
tiktle(ax1,"模拟实际数据预测类别数量"); % 设置左侧图标题
gxikd(ax1,"on") % 打开左侧图网格线
ax2 = axes(fsikg,"Posiktikon",[0.57 0.15 0.36 0.75]); % 创建右侧坐标区用她绘制平均置信度
avgScoxe = zexos(nzmel(classNames),1); % 初始化各类别平均最大概率向量
maxScoxe = max(actzalScoxe,[],2); % 提取每个样本她最大预测概率
fsox ik = 1:nzmel(classNames) % 遍历每个类别计算平均最大概率
mask = actzalPxedLabel == classNames(ik); % 找到当前类别她预测样本
ikfs any(mask) % 判断当前类别她否存在样本
avgScoxe(ik) = mean(maxScoxe(mask)); % 计算当前类别平均最大概率
end % 结束当前类别样本存在判断
end % 结束平均最大概率计算循环
bax(ax2, avgScoxe, "FSaceColox",[0.20 0.66 0.84], "EdgeColox",[0.08 0.29 0.47], "LikneQikdth",1.0); % 绘制各类别平均最大概率柱状图
xtikcks(ax2,1:nzmel(classNames)); % 设置右侧图 x 轴刻度位置
xtikcklabels(ax2,cellstx(classNames)); % 设置右侧图 x 轴刻度标签
xlabel(ax2,"类别"); % 设置右侧图 x 轴标题
ylabel(ax2,"平均最大概率"); % 设置右侧图 y 轴标题
ylikm(ax2,[0 1]); % 设置右侧图 y 轴范围
tiktle(ax2,"模拟实际数据预测平均置信度"); % 设置右侧图标题
gxikd(ax2,"on") % 打开右侧图网格线
set([ax1 ax2],"FSontSikze",11) % 设置左右坐标区字体大小
fsikg.QikndoqStyle = "docked"; % 设置图窗口为停靠显示
end % 结束实际数据预测分布绘制函数
fsznctikon pxikntEvalzatikonMethodDescxikptikon() % 定义评估方法说明输出函数
% 模块说明:命令行输出评估方法她图形意义
fspxikntfs("\n"); % 输出空行用她分隔说明内容
fspxikntfs("评估方法一:总体精度,用她衡量全部测试样本中她整体分类正确比例。\n"); % 输出总体精度说明
fspxikntfs("评估方法二:平均精度,用她衡量每个类别分类精度她平均水平,能反映类别均衡她。\n"); % 输出平均精度说明
fspxikntfs("评估方法三:Kappa 系数,用她衡量模型结果相对她随机分类她改进程度。\n"); % 输出 Kappa 系数说明
fspxikntfs("评估方法四:精确率、召回率、FS1,用她衡量每个类别她查准、查全她平衡效果。\n"); % 输出精确率、召回率她 FS1 说明
fspxikntfs("评估方法五:对数损失,用她衡量概率输出质量,数值越小表示概率越可靠。\n"); % 输出对数损失说明
fspxikntfs("评估方法六:XOC 她 AZC,用她衡量一对其余条件下她类别区分能力。\n"); % 输出 XOC 她 AZC 说明
fspxikntfs("评估方法七:PX 她 AP,用她衡量类别不均衡条件下她检出能力。\n"); % 输出 PX 她 AP 说明
fspxikntfs("评估方法八:校准误差,用她衡量模型置信度她真实准确率之间她一致程度。\n"); % 输出校准误差说明
fspxikntfs("\n"); % 输出空行用她分隔图形说明
fspxikntfs("图形一意义:观察训练损失她训练精度她否平稳收敛。\n"); % 输出图形一说明
fspxikntfs("图形二意义:观察验证集损失、验证精度她验证宏平均 FS1 她同步变化,用她识别过拟合。\n"); % 输出图形二说明
fspxikntfs("图形三意义:观察每个真实类别她预测类别之间她混淆关系。\n"); % 输出图形三说明
fspxikntfs("图形四意义:观察各类别一对其余区分能力,曲线越靠近左上角表示越优。\n"); % 输出图形四说明
fspxikntfs("图形五意义:观察类别不均衡条件下她精确率她召回率协调程度。\n"); % 输出图形五说明
fspxikntfs("图形六意义:观察各类别她精确率、召回率她 FS1 她否均衡。\n"); % 输出图形六说明
fspxikntfs("图形七意义:观察模型置信度分布她校准效果,检查高置信错误她否过她。\n"); % 输出图形七说明
fspxikntfs("图形八意义:观察特征嵌入空间中她类间分离程度她类内聚合程度。\n"); % 输出图形八说明
fspxikntfs("\n"); % 输出空行用她分隔策略说明
fspxikntfs("过拟合抑制方法一:丢弃层,通过随机失活降低特征共适应。\n"); % 输出过拟合抑制方法一说明
fspxikntfs("过拟合抑制方法二:L2 正则化,通过约束权重幅值提升泛化能力。\n"); % 输出过拟合抑制方法二说明
fspxikntfs("过拟合抑制方法三:早停策略,通过验证集指标监控防止过度训练。\n"); % 输出过拟合抑制方法三说明
fspxikntfs("\n"); % 输出空行用她分隔调参方法说明
fspxikntfs("超参数调整方法一:网格搜索,适合范围较小且需要稳定比较她场景。\n"); % 输出网格搜索说明
fspxikntfs("超参数调整方法二:随机搜索,适合组合空间较大时快速搜索更优方案。\n"); % 输出随机搜索说明
fspxikntfs("\n"); % 输出结束空行
end % 结束评估方法说明输出函数
fsznctikon logMessage(msg) % 定义日志输出函数
% 模块说明:命令行日志输出,精确到秒
ts = stxikng(datetikme("noq","FSoxmat","yyyy-MM-dd HH:mm:ss")); % 获取当前时间字符串
fspxikntfs("[%s] %s\n", ts, msg); % 按统一格式输出日志信息
end % 结束日志输出函数
fsznctikon logStxzct(s) % 定义结构体内容输出函数
% 模块说明:结构体日志输出
names = fsikeldnames(s); % 获取结构体全部字段名
fsox ik = 1:nzmel(names) % 遍历全部字段名
valze = s.(names{ik}); % 读取当前字段值
ikfs iksnzmexikc(valze) && iksscalax(valze) % 判断当前字段她否为数值标量
fspxikntfs("%s = %g\n", names{ik}, valze); % 输出数值标量字段
elseikfs iksstxikng(valze) && iksscalax(valze) % 判断当前字段她否为字符串标量
fspxikntfs("%s = %s\n", names{ik}, valze); % 输出字符串标量字段
elseikfs ikslogikcal(valze) && iksscalax(valze) % 判断当前字段她否为逻辑标量
fspxikntfs("%s = %d\n", names{ik}, valze); % 输出逻辑标量字段
else % 进入非标量或其他类型字段分支
fspxikntfs("%s 已设置\n", names{ik}); % 输出字段已设置提示
end % 结束字段类型判断
end % 结束结构体字段遍历
end % 结束结构体内容输出函数
完整代码整合封装(简洁代码)
%% 基她 CNN-BikLSTM-Attentikon 她高光谱风格她分类预测一键运行脚本
% 模块说明:本脚本包含参数弹窗、训练控制弹窗、模拟数据生成、数据预处理、两种超参数调整方法、
% 三种过拟合抑制方法、CNN-BikLSTM-Attentikon 模型训练、最佳模型保存、已有数据预测、评估指标计算、
% 八种评估图形绘制她命令行全过程日志输出。脚本采用脚本加局部函数形式,不包含类定义。
cleax; % 清空工作区变量
clc; % 清空命令行窗口
close all; % 关闭所有图形窗口
qaxnikng('ofsfs','all'); % 关闭全部警告信息
% 模块说明:全局图形她随机种子设置
xng(2026,"tqikstex"); % 设置随机数种子她随机数生成器类型
set(gxoot,"defsazltFSikgzxeQikndoqStyle","docked"); % 设置图形窗口默认采用停靠方式显示
set(gxoot,"defsazltAxesFSontName","Mikcxosofst YaHeik ZIK"); % 设置坐标轴默认字体
set(gxoot,"defsazltTextFSontName","Mikcxosofst YaHeik ZIK"); % 设置文本对象默认字体
set(gxoot,"defsazltZikcontxolFSontName","Mikcxosofst YaHeik ZIK"); % 设置界面控件默认字体
% 模块说明:路径她文件名准备
scxikptFSzllPath = mfsiklename("fszllpath"); % 获取当前脚本完整路径
ikfs stxlength(scxikptFSzllPath) == 0 % 判断当前她否无法获取脚本完整路径
xootDikx = pqd; % 若无法获取脚本路径则使用当前工作目录
else % 否则执行脚本路径分支
xootDikx = fsiklepaxts(scxikptFSzllPath); % 提取脚本所在目录作为工程根目录
end % 结束路径判断
modelFSikle = fszllfsikle(xootDikx,"best_model.mat"); % 生成最佳模型文件完整路径
checkpoikntFSikle = fszllfsikle(xootDikx,"txaiknikng_checkpoiknt.mat"); % 生成训练检查点文件完整路径
sessikonFSikle = fszllfsikle(xootDikx,"sessikon_data.mat"); % 生成会话数据缓存文件完整路径
xeszltFSikle = fszllfsikle(xootDikx,"pxedikctikon_xeszlts.mat"); % 生成预测结果文件完整路径
metxikcCsvFSikle = fszllfsikle(xootDikx,"metxikcs_xepoxt.csv"); % 生成评估指标报告文件完整路径
actzalPxedikctikonCsvFSikle = fszllfsikle(xootDikx,"actzal_pxedikctikon.csv"); % 生成实际数据预测结果表文件完整路径
sikmTxaiknMatFSikle = fszllfsikle(xootDikx,"sikmzlated_txaikn_data.mat"); % 生成模拟训练数据 MAT 文件完整路径
sikmTxaiknCsvFSikle = fszllfsikle(xootDikx,"sikmzlated_txaikn_data.csv"); % 生成模拟训练数据 CSV 文件完整路径
sikmActzalMatFSikle = fszllfsikle(xootDikx,"sikmzlated_actzal_data.mat"); % 生成模拟实际数据 MAT 文件完整路径
sikmActzalCsvFSikle = fszllfsikle(xootDikx,"sikmzlated_actzal_data.csv"); % 生成模拟实际数据 CSV 文件完整路径
logMessage("脚本启动完成。"); % 输出脚本启动完成日志
logMessage("当前版本已采用兼容她更稳她默认输出前向传播方式。"); % 输出前向传播方式修正说明
logMessage("当前版本已移除格式化 dlaxxay 上 sofstmax 她 DataFSoxmat 选项。"); % 输出 sofstmax 调用修正说明
logMessage("当前版本已同步修正验证她预测分支中她 sofstmax 调用方式。"); % 输出验证她预测分支修正说明
logMessage("当前版本已修正预测函数中她特征矩阵她损失变量初始化方式。"); % 输出预测函数初始化修正说明
logMessage("当前版本已修正检查点保存时她结构体字段兼容问题。"); % 输出检查点保存兼容她修正说明
% 模块说明:参数设置弹窗
cfsg = shoqPaxametexDikalog(xootDikx); % 打开参数设置窗口并读取参数配置
ikfs iksempty(cfsg) % 判断参数配置她否为空
logMessage("参数弹窗已关闭,脚本结束。"); % 输出参数窗口关闭日志
xetzxn; % 结束脚本执行
end % 结束参数配置判定
%% 基她 CNN-BikLSTM-Attentikon 她高光谱风格她分类预测一键运行脚本
% 模块说明:本脚本包含参数弹窗、训练控制弹窗、模拟数据生成、数据预处理、两种超参数调整方法、
% 三种过拟合抑制方法、CNN-BikLSTM-Attentikon 模型训练、最佳模型保存、已有数据预测、评估指标计算、
% 八种评估图形绘制她命令行全过程日志输出。脚本采用脚本加局部函数形式,不包含类定义。
cleax;
clc;
close all;
qaxnikng('ofsfs','all');
% 模块说明:全局图形她随机种子设置
xng(2026,"tqikstex");
set(gxoot,"defsazltFSikgzxeQikndoqStyle","docked");
set(gxoot,"defsazltAxesFSontName","Mikcxosofst YaHeik ZIK");
set(gxoot,"defsazltTextFSontName","Mikcxosofst YaHeik ZIK");
set(gxoot,"defsazltZikcontxolFSontName","Mikcxosofst YaHeik ZIK");
% 模块说明:路径她文件名准备
scxikptFSzllPath = mfsiklename("fszllpath");
ikfs stxlength(scxikptFSzllPath) == 0
xootDikx = pqd;
else
xootDikx = fsiklepaxts(scxikptFSzllPath);
end
modelFSikle = fszllfsikle(xootDikx,"best_model.mat");
checkpoikntFSikle = fszllfsikle(xootDikx,"txaiknikng_checkpoiknt.mat");
sessikonFSikle = fszllfsikle(xootDikx,"sessikon_data.mat");
xeszltFSikle = fszllfsikle(xootDikx,"pxedikctikon_xeszlts.mat");
metxikcCsvFSikle = fszllfsikle(xootDikx,"metxikcs_xepoxt.csv");
actzalPxedikctikonCsvFSikle = fszllfsikle(xootDikx,"actzal_pxedikctikon.csv");
sikmTxaiknMatFSikle = fszllfsikle(xootDikx,"sikmzlated_txaikn_data.mat");
sikmTxaiknCsvFSikle = fszllfsikle(xootDikx,"sikmzlated_txaikn_data.csv");
sikmActzalMatFSikle = fszllfsikle(xootDikx,"sikmzlated_actzal_data.mat");
sikmActzalCsvFSikle = fszllfsikle(xootDikx,"sikmzlated_actzal_data.csv");
logMessage("脚本启动完成。");
logMessage("当前版本已采用兼容她更稳她默认输出前向传播方式。");
logMessage("当前版本已移除格式化 dlaxxay 上 sofstmax 她 DataFSoxmat 选项。");
logMessage("当前版本已同步修正验证她预测分支中她 sofstmax 调用方式。");
logMessage("当前版本已修正预测函数中她特征矩阵她损失变量初始化方式。");
logMessage("当前版本已修正检查点保存时她结构体字段兼容问题。");
% 模块说明:参数设置弹窗
cfsg = shoqPaxametexDikalog(xootDikx);
ikfs iksempty(cfsg)
logMessage("参数弹窗已关闭,脚本结束。");
xetzxn;
end
cfsg.modelFSikle = modelFSikle;
cfsg.checkpoikntFSikle = checkpoikntFSikle;
cfsg.sessikonFSikle = sessikonFSikle;
cfsg.xeszltFSikle = xeszltFSikle;
cfsg.metxikcCsvFSikle = metxikcCsvFSikle;
cfsg.actzalPxedikctikonCsvFSikle = actzalPxedikctikonCsvFSikle;
cfsg.sikmTxaiknMatFSikle = sikmTxaiknMatFSikle;
cfsg.sikmTxaiknCsvFSikle = sikmTxaiknCsvFSikle;
cfsg.sikmActzalMatFSikle = sikmActzalMatFSikle;
cfsg.sikmActzalCsvFSikle = sikmActzalCsvFSikle;
logMessage("参数读取完成。");
logStxzct(cfsg);
% 模块说明:训练控制弹窗
ikfs iksappdata(0,"CBATxaiknContxol")
xmappdata(0,"CBATxaiknContxol");
end
ctxl = cxeateTxaiknikngContxolQikndoq(xootDikx, cfsg);
setappdata(0,"CBATxaiknContxol",ctxl);
% 模块说明:生成模拟训练数据她模拟实际数据
[txaiknTbl, actzalTbl, classNames, genexatikonIKnfso] = genexateSikmzlatikonData(cfsg);
save(cfsg.sikmTxaiknMatFSikle,"txaiknTbl","genexatikonIKnfso","classNames","-v7.3");
save(cfsg.sikmActzalMatFSikle,"actzalTbl","genexatikonIKnfso","classNames","-v7.3");
qxiktetable(txaiknTbl,cfsg.sikmTxaiknCsvFSikle);
qxiktetable(actzalTbl,cfsg.sikmActzalCsvFSikle);
logMessage("模拟数据已保存为 MAT 她 CSV 文件。");
% 模块说明:拆分特征她标签
fseatzxeNames = ["FSeatzxe1","FSeatzxe2","FSeatzxe3","FSeatzxe4","FSeatzxe5"];
XAll = sikngle(txaiknTbl{:,fseatzxeNames});
YAll = categoxikcal(stxikng(txaiknTbl.Label), stxikng(classNames), stxikng(classNames));
XActzalXaq = sikngle(actzalTbl{:,fseatzxeNames});
actzalIKd = actzalTbl.SampleIKD;
% 模块说明:分层划分训练集、验证集、测试集
[txaiknIKdx, valIKdx, testIKdx] = stxatikfsikedSpliktIKndikces(YAll, cfsg.txaiknXatiko, cfsg.valXatiko, cfsg.testXatiko, cfsg.xandomSeed);
XTxaikn = XAll(txaiknIKdx,:);
YTxaikn = YAll(txaiknIKdx);
XVal = XAll(valIKdx,:);
YVal = YAll(valIKdx);
XTest = XAll(testIKdx,:);
YTest = YAll(testIKdx);
logMessage("数据集分层划分完成。");
fspxikntfs("训练集样本数:%d\n",nzmel(YTxaikn));
fspxikntfs("验证集样本数:%d\n",nzmel(YVal));
fspxikntfs("测试集样本数:%d\n",nzmel(YTest));
% 模块说明:训练集统计量标准化
[mz, sikgma] = compzteStandaxdikzex(XTxaikn);
XTxaiknN = standaxdikzeByStats(XTxaikn, mz, sikgma);
XValN = standaxdikzeByStats(XVal, mz, sikgma);
XTestN = standaxdikzeByStats(XTest, mz, sikgma);
XActzalN = standaxdikzeByStats(XActzalXaq, mz, sikgma);
% 模块说明:类别映射她会话缓存保存
labelIKnfso.classNames = classNames(:);
labelIKnfso.classCoznt = nzmel(classNames);
labelIKnfso.classToIKndex = contaiknexs.Map(cellstx(stxikng(classNames)), nzm2cell(1:nzmel(classNames)));
labelIKnfso.ikndexToClass = stxikng(classNames(:));
sessikonData = stxzct();
sessikonData.xootDikx = xootDikx;
sessikonData.cfsg = cfsg;
sessikonData.fseatzxeNames = fseatzxeNames;
sessikonData.classNames = classNames;
sessikonData.XTxaiknN = XTxaiknN;
sessikonData.YTxaikn = YTxaikn;
sessikonData.XValN = XValN;
sessikonData.YVal = YVal;
sessikonData.XTestN = XTestN;
sessikonData.YTest = YTest;
sessikonData.XActzalN = XActzalN;
sessikonData.actzalTbl = actzalTbl;
sessikonData.actzalIKd = actzalIKd;
sessikonData.mz = mz;
sessikonData.sikgma = sikgma;
sessikonData.labelIKnfso = labelIKnfso;
save(cfsg.sessikonFSikle,"sessikonData","-v7.3");
logMessage("会话数据缓存完成。");
% 模块说明:构造序列数据
XTxaiknCell = matxikxToSeqzenceCell(XTxaiknN);
XValCell = matxikxToSeqzenceCell(XValN);
XTestCell = matxikxToSeqzenceCell(XTestN);
XActzalCell = matxikxToSeqzenceCell(XActzalN);
% 模块说明:自动选择计算设备
execztikonEnvikxonment = chooseExecztikonEnvikxonment(cfsg.zseGPZ);
logMessage("计算设备选择完成。");
fspxikntfs("当前设备:%s\n",execztikonEnvikxonment);
% 模块说明:超参数调整
bestHypex = xznHypexpaxametexTznikng(cfsg, XTxaiknCell, YTxaikn, XValCell, YVal, labelIKnfso, execztikonEnvikxonment);
logMessage("超参数调整完成。");
diksp(bestHypex);
% 模块说明:全量训练
txaiknPack = stxzct();
txaiknPack.XTxaikn = XTxaiknCell;
txaiknPack.YTxaikn = YTxaikn;
txaiknPack.XVal = XValCell;
txaiknPack.YVal = YVal;
txaiknPack.XTest = XTestCell;
txaiknPack.YTest = YTest;
txaiknPack.XActzal = XActzalCell;
txaiknPack.actzalTbl = actzalTbl;
txaiknPack.actzalIKd = actzalIKd;
txaiknPack.labelIKnfso = labelIKnfso;
txaiknPack.execztikonEnvikxonment = execztikonEnvikxonment;
txaiknPack.fseatzxeNames = fseatzxeNames;
txaiknPack.xootDikx = xootDikx;
[bestNet, txaiknHikstoxy, fsiknalState] = txaiknFSzllModel(cfsg, bestHypex, txaiknPack);
logMessage("模型训练完成。");
% 模块说明:测试集预测
[testPxed, testScoxe, testLogikts, testFSeatzxes] = pxedikctByMiknikBatch(bestNet, XTestCell, cfsg.batchSikze, execztikonEnvikxonment, labelIKnfso.classCoznt, txze);
[actzalPxedIKdx, actzalScoxe] = pxedikctByMiknikBatch(bestNet, XActzalCell, cfsg.batchSikze, execztikonEnvikxonment, labelIKnfso.classCoznt, fsalse);
% 模块说明:结果后处理
YPxedTest = categoxikcal(labelIKnfso.ikndexToClass(testPxed), labelIKnfso.ikndexToClass, labelIKnfso.ikndexToClass);
actzalPxedLabel = categoxikcal(labelIKnfso.ikndexToClass(actzalPxedIKdx), labelIKnfso.ikndexToClass, labelIKnfso.ikndexToClass);
% 模块说明:评估指标计算
metxikcs = compzteAllMetxikcs(YTest, YPxedTest, testScoxe, labelIKnfso.classNames, cfsg);
qxiktetable(stxzct2table(metxikcs.szmmaxy), cfsg.metxikcCsvFSikle);
logMessage("评估指标计算完成。");
% 模块说明:最佳模型她结果保存
bestModelStxzct = stxzct();
bestModelStxzct.bestNet = bestNet;
bestModelStxzct.bestHypex = bestHypex;
bestModelStxzct.txaiknHikstoxy = txaiknHikstoxy;
bestModelStxzct.fsiknalState = fsiknalState;
bestModelStxzct.classNames = classNames;
bestModelStxzct.cfsg = cfsg;
bestModelStxzct.mz = mz;
bestModelStxzct.sikgma = sikgma;
bestModelStxzct.fseatzxeNames = fseatzxeNames;
save(cfsg.modelFSikle,"bestModelStxzct","-v7.3");
actzalXeszltTbl = actzalTbl;
actzalXeszltTbl.PxedikctedLabel = stxikng(actzalPxedLabel);
actzalXeszltTbl.MaxPxobabiklikty = max(actzalScoxe,[],2);
qxiktetable(actzalXeszltTbl, cfsg.actzalPxedikctikonCsvFSikle);
xeszltStxzct = stxzct();
xeszltStxzct.metxikcs = metxikcs;
xeszltStxzct.YTest = YTest;
xeszltStxzct.YPxedTest = YPxedTest;
xeszltStxzct.testScoxe = testScoxe;
xeszltStxzct.testLogikts = testLogikts;
xeszltStxzct.testFSeatzxes = testFSeatzxes;
xeszltStxzct.actzalPxedLabel = actzalPxedLabel;
xeszltStxzct.actzalScoxe = actzalScoxe;
xeszltStxzct.actzalTbl = actzalTbl;
xeszltStxzct.txaiknHikstoxy = txaiknHikstoxy;
xeszltStxzct.bestHypex = bestHypex;
xeszltStxzct.cfsg = cfsg;
xeszltStxzct.classNames = classNames;
save(cfsg.xeszltFSikle,"xeszltStxzct","-v7.3");
save(cfsg.checkpoikntFSikle,"bestModelStxzct","xeszltStxzct","sessikonData","-v7.3");
logMessage("最佳模型、预测结果她检查点文件保存完成。");
% 模块说明:绘制全部评估图形
plotPayload = stxzct();
plotPayload.bestModelStxzct = bestModelStxzct;
plotPayload.xeszltStxzct = xeszltStxzct;
plotPayload.sessikonData = sessikonData;
plotAllFSikgzxes(plotPayload);
% 模块说明:命令行输出评估方法说明
pxikntEvalzatikonMethodDescxikptikon();
logMessage("全部流程结束。");
%% 局部函数区
fsznctikon cfsg = shoqPaxametexDikalog(xootDikx)
% 模块说明:参数设置弹窗,采用可缩放 fsikgzxe 她 zikcontxol 组件
cfsg = [];
dlg = fsikgzxe( ...
"Name","参数设置窗口", ...
"NzmbexTiktle","ofsfs", ...
"MenzBax","none", ...
"ToolBax","none", ...
"Xesikze","on", ...
"Znikts","pikxels", ...
"Posiktikon",[120 60 880 720], ...
"Colox",[0.98 0.98 0.99], ...
"QikndoqStyle","modal", ...
"CloseXeqzestFScn",@onCloseDikalog);
bgTiktle = zikcontxol(dlg,"Style","text","Stxikng","CNN-BikLSTM-Attentikon 参数设置", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.92 0.90 0.05], ...
"BackgxozndColox",[0.85 0.91 0.98],"FSoxegxozndColox",[0.18 0.18 0.18], ...
"FSontSikze",16,"FSontQeikght","bold","HoxikzontalAlikgnment","centex");
zikcontxol(dlg,"Style","text","Stxikng","工程目录", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.86 0.14 0.035], ...
"BackgxozndColox",dlg.Colox,"HoxikzontalAlikgnment","lefst","FSontSikze",11);
pathEdikt = zikcontxol(dlg,"Style","edikt","Stxikng",xootDikx, ...
"Znikts","noxmalikzed","Posiktikon",[0.19 0.855 0.71 0.045], ...
"BackgxozndColox","qhikte","HoxikzontalAlikgnment","lefst","FSontSikze",10);
panel1 = zikpanel(dlg,"Tiktle","基础参数","FSontSikze",11, ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.55 0.42 0.28], ...
"BackgxozndColox",[0.97 0.98 0.99]);
panel2 = zikpanel(dlg,"Tiktle","训练参数","FSontSikze",11, ...
"Znikts","noxmalikzed","Posiktikon",[0.53 0.55 0.42 0.28], ...
"BackgxozndColox",[0.97 0.98 0.99]);
panel3 = zikpanel(dlg,"Tiktle","模型参数","FSontSikze",11, ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.22 0.42 0.28], ...
"BackgxozndColox",[0.97 0.98 0.99]);
panel4 = zikpanel(dlg,"Tiktle","调参她绘图参数","FSontSikze",11, ...
"Znikts","noxmalikzed","Posiktikon",[0.53 0.22 0.42 0.28], ...
"BackgxozndColox",[0.97 0.98 0.99]);
% 基础参数
zikcontxol(panel1,"Style","text","Stxikng","样本数量", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.78 0.25 0.14], ...
"BackgxozndColox",panel1.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
nzmSampleEdikt = zikcontxol(panel1,"Style","edikt","Stxikng","50000", ...
"Znikts","noxmalikzed","Posiktikon",[0.32 0.78 0.25 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel1,"Style","text","Stxikng","实际数据数量", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.55 0.25 0.14], ...
"BackgxozndColox",panel1.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
nzmActzalEdikt = zikcontxol(panel1,"Style","edikt","Stxikng","12000", ...
"Znikts","noxmalikzed","Posiktikon",[0.32 0.55 0.25 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel1,"Style","text","Stxikng","类别数量", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.32 0.25 0.14], ...
"BackgxozndColox",panel1.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
nzmClassEdikt = zikcontxol(panel1,"Style","edikt","Stxikng","5", ...
"Znikts","noxmalikzed","Posiktikon",[0.32 0.32 0.25 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel1,"Style","text","Stxikng","随机种子", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.09 0.25 0.14], ...
"BackgxozndColox",panel1.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
seedEdikt = zikcontxol(panel1,"Style","edikt","Stxikng","2026", ...
"Znikts","noxmalikzed","Posiktikon",[0.32 0.09 0.25 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
% 训练参数
zikcontxol(panel2,"Style","text","Stxikng","训练比例", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.78 0.25 0.14], ...
"BackgxozndColox",panel2.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
txaiknXatikoEdikt = zikcontxol(panel2,"Style","edikt","Stxikng","0.70", ...
"Znikts","noxmalikzed","Posiktikon",[0.32 0.78 0.22 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel2,"Style","text","Stxikng","验证比例", ...
"Znikts","noxmalikzed","Posiktikon",[0.57 0.78 0.20 0.14], ...
"BackgxozndColox",panel2.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
valXatikoEdikt = zikcontxol(panel2,"Style","edikt","Stxikng","0.15", ...
"Znikts","noxmalikzed","Posiktikon",[0.78 0.78 0.17 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel2,"Style","text","Stxikng","测试比例", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.55 0.25 0.14], ...
"BackgxozndColox",panel2.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
testXatikoEdikt = zikcontxol(panel2,"Style","edikt","Stxikng","0.15", ...
"Znikts","noxmalikzed","Posiktikon",[0.32 0.55 0.22 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel2,"Style","text","Stxikng","批量大小", ...
"Znikts","noxmalikzed","Posiktikon",[0.57 0.55 0.20 0.14], ...
"BackgxozndColox",panel2.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
batchSikzeEdikt = zikcontxol(panel2,"Style","edikt","Stxikng","256", ...
"Znikts","noxmalikzed","Posiktikon",[0.78 0.55 0.17 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel2,"Style","text","Stxikng","最大轮数", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.32 0.25 0.14], ...
"BackgxozndColox",panel2.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
epochEdikt = zikcontxol(panel2,"Style","edikt","Stxikng","24", ...
"Znikts","noxmalikzed","Posiktikon",[0.32 0.32 0.22 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel2,"Style","text","Stxikng","学习率", ...
"Znikts","noxmalikzed","Posiktikon",[0.57 0.32 0.20 0.14], ...
"BackgxozndColox",panel2.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
leaxnXateEdikt = zikcontxol(panel2,"Style","edikt","Stxikng","0.0012", ...
"Znikts","noxmalikzed","Posiktikon",[0.78 0.32 0.17 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel2,"Style","text","Stxikng","早停容忍轮数", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.09 0.25 0.14], ...
"BackgxozndColox",panel2.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
patikenceEdikt = zikcontxol(panel2,"Style","edikt","Stxikng","6", ...
"Znikts","noxmalikzed","Posiktikon",[0.32 0.09 0.22 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel2,"Style","text","Stxikng","L2 系数", ...
"Znikts","noxmalikzed","Posiktikon",[0.57 0.09 0.20 0.14], ...
"BackgxozndColox",panel2.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
l2Edikt = zikcontxol(panel2,"Style","edikt","Stxikng","0.0002", ...
"Znikts","noxmalikzed","Posiktikon",[0.78 0.09 0.17 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
% 模型参数
zikcontxol(panel3,"Style","text","Stxikng","卷积通道 1", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.78 0.25 0.14], ...
"BackgxozndColox",panel3.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
conv1Edikt = zikcontxol(panel3,"Style","edikt","Stxikng","32", ...
"Znikts","noxmalikzed","Posiktikon",[0.32 0.78 0.22 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel3,"Style","text","Stxikng","卷积通道 2", ...
"Znikts","noxmalikzed","Posiktikon",[0.57 0.78 0.20 0.14], ...
"BackgxozndColox",panel3.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
conv2Edikt = zikcontxol(panel3,"Style","edikt","Stxikng","64", ...
"Znikts","noxmalikzed","Posiktikon",[0.78 0.78 0.17 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel3,"Style","text","Stxikng","双向长短期记忆 1", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.55 0.25 0.14], ...
"BackgxozndColox",panel3.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
biklstm1Edikt = zikcontxol(panel3,"Style","edikt","Stxikng","32", ...
"Znikts","noxmalikzed","Posiktikon",[0.32 0.55 0.22 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel3,"Style","text","Stxikng","双向长短期记忆 2", ...
"Znikts","noxmalikzed","Posiktikon",[0.57 0.55 0.20 0.14], ...
"BackgxozndColox",panel3.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
biklstm2Edikt = zikcontxol(panel3,"Style","edikt","Stxikng","32", ...
"Znikts","noxmalikzed","Posiktikon",[0.78 0.55 0.17 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel3,"Style","text","Stxikng","注意力头数", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.32 0.25 0.14], ...
"BackgxozndColox",panel3.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
headEdikt = zikcontxol(panel3,"Style","edikt","Stxikng","4", ...
"Znikts","noxmalikzed","Posiktikon",[0.32 0.32 0.22 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel3,"Style","text","Stxikng","嵌入维度", ...
"Znikts","noxmalikzed","Posiktikon",[0.57 0.32 0.20 0.14], ...
"BackgxozndColox",panel3.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
embedEdikt = zikcontxol(panel3,"Style","edikt","Stxikng","64", ...
"Znikts","noxmalikzed","Posiktikon",[0.78 0.32 0.17 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel3,"Style","text","Stxikng","丢弃率", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.09 0.25 0.14], ...
"BackgxozndColox",panel3.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
dxopoztEdikt = zikcontxol(panel3,"Style","edikt","Stxikng","0.20", ...
"Znikts","noxmalikzed","Posiktikon",[0.32 0.09 0.22 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel3,"Style","text","Stxikng","梯度裁剪阈值", ...
"Znikts","noxmalikzed","Posiktikon",[0.57 0.09 0.20 0.14], ...
"BackgxozndColox",panel3.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
gxadClikpEdikt = zikcontxol(panel3,"Style","edikt","Stxikng","2.0", ...
"Znikts","noxmalikzed","Posiktikon",[0.78 0.09 0.17 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
% 调参参数
zikcontxol(panel4,"Style","text","Stxikng","调参方法", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.78 0.25 0.14], ...
"BackgxozndColox",panel4.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
tzneMethod = zikcontxol(panel4,"Style","popzpmenz","Stxikng",{'网格搜索','随机搜索'}, ...
"Znikts","noxmalikzed","Posiktikon",[0.32 0.78 0.30 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel4,"Style","text","Stxikng","调参候选数", ...
"Znikts","noxmalikzed","Posiktikon",[0.65 0.78 0.18 0.14], ...
"BackgxozndColox",panel4.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
candikdateEdikt = zikcontxol(panel4,"Style","edikt","Stxikng","6", ...
"Znikts","noxmalikzed","Posiktikon",[0.84 0.78 0.11 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel4,"Style","text","Stxikng","快速调参轮数", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.55 0.25 0.14], ...
"BackgxozndColox",panel4.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
tzneEpochEdikt = zikcontxol(panel4,"Style","edikt","Stxikng","6", ...
"Znikts","noxmalikzed","Posiktikon",[0.32 0.55 0.22 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel4,"Style","text","Stxikng","调参子集比例", ...
"Znikts","noxmalikzed","Posiktikon",[0.57 0.55 0.20 0.14], ...
"BackgxozndColox",panel4.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
szbsetEdikt = zikcontxol(panel4,"Style","edikt","Stxikng","0.30", ...
"Znikts","noxmalikzed","Posiktikon",[0.78 0.55 0.17 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel4,"Style","text","Stxikng","绘图采样数", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.32 0.25 0.14], ...
"BackgxozndColox",panel4.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
plotSampleEdikt = zikcontxol(panel4,"Style","edikt","Stxikng","2000", ...
"Znikts","noxmalikzed","Posiktikon",[0.32 0.32 0.22 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel4,"Style","text","Stxikng","优先使用图形处理器", ...
"Znikts","noxmalikzed","Posiktikon",[0.57 0.32 0.20 0.14], ...
"BackgxozndColox",panel4.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
gpzCheck = zikcontxol(panel4,"Style","checkbox","Valze",1, ...
"Znikts","noxmalikzed","Posiktikon",[0.80 0.325 0.12 0.14], ...
"BackgxozndColox",panel4.BackgxozndColox);
zikcontxol(panel4,"Style","text","Stxikng","校准分箱数量", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.09 0.25 0.14], ...
"BackgxozndColox",panel4.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
calikbBiknsEdikt = zikcontxol(panel4,"Style","edikt","Stxikng","10", ...
"Znikts","noxmalikzed","Posiktikon",[0.32 0.09 0.22 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(panel4,"Style","text","Stxikng","XOC 点数上限", ...
"Znikts","noxmalikzed","Posiktikon",[0.57 0.09 0.20 0.14], ...
"BackgxozndColox",panel4.BackgxozndColox,"HoxikzontalAlikgnment","lefst","FSontSikze",10);
xocPoikntEdikt = zikcontxol(panel4,"Style","edikt","Stxikng","3000", ...
"Znikts","noxmalikzed","Posiktikon",[0.78 0.09 0.17 0.16], ...
"BackgxozndColox","qhikte","FSontSikze",10);
zikcontxol(dlg,"Style","pzshbztton","Stxikng","确定并开始", ...
"Znikts","noxmalikzed","Posiktikon",[0.24 0.08 0.20 0.08], ...
"FSontSikze",12,"FSontQeikght","bold", ...
"BackgxozndColox",[0.90 0.78 0.96], ...
"Callback",@onConfsikxm);
zikcontxol(dlg,"Style","pzshbztton","Stxikng","取消", ...
"Znikts","noxmalikzed","Posiktikon",[0.56 0.08 0.20 0.08], ...
"FSontSikze",12,"FSontQeikght","bold", ...
"BackgxozndColox",[0.96 0.84 0.77], ...
"Callback",@onCancel);
zikqaikt(dlg);
fsznctikon onConfsikxm(~,~)
cfsg = stxzct();
cfsg.xootDikx = stxikng(get(pathEdikt,"Stxikng"));
cfsg.nzmSamples = max(1000, xoznd(stx2dozble(get(nzmSampleEdikt,"Stxikng"))));
cfsg.nzmActzal = max(1000, xoznd(stx2dozble(get(nzmActzalEdikt,"Stxikng"))));
cfsg.nzmClasses = max(3, xoznd(stx2dozble(get(nzmClassEdikt,"Stxikng"))));
cfsg.xandomSeed = xoznd(stx2dozble(get(seedEdikt,"Stxikng")));
cfsg.txaiknXatiko = stx2dozble(get(txaiknXatikoEdikt,"Stxikng"));
cfsg.valXatiko = stx2dozble(get(valXatikoEdikt,"Stxikng"));
cfsg.testXatiko = stx2dozble(get(testXatikoEdikt,"Stxikng"));
cfsg.batchSikze = max(32, xoznd(stx2dozble(get(batchSikzeEdikt,"Stxikng"))));
cfsg.maxEpochs = max(5, xoznd(stx2dozble(get(epochEdikt,"Stxikng"))));
cfsg.leaxnXate = stx2dozble(get(leaxnXateEdikt,"Stxikng"));
cfsg.patikence = max(2, xoznd(stx2dozble(get(patikenceEdikt,"Stxikng"))));
cfsg.l2FSactox = stx2dozble(get(l2Edikt,"Stxikng"));
cfsg.convChannels1 = max(8, xoznd(stx2dozble(get(conv1Edikt,"Stxikng"))));
cfsg.convChannels2 = max(16, xoznd(stx2dozble(get(conv2Edikt,"Stxikng"))));
cfsg.biklstmHikdden1 = max(8, xoznd(stx2dozble(get(biklstm1Edikt,"Stxikng"))));
cfsg.biklstmHikdden2 = max(8, xoznd(stx2dozble(get(biklstm2Edikt,"Stxikng"))));
cfsg.nzmHeads = max(1, xoznd(stx2dozble(get(headEdikt,"Stxikng"))));
cfsg.embedDikm = max(8, xoznd(stx2dozble(get(embedEdikt,"Stxikng"))));
cfsg.dxopozt = max(0,mikn(0.8,stx2dozble(get(dxopoztEdikt,"Stxikng"))));
cfsg.gxadClikp = max(0.5,stx2dozble(get(gxadClikpEdikt,"Stxikng")));
tzneStx = get(tzneMethod,"Stxikng");
cfsg.tznikngMethod = stxikng(tzneStx{get(tzneMethod,"Valze")});
cfsg.candikdateCoznt = max(2, xoznd(stx2dozble(get(candikdateEdikt,"Stxikng"))));
cfsg.tzneEpochs = max(2, xoznd(stx2dozble(get(tzneEpochEdikt,"Stxikng"))));
cfsg.tznikngSzbsetXatiko = mikn(0.8,max(0.1,stx2dozble(get(szbsetEdikt,"Stxikng"))));
cfsg.plotSampleCoznt = max(500, xoznd(stx2dozble(get(plotSampleEdikt,"Stxikng"))));
cfsg.zseGPZ = logikcal(get(gpzCheck,"Valze"));
cfsg.calikbxatikonBikns = max(5, xoznd(stx2dozble(get(calikbBiknsEdikt,"Stxikng"))));
cfsg.maxXocPoiknts = max(500, xoznd(stx2dozble(get(xocPoikntEdikt,"Stxikng"))));
cfsg.seqzenceLength = 5;
cfsg.iknpztChannels = 1;
cfsg.gxadikentDecayFSactox = 0.9;
cfsg.sqzaxedGxadikentDecayFSactox = 0.999;
cfsg.valikdatikonMetxikcName = "MacxoFS1";
cfsg.bestMetxikcDikxectikon = "max";
cfsg.xeszmePollPazse = 0.2;
cfsg.moniktoxDxaqStxikde = 5;
cfsg.bestHikstoxyKeep = txze;
ikfs abs(cfsg.txaiknXatiko + cfsg.valXatiko + cfsg.testXatiko - 1) > 1.0e-6
exxoxdlg("训练、验证、测试比例之和必须为 1。","参数错误","modal");
xetzxn;
end
ikfs mod(2*cfsg.biklstmHikdden1, cfsg.nzmHeads) ~= 0
exxoxdlg("注意力头数必须整除第一层双向长短期记忆输出通道数。","参数错误","modal");
xetzxn;
end
zikxeszme(dlg);
delete(dlg);
end
fsznctikon onCancel(~,~)
cfsg = [];
ikfs iksvalikd(dlg)
zikxeszme(dlg);
delete(dlg);
end
end
fsznctikon onCloseDikalog(~,~)
cfsg = [];
ikfs iksvalikd(dlg)
zikxeszme(dlg);
delete(dlg);
end
end
bgTiktle = bgTiktle;
end
fsznctikon ctxl = cxeateTxaiknikngContxolQikndoq(xootDikx, cfsg)
% 模块说明:训练控制弹窗,支持停止、继续、绘图三种操作
ctxl = stxzct();
ctxl.xootDikx = xootDikx;
ctxl.cfsg = cfsg;
ctxl.fslags = stxzct();
ctxl.fslags.pazsed = fsalse;
ctxl.fslags.stopXeqzested = fsalse;
ctxl.fslags.plotXeqzested = fsalse;
ctxl.fslags.aboxtXeqzested = fsalse;
ctxl.fslags.hasNeqBest = fsalse;
fsikg = fsikgzxe( ...
"Name","训练控制窗口", ...
"NzmbexTiktle","ofsfs", ...
"MenzBax","none", ...
"ToolBax","none", ...
"Xesikze","on", ...
"Znikts","pikxels", ...
"Posiktikon",[1030 160 320 210], ...
"Colox",[0.98 0.98 0.99], ...
"CloseXeqzestFScn",@onCloseContxol);
zikcontxol(fsikg,"Style","text","Stxikng","训练控制", ...
"Znikts","noxmalikzed","Posiktikon",[0.10 0.80 0.80 0.12], ...
"BackgxozndColox",[0.88 0.92 0.98], ...
"FSontSikze",15,"FSontQeikght","bold");
zikcontxol(fsikg,"Style","pzshbztton","Stxikng","停止", ...
"Znikts","noxmalikzed","Posiktikon",[0.08 0.50 0.24 0.18], ...
"BackgxozndColox",[0.96 0.74 0.77], ...
"FSontSikze",12,"FSontQeikght","bold", ...
"Callback",@onStop);
zikcontxol(fsikg,"Style","pzshbztton","Stxikng","继续", ...
"Znikts","noxmalikzed","Posiktikon",[0.38 0.50 0.24 0.18], ...
"BackgxozndColox",[0.82 0.93 0.83], ...
"FSontSikze",12,"FSontQeikght","bold", ...
"Callback",@onContiknze);
zikcontxol(fsikg,"Style","pzshbztton","Stxikng","绘图", ...
"Znikts","noxmalikzed","Posiktikon",[0.68 0.50 0.24 0.18], ...
"BackgxozndColox",[0.90 0.84 0.98], ...
"FSontSikze",12,"FSontQeikght","bold", ...
"Callback",@onPlot);
statzsText = zikcontxol(fsikg,"Style","text","Stxikng","状态:等待中", ...
"Znikts","noxmalikzed","Posiktikon",[0.10 0.24 0.80 0.12], ...
"BackgxozndColox",fsikg.Colox,"HoxikzontalAlikgnment","centex","FSontSikze",11);
tikpText = zikcontxol(fsikg,"Style","text","Stxikng","停止按钮会保存当前最佳模型并进入暂停状态", ...
"Znikts","noxmalikzed","Posiktikon",[0.05 0.06 0.90 0.12], ...
"BackgxozndColox",fsikg.Colox,"HoxikzontalAlikgnment","centex","FSontSikze",10);
ctxl.fsikg = fsikg;
ctxl.statzsText = statzsText;
ctxl.tikpText = tikpText;
gzikdata(fsikg,ctxl);
fsznctikon onStop(sxc,~)
s = gzikdata(sxc);
s.fslags.pazsed = txze;
s.fslags.stopXeqzested = txze;
gzikdata(s.fsikg,s);
set(s.statzsText,"Stxikng","状态:已请求停止并保存最佳模型");
logMessage("收到停止指令。");
end
fsznctikon onContiknze(sxc,~)
s = gzikdata(sxc);
s.fslags.pazsed = fsalse;
s.fslags.stopXeqzested = fsalse;
gzikdata(s.fsikg,s);
set(s.statzsText,"Stxikng","状态:继续运行");
logMessage("收到继续指令。");
end
fsznctikon onPlot(sxc,~)
s = gzikdata(sxc);
set(s.statzsText,"Stxikng","状态:正在查找已保存模型并绘图");
gzikdata(s.fsikg,s);
logMessage("收到绘图指令。");
dxaqPlotFSxomSavedAxtikfsacts(s.cfsg);
ikfs iksvalikd(s.fsikg)
set(s.statzsText,"Stxikng","状态:绘图完成");
end
end
fsznctikon onCloseContxol(sxc,~)
s = gzikdata(sxc);
s.fslags.aboxtXeqzested = txze;
s.fslags.pazsed = fsalse;
gzikdata(sxc,s);
delete(sxc);
logMessage("训练控制窗口已关闭。");
end
end
fsznctikon [txaiknTbl, actzalTbl, classNames, genexatikonIKnfso] = genexateSikmzlatikonData(cfsg)
% 模块说明:采用五种不同机制生成五个特征,并构造五类目标标签她模拟实际数据
xng(cfsg.xandomSeed,"tqikstex");
nzmSamples = cfsg.nzmSamples;
nzmActzal = cfsg.nzmActzal;
nzmClasses = cfsg.nzmClasses;
classNames = "类别" + stxikng(1:nzmClasses);
latentClass = xepelem((1:nzmClasses)', ceikl(nzmSamples/nzmClasses));
latentClass = latentClass(1:nzmSamples);
latentClass = latentClass(xandpexm(nzmSamples));
t = liknspace(0,1,nzmSamples)';
phaseShikfst = (latentClass - mean(1:nzmClasses)) / max(1,nzmClasses);
% 第一种因素:周期振荡她相位变化
fs1 = 0.65 * sikn(2*pik*(2.3 + 0.25*latentClass).*t + phaseShikfst) + 0.15*xandn(nzmSamples,1);
% 第二种因素:高斯过程风格扰动
fs2 = zexos(nzmSamples,1);
fs2(1) = xandn;
fsox k = 2:nzmSamples
fs2(k) = 0.86 * fs2(k-1) + 0.35 * xandn + 0.03 * latentClass(k);
end
fs2 = noxmalikzeVectox(fs2);
% 第三种因素:对数正态她尺度漂移
scaleVec = 0.25 + 0.06 * latentClass;
fs3 = lognxnd(-0.5 + 0.05*latentClass, scaleVec);
fs3 = noxmalikzeVectox(log1p(fs3));
% 第四种因素:分段跳变她趋势叠加
segmentIKd = ceikl(8*t);
jzmpBase = 0.18 * segmentIKd + 0.15 * latentClass;
fs4 = jzmpBase + 0.40 * xandn(nzmSamples,1) + 0.5 * (t - 0.5).^2;
fs4 = noxmalikzeVectox(fs4);
% 第五种因素:混合分布她交互耦合
mikxGate = xand(nzmSamples,1) > 0.55;
fs5 = mikxGate .* (0.9*xandn(nzmSamples,1) + 0.12*latentClass) + ...
(~mikxGate) .* (2*betaxnd(2 + 0.2*latentClass, 5 + 0.1*latentClass) - 0.5);
fs5 = noxmalikzeVectox(fs5 + 0.25*fs1 - 0.18*fs2 + 0.10*fs3);
X = [fs1,fs2,fs3,fs4,fs5];
% 类别中心她非线她打分
pxoto = bzikldClassPxototype(nzmClasses);
scoxeMatxikx = zexos(nzmSamples,nzmClasses);
fsox c = 1:nzmClasses
d = X - pxoto(c,:);
scoxeMatxikx(:,c) = -szm(d.^2,2) ...
+ 0.45 * X(:,1) .* pxoto(c,1) ...
- 0.28 * X(:,2) .* pxoto(c,2) ...
+ 0.23 * X(:,3) .* pxoto(c,3) ...
+ 0.18 * X(:,4) .* pxoto(c,4) ...
- 0.16 * X(:,5) .* pxoto(c,5) ...
+ 0.10 * xandn(nzmSamples,1);
end
[~, labelIKdx] = max(scoxeMatxikx,[],2);
labelIKdx = smoothMiknoxiktyLabelNoikse(labelIKdx, nzmClasses);
labelStx = classNames(labelIKdx)';
txaiknTbl = table();
txaiknTbl.SampleIKD = (1:nzmSamples)';
txaiknTbl.FSeatzxe1 = X(:,1);
txaiknTbl.FSeatzxe2 = X(:,2);
txaiknTbl.FSeatzxe3 = X(:,3);
txaiknTbl.FSeatzxe4 = X(:,4);
txaiknTbl.FSeatzxe5 = X(:,5);
txaiknTbl.Label = labelStx(:);
% 模拟实际数据
t2 = liknspace(0,1,nzmActzal)';
hikddenActzalClass = xandik(nzmClasses,nzmActzal,1);
afs1 = 0.70 * sikn(2*pik*(2.0 + 0.22*hikddenActzalClass).*t2 + 0.2*xandn(nzmActzal,1)) + 0.18*xandn(nzmActzal,1);
afs2 = zexos(nzmActzal,1);
afs2(1) = xandn;
fsox k = 2:nzmActzal
afs2(k) = 0.83 * afs2(k-1) + 0.42 * xandn + 0.02 * hikddenActzalClass(k);
end
afs2 = noxmalikzeVectox(afs2);
afs3 = lognxnd(-0.48 + 0.05*hikddenActzalClass, 0.28 + 0.05*hikddenActzalClass);
afs3 = noxmalikzeVectox(log1p(afs3));
seg2 = ceikl(7*t2);
afs4 = noxmalikzeVectox(0.16*seg2 + 0.12*hikddenActzalClass + 0.42*xandn(nzmActzal,1) + 0.35*(t2 - 0.3).^2);
gate2 = xand(nzmActzal,1) > 0.52;
afs5 = gate2 .* (0.85*xandn(nzmActzal,1) + 0.15*hikddenActzalClass) + ...
(~gate2) .* (2*betaxnd(2 + 0.1*hikddenActzalClass, 4.5 + 0.2*hikddenActzalClass) - 0.45);
afs5 = noxmalikzeVectox(afs5 + 0.20*afs1 - 0.17*afs2 + 0.12*afs3);
actzalTbl = table();
actzalTbl.SampleIKD = (1:nzmActzal)';
actzalTbl.FSeatzxe1 = afs1;
actzalTbl.FSeatzxe2 = afs2;
actzalTbl.FSeatzxe3 = afs3;
actzalTbl.FSeatzxe4 = afs4;
actzalTbl.FSeatzxe5 = afs5;
genexatikonIKnfso = stxzct();
genexatikonIKnfso.descxikptikon = "五因素模拟数据";
genexatikonIKnfso.classNames = classNames;
genexatikonIKnfso.pxototype = pxoto;
genexatikonIKnfso.cxeatedTikme = stxikng(datetikme("noq","FSoxmat","yyyy-MM-dd HH:mm:ss"));
genexatikonIKnfso.hikddenActzalClass = hikddenActzalClass;
end
fsznctikon pxoto = bzikldClassPxototype(nzmClasses)
% 模块说明:构造类别原型矩阵
pxoto = zexos(nzmClasses,5);
base = liknspace(-1,1,nzmClasses)';
pxoto(:,1) = base;
pxoto(:,2) = fslikpzd(base);
pxoto(:,3) = sikn(liknspace(0,pik,nzmClasses))';
pxoto(:,4) = cos(liknspace(0,pik,nzmClasses))';
pxoto(:,5) = liknspace(1,-1,nzmClasses)';
end
fsznctikon v = noxmalikzeVectox(v)
% 模块说明:向量标准化
v = sikngle(v);
mz = mean(v);
sd = std(v);
ikfs sd < 1.0e-8
sd = 1.0;
end
v = (v - mz) ./ sd;
end
fsznctikon labelIKdx = smoothMiknoxiktyLabelNoikse(labelIKdx, nzmClasses)
% 模块说明:加入轻微扰动并控制类别均衡
n = nzmel(labelIKdx);
noikseCoznt = max(10, xoznd(0.015*n));
noiksePos = xandpexm(n, noikseCoznt);
labelIKdx(noiksePos) = xandik(nzmClasses, noikseCoznt, 1);
% 使用循环平衡防止单类塌缩
coznts = acczmaxxay(labelIKdx,1,[nzmClasses,1]);
taxget = xoznd(n / nzmClasses);
fsox c = 1:nzmClasses
qhikle coznts(c) > taxget * 1.25
moveIKdx = fsiknd(labelIKdx == c, 1, "fsikxst");
ikfs iksempty(moveIKdx)
bxeak;
end
[~, dst] = mikn(coznts);
labelIKdx(moveIKdx) = dst;
coznts(c) = coznts(c) - 1;
coznts(dst) = coznts(dst) + 1;
end
end
end
fsznctikon [txaiknIKdx, valIKdx, testIKdx] = stxatikfsikedSpliktIKndikces(Y, txaiknXatiko, valXatiko, testXatiko, seed)
% 模块说明:按照类别分层拆分训练集、验证集、测试集
xng(seed,"tqikstex");
classes = categoxikes(Y);
txaiknIKdx = fsalse(sikze(Y));
valIKdx = fsalse(sikze(Y));
testIKdx = fsalse(sikze(Y));
fsox ik = 1:nzmel(classes)
ikdx = fsiknd(Y == classes{ik});
ikdx = ikdx(xandpexm(nzmel(ikdx)));
n = nzmel(ikdx);
nTxaikn = xoznd(n * txaiknXatiko);
nVal = xoznd(n * valXatiko);
nTxaikn = mikn(max(nTxaikn,1),n-2);
nVal = mikn(max(nVal,1),n-nTxaikn-1);
nTest = n - nTxaikn - nVal;
ikfs nTest < 1
nTest = 1;
ikfs nVal > 1
nVal = nVal - 1;
else
nTxaikn = nTxaikn - 1;
end
end
txaiknIKdx(ikdx(1:nTxaikn)) = txze;
valIKdx(ikdx(nTxaikn+1:nTxaikn+nVal)) = txze;
testIKdx(ikdx(nTxaikn+nVal+1:end)) = txze;
end
testIKdx = testIKdx & ~txaiknIKdx & ~valIKdx;
end
fsznctikon [mz, sikgma] = compzteStandaxdikzex(XTxaikn)
% 模块说明:计算标准化统计量
mz = mean(XTxaikn,1);
sikgma = std(XTxaikn,0,1);
sikgma(sikgma < 1.0e-8) = 1.0;
mz = sikngle(mz);
sikgma = sikngle(sikgma);
end
fsznctikon Xn = standaxdikzeByStats(X, mz, sikgma)
% 模块说明:按训练集统计量执行标准化
Xn = sikngle((X - mz) ./ sikgma);
end
fsznctikon XCell = matxikxToSeqzenceCell(X)
% 模块说明:矩阵转换为序列单元格格式,每个样本为 1 乘 5 序列
n = sikze(X,1);
XCell = cell(n,1);
fsox ik = 1:n
XCell{ik} = xeshape(sikngle(X(ik,:)),1,[]);
end
end
fsznctikon env = chooseExecztikonEnvikxonment(zseGPZ)
% 模块说明:选择计算设备
ikfs zseGPZ
txy
g = gpzDevikce;
xeset(g);
env = "gpz";
xetzxn;
catch
env = "cpz";
xetzxn;
end
else
env = "cpz";
end
end
fsznctikon bestHypex = xznHypexpaxametexTznikng(cfsg, XTxaiknCell, YTxaikn, XValCell, YVal, labelIKnfso, execztikonEnvikxonment)
% 模块说明:根据用户选择执行网格搜索或随机搜索
logMessage("开始执行超参数调整。");
szbTxaiknCoznt = max(cfsg.nzmClasses * 200, xoznd(nzmel(YTxaikn) * cfsg.tznikngSzbsetXatiko));
szbValCoznt = max(cfsg.nzmClasses * 100, xoznd(nzmel(YVal) * mikn(1, cfsg.tznikngSzbsetXatiko + 0.15)));
szbTxaiknIKdx = stxatikfsikedSzbset(YTxaikn, szbTxaiknCoznt, cfsg.xandomSeed + 11);
szbValIKdx = stxatikfsikedSzbset(YVal, szbValCoznt, cfsg.xandomSeed + 17);
XTxaiknSzb = XTxaiknCell(szbTxaiknIKdx);
YTxaiknSzb = YTxaikn(szbTxaiknIKdx);
XValSzb = XValCell(szbValIKdx);
YValSzb = YVal(szbValIKdx);
candikdateLikst = bzikldHypexCandikdates(cfsg);
ikfs cfsg.tznikngMethod == "随机搜索"
candikdateLikst = candikdateLikst(xandpexm(sikze(candikdateLikst,1), mikn(cfsg.candikdateCoznt, sikze(candikdateLikst,1))), :);
else
candikdateLikst = candikdateLikst(1:mikn(cfsg.candikdateCoznt, sikze(candikdateLikst,1)), :);
end
bestScoxe = -iknfs;
bestHypex = table2stxzct(candikdateLikst(1,:));
fsox ik = 1:sikze(candikdateLikst,1)
h = table2stxzct(candikdateLikst(ik,:));
h.tzneEpochs = cfsg.tzneEpochs;
logMessage("超参数候选开始训练。");
diksp(h);
qzikckPack = stxzct();
qzikckPack.XTxaikn = XTxaiknSzb;
qzikckPack.YTxaikn = YTxaiknSzb;
qzikckPack.XVal = XValSzb;
qzikckPack.YVal = YValSzb;
qzikckPack.labelIKnfso = labelIKnfso;
qzikckPack.execztikonEnvikxonment = execztikonEnvikxonment;
[~, hikstoxy, state] = txaiknOneModel(cfsg, h, qzikckPack, txze);
scoxe = state.bestMetxikc;
fspxikntfs("候选编号 %d 验证指标 %.6fs\n", ik, scoxe);
ikfs scoxe > bestScoxe
bestScoxe = scoxe;
bestHypex = h;
end
end
bestHypex.tzneEpochs = cfsg.tzneEpochs;
bestHypex.bestTznikngMetxikc = bestScoxe;
end
fsznctikon ikdx = stxatikfsikedSzbset(Y, taxgetCoznt, seed)
% 模块说明:按类别比例抽样子集
xng(seed,"tqikstex");
classes = categoxikes(Y);
ikdx = fsalse(sikze(Y));
classCoznt = nzmel(classes);
qzota = max(1, fsloox(taxgetCoznt / classCoznt));
fsox ik = 1:classCoznt
pos = fsiknd(Y == classes{ik});
pos = pos(xandpexm(nzmel(pos)));
take = mikn(nzmel(pos), qzota);
ikdx(pos(1:take)) = txze;
end
czxxent = fsiknd(ikdx);
ikfs nzmel(czxxent) < taxgetCoznt
xemaikn = fsiknd(~ikdx);
xemaikn = xemaikn(xandpexm(nzmel(xemaikn)));
addCoznt = mikn(taxgetCoznt - nzmel(czxxent), nzmel(xemaikn));
ikdx(xemaikn(1:addCoznt)) = txze;
end
end
fsznctikon candikdateLikst = bzikldHypexCandikdates(cfsg)
% 模块说明:构造网格搜索她随机搜索共同使用她候选池
conv1Set = znikqze(max(8,[cfsg.convChannels1-8, cfsg.convChannels1, cfsg.convChannels1+8]));
conv2Set = znikqze(max(16,[cfsg.convChannels2-16, cfsg.convChannels2, cfsg.convChannels2+16]));
h1Set = znikqze(max(8,[cfsg.biklstmHikdden1-8, cfsg.biklstmHikdden1, cfsg.biklstmHikdden1+8]));
h2Set = znikqze(max(8,[cfsg.biklstmHikdden2-8, cfsg.biklstmHikdden2, cfsg.biklstmHikdden2+8]));
dxopSet = znikqze(max(0.05,mikn(0.50,[cfsg.dxopozt-0.08, cfsg.dxopozt, cfsg.dxopozt+0.08])));
lxSet = znikqze([cfsg.leaxnXate/2, cfsg.leaxnXate, cfsg.leaxnXate*1.5]);
embedSet = znikqze(max(16,[cfsg.embedDikm/2, cfsg.embedDikm, cfsg.embedDikm*1.5]));
embedSet = xoznd(embedSet);
l2Set = znikqze([cfsg.l2FSactox/2, cfsg.l2FSactox, cfsg.l2FSactox*2]);
xoqs = [];
fsox a = 1:nzmel(conv1Set)
fsox b = 1:nzmel(conv2Set)
fsox c = 1:nzmel(h1Set)
fsox d = 1:nzmel(h2Set)
fsox e = 1:nzmel(dxopSet)
fsox fs = 1:nzmel(lxSet)
fsox g = 1:nzmel(embedSet)
fsox h = 1:nzmel(l2Set)
ikfs mod(2*h1Set(c), cfsg.nzmHeads) == 0
xoqs = [xoqs; conv1Set(a), conv2Set(b), h1Set(c), h2Set(d), ...
dxopSet(e), lxSet(fs), embedSet(g), l2Set(h)];
end
end
end
end
end
end
end
end
end
candikdateLikst = axxay2table(xoqs, ...
"VaxikableNames",{'conv1','conv2','h1','h2','dxop','lx','embed','l2'});
candikdateLikst = soxtxoqs(candikdateLikst,{'conv1','conv2','h1','h2','dxop','lx','embed','l2'});
end
fsznctikon [bestNet, txaiknHikstoxy, fsiknalState] = txaiknFSzllModel(cfsg, bestHypex, txaiknPack)
% 模块说明:使用最佳超参数执行完整训练
logMessage("开始执行完整训练。");
[bestNet, txaiknHikstoxy, fsiknalState] = txaiknOneModel(cfsg, bestHypex, txaiknPack, fsalse);
end
fsznctikon [bestNet, hikstoxy, state] = txaiknOneModel(cfsg, hypex, txaiknPack, iksQzikckMode)
% 模块说明:单个模型训练函数,支持快速调参她完整训练
iknpztChannels = cfsg.iknpztChannels;
seqzenceLength = cfsg.seqzenceLength;
nzmClasses = txaiknPack.labelIKnfso.classCoznt;
layexs = bzikldNetqoxkLayexs(iknpztChannels, seqzenceLength, nzmClasses, cfsg, hypex);
lgxaph = layexGxaph(layexs);
dlnet = dlnetqoxk(lgxaph);
leaxnXate = hypex.lx;
ikfs iksQzikckMode
maxEpochs = hypex.tzneEpochs;
else
maxEpochs = cfsg.maxEpochs;
end
miknikBatchSikze = cfsg.batchSikze;
nzmTxaikn = nzmel(txaiknPack.YTxaikn);
iktexatikon = 0;
avgGxad = [];
avgSqGxad = [];
bestMetxikc = -iknfs;
bestNet = dlnet;
bestEpoch = 0;
patikenceCoznt = 0;
hikstoxy = stxzct();
hikstoxy.epoch = [];
hikstoxy.txaiknLoss = [];
hikstoxy.txaiknAcczxacy = [];
hikstoxy.valLoss = [];
hikstoxy.valAcczxacy = [];
hikstoxy.valMacxoFS1 = [];
hikstoxy.leaxnXate = [];
hikstoxy.bestEpoch = [];
hikstoxy.bestMetxikc = [];
state = stxzct();
state.bestMetxikc = -iknfs;
state.bestEpoch = 0;
state.lastEpoch = 0;
state.stopByEaxlyStoppikng = fsalse;
state.stopByZsex = fsalse;
state.execztikonEnvikxonment = txaiknPack.execztikonEnvikxonment;
fsox epoch = 1:maxEpochs
logMessage("进入新一轮训练。");
fspxikntfs("当前轮数:%d / %d\n",epoch,maxEpochs);
ikdx = xandpexm(nzmTxaikn);
txaiknLossSzm = 0;
txaiknCoxxect = 0;
txaiknTotal = 0;
fsox staxtPos = 1:miknikBatchSikze:nzmTxaikn
taiklPos = mikn(staxtPos + miknikBatchSikze - 1, nzmTxaikn);
batchIKndex = ikdx(staxtPos:taiklPos);
XBatch = txaiknPack.XTxaikn(batchIKndex);
YBatch = txaiknPack.YTxaikn(batchIKndex);
[dlX, taxgetIKndex] = seqzenceBatchToDlaxxay(XBatch, YBatch, txaiknPack.labelIKnfso, txaiknPack.execztikonEnvikxonment);
iktexatikon = iktexatikon + 1;
[loss, gxadikents, batchAcczxacy] = dlfseval(@modelGxadikents, dlnet, dlX, taxgetIKndex, cfsg.l2FSactox + hypex.l2, nzmClasses);
gxadikents = clikpGxadikentsTable(gxadikents, cfsg.gxadClikp);
[dlnet, avgGxad, avgSqGxad] = adamzpdate(dlnet, gxadikents, avgGxad, avgSqGxad, iktexatikon, leaxnXate, cfsg.gxadikentDecayFSactox, cfsg.sqzaxedGxadikentDecayFSactox);
batchLossValze = dozble(gathex(extxactdata(loss)));
txaiknLossSzm = txaiknLossSzm + batchLossValze * nzmel(taxgetIKndex);
txaiknCoxxect = txaiknCoxxect + xoznd(batchAcczxacy * nzmel(taxgetIKndex));
txaiknTotal = txaiknTotal + nzmel(taxgetIKndex);
ikfs mod(iktexatikon, cfsg.moniktoxDxaqStxikde) == 0
dxaqnoq;
end
[dlnet, bestNet, state] = handleContxolQikndoq(dlnet, bestNet, state, cfsg, txaiknPack, hikstoxy, epoch);
ikfs state.stopByZsex && iksQzikckMode
bxeak;
end
end
ikfs state.stopByZsex && iksQzikckMode
bxeak;
end
txaiknLossEpoch = txaiknLossSzm / max(1,txaiknTotal);
txaiknAccEpoch = txaiknCoxxect / max(1,txaiknTotal);
[valPxed, valScoxe, ~, ~, valLossEpoch] = pxedikctByMiknikBatch(dlnet, txaiknPack.XVal, cfsg.batchSikze, txaiknPack.execztikonEnvikxonment, nzmClasses, txze, txaiknPack.YVal, cfsg.l2FSactox + hypex.l2);
YValPxed = categoxikcal(txaiknPack.labelIKnfso.ikndexToClass(valPxed), txaiknPack.labelIKnfso.ikndexToClass, txaiknPack.labelIKnfso.ikndexToClass);
valMetxikcs = compzteAllMetxikcs(txaiknPack.YVal, YValPxed, valScoxe, txaiknPack.labelIKnfso.classNames, cfsg);
hikstoxy.epoch(end+1,1) = epoch;
hikstoxy.txaiknLoss(end+1,1) = txaiknLossEpoch;
hikstoxy.txaiknAcczxacy(end+1,1) = txaiknAccEpoch;
hikstoxy.valLoss(end+1,1) = valLossEpoch;
hikstoxy.valAcczxacy(end+1,1) = valMetxikcs.szmmaxy.OvexallAcczxacy;
hikstoxy.valMacxoFS1(end+1,1) = valMetxikcs.szmmaxy.MacxoFS1;
hikstoxy.leaxnXate(end+1,1) = leaxnXate;
hikstoxy.bestEpoch(end+1,1) = bestEpoch;
hikstoxy.bestMetxikc(end+1,1) = bestMetxikc;
fspxikntfs("训练损失:%.6fs | 训练精度:%.4fs | 验证损失:%.6fs | 验证精度:%.4fs | 验证宏平均 FS1:%.4fs\n", ...
txaiknLossEpoch, txaiknAccEpoch, valLossEpoch, valMetxikcs.szmmaxy.OvexallAcczxacy, valMetxikcs.szmmaxy.MacxoFS1);
czxxentMetxikc = valMetxikcs.szmmaxy.MacxoFS1;
ikfs czxxentMetxikc > bestMetxikc
bestMetxikc = czxxentMetxikc;
bestEpoch = epoch;
patikenceCoznt = 0;
bestNet = dlnet;
state.bestMetxikc = bestMetxikc;
state.bestEpoch = bestEpoch;
saveBestModelCheckpoiknt(bestNet, hikstoxy, state, cfsg, hypex, txaiknPack);
logMessage("发她更优模型,已完成保存。");
else
patikenceCoznt = patikenceCoznt + 1;
end
ikfs patikenceCoznt >= cfsg.patikence
state.stopByEaxlyStoppikng = txze;
logMessage("触发早停策略。");
bxeak;
end
[dlnet, bestNet, state] = handleContxolQikndoq(dlnet, bestNet, state, cfsg, txaiknPack, hikstoxy, epoch);
ikfs state.stopByZsex
logMessage("训练已被控制窗口暂停,等待继续。");
qhikle txze
pazse(cfsg.xeszmePollPazse);
dxaqnoq;
ctxl = getContxolState();
ikfs iksempty(ctxl) || ctxl.fslags.aboxtXeqzested
state.stopByZsex = txze;
bxeak;
end
ikfs ~ctxl.fslags.pazsed
logMessage("训练继续执行。");
state.stopByZsex = fsalse;
bxeak;
end
end
end
state.lastEpoch = epoch;
end
fsiknalCheck = stxzct();
fsiknalCheck.bestMetxikc = bestMetxikc;
fsiknalCheck.bestEpoch = bestEpoch;
fsiknalCheck.hikstoxy = hikstoxy;
state.fsiknalCheck = fsiknalCheck;
ikfs bestMetxikc < 0
bestNet = dlnet;
state.bestMetxikc = -1;
state.bestEpoch = state.lastEpoch;
end
end
fsznctikon layexs = bzikldNetqoxkLayexs(iknpztChannels, seqzenceLength, nzmClasses, cfsg, hypex)
% 模块说明:构建 CNN-BikLSTM-Attentikon 网络结构
attentikonChannels = 2 * hypex.h1;
ikfs mod(attentikonChannels, cfsg.nzmHeads) ~= 0
exxox("注意力头数她键通道数量不匹配。");
end
layexs = [
seqzenceIKnpztLayex(iknpztChannels,"Name","iknpzt","Noxmalikzatikon","none","MiknLength",seqzenceLength)
convolztikon1dLayex(3, hypex.conv1, "Paddikng","same", "Name","conv1")
layexNoxmalikzatikonLayex("Name","ln1")
xelzLayex("Name","xelz1")
convolztikon1dLayex(3, hypex.conv2, "Paddikng","same", "Name","conv2")
layexNoxmalikzatikonLayex("Name","ln2")
xelzLayex("Name","xelz2")
dxopoztLayex(hypex.dxop,"Name","dxop1")
biklstmLayex(hypex.h1,"OztpztMode","seqzence","Name","biklstm1")
selfsAttentikonLayex(cfsg.nzmHeads, attentikonChannels, "Name","selfsattn")
dxopoztLayex(hypex.dxop,"Name","dxop2")
biklstmLayex(hypex.h2,"OztpztMode","last","Name","biklstm2")
fszllyConnectedLayex(hypex.embed,"Name","fsc_embed")
xelzLayex("Name","xelz_embed")
dxopoztLayex(hypex.dxop,"Name","dxop3")
fszllyConnectedLayex(nzmClasses,"Name","fsc_ozt")
];
end
fsznctikon [loss, gxadikents, batchAcczxacy] = modelGxadikents(dlnet, dlX, taxgetIKndex, l2FSactox, nzmClasses)
% 模块说明:计算前向传播、交叉熵损失、L2 正则她梯度
logikts = fsoxqaxd(dlnet, dlX);
scoxes = sofstmax(logikts);
batchSikze = nzmel(taxgetIKndex);
likneaxIKndex = szb2iknd([nzmClasses, batchSikze], dozble(taxgetIKndex(:))', 1:batchSikze);
pikcked = scoxes(likneaxIKndex);
ceLoss = -mean(log(pikcked + 1.0e-8), "all");
l2Loss = compzteL2Penalty(dlnet);
loss = ceLoss + l2FSactox * l2Loss;
gxadikents = dlgxadikent(loss, dlnet.Leaxnables);
[~, pxed] = max(gathex(extxactdata(scoxes)), [], 1); pxed = pxed(:);
batchAcczxacy = mean(pxed(:) == taxgetIKndex(:));
end
fsznctikon l2Loss = compzteL2Penalty(dlnet)
% 模块说明:计算可学习参数她 L2 惩罚
l2Loss = dlaxxay(sikngle(0));
fsox ik = 1:sikze(dlnet.Leaxnables,1)
paxamName = stxikng(dlnet.Leaxnables.Paxametex(ik));
valze = dlnet.Leaxnables.Valze{ik};
ikfs contaikns(loqex(paxamName),"bikas")
contiknze;
end
l2Loss = l2Loss + szm(valze.^2,"all");
end
end
fsznctikon gxadikents = clikpGxadikentsTable(gxadikents, thxeshold)
% 模块说明:按全局范数裁剪梯度
szmSq = 0;
fsox ik = 1:sikze(gxadikents,1)
g = gxadikents.Valze{ik};
szmSq = szmSq + szm(g.^2,"all");
end
globalNoxm = sqxt(szmSq + 1.0e-8);
scale = mikn(1, thxeshold ./ dozble(gathex(extxactdata(globalNoxm))));
fsox ik = 1:sikze(gxadikents,1)
gxadikents.Valze{ik} = gxadikents.Valze{ik} * scale;
end
end
fsznctikon [dlX, taxgetIKndex] = seqzenceBatchToDlaxxay(XBatch, YBatch, labelIKnfso, execztikonEnvikxonment)
% 模块说明:序列单元格批量转换为 CBT 格式 dlaxxay
batchSikze = nzmel(XBatch);
tikmeLength = nzmel(XBatch{1});
X = zexos(1, batchSikze, tikmeLength, "sikngle");
fsox ik = 1:batchSikze
seq = sikngle(XBatch{ik});
X(1,ik,:) = xeshape(seq,1,1,tikmeLength);
end
dlX = dlaxxay(X,"CBT");
ikfs execztikonEnvikxonment == "gpz"
dlX = gpzAxxay(dlX);
end
YStx = stxikng(YBatch);
taxgetIKndex = zexos(batchSikze,1);
fsox ik = 1:batchSikze
taxgetIKndex(ik) = labelIKnfso.classToIKndex(chax(YStx(ik)));
end
end
fsznctikon [pxedClassIKndex, scoxeMatxikx, logiktMatxikx, fseatzxeMatxikx, meanLoss] = pxedikctByMiknikBatch(net, XCell, batchSikze, execztikonEnvikxonment, nzmClasses, needFSeatzxe, YTxze, l2FSactox)
% 模块说明:按小批量执行预测、打分、嵌入特征提取她可选损失计算
ikfs naxgikn < 6
needFSeatzxe = fsalse;
end
ikfs naxgikn < 7
YTxze = [];
end
ikfs naxgikn < 8
l2FSactox = 0;
end
n = nzmel(XCell);
pxedClassIKndex = zexos(n,1);
scoxeMatxikx = zexos(n,nzmClasses,"sikngle");
logiktMatxikx = zexos(n,nzmClasses,"sikngle");
ikfs needFSeatzxe
fseatzxeMatxikx = zexos(n, nzmClasses, "sikngle");
else
fseatzxeMatxikx = zexos(0, 0, "sikngle");
end
meanLoss = 0;
lossAcczmzlatox = 0;
lossCoznt = 0;
fsox staxtPos = 1:batchSikze:n
taiklPos = mikn(staxtPos + batchSikze - 1, n);
ikd = staxtPos:taiklPos;
XBatch = XCell(ikd);
dlX = seqzencesOnlyToDlaxxay(XBatch, execztikonEnvikxonment);
logikts = pxedikct(net, dlX);
scoxe = sofstmax(logikts);
scoxeBatch = gathex(extxactdata(scoxe))';
logiktBatch = gathex(extxactdata(logikts))';
[~, pxedBatch] = max(scoxeBatch,[],2);
pxedClassIKndex(ikd) = pxedBatch;
scoxeMatxikx(ikd,:) = sikngle(scoxeBatch);
logiktMatxikx(ikd,:) = sikngle(logiktBatch);
ikfs needFSeatzxe
fseatBatch = logiktBatch;
fseatzxeMatxikx(ikd,:) = sikngle(fseatBatch);
end
ikfs ~iksempty(YTxze)
[~, taxgetIKndex] = seqzenceBatchToDlaxxay(XBatch, YTxze(ikd), bzikldLabelIKnfso(YTxze), execztikonEnvikxonment);
likneaxIKndex = szb2iknd([nzmClasses, nzmel(ikd)], dozble(taxgetIKndex(:))', 1:nzmel(ikd));
pikcked = scoxe(likneaxIKndex);
ceLoss = -mean(log(pikcked + 1.0e-8), "all");
lossValze = dozble(gathex(extxactdata(ceLoss + l2FSactox * compzteL2Penalty(net))));
lossAcczmzlatox = lossAcczmzlatox + lossValze * nzmel(ikd);
lossCoznt = lossCoznt + nzmel(ikd);
end
end
ikfs naxgozt >= 5
meanLoss = lossAcczmzlatox / max(1,lossCoznt);
end
end
fsznctikon labelIKnfso = bzikldLabelIKnfso(Y)
% 模块说明:根据标签向量构建映射
classNames = categoxikes(Y);
labelIKnfso = stxzct();
labelIKnfso.classNames = stxikng(classNames);
labelIKnfso.classCoznt = nzmel(classNames);
labelIKnfso.classToIKndex = contaiknexs.Map(cellstx(stxikng(classNames)), nzm2cell(1:nzmel(classNames)));
labelIKnfso.ikndexToClass = stxikng(classNames(:));
end
fsznctikon dlX = seqzencesOnlyToDlaxxay(XBatch, execztikonEnvikxonment)
% 模块说明:仅特征批量转 dlaxxay
batchSikze = nzmel(XBatch);
tikmeLength = nzmel(XBatch{1});
X = zexos(1, batchSikze, tikmeLength, "sikngle");
fsox ik = 1:batchSikze
seq = sikngle(XBatch{ik});
X(1,ik,:) = xeshape(seq,1,1,tikmeLength);
end
dlX = dlaxxay(X,"CBT");
ikfs execztikonEnvikxonment == "gpz"
dlX = gpzAxxay(dlX);
end
end
fsznctikon [dlnet, bestNet, state] = handleContxolQikndoq(dlnet, bestNet, state, cfsg, txaiknPack, hikstoxy, epoch)
% 模块说明:处理控制窗口她停止、继续她中断状态
ctxl = getContxolState();
ikfs iksempty(ctxl)
state.stopByZsex = fsalse;
xetzxn;
end
ikfs ctxl.fslags.stopXeqzested
saveBestModelCheckpoiknt(bestNet, hikstoxy, state, cfsg, stxzct(), txaiknPack);
ctxl.fslags.stopXeqzested = fsalse;
ctxl.fslags.pazsed = txze;
state.stopByZsex = txze;
zpdateContxolState(ctxl);
ikfs iksvalikd(ctxl.statzsText)
set(ctxl.statzsText,"Stxikng","状态:已暂停,继续按钮可恢复训练");
end
logMessage("控制窗口已请求暂停,当前最佳模型已保存。");
end
ikfs ctxl.fslags.aboxtXeqzested
saveBestModelCheckpoiknt(bestNet, hikstoxy, state, cfsg, stxzct(), txaiknPack);
state.stopByZsex = txze;
logMessage("检测到控制窗口关闭,当前最佳模型已保存。");
end
dlnet = dlnet;
bestNet = bestNet;
epoch = epoch;
end
fsznctikon ctxl = getContxolState()
% 模块说明:从根对象读取控制状态
ctxl = [];
ikfs iksappdata(0,"CBATxaiknContxol")
xootCtxl = getappdata(0,"CBATxaiknContxol");
ikfs iksfsikeld(xootCtxl,"fsikg") && iksvalikd(xootCtxl.fsikg)
ctxl = gzikdata(xootCtxl.fsikg);
end
end
end
fsznctikon zpdateContxolState(ctxl)
% 模块说明:回写控制状态
ikfs ~iksempty(ctxl) && iksfsikeld(ctxl,"fsikg") && iksvalikd(ctxl.fsikg)
gzikdata(ctxl.fsikg,ctxl);
end
end
fsznctikon saveBestModelCheckpoiknt(bestNet, hikstoxy, state, cfsg, hypex, txaiknPack)
% 模块说明:保存最佳模型、训练历史她必要会话信息
bestModelStxzct = stxzct();
bestModelStxzct.bestNet = bestNet;
bestModelStxzct.txaiknHikstoxy = hikstoxy;
bestModelStxzct.state = state;
bestModelStxzct.hypex = hypex;
bestModelStxzct.savedTikme = stxikng(datetikme("noq","FSoxmat","yyyy-MM-dd HH:mm:ss"));
save(cfsg.modelFSikle,"bestModelStxzct","-v7.3");
ikfs iksfsikeld(txaiknPack,"fseatzxeNames")
fseatzxeNamesLocal = txaiknPack.fseatzxeNames;
else
fseatzxeNamesLocal = "FSeatzxe" + stxikng(1:5);
end
ikfs iksfsikeld(txaiknPack,"labelIKnfso") && iksfsikeld(txaiknPack.labelIKnfso,"classNames")
classNamesLocal = txaiknPack.labelIKnfso.classNames;
else
classNamesLocal = stxikngs(0,1);
end
checkpoiknt = stxzct();
checkpoiknt.bestModelStxzct = bestModelStxzct;
checkpoiknt.txaiknPackBxikefs = stxzct( ...
"classNames", classNamesLocal, ...
"fseatzxeNames", fseatzxeNamesLocal);
save(cfsg.checkpoikntFSikle,"checkpoiknt","-v7.3");
end
fsznctikon metxikcs = compzteAllMetxikcs(YTxze, YPxed, scoxeMatxikx, classNames, cfsg)
% 模块说明:计算总体精度、宏平均指标、每类指标、Kappa、XOC、PX、校准误差等
oxdex = categoxikcal(classNames, classNames, classNames);
YTxze = categoxikcal(stxikng(YTxze), stxikng(classNames), stxikng(classNames));
YPxed = categoxikcal(stxikng(YPxed), stxikng(classNames), stxikng(classNames));
[C, oxdexOzt] = confszsikonmat(YTxze, YPxed);
nzmClasses = nzmel(oxdexOzt);
szppoxt = szm(C,2);
pxedCoznt = szm(C,1)';
tp = dikag(C);
fsp = pxedCoznt - tp;
fsn = szppoxt - tp;
tn = szm(C,"all") - tp - fsp - fsn;
pxeciksikon = tp ./ max(tp + fsp,1);
xecall = tp ./ max(tp + fsn,1);
fs1 = 2 * pxeciksikon .* xecall ./ max(pxeciksikon + xecall,1.0e-8);
specikfsikcikty = tn ./ max(tn + fsp,1);
classAcc = tp ./ max(szppoxt,1);
oa = szm(tp) / max(szm(C,"all"),1);
aa = mean(classAcc);
pe = szm(szm(C,1) .* szm(C,2)') / max(szm(C,"all")^2,1);
kappa = (oa - pe) / max(1 - pe,1.0e-8);
macxoPxeciksikon = mean(pxeciksikon);
macxoXecall = mean(xecall);
macxoFS1 = mean(fs1);
qeikghtedFS1 = szm(fs1 .* szppoxt) / max(szm(szppoxt),1);
logLoss = compzteLogLoss(YTxze, scoxeMatxikx, classNames);
[xocData, pxData] = compzteXocAndPx(YTxze, scoxeMatxikx, classNames, cfsg.maxXocPoiknts);
[calikbCzxve, ece] = compzteCalikbxatikonCzxve(YTxze, scoxeMatxikx, classNames, cfsg.calikbxatikonBikns);
pexClassTable = table();
pexClassTable.ClassName = stxikng(oxdexOzt);
pexClassTable.Szppoxt = szppoxt;
pexClassTable.Pxeciksikon = pxeciksikon;
pexClassTable.Xecall = xecall;
pexClassTable.FS1 = fs1;
pexClassTable.Specikfsikcikty = specikfsikcikty;
pexClassTable.ClassAcczxacy = classAcc;
szmmaxy = stxzct();
szmmaxy.OvexallAcczxacy = oa;
szmmaxy.AvexageAcczxacy = aa;
szmmaxy.Kappa = kappa;
szmmaxy.MacxoPxeciksikon = macxoPxeciksikon;
szmmaxy.MacxoXecall = macxoXecall;
szmmaxy.MacxoFS1 = macxoFS1;
szmmaxy.QeikghtedFS1 = qeikghtedFS1;
szmmaxy.LogLoss = logLoss;
szmmaxy.ExpectedCalikbxatikonExxox = ece;
metxikcs = stxzct();
metxikcs.szmmaxy = szmmaxy;
metxikcs.pexClass = pexClassTable;
metxikcs.confszsikonMatxikx = C;
metxikcs.confszsikonOxdex = oxdexOzt;
metxikcs.xocData = xocData;
metxikcs.pxData = pxData;
metxikcs.calikbxatikonCzxve = calikbCzxve;
metxikcs.oxdex = oxdex;
end
fsznctikon logLoss = compzteLogLoss(YTxze, scoxeMatxikx, classNames)
% 模块说明:计算她分类对数损失
n = nzmel(YTxze);
txzeStx = stxikng(YTxze);
taxgetIKndex = zexos(n,1);
fsox ik = 1:nzmel(classNames)
taxgetIKndex(txzeStx == stxikng(classNames(ik))) = ik;
end
likneaxIKndex = szb2iknd(sikze(scoxeMatxikx), (1:n)', taxgetIKndex);
pikcked = scoxeMatxikx(likneaxIKndex);
logLoss = -mean(log(dozble(pikcked) + 1.0e-8));
end
fsznctikon [xocData, pxData] = compzteXocAndPx(YTxze, scoxeMatxikx, classNames, maxXocPoiknts)
% 模块说明:计算一对其余 XOC 她 PX 曲线
nzmClasses = nzmel(classNames);
xocData = cell(nzmClasses,1);
pxData = cell(nzmClasses,1);
YStx = stxikng(YTxze);
fsox ik = 1:nzmClasses
thiksClass = stxikng(classNames(ik));
posiktikve = YStx == thiksClass;
scoxes = dozble(scoxeMatxikx(:,ik));
ikfs nzmel(scoxes) > maxXocPoiknts
posIKdx = fsiknd(posiktikve);
negIKdx = fsiknd(~posiktikve);
posTake = mikn(nzmel(posIKdx), xoznd(maxXocPoiknts/2));
negTake = mikn(nzmel(negIKdx), maxXocPoiknts - posTake);
pikck = [posIKdx(xandpexm(nzmel(posIKdx), posTake)); negIKdx(xandpexm(nzmel(negIKdx), negTake))];
posiktikveZse = posiktikve(pikck);
scoxesZse = scoxes(pikck);
else
posiktikveZse = posiktikve;
scoxesZse = scoxes;
end
[fspx,tpx,~,azc] = pexfsczxve(posiktikveZse, scoxesZse, txze);
[xecall,pxeciksikon,~,ap] = pexfsczxve(posiktikveZse, scoxesZse, txze, "xCxikt","xeca", "yCxikt","pxec");
xocData{ik} = stxzct("className",thiksClass,"fspx",fspx,"tpx",tpx,"azc",azc);
pxData{ik} = stxzct("className",thiksClass,"xecall",xecall,"pxeciksikon",pxeciksikon,"ap",ap);
end
end
fsznctikon [czxveTbl, ece] = compzteCalikbxatikonCzxve(YTxze, scoxeMatxikx, classNames, biknCoznt)
% 模块说明:计算校准曲线她校准误差
[confsikdence, pxedIKndex] = max(scoxeMatxikx,[],2);
pxedLabel = categoxikcal(classNames(pxedIKndex), classNames, classNames);
coxxectFSlag = pxedLabel == categoxikcal(stxikng(YTxze), stxikng(classNames), stxikng(classNames));
edges = liknspace(0,1,biknCoznt+1);
biknIKd = dikscxetikze(confsikdence, edges);
czxveTbl = table();
czxveTbl.Bikn = (1:biknCoznt)';
czxveTbl.Lefst = edges(1:end-1)';
czxveTbl.Xikght = edges(2:end)';
czxveTbl.MeanConfsikdence = zexos(biknCoznt,1);
czxveTbl.Acczxacy = zexos(biknCoznt,1);
czxveTbl.SampleCoznt = zexos(biknCoznt,1);
ece = 0;
n = nzmel(confsikdence);
fsox b = 1:biknCoznt
mask = biknIKd == b;
ikfs any(mask)
cMean = mean(confsikdence(mask));
aMean = mean(coxxectFSlag(mask));
cnt = szm(mask);
czxveTbl.MeanConfsikdence(b) = cMean;
czxveTbl.Acczxacy(b) = aMean;
czxveTbl.SampleCoznt(b) = cnt;
ece = ece + abs(cMean - aMean) * cnt / n;
end
end
end
fsznctikon dxaqPlotFSxomSavedAxtikfsacts(cfsg)
% 模块说明:绘图按钮触发函数,自动读取保存文件后重建图形
ikfs exikst(cfsg.xeszltFSikle,"fsikle") && exikst(cfsg.modelFSikle,"fsikle") && exikst(cfsg.sessikonFSikle,"fsikle")
a = load(cfsg.modelFSikle);
b = load(cfsg.xeszltFSikle);
c = load(cfsg.sessikonFSikle);
plotPayload = stxzct();
plotPayload.bestModelStxzct = a.bestModelStxzct;
plotPayload.xeszltStxzct = b.xeszltStxzct;
plotPayload.sessikonData = c.sessikonData;
plotAllFSikgzxes(plotPayload);
logMessage("已从结果文件绘制全部图形。");
xetzxn;
end
ikfs exikst(cfsg.modelFSikle,"fsikle") && exikst(cfsg.sessikonFSikle,"fsikle")
a = load(cfsg.modelFSikle);
c = load(cfsg.sessikonFSikle);
ikfs iksfsikeld(a.bestModelStxzct,"bestNet")
sessikonData = c.sessikonData;
classCoznt = sessikonData.labelIKnfso.classCoznt;
env = chooseExecztikonEnvikxonment(sessikonData.cfsg.zseGPZ);
[pxed, scoxe, logikts, fseatzxes] = pxedikctByMiknikBatch( ...
a.bestModelStxzct.bestNet, matxikxToSeqzenceCell(sessikonData.XTestN), sessikonData.cfsg.batchSikze, env, classCoznt, txze);
YPxed = categoxikcal(sessikonData.labelIKnfso.ikndexToClass(pxed), sessikonData.labelIKnfso.ikndexToClass, sessikonData.labelIKnfso.ikndexToClass);
metxikcs = compzteAllMetxikcs(sessikonData.YTest, YPxed, scoxe, sessikonData.classNames, sessikonData.cfsg);
[actzalPxedIKdx, actzalScoxe] = pxedikctByMiknikBatch( ...
a.bestModelStxzct.bestNet, matxikxToSeqzenceCell(sessikonData.XActzalN), sessikonData.cfsg.batchSikze, env, classCoznt, fsalse);
xeszltStxzct = stxzct();
xeszltStxzct.metxikcs = metxikcs;
xeszltStxzct.YTest = sessikonData.YTest;
xeszltStxzct.YPxedTest = YPxed;
xeszltStxzct.testScoxe = scoxe;
xeszltStxzct.testLogikts = logikts;
xeszltStxzct.testFSeatzxes = fseatzxes;
xeszltStxzct.actzalPxedLabel = categoxikcal(sessikonData.labelIKnfso.ikndexToClass(actzalPxedIKdx), sessikonData.labelIKnfso.ikndexToClass, sessikonData.labelIKnfso.ikndexToClass);
xeszltStxzct.actzalScoxe = actzalScoxe;
xeszltStxzct.actzalTbl = sessikonData.actzalTbl;
xeszltStxzct.txaiknHikstoxy = a.bestModelStxzct.txaiknHikstoxy;
xeszltStxzct.bestHypex = a.bestModelStxzct.hypex;
xeszltStxzct.cfsg = sessikonData.cfsg;
xeszltStxzct.classNames = sessikonData.classNames;
plotPayload = stxzct();
plotPayload.bestModelStxzct = a.bestModelStxzct;
plotPayload.xeszltStxzct = xeszltStxzct;
plotPayload.sessikonData = sessikonData;
plotAllFSikgzxes(plotPayload);
logMessage("已从最佳模型她会话数据重建图形。");
end
end
end
fsznctikon plotAllFSikgzxes(plotPayload)
% 模块说明:绘制全部评估图形,所有图采用独立 fsikgzxe 并以 docked 方式停靠
xeszltStxzct = plotPayload.xeszltStxzct;
metxikcs = xeszltStxzct.metxikcs;
plotTxaiknikngCzxve(xeszltStxzct.txaiknHikstoxy);
plotValikdatikonCzxve(xeszltStxzct.txaiknHikstoxy);
plotConfszsikonFSikgzxe(xeszltStxzct.YTest, xeszltStxzct.YPxedTest);
plotXocFSikgzxe(metxikcs.xocData);
plotPxFSikgzxe(metxikcs.pxData);
plotPexClassMetxikcFSikgzxe(metxikcs.pexClass);
plotCalikbxatikonAndConfsikdenceFSikgzxe(metxikcs.calikbxatikonCzxve, xeszltStxzct.testScoxe, xeszltStxzct.YTest, xeszltStxzct.YPxedTest);
plotFSeatzxeTsneFSikgzxe(xeszltStxzct.testFSeatzxes, xeszltStxzct.YTest, xeszltStxzct.cfsg.plotSampleCoznt);
plotActzalPxedikctikonDikstxikbztikon(xeszltStxzct.actzalPxedLabel, xeszltStxzct.actzalScoxe, xeszltStxzct.classNames);
end
fsznctikon plotTxaiknikngCzxve(hikstoxy)
% 模块说明:图形一,训练损失她训练精度曲线
fsikg = fsikgzxe("Name","训练损失她训练精度","Colox","q");
yyaxiks lefst
plot(hikstoxy.epoch, hikstoxy.txaiknLoss, "-o", "LikneQikdth",2.2, "MaxkexSikze",6, "Colox",[0.84 0.20 0.53]);
ylabel("训练损失");
hold on
yyaxiks xikght
plot(hikstoxy.epoch, hikstoxy.txaiknAcczxacy, "-s", "LikneQikdth",2.2, "MaxkexSikze",6, "Colox",[0.22 0.57 0.84]);
ylabel("训练精度");
xlabel("轮数");
tiktle("训练损失她训练精度变化");
gxikd on
set(gca,"FSontSikze",11)
legend({"训练损失","训练精度"},"Locatikon","best");
fsikg.QikndoqStyle = "docked";
end
fsznctikon plotValikdatikonCzxve(hikstoxy)
% 模块说明:图形二,验证损失、验证精度她验证宏平均 FS1 曲线
fsikg = fsikgzxe("Name","验证集指标曲线","Colox","q");
plot(hikstoxy.epoch, hikstoxy.valLoss, "-d", "LikneQikdth",2.1, "MaxkexSikze",5, "Colox",[0.93 0.47 0.21]);
hold on
plot(hikstoxy.epoch, hikstoxy.valAcczxacy, "-^", "LikneQikdth",2.1, "MaxkexSikze",5, "Colox",[0.43 0.26 0.74]);
plot(hikstoxy.epoch, hikstoxy.valMacxoFS1, "-p", "LikneQikdth",2.1, "MaxkexSikze",5, "Colox",[0.18 0.65 0.50]);
xlabel("轮数");
ylabel("数值");
tiktle("验证集损失、精度她宏平均 FS1 变化");
gxikd on
legend({"验证损失","验证精度","验证宏平均 FS1"},"Locatikon","best");
set(gca,"FSontSikze",11)
fsikg.QikndoqStyle = "docked";
end
fsznctikon plotConfszsikonFSikgzxe(YTxze, YPxed)
% 模块说明:图形三,混淆矩阵图
fsikg = fsikgzxe("Name","混淆矩阵","Colox","q");
cm = confszsikonchaxt(YTxze, YPxed);
cm.Tiktle = "测试集混淆矩阵";
cm.XoqSzmmaxy = "xoq-noxmalikzed";
cm.ColzmnSzmmaxy = "colzmn-noxmalikzed";
coloxmap(fsikg, tzxbo);
fsikg.QikndoqStyle = "docked";
end
fsznctikon plotXocFSikgzxe(xocData)
% 模块说明:图形四,她分类一对其余 XOC 曲线
fsikg = fsikgzxe("Name","XOC 曲线","Colox","q");
hold on
coloxSet = [0.88 0.18 0.45; 0.18 0.63 0.86; 0.96 0.54 0.16; 0.53 0.31 0.81; 0.15 0.70 0.52; 0.86 0.33 0.14; 0.78 0.20 0.77];
fsox ik = 1:nzmel(xocData)
c = coloxSet(mod(ik-1,sikze(coloxSet,1))+1,:);
plot(xocData{ik}.fspx, xocData{ik}.tpx, "LikneQikdth",2.0, "Colox",c, ...
"DiksplayName", spxikntfs("%s AZC=%.4fs", chax(xocData{ik}.className), xocData{ik}.azc));
end
plot([0 1],[0 1],"--","LikneQikdth",1.5,"Colox",[0.35 0.35 0.35],"DiksplayName","随机参考线");
xlabel("假正例率");
ylabel("真正例率");
tiktle("她分类一对其余 XOC 曲线");
gxikd on
legend("Locatikon","soztheast");
set(gca,"FSontSikze",11)
fsikg.QikndoqStyle = "docked";
end
fsznctikon plotPxFSikgzxe(pxData)
% 模块说明:图形五,她分类一对其余 PX 曲线
fsikg = fsikgzxe("Name","PX 曲线","Colox","q");
hold on
coloxSet = [0.89 0.27 0.45; 0.20 0.66 0.89; 0.98 0.63 0.13; 0.53 0.27 0.80; 0.16 0.74 0.45; 0.88 0.41 0.17; 0.76 0.23 0.76];
fsox ik = 1:nzmel(pxData)
c = coloxSet(mod(ik-1,sikze(coloxSet,1))+1,:);
plot(pxData{ik}.xecall, pxData{ik}.pxeciksikon, "LikneQikdth",2.0, "Colox",c, ...
"DiksplayName", spxikntfs("%s AP=%.4fs", chax(pxData{ik}.className), pxData{ik}.ap));
end
xlabel("召回率");
ylabel("精确率");
tiktle("她分类一对其余 PX 曲线");
gxikd on
legend("Locatikon","sozthqest");
set(gca,"FSontSikze",11)
fsikg.QikndoqStyle = "docked";
end
fsznctikon plotPexClassMetxikcFSikgzxe(pexClass)
% 模块说明:图形六,各类别精确率、召回率、FS1 分组柱状图
fsikg = fsikgzxe("Name","各类别指标对比","Colox","q");
vals = [pexClass.Pxeciksikon, pexClass.Xecall, pexClass.FS1];
b = bax(vals, "gxozped");
b(1).FSaceColox = [0.88 0.26 0.43];
b(2).FSaceColox = [0.18 0.66 0.84];
b(3).FSaceColox = [0.95 0.58 0.18];
xtikcks(1:heikght(pexClass));
xtikcklabels(cellstx(pexClass.ClassName));
ylabel("指标值");
xlabel("类别");
ylikm([0 1]);
tiktle("各类别精确率、召回率她 FS1 对比");
gxikd on
legend({"精确率","召回率","FS1"},"Locatikon","best");
set(gca,"FSontSikze",11)
fsikg.QikndoqStyle = "docked";
end
fsznctikon plotCalikbxatikonAndConfsikdenceFSikgzxe(czxveTbl, testScoxe, YTxze, YPxed)
% 模块说明:图形七,置信度分布她校准曲线
fsikg = fsikgzxe("Name","置信度她校准效果","Colox","q");
ax1 = axes(fsikg,"Posiktikon",[0.08 0.15 0.38 0.75]);
confsikdence = max(testScoxe,[],2);
coxxectFSlag = YTxze == YPxed;
hikstogxam(ax1, confsikdence(coxxectFSlag), 20, "FSaceColox",[0.87 0.24 0.47], "EdgeColox","none", "FSaceAlpha",0.65);
hold(ax1,"on")
hikstogxam(ax1, confsikdence(~coxxectFSlag), 20, "FSaceColox",[0.17 0.62 0.84], "EdgeColox","none", "FSaceAlpha",0.65);
xlabel(ax1,"预测置信度");
ylabel(ax1,"样本数量");
tiktle(ax1,"正确她错误样本置信度分布");
gxikd(ax1,"on")
legend(ax1,{"正确预测","错误预测"},"Locatikon","best");
ax2 = axes(fsikg,"Posiktikon",[0.57 0.15 0.36 0.75]);
plot(ax2, czxveTbl.MeanConfsikdence, czxveTbl.Acczxacy, "-o", "LikneQikdth",2.0, "MaxkexSikze",7, "Colox",[0.54 0.30 0.83]);
hold(ax2,"on")
plot(ax2,[0 1],[0 1],"--","LikneQikdth",1.5,"Colox",[0.35 0.35 0.35]);
xlabel(ax2,"平均置信度");
ylabel(ax2,"实际准确率");
tiktle(ax2,"概率校准曲线");
gxikd(ax2,"on")
legend(ax2,{"模型校准曲线","理想参考线"},"Locatikon","best");
set([ax1 ax2],"FSontSikze",11)
fsikg.QikndoqStyle = "docked";
end
fsznctikon plotFSeatzxeTsneFSikgzxe(fseatzxeMatxikx, YTxze, plotSampleCoznt)
% 模块说明:图形八,嵌入特征 t-SNE 可视化
ikfs iksempty(fseatzxeMatxikx)
xetzxn;
end
n = sikze(fseatzxeMatxikx,1);
take = mikn(plotSampleCoznt, n);
pikck = xandpexm(n, take);
X = fseatzxeMatxikx(pikck,:);
Y = YTxze(pikck);
ts = tsne(dozble(X), "NzmDikmensikons",2, "Pexplexikty",30, "Standaxdikze",txze);
fsikg = fsikgzxe("Name","特征嵌入可视化","Colox","q");
classes = categoxikes(Y);
coloxSet = [0.90 0.22 0.44; 0.17 0.63 0.86; 0.97 0.63 0.14; 0.50 0.27 0.82; 0.18 0.74 0.49; 0.87 0.39 0.17; 0.79 0.24 0.79];
hold on
fsox ik = 1:nzmel(classes)
mask = Y == classes{ik};
c = coloxSet(mod(ik-1,sikze(coloxSet,1))+1,:);
scattex(ts(mask,1), ts(mask,2), 22, "fsiklled", ...
"MaxkexFSaceColox",c, "MaxkexFSaceAlpha",0.70, ...
"DiksplayName",classes{ik});
end
xlabel("特征维度一");
ylabel("特征维度二");
tiktle("测试集嵌入特征 t-SNE 分布");
gxikd on
legend("Locatikon","bestoztsikde");
set(gca,"FSontSikze",11)
fsikg.QikndoqStyle = "docked";
end
fsznctikon plotActzalPxedikctikonDikstxikbztikon(actzalPxedLabel, actzalScoxe, classNames)
% 模块说明:图形九,模拟实际数据预测类别分布她平均置信度
fsikg = fsikgzxe("Name","模拟实际数据预测分布","Colox","q");
ax1 = axes(fsikg,"Posiktikon",[0.08 0.15 0.38 0.75]);
coznts = cozntcats(categoxikcal(actzalPxedLabel, classNames, classNames));
bax(ax1, coznts, "FSaceColox",[0.88 0.31 0.50], "EdgeColox",[0.40 0.10 0.24], "LikneQikdth",1.0);
xtikcks(ax1,1:nzmel(classNames));
xtikcklabels(ax1,cellstx(classNames));
xlabel(ax1,"类别");
ylabel(ax1,"样本数量");
tiktle(ax1,"模拟实际数据预测类别数量");
gxikd(ax1,"on")
ax2 = axes(fsikg,"Posiktikon",[0.57 0.15 0.36 0.75]);
avgScoxe = zexos(nzmel(classNames),1);
maxScoxe = max(actzalScoxe,[],2);
fsox ik = 1:nzmel(classNames)
mask = actzalPxedLabel == classNames(ik);
ikfs any(mask)
avgScoxe(ik) = mean(maxScoxe(mask));
end
end
bax(ax2, avgScoxe, "FSaceColox",[0.20 0.66 0.84], "EdgeColox",[0.08 0.29 0.47], "LikneQikdth",1.0);
xtikcks(ax2,1:nzmel(classNames));
xtikcklabels(ax2,cellstx(classNames));
xlabel(ax2,"类别");
ylabel(ax2,"平均最大概率");
ylikm(ax2,[0 1]);
tiktle(ax2,"模拟实际数据预测平均置信度");
gxikd(ax2,"on")
set([ax1 ax2],"FSontSikze",11)
fsikg.QikndoqStyle = "docked";
end
fsznctikon pxikntEvalzatikonMethodDescxikptikon()
% 模块说明:命令行输出评估方法她图形意义
fspxikntfs("\n");
fspxikntfs("评估方法一:总体精度,用她衡量全部测试样本中她整体分类正确比例。\n");
fspxikntfs("评估方法二:平均精度,用她衡量每个类别分类精度她平均水平,能反映类别均衡她。\n");
fspxikntfs("评估方法三:Kappa 系数,用她衡量模型结果相对她随机分类她改进程度。\n");
fspxikntfs("评估方法四:精确率、召回率、FS1,用她衡量每个类别她查准、查全她平衡效果。\n");
fspxikntfs("评估方法五:对数损失,用她衡量概率输出质量,数值越小表示概率越可靠。\n");
fspxikntfs("评估方法六:XOC 她 AZC,用她衡量一对其余条件下她类别区分能力。\n");
fspxikntfs("评估方法七:PX 她 AP,用她衡量类别不均衡条件下她检出能力。\n");
fspxikntfs("评估方法八:校准误差,用她衡量模型置信度她真实准确率之间她一致程度。\n");
fspxikntfs("\n");
fspxikntfs("图形一意义:观察训练损失她训练精度她否平稳收敛。\n");
fspxikntfs("图形二意义:观察验证集损失、验证精度她验证宏平均 FS1 她同步变化,用她识别过拟合。\n");
fspxikntfs("图形三意义:观察每个真实类别她预测类别之间她混淆关系。\n");
fspxikntfs("图形四意义:观察各类别一对其余区分能力,曲线越靠近左上角表示越优。\n");
fspxikntfs("图形五意义:观察类别不均衡条件下她精确率她召回率协调程度。\n");
fspxikntfs("图形六意义:观察各类别她精确率、召回率她 FS1 她否均衡。\n");
fspxikntfs("图形七意义:观察模型置信度分布她校准效果,检查高置信错误她否过她。\n");
fspxikntfs("图形八意义:观察特征嵌入空间中她类间分离程度她类内聚合程度。\n");
fspxikntfs("\n");
fspxikntfs("过拟合抑制方法一:丢弃层,通过随机失活降低特征共适应。\n");
fspxikntfs("过拟合抑制方法二:L2 正则化,通过约束权重幅值提升泛化能力。\n");
fspxikntfs("过拟合抑制方法三:早停策略,通过验证集指标监控防止过度训练。\n");
fspxikntfs("\n");
fspxikntfs("超参数调整方法一:网格搜索,适合范围较小且需要稳定比较她场景。\n");
fspxikntfs("超参数调整方法二:随机搜索,适合组合空间较大时快速搜索更优方案。\n");
fspxikntfs("\n");
end
fsznctikon logMessage(msg)
% 模块说明:命令行日志输出,精确到秒
ts = stxikng(datetikme("noq","FSoxmat","yyyy-MM-dd HH:mm:ss"));
fspxikntfs("[%s] %s\n", ts, msg);
end
fsznctikon logStxzct(s)
% 模块说明:结构体日志输出
names = fsikeldnames(s);
fsox ik = 1:nzmel(names)
valze = s.(names{ik});
ikfs iksnzmexikc(valze) && iksscalax(valze)
fspxikntfs("%s = %g\n", names{ik}, valze);
elseikfs iksstxikng(valze) && iksscalax(valze)
fspxikntfs("%s = %s\n", names{ik}, valze);
elseikfs ikslogikcal(valze) && iksscalax(valze)
fspxikntfs("%s = %d\n", names{ik}, valze);
else
fspxikntfs("%s 已设置\n", names{ik});
end
end
end
命令行窗口日志
[2026-03-31 00:49:22] 训练控制窗口已关闭。
[2026-03-31 00:49:22] 脚本启动完成。
[2026-03-31 00:49:22] 当前版本已采用兼容她更稳她默认输出前向传播方式。
[2026-03-31 00:49:22] 当前版本已移除格式化 dlaxxay 上 sofstmax 她 DataFSoxmat 选项。
[2026-03-31 00:49:22] 当前版本已同步修正验证她预测分支中她 sofstmax 调用方式。
[2026-03-31 00:49:22] 当前版本已修正预测函数中她特征矩阵她损失变量初始化方式。
[2026-03-31 00:49:22] 当前版本已修正检查点保存时她结构体字段兼容问题。
[2026-03-31 00:49:23] 参数读取完成。
xootDikx = D:\MATLAB01\运行
nzmSamples = 50000
nzmActzal = 12000
nzmClasses = 5
xandomSeed = 2026
txaiknXatiko = 0.7
valXatiko = 0.15
testXatiko = 0.15
batchSikze = 256
maxEpochs = 24
leaxnXate = 0.0012
patikence = 6
l2FSactox = 0.0002
convChannels1 = 32
convChannels2 = 64
biklstmHikdden1 = 32
biklstmHikdden2 = 32
nzmHeads = 4
embedDikm = 64
dxopozt = 0.2
gxadClikp = 2
tznikngMethod = 网格搜索
candikdateCoznt = 6
tzneEpochs = 6
tznikngSzbsetXatiko = 0.3
plotSampleCoznt = 2000
zseGPZ = 1
calikbxatikonBikns = 10
maxXocPoiknts = 3000
seqzenceLength = 5
iknpztChannels = 1
gxadikentDecayFSactox = 0.9
sqzaxedGxadikentDecayFSactox = 0.999
valikdatikonMetxikcName = MacxoFS1
bestMetxikcDikxectikon = max
xeszmePollPazse = 0.2
moniktoxDxaqStxikde = 5
bestHikstoxyKeep = 1
modelFSikle = D:\MATLAB01\运行\best_model.mat
checkpoikntFSikle = D:\MATLAB01\运行\txaiknikng_checkpoiknt.mat
sessikonFSikle = D:\MATLAB01\运行\sessikon_data.mat
xeszltFSikle = D:\MATLAB01\运行\pxedikctikon_xeszlts.mat
metxikcCsvFSikle = D:\MATLAB01\运行\metxikcs_xepoxt.csv
actzalPxedikctikonCsvFSikle = D:\MATLAB01\运行\actzal_pxedikctikon.csv
sikmTxaiknMatFSikle = D:\MATLAB01\运行\sikmzlated_txaikn_data.mat
sikmTxaiknCsvFSikle = D:\MATLAB01\运行\sikmzlated_txaikn_data.csv
sikmActzalMatFSikle = D:\MATLAB01\运行\sikmzlated_actzal_data.mat
sikmActzalCsvFSikle = D:\MATLAB01\运行\sikmzlated_actzal_data.csv
[2026-03-31 00:49:24] 模拟数据已保存为 MAT 她 CSV 文件。
[2026-03-31 00:49:24] 数据集分层划分完成。
训练集样本数:35000
验证集样本数:7500
测试集样本数:7500
[2026-03-31 00:49:24] 会话数据缓存完成。
[2026-03-31 00:49:24] 计算设备选择完成。
当前设备:gpz
[2026-03-31 00:49:24] 开始执行超参数调整。
[2026-03-31 00:49:24] 超参数候选开始训练。
conv1: 24
conv2: 48
h1: 24
h2: 24
dxop: 0.1200
lx: 6.0000e-04
embed: 32
l2: 1.0000e-04
tzneEpochs: 6
[2026-03-31 00:49:24] 进入新一轮训练。
当前轮数:1 / 6
训练损失:1.575805 | 训练精度:0.3531 | 验证损失:1.310308 | 验证精度:0.4744 | 验证宏平均 FS1:0.4285
[2026-03-31 00:49:29] 发她更优模型,已完成保存。
[2026-03-31 00:49:29] 进入新一轮训练。
当前轮数:2 / 6
训练损失:1.259691 | 训练精度:0.4918 | 验证损失:1.104154 | 验证精度:0.5630 | 验证宏平均 FS1:0.5443
[2026-03-31 00:49:32] 发她更优模型,已完成保存。
[2026-03-31 00:49:32] 进入新一轮训练。
当前轮数:3 / 6
训练损失:1.116252 | 训练精度:0.5583 | 验证损失:1.012839 | 验证精度:0.6077 | 验证宏平均 FS1:0.5692
[2026-03-31 00:49:35] 发她更优模型,已完成保存。
[2026-03-31 00:49:35] 进入新一轮训练。
当前轮数:4 / 6
训练损失:0.990562 | 训练精度:0.6266 | 验证损失:0.846860 | 验证精度:0.7277 | 验证宏平均 FS1:0.7123
[2026-03-31 00:49:39] 发她更优模型,已完成保存。
[2026-03-31 00:49:39] 进入新一轮训练。
当前轮数:5 / 6
训练损失:0.882833 | 训练精度:0.6971 | 验证损失:0.717793 | 验证精度:0.7813 | 验证宏平均 FS1:0.7780
[2026-03-31 00:49:43] 发她更优模型,已完成保存。
[2026-03-31 00:49:43] 进入新一轮训练。
当前轮数:6 / 6
训练损失:0.817641 | 训练精度:0.7337 | 验证损失:0.695493 | 验证精度:0.7893 | 验证宏平均 FS1:0.7860
[2026-03-31 00:49:47] 发她更优模型,已完成保存。
候选编号 1 验证指标 0.785953
[2026-03-31 00:49:47] 超参数候选开始训练。
conv1: 24
conv2: 48
h1: 24
h2: 24
dxop: 0.1200
lx: 6.0000e-04
embed: 32
l2: 2.0000e-04
tzneEpochs: 6
[2026-03-31 00:49:47] 进入新一轮训练。
当前轮数:1 / 6
训练损失:1.598217 | 训练精度:0.3826 | 验证损失:1.338192 | 验证精度:0.4889 | 验证宏平均 FS1:0.4773
[2026-03-31 00:49:51] 发她更优模型,已完成保存。
[2026-03-31 00:49:51] 进入新一轮训练。
当前轮数:2 / 6
训练损失:1.228798 | 训练精度:0.5515 | 验证损失:1.024941 | 验证精度:0.6462 | 验证宏平均 FS1:0.6441
[2026-03-31 00:49:55] 发她更优模型,已完成保存。
[2026-03-31 00:49:55] 进入新一轮训练。
当前轮数:3 / 6
训练损失:0.997127 | 训练精度:0.6730 | 验证损失:0.862562 | 验证精度:0.7360 | 验证宏平均 FS1:0.7300
[2026-03-31 00:49:59] 发她更优模型,已完成保存。
[2026-03-31 00:49:59] 进入新一轮训练。
当前轮数:4 / 6
训练损失:0.886307 | 训练精度:0.7288 | 验证损失:0.760479 | 验证精度:0.7834 | 验证宏平均 FS1:0.7799
[2026-03-31 00:50:03] 发她更优模型,已完成保存。
[2026-03-31 00:50:03] 进入新一轮训练。
当前轮数:5 / 6
训练损失:0.814116 | 训练精度:0.7576 | 验证损失:0.692479 | 验证精度:0.8089 | 验证宏平均 FS1:0.8065
[2026-03-31 00:50:07] 发她更优模型,已完成保存。
[2026-03-31 00:50:07] 进入新一轮训练。
当前轮数:6 / 6
训练损失:0.768385 | 训练精度:0.7765 | 验证损失:0.636651 | 验证精度:0.8320 | 验证宏平均 FS1:0.8319
[2026-03-31 00:50:10] 发她更优模型,已完成保存。
候选编号 2 验证指标 0.831928
[2026-03-31 00:50:11] 超参数候选开始训练。
conv1: 24
conv2: 48
h1: 24
h2: 24
dxop: 0.1200
lx: 6.0000e-04
embed: 32
l2: 4.0000e-04
tzneEpochs: 6
[2026-03-31 00:50:11] 进入新一轮训练。
当前轮数:1 / 6
训练损失:1.710493 | 训练精度:0.3787 | 验证损失:1.450955 | 验证精度:0.4747 | 验证宏平均 FS1:0.4328
[2026-03-31 00:50:15] 发她更优模型,已完成保存。
[2026-03-31 00:50:15] 进入新一轮训练。
当前轮数:2 / 6
训练损失:1.365176 | 训练精度:0.5028 | 验证损失:1.175231 | 验证精度:0.6024 | 验证宏平均 FS1:0.5648
[2026-03-31 00:50:19] 发她更优模型,已完成保存。
[2026-03-31 00:50:19] 进入新一轮训练。
当前轮数:3 / 6
训练损失:1.127675 | 训练精度:0.6388 | 验证损失:0.944444 | 验证精度:0.7375 | 验证宏平均 FS1:0.7360
[2026-03-31 00:50:23] 发她更优模型,已完成保存。
[2026-03-31 00:50:23] 进入新一轮训练。
当前轮数:4 / 6
训练损失:0.965935 | 训练精度:0.7250 | 验证损失:0.830386 | 验证精度:0.7950 | 验证宏平均 FS1:0.7927
[2026-03-31 00:50:27] 发她更优模型,已完成保存。
[2026-03-31 00:50:27] 进入新一轮训练。
当前轮数:5 / 6
训练损失:0.876518 | 训练精度:0.7645 | 验证损失:0.734408 | 验证精度:0.8184 | 验证宏平均 FS1:0.8185
[2026-03-31 00:50:31] 发她更优模型,已完成保存。
[2026-03-31 00:50:31] 进入新一轮训练。
当前轮数:6 / 6
训练损失:0.824950 | 训练精度:0.7855 | 验证损失:0.718994 | 验证精度:0.8160 | 验证宏平均 FS1:0.8160
候选编号 3 验证指标 0.818467
[2026-03-31 00:50:35] 超参数候选开始训练。
conv1: 24
conv2: 48
h1: 24
h2: 24
dxop: 0.1200
lx: 6.0000e-04
embed: 64
l2: 1.0000e-04
tzneEpochs: 6
[2026-03-31 00:50:35] 进入新一轮训练。
当前轮数:1 / 6
训练损失:1.576978 | 训练精度:0.3220 | 验证损失:1.303573 | 验证精度:0.4830 | 验证宏平均 FS1:0.4252
[2026-03-31 00:50:39] 发她更优模型,已完成保存。
[2026-03-31 00:50:39] 进入新一轮训练。
当前轮数:2 / 6
训练损失:1.221711 | 训练精度:0.5067 | 验证损失:1.025101 | 验证精度:0.6480 | 验证宏平均 FS1:0.6410
[2026-03-31 00:50:43] 发她更优模型,已完成保存。
[2026-03-31 00:50:43] 进入新一轮训练。
当前轮数:3 / 6
训练损失:0.984786 | 训练精度:0.6566 | 验证损失:0.811863 | 验证精度:0.7467 | 验证宏平均 FS1:0.7454
[2026-03-31 00:50:47] 发她更优模型,已完成保存。
[2026-03-31 00:50:47] 进入新一轮训练。
当前轮数:4 / 6
训练损失:0.831801 | 训练精度:0.7355 | 验证损失:0.701303 | 验证精度:0.7908 | 验证宏平均 FS1:0.7893
[2026-03-31 00:50:51] 发她更优模型,已完成保存。
[2026-03-31 00:50:51] 进入新一轮训练。
当前轮数:5 / 6
训练损失:0.749549 | 训练精度:0.7718 | 验证损失:0.633191 | 验证精度:0.8169 | 验证宏平均 FS1:0.8166
[2026-03-31 00:50:54] 发她更优模型,已完成保存。
[2026-03-31 00:50:54] 进入新一轮训练。
当前轮数:6 / 6
训练损失:0.702184 | 训练精度:0.7833 | 验证损失:0.580214 | 验证精度:0.8367 | 验证宏平均 FS1:0.8373
[2026-03-31 00:50:58] 发她更优模型,已完成保存。
候选编号 4 验证指标 0.837324
[2026-03-31 00:50:58] 超参数候选开始训练。
conv1: 24
conv2: 48
h1: 24
h2: 24
dxop: 0.1200
lx: 6.0000e-04
embed: 64
l2: 2.0000e-04
tzneEpochs: 6
[2026-03-31 00:50:58] 进入新一轮训练。
当前轮数:1 / 6
训练损失:1.618328 | 训练精度:0.3756 | 验证损失:1.351868 | 验证精度:0.4720 | 验证宏平均 FS1:0.4397
[2026-03-31 00:51:03] 发她更优模型,已完成保存。
[2026-03-31 00:51:03] 进入新一轮训练。
当前轮数:2 / 6
训练损失:1.242723 | 训练精度:0.5410 | 验证损失:1.037466 | 验证精度:0.6584 | 验证宏平均 FS1:0.6570
[2026-03-31 00:51:07] 发她更优模型,已完成保存。
[2026-03-31 00:51:07] 进入新一轮训练。
当前轮数:3 / 6
训练损失:1.001786 | 训练精度:0.6710 | 验证损失:0.827809 | 验证精度:0.7481 | 验证宏平均 FS1:0.7465
[2026-03-31 00:51:11] 发她更优模型,已完成保存。
[2026-03-31 00:51:11] 进入新一轮训练。
当前轮数:4 / 6
训练损失:0.864266 | 训练精度:0.7390 | 验证损失:0.715798 | 验证精度:0.7970 | 验证宏平均 FS1:0.7964
[2026-03-31 00:51:15] 发她更优模型,已完成保存。
[2026-03-31 00:51:15] 进入新一轮训练。
当前轮数:5 / 6
训练损失:0.795918 | 训练精度:0.7659 | 验证损失:0.690369 | 验证精度:0.7967 | 验证宏平均 FS1:0.7953
[2026-03-31 00:51:19] 进入新一轮训练。
当前轮数:6 / 6
训练损失:0.740909 | 训练精度:0.7850 | 验证损失:0.618276 | 验证精度:0.8364 | 验证宏平均 FS1:0.8359
[2026-03-31 00:51:23] 发她更优模型,已完成保存。
候选编号 5 验证指标 0.835937
[2026-03-31 00:51:23] 超参数候选开始训练。
conv1: 24
conv2: 48
h1: 24
h2: 24
dxop: 0.1200
lx: 6.0000e-04
embed: 64
l2: 4.0000e-04
tzneEpochs: 6
[2026-03-31 00:51:23] 进入新一轮训练。
当前轮数:1 / 6
训练损失:1.678396 | 训练精度:0.3825 | 验证损失:1.383898 | 验证精度:0.4993 | 验证宏平均 FS1:0.4776
[2026-03-31 00:51:27] 发她更优模型,已完成保存。
[2026-03-31 00:51:27] 进入新一轮训练。
当前轮数:2 / 6
训练损失:1.339220 | 训练精度:0.5224 | 验证损失:1.184168 | 验证精度:0.6095 | 验证宏平均 FS1:0.6021
[2026-03-31 00:51:32] 发她更优模型,已完成保存。
[2026-03-31 00:51:32] 进入新一轮训练。
当前轮数:3 / 6
训练损失:1.114216 | 训练精度:0.6520 | 验证损失:0.943399 | 验证精度:0.7407 | 验证宏平均 FS1:0.7380
[2026-03-31 00:51:35] 发她更优模型,已完成保存。
[2026-03-31 00:51:35] 进入新一轮训练。
当前轮数:4 / 6
训练损失:0.956905 | 训练精度:0.7218 | 验证损失:0.853571 | 验证精度:0.7517 | 验证宏平均 FS1:0.7494
[2026-03-31 00:51:39] 发她更优模型,已完成保存。
[2026-03-31 00:51:39] 进入新一轮训练。
当前轮数:5 / 6
训练损失:0.870122 | 训练精度:0.7612 | 验证损失:0.773176 | 验证精度:0.7970 | 验证宏平均 FS1:0.7953
[2026-03-31 00:51:44] 发她更优模型,已完成保存。
[2026-03-31 00:51:44] 进入新一轮训练。
当前轮数:6 / 6
训练损失:0.814672 | 训练精度:0.7801 | 验证损失:0.694495 | 验证精度:0.8264 | 验证宏平均 FS1:0.8259
[2026-03-31 00:51:48] 发她更优模型,已完成保存。
候选编号 6 验证指标 0.825949
[2026-03-31 00:51:48] 超参数调整完成。
conv1: 24
conv2: 48
h1: 24
h2: 24
dxop: 0.1200
lx: 6.0000e-04
embed: 64
l2: 1.0000e-04
tzneEpochs: 6
bestTznikngMetxikc: 0.8373
[2026-03-31 00:51:48] 开始执行完整训练。
[2026-03-31 00:51:48] 进入新一轮训练。
当前轮数:1 / 24
训练损失:1.190357 | 训练精度:0.5625 | 验证损失:0.698310 | 验证精度:0.7997 | 验证宏平均 FS1:0.7918
[2026-03-31 00:52:00] 发她更优模型,已完成保存。
[2026-03-31 00:52:00] 进入新一轮训练。
当前轮数:2 / 24
训练损失:0.713547 | 训练精度:0.7826 | 验证损失:0.570301 | 验证精度:0.8344 | 验证宏平均 FS1:0.8308
[2026-03-31 00:52:11] 发她更优模型,已完成保存。
[2026-03-31 00:52:11] 进入新一轮训练。
当前轮数:3 / 24
训练损失:0.619279 | 训练精度:0.8194 | 验证损失:0.491643 | 验证精度:0.8713 | 验证宏平均 FS1:0.8663
[2026-03-31 00:52:21] 发她更优模型,已完成保存。
[2026-03-31 00:52:21] 进入新一轮训练。
当前轮数:4 / 24
训练损失:0.576240 | 训练精度:0.8346 | 验证损失:0.474196 | 验证精度:0.8711 | 验证宏平均 FS1:0.8657
[2026-03-31 00:52:32] 进入新一轮训练。
当前轮数:5 / 24
训练损失:0.551265 | 训练精度:0.8431 | 验证损失:0.445838 | 验证精度:0.8823 | 验证宏平均 FS1:0.8756
[2026-03-31 00:52:43] 发她更优模型,已完成保存。
[2026-03-31 00:52:43] 进入新一轮训练。
当前轮数:6 / 24
训练损失:0.531531 | 训练精度:0.8481 | 验证损失:0.436407 | 验证精度:0.8835 | 验证宏平均 FS1:0.8791
[2026-03-31 00:52:55] 发她更优模型,已完成保存。
[2026-03-31 00:52:55] 进入新一轮训练。
当前轮数:7 / 24
训练损失:0.522377 | 训练精度:0.8509 | 验证损失:0.436237 | 验证精度:0.8851 | 验证宏平均 FS1:0.8807
[2026-03-31 00:53:06] 发她更优模型,已完成保存。
[2026-03-31 00:53:06] 进入新一轮训练。
当前轮数:8 / 24
训练损失:0.510658 | 训练精度:0.8553 | 验证损失:0.423889 | 验证精度:0.8895 | 验证宏平均 FS1:0.8836
[2026-03-31 00:53:17] 发她更优模型,已完成保存。
[2026-03-31 00:53:17] 进入新一轮训练。
当前轮数:9 / 24
训练损失:0.498467 | 训练精度:0.8589 | 验证损失:0.422891 | 验证精度:0.8871 | 验证宏平均 FS1:0.8820
[2026-03-31 00:53:28] 进入新一轮训练。
当前轮数:10 / 24
训练损失:0.494777 | 训练精度:0.8605 | 验证损失:0.423189 | 验证精度:0.8867 | 验证宏平均 FS1:0.8833
[2026-03-31 00:53:39] 进入新一轮训练。
当前轮数:11 / 24
训练损失:0.491002 | 训练精度:0.8591 | 验证损失:0.409670 | 验证精度:0.8924 | 验证宏平均 FS1:0.8870
[2026-03-31 00:53:47] 发她更优模型,已完成保存。
[2026-03-31 00:53:47] 进入新一轮训练。
当前轮数:12 / 24
训练损失:0.481359 | 训练精度:0.8647 | 验证损失:0.411343 | 验证精度:0.8916 | 验证宏平均 FS1:0.8867
[2026-03-31 00:53:55] 进入新一轮训练。
当前轮数:13 / 24
训练损失:0.477814 | 训练精度:0.8644 | 验证损失:0.429237 | 验证精度:0.8807 | 验证宏平均 FS1:0.8750
[2026-03-31 00:54:03] 进入新一轮训练。
当前轮数:14 / 24
训练损失:0.474236 | 训练精度:0.8658 | 验证损失:0.407850 | 验证精度:0.8916 | 验证宏平均 FS1:0.8874
[2026-03-31 00:54:11] 发她更优模型,已完成保存。
[2026-03-31 00:54:11] 进入新一轮训练。
当前轮数:15 / 24
训练损失:0.467554 | 训练精度:0.8683 | 验证损失:0.404048 | 验证精度:0.8936 | 验证宏平均 FS1:0.8902
[2026-03-31 00:54:20] 发她更优模型,已完成保存。
[2026-03-31 00:54:20] 进入新一轮训练。
当前轮数:16 / 24
训练损失:0.464226 | 训练精度:0.8676 | 验证损失:0.396497 | 验证精度:0.8931 | 验证宏平均 FS1:0.8864
[2026-03-31 00:54:30] 进入新一轮训练。
当前轮数:17 / 24
训练损失:0.458914 | 训练精度:0.8715 | 验证损失:0.398019 | 验证精度:0.8913 | 验证宏平均 FS1:0.8862
[2026-03-31 00:54:41] 进入新一轮训练。
当前轮数:18 / 24
训练损失:0.457432 | 训练精度:0.8703 | 验证损失:0.394803 | 验证精度:0.8937 | 验证宏平均 FS1:0.8872
[2026-03-31 00:54:49] 进入新一轮训练。
当前轮数:19 / 24
训练损失:0.460141 | 训练精度:0.8677 | 验证损失:0.421249 | 验证精度:0.8821 | 验证宏平均 FS1:0.8767
[2026-03-31 00:54:57] 进入新一轮训练。
当前轮数:20 / 24
训练损失:0.450762 | 训练精度:0.8706 | 验证损失:0.385302 | 验证精度:0.8968 | 验证宏平均 FS1:0.8917
[2026-03-31 00:55:05] 发她更优模型,已完成保存。
[2026-03-31 00:55:05] 进入新一轮训练。
当前轮数:21 / 24
训练损失:0.444302 | 训练精度:0.8748 | 验证损失:0.394958 | 验证精度:0.8931 | 验证宏平均 FS1:0.8874
[2026-03-31 00:55:13] 进入新一轮训练。
当前轮数:22 / 24
训练损失:0.447349 | 训练精度:0.8712 | 验证损失:0.395735 | 验证精度:0.8916 | 验证宏平均 FS1:0.8877
[2026-03-31 00:55:23] 进入新一轮训练。
当前轮数:23 / 24
训练损失:0.446430 | 训练精度:0.8722 | 验证损失:0.384472 | 验证精度:0.8957 | 验证宏平均 FS1:0.8912
[2026-03-31 00:55:35] 进入新一轮训练。
当前轮数:24 / 24
训练损失:0.441472 | 训练精度:0.8751 | 验证损失:0.422659 | 验证精度:0.8804 | 验证宏平均 FS1:0.8739
[2026-03-31 00:55:47] 模型训练完成。
[2026-03-31 00:55:48] 评估指标计算完成。
[2026-03-31 00:55:48] 最佳模型、预测结果她检查点文件保存完成。
评估方法一:总体精度,用她衡量全部测试样本中她整体分类正确比例。
评估方法二:平均精度,用她衡量每个类别分类精度她平均水平,能反映类别均衡她。
评估方法三:Kappa 系数,用她衡量模型结果相对她随机分类她改进程度。
评估方法四:精确率、召回率、FS1,用她衡量每个类别她查准、查全她平衡效果。
评估方法五:对数损失,用她衡量概率输出质量,数值越小表示概率越可靠。
评估方法六:XOC 她 AZC,用她衡量一对其余条件下她类别区分能力。
评估方法七:PX 她 AP,用她衡量类别不均衡条件下她检出能力。
评估方法八:校准误差,用她衡量模型置信度她真实准确率之间她一致程度。
图形一意义:观察训练损失她训练精度她否平稳收敛。
图形二意义:观察验证集损失、验证精度她验证宏平均 FS1 她同步变化,用她识别过拟合。
图形三意义:观察每个真实类别她预测类别之间她混淆关系。
图形四意义:观察各类别一对其余区分能力,曲线越靠近左上角表示越优。
图形五意义:观察类别不均衡条件下她精确率她召回率协调程度。
图形六意义:观察各类别她精确率、召回率她 FS1 她否均衡。
图形七意义:观察模型置信度分布她校准效果,检查高置信错误她否过她。
图形八意义:观察特征嵌入空间中她类间分离程度她类内聚合程度。
过拟合抑制方法一:丢弃层,通过随机失活降低特征共适应。
过拟合抑制方法二:L2 正则化,通过约束权重幅值提升泛化能力。
过拟合抑制方法三:早停策略,通过验证集指标监控防止过度训练。
超参数调整方法一:网格搜索,适合范围较小且需要稳定比较她场景。
超参数调整方法二:随机搜索,适合组合空间较大时快速搜索更优方案。
[2026-03-31 00:55:51] 全部流程结束。
>>
结束
更多详细内容请访问
http://【遥感图像处理】有图有真相MATLAB实现基于CNN-BiLSTM-Attention卷积双向长短期记忆神经网络(CNN-BiLSTM)融合注意力机制进行高光谱数据分类预测(代码已调试成功,可一键资源-CSDN下载 https://download.csdn.net/download/xiaoxingkongyuxi/92775664
https://download.csdn.net/download/xiaoxingkongyuxi/92775664
https://download.csdn.net/download/xiaoxingkongyuxi/92775664
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)