跳转至

GRAIL–PULSE-X Integration:代码修改计划与验收标准

最后更新:2026-07-26。

状态:训练暂停,且此前 pnp_table_smplx_pulsex_minimal 的 Seed-0 不再是 canonical 实验:它最多是旧 PnP/hand-interface diagnostic。新的唯一主条件是 advanced_manip_table_smplx_pulsex_minimal;它已通过 source-to-adaptation static config audit,但尚未重跑任何 Isaac runtime gate 或正式训练。其 Seed-0 必须从 frozen PULSE-X 重新开始,禁止 warm-start 旧 checkpoint。

本页定义 A2-G 的 canonical 工程方案:在 GRAIL 的 Isaac Lab scene-aware HOI runtime 中,使用 frozen PULSE-X reference encoder / decoder 执行 SMPL-X 控制,并仅训练 GRAIL PPO actor 输出的 48D latent residual。 它同时定义代码合并、runtime launch 与正式实验成功的验收标准。

旧版 GRAIL observation/reward + frozen PHC-X + 63D direct body residual + 2D binary hand primitive 不删除,但从 canonical A2-G 降级为 legacy diagnostic。 它不是本页方案,也不再代表严格的 GRAIL-style latent residual。

当前实施证据

范围 状态 证据
advanced config mapping ✅(静态) output/grail_pulsex_config_audit_advanced_draft_20260726/config_audit.json:20 policy / 22 critic terms 与官方 advanced_manip_table 对齐;dense object reward、primary/assist weights、object mass/density、contact sampling 与 termination constants 已逐项审计
parity / rollout / smoke / fullscale init 旧 pnp-table artifact 的 config/source hash 与 reward/termination 合同不同,不可复用
4096-env production factory output/grail_pulsex_acceptance_20260726/fullscale_init_fix_v2/fullscale_init_report.json + clean-exit marker:4096 × 52 = 212,992 body instances、4 个 [4096,1,16,3] support contact sensor,且无 direct /Robot/<body> path
seed-0 首次启动 ⚠️ 历史 output/grail_pulsex_train/seed_0/ 在 PPO 前因 direct contact-sensor body path 退出;这不是训练结果,也不计作 seed failure
pnp-table Seed-0 retries ⚠️ 历史 retry 只证明旧 config 曾进入 PPO;当前主条件的 reward、termination、contact sampling、object density 与 hand role semantics 均已改变,不能 warm-start 或报告为 GRAIL-Min 结果
PPO micro-batch contract ✅(代码) 保留 4096 env、4 个 1024-env mini-batch、5 PPO epochs 与一次 mini-batch optimizer update;仅以 128 × 8 gradient accumulation 限制 activation memory;定向回归 40 passed
seeds 0/1/2 新的 source-bound preflight 和 runtime gate 后才启动;不得把 Layer A/B 写成 teacher success

1. 决策与边界

1.1 唯一训练条件

本阶段只有一个训练条件:

A2-G / GRAIL-Min
= GRAIL observation + GRAIL human reward / termination + GRAIL PPO
+ frozen PULSE-X reference encoder/decoder
+ 48D latent residual
+ SMPL-X articulated body and hands

本文中的静态测试、数值 parity、zero-residual rollout 和 PPO smoke 都是同一 条件的实现检查,不是额外实验组,不产生论文中的新方法行。

manager_env.config.human_tracking_reward_mode 是唯一的 human-reward selector: 默认 grail,逐项复现原先 six-term GRAIL human tracking sum;可显式设为 phcx_global,以 PHC-X compute_imitation_reward 的 global position/rotation/linear-velocity/angular-velocity 公式替换这一项。它仍使用 当前 GRAIL command 的 14 个 body names,故不改 command、observation、HOI reward、 termination 或 PPO 合同。phcx_global 的 reward 权重和为 1.0,而 grail 分支 的 six-term 峰值和为 11.5;因此这是清晰记录的 PHC-X-compatible reward adaptation, 不是“严格不变”的 GRAIL-Min run,也不能静默替换默认结果。 human_tracking.weight 是已有的 RewardTermCfg 外层权重,默认同为 1.0;若日后 需要任务级 reward rebalance,只调整这一既有权重并重新冻结 config gate,不新增 第二个 PHC-X scale 常数。

1.2 必须保留的 GRAIL 语义

  • GRAIL Isaac Lab manager environment;
  • advanced_manip_table manipulation actor/critic observation term、顺序、future horizon、 object/support/BPS/contact 语义;
  • advanced_manip_table reward term、termination term、权重与 PPO objective;
  • scene object、target object、support object、mass、contact sensor 与 role binding;
  • 0.1 latent residual scale;
  • rollout horizon、motion resampling、optimizer、network hidden layers和训练预算;
  • 50 Hz GRAIL control runtime。

内存实现允许把同一个 PPO mini-batch 切为 micro-batches,但必须保持 mini-batch 分母、梯度平均、optimizer update 次数和学习率不变。当前固定为 4096 / 4 = 1024 env per mini-batch,128 × 8 accumulation;它是 24 GB GPU 上的 execution contract,不是另一种 PPO 条件。

1.3 只允许的必需变化

