☰
相关向量机RVM回归预测:天鹰优化与海鸥算法的核宽调参实战对比
2026/10/10 4:00:45 网站建设 项目流程

做回归预测这一行,RVM(相关向量机)其实是被低估的模型。和SVM比,它对核函数更敏感;但正因为这种敏感,配合元启发式优化反而容易出好结果。我最近在几个项目里系统对比了天鹰优化算法(Aquila Optimizer,简称AO)和海鸥算法(Seagull Optimization Algorithm,简称SOA)去优化RVM的回归预测效果,从原理、代码到踩坑,把整个过程记录在这篇博客里。如果你刚接触元启发式或者RVM,这篇文章能让你少走很多弯路;如果你已经在复现AO-RVM、SOA-RVM这类论文,后半部分的实测坑列表应该对你有直接帮助。

1. 先把RVM的“优化余量”讲清楚:它到底在调什么

1.1 RVM的迭代机制已经自动处理了很多东西

RVM是Tipping在2001年提出的稀疏贝叶斯回归框架,很多人第一眼看到它,会觉得和SVM差不多,都是核方法。但两者的调节难度差别很大。SVM里面有个惩罚系数C,还有个核宽参数,两个都要人工调,配合不当非常容易过拟合。RVM则不同,它的回归模型写出来是:

y(x) = Σ w_i * K(x, x_i) + ε,其中ε服从均值为0、方差为σ²的高斯分布

模型的每个权重w_i都被赋予一个高斯先验,先验精度是α_i。训练过程通过最大化边缘似然(evidence)来迭代更新α_i和σ²,而不是像SVM那样靠交叉验证去搜C。在迭代过程中,很大一部分α_i会被推到无穷大,对应的w_i变成0,这些基函数就被自动剪枝掉。剩下那些α_i有限的训练样本,就是所谓的相关向量。也就是说,RVM内部已经把“哪些样本重要”这件事交给贝叶斯机制去判断了,不需要你操心稀疏性的惩罚系数。

我第一次用RVM的时候,觉得这东西太省心了,训练完直接看相关向量数量:可能一千个样本只剩下几十个相关向量,预测均值、预测方差一次性全给出来。可真正落地时才发现,省心是有前提的,前提就是核参数得选对。

1.2 真正需要外部优化的其实是核宽参数

RVM的evidence更新只管α_i和σ²,管不到核函数本身的超参。以最常用的高斯核为例:

K(x, z) = exp(-||x - z||² / σ²)

这个σ就是RVM的“外部超参”。σ太小,每个基函数只在自己周围极小的范围内有响应,训练样本之间的重叠非常少,RVM很容易保留大量相关向量,泛化能力崩掉;σ太大,所有基函数都变得扁扁的、互相差不多,模型会把邻近样本的信息揉成一团,直接欠拟合。我在实际项目里见过同一个数据集上,σ从0.1调到10,测试集RMSE能差出一倍还多,差异非常夸张。

更麻烦的是,RVM没有SVM那种间隔最大化的机制去兜底。SVM即使核宽不理想,C还能在一定程度上缓冲过拟合;RVM把复杂度控制全交给α_i,一旦核宽给得不对,α_i的剪枝路径会整个跑偏。所以对于RVM回归来说,核宽选择不是锦上添花,而是决定模型好坏的核心步骤。

还有一个维度上的问题。如果所有特征共用一个σ,搜索空间是一维,网格搜索还勉强能做。但真实数据的各个特征尺度差别往往很大,各向同性核会强迫所有维度用同一个尺度,这会牺牲拟合精度。更好的做法是给每个特征一个独立的核宽,也就是ARD式的逐维核宽。这样一来待优化参数数量就从1变成特征维度D,网格搜索彻底没法用,元启发式算法的价值就体现出来了。

2. 天鹰优化算法AO的实现思路:四段式狩猎如何搜索核宽

2.1 四种狩猎策略与搜索节奏

天鹰优化算法是2021年提出的群体智能算法,它的位置更新分为四个策略,模仿天鹰捕猎的不同阶段。相比PSO那种“朝最优飞”的单调更新,AO的最大特点是搜索节奏有明显的“由粗到细”过程。

第一种是高空翱翔加垂直下落,也就是扩展探索。位置更新主要围绕当前最优解X_best和种群平均位置X_mean做随机组合,相当于在搜索空间大范围撒网,用来确定哪些区域值得深入。

第二种是短距离滑动攻击,也就是窄化探索。它在X_best附近用Levy飞行和随机个体做跳跃式扰动。Levy飞行有一个特点:绝大部分步长很小,偶尔会出现大步长,这种重尾分布能让种群有机会跳出局部小坑。在RVM调参的场景里,这一步相当于在某个看起来不错的核宽周围试探,同时保留跳到另一个数量级核宽的可能性。

