r
redannancy/YingLong_110m
模型介绍
文件和版本
Pull Requests
讨论
分析

YingLong_110m 昇腾推理仓库

快速上手

如果你只是想尽快把模型跑起来看个效果,照下面三步走:

pip install -r requirements.txt

# 起一个服务,默认 8001 端口
python inference.py --serve

# 另开一个终端,POST 一段序列过去,马上就能拿到预测
curl -X POST http://127.0.0.1:8001/v1/forecast \
  -H "Content-Type: application/json" \
  -d '{"input":[0.5,0.52,0.51,0.55,0.58,0.6,0.62,0.61,0.64,0.66],"horizon":32}'

大概十几毫秒后,接口就会回给你未来 32 个时刻的预测,每个时刻带 99 个分位点。就这么简单。

简介

这个模型是通义实验室开源的 YingLong(应龙)时序基础模型家族里的 110M 版本。它不是那种"你说一句话它回一句话"的大语言模型,而是专门吃连续数值序列、往外预测的模型——比如温度曲线、能耗序列、股票价格这类带时间先后关系的数据。

模型本身约 1.2 亿参数,权重是 BF16 的 safetensors,整套文件加起来大概 240MB。结构上走的是 GPT 那一套:先把序列切块(每 32 个点一块),做一次 Haar 小波变换再映射进向量空间,中间过 12 层自注意力,最后一口气吐出未来若干时刻的分位数分布。输出 99 个分位数意味着它给的不只是一个"点",而是一整条概率带,业务上可以拿来做区间预测。

精度测评

先说大家最关心的:预测准不准。我在本地用正弦波做了两组外推实验,拿中位数(50% 分位)当点预测去和真实值比:

测试输入预测步MAERMSE
干净正弦512640.16770.1953
带噪声正弦512320.29490.3505

干净信号下中位数预测能贴着真实曲线走,前几步误差基本在 0.1~0.2 之间;把 5% 的噪声加进去之后误差变大一些,这也符合直觉——输入越脏,越难预测准。另外检查了分位数的自洽性,99 个分位点整体是单调递增的,只有少量边界位置因为 BF16 舍入出现 ±1 个最小单位的抖动,属于正常现象,不影响使用。

验证环境

我是跑在昇腾 Atlas 800 上的,具体环境如下:

  • 昇腾芯片:Ascend910_9362,机器上一共两张卡,推理默认用第 1 张(npu:1)
  • CANN:8.5.1 版本,npu-smi 显示 25.5.5
  • 系统:openEuler,aarch64 架构
  • Python 3.11.14,PyTorch 2.9.0,配套 torch_npu 2.9.0.post1
  • 服务用的是 FastAPI + uvicorn

服务启动

依赖装好之后,一条命令起服务:

python inference.py --model-dir /你的/权重/路径 --serve --port 8001

权重目录就是放 config.json 和 model.safetensors 的那个文件夹。--port 可以按需改,但注意别和机器上其他服务撞了。

如果不想起服务,也可以直接命令行跑单次预测:

python inference.py --input "0.5,0.6,0.7,0.8" --horizon 32 --json

Smoke 验证

服务起来之后,两个接口够用了:

  • GET /health:确认服务还活着。会返回 {"status":"ok","model":"YingLong_110m","device":"npu:1",...}。
  • POST /v1/forecast:真正干活的接口,传 {"input":[序列],"horizon":步数}。

我自己验证过一轮:起服务 → curl 健康检查 → 发一次 512 点的请求 → 拿到 64 步 × 99 分位的结果,整个流程没有报错,返回的 JSON 里 steps 和 horizon 对得上,point_forecast 是 64 个数的中位数序列,看着是合理的趋势外推。

性能参考

实测的数据(输入 512、输出 64 步、单张卡):

  • 单次请求稳定在 14ms 左右,压了 25 次平均 14.4ms,波动很小;
  • 持续压测吞吐约 21.7 请求/秒;
  • 第一次请求会慢一点,大概 300ms,因为要编译算子图,后面就快了;
  • 跑起来之后 NPU 显存占 484MB,卡上 HBM 从 2870MB 涨到 3299MB;
  • AICore 利用率在 3%~7% 之间浮动。模型本身小,这个占用水平很正常,别指望它把卡吃满。

注意事项

  1. 输入别太短,少于 64 个点会直接报错;长度不需要是 32 的倍数,脚本会自动补齐。
  2. 注意选卡。机器上可能同时跑着别人的任务,起服务前先 npu-smi info 看看哪张卡空闲,用 --device npu:0 或 npu:1 指定,别把别人的进程挤掉。
  3. 第一次调用慢是正常的,那是图编译的一次性开销,不要误以为服务卡死了。
  4. 不要拿 vLLM 去硬加载这个模型。它不在 vLLM 的支持列表里,而且输出是连续数值不是 token,直接 serve 会报 "architectures ['YingLong'] are not supported"。本仓库这套方案是验证过的。
  5. 模型权重是 BF16 的,个别分位数边界有极小舍入抖动,做业务判断时一般不用管。

适配过程中做了什么

最麻烦的是官方原版代码里引了 xformers、flash-attn、dropout_layer_norm、rotary_emb 这几个东西,全是 CUDA 专用内核,昇腾上根本没有。我把它们逐个改成了纯 PyTorch 写法:SwiGLU 用三个线性层自己拼,RMSNorm 直接手写归一化公式,旋转位置编码也用纯张量运算重写。改完之后的权重和官方参数名一一对应,能原样加载不丢一个张量。整个适配和验证的日志、踩坑记录都整理在 assets/ 目录下。


数据与论文来源:阿里巴巴通义实验室 YingLong(arXiv:2506.11029),权重许可证 CC-BY-4.0。