☰
基于粒子群优化算法的神经网络非线性函数拟合
2026/10/22 18:06:47 网站建设 项目流程

从一次把BP网络调崩溃的实验说起。

当时拿一个带噪声的非线性函数做拟合,函数本身不复杂:y = sin(3x)·exp(-0.5x²),只是在样本点上加了一点随机噪声。我按最常规的方式搭了一个单隐层BP网络,隐层节点取了6个,用MATLAB的nnet工具箱直接trainlm开训。头两次跑出来效果还行,但第三次、第四次训练曲线就像脱缰的野马,误差降到某个位置就再也不动了。换了不同初始权重、动了学习率、改了训练函数,折腾了一晚上,结论就一句话:BP对初始值太敏感,而这个初始值又是随机给的,心跳全交给运气了。

后来就把目光放到全局优化算法上。粒子群优化(PSO)这个算法原理不复杂,实现也不长,但它恰好补上了BP最难受的那块短板——不依赖梯度信息,靠群体协作在搜索空间里找最优位置。把粒子的位置设计成神经网络的权重和阈值,适应度函数设计成拟合误差,跑完迭代之后拿着搜索到的最优参数去搭网络,一次就能拿到一个稳定结果。这也就是标题里"基于粒子群优化算法的神经网络非线性函数拟合"这套方法的核心思路。

这篇文章会把整个方案展开讲清楚:为什么选PSO、怎么和神经网络结合、MATLAB代码怎么写、哪些参数坑最多、实测中遇到什么翻车问题,以及这套思路还能扩展到哪些场景。内容主要面向两类人:一是正在做课程设计或论文复现的学生,二是工作中遇到非线性建模需求、被BP调参折磨过的工程师。

1. 为什么这类拟合问题最后选了PSO:BP网络的两个老毛病

1.1 从一次不顺利的拟合实验说起

继续讲开头那次实验。函数原型是:

rng(2023); x = (-2: 0.05: 2)'; y = sin(3 * x) .* exp(-0.5 * x.^2) + 0.08 * randn(size(x));

一共81个样本点,输入x是[-2, 2]区间上的等间隔取值,输出y是一个典型的非线性映射关系。这种数据拿到手里,第一反应就是用BP网络拟合。网络结构设计成单隐层,输入节点1个,隐层节点6个,输出节点1个。隐层激活函数用tansig,输出层用purelin。之所以这么选,是因为输出值范围不是0到1的二分类问题,tansig输出区间是[-1, 1],经过输出层线性加权之后可以覆盖任意实数范围。

问题出在训练环节。我用trainlm跑了10次同样的实验,每次重新初始化网络,最后统计测试集均方根误差,最好的一次拟合曲线和原始曲线几乎重合,最差的一次误差大了将近一个数量级,曲线形状明显失真。这不是代码写错了——用同样的数据、同样的网络结构、同样的训练算法,只因为随机初始值不同,结果差异就大到没法接受。这就是BP网络最典型的问题之一:对初始权重的敏感性。

1.2 BP的局部最优与初始敏感问题

深入说一句本质。BP的训练过程基于梯度下降,误差曲面在参数空间里是一个高维非线性函数,上面布满了局部极小值。初始点落在一个局部极小值附近,梯度下降就只会往那个局部极小值跑,不会再跳出去。

MATLAB里随机初始化默认行为就是生成一组[-1, 1]或者更小区间的随机数。每一次随机生成的初始点,落在哪个"山谷"里完全是运气,这就是为什么同样的代码跑十次会出现十种结果。

为了削弱这个问题,我试过缩小初始权重范围、改用贝叶斯正则化训练函数trainbr、增加动量项,甚至把网络结构从6个隐层节点一路加到20个。效果有改善,但不能根治。误差曲面长什么样我们看不到,梯度下降本质上又是一个"近视眼"算法,它只能告诉你脚下哪个方向能往下走,没法告诉你远方哪个方向的山谷更深。这种局限决定了BP对初值的敏感和容易陷入局部最优。

1.3 粒子群为什么适合补这个位

PSO解决这个问题的思路完全不一样。它不需要计算梯度,只需要知道每个参数组合下误差有多大。一群粒子同时在搜索空间里飞行,每个粒子记录自己历史上最好的位置,整个群体记录全局最好的位置,飞行速度受这两个最优位置吸引,不断在探索和收敛之间平衡。

