File size: 13,085 Bytes
fbd9366
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# T-Rex Track-Force:16-step、20 Hz 动作与 5 Hz 触觉模型

本文描述独立的 `trex_track_force` 模型、数据契约、embedding、注意力、两阶段
flow matching、训练和在线执行。它不会修改原 DreamZero 的模型调用路径。

## 1. 固定时序契约

- 每个 action chunk 含 **16 个动作**,动作频率为 **20 Hz**- 一个 chunk 覆盖 `16 / 20 = 0.8 s`;动作时间戳跨度为 `0.75 s`- 触觉频率为 **5 Hz**,因此每 **4 个动作步**刷新一次。
- 一个 chunk 内的触觉刷新 offset 固定为 `[0, 4, 8, 12]`- 每次刷新只重新去噪尚未执行的 action suffix;已经执行的前缀保持不变。
- `max_chunk_size=4` 保留 DreamZero 原有的 autoregressive block memory。
  这里的 `max_chunk_size` 是跨 block 的记忆窗口,不是单个 action chunk 的长度。
- 一个训练 sample 仍由 4 个 autoregressive blocks 组成,因此共有 64 个动作;
  只有每 block 的 action 长度从 24 改为 16。
- 三路视频保持 DreamZero 的 33 帧布局:1 帧 clean conditioning observation,
  后接每 block 8 帧、共 32 帧 10 Hz future-video targets。
- 每个 block 都有 16 帧过去 track 和 16 步 target track;target 的第 0 步就是
  当前 anchor 帧,与 OpenPI 的 track window 契约一致。

## 2. 总体架构

```mermaid
flowchart LR
    V["三视角 RGB\nhead + left wrist + right wrist"] --> GRID["三视角拼图\n160 × 320"]
    GRID --> VAE["Wan2.2 VAE38\n48-channel latent"]
    GRID --> CLIP["Wan CLIP\n图像条件"]
    TXT["任务文本"] --> T5["UMT5\n文本条件"]

    TRK["250 点 track\npast clean + future noisy"] --> TE["TrackEncoder\n几何 + 可见性 + 身份 embedding"]
    ACT["16 × 62D delta-base action\n补零到 64D"] --> AE["Action encoder"]
    ST["62D 当前 EEF/hand state"] --> SE["State encoder"]

    VAE --> WAN["CausalWanTrackForceModel\nWan2.2-TI2V-5B · 30 blocks"]
    CLIP --> WAN
    T5 --> WAN
    TE --> WAN
    AE --> WAN
    SE --> WAN

    WAN --> COARSE["τ: 1 → 0.4\n6-step coarse action"]
    WAN --> TFLOW["未来 track flow"]
    WAN --> VFLOW["未来 video flow"]
    WAN --> MEM["τ=0.4 coarse memory"]

    RAW["10 fingers × 6D force\n16-sample history"] --> VQ["Per-finger force VQ-VAE\n64 codes · 256D"]
    FRESH["当前 10 × 6D force"] --> FT["Force-only Transformer\n6 layers · width 768"]
    VQ --> FT
    MEM --> FT
    COARSE --> FT
    FT --> FINE["τ: 0.4 → 0\n4-step tactile action suffix"]
```

粗阶段负责从视觉、状态、语言和 track 中得到动作的大尺度结构;独立的
force-only transformer 只使用力信号和粗阶段 memory 完成剩余去噪,使触觉
负责接触后的细粒度修正。

## 3. 62DoF 动作空间

每只手臂占 31 维,两侧共 62 维:

- 手腕/末端位姿:`xyz + rotation-6D`,共 9 维。
- 手部关节目标:22 维。

训练动作不是世界坐标绝对位姿。loader 以 chunk 起始状态为 reference,把每个
目标手腕位姿转换为 **delta-base**- 平移在 chunk 起始手腕坐标系中表示。
- 旋转为 `R_reference^-1 × R_target`,再编码为 rotation-6D。
- 手部 22 维仍是绝对目标。

模型内部把 62 个物理维补零为 64 维;采样的两个 padding 维在初始化和每个
Euler step 后都会重新置零。输出先按 relative-action 统计量反归一化,再用
chunk 起始 state 恢复绝对 EEF 位姿。

## 4. Track 数据和点身份

250 个点具有固定、可验证的顺序:

- `0:50`:头部视角左手及手臂。
- `50:100`:头部视角右手及手臂。
- `100:125`:左腕视角 5×5 背景点。
- `125:175`:左腕视角手掌点。
- `175:200`:右腕视角 5×5 背景点。
- `200:250`:右腕视角手掌点。

SAM2 只在 episode 第 0 帧根据固定 prompt 产生手/臂 mask;点从 mask 中采样,
随后由 CoTracker 跟踪整段视频。保存字段为:

- `observation.track_xy``[250, 2]`,坐标归一化到 `[0, 1]`- `observation.track_visibility``[250]`- metadata 中同时记录 view、hand、role、point index 和各 segment 边界。