原 GRAIL / 旧 A2-G 本方案 原因
G1 embodiment SMPL-X,52 bodies / 153 revolute DOFs 目标 embodiment
SONIC 64D pre-FSQ latent PULSE-X 48D VAE posterior latent frozen checkpoint interface 不同
FSQ 后送 SONIC decoder 不经过 FSQ,直接送 PULSE-X decoder PULSE-X checkpoint 没有 SONIC FSQ
64D + 2D meta action 48D latent residual PULSE-X 已输出完整 articulated hand action
G1 binary fake gripper PULSE-X decoder 的完整 90D hand action SMPL-X 需要 articulated hands
G1 joint/link index name-based SMPL-X joint/body/contact mapping embodiment 必需转换
SONIC controller checkpoint PULSE-X checkpoint SMPL-X frozen controller
PPO actor 输出 65D 48D latent residual PULSE-X latent interface 的必需连带变化
release 固定 right primary / left assist metadata active_hand primary / counterpart assist 不能把 canonical 左手 motion 改写成 hard-coded right-hand task
release 单 table contact metadata active_support 的 one-to-many support contact stack canonical scene 有 source/destination supports,必须只读取当前 task support
release sample_before_contact_hand: right_hand role-derived primary-hand contact frame contact sampling 与 reference task hand 同源
six 个 GRAIL human tracking terms 一个 selectable human_tracking term,默认精确 GRAIL 加权和;phcx_global 时用 PHC-X global imitation 只为诊断/验证 global imitation 是否能纠正 reference tracking drift;不能影响 HOI/physics 语义

除上表外,不增加新的 object feature、scene encoder、reward shaping、termination 或网络分支。若实现过程中发现新的必需差异,必须先补入本表,再改代码。

1.4 明确禁止

  • 不同时 import submodules/PHC/phcsubmodules/Omnigrasp/phc 两个顶层 phc package;
  • 不把 OmniGrasp task/environment、Isaac Gym runtime 或 reward 引入 GRAIL;
  • 不使用 PHC-X PNN 作为 base action;
  • 不使用 PULSE-X state prior z_prior_mu(self_obs)
  • 不使用 FSQ、sphere projection、tanh、latent clipping 或额外 projection;
  • 不保留 2D hand primitive,不用 motion hand action 覆盖 decoder 的 90D hand;
  • 不把 153D PULSE action先手工转成 PD target、再让 ActionManager 做第二次 affine;
  • 不为绕过失败而改变 GRAIL observation、HOI reward、termination 或控制频率;
  • 不将 phcx_global 的结果描述为 strict GRAIL reward,或与默认 grail run 混合汇报;
  • 不删除旧 PHC-X path,直到新 PULSE-X path 完成全部代码合并验收。

1.5 Research question 与统计边界

RQ:在严格保留 advanced_manip_table scene-aware observation、reward/termination 与 PPO 的 前提下,将其 SONIC action-transform 替换为 frozen PULSE-X reference-posterior controller,48D latent residual 能否把同一条 canonical SMPL-X pick–place reference 变成通过 physics gate 的 teacher candidate?

本阶段是 single-case、三 seed 的工程复现与可行性实验,不做 population-level 显著性推断。结果逐 seed 报告并汇总 median/range;2/3 seed success 只作为 预注册的 robustness gate,不解释为跨 object/scene 的统计泛化。


2. 输入材料护照(Material Passport)

材料 路径 / 版本 当前证据 用途
GRAIL/SONIC runtime submodules/GRAIL/imports/SONIC/ 旧 A2-G 已完成 SMPL-X scene/reference/action 静态合同 runtime host
PULSE loader submodules/PHC/phc/learning/network_loader.py 提供 load_z_encoder / load_z_decoder 唯一 phc Python package
PULSE-X checkpoint submodules/Omnigrasp/output/HumanoidIm/pulse_x_omnigrasp/Humanoid.pth SHA-256 185ba564345f2c57e10ca538984366d9d3461269baa17842f53f064535f83d86 只作为 checkpoint 数据读取
PD affine submodules/PHC/data/action_offset_smplx.pkl 旧 A2-G 已接入 ActionManager normalized action → joint target
teacher-forced metrics output/auto_experiments/20260718_pulsex_encoder_sanity/teacher_forced_verified/metrics.json 219 frames;human body mean 2.59 cm controller parity 参考
teacher-forced trace output/auto_experiments/20260718_pulsex_encoder_sanity/teacher_forced_verified/rollout_trace.npz SHA-256 e68667ee5e8bf36d175e24e608dd0ee0821dd5cc0ae3824fbb65bf9fccf87218;包含 48D reference latent 与 153D action,但不含原始 2026D input golden output 与 body-state 证据
canonical SMPL-X reference/scene output/grail_minimal_smplx_phcx_20260724/reference/ E0 static/USD contract 已有证据 新 path 复用,不重新生成

已有 PULSE-X teacher-forced 结果只证明 encoder/decoder 在对齐状态下的单步合同。 历史 zero-residual closed-loop 发散仍作为已知诊断保留,但它没有包含 GRAIL residual policy,因此不作为禁止本次实现或 PPO smoke 的硬 blocker。


3. 冻结的控制合同

3.1 数据流

GRAIL actor observation
  -> GRAIL PPO actor
  -> raw latent residual Δz_raw [B,48]
  -> GRAIL scale: Δz = 0.1 * Δz_raw

current SMPL-X state + next reference state
  -> PULSE observation o [B,2026]
     = self observation [B,778]
     + imitation observation [B,1248]
  -> checkpoint RMS normalization and clamp [-5,5]
  -> frozen PULSE-X encoder posterior mean z_base [B,48]

z_exec = z_base + Δz
  -> frozen PULSE-X decoder([normalized self observation, z_exec])
  -> normalized SMPL-X action a_pulse [B,153]
  -> canonical-name permutation
  -> GRAIL ActionManager PHC-X affine exactly once
  -> simulator PD target

精确定义为:

[ \hat{o}=\operatorname{clip} \left( \frac{o-\mu_{\mathrm{PULSE}}} {\sqrt{\sigma^2_{\mathrm{PULSE}}+10^{-5}}}, -5,5 \right), ]

