☰
极限学习机结合流形正则:SS-US-ELM在少量标签场景下的半监督与无监督分类实现
2026/10/18 14:49:49 网站建设 项目流程

手里只有30个带标签的样本,剩下四千多条数据安安静静躺在硬盘里,没有标签,但明显不是噪声。标签费时费力,丢掉这些无标签数据又可惜,这是我在做一个分类任务时最真实的窘境。后来我翻到半监督极限学习机(SS-ELM)和无监督极限学习机(US-ELM)的实现思路,才意识到原本纠结的问题可以用一个统一框架解决:给极端学习机加一顶“流形正则化”的帽子,让少量标签和大量无标签数据在同一个训练闭环里协作。这篇文章我按自己的理解,把SS-US-ELM的原理、公式到Matlab代码串了一遍,适合手里有Matlab、想快速复现又不想啃一堆论文的读者。

这个标题下的代码解决的核心问题,说白了就是:需求是“分类器”但只有少量标注数据时,怎么把无标签样本用起来;需求是“聚类”但完全不想碰标签时,怎么让ELM也能输出有意义的嵌入和簇。两种需求共用同一套隐层映射逻辑,只是目标函数里取舍不同。我下面会先讲清楚ELM为什么快、SS-ELM三个目标项是怎么协同的、US-ELM如何退化成特征分解问题,再给一套能直接跑的Matlab代码段,最后说说我调参和踩坑的实际经验。

1. 理解ELM的核心逻辑:随机映射加上最小二乘输出

1.1 ELM为什么快:把“反向传播学习隐层”变成“随机生成隐层”

传统的BP神经网络训练慢,很大程度是因为隐层的权重和偏置要通过误差反传反复迭代调整,每调一次都要跑一轮前向和反向。极限学习机(ELM)做了一个非常大胆的简化:隐层的输入权重和偏置不需要学习,直接随机生成,训练阶段只学习隐层到输出的那一层线性权重。这样一来,训练从“非线性迭代优化”降维成“线性最小二乘求解”,速度能提升几个数量级。

ELM的过程可以拆成两步。第一步,给定输入数据矩阵X(n×d),随机生成输入权重W(d×L)和偏置b(1×L),经过激活函数得到隐层输出矩阵H(n×L): H = g(X·W + b) 这里g就是激活函数,可以是sigmoid、tanh、rbf等。矩阵的每一行是对应样本的隐层特征,每一列对应一个随机映射后的“特征维度”。为什么说这是特征学习?因为ELM把原始输入投射到一个随机的高维空间里,在这个空间里再做线性分类或回归,等价于用一组基函数去拟合目标。

第二步,求解隐层到输出的权重β(L×m),目标是最小化训练误差: min ||H·β - T||² T是标签矩阵(n×m)。这是个典型的线性最小二乘问题,解是β = H†·T,其中H†是H的伪逆。伪逆的Matlab实现非常简单,一行pinv(H) * T就跑完了。当年我第一次跑通这个流程时,感觉训练时间几乎可以忽略不计,这就是ELM的核心价值所在。

1.2 输出权重求解:从伪逆到正则化

如果H的列数比较少、样本量很大,伪逆求解的稳定性其实还可以。但一旦隐层节点数L接近或超过样本数n,问题就变成欠定,直接用伪逆容易过拟合。实践里我在ELM后面加上一个L2正则项,把训练目标改成: min (1/2)·||β||² + (C/2)·||Hβ - T||² 这个C就是正则化系数,控制模型复杂度和训练误差的平衡。解变成: β = (I/C + HᵀH)⁻¹·HᵀT 等价形式是β = (I + C·HᵀH)⁻¹·HᵀT。这里I是单位矩阵,维度等于隐层节点数L。这样既保证模型有足够表达能力,又不会因为隐层太大而把噪声也一并记下来。这个正则化思想在后面SS-ELM和US-ELM里会被放大成更具灵活性的框架,理解这一步很重要。

1.3 为什么在ELM之上做半监督和无监督

