2026/4/6 16:10:12
网站建设
项目流程
基于灰狼优化长短期记忆网络(GWO-LSTM)的数据分类预测 优化参数为学习率隐藏层节点个数正则化参数要求2019及以上版本加入交叉验证抑制过拟合 matlab代码害谁懂啊调LSTM参数调到凌晨两点学习率试了一堆隐藏层节点数从10试到100正则化系数更是试了好几个数量级最后还是过拟合了…直到后来发现用灰狼优化自动找参数简直是救大命基于灰狼优化长短期记忆网络(GWO-LSTM)的数据分类预测 优化参数为学习率隐藏层节点个数正则化参数要求2019及以上版本加入交叉验证抑制过拟合 matlab代码今天就给大家整一个基于Matlab的GWO-LSTM分类预测脚本完全适配2019及以上版本还加了交叉验证压过拟合优化的就是咱们最头疼的三个参数学习率、隐藏层节点个数、正则化参数代码直接复制就能跑不用瞎改太多。先唠唠整体思路说白了就是用灰狼算法(GWO)当“调参工具人”给它一堆参数搜索范围让它自己试试完选出准确率最高的那组参数再用最优参数搭LSTM模型最后用交叉验证确保模型不会瞎拟合训练集。直接上代码边看边唠首先先清场检查版本别用旧版本跑报错% 清理工作区和命令行 clear;clc;close all % 强制要求Matlab2019及以上不然深度学习工具箱的函数不兼容 assert(version(-release) 2019, 请使用Matlab 2019及以上版本);这里就是先把之前的垃圾数据清掉再卡一下版本省得有人用2018a跑半天报错找不到函数。接下来生成模拟的时序分类数据懒得找真实数据集的直接用这个想换自己的真实数据也很简单把X和Y替换成你的数据就行% 生成模拟时序分类数据集 numSamples 1000; % 总样本数 timeSteps 10; % 每个样本的时间步长 numFeatures 3; % 每个时间步的特征数 numClasses 2; % 分类类别数二分类就设2 % 随机生成特征和标签模拟真实的时序数据 X randn(numSamples, timeSteps, numFeatures); % 生成0/1标签转成one-hot编码适配LSTM分类 Y randi([0,1], numSamples, 1); Y onehotencode(Y, 2);这里解释一下时序数据必须是[样本数, 时间步, 特征数]的格式别搞反了不然trainNetwork会报错。然后设置灰狼优化的基础参数还有咱们要优化的三个参数的搜索范围% 灰狼优化核心参数 popSize 10; % 狼群种群数越多找的越准但越慢 maxIter 20; % 最大迭代次数迭代够了就停 % 待优化参数的搜索范围自己可以根据任务改 % 第一行学习率lr范围1e-4到1e-2 % 第二行隐藏层节点数范围10到100必须整数后面会取整 % 第三行L2正则化系数范围1e-5到1e-2 paramRange [1e-4, 1e-2; 10, 100; 1e-5, 1e-2]; dim size(paramRange,1); % 参数维度固定3个这仨搜索范围都是凭经验拍的要是你的数据集特别大可以把隐藏层节点数上限调到200学习率也可以放宽到1e-3。重头戏来了适应度函数说白了就是给灰狼一组参数让它训练LSTM然后返回交叉验证的准确率准确率越高说明这组参数越好function acc fitnessFunc(params, X, Y) % 解析当前要测试的三组参数 lr params(1); hiddenSize round(params(2)); % 隐藏层节点必须是整数强制取整 lambda params(3); % 搭建基础LSTM分类网络结构 layers [ sequenceInputLayer(size(X,3)) % 输入层匹配特征数 lstmLayer(hiddenSize,OutputMode,last) % LSTM层只取最后一个时间步的输出做分类 fullyConnectedLayer(numClasses) % 全连接层输出分类结果 softmaxLayer % 概率归一化 classificationLayer % 分类层 ]; % 训练选项把优化参数塞进去 trainOpts trainingOptions(adam, ... InitialLearnRate, lr, ... % 传入学习率 L2Regularization, lambda, ... % 传入正则化系数 MaxEpochs, 20, ... % 训练轮次 MiniBatchSize, 32, ... % 批次大小 Verbose, 0, ... % 不打印训练日志看着烦 Plots, none); % 不画训练进度图 % 5折交叉验证彻底抑制过拟合 cv cvpartition(size(Y,1), KFold,5); totalAcc 0; for fold 1:cv.NumFolds % 划分每折的训练集和测试集 trainIdx cv.training(fold); testIdx cv.test(fold); XTrain X(trainIdx,:,:); YTrain Y(trainIdx,:); XTest X(testIdx,:,:); YTest Y(testIdx,:); % 训练当前折的模型 net trainNetwork(XTrain, YTrain, layers, trainOpts); % 预测测试集 YPred classify(net, XTest); % 把one-hot标签转成原始标签计算准确率 YTestLabel onehotdecode(YTest, [0;1],2); totalAcc totalAcc sum(YPred YTestLabel)/length(YTestLabel); end % 返回5折平均准确率作为适应度 acc totalAcc / cv.NumFolds; end这里踩过最坑的一点就是隐藏层节点必须是整数所以特意加了round之前没加的时候直接报错整得我愣了半天。还有交叉验证这里每折都重新训练一次避免了单次划分数据集的随机性彻底把过拟合摁死在摇篮里。接下来就是灰狼算法的主循环让狼群自己迭代找最优参数% 初始化狼群种群随机生成在参数搜索范围内 wolfPop rand(popSize, dim) .* (paramRange(:,2) - paramRange(:,1)) paramRange(:,1); % 初始化三只领头狼alpha最优beta次优delta第三优 alphaScore -inf; alphaPos zeros(1,dim); betaScore -inf; betaPos zeros(1,dim); deltaScore -inf; deltaPos zeros(1,dim); % 记录每一代的最优准确率用来画收敛图 accCurve zeros(1,maxIter); % 开始迭代找参数 for iter 1:maxIter % 计算每只狼的适应度更新领头狼 for i 1:popSize currentAcc fitnessFunc(wolfPop(i,:), X, Y); % 更新三只领头狼的位置和得分 if currentAcc alphaScore deltaScore betaScore; deltaPos betaPos; betaScore alphaScore; betaPos alphaPos; alphaScore currentAcc; alphaPos wolfPop(i,:); elseif currentAcc betaScore deltaScore betaScore; deltaPos betaPos; betaScore currentAcc; betaPos wolfPop(i,:); elseif currentAcc deltaScore deltaScore currentAcc; deltaPos wolfPop(i,:); end end % 更新所有狼的位置收敛因子从2线性降到0前期广撒网后期精准找 a 2 - iter*(2/maxIter); for i 1:popSize for j 1:dim % 三只领头狼的位置影响 r1 rand(); r2 rand(); A1 2*a*r1 -a; C1 2*r2; D_alpha abs(C1*alphaPos(j) - wolfPop(i,j)); X1 alphaPos(j) - A1*D_alpha; r1 rand(); r2 rand(); A2 2*a*r1 -a; C2 2*r2; D_beta abs(C2*betaPos(j) - wolfPop(i,j)); X2 betaPos(j) - A2*D_beta; r1 rand(); r2 rand(); A3 2*a*r1 -a; C3 2*r2; D_delta abs(C3*deltaPos(j) - wolfPop(i,j)); X3 deltaPos(j) - A3*D_delta; % 综合三只狼的位置更新当前狼的位置 wolfPop(i,j) (X1 X2 X3)/3; % 把参数限制在搜索范围内别跑出合理区间 wolfPop(i,j) max(wolfPop(i,j), paramRange(j,1)); wolfPop(i,j) min(wolfPop(i,j), paramRange(j,2)); end end % 记录当前代的最优准确率 accCurve(iter) alphaScore; fprintf(迭代第%d次当前最优准确率%.4f\n, iter, alphaScore); end这段就是标准的灰狼算法流程不用改太多直接用就行每迭代一次都会打印当前的最优准确率你能看到准确率慢慢上升最后趋于平稳说明已经找到最优参数了。最后就是输出最优参数画收敛图再用最优参数训练最终模型% 打印最终找到的最优参数 fprintf(\n最优参数\n); fprintf(最优学习率%.6f\n, alphaPos(1)); fprintf(最优隐藏层节点数%d\n, round(alphaPos(2))); fprintf(最优正则化系数%.6f\n, alphaPos(3)); fprintf(交叉验证最优平均准确率%.4f\n, alphaScore); % 画收敛曲线看看有没有收敛 figure(Name,GWO优化收敛曲线); plot(accCurve,LineWidth,2); xlabel(迭代次数); ylabel(交叉验证平均准确率); title(灰狼优化LSTM参数收敛过程); grid on; % 用最优参数训练最终全量模型 bestLR alphaPos(1); bestHiddenSize round(alphaPos(2)); bestLambda alphaPos(3); finalLayers [ sequenceInputLayer(size(X,3)) lstmLayer(bestHiddenSize,OutputMode,last) fullyConnectedLayer(numClasses) softmaxLayer classificationLayer ]; finalOpts trainingOptions(adam, ... InitialLearnRate, bestLR, ... L2Regularization, bestLambda, ... MaxEpochs, 30, ... MiniBatchSize, 32, ... Verbose, 1, ... Plots, training-progress); % 用全量数据训练最终模型 finalNet trainNetwork(X, Y, finalLayers, finalOpts); % 划分20%的数据当独立测试集验证最终效果 cvTest cvpartition(numSamples,Holdout,0.2); XTestFinal X(cvTest.test,:,:); YTestFinal Y(cvTest.test,:); YPredFinal classify(finalNet, XTestFinal); YTestFinalLabel onehotdecode(YTestFinal, [0;1],2); finalAcc sum(YPredFinal YTestFinalLabel)/length(YTestFinalLabel); fprintf(\n最终模型在独立测试集上的准确率%.4f\n, finalAcc);这里把收敛图画出来之后你能看到大概迭代到10次左右准确率就不再涨了说明已经找到了最优参数。最后用独立测试集验证一下要是准确率和交叉验证的差不多就说明模型没 overfit。一些碎碎念的注意事项要是跑的时候报错说找不到工具箱记得确认装了Matlab的深度学习工具箱2019b之后自带的LSTM支持已经很完善了模拟数据是随机生成的每次跑的结果不一样换真实数据集比如UCI的HAR人体活动识别数据集效果会好很多种群数和迭代次数可以自己调比如popSize设15maxIter设30找参数会更快但也更耗时间要是多分类任务只需要改numClasses的数值就行标签会自动适配要是还是过拟合可以加大正则化系数或者多加点训练数据整个脚本跑下来大概十几分钟看你的电脑配置再也不用手动调参调到秃头了亲测比瞎试参数效果好太多