[ z_{\mathrm{base}} =E_{\mathrm{PULSE}}(\hat{o}){\mu}, \qquad z =z_{\mathrm{base}}+0.1\Delta z_{\mathrm{GRAIL}}, ]}

[ a_{\mathrm{SMPLX}} =D_{\mathrm{PULSE}} \left( [\hat{o}{0:778},z] \right)\in\mathbb{R}^{153}. ]}

z_base 必须取 posterior mean encoder.z_mu(encoder.encoder(...))。 本 checkpoint 配置不做 unit-sphere projection;z_exec 不经 FSQ、tanh 或 其他投影。

3.2 PULSE observation

PULSE observation 不等于 GRAIL actor observation。两者由同一 simulator state 分别构造:

  • GRAIL actor observation:scene-aware policy 输入,保留 20 个 term;
  • PULSE observation:frozen controller 私有输入,严格为 778D self + 1248D imitation = 2026D

第一版实现直接复用 phcx_action_adapter.py::compute_phcx_human_observation,因为 PHC-X 与 PULSE-X 在这里共享 PHC observation-v6 数学合同。不得从 flattened GRAIL actor observation 中切片拼出 2026D。

reference time 使用当前 GRAIL motion command 的 next-frame、terminal clamp 与 52-body canonical ordering。所有 position、rotation、linear/angular velocity 都在同一次 wrapper step 中读取,禁止跨 step 缓存不同时间的字段。

3.3 Action 与 hand

PULSE decoder 输出的 153D 是完整 SMPL-X normalized joint action,其中:

  • body:63D
  • articulated hands:90D
  • 两部分均来自同一次 decoder forward。

本方案不再使用 GRAIL 的 2D binary hand primitive。原因不是删减 object awareness,而是 G1 的 primitive 控制假手开/合;在 SMPL-X 中覆盖 PULSE 的 90D 输出会破坏 pretrained controller 的 action distribution。

GRAIL 的 hand/object contact observation、grasp reward、finger-direction reward、 table-contact penalty 和 role-aware contact attribution全部保留,它们读取真实 SMPL-X finger links 与 contact sensors,不依赖 2D primitive。

3.4 Control frequency

GRAIL runtime 保持:

simulation dt = 0.005 s
decimation    = 4
control rate  = 50 Hz

PULSE-X 原生验证主要在 30 Hz50 Hz 是 GRAIL runtime 与当前 canonical reference 的冻结选择,也是必须披露的 checkpoint-interface 差异。验收时必须记录 该差异及 action continuity;不得把 30/50 Hz 差异静默隐藏,也不得在首次实现中 引入插值 controller 或第二训练条件。


4. 代码组织

4.1 新增文件

文件 职责 预计新增
submodules/GRAIL/imports/SONIC/gear_sonic/envs/wrapper/pulsex_controller.py frozen encoder/RMS/latent addition/decoder 90–130 LOC
submodules/GRAIL/imports/SONIC/gear_sonic/config/actor_critic/hoi_staged_mlp_aux_pulsex.yaml 原 GRAIL MLP,latent aux width 改为 48 30–40 LOC
submodules/GRAIL/imports/SONIC/gear_sonic/config/exp/manager/universal_token/hoi/advanced_manip_table_smplx_pulsex_minimal.yaml 唯一 canonical GRAIL-Min config advanced source recipe 的显式 SMPL-X/PULSE-X adaptation
.../rewards/hoi_manip/grab_rewards_advanced_manip_smplx_roles.yaml release primary/assist reward 的 role routing 新增
.../terminations/tracking/hoi_advanced_manip_smplx_roles.yaml 0.25 m object gate 与 50-frame primary-grasp failure 新增
tests/test_grail_pulsex_controller.py pure-PyTorch controller、freeze、parity、forbidden-path tests 已实现
utils/tracking_adapters/grail/pulsex_evidence.py parity/runtime trace 的领域级采集与验证 已实现
tools/run_grail_pulsex_acceptance.py 编排 parity/rollout/smoke/fullscale_init,父进程监督 Isaac child clean exit 已实现
tools/audit_grail_pulsex_config.py 对照 official advanced_manip_table,逐项验证 observation order、reward primary/assist mapping、object density/mass、contact sampling 与 termination constants 已实现
tools/audit_grail_pulsex_preflight.py 将 config/parity/rollout/smoke/4096-env production init 与 source hash 合并为 fail-closed train preflight 已实现
tools/audit_grail_pulsex_runtime_config.py 为每个 seed 冻结 exact Hydra config 与 checkpoint rule 已实现
tools/run_grail_pulsex_train.py 校验 runtime gate 后启动一个 seed;支持 --dry-run 已实现

4.2 修改文件