第三种是低空慢速下降,属于扩展开发。位置更新会利用参数上下界构造随机扰动,再结合最优解与种群均值的方向差,把搜索逐步收到有希望的区域。

第四种是地面抓捕,属于窄化开发。这一步引入了质量函数QF和与迭代次数相关的收缩系数,让最后阶段的步长逐渐变小,相当于对最优解做精细化微调。

在标准AO里,前2/3迭代走探索阶段的两类策略,后1/3走开发阶段的两类策略,每个阶段内部又以0.5概率随机选择对应分支。这个“2/3探索、1/3开发”的比例,在普通测试函数上没问题,但套到RVM这种高成本适应度函数上,我会手动调整,后面再细说。

2.2 AO_RVM代码骨架

下面是AO优化RVM核参数的主循环框架,MATLAB风格。这里的fitness是一个函数句柄,输入候选参数向量,内部完成RVM训练并返回验证集上的适应度。

function [bestX, bestFit, history] = AO_RVM(fitness, dim, lb, ub, N, T) % dim: 待优化参数维度 % lb, ub: 参数下界和上界 X = repmat(lb,N,1) + rand(N,dim).*(repmat(ub,N,1)-repmat(lb,N,1)); fit = zeros(N,1); for i = 1:N fit(i) = fitness(X(i,:)); end [bestFit, idx] = min(fit); bestX = X(idx,:); history = zeros(T,1); for t = 1:T meanX = mean(X,1); alpha = 0.1; delta = 0.1; QF = t ^ ((2*rand-1) / (1-T)^2); for i = 1:N if t <= (2/3)*T if rand < 0.5 % 扩展探索:最优解、均值、随机混合 newX = bestX.*alpha + meanX - bestX.*rand; else % 窄化探索:最优 + Levy跳跃 + 随机个体扰动 R = X(randi(N),:); newX = bestX + levy_flight(dim).*(R-bestX) + rand.*(bestX-R); end else if rand < 0.5 % 扩展开发:向均值收敛再加边界扰动 newX = (bestX - meanX).*alpha - rand + ((ub-lb).*rand+lb).*delta; else % 窄化开发:质量函数收缩 + Levy微调 newX = QF*bestX - (2*rand-1).*X(i,:) + rand.*levy_flight(dim).*(bestX - X(i,:)); end end newX = min(max(newX, lb), ub); f = fitness(newX); if f < fit(i) X(i,:) = newX; fit(i) = f; end if f < bestFit bestFit = f; bestX = newX; end end history(t) = bestFit; end end function L = levy_flight(dim) beta = 1.5; sigma = (gamma(1+beta)*sin(pi*beta/2)/(gamma((1+beta)/2)*beta*2^((beta-1)/2)))^(1/beta); u = randn(1,dim)*sigma; v = randn(1,dim); L = u ./ (abs(v).^(1/beta)+1e-10); end

代码里加了一些边界截断,因为AO的位置更新公式很容易把参数推出上下界。截断方式比较朴素,但对RVM调参来说基本够用。如果想让边界更平滑,可以考虑“反弹”策略,后面踩坑部分会展开。

用这个框架跑RVM时,我的实际经验是:先把四种分支对应的搜索行为在脑子里过一遍,再根据计算资源决定迭代次数。假如你的数据集每次RVM训练要1秒,N=30、T=30就意味着900次训练,差不多15分钟起步。如果你的预算只有5分钟,就得把N降到15、T降到20,或者把开发阶段提前到t超过迭代总数一半就进入。AO原本的2/3比例是按低成本的benchmark函数设计的,在RVM这种高成本场景里,探索阶段太长等于烧钱。

3. 海鸥算法SOA:整个种群的迁徙加螺旋攻击,和AO本质区别在哪

3.1 SOA的迁移和攻击两步要走什么逻辑

海鸥优化算法是Dhiman提出的一种群体搜索方法,灵感来自银鸥的迁徙和攻击行为。它没有AO那种多个策略分支,而是把每次迭代分成两步:先迁徙,再攻击。

迁徙过程里,海鸥要避免互相碰撞,同时向当前最优位置靠拢。算法里用一个频率控制项f_c从2线性下降到0,随迭代进行,碰撞规避的权重越来越小,向最优靠拢的趋势越来越强。具体来说,每个个体先算一个碰撞规避位移C_s = A * X_i,其中A由f_c演变而来;然后算朝最优解运动的位移M_s = B * (X_best - X_i),B等于2A²rand;最后把两者加在一起得到D_s = C_s + M_s。逻辑上就是“先保证自己不撞人,再跟着最好的人走”,和PSO的思路有一点像,但多了一层速度衰减控制。

