遗传算法GA优化极限学习机ELM预测的MATLAB实现
2026/9/11 20:08:56 网站建设 项目流程

简介:遗传算法(GA)优化极限学习机(ELM)的MATLAB实现代码,面向需要快速构建高精度预测模型的机器学习研究者和工程师。该资源通过模拟生物进化中的选择、交叉与变异机制,自动寻优ELM的隐藏层节点数、输入权重和偏置,克服了传统试错法效率低、易陷入局部最优的痛点。压缩包共7个文件,包含5个M脚本(主程序、适应度评估、ELM训练与预测、误差计算等)、1个MAT数据文件与1个Excel数据集,包体仅197KB,结构清晰便于复用。目前已有641人学习下载,代码提供了完整的GA-ELM流程注释,用户只需将数据转为Excel格式即可运行。相比网格搜索与随机搜索,该方法利用遗传算法全局搜索能力,可挖掘更优超参数组合,从而明显提升回归或分类任务的预测精度与泛化性能,是理解群智能优化与神经网络结合的理想范例。

1. 遗传算法GA优化极限学习机预测MATLAB代码要解决的实际问题

极限学习机(ELM)一贯的卖点是“免调参、秒级训练”:输入权值和隐层偏置随机生成,输出权值用一次伪逆求出,训练一个网络只需要毫秒到秒级。但同一套代码换个随机种子,测试集R²可能从0.85掉到0.70。做光伏功率预测、用户消费预测、金融时序预测这类要交付结果的回归任务时,这种随机波动比精度本身更让人头疼。GA-ELM就是拿遗传算法(GA)把ELM的输入权值和隐层偏置从“随机碰运气”改成“种群定向搜索”,保留ELM免梯度训练的速度,同时把随机种子带来的不确定性压下去。对刚接触MATLAB优化工具箱的新手,这套流程能完整跑通一次进化优化;对有经验的数据工程师,它也是做基线对照、消融实验时最省成本的结构之一。下面对应算法契合点、可执行代码、参数调法和稳定性验证四层展开,代码以全局优化工具箱的 ga() 为主体。

2. 遗传算法GA和极限学习机的契合点:从随机走向定向搜索

2.1 ELM的矩阵解:快在哪,又哪里不稳定

极限学习机本质是单隐层前馈网络。给定输入矩阵 X(N×m),隐层节点数 L,激活函数 g,隐层输出矩阵 H(N×L)可以写成:

function H = elm_hidden(X, W, b, activ) % X: 样本x特征,已归一化 % W: L x nFeature 输入权值 % b: 1 x L 隐层偏置 H = X * W' + b; % R2016b+ 自动广播 switch activ case 'sigmoid' H = 1 ./ (1 + exp(-H)); case 'tanh' H = tanh(H); case 'relu' H = max(H, 0); end end

W 是 L×m,b 是 1×L,X 乘以 W 的转置得到 N×L,再与 b 相加时 MATLAB 会把偏置向量复制到每一行。旧版本没有自动广播,手写时建议改成H = X * W' + repmat(b, size(X,1), 1);,否则 R2016a 之前的机器会直接报维度错误。

ELM 只训练输出层:在隐层输出 H 固定的前提下,解线性方程 Hβ = T,β 的最小二乘解就是矩阵伪逆形式:

beta = pinv(H) * T;

pinv 对矩阵求 Moore-Penrose 伪逆,即使 H 不满秩也能给出最小范数解。训练过程不迭代、不反向传播,这是它比 BP 快几个数量级的原因。

不稳定就出在“W 和 b 随机”这一步。伪逆解的质量取决于 H 的列空间性质,而 H 由随机权重决定。当随机出的权重集中在激活函数饱和区,或偏置大小与输入分布不匹配时,H 的列容易近似线性相关,伪逆解的范数偏大,训练集拟合得很好,测试集泛化却明显下滑。GA 要做的不是证明某个随机初始化最优,而是用种群搜索代替单次随机猜测,在同样的 L 和激活函数下,找一组让验证误差更稳的 W、b。注意这里没有“全局最优”的保证,GA 本质上是一种工程化的定向采样,只是它的重复性远好于裸随机。

2.2 哪些参数让 GA 搜,哪些先用经验固定

GA 编码的是连续实数变量,输入权值 W 和隐层偏置 b 是首选。它们数量大、连续可调,正好匹配遗传算法的实数编码与算术交叉。下面的表是常见分工:

参数是否交给 GA理由与推荐做法
输入权值 W实数编码,范围先取 [-1,1]
隐层偏置 b与 W 分开设范围,建议 [-0.5,0.5]
隐层节点数 L经验公式sqrt(m+n)+1~10起步,再网格扫描
激活函数sigmoid 与 tanh 离线各跑一遍,别加进进化
归一化方式统一 mapminmax 到 [0,1] 或 [-1,1]

L 和激活函数本来也可以作为变量编码,但 GA 对离散整数和枚举值编码效果差,交叉变异常常产生无效个体,一百代内搜不均匀。常见做法是先固定激活函数为 sigmoid,L 从经验公式给出初值,再在 20:5:40 这样的小范围里扫一遍。这样 nvars 只等于 L×(m+1),维度可控,适应性函数也不会因为 L 变化而每次都换矩阵规模。

适应度函数在整个流程里只做一件事:解码个体、算 H、求 β、在验证集上算误差。下面这个函数就是 GA 与 ELM 之间的桥,后面主脚本直接调用:

function f = gaELM_fitness(x, Xtr, Ytr, Xva, Yva, L, activ) % 个体x排列:[W(1:L*nFeat), b(1:L)] nFeat = size(Xtr, 2); W = reshape(x(1:L*nFeat), L, nFeat); b = x(L*nFeat+1:end); Htr = elm_hidden(Xtr, W, b, activ); beta = pinv(Htr) * Ytr; % 在训练集上求输出权值 Hva = elm_hidden(Xva, W, b, activ); Yp = Hva * beta; % 验证集前向一次 f = sqrt(mean((Yva - Yp).^2)); % 适应度越小越好 end

一个容易忽略的设计是:适应度的 β 在训练集上求出,误差在验证集上计算。如果把测试集放进适应度函数,GA 的代际选择会隐式窥探测试分布,最终排名虚高。后面所有调参都同步遵守这个约定。

3. 用MATLAB从零写GA-ELM预测:主脚本与三个函数

3.1 归一化、按时间切分与滑窗构造

回归预测里数据划分要先于一切代码。分类任务可以随机打乱,时序任务不行。常见做法是按时间顺序切成三段:前 60% 训练、中间 20% 验证、最后 20% 测试。验证集用于 GA 的适应度评估和 L 的选择,测试集只在全部调优结束后用一次。