文件 必须修改
gear_sonic/envs/wrapper/manager_env_wrapper.py 增加 action_transform_type: pulsex;构造 2026D input;执行 48D → 153D;写 latent history;不进入 PHC-X direct residual 或 finger primitive 分支
gear_sonic/envs/manager_env/modular_tracking_env_cfg.py SMPL-X robot 仅在 use_finger_primitive=true 时要求 primitive contract;PULSE path 不加载 hand default positions;每个 support 使用独立 one-to-many hand-contact sensor
gear_sonic/envs/manager_env/task_roles.py 将 per-support contact sensor stack 成原 GRAIL term 所需的 [env,support,filter,3],并提供 metadata-routed primary/assist hand selection
gear_sonic/envs/manager_env/mdp/rewards.py 保留公式,按 primary/assist 路由 release 的 40/20 grasp、10/5 finger-direction 与 0.1/0.05 contact-center terms;PULSE interface 不使用 primitive reward
gear_sonic/envs/manager_env/mdp/terminations.py 复用同一 support stack,并把 release 的 GraspFailureAfterContact 路由到 metadata-selected primary hand,保留 50-frame grace
gear_sonic/trl/trainer/ppo_trainer.py assert_phcx_frozen 改成 controller-neutral frozen audit,覆盖 PULSE encoder、decoder 与 RMS
utils/tracking_adapters/grail/code_contract.py 新增 PULSE config/source allowlist;PHC-X 旧 path 标记 legacy,不删除
gear_sonic/utils/grail_runtime_contract.py canonical experiment 指向 advanced_manip_table_smplx_pulsex_minimal;验证 PULSE preflight、exact config hash 和 frozen source
utils/tracking_adapters/grail/runtime.py canonical compose 默认 PULSE;旧 PHC-X runner 必须显式请求 legacy experiment
docs/project/implementation_details.mddocs/experiments/grail_minimal.mddocs/experiments/evaluation_strategy.mddocs/experiments/overall_plan.md canonical A2-G 指向本方案,旧 A2-G 结果不得冒充 PULSE 证据

4.3 第一版不做的重构

第一版不同时抽取 smplx_controller_contract.py。先直接复用 phcx_action_adapter.py 中已经验证的:

  • 52-body / 153-DOF canonical names;
  • compute_phcx_human_observation
  • next-reference selection;
  • simulator/reference name permutation;
  • ActionManager affine contract。

PULSE 数值 parity 与 runtime smoke 通过后,才把这些与 PHC-X/PULSE-X 共同的 内容移动到 smplx_controller_contract.py。该移动必须是纯重构:重构前后 controller output、permutation 与 PD target 逐 tensor parity。


5. 核心 API

pulsex_controller.py 只暴露一个小型 nn.Module

class FrozenPulseXController(nn.Module):
    @classmethod
    def from_checkpoint(
        cls,
        checkpoint_path,
        *,
        device,
    ): ...

    def forward(
        self,
        observation_2026,          # [B, 2026], raw
        scaled_latent_residual_48, # [B, 48], wrapper 已乘 0.1
    ):
        # returns: z_base [B,48], z_exec [B,48], action [B,153]
        ...

不增加公开的 encode_reference() / decode() facade,也不要求 NamedTuple。controller 内部拥有:

  • PULSE encoder;
  • PULSE decoder;
  • running_mean / running_var buffers;
  • checkpoint hash 与 frozen state digest;
  • shape、dtype、device 与 finite 检查。

ManagerEnvWrapper 负责:

  • GRAIL 0.1 scale;
  • current/reference state 到 2026D observation;
  • canonical-to-simulator joint permutation;
  • ActionManager 输入;
  • _last_meta_action / _prev_meta_action
  • _full_latent=z_exec / _prev_full_latent
  • audit trace snapshot。

这条边界保证 PULSE controller 是纯 PyTorch 模块,不 import OmniGrasp task 或 Isaac runtime;GRAIL wrapper 保持唯一 simulator owner。


6. 分阶段修改清单

阶段是实现顺序,不是实验条件。

Phase A — side-by-side functional path

  • 保留 phcx_action_adapter.py 与旧 config,明确标注 legacy。
  • 新增 FrozenPulseXController,仅依赖 submodules/PHC/phc loader。
  • checkpoint load 后验证 RMS 2026D、latent 48D、action 153D
  • 所有 controller parameters requires_grad=False 且永久 eval()
  • wrapper 新增独立 pulsex branch,不修改旧 phcx branch 行为。
  • wrapper 计算 scaled_delta=0.1*raw_delta,调用 controller。
  • decoder 的完整 153D action按 joint name scatter 到 simulator order。
  • 不调用 _setup_finger_primitives(),不读取 motion hand actions。
  • buffer shape 改为 _last_meta_action:[B,48]_full_latent:[B,48]
  • 新 actor config 输出 48D,hidden layers、activation、aux coefficient保持 原 GRAIL。
  • 新 experiment config 继承现有 SMPL-X scene/reference/roles,只替换 controller/action fields。

Phase A 完成定义:pure-PyTorch 单测通过,Hydra compose 后 action/observation/ reward contract 可静态解析。

Phase B — parity、runtime 与 PPO

  • 新增 PULSE controller checkpoint/RMS/freeze audit。
  • 从 official loader source path 导出包含 raw 2026D input、 48D z_base153D action 的小型 parity fixture,并绑定 source/checkpoint hash;再对新 controller 做 same-device FP32 parity。
  • 在 Isaac runtime 做 zero-residual closed-loop 诊断,保存完整 trace。
  • 验证 ActionManager affine 只应用一次。
  • 验证 PULSE 90D hand slice 未被 primitive、reference 或 post-hook 覆盖。
  • 将 trainer frozen audit 泛化为 assert_frozen_controller
  • 执行 2 env / 1 iteration / 24 steps PPO smoke。
  • 验证 checkpoint save/load 不保存第二份可训练 PULSE parameters。
  • 生成 machine-readable acceptance summary。
  • production create_manager_env() 在构造 ManagerBasedRLEnv 前,将 SMPL-X PHC-X USD 的 direct /Robot/<body> contact paths 等价改写为 /Robot/Pelvis/<body>4096-env init-only gate clean-exit 通过。
  • 在上述 production-factory 修复后的 source hash 上复跑 config/parity/ rollout/smoke,再生成新的 preflight。
  • 以正式 Seed-0 证明运行越过 factory 与 trainer.train;定位原始 1024 × 24 update graph 的 CUDA OOM。
  • 将 PPO mini-batch 执行改为 128 × 8 gradient accumulation;仅在 accelerator.sync_gradients 时 clip / step / zero-grad,以保留一次 1024-sample mini-batch update。
  • 用 micro-batch contract 重跑 source-bound acceptance、runtime gate 与 Seed-0;此前所有 preflight 均不可复用。

