z
z_studio/WindFM-NPU
模型介绍
文件和版本
Pull Requests
讨论
分析

NeoQuasar/WindFM on Ascend NPU

昇腾 NPU 适配说明:本文档记录 NeoQuasar/WindFM 风电功率预测基础模型在 昇腾 910B NPU 上的部署与验证过程。推理引擎为 torch_npu(官方 WindFM 模型代码 + torch_npu 后端),已在单卡 Ascend 910B 上完整跑通零样本风电 功率预测(确定性 / 概率性) 与 tokenizer 编解码重建,并完成 CPU fp32 数值对齐验证(相对偏差 ~1e-7)。

1. 模型简介

WindFM(Wind Foundation Model)是首个开源的零样本风电功率预测基础模型 (Zero-shot Wind Power Forecasting)1,由清华大学 / 国家电网研究团队发布于 HuggingFace(NeoQuasar/WindFM)。它在约 1500 亿时间步、12.6 万个风电场 站点的大规模数据上预训练,学习风电机组发电的通用物理 / 气象规律,从而可以对 未见过的风电场直接做出确定性或概率性功率预测,无需站点数据收集与微调。

与文本生成 LLM 不同,WindFM 采用**"离散化-生成"(Discretize-and-Generate)** 框架,由两个子模型构成(合计约 8.06M 参数):

  1. WindFM-Tokenizer(≈3.96M 参数):残差 VAE + BSQ(Binary Spherical Quantizer) 时间序列 tokenizer,把连续多变量风速序列(wind_speed / wind_direction / power / density / temperature / pressure 六特征) 压缩为两级分层离散 token(s1 / s2 各 10 bit,码本大小 1024);
  2. WindFM(≈4.10M 参数):decoder-only Transformer(4 层、d_model=256、 8 头、SwiGLU FFN、RoPE 旋转位置编码),自回归地预测"下一个 token",配合 FourierTemporalEmbedding 时间特征(minute / hour / weekday / day / month 五个维度)与 DependencyAwareLayer(对 s1 条件建模 s2 的依赖感知 层,采用交叉注意力)。

推理流程:历史上下文六特征 → 归一化 → tokenizer 编码为 s1/s2 token 序列 → WindFM 依据时间戳与 token 历史自回归采样生成未来 token → tokenizer 解码回连续 功率(MW)预测 → 反归一化输出。

任务说明验证状态
forecast零样本风电功率预测(确定性 greedy / 概率性多采样)✅ 通过
reconstructtokenizer 编解码重建(编码 → 离散 token → 解码 → 对齐)✅ 通过
数值校验NPU 与 CPU fp32 参考对齐(greedy,同种子)✅ 通过(相对偏差 ~1e-7)
  • 总参数量: 约 8.06M(WindFM 4.10M + Tokenizer 3.96M)
  • 适配状态: SUCCESS
  • 适配时间: 2026-08-19

引擎选型说明:vllm-ascend / sglang 面向文本 / 多模态生成式 LLM,其模型 注册表(vllm/model_executor/models/registry.py)只包含文本/视觉生成架构,无法 加载时序 tokenizer + 时序生成器;WindFM 为自包含 PyTorch 模型(官方仓库的 model/ 包,仅依赖 torch / numpy / pandas / einops / tqdm / safetensors / huggingface_hub),配合 torch_npu 后端即可在昇腾 NPU 上完整运行,故推理脚本 选用 torch_npu 引擎(详见第 6 节)。

2. 验证环境

组件版本
操作系统Linux 5.10.0(aarch64)
Python3.11.14
CANN8.5.1
NPU 芯片Ascend 910B(Ascend910_9362,逻辑卡 ×2,单卡 HBM 64 GB)
torch2.9.0+cpu
torch-npu2.9.0.post1+gitee7ba04
numpy1.26.4
pandas3.0.2
einops0.8.2
safetensors0.7.0
tqdm4.67.3
huggingface-hub0.36.2
推理引擎torch_npu
模型路径/data/models/NeoQuasar/WindFM
Tokenizer 路径/data/models/NeoQuasar/WindFM-Tokenizer
设备npu:0(验证时可切换 npu:1)

