z
zhangyuge147/qcw2333-YingLong_110m-NPU
模型介绍
文件和版本
Pull Requests
讨论
分析

qcw2333/YingLong_110m 在 Ascend NPU 上

1. 模型简介

  • 模型名称: qcw2333/YingLong_110m
  • 权重URL: https://huggingface.co/qcw2333/YingLong_110m(revision e3738d65f445024cb912063680da6293aacd1d1e)
  • 任务类型: 时间序列预测 / 概率预测(time-series-forecasting、foundation model)
  • 论文: https://huggingface.co/papers/2506.11029,训练数据为 78B 时序点
  • 架构: YingLong(基于 TinyLlama Decoder,12 层,n_embd 768,n_head 12,n_query_groups 4,intermediate 3072,patch_size 32,haar_trans True,unet True,block_size 8224)
  • 权重格式: model.safetensors(240,947,188 字节,BF16,120M 参数,safetensors)
  • 自定义代码: 需要 trust_remote_code=True(model.py + model_config.py,已审查并针对 NPU 打补丁:纯 PyTorch SwiGLU / RMSNorm / Rotary,禁用 flash_attn)
  • 输入契约: torch.randn([B, T]),其中 T=context_length=2880(BFloat16),内部按 patch_size=32 切分为 90 个 patch,经 Haar 小波变换后进行线性投影
  • 输出契约: generate(seqs, future_token=96) -> [B, horizon=96, 99],BF16 概率预测(99 个分位数,1%..99%),median 为 q50(index 49),需检查分位数的单调性
  • 许可证: cc-by-4.0

2. 验证环境

  • NPU: Ascend910_9362(Ascend910),CANN 8.5.1,64GB HBM,npu-smi 25.5.5
  • 驱动: torch.npu.is_available()=True, device_count=2, device_name Ascend910_9362
  • PyTorch: 2.9.0+cpu,torch_npu: 2.9.0.post1+gitee7ba04,Transformers: 4.57.6,einops: 0.8.2
  • Python: 3.11.14,aarch64
  • 本地权重: /tmp/yinglong_adapted/model.safetensors(SHA 230MiB,commit e3738d65f445024cb912063680da6293aacd1d1e)
  • 测试输入: 固定种子 seed=42,torch.randn([1,2880], dtype=bfloat16) 生成后搬运至对应 device,确保 CPU/NPU 输入一致

3. 安装依赖

pip install -r requirements.txt
# torch==2.9.0
# torch_npu==2.9.0.post1
# transformers>=4.39.1
# huggingface_hub>=0.20
# einops==0.8.2
# numpy<2.0
# safetensors

4. NPU 推理

# 默认执行 (自动完成 CPU 基准 + NPU 推理 + 一致性验证 + 10次性能测试)
python inference.py

# 仅验证模式
python inference.py --mode validate

# 仅性能测试
python inference.py --mode benchmark

核心逻辑(inference.py:85):

  • 本地加载 AutoModelForCausalLM.from_pretrained(MODEL_DIR, trust_remote_code=True, dtype=bfloat16),并执行 .to(npu:0)
  • 补丁处理:model.py 中 flash_attn/xformers/dropout_layer_norm/rotary_emb 改为纯 PyTorch 实现(RMSNorm 使用 torch.rsqrt,rotary 的 cos/sin 采用纯计算,SwiGLU 采用三个线性层)
  • 前向过程:model.generate(seqs, future_token=96) 的内部流程为 tokenizer -> 12×Block (RMSNorm+Attention+SwiGLU) -> lm_head -> Haar逆变换 -> 逆归一化
  • 同步计时:使用 torch.npu.synchronize() 包裹计时区间

5. 真实推理结果

执行命令:python inference.py(在 npu:0 上真实执行,权重来自本地 /tmp/yinglong_adapted/model.safetensors,输入在 CPU 生成后拷贝)