类比一下就是,一群人被蒙着眼睛送到一片山区里找最低点,每个人脚下能测出海拔。找不到梯度方向没关系,先各走各的,每到一个位置测一次海拔;发现自己走过的某个位置海拔最低,就往那里靠;听到群体里有人说某个位置海拔更低,也往那里飞。这样就不会被脚下的小坑锁死,因为群体信息一直在引导粒子跳出来。

换到我们的场景里,粒子的位置就是一个候选的神经网络权重和阈值向量。适应度就是这个网络在训练集上的拟合误差。因为是直接搜参数空间而不是沿着梯度走,PSO对初始位置的要求低得多,只要搜索范围和迭代次数设计合理,即使初始点落在不好的区域,最终也大概率能收敛到一个更优的解。这正是把粒子群引入神经网络拟合的根本动机。

2. PSO与神经网络结合的方式:优化初始权重还是全程替代

2.1 两种主流结合思路的对比

标题里写的是"粒子群优化算法神经网络非线性函数拟合",实际操作中常见有两种结合方式,需要先分清楚。

结合方式流程优点缺点
方式一:PSO优化初始权重,再用BP训练PSO搜索出一组参数作为网络初始值,然后交给BP继续梯度下降收敛快,充分利用PSO全局搜索和BP局部精调的优势最终结果仍然依赖BP的训练质量,设置不当还会出现收敛抖动
方式二:PSO完全替代BP训练过程PSO直接搜索最优权重阈值,适应度函数就是网络误差,迭代结束后参数即为最终结果过程稳定、可复现,不依赖梯度算法,适合复现对比实验高维参数搜索成本高,网络结构较大时收敛变慢

在论文和工程里,这两种都被称作"PSO优化神经网络"。但在做非线性函数拟合时,我更推荐方式二。原因很简单:通过PSO搜索到的参数本身就是全局寻优的结果,整个训练过程只依赖随机初始群体,多次运行的稳定性比BP强得多;而且方式二对MATLAB工具箱版本没有额外依赖,核心代码可以完全自己写清楚,复现性也更好。接下来整篇文章的代码都以方式二为主线来展开。

2.2 粒子编码:把网络参数变成位置向量

先约定网络结构。这里用单隐层前馈网络,输入维度为nInput,隐层节点数为nHidden,输出维度为nOutput。输入层到隐层的权重个数为 nInput×nHidden,隐层阈值为 nHidden 个;隐层到输出层的权重个数为 nHidden×nOutput,输出层阈值为 nOutput 个。把这些参数全部拼接成一个一维向量,粒子的位置就是这个向量。编码长度dim的计算公式:

dim = nInput×nHidden + nHidden + nHidden×nOutput + nOutput

对于本文的例子,nInput=1,nHidden=6,nOutput=1,那么 dim = 1×6 + 6 + 6×1 + 1 = 19。每个粒子是19维的位置向量,每一维对应网络里的一个权重或阈值。解码时按顺序切回去即可:先取前6维 reshape 成输入层到隐层的权矩阵,接着取6维作为隐层阈值,再取6维 reshape 成隐层到输出层的权矩阵,最后 1 维作为输出层阈值。

2.3 适应度函数:拟合问题的"评分规则"

粒子群优化的目标就是最小化适应度函数。对拟合问题来说,最直观的设计是均方误差(MSE)。适应度函数输入是粒子的位置向量,输出是对应网络在训练集上的均方误差:

fitness = mean( (output - target).^2 )

这里有个关键细节,适应度函数里要用到训练集的输入P_train和输出T_train,也就是说粒子在搜索过程中每评估一次,都要对全体训练样本做一遍前向传播。所以适应度的计算量等于"训练样本数×网络参数量",这也是为什么粒子维度太高或样本量太大的时候,PSO迭代会明显变慢。

另一个容易踩的坑是适应度函数的尺度问题。如果训练集的输出值范围很大,比如在数万级别,MSE可以高达几千甚至上万,粒子位置更新时需要的速度范围也要相应调整。所以通常建议把输入输出都做归一化处理,把数据压到[-1, 1]或者[0, 1]区间,这样PSO的搜索边界、初始速度范围都好控制得多。

3. MATLAB代码逐段拆解:从数据准备到粒子群主循环

3.1 数据生成与归一化处理

首先写数据准备部分。为了让读者能直接复现,我用一个具体的非线性函数作为演示对象:

