资讯详情

本地部署气象大模型实战:从环境搭建到区域预报推理

📅 2026/10/17 14:42:58 | 华诺云谱 👁 阅读
本地部署气象大模型实战:从环境搭建到区域预报推理
简介这份资源面向气象学研究者、AI 工程实践者及希望本地跑通气象大模型的学生提供 Pangu、Fuxi、Fengwu、GraphCast、FourCastNet 等主流模型的本地部署项目代码。压缩包共 2 个文件以 html 与 inscode 为主html 承载项目说明与结构入口inscode 用于代码组织与运行配置整体约 5KB轻量便于快速查阅与二次整理。已有 138 人学习下载说明其在气象大模型本地化部署方向具备一定参考价值。读者可据此了解从虚拟环境创建、依赖库安装、模型接入到预训练权重下载与输入数据对接的完整链路并获取 GPU 调用失败、版本不匹配等常见问题的排错思路同时涉及通过 CDS 访问 ERA5 数据并驱动模型开展气象预报的实践路径适合作为本地部署与调试的起步参考。1. 本地部署气象大模型从一张显卡到一次可复现的区域预报区域气象预报这件事过去要么依赖超算中心跑数值模式要么调用外部接口拿现成结果。前者门槛高后者不可控。本地部署气象大模型本质是把一个已经训练好的气象预测网络连同它的权重、推理脚本和依赖环境完整搬到自己的机器上跑起来。它解决的核心问题是在断网或数据敏感的场景下依然能对指定区域做未来数小时到数天的气象要素预测。适合谁有 GPU 工作站、需要做区域精细化预报验证、或者想把气象预测嵌入自己业务流水线的工程师。这篇文章不讲气象学原理只讲怎么把这件事从零跑通以及跑通之后怎么调、怎么排错。2. 选型与最小可跑通环境为什么不是随便找个模型就能跑2.1 气象大模型的三种常见形态与本地部署的匹配度目前能拿到代码的气象大模型大致分三类。第一类是纯数据驱动的全球中期预报模型输入是历史再分析数据输出是未来若干天的全球格点场典型结构是 Transformer 或 GraphCast 类的图神经网络。第二类是区域降尺度模型输入粗分辨率预报场输出高分辨率局地场参数量通常小很多。第三类是时序预测模型只针对单站点或小区域做温度、风速等要素的序列预测。本地部署最友好的其实是第二类和第三类。第一类全球模型虽然效果惊艳但推理一次动辄需要几十 GB 显存普通工作站根本吃不下。我一般会先看模型仓库里的推理脚本如果它默认加载的是全球 0.25 度格点、时间步长 6 小时、预报 10 天那基本可以判断这不是一张消费级显卡能碰的。区域模型和站点模型则现实得多一张 24GB 显存的卡就能跑甚至有些轻量模型 8GB 也能推理。选型时还有一个容易被忽略的点模型是否依赖特定的气象数据格式。很多模型训练时用的是 NetCDF 格式的再分析数据变量名、维度顺序、单位都有固定约定。如果你手头只有 GRIB 格式或者站点 CSV就需要先做格式转换。这个转换工作量往往比部署模型本身还大。2.2 最小环境搭建CUDA、PyTorch 与气象库的版本咬合本地部署翻车最多的地方不是模型本身而是环境。气象大模型通常依赖 PyTorch而 PyTorch 又和 CUDA 版本强绑定。更麻烦的是气象数据处理库如 xarray、netCDF4、cfgrib 对底层库版本也有要求。我踩过的坑是先装了最新版 PyTorch结果 cfgrib 编译不过回头降 PyTorch 又导致 CUDA 不匹配。稳妥的做法是先确定 CUDA 版本再选 PyTorch最后装气象库。假设你的显卡驱动支持 CUDA 12.1那么# 创建独立环境避免污染系统 Python conda create -n weather-llm python3.10 -y conda activate weather-llm # 安装 PyTorch注意 cu121 对应 CUDA 12.1 pip install torch2.1.0 torchvision0.16.0 --index-url https://download.pytorch.org/whl/cu121 # 安装气象数据处理基础库 pip install xarray netCDF4 cfgrib numpy pandas # 安装模型推理常用依赖 pip install einops timm matplotlib这段命令的关键参数是--index-url它决定了 PyTorch 从哪个源下载对应 CUDA 版本的二进制包。如果这里写错后面torch.cuda.is_available()会返回 False模型加载时直接报错。einops和timm是很多气象 Transformer 模型会用到的张量操作和视觉骨干库提前装上省得后面缺依赖。装完后用一段短脚本验证import torch import xarray as xr # 检查 CUDA 是否可用这是后续所有推理的前提 print(CUDA available:, torch.cuda.is_available()) print(CUDA version:, torch.version.cuda) print(Device count:, torch.cuda.device_count()) # 检查 xarray 能否正常读取 NetCDF # 这里用随机数据模拟实际使用时替换为你的 .nc 文件路径 import numpy as np fake xr.Dataset({t2m: ((time, lat, lon), np.random.rand(1, 10, 10))}) print(fake)如果 CUDA available 是 Truexarray 也能正常构造数据集说明基础环境没问题。注意这里没有直接读真实文件因为不同来源的 NetCDF 文件变量名差异很大先确认库能用再处理具体文件。2.3 模型权重与配置文件的放置约定拿到项目代码后不要急着运行推理脚本。先看目录结构。常见的气象大模型仓库会有configs/、checkpoints/、data/、scripts/这几个目录。权重文件通常是.pt或.ckpt格式配置文件是.yaml或.json。我一般会做三件事。第一把权重文件放到checkpoints/下并确认文件名和配置文件里写的路径一致。第二打开配置文件找到data_path、stats_path、output_dir这几个字段改成自己机器上的绝对路径。第三检查配置文件里的device字段如果是cuda:0就保持如果是cpu就改成cuda:0否则推理速度会让你怀疑人生。有一个细节很多模型会附带一个stats.npz或normalization.json里面存的是训练数据的均值和标准差。推理前必须用同样的统计量做归一化否则输出结果完全不可信。这个文件如果缺失模型基本等于废了因为气象变量的量级差异很大不做归一化网络根本没法正常工作。3. 推理脚本拆解从加载权重到输出预报场3.1 加载模型与权重的标准流程假设项目里有一个inference.py但直接运行往往报错。我习惯先把它拆开逐段理解。下面是一个典型的气象大模型加载流程import torch import yaml from model import WeatherModel # 假设模型定义在 model.py 中 # 读取配置文件 with open(configs/inference.yaml, r) as f: cfg yaml.safe_load(f) # 实例化模型注意参数要和训练时一致 model WeatherModel( in_channelscfg[in_channels], # 输入变量数如温度、风速、气压等 out_channelscfg[out_channels], # 输出变量数 hidden_dimcfg[hidden_dim], # 隐藏层维度影响模型容量 num_layerscfg[num_layers], # 层数越深越吃显存 ) # 加载权重map_location 确保在 GPU 上加载 state_dict torch.load(cfg[checkpoint_path], map_locationcuda:0) model.load_state_dict(state_dict) model model.to(cuda:0) model.eval() # 切换到推理模式关闭 dropout 和 batchnorm 更新 print(Model loaded, params:, sum(p.numel() for p in model.parameters()))这里的关键是model.eval()。如果忘了这行dropout 会随机丢弃神经元每次推理结果都不一样你会以为模型有问题其实是模式没切对。另一个关键是map_location如果权重是在多卡上保存的直接加载可能会因为设备编号不匹配而报错指定cuda:0能解决大部分问题。3.2 输入数据的预处理格点对齐与时间维构造气象大模型的输入不是随便一张图而是有严格维度顺序的张量。常见格式是(batch, time, channel, lat, lon)或(batch, channel, time, lat, lon)。顺序搞错模型不会报错但输出会完全离谱。import xarray as xr import numpy as np # 读取再分析数据假设是 NetCDF 格式 ds xr.open_dataset(data/era5_subset.nc) # 选择需要的变量注意变量名要和训练时一致 # 常见变量t2m2米温度、u10/v1010米风速、msl海平面气压 variables [t2m, u10, v10, msl] data ds[variables].values # 形状为 (time, channel, lat, lon) # 归一化使用训练时的统计量 stats np.load(checkpoints/stats.npz) mean stats[mean] # 形状 (channel,) std stats[std] data (data - mean[:, None, None]) / std[:, None, None] # 构造输入张量取最近 2 个时间步作为输入 # 假设模型要求输入时间长度为 2 input_tensor torch.tensor(data[-2:], dtypetorch.float32) input_tensor input_tensor.unsqueeze(0).to(cuda:0) # 增加 batch 维 print(Input shape:, input_tensor.shape)这段代码里mean[:, None, None]的广播操作是为了让每个通道减去自己的均值。如果直接减一个标量不同量级的变量会被错误缩放。data[-2:]取最后两个时间步是因为很多模型用过去两个时刻预测未来一个或多个时刻。具体取几个时间步要看配置文件里的input_length。3.3 推理与输出后处理把张量变回气象场模型输出的是归一化后的张量必须反归一化才能得到物理量。# 推理关闭梯度计算节省显存 with torch.no_grad(): output model(input_tensor) # 形状 (batch, out_channels, lat, lon) # 反归一化 output output.squeeze(0).cpu().numpy() # 去掉 batch 维 output output * std_out[:, None, None] mean_out[:, None, None] # 保存为 NetCDF方便后续分析和可视化 out_ds xr.Dataset( {var: ((lat, lon), output[i]) for i, var in enumerate(variables)}, coords{lat: ds.lat.values, lon: ds.lon.values}, ) out_ds.to_netcdf(output/forecast.nc) print(Forecast saved.)反归一化用的std_out和mean_out必须和训练时输出变量的统计量一致。如果项目只提供了一个stats.npz里面通常同时包含输入和输出的统计量注意区分键名。保存为 NetCDF 是为了后续能用 xarray 直接做差值分析和画图比存成 CSV 方便得多。4. 避坑与排查本地部署气象大模型最常见的五类翻车4.1 显存溢出现象、原因与解决现象运行推理脚本时抛出CUDA out of memory即使把 batch size 设为 1 也一样。原因气象大模型的输入张量往往很大。一个全球 0.25 度格点、70 个变量、2 个时间步的输入展开后就是几千万个浮点数。如果模型中间层还做了上采样或注意力计算显存占用会成倍增加。解决先看模型是否支持混合精度推理。在torch.no_grad()外面套一层torch.cuda.amp.autocast()能把显存占用降一半左右。如果还不行就考虑把输入裁剪到只保留你关心的区域而不是全球。很多区域模型本身就只接受局地输入用全球数据反而会出错。4.2 输出全是 NaN归一化统计量缺失或错位现象推理结果保存后打开一看全是 NaN 或者数值大得离谱。原因最常见的是归一化统计量没加载对。比如stats.npz里的mean是输入变量的均值但代码里错误地用它去反归一化输出。另一种情况是变量顺序不一致训练时通道顺序是[t2m, u10, v10, msl]推理时变成了[msl, t2m, v10, u10]归一化自然全乱。解决打印stats.npz的所有键确认输入和输出统计量是分开的。然后对照配置文件里的variables列表确保数据读取时的变量顺序和训练时完全一致。如果找不到统计量文件可以尝试用输入数据自身的均值和标准差做近似但效果会打折扣。4.3 推理速度极慢没有切到 eval 模式或误用 CPU现象一次推理要几分钟甚至更久GPU 利用率却很低。原因忘了写model.eval()导致 dropout 和 batchnorm 在推理时仍然活跃计算量增加。或者模型加载时map_location写成了cpu整个推理都在 CPU 上跑。解决在加载权重后立刻加model.eval()和model.to(cuda:0)。用nvidia-smi看 GPU 利用率如果低于 30%基本可以确定模型没在 GPU 上跑。另外检查数据加载部分有没有.cpu()调用把数据留在 GPU 上能省不少时间。4.4 时间维对不上输入长度与模型预期不符现象模型前向传播时报维度错误提示Expected input time dimension 2, got 1。原因配置文件里写的input_length是 2但数据读取时只取了 1 个时间步。或者数据本身的时间分辨率不对模型训练时用的是 6 小时间隔你给的是 1 小时间隔时间步数量对不上。解决打开配置文件找到input_length或history_length字段确认具体数值。然后在数据预处理代码里用data[-input_length:]来取输入。如果数据时间分辨率不同需要先做时间重采样用 xarray 的resample方法统一到模型要求的间隔。4.5 输出地理坐标错位lat/lon 顺序颠倒现象预报场保存后画图发现南北颠倒或者东西镜像。原因NetCDF 里 lat 通常是从小到大排列但有些模型训练时用的是从大到小。如果推理时直接沿用原始 lat 数组而模型输出是按训练时的顺序排列的就会错位。解决检查训练数据里 lat 的排列顺序。如果模型输出和原始 lat 顺序不一致在保存前用output[::-1, :]翻转纬度维。更稳妥的做法是在配置文件里找lat_order或类似字段按模型要求调整。5. 进阶技巧用滑动窗口做连续预报与结果验证5.1 滑动窗口推理把单次预报串成时间序列单次推理只能得到一个时刻的预报。要得到连续多个时刻需要用滑动窗口把上一次的输出作为下一次输入的一部分。这里有一个关键选择是只用模型自己的输出做自回归还是每次都用真实观测做修正。前者误差会累积后者需要持续有观测数据。# 滑动窗口推理预报未来 4 个时刻 forecast_steps 4 current_input input_tensor.clone() # 初始输入形状 (1, time, channel, lat, lon) forecasts [] for step in range(forecast_steps): with torch.no_grad(): pred model(current_input) # 预测下一个时刻 forecasts.append(pred.cpu().numpy()) # 把预测结果拼接到输入中去掉最老的时间步 # 注意这里假设模型输出通道和输入通道一致 pred_expanded pred.unsqueeze(1) # 增加时间维 current_input torch.cat([current_input[:, 1:], pred_expanded], dim1) print(Forecast steps:, len(forecasts))这段代码里current_input[:, 1:]去掉了最早的时间步pred_expanded补到末尾保持输入时间长度不变。如果模型输出通道和输入通道不一致比如输出只有温度输入有多个变量就需要单独处理不能直接拼接。5.2 用再分析数据做快速验证三个必看的指标预报结果出来后怎么判断它靠不靠谱我一般会算三个指标均方根误差、异常相关系数和偏差。均方根误差看整体误差大小异常相关系数看空间分布是否合理偏差看有没有系统性高估或低估。import numpy as np # 假设 truth 是真实观测场forecast 是预报场形状均为 (lat, lon) def rmse(truth, forecast): return np.sqrt(np.mean((truth - forecast) ** 2)) def acc(truth, forecast, climatology): # 异常相关系数climatology 是气候态 t_anom truth - climatology f_anom forecast - climatology return np.corrcoef(t_anom.flatten(), f_anom.flatten())[0, 1] def bias(truth, forecast): return np.mean(forecast - truth) # 示例用法 # truth xr.open_dataset(data/truth.nc)[t2m].values # forecast xr.open_dataset(output/forecast.nc)[t2m].values # clim xr.open_dataset(data/climatology.nc)[t2m].values # print(RMSE:, rmse(truth, forecast)) # print(ACC:, acc(truth, forecast, clim)) # print(Bias:, bias(truth, forecast))均方根误差对极端值敏感如果某个区域误差特别大会被放大。异常相关系数需要气候态数据如果没有可以先用时间平均代替。偏差为正说明预报偏高为负说明偏低。这三个指标不用同时追求最优先看偏差是否在可接受范围内再看异常相关系数是否超过 0.5最后才看均方根误差。5.3 一个容易被忽略的细节输出变量的单位气象数据的单位经常被搞混。温度可能是摄氏度也可能是开尔文风速可能是米每秒也可能是节。模型训练时用的单位推理输出必须保持一致。我遇到过一种情况模型输出的是开尔文但可视化时按摄氏度画结果整个图看起来像在北极。检查单位的方法很简单看配置文件里有没有units字段或者看训练数据 NetCDF 文件里变量的units属性。如果没有就找一份同来源的数据对比数值范围温度在 250 到 320 之间基本是开尔文在 -20 到 50 之间基本是摄氏度。本地部署气象大模型这件事最耗时间的从来不是写推理代码而是对齐数据格式和排查环境问题。我的习惯是每跑通一个环节就存一个检查点比如数据预处理完存一份模型加载完打印一次参数量推理完先保存原始张量再后处理。这样一旦后面出错能快速定位是哪一步的问题。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