ELM虽然快,但它本身是有监督的,必须给标签。实际场景里标签往往是最贵的资源。我碰到的项目里,有时专家手工标注一批数据需要一两天,而无标签数据每天都在产生。这时候有两个直接需求:

  • 半监督:用少量有标签样本加大量无标签样本共同训练,让无标签样本通过数据分布和邻居关系“间接”参与训练。
  • 无监督:完全没有标签,但希望ELM能输出一个可聚类的嵌入表示。

标准ELM在这两种场景下都无能为力,但它的隐层随机映射机制给半监督和无监督留了一扇窗:既然隐层是固定的、不需要额外学习,那我们只需要在输出权重β上做文章。把流形正则化加进目标函数,就能让无标签样本的几何结构影响β的求解。这就是SS-US-ELM这套框架的出发点,也是我下文要展开的核心。

2. 半监督极限学习机:三个目标项如何在闭环中协作

2.1 目标函数拆解,每一项代表一个需求

半监督极限学习机(SS-ELM)的目标函数在我看来就是三个需求的叠加:结构风险、经验风险、流形正则。写成公式就是:

min (1/2)·||β||² + (C/2)·Σᵢ₌₁ˡ ||eᵢ||² + (λ/2)·Tr(Fᵀ·L·F)

三个项各自的分工非常明确。第一项(1/2)·||β||²是L2正则,约束模型的复杂度,防止在标签极少时输出权重出现极端取值。第二项是有标签样本的误差项,Σᵢ₌₁ˡ ||eᵢ||²只对前面l个有标签样本计算误差,eᵢ = Tᵢ - Hβ。C控制这部分在整体目标里的权重——标签越可靠、越重要,C就越大。第三项是流形正则,对所有样本(不管标没标标签)的隐层输出F = Hβ做平滑性约束,Tr(FᵀLF)表示预测结果在数据流形上的“变化剧烈程度”。

这个三项结构最妙的地方在于:它不是把无标签样本强行赋予伪标签来参与训练,而是让无标签样本通过图结构“告诉”模型,彼此的预测应该保持在怎样的相对关系里。标签只负责校准绝对位置,流形负责维持相对结构。

2.2 图拉普拉斯正则的直观含义——平滑性假设

很多人第一次看Tr(FᵀLF)会觉得抽象。实际上这个式子做一次恒等变形就好理解了:

Tr(FᵀLF) = (1/2)·Σᵢⱼ Wᵢⱼ·||Fᵢ - Fⱼ||²

Fᵢ是样本i的网络输出。Wᵢⱼ是样本i和样本j之间的相似度权重。这个式子的意思是:如果两个样本在原始空间里离得近(Wᵢⱼ大),那它们对应的输出Fᵢ和Fⱼ也应该尽量接近。这个假设就是半监督学习里的平滑性假设——数据分布的密度高区域内部,标签变化不应太剧烈。用生活里的类比来说,一条街道相邻门牌号的房价不会突然从五位数跳到大七位数,邻居之间总是渐变的。

构造L的过程有两种常用做法。第一种是k近邻图加高斯核权重:先对每个样本找它的k个近邻,然后对近邻对赋予高斯相似度Wᵢⱼ = exp(-||xᵢ - xⱼ||²/(2σ²)),非近邻权重为0。第二种是直接用全连接高斯核,但样本量大时矩阵会太密,我一般用k近邻图。得到相似度矩阵W后,令度矩阵D为对角阵,对角线元素Dᵢᵢ = Σⱼ Wᵢⱼ,拉普拉斯矩阵L = D - W。实践中我也常用对称归一化的版本L_sym = D^(-1/2)·L·D^(-1/2),数值上更稳定,后面代码里就用这个。

2.3 闭式解的推导思路与Matlab代码中的矩阵组装

SS-ELM的优点之一是求解过程仍然是解析解,不需要迭代。把目标函数的误差项写成矩阵形式:误差向量只对有标签样本有效,这里用一个对角矩阵J来实现,维度n×n,对角线前l个元素为1,后u个元素为0。T̃是同标签矩阵,有标签部分放真实标签,无标签部分置0即可,因为对应的误差项被J屏蔽了。整体优化问题等价于:

min (1/2)·||β||² + (C/2)·||J^(1/2)(Hβ - T̃)||² + (λ/2)·βᵀHᵀLHβ

