ARTICLE DETAIL

资讯详情

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

基于MATLAB的RBF神经网络预测模型实现与调参实践

基于MATLAB的RBF神经网络预测模型实现与调参实践 简介这是一份基于MATLAB的RBF径向基函数神经网络预测程序面向需要开展函数拟合、分类或时序预测的科研与工程人员。程序围绕RBF网络核心流程组织涵盖高斯径向基函数定义、隐藏层中心选取、输出层权重训练以及预测调用既适合初学者对照学习网络结构也便于进阶用户调整参数完成自定义预测任务。资源共13个文件以7个.m脚本为主另有5个.asv自动保存备份和1个运行日志压缩包整体仅18KB内容精简、便于快速查看与移植。目前已有290人学习使用。通过脚本可直观理解RBF建模与预测的完整链路包括数据读取、模型构建、误差优化和结果输出并可根据实际数据替换样本、调整核宽度与中心点快速验证预测效果是MATLAB环境下开展RBF网络实践的有效参考资料。1. 为什么RBF神经网络预测模型在MATLAB里比BP更值得一试RBF神经网络经常被拿来和BP网络比但很多人忽略一点RBF的训练速度在中小规模样本下往往比BP快一个数量级因为输出层是线性权重求解隐层中心固定后没有梯度消失问题。但在MATLAB里实现预测程序时RBF的spread参数、隐层神经元数量和样本划分都会让同一份数据跑出截然不同的结果。这篇文章围绕“RBF神经网络预测程序、RBF神经网络预测模型、MATLAB”这套组合从径向基函数的映射原理讲起给出可直接运行的滑窗数据构造、newrb训练、参数搜索和残差验证代码最后落到多步滚动预测的具体技巧。适合需要用MATLAB快速建立回归预测模型、又不想花太多时间调BP结构的工程人员和科研用户。2. RBF神经网络预测模型的核心原理与MATLAB数据准备在MATLAB里写RBF预测程序之前需要理解RBF是怎么做预测的。BP是全局逼近每个隐层节点都会响应整个输入空间RBF是局部逼近每个隐层节点只在输入空间的一个“局部”产生显著响应。这个区别直接决定了你该怎么处理数据、该怎么解释神经元数量。2.1 径向基函数为什么能把非线性预测问题变成线性问题RBF网络的标准输出形式是y sum(w_i * phi(||x - c_i||))其中c_i是中心向量phi是径向基函数。在MATLAB的newrb实现中基函数是高斯函数phi exp(-||x - c_i||^2 / spread^2)这里spread直接控制“影响半径”。输入样本x与中心c_i越近该隐层节点的激活值越高距离超过若干倍spread后激活值趋近于零。因此网络的整体输出是若干局部高斯场的加权求和。从模型数学形式看一旦中心c_i确定待求的只有输出层权重w_i此时它是一个线性方程组的求解问题。这就是RBF训练快的原因——不需要像BP那样反向传播多次计算梯度而是先用聚类或随机采样确定中心再解线性最小二乘问题。在MATLAB预测模型场景中这意味着小样本训练时不容易被局部极小值卡住但代价是中心数量和spread的设定高度依赖经验。2.2 构造训练集用滑窗把一维时间序列变成输入特征RBF网络本身不是时序网络它默认输入是独立特征向量。所以做股票预测、风速预测或振动趋势预测之前必须把原始序列转换成“用前几个点预测下一个点”的监督学习格式。常见做法是用滑窗滑动窗口。% 生成模拟的一维时间序列正弦加噪声 t (0:0.1:20); y sin(t) 0.08 * randn(size(t)); % 滑窗长度用过去5个点预测下一个点 lag 5; X []; % 每行是一个样本列是lag个历史值顺序变量 Y []; % 每行是目标值 for i lag1:length(y) X [X; y(i-lag:i-1)]; Y [Y; y(i)]; end % 画出原始数据和前100个样本确认滑窗没有错位 subplot(2,1,1); plot(t, y); title(原始时间序列); subplot(2,1,2); plot(1:100, Y(1:100), ro); hold on; plot(1:100, X(1:100, end), b-); % 只画第100个样本的前一时刻特征这段代码把长度为201的序列转换成了196个样本。X的第 i 行对应原始序列第 i 到第 ilag-1 个点Y对应第 ilag 个点。注意滑窗顺序没有打乱因为预测任务要求时间连续性。若要用于随机交叉验证需要避免把相邻样本放进不同集合否则会造成信息泄漏导致预测模型精度虚高。关键参数是lag。lag太小网络看不到足够趋势lag太大特征维度膨胀且样本数减少。我在实际预测中一般先用自相关函数ACF粗略估计滞后阶数如果自相关系数在滞后3阶后断崖式下降lag取3到5就够如果是强趋势数据lag需要更大。这里用5是折中。2.3 数据归一化mapminmax为什么不能省RBF的激活函数是高斯函数输入距离直接参与指数运算。如果特征量纲差异过大比如一个特征在0到1之间、另一个在几千到几万之间距离会被大数值特征主导导致小数值特征几乎失效。所以在进入newrb之前必须做归一化。MATLAB里最常用的是mapminmax它默认把矩阵的每一行线性映射到[-1,1]也可以指定范围。% 注意mapminmax按行处理所以需要把X转置成“每行一个特征” [X_norm, X_ps] mapminmax(X, 0, 1); [Y_norm, Y_ps] mapminmax(Y, 0, 1); % 转置回来让每一行对应一个样本 X_norm X_norm; Y_norm Y_norm; % 划分训练集和测试集按时间顺序前80% n size(X_norm, 1); trainNum floor(n * 0.8); X_train X_norm(1:trainNum, :); Y_train Y_norm(1:trainNum, :); X_test X_norm(trainNum1:end, :); Y_test Y_norm(trainNum1:end, :);mapminmax(X,0,1)先求X每一列的最小值、最大值再把列值映射到0到1区间。返回的X_ps结构体保存了这些映射参数。预测阶段必须用训练集的X_ps去变换测试集而不能在测试集上重新调用mapminmax否则测试值的区间会受未来信息影响。同理网络输出后要用mapminmax(reverse, ..., Y_ps)还原成原始量纲。参数典型值影响lag3~10过小欠拟合过大特征冗余归一化范围0~1 或 -1~1影响高斯距离尺度最终会被spread吸收训练集比例70%~85%时序数据不能随机切必须按时间切是否保留ps结构体必须保留测试集和未来预测都要用训练集的映射在以往我调过的预测程序里漏掉mapminmax反向还原是最常见的“预测结果全是一个常数”的原因。如果net输出后反归一化值非常接近训练集均值先检查是不是归一化范围或者中心设置问题。3. 用MATLAB构建RBF神经网络预测程序newrb与newrbe的取舍MATLAB的神经网络工具箱提供了两条路线newrbe和newrb。很多人第一次查文档时看到两个函数都带“径向基”会以为只是精度不同。实际区别是结构确定方式完全不同直接决定了网络的规模。3.1 newrbe与newrb的核心差异newrbe会生成一个精确网络即让训练集误差尽量到0它的隐层神经元数量等于训练集样本数。如果训练集有2000个样本网络就有2000个中心每个中心对应一个输入样本。优点是只有spread一个参数需要调且训练矩阵直接一次求解。缺点是模型巨大预测速度和内存占用都很差而且精确拟合往往意味着过拟合在噪声较大的预测任务中表现反而不如普通RBF。newrb走的是增量式训练从空网络开始每次迭代选一个误差最大的样本作为新的中心直到达到目标均方误差goal或到达最大神经元数量MN。这样得到的隐层神经元数远小于样本数是一个近似网络泛化能力通常会更好。在写预测程序时我几乎总用newrb只有训练集很小比如少于100个样本且对实时性要求不高时才考虑newrbe。3.2 最小可运行代码newrb训练与预测下面这段代码基于上一章的X_train、Y_train直接训练RBF网络并预测测试集。% 设置目标误差、扩展常数、最大神经元数 goal 0.001; spread 1.5; MN 50; % 最大隐层神经元数防止无限增长 DF 5; % 每增加5个神经元显示一次训练过程 % 训练RBF网络 net_rbf newrb(X_train, Y_train, goal, spread, MN, DF); % 用测试集预测 Y_test_norm net_rbf(X_test); % 反归一化还原到原始量纲 Y_pred mapminmax(reverse, Y_test_norm, Y_ps); % 计算训练集预测值用于后续过拟合检查 Y_train_pred_norm net_rbf(X_train); Y_train_pred mapminmax(reverse, Y_train_pred_norm, Y_ps); % 计算RMSE train_rmse sqrt(mean((Y_train - Y_train_pred).^2)); test_rmse sqrt(mean((Y_test - Y_pred).^2)); fprintf(训练集RMSE: %.4f\n, train_rmse); fprintf(测试集RMSE: %.4f\n, test_rmse);newrb内部输入和输出都是矩阵输入每一列是一个样本输出每一列是对应目标。所以这里必须把样本行向量转成列向量传入X_train。Y_train同理。goal0.001是均方误差的绝对目标如果数据归一化到0~1这个目标合理如果没归一化或目标序列本身很大goal需要相应扩大。spread在后面的调参循环里是主角暂时设为1.5。MN建议不要超过训练样本数的三分之一否则极限情况下仍会陷入过拟合。3.3 训练过程的显示参数DF与收敛信息newrb的第六个参数DF控制显示步长。DF1时每增加一个神经元就打印进度节奏很吵DF5或10更适合观察收敛趋势。训练结束后命令行会显示类似“RBF neurons 20, SSE 0.0008”的信息。看到这个信息需要关注两个方面一是最终神经元数是否逼近MN如果是说明MN限制了拟合能力或spread过小导致每个中心只影响极小的局部区域二是SSE是否降到目标以下如果一直没有下降说明spread太小或goal定得太苛刻。3.4 保存模型避免反复训练训练好的网络可以这样保存save(rbf_model.mat, net_rbf, X_ps, Y_ps, lag);加载后预测新样本时必须同时加载X_ps和Y_ps并且用相同lag窗口拼接新样本的输入。很多人在部署阶段只保存了net_rbf结果预测新序列时归一化参数对不上输出完全错误。保存这些关联数据是一次成型预测程序的基本要求。4. 预测模型调参Spread、目标误差与神经元上限的影响RBF预测模型真正需要手工干预的就是spread、goal和MN这三个参数。先给结论spread决定了每个隐层节点的“感知范围”影响的是拟合曲面的平滑程度goal影响神经元数量MN是上限约束。三者之间有很强的耦合调spread时一定要看网络实际增长的神经元数量而不是只看误差。4.1 Spread对拟合曲面和泛化的影响spread值越小高斯函数越“尖”每个样本中心只能影响周围很小的区域。为了逼近远离中心的数据点newrb必须不断增加隐层神经元结果网络变得很“碎”测试误差上升。反之spread太大高斯函数变得很“平”每个中心的影响范围相互重叠网络需要更多努力才能区分不同局部细节虽然神经元数可能减少但拟合精度不足出现系统性偏差。以一个简单的正弦序列为例预测模型在不同spread下的RMSE趋势通常是一条U形曲线在1附近到达谷底两边都会恶化。U谷的具体位置取决于数据采样密度和噪声程度。所以调spread时不要依赖某个固定经验值应该做网格搜索。4.2 用循环自动搜索Spread最佳取值在MATLAB里可以用简单的循环完成参数搜索不需要额外工具箱。% 参数网格 spreads 0.2:0.2:4; goal 0.001; MN 50; train_errors zeros(size(spreads)); test_errors zeros(size(spreads)); used_neurons zeros(size(spreads)); for i 1:length(spreads) net_tmp newrb(X_train, Y_train, goal, spreads(i), MN, 5); tr_pred net_tmp(X_train); te_pred net_tmp(X_test); tr_pred mapminmax(reverse, tr_pred, Y_ps); te_pred mapminmax(reverse, te_pred, Y_ps); train_errors(i) sqrt(mean((Y_train - tr_pred).^2)); test_errors(i) sqrt(mean((Y_test - te_pred).^2)); used_neurons(i) size(net_tmp.LW{2,1}, 2); % 隐层神经元数量 end % 画出误差与神经元数找U形曲线谷底 figure; yyaxis left; plot(spreads, train_errors, b-o); hold on; plot(spreads, test_errors, r-s); ylabel(RMSE); yyaxis right; plot(spreads, used_neurons, k--); ylabel(隐层神经元数); xlabel(spread); legend(训练RMSE,测试RMSE,神经元数); grid on;代码中的net_tmp.LW{2,1}是输出层权重矩阵其行数等于隐层神经元数量所以用size(net_tmp.LW{2,1}, 2)直接拿到中心数。不同MATLAB版本的RBF网络内部结构描述略有差异但输出层权重的列数通常稳定。如果这一步报错可以改看numel(net_tmp.LW{2,1}) / size(net_tmp.LW{2,1}, 1)或者直接信任训练日志里的神经元数。判断依据测试RMSE最小的点对应的spread和神经元数就可以作为生产配置目标。不过要注意如果最小测试RMSE附近used_neurons已经逼近MN说明当前MN限制了网络的表达空间应当把MN扩大再重新搜索。如果goal太小则训练会在达到MN上限时强制停止此时打印输出的最终SSE没有收敛到目标也是一个信号。4.3 目标误差goal与MN的组合约束goal设置的是训练均方误差下线。如果设置得过大比如0.1newrb可能只增加几个神经元就停止设置得过小比如0.000001网络会尽可能增加神经元很容易出现过拟合。推荐先保持MN固定然后做一个goal的粗扫描goal神经元数训练RMSE测试RMSE现象1e-280.09120.0834欠拟合曲线平滑1e-3240.03510.0320最佳区间1e-5490.00420.0521过拟合测试误差反弹这张表是模拟结果真实数据数值会不同但趋势一致。训练误差不断下降并不代表预测模型更好测试误差才是最终衡量标准。在预测任务里噪声数据上的训练误差不是优化目标。如果碰到某种参数下测试RMSE是训练RMSE的3倍以上说明网络已经在背诵训练集需要把spread调大或放宽goal。5. 验证RBF预测模型残差自相关与多步滚动预测训练完成后不能只看RMSE。时序预测程序里有个常被忽略的验证步骤检查误差是否还残留着可预测的模式。如果残差存在明显的自相关说明模型没有把序列中的时序信息抽干还有改进空间。5.1 残差自相关计算与判断resid Y_test - Y_pred; maxLag min(20, length(resid) - 1); acf zeros(1, maxLag); for k 1:maxLag acf(k) corr(resid(1:end-k), resid(k1:end)); end figure; bar(1:maxLag, acf); hold on; band 1.96 / sqrt(length(resid)); plot([1 maxLag], [band band], r--); plot([1 maxLag], [-band -band], r--); grid on;红色虚线是95%置信带。如果残差自相关在第一、第二个滞后阶就显著超出虚线说明模型遗漏了短期的序列依赖。对于RBF这种静态网络常见的补救方法是把lag增加1到2或者在输入中额外加入差分项。如果自相关在某个固定周期处显著比如滞阶24处说明数据存在日周期或季节周期需要把周期滞后值也作为特征输入。5.2 多步滚动预测的技巧单步预测可以做得好但真正部署时往往要预测未来多步。直接让网络输出多个点容易累积误差因为每一步都会把上一个预测值当作输入。最简单的滚动策略是递归预测先用已知历史预测t1再把t1的预测值拼接到输入窗口末端预测t2。这个过程中窗口内的未来值不断被替换为预测值误差会逐渐扩大。所以一般不建议滚动的步数超过原始lag的2到3倍。如果必须做较长预测可以训练多个模型分别输出第1步、第2步而不是递归调用同一个模型。5.3 用网络响应曲面检查局部行为训练完成后可以画出网络输出随输入两个特征变化的曲面确认RBF预测模型是否真的在利用局部结构。手动计算网格输出% 对前两个特征做网格扫描 g1 linspace(min(X_train(:,1)), max(X_train(:,1)), 50); g2 linspace(min(X_train(:,2)), max(X_train(:,2)), 50); [G1, G2] meshgrid(g1, g2); G [G1(:), G2(:), repmat(mean(X_train(:,3:end)), numel(G1), 1)]; G_norm mapminmax(apply, G, X_ps); Y_grid mapminmax(reverse, net_rbf(G_norm), Y_ps); surf(G1, G2, reshape(Y_grid, size(G1)));这段代码把第三个往后的特征固定在均值观察网络对前两个特征的响应。如果预测模型曲面在某个局部出现剧烈尖峰往往意味着spread过小或中心重叠如果曲面几乎是平面则spread可能过大。调整后重新训练再对比曲面的平滑度是比单个RMSE指标更直观的调参参考。本文还有配套的精品资源点击获取
返回列表