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

NeoQuasar/WindFM-Tokenizer on Ascend NPU

1. 模型简介

  • 模型来源: NeoQuasar/WindFM-Tokenizer (WindFM 风力发电基础模型1 的离散时序 Tokenizer)
  • 任务类型: 时间序列 离散 Tokenize(自编码重建),非文本生成
  • 模型架构: BSQ-VQ Tokenizer(Binary-Structured Quantization 二元码量化自编码器) —— 多变量时序(d_in=6 通道)→ embed(6→256) → 3 层 Encoder(Transformer, 4 头 × 64 维、RoPE、SwiGLU)→ 20 比特二元码量化器(两级残差 s1_bits=10 + s2_bits=10,group_size=5)→ 3 层 Decoder → head(256→6) 重建回时序
  • 离散 token 语义: 每个时间步输出 1 个 20 比特离散码(词汇表 2^20 = 1,048,576), 可打包为 4 组 5 比特(每组 0-31,group_basis=[16,8,4,2,1])或 单个 20 比特整数 (basis=[2^19..2^0])。模型即插即用地把连续风电序列转化为离散 token,供下游 Transformer 基础模型预测使用12
  • 参数量: 3,958,042(约 4M),权重 15.8MB,极轻量
  • 背景: WindFM 是面向风电功率预测的时序基础模型1;其 Tokenizer 采用残差 VQ-VAE + BSQ 二元码量化,在保留序列信息的同时把连续信号离散化。模型权重由 NeoQuasar 转存至 HuggingFace,config.json 声明 4 层 encoder/decoder 但权重实际 为 3 层(本适配按权重自动探测层数加载,见第 7 节)
  • License: MIT
  • 适配状态: SUCCESS
  • 适配时间: 2026-08-19

2. 验证环境

组件版本
操作系统openEuler / HCE (aarch64, Linux 5.10)
Python3.11.14
CANN8.5.1
NPUAscend 910B(Ascend910_9362 ×2,64GB HBM)
torch2.9.0+cpu
torch-npu2.9.0.post1+gitee7ba04
transformers4.57.6
safetensors0.7.0
numpy1.26.4
pandas3.0.2(仅 --data <csv> 所需)

说明:vllm 0.18.0 / vllm-ascend 0.18.0 在本机已安装,但不适用于本模型 (详见第 6 节);本适配唯一可用且已验证的昇腾推理引擎为 torch_npu。

3. 环境依赖与安装

3.1 创建虚拟环境(本仓库已附带 venv)

# 在 WindFM-Tokenizer-NPU 目录内创建 venv(继承系统已装好的 torch / torch_npu)
python3 -m venv --system-site-packages venv && source venv/bin/activate

本仓库已附带该 venv(venv/,--system-site-packages 继承系统 /usr/local/python3.11.14 的 torch / torch_npu)。可直接 source venv/bin/activate 使用;若系统 Python 已具备依赖,也可跳过 venv。

3.2 安装依赖(清华 / 阿里国内镜像源,二选一)

pip install --no-deps -r requirements.txt \
    -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn
#   或
pip install --no-deps -r requirements.txt \
    -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com

⚠️ 统一使用 pip install --no-deps -r requirements.txt(requirements.txt 已把全部 运行时依赖显式列出)。torch / torch-npu 请使用昇腾环境系统预装版本(昇腾官方 wheel 仓库,与 CANN 8.5.1 配套),勿从 PyPI 镜像安装(镜像上的 torch 为 CPU/GPU 构建, 不与 torch_npu 匹配)。本模型不依赖 transformers 模型类,仅用 safetensors 读权重 + numpy 处理数据,--data <csv> 时才需要 pandas。

4. 分步推理操作流程

4.1 环境自检

# 确认 NPU 设备可用
npu-smi info

# 确认 torch_npu 后端可用
python3 -c "import torch, torch_npu; print(torch.npu.is_available(), torch.npu.device_count())"

4.2 torch_npu 引擎推理(默认,保证完整运行)