torch / torch-npu / pandas / einops 等为昇腾环境系统级预装(本机 /usr/local/python3.11.14),venv 通过 --system-site-packages 复用; 本项目为自包含模型包(model/ 目录),无需安装任何第三方 model 库。

3. 环境依赖

3.1 创建虚拟环境(本目录 venv/)

cd /opt/atomgit/model_adapt/WindFM-NPU
/usr/local/python3.11.14/bin/python3 -m venv --system-site-packages venv

说明:--system-site-packages 复用系统预装的 torch / torch_npu / CANN 昇腾栈, 避免重复安装驱动相关包。若需在全新环境部署,请先按昇腾官方指引安装 CANN Toolkit 与配套 torch-npu(版本需与 CANN 匹配),再执行本步骤。

3.2 安装依赖(国内镜像源)

本项目无第三方 model 库依赖,仅需补齐 PyPI 通用包(若系统已预装则跳过):

venv/bin/pip install -r requirements.txt \
  -i https://pypi.tuna.tsinghua.edu.cn/simple

备用镜像(阿里云):

venv/bin/pip install -r requirements.txt \
  -i https://mirrors.aliyun.com/pypi/simple

3.3 校验环境

venv/bin/python3 -c "import torch, torch_npu; \
print(torch.__version__, torch_npu.__version__); \
print('npu_available =', torch.npu.is_available())"

预期输出(版本号以本机为准,npu_available 必须为 True):

2.9.0+cpu 2.9.0.post1+gitee7ba04
npu_available = True

完整依赖清单见同目录 requirements.txt。

4. 分步推理操作流程

4.1 第 1 步:确认 NPU 可用

npu-smi info
# 需能看到 Health=OK 的逻辑卡(本机 Phy-ID 10 / 11,对应 npu:0 / npu:1)

4.2 第 2 步:进入目录并激活环境

cd /opt/atomgit/model_adapt/WindFM-NPU
# 方式一:直接调用 venv 解释器(推荐,无需 activate)
./venv/bin/python3 inference.py --help
# 方式二:激活后使用 python3
source venv/bin/activate
python3 inference.py --help

4.3 第 3 步:运行推理

脚本默认执行 forecast 任务:在 NPU 上对确定性合成风电场数据做零样本功率 预测,对比已知真值给出 MAE / RMSE,并加载 CPU fp32 参考模型做数值对齐校验:

# 默认任务:零样本预测(pred_len=48, greedy, 对比真值 + CPU 对齐 + 保存 JSON)
./venv/bin/python3 inference.py --output output/default_forecast.json

# 概率预测:sample_count=100 生成 48 点 × 100 条未来场景(p10/p50/p90)
./venv/bin/python3 inference.py --task forecast --pred-len 48 \
  --sample-count 100 --output output/probabilistic.json

# 指定上下文长度 / 采样参数 / 设备 / 精度
./venv/bin/python3 inference.py --lookback 240 --pred-len 80 \
  --temperature 0.8 --top-p 0.9
./venv/bin/python3 inference.py --device npu:1 --dtype bfloat16

# tokenizer 编解码重建验证
./venv/bin/python3 inference.py --task reconstruct --lookback 96 \
  --output output/reconstruct.json

# 使用自定义 CSV(需含 time + 6 特征列,UTC 时间戳)
./venv/bin/python3 inference.py --task forecast --data /path/to/wind_farm.csv

4.4 第 4 步:一键运行 41 组完整测试用例

./venv/bin/python3 inference.py --suite

脚本将依次运行环境检查 / 模型加载 / 预测正确性 / 上下文长度 / 采样参数 / 设备与精度 / 数据边界共 41 组用例,完整转录见 output/suite_41_cases.txt 与 README 第 5 节。

4.5 第 5 步:查看结果

  • 任务输出与精度指标实时打印在终端;
  • 指定 --output xxx.json 时,输入上下文、预测 / 重建结果、性能与精度指标 一并写入 JSON,便于二次分析(详见 output/ 目录)。

5. 完整测试用例与输出结果