[INFO] Model: qcw2333/YingLong_110m
[INFO] Task: time-series forecasting (context 2880 -> horizon 96, 99 quantiles)
[INFO] Architecture: YingLong (n_embd 768, n_layer 12, n_head 12, patch_size 32), haar_trans True
[INFO] Loading backend: transformers AutoModelForCausalLM (trust_remote_code=True, patched for NPU)
[INFO] Dtype: torch.bfloat16, Batch: 1, Patch: 32
[INFO] torch 2.9.0+cpu, torch_npu 2.9.0.post1+gitee7ba04
[INFO] NPU available: True, count: 2
[INFO] NPU device 0: Ascend910_9362

[STEP] CPU inference for consistency baseline
[INFO] Model dir: /tmp/yinglong_adapted
[INFO] Loading qcw2333/YingLong_110m with dtype=torch.bfloat16, device=cpu, trust_remote_code=True
[INFO] Param device: cpu, dtype: torch.bfloat16
[INPUT] shape [1, 2880], dtype torch.bfloat16, device cpu, seed 42
[INPUT] stats min -2.8906 max 3.2969 mean 0.0228 std 1.0078
[INPUT] first 5 values: [-0.80859375, -1.53125, 0.40625, 0.171875, -0.2470703125]
[OUTPUT] shape [1, 96, 99], dtype torch.bfloat16, device cpu
[OUTPUT] latency 547.44 ms (synchronized)
[OUTPUT] stats min -1.7891 max 2.0156 mean -0.0430 std 0.5957
[OUTPUT] median quantile (q50) first 5 horizons: [0.08935546875, -0.00634765625, -0.173828125, -0.15625, -0.029296875]
[OUTPUT] quantile monotonic (first horizon): True
[OUTPUT] first horizon 0-4 quantiles (0%,25%,50%,75%,99% approx): [-0.83984375, -0.212890625, 0.08935546875, 0.443359375, 1.4921875]
[OUTPUT] horizon 0 quantiles 0-2: [-0.83984375, -0.74609375, -0.68359375]
[OUTPUT] horizon 1 median: -0.0063, horizon 95 median: -0.1582
[CPU] latency 547.44 ms, output mean -0.0430

[STEP] NPU inference (npu:0)
[INFO] Model dir: /tmp/yinglong_adapted
[INFO] Loading qcw2333/YingLong_110m with dtype=torch.bfloat16, device=npu:0, trust_remote_code=True
[INFO] Param device: npu:0, dtype: torch.bfloat16
[INPUT] shape [1, 2880], dtype torch.bfloat16, device npu:0, seed 42
[INPUT] stats min -2.8906 max 3.2969 mean 0.0228 std 1.0078
[INPUT] first 5 values: [-0.80859375, -1.53125, 0.40625, 0.171875, -0.2470703125]
[OUTPUT] shape [1, 96, 99], dtype torch.bfloat16, device npu:0
[OUTPUT] latency 218.47 ms (synchronized)
[OUTPUT] stats min -1.7734 max 2.0156 mean -0.0445 std 0.6008
[OUTPUT] median quantile (q50) first 5 horizons: [0.080078125, -0.00634765625, -0.177734375, -0.150390625, -0.0302734375]
[OUTPUT] quantile monotonic (first horizon): True
[OUTPUT] first horizon 0-4 quantiles (0%,25%,50%,75%,99% approx): [-0.85546875, -0.228515625, 0.080078125, 0.439453125, 1.4921875]
[OUTPUT] horizon 0 quantiles 0-2: [-0.85546875, -0.76171875, -0.70703125]
[OUTPUT] horizon 1 median: -0.0063, horizon 95 median: -0.1523
[NPU] latency 218.47 ms, output mean -0.0445
  • 输入: [1,2880] BF16,种子 42,片内 Haar 变换,90 tokens
  • 输出: [1,96,99] BF16,99 分位数,中位数(q50)Horizon 0:NPU 为 0.080,CPU 为 0.089,误差 0.009
  • 分位数单调性: CPU True,NPU True(首个 horizon 的 99 个点严格递增)
  • 设备: 参数设备均为 npu:0,验证通过(next(model.parameters()).device == npu:0)