%% 数据生成 x = (-2: 0.05: 2)'; y = sin(3 * x) .* exp(-0.5 * x.^2) + 0.08 * randn(size(x)); % 划分训练集和测试集 indices = randperm(length(x)); trainIdx = indices(1:round(0.7 * length(x))); testIdx = indices(round(0.7 * length(x)) + 1:end); P_train = x(trainIdx)'; T_train = y(trainIdx)'; P_test = x(testIdx)'; T_test = y(testIdx)';

这里有一个值得注意的选择:为什么用 randperm 随机划分为训练集和测试集?因为非线性拟合实验里,我们希望模型能在未参与训练的位置上也能给出合理预测。如果按顺序取前70%做训练、后30%做测试,当函数在外面区间变化剧烈时,测试集的误差会明显偏大,且不能反映模型真实泛化能力。随机划分能让训练集和测试集在分布上更接近。

然后做归一化。在PSO训练神经网络时,归一化几乎可以说是必要条件。我用MATLAB自带的mapminmax函数,把输入和输出都映射到[-1, 1]区间:

[P_train_norm, ps_in] = mapminmax(P_train, -1, 1); [T_train_norm, ps_out] = mapminmax(T_train, -1, 1); P_test_norm = mapminmax('apply', P_test, ps_in); T_test_norm = mapminmax('apply', T_test, ps_out);

注意测试集的归一化参数必须来自训练集,不能自己单独重新计算。这是一个很经典的错误:如果测试集单独调用mapminmax,得到的归一化结果会把测试集的分布信息掺进预处理里,测试误差就不再客观了。正确做法是保存训练集的ps_in和ps_out,然后用apply命令用同一套参数做转换。

% 网络结构参数 nInput = size(P_train_norm, 1); % 输入节点数 nHidden = 6; % 隐层节点数 nOutput = size(T_train_norm, 1); % 输出节点数 dim = nInput * nHidden + nHidden + nHidden * nOutput + nOutput;

3.2 PSO主程序的完整实现

接下来是整篇文章的核心:粒子群优化的主循环。用最经典的带惯性权重的标准PSO版本。粒子数量、惯性权重上下限、学习因子的设置,我基于常见实践做了预设:

%% PSO参数设置 nPop = 30; % 粒子数 maxIter = 300; % 最大迭代次数 wMax = 0.9; % 惯性权重上限 wMin = 0.4; % 惯性权重下限 c1 = 1.5; % 个体学习因子 c2 = 2.0; % 群体学习因子 lb = -5 * ones(1, dim); % 参数下界 ub = 5 * ones(1, dim); % 参数上界 % 初始化粒子位置与速度 x = zeros(nPop, dim); v = zeros(nPop, dim); for i = 1:nPop x(i, :) = lb + (ub - lb) .* rand(1, dim); v(i, :) = (ub - lb) .* (rand(1, dim) * 0.2 - 0.1); end % 初始适应度 fitness = zeros(nPop, 1); for i = 1:nPop fitness(i) = fitnessFunc(x(i, :), P_train_norm, T_train_norm); end pbest = x; pbestFitness = fitness; [gbestFitness, idx] = min(fitness); gbest = x(idx, :); %% 主循环 record = zeros(1, maxIter); for iter = 1:maxIter w = wMax - (wMax - wMin) * iter / maxIter; for i = 1:nPop r1 = rand(1, dim); r2 = rand(1, dim); % 速度更新 v(i, :) = w * v(i, :) + c1 * r1 .* (pbest(i, :) - x(i, :)) + c2 * r2 .* (gbest - x(i, :)); % 速度限幅(防止粒子飞出合理范围) maxV = 0.3 * (ub - lb); v(i, :) = max(min(v(i, :), maxV), -maxV); % 位置更新 x(i, :) = x(i, :) + v(i, :); x(i, :) = max(min(x(i, :), ub), lb); % 适应度评估 fitness(i) = fitnessFunc(x(i, :), P_train_norm, T_train_norm); % 更新个体最优 if fitness(i) < pbestFitness(i) pbest(i, :) = x(i, :); pbestFitness(i) = fitness(i); end end % 更新全局最优 [bestFitness, idx] = min(pbestFitness); if bestFitness < gbestFitness gbestFitness = bestFitness; gbest = pbest(idx, :); end record(iter) = gbestFitness; end

这段代码里有几个地方值得展开说明。首先是惯性权重w的线性递减。迭代初期需要较大的w来保持粒子的探索能力,让粒子飞得远一点,避免过早聚集;迭代后期则希望粒子收敛到最优位置附近精细搜索,所以w要逐渐减小。从0.9线性降到0.4是经典取值区间,大多数实际问题在这个区间内都能有不错表现。

