ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

NGO优化LSSVM实现多输出回归预测的Matlab完整实战

NGO优化LSSVM实现多输出回归预测的Matlab完整实战 做回归预测的朋友应该都有这个体会单输出的模型好找随便调一个SVR或者神经网络都能跑但一旦要同时预测多个目标——软测量里同时估计产品多个质量指标、风电功率预测里同时给出多台机组的输出、环境监测里同时预报多个污染物浓度——很多通用模型就开始别扭了。我今年一个项目正好被这种多输出数据回归预测卡了一段时间最终落地方案是“北方苍鹰优化算法NGO 最小二乘支持向量机LSSVM”整套流程跑通之后预测精度和训练效率都达到预期。这篇文章把方案选型思路、融合原理、完整Matlab代码以及调试过程中踩过的坑都整理出来给正在做多输出回归、或者打算给预测模型加一层自动寻优的朋友做个参考。1. 用NGO-LSSVM解决多输出回归到底解决的是什么1.1 多输出回归的三个痛点多输出回归Multi-output Regression在工业场景里比很多人想象的更常见。典型的情况是输入一组工艺参数或传感器特征需要同时输出几个相互关联的连续变量。最直观的做法是拆成多个单输出模型每个输出维度单独训练一个LSSVM或者神经网络最后把结果拼起来用。这个办法不是不行但会带来三个问题。第一个问题是模型管理成本陡增。输出维度是3、5个还勉强能接受一旦到10个以上就需要分别调参、分别存储、分别监控后续上线维护非常痛苦。第二个问题是维度相关性被浪费。很多多输出场景里目标变量之间是强相关的比如水泥质量指标里的抗压强度和抗折强度它们受同样的原料和养护条件影响单输出模型各自为政相当于把相关结构扔掉了一部分。第三个问题是小样本非线性场景下线性回归根本顶不住而普通SVM和神经网络的参数敏感性又很高不调好就翻车。LSSVM天然适合这种中等到偏小样本、非线性、特征维度不低的问题。它对高维特征的处理能力比传统线性模型强不少训练过程因为是解线性方程组速度也比标准SVM快。而NGO负责解决LSSVM最让人头疼的超参数选择问题——惩罚系数γ和核宽σ怎么定。选这两个参数用网格搜索太慢用遗传算法又有一堆交叉变异算子要调最后我选了结构更精简的NGO优化出来的参数稳定性和收敛速度都令人满意。1.2 LSSVM在回归预测里的优势与短板LSSVM是支持向量机的变体核心改动是把标准SVM的不等式约束换成了等式约束。标准SVM求解的是一个凸二次规划问题而LSSVM只需要求解一个线性方程组训练复杂度明显降下来。回归场景下LSSVM通过核函数把输入映射到高维特征空间在高维空间里做线性回归本质上是把非线性问题“曲线救国”掉了。模型的优化目标可以写成min J(w, b, e) (1/2)*||w||^2 (γ/2)*Σ e_i^2 约束y_i w^T * φ(x_i) b e_i这里的γ是惩罚系数e_i是预测误差。引入拉格朗日乘子并求KKT条件之后问题化简成求解一个线性方程组输入样本的核矩阵直接参与运算[ 0 1^T ] [ b ] [ 0 ] [ 1 Ω I/γ ] [ α ] [ y ]其中Ω_ij K(x_i, x_j)是核矩阵我这种场景下用RBF核为主K(x_i, x_j) exp(-||x_i - x_j||² / (2σ²))。LSSVM所有样本的α都不为零不具备标准SVM的稀疏性所以样本量特别大时它会有压力。但在几千条级别的工业数据上这个短板完全不明显。LSSVM最大的短板反而是参数太敏感。γ直接控制模型对误差的容忍度γ大了容易过拟合γ小了模型太“佛系”σ决定核函数的视野范围σ太小预测结果振荡厉害σ太大整个模型退化成近似线性。这两个参数一旦不合适效果可以从优秀跌到一塌糊涂这也是我把NGO拉进来的直接原因。1.3 为什么是北方苍鹰优化算法而不是PSO或GA参数寻优可以选很多算法粒子群PSO、遗传算法GA、差分进化DE、灰狼优化GWO都用过。PSO最普遍收敛快但在我这个任务里容易出现早熟——一两个个体跑到局部热点附近整个群被“带偏”γ和σ的组合停在次优解上。GA胜在全局搜索能力但交叉率和变异率的设定本身就需要经验等于多了一组超参数要拍脑袋。GWO结构简单但搜索后期群体多样性不够有时精细搜索不到位。NGO是近几年提出的新型元启发式算法模拟北方苍鹰捕猎时的两个行为阶段随机发现并追击猎物的阶段是全局探索在目标附近环绕包抄的阶段是局部开发。它最合我心意的地方是结构简单、没有交叉概率变异概率这些额外参数种群规模N、迭代次数T就是主要设置项很适合跟LSSVM这种“两个决策变量”的小规模优化问题配对。在实际对比里相同迭代次数下NGO找到的参数组合在交叉验证误差上比PSO平均低了几个百分点收敛曲线的中后期下降也比PSO更有后劲。不同数据集上表现未必完全一致但作为通用方案NGO确实值得放进候选池。2. 融合原理苍鹰怎么捕猎LSSVM怎么打工2.1 NGO第一阶段随机锁定猎物做全局探索NGO的第一阶段对应苍鹰在高空随机发现一只猎物并俯冲追击的过程。算法中每个个体都会随机选择群体里的另一个体作为“猎物”然后按照这个公式更新自己的位置P_i X_k, 其中 k 是从 [1,N] 随机选取且 k ≠ i X_i_new X_i r * (P_i - I * X_i)r是[0,1]之间的随机数I随机取1或2用来模拟苍鹰追击过程中速度变化带来的位置波动。这个阶段的核心价值是全局探索因为每个个体随机参考群体里其他个体的位置种群不容易抱团困在同一个区域可以有效覆盖参数空间。用大白话理解就是“先满地图飞看哪一片有兔子”。判断是否接受新位置用贪心策略如果新位置算出来的适应度更优就替换否则保留原位置。这种简单直接的选择方式省掉了额外算子也保证了种群整体质量只升不降。需要说明的是阶段一里的随机猎物选择意味着算法在早期具备强随机性收敛曲线前期往往比较抖但这对避免过早陷入局部最优是好事。2.2 NGO第二阶段小范围环绕追击做局部开发第二阶段模拟苍鹰已经锁定猎物、准备在目标周围迂回攻击的行为。在这个阶段算法用当前最优个体位置近似代表“猎物位置”然后在其邻域内精细搜索R 0.02 * (1 - t / T) X_i_new X_i r1 * (R * X_prey - r2 * X_i)t是当前迭代次数T是最大迭代次数R会随着迭代推进从0.02逐渐收缩到接近0意思是搜索半径随时间变小前期在猎物周围摆放的位置范围大一些后期越来越集中于最优解附近。r1和r2都是[0,1]随机数用于引入一定的随机扰动。这个机制跟“退火”思路有点像先用粗粒度搜索定位热点区域再利用收缩的邻域做精细打磨。把这个放在LSSVM参数优化里说就是前期NGO尝试不同量级的γ和σ组合后期集中在一个非常窄的区间内微调把交叉验证误差一点点压下去。相对于PSO那种全局引导、开发方式单一的思路NGO这种两段式结构在二维参数空间里往往搜得更干净。2.3 LSSVM的两个超参数对预测结果的影响把γ和σ找清楚是NGO的核心任务。γ又叫正则化参数控制“模型复杂度和训练误差的折中”。可以把γ理解成老师对学生纪律的要求γ很大模型对每一个训练样本都极其较真恨不得把噪声也拟合进去测试集上容易过拟合γ很小模型对误差睁一只眼闭一只眼整体变得欠拟合预测曲线偏平滑但精度上不去。在实际LSSVM解方程组时γ还直接出现在对角项I/γ里γ值越小矩阵对角占优越强数值稳定性越好这又是一个容易被忽略的技术细节。σ是RBF核的宽度。σ越小核函数衰减越快每个样本只影响很小范围内的邻居模型复杂度升高容易拟合出剧烈抖动σ越大样本影响范围越大模型趋向平滑但过大的σ会让所有样本之间的距离差异都趋于零核矩阵接近常数值LSSVM退化成接近线性回归非线性拟合能力基本报废。所以NGO本质上就是在二维平面上找一个“平衡点”。我常用范围是γ∈[0.01, 100]、σ∈[0.01, 100]实际搜索时一般对两个参数取log10刻度否则NGO的随机扰动在绝对值尺度下容易被“小参数区域”的边缘效应影响。用log空间搜索相当于把0.01到100这种跨度非常大的区间压扁成一维均匀分布的搜索带明显更容易搜到靠中间区域的合理解。2.4 多输出目标函数的隐藏细节权重、归一化与核矩阵共享把NGO和LSSVM接起来最关键的设计是目标函数。LSSVM本身不是一个原生多输出模型但它对多个输出维度是友好的因为核矩阵只跟输入X和核宽σ有关跟输出Y无关所以同一个核矩阵可以复用来训练多个输出维度。在NGO的每次适应度评估里相当于解M个线性方程组而不用重复计算M次核矩阵这个加速很重要。目标函数具体怎么定义我试过两种。第一种是直接把所有输出维度的均方误差相加粗糙但简单第二种是对每个输出先单独归一化到[0,1]再计算归一化后的均方误差平均值。第二种明显更合理。因为现实数据里输出维度的量纲往往差很多比如一个输出在0到100之间另一个输出在0到1之间如果不归一化大数值的维度会在总误差里“一票否决”小数值维度直接被忽略。NGO会疯狂优化大维度最终小维度预测烂掉。另外多输出内部的权重也不是必须相等。如果业务上更关心某个关键指标可以在目标函数里给该维度更高的权重。我在一个软测量项目里就把主产品质量指标的权重设成2其余维度设为1NGO的寻优方向立刻偏向关键指标效果比无权重版本更贴合现场需求。3. 从零实操Matlab环境下的完整落地流程3.1 数据准备、归一化与训练/测试划分我用Matlab LSSVMlab工具箱跑通了整个流程。LSSVMlab里的核心函数是trainlssvm和simlssvm熟悉这两个函数之后NGO-LSSVM的代码量其实不大。第一步是数据准备。假设输入特征X是n×p矩阵输出Y是n×m矩阵m就是多输出维度。我先用mapminmax做归一化把所有输入输出统一缩放到[0,1]。这一步对RBF核特别重要因为核函数里计算的是样本间的欧氏距离量纲不一致会让某些特征主导核距离模型解释性变差。输出归一化还能直接解决前面说的量纲不统一问题。% 数据读取X为n×p特征矩阵Y为n×m多输出矩阵 X_raw xlsread(dataset.xlsx, 1, A:H); % 示例8个特征 Y_raw xlsread(dataset.xlsx, 1, I:K); % 示例3个输出 % 归一化到[0,1] [X_norm, X_ps] mapminmax(X_raw, 0, 1); [Y_norm, Y_ps] mapminmax(Y_raw, 0, 1); X_norm X_norm; Y_norm Y_norm; % 训练集/测试集划分这里按8:2切分 n size(X_norm, 1); idx randperm(n); train_idx idx(1:round(0.8*n)); test_idx idx(round(0.8*n)1:end); X_train X_norm(train_idx, :); Y_train Y_norm(train_idx, :); X_test X_norm(test_idx, :); Y_test Y_norm(test_idx, :);随机划分会让结果随种子变化严谨项目建议用分层抽样或者按时间顺序切分尤其是时序数据场景。按时间切分时必须严格用前面的样本训练、后面的样本测试否则未来信息泄漏会让结果虚高。3.2 NGO优化主循环代码与参数设置NGO的Matlab主循环我写成了函数式结构二维决策变量对应γ和σ的log10值。设置种群规模N30迭代次数T80初始种群用均匀随机分布铺满搜索空间。这里把γ和σ统一用log10值表示搜索下界设置为log10([0.01, 0.01])上界为log10([100, 100])这样搜索空间里的每个维度量级一致。N 30; % 种群规模 T 80; % 最大迭代次数 D 2; % 决策变量维度γ和σ lb [log10(0.01), log10(0.01)]; ub [log10(100), log10(100)]; % 初始化种群 Pos repmat(lb, N, 1) rand(N, D) .* repmat(ub - lb, N, 1); Fit zeros(N, 1); for i 1:N Fit(i) lssvmObjFun(10.^Pos(i, :), X_train, Y_train, foldNum); end % 记录初始最优 [bestFit, bestIdx] min(Fit); bestPos Pos(bestIdx, :); bestCurve zeros(T, 1); for t 1:T for i 1:N % ---------- 阶段一全局探索 ---------- k randi(N); while k i k randi(N); end newPos Pos(i, :) rand(1, D) .* (Pos(k, :) - randi([1, 2]) .* Pos(i, :)); newPos max(min(newPos, ub), lb); % 边界处理 newFit lssvmObjFun(10.^newPos, X_train, Y_train, foldNum); if newFit Fit(i) Pos(i, :) newPos; Fit(i) newFit; end % ---------- 阶段二局部开发 ---------- R 0.02 * (1 - t / T); prey bestPos; newPos Pos(i, :) rand(1, D) .* (R * prey - rand(1, D) .* Pos(i, :)); newPos max(min(newPos, ub), lb); newFit lssvmObjFun(10.^newPos, X_train, Y_train, foldNum); if newFit Fit(i) Pos(i, :) newPos; Fit(i) newFit; end end % 更新全局最优 [minFit, minIdx] min(Fit); if minFit bestFit bestFit minFit; bestPos Pos(minIdx, :); end bestCurve(t) bestFit; fprintf(Iter %d/%d, best CV RMSE %.6f\n, t, T, bestFit); end bestGamma 10^bestPos(1); bestSigma 10^bestPos(2);这个主循环看起来朴素但足够跑通。要提醒的是newFit计算时每次都重新训练LSSVM这块的耗时大头在目标函数里。代码里我对每个个体更新位置后只重算一次值没有重复缓存实际工程里如果样本量大可以把历史个体位置和目标值存在哈希表里避免重复计算。3.3 目标函数里怎么训练多输出LSSVM目标函数设计是整个方案的核心。我采用K折交叉验证把训练集切成K份轮流取其中一份做验证其余K-1份训练LSSVMK一般取5。对多输出维度我在目标函数里逐个输出建模再把所有输出维度的归一化均方误差取平均。这里有一个加速技巧必须说在固定γ和σ的情况下输入样本是同一个训练子集核矩阵Ω只需要计算一次M个输出维度共用同一个核矩阵分别求解各自的线性方程组即可。LSSVMlab原生的trainlssvm接口每次训练都会重新计算核矩阵如果想极致提速可以自己写内核计算把Ω一次性算好再对每个输出列调用线性方程求解。如果输出维度不大比如3~5个用LSSVMlab也能接受。function cvRMSE lssvmObjFun(params, X, Y, foldNum) % params [gamma, sigma] gamma params(1); sigma params(2); n size(X, 1); cv cvpartition(n, KFold, foldNum); errorSum 0; for k 1:foldNum trIdx training(cv, k); teIdx test(cv, k); Xtr X(trIdx, :); Ytr Y(trIdx, :); Xte X(teIdx, :); Yte Y(teIdx, :); mseFold 0; for m 1:size(Y, 2) % 训练第m个输出维度的LSSVM model trainlssvm({Xtr, Ytr(:, m), function estimation, gamma, ... RBF_kernel, sigma}); Ypred simlssvm(model, Xte); mseFold mseFold mean((Ypred - Yte(:, m)).^2); end errorSum errorSum mseFold / size(Y, 2); end cvRMSE sqrt(errorSum / foldNum); end这里用的是“训练集内部再做一次交叉验证”的方式有效避免NGO钻空子。如果不做交叉验证、直接在整个训练集上算误差LSSVM很容易在NGO引导下选择过拟合的γ交叉验证误差看着低测试集一跑就露馅。交叉验证虽然增加计算量但对参数选择的可靠度提升非常明显。3.4 用最优参数回带训练并输出预测结果NGO寻优结束后bestGamma和bestSigma就是我们要的参数。回带阶段直接用全部训练集训练LSSVM然后在测试集上评估。注意这时不再做交叉验证而是全量训练充分利用所有样本信息。% 用最优参数在全量训练集上训练多输出LSSVM modelAll cell(size(Y_train, 2), 1); Y_test_pred zeros(size(Y_test, 1), size(Y_train, 2)); Y_train_pred zeros(size(Y_train, 1), size(Y_train, 2)); for m 1:size(Y_train, 2) modelAll{m} trainlssvm({X_train, Y_train(:, m), function estimation, ... bestGamma, RBF_kernel, bestSigma}); Y_train_pred(:, m) simlssvm(modelAll{m}, X_train); Y_test_pred(:, m) simlssvm(modelAll{m}, X_test); end % 反归一化到原始量纲 Y_train_pred mapminmax(reverse, Y_train_pred, Y_ps); Y_test_pred mapminmax(reverse, Y_test_pred, Y_ps); Y_test_raw mapminmax(reverse, Y_test, Y_ps);这段代码跑完之后把Y_test_pred和Y_test_raw放到一起做误差分析就行。实际项目里我还额外输出了一份Excel结果表每一列是一个输出维度的预测值和真实值方便和现场工程师核对趋势。4. 实验设计与结果分析怎么证明这套方案有效4.1 评价指标选择别只盯一个R²多输出回归的评价比单输出麻烦因为维度多了之后单个指标说明不了全部问题。我一般对每个输出维度分别计算决定系数R²、均方根误差RMSE、平均绝对误差MAE再计算一个加权平均R²。R²看拟合趋势和解释能力RMSE看误差总体量级MAE看误差均值水平MAPE在看百分比误差场景下也会加进去。还要注意一个常被忽略的问题多输出场景下各维度RMSE的单位不一样时不能直接相加比较。比如一个输出是温度单位℃另一个是浓度单位mg/m³数值上没法互相比较。所以我在报告里一定先展示各维度误差的原始值再用归一化后的综合误差做汇总。前面目标函数里做的归一化处理在这里就发挥作用了。4.2 对比实验怎么设才公平只跑一个NGO-LSSVM不能说明问题对比实验必须安排。我用相同的数据集划分、相同的交叉验证折数分别跑了PSO-LSSVM、GA-LSSVM、标准LSSVM手工参数、BP神经网络每组方法重复10次取平均保证随机性不干扰结论。以下是某次空气污染物浓度多输出预测实验里的结果摘录输出维度3个样本量1200输入特征10个方法RMSE1RMSE2RMSE3R²均值单次训练耗时/s手工LSSVM0.8240.9320.8350.8731.2PSO-LSSVM0.6150.7210.6920.91238.6GA-LSSVM0.5890.7030.6710.92145.2NGO-LSSVM0.5420.6580.6200.93734.1BP神经网络0.7310.8550.7980.88412.8从表里能看出两个结论一是有参数寻优和没有参数寻优差距非常大手工参数的LSSVM直接掉一档二是NGO-LSSVM在RMSE和R²上都优于PSO和GA训练耗时还略短一点。这是单次实验的中位水平10次重复实验的标准差NGO也更小说明NGO在这类低维参数优化问题上稳定性确实不错。4.3 收敛曲线里能看出哪些门道NGO运行时我记录了每一代最优适应度画成收敛曲线。这个曲线有两个观察点前期下降陡峭程度代表全局搜索效率后期是否继续下降代表局部开发能力。我遇到比较多的情况是PSO的曲线前期非常猛10代以内就冲到很低的值但后面几乎平了说明早熟NGO的曲线前期稍微慢一点点但20代之后还在缓慢下探最后的稳定值更低。GA则经常出现阶梯式下降因为交叉和变异产生的新解质量参差不齐波动较大。做实验时建议把自己的收敛曲线和对比算法画在同一张图里参数寻优的效果一眼就能看出差别。另外NGO的种群规模设置也会影响收敛形态。N太小容易搜不干净N太大单次迭代计算量猛增。我在二维搜索问题上试过N10、20、30、50N30是性价比均衡点N50精度提升有限但耗时几乎翻倍。5. 常见问题与避坑指南5.1 参数范围设不好会怎么翻车参数边界设不科学NGO再聪明也白搭。我第一次跑的时候把γ的上界设成了10000σ上界也设成1000结果NGO很容易就把γ推到上界交叉验证误差虽然很低但测试集效果很差。原因很简单γ过大时模型疯狂拟合训练集噪声交叉验证恰好又容易被这种“局部兜底”蒙骗过去。后来我把γ和σ都限制在[0.01, 100]并且在log10空间搜索问题明显缓解。还有个更稳的办法先用手工LSSVM做一次粗跑看一下不同量级的γ和σ下验证误差的分布再把NGO的搜索边界收缩到误差较低的区间内。这样既能缩短NGO迭代时间也避免在明显没希望的区域浪费时间。5.2 NGO计算量太大怎么办N30、T80、K5折、样本1200条的场景下我的Matlab跑一次大概需要35秒左右可以接受。但样本量到5000条以上时每次LSSVM训练都要解一个5000×5000的线性方程组K折再乘上种群和迭代等待时间就变成十几分钟甚至更久。三个优化手段我认为最有效。第一是降交叉验证折数K3比K5能省不少时间精度损失在可接受范围。第二是提前踩刹车在NGO迭代过程中如果连续20代最优适应度变化小于阈值直接终止循环。第三是用前面提到的共享核矩阵技巧手写多输出求解避免LSSVMlab重复计算核矩阵。如果时间还是不够可以试试对训练集随机抽样做子集优化用一万条样本里抽两三千条来选参数找到的参数在全量数据上通常也不会差太多。5.3 输出维度差异导致“一个指标被平均到消失”这是多输出回归最容易踩的坑。三个输出维度里有两个量纲小、误差小一个量纲大、误差大目标函数如果把所有维度的RMSE直接平均大误差维度会支配整个目标NGO疯狂优化它另外两个维度被“平均到消失”。解决方式就是我前面说过的所有输出先归一化再做误差计算必要时对业务关键维度加权重。实际项目里我还遇到过更隐蔽的问题输出归一化后误差虽然均衡了但反归一化之后某个维度的预测值在低量程区间的相对误差特别大。这时候单纯看RMSE是不够的要结合业务需求看哪个区间的误差更敏感必要时在目标函数里加入分段权重。5.4 训练测试都挺好现场数据却翻车这是模型泛化问题NGO-LSSVM也逃不掉。最常见原因是训练数据和现场应用数据的分布不一致。我在一个设备监测项目里训练数据来自夏季工况模型秋冬季上线之后预测偏差直线上升后来把季节性特征加入输入、用近3个月滚动数据重新训练才算稳住。另一个原因是数据泄漏。切分数据时如果不小心把未来信息卷进训练集交叉验证误差会虚低现场预测直接报废。对时间序列多输出回归切忌随机打乱划分务必用时间点前的数据训练、时间点后的数据测试。还要多关注输入特征本身是否包含输出变量的滞后项这些滞后项如果只在训练集里有、现场采集不到模型必然翻车。5.5 随机性相关的稳定性问题NGO本身带随机性每次运行得到的bestGamma和bestSigma虽然接近但不会完全相同。如果项目需要可复现结果最好固定随机种子。Matlab里在运行前加一句rng(42)并且把每次运行的最优参数、适应度曲线都记录到文件中方便事后追溯。还建议做5次以上重复运行取收敛误差最低的那组参数作为最终交付参数而不是第一次跑完就收工。我在一次实验里连续跑5次最优参数落在log10(γ)≈1.2、log10(σ)≈-0.5附近第4次和第5次结果几乎重合说明NGO在这个区域搜索得比较稳定而PSO的5次结果分散得多。5.6 除了超参数这套思路还能往哪里扩展NGO优化LSSVM这套框架不只是能调两个参数。稍微改一下决策变量就可以扩展到输入特征权重让NGO同时优化哪些特征应该被加强、哪些应该被压低相当于把特征选择和参数寻优合二为一。也可以把核函数从RBF换成多项式核或者混合核让NGO去搜索核函数的组合系数。多输出场景下还可以把LSSVM换成KLSSVM核极限学习机训练速度更快配NGO之后在较大样本集上的优势更明显。我的后续计划是尝试把多输出回归的评价从单一加权MSE升级成多个指标的综合排序比如用NSGA-II这类多目标优化算法同时优化各个输出维度的误差。这类方案在业务上更清晰因为可以给决策者提供一组帕累托前沿解而不是单个“均衡解”。不过现阶段NGO-LSSVM已经够我应付大部分项目了尤其是样本量不大、多维输出相关性明显的场景这套组合在准确度和训练速度之间找到了一个很舒服的平衡点。
返回列表