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_tablemanipulation actor/critic observation term、顺序、future horizon、 object/support/BPS/contact 语义;advanced_manip_tablereward term、termination term、权重与 PPO objective;- scene object、target object、support object、mass、contact sensor 与 role binding;
0.1latent residual scale;- rollout horizon、motion resampling、optimizer、network hidden layers和训练预算;
50 HzGRAIL 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/phc与submodules/Omnigrasp/phc两个顶层phcpackage; - 不把 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 的
90Dhand; - 不把
153DPULSE action先手工转成 PD target、再让 ActionManager 做第二次 affine; - 不为绕过失败而改变 GRAIL observation、HOI reward、termination 或控制频率;
- 不将
phcx_global的结果描述为 strict GRAIL reward,或与默认grailrun 混合汇报; - 不删除旧 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 保持:
PULSE-X 原生验证主要在 30 Hz。50 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.md、docs/experiments/grail_minimal.md、docs/experiments/evaluation_strategy.md、docs/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_varbuffers;- checkpoint hash 与 frozen state digest;
- shape、dtype、device 与 finite 检查。
ManagerEnvWrapper 负责:
- GRAIL
0.1scale; - 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/phcloader。 - checkpoint load 后验证 RMS
2026D、latent48D、action153D。 - 所有 controller parameters
requires_grad=False且永久eval()。 - wrapper 新增独立
pulsexbranch,不修改旧phcxbranch 行为。 - wrapper 计算
scaled_delta=0.1*raw_delta,调用 controller。 - decoder 的完整
153Daction按 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
2026Dinput、48D z_base与153D action的小型 parity fixture,并绑定 source/checkpoint hash;再对新 controller 做 same-device FP32 parity。 - 在 Isaac runtime 做 zero-residual closed-loop 诊断,保存完整 trace。
- 验证 ActionManager affine 只应用一次。
- 验证 PULSE
90Dhand slice 未被 primitive、reference 或 post-hook 覆盖。 - 将 trainer frozen audit 泛化为
assert_frozen_controller。 - 执行
2 env / 1 iteration / 24 stepsPPO 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 × 24update graph 的 CUDA OOM。 - 将 PPO mini-batch 执行改为
128 × 8gradient 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_*.py:160 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; 每100iterations 写 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=10、dt_future_ref_frames=0.1;smpl_num_future_frames=10、smpl_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 显式断言:
- policy/critic 20/22 term 的顺序;
20object tracking、40/20primary/assist grasp、10/5finger direction、0.1/0.05contact center,以及 object formula coefficients;0.25 mobject、0.3 mobject-z、3contacts /0.1force /50frames contact-failure constants;sample_before_contact=true、margin10、density300、massnull;- 仅 controller-interface 的
65D → 48D、primitive removal 与128 × 8execution micro-batching;PPO logical mini-batch 仍为4096 / 4 = 1024。
pulsex_checkpoint_path、latent_residual_scale、meta_action_dim、
tokenizer_action_dim、hand_action_dim、use_finger_primitive 和
use_motion_hand_actions 都是 required fields;新 PULSE path 必须用
config[...] 显式读取并在缺失时立即失败,不允许用默认值静默回退到 SONIC
或 PHC-X。
8. 验收标准
验收分为三层。前一层失败时不得声称后一层完成。
8.1 Layer A:代码合并验收
A1. Import 与依赖
- runtime 中只解析到一个顶层
phcpackage,来源为submodules/PHC/phc。 - checkpoint 可以来自
submodules/Omnigrasp/output/...,但pulsex_controller.py不 importsubmodules/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=0时z_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_2026、z_base、action_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/normalized2026Dobservation。 -
z_baseparity:atol=1e-6, rtol=1e-5。 - decoder
153Daction 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 的
90Dhand 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 不变。
-
actionsobservation term 继续记录 ActionManager 上一步执行的153DSMPL-X joint action;其 term、顺序和宽度不变。只有 PPO actor 输出及_last_meta_action/_prev_meta_actionreward 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-clip153D 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_forces为4096 × 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.json为exit_code=0。
任何一项失败都阻止正式 PPO,即使 2-env smoke 通过也不例外。
B3. PPO smoke
固定:
必须满足:
- 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
48Dresidual; - decoder 实际产生 finite/nonzero
153Daction; - 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=4、per_device_train_batch_size=128与gradient_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/3seeds 的 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:
- 新 controller 不能复现已有 PULSE teacher-forced 数值;
- 无法证明 encoder/decoder/RMS 在 PPO 中保持 frozen;
- 无法证明 hand output 未被覆盖;
- joint permutation 不是双射或 affine 被应用超过一次;
- GRAIL observation/reward/termination 出现 allowlist 之外的变化;
- 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 Minimal 与 Teacher 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 行新增/修改。
主要风险不是网络代码量,而是:
- PULSE loader 数值 parity;
- 2026D observation 的时间与 body-order 对齐;
153Daction permutation与单次 affine;- articulated hand output 不被旧 GRAIL primitive path覆盖;
- GRAIL PPO action-history与 latent regularizer 从旧维度正确迁移到
48D。
因此不需要推倒旧 A2-G 的 scene/reference/reward 工作;应保留约
70–80% 的 SMPL-X environment adaptation,只并行新增并替换 controller/action
backend,再在验收后完成命名与文档 canonicalization。