
这两年没有人能绕开天气基础模型的讨论。公开的预训练基座在再分析资料上学到了很多全球尺度的物理规律但把它搬到具体业务场景时往往会有一种“什么都懂一点、什么都差一点”的感觉。WeatherPEFT 这个项目的出发点很朴素在不动基座核心参数的前提下用参数高效微调PEFT做天气基础模型调优把通用模型改造成更贴合区域气候、站点观测和极端天气表达的专家模型。它适合正在做气象大模型落地的算法工程师、做相关论文复现的研究生以及所有被“全量微调太贵、直接推理又不够准”折磨的小伙伴。这篇文章我会把方案选型、数据构造、实操流程和踩坑记录都摊开来讲。1. 为什么通用天气模型还需要再做一轮PEFT调优1.1 全球基座的“平均水平”与业务预测的裂缝先说一个最直观的感受。公开天气大模型大多是在全球再分析场上学出来的它的预训练目标是让全世界不同地区的平均误差最小。这个目标天然导向“取中位数式”的预测大尺度环流、常规温度变化它学得很好一旦落到某个具体地点误差就藏不住了。举个例子全球网格场在高原、盆地、沿海附近往往只有平滑的低频信号而业务预报要求的是“这片山地午后有没有对流”“这个港口未来两天阵风大概几级”。基座模型没有能力区分这些局地现象因为预训练阶段的数据分布和训练目标就没有给它这个能力。用一句话总结全球模型学到的是气候平均态的演变业务预报要的是局地天气过程的逐时变化两者之间存在天然裂缝。这种裂缝不是靠加大基座尺度就能自动填补的。模型越大预训练阶段的“全球味道”越重对具体站点的敏感性反而可能越钝。所以真正到了落地阶段几乎所有人都会想到同一件事在基座模型上再做一轮针对性训练。1.2 全量微调的成本和风险为什么不能硬来既然基座不满足第一反应当然是微调。真正动手你会立刻发现天气大模型全量微调是最不划算的路线。以常见的亿级参数Transformer基座为例做完AdamW的状态维护后每个参数至少对应十几字节以上的显存开销参数本身、梯度、一阶矩、二阶矩一个百亿规模模型光优化器状态就能吃掉上百GB显存。加上中间激活值、输入场数据想单卡跑起来基本不现实得靠多机多卡硬扛。麻烦还不止显存。全量微调通常需要足够多的目标域数据而气象观测数据远没有文本数据那么充裕样本少、噪声大、极端事件稀疏。几轮训练下来模型往往学会的是“把训练区域的风场调准了但其他地方原本会预报的天气也忘了”这就是灾难性遗忘。对于天气任务来说灾难性遗忘比自然语言处理里更致命因为基座里的全球环流先验一旦被覆盖后续很难补回来。我见过不止一次有人把全量微调跑完区域评分涨了但全球范围评估掉了十几个百分点这种模型根本不敢上线。1.3 WeatherPEFT要解决的四类问题所以 WeatherPEFT 的思路就是换一种微调范式全量参数冻结只在原有权重旁加一条低秩分支。它想解决的四类问题非常明确区域分布漂移全球统计均值与特定气候区的统计特征不一致分辨率不匹配业务站点或高分辨率网格需要比全球网格更细的局地订正极端天气召回低暴雨、大风、高温这类小概率事件在均方误差下会被严重平滑迭代成本高业务模型要随着季节变化和新站点加入持续更新总不能每次更新都重训一遍全模型。把这些问题拆开以后PEFT 的定位就清楚了它不是取代基座模型而是给基座装上针对特定场景的“传感器”让模型在不改变整体架构的前提下把注意力投向真正重要的地方。整个过程看起来像是在“做减法”实际是在“做加法”模型主体不变新增的参数不多但对目标场景的表达能力会明显上台阶。2. PEFT技术选型LoRA为什么是天气场景的优选2.1 三种主流PEFT方法横向对比PEFT 家族里常被提到的有三条路线Adapter、Prefix-Tuning、LoRA。我最初做方案时把这三条路线都过了一遍心里大概有个谱。方法核心原理新增参数量在天气任务中的表现Adapter在每层Transformer内部插入小型前馈网络少串行会改变层间信号流并行设计更接近残差吞吐有一定损失Prefix-Tuning在注意力序列上加入可学习的虚拟Token很少天气场是时空张量虚拟Token缺乏直观物理含义迁移效果一般LoRA在权重矩阵旁加入低秩分解分支少对原始信号路径改动小训练稳定可复现部署灵活我的选择是 LoRA 作为主力方案。理由很直白天气基础模型的骨干结构普遍是Transformer演进出来的LoRA 在注意力投影矩阵和多层感知机层上挂低秩分支对原有特征提取路径的影响最小训练过程中不改变输入场的序列结构也不破坏位置编码信息。对一片经纬度网格来说空间位置本身就是极重要的物理信息Prefix-Tuning那种给序列头部塞虚拟Token的做法很容易让模型混淆“哪个位置才是目标区域”。2.2 LoRA低秩注入的原理解读秩、目标模块和缩放因子LoRA 的低秩分解可以这样理解预训练权重矩阵 W 保持不动新增加一个 ΔW 被分解成两个小矩阵 B 和 A 的乘积。B 的维度是 d×rA 的维度是 r×d其中秩 r 远远小于原始维度 d。训练时只优化 B 和 A推理时把 BA 合并回 W 里或者保留低秩分支动态叠加。我一般用一个生活化的比喻解释秩 r它相当于你在模型上开的“调节旋钮”数量。r 太小旋钮太少模型很难表达出复杂的局地误差修正r 太大旋钮太多模型容易只记住训练样本里的噪声。在天气任务上我常用的初始配置是 r8、alpha16作用在注意力层的 Q 和 V 投影上。如果任务比较复杂比如同时做多要素预报和极端天气分类可以提高到 r16 或 r32。目标模块的选择也值得讲究。有人习惯把所有线性层都挂上LoRA我建议先从注意力层的 Q、K、V、O 投影开始再叠加多层感知机层的第一个全连接。这样做的原因是注意力层决定了模型“看哪里”多层感知机层决定了模型“怎么把看到的内容转换成预报结果”这两个位置是天气场特征变化最敏感的地方。全部挂上的收益不大反而增加过拟合风险。2.3 比LoRA再进阶一步DoRA、AdaLoRA与QLoRA基础LoRA能用之后我还试过几个改进版本各有适用场景。DoRA 的思路是把权重矩阵拆成幅度和方向两个部分方向部分用低秩矩阵微调。实测下来它对学习率的敏感度更低收敛过程更顺适合训练数据不太干净的业务场景。AdaLoRA 则会根据每个参数的重要性自动分配秩预算相当于给不同位置的旋钮动态调大小在多任务联合微调时比较省心。QLoRA 把基座模型量化到4bit再挂LoRA显存占用能再降一个量级适合只有单张消费级显卡的环境。需要提醒的是这些变体都不是银弹。AdaLoRA 的自动分配逻辑在气象场上的可解释性比较差出了问题不容易追溯QLoRA 的量化误差在极端降水这类高动态范围变量上会被放大。我现在的习惯是先跑标准LoRA建立基线如果发现某些区域明显欠拟合再针对性地换DoRA或AdaLoRA做对照实验。2.4 冻结基座的核心逻辑保留物理先验为什么强调冻结基座关键在于物理先验不可覆盖。天气基础模型经过大规模预训练后内部已经编码了大量大气物理约束例如地转平衡关系、温度平流输送、高低压系统联动等。这些先验知识是用再分析资料“喂”出来的覆盖的是全球范围、长时序的规律。业务微调数据规模小、分布窄如果全部放开训练模型很快就会把这些宝贵的物理规律“挤”出去取而代之的是训练区域里那些短期的统计相关。冻结基座 低秩分支其实是在做知识分层主干的物理先验负责回答“天气系统怎么演变”这一全局问题LoRA分支只学习“在特定区域、特定尺度下预报偏差长什么样、怎么订正”这一局部问题。这种分工让模型在目标场景之外保持可用即使某天要换一个区域继续微调基座仍然保留完整的全球能力不会因为之前的调优就废掉。3. 训练数据与任务定义把“调优”变成可计算问题3.1 基座调优任务到底是什么任务回归、分类还是修正拿到天气基础模型后第一件事是明确任务形态。WeatherPEFT 实际涵盖三类任务回归预测给定过去若干个时次的多变量场预测未来某一时刻的温度、风、降水等要素分类辅助判断某个格点或站点未来一段时间内是否发生极端天气事件比如暴雨、大风、冰雹后处理订正把基座模型或数值模式输出的原始预测映射到站点观测对应的真值上本质上是偏差修正。三类任务的目标函数不同评估口径也不同。回归任务适合用均方根误差和距平相关系数评估分类任务要看命中率、空报率、漏报率后处理订正则更关注预报值和观测值的概率分布是否贴合。如果一开始就把这些混在一起后面调参很容易左右互搏。3.2 训练样本构造多变量时空张量到站点序列构造训练样本时我通常把输入组织成形状为样本数、时间步数、变量通道数、纬度格点数、经度格点数的五维张量。变量通道里至少包含位势高度、温度、相对湿度、经向风速和纬向风速时间步数一般取过去6到24个小时按分辨率不同选择每小时或每3小时间隔输出则根据任务需求可能是未来6小时、24小时甚至72小时的要素场也可能是对应站点的观测序列。如果目标是站点级预报需要先把网格场通过双线性插值提取到站点坐标上。这一步看起来简单但有个容易被忽略的细节站点观测和再分析资料在海拔、地形代表性上存在系统性差异直接把两者配对会让模型学到“观测值整体偏低或偏高”这种假规律。我习惯在输入张量里额外拼上站点高程、经纬度、地形粗糙度这几个静态特征让LoRA分支有足够线索把地形偏差分离出来。下面是一个简化版的数据集构造思路方便理解数据流class WeatherDataset(Dataset): def __init__(self, fields, obs, static, seq_len8): self.fields fields self.obs obs self.static static self.seq_len seq_len def __len__(self): return len(self.obs) - self.seq_len def __getitem__(self, idx): x self.fields[idx:idx self.seq_len] # 过去N个时次的多变量场 x torch.cat([x, self.static], dim1) # 拼接静态地形特征 y self.obs[idx self.seq_len] # 未来时次的站点观测 return x, y3.3 时间切分与数据泄漏千万别随机拆分气象数据最大的特点就是时空自相关。相邻两个小时的天气场高度相似如果做随机拆分训练集里的样本和验证集里的样本实际上来自同一段天气过程验证指标会虚高到让你误以为模型已经练成了。正确的做法是按时间块切分把整段数据按时间顺序分成训练期、验证期、测试期比例大概是70%、15%、15%。如果数据覆盖了多年最好把完整年份作为边界避免一个天气过程被拦腰截断。做多区域微调时还要注意空间泄漏相邻站点的观测高度相关验证集应该整块保留一个独立区域而不是随机挑几个站点进去。这个坑我在早期踩过。当时随机拆分后验证集RMSE低得离谱可一换到新站点效果立刻打回原形。改成时间块切分和区域级留出后指标才真正能反映模型的外推能力。3.4 极端天气不能靠MSE样本加权与损失设计用普通均方误差训练天气模型最典型的问题是极端天气被“平均”掉。原因很简单晴天、小雨这类样本占了绝大多数模型只要把常规样本预测准确损失就已经很低了暴雨、大风这些稀疏样本对梯度的贡献微乎其微。解决办法通常分两步。第一步是样本加权根据预报目标的值域给样本赋予不同权重比如降水强度越大权重越高第二步是损失函数改造降水回归任务可以先把降水量做对数变换再用加权误差或者干脆把降水任务拆成“是否下雨”的分类和“雨量多少”的回归两个子任务。分类子任务我更推荐 Focal Loss。它在气象目标上尤其合适因为绝大多数格点是无雨状态Focal Loss 会降低易分无雨样本的权重把模型的注意力逼到“雨带在哪、强中心在哪”这两个真正关键的问题上。4. 实操流程从冻结基座到保存Adapter4.1 环境准备与基座模型加载实操层面我推荐 Python 3.10 以上、PyTorch 2.x、CUDA 12显存按模型规模准备。先把基座模型加载进来并冻结所有参数import torch from transformers import AutoModel model AutoModel.from_pretrained(path/to/weather_base_model) for param in model.parameters(): param.requires_grad False冻结这一步不是走过场。它保证了后续所有训练操作都集中在LoRA分支上反向传播不需要为主干保存梯度显存和计算量都会大幅下降。加载后建议先跑一次完整的前向推理确认输入输出形状与预期一致再进入LoRA注入。4.2 注入LoRA配置目标模块和参数量估算使用开源PEFT工具库可以快速注入LoRA配置from peft import LoraConfig, get_peft_model lora_config LoraConfig( r8, lora_alpha16, target_modules[q_proj, v_proj, k_proj, o_proj], lora_dropout0.05, biasnone, ) model get_peft_model(model, lora_config) trainable sum(p.numel() for p in model.parameters() if p.requires_grad) total sum(p.numel() for p in model.parameters()) print(ftrainable params: {trainable / 1e6:.2f}M / {total / 1e6:.2f}M)实际跑下来一个百亿参数基座在挂上四组LoRA之后可训练参数量通常只占总参数的0.1%到1%。我见过最多的场景是0.3%左右对应几十万个参数单张高端显卡就能完成整个微调过程。这也是WeatherPEFT最吸引人的地方调的是“大模型”用的却是“小模型”的资源开销。4.3 训练策略优化器、学习率和调度训练配置我一般这样定优化器用AdamW学习率从2e-4开始配合余弦退火调度降到1e-5左右批次大小16到32如果显存不够就用梯度累积混合精度开BF16既省显存又不容易出现数值溢出。说一个容易被忽略的点LoRA训练不宜跑太多轮。天气任务和自然语言任务不一样文本数据量大、语义层次多多轮训练还能学到新知识天气场样本的时间自相关强两三轮之后验证集指标通常会收敛继续训练就开始记忆训练期天气过程的细节了。我一般设epoch上限为5同时开启早停监控验证集RMSE和ACC指标。4.4 损失函数与气象评估指标回归任务我常用加权后的误差作为损失同时会特别关注两个气象领域核心指标RMSE衡量预测与观测的绝对偏差直观但容易被少数极端样本拉高ACC距平相关系数衡量模型对“偏离气候平均状态”的预测能力公式为预测距平与观测距平的协方差除以两者标准差乘积。ACC大于0.6通常认为有用的预报信号存在越接近1越好。降水任务还要额外看TS评分命中数除以命中、空报、漏报之和。TS只关心事件有没有报对不关心量级偏差适合评估强降水落区。风速任务则应该关心极端分位数比如95分位风速的误差而不是只看平均风误差。4.5 完整训练流程与Adapter保存一个完整的训练流程大概是加载再分析数据和站点观测按时间块切分构造五维时空张量拼接静态地形特征加载基座模型并冻结骨干参数注入LoRA配置打印可训练参数量设定损失函数、优化器、学习率调度、混合精度每个epoch结束后在验证集上计算RMSE、ACC、降水TS保存效果最好的Adapter权重而不是最后一轮权重。python train_weather_peft.py --data_dir ./data \ --base_model ./weather_base \ --lr 2e-4 --epochs 5 \ --batch_size 16 --bf16 \ --output_dir ./adapter_weights保存下来的Adapter权重非常轻通常只有几十MB和动辄几十GB的基座模型形成鲜明对比。部署时可以把Adapter合并回基座也可以保持LoRA分支独立按不同场景动态切换。5. 常见问题与排错实录调优路上的十个坑5.1 快速问题速查表现象可能原因对策Loss一直不降输入输出标准化不一致或学习率过高检查归一化统计量把学习率降到1e-4再试训练集Loss降验证集不降过拟合秩太大训练轮数过多减小秩增加Dropout早停区域A表现好区域B表现差样本不均衡空间分布差异大按气候区拆成多组Adapter分别训练降水预报一片模糊普通MSE均化了降水量级改用分位数加权拆分“有无降水”分类子任务极端风速总是报低极端样本占比过少对高风速样本做重采样或单独加权推理速度变慢Adapter没有合并回基座推理前把BA合并到原权重中换机器推理结果不一致归一化参数没有随权重保存把标准化统计量写进配置元数据5.2 三个典型排查案例第一个案例是Loss降了但降水TS反而变差。当时我盯着训练曲线很开心验证集RMSE明显下降可一旦单独看暴雨样本命中率惨不忍睹。排查之后发现RMSE改善主要来自常规天气模报得更准LoRA分支并没有学到强降水过程的触发条件。后来我把任务改成双分支输出一个分支回归降水强度一个分支做有无降水的分类分类分支用Focal Loss修正效果立刻明显。第二个案例是站点误差始终压不下去。训练集和验证集整体RMSE都在合理范围但某个海拔较高的站点误差异常大。问题出在输入特征里没有地形信息LoRA只能从周围的网格猜测这个站点的气候背景。加入站点高程和地形粗糙度特征之后该站点误差明显下降。这个案例提醒我气象调优任务特征工程和模型结构同等重要。第三个案例是某一年验证集整体指标跳水。后来把那一年挑出来仔细看发现里面包含了好几次历史罕见的极端天气过程训练期内几乎没有相似样本。单纯增加样本量解决不了这种长尾问题我采用了两条腿走路对极端天气样本做重采样同时在损失里提高极端事件权重。调完之后正常年份的指标没有明显下降极端年份的评分改善了一截。5.3 避坑清单我踩过的坑有几点经验是常规文档里不会写的这里专门列一下。输入归一化统计量必须和基座预训练时保持一致。重新计算一遍均值和方差看起来更严谨但它会改变输入分布让基座的物理先验在入口处就被扭曲。这不是模型调优这是在“破坏数据分布”。验证集不要使用和训练集同一天的样本。天气过程在小时尺度上高度相关同一天里“训练两个小时、验证两个小时”等于让模型开卷考试。时间边界要放在完整天气过程之外。极端事件的重采样要注意平衡不能把非极端样本压得太少。如果极端样本占比过高模型会变得“动辄报警”空报率飙升业务上一样不可用。6. 后续扩展从一个区域到一个可运营的系统6.1 多区域多Adapter分组微调WeatherPEFT 这套思路天然支持“一个基座、多套Adapter”的运营模式。不同气候区、不同行业场景可以各自训练一套Adapter部署时按区域加载基座模型始终只有一份。这种方式很像同一套底盘配不同调校平原地带注重风场订正山地场景注重对流指标沿海场景注重阵风和高湿天气。每一套Adapter都独立训练、独立评估、独立版本管理互不干扰。我在实践中的做法是先做一个全局Adapter作为基线再按区域和天气类型细分。如果一个新区域的样本量不够可以用全局Adapter作为初始化权重继续微调比从随机初始化起步要快得多。6.2 持续更新与部署把Adapter纳入版本管理天气模型的业务更新节奏通常是季度级甚至月度级季节更替会带来完全不同的天气过程分布。PEFT的最大优势就是把“模型更新”简化成了“Adapter更新”。新数据到来时从上一个Adapter继续训练而不是从头开始。这个过程开销小、上线快适合业务系统的快速迭代。部署时我强烈建议给每个Adapter建立一个配置包里面包含基座版本号、训练时间范围、输入输出变量列表、归一化统计量、评估报告。这样即使过了几个月也能准确知道某个Adapter是在什么数据条件下训练出来的避免模型版本错配导致的神秘误差。天气基础模型的调优不是一锤子买卖它是和季节赛跑的持续长期工程。最后说点个人平时不太会写进文档里的体会。天气基础模型的调优表面上是在调模型实际上是在调数据、调评估口径、调对天气过程的理解。Loss曲线漂亮不重要验证集上降水TS和风速极端分位数有没有变好才重要。我现在的习惯是每次训练前先把验证集里的关键天气事件列成清单训练完逐个看样本输出差异而不是只看全局指标。另一个小技巧是把训练时用的输入输出标准化统计量写进Adapter的元数据和权重一起保存。这样后续推理、换机器、升级基座版本时不会因为归一化版本不一致出现莫名其妙的偏差。天气模型调优这条路还很长但把每一轮小成本迭代的颗粒度做细整个系统会变得非常扎实。