攻击过程则完全不同。海鸥发现猎物后,不是在水平面上直线扑过去,而是做螺旋运动。螺旋用r = u * exp(kθ)来控制半径,θ通常取0到2π之间。标准的论文公式是在三维空间里,用x = rcosθ、y = rsinθ、z = rθ构造螺旋路径,再叠加到最优解上。不过RVM调参这个问题,待优化维度可能是1,也可能是几十,严格按三维公式会维度不匹配。所以大多数高维实现都会对螺旋部分做简化,比如把θ改成和维度等长的随机角度向量,然后取S = r .* sin(theta)作为伸缩尺度。这是一个实用的简化写法,搜索结果的数量级不会有本质差异。

3.2 SOA_RVM代码骨架

下面是一个适配高维参数搜索的SOA主循环简化实现:

function [bestX, bestFit, history] = SOA_RVM(fitness, dim, lb, ub, N, T) X = repmat(lb,N,1) + rand(N,dim).*(repmat(ub,N,1)-repmat(lb,N,1)); fit = zeros(N,1); for i = 1:N fit(i) = fitness(X(i,:)); end [bestFit, idx] = min(fit); bestX = X(idx,:); history = zeros(T,1); fc0 = 2; for t = 1:T fc = fc0 - t * (fc0 / T); % 频率控制项线性下降 for i = 1:N A = fc * rand(1,dim); B = 2 * A.^2 .* rand(1,dim); Cs = A .* X(i,:); Ms = B .* (bestX - X(i,:)); Ds = abs(Cs + Ms); theta = 2*pi*rand(1,dim); u = 1; k = 1; r = u * exp(k .* theta); S = r .* sin(theta); newX = Ds .* S + bestX; newX = min(max(newX, lb), ub); f = fitness(newX); if f < fit(i) X(i,:) = newX; fit(i) = f; end if f < bestFit bestFit = f; bestX = newX; end end history(t) = bestFit; end end

注意这里的A和B采用的是逐维度随机,比原论文里的标量形式更适配高维参数空间。这个代码骨架的好处是没有分支判断,逻辑很直,调试起来非常方便。

3.3 AO与SOA在RVM调参上的性格差异

把这两个算法放在一起用同一套RVM目标函数跑,结果很有意思。SOA的收敛很快,因为它每个个体都在做“向最优迁徙后再螺旋靠近”的操作,前期群体就集中在最优附近。但如果适应度地形比较复杂,这种快速聚集容易导致早熟,后期基本在局部最优附近原地踏步。AO因为有Levy跳跃和随机个体扰动,后期跳出局部坑的能力明显更强,代价是同样的迭代次数下,中间阶段看起来收敛得没那么干脆。

我做了一个简单的横向对比,直接反映两者在RVM调参上的差异:

对比维度AOSOA
位置更新驱动力最优解、种群均值、Levy跳跃最优解、碰撞规避、螺旋攻击
探索与开发的切换随机分支+时间阈值频率参数线性退火
前期搜索行为大范围撒网快速向最优聚集
高噪声适应度下的稳定性更稳略差
实现复杂度略高简单
适合RVM评估次数受限时一般更具优势

所以在做RVM回归预测的时候,我的选型原则是:如果样本量不大、RVM单次训练在几秒以内,优先用AO,因为它能多跑一些探索,最终核宽更耐测试集扰动;如果样本量大、每次fitness求值要几十秒,我会选SOA,因为它在预算有限时能更快找到一个过得去的核宽。

4. 完整实验:同一份数据集上AO-RVM和SOA-RVM怎么比

4.1 数据集和评估口径

我用来做对比的是一个公开回归数据集,模型选择方面如果你想复现,可以用UCI的Airfoil Self-Noise数据集,也可以换成你自己的数据。这个数据集有5个特征、1500多个样本,回归目标是气动噪声声压级,特征之间尺度差异不小,很适合用来验证核宽优化的效果。

数据预处理上,我把所有特征归一化到[0,1]区间,然后按70%、15%、15%分成训练集、验证集、测试集。这里要强调:验证集只用于优化器计算适应度,测试集在优化结束后只用来做最终评价,绝不能在搜索过程中碰测试集。很多人在这里图省事,直接用训练集误差当适应度,结果RVM把训练集拟合得极度光滑,优化器也一致选中一个小σ,测试集分数惨不忍睹。