测试输入为确定性合成风电场小时序列(无随机成分,可直接复现):功率以慢变 天气尺度(月 720h / 周 240h / 48h 微扰)主导,与真实风电的持久性(persistence) 特性一致;风速由标准功率曲线(切入 3 m/s、额定 13 m/s、切出 25 m/s, P_rated=1500 MW)反算保证物理自洽;时间戳固定为 2024-01-01 00:00 UTC 起。 完整转录见 output/suite_41_cases.txt,单个用例 JSON 见 output/*.json。

5.1 用例 1~10:环境与模型加载

命令:

./venv/bin/python3 inference.py --suite    # 用例 1~10 为前 10 组

输出(关键行,完整见 output/suite_41_cases.txt):

--- [用例 01/41] 环境检查:NPU 设备可见性(npu-smi) ---
[环境] 逻辑卡数: 2
[环境] npu:0 -> Ascend910_9362
[环境] npu:1 -> Ascend910_9362
--- [用例 02/41] 环境检查:昇腾软件栈版本 ---
[环境] torch=2.9.0+cpu  torch_npu=2.9.0.post1+gitee7ba04
[环境] safetensors=0.7.0  einops=0.8.2  pandas=3.0.2
--- [用例 03/41] 环境检查:推理引擎可用性 ---
[环境] torch.npu.is_available() = True
--- [用例 04/41] 环境检查:NPU 逻辑卡型号与数量 ---
[环境] npu:0 名称=Ascend910_9362  能力=None
[环境] npu:1 名称=Ascend910_9362  能力=None
--- [用例 05/41] 模型加载:WindFM 主模型(NeoQuasar/WindFM) ---
[模型] WindFM 加载成功:4,100,096 参数
--- [用例 06/41] 模型加载:WindFM-Tokenizer ---
[模型] WindFM-Tokenizer 加载成功:3,958,042 参数
--- [用例 07/41] 模型加载:总参数量 ---
[模型] 总参数量 = 8,058,138  ≈ 8.06M
--- [用例 08/41] 模型加载:config.json 关键超参 ---
[模型] d_model=256  n_layers=4  n_heads=8  ff_dim=512
[模型] s1_bits=10  s2_bits=10  learn_te=True  vocab=2^10=1024
--- [用例 09/41] 模型加载:safetensors 权重完整性 ---
[模型] WindFM safetensors keys=90,WindFM-Tokenizer keys=96,均可正常打开
--- [用例 10/41] 模型加载:权重数值统计(fp32) ---
[模型] 示例权重 transformer.0.self_attn.q_proj.weight: shape=(256, 256)  mean=0.000267  std=0.051530  min=-0.215765  max=0.261892
用例项目结果
1NPU 逻辑卡数2(Ascend910_9362 ×2,64 GB HBM/卡)
2昇腾软件栈版本torch 2.9.0+cpu / torch_npu 2.9.0.post1 / safetensors 0.7.0
3推理引擎可用性torch.npu.is_available() = True ✅
4NPU 型号npu:0 / npu:1 = Ascend910_9362
5WindFM 参数量4,100,096(≈4.10M)
6Tokenizer 参数量3,958,042(≈3.96M)
7总参数量8,058,138(≈8.06M)
8关键超参d_model=256, n_layers=4, n_heads=8, s1/s2_bits=10, vocab=1024
9权重完整性WindFM 90 keys / Tokenizer 96 keys,可正常打开
10权重数值统计q_proj.weight: mean=0.000267, std=0.051530, min=-0.2158, max=0.2619

5.2 用例 11~18:零样本预测正确性

用例 12(默认,pred_len=48, greedy)命令:

./venv/bin/python3 inference.py --task forecast --pred-len 48 --greedy \
  --output output/default_forecast.json

输出(关键行,完整见 output/default_forecast.json):

NeoQuasar/WindFM @ Ascend NPU (零样本风功率预测基础模型)
  引擎: torch_npu    模型: /data/models/NeoQuasar/WindFM    设备: npu:0
==============================================================================
[torch_npu] 模型加载完成: 总参数 8,058,138 (tokenizer 3,958,042 + WindFM 4,100,096), max_context=512, clip=5, dtype=float32, device=npu:0
[结果] 预测长度: 48 点  采样条数: 1  推理耗时: 520.4 ms
[结果] 预测中位数前 6 点 (MW): 1043.107 1042.016 1040.731 1039.826 1039.256 1039.019
[结果] 预测中位数末 6 点 (MW): 1030.019 1029.953 1029.862 1029.782 1029.773 1029.851
[结果] 预测中位数 min/max/mean: 1029.773 / 1043.107 / 1033.644
[指标] 对已知真值 (零样本): 中位数 MAE=37.8466  RMSE=44.9674  (mean MAE=37.8466)
[校验] CPU fp32 参考对比 (greedy, 同种子同输入):
[校验]   最大绝对偏差=0.000122 MW  相对偏差=1.17e-07
[校验]   MAE=0.000008  RMSE=0.000031
[校验]   NPU 与 CPU fp32 参考数值一致 ✅
SUCCESS

48 点预测 vs 真值:

时刻预测 (MW)真值 (MW)时刻预测 (MW)真值 (MW)
01043.1071075.984241031.6811077.991
11042.0161080.032251031.3871073.964
21040.7311083.970261031.0481069.920
31039.8261087.743271030.7621065.914
41039.2561091.296281030.6081061.997
51039.0191094.579291030.6011058.219
61038.9231097.544301030.6571054.628
71038.7501100.148311030.6931051.264
81038.4811102.351321030.6801048.165
91038.2161104.124331030.6301045.362
101038.0071105.439341030.5601042.879
111037.8991106.278351030.4731040.734
121037.8241106.629361030.3851038.938
131036.0521106.487371030.3261037.495
141035.4131105.856381030.2871036.401
151035.0401104.744391030.1971035.646
161034.7321103.170401030.0981035.212
171034.3821101.158411030.0511035.073
181033.9751098.737421030.0191035.201
191033.4891095.944431029.9531035.557
201032.9371092.821441029.8621036.100
211032.4501089.413451029.7821036.784
221032.1161085.770461029.7731037.559
231031.9001081.945471029.8511038.374

说明:真值列来自确定性合成数据;NPU 与 CPU fp32 参考的最大绝对偏差仅 0.000122 MW(相对偏差 1.17e-07),证明昇腾 NPU 数值计算与官方实现 完全一致、适配正确。MAE=37.85 反映的是零样本预测对合成数据的误差(模型未见 过该合成风电场)。

用例 11~18 结果汇总:

用例参数推理耗时预测中位数 MAERMSE
11pred_len=24, sample=1, greedy654.8 ms59.067759.9677
12pred_len=48, sample=1, greedy604.8 ms37.846644.9674
13pred_len=80, sample=1, greedy(官方示例默认)986.6 ms37.442347.8411
14pred_len=96, sample=1, greedy(4 天)1225.8 ms56.530476.1025
15pred_len=168, sample=1, greedy(7 天)2426.6 ms164.4691215.9769
16pred_len=24, sample=5(概率)544.7 ms83.489586.9444
17pred_len=48, sample=20(概率)1038.6 ms55.561863.2690
18pred_len=48, sample=100(p10/p50/p90)3074.0 ms52.596158.1624

概率模式下表格列为采样路径的中位数 MAE/RMSE;多采样路径还可输出 p10 / p50 / p90 分位数区间(见用例 18 与 output/probabilistic.json)。

5.3 用例 19~24:上下文长度

用例lookback推理耗时MAERMSE说明
1996892.6 ms23.307327.63674 天历史
20168864.5 ms32.608235.10331 周历史
21240573.6 ms37.846644.9674默认 10 天
22336657.2 ms183.3647198.20752 周历史
23512906.5 ms19.799827.7833= max_context
24700969.3 ms67.982477.3495超出 max_context,截断回看 512

用例 23(lookback=512)预测值围绕 635 MW,贴近该窗口真值(约 617~622 MW), MAE=19.8 为 41 组中最优;用例 22(lookback=336)处于功率爬升段,零样本误差 偏大。全部 6 组均正常推理,说明上下文长度对模型运行无影响,仅影响预测精度。

5.4 用例 25~32:采样参数

用例采样参数推理耗时MAERMSE
25temperature=0.5649.9 ms36.568544.2372
26temperature=0.8616.5 ms55.590859.7709
27temperature=1.0(默认)607.0 ms64.853972.5901
28temperature=1.5596.4 ms82.953191.0703
29top_k=10591.5 ms91.401496.2283
30top_k=50560.9 ms48.752753.6894
31top_p=0.8(nucleus)586.1 ms39.305944.6253
32top_p=1.0(无过滤)524.6 ms63.362671.2442

温度越高采样多样性越强、单路径 MAE 越大(用例 25→28);greedy(用例 12) 与低温采样(T=0.5)误差相当,适合确定性部署;概率集成(用例 17/18/41)用 多条路径的中位数可显著提升鲁棒性。

5.5 用例 33~38:设备与精度

用例设备 / 精度推理耗时MAERMSE
33npu:0 float32(默认)589.4 ms37.846644.9674
34npu:1 float32872.9 ms37.846644.9674
35npu:0 bfloat161159.4 ms38.987045.8256
36npu:0 float161137.5 ms37.873644.9675
37CPU float32(参考)2751.4 ms37.846644.9674
38NPU vs CPU fp32 对齐—最大偏差 0.000122 MW相对 1.17e-07

用例 38(数值对齐)输出:

[校验] CPU fp32 参考对比 (greedy, 同种子同输入):
[校验]   最大绝对偏差=0.000122 MW  相对偏差=1.17e-07
[校验]   MAE=0.000008  RMSE=0.000031
[校验]   NPU 与 CPU fp32 参考数值一致 ✅

用例 33 与 34 在不同逻辑卡上结果完全一致(确定性);用例 35/36 说明 fp16/bf16 均可运行,其中 fp16 精度接近 fp32,bf16 因尾数精度低误差略大——生产环境默认 推荐 fp32。用例 37 证明 CPU 上同样可完整运行(供参考对比)。

5.6 用例 39~41:数据与边界

用例 39(自定义 CSV 输入)输出:

[数据] 已导出 output/synthetic_input.csv(288 行)
[结果] 预测长度: 48 点  采样条数: 1  推理耗时: 591.2 ms
[指标] 对已知真值 (零样本): 中位数 MAE=37.8466  RMSE=44.9674

用例 40(NaN 输入校验)输出:

[校验] 已正确拦截 NaN 输入并抛错: Input DataFrame contains NaN values in price or volume columns.  ✅

用例 41(概率集成,pred_len=48, sample_count=50)输出:

[结果] 预测长度: 48 点  采样条数: 50  推理耗时: 1030.8 ms
[结果] 预测中位数前 6 点 (MW): 1043.077 1041.572 1039.526 1038.327 1037.037 1035.313
[结果] 预测中位数末 6 点 (MW): 1007.765 1008.524 1007.245 1013.488 1018.135 1014.538
[指标] 对已知真值 (零样本): 中位数 MAE=55.1279  RMSE=61.4696  (mean MAE=63.6659)
用例数据结果
39自定义 CSV(导出后读入)正常预测,MAE=37.85 ✅
40CSV 含 NaN正确拦截并抛 ValueError ✅
41概率集成 50 条路径中位数 MAE=55.13,耗时 1030.8 ms ✅

41 组用例全部运行通过;完整逐行转录见 output/suite_41_cases.txt。

6. 引擎选型说明

引擎是否适用说明
torch_npu✅ 选用直接加载官方权重 + PyTorch 原生算子在 NPU 上完整前向
vllm-ascend❌ 不适用面向文本/多模态生成式 LLM,模型注册表无时序架构
sglang❌ 不适用同样面向 LLM 文本生成,无法加载 WindFM tokenizer/生成器

WindFM 为自包含 PyTorch 模型(官方仓库 model/ 包,纯 nn.Module 实现), 其算子在 torch_npu 上均有原生实现(Linear / MultiHeadAttention+RoPE / SwiGLU FFN / RMSNorm / BSQ 量化),无需任何自定义算子或内核适配。本适配将官方模型代码 打包进 model/ 目录,仅做工程化 / 正确性改动(详见 model/windfm.py 头部 注释):

  1. 相对导入改造(from .module import *),使其可作为独立 Python 包导入;
  2. WindFMPredictor 构造时显式 .eval(),关闭 dropout,保证自回归采样 (尤其 greedy/argmax)完全确定、可复现——官方代码未显式 eval,训练态下 dropout 会使结果带随机性;
  3. 修复官方 generate 的切片 bug:官方 preds[:, -pred_len:, :] 会错误 裁剪采样维度,导致 sample_count > pred_len 时采样路径被截断(例如 sample_count=100、pred_len=48 时只剩 48 条路径),已改为裁剪序列维度 preds[:, :, -pred_len:, :];
  4. 解码输出统一转 float32 再落地 CPU,兼容 fp16 / bf16 低精度推理;
  5. 增加 --greedy 确定性 argmax 采样,用于 CPU/NPU 数值对齐验证。

7. 性能参考

测试条件:单卡 Ascend 910B,lookback=240,dtype=float32,自回归推理 (含一次预热后计时,sample_count 为并行采样路径数)。

任务 / 参数推理耗时
reconstruct(96 点 × 6 特征,单次前向)12.2~15.0 ms
forecast pred_len=48, sample=1≈ 520~605 ms
forecast pred_len=80, sample=1≈ 987 ms
forecast pred_len=168, sample=1≈ 2427 ms
forecast pred_len=48, sample=100≈ 2183~3074 ms
CPU fp32 forecast pred_len=48, sample=1(参考)≈ 2751 ms

推理耗时会随系统负载小幅波动(本机实测范围见第 5 节表格);预测数值为 确定性结果,与 output/*.json 保存的实测一致、可精确复现2。NPU 上 pred_len=48 单路径约 0.5~0.6 s,较 CPU(约 2.8 s)快 约 4.5~5 倍。

8. 注意事项与常见问题

  1. 推理前务必将模型切到 eval 模式:官方 WindFMPredictor 未显式 .eval(), 训练态下 attention/FFN 的 dropout 会引入随机性。本适配已在构造时自动 .eval(),greedy 输出完全确定(用例 38 复现成功)。
  2. 时间戳必须为 UTC:模型预训练将所有时间信息标准化为 UTC(跨时区消除 歧义),自定义 CSV 输入需 pd.to_datetime(..., utc=True)。
  3. 特征列必须齐全:predict 要求 wind_speed / wind_direction / power / density / temperature / pressure 六列齐全且无 NaN,否则抛 ValueError (见用例 40)。
  4. 上下文窗口:max_context=512,lookback 超过 512 时会截断回看最近 512 点(见用例 24),不影响运行。
  5. 设备切换:单机含 2 张逻辑卡(npu:0 / npu:1),可用 --device npu:1 切换;若同时跑其他任务,请用 npu-smi info 确认卡空闲。
  6. 精度选择:fp32 为默认推荐;fp16 精度接近 fp32;bf16 尾数精度低(约 3 位十进制),自回归误差会累积,结果与 fp32 有偏差(用例 35)。
  7. torch_npu 运行日志噪音:脚本已通过 warnings.filterwarnings 屏蔽 Ascend 目录属主告警,并将 CANN 日志落到 /tmp (ASCEND_PROCESS_LOG_PATH)。加载权重时 stderr 可能打印 1~2 行 Loading weights from local directory,以及首次前向的 path string is NULL 提示,均为无害的环境信息,不影响 stdout 结果与推理正确性。
  8. 依赖安装:勿用默认方式安装会强制降级 transformers / numpy 的包; 本项目无第三方 model 库依赖,PyPI 通用包统一走清华 / 阿里镜像(见 3.2 节)。

9. 参考链接

  • 权重(HuggingFace):https://huggingface.co/NeoQuasar/WindFM
  • Tokenizer(HuggingFace):https://huggingface.co/NeoQuasar/WindFM-Tokenizer
  • 官方代码(GitHub):https://github.com/shiyu-coder/WindFM
  • 论文:https://arxiv.org/abs/2509.06311
  • vllm-ascend 文档

贡献者: z_studio | 赛道: 模型适配赛道 | 适配时间: 2026-08-19

Footnotes

  1. Fan et al., "WindFM: An Open-Source Foundation Model for Zero-Shot Wind Power Forecasting", arXiv:2509.06311, 2025. ↩

  2. 时序数字与 output/*.json 中保存的实测结果一致;推理耗时会随系统负载小幅 波动,但预测数值(greedy / 固定种子)为确定性结果,可精确复现。 ↩