## 5. Embedding 设计

### 5.1 Video、语言和图像条件

- 三视角拼入 2×2 canvas 的三个有效格,再统一缩放到 `160×320`- Wan2.2 VAE38 生成 48-channel latent。
- `patch_size=[1,2,2]`,每 latent frame 形成 50 个 video tokens。
- video token 使用 Wan 原生 3D RoPE,编码时间、高度和宽度。
- UMT5 输出 4096D 文本条件。
- Wan CLIP 输出 1280D 图像条件,并经 `img_emb` 投影。
- CLIP/T5 cross-attention 只作用于 observation/action query,不向 track query
  泄漏视觉或语言信息。

### 5.2 Action 和 state

- action:每个 62D 动作补零到 64D,经线性层投影到 Wan hidden dim 3072。
- 一个 block 有 16 个 action tokens;位置由 1D action RoPE 编码。
- state:62D 当前状态补到 64D,经线性层得到一个 state token。
- flow 时间 `τ` 经 sinusoidal embedding 和 MLP 后参与 Wan modulation。

### 5.3 TrackEncoder

每个点分别产生一个 `past token` 和一个 `future token`。时间序列输入特征为:

```text
[x, y, visibility, Δx, Δy]
```

不可见时刻的坐标和 motion 先清零,随后完整的 `16×5` 时序按固定顺序展平,再经
`Linear → SiLU → Linear` 投影。不能在时间维求平均:future flow 的每个时刻含有
独立噪声,平均会丢失“哪一个噪声属于哪一个 timestep”,使 16-step 重建不可解。

最终每个点 token 是下列 embedding 的和,再经 LayerNorm:

```text
trajectory
+ view(head / left_wrist / right_wrist)
+ hand(none / left / right)
+ role(head_hand / wrist_background / wrist_hand)
+ canonical point id(0...249)
+ autoregressive block id
+ temporal role(past / future)
```

左右手不只通过点序号区分,还具有显式 hand embedding。背景点使用
`hand=none` 和独立 role embedding。

与 OpenPI 一致,track target 始终是 `[0,1]` 内的绝对归一化 XY;target window
从当前帧开始,因此第 0 步等于 GT anchor。`TrackDecoder` 对 250 个
future-track hidden token 分别执行 `LayerNorm → Linear(16×2)`,预测 CFM
velocity `noise-clean_xy`。Euler 积分后的结果已经是绝对坐标,不做空间
`cumsum`,也不再额外加 anchor。

### 5.4 Force-only VQ-VAE

输入只包含 force/wrench,不包含 deformation map:

```text
[batch, history=16, fingers=10, wrench=6]
```

- 两只手共享同一套时序卷积 encoder/decoder。
- 每只手内部加入 5 个 finger identity embeddings。
- 输出每根手指一个 256D latent,共 10 个 tactile history tokens。
- EMA codebook 大小为 64,带 commitment loss、perplexity 统计和 dead-code
  revival。
- 左右手通过 side embedding 区分,手指位置通过 finger embedding 区分。
- 训练可直接输入 raw 16-step history;推理也可输入预计算的 10 个离散 codes。
- episode 前缀缺失的历史填为归一化中性值,并用 validity mask 从 VQ 重建
  loss 中排除 padding 步。

### 5.5 Force-only Transformer

输入 token 包括:

- 16 个 noisy action tokens。
- 10 个当前 force tokens。
- 10 个 VQ history tokens。
- 从 Wan `τ=0.4` hidden state 提取的 coarse memory tokens。

action token 叠加 action position、5Hz force slot、token type、当前 refresh
offset 和 `τ` embedding。force/history token叠加 finger position、token type 和
refresh offset。独立 transformer 为 6 层、12 heads、hidden dim 768。

## 6. 非对称 attention 契约

每个 autoregressive block 的 packed 顺序为:

```text
[obs, action, state, track_past, track_future]
```

其可见性严格为:

- observation query 和 action query 在同一 block 内互相可见。
- observation/action query 可读取同 block 的 state、past track 和 noisy future
  track,也可读取有限 AR 窗口内的历史 obs/action/track。
- state query 只读取自己的 state token,避免把多模态信息反向带给 track。
- past-track query 读取历史 block 的 track 和当前 past track,但不能读取当前
  noisy future track。
- future-track query 只读取当前及历史 track。
- **任何 track query 都不能读取 observation、action、state、CLIP 或文本。**
- 任何 query 都不能读取未来 block。

因此实现了要求的方向性:`obs/action → track` 表示 obs/action 可以把 track
作为条件;反方向被 mask 禁止。

## 7. 两阶段 flow matching

使用线性插值:

```text
x_τ = τ · noise + (1 - τ) · clean
target flow = noise - clean
x_next = x_τ + (τ_next - τ) · predicted_flow
```

### 粗阶段:Wan,`τ=1 → 0.4`