Phase B 完成定义:第 8 节的代码合并、4096-env production init 与当前 source-hash 的 launch acceptance 全部通过。

Phase C — canonicalization 与清理

  • grail_runtime_contract.py 与正式 runner 默认指向 PULSE config。
  • 更新 A2-G 文档与 evidence pointer。
  • 旧 PHC-X GRAIL config 在 canonical 文档中标记 legacy_phcx_direct_residual,不删除 artifact。
  • 可选抽取 smplx_controller_contract.py;必须先后数值等价。
  • 复跑全部 tests/test_grail_*.py160 passed, 5 warnings

Phase C 完成定义:canonical 文档、runner、config 和 artifact schema 均只把 GRAIL–PULSE-X 称为 A2-G。

Phase D — 唯一正式训练

  • 冻结 config hash、checkpoint hash、reference hash、scene contract 与 seeds 0/1/2
  • 三个 seed 使用完全相同的 config 与训练预算。
  • single-case runtime schedule 冻结为 4096 env / 24 steps / 500 iterations; 每 100 iterations 写 checkpoint,最终选择 iteration-500 checkpoint,并写入 runtime gate。源 recipe 的 20k 默认只用于 strict upstream config parity,不能 被当作本 canonical motion 的训练预算。
  • 对新 seed_0_retry_after_fullscale_20260726 做 dry-run runtime gate, 再启动真实 PPO;不覆盖历史 pre-PPO failure artifact。
  • 每个 seed 运行 deterministic policy-mean full-sequence evaluation。
  • 汇总 fixed-denominator human/object/contact/task/termination telemetry。
  • 不因某 seed 失败而新增 controller、reward 或 observation 条件。

7. 配置冻结表

新 config 的 controller/action 字段必须为:

manager_env:
  config:
    action_transform_type: pulsex
    pulsex_checkpoint_path: /mnt/data/PhysHSI/submodules/Omnigrasp/output/HumanoidIm/pulse_x_omnigrasp/Humanoid.pth
    use_latent_residual: true
    latent_residual_mode: pulsex_reference_posterior
    latent_residual_scale: 0.1
    meta_action_dim: 48
    tokenizer_action_dim: 48
    hand_action_dim: 0
    use_finger_primitive: false
    use_motion_hand_actions: false
    needs_policy_atm: false

以下字段从 legacy GRAIL-SMPL-X config 等价迁移,并保持当前 GRAIL–PULSE-X config:

  • canonical robot USD、motion/reference、object motion、BPS、scene roles;
  • num_future_frames=10dt_future_ref_frames=0.1
  • smpl_num_future_frames=10smpl_dt_future_ref_frames=0.02
  • target_fps=50
  • actor/critic observation YAML;
  • advanced reward/termination YAML、object density/mass 与本页列出的 exact mapping;
  • num_envs=4096 的正式训练预算;
  • actor/critic MLP hidden dims [512,256,128]SiLU

config audit 不做无意义的全 YAML leaf diff;它必须对照 official source 显式断言:

  1. policy/critic 20/22 term 的顺序;
  2. 20 object tracking、40/20 primary/assist grasp、10/5 finger direction、 0.1/0.05 contact center,以及 object formula coefficients;
  3. 0.25 m object、0.3 m object-z、3 contacts / 0.1 force / 50 frames contact-failure constants;
  4. sample_before_contact=true、margin 10、density 300、mass null
  5. 仅 controller-interface 的 65D → 48D、primitive removal 与 128 × 8 execution micro-batching;PPO logical mini-batch 仍为 4096 / 4 = 1024

pulsex_checkpoint_pathlatent_residual_scalemeta_action_dimtokenizer_action_dimhand_action_dimuse_finger_primitiveuse_motion_hand_actions 都是 required fields;新 PULSE path 必须用 config[...] 显式读取并在缺失时立即失败,不允许用默认值静默回退到 SONIC 或 PHC-X。


8. 验收标准

验收分为三层。前一层失败时不得声称后一层完成。

8.1 Layer A:代码合并验收

A1. Import 与依赖

  • runtime 中只解析到一个顶层 phc package,来源为 submodules/PHC/phc
  • checkpoint 可以来自 submodules/Omnigrasp/output/...,但 pulsex_controller.py 不 import submodules/Omnigrasp/phc
  • controller source 不 import OmniGrasp env/task、Isaac Gym、Isaac Lab、 object reward 或 contact code。
  • import controller 不创建 simulator、不读取 reference artifact、不改变 global default dtype/device。

A2. Checkpoint 与 tensor contract

  • checkpoint SHA-256 等于本页冻结值。
  • running_mean.shape == running_var.shape == (2026,)
  • RMS tensor finite,running_var >= 0
  • input [B,2026] 输出 z_base:[B,48]z_exec:[B,48]action:[B,153]
  • 错误 shape、dtype/device mismatch、NaN/Inf 均 fail fast,并包含字段名与 实际 shape。
  • delta=0z_exec == z_base
  • 非零 residual 的 z_exec 与同一 FP32 表达式 z_base + scaled_latent_residual 逐位一致;另报告 z_exec-z_base 的 cancellation error,不用该反向减法替代定义式验收。
  • decoder input 的 self block恰为 normalized observation 的前 778D