速度限幅也非常重要。如果速度无限大,粒子可能直接飞出搜索边界,或者把本来很好的位置一步踢走。maxV取变量范围的30%左右,既允许粒子有大步跨越能力,又不会导致搜索失控。位置更新之后还需要做边界钳制,超出范围的值被拉回边界。

位置越界处理其实有不同的策略。这里用的是最简单的"截断法"——把越界的维度直接钳制到边界值。更精细的做法是"边界吸收+速度重置",即把粒子钳制到边界的同时把该维度的速度清零,防止粒子粘在边界上反复振动。我在实际调试中,截断法在绝大多数情况下够用,但如果发现边界附近的粒子反复聚集,可以再改成吸收法。

3.3 适应度函数:把参数向量变成网络误差

适应度函数是整个PSO流程里和神经网络关系最紧密的部分。它要做的事情很明确:把一维参数向量解码成权重和阈值,然后用它们对训练集做一次前向传播,返回均方误差:

function mse = fitnessFunc(theta, P_train, T_train) nInput = size(P_train, 1); nHidden = 6; nOutput = size(T_train, 1); nSample = size(P_train, 2); % 解码:拆分权重和阈值 w1 = reshape(theta(1:nInput * nHidden), nHidden, nInput); b1 = theta(nInput * nHidden + 1 : nInput * nHidden + nHidden); w2 = reshape(theta(nInput * nHidden + nHidden + 1 : nInput * nHidden + nHidden + nHidden * nOutput), nOutput, nHidden); b2 = theta(nInput * nHidden + nHidden + nHidden * nOutput + 1 : end); % 前向传播(隐层 tansig + 输出层 purelin) hidden = tansig(w1 * P_train + b1 * ones(1, nSample)); output = purelin(w2 * hidden + b2 * ones(1, nSample)); % 均方误差 mse = mean((output - T_train).^2, 'all'); end

注意这里有个容易出错的地方:MATLAB的reshape默认按列填充,而网络权重矩阵的习惯写法是"后层节点数×前层节点数"。如果解码时顺序错了,矩阵维度虽然不会报错,但权重对应关系完全错乱,PSO搜索就没意义了。建议在每个维度切分之后手动检查一下size,确保和网络结构一致。

3.4 跑通整个流程的关键衔接点

PSO迭代结束之后,就拿到了最优粒子gbest。剩下的工作是把gbest解码成网络参数,然后在测试集上验证:

%% 用最优粒子搭建网络并验证 w1 = reshape(gbest(1:nInput * nHidden), nHidden, nInput); b1 = gbest(nInput * nHidden + 1 : nInput * nHidden + nHidden); w2 = reshape(gbest(nInput * nHidden + nHidden + 1 : nInput * nHidden + nHidden + nHidden * nOutput), nOutput, nHidden); b2 = gbest(nInput * nHidden + nHidden + nHidden * nOutput + 1 : end); nTest = size(P_test_norm, 2); hiddenTest = tansig(w1 * P_test_norm + b1 * ones(1, nTest)); Y_test_norm = purelin(w2 * hiddenTest + b2 * ones(1, nTest)); % 反归一化,得到实际输出 Y_test = mapminmax('reverse', Y_test_norm, ps_out); % 计算拟合误差 rmse_test = sqrt(mean((Y_test - T_test).^2, 'all')); % 绘制适应度曲线 figure; plot(record, 'LineWidth', 1.5); xlabel('迭代次数'); ylabel('适应度值(MSE)'); title('粒子群优化过程中的适应度收敛曲线');

这里最后一步反归一化很容易漏。如果不做mapminmax的reverse操作,看到的输出是归一化后的数值,和原始y值完全不在一个量级,误差计算也没有意义。在调试过程中,我最常做的事情之一就是打印几个关键变量的尺寸和量级,一旦发现维度对不上或者数值明显异常,就能快速定位是解码错误还是归一化遗漏。

4. 参数一改效果就崩:粒子群参数的调参心法

4.1 核心参数的经验区间与作用

很多读者拿到代码第一件事是跑通,第二步就发现一个尴尬的问题:换一组数据、换一个网络结构,同一个参数组合的效果千差万别。这不奇怪,PSO的每个参数都在控制搜索行为的某个侧面。