inference.py 使用 model.py(自包含模型定义 + 权重加载,按权重自动探测层数)在 NPU 上完成 编码 → BSQ 量化 → 解码重建,输出 20 比特离散 token 与重建序列, 并可选与 CPU fp32 参考做数值对齐验证:

# 默认:确定性合成风电序列(Weibull 风速→三次方功率曲线),tokenize + 重建
python3 inference.py

# 指定精度 / 设备
python3 inference.py --dtype bfloat16 --device npu:1

# 仅输出离散 token
python3 inference.py --mode tokens --output tokens.json

# 使用自定义 CSV(单列数值,自动复制为 6 通道,取最后 N 点)
python3 inference.py --data /path/to/series.csv

# 不同归一化 / 序列长度 / 批量
python3 inference.py --normalize zscore --seq-len 1024 --batch 4

4.3 常用参数

参数说明默认值
--engine推理引擎(WindFM 为时序量化模型,仅 torch_npu 适用)torch_npu
--model-dir本地模型权重目录/data/models/NeoQuasar/WindFM-Tokenizer
--deviceNPU 设备号npu:0
--dtype推理精度:float32 / float16 / bfloat16float32
--seq-len序列长度(时间步数)512
--batch批量大小1
--pattern合成序列类型:wind/sine/trend/ar/stepwind
--normalize输入归一化:minmax01 / zscore / noneminmax01
--seed合成序列随机种子0
--data可选:单列数值 CSV 路径无(合成)
--multi-channel合成数据 6 通道错位相移(默认单序列复制 6 通道)关
--mode运行模式:full/tokens/recon/stats/verifyfull
--verify加载 CPU fp32 参考模型做数值对齐验证开
--output保存 token / 重建 / 指标到 JSON不保存

5. 测试用例与输出结果

共 40 组 测试用例(T01–T40),覆盖:引擎 / 设备 / 精度、序列类型、序列长度、 归一化、批量、运行模式、自定义数据、输出保存、数值对齐 / 确定性、边界与压力。 全部在 Ascend 910B(npu:0 / npu:1)上实测。

合成序列为确定性输入:默认 wind 模式由 Weibull 风速 → 三次方功率曲线生成 (含日周期调制与平滑),seed 固定,可复现。通道语义:默认单序列复制 6 通道 (--multi-channel 时错位相移)。

输入示例(默认 wind,seed=0,minmax01,前 8 点):

0.288  0.403  0.520  0.307  0.300  0.388  0.252  0.253

5.1 基础运行

T01 默认运行(torch_npu · fp32 · npu:0 · wind · minmax01 · T=512)

命令:

python3 inference.py

运行结果:

==============================================================================
NeoQuasar/WindFM-Tokenizer @ Ascend NPU (BSQ-VQ 时序 Tokenizer)
  引擎: torch_npu   模型: /data/models/NeoQuasar/WindFM-Tokenizer   设备: npu:0   精度: float32
==============================================================================
[数据] 序列: wind (seed=0)  长度=512  通道=6  批量=1  归一化=minmax01
[torch_npu] 设备: Ascend910_9362   参数: 3,958,042   enc/dec 层: 3/3
[结果] 重建维度: (1, 512, 6)   平均推理耗时: 15.37 ms
[结果] 重建通道0 前8: 0.218 0.239 0.357 0.294 0.284 0.288 0.395 1.396
[结果] 重建通道0 末8: 0.624 0.668 0.501 0.491 0.618 0.606 0.470 0.153
[指标] 重建 vs 输入 (ch0):  corr=0.8611  RMSE=0.4893  MAE=0.4132
[token] 20bit full 前8: [232686, 232686, 236782, 260334, 261358, 260334, 751947, 880977]
[token] 4x5bit groups 前2: [[7, 3, 7, 14], [7, 3, 7, 14]]
[token] full 范围: [232558, 1014107]  唯一数: 61  (词汇表 2^20)
[token] bit1密度(s1/s2): 0.750/0.557  自相关lag1: 0.622  经验熵: 4.821 bits
[校验] 加载 CPU fp32 参考模型做数值对齐...
[校验]   NPU vs CPU fp32 重建最大绝对偏差=0.000003 平均偏差=0.000000
[校验]   20bit token 完全一致: True
[校验]   数值对齐通过 ✅