A3. Frozen contract

  • controller、encoder、z_mu、decoder 均为 eval()
  • 所有 PULSE parameters requires_grad=False
  • PPO optimizer parameter id 集合与 PULSE parameter id 集合交集为空。
  • rollout、backward、optimizer step 前后 controller state digest 完全相同。
  • PULSE parameter .grad is None
  • 对 wrapper/controller 调用 .train() 后,PULSE 子模块仍保持 eval。

A4. Numerical parity

  • 从 canonical zero-residual runtime trace 选取固定 frame subset 的 observation_2026z_baseaction_153,形成只用于测试的 golden fixture; fixture 记录 source file hash、checkpoint hash、reference frame 与 tensor hash。
  • 新 controller 使用该 fixture 的相同 input、checkpoint、normalizer与 same-device FP32 forward;rollout_trace.npz 现已包含 raw/normalized 2026D observation。
  • z_base parity:atol=1e-6, rtol=1e-5
  • decoder 153D action parity:atol=1e-6, rtol=1e-5
  • GPU runtime 若因 kernel 差异不能逐位一致,则每 tensor max_abs_error <= 1e-5;不得放宽到影响 PD target 的误差。
  • 新 parity 报告同时写 source file hash、checkpoint hash、device、dtype与 tolerance,禁止只写 passed=true

A5. SMPL-X action path

  • canonical joint list恰有 153 个唯一名称。
  • canonical-to-simulator permutation 是 0..152 的双射,round-trip 完全 恢复输入。
  • wrapper 输出的完整 153D 先 permutation,再交给 ActionManager。
  • ActionManager processed target 满足 target = normalized_action * scale + offset,且 affine 只执行一次。
  • decoder 的 90D hand slice在进入 ActionManager 前只允许 joint permutation,不允许 binary primitive、reference overwrite 或独立 clip。
  • global action clip若保留,必须与原 GRAIL config 同值,并在 trace 同时保存 pre/post-clip tensor 与 clamp fraction。

A6. GRAIL semantic parity

  • actor observation仍为同一 20 个 term、同一顺序与同一语义。
  • critic observation term、顺序与 privileged boundary 不变。
  • actions observation term 继续记录 ActionManager 上一步执行的 153D SMPL-X joint action;其 term、顺序和宽度不变。只有 PPO actor 输出及 _last_meta_action/_prev_meta_action reward buffer 从 65D 变为 48D
  • object、future object、BPS、target/support、active-hand、finger contact tensor逐项 finite,shape与适配后的 contract 一致。
  • static config audit 已证明 advanced reward weights/formula coefficients、 termination thresholds、contact sampling、object mass/density 与 source 对齐; primary/assist routing 是唯一 hand-side adaptation。
  • runtime 仍须证明 role-routed GraspFailureAfterContact、support contact 和 dense object reward 在 Isaac host 上真实触发、finite 且不发生 hard-coded side leak。
  • config 中没有新的 observation、curriculum 或 hidden layer;PULSE interface 仅移除了不兼容的 primitive reward。

Layer A 的合格判定:A1–A6 全部通过;任一 required item 失败则不得合并为 canonical A2-G。

8.2 Layer B:runtime launch 验收

B1. Zero-residual diagnostic

固定 Δz_raw=0,在正式 Isaac/GPU host 运行 canonical reference:

  • 命令干净退出,exit code 0,final marker 为终态;
  • 至少写出每步 o_raw/o_normalized 统计、 z_base/z_exec、pre/post-clip 153D action、PD target、reference frame与 termination reason;
  • 全部 tensor finite;
  • z_exec==z_base
  • 无 observation time skew、joint permutation 或 double-affine;
  • 若 early termination,trace 包含有效 prefix 与明确 reason。

该诊断必须报告 body/root/hand error、latent norm、action-rate、clamp fraction 与 valid prefix。tracking error 大或提前终止不是代码验收的自动失败; 它用于判断 frozen posterior base 的闭环难度,不替代带 GRAIL policy 的训练结果。 NaN、错误 mapping、错误 affine、缺 trace 或命令不能干净退出才是硬失败。

B2. 4096-env production-factory init

该 gate 必须通过正式 gear_sonic.train_agent_trl.create_manager_env() 构造环境, 但在 trainer/optimizer 之前退出;它不是缩小规模的 smoke 替代品。

  • num_envs == 4096
  • contact_forces4096 × 52 = 212,992 个 body instance;
  • contact_forces 和所有 ContactSensor 的 robot paths 使用真实 USD /Robot/Pelvis/<body> hierarchy,而没有 direct /Robot/<body> path;
  • 四个 support-hand sensor 均为 [4096,1,16,3]
  • Isaac child 与父监督进程均 clean-exit,final_marker.jsonexit_code=0

任何一项失败都阻止正式 PPO,即使 2-env smoke 通过也不例外。

B3. PPO smoke

固定:

2 env
1 PPO iteration
24 rollout steps

必须满足:

  • environment reset、rollout、reward、termination、GAE、backward、 optimizer step 全部执行;
  • actor/critic loss、advantage、return、gradient norm finite;
  • 至少一个 GRAIL actor parameter获得 finite nonzero gradient并在 step 后变化;
  • PULSE state digest不变且没有 gradient;
  • policy 实际产生 nonzero 48D residual;
  • decoder 实际产生 finite/nonzero 153D action;
  • checkpoint save/load 成功;
  • reload 后,固定 observation 下 deterministic actor mean与保存前一致: atol=1e-6, rtol=1e-5
  • command exit code 0,artifact 中记录 composed config 与 source hashes。

smoke reward、contact、completion 或 MPJPE 不作为收敛结论。