参数常用范围作用调参建议
nPop(粒子数)20-60粒子越多,群体探索越充分,但每轮评估耗时线性增加维度在50以下时粒子数取30足够;维度越高越需要增加粒子数
maxIter(迭代次数)100-500迭代不足会欠收敛,过多则浪费计算量先跑300次看曲线是否平坦,若后期仍在下降再加
wMax/wMin(惯性权重)0.9 / 0.4控制粒子继承上一时刻速度的比例,是平衡探索与开发的关键大多数问题这组值都可用;若收敛慢可把下限提到0.5
c1/c2(学习因子)1.5 / 2.0 附近c1偏向个体经验,c2偏向群体经验;c2太大容易让粒子过早汇聚个体最优和群体最优哪个更重要,取决于问题地貌,建议初值c1=c2=1.5
lb/ub(搜索边界)以权重阈值的合理范围定决定搜索空间的物理边界归一化数据下用[-5,5]通常足够;边界过大浪费搜索,过小则容易漏掉最优

在粒子群参数中,最容易出问题的其实是搜索边界lb和ub。如果数据没有归一化,输出值范围可能很大,最优权重往往也会很大,此时如果边界还用[-5,5],直接约束了网络表达能力;如果归一化到[-1,1]且采用tansig激活函数,权重超过5在网络输出上几乎没有额外影响了,边界取[-5,5]是一个经验上稳妥的选择。

还有一个小技巧:粒子速度的初始范围不要太大也不要太小。设置在变量范围的20%左右,让粒子一开始有足够的探索能力,又不至于飞出边界太远。如果初始速度为零,粒子初期会先被个体最优和全局最优牵引,前期搜索效率偏低;如果初始速度过大,则前期容易反复撞边界,浪费迭代次数。

4.2 一组带坑的调试记录

分享一个实际调试过程。有一次我调整了网络结构,把隐层节点从6改到15,其他代码没动,结果粒子群优化彻底不收敛。适应度在迭代10次左右就停在某个值不再下降,而同样的函数之前用6个隐层节点能收敛得很好。

排查之后发现两个问题。第一,维度从19涨到了46,粒子数还是30,搜索空间呈指数增长,粒子群体规模严重不足,所以把nPop从30提到了60。第二,隐层节点增加后,网络表达能力变强,但冗余参数也增多,均方误差更容易陷入某个可以接受的局部最小,单纯的PSO没有足够压力继续探索,此时把迭代次数从300提升到500,并稍微加大c2到2.2,促进群体向最优靠拢。

把这两个改动一起做了之后,收敛曲线才重新回到正常水平。这段经历说明,网络结构变化之后,PSO参数要跟着改,不存在一套固定参数适用于所有场景。新手最容易犯的错,是把课程设计里的一组参数当成放之四海而皆准的真理,换场景之后没意识到要重新调整。

5. 实测中遇到的翻车现场与排查思路

5.1 适应度曲线纹丝不动

现象:迭代跑了几十次,适应度值一直是同一个数,几乎不变。

先检查适应度函数本身。最常见的原因是解码后的网络结构出错,比如reshape后的w1维度跟预期不一致,前向传播计算出错,导致每轮误差都一样。建议在fitnessFunc里临时打印一下output的size和mean值,确认网络输出确实随参数变化而变化。

再检查参数更新逻辑。粒子位置更新后,要确保每个粒子的位置真的发生了变化。如果位置更新被边界限幅卡死,所有粒子都贴在下边界上,自然无法收敛。打印一下每次迭代的x变化量,一目了然。

最后检查数据。如果训练集的输入输出维度有问题,比如P_train是81×1而实际前向传播需要1×81,那么归一化时mapminmax的输入就错了,适应度计算也会出错。在MATLAB里维度错误往往会报错,但如果恰好不报错而是产生一个隐式转换,则适应度始终是一个错误值,这种情况最难排查,碰到时务必用size逐行核对所有变量的维度。

5.2 训练集漂亮、测试集拉胯

现象:训练集上MSE很小,拟合曲线几乎完美;但测试集上误差巨大,拟合曲线扭曲。

这是典型的过拟合。PSO优化的目标是训练集误差,并不会自动考虑泛化能力。当网络模型容量大于任务需求时,网络会记住训练集上的噪声模式,而不是学习潜在的函数关系。特别是本文这种带噪声的数据,噪声本身是不可预测的,强行拟合噪声必然牺牲泛化性能。