% data:N行矩阵,最后一列为待预测目标 N = size(data, 1); idxTr = 1:floor(0.6*N); idxVa = floor(0.6*N)+1:floor(0.8*N); idxTe = floor(0.8*N)+1:N; % mapminmax按行处理,需要转置 [Xn, psx] = mapminmax(X', 0, 1); Xn = Xn'; [Yn, psy] = mapminmax(Y', 0, 1); Yn = Yn'; Xtr = Xn(idxTr,:); Ytr = Yn(idxTr,:); Xva = Xn(idxVa,:); Yva = Yn(idxVa,:); Xte = Xn(idxTe,:); Yte = Yn(idxTe,:);

mapminmax 的返回值 psx、psy 要保留下来,测试集反归一化时还要用。特征列如果包含 NaN,先data = rmmissing(data);,否则伪逆计算结果全是 NaN,GA 适应度函数会直接退化,命令行里看到 fval 一直不变先查这一条。如果做多步预测,把 Y 构造成 h 列矩阵即可,每一列对应未来第几步,ELM 输出层 β 的维度自动变成 L×h,适应度函数不用改。

3.2 主脚本:变量边界与 ga() 调用参数

核心调用如下:

L = 30; % 隐层节点数,先用经验值 activ = 'sigmoid'; nFeat = size(Xtr, 2); nvars = L * (nFeat + 1); % W占L*nFeat个,b占L个 lb = [-ones(1, L*nFeat), -0.5*ones(1, L)]; ub = [ ones(1, L*nFeat), 0.5*ones(1, L)]; options = optimoptions('ga', ... 'PopulationSize', 60, ... 'MaxGenerations', 120, ... 'Display', 'iter'); rng(42); % 固定随机流,保证后续复现 [xbest, fbest] = ga(... @(x) gaELM_fitness(x, Xtr, Ytr, Xva, Yva, L, activ), ... nvars, [], [], [], [], lb, ub, [], options);

ga() 是 MATLAB 全局优化工具箱的函数,没有线性约束、等式约束和非线性约束时,对应参数全部用空矩阵占位,最后一个 options 控制进化过程。Display设为'iter'会在命令行每代打印最佳适应度,跑几十代后如果数值不动,说明种群已经收敛。R2013b 到 R2018a 之间的版本用的是gaoptimset,R2018a 之后推荐optimoptions,两者字段名也略有差异,例如Generations变成了MaxGenerations。机器上没装优化工具箱时,ga会直接报 “Undefined function”,不涉及任何算法逻辑,先确认工具箱再排查代码。

lb 和 ub 的写法有个细节:W 和 b 分开设置范围,个体向量前 L×nFeat 个分量对应 W,后 L 个对应 b。GA 默认从 lb 到 ub 之间均匀随机生成初始种群,两个范围若设成完全一样,搜索空间会膨胀,收敛反而变慢。偏置范围通常比权重范围小一半左右,这个比例对应 sigmoid 的敏感区间。

3.3 解码最优个体、全量重训与反归一化

GA 返回的是最优个体 xbest,不是训练好的模型。按常见做法,把验证集并回训练集,用最优 W、b 重新求一次 β,再对测试集做最终推断:

% 训练+验证作为最终训练集 Xall = [Xn(idxTr,:); Xn(idxVa,:)]; Yall = [Yn(idxTr,:); Yn(idxVa,:)]; W0 = reshape(xbest(1:L*nFeat), L, nFeat); b0 = xbest(L*nFeat+1:end); Hall = elm_hidden(Xall, W0, b0, activ); beta_final = pinv(Hall) * Yall; Hte = elm_hidden(Xte, W0, b0, activ); Yp_n = Hte * beta_final; Yp = mapminmax('reverse', Yp_n', psy)'; % 反归一化 RMSE = sqrt(mean((Yte - Yp).^2)); R2 = 1 - sum((Yte - Yp).^2) / sum((Yte - mean(Yte)).^2);

反归一化是踩坑重灾区。mapminmax 的作用对象是行向量,训练时对 Y' 做的变换,测试时也要先转置再 reverse、再转置回列向量。不少人在这一步直接传 Yp_n,结果数值范围完全对不上,RMSE 算出来大得离谱。beta_final用的是包含验证集的全部数据,这是合理的:验证集没有参与 GA 的逐代选择,它只被征用来重训一次最终模型,不会被复用去调别的参数。

4. GA-ELM参数设置与数据集处理:把预测误差调低的四个步骤

4.1 先扫描 L,让 GA 每次只集中干一件事

GA 的搜索质量严重依赖 nvars 大小。L 每增加 1,nvars 增加 m+1;当特征数 m 到 20 以上、L 从 20 调到 40,nvars 从 440 涨到 880,同样 120 代内搜索密度直接减半。所以不要一上来就跑 GA,先用一到两次 L 扫描确定结构。

candidateL = 20:5:40; bestL = 20; bestVal = inf; for LL = candidateL nv = LL * (nFeat + 1); lb_t = [-ones(1, LL*nFeat), -0.5*ones(1, LL)]; ub_t = [ ones(1, LL*nFeat), 0.5*ones(1, LL)]; opt_t = optimoptions('ga', 'PopulationSize', 40, ... 'MaxGenerations', 80, 'Display', 'off'); [~, fval_t] = ga(@(x) gaELM_fitness(... x, Xtr, Ytr, Xva, Yva, LL, activ), ... nv, [], [], [], [], lb_t, ub_t, [], opt_t); if fval_t < bestVal bestVal = fval_t; bestL = LL; end end

这个循环用较小的种群和代数快速定位区间,定位到 bestL 后再加大种群跑正式的那次 GA。注意验证集在这里被用了两次:一次选 L、一次在正式 GA 里当适应度数据。单次使用还能接受,如果还要再选激活函数、归一化范围,验证集就会被反复消耗。稳妥做法是再切一段独立数据专门做最终验证,或者接受工程简化的偏差,不要回过头用测试集做任何选择。

4.2 GA 自身参数的推荐表与调整顺序

GA 的默认参数能用,但预测任务有自己的经验区间,某些默认值表现平庸。下表中中间值作为第一轮配置:

参数推荐区间调整方向
PopulationSize50~80特征多、数据量大时加到 120
MaxGenerations100~200看收敛曲线,40 代不动就提前停止
交叉概率0.75~0.85默认 0.8,收敛慢可降到 0.7
变异概率0.01~0.05停滞时上调,过快震荡时下调
精英保留默认即可不建议超过种群 5%,否则容易早熟
W 范围[-1,1]输入分布区间小时放宽到 [-2,2]
b 范围[-0.5,0.5]单独缩小,不与 W 共用范围

调参顺序有一个常见误区:一上来就加大种群。每代多 20 个个体意味着多 20 次完整训练和验证前向,代价线性增长,但收益在种群达到 80 以后明显放缓。先固定种群 60,代数 120,看 fval 曲线末端是否还在下降;下降明显则加代数,曲线平了但测试误差高,再动 W 和 b 的范围。变异概率保持 0.01 到 0.03 之间即可,ELM 的伪逆解对个体变化不算特别敏感,变异过大只会让收敛段出现无规则跳跃。

提示:每代 60 个个体各做一次 pinv 计算,复杂度与样本量和 L 直接相关。样本量上万、L 超 50 时,单次迭代可能从秒级变成分钟级。先用小样本跑通逻辑,再放大数据量。

4.3 和随机ELM对比:标准差比均值更能说明问题

GA-ELM 的价值不单是“精度更高”,更是“多次重复的波动更小”。验证这一步不能只跑一次:固定随机种子跑一次容易碰运气,跑多次看分布才有说服力。用同 L、同数据划分跑 20 次随机初始化 ELM 作对照:

rng(0); rmse_elm = zeros(20, 1); for k = 1:20 Wr = rand(L, nFeat) * 2 - 1; % [-1,1] br = rand(1, L) - 0.5; % [-0.5,0.5] Htr = elm_hidden(Xtr, Wr, br, 'sigmoid'); beta_r = pinv(Htr) * Ytr; Hte = elm_hidden(Xte, Wr, br, 'sigmoid'); Ypr = mapminmax('reverse', (Hte*beta_r)', psy)'; rmse_elm(k) = sqrt(mean((Yte - Ypr).^2)); end fprintf('随机ELM : %.4f ± %.4f\n', mean(rmse_elm), std(rmse_elm));

同样的 20 次重复放到 GA-ELM 上,用不同的 rng 种子重新执行完整流程。报告结果时同时写均值和标准差,业务方关心的往往不是单次最好成绩,而是“换一天数据再跑还能不能复现”。GA-ELM 在同一数据量下的标准差通常小于随机 ELM,这是用几十代进化换来的稳定性。

如果 GA-ELM 和随机 ELM 的均值差距很小但标准差明显缩小,说明增益主要来自平稳性;如果均值也系统性下降,说明 GA 真的找到了更合理的权值分布。两种结论在项目里都成立,但要区分表述。

5. 让GA-ELM下场前可靠的三个进阶验证技巧

5.1 固定随机流,把重复实验作为验收门槛

rng(42)只能保证同一次实验可复现,不能证明算法稳定。更严格的做法是跑 10 到 20 次完整流程,每次换一个种子但保持种子可记录:

for rep = 1:10 rng(1000 + rep); % 每次都不同,但下次运行结果一致 % 在这里执行从数据划分、GA优化到测试集评估的全流程 % 记录 GA-ELM 的 RMSE 到数组 ga_rmse(rep) % 记录随机ELM 的 RMSE 到数组 elm_rmse(rep) end fprintf('GA-ELM: %.4f ± %.4f\n', mean(ga_rmse), std(ga_rmse)); fprintf('ELM : %.4f ± %.4f\n', mean(elm_rmse), std(elm_rmse));

如果 GA 的多次重复标准差仍然很大,往往不是运气问题,而是种群过早收敛。优先调小 W 和 b 的范围,而不是加代数;范围缩小后初始种群个体间距变小,交叉产生的后代才更可能落在同一个优质区域。

5.2 时间序列对比时保持数据规范一致

预测项目里越来越多地用 Python 写完 LSTM、Transformer 甚至 mamba-3 这类状态空间模型,再拿它们和 MATLAB 侧的 ELM 系模型对比。对比本身没问题,但规范必须统一:数据划分的边界索引要完全一致,归一化参数只在训练段上计算,验证集、测试集不能提前参与标准化。很多人从 MATLAB 导出预测结果后,在 Python 里直接用 sklearn 的新的 scaler 重放一遍预测,分布就变了。较稳妥的做法是 MATLAB 一侧把所有划分索引和归一化参数保存成 mat 文件,另一侧只读取结果,不重新计算 scaler。

GA-ELM 更适合作为强基线而不是“最终卖点”。在与更复杂的深度模型对比时,把 GA-ELM 的 L 设置成与 LSTM 隐单元数在同一量级,对比才有说服力。

5.3 多步预测和分类任务的等价改造

多步预测把 Y 从单列换成 h 列,β 变成 L×h,适应度函数里sqrt(mean((Yva - Yp).^2))自动对所有输出列取平均,GA 无感知。分类任务把输出层的激活换成 sigmoid,预测值大于 0.5 判为正类,适应度用错误率或 AUC 替代 RMSE;GA 的个体编码、交叉和变异完全不动。这两类改造都不需要新增进化算子,真正的成本只在适应度函数的重新设计上。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询