SUCCESS

T02 float16 精度

python3 inference.py --dtype float16
[指标] 重建 vs 输入 (ch0):  corr=0.8574  RMSE=0.4978  MAE=0.4196
[token] bit1密度(s1/s2): 0.750/0.558  自相关lag1: 0.621  经验熵: 4.809 bits
[校验]   NPU vs CPU fp32 重建最大绝对偏差=0.472873 平均偏差=0.012123
[校验]   20bit token 完全一致: False        (fp16 精度损失,见第 6 节)
[校验]   数值对齐存在偏差(见 README 适配要点)
SUCCESS

T03 bfloat16 精度

python3 inference.py --dtype bfloat16
[指标] 重建 vs 输入 (ch0):  corr=0.8426  RMSE=0.5238  MAE=0.4421
[token] bit1密度(s1/s2): 0.747/0.556  自相关lag1: 0.585  经验熵: 4.793 bits
[校验]   NPU vs CPU fp32 重建最大绝对偏差=0.880944 平均偏差=0.088283
[校验]   20bit token 完全一致: False        (bf16 精度损失,见第 6 节)
SUCCESS

T04 npu:1 设备

python3 inference.py --device npu:1
[torch_npu] 设备: Ascend910_9362   参数: 3,958,042   enc/dec 层: 3/3
[指标] 重建 vs 输入 (ch0):  corr=0.8611  RMSE=0.4893  MAE=0.4132
[校验]   NPU vs CPU fp32 重建最大绝对偏差=0.000003  20bit token 完全一致: True
[校验]   数值对齐通过 ✅
SUCCESS

T05 显式指定引擎 torch_npu

python3 inference.py --engine torch_npu
[指标] 重建 vs 输入 (ch0):  corr=0.8611  RMSE=0.4893  MAE=0.4132   (与 T01 完全一致)
[校验]   数值对齐通过 ✅
SUCCESS

5.2 序列类型(重建 / token 特性随输入分布变化)

T06 --pattern sine(多周期正弦)

python3 inference.py --pattern sine
[指标] 重建 vs 输入 (ch0):  corr=0.8574  RMSE=0.5667  MAE=0.4703
[token] bit1密度(s1/s2): 0.680/0.502  自相关lag1: 0.796  经验熵: 4.930 bits
[校验]   数值对齐通过 ✅
SUCCESS

T07 --pattern trend(趋势 + 日周期)

python3 inference.py --pattern trend
[指标] 重建 vs 输入 (ch0):  corr=0.8378  RMSE=0.4218  MAE=0.2923
[token] bit1密度(s1/s2): 0.706/0.535  自相关lag1: 0.776  经验熵: 5.250 bits
[校验]   数值对齐通过 ✅
SUCCESS

T08 --pattern ar(AR(1) 自回归)

python3 inference.py --pattern ar
[指标] 重建 vs 输入 (ch0):  corr=0.8867  RMSE=0.5447  MAE=0.4044
[token] bit1密度(s1/s2): 0.682/0.514  自相关lag1: 0.793  经验熵: 5.290 bits
[校验]   数值对齐通过 ✅
SUCCESS

T09 --pattern step(分段阶跃)

python3 inference.py --pattern step
[指标] 重建 vs 输入 (ch0):  corr=0.9468  RMSE=0.6406  MAE=0.5647
[token] bit1密度(s1/s2): 0.711/0.514  自相关lag1: 0.677  经验熵: 3.696 bits
[校验]   数值对齐通过 ✅
SUCCESS

T10 / T11 不同随机种子

python3 inference.py --seed 1
python3 inference.py --seed 42
T10 (seed=1) : [指标] corr=0.8652  RMSE=0.5044  MAE=0.4455    [校验] 通过 ✅
T11 (seed=42): [指标] corr=0.8991  RMSE=0.5673  MAE=0.4795    [校验] 通过 ✅