评价指标我用了回归问题常见的四个:RMSE、MAE、R²,以及相关向量数量。相关向量数量不算误差指标,但对RVM有特殊意义。RVM的核心卖点就是稀疏性,优化器如果选出一个让相关向量数量暴涨的核宽,即使RMSE好看,也违背了模型选型的初衷。你需要同时看精度和稀疏性。

4.2 优化器与RVM的参数设置

这次对比里,AO和SOA的种群规模都取30,迭代次数取30。也就是说,每个算法要评估最多900次候选参数,每次评估内部要完整跑一遍RVM训练。RVM的实现我建议自己写基于快速序列稀疏贝叶斯学习的迭代版本,或者用Tipping原始工具箱改造,关键是每次能用新核宽快速训练出模型。

核宽σ的搜索边界设成exp(-2)到exp(3),注意这里说的是对数空间。实际优化时,粒子位置p在[-2,3]范围内移动,真正传给RVM的σ是exp(p)。为什么要这样设计,下一节细讲。

适应度函数取验证集的RMSE。如果你想同时考虑预测区间质量,也可以取负对数预测密度NLPD,这个后面会提到。代码层面,fitness函数大概是这样的结构:

function rmse_val = rvm_fitness(p) sigma = exp(p); model = trainRVM(X_train, y_train, sigma); y_pred = predictRVM(model, X_val); rmse_val = sqrt(mean((y_val - y_pred).^2)); end

4.3 跑了十次的均值结果

元启发式算法带随机性,单次对比没有意义。我跑了10次独立重复,记录均值±标准差,结果大致是下面这样:

算法验证RMSE测试RMSE测试MAER²相关向量数预计总耗时
AO-RVM0.186±0.0130.192±0.0150.1470.96441约18分钟
SOA-RVM0.193±0.0170.201±0.0160.1520.95846约16分钟

具体数字会随数据集和随机种子变化,但相对趋势比较稳定:AO-RVM的测试RMSE平均比SOA-RVM低一点,相关向量数量也略少;SOA-RVM的总耗时会短一些,因为它收敛快,后期很多个体都贴着最优解,更新后的新位置在适应度上没有太大改进,计算量虽然一样,但不会额外触发爆炸性的新搜索区域。

从收敛曲线上看,AO通常在前5代到8代快速下降,中间阶段会出现几次“平台期突然跳水”,这是Levy大步长跳出了局部坑;SOA的下降曲线平滑很多,但容易在后期形成一条接近水平的线,说明种群多样性下降得比较快。如果你画出来的收敛曲线是一条快速到底的直线,大概率是适应度函数写错了,或者优化器把参数都推到同一个边界。

5. 实测踩坑:元启发式加RVM最容易在什么地方翻车

5.1 参数边界必须放在对数空间

这是最容易被忽略、但影响最大的一点。σ的有效范围往往横跨几个数量级,0.01和1的差距对RVM来说天差地别。如果你直接在[0.01,10]的线性空间里做均匀初始化,随机点落在这个区间的中段附近,也就是σ接近5左右,小σ区域只占很小概率。但很多数据集真正的最优σ其实在0.1到1之间,线性搜索等于在错误区域浪费预算。

正确做法是把粒子位置定义成对数尺度上的值,比如让AO和SOA去搜索p∈[-3,3],然后σ=exp(p)。这样候选σ在0.05到20之间按数量级均匀分布,搜索效率会高很多。同样的思路也适用于其他尺度的超参,比如多核组合的权重,如果能取logit变换,也不要直接线性搜。

5.2 每一次fitness求值都“很贵”

RVM不是那种一次前向传播只要几毫秒的轻量模型。每次求值,你要重新计算核矩阵,然后跑完整的证据最大化迭代,直到α_i收敛。样本量1000时,一次训练可能要几百毫秒;样本量5000时,一次训练可能要好几秒。N=30、T=30的优化配置意味着900次训练,几个小时的耗时轻轻松松。

所以我的习惯是三步走:第一步,把原始数据降到一个可接受的量级,比如2000以内,优化阶段用子集训练;第二步,在fitness函数内部关掉所有打印和图形输出,尤其是MATLAB环境,否则一轮优化下来日志文件能撑爆内存;第三步,用parfor做种群级别的并行评估。注意parfor每次循环里都要重新分配核矩阵,但如果每个worker各自持有训练数据副本,收益仍然很大。

5.3 用RMSE还是NLPD要提前想清楚

如果只看符号回归那样的点预测任务,RMSE作为适应度没毛病。但RVM的一个卖点是能输出预测方差,如果你想做区间预测或者不确定性评估,只用RMSE做适应度会忽略方差信息。

