news 2026/9/18 22:31:17

PyPTO-Gym 模型转换矩阵解读:pypto-convert-model 的三格式 Round-Trip 校验与冻结测试证据

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PyPTO-Gym 模型转换矩阵解读:pypto-convert-model 的三格式 Round-Trip 校验与冻结测试证据

PyPTO-Gym 模型转换矩阵解读:pypto-convert-model 的三格式 Round-Trip 校验与冻结测试证据

【免费下载链接】pypto-gymPyPTO-Gym 是基于 PyPTO 编程框架构建的算子与模型样例仓库项目地址: https://gitcode.com/cann/pypto-gym

本文以 PyPTO-Gym 仓库中pypto-convert-modelskill 自带的转换证据文件 matrix.md 为主体,逐列解读这张"模型 × 目标格式"校验矩阵:它由谁生成、七种状态码如何定义、测试设备如何自动检测、11 个被测模型从哪里来、每个格子结果背后的真实含义是什么,以及如何在本地复现并刷新这张矩阵。读完后你可以独立读懂该仓库任何一次批量转换的 PASS/FAIL 证据,并按同样的流程接入自己的模型。

1. matrix.md 是什么:一次批量转换实验的冻结证据

pypto-convert-model是一个在onnx ↔ pt (TorchScript) ↔ safetensors三种格式之间双向互转的工具链,核心承诺是:每转换一次,就把产物重新加载,用同一个 dummy input 各跑一次 forward,再与源模型输出比对,以max_abs差异作为首要判据。详见 SKILL.md。

matrix.md 就是这条工具链批量实验(run.py)跑完后提交进仓库的聚合结果表,属于"冻结测试证据":它记录的是某一次真实运行环境下、11 个注册模型 × 3 个目标格式的全部结论。文件开头一行记录了当时的测试设备:

Test device (auto-detected):npu

即该次实验运行在 Ascend NPU 环境上(设备自动检测机制见第 3 节)。

2. 矩阵本体:完整表格与状态码图例

以下是该文件的完整内容(逐行继承原文档):

modelonnxptsafetensors
resnet18L-FAILL-FAILL-FAIL
mobilenet_v2L-FAILL-FAILL-FAIL
efficientnet_b0L-FAILL-FAILL-FAIL
mlp_mixerL-FAILL-FAILL-FAIL
gmlpL-FAILL-FAILL-FAIL
resmlpL-FAILL-FAILL-FAIL
switch_base_8L-FAILL-FAILL-FAIL
qwen_moeL-FAILL-FAILL-FAIL
toy_moeC-FAILOK
max_abs=0.00e+00
OK
max_abs=0.00e+00
toy_soft_moeC-FAILOK
max_abs=0.00e+00
OK
max_abs=0.00e+00
toy_switch_moeC-FAILOK
max_abs=0.00e+00
OK
max_abs=0.00e+00

图例(原文逐字继承):

Legend: OK=pass, DIFF=converted but output differs, SKIP=not applicable, C-FAIL=convert failed, T-FAIL=test failed, T-SKIP=test skipped, L-FAIL=load failed.

这 7 种状态码不是随手定的,它们与 run.py 中的STATUS_EMOJI映射一一对应——矩阵格子里显示的是短标签,内部记录的是全名:

矩阵显示内部 status含义
OKPASS转换成功且 round-trip 比对通过(allclose)
DIFFDIFF转换成功,但输出差异超出容差
SKIPSKIP不适用(转换器抛出 NotImplementedError)
C-FAILCONVERT_FAIL转换阶段本身失败
T-FAILTEST_FAIL转换成功,但产物复测阶段失败
T-SKIPTEST_SKIP复测被跳过
L-FAILLOAD_FAIL源模型加载失败(还没走到转换)