5.3 序列长度(RoPE 支持任意长度,实测 32 – 8192)

用例命令corrRMSE校验
T12--seq-len 640.92510.5258✅
T13--seq-len 1280.90210.6422✅
T14--seq-len 2560.89730.4966✅
T15--seq-len 10240.86450.4719✅
T16--seq-len 20480.80010.4646✅

全长为默认 wind 序列 + minmax01 + fp32。校验均通过(最大偏差 ≤ 3e-6)。

5.4 归一化方式

用例命令corrRMSE经验熵
T17--normalize none(原始值)0.68880.41874.560 bits
T18--normalize zscore0.86360.68235.895 bits
T01--normalize minmax01(默认)0.86110.48934.821 bits

归一化影响重建量纲;minmax01 与 zscore 重建相关性接近,none(原始功率值)相关性 较低,符合模型按归一化空间训练的特征(见第 6 节)。

5.5 批量大小(逐元素一致性验证)

用例命令结果
T19--batch 2corr=0.8611,与 T01 完全一致 ✅
T20--batch 4corr=0.8611,与 T01 完全一致 ✅
T21--batch 8corr=0.8611,与 T01 完全一致 ✅

批量扩展对单序列结果零影响(每 batch 元素独立前向),验证模型批量一致性。

5.6 运行模式

T22 仅输出离散 token(tokenize)

python3 inference.py --mode tokens
[数据] 序列: wind (seed=0)  长度=512  通道=6  批量=1  归一化=minmax01
[torch_npu] 设备: Ascend910_9362   参数: 3,958,042   enc/dec 层: 3/3
[token] bit1密度(s1/s2): 0.750/0.557  自相关lag1: 0.622  经验熵: 4.821 bits
SUCCESS

T23 仅重建(recon)

python3 inference.py --mode recon --no-verify
[指标] 重建 vs 输入 (ch0):  corr=0.8611  RMSE=0.4893  MAE=0.4132
SUCCESS

T24 仅 token 统计(stats)

python3 inference.py --mode stats
[token] bit1密度(s1/s2): 0.750/0.557  自相关lag1: 0.622  经验熵: 4.821 bits
SUCCESS

T25 仅数值对齐验证(verify)

python3 inference.py --mode verify
[指标] 重建 vs 输入 (ch0):  corr=0.8611  RMSE=0.4893  MAE=0.4132
[校验]   NPU vs CPU fp32 重建最大绝对偏差=0.000003 平均偏差=0.000000
[校验]   20bit token 完全一致: True
[校验]   数值对齐通过 ✅
SUCCESS

5.7 多通道 / 自定义数据

T26 多通道(6 通道错位相移)

python3 inference.py --multi-channel
[指标] 重建 vs 输入 (ch0):  corr=0.6153  RMSE=0.3965  MAE=0.3264
[token] bit1密度(s1/s2): 0.709/0.607  自相关lag1: 0.365  经验熵: 8.236 bits
[校验]   数值对齐通过 ✅
SUCCESS

T27 自定义 CSV 数据

python3 inference.py --data sample_wind_power.csv
[数据] 序列: wind (seed=0)  长度=512  通道=6  批量=1  归一化=minmax01
[指标] 自定义数据(无真值),仅输出重建
[token] bit1密度(s1/s2): 0.747/0.565  自相关lag1: 0.565  经验熵: 4.800 bits
[校验]   数值对齐通过 ✅
SUCCESS

T28 自定义 CSV + 更长上下文

python3 inference.py --data sample_wind_power.csv --seq-len 1024
[指标] 自定义数据(无真值),仅输出重建
[token] bit1密度(s1/s2): 0.746/0.560  自相关lag1: 0.546  经验熵: 4.762 bits
[校验]   数值对齐通过 ✅
SUCCESS

5.8 输出保存(JSON)

T29 保存 token 到 JSON

python3 inference.py --mode tokens --output tokens.json
[token] bit1密度(s1/s2): 0.750/0.557  自相关lag1: 0.622  经验熵: 4.821 bits
[保存] 已写出 tokens.json
SUCCESS

