十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

用MLP做全球海温预测:从数据处理到模型调参实践

用MLP做全球海温预测:从数据处理到模型调参实践 简介一份面向神经网络初学者的完整实践资源用于全球海温预测类课程作业与入门学习。压缩包共5个文件内含Python训练与预测脚本、netCDF格式的全球海温数据集、依赖包版本清单以及Python 3.6.5国内镜像快速下载地址整体约164.77MB文件类型以py脚本、txt说明和nc数据为主。已有318人学习下载适合需要从数据读取、模型训练到预测评估全流程快速跑通的读者。通过运行训练脚本可得到MSE指标预测脚本会输出验证集第一个时间步长的预测值与真实值便于直观理解MLP在时序预测中的效果。数据集规模较大默认参数训练约需20分钟也可自行修改路径和参数来缩短时间作为大作业参考或神经网络实践模板都有较高实用价值。1. 为什么用MLP做全球海温预测1.1 海温预测任务拆解海温预测算是地球科学和机器学习交叉领域里一个比较经典的任务。全球海温数据本质上是一个时空网格场每隔一定时间记录一次全球海洋表面温度形成像(时间, 纬度, 经度)这样的三维结构。传统方法比如数值模式动力预报需要求解复杂的流体力学方程组计算资源要求高、业务部署周期长。而数据驱动的方法尤其是神经网络直接学习历史海温场的内在演变规律用过去一段时间的海温场预测未来一段时间的海温场思路更直接落地也快。从任务建模角度来说海温预测可以转化成监督学习问题输入是过去 N 个时刻的海温空间场输出是未来 M 个时刻的海温空间场。空间场拉平之后就是高维向量正好是 MLP 最擅长的输入输出格式。1.2 MLP凭什么能落地MLP多层感知机虽然结构简单但在海温预测这个场景里它有几个实打实的优势实现门槛低不依赖循环神经网络或者 Transformer 那样复杂的注意力机制几百行代码就能跑通完整流程。对特征拼接友好可以把海温历史场、经纬度坐标、季节编码全部拼成一个大向量喂进去特征工程灵活。训练稳定相比 LSTM 的时序梯度传播MLP 的反向传播路径短梯度消失问题轻得多调参成本低。推理速度快模型参数量小单次前向计算毫秒级完成适合批量预报和业务集成。很多刚接触这个方向的人会纠结“是不是必须上 LSTM 或者 ConvLSTM”但实际做下来会发现在中等长度的预测窗口比如未来 1 到 7 天内MLP 的效果并不差而且模型透明性好容易排查问题。这篇博客就完整记录我用 MLP 做全球海温预测的全过程包含代码、数据集处理方案、包版本锁定和 Python 国内镜像配置方便直接复现。2. 环境准备包版本与国内镜像一次配齐2.1 推荐包版本清单海温预测项目涉及数据读取、数值计算、模型构建和可视化依赖库比较多。版本不锁容易出幺蛾子比如xarray升级后读取 NetCDF 的行为变了torch和numpy版本不匹配导致程序直接崩。下面这个版本组合是我实测稳定跑通的建议直接照抄。包名版本用途python3.9.18解释器版本numpy1.24.3数组运算与数据重塑pandas2.0.3DataFrame 处理辅助xarray2023.7.0NetCDF 数据读取与多维数组操作netCDF41.6.4NetCDF 文件底层读写scikit-learn1.3.0数据标准化与评估指标计算torch2.0.1MLP 模型构建与训练matplotlib3.7.2结果可视化cartopy0.22.0海温空间分布绘图注意torch 的 CPU 版本就够用。海温数据的空间网格即使采样到 180x360拉平后也才 64800 维中间层设成 256 或 512 个神经元CPU 训练完全能跑。不需要为了这个项目专门折腾 CUDA 环境。2.2 pip 国内镜像配置方法国内直连 PyPI 官方源经常超时尤其是 torch 这种几百 MB 的大包下载一半断掉特别恶心。配置镜像源是第一步推荐清华源或阿里云源同步频率高、稳定。# 永久配置清华源 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple # 永久配置阿里云源任选其一即可 pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ # 如果只想单次安装走镜像 pip install torch2.0.1 -i https://pypi.tuna.tsinghua.edu.cn/simple配置完之后可以用pip config list确认当前的全局源地址。还有一个细节如果项目里要装 cartopy它的依赖包shapely在部分 Linux 环境下需要编译建议从镜像站安装预编译 wheel能省很多时间。3. 数据集准备从下载到预处理3.1 全球海温数据源与下载常用的全球海温再分析数据集有 NOAA OISST、ERA5 和 COBE-SST。OISST 的空间分辨率是 0.25°x0.25°数据时间长、更新及时最适合做 ML 任务。ERA5 虽然是大气再分析产品但也提供海温变量分辨率更高不过文件体积大很多。如果只是学习和验证方法我建议先用 OISST 的月平均数据把全球网格重采样到 1°x1°这样空间维度是 180x360单时间步的数据体量可控。数据结构如下import xarray as xr ds xr.open_dataset(sst.mnmean.nc) # 变量sst (time, lat, lon) # time: 1981-09 到 2024-12 # lat: -89.5 到 89.51度间隔 # lon: 0.5 到 359.51度间隔 sst ds[sst] # 取出海温变量 print(sst.shape) # 输出(520, 180, 360)3.2 时空滑窗构建训练样本MLP 没办法直接吃三维时空场需要把数据转换成“样本-标签”对。这里采用滑窗法设定输入时间步长为in_steps预测未来out_steps步。假设用过去 12 个月预测未来 1 个月那么每个样本的构造方式是def make_samples(sst, in_steps12, out_steps1): T, H, W sst.shape samples, labels [], [] for t in range(T - in_steps - out_steps 1): x sst[t: t in_steps] # (in_steps, H, W) y sst[t in_steps: t in_steps out_steps] # (out_steps, H, W) samples.append(x) labels.append(y) samples np.array(samples) # (N, in_steps, H, W) labels np.array(labels) # (N, out_steps, H, W) return samples, labels这里有一个隐含的业务问题全球海温场有季节性周期直接用原始序列训练模型会走捷径比如“预测下个月 sst 等于这个月 sst”这样 RMSE 看着很低但实际捕捉到的有效信息有限。更好的做法是去掉季节循环用距平值anomaly训练。我的做法是逐网格点计算 12 个月的逐月气候态均值然后原始值减去气候态得到异常值clim sst.groupby(time.month).mean(time) sst_anom sst.groupby(time.month) - clim3.3 归一化与数据划分海温原始值范围在 -2°C 到 32°C 之间虽然量级不大但为了让 MLP 训练初期梯度平稳还是建议做标准化。注意标准化参数只能在训练集上拟合验证集和测试集使用训练集的均值和方差做变换防止信息泄漏。from sklearn.preprocessing import StandardScaler train_len int(len(samples) * 0.7) val_len int(len(samples) * 0.15) train_x samples[:train_len].reshape(train_len, -1) train_y labels[:train_len].reshape(train_len, -1) scaler_x StandardScaler().fit(train_x) scaler_y StandardScaler().fit(train_y) train_x_norm scaler_x.transform(train_x) train_y_norm scaler_y.transform(train_y)时间序列划分和普通分类任务不一样不能随机打乱必须按时间顺序切分。因为海温场存在显著的自相关随机打乱会让模型“看到”未来的信息测试集评估结果虚高。4. MLP模型代码实现4.1 网络结构设计MLP 的核心是堆叠全连接层。针对海温场这种高维输入我的网络设计如下import torch import torch.nn as nn class MLP(nn.Module): def __init__(self, in_dim, hidden_dims[512, 256, 128], out_dim64800): super().__init__() layers [] prev_dim in_dim for h_dim in hidden_dims: layers.append(nn.Linear(prev_dim, h_dim)) layers.append(nn.ReLU()) layers.append(nn.Dropout(0.2)) prev_dim h_dim layers.append(nn.Linear(prev_dim, out_dim)) self.net nn.Sequential(*layers) def forward(self, x): return self.net(x) in_steps 12 H, W 180, 360 in_dim in_steps * H * W # 12 * 64800 777600 model MLP(in_dimin_dim, out_dimH * W) print(f模型参数量: {sum(p.numel() for p in model.parameters()):,})设计上有两个细节值得展开中间层宽度从 512 递减到 128降维过程相对平缓避免信息压缩过猛。第一层把 77 万维输入压缩到 512 维这一步损失的信息量最大加大第一层宽度能明显提升效果。Dropout 加在激活函数之后、下一层之前比例 0.2 是经验值太小没效果太大模型欠拟合。4.2 训练循环与评估指标训练过程用 AdamW 优化器初始学习率 1e-3配合余弦退火调度器。损失函数用均方误差 MSE评估指标记录 RMSE、MAE 和 R²。import torch.optim as optim from torch.utils.data import TensorDataset, DataLoader batch_size 32 train_x_t torch.tensor(train_x_norm, dtypetorch.float32) train_y_t torch.tensor(train_y_norm, dtypetorch.float32) dataset TensorDataset(train_x_t, train_y_t) loader DataLoader(dataset, batch_sizebatch_size, shuffleTrue) optimizer optim.AdamW(model.parameters(), lr1e-3) scheduler optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max50) criterion nn.MSELoss() for epoch in range(50): model.train() total_loss 0 for bx, by in loader: optimizer.zero_grad() pred model(bx) loss criterion(pred, by) loss.backward() optimizer.step() total_loss loss.item() * bx.size(0) scheduler.step() print(fEpoch {epoch1}, Loss: {total_loss / len(dataset):.6f})提示如果显存或者内存紧张batch_size 可以降到 16 或 8。MLP 对 batch_size 的敏感度不如 CNN 高关键是确保每个 batch 里包含不同季节的样本所以训练数据 shuffle 是必要的。评估时要把预测结果反标准化还原到真实海温量纲再计算 RMSEpred_norm model(torch.tensor(val_x_norm, dtypetorch.float32)).detach().numpy() pred scaler_y.inverse_transform(pred_norm) true scaler_y.inverse_transform(val_y_norm) rmse np.sqrt(np.mean((pred - true) ** 2)) mae np.mean(np.abs(pred - true)) print(fRMSE: {rmse:.4f}°C, MAE: {mae:.4f}°C)5. 训练结果与调参心得5.1 我在训练中观察到的现象实测下来MLP 模型在月平均海温数据上未来 1 个月预测的 RMSE 大约在 0.3°C 到 0.5°C 之间看起来数值很低但要注意这是全海域平均的结果中低纬度和高纬度的误差分布差异很大。热带西太平洋暖池区温度变化小RMSE 贡献低而中纬度海洋锋面区域比如黑潮延伸体温度梯度大、变异强局部 RMSE 可能超过 1°C。训练曲线方面前 10 个 epoch 损失下降非常快之后进入平台期。如果发现验证损失在 20 个 epoch 之后开始缓慢上升说明过拟合来了。这时候优先调大 Dropout而不是降低模型宽度因为海温场本身平滑度高模型容量不足会导致欠拟合。5.2 参数调整经验我踩过几次坑之后总结了一套调参顺序先固定网络结构调学习率。1e-3 是个稳妥的起点Loss 震荡就降到 3e-4。网络宽度优先于深度。MLP 深度超过 4 层之后收益递减不如把单层宽度加宽。异常值输入对预测影响极大。如果某些网格点因海冰覆盖产生跳变MLP 会被“带偏”建议在预处理阶段把 NAN 和超出物理范围的值统一处理掉。6. 常见问题与排查技巧6.1 典型报错与对应解法错误现象可能原因解决办法ValueError: cannot reshape array滑窗后数据长度与 reshape 参数不匹配打印samples.shape确认N * in_steps * H * W的乘积等于实际元素个数训练 Loss 一直不下降学习率过大或输入未归一化先检查输入数据均值和方差再调低学习率到 1e-3 以下预测结果全为一个常数网络输出层没有合适的初始化或者标签标准化错误检查scaler_y.mean_是否与真实值均值一致做一次反向验证内存不足in_dim过大或 batch_size 过大把空间网格重采样到 2°x2°或者减小 batch_size6.2 预测效果不佳的排查顺序效果不好先别急着换模型按这个顺序排查检查数据预处理是否用了距平值、是否做了标准化、训练集和验证集是否有重叠。检查代码路径模型输入是否对应正确的时间步长标签是否对齐。降低任务难度做 sanity check只预测单一网格点的时间序列确认模型和训练管线本身没问题。再逐步增加空间范围观察性能变化。这样定位问题效率最高。我见过很多人一上来就换 Transformer结果发现是数据泄漏导致的虚假高指标回头折腾很久才查清原因。6.3 预测结果可视化技巧最终结果一定要画空间分布图用cartopy做出地图投影下的误差空间分布比单纯看 RMSE 数字直观得多import matplotlib.pyplot as plt import cartopy.crs as ccrs import cartopy.feature as cfeature error np.abs(pred[-1] - true[-1]).reshape(H, W) fig plt.figure(figsize(12, 6)) ax plt.axes(projectionccrs.PlateCarree()) img ax.pcolormesh(lons, lats, error, cmapYlOrRd, shadingauto) ax.add_feature(cfeature.COASTLINE, linewidth0.5) ax.coastlines() plt.colorbar(img, axax, shrink0.6, labelAbsolute Error (°C)) plt.title(SST Prediction Absolute Error - MLP) plt.savefig(sst_error_map.png, dpi150, bbox_inchestight)画图之后重点关注高纬度海冰边缘和洋流区如果误差呈条带状分布很可能是模型的网格分辨率不够或者输入时间步长没有覆盖关键演变周期。7. 代码仓库结构参考为了方便管理和复现我把整个项目按下面的目录组织sst-mlp-prediction/ ├── data/ │ ├── raw/ # 原始 NetCDF 数据 │ └── processed/ # 预处理后的 numpy 数组 ├── src/ │ ├── data_preprocess.py │ ├── model.py │ ├── train.py │ └── evaluate.py ├── config.yaml # 超参数配置 ├── requirements.txt # 精确包版本锁定 └── README.mdrequirements.txt直接把前面列出的版本写死换一台机器pip install -r requirements.txt就能复现省去“在我电脑上能跑”的尴尬。最后分享一个小经验如果你打算长期做海温预测方向MLP 适合当基线模型后续往上加空间卷积或者注意力机制对比提升幅度才有底气。我自己每次换新数据集都会先跑一遍 MLP 基线再考虑更复杂的模型。这个习惯能帮你省掉很多不必要的试错时间。本文还有配套的精品资源点击获取
返回列表