矩阵的写盘逻辑在 run.py 的 write_matrix():行顺序取自注册表REGISTRY的插入顺序,列固定为TARGET_FORMATS = ["onnx", "pt", "safetensors"](见 registry.py);当某格带 diff 数据时,会在标签后追加<br/>max_abs=...(格式化为两位有效数字的科学计数法)。每跑完一个模型就会立即重写一次矩阵文件,因此矩阵天然支持"部分进度累积"——main() 启动时还会先读回references/results/*.json里的历史结果合并进来。

3. "Test device: npu" 是怎么来的:设备自动检测

矩阵首行的设备标签由pick_device()在运行启动时确定。device_util.py 的检测优先级为NPU > CUDA/ROCm > XPU > MPS > CPU:NPU 通过torch.npu.is_available()(或尝试导入torch_npu)判定,结果会缓存进模块级变量_CACHED,整个进程内只检测一次。

两个细节值得注意:

  • 强制覆盖:环境变量CONVERT_EXP_DEVICE=npu|cuda|xpu|mps|cpu可覆盖自动检测;若指定的设备不可用会直接抛错并列出可用设备,而不是静默回退。
  • ORT 执行器独立选择:ONNX 产物复测走 onnxruntime,onnxruntime_providers() 按Tensorrt → CUDA → ROCm/MIGraphX → CANN(Ascend NPU) → QNN → Dml → CoreML → OpenVINO → Xnnpack → CPU的优先级,从本机已安装的 provider 中挑选。也就是说,即使 PyTorch 侧跑在 NPU 上,ONNX 侧实际用哪个执行器取决于 ORT 的构建形态。

比对阶段对设备同样敏感:compare.py 的 reference_output() 会把模型临时搬上加速器算参考输出,再恢复回 CPU——因为后续 ONNX/TorchScript 导出假定模型在 CPU 上;若加速器 OOM(统一内存主机上常见),则自动回退 CPU 继续跑,保证转换流程不因显存中断。

4. 矩阵里的 11 个模型:注册表与加载器

矩阵每一行对应 registry.py 中REGISTRY的一个条目,共 11 个模型、3 个类别(cnn / mlp / moe):

类别模型来源仓库 id加载器输入
cnnresnet18HFmicrosoft/resnet-18image-classification图像 (1,3,224,224)
cnnmobilenet_v2HFgoogle/mobilenet_v2_1.0_224image-classification图像 (1,3,224,224)
cnnefficientnet_b0timmtimm/efficientnet_b0.ra_in1ktimm图像 (1,3,224,224)
mlpmlp_mixertimmtimm/mixer_b16_224.goog_in21k_ft_in1ktimm图像 (1,3,224,224)
mlpgmlptimmtimm/gmlp_s16_224.ra3_in1ktimm图像 (1,3,224,224)
mlpresmlptimmtimm/resmlp_12_224.fb_in1ktimm图像 (1,3,224,224)
moeswitch_base_8HFgoogle/switch-base-8seq2seq-lm文本 prompt
moeqwen_moeHFQwen/Qwen1.5-MoE-A2.7Bcausal-lm文本 prompt(size_warning_gb: 14
moetoy_moe / toy_soft_moe / toy_switch_moetoy(本地)本地构建toy张量 (2,64)

加载器由 loaders.py 的 load() 分发,统一返回(model, sample_input, meta)三元组:

  • image-classification / seq2seq-lm / causal-lm:走transformers自动类加载,并用TensorOutputAdapter_CausalLogits这类薄包装把 HF 的 dataclass 输出剥成裸 logits、把输入固定成位置参数签名,保证三种格式走同一条导出路径;
  • timmtimm.create_model(name, pretrained=True)
  • causal-lm默认以fp16 +low_cpu_mem_usage=True加载(可用CONVERT_EXP_DTYPE覆盖为 float16/bfloat16/float32),这是针对统一内存主机上 14B+ 模型 fp32 加载爆 RAM 的对策;
  • toy:不下载任何东西,直接实例化 toy_moe.py 里三个用随机权重的小型 MoE 分类器:TopKMoE(top-k=2 门控)、SoftMoE(所有专家全加权)、SwitchMoE(top-1 门控)。build_toy()固定torch.manual_seed(42),输入为torch.randn(2, 64)——权重与输入完全确定性,这正是第 5 节零差异结果的关键。

注册表还提供了by_category()辅助函数,qwen_moe条目带size_warning_gb: 14,提醒 7B+ 量级 LLM 下载前需要向用户确认磁盘与时间成本。

5. 逐行解读本矩阵:L-FAIL、C-FAIL 与零差异 OK

8 个 HF/timm 模型整行 L-FAIL。从源码结构看,这对应 process_model() 中的加载分支:源模型加载(load(),对 HF/timm 模型意味着从远端下载权重并实例化)抛异常后,三个目标格式会被统一标记为LOAD_FAIL并直接返回,因此这些行连转换都未开始。值得注意的是该分支不会写每模型明细 JSON(JSON 落盘在 L169-L170 的格式循环之后),这与仓库references/results/目录下只提交了 3 个 toy 模型 JSON 的事实完全吻合。从源码结构看,加载阶段的常见诱因是网络下载失败或依赖缺失,但该文件本身未记录具体错误信息,此处不做断言。

3 个 toy 模型的 onnx 列为 C-FAIL。明细 toy_moe.json 给出了确切原因:

"onnx": { "status": "CONVERT_FAIL", "error": "OnnxExporterError('Module onnx is not installed!')" }

即冻结这份证据的运行时没有安装onnx包——这是环境缺包问题,而不是 ONNX 导出逻辑本身的缺陷;pt 与 safetensors 两条路径不依赖 onnx 模块,所以正常通过。

toy 模型的 pt / safetensors 列为OKmax_abs=0.00e+00明细 JSON 同时给出了耗时与产物体积:pt 转换 0.35 s、产物 0.3 MB;safetensors 转换 0.0 s、产物 0.27 MB,两者diff均为max_abs=0.0, mean_abs=0.0, max_rel=0.0, allclose=true。零差异的成因是双重的:build_toy()固定随机种子使源模型确定,而 pt(TorchScript)与 safetensors 的 round-trip 本质是权重的精确往返,同一份权重在同一设备上 forward 结果逐位一致。

对比判据本身由 compare.py 的 diff() 定义:两端输出展平后以 float64 计算逐元素绝对/相对误差,非有限值(且非同符号无穷)计为 invalid 并强制allclose=false;返回max_abs / mean_abs / max_rel / p50 / p95 / p99 / top_mismatch(前 5 个最大误差索引) / allclose等字段,判定阈值默认atol=1e-4, rtol=1e-3。SKILL.md 同时给出了实践预期:在 opset 差异、动态轴、dtype 转换下,1e-4 ~ 1e-3 量级的漂移属正常,应把矩阵中的max_abs作为第一信任信号;CUDA 上由于 cudnn 重复 forward 有约 5e-4 噪声,port.py会把容差放宽到atol=5e-3(CPU 校验仍用atol=1e-4)。

6. 复现与刷新矩阵:环境、命令与产物布局

6.1 环境检查

python -c "import torch, onnx, onnxruntime, safetensors, onnx2torch; print('ok')"

依赖来自 requirements.txt,按 SKILL.md 的划分:

用途依赖
必装torch>=2.5, transformers>=4.46, onnx, onnxruntime, safetensors
onnx -> pt / safetensorsonnx2torch
safetensors I/Otimm 或 transformers(用于实例化 HF 仓库的架构)

6.2 批量实验(生成/刷新矩阵)

# registry 中全部 11 个模型 python scripts/run.py # 只跑子集 python scripts/run.py mobilenet_v2 toy_moe

注意路径约定:run.py/port.py需以 scripts/ 目录为工作目录执行(脚本内用Path(__file__).resolve().parent.parent定位 skill 根目录)。

6.3 单模型转换(port.py)

# pt -> onnx(TorchScript 自包含,只需 --input-shape) python scripts/port.py model.pt out.onnx --input-shape 1,3,224,224 # safetensors -> onnx(仅权重;架构经 HF repo 提供) python scripts/port.py model.safetensors out.onnx \ --hf-repo google/mobilenet_v2_1.0_224 # onnx -> pt(经 onnx2torch 重建计算图) python scripts/port.py model.onnx out.pt --input-shape 1,3,224,224

常用选项:--input-format/--output-format覆盖扩展名推断;--hf-repo为 safetensors 端提供架构;--skip-verify关闭 round-trip 校验(超大模型);-v输出各阶段计时、两端 forward 的 min/max/mean/std/first5 统计、diff 分布(p50/p95/p99)与 top-5 mismatch 索引。退出码语义:0PASS、1DIFF(转出但差异超容差)、2转换失败。

6.4 产物布局

  • 冻结证据(提交进仓库)references/matrix.md(聚合表)+references/results/<model>.json(每模型明细,含 convert_seconds、artifact 路径、size_mb、diff)。
  • 运行时产物(gitignore):默认位于~/.cache/pypto-convert-model/,可用$CONVERT_MODEL_WORKDIR覆盖,内含models/(HF/timm 下载缓存)、outputs/<model>/<fmt>/(转换产物)、logs/master.log+logs/<model>__<format>.log(运行日志)。

6.5 已知限制与新增模型

解读矩阵前应了解 SKILL.md 记录的四条限制:transformers>=5的 attention 路径回归会导致 transformer-MoE(Switch-T、Qwen-MoE)的 onnx/pt 导出失败(safetensors 权重路径始终可用,绕过办法是降级transformers<5或只走 safetensors);CUDA fp32 非确定性噪声;aarch64 无onnxruntime-gpu轮子导致 ORT 回退 CPU;统一内存主机的 RAM 压力(已由 fp16 默认加载缓解)。

新增模型的固定动作:在 registry.py 增加条目(CNN 用image-classificationtimm加载器,transformer LM 用causal-lm/seq2seq-lm,自定义架构用toy类别并按 toy_moe.py 的写法定义模块),然后重新运行run.py刷新矩阵。转换逻辑一律复用 converters.py 中注册到CONVERTERS字典的函数,不要另起炉灶。

7. 小结

matrix.md 不是一张静态结果表,而是registry → load → convert → round-trip test → write_matrix整条流水线的可审计终点:8 行 L-FAIL 说明那次实验的远端加载未成功,3 行 toy 证据则以max_abs=0.00e+00证明了 pt/safetensors 往返的位级一致性,onnx 列的 C-FAIL 则精确定位到运行环境缺onnx包。当你拿到一份新的矩阵时,按"先看设备行、再按状态码分层排查(L-FAIL 查加载与网络、C-FAIL 查转换依赖、T-FAIL 查产物加载、DIFF 查 max_abs 与 opset/dtype)、最后对照results/<model>.json取明细"的顺序阅读,就能快速定位问题所在阶段。

【免费下载链接】pypto-gymPyPTO-Gym 是基于 PyPTO 编程框架构建的算子与模型样例仓库项目地址: https://gitcode.com/cann/pypto-gym

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 22:28:25

Axmol RHI升级:GPU Compute如何重塑2D引擎粒子与渲染管线

1. 这次升级到底解决什么问题&#xff1a;先看清 RHI 的能力边界1.1 老 RHI 只管"画"&#xff0c;不管"算"三个月前&#xff0c;我在一个用 Axmol 引擎做的 2D 项目里碰了一鼻子灰&#xff1a;粒子数量上到八千之后&#xff0c;帧时间平白多出三四毫秒&…

作者头像 李华
网站建设 2026/9/18 22:28:23

基于FPGA的曼彻斯特编码器设计:VHDL实现与QUARTUS II验证

简介&#xff1a;这份毕业设计文档面向电子信息工程、通信工程等专业的本科生与FPGA初学者&#xff0c;围绕基于FPGA的曼彻斯特编码器设计展开&#xff0c;可用于课程设计参考、毕设选题借鉴或数字通信编码的学习。文档完整呈现了课题背景与意义、曼彻斯特编码理论与方法、M序列…

作者头像 李华
网站建设 2026/9/18 22:26:05

MATLAB入门:命令行、脚本与函数运行机制解析

简介&#xff1a;这份MATLAB基础入门PPT教程共六十九页&#xff0c;面向零基础或刚接触MATLAB的学员&#xff0c;系统讲解基本操作与重要系统命令。教程从桌面快捷方式讲起&#xff0c;涵盖命令窗口、历史指令窗口、工作空间浏览器、当前目录浏览器、内存数组编辑器、M文件编辑…

作者头像 李华
网站建设 2026/9/18 22:24:11

使用 dlt 将 Langfuse 可观测性数据导出到数据湖仓

使用 dlt 将 Langfuse 可观测性数据导出到数据湖仓 【免费下载链接】dlt data load tool (dlt) is an open source Python library that makes data loading easy &#x1f6e0;️ 项目地址: https://gitcode.com/GitHub_Trending/dl/dlt 导读 Langfuse 是开源的 LLM …

作者头像 李华