对β求导并令导数为0,整理后就得到闭式解:

β = (I + C·Hᵀ·J·H + λ·Hᵀ·L·H)⁻¹·Hᵀ·J·T̃

从公式可以看出,HᵀJH是在有标签样本上积累信息,HᵀLH是在全部样本上做流形正则。两者共享同一套隐层特征H,只是作用方式不同。在我实际写的Matlab代码里,整个求解过程不过三五行矩阵操作。预计算H,构造J、L,然后一次左除“\”就解出β,训练过程仍然保持了ELM系列“快”的基因。我强烈建议你自己推一遍这个求导过程,哪怕只在草稿纸上写写符号,也会对矩阵组装的理解深很多。

3. 无监督极限学习机:没有标签时的嵌入与聚类

3.1 去掉误差项之后,目标函数还剩什么

无监督极限学习机(US-ELM)是SS-ELM的一个极端情形:没有标签,目标函数里去掉经验误差项,只剩结构风险和流形正则。于是优化目标变成:

min (1/2)·||β||² + (λ/2)·Tr(Fᵀ·L·F)

但这里藏着一个致命问题:如果不加任何约束,β = 0就是最小值。L·F里如果F全为0,Tr(FᵀLF)=0,||β||²也是0,模型直接学出一个全零输出。这是我在初学US-ELM时踩过的最大坑——跑出来所有样本的嵌入一模一样,聚类结果自然一团糟。

要避免平凡解,必须给输出嵌入加上约束。常见做法是要求嵌入正交归一:FᵀF = I,或者说(Hβ)ᵀ(Hβ) = I。正交约束的意思是:不同维度上的嵌入要彼此独立,且保持单位能量。这样模型被迫在“保持流形平滑”和“输出不退化”之间寻找平衡,学出来的嵌入才有辨识度。

3.2 正交约束与广义特征值问题

加上约束后,原本的简单最小二乘问题变成了约束优化问题,用拉格朗日乘子法可以转成一个广义特征值问题。推导思路大致是:构造拉格朗日函数,对β求导置零,整理后得到:

Hᵀ·L·H·β = λ·Hᵀ·H·β

这是一个标准的广义特征值问题:A = HᵀLH,B = HᵀH,求解使得Aβ = λBβ的β。最优解取最小的m个特征值对应的特征向量,m是希望的嵌入维度或聚类簇数。这背后有谱聚类的思想:拉普拉斯矩阵最小的非零特征向量恰恰对应着数据流形上最“平滑”的切分方向,把这些方向作为嵌入特征,后续聚类更容易分开。

在实际Matlab代码里,求广义特征值用的是eigs函数:

[V, ~] = eigs(A, B, m, 'smallestabs'); beta = V;

一个很容易被忽略的细节是eigs默认返回模最大的特征值,必须显式指定'smallestabs'才是最小特征值方向。我一开始没注意,结果聚类效果诡异,排查了半天才发现是特征值选向反了。

3.3 聚类嵌入怎么落地成最后的类别

拿到β之后,把所有样本映射到嵌入空间:F = H·β。F是n×m的矩阵,每一行是一个样本的低维嵌入。对F直接跑kmeans聚类,就能得到每个样本的簇标签。这个流程跟谱聚类的embedd后接kmeans是一样的套路,只是这里嵌入的基来自ELM随机映射后的H空间,而不是原始特征空间。

嵌入维度m通常取簇数本身,但也可以稍微大一点再做PCA降维。在我的实验里,m等于簇数时效果最直接;如果数据簇内结构复杂,可以取2~3倍的簇数,然后聚类前用PCA压缩到簇数维度,往往更稳。后面我会在代码段里展示完整步骤。

4. Matlab实现细节:我的这套代码长什么样

4.1 输入输出约定与核心参数

先说我代码里约定的输入输出,这样你拿到任何一份SS-US-ELM代码都能快速对齐。输入是特征矩阵X(n×d),标签矩阵Y(n×c,c是类别数或输出维度)。半监督场景下,无标签样本在Y中的对应行全部置0;纯监督场景下每行是one-hot标签。输出是输出权重β和一个结构体model,里面存了随机权重W、偏置b、激活函数类型等,方便预测阶段复用。

