☰
PEFT+LoRA实战:把通用天气大模型调成区域专家
2026/10/21 3:02:32 网站建设 项目流程

这两年没有人能绕开天气基础模型的讨论。公开的预训练基座在再分析资料上学到了很多全球尺度的物理规律,但把它搬到具体业务场景时,往往会有一种“什么都懂一点、什么都差一点”的感觉。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×r,A 的维度是 r×d,其中秩 r 远远小于原始维度 d。训练时只优化 B 和 A,推理时把 BA 合并回 W 里,或者保留低秩分支动态叠加。

我一般用一个生活化的比喻解释秩 r:它相当于你在模型上开的“调节旋钮”数量。r 太小,旋钮太少,模型很难表达出复杂的局地误差修正;r 太大,旋钮太多,模型容易只记住训练样本里的噪声。在天气任务上,我常用的初始配置是 r=8、alpha=16,作用在注意力层的 Q 和 V 投影上。如果任务比较复杂,比如同时做多要素预报和极端天气分类,可以提高到 r=16 或 r=32。

目标模块的选择也值得讲究。有人习惯把所有线性层都挂上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_len=8): 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], dim=1) # 拼接静态地形特征 y = self.obs[idx + self.seq_len] # 未来时次的站点观测 return x, y

3.3 时间切分与数据泄漏:千万别随机拆分

气象数据最大的特点就是时空自相关。相邻两个小时的天气场高度相似,如果做随机拆分,训练集里的样本和验证集里的样本实际上来自同一段天气过程,验证指标会虚高到让你误以为模型已经练成了。

正确的做法是按时间块切分:把整段数据按时间顺序分成训练期、验证期、测试期,比例大概是70%、15%、15%。如果数据覆盖了多年,最好把完整年份作为边界,避免一个天气过程被拦腰截断。做多区域微调时还要注意空间泄漏,相邻站点的观测高度相关,验证集应该整块保留一个独立区域,而不是随机挑几个站点进去。

这个坑我在早期踩过。当时随机拆分后验证集RMSE低得离谱,可一换到新站点,效果立刻打回原形。改成时间块切分和区域级留出后,指标才真正能反映模型的外推能力。

3.4 极端天气不能靠MSE:样本加权与损失设计

用普通均方误差训练天气模型,最典型的问题是极端天气被“平均”掉。原因很简单:晴天、小雨这类样本占了绝大多数,模型只要把常规样本预测准确,损失就已经很低了,暴雨、大风这些稀疏样本对梯度的贡献微乎其微。

解决办法通常分两步。第一步是样本加权:根据预报目标的值域给样本赋予不同权重,比如降水强度越大权重越高;第二步是损失函数改造:降水回归任务可以先把降水量做对数变换,再用加权误差,或者干脆把降水任务拆成“是否下雨”的分类和“雨量多少”的回归两个子任务。

分类子任务我更推荐 Focal Loss。它在气象目标上尤其合适,因为绝大多数格点是无雨状态,Focal Loss 会降低易分无雨样本的权重,把模型的注意力逼到“雨带在哪、强中心在哪”这两个真正关键的问题上。

4. 实操流程:从冻结基座到保存Adapter

4.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( r=8, lora_alpha=16, target_modules=["q_proj", "v_proj", "k_proj", "o_proj"], lora_dropout=0.05, bias="none", ) 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(f"trainable 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保存

一个完整的训练流程大概是:

  1. 加载再分析数据和站点观测,按时间块切分;
  2. 构造五维时空张量,拼接静态地形特征;
  3. 加载基座模型并冻结骨干参数;
  4. 注入LoRA配置,打印可训练参数量;
  5. 设定损失函数、优化器、学习率调度、混合精度;
  6. 每个epoch结束后在验证集上计算RMSE、ACC、降水TS;
  7. 保存效果最好的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的元数据,和权重一起保存。这样后续推理、换机器、升级基座版本时,不会因为归一化版本不一致出现莫名其妙的偏差。

天气模型调优这条路还很长,但把每一轮小成本迭代的颗粒度做细,整个系统会变得非常扎实。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询