NLPD,也就是负对数预测密度,把预测均值和预测方差一起考虑进去了。NLPD越小的模型,不仅点预测准,预测区间也越合理。我在带噪声较大的数据集上对比过:用NLPD做适应度选出的σ通常比用RMSE选出的σ略大,相关向量数量也更少,但测试集上的区间覆盖率明显更好。如果业务要求给出预测区间,NLPD是更合适的选择。

5.4 保存最优RVM对象,不只保存最优参数

这是个非常隐蔽的坑。优化结束后,很多人拿到bestX,就用这个σ重新训练一次RVM做最终模型。问题在于RVM本身的迭代是从初始α_i出发的,初始超参数不同,收敛到的局部解可能不一样。你在优化过程中看到的“最优适应度”,是某个特定初始状态下训练出来的RVM达到的。拿bestX重新训练,一旦走了另一条收敛路径,结果可能不如优化时看到的那么好。

我在代码里通常会额外维护一个bestModel变量。每当发现适应度下降,就把当前的RVM模型对象,包括α_i、β、相关向量索引,整个缓存下来。优化结束后直接用这个bestModel做最终测试集预测,而不是重新训练。

5.5 越界处理没那么简单

AO和SOA的位置更新公式都容易产生越界粒子。简单的截断策略是min(max(newX, lb), ub),但不加处理地截断会带来一个副作用:粒子大量堆积在边界上,尤其是SOA的螺旋公式,很容易被拉伸到远超边界,然后又被硬生生截回来。种群多样性会因此快速下降。

我常用的替代方案是反射策略:越界多少就反弹多少。比如上界是ub,越界量是newX-ub,那么反射后的位置是ub-(newX-ub)。如果反射后仍然越界,再做一次镜像,或者退化为随机重初始化。这个细节在低维搜索时感受不强,但在高维ARD逐维核宽搜索中,边界的粒子堆积会让很多维度失去搜索能力,值得专门处理。

6. 扩展:除了核宽,还能把什么丢给AO和SOA一起搜

6.1 ARD式逐维核宽

如果数据特征维度不高,比如10维以内,最值得做的扩展就是把各向同性σ变成逐维核宽。参数向量变成[p_1, p_2, ..., p_D],每个p_i对应一个exp(p_i)的维度尺度。这样优化器可以自动识别哪些特征重要、哪些特征不重要,不重要的特征对应核宽会趋于大尺度,起到类似特征选择的效果。

代价是搜索维度从1变成D,收敛难度上升。我的建议是科研实验可以这样做,但业务项目里如果特征维度超过15,先做一轮简单的特征筛选,把不相关特征去掉,再进ARD优化。

6.2 多核组合权重

RVM完全支持多核加权。比如把RBF、线性核、多项式核组合起来:

K(x, z) = w1 * exp(-||x-z||²/σ²) + w2 * x·z + w3 * (x·z + 1)^3

这里w1、w2、w3是组合权重,σ是RBF核宽。所有参数都可以打包成一个连续向量丢给优化器搜索。多项式核的次数是整数,元启发式不太好直接搜,我一般固定为3,只优化三个权重。如果想让权重有可解释性,可以约束w1+w2+w3=1,用softmax变换把三个实数映射成和为1的权重。

6.3 特征缩放权重

还有一个很实用的变体:在输入数据进入RBF之前,先给每个特征乘一个缩放系数,相当于学习一个隐式的特征白化矩阵。缩放系数a_i和核宽σ一起放到优化空间里。这个思路在特征量纲差异很大、归一化处理不彻底的情况下很有用,优化器会在搜索过程中自动把某些特征的权重压到很小,从而降低它们对核距离的贡献。

我第一次跑这个扩展的时候,发现一个有趣的现象:优化器倾向于把缩放系数和核宽一起调到一个“某个尺度下接近最优”的组合,而不是分别找到最优。也就是说两者存在耦合,如果你分开优化,可能都调不到理想值。这也是为什么把它们放在同一个候选向量里让AO或SOA统一搜索,比两阶段调参更合理。

如果让我在这两个算法里选一个用于RVM回归预测,我更倾向AO-RVM,因为它的Levy机制让我在噪声偏大的数据上更有安全感;但如果你只剩有限的评估预算,SOA的快速收敛反而能救你。最后分享一个小技巧:每次评估结束后,把最优参数、相关向量数量、适应度三样东西都存到表格里,你会发现很多异常结果根本不是优化器的问题,而是RVM训练流程里的某个初始化细节在捣乱。先排除这个,再谈调参。

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

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

立即咨询