FACT: A Multimodal Force–Action–Track Foundation Model for Human-to-Robot Dexterity

Training code for FACT. The policy is a block-causal transformer trained from scratch on T-Rex-format LeRobot v2.1 data; it predicts 16-step, 20 Hz delta-base EEF62 action chunks together with the 16 following EEF62 states (coarse flow, τ 1→0.4), followed by a force-only tactile refinement stage (τ 0.4→0, refreshed at 5 Hz from 10 F6 tactile sensors). Frozen perception (Wan2.2 VAE image tokenizer, umT5-XXL text encoder) is used offline only.

Layout

fact/                 model + data package
  model.py            FactConfig, FactCoarseTransformer, FactPolicy (forward / sample / refine_action_suffix)
  force.py            force-only refinement stage;  tactile_vq.py  tactile VQ
  data.py             FactEpisode / FactAnchorDataset / FactMultiEpisodeDataset / collate
  data_utils.py       20 Hz timestamp grid, 6-D rotation, delta-base EEF62 math
  runtime_stats.py    q01/q99 normalisation statistics, delta-base -> absolute inversion
  perception/         Wan2.2 VAE, umT5 encoder, tokenizer (cache building only)
configs/              fact_base.json (209 M), fact_base_text.json (+ text conditioning, 213 M), fact_small.json (109 M)
scripts/
  train_full.sh       full training launcher: offline caches -> torch.distributed DDP (single / multi node)
  train_ddp.py        DDP trainer (bf16, cosine LR, checkpoint / resume, W&B, monitoring video)
  build_cache_dataset.py   VAE latent cache (shardable over GPUs) and umT5 text cache for a dataset
  check_dataset_ready.py   dataset structure / statistics validation
  eval_multi.py       open-loop evaluation of a checkpoint over many episodes
  train.py / eval.py / build_cache.py / run_single_episode.sh / collect.py   single-episode protocol
  param_count.py      parameter budget of a config
data_tools/           build_merged_dataset.py (merge several datasets), north_ces_fk_params.json (Sharpa FK)
docs/                 METHOD.md (architecture), DATA_FORMAT.md (dataset layout), FACT_MODEL_zh.md
results/              single-episode benchmark tables and raw baseline JSON

Installation

pip install -e ".[train]"        # torch>=2.8, pyarrow, einops, transformers, wandb, decord2, ...

Frozen perception weights (from the Wan2.2-TI2V-5B release) under checkpoints/Wan2.2-TI2V-5B/ (or WAN22_CKPT_DIR=...): Wan2.2_VAE.pth, models_t5_umt5-xxl-enc-bf16.pth, google/umt5-xxl/tokenizer.json.

Data

LeRobot v2.1 datasets in the T-Rex force layout (see docs/DATA_FORMAT.md): per-episode parquet with timestamp, observation.state_eef62 [62], action.eef62_absolute [62], observation.tactile_force [60], three RGB views (head_left, left_wrist, right_wrist) and meta/{info.json, episodes.jsonl, tasks.jsonl, stats.json, relative_stats_dreamzero.json, modality.json}.

python scripts/check_dataset_ready.py --dataset-root /data/trex_full_force
python data_tools/build_merged_dataset.py --source trex=/data/trex_full_force:/cache/trex_full_force \
    --source sharpadex=/data/SharpaDex_trex --out /data/ALL_trex --cache /cache/ALL_trex   # optional merge

Training

DATA_ROOT=/data/trex_full_force OUTPUT_DIR=checkpoints/fact_trex NUM_GPUS=16 PER_DEVICE_BATCH=8 \
bash scripts/train_full.sh                         # extra args are forwarded to scripts/train_ddp.py

The launcher builds the caches on first use (<CACHE_DIR>/latents/episode_XXXXXX.npy float16 [N,48,10,20]; <CACHE_DIR>/text_cache.npz), validates the dataset and runs python -m torch.distributed.run scripts/train_ddp.py --config configs/fact_base_text.json --blocks 4 .... Defaults: 100 k steps, global batch 16×8, AdamW lr 3e-4 cosine (warm-up 2000), weight decay 0.01, grad clip 1.0, bf16 (force stage fp32, lr×0.3), checkpoint every 10 k steps, --resume auto. Multi-node: run the same command on every node with NNODES=<n> NODE_RANK=<i> MASTER_ADDR=<node0>. Env overrides: DATA_ROOT OUTPUT_DIR CACHE_DIR FACT_CONFIG WAN22_CKPT_DIR NUM_GPUS PER_DEVICE_BATCH LR MAX_STEPS SAVE_STEPS VIDEO_STEPS WANDB_PROJECT WANDB_RUN_NAME.

Single-episode protocol (results/single_episode_benchmark.md):

bash scripts/run_single_episode.sh fact_base 0 --config-json "$(cat configs/fact_base.json)" \
    --steps 3000 --batch 8 --lr 2e-4 --bf16

Evaluation

python scripts/eval_multi.py --checkpoint checkpoints/fact_trex/checkpoint-100000 \
    --dataset-root /data/trex_full_force --cache-dir cache/trex_full_force \
    --episodes 0-99 --anchors-per-episode 8 --out eval.json --bf16

Reports normalised 62-D delta-base action MSE (cascade / coarse-only / coarse-to-zero, arm / hand) and future-state MSE. FactPolicy.sample() returns a chunk; FactPolicy.refine_action_suffix() re-runs the force stage at offsets 0/4/8/12 on new tactile readings; fact.runtime_stats.delta_base_to_absolute() converts the output to absolute EEF poses.

License

MIT (LICENSE). fact/perception/ is derived from the Wan2.2 release and keeps its license.

Downloads last month

-

Downloads are not tracked for this model. How to track
Video Preview
loading