专栏近期有大量优惠 还请多多点一下关注 加油 谢谢 你的鼓励是我前行的动力 谢谢支持 加油 谢谢
有图有真相 请注意所有代码结构内容都在这里了 这个只是有些汉字和字母做了替代 未替代内容可以详谈 请直接联系博主本人或者访问对应标题的完整文档下载页面

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

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

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

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

目录

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

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

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

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

项目实际效果图... 1

MATLAB实现基于CNN-BiLSTM-Attention卷积双向长短期记忆神经网络(CNN-BiLSTM)融合注意力机制进行高光谱数据分类预测... 9

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

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

命令行窗口日志... 112

结束... 123

项目实际效果图

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) % 定义全部评估指标计算函数

% 模块说明:计算总体精度、宏平均指标、每类指标、KappaXOCPX、校准误差等

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)

% 模块说明:计算总体精度、宏平均指标、每类指标、KappaXOCPX、校准误差等

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

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