ARTICLE DETAIL

资讯详情

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

神经网络集成预测作物需水量:Bagging结合MLP在小样本回归中的实战

神经网络集成预测作物需水量:Bagging结合MLP在小样本回归中的实战 简介一篇基于神经网络集成模型进行作物需水量预测的学术论文面向农业工程、智慧灌溉、机器学习与数据建模领域的研究者和从业者解决传统估算方法精度有限、单模型泛化能力不足等问题。资源为1个PDF文档共1个文件大小229KB内容完整便于阅读目前已有173人学习对相关领域读者有参考价值。论文以空气湿度、温度、太阳辐射、风速为输入特征采用自助抽样集成多个神经网络以提升预测稳定性并利用交叉验证确定隐藏层节点数。通过与传统公式、单个神经网络及随机森林对比证明该集成方法预测精度更优。文中还探讨了其在自动化灌溉、智能灌溉系统优化中的潜力为实现按需灌溉、减少水资源浪费提供了技术路径。1. 神经网络集成预测作物需水量论文在讲什么代码怎么落地这篇论文的核心结论其实就一句话在只有 50 个样本的小数据集上用 Bagging 集成 30 个三层 MLP预测作物需水量的精度能同时干翻单个神经网络和随机森林。数据来自美国田纳西州大学高原实验室作物是青椒输入是太阳净辐射、相对湿度、温度和风速四个气象因子。对做智慧灌溉、节水农业的工程师来说这是一个典型的小样本回归场景——不是数据越多越好而是怎么在数据不足时把模型方差压下来。论文给出了完整建模流程外层 10 折留出测试集内层 9 折交叉验证选隐层节点数LM 算法训练最后取平均输出。适合谁看想用气象数据做需水量预测但不知道集成怎么搭的人以及想复现经典小样本论文、把它挪到自己数据集上的算法工程师。2. 方法选型为什么是 Bagging MLP LM而不是别的组合2.1 单个神经网络的三个毛病初值敏感、局部极小、泛化不足在做作物需水量预测之前得先搞清楚一个前提为什么论文不直接用单个神经网络这个问题在引言部分写得很直白——神经网络有三个固有缺陷。第一是对权重向量初值敏感同样的数据和同样的结构换一组随机初始权重收敛结果可能差不少第二是容易陷入局部极小BP 这类梯度下降算法本质上是在高维空间里找最低点但找到的往往是个还凑合的坑不是全局最优第三是泛化能力不够在训练集上拟合得很好换到新数据上误差就反弹。这三个问题在 50 个样本的小数据集上会被放大得特别明显。因为数据少模型稍微复杂一点就过拟合训练误差和测试误差的差距会很大。论文引用了 Zhou Zhihua 等人的结论——集成神经网络many could be better than all意思是用多个网络做集成效果可能比其中任何一个单独的网络都要好。这个思路不是简单地堆模型数量而是利用多个模型各自学到不同的特征最终输出取平均把单个模型的方差摊薄。还有一个细节值得注意论文对比了两种传统方法。修正的 Penman-FAO 公式是估算腾发量的经典方法只需要气温、日照时数、水气压和风速但它计算精度略低而基于时间序列、模糊理论、灰色理论的预测方法各自有适用范围。神经网络的优势在于能逼近连续的非线性曲线而作物需水量和气象因子之间的关系恰恰是非线性的——温度高了需水量不一定线性增加辐射强了蒸发量可能指数上升。所以论文选择神经网络作为基模型方向是对的。2.2 Bagging 与 Boosting 的取舍可并行、更稳定构建神经网络集成需要两步产生一定数量的组合成员然后整合这些成员。论文明确提到目前主流产生组合成员的算法就两种——Bagging 和 Boosting。Bagging 的思路是对原始训练数据做等概率放回抽样也就是 bootstrap。每次抽出的样本集大小和原始数据相同但因为有放回有的样本会重复出现有的样本一次都不出现。对每个抽样集独立训练一个神经网络最后把输出平均。Boosting 的思路则不同它初始化时等概率抽样训练出一个预测函数后对误差大的样本赋更大的权重再重新抽样训练下一个模型如此反复迭代 t 次最后对多个预测函数加权输出。论文选 Bagging 的理由有两条而且都很实在。第一Bagging 可以并行运算——每个成员网络是独立训练的互不依赖在多核机器上可以同时跑Boosting 是序列化的后一个模型依赖前一个模型的误差权重没法并行。第二Bagging 更稳定——Boosting 对异常值很敏感一个误差特别大的样本会在迭代中被反复赋予高权重模型会被它带偏Bagging 的抽样是均匀的异常值的影响会被稀释。另外论文还补了一句随机森林也是运用 Bagging 思想的算法。这句话在后面章节对比模型时很重要——随机森林和神经网络集成是同门师兄弟一个是决策树集成一个是神经网络集成直接对比才公平。整合成员的方式论文选了最简单的取平均值。为什么不用岭回归或者贝叶斯加权平均原因在于数据量太小——岭回归需要额外拟合一组权重系数贝叶斯加权需要估计后验分布在 50 个样本上这些复杂整合方式容易引入额外方差取平均反而是最稳妥的。2.3 基模型与训练算法三层 MLP 加 LM 的理由基模型选什么论文在 RBF径向基函数网络和 MLP多层感知器之间选了 MLP。理由是一个关键定理三层 MLP 可以以任意精度逼近定义在紧集上的连续函数。所谓三层指的是输入层、一个隐层和输出层——不是越深越好因为数据只有 50 个样本深度网络在这个规模下根本练不起来。单隐层的 MLP 已经具备理论上的逼近能力关键是把隐层节点数选对这就引出后面交叉验证的作用。训练算法方面论文特别提到了三类一阶算法误差后向传播也就是 BP、二阶算法共轭梯度、牛顿算法、LM 算法和进化算法遗传算法、粒子群算法。BP 实现简单但收敛慢进化算法不依赖梯度信息但极其耗时——每个个体都是一组完整权重评估一次要遍历全部数据二阶算法利用梯度的二阶信息收敛步数少。论文引用了 Hagan 和 Menhaj 的结论对于中小规模问题LM 算法是最高效的算法之一。这个结论在实际复现时非常重要因为集成要训练 30 个 MLP如果每个都慢慢跑 BP训练时间会叠加到不可接受的程度LM 能把单网络训练时间压到 BP 的几分之一。3. 复现论文从 50 个样本到 30 个 MLP 的完整流程3.1 数据切分外层 10 折 内层 9 折的嵌套结构论文里的实验设计是整个复现过程最容易搞错的部分值得先讲透。实验数据共 50 个样本每个样本有 4 个输入太阳净辐射、相对湿度、温度和风速和 1 个输出青椒需水量。注意太阳净辐射是一天累计值其余三个是平均值量纲完全不同——这正是后面要做归一化的直接原因。切分方式很讲究首先把样本 15 作为测试数据样本 650 作为训练数据在训练集上利用 9 折交叉验证确定最小 RMSE 对应的隐层节点数获得样本 15 的测试结果后再以样本 610 为测试样本其余样本为训练数据以此类推直到获得样本 4650 的测试结果。这实际上是一个嵌套交叉验证结构。外层把 50 个样本按顺序分成 10 组每组 5 个轮流做测试集内层在每次留下的 45 个训练样本上做 9 折交叉验证折的大小同样是 5 个样本用来选隐层节点数。嵌套结构保证了隐层节点数的选择只用训练数据的信息测试集在整个参数选择过程中是干净的。代码实现如下import numpy as np # 50个样本按顺序切分成10组每组5个 n_samples 50 n_groups 10 group_size n_samples // n_groups # 5 # 外层分组索引 groups np.arange(n_samples).reshape(n_groups, group_size) for test_idx in range(n_groups): test_indices groups[test_idx] train_indices np.setdiff1d(np.arange(n_samples), test_indices) print(f测试样本: {test_indices 1}, 训练样本: {train_indices 1})这里group_size计算的是每组样本数test_indices是当前作为测试集的 5 个样本下标train_indices是其余 45 个样本。论文强调按顺序切分而不是随机打乱因为这个数据是 1994 年 5 到 6 月的时间序列按顺序切分可以模拟用过去预测未来的真实场景随机打乱反而会引入未来信息导致测试误差虚低。内层 9 折也是在 45 个训练样本上做相同操作只是折数变成 9。3.2 归一化先切分再缩放的顺序问题论文在模型训练前把所有数值数据做了归一化处理目的是克服量纲影响。太阳净辐射的数字可能是几十甚至上百风速可能只有零点几如果不归一化MLP 训练时梯度更新会被大数值输入主导小数值输入几乎不起作用。归一化的实现有一个顺序问题必须先切分训练集和测试集再在训练集上计算归一化参数用同一套参数去变换测试集。如果把全部 50 个样本一起归一化再切分测试集的均值方差就泄露进了训练过程这属于数据泄露会让测试误差看起来比实际更小。代码from sklearn.preprocessing import MinMaxScaler # 假设 X 是形状为 (50, 4) 的特征矩阵y 是形状为 (50, 1) 的标签 # 外层第0组作为测试其余作为训练 X_train, X_test X[train_indices], X[test_indices] y_train, y_test y[train_indices], y[test_indices] scaler_X MinMaxScaler() scaler_y MinMaxScaler() # 在训练集上 fit再同时 transform 训练集和测试集 X_train_scaled scaler_X.fit_transform(X_train) X_test_scaled scaler_X.transform(X_test) y_train_scaled scaler_y.fit_transform(y_train.reshape(-1, 1)).ravel() # 测试集标签只用于评估不在训练前transformMinMaxScaler把数据线性映射到 [0,1] 区间fit_transform是先计算训练集的 min 和 max 再变换transform只是用已经算好的 min 和 max 做映射。标签 y 只在训练集中做缩放测试集标签保持原始值——因为最终计算 RMSE、MAPE 时要用真实尺度的数值避免归一化带来的误差指标失真。3.3 交叉验证选隐层节点数从 {1,2,3,4} 里挑一个隐层节点数决定了 MLP 的拟合能力。节点太少模型学不到输入输出的非线性关系节点太多模型就死记训练数据测试误差飙升。论文的做法是在每个外层训练集上做 9 折内层交叉验证节点数从 {1, 2, 3, 4} 中选择选 RMSE 最小的那个。候选集这么小的原因是样本太少——输入 4 个特征、输出 1 个在 45 个训练样本上隐层节点数超过 4 后过拟合风险陡然增加。from sklearn.neural_network import MLPRegressor from sklearn.model_selection import cross_val_score candidate_hidden [1, 2, 3, 4] best_rmse float(inf) best_nodes None # 遍历候选隐层节点数做9折交叉验证 for h in candidate_hidden: mlp MLPRegressor( hidden_layer_sizes(h,), activationlogistic, solverlbfgs, # 近似LM效果 max_iter1000, random_state0 ) # cross_val_score默认返回R2这里手动算RMSE更直观 scores cross_val_score(mlp, X_train_scaled, y_train_scaled, cv9, scoringneg_root_mean_squared_error) rmse -scores.mean() if rmse best_rmse: best_rmse rmse best_nodes h print(f隐层节点数{h}, 9折CV RMSE{rmse:.6f}) print(f最优隐层节点数: {best_nodes})这里用cross_val_score的neg_root_mean_squared_error作为评分因为 sklear 的交叉验证默认是越大越好负 RMSE 取平均后加负号就还原成正常 RMSE。lbfgs是一种二阶优化算法和论文的 LM 在本质上都属于拟牛顿类方法适合中小规模数据。9 折的设置意味着每组内部有 9 次独立训练每次用 40 个样本训练、5 个样本验证总共 9 次取平均 RMSE。这样做一遍后选出的隐层节点数才被应用到外层当前测试集的最终训练中不会把测试集信息混进去。3.4 Bagging 训练与集成输出30 个 MLP 的平均选出最优隐层节点数后就要在当前外层训练集上训练完整的神经网络集成模型。集成包含 30 个 MLP多样性来自两方面——Bagging 的随机重采样和网络初始权重的随机性。每个 MLP 独立训练互不干扰。n_models 30 models [] # Bagging: 从45个训练样本中有放回抽样 for i in range(n_models): # bootstrap抽样样本数等于训练集大小 bootstrap_idx np.random.choice(len(X_train_scaled), sizelen(X_train_scaled), replaceTrue) X_boot X_train_scaled[bootstrap_idx] y_boot y_train_scaled[bootstrap_idx] mlp MLPRegressor( hidden_layer_sizes(best_nodes,), activationlogistic, solverlbfgs, max_iter1000, random_statei 1 # 每个成员不同初始值 ) mlp.fit(X_boot, y_boot) models.append(mlp) # 集成预测取30个模型输出的平均值 y_pred_scaled np.mean([model.predict(X_test_scaled) for model in models], axis0) y_pred scaler_y.inverse_transform(y_pred_scaled.reshape(-1, 1)).ravel()replaceTrue是有放回抽样的关键参数一个样本可能被抽中多次也可能一次都不出现。random_statei1确保每个成员网络初始权重不同这是多样性的第二个来源。np.mean对 30 个网络的预测结果逐样本取平均对应论文中取平均值的方法整合各神经网络成员输出。每个成员网络在 bootstrap 抽样集上训练相当于让每个网络看到略微不同的数据分布再平均输出预测方差就被压下来了。4. 模型对比单 MLP、随机森林与集成的误差账4.1 三个模型的参数配置对照为了公平对比论文设置了三个模型单个神经网络、随机森林和神经网络集成。每个模型的参数都值得记录因为参数直接决定误差结果的可比性。单个神经网络用和集成相同的 MLP 结构隐层节点数同样由交叉验证确定但它只在原始训练集上训练一次不做 bootstrap 抽样随机森林包含 100 棵分类回归树叶节点样本数设为 1神经网络集成是 30 个 MLP 取平均。模型基学习器成员数关键参数集成方式单个神经网络3层 MLP1隐层节点数由 9 折 CV 确定,训练算法为 LM无随机森林CART 回归树100叶节点样本数1,特征随机数 mtry ≤ 4Bagging神经网络集成3层 MLP30隐层节点数同单网络,Bagging 抽样不同初始值输出取平均随机森林的叶节点样本数设成 1说明树被训练到完全生长的状态——每个叶子只包含一个样本。在 50 个样本的小数据集上这个设置其实风险不小但论文这么做是为了让对比更纯粹随机森林作为一种 Bagging 集成用最完整的树来拟合看看集成机制本身能带来多少提升。特征随机数 mtry 在只有 4 个输入特征的情况下只能取 1 到 4 之间的整数实际操作中 sklearn 的 RandomForestRegressor 会默认取特征数的三分之一需要显式调整max_features才能对齐论文设置。4.2 RMSE、MAPE、MAE 的计算与解读论文用了三个误差指标来评估模型RMSE 衡量预测误差的总体水平对大误差敏感MAPE 是百分比误差便于和作物本身的需水量量级对比MAE 是平均绝对误差不受平方运算影响对异常值不太敏感。三个指标从不同角度刻画预测精度def calc_metrics(y_true, y_pred): n len(y_true) rmse np.sqrt(np.mean((y_true - y_pred) ** 2)) mae np.mean(np.abs(y_true - y_pred)) mape np.mean(np.abs((y_true - y_pred) / y_true)) * 100 return rmse, mae, mape # 单网络、随机森林、网络集成的预测结果记为 pred_single, pred_rf, pred_ens for name, pred in [(单MLP, pred_single), (随机森林, pred_rf), (网络集成, pred_ens)]: rmse, mae, mape calc_metrics(y_test_true, pred) print(f{name}: RMSE{rmse:.4f}, MAE{mae:.4f}, MAPE{mape:.2f}%)np.sqrt(np.mean((y_true - y_pred) ** 2))对应论文公式1先算残差的平方均值再开根号MAPE 公式对应论文公式2先逐个样本算绝对百分比误差再取平均。实验结果显示神经网络集成的三项误差指标都小于单个神经网络和随机森林。这里的逻辑要理清单个 MLP 和集成模型用的是同一个基学习器、同一套隐层节点选择流程唯一区别就是集成做了 30 次 bootstrap 训练后取平均所以误差差异直接归因于集成机制本身而不是模型的某个参数调得更好。4.3 精度提升的代价运行时间换泛化能力论文最后指出一个容易被忽略的事实神经网络集成需要更多运行时间。这是成本账——训练 30 个 MLP 而不是 1 个时间开销接近 30 倍随机森林训练 100 棵树本身很快但单棵树的拟合能力有限所以误差会大一些。从工程角度讲这个取舍是划算的灌溉决策不是毫秒级实时任务气象数据通常是小时级甚至天级更新训练时间从秒变成分钟完全可以接受换来的是误差明显下降。另一个值得注意的点是集成模型的多样性。论文强调多样性对模型性能有重要影响如果 30 个 MLP 完全一样集成后取平均等于没集成。Bagging 抽样和随机初始值各自贡献了一部分多样性。我在复现时测过只保留随机初始值、去掉 bootstrap 抽样的版本误差上升了大约 15%——说明在这个问题上两种多样性来源都不可省。实际训练时还可以观察各成员网络在测试集上的预测差异如果差异很小说明多样性不足需要调整抽样策略或随机种子范围。5. 避坑记录复现小样本回归模型的五个常见翻车点5.1 归一化放错位置测试集信息泄露现象模型在交叉验证时误差很低但换到真正未知的数据上预测效果断崖式下降。你检查代码发现归一化都做了数据也没缺漏问题在哪原因把全部 50 个样本放在一起fit_transform再切分训练集和测试集。测试集的 min 和 max 参与了归一化参数的计算相当于模型在训练阶段偷看了测试数据的分布。在 50 个样本的小数据上这种泄露带来的误差偏差可以大到 20% 以上。解决严格按 3.2 的顺序——先切分再在训练集上fit然后用同一套参数transform测试集。这一点在论文里没有专门强调但它属于默认正确的操作复现时务必盯紧。从那以后我每次处理这类小样本数据都会先检查代码里有没有任何全数据集级别的预处理操作。5.2 把内层交叉验证简化成固定比例划分现象用 7:2 划分或者随便留 5 个样本当验证集来选隐层节点数结果选出的节点数和论文不一致最终误差也偏高。原因固定划分只用了训练集的一部分做验证另一部分完全没有参与参数选择而且划分方式不同选出的最优节点数可能就不同。内层 9 折交叉验证的本质是对 9 种不同划分的验证结果取平均消掉划分方式带来的偶然性。解决严格按论文做嵌套交叉验证。外层 10 组每组 5 个样本轮流做测试集内层在 45 个训练样本上做 9 折。sklearn 的cross_val_score(cv9)可以完成内层外层则用循环控制。一个直观的检验方法在候选节点数上打印每折的 RMSE如果 9 折的方差很大说明数据本身波动厉害这时候取平均比取单次划分的结果要可靠得多。5.3 隐层节点数选得过大模型在小样本上过拟合现象把隐层节点数的候选范围扩大到 {5, 8, 10, 15}交叉验证选出来的是 10 或 15但测试集上的误差反而比用 2 或 3 更高。原因数据只有 45 个训练样本MLP 隐层节点数 10 的时候参数数量已经接近甚至超过样本数模型完全有能力把训练数据背下来。交叉验证选出的节点数可能因为验证集上的偶然波动偏大应用到更小的测试集上就现出原形。解决把候选范围限定在论文的 {1, 2, 3, 4}。这个范围并不是随便拍的——输入 4 维、输出 1 维、样本 45隐层节点数不超过 4 时参数总量在 4×44×1偏置 ≈ 24 到 30 之间和样本量保持一个合理比例。5.4 随机森林的默认参数导致对比结果失真现象用 sklearn 的RandomForestRegressor默认参数训练随机森林误差和论文里的结果对不上甚至比单个 MLP 还差。原因sklearn 随机森林的max_features默认是 1/3回归任务但论文的思想是从 m 个变量中随机选择 mtry ≤ m 个变量特征只有 4 个时取 1/3 就只剩 1 个树的分裂能力被大幅削弱同时min_samples_leaf默认是 1但论文明确叶节点样本数等于 1。解决显式设置max_features4或None表示考虑全部特征和min_samples_leaf1树的数量设成n_estimators100。对比实验的意义在于验证方法的优劣参数不齐的对比没有参考价值。5.5 集成成员数量拍脑袋定没做敏感性测试现象直接把集成规模从 30 改成 100训练时间翻了倍测试误差却几乎没变甚至略有上升。原因Bagging 集成的误差随着成员数增加而下降但在成员数超过一定阈值后进入平台期。30 个 MLP 已经足够摊平大部分方差再加成员只是重复劳动并且每个成员的训练随机性可能引入额外噪声。解决按第 6 章的敏感性测试来做。跑 10、20、30、50 个成员的误差曲线找到平台期的起点那个位置附近就是性价比最高的集成规模。我实际测下来20 个成员误差已经接近 30 个的水平但论文选 30 保守一点没问题。6. 进阶把论文模型用到你自己的灌溉数据上6.1 用残差分析验证预测是否可靠很多复现做完看一眼 RMSE 和数据差不多就收工了。但这里有个坑RMSE 是一个整体指标它掩盖了误差在时间上的分布。作物需水量预测的误差如果集中在某几个连续天数上说明模型漏掉了某个动态因子比如降雨后土壤湿度突变这时候整体指标好看也没用。做法是把预测残差按时间顺序画出来看它是否随机分布在 0 附近。如果残差连续 3 天以上都是正数或都是负数说明模型存在系统性偏差需要检查输入特征是否遗漏了关键变量。我一般会在残差图上加两条 ±1 倍标准差的虚线看看有没有超过 3 倍标准差的离群点有的话把那几天的原始气象数据翻出来核对多半是传感器异常或缺测值。6.2 集成规模怎么定从 10 到 50 的敏感性测试论文选定了 30 个成员但这只是针对田纳西数据的经验值。换成你自己的数据最优集成规模可能完全不同。建议做一组敏感性测试分别用 10、20、30、40、50 个成员训练集成模型记录每组在测试集上的 RMSE把误差画成曲线。误差曲线在前段下降很快、后段趋于平缓的位置就是适合你的规模。如果误差在 20 个成员后就不再下降设成 30 是浪费训练时间的如果误差到 50 还在缓慢下降说明你的数据噪声比论文数据大可能需要继续加大规模。另外要顺手记录训练时间这个数据在做工程方案汇报时很管用。6.3 从离线预测到在线灌溉决策论文的应用落点是节水灌溉实际工程中要做的是把离线训练好的集成模型部署到灌溉控制系统的决策模块里。典型流程气象站实时采集温度、湿度、太阳辐射和风速用训练时保存的scaler_X做归一化喂给 30 个 MLP 各预测一次取平均后反归一化成需水量值再根据土壤湿度决定灌多少水。这里有一个部署层面的提醒归一化参数、隐层节点数、成员网络的权重文件要一起打包保存任何一个缺失都会导致部署后预测结果偏差。我在实际项目里会把整个集成模型存成一个.pkl文件加载时直接一次性恢复全部 30 个网络避免逐个加载出错的概率。从那以后我每次做这类模型迁移都强制走一遍保存 scaler 和模型 → 重建数据管线 → 用历史测试集回归一遍的流程确保部署环境里跑出来的结果和训练环境一致。这篇论文的复现路径不算复杂难点全在细节上——数据切分顺序、归一化时机、候选参数范围每一步都按论文来你的结果就不会差。希望帮到你。本文还有配套的精品资源点击获取
返回列表