REPRODUCTION REPORT • 2026-07-26

RynnWorld-4D:复现、Pipeline 与模型规模

Stage-3 EMA world model 的 50-step RGB/Depth/Flow 联合生成已跑通;报告进一步按代码和 checkpoint 解剖 14.8206B 主干、各种 fusion 模式、policy 数据流与下游开发边界。

结论先行

World model
PASS

官方 Stage-3 + EMA,50 steps,6 路 MP4 均产生。

Action policy
EXECUTION PASS

1×10×54 输出成功;随机 head 不能作为机器人控制策略。

Integrity
11 / 11 OK

World raw、EMA、DA3 与 Wan 主要分片逐文件 SHA-256 通过。

关键边界:官方 ModelScope/Hugging Face 发布物只有 world-model raw/EMA;代码仓库包含 policy 架构与 inference example,但没有训练后的 action-policy checkpoint。因此 policy 结果只证明端到端程序、DA3 前处理和张量形状正确,不代表任务成功率或可部署控制质量。

结合结构图还原端到端 Pipeline

图中其实叠放了两条计算路径:上半部是可解码的 4D world generation;下半部是只取中间 latent feature 的 action policy。两者共享 RynnWorld-4D 主干,但推理步数、加载组件和输出语义完全不同。

flowchart LR
  TXT["任务文本"] --> T5["UMT5-XXL
77/512 × 4096"] RGB0["首帧 RGB"] --> VAE1["Wan VAE encoder"] DEP0["首帧 Depth"] --> VAE2["同一套 VAE encoder"] FLO0["t=0 零光流"] --> VAE3["同一套 VAE encoder"] VAE1 --> ZR["RGB latent
48×21×30×40"] VAE2 --> ZD["Depth latent
48×21×30×40"] VAE3 --> ZF["Flow latent
48×21×30×40"] T5 --> DIT["30-block 三分支 DiT
50 次 flow-shifted denoise"] ZR --> DIT ZD --> DIT ZF --> DIT DIT --> DR["VAE decoder → RGB 81 帧"] DIT --> DD["VAE decoder → Depth 81 帧"] DIT --> DF["VAE decoder → Flow 81 帧"]

三个“VAE Encoder/Decoder”是同构、同权重的 Wan VAE 调用,不是三套各 705M 的独立常驻模型。噪声位于 VAE latent;Rynn block 预测三路 latent 的去噪方向。

flowchart LR
  CAM["当前 RGB observation"] --> VAE["VAE 编码 RGB"]
  CAM --> DA3["DA3 估计当前深度"]
  DA3 --> VAEDEP["VAE 编码 Depth"]
  ZERO["首帧零光流"] --> VAEF["VAE 编码 Flow"]
  EMB["预计算 UMT5 embedding"] --> WB["Rynn 前 20/30 blocks
单一 timestep=500"] VAE --> WB VAEDEP --> WB VAEF --> WB WB --> HOOK["Hook block 15
RGB/Depth/Flow 3×3072"] HOOK --> VF["Video Former 3D
336 latent tokens × 384"] STATE["54D proprio state"] --> FM["4+4 层 flow-matching DiT"] EMB --> FM VF --> FM FM --> ACT["4-step Euler ODE
10×54 action sequence"]

Policy 不先生成 81 帧视频:它只做一次 world-backbone 前向,在 block 15 取三模态特征,并在 block 19 后早停。因此图中从 world block 指向 policy 的箭头代表 latent feature,不是解码后的视频。

Self Attention

RGB、Depth、Flow 各自在自身时空 token 内建模;三套 Q/K/V 独立。

Cross Attention

这里是各分支对文本 embedding 的 cross-attention。三路 Q/输出独立,但文本 K/V 物理共享。

Joint Cross-Modal

RGB/Depth/Flow 互相提供 K/V;发布权重只在 0,3,…,27 共 10 个 block 激活。

代码中的融合模式与方向

模式跨模态路径每层新增适用含义
none无;三分支仅共享文本 K/V0三路并行 baseline,不能交换视觉几何信息
unidirectionalDepth/Flow → RGB2× Linear(3072,3072)让几何/运动辅助 RGB,不反向修改几何分支
bidirectionalDepth/Flow ↔ RGB4× Linear(3072,3072)轻量线性残差融合;没有完整 token-to-token 跨模态注意力
joint三模态 Q 对其他模态 K/V约 113.32M / 激活层发布 Stage-3;frame-wise + 3D RoPE,共 10 层
容易误读的命名:普通 block 的 unidirectional 是 Depth/Flow → RGB;joint block 的 joint_unidirectional=True 则是 RGB 只作为 K/V teacher,Depth/Flow ← RGB。两处“单向”的箭头正好相反。

发布 Stage-3 的实际开关

fusion=jointshare_ffn=False、block 0–29 每 3 层插入一次 joint,共 10 次。

joint_frame_wise=True 把跨模态注意力限制在同一时间帧,避免跨时间混合造成运动模糊,并把注意力长度从 3TS 降到每帧 3S。

joint_use_rope=True 对 joint Q/K 应用与三分支对齐的 3D RoPE;joint_unidirectional=False 表示三路双向交换。

Stage-3 训练把 joint_gate_video_decay 从 1 衰减到 0:后期逐步切断 Depth/Flow 对 RGB 的回写,让 RGB 维持生成质量,同时 RGB 仍可作为 Depth/Flow 的信息源。

Checkpoint + Code 参数规模审计

以下不是按文件大小反推:safetensors 由 tensor header 逐项计数,DeepSpeed raw checkpoint 以 data pointer + offset 去重别名。特别是三路 text cross-attention 的 K/V 指向同一 Parameter,直接累加 2723 个 state_dict entry 会虚高到 15.954B。

组件参数权重驻留
Rynn full joint transformer14.8206B27.606 GiB BF16
Policy truncated Rynn 20/309.9490B18.531 GiB BF16
UMT5-XXL encoder5.6809B10.582 GiB BF16
Wan VAE704.689M1.313 GiB BF16
DA3-LARGE410.942M1.531 GiB FP32
Video Former 3D22.870M87.2 MiB FP32
Flow-matching policy28.234M107.7 MiB FP32

Rynn 14.8206B 如何组成

  • RGB/base branch:4.34264B(29.30%)
  • Depth branch:4.34264B(29.30%)
  • Flow branch:4.34264B(29.30%)
  • 共享 text K/V:566.508M(3.82%)
  • 10 个 joint block:1.13317B(7.65%)
  • 共享 conditioning + 三路 I/O:约 93.0M(0.63%)

磁盘、参数和显存不是一回事

  • raw 文件 29.83 GB;EMA 文件 29.45 GB。world inference 先载 raw,再用 2383 个 EMA tensor 覆盖,不会在 GPU 同时常驻两套主干。
  • EMA 少 340 个 state_dict key:其中 300 个是共享 text K/V 的 depth/flow 别名,另 40 个是 raw 保留的 video-side joint output/gate/buffer。
  • World 权重理论底座约 39.50 GiB(Rynn + UMT5 + BF16 VAE),实测峰值 75.15 GiB;差额来自 50-step 三分支 activations、attention 临时张量、VAE decode 与 CUDA allocator。
  • Policy 跳过 UMT5、物理删除后 10 个 block、DA3 用后回 CPU,实测峰值 20.98 GiB。

运行环境

硬件

GPU8× NVIDIA H20,95.1 GiB/卡
Driver580.105.08
Host RAM2 TiB
执行卡GPU 3 / GPU 6

软件

Python3.10.20
PyTorch2.6.0+cu124
diffusers0.35.2
transformers4.57.1
Repo revision2c748539849ada70d9148327e2195543ba3a921a

下载阶段仅对单条命令临时移除本机 127.0.0.1:7890 代理;代理会截断多 GB TLS 流。运行环境本身未修改全局代理配置。

模型来源与完整性

发布物大小SHA-256结果
Wan transformer 5 shards20.00 GB5 hashesOK
Wan UMT5 3 shards11.36 GB3 hashesOK
Wan VAE2.82 GB62cd18…OK
RynnWorld raw29.83 GBc69344…OK
RynnWorld EMA29.45 GBa08bcb…OK
DA3-LARGE1.64 GBeaf2ae…OK

World model:正式 50-step 结果

输入为官方 data/sample.json 第一个 agibot latent:左臂从篮子拿起红苹果并放入购物车。使用双向 joint attention、3D RoPE、每 3 层融合、EMA。

Wall time
11m 48s
Peak GPU memory
75.2 GiB
Avg util / peak power
81.9% / 436 W

左到右:generated RGB / depth / optical flow。压缩预览仅用于浏览,原始 MP4 保留在结果目录。

RynnWorld six-stream temporal montage
streamframesresolutionfpsfile size
rgb81640×48016.00.27 MiB
depth81640×48016.00.05 MiB
flow81640×48016.00.16 MiB
gt81640×48016.00.29 MiB
gt_depth81640×48016.00.06 MiB
gt_flow81640×48016.00.26 MiB

Action policy:官方程序链路结果

DA3 已先在 Tianji 官方样例首帧上独立前向成功(224×392 float32 depth,forward 约 0.56s),随后完整加载 world backbone、Video Former 和 flow-matching head。

Output
1×10×54
dtype
torch.float32
Wall time
2m 5s
Peak GPU
21.0 GiB
Action tensor heatmap and selected dimensions

随机初始化 head 的数值统计:min -3.9241,max 2.3571,mean 0.0107,std 1.0366。这些数字不可解释为控制精度。

Policy head 的 token 与层级细节

Video Former 3D · 22.870M

  • 输入通道:RGB/Depth/Flow hook feature 拼接,3072×3=9216。
  • goal_emb:9216→768→384,占 7.374M。
  • 336 个 learnable latent,按 21 帧×16 token 排列;6 层逐帧 Perceiver attention + temporal attention + FFN。
  • 输出 [B,336,384],把高分辨率 world token 压缩为 policy observation token。

Flow Matching DiT · 28.234M

  • 条件:32 个 UMT5 goal token、336 个视觉 token、1 个 54D proprio token和 flow time embedding。
  • 4 层 encoder + 4 层 decoder,hidden=384,8 heads;动作 horizon=10,action_dim=54。
  • 从高斯动作噪声出发,4 次 Euler 更新得到 [B,10,54];部署 step() 每 10 个控制周期重规划一次。
  • 公开仓库没有这 51.10M policy head 的训练 checkpoint;目前输出只是随机网络的合法张量。

基于该模型的下游开发地图

最值得利用的不是“再生成一个视频”,而是三模态对齐 latent:RGB 给语义外观,Depth 给几何,Flow 给运动。下面按落地成本区分立即可做、需要数据训练和需要改架构的方向。

现在即可验证

冻结主干 + 小头

  • block 15 三模态 feature probing:动作阶段、接触、物体状态分类。
  • RGB-D-flow 检索、视频片段匹配、语言条件事件定位。
  • 2D point tracking + depth lifting,构造近似 3D scene flow / 轨迹。
  • 三路预测不一致度作为 OOD、异常动作和失败预警信号。
需要标注/训练

策略与规划

  • 用 Tianji/LeRobot episode 训练缺失的 51.10M policy head;先冻结 world,再逐层解冻或 LoRA。
  • 学习 success/reward/collision head,对候选轨迹或 action chunk 排序。
  • 离线 imitation / offline RL:把 336×384 world token 当作统一 observation。
  • 多任务 action tokenizer 与不同机器人 embodiment 的动作 retargeting。
需要改主干

闭环 World Model

  • 把 action sequence 注入 world DiT,训练 action-conditioned dynamics;当前模型只有首帧+文本条件。
  • 基于 latent imagination 的 MPC:采样动作→rollout→reward/risk 打分→执行首个 chunk。
  • 多相机 joint attention、相机内外参 token 与跨视角 3D 对齐。
  • 蒸馏/consistency/量化到实时 backbone,加入 recurrent memory 做在线闭环。
推荐优先级最小实验成功指标主要风险
P0冻结 block15,训练 contact/success probe相对 RGB-only 的 AUC / F1 增益feature 对真实传感器 domain shift
P0补齐 Tianji 54D action head 训练offline action MSE + rollout success公开权重缺失;动作归一化定义必须一致
P1三模态不一致度失败预测提前量固定时的 failure AUROC生成不确定性与真实风险不完全等价
P1action-conditioned adapter未来 RGB/depth/flow + state prediction需要动作对齐的长序列数据和高训练成本
P2latent MPC / candidate ranking闭环成功率、碰撞率、规划延迟50-step rollout 太慢,必须先蒸馏或单步化
边界条件:Depth 是单目 DA3 估计而非保证公制准确;Flow 是视频像素运动而不是直接的 3D scene flow;world model 当前不接收机器人 action。因此“4D”不能直接等同于可用于控制的度量 3D 动力学模型,必须用相机标定、真实 depth/pose 和闭环指标重新验证。

为跑通官方发布物所需的兼容性修复

  1. inference-sft.py 补入 model card 使用、但 CLI 原本缺失的 --joint_unidirectional,并传入 Stage-3 transformer。
  2. 取消约 30 GB raw checkpoint 无条件复制到 /tmp;改为原地 mmap,并保留显式缓存目录开关。本机根分区只有 51 GB 可用。
  3. world example 显式使用 --per_dataset_samples 0;否则默认值会忽略 sample.json,转而扫描本机不存在的数据集 JSON。
  4. VPP_Policy 构造函数补齐 YAML 已声明的 joint-attention 与 DA3 参数;原配置无法被 Hydra 正常实例化。
  5. policy YAML 指向实际 ModelScope 目录,并清空会覆盖正确 world checkpoint 的错误 sft_ckpt_path
  6. 修复 safetensors 中读取字符串 text.decode() 的崩溃:safetensors 只保存 tensor,官方 bundled embedding 没有该字符串字段。
  7. 补齐 DA3 API 实际导入所需的 evogsplat 只服务 3DGS rendering,不影响本次 depth inference。

可复现命令

仓库新增了三个入口:setup_runtime.shdownload_modelscope.shrun_verified_examples.sh。正式执行命令如下。

World model

CUDA_VISIBLE_DEVICES=3 python inference-sft.py \
  --model_path ./pretrained/Wan2.2-TI2V-5B-Diffusers \
  --checkpoint_path ./pretrained/RynnWorld-4D \
  --json_path ./data/sample.json --output_dir ./results/official-world \
  --fusion_mode joint --share_ffn False \
  --joint_start_layer 0 --joint_end_layer 30 --joint_every_n_layers 3 \
  --joint_frame_wise True --joint_use_rope True \
  --joint_unidirectional False --zero_fusion False --use_ema True \
  --num_inference_steps 50 --guidance_scale 1.0 \
  --per_dataset_samples 0 --max_samples 1 --keep_on_gpu True

Action policy program smoke

cd rynnworld4d_policy
CUDA_VISIBLE_DEVICES=6 PYTHONPATH=. python inference_with_embeddings.py \
  --embedding_path ./text_embeddings/pick_up.safetensors \
  --checkpoint_path "" --output_dir ../results/official-policy \
  --device cuda --seed 42

原始证据与来源

World inference log(节选)
✅ [Monkey Patch Applied] `WanTimeTextImageEmbedding.forward` has been replaced to ensure float32 stability during mixed-precision training.
✅ [Monkey Patch Applied] `WanTimeTextImageEmbedding.forward` has been replaced to ensure float32 stability during mixed-precision training.
✅ [Monkey Patch Applied] `WanTransformer3DModel.forward` has been added control video latent.
Joint attention ENABLED at inference. Output dir suffixed: ./results/official-world_joint-on
  sample.json: selected 1 samples
Total samples to process: 1
Loading pipeline ...

Loading checkpoint shards:   0%|          | 0/5 [00:00<?, ?it/s]
Loading checkpoint shards:  20%|██        | 1/5 [00:00<00:00,  5.88it/s]
Loading checkpoint shards:  40%|████      | 2/5 [00:00<00:00,  6.06it/s]
Loading checkpoint shards:  60%|██████    | 3/5 [00:00<00:00,  6.20it/s]
Loading checkpoint shards:  80%|████████  | 4/5 [00:00<00:00,  6.25it/s]
Loading checkpoint shards: 100%|██████████| 5/5 [00:00<00:00,  7.50it/s]
Joint attention config: frame_wise=True, use_rope=True, unidirectional=False, layers=[0, 30) every 3.

Loading pipeline components...:   0%|          | 0/5 [00:00<?, ?it/s]The config attributes {'clip_output': False} were passed to AutoencoderKLWan, but are not expected and will be ignored. Please verify your config.json configuration file.

Loading pipeline components...:  40%|████      | 2/5 [00:00<00:00, 13.24it/s]`torch_dtype` is deprecated! Use `dtype` instead!


Loading checkpoint shards:   0%|          | 0/3 [00:00<?, ?it/s]
Loading checkpoint shards: 100%|██████████| 3/3 [00:00<00:00, 154.32it/s]

Loading pipeline components...:  80%|████████  | 4/5 [00:00<00:00,  7.07it/s]
Loading pipeline components...: 100%|██████████| 5/5 [00:00<00:00,  9.49it/s]
Loading SFT checkpoint from ./pretrained/RynnWorld-4D/pytorch_model/mp_rank_00_model_states.pt ...
  Memory-mapping checkpoint in place.
Checkpoint has 2723 keys.
SFT checkpoint loaded incrementally. Loaded: 2723, Missing: 0.
EMA weights loaded from ./pretrained/RynnWorld-4D/ema_weights.pt (2383 params overridden).
Scheduler flow_shift = 5.0 (flow-shifted sigma).
Skipping fusion layer zeroing — using trained fusion weights.
VAE tiling DISABLED (workaround for diffusers tiled_decode shape bug).
Pipeline ready (kept entirely on GPU; faster but more VRAM).

Initial VRAM: 72.07 GB
[1/1] [sample] The robot uses its left arm to pick up a red apple from a basket and places it i

  0%|          | 0/50 [00:00<?, ?it/s]
  2%|▏         | 1/50 [00:11<09:06, 11.15s/it]
  4%|▍         | 2/50 [00:22<08:50, 11.06s/it]
  6%|▌         | 3/50 [00:33<08:38, 11.04s/it]
  8%|▊         | 4/50 [00:44<08:26, 11.02s/it]
 10%|█         | 5/50 [00:55<08:15, 11.01s/it]
…
 32%|███▏      | 16/50 [02:56<06:13, 10.99s/it]
 34%|███▍      | 17/50 [03:07<06:02, 10.99s/it]
 36%|███▌      | 18/50 [03:17<05:51, 10.99s/it]
 38%|███▊      | 19/50 [03:28<05:40, 10.99s/it]
 40%|████      | 20/50 [03:39<05:29, 10.99s/it]
 42%|████▏     | 21/50 [03:50<05:18, 10.99s/it]
 44%|████▍     | 22/50 [04:01<05:07, 10.99s/it]
 46%|████▌     | 23/50 [04:12<04:56, 10.99s/it]
 48%|████▊     | 24/50 [04:23<04:45, 10.99s/it]
 50%|█████     | 25/50 [04:34<04:34, 10.99s/it]
 52%|█████▏    | 26/50 [04:45<04:23, 10.99s/it]
 54%|█████▍    | 27/50 [04:56<04:12, 10.99s/it]
 56%|█████▌    | 28/50 [05:07<04:01, 10.99s/it]
 58%|█████▊    | 29/50 [05:18<03:50, 10.99s/it]
 60%|██████    | 30/50 [05:29<03:39, 10.99s/it]
 62%|██████▏   | 31/50 [05:40<03:28, 10.99s/it]
 64%|██████▍   | 32/50 [05:51<03:17, 10.99s/it]
 66%|██████▌   | 33/50 [06:02<03:06, 10.99s/it]
 68%|██████▊   | 34/50 [06:13<02:55, 10.99s/it]
 70%|███████   | 35/50 [06:24<02:44, 10.99s/it]
 72%|███████▏  | 36/50 [06:35<02:33, 10.99s/it]
 74%|███████▍  | 37/50 [06:46<02:22, 10.99s/it]
 76%|███████▌  | 38/50 [06:57<02:11, 10.99s/it]
 78%|███████▊  | 39/50 [07:08<02:00, 10.99s/it]
 80%|████████  | 40/50 [07:19<01:49, 10.99s/it]
 82%|████████▏ | 41/50 [07:30<01:38, 10.99s/it]
 84%|████████▍ | 42/50 [07:41<01:27, 10.99s/it]
 86%|████████▌ | 43/50 [07:52<01:16, 10.99s/it]
 88%|████████▊ | 44/50 [08:03<01:05, 10.99s/it]
 90%|█████████ | 45/50 [08:14<00:54, 10.99s/it]
 92%|█████████▏| 46/50 [08:25<00:43, 10.99s/it]
 94%|█████████▍| 47/50 [08:36<00:32, 10.99s/it]
 96%|█████████▌| 48/50 [08:47<00:21, 10.99s/it]
 98%|█████████▊| 49/50 [08:58<00:10, 10.99s/it]
100%|██████████| 50/50 [09:09<00:00, 10.99s/it]
100%|██████████| 50/50 [09:09<00:00, 10.99s/it]
  Saved ./results/official-world_joint-on/sample_0_rgb.mp4
  Saved ./results/official-world_joint-on/sample_0_gt.mp4
  Saved ./results/official-world_joint-on/sample_0_depth.mp4
  Saved ./results/official-world_joint-on/sample_0_flow.mp4
  Saved ./results/official-world_joint-on/sample_0_gt_depth.mp4
  Saved ./results/official-world_joint-on/sample_0_gt_flow.mp4
  VRAM after cleanup: 72.12 GB

All done.
Policy inference log(节选)
/nvme3/xinhai/micromamba/envs/rynnworld4d/lib/python3.10/site-packages/hydra/_internal/defaults_list.py:251: UserWarning: In 'train_config': Defaults list is missing `_self_`. See https://hydra.cc/docs/1.2/upgrades/1.0_to_1.1/default_composition_order for more information
  warnings.warn(msg, UserWarning)
Loaded text embedding: 'unknown' -> torch.Size([1, 77, 4096])
Loading rynnworld4d-policy...
✅ [Monkey Patch Applied] `WanTimeTextImageEmbedding.forward` has been replaced to ensure float32 stability during mixed-precision training.
✅ [Monkey Patch Applied] `WanTimeTextImageEmbedding.forward` has been replaced to ensure float32 stability during mixed-precision training.
✅ [Monkey Patch Applied] `WanTransformer3DModel.forward` has been added control video latent.

Loading checkpoint shards:   0%|          | 0/5 [00:00<?, ?it/s]
Loading checkpoint shards:  20%|██        | 1/5 [00:00<00:00,  5.77it/s]
Loading checkpoint shards:  40%|████      | 2/5 [00:00<00:00,  6.01it/s]
Loading checkpoint shards:  60%|██████    | 3/5 [00:00<00:00,  6.17it/s]
Loading checkpoint shards:  80%|████████  | 4/5 [00:00<00:00,  6.15it/s]
Loading checkpoint shards: 100%|██████████| 5/5 [00:00<00:00,  7.40it/s]
[WanFeatureExtractor] No safetensors index, falling back to DeepSpeed loading
  Loaded: 2723 keys, missing=0, unexpected=0

Loading pipeline components...:   0%|          | 0/4 [00:00<?, ?it/s]The config attributes {'clip_output': False} were passed to AutoencoderKLWan, but are not expected and will be ignored. Please verify your config.json configuration file.

Loading pipeline components...:  75%|███████▌  | 3/4 [00:00<00:00, 15.43it/s]
Loading pipeline components...: 100%|██████████| 4/4 [00:00<00:00,  7.43it/s]
[WanFeatureExtractor] Early-exit enabled: running 20/30 transformer blocks
[WanFeatureExtractor] Dropped 10 trailing transformer blocks (not loaded to GPU)
obs dim: 384, goal_dim: 4096, action_dim: 54, proprio_dim: 54
seq_size: 378
WARNING: no action-policy checkpoint supplied; the policy head is randomly initialized. This run validates execution and tensor shapes only.
Running inference...
[WARN ] Dependency `gsplat` is required for rendering 3DGS. Install via: pip install git+https://github.com/nerfstudio-project/gsplat.git@0b4dddf04cb687367602c01196913cde6a743d70
[WanFeatureExtractor] Loading DA3 from ../pretrained/da3
[INFO ] using MLP layer as FFN
Loading weights from local directory
[INFO ] Processed Images Done taking 0.0093841552734375 seconds. Shape:  torch.Size([1, 3, 392, 392])
[INFO ] Model Forward Pass Done. Time: 0.25443601608276367 seconds
[INFO ] Conversion to Prediction Done. Time: 0.00030612945556640625 seconds
Action sequence shape: torch.Size([1, 10, 54])
Current action shape: torch.Size([54])
First action: [-0.6341481 -1.9253476 -1.0167533 -1.6653363 -0.1967295] ...
Saved action to ../results/official-policy/action.pt