FACT / docs /METHOD.md
zhicao's picture
Add FACT training code
af8c481 verified
|
Raw History Blame Contribute Delete
3.66 kB
# FACT architecture
## Token layout
Each autoregressive block covers 0.8 s and packs **83 tokens**:
`[obs 50][state 1][action 16][future-state 16]`, preceded by one learnable task token
(and, with `use_text`, up to 64 umT5-XXL text tokens as a clean prefix, padding masked).
Training runs K = 4 blocks (3.2 s) in one forward pass with a block-causal mask: block *k*
attends to blocks `[k-window, k]` (window = 4) and the prefix; online K = 1.
| token | source | noise |
|---|---|---|
| obs (50) | current 3-view frame tiled into a 2×2 grid (head \| right ; left \| black) at 160×320, Wan2.2 VAE → 48×10×20 latent, 2×2 patches, `Linear(192→d)` | clean |
| state (1) | 62-D EEF62 state (zero-padded to 64), MLP → d | clean, τ = 0 |
| action (16) | 16 × 62 delta-base actions (T-Rex reference frame and q01/q99 normalisation), `Linear(64→d)` | noisy, τ ~ Beta(1.5, 1) per block |
| future state (16) | EEF62 states at +1..+16 steps (20 Hz) after the block anchor, delta-base w.r.t. the block reference state, normalised with the action statistics | noisy, same τ as action |
Positional information: slot embedding (83 slots) + block embedding + token-type embedding
(no RoPE). Each token carries its own τ → sinusoidal(256) → MLP → per-token adaLN-zero
(6 modulation vectors, so different modalities can sit at different noise levels);
qk-RMSNorm; final adaLN followed by two linear heads (action flow, future-state flow).
## Two-stage flow
* **Coarse stage** (`FactCoarseTransformer`): joint rectified flow on `[action, future state]`
from τ = 1 to τ = 0.4 (6 Euler steps at inference).
* **Coarse memory**: last-layer hidden states visible to block *k* (84 tokens online).
* **Force stage** (`ForceOnlyTransformer`, 768-d, 6 layers, re-used unchanged from T-Rex):
16 action tokens + 10 current F6 force tokens + 10 tactile-VQ history tokens + memory;
τ 0.4 → 0 in 4 steps, suffix-only refinement at offsets 0/4/8/12 (5 Hz tactile refresh),
tactile dropout 0.1. The tactile VQ (64 codes × 256-d) is trained jointly with the
standard VQ + 0.25 · commitment loss.
Loss: `action_flow_mse + state_flow_mse + force_flow_mse + vq + 0.25·commitment` (all weights 1).
Sampling: 6 coarse steps (τ 1 → 0.4) → forward at τ = 0.4 to obtain memory and clean future
states → 4 force steps. `coarse_to_zero` lets the coarse model run to τ = 0 instead (used
when the force stage is disabled or for analysis).
## Configurations
| config | d / layers / heads / FFN | params | notes |
|---|---|---|---|
| `fact_base.json` | 1024 / 12 / 16 / 4096 | 209 M | finalised model |
| `fact_base_text.json` | same + `use_text` (4096-d umT5 tokens, `LayerNorm + Linear(4096→d)`) | 213 M | multi-task training |
| `fact_small.json` | 768 / 8 / 12 / 3072 | 109 M | resource-constrained variant |
All configs keep the force stage (768 / 6 / 12 / 3072), window 4, 6 coarse + 4 force steps,
τ_split 0.4.
## Full-data training recipe
Global batch 16 × 8 = 128 samples (4 AR blocks each), AdamW, lr 3e-4 cosine to 10 % with
2000 warm-up steps, weight decay 0.01, grad clip 1.0, bf16 autocast (force stage in fp32),
force-stage lr × 0.3, optimizer step skipped when the pre-clip grad norm exceeds 20.
100 k steps ≈ 15 h on 32 accelerators at 0.55–1.1 s/it.
Every `--video-steps` the rank-0 process samples 4 consecutive chunks of one episode and logs
`eval/openloop_cascade_mse`, `eval/openloop_coarse_only_mse`, `eval/future_state_mse` and a
monitoring video (left: head camera at 20 Hz; right: predicted vs ground-truth action and
future-state curves — black GT / red cascade / blue coarse τ = 0.4 / green future state).