ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

深度学习驱动的作物产量预测:从数据工程到模型实践

深度学习驱动的作物产量预测:从数据工程到模型实践 简介面向需要复现深度学习作物产量预测研究的开发者AAAI 2017最佳学生论文奖配套代码覆盖从遥感数据获取到模型训练与结果分析的完整链路。包内共54个文件以38个Python脚本为核心分别实现Google Earth Engine数据下载、图像切片与三维直方图清理、CNN/LSTM与高斯过程建模、批量训练及半监督实验另有csv标签数据、npy/npz结果矩阵、svg可视化图和mat变化函数文件辅助分析压缩包仅1.25MB。目前已吸引1539人浏览/学习适合有一定Python和深度学习基础、希望了解遥感时序建模或复现论文实验的研究者也可用作课程设计与科研入门的基线参考。通过目录模块可快速定位1下载数据、2干净数据、3模型、4 model_batch、5 model_semi_supervised等环节拿到完整可运行代码、结果分析工具和半监督扩展思路省去从GEE批量导出影像和调参的重复工作。1. 产量预测为什么难在动手写模型之前先回答这四个问题我最初做 crop_yield_prediction 这个项目时和大家一样直接跳到模型搭建想着尽快把神经网络跑起来、把精度刷上去。结果试了两周模型效果始终不理想。回头复盘才发现问题根本不在模型而在产量预测这四个字本身太模糊了。深度学习技术再强也得先回答清楚你要预测什么、用谁的数据、在哪个时间点预测、服务什么决策。这四个问题不解决后面所有工作都是在沙地上盖楼。先说空间尺度。产量数据的粒度直接决定建模上限。国内公开的统计产量大多到县区一级样本量够但内部差异大美国 USDA-NASS 的县级数据则相对规范也是国外论文里最常用的训练集。田块级数据精度最高但人工标注成本很高普通个人项目很难负担。我的项目选择了县级尺度的玉米产量预测好处是数据公开且易复现坏处是模型天然忽略田间的灌溉、施肥差异。你要清楚自己做的属于哪一种别期望县级模型给出田块级建议。其次是预测时间点。播种前、营养生长期、收获前30天这三个时间点能做预测的特征完全不同。播种前只有气候统计量和土壤属性准确率天花板就摆在那里等到生长季中后期遥感影像可以把叶面积指数、冠层温度、叶绿素含量都记录下来这些和最终产量高度相关。我最终把预测窗口放在生长季后期既保证了精度也能为粮食收购、保险定损留出操作时间。你在做类似项目时建议先确定决策时点再回过头选特征。第三是标签对齐。县级产量是一个行政区域内整季作物的平均单产而遥感影像的一个像素只有30米分辨率两者尺度根本不在一个层级。如果直接把县平均产量当作每一个像素的监督标签模型就会学到大量噪声区域内部的空间差异会被抹平。我的处理方式是把一个县范围内所有有效像元的特征做空间聚合再和县级标签配对。这个操作很基础但对最终模型性能影响极大。最后想清楚你要的是绝对产量还是相对丰欠。很多政府决策只需要知道今年比常年增产还是减产这时候预测相对变化更稳定但保险定价、期货交易则需要绝对数值。我最后同时训练了两个输出头分别回归绝对单产和年际差分发现差分目标在异常年份的鲁棒性明显更好。这也是传统统计模型和树模型很难处理的点因为它们把产量当作一组静态特征的回归问题忽略了时空动态深度学习恰好能通过卷积、循环网络和注意力机制把这种动态结构建模出来。2. 数据工程crop_yield_prediction 项目里最花时间的环节2.1 数据源选型和组合策略很多人以为产量预测模型的核心在算法实际把项目完整走一遍就会发现数据工程至少占掉70%的时间。我梳理过一轮公开数据源最终锁定四类遥感影像、气象再分析数据、土壤属性数据、官方产量统计。数据类别推荐来源空间/时间分辨率在模型中扮演的角色遥感植被指数MODIS NDVI/EVI、Sentinel-2250m/5天、10m/5天直接反映作物长势是最强特征气象数据ERA5、PRISM0.25°/逐小时、4km/逐日温度、降水、辐射的时序变化土壤属性SoilGrids250m质地、有机碳、阳离子交换量产量统计USDA-NASS / 中国统计年鉴县/年监督标签这几种数据在项目里承担的职责完全不同。遥感植被指数是产量的直接影像化表达尤其是生长季累计的 NDVI 峰值和积分值几乎和最终产量线性相关气象数据描述的是环境胁迫像热浪、干旱这些极端事件遥感影像可能有滞后气象序列能及时捕捉土壤数据是静态的却决定了产量的基础水平和潜在上限许多模型忽略这个变量导致跨区域泛化很差。2.2 样本构造时间窗口怎么滑、标签怎么对齐原始数据处理完之后下一步是造样本。这一步看似机械实际决定模型能不能学到因果信息而不是把时序关系弄混。我用的做法是把整个生长季按天划分用10天一期的合成影像生成NDVI曲线再以每3个月为一个输入窗口、步长为10天滑动截取构造出多段重叠的时序样本。每段样本的标签对应窗口结束后最终的县级产量。这里有一个关键细节特征时间必须严格早于预测时间点否则就引入了未来信息泄漏。比如我要在当地收获前30天出预测那么输入窗口就必须截止到那一天后面所有数据一概不能进入模型。我知道有人为了提升指标把整个生长季的影像全部输入模型这当然精度高但实际部署时根本没法用因为你手里没有未来的数据。做这类项目一定要先明确预测截止日然后按这个截止日构造训练和测试样本。2.3 预处理里那些很容易踩的坑数据预处理看起来都是琐碎活但每一项都在悄悄影响精度。我踩过的坑至少有三个这里直接说出来。第一个坑是归一化参数混用。我一开始直接对整个数据集做了全局 z-score 归一化后来用按年份划分的验证集评估时发现指标虚高。原因是全局归一化已经把验证集的均值和标准差带入训练过程形成了隐性泄漏。正确做法是只在训练集上计算均值和标准差然后原样套用到验证集和测试集。这个错误在表格类数据里不致命在深度学习里却可能让你对泛化能力产生严重错觉。第二个坑是云层和无效像元。遥感影像不是每一帧都干净云层遮挡会让 NDVI 值骤降。我第一次做的时候直接用原始像元均值结果某些多雨地区出现大量异常峰值。后面换了 Savitzky-Golay 滤波配合云掩膜cloud mask数据把受污染的时序点剔除后再做合成才算把噪声压下去。第三个坑是数据缓存。几十个县、十多年、多个数据源叠加原始数据量很容易超过几十 GB。每迭代一次预处理就全部重跑一遍时间成本完全不能接受。我后来把所有预处理结果缓存成 NumPy 数组或 Parquet 文件并且给每个版本打上哈希标识这样调模型时可以秒级加载特征不必反复读原始影像。3. 模型选型实战CNN、LSTM、Transformer 各自的适用边界3.1 三种模型到底在解决什么问题模型选型不是越先进越好关键是匹配数据形态。产量预测输入本质是一个带空间位置标记的时间序列各特征之间的相互作用很复杂。围绕这个数据形态我对比过三类架构一维 CNN 的优势在于参数少、训练快能有效提取局部时序模式比如连续两个月的气温高温累积对后期灌浆的影响。缺点是感受野有限单纯堆很多层才能捕捉更长期的依赖容易带来优化困难。LSTM 天然适合时序建模理论上可以记忆几个月前的关键事件比如花期低温对授粉的影响但训练比较慢对初始化和学习率更敏感调参成本高。Transformer 用自注意力机制直接建模任意时间步之间的依赖长程信息传递很高效但需要足够多的数据否则容易过拟合。在实际项目中我并没有在三者之间做非此即彼的选择而是把它们组合起来先用 CNN 提取局部特征再送入 LSTM 和 Transformer 编码器的混合结构让模型同时具备局部敏感性、长程记忆和全局关联能力。这不是炫技而是产量数据本身包含多尺度信息单一结构很难全部覆盖。3.2 一种可复现的基线结构我的模型输入张量形状是(batch, time_steps, num_features)其中time_steps是滑动窗口长度num_features是遥感、气象、土壤三类特征拼接后的维度。用 PyTorch 实现时核心结构大致是这样的class CropYieldModel(nn.Module): def __init__(self, time_steps36, num_features12, d_model128): super().__init__() # 先用一维卷积提取每个特征自身的局部模式 self.cnn nn.Sequential( nn.Conv1d(num_features, 64, kernel_size3, padding1), nn.BatchNorm1d(64), nn.ReLU(), ) # LSTM 负责捕捉跨时间的动态变化 self.lstm nn.LSTM(64, 128, num_layers2, batch_firstTrue) # Transformer 编码器补充全局依赖 self.transformer nn.TransformerEncoder( nn.TransformerEncoderLayer(d_model128, nhead4, batch_firstTrue), num_layers2 ) # 回归头输出绝对产量和年际差分 self.head nn.Sequential( nn.Linear(128, 64), nn.GELU(), nn.Dropout(0.2), nn.Linear(64, 2) ) def forward(self, x): # x: (batch, time_steps, num_features) x x.transpose(1, 2) x self.cnn(x) x x.transpose(1, 2) x, _ self.lstm(x) x self.transformer(x) x x.mean(dim1) return self.head(x)这个结构在多种遥感产量预测论文里都有类似影子属于稳妥的基线。如果你刚入门建议先把这个模型跑通再逐步替换模块做对比不要一上来就堆大模型。3.3 消融实验里最让我意外的结论消融实验是这类项目里必须做的否则你不知道精度到底来自哪里。我的实验中出现了几个反直觉的结果。第一个是把气象特征全部去掉之后模型精度只下降了不到百分之十反倒是去掉遥感 NDVI 特征后测试集误差急转直下短期内心脏骤停那种。这告诉我植被指数在整个产量形成预测里占绝对主导地位。但这不代表气象数据没用在极端年份比如2020年的高温干旱加入气象胁迫特征能让模型的绝对误差显著降低。也就是说遥感是常规年份的主力气象是异常年份的保险。第二个是Transformer 部分在数据量不足时会拖后腿。我训练集只有不到一千个县年样本直接把 Transformer 层加到三层以上训练损失能降验证集却明显过拟合。最后我把层数压到两层、嵌入维度降到128各方面表现才正常。这说明在中小规模数据集上Transformer 不是白给的数据量不够时反而要优先保证 CNN 和 LSTM 的稳定性。4. 训练和评估中容易翻车的几个细节4.1 损失函数、激活函数与优化器选择产量预测是回归任务最常见的损失函数是 MSE但它对异常年份的惩罚特别大。一年极端干旱造成大面积减产MSE 会把模型往这个离群点方向猛拉牺牲平均表现。我实验下来Huber 损失比纯 MSE 稳得多它结合了 MAE 和 MSE 的优点在残差较小时梯度变化平缓残差很大时又不会彻底被离群值带跑。如果你更关心相对误差还可以尝试对预测值和标签取对数后再算回归损失这样在小产区和高产区之间做损失平衡效果更好。激活函数的选择也是影响模型能否训动的重要因素。隐藏层里我尽量避免用饱和激活函数比如 sigmoid 和 tanh因为层数一深梯度容易消失ReLU 系列在实测中表现最好尤其是 GELU在 Transformer 和 MLP 结构里都比 ReLU 稳定。输出层则不加任何激活直接输出实数值千万不要为了归一化而加 sigmoid那会把预测限制在0到1之间完全错乱。优化器方面如果你直接踩进深度学习新手的经典坑——随便用默认学习率开跑会发现损失很容易爆炸。我用的是一段式余弦退火学习率调度初始学习率设在1e-4配合 AdamW 优化器和 20 个 epoch 的 warmup整体训练稳定许多。环境配置上我当初装深度学习框架时也折腾过不少时间国内镜像源加 conda 虚拟环境是解决依赖冲突最省心的组合PyTorch 的 CUDA 版本和显卡驱动一定要核对否则模型能跑 CPU 版但速度惨不忍睹。4.2 验证集划分按年份切和按地区切结果差别很大许多做表格回归习惯用随机抽样划分训练集和验证集在产量预测里这是大忌。同一个县同一年的地块特征高度相似随机划分会把相邻时间的样本同时放进训练和验证指标虚高到失真。我试过两种合理划分效果差异非常明显。第一种是按年份划分把最后两年作为验证集前十年数据训练模拟的是用历史预测未来的真实场景模型要面对气候波动和品种更新挑战最大第二种是按地区划分留出一整个州的产量数据不参与训练检验的是模型能不能迁移到没见过的地理区域。两种划分方式得到的误差可以相差百分之二三十。如果你的模型只在随机划分下表现好按年份划分后误差大幅上升基本可以断定模型记住了时间相关的模式并没有学到真正的因果特征。在最终评估时我同时报告按年份和按地区划分的结果并单独挑出极端气候年份做压力测试。模型在正常年份误差很低但一到极端年份误差放大不少这也暴露了当前方法的天花板——训练数据里如果没有足够的极端样本模型很难凭空学会应对未知灾害。4.3 评估指标组合R² 是最常见也最容易被误用的产量预测指标原因是当数据方差很大时哪怕模型只是简单预测历史均值R² 也能超过0.8看似很好实际已经失去区分度。我的习惯是至少同时看四个指标RMSE、MAE、MAPE、R²各有各的侧重。指标公式说明RMSE√(Σ(yi-ŷi)²/n)对大误差敏感适合风险控制场景MAEΣyi-ŷiMAPEΣ(yi-ŷi)/yiR²1 - SSres/SStot解释方差比例需要结合数据方差看实际部署时我会主看 RMSE 和 MAPERMSE 告诉农民或保险公司最坏情况下能差多少吨MAPE 方便在不同县之间对比预测质量。R² 只作为参考不单独作为考核指标。5. 从实验到落地产量模型真正能用的最后一公里5.1 跨区域、跨年份泛化模型在新地盘上还灵不灵实验室指标好看不等于模型在真实世界能用。我拿训好的模型去预测一个完全没参与训练的州时误差比本地验证集高出一截。仔细分析后发现核心原因是训练集里这个州的地块很少模型没见过当地特有的种植制度和土壤条件。要改善这一点最有效的办法不是调模型结构而是把土壤属性特征和气候分区标签显式加入输入。加上之后跨区域误差明显回落。跨年份泛化同样棘手。产量预测面对的是不断变化的农业系统新品种、新农药、种植结构调整都在悄悄改变产量与特征之间的关系。我做过一个最直接的压力测试用2005到2015年的数据训练去预测2016到2020年的产量发现极端年份误差被明显放大。这意味着模型部署到生产环境后必须定期用最近年份数据重新微调否则预测能力会逐年衰减。5.2 可解释性农业专家需要你解释为什么预测这个数模型上线后我发现自己陷入了另一个困境模型精度够了但没有业务方敢用它。农技站的人会问你预测这块地亩产600公斤依据是什么如果只甩出一句深度学习算出来的对方大概率直接不采用。可解释性不是加分项而是落地的前提。我后来给模型加了特征重要度分析用类似 SHAP 的方式计算每个输入特征对预测结果的贡献并按县域输出可读报表。比如本县今年7月 NDVI 偏低叠加8月高温天数增加模型因此下调产量估值。经过这样的形式基层人员能理解模型的判断依据才真正愿意拿模型结果做参考。5.3 上线部署时容易被忽视的更新策略深度学习模型的部署和传统软件不一样不是训练完永久上线就完事。产量预测模型强烈依赖当年的气象和遥感数据数据本身的延迟和缺失会直接影响推理结果。我的生产系统里设置了两条更新路径一条是快速路径生长季内每天拉取最新遥感影像和气象预报数据跑增量推理刷新预测另一条是慢速路径每年生产周期结束后用当年完整数据重新训练一遍模型替换旧版本。推理延迟在这个场景里不是什么大问题一个县的预测用 GPU 跑毫秒级就能完成真正限制业务更新频率的是数据获取和预处理链路。遥感数据清洗、云掩膜、特征计算这一套流程平时要提前建好流水线等数据一到就能滚动更新。很多项目模型本身做得不错却因为数据管道搭建不及时错过最佳预测窗口最终没有发挥实际价值。我个人在跑完这套 crop_yield_prediction 项目后最大的感受是深度学习在农业遥感领域的潜力很大但做好产量预测的瓶颈从来不只是算法本身。数据治理、问题定义、评估设计、业务解释每一个环节都能让最终效果天差地别。如果你刚接触这类项目建议先别急着堆模型多花点时间把数据和评估方案理清楚后面自然水到渠成。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进