- 具身智能
- 机器人
- 人工智能
- 大模型
- 模型推理服务
- 本地部署
- 计算机视觉
- ROS
【免费下载链接】IB_Robot
Save the code of IB-Robot, an AI robot execution framework developed by openEuler Embedded for embodied intelligence scenarios. It includes references to the forked version of tensormsg, references to lerobot fork, code references to the lerobot_ros2:ros2_ws branch, as well as some code related to development usability.
本指南面向 IB_Robot(openEuler Embedded 面向具身智能场景的 AI 机器人执行框架)中「LeRobot 策略模型 → Ascend OM 转换」的精度验证环节,讲解一套可跨机器复现、可审计、可交接的多主机精度对齐方法。核心思路是:Torch 目标生成、ONNX/OM 转换与昇腾部署可能发生在三台不同的机器上,因此必须用一份「不可变的规范化验证包」把基线输入、权威动作目标与随机噪声固定下来,再通过哈希校验保证每一次 Torch-vs-OM 对比都基于完全相同的输入。读完本文,你将掌握hosts.json拓扑记录、validation-inputs验证包封包、loss_compare.py目标生成与计算损失、SHA256SUMS 校验、跨主机传输与交接报告的一整套可落地流程,并理解 IB_Robot 仓库中相关源码的设计意图。
本文的主体是仓库中.agents/skills/om-convert/references/multi-host-validation.md(IB_Robot 统一的 Ascend OM 转换入口om-convert的内部参考文档),源码与测试仅用于佐证和深化。所有命令均以仓库当前实现为准。
一、适用场景与三条核心原则
在 IB_Robot 的 Ascend OM 转换链路(统一入口见 .agents/skills/om-convert/SKILL.md)中,一条完整链路包含三个角色:
| 角色 | 职责 |
|---|---|
| Torch 主机 | 运行原始 LeRobot/Torch 部署,生成权威动作目标(target)与持久化噪声 |
| 转换主机 | 执行 ONNX 导出与 ATC 编译,产出 OM 候选 |
| Ascend 主机 | 加载 OM 部署,对同一批观测计算损失,与 Torch 目标对比 |
多主机精度工作流建立在三条硬性原则上:
- 绝不假设路径或环境是共享的。Torch 目标生成、转换、昇腾部署可能运行在不同的机器上,同一绝对路径在另一台机器上可能不存在,
install/setup.sh、venv、CANN 环境也各不相同。 - 每个固定参考契约只生成一次权威目标。所有 ONNX、OM、编译器和语义保持型优化候选都必须与同一份目标包对比;导出器修复、宿主预处理变体、dtype 实验、ONNX/OM 候选、优化阶段都不允许生成新的
target.json包。 - 每一次跨主机对比前都必须验证输入一致性。观测、目标、raw 目标、噪声必须来自同一权威包目录,并校验其记录在案的哈希值。
关于远程执行:仅询问一次是否允许远程执行;复用用户已有的 SSH 配置,绝不索取密码、私钥、访问令牌或密钥文件内容。如果直接传输不可用,给出精确命令并在明确的交接点停下。许多实验室主机禁用了密码认证,跨主机运行前应先在控制机上准备好基于密钥的访问:
ssh-copy-id "RESOLVED_USER@RESOLVED_HOST" ssh -o BatchMode=yes "RESOLVED_USER@RESOLVED_HOST" true若策略禁止ssh-copy-id,请用户改用组织批准的密钥提供方式。不得修改sshd_config或启用密码认证。
二、拓扑记录:reports/hosts.json
在动手之前,先创建不含任何机密信息的reports/hosts.json,把三台主机的关键信息固化下来:
{ "torch": { "location": "local-or-user@ip", "workspace": "/absolute/IB_Robot", "bundle": "/absolute/policy", "deployment": "torch-device", "device": "cpu|cuda|npu" }, "conversion": { "location": "local-or-user@ip", "workspace": "/absolute/IB_Robot", "bundle": "/absolute/policy", "experiment": "/absolute/experiment" }, "ascend": { "location": "local-or-user@ip", "workspace": "/absolute/IB_Robot", "bundle": "/absolute/policy", "deployment": "ascend-name", "device_id": 0 } }字段语义要点:
location:本机写local,远程写user@ip;workspace:每台机器上 IB_Robot 仓库的绝对路径;bundle:策略 bundle 的绝对路径(需含config.json、model.safetensors、policy_preprocessor.json、policy_postprocessor.json);deployment:bundle 内inference_manifest.json中的命名部署;device:Torch 侧的cpu|cuda|npu;Ascend 侧用device_id指定 ACL 设备号。
这与om-convert前置信息采集(.agents/skills/om-convert/SKILL.md 的 Upfront Intake 一节)一一对应:Torch 主机、转换主机、Ascend 主机各自的 SSH 目标、IB_Robot 路径、bundle 路径、部署名与设备都必须显式采集。若三个角色都在同一台机器上,只问一次并记录"拓扑共享",但主机的路径仍然相互独立,绝不假定同一绝对路径在两台机器上都存在。
三、规范化验证包:唯一权威的对比输入
跨主机精度验证只认一份「规范化验证包」——一组不可变的对比输入。目录结构如下:
validation-inputs/ ├── observations.safetensors ├── target.json ├── target_raw.json ├── noises/ ├── validation.json └── SHA256SUMS其中:
observations.safetensors:带版本号的观测批次(Safetensors 格式);target.json:Torch 部署生成的动作目标(反归一化/物理空间);target_raw.json:归一化(pre-postprocessor)空间的原始动作目标;noises/:为随机策略持久化的逐样本控制噪声;validation.json:记录参考契约全部关键元数据;SHA256SUMS:除自身外所有文件的 SHA-256 校验和清单。
validation.json记录的内容包括:策略类型(policy type)、源 bundle、Torch 部署、观测来源(provenance)、任务(task)、随机种子(seed)、样本数、目标生成命令、IB-Robot 修订号(SHA)与 LeRobot 修订号(SHA)。哈希应在目标生成后立即计算,并在每次传输后重新校验。
这份验证包是其记录的参考契约下唯一权威的动作目标包。导出器修复、宿主预处理变体、dtype 实验、ONNX/OM 候选、优化阶段的产物只能存到reports/或候选目录,命名如candidate_output.json、metrics.json、stage_reference/,绝不能作为另一个可消费的target.json包。
如果仓库里已存在多个历史 target 目录,不要按名字或时间新旧来选:应根据 manifest 与哈希识别权威包,并通过重跑被接受的基线产物、复现其记录的指标来证明其权威性;其余目录标记为历史诊断快照(记入实验台账),严禁跨包混用文件。
四、观测批次:优先真实本地 LeRobot 数据集
4.1 生成与检查命令
优先使用真实本地 LeRobot 数据集生成观测批次。在 IB_Robot 工作区中执行(.shrc_local负责加载 ROS 2 Humble、venv、libs/lerobot/src的 PYTHONPATH 以及已安装的 CANN 环境,见 .shrc_local):
source .shrc_local source install/setup.sh ros2 run model_utils observation-batch dataset \ --dataset-root "RESOLVED_DATASET_ROOT" \ --policy-path "RESOLVED_TORCH_BUNDLE" \ --output "RESOLVED_INPUT_DIR/observations.safetensors" \ --samples "RESOLVED_SAMPLE_COUNT" \ --sampling episode-stratified \ --seed "RESOLVED_SEED"检查生成结果:
ros2 run model_utils observation-batch inspect \ "RESOLVED_INPUT_DIR/observations.safetensors"已经存在且带版本号的批次同样有效。仅当用户完全没有数据时,才允许用确定性随机观测做 smoke 转换,且结果必须标注为非代表性;随机观测永远不能作为校准输入。
4.2 源码级实现佐证
observation-batch命令的实现位于 src/model_utils/model_utils/observation_batch_cli.py,底层由 src/model_utils/model_utils/observation_batch.py 支撑。从源码可以确认:
- 格式规范:Safetensors 文件携带
__ibrobot.format=ibrobot-observation-batch与__ibrobot.schema_version=1元数据,加载时严格校验格式与版本(load_observation_batch); - 采样策略:CLI 支持
episode-stratified、global-random、global-uniform三种策略,默认episode-stratified(按 episode 分层,见select_dataset_indices);--samples必须落在[1, 数据集帧数]区间; - 字段约束:策略 bundle 的
config.json中input_features定义字段形状与类型,VISUAL特征强制为图像语义(CHW 布局),数字字段必须显式声明 FieldSpec(NAME=SHAPE,DTYPE,MIN,MAX[,SEMANTIC,LAYOUT]); - 任务文本编码:字符串型
task字段被编码为task-index张量 + 字符串表,供 VLA 策略的语言条件推理使用; - 来源追踪:批次元数据记录
source/root/policy_path/repo_id/sampling_strategy/seed/selected_indices/video_backend,且带dataset_index/episode_index/frame_index逐样本溯源张量; - 原子写入:
save_observation_batch通过临时文件 +os.replace原子落盘,且默认拒绝覆盖已存在文件(--force除外)。
loss_compare.py加载观测时还会做关键预处理:图像从 HWC 转 NCHW 并归一化到[0,1](若最大值 >1 则除以 255,见_prepare_image),并把task作为自然语言提示透传给 VLA 预处理器(src/model_utils/model_utils/loss_compare.py)。
五、Torch 目标生成
5.1 前置条件
在 Torch 主机上,首先要证明 IB-Robot 能加载并执行原始 Torch 部署,然后才运行目标生成。目标生成使用loss_compare.py的--generate-target模式,该模式只应运行一次(除非用户明确批准替换基线,否则不要加--force)。
5.2 生成命令
source .shrc_local source install/setup.sh python3 src/model_utils/model_utils/loss_compare.py \ --policy_path "RESOLVED_TORCH_BUNDLE" \ --deployment "RESOLVED_TORCH_DEPLOYMENT" \ --batch_path "RESOLVED_INPUT_DIR/observations.safetensors" \ --task "RESOLVED_TASK" \ --seed "RESOLVED_SEED" \ --exp-dir "RESOLVED_INPUT_DIR" \ --generate-target要点:
- 使用新的实验目录:
--exp-dir会自动派生三条长路径——target.json、target_raw.json、noises/(见 src/model_utils/model_utils/loss_compare_cli.py 的apply_exp_dir_derivation); - 覆盖保护:
generate-target模式下,若目标文件已存在或noises/非空,CLI 会拒绝覆盖并要求换新目录或显式加--force(check_overwrite_guard); - 噪声必须持久化:对随机策略,目标生成必须持久化
noises/;缺失噪声在跨机对比中属于硬失败; - 任务与种子必须与后续计算损失完全一致;
- 每个参考契约版本只生成一次目标。封包后,所有后续诊断与优化候选都复用同一份目标;候选失败不得触发重新生成目标。
5.3 噪声自检与确定性证明(源码级)
对随机策略,--generate-target在写出任何目标前会先执行噪声自检_assert_noise_effective(src/model_utils/model_utils/loss_compare.py),对批次 0 做 3 次前向:
- A1、A2 使用
noise=zeros,B 使用noise=3*ones; - 确定性检查:A1 ≈ A2(否则说明存在 RNG 泄漏或 dropout 未关闭,拒绝生成不可复现目标);
- 有效性检查:A1 ≠ B(否则说明噪声被忽略,终止并报告)。
该自检把「manifest 噪声绑定缺失或被忽略」这类问题在写出坏目标之前变成硬失败。loss_compare的统一推理管线通过PureInferenceEngine.control_inputs把噪声绑定到选定的 PI05 codec,并捕获 pre-postprocessor 的raw_action(capture_raw_action=True),从而同时产出target.json(物理空间)与target_raw.json(归一化空间)。
从源码结构可以推断,这套流程面向 PI0、PI05、SmolVLA、Diffusion Policy 以及任何生产推理接受随机噪声或随机控制输入的新策略。但需要注意一个明确的边界:当前loss_compare只为 PI05 实现了持久化噪声(_resolve_noise与_pi05_noise_shape均以policy_type == "pi05"为前置条件,噪声形状(1, chunk_size, max_action_dim)从引擎声明的nominal_chunk_size与max_action_dimension推导)。在验证其他随机家族之前,必须为其扩展 codec/运行时与对比工具(家族特定的控制输入生成、版本化存储、回放、形状/dtype 校验与有效性测试)。不要假设仅靠--seed就能复现某个后端内部随机状态。
相关测试覆盖在 src/model_utils/test/test_loss_compare.py:包括噪声确定性、generate-target必须持久化噪声(RuntimeError匹配noise-dir)、噪声自检 3 次 reset、target.json/target_raw.json同时写出等。
六、封包:写入validation.json与计算 SHA256SUMS
6.1 生成validation.json
目标生成完成后,用解析后的真实值生成validation.json(用排序 JSON 保证记录稳定;所有占位符必须先替换再执行,数值保持数值类型):
python3 - "RESOLVED_INPUT_DIR/validation.json" "RESOLVED_SEED" "RESOLVED_SAMPLE_COUNT" <<'PY' import json import sys from pathlib import Path payload = { "format": "ibrobot-om-validation-v1", "policy_type": "RESOLVED_POLICY_TYPE", "source_bundle": "RESOLVED_TORCH_BUNDLE", "torch_deployment": "RESOLVED_TORCH_DEPLOYMENT", "observation_batch": "observations.safetensors", "observation_provenance": "RESOLVED_PROVENANCE", "task": "RESOLVED_TASK", "seed": int(sys.argv[2]), "sample_count": int(sys.argv[3]), "generation_command": "RESOLVED_GENERATION_COMMAND", "ibrobot_revision": "RESOLVED_IBROBOT_SHA", "lerobot_revision": "RESOLVED_LEROBOT_SHA", } Path(sys.argv[1]).write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8") PY6.2 计算校验和清单
然后对包内除校验和清单本身外的每个文件计算 SHA-256:
python3 - "RESOLVED_INPUT_DIR" <<'PY' import hashlib import sys from pathlib import Path root = Path(sys.argv[1]).resolve(strict=True) files = sorted(path for path in root.rglob("*") if path.is_file() and path.name != "SHA256SUMS") lines = [] for path in files: digest = hashlib.sha256(path.read_bytes()).hexdigest() lines.append(f"{digest} {path.relative_to(root)}") (root / "SHA256SUMS").write_text("\n".join(lines) + "\n", encoding="utf-8") PY这两段脚本分别对应文档规定的「目标生成后计算哈希、每次传输后验证哈希」纪律。封包完成即视为「seal」:此后所有诊断与优化候选复用此包,任何候选不得触发目标重生成。
七、跨主机传输:整体搬运,逐项校验
7.1 传输命令
传输的是完整验证包,而不是选中的若干文件。示例(使用已批准的 SSH 目标):
rsync -a --checksum "RESOLVED_INPUT_DIR/" \ "RESOLVED_ASCEND_SSH:RESOLVED_ASCEND_INPUT_DIR/"要点:
- 路径必须加引号;
- 在目标机验证
SHA256SUMS; - 若
rsync不可用,改用scp -r并单独校验哈希; - 绝不允许在另一台主机上静默重新生成观测、目标、raw 目标或噪声。
7.2 校验命令
可用系统自带的:
sha256sum -c SHA256SUMS若系统没有sha256sum,用解析每个 digest 与相对路径的 Python 等价实现。校验清单不得包含SHA256SUMS自身。
7.3 可部署 bundle 的单独传输
可部署 bundle(或托管生成产物)需要单独传输,并保留inference_manifest.json、其引用的全部构件、processor 资产以及相对路径。bundle 的加载契约见 inference_manifest 模块 与 loss_compare_cli.py 中--policy_path的说明("bundle 目录必须包含config.json与inference_manifest.json")。PI05 转换的产物布局为<policy-path>/artifacts/ascend/<deployment>/...(见 .agents/skills/om-convert/references/pi05.md)。
八、Ascend 计算损失:Torch-vs-OM 对齐
8.1 计算命令
在 Ascend 主机上使用传输过来的包(注意此时不带--generate-target):
source .shrc_local source install/setup.sh python3 src/model_utils/model_utils/loss_compare.py \ --policy_path "RESOLVED_ASCEND_BUNDLE" \ --deployment "RESOLVED_ASCEND_DEPLOYMENT" \ --batch_path "RESOLVED_ASCEND_INPUT_DIR/observations.safetensors" \ --task "RESOLVED_TASK" \ --seed "RESOLVED_SEED" \ --exp-dir "RESOLVED_ASCEND_INPUT_DIR" \ --metrics-json "RESOLVED_REPORT_DIR/torch-vs-om.json"硬性约束:
- 严禁对被测 Ascend 部署使用
--generate-target——目标只能来自原始 Torch 部署; --task与--seed必须与目标生成时完全一致;- 执行前必须确认
--batch_path、--exp-dir,以及任何显式的 target、raw-target、noise 路径,全部解析到同一个传输包目录;严禁从不同目录里按相似文件名手动拼装对比。
8.2 指标输出(源码级)
loss_compare.py的compute_loss(src/model_utils/model_utils/loss_compare.py)对每个样本计算:
- unnormalized(物理空间):L1 loss 与余弦相似度,并按批次打印汇总表与
Avg; - normalized(pre-postprocessor 空间):若存在 raw 预测与
target_raw.json,额外比较归一化空间的 L1 与余弦,用于隔离「真实模型漂移」与「反归一化放大」; - batch 0 诊断:预测/目标的 shape、dtype、范围、均值、标准差、逐 action 维 L1/Linf;
- PI05 专属分布度量:见下文;
--metrics-json:以loss-compare-metrics-v1格式写出结构化 JSON(sample_count、inference、unnormalized、normalized、pi05_distribution、aggregates),aggregates 汇总raw_l1/raw_cos/unnorm_l1/unnorm_cos、归一化空间平均 W1/std 与首帧余弦。
从 .agents/skills/om-convert/references/accuracy.md 可知,整个工作流只设置两道数值门:Torch vs ONNX 与 Torch vs Ascend OM。Torch-vs-OM 的契约是mean_l1_max与cosine_min;当前工具不输出全局 max-abs 指标,因此除非扩展实现,不得声称存在 Torch-vs-OM 的 max-abs 判定。
8.3 PI05 的混沌鲁棒分布度量
对于 PI05(10 步 Euler 积分 flow-matching ODE),逐点余弦相似度会被 ODE 的混沌放大效应破坏:即使实现数学上正确,微小扰动(如 fp16 KV-cache 漂移 1-cos ~ 2e-5)也会随步数指数放大,导致逐样本余弦塌缩到 0。因此 src/model_utils/model_utils/pi05_dist_metrics.py 提供了两种混沌鲁棒指标:
- Method A — 逐 action 维边际 Wasserstein-1(W1/std):比较每个动作维的值分布而非逐点对齐,尺度不变;
mean_ratio ≤ 0.05为 EXCELLENT(可部署),≤ 0.15GOOD,≤ 0.30MARGINAL,更大为 POOR; - Method C — 首帧余弦:滚动时域控制真正执行的是
chunk[:, 0, :],该帧受混沌影响最小且唯一驱动物理运动;mean_cos ≥ 0.95EXCELLENT,≥ 0.80GOOD,≥ 0.50MARGINAL,更低为 POOR。
evaluate_pi05会同时对归一化与物理空间输出 W1/首帧余弦报告。最终部署验证仍建议在仿真或真机上做任务级成功率评估(模块注释中明确提示)。
九、交接报告:可审计的实验记录
跨主机检查结束后,记录以下内容,形成交接报告:
- 执行的命令(含各主机上的实际参数);
- 源/目标路径;
- 各文件哈希;
- 各主机工作区路径;
- IB-Robot / LeRobot 修订号(SHA);
- 每次传输由 Agent 还是用户执行;
- 被测部署的
soc_version、NPU、驱动、CANN、ATC、ACL、deployment 指纹与 ABI 哈希(若 OM 哈希变化,旧 OM 的精度结论失效)。
文档明确规定:输入不匹配的跨主机检查无效。换句话说,精度结论只有在「观测、目标、raw 目标、噪声全部来自同一封包且哈希一致」的前提下才成立。
十、落地到完整 OM 转换链路的衔接
multi-host-validation.md是om-convert工作流中「生成 Torch 目标后再测试 OM 精度」这一环节的专项规范,它与其他环节的衔接关系如下:
| 环节 | 依据文档/实现 | 与本工作流的衔接 |
|---|---|---|
| 前置信息采集 | om-convert/SKILL.md | 一次性采集三主机拓扑、bundle、部署、设备、远程执行许可 |
| 观测批次 | observation_batch.py | 本工作流第四节 |
| 目标生成 | loss_compare.py | 本工作流第五、六节 |
| 精度门限 | accuracy.md | 两道数值门;单一权威目标规则;精度预检 |
| PI05 专项 | pi05.md | 目标仅从原 Torch 部署生成,噪声包按本文封包传输 |
| 性能基线 | benchmark.md | 精度通过后,每个 OM 跑ais_bench --loop 20,按角色调用次数加权计算total_mean_ms |
对随机策略而言,「持久化噪声 + 逐主机消费同一噪声」是本工作流正确性的命门:验证「相同持久化噪声复现相同 Torch 动作、不同噪声产生不同动作、Ascend 运行消费的是传输过来的噪声而不是重新生成」,是每个随机策略家族通过精度验证前必须证明的三件事。谨记当前实现仅覆盖 PI05,其他家族需先扩展 codec/运行时与对比工具,再谈精度结论。
- 具身智能
- 机器人
- 人工智能
- 大模型
- 模型推理服务
- 本地部署
- 计算机视觉
- ROS
【免费下载链接】IB_Robot
Save the code of IB-Robot, an AI robot execution framework developed by openEuler Embedded for embodied intelligence scenarios. It includes references to the forked version of tensormsg, references to lerobot fork, code references to the lerobot_ros2:ros2_ws branch, as well as some code related to development usability.
相关推荐
IB_Robot 昇腾 OM 转换精度门禁:Torch vs ONNX 与 Torch vs Ascend OM 双数值门禁的完整规则与实践
IB_Robot 昇腾 OM 转换精度门禁:Torch vs ONNX 与 Torch vs Ascend OM 双数值门禁的完整规则与实践 本文基于 IB_R
具身智能机器人人工智能大模型模型推理服务本地部署计算机视觉ROSopenEulerOpenHarmony深度学习语音AI AgentAscendIB_Robot Ascend OM 转换工作流:Experience Ledger 经验台账与最终报告机制
IB_Robot Ascend OM 转换工作流:Experience Ledger 经验台账与最终报告机制 在 IB_Robot 的 om convert 技
具身智能机器人人工智能大模型模型推理服务本地部署计算机视觉ROSopenEulerOpenHarmony深度学习语音AI AgentAscendIB-Robot 板端推理验证实战:Ascend 310B 上的 OM 脚本、ROS Mock 与 Torch NPU 验证指南
IB Robot 板端推理验证实战:Ascend 310B 上的 OM 脚本、ROS Mock 与 Torch NPU 验证指南 导读 本文是 IB Robot
具身智能机器人人工智能大模型模型推理服务本地部署计算机视觉ROSopenEulerOpenHarmony深度学习语音AI AgentAscend
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考