解决思路有三条。第一,减少隐层节点数,降低模型容量,例如把nHidden从15降到8或6,让网络没有能力记住噪声细节。第二,在适应度函数里加入正则项,仿照BP里的权重衰减,把权重平方和作为惩罚项加进MSE里,促使粒子搜索权重较小的区域,控制模型复杂度。第三,用验证集对最优粒子做筛选,每次迭代结束后把当前gbest在验证集上算一次误差,保存验证误差最小的粒子作为最终结果,而不是一味追求训练集最优。

5.3 粒子聚集但拟合曲线依旧扭曲

现象:迭代收敛了,所有粒子的位置都聚集在gbest附近,适应度也很小,但画出拟合曲线之后发现某一段区间完全偏离原始曲线。

这个问题的根源是"训练集分布偏差"。如果训练集和测试集的随机划分不合理,比如某些区间内训练样本恰好很少,粒子只对样本密集区域敏感,样本稀疏区域的误差在均方误差里权重很低,搜索过程自然不重视那些区域。此时拟合出的曲线在样本密集处很好,稀疏处就随意飘。

解决办法也很直接:重新划分训练集和测试集,尽量保证两个集合在输入分布上一致;或者使用分层抽样。对一维函数拟合,可以在样本点里按间隔抽样,比如每隔5个点取1个作为测试集,其余做训练集,这样训练集覆盖整个区间内所有子区域。如果随机划分后,可视化显示训练集在某些区间明显缺失,果断重新划分,不要勉强用。

6. 这套方法还能用在哪:扩展与个人体会

6.1 换网络结构、换优化器的改造点

这套PSO+神经网络的框架只依赖于两层前向传播,结构上非常开放。改造成RBF神经网络时,粒子编码可以换成:RBF的中心、宽度、输出层权重,适应度函数改成RBF网络的前向传播。改造成LSTM或者深度网络时,需要注意粒子维度会急剧膨胀,高维空间里标准PSO的收敛速度会明显下降,建议先用PSO优化网络的初始权重或超参数(学习率、层数、每层节点数),再用梯度类方法精调,而不是完全替代训练。

换优化器思路也一样。PSO变体里有带收缩因子的标准PSO、量子行为PSO(QPSO)、差分进化、灰狼优化、鲸鱼优化等。不同算法在收敛速度和全局搜索能力上各有侧重。我的建议是:如果做对比实验,把PSO、差分进化、灰狼优化放在同一套代码框架下跑,统一适应度函数和评估次数,然后比较收敛曲线和多次运行的方差;如果只是工程上想稳定解决一个拟合问题,PSO加合理调参已经足够。

6.2 我的实操经验与调试建议

最后分享一点个人经验。整套方法跑稳之后,我形成的调试套路是:

第一,先用小粒子群、小迭代次数快速试跑。nPop取10,maxIter取50,观察适应度是否下降、下降趋势是否合理。如果这个阶段就卡住,不要急着调参,先定位代码问题;只有当快速试跑能稳定下降,才有必要跑正式的大规模搜索。这个习惯帮我省了大量等待时间,因为正式配置下跑一次实验可能是几十分钟,而快速试跑只需要一两分钟。

第二,画图永远比看数字直观。把适应度收敛曲线、拟合结果曲线、测试样本散点图放在同一张图上观察。如果收敛曲线在迭代中期出现平台,说明粒子陷入局部最优,可以考虑提高c1或者给粒子加扰动;如果收敛很快但测试误差大,多半是过拟合,先检查模型容量和训练集覆盖。

第三,多次运行取统计结果是做对比实验的基本功。PSO和BP都带有随机性,一次运行的结果没有说服力。写一个for循环跑20次,记录每次的测试误差,然后统计均值、标准差和最好值。你会发现PSONet的均值明显低于BP的均值,方差也小得多,这个结论才站得住脚。

第四,任何改动都要增量验证。改边界、改粒子数、改网络结构,一次改一个变量,记录下改动前后的收敛曲线和误差曲线,形成一张对比表。盲目同时改多个参数,出了问题很难定位是哪一步造成的。

非线性函数拟合这个问题看似简单,但背后涉及的核心问题——高维参数寻优、梯度信息缺失、局部最优、过拟合与泛化——在更复杂的建模任务里同样存在。PSO提供了一种不依赖梯度、结构简单、容易和任意前向模型结合的解决思路,这也是它这么多年仍在各种论文和工程实践中被反复使用的原因。希望这篇内容能把整个流程拆透,让打算用这个方案的人少走一些弯路。

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

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

立即咨询