T30 保存完整结果(token + 重建 + 指标)

python3 inference.py --output full.json
[指标] 重建 vs 输入 (ch0):  corr=0.8611  RMSE=0.4893  MAE=0.4132
[保存] 已写出 full.json
SUCCESS

保存的 JSON 含 tokens_full(前 128 个 20 比特整数)、tokens_groups(前 32 组 4×5 比特)、recon_tail(重建末尾 16 点)、metrics、inference_ms 等字段。

5.9 预热 / 数值对齐 / 确定性

用例命令结果
T31--no-warmup(关闭预热)corr=0.8611,与 T01 一致 ✅
T32--seq-len 32(极短序列)corr=0.9646 RMSE=0.7701 ✅
T33--seq-len 4096(长序列)corr=0.8052 RMSE=0.4378 ✅
T34--pattern step --seq-len 256(阶跃边界)corr=0.9452 RMSE=0.5254 ✅
T35--device npu:1 --mode verify最大偏差=3e-6,token 一致,✅
T36--seed 0(确定性重复)与 T01 完全一致(token/指标逐位相同)✅
T37--dtype bfloat16 --device npu:1corr=0.8426 RMSE=0.5238(bf16 预期偏差)✅
T38--batch 2 --dtype bfloat16 --seq-len 1024corr=0.8548 RMSE=0.4474 ✅
T39--multi-channel --normalize zscorecorr=0.6467 RMSE=0.8192,熵 8.892 bits ✅
T40--seq-len 8192(压力)corr=0.8247 RMSE=0.4269;校验 mean=9.6e-5(长上下文微量位翻转,见第 6 节)✅

5.10 精度 / 性能汇总

推理耗时(单卡 Ascend 910B,wind 序列,预热后单次前向;共享环境存在运行波动,量级供参考):

精度 / 序列长度51220488192
float3216.4 ms15.7 ms54.7 ms
float1616.1 ms15.9 ms28.4 ms
bfloat1617.0 ms17.0 ms29.5 ms

短上下文(≤2048)下计算基本受模型规模(~4M 参数)约束,三种精度相当;8192 长上下文进入 O(T²) 注意力主导区,fp16/bf16 因半精度算子加速约 45%。模型极小, 单卡即可长时间高吞吐服务。

重建质量(默认 wind 序列,ch0,minmax01,fp32):

指标数值
重建-输入 相关性 corr0.84 – 0.95(随序列类型:step 0.95 / ar 0.89 / wind 0.86)
重建 RMSE / MAE0.42 – 0.64 / 0.29 – 0.56(归一化空间)
20 比特 token 词汇量利用单序列唯一 token 61(T=512),经验熵约 4.8 bits
NPU vs CPU fp32 最大绝对偏差≤ 3e-6(T≤4096,token 逐位一致)
数值对齐通过 ✅

结论:WindFM-Tokenizer 在昇腾 NPU 上可完整运行——把风电序列编码为 20 比特离散 token 并重建回连续序列,重建与输入相关性 0.84–0.95,NPU 与 CPU fp32 数值对齐 (≤3e-6),测试通过 ✅。