6. CPU-NPU 一致性验证

  • 方法: 使用同一权重(model.safetensors,BF16)、同一输入(在 CPU 上生成后拷贝至 NPU)、同一预处理(patch 32 + Haar + 归一化)、同一 dtype(bfloat16)、同一 eval 模式,并固定种子 42;分别保存为 *.npy(float32),使用 scripts/compare_outputs.py --task regression --atol 0.2 --rtol 0.02 与自定义 MAE/RMSE 进行对比
  • 指标(BF16,shape [1,96,99]):
    • MAE: 0.008932(<0.15,通过)
    • RMSE: 0.011438
    • MaxAbs: 0.05469(<1.0,通过;阈值 0.2 的脚本对比也通过)
    • MeanRel: 0.024
    • CPU 中位数 h0 为 0.0894,NPU 为 0.0801(差值 0.0093)
    • CPU 中位数 h95 为 -0.1582,NPU 为 -0.1523(差值 0.0059)
    • 单调性: CPU True,NPU True
    • compare_outputs.py 结果为 passed: true(atol 0.2,max_abs 0.031)
  • 结论: 仅为冒烟级一致性(单窗口 1×96 预测),非完整数据集评测;误差源于 BF16 数值累积与 NPU/CPU 算子实现差异,处于阈值内可视为一致
  • 设备: 模型参数设备验证覆盖 cpu 与 npu:0,输入与输出 Tensor 的 device 均为 npu:0(NPU 侧)

7. 性能测试

条件: npu:0、bfloat16、batch=1、context 2880 -> horizon 96、patch 32;调用 torch.npu.synchronize() 计时,预热 3 次,正式执行 10 次

Benchmark NPU: avg 16.09 ms, min 15.8 ms, max 16.5 ms, p50 16.03 ms, p90 16.21 ms, p95 16.4 ms
Throughput: 62.16 windows/s (series/s)
Benchmark CPU: avg 547 ms (单次 547 ms)
首次推理 218 ms (含图编译与 Haar 缓存), 稳定后 16.0 ms, 加速比 ~34x
输入 [1,2880] -> 输出 [1,96,99], dtype bfloat16, 120M 参数, 峰值 HBM ~3.1GB (npu-smi)
设备编译/首轮平均P50P90P95吞吐
NPU (npu:0)218 ms16.09 ms16.0316.21~16.462.2 窗口/s
CPU547 ms547 ms---1.8 窗口/s

预处理(patch + Haar + 归一化)计入模型计时;不包含权重加载时间

8. 自验证截图

  • assets/agent_workflow.png - 本次真实 NPU 适配工作流日志(下载、打补丁、加载、CPU/NPU 推理、一致性检查、基准测试、校验)
  • assets/npu_device_call.png - npu-smi info + torch.npu.is_available() + 设备名称 + 参数 device/dtype + 输入/输出 device 验证
  • assets/model_result.png - python inference.py 完整输出(输入摘要、输出分位数、耗时、PASS)

三张图均基于本次真实日志,通过 scripts/render_xterm_evidence.mjs --style raw 渲染;提示符 atomgit@pod-a94f8701860f4700b161b00e290de466:~$ 仅为展示标签

9. 已知限制

  • 模型依赖 trust_remote_code=True。已针对 NPU 使用纯 PyTorch 重写 SwiGLU / RMSNorm / Rotary,但未启用 flash_attn(NPU 侧禁用,回退至 scaled_dot_product_attention)
  • 输入固定为 [B, T] 形状,T 必须能被 patch_size=32 整除,且 T <= block_size=8224;超长输入需截断
  • 仅验证 bfloat16、batch=1 以及 context 2880 + horizon 96 的单窗口场景,未进行多 batch、多通道、多长度泛化
  • 量化与 KV cache 未验证;int8 / fp8 不在本次适配范围内
  • 首次推理包含编译,约 200 ms;稳定推理约 14.7 ms;不同 NPU 驱动/CANN 版本可能存在 ±2 ms 抖动
  • 数据为随机正态合成序列(seed 42),并非真实业务时序;业务数据需额外校验缩放与逆缩放

10. 标签

NPU Ascend Ascend910 Hardware: NPU time-series forecasting probabilistic quantile bfloat16 YingLong #NPU


由 Ascend910_9362 上真实 NPU 运行的 xterm.js 证据生成,2026-08-21