核心参数包括:

  • num_hidden:隐层节点数L,我常用范围100~1000
  • C:经验风险正则系数,常用1e-3~1e3
  • lambda:流形正则系数,常用1e-4~1e-1
  • k:k近邻图中近邻个数,常用5~20
  • gamma:高斯核宽度参数σ,影响相似度权重的衰减速度

我通常这样组织代码:一个主函数,一个隐层计算函数,一个图拉普拉斯构造函数。数据量不大时全部用普通矩阵即可;超过一万条样本我建议把W和L都转成sparse矩阵,内存会舒服很多。

4.2 隐层映射与图拉普拉斯构造代码

隐层映射函数我一般写成这样:

function H = compute_hidden(X, W, b, activation) % X: n*d % W: d*L % b: 1*L % activation: 'sigmoid' | 'tanh' | 'rbf' n = size(X, 1); if strcmp(activation, 'sigmoid') H = 1 ./ (1 + exp(-(X * W + repmat(b, n, 1)))); elseif strcmp(activation, 'tanh') H = tanh(X * W + repmat(b, n, 1)); elseif strcmp(activation, 'rbf') % 高斯核映射,需要额外传gamma参数,这里简化 H = exp(-gaussian_dist(X * W)); else error('unknown activation'); end end

其中W和b可以用rand(d, L)*2-1和rand(1, L)生成。这里需要提醒:偏置b的维度要和W的输出维度匹配,我见过有人把b生成成n×L,直接让隐层计算变成全零,排查老半天。

图拉普拉斯构造函数:

function Lap = compute_laplacian(X, k, gamma) n = size(X, 1); idx = knnsearch(X, X, 'K', k+1); % 不包括自身 idx = idx(:, 2:end); % 去掉自近邻 W = zeros(n, n); for i = 1:n diff = X(idx(i,:), :) - repmat(X(i,:), k, 1); dist2 = sum(diff .^ 2, 2); W(i, idx(i,:)) = exp(-dist2 / (2 * gamma^2)); W(idx(i,:), i) = W(i, idx(i,:)); end D = diag(sum(W, 2)); Lap = D - W; % 对称归一化 D_inv_sqrt = diag(1 ./ sqrt(sum(W, 2) + eps)); Lap = D_inv_sqrt * Lap * D_inv_sqrt; end

这个函数看起来简单,但我建议实际项目里把W和L都声明成sparse类型,尤其n超过五千时,稠密W矩阵会瞬间吃掉几个GB内存。我曾在一个两万样本的任务里用稠密矩阵,直接内存溢出,改成sparse(n,n)后才跑通。

4.3 SS-ELM求解核心代码

主函数半监督部分,核心代码很短:

function beta = train_sselm(X, Y, label_mask, opts) n = size(X, 1); L = opts.num_hidden; % 1. 随机生成隐层参数 W = rand(size(X,2), L) * 2 - 1; b = rand(1, L); H = compute_hidden(X, W, b, opts.activation); % 2. 构造图拉普拉斯 Lap = compute_laplacian(X, opts.k, opts.gamma); % 3. 半监督标识矩阵 J J = diag(label_mask); % label_mask是n*1逻辑列向量 T = Y; % 无标签行全0 % 4. 组装矩阵求解 A = eye(L) + opts.C * (H' * J * H) + opts.lambda * (H' * Lap * H); B = H' * J * T; beta = A \ B; end

这里的label_mask尤其关键,它同时体现在J矩阵和T矩阵的处理里。J让无标签样本的误差项不进入目标函数,T的无标签行虽然置0但不影响最终结果,因为对应的J在乘法中把贡献屏蔽了。很多复现SS-ELM的人在这块容易绕晕,我以为当初写代码时也怀疑过“无标签行的标签设成0不会误导吗”,推导一遍公式就明白了——它只是占位,真正决定无标签样本影响力的是流形正则项的L。

4.4 US-ELM求解和聚类代码

US-ELM部分区别更大,因为不需要J和T,目标函数直接变成广义特征值问题:

function cluster_labels = train_uselm(X, num_clusters, opts) n = size(X, 1); L = opts.num_hidden; W = rand(size(X,2), L) * 2 - 1; b = rand(1, L); H = compute_hidden(X, W, b, opts.activation); Lap = compute_laplacian(X, opts.k, opts.gamma); % 广义特征值问题 A = H' * Lap * H; B = H' * H; [V, ~] = eigs(A, B, num_clusters, 'smallestabs'); beta = V; embedding = H * beta; % 对嵌入做kmeans聚类 cluster_labels = kmeans(embedding, num_clusters, 'Replicates', 10); end

这里有一个重要细节:取最小特征向量时,要不要剔除全零的特征向量?如果是归一化拉普拉斯,最小的特征值对应0,它的特征向量是常数向量,输入给kmeans没有区分度。但eigs返回的前几个特征向量通常会包含这个常数方向,我建议要么从第二个特征向量开始取,要么直接对所有特征向量做一次小方差过滤。我自己的做法是:取num_clusters+1个最小特征向量,去掉第一个常数方向,保留后面num_clusters个。如果你发现聚类结果某簇特别大,其他簇特别小,往往就是常数方向混进去了。

5. 参数选择与调优经验(含踩坑记录)

5.1 五个关键参数的推荐范围和一个建议调试顺序

SS-US-ELM看起来很省事,但参数一多还是容易迷茫。我整理了一个比较实用的参考范围表:

参数推荐范围说明
num_hidden100 ~ 1000太小欠拟合,太大计算变慢,效果不一定更好
C1e-3 ~ 1e3有标签样本越多、越可靠,C可适当调大
lambda1e-4 ~ 1e-1无标签数据越有结构,lambda的作用越明显
k5 ~ 20数据越密,k可以稍大,但要避免图过密失去局部性
gamma数据特征尺度可以用所有样本对距离的中位数做初始值

调试顺序我建议固定成:先用纯监督ELM(λ=0)跑一遍有标签数据,确认隐层节点数和C在一个合理范围,然后逐步增大λ观察交叉验证或聚类指标。不要一开始就所有参数同时调,否则出了问题根本定位不到是哪个参数引起的。

5.2 激活函数和近邻图的数值稳定性问题

激活函数的选择会直接影响隐层输出H的数值范围。sigmoid输出在(0,1)之间,tanh在(-1,1)之间,RBF高斯核在(0,1)之间但衰减速度受gamma影响很大。如果H的数值范围太小,HᵀH和HᵀLH的数值就会接近机器精度,求解β时容易出现奇异或矩阵不可逆。我在一个任务里用RBF核时把gamma设得太小,导致H几乎全为0,A矩阵条件数爆炸,A\B警告矩阵接近奇异。解决方法很简单:把gamma调到数据距离的中位数量级,并检查H的方差是否在一个可接受范围。

近邻图构造的数值问题同样常见。knnsearch默认用欧氏距离,在特征维度很高时,距离几乎全部集中在某个均值附近,高斯核权重会退化成近似常数,流形正则项失去区分度。这种情况我会先对X做标准化或PCA降维,再构造图。注意标准化一定要用全部样本的均值和方差计算,不能用有标签子集单独算,否则会把分布信息泄露给训练过程。

5.3 新手最常遇到的问题和排查思路

第一个高频问题是“无标签样本的预测输出全为0”。大多数人会怀疑是代码bug,但其实先检查J矩阵和T̃矩阵是否正确。如果J的对角线在无标签位置不是0而是1,那无标签样本的误差就被强行加进了目标函数,模型为了拟合那些全0标签,当然输出全0。排查方式是打印所有样本的误差均值,看有标签和无标签样本的误差是否分布合理。

第二个高频问题是“eigs收敛失败或警告”。这多半是A或B矩阵不是对称半正定的。HᵀLH理论上是对称半正定的,但数值上如果拉普拉斯矩阵的对称性被破坏了,比如图构造时只给W设了上三角没设下三角,对称性就没了。我建议构造L后,直接检查norm(L - L'),如果大于1e-10,说明对称性有问题,需要对L做一次(L+L')/2处理。