- 训练时 action/Wan expert 遵循原始 T-Rex,在完整 `(0,1]` 上按
  `Beta(1.5,1.0)` 采样;其均值约为 `0.6`,但这不是 split timestep。
- Wan 联合预测 action flow、future-track flow 和 future-video flow。
- 推理按总计 10 个、`Δτ=-0.1` 的 Euler 网格运行前 6 步,到达 `τ=0.4`- 在精确的 `τ=0.4` 再执行一次 Wan,生成给触觉 transformer 使用的 detached
  coarse memory。

### 精阶段:触觉,`τ=0.4 → 0`

- 训练时 `τ_tactile = 0.4 × Beta(1.5,1.0)`,覆盖 `(0,0.4]`- 每个训练 chunk 对 offset `0/4/8/12` 分别提供对应的 force 与 16-sample
  history。
- offset 为 `k` 时,loss 只覆盖 action `k:16`- 推理运行剩余 4 个 Euler updates;每次 5Hz 刷新只写入未执行 suffix。
- runtime controller 保存之前已经发出的 prefix,确保后续触觉刷新不能改写历史
  command。

## 8. 训练 loss

总 loss 由以下部分加权求和:

- `dynamics_loss`:未来视频 latent flow MSE。
- `action_loss`:粗阶段 62 个物理动作维的 flow MSE。
- `track_loss`:可见性 mask 后的绝对 XY CFM velocity MSE。
- `force_loss`:按 refresh offset mask 后的动作 suffix flow MSE。
- `vq_loss`:仅在有效历史步计算的 force history reconstruction loss。
- `commitment_loss`:VQ commitment loss,默认系数 0.25。

训练使用 Wan2.2-TI2V-5B 共享权重和 LoRA。LoRA 注入
`q,k,v,o,k_img,v_img,ffn.0,ffn.2`;新建的 action/state/track/force、video token
投影和 decoder 完整训练。checkpoint 保存 LoRA、新模块参数以及 VQ EMA buffers。

## 9. 在线执行

1. 收集三视角 conditioning observation(在线接口也可编码多帧历史)、当前
   62D state、16 帧 past track、当前 force 和 16-sample force history。
2. Wan 对 action、future track 和 future video 运行 6 步,从 `τ=1``τ=0.4`3. offset 0 的触觉运行剩余 4 步,把完整 16-step action 去噪到 `τ=0`4. 以 20 Hz 执行动作。
5. 执行 4、8、12 步后,各接收一次新的 5Hz 触觉;每次从缓存的 coarse state
   重新去噪剩余 suffix,同时保留已执行 prefix。
6. 输出 delta-base 动作反归一化并恢复为绝对手腕 `xyz + rotation-6D`## 10. 入口

训练:

```bash
cd /scratch1/home/zhicao/dreamzero
bash scripts/train/trex_track_force_training_wan22.sh
```

训练脚本直接使用已经构建完成的 `data/trex_small`,启动前只执行 schema
完整性校验,不会再次运行 SAM2/CoTracker。

日志、checkpoint 与原 T-Rex 训练共用同一套 Trainer 回调。每隔
`wandb_video_reconstruction_steps` 个 global step 会分别保存两个监控视频:
不带标记的原始重建视频位于
`OUTPUT_DIR/eval_videos/train_step_XXXXXX.mp4`,20Hz 预测 track motion
叠加到 10Hz head/left-wrist/right-wrist 三面板后的版本位于
`OUTPUT_DIR/eval_track_videos/train_step_XXXXXX.mp4`。原始预测与目标
track 同时写入 `OUTPUT_DIR/eval_tracks/train_step_XXXXXX.npz`。两个视频
分别记录到 W&B `eval/predicted_video``eval/predicted_track_video``dynamics/action/track/force/VQ/commitment` loss 和触觉 codebook
perplexity/active-code 指标同时写入 W&B 与 `OUTPUT_DIR/loss_log.jsonl`。
两个视频的首帧都是精确 GT conditioning frame;track target/prediction 的第 0
步在模型链路内就是当前 GT anchor。可视化不再对整段预测做事后平移。

训练可视化默认使用
`wandb_video_reconstruction_inference_steps=1`:先运行一次 coarse WAN
Euler update,再在 `tau=0.4` 用一次边界预测恢复 clean video/track;不会直接
解码半噪声状态,并跳过不会改变这两个输出的 action-only 触觉精修。
这不会改变训练或正式在线推理的 6+4 两阶段 schedule;如需更高质量的监控视频,
可以单独提高该值,但耗时近似按 inference steps 线性增长。

离线 NPZ 推理:

```bash
python scripts/eval/trex_track_force_inference.py \
  --checkpoint checkpoints/trex_track_force_wan22_lora/checkpoint-8000 \
  --dataset-root data/trex_small \
  --input sample_input.npz \
  --output prediction.npz
```

核心实现位于 `groot/vla/model/trex_track_force/`;独立 Hydra 配置为
`model=trex_track_force/vla``data=dreamzero/trex_track_force_wan22`