昇腾 NPU 适配说明:本文档记录
NeoQuasar/WindFM风电功率预测基础模型在 昇腾 910B NPU 上的部署与验证过程。推理引擎为 torch_npu(官方 WindFM 模型代码 + torch_npu 后端),已在单卡 Ascend 910B 上完整跑通零样本风电 功率预测(确定性 / 概率性) 与 tokenizer 编解码重建,并完成 CPU fp32 数值对齐验证(相对偏差 ~1e-7)。
WindFM(Wind Foundation Model)是首个开源的零样本风电功率预测基础模型
(Zero-shot Wind Power Forecasting)1,由清华大学 / 国家电网研究团队发布于
HuggingFace(NeoQuasar/WindFM)。它在约 1500 亿时间步、12.6 万个风电场
站点的大规模数据上预训练,学习风电机组发电的通用物理 / 气象规律,从而可以对
未见过的风电场直接做出确定性或概率性功率预测,无需站点数据收集与微调。
与文本生成 LLM 不同,WindFM 采用**"离散化-生成"(Discretize-and-Generate)** 框架,由两个子模型构成(合计约 8.06M 参数):
wind_speed /
wind_direction / power / density / temperature / pressure 六特征)
压缩为两级分层离散 token(s1 / s2 各 10 bit,码本大小 1024);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 / 概率性多采样) | ✅ 通过 |
reconstruct | tokenizer 编解码重建(编码 → 离散 token → 解码 → 对齐) | ✅ 通过 |
| 数值校验 | NPU 与 CPU fp32 参考对齐(greedy,同种子) | ✅ 通过(相对偏差 ~1e-7) |
引擎选型说明: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 节)。
| 组件 | 版本 |
|---|---|
| 操作系统 | Linux 5.10.0(aarch64) |
| Python | 3.11.14 |
| CANN | 8.5.1 |
| NPU 芯片 | Ascend 910B(Ascend910_9362,逻辑卡 ×2,单卡 HBM 64 GB) |
| torch | 2.9.0+cpu |
| torch-npu | 2.9.0.post1+gitee7ba04 |
| numpy | 1.26.4 |
| pandas | 3.0.2 |
| einops | 0.8.2 |
| safetensors | 0.7.0 |
| tqdm | 4.67.3 |
| huggingface-hub | 0.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 库。
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 匹配),再执行本步骤。
本项目无第三方 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/simplevenv/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。
npu-smi info
# 需能看到 Health=OK 的逻辑卡(本机 Phy-ID 10 / 11,对应 npu:0 / npu:1)cd /opt/atomgit/model_adapt/WindFM-NPU
# 方式一:直接调用 venv 解释器(推荐,无需 activate)
./venv/bin/python3 inference.py --help
# 方式二:激活后使用 python3
source venv/bin/activate
python3 inference.py --help脚本默认执行 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./venv/bin/python3 inference.py --suite脚本将依次运行环境检查 / 模型加载 / 预测正确性 / 上下文长度 / 采样参数 /
设备与精度 / 数据边界共 41 组用例,完整转录见 output/suite_41_cases.txt
与 README 第 5 节。
--output xxx.json 时,输入上下文、预测 / 重建结果、性能与精度指标
一并写入 JSON,便于二次分析(详见 output/ 目录)。测试输入为确定性合成风电场小时序列(无随机成分,可直接复现):功率以慢变
天气尺度(月 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。
命令:
./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| 用例 | 项目 | 结果 |
|---|---|---|
| 1 | NPU 逻辑卡数 | 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 ✅ |
| 4 | NPU 型号 | npu:0 / npu:1 = Ascend910_9362 |
| 5 | WindFM 参数量 | 4,100,096(≈4.10M) |
| 6 | Tokenizer 参数量 | 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 |
用例 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 参考数值一致 ✅
SUCCESS48 点预测 vs 真值:
| 时刻 | 预测 (MW) | 真值 (MW) | 时刻 | 预测 (MW) | 真值 (MW) |
|---|---|---|---|---|---|
| 0 | 1043.107 | 1075.984 | 24 | 1031.681 | 1077.991 |
| 1 | 1042.016 | 1080.032 | 25 | 1031.387 | 1073.964 |
| 2 | 1040.731 | 1083.970 | 26 | 1031.048 | 1069.920 |
| 3 | 1039.826 | 1087.743 | 27 | 1030.762 | 1065.914 |
| 4 | 1039.256 | 1091.296 | 28 | 1030.608 | 1061.997 |
| 5 | 1039.019 | 1094.579 | 29 | 1030.601 | 1058.219 |
| 6 | 1038.923 | 1097.544 | 30 | 1030.657 | 1054.628 |
| 7 | 1038.750 | 1100.148 | 31 | 1030.693 | 1051.264 |
| 8 | 1038.481 | 1102.351 | 32 | 1030.680 | 1048.165 |
| 9 | 1038.216 | 1104.124 | 33 | 1030.630 | 1045.362 |
| 10 | 1038.007 | 1105.439 | 34 | 1030.560 | 1042.879 |
| 11 | 1037.899 | 1106.278 | 35 | 1030.473 | 1040.734 |
| 12 | 1037.824 | 1106.629 | 36 | 1030.385 | 1038.938 |
| 13 | 1036.052 | 1106.487 | 37 | 1030.326 | 1037.495 |
| 14 | 1035.413 | 1105.856 | 38 | 1030.287 | 1036.401 |
| 15 | 1035.040 | 1104.744 | 39 | 1030.197 | 1035.646 |
| 16 | 1034.732 | 1103.170 | 40 | 1030.098 | 1035.212 |
| 17 | 1034.382 | 1101.158 | 41 | 1030.051 | 1035.073 |
| 18 | 1033.975 | 1098.737 | 42 | 1030.019 | 1035.201 |
| 19 | 1033.489 | 1095.944 | 43 | 1029.953 | 1035.557 |
| 20 | 1032.937 | 1092.821 | 44 | 1029.862 | 1036.100 |
| 21 | 1032.450 | 1089.413 | 45 | 1029.782 | 1036.784 |
| 22 | 1032.116 | 1085.770 | 46 | 1029.773 | 1037.559 |
| 23 | 1031.900 | 1081.945 | 47 | 1029.851 | 1038.374 |
说明:真值列来自确定性合成数据;NPU 与 CPU fp32 参考的最大绝对偏差仅 0.000122 MW(相对偏差 1.17e-07),证明昇腾 NPU 数值计算与官方实现 完全一致、适配正确。MAE=37.85 反映的是零样本预测对合成数据的误差(模型未见 过该合成风电场)。
用例 11~18 结果汇总:
| 用例 | 参数 | 推理耗时 | 预测中位数 MAE | RMSE |
|---|---|---|---|---|
| 11 | pred_len=24, sample=1, greedy | 654.8 ms | 59.0677 | 59.9677 |
| 12 | pred_len=48, sample=1, greedy | 604.8 ms | 37.8466 | 44.9674 |
| 13 | pred_len=80, sample=1, greedy(官方示例默认) | 986.6 ms | 37.4423 | 47.8411 |
| 14 | pred_len=96, sample=1, greedy(4 天) | 1225.8 ms | 56.5304 | 76.1025 |
| 15 | pred_len=168, sample=1, greedy(7 天) | 2426.6 ms | 164.4691 | 215.9769 |
| 16 | pred_len=24, sample=5(概率) | 544.7 ms | 83.4895 | 86.9444 |
| 17 | pred_len=48, sample=20(概率) | 1038.6 ms | 55.5618 | 63.2690 |
| 18 | pred_len=48, sample=100(p10/p50/p90) | 3074.0 ms | 52.5961 | 58.1624 |
概率模式下表格列为采样路径的中位数 MAE/RMSE;多采样路径还可输出 p10 / p50 / p90 分位数区间(见用例 18 与
output/probabilistic.json)。
| 用例 | lookback | 推理耗时 | MAE | RMSE | 说明 |
|---|---|---|---|---|---|
| 19 | 96 | 892.6 ms | 23.3073 | 27.6367 | 4 天历史 |
| 20 | 168 | 864.5 ms | 32.6082 | 35.1033 | 1 周历史 |
| 21 | 240 | 573.6 ms | 37.8466 | 44.9674 | 默认 10 天 |
| 22 | 336 | 657.2 ms | 183.3647 | 198.2075 | 2 周历史 |
| 23 | 512 | 906.5 ms | 19.7998 | 27.7833 | = max_context |
| 24 | 700 | 969.3 ms | 67.9824 | 77.3495 | 超出 max_context,截断回看 512 |
用例 23(lookback=512)预测值围绕 635 MW,贴近该窗口真值(约 617~622 MW), MAE=19.8 为 41 组中最优;用例 22(lookback=336)处于功率爬升段,零样本误差 偏大。全部 6 组均正常推理,说明上下文长度对模型运行无影响,仅影响预测精度。
| 用例 | 采样参数 | 推理耗时 | MAE | RMSE |
|---|---|---|---|---|
| 25 | temperature=0.5 | 649.9 ms | 36.5685 | 44.2372 |
| 26 | temperature=0.8 | 616.5 ms | 55.5908 | 59.7709 |
| 27 | temperature=1.0(默认) | 607.0 ms | 64.8539 | 72.5901 |
| 28 | temperature=1.5 | 596.4 ms | 82.9531 | 91.0703 |
| 29 | top_k=10 | 591.5 ms | 91.4014 | 96.2283 |
| 30 | top_k=50 | 560.9 ms | 48.7527 | 53.6894 |
| 31 | top_p=0.8(nucleus) | 586.1 ms | 39.3059 | 44.6253 |
| 32 | top_p=1.0(无过滤) | 524.6 ms | 63.3626 | 71.2442 |
温度越高采样多样性越强、单路径 MAE 越大(用例 25→28);greedy(用例 12) 与低温采样(T=0.5)误差相当,适合确定性部署;概率集成(用例 17/18/41)用 多条路径的中位数可显著提升鲁棒性。
| 用例 | 设备 / 精度 | 推理耗时 | MAE | RMSE |
|---|---|---|---|---|
| 33 | npu:0 float32(默认) | 589.4 ms | 37.8466 | 44.9674 |
| 34 | npu:1 float32 | 872.9 ms | 37.8466 | 44.9674 |
| 35 | npu:0 bfloat16 | 1159.4 ms | 38.9870 | 45.8256 |
| 36 | npu:0 float16 | 1137.5 ms | 37.8736 | 44.9675 |
| 37 | CPU float32(参考) | 2751.4 ms | 37.8466 | 44.9674 |
| 38 | NPU 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 上同样可完整运行(供参考对比)。
用例 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 ✅ |
| 40 | CSV 含 NaN | 正确拦截并抛 ValueError ✅ |
| 41 | 概率集成 50 条路径 | 中位数 MAE=55.13,耗时 1030.8 ms ✅ |
41 组用例全部运行通过;完整逐行转录见
output/suite_41_cases.txt。
| 引擎 | 是否适用 | 说明 |
|---|---|---|
| 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 头部
注释):
from .module import *),使其可作为独立 Python 包导入;WindFMPredictor 构造时显式 .eval(),关闭 dropout,保证自回归采样
(尤其 greedy/argmax)完全确定、可复现——官方代码未显式 eval,训练态下
dropout 会使结果带随机性;generate 的切片 bug:官方 preds[:, -pred_len:, :] 会错误
裁剪采样维度,导致 sample_count > pred_len 时采样路径被截断(例如
sample_count=100、pred_len=48 时只剩 48 条路径),已改为裁剪序列维度
preds[:, :, -pred_len:, :];--greedy 确定性 argmax 采样,用于 CPU/NPU 数值对齐验证。测试条件:单卡 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 倍。
WindFMPredictor 未显式 .eval(),
训练态下 attention/FFN 的 dropout 会引入随机性。本适配已在构造时自动
.eval(),greedy 输出完全确定(用例 38 复现成功)。pd.to_datetime(..., utc=True)。predict 要求 wind_speed / wind_direction / power / density / temperature / pressure 六列齐全且无 NaN,否则抛 ValueError
(见用例 40)。max_context=512,lookback 超过 512 时会截断回看最近
512 点(见用例 24),不影响运行。npu:0 / npu:1),可用 --device npu:1
切换;若同时跑其他任务,请用 npu-smi info 确认卡空闲。warnings.filterwarnings 屏蔽
Ascend 目录属主告警,并将 CANN 日志落到 /tmp
(ASCEND_PROCESS_LOG_PATH)。加载权重时 stderr 可能打印 1~2 行
Loading weights from local directory,以及首次前向的 path string is NULL
提示,均为无害的环境信息,不影响 stdout 结果与推理正确性。transformers / numpy 的包;
本项目无第三方 model 库依赖,PyPI 通用包统一走清华 / 阿里镜像(见 3.2 节)。贡献者: z_studio | 赛道: 模型适配赛道 | 适配时间: 2026-08-19