第三个问题是“隐层节点数一多,SS-ELM效果反而变差”。这在半监督场景很常见:无标签数据占比高时,隐层过大意味着模型参数太多,而流形正则虽然提供了约束,但约束强度不够时噪声仍然会被记住。解决思路不是简单调小隐层,而是同步调大λ,让流形正则的约束力跟模型容量匹配。

6. 应用场景扩展与我的使用体会

6.1 适合SS-US-ELM的任务特征

结合我自己的跑题经验,SS-ELM特别适合“标签极少、无标签数据量大、数据本身有清晰流形结构”的任务。典型的比如文本分类里只有几十篇人工标注,但语料库里躺着几万篇未标注文档,词语的分布本身就带着很强的结构线索;再比如工业场景的传感器故障诊断,正常样本随手可得,故障样本要等真实故障出现才有一条。US-ELM则适合那些“不知道有几类、需要快速看结构”的探索性分析,比如用户行为分群、图像特征预聚类,在正式标注之前先跑一遍US-ELM看看簇与簇之间分得开不开,能省不少标注预算。

一个我自己印象很深的例子:实验室A同学要给一组高维传感器数据做状态识别,手里只有20来个有效标注样本,剩下四千多个样本不知道属于哪类。他一开始直接用监督ELM训练,测试准确率最高只有61%,而且很不稳定。后来我把SS-ELM的框架给他,无标签样本参与流形正则后,准确率在同一个数据集上直接到了82%。差别就在于那四千个样本虽然没有标签,但它们在高维空间里的近邻关系把不同状态之间的边界“撑开”了,分类器因此变得稳定很多。

6.2 扩展思路:集成、多核、在线学习

SS-US-ELM的框架还能往几个方向扩展。第一个是多核ELM,把不同激活函数(sigmoid、tanh、RBF)生成的隐层拼接在一起,相当于构造一个更宽的特征空间,之后再套SS-ELM或US-ELM,往往能提升流形正则项的表达力。第二个是集成学习,每次随机生成不同的W和b,重复训练多个SS-ELM模型,最后对输出投票或取平均。ELM本身带随机性,集成能显著平滑这种方差。第三个是在线学习,如果数据流式到来,可以分批更新图拉普拉斯和H矩阵,再用增量方式更新β,不必每次全量重算。

不过扩展时也要注意控制成本。多核拼接会让L成倍增加,HᵀLH的计算代价上涨很快;集成训练则是拿时间换稳定性。我一般会先跑一个单模型判断方向,再决定要不要上扩展方案。

6.3 关于这套框架的使用体会

写了这么多代码和公式,最后聊聊我对SS-US-ELM的个人判断。它的定位不是要替代深度神经网络,而是给“标签稀缺、算力有限、需要快速出结果”的场景提供一个高性价比选项。优点非常明显:闭式解、不迭代、Matlab代码几十行能跑通、原理透明可控。瓶颈也很清楚:图拉普拉斯构造依赖k近邻,样本量大了以后计算量是瓶颈;随机隐层虽然快,但可复现性不如全监督学习的显式特征提取,需要多次随机种子做对比才能确定结果稳定。

我自己的实践心得是:拿到一份新的SS-US-ELM代码,千万不要直接拿默认参数去跑业务数据。先在一个小规模子集上把隐层节点数、C、λ分别扫一遍,画出一条简单的性能曲线,确认这套代码在你的数据分布下确实work,再放大到全量数据。ElM系列最迷惑人的地方在于它训练得太快了,以至于样本处理流程里细微的错误会被速度掩盖。只有先在小样本上把机制跑通,心里才有底。

最后再分享一个小技巧:如果你不太确定无标签数据的图结构应该用多少近邻数,不妨把k从5到20扫一遍,观察β矩阵的变化幅度。如果k在这个区间内β的数值变化很小,说明流形正则对k不敏感,结果可靠;如果β变化巨大,那说明你的特征尺度或归一化方式有问题,先回去修数据预处理,比调k更重要。这套代码的价值不在于“跑通”,而在于你通过调整λ和k,真正理解了无标签数据是如何通过图结构把自己的先验知识传递给分类器的。

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

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

立即咨询