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) 重建回时序group_basis=[16,8,4,2,1])或 单个 20 比特整数
(basis=[2^19..2^0])。模型即插即用地把连续风电序列转化为离散 token,供下游
Transformer 基础模型预测使用12config.json 声明 4 层 encoder/decoder 但权重实际
为 3 层(本适配按权重自动探测层数加载,见第 7 节)| 组件 | 版本 |
|---|---|
| 操作系统 | openEuler / HCE (aarch64, Linux 5.10) |
| Python | 3.11.14 |
| CANN | 8.5.1 |
| NPU | Ascend 910B(Ascend910_9362 ×2,64GB HBM) |
| torch | 2.9.0+cpu |
| torch-npu | 2.9.0.post1+gitee7ba04 |
| transformers | 4.57.6 |
| safetensors | 0.7.0 |
| numpy | 1.26.4 |
| pandas | 3.0.2(仅 --data <csv> 所需) |
说明:vllm 0.18.0 / vllm-ascend 0.18.0 在本机已安装,但不适用于本模型 (详见第 6 节);本适配唯一可用且已验证的昇腾推理引擎为 torch_npu。
# 在 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。
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。
# 确认 NPU 设备可用
npu-smi info
# 确认 torch_npu 后端可用
python3 -c "import torch, torch_npu; print(torch.npu.is_available(), torch.npu.device_count())"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| 参数 | 说明 | 默认值 |
|---|---|---|
--engine | 推理引擎(WindFM 为时序量化模型,仅 torch_npu 适用) | torch_npu |
--model-dir | 本地模型权重目录 | /data/models/NeoQuasar/WindFM-Tokenizer |
--device | NPU 设备号 | npu:0 |
--dtype | 推理精度:float32 / float16 / bfloat16 | float32 |
--seq-len | 序列长度(时间步数) | 512 |
--batch | 批量大小 | 1 |
--pattern | 合成序列类型:wind/sine/trend/ar/step | wind |
--normalize | 输入归一化:minmax01 / zscore / none | minmax01 |
--seed | 合成序列随机种子 | 0 |
--data | 可选:单列数值 CSV 路径 | 无(合成) |
--multi-channel | 合成数据 6 通道错位相移(默认单序列复制 6 通道) | 关 |
--mode | 运行模式:full/tokens/recon/stats/verify | full |
--verify | 加载 CPU fp32 参考模型做数值对齐验证 | 开 |
--output | 保存 token / 重建 / 指标到 JSON | 不保存 |
共 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命令:
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
[校验] 数值对齐通过 ✅
SUCCESSpython3 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 适配要点)
SUCCESSpython3 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 节)
SUCCESSpython3 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
[校验] 数值对齐通过 ✅
SUCCESSpython3 inference.py --engine torch_npu[指标] 重建 vs 输入 (ch0): corr=0.8611 RMSE=0.4893 MAE=0.4132 (与 T01 完全一致)
[校验] 数值对齐通过 ✅
SUCCESS--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--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--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--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
[校验] 数值对齐通过 ✅
SUCCESSpython3 inference.py --seed 1
python3 inference.py --seed 42T10 (seed=1) : [指标] corr=0.8652 RMSE=0.5044 MAE=0.4455 [校验] 通过 ✅
T11 (seed=42): [指标] corr=0.8991 RMSE=0.5673 MAE=0.4795 [校验] 通过 ✅| 用例 | 命令 | corr | RMSE | 校验 |
|---|---|---|---|---|
| T12 | --seq-len 64 | 0.9251 | 0.5258 | ✅ |
| T13 | --seq-len 128 | 0.9021 | 0.6422 | ✅ |
| T14 | --seq-len 256 | 0.8973 | 0.4966 | ✅ |
| T15 | --seq-len 1024 | 0.8645 | 0.4719 | ✅ |
| T16 | --seq-len 2048 | 0.8001 | 0.4646 | ✅ |
全长为默认
wind序列 + minmax01 + fp32。校验均通过(最大偏差 ≤ 3e-6)。
| 用例 | 命令 | corr | RMSE | 经验熵 |
|---|---|---|---|---|
| T17 | --normalize none(原始值) | 0.6888 | 0.4187 | 4.560 bits |
| T18 | --normalize zscore | 0.8636 | 0.6823 | 5.895 bits |
| T01 | --normalize minmax01(默认) | 0.8611 | 0.4893 | 4.821 bits |
归一化影响重建量纲;minmax01 与 zscore 重建相关性接近,
none(原始功率值)相关性 较低,符合模型按归一化空间训练的特征(见第 6 节)。
| 用例 | 命令 | 结果 |
|---|---|---|
| T19 | --batch 2 | corr=0.8611,与 T01 完全一致 ✅ |
| T20 | --batch 4 | corr=0.8611,与 T01 完全一致 ✅ |
| T21 | --batch 8 | corr=0.8611,与 T01 完全一致 ✅ |
批量扩展对单序列结果零影响(每 batch 元素独立前向),验证模型批量一致性。
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
SUCCESSpython3 inference.py --mode recon --no-verify[指标] 重建 vs 输入 (ch0): corr=0.8611 RMSE=0.4893 MAE=0.4132
SUCCESSpython3 inference.py --mode stats[token] bit1密度(s1/s2): 0.750/0.557 自相关lag1: 0.622 经验熵: 4.821 bits
SUCCESSpython3 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
[校验] 数值对齐通过 ✅
SUCCESSpython3 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
[校验] 数值对齐通过 ✅
SUCCESSpython3 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
[校验] 数值对齐通过 ✅
SUCCESSpython3 inference.py --data sample_wind_power.csv --seq-len 1024[指标] 自定义数据(无真值),仅输出重建
[token] bit1密度(s1/s2): 0.746/0.560 自相关lag1: 0.546 经验熵: 4.762 bits
[校验] 数值对齐通过 ✅
SUCCESSpython3 inference.py --mode tokens --output tokens.json[token] bit1密度(s1/s2): 0.750/0.557 自相关lag1: 0.622 经验熵: 4.821 bits
[保存] 已写出 tokens.json
SUCCESSpython3 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等字段。
| 用例 | 命令 | 结果 |
|---|---|---|
| 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:1 | corr=0.8426 RMSE=0.5238(bf16 预期偏差)✅ |
| T38 | --batch 2 --dtype bfloat16 --seq-len 1024 | corr=0.8548 RMSE=0.4474 ✅ |
| T39 | --multi-channel --normalize zscore | corr=0.6467 RMSE=0.8192,熵 8.892 bits ✅ |
| T40 | --seq-len 8192(压力) | corr=0.8247 RMSE=0.4269;校验 mean=9.6e-5(长上下文微量位翻转,见第 6 节)✅ |
推理耗时(单卡 Ascend 910B,wind 序列,预热后单次前向;共享环境存在运行波动,量级供参考):
| 精度 / 序列长度 | 512 | 2048 | 8192 |
|---|---|---|---|
| float32 | 16.4 ms | 15.7 ms | 54.7 ms |
| float16 | 16.1 ms | 15.9 ms | 28.4 ms |
| bfloat16 | 17.0 ms | 17.0 ms | 29.5 ms |
短上下文(≤2048)下计算基本受模型规模(~4M 参数)约束,三种精度相当;8192 长上下文进入 O(T²) 注意力主导区,fp16/bf16 因半精度算子加速约 45%。模型极小, 单卡即可长时间高吞吐服务。
重建质量(默认 wind 序列,ch0,minmax01,fp32):
| 指标 | 数值 |
|---|---|
| 重建-输入 相关性 corr | 0.84 – 0.95(随序列类型:step 0.95 / ar 0.89 / wind 0.86) |
| 重建 RMSE / MAE | 0.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),测试通过 ✅。
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。models/registry.py)不含时序量化架构,无法加载本模型;本模型唯一适用且
已验证的昇腾推理引擎为 torch_npu(model.py 全 PyTorch 原生算子 +
torch_npu 后端)。这也符合模型定位——极小(4M 参数),官方即支持单机部署2。config.json 声明 n_enc_layers/
n_dec_layers = 4,但 model.safetensors 实际仅 3 层。build_model() 从权重
键自动探测层数(encoder.2.* 存在而 encoder.3.* 不存在),strict 加载保证无
缺键 / 多余键。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。--normalize minmax01)。重建与输入相关性 0.84–0.95(形状正确跟踪),但
重建幅值相对输入存在约 2× 的放大——推测 WindFM 训练数据使用全局归一化统计,
其精确 min/max 统计值未随权重发布,无法在本地完全复现绝对量纲。因此本适配:
(1) 提供 none/minmax01/zscore 三种归一化可切换;(2) 以相关性 + 形状跟踪 +
离散 token 质量作为重建验证标准;(3) 若下游需要绝对量纲,建议在序列进入
tokenizer 前使用用户已知的场址容量 / 全局统计做归一化。离散 token(模型主输出)
不受该量纲问题影响。fp16 / bf16 可正常
推理(corr 与 fp32 基本一致),但量化器 sign 阈值附近的 logits 在低精度下会轻微
翻转个别比特,导致 token 与 fp32 不完全一致——这是量化器硬阈值的固有特性,非算子
缺陷;追求可复现 token 时建议使用 fp32。--dtype float32(默认)、换卡
--device npu:1、--no-warmup;数据侧可切换 --normalize。--verify 可跳过
以省去 CPU 参考模型加载。贡献者: z_studio | 赛道: 模型适配赛道