B4. 24 GB PPO execution contract

  • formal config 固定 num_mini_batches=4per_device_train_batch_size=128gradient_accumulation_steps=8
  • 128 × 8 后只发生一次 clip/optimizer-step/zero-grad;Accelerate 数值等价测试通过;
  • 一次 4096-env formal startup 越过首个 PPO update,且不触发 CUDA OOM。

该项仅限制 activation memory;mini-batch 样本数仍为 1024,不新建 baseline。

Layer B 的合格判定:B1–B4 全部通过,且 parity/rollout/smoke 的 source hash 与当前 production factory 一致。完成后才允许启动正式 4096-env 训练。

8.3 Layer C:正式实验成功标准

Layer C 判断 A2-G 是否成为可用 teacher candidate,不反向决定代码是否正确。 唯一条件运行 seeds 0/1/2,不得按 test metric 删除 seed 或改 checkpoint。

必报分母与 telemetry

  • 每个 seed 的训练 steps、wall-clock、GPU、并行 env、checkpoint rule;
  • deterministic policy-mean 与 stochastic rollout 分开;
  • full reference 总帧数、valid frames、completion ratio;
  • human root/body/active arm-hand mean、p95 与 max error;
  • object position/rotation mean、p95、final goal error;
  • pick、carry、place、full-task success;
  • target-contact precision/recall/F1、required-contact hold、non-target contact;
  • lift height、sustained hold、drop/release;
  • fall、human/object/contact/timeout 等全部 termination reason;
  • NaN/Inf、penetration、joint-limit、action clamp 与 unavailable telemetry。

预注册成功门槛

在 fixed canonical case 上,A2-G 只有同时满足以下条件才通过 G3 single-case teacher gate:

  • 三个 seed 全部完成训练与固定规则评估;
  • 至少 2/3 seeds 的 deterministic rollout 完成完整序列;
  • 同一成功 seed 中 pick、carry、place 和 full-task success 全为 1
  • 成功 seed 的 full-sequence human body position error: mean <= 0.15 m、p95 <= 0.30 m
  • 成功 seed 的 object position error: mean <= 0.10 m、final goal error <= 0.10 m
  • required-contact 区间 target-contact F1 >= 0.80
  • task-derived lift/hold interval 不发生 drop,place 后 object 由目标 support 稳定承载;
  • 无 NaN/Inf、fall、非法 collision reset 或 telemetry 缺失。

所有阈值在正式 seed 启动后不得根据结果调整。若 task metadata 给出的 required-contact/lift/place 区间改变,必须先重签 reference hash 与本页版本, 再运行全部三个 seed。

通过 Layer C 只支持“GRAIL–PULSE-X 在该 canonical SMPL-X case 上可作为 teacher candidate”。跨 object/scene/motion 的 teacher、shared teacher 与 student generalization 仍需 G4–G6 的独立实验。


9. 测试与运行命令合同

当前可复现入口:

PYTHONPATH=/mnt/data/PhysHSI:/mnt/data/PhysHSI/submodules/GRAIL/imports/SONIC:/mnt/data/PhysHSI/submodules/PHC \
/mnt/data/PhysHSI/.envs/sonic/bin/python -m pytest -q \
  tests/test_grail_pulsex_controller.py
PYTHONPATH=/mnt/data/PhysHSI:/mnt/data/PhysHSI/submodules/GRAIL/imports/SONIC:/mnt/data/PhysHSI/submodules/PHC \
/mnt/data/PhysHSI/.envs/sonic/bin/python tools/run_grail_pulsex_acceptance.py \
  --stage rollout \
  --output-dir output/grail_pulsex_acceptance_20260726/revalidated_after_fullscale/rollout \
  --runtime-timeout-seconds 660 --headless --device cuda:0
PYTHONPATH=/mnt/data/PhysHSI:/mnt/data/PhysHSI/submodules/GRAIL/imports/SONIC:/mnt/data/PhysHSI/submodules/PHC \
/mnt/data/PhysHSI/.envs/sonic/bin/python tools/run_grail_pulsex_acceptance.py \
  --stage parity \
  --observation-trace output/grail_pulsex_acceptance_20260726/revalidated_after_fullscale/rollout/rollout_trace.npz \
  --output-dir output/grail_pulsex_acceptance_20260726/revalidated_after_fullscale/parity \
  --device cuda:0
PYTHONPATH=/mnt/data/PhysHSI:/mnt/data/PhysHSI/submodules/GRAIL/imports/SONIC:/mnt/data/PhysHSI/submodules/PHC \
/mnt/data/PhysHSI/.envs/sonic/bin/python tools/run_grail_pulsex_acceptance.py \
  --stage smoke \
  --output-dir output/grail_pulsex_acceptance_20260726/revalidated_after_fullscale/smoke \
  --runtime-timeout-seconds 660 --headless --device cuda:0

再运行同一 production factory 的 full-scale gate:

PYTHONPATH=/mnt/data/PhysHSI:/mnt/data/PhysHSI/submodules/GRAIL/imports/SONIC:/mnt/data/PhysHSI/submodules/PHC \
OMNI_KIT_ACCEPT_EULA=YES /mnt/data/PhysHSI/.envs/sonic/bin/python tools/run_grail_pulsex_acceptance.py \
  --stage fullscale_init \
  --output-dir output/grail_pulsex_acceptance_20260726/revalidated_after_fullscale/fullscale_init \
  --runtime-timeout-seconds 660 --headless --device cuda:0

随后用 audit_grail_pulsex_preflight.py 合并 config/parity/rollout/smoke/fullscale-init, 为每个 seed 用 audit_grail_pulsex_runtime_config.py 生成 exact gate,并先执行:

PYTHONPATH=/mnt/data/PhysHSI:/mnt/data/PhysHSI/submodules/GRAIL/imports/SONIC:/mnt/data/PhysHSI/submodules/PHC \
/mnt/data/PhysHSI/.envs/sonic/bin/python tools/run_grail_pulsex_train.py \
  --runtime-config-gate <seed_gate.json> \
  --experiment-dir <seed_output_dir> \
  --seed <0|1|2> --dry-run

去掉 --dry-run 才启动正式 500-iteration single-case 训练。PYTHONPATH 中不得出现 submodules/Omnigrasp;OmniGrasp 目录只提供 checkpoint 文件。


10. Artifact 合同

当前稳定输出根目录:

output/grail_pulsex_acceptance_20260726/revalidated_after_fullscale/
├── config/
│   ├── config_audit.json
│   ├── config_diff.json
│   └── resolved_pulsex_config.yaml
├── parity/
│   ├── parity_report.json
│   ├── parity_fixture.npz
│   └── final_marker.json
├── rollout/
│   ├── rollout_summary.json
│   ├── rollout_trace.npz
│   ├── runtime.log
│   └── final_marker.json
├── smoke/
│   ├── smoke_report.json
│   ├── smoke_trace.npz
│   ├── checkpoint.pt
│   ├── runtime.log
│   └── final_marker.json
├── fullscale_init/
│   ├── fullscale_init_report.json
│   └── final_marker.json
└── contract/
    ├── train_preflight.json
    └── seed_{0,1,2}_runtime_gate.json

每个 metrics.json 至少记录:

  • schema version;
  • source commit/hash;
  • composed config hash;
  • checkpoint/reference/scene hashes;
  • device、dtype、control frequency;
  • command、start/end time、exit code;
  • fixed denominator;
  • pass/fail items 与实际误差;
  • artifact 相对路径。

这些文件只用于 provenance 与复核,不作为下游 runtime 的状态总线。runner 不得通过扫描目录猜测输入;checkpoint、reference 和 scene 必须由显式参数或 冻结 config 提供。


11. 失败处理与停止条件

失败 处理 禁止做法
PHC/OmniGrasp phc namespace 冲突 只保留 submodules/PHC Python root,checkpoint按文件读取 调整 import 顺序碰运气
loader 与历史 PULSE 数值不一致 比较 loader source、checkpoint keys、RMS、activation 与 dtype,修到 parity 放宽 tolerance 掩盖差异
zero residual闭环发散 记录 prefix/error/action,继续做已授权的 PPO smoke 宣称 frozen tracker 已稳定;或因此改 reward
90D hand 被覆盖 删除 primitive/reference override,检查 permutation 与 ActionManager 继续保留 2D 假手作为“GRAIL 等价”
action double affine 统一让 ActionManager做唯一 affine 手工输出 PD target 后再送 normalized action path
PPO 无 actor gradient 检查 action detach、distribution、loss 与 optimizer membership 解冻 PULSE
reward/observation diff 超出 allowlist 回退非必需变化并重跑 contract 把新 feature 包装成 SMPL-X conversion
训练不成功但代码验收通过 报告负结果与三 seed 分布,分析 latent capacity/30→50 Hz/closed-loop stabilization 新增未预注册条件或只报告最佳 seed

以下情况应停止 canonical merge:

  1. 新 controller 不能复现已有 PULSE teacher-forced 数值;
  2. 无法证明 encoder/decoder/RMS 在 PPO 中保持 frozen;
  3. 无法证明 hand output 未被覆盖;
  4. joint permutation 不是双射或 affine 被应用超过一次;
  5. GRAIL observation/reward/termination 出现 allowlist 之外的变化;
  6. PPO smoke 不能完成真实 rollout、backward、optimizer 与 save/load。

zero-residual tracking performance 差不在上述停止条件内;它是需要由 GRAIL residual policy解决或最终以负结果报告的科学风险。


12. 完成定义

代码完成

  • Phase A–C 全部完成;
  • Layer A 与 Layer B 全部通过;
  • 新旧 path 定向测试和全部 tests/test_grail_*.py 通过;
  • canonical runner/config/docs 只把 GRAIL–PULSE-X 称为 A2-G;
  • 旧 PHC-X direct-residual path 可复现但明确标记 legacy。

实验完成

  • seeds 0/1/2 均按同一冻结配置结束;
  • Layer C 全部 telemetry 与门槛完成判定;
  • 结果写回 GRAIL MinimalTeacher Model
  • 通过则交接 rollout dataset 给 state-conditioned student;
  • 未通过则保留完整负结果,不把 smoke、单步 parity 或最佳 seed 写成 teacher success。

13. 预计工作量

最小功能路径约:

  • controller 与 wrapper核心逻辑:160–240 行;
  • config 与定向测试:250–360 行;
  • 合计约 450–600 行 diff。

若同时完成 evidence schema、generic frozen audit、runner canonicalization 和旧 PHC-X compatibility,预计涉及 12–20 个文件、约 500–900 行新增/修改。 主要风险不是网络代码量,而是:

  1. PULSE loader 数值 parity;
  2. 2026D observation 的时间与 body-order 对齐;
  3. 153D action permutation与单次 affine;
  4. articulated hand output 不被旧 GRAIL primitive path覆盖;
  5. GRAIL PPO action-history与 latent regularizer 从旧维度正确迁移到 48D

因此不需要推倒旧 A2-G 的 scene/reference/reward 工作;应保留约 70–80% 的 SMPL-X environment adaptation,只并行新增并替换 controller/action backend,再在验收后完成命名与文档 canonicalization。