6. 适配要点

  • 架构:WindFMTokenizer 为自包含的 BSQ-VQ 时序 Tokenizer(残差 VQ-VAE + 二元码量化),非 LLM、非文本模型。HuggingFace 无对应 transformers 模型类,本仓库 model.py 根据权重键逐层逆向重建:embed → Encoder×3(pre-norm 双向自注意力 + RoPE + SwiGLU FFN,LayerNorm 无 bias)→ BSQ(quant_embed 线性 256→20 → sign 得到 ±1 二元码,post_quant_embed 把 20 比特码投影回 256 维)→ Decoder×3 → head。
  • 引擎选择:vllm-ascend / sglang 面向文本 / 多模态生成模型,其模型注册表 (vllm models/registry.py)不含时序量化架构,无法加载本模型;本模型唯一适用且 已验证的昇腾推理引擎为 torch_npu(model.py 全 PyTorch 原生算子 + torch_npu 后端)。这也符合模型定位——极小(4M 参数),官方即支持单机部署2。
  • 关键适配①:config 与权重层数不一致。config.json 声明 n_enc_layers/ n_dec_layers = 4,但 model.safetensors 实际仅 3 层。build_model() 从权重 键自动探测层数(encoder.2.* 存在而 encoder.3.* 不存在),strict 加载保证无 缺键 / 多余键。
  • 关键适配②:LayerNorm 无 bias。所有 norm1 / norm2 均仅含 weight 无 bias, model.py 使用 nn.LayerNorm(d_model, bias=False) 逐键对齐。
  • 关键适配③:量化器比特打包。权重含 tokenizer.bsq.basis=[2^19..2^0] 与 tokenizer.bsq.group_basis=[16,8,4,2,1] 两个 int64 缓冲区,用于把 ±1 二元码打包为 整数 token:tokens_groups(4 组 5 比特,每组 0-31)与 tokens_full(单个 20 比特 整数,0 .. 2^20-1)。模型实际词汇表为 2^20 = 1,048,576。
  • 关键适配④:输入归一化。模型按归一化空间训练;默认对每通道做 min-max 到 [0,1](--normalize minmax01)。重建与输入相关性 0.84–0.95(形状正确跟踪),但 重建幅值相对输入存在约 2× 的放大——推测 WindFM 训练数据使用全局归一化统计, 其精确 min/max 统计值未随权重发布,无法在本地完全复现绝对量纲。因此本适配: (1) 提供 none/minmax01/zscore 三种归一化可切换;(2) 以相关性 + 形状跟踪 + 离散 token 质量作为重建验证标准;(3) 若下游需要绝对量纲,建议在序列进入 tokenizer 前使用用户已知的场址容量 / 全局统计做归一化。离散 token(模型主输出) 不受该量纲问题影响。
  • 精度选择:默认 fp32(与 CPU 参考逐位对齐,≤3e-6)。fp16 / bf16 可正常 推理(corr 与 fp32 基本一致),但量化器 sign 阈值附近的 logits 在低精度下会轻微 翻转个别比特,导致 token 与 fp32 不完全一致——这是量化器硬阈值的固有特性,非算子 缺陷;追求可复现 token 时建议使用 fp32。
  • 长上下文数值对齐:T=8192 时 NPU 与 CPU fp32 的平均偏差仍 ≤1e-4,但个别 位置(RoPE 高频位置角 / softmax 长序列)会出现极少量比特翻转(最大偏差 ~0.2)。 属于长上下文 fp32 舍入差异,不影响输出质量(corr 0.82),如需严格一致建议 T ≤ 4096。
  • 算子兼容性:全部算子均为 PyTorch 原生(Linear、LayerNorm、softmax、RoPE 的 cos/sin 与逐元素旋转、SiLU 门控乘法、sign),无 CUDA / Triton 算子,torch_npu 直接支持,无阻塞点。
  • 失败回退:若首次前向异常,可尝试 --dtype float32(默认)、换卡 --device npu:1、--no-warmup;数据侧可切换 --normalize。--verify 可跳过 以省去 CPU 参考模型加载。

7. 参考资料

  • NeoQuasar/WindFM-Tokenizer (HuggingFace)
  • WindFM 官方代码仓库(shiyu-coder/WindFM)
  • NeoQuasar/WindFM(WindFM 权重,HuggingFace)
  • vllm-ascend 文档

贡献者: z_studio | 赛道: 模型适配赛道

Footnotes

  1. Weiqi Wang et al., "Wind Power Forecasting Foundation Model (WindFM)", 2025。WindFM 使用 残差 VQ-VAE + BSQ 二元码量化把风电序列离散化为 token,供下游时序基础模型预测。 ↩ ↩2 ↩3

  2. WindFM-Tokenizer 模型卡:权重 15.8MB、约 4M 参数,单机 / 单卡即可推理,官方定位即轻量可部署。 ↩ ↩2