
简介一份MATLAB实现的极限学习机ELM算法全家桶涵盖基础ELM、正交ELMOSELM、核ELMKELM、半监督SSELM和无监督USELM五种主流变体并提供可直接运行的完整源码适合机器学习入门者、算法研究者以及需要快速搭建ELM实验的工程人员。包内共31个文件核心为23个m脚本覆盖模型训练、预测、激活函数构造与核函数实现同时附带sinc、diabetes、iris、g50c等多组示例数据便于测试回归与分类效果压缩包仅451KB下载后可快速部署。代码以模块化方式组织从随机初始化隐藏层到最小二乘求解输出权重再到各变体的特有处理逻辑清晰注释简洁。已有1023人学习使用无论是理解ELM原理、对比不同改进策略还是在此基础上做二次开发都能提供扎实的实践起点。1. 极限学习机ELM与OSELM、KELM、SSELM、USELM一套MATLAB代码覆盖五种学习范式把随机生成的输入权重和偏置固定住只训练输出层这就是极限学习机ELM反直觉的第一步。它丢掉反向传播用最小二乘一步解出输出权值训练速度比BP快一到两个数量级代价是隐层语义不可解释。这套ELM、OSELM、KELM、SSELM、USELM的MATLAB代码把五种学习范式装进同一个工程。ELM是基座OSELM用于流式数据KELM用核函数替代随机投影SSELM与USELM分别吃下半监督和无监督场景。适合用MATLAB做数据建模的工程师和研究生尤其是标注成本高、数据分块到达或需要快速原型验证的场景。整套实现不依赖优化工具箱不依赖深度学习框架脚本文件可直接运行。2. 极限学习机ELM的MATLAB最小实现固定随机投影只解最小二乘2.1 ELM省掉反向传播的理论依据与激活函数选型ELM最初的论文里的核心观察是只要隐层节点足够多且激活函数满足非线性逼近条件输入权重W和偏置b取随机值还是训练值对最终表示能力的影响远小于输出层权重。于是W和b被冻结在[-1,1]均匀分布的随机值上目标函数从多层非凸优化退化成单层线性最小二乘min ||Hβ - T||²其中H是N×L隐层输出矩阵β是L×m输出权值矩阵T是目标矩阵。这个问题的解是β H†TH†是H的伪逆。MATLAB里一个反斜杠运算符H \ T就能完成不需要梯度下降也不需要调用优化工具箱做迭代求解。L通常取100到500比输入维度高一个量级随机投影才够提供分隔空间L一旦超过样本数NH行不满秩过拟合会立刻出现。激活函数在随机权重下也有讲究。sigmoid和tanh表现接近relu由于随机偏置会产生死节点在单隐层ELM里优势有限一般先固定sigmoid特征明显稀疏时再换relu对比激活函数输出范围适用场景注意sigmoid(0,1)二分类、默认选项输入需标准化tanh(-1,1)特征零均值化后比sigmoid梯度更平缓relu(0,∞)稀疏高维特征随机偏置下易出死节点注意隐层节点数L既不能小于输入维度也不能超过样本数N前者欠拟合后者直接过拟合从min(200, 2*d)起步逐步翻倍是省时间的做法。2.2 elm_train、hidden_out、elm_predict三个函数完整代码先写共用的隐层计算函数hidden_out后续OSELM、SSELM、USELM全部复用它避免每个变种各自写一份投影逻辑。它的职责是把标准化输入映射到随机隐层空间并施加非线性是整套代码里唯一重复出现的公共件。function H hidden_out(X, model) % 随机投影 激活ELM 家族共用的隐层计算 H X * model.W model.b; % 线性组合 switch model.actType case sig H 1 ./ (1 exp(-H)); case tanh H tanh(H); case relu H max(0, H); end end隐层计算分两步X * model.W把d维样本投影到L维隐层空间model.b是1×L的偏置向量R2016b之后MATLAB自动做隐式扩展加到每一行。如果你的代码要在R2016b之前跑这一行必须改成bsxfun(plus, X*model.W, model.b)否则报维度不匹配。训练函数把随机权重生成和解最小二乘包在一起整个ELM的训练过程到反斜杠一行就结束了function model elm_train(X, T, nHidden, actType) % X: N*d 标准化后的输入; T: N*m 目标矩阵 % nHidden: 隐层节点数; actType: sig|tanh|relu rng(42); model.W rand(nHidden, size(X,2)) * 2 - 1; model.b rand(nHidden, 1) * 2 - 1; model.actType actType; H hidden_out(X, model); model.beta H \ T; % 最小二乘一步求解 endrng(42)固定随机种子保证同一份数据每次跑出来的W、b一致实验可复现。H \ T在L小于N且H列满秩时走QR分解比显式pinv(H)*T更快数值上也更可靠。预测函数同样复用hidden_out预测阶段不要再调用rng权重必须来自训练好的model结构体function Y elm_predict(model, X) Y hidden_out(X, model) * model.beta; end分类任务里对Y按行argmax得到类别索引回归任务Y本身就是预测值。elm_predict不保存中间变量内存占用与训练阶段解耦适合批量打分。2.3 用fisheriris跑通分类的最小脚本用MATLAB自带的fisheriris做端到端验证全程不依赖统计工具箱函数复制即跑load fisheriris X meas; [~, ~, gid] unique(species); % 类别转索引 T double(gid (1:3)); % one-hot 目标 X (X - mean(X)) ./ std(X); % 标准化 rng(1); idx randperm(150); model elm_train(X(idx(1:100),:), T(idx(1:100),:), 200, sig); Y elm_predict(model, X(idx(101:end),:)); [~, pred] max(Y, [], 2); [~, tru] max(T(idx(101:end),:), [], 2); fprintf(ELM test acc %.2f%%\n, mean(pred tru) * 100);unique返回的gid本身就是1到3的整数gid (1:3)利用隐式扩展生成逻辑矩阵double转成数值型比dummyvar少一个工具箱依赖。demo里为简洁把标准化放在划分之前实际工程应只用训练集计算均值方差再套用到测试集避免统计量泄漏。隐层节点取200对150个样本的鸢尾花数据已经足够测试精度通常在95%以上换到高维数据时先降回2倍输入维度再逐步往上调。3. OSELM在线序列ELM与KELM核极限学习机的MATLAB实现3.1 OSELM的递推更新公式增量修正代替全量重算OSELM解决数据分块到达、不能一次性载入内存的问题典型场景是传感器时序、日志流和在线推荐。它把批量ELM的最小二乘解改写成递归形式设P_k (H_k H_k)^(-1)新块(X_{k1}, T_{k1})的隐层输出为H_{k1}P和β按下式递推P_{k1} P_k - P_k H_{k1}(I H_{k1} P_k H_{k1})^(-1) H_{k1} P_kβ_{k1} β_k P_{k1} H_{k1}(T_{k1} - H_{k1} β_k)第一式本质是Woodbury矩阵恒等式避免对累积数据重新求逆第二式括号里是新块的预测残差残差乘以增益矩阵P_{k1}H_{k1}就是本次修正量。修正量完全由当前块决定历史数据只通过P和β被隐式记忆所以OSELM内存占用恒定不随数据总量增长。三个变种对数据形态的适配关系如下数据形态ELMOSELMKELM一次性读入内存✓✓✓流式分块到达✗✓✗样本数超过1万勉强✓✗需要在线同步更新✗✓✗3.2 OSELM初始化与顺序更新的MATLAB代码及N0参数function model oselm_init(X0, T0, nHidden, actType) % 预热阶段第一批样本数必须不小于隐层节点数 if size(X0,1) nHidden error(初始块样本数必须大于隐层节点数); end rng(42); model.W rand(nHidden, size(X0,2))*2 - 1; model.b rand(nHidden, 1)*2 - 1; model.actType actType; H0 hidden_out(X0, model); model.P inv(H0*H0 1e-8*eye(nHidden)); model.beta model.P * H0 * T0; end初始化阶段与批量ELM的唯一区别是额外保存了P矩阵。inv里的1e-8*eye(nHidden)是岭正则保证H0 H0可逆如果N0只比nHidden大一点最小奇异值接近零这个正则项能避免P出现巨大元素。初始化完成后每个新块调用更新函数function model oselm_update(model, Xc, Tc) % 顺序更新一块新数据 Hc hidden_out(Xc, model); Lk size(Xc, 1); K model.P * Hc / (eye(Lk) Hc * model.P * Hc); model.P model.P - K * Hc * model.P; model.beta model.beta K * (Tc - Hc * model.beta); endK在结构上等价于卡尔曼滤波里的增益衡量新块信息对模型的贡献。块大小Lk不需要固定每块样本数不同也能正确更新矩阵乘法会自动适配维度。两个参数直接决定行为N0太小则P_0噪声大后续要很多块才能收敛正则项1e-8如果改成1相当于给每个隐层节点加强惩罚增量修正被压得过于保守在线精度下降。提示OSELM面对分布漂移时P矩阵会自动放大对新块的增益模型逐步贴近新分布代价是噪声块也被同步放大。工程上可以对残差设门限残差超过历史标准差3倍时跳过该块。3.3 KELM核极限学习机核矩阵替换随机隐层与gamma、C调参KELM放弃随机投影路径改用核函数直接计算样本对相似度隐层维度从L换成样本数N。目标函数变成min ||Ωβ - T||² (1/C)||β||²解为β (Ω I/C)^(-1)T。Ω是N×N核矩阵RBF核Ω_ij exp(-γ||x_i - x_j||²)是最常用选择function model kelm_train(X, T, gamma, C) % RBF核ELMgamma为核宽度C为正则系数 N size(X, 1); G sum(X.^2, 2); Omega exp(-gamma * (G G - 2 * (X * X))); model.X X; model.gamma gamma; model.beta (Omega eye(N) / C) \ T; end function Y kelm_predict(model, Xnew) G sum(model.X.^2, 2); Gn sum(Xnew.^2, 2); K exp(-model.gamma * (Gn G - 2 * (Xnew * model.X))); Y K * model.beta; end核矩阵用距离展开式一次成型避免双层for循环。训练时对N×N矩阵求逆预测时只算新样本与全部训练样本的核向量K再做K * beta。gamma和C是仅有的两个超参数gamma过大时核矩阵对角占优每个样本只影响自己测试几乎变成查表过小则全部样本相似度趋同输出退化成常数。常见做法是在gamma取2^-15到2^3、C取2^-5到2^15的指数网格上做交叉验证尺度跨5个数量级才能看清响应面。注意Omega是稠密矩阵N超过1万时内存和求逆时间都不可接受。KELM适合样本量中等、特征维度高且核相似度有物理语义的数据样本量大的流式场景退回OSELM。4. SSELM半监督ELM与USELM无监督ELM无标注数据的两种用法4.1 SSELM流形正则项的由来与闭式解半监督场景里标注样本可能只有几十条无标注样本却有几千条。SSELM的假设是流形平滑如果两个样本在特征空间靠得近它们的输出也应该接近。用kNN图把全部样本连成图定义图拉普拉斯L D - W其中W是邻接权重D是度矩阵正则项βHLHβ度量的就是相邻样本预测差的平方和。合并进ELM目标后得到min ||Hβ - T̃||² (1/C)||β||² λ βHLHβT̃是扩展目标矩阵前l行是标注one-hot后u行全零。对β求导并置零得到闭式解β (I/C HH λHLH)^(-1) HT̃。λ是半监督强度的总开关λ0时退化为带正则ELM无标注数据完全不参与λ变大时无标注数据借L逐步主导解的形态。4.2 SSELM的MATLAB代码kNN图拉普拉斯与扩展目标矩阵function model sselm_train(Xl, Tl, Xu, nHidden, C, lambda, kNN) % Xl: 标注样本; Tl: one-hot标签; Xu: 无标注样本 % C: 正则化系数; lambda: 流形正则强度; kNN: 近邻个数 X [Xl; Xu]; Nl size(Xl, 1); T_tilde zeros(size(X,1), size(Tl,2)); T_tilde(1:Nl, :) Tl; % 无标注行保持全零 G sum(X.^2, 2); Dist G G - 2 * (X * X); % 欧氏距离平方矩阵 Dist(1:size(X,1)1:end) inf; % 对角线置inf排除自身 Adj zeros(size(X,1)); for i 1:size(X,1) [~, idx] mink(Dist(i,:), kNN); Adj(i, idx) 1; end Adj max(Adj, Adj); % 对称化 W_adj Adj .* exp(-Dist); % 热核权重 W_adj(isnan(W_adj)) 0; L_matrix diag(sum(W_adj,2)) - W_adj; rng(42); model.W rand(nHidden, size(X,2))*2 - 1; model.b rand(nHidden, 1)*2 - 1; model.actType sig; H hidden_out(X, model); model.beta (eye(nHidden)/C H*H lambda * H*L_matrix*H) \ H*T_tilde; model.X X; end代码里最值得注意的三处Dist用展开式一次算全距离矩阵不调pdist2省去统计工具箱依赖mink取每行最近的kNN个邻居旧版本用sort加索引截断代替热核权重exp(-Dist)乘到邻接关系上距离近的邻居权重高距离远的即使入选权重也趋近于零。T_tilde前Nl行保留one-hot标签其余行全零这意味着无标注样本不直接贡献目标误差只通过L_matrix进入正则项。求解出的beta维度是nHidden×m评估时在标注验证集上算精度。lambda从0.01起步每增大10倍观察验证集变化超过某个阈值后精度掉头向下说明无标注先验开始压过标签真值。4.3 USELM的无监督嵌入与kmeans聚类代码USELM把同一套随机投影当成无监督特征提取器。流程是先算隐层输出H再构造样本空间的kNN拉普拉斯L然后求解广义特征问题HLHβ γ(HH I/C)β取最小的kcls个特征值对应的特征向量组成嵌入最后对嵌入做kmeans聚类function [embed, beta] uselm_embed(X, nHidden, kcls, kNN, C) % X: N*d; nHidden: 随机投影维度; kcls: 聚类簇数 % kNN: 近邻个数; C: 正则系数 rng(42); W rand(nHidden, size(X,2))*2 - 1; b rand(nHidden, 1)*2 - 1; model.W W; model.b b; model.actType sig; H hidden_out(X, model); L laplacian_knn(X, kNN); % 复用4.2的拉普拉斯构造 A H * L * H; B H * H eye(nHidden) / C; [V, ~] eigs(A, B, kcls, smallestabs); beta V; embed H * V; % N*kcls 嵌入 % 聚类idx kmeans(embed, kcls); endeigs(A, B, kcls, smallestabs)取最小的kcls个广义特征值对应的特征向量这一选择等价于让聚类结果在图上足够平滑——同一连通分量里的样本在嵌入中挤在一起kmeans在这些方向上的划分比原始空间干净得多。环节SSELMUSELM显式目标矩阵有无标注行全零无求解方式最小二乘闭式解广义特征分解输出回归/分类模型嵌入 kmeans聚类正则项来源C和λ只有CC的取值控制B矩阵可逆性C太小B退化C太大约束松弛嵌入退化成普通随机投影。kNN对USELM比对SSELM敏感因为没有标签兜底建议在3到8之间用轮廓系数选择。5. 五个ELM变种的参数速查、一致性验证与MATLAB坑位5.1 五组核心参数的速查表变种必调参数推荐起点失效信号ELMnHiddenmin(200, 2*d)训练acc高、测试acc低OSELMN0初始块大小≥ nHiddeninv报奇异或预测发散KELMgamma, Cgamma1/d, C100预测全部挤到同一类SSELMlambda, kNNlambda0.1, kNN5精度不如只带标注的ELMUSELMkcls, kNN真实簇数, kNN5轮廓系数接近0调参时把五个变种当成一条决策链数据量小且能一次载入用ELM打底流式到达换OSELM样本量中等且核函数有物理意义用KELM标注稀缺补SSELM完全没有标签用USELM。5.2 OSELM回退ELM的一致性验证脚本OSELM最容易出错的环节是P矩阵递推。验证方法不依赖外部标签把完整数据切成若干块第一块做oselm_init其余块顺序oselm_update同时用全部数据直接elm_train。两个模型beta逐元素比较最大绝对误差应当落在1e-10量级model_batch elm_train(Xall, Tall, 200, sig); model_os oselm_init(Xall(1:N0,:), Tall(1:N0,:), 200, sig); for k 2:nBlocks model_os oselm_update(model_os, Xblk{k}, Tblk{k}); end max(abs(model_os.beta - model_batch.beta), [], all)Xblk、Tblk是按块切好的元胞数组。输出量级在1e-10附近说明递推公式和正则位置都正确误差到1e-3以上基本可以断定P更新写错。同理SSELM令lambda0时应回退到带正则ELMUSELM令C取极大时嵌入应接近普通随机投影。这条回退链是整套代码的免费自检每次改完公式跑一遍只要几秒。5.3 MATLAB版本差异与三个常见坑三个坑值得提前标出来。第一隐式扩展依赖R2016b老版本要把hidden_out里的加法改成bsxfun(plus, ...)。第二mink和eigs的smallestabs都是较新版本才有的接口旧版分别用sort加索引截断和sm替代。第三rng(42)只保证调用后的第一个随机序列固定oselm_init与批量elm_train之间若插入其他随机函数W、b不再对齐一致性验证会莫名失败把W、b存进model结构体就能绕开。完整工程建议按函数拆文件hidden_out.m、elm_train.m、elm_predict.m、oselm_init.m、oselm_update.m、kelm_train.m、kelm_predict.m、sselm_train.m、uselm_embed.m同目录addpath后直接调用第2到第4章的代码去掉注释即为完整可运行版本。本文还有配套的精品资源点击获取