尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

【SONIC源码阅读系列2】运动数据到观测

【SONIC源码阅读系列2】运动数据到观测 现在开始整个系列的Phase 0 Phase 1。这一部分会刻意放慢一点因为后面 Universal Token、PPO 和 deployment 都建立在这里的数据定义之上。这次直接以当前 main 分支代码为准而不是只根据 SONIC report 复述。当前 repo 已经发展到包含 Default SONIC、Low-latency SONIC 和 v1.1因此个别参数会明确区分“原始 SONIC”和“当前代码”。(GitHub)Phase 0 VLA → SONIC 的边界0.1 最终部署系统当前 repo 给出的 VLA inference 是一个很好的入口Camera / Prompt │ ▼ ┌─────────────┐ │ VLA │ │ Isaac-GR00T │ └──────┬──────┘ │ action / motion │ ▼ ┌─────────────────┐ │ SONIC │ │ C WBC │ └────────┬────────┘ │ joint control │ ▼ G1launch_inference.py实际上就是把这个系统串起来它启动 C SONIC deployment同时启动 Python VLA inference client、keyboard publisher以及可选的数据 exporter。(GitHub)所以这里首先要纠正一个非常容易产生的误解SONIC 并不负责“理解 pick up the cup”。例如pick up the cup │ ▼ VLA [task → action / motion intent] │ ▼ motion/action │ ▼ SONIC [motion intent / reference → physically executable whole-body behavior] │ ▼ G1 motion这也是为什么 NVIDIA 可以把两者独立训练、独立部署。当前官方 VLA workflow 就是teleop data ↓ fine-tune Isaac-GR00T ↓ PolicyServer ↓ launch_inference.py ↓ SONIC ↓ G1而不是重新训练一个端到端image language → motor torque的巨大模型。(GitHub)0.2 重要发现SONIC Action Space这里开始出现一个非常有意思的接口。当前 VLA Inference 文档明确写unitree_g1_sonic的 action space 是78 dimensions(GitHub)64-dim motion token 7-dim left hand joints 7-dim right hand joints 78这意味着VLA │ ▼ ┌──────────────────┐ │ 78-D action │ ├──────────────────┤ │ 64-D motion token│ │ 7-D left hand │ │ 7-D right hand │ └────────┬─────────┘ │ ▼ SONIC这说明一个非常重要的架构事实SONIC 的 64-D token 并不只是内部 latent。至少在当前 VLA 接口中它已经成为一个可以由上层 policy 操作的action-level interface。问题Universal Token 到底是 latent representation还是 robot control interface初步判断是两者兼具。但我们后面必须通过代码把它证明出来而不是先下结论。0.3 SONIC 并不是“VLA 后面的 PD Controller”这一点也非常重要。传统机器人 pipelineVLA ↓ target pose ↓ IK ↓ joint target ↓ PD ↓ motorSONIC 更像VLA / Motion Source ↓ motion representation ↓ ┌──────────────────────┐ │ SONIC │ │ │ │ representation │ │ ↓ │ │ whole-body policy │ │ ↓ │ │ robot action │ └──────────┬───────────┘ ↓ low-level所以 SONIC 的贡献不是做了一个更好的 IK而是把 whole-body coordination 本身学习成一个 generalist policy。这和 SONIC report 的定位一致官方现在把 SONIC 定义为 humanoid behavior foundation model通过 scalable motion tracking 从大规模 human motion 中学习统一的 whole-body behavior。(GitHub)Phase 1Motion Reference → Observation现在正式进入源码。整个 SONIC 从这里开始因为policy 学什么首先由 observation 决定。1.1 Training 的真正入口当前训练命令python gear_sonic/train_agent_trl.py \ expmanager/universal_token/all_modes/sonic_release(GitHub)入口gear_sonic/train_agent_trl.pytrain_agent_trl.py │ ├── Hydra config │ ├── environment │ ├── actor │ ├── critic │ └── trainer然后 Hydra 加载 architectureconfig/base.yaml │ ▼ exp/manager/universal_token/all_modes/sonic_release.yaml │ ├── algo ├── actor_critic ├── manager_env ├── observations ├── rewards ├── terminations ├── events └── aux_losses官方 training-code 文档已经把这条 composition chain 明确列出来。(GitHub)1.2 Configuration hierarchy当前 release 的核心配置是sonic_release │ ├── algo │ └── ppo_im_phc │ ├── actor_critic │ └── universal_token/all_mlp_v1 │ ├── manager_env │ │ │ ├── observations │ │ ├── tokenizer │ │ ├── policy │ │ └── critic │ │ │ ├── rewards │ │ │ ├── terminations │ │ │ └── events │ ├── aux_losses │ └── trainer └── PPO auxiliary loss(GitHub)这已经开始暴露出 SONIC 的核心结构Environment │ ┌────────────┼────────────┐ │ │ │ ▼ ▼ ▼ tokenizer policy critic │ │ │ ▼ ▼ ▼ Encoder Actor Value │ ▼ Universal Token │ ▼ Decoder注意tokenizer 和 policy 是两个不同的 observation group。1.3 SONIC 的 Observation 并不是一个 vector看当前gear_sonic/envs/manager_env/mdp/observations.py。它定义了大量 observation terms。比如 policy group 里包括joint_pos joint_vel base_ang_vel gravity_dir actions以及大量 motion-reference termscommand_multi_future command_multi_future_joint_pos command_multi_future_joint_body_pos command_multi_future_joint_body_diff_pos ... smpl_joints_multi_future ... motion_anchor_ori_b_mf ...同时还有 teleoperationvr_3point_target_multi_future vr_3point_orn_target_multi_future vr_wrists_local_pos_target vr_wrists_local_orn_target vr_head_local_orn_target等等。(GitHub)因此更准确的抽象应该是Observation │ ┌─────────────────────┼─────────────────────┐ │ │ │ ▼ ▼ ▼ Motion Reference Robot State Teleop / SMPL │ │ │ └─────────────────────┬─────────────────────┘ ▼ observation dict然后再根据用途拆成obs_dict │ ├── tokenizer ├── policy ├── critic ├── ...1.4 为什么要拆成 tokenizer / policy / critic这是第一个值得研究的设计。官方文档明确Policy给 actor 的joint_pos joint_vel base_ang_vel gravity_dir last_actions ...Critic可以拿到 privileged informationbase_lin_vel body_pos body_ori ...Tokenizer给 UniversalTokenModulemulti-future joint commands SMPL joints VR targets anchor orientations ...(GitHub)因此Environment │ ┌───────┴───────┐ │ │ motion ref robot state │ │ ▼ ▼ ┌──────────┐ ┌──────────┐ │ Tokenizer│ │ Policy │ │ Obs │ │ Obs │ └────┬─────┘ └────┬─────┘ │ │ ▼ │ Universal │ Token │ │ │ └──────┬────────┘ ▼ Actor这个结构说明SONIC 的 motion representation learning 和 control policy 并不是完全相同的东西。它们之间存在一个明确的 bottleneckmotion observations ↓ tokenizer ↓ universal token ↓ actor这就是下一阶段要重点扒开 Universal Token 的原因。1.5 Motion Reference 来自哪里进入gear_sonic/envs/manager_env/mdp/commands.py核心类TrackingCommand当前代码对它的定义非常明确TrackingCommand是 SONIC-style motion tracking RL environment 的 primary command term。它负责加载 motion librarysample motion IDsample episode start time每个 simulation step 推进 motion cursor提供 current reference提供 multi-future reference提供 joint/body/root/SMPL 等数据做 robot-local / egocentric / heading-canonicalized transformation。(GitHub)所以整个 motion pipeline 实际上是Motion Dataset │ ▼ Motion Library │ ▼ TrackingCommand │ ┌────────┴────────┐ │ │ current frame future frames │ │ └────────┬────────┘ ▼ observations1.6 Future Reference 是怎么生成的这里终于可以把 report 里的“lookahead”落实到代码。当前配置target_fps 50 Hz num_future_frames 10 dt_future_ref_frames 0.1 s来自当前configuration.md。(GitHub)但是这里有一个非常值得注意的细节当前 training config 的dt_future_ref_frames是0.1 s。也就是说训练配置中的未来 referencet t 100ms t 200ms ...而模型 card 对 released deployment model 描述的是10 future frames 20 ms spacing ≈ 200 ms lookahead(GitHub) 因此不要简单把 README 的 release checkpoint observation protocol 和当前 training config 当成完全相同的东西。这是我们后面必须仔细追的一个版本差异。TrackingCommand内部实际上按照frame_skipsdt_future_ref_frames*target_fps计算未来帧间隔然后future_time_steps_initarange(num_future_frames)*frame_skips也就是future_time_steps [0, frame_skip, 2*frame_skip, ...](GitHub) 这才是实际 motion sampling mechanism。1.7 所以一个 Motion Clip 到底发生了什么假设某条 motionM {x0, x1, x2, ..., xN}每个 motion frame 是x_t { root pose body pose joint pose velocity orientation ... }episode reset 时motion_id k start_time t0然后第n个 RL stepcurrent_time t0 n * ΔtTrackingCommand 给出x(t) x(t Δt_ref) x(t 2Δt_ref) ... x(t HΔt_ref)因此 policy 看到的不是“机器人现在应该在哪里”而更接近“机器人现在在哪里 未来一段时间 reference 会怎么变化”这其实是 SONIC 的一个非常重要的 inductive biascontrol policy 是 trajectory-conditioned而不是 single-pose-conditioned。1.8 更重要Reference 会被变换到机器人坐标系observations.py里面大量出现*_b *_l *_w *_mf这几个后缀非常值得我们在以后形成条件反射w world frame b body / local frame l local / heading-related frame mf multi-future例如motion_anchor_ori_b_mf可以理解成motion anchor orientation ↓ body/local frame ↓ multiple future frames而smpl_joints_multi_future就是SMPL joints ↓ multiple future frames1.9 为什么不直接把 World-frame Pose 给 Policy这是 SONIC 非常典型的 robot learning design。假设reference: root (10m, 5m)policy 其实不应该关心“机器人在世界坐标的 x10, y5。”它应该关心 “reference 相对于我现在的位置在哪里”所以代码大量做world frame ↓ anchor frame ↓ robot local frame例如motion_anchor_gravity_dir()world gravity ↓ inverse(anchor quaternion) ↓ anchor-local gravity代码直接实现了这个变换。(GitHub)这说明 SONIC 的 observation design 在努力做到把 global trajectory 转换成 robot-centric control problem。1.10 一个特别值得关注的变化v1.1这里和当前 repo 的 evolution 有关系。最新 SONIC v1.1 使用robot-heading-normalized target orientation并加入wrist-pose augmentation官方说这是为了提高 whole-body teleoperation 和 VLA execution 的 heading stability。(GitHub)这说明一个很有研究价值的事实SONIC 的 performance 很大程度上取决于 reference coordinate representation。不是network bigger → performance better而可能是better reference parameterization ↓ easier learning problem ↓ better whole-body control1.11 Phase-1 数据流现在不要急着进入 network。先把我们已经追到的部分固定下来Motion Dataset │ ▼ Motion Library │ ▼ TrackingCommand │ ┌───────────┼────────────┐ │ │ │ current future SMPL frame frames frames │ │ │ └───────────┼────────────┘ │ ▼ coordinate transforms │ ┌──────────────┼──────────────┐ │ │ │ ▼ ▼ ▼ Tokenizer Policy Critic observations observations observations │ │ │ │ │ │ ▼ │ ▼ Encoder │ Value network │ │ ▼ │ Universal Token │ │ │ └──────┬───────┘ ▼ Actor [Decoder] │ ▼ Action1.12 Decoder的输入之前说Motion → Encoder → 64-D token → Policy [Decoder] → Action这个说法作为高层理解没错但现在看源码后需要精确化。当前UniversalTokenModule的代码 docstring 实际写的是tokenizer_obs ↓ encoder(s) ↓ latent ↓ FSQ ↓ token ↓ decoder(s) ↓ action_mean而且 decoder 还可以同时接收token proprioception也就是说更加准确的是motion/reference │ ▼ tokenizer obs │ ▼ ┌──────────────────┐ │ Encoder(s) │ │ │ │ G1 │ │ SMPL │ │ Teleop │ └────────┬─────────┘ │ pre-quant latent │ ▼ FSQ │ universal token │ ▼ ┌──────────────────┐ │ Decoder(s) │ │ │ │ proprioception │ └────────┬─────────┘ │ ▼ action_mean当前源码明确把它实现成UniversalTokenModule并且其forward()明确返回action_meanaux_lossesdecoded_outputstokenizer_obsencoder_masksencoded_tokensencoded_latents(GitHub)这其实比我们最开始画的架构更加有意思。1.13 不止“一个 Encoder”当前UniversalTokenModule明确是encoders ModuleDict可以有g1 smpl teleop soma ...当前 release configuration 使用G1 Encoder SMPL Encoder Teleop Encoder而 extended Bones-SEED configuration 还可以加入 SOMA encoder。(GitHub)所以真正的 architecture 是G1 reference │ ▼ G1 Encoder ──┐ │ SMPL ────────┤ │ │ ▼ │ SMPL Encoder ──┼──→ FSQ → shared token │ Teleop ──────┤ │ │ ▼ │ Teleop Encoder ─┘这才是 Universal Token 真正的含义。1.14 那么“Universal”究竟是什么意思现在我们可以给出一个暂时性的、源码支持的定义Universal 并不是说一个 encoder 能理解所有 motion。恰恰相反G1 → G1 encoder SMPL → SMPL encoder Teleop → Teleop encoder每一种输入都有自己的 encoder。真正 universal 的地方是different modality ↓ different encoder ↓ same shared latent/token space ↓ common decoder/control interface即modality-specific encoders │ ┌────────────┼────────────┐ │ │ │ G1 SMPL Teleop │ │ │ ▼ ▼ ▼ Enc-G1 Enc-SMPL Enc-Teleop │ │ │ └────────────┼────────────┘ ▼ FSQ │ ▼ Universal Motion Token │ ▼ G1 Decoder │ ▼ Robot Action这其实是笔者认为整个 SONIC architecture 最漂亮的地方之一。1.15 跨模态对齐机制当前代码中明确出现了 encoder mask combinationsg1 ↔ smpl teleop ↔ smpl g1 ↔ teleop g1 ↔ soma以及 auxiliary lossesG1-SMPL alignment cycle consistency ...UniversalTokenModule的 forward 还专门保留encoded_latents encoded_tokens aux_losses encoder_masks(GitHub)这意味着 Universal Token 并不是三个 encoder ↓ 简单 concat ↓ decoder而是在训练过程中存在一种让不同 encoder 产生相互兼容 latent 的机制。这就是我们下一章必须重点拆开的地方。1.16 最初的第一个研究问题QSONIC 到底看到了什么答案现在已经相当清楚它同时拥有三类信息① Reference motioncurrent future可能来自G1 SMPL Teleop② Robot proprioception例如joint_pos joint_vel base_ang_vel gravity_dir last_actions③ Privileged state训练 critic例如base_lin_vel body_pos body_ori height map ...(GitHub)所以它是Motion Reference │ ▼ Token │ │ Robot State ───────────┤ ▼ Controller │ ▼ Action也就是motion-conditioned state-feedback control1.17 第二个研究问题为什么要 future reference现在也可以更准确地回答。如果只给x_ref(t)policy 需要自己从x_ref(t)推断dx_ref/dt d²x_ref/dt² future contact future balance而现在直接给x_ref(t) x_ref(tΔ) x_ref(t2Δ) ...于是 policy 实际上获得trajectory context因此它学习的是π(a_t | s_t, R_{t:tH})这对 humanoid 尤其重要因为当前 pose 通常不足以决定下一步脚该落在哪里 身体 momentum 怎么变化 手臂应该如何配合所以 future reference 是一个非常合理的control inductive bias。1.18 一个小问题既然 SONIC 给了 future trajectory为什么还需要一个 learned latent token理论上完全可以future reference robot state ↓ MLP ↓ action为什么还要reference ↓ encoder ↓ FSQ ↓ 64D token ↓ decoder ↓ action判断是Universal Token 并不主要是为了“压缩”。真正的意义更接近把不同 motion modalities 映射到一个统一的 control representation。也就是SMPL G1 Teleop SOMA ... ↓ shared latent ↓ same controller这比单纯 compression 更重要。下一阶段我们验证这个判断。Phase 1 小结┌──────────────┐ │ VLA / Teleop │ └──────┬───────┘ │ ▼ Motion Reference │ ┌────────────┼────────────┐ │ │ │ G1 SMPL Teleop │ │ │ └────────────┼────────────┘ ▼ TrackingCommand │ ▼ Current Future Motion │ ▼ Coordinate Transform │ ┌─────────┴─────────┐ │ │ ▼ ▼ Tokenizer Policy │ │ ▼ │ Encoder(s) │ │ │ ▼ │ FSQ │ │ │ ▼ │ Universal Token │ │ │ └────────┬──────────┘ ▼ Decoder │ proprioception │ ▼ Action │ ▼ G1 / WBC下一阶段进入核心Phase 2 — Universal Token不再做高层概括直接沿着当前代码gear_sonic/trl/modules/universal_token_modules.py往下追。这个文件目前有1256 行里面已经把 SONIC 的核心机制基本暴露出来了。(GitHub) 我们重点逐行搞清楚tokenizer_obs ↓ encoder_index ↓ encoder_masks ↓ G1 / SMPL / Teleop Encoder ↓ pre-quantization latent ↓ FSQ ↓ 64-D token ↓ latent residual ↓ G1 Dynamic Decoder ↓ action_mean尤其重点帮解决三个问题①64-D 到底是怎么来的不是只说“FSQ 输出 64-D”而是把num_fsq_levels fsq_level_list max_num_tokens down_t全部对应到数学上的 latent shape。②为什么 G1 / SMPL / Teleop 可以共用一个 token space我们会追encoder masks encoder sampling auxiliary losses latent alignment reconstruction最后回答这个 shared latent space 到底是怎么被训练出来的。③为什么 Decoder 还要 proprioception这是一个非常关键的问题token proprioception ↓ decoder ↓ action为什么 token 本身不能决定 action这个问题实际上会把我们带进 SONIC 最核心的representation vs control分工。
返回列表