JackLiu0406's picture
Fix stale line in task-77 card
9d00298 verified
|
Raw
History Blame Contribute Delete
9.6 kB

Task 77 β€” installing_a_modem (PiBehavior / pi0.5, no DA3)

Single-task fine-tune for the BEHAVIOR-1K 2026 challenge. Part of JackLiu0406/b1k-checkpoints.

This is one checkpoint line in the repo; the DA3 K/V-split spatial models are documented in the root README.


Quick facts

architecture PiBehavior / Ο€0.5 β€” gemma_2b VLM + gemma_300m action expert
parameters 3,826.8 M
framework JAX / Flax NNX, Orbax checkpoint
initialised from IliaLarchenko/behavior_50t_checkpoint (50-task meta-trained)
fine-tuned on task 77 = installing_a_modem, 200 episodes, ~476 k samples
checkpoint step 29,000 (of a 30,000-step schedule β€” see Caveats)
task-embedding space 100 tasks (expanded from the upstream 50)
DA3 not used β€” this is the plain Ο€0.5 path
precision params stored as saved by Orbax; model runs bf16 compute

Final training metrics (step 29,275, last logged)

metric value
action_loss 0.0081
total_loss 0.0097
fast_accuracy 0.9932
subtask_accuracy 1.0000

Repo layout

task77_installing_a_modem/
└── 29000/
    β”œβ”€β”€ params/                 # Orbax OCDBT param tree (~11.8 GiB) β€” inference weights
    β”œβ”€β”€ assets/
    β”‚   └── IliaLarchenko/
    β”‚       └── behavior_224_rgb/
    β”‚           β”œβ”€β”€ norm_stats.json     # state/action normalisation
    β”‚           └── fast_tokenizer/     # FAST action tokenizer (auxiliary head)
    └── _CHECKPOINT_METADATA

train_state/ is deliberately not included. That directory is 31 GB of Adam optimiser moments, needed only to resume training. Everything required for inference and evaluation is in params/.


Input contract

This is the part most people get wrong, so it is spelled out exactly.

⚠️ There is no text prompt

PiBehavior does not take a language instruction. It is conditioned by a task embedding and a stage (subtask) embedding, both looked up by integer index. Any prompt string you pass is ignored β€” serve_b1k.py sets a placeholder string purely for logging.

Observation dict

key shape dtype notes
images["base_0_rgb"] [B, 224, 224, 3] float32 head/base camera
images["left_wrist_0_rgb"] [B, 224, 224, 3] float32 left wrist camera
images["right_wrist_0_rgb"] [B, 224, 224, 3] float32 right wrist camera
image_masks[<same three keys>] [B] bool one flag per image, not per pixel β€” False marks a missing camera
state [B, 32] float32 proprioception, normalised with norm_stats.json
tokenized_prompt [B, 2] int32 [task_id, subtask_state]
tokenized_prompt_mask [B, 2] bool normally [True, True]

fast_tokens / fast_token_mask appear only when the FAST auxiliary loss is enabled; they are a training-time auxiliary target and are not needed at inference.

Image resolution is openpi.models.model.IMAGE_RESOLUTION == (224, 224).

Output

key shape dtype
actions [B, 30, 32] float32

That is an action chunk: horizon 30, action dimension 32. Denormalise with the actions entry of norm_stats.json. The 32 dims cover base velocity (x, y, z), left arm (7) + left gripper, right arm (7) + right gripper, and trunk (4), with the remainder padding to 32.


Task and stage indexing β€” important

The upstream release has a 50-task embedding table. installing_a_modem is a 2026-only activity and is not in those 50, so this model was trained with the table expanded to 100 tasks; rows 50–99 were freshly initialised from normal(0, 1/√features) and rows 0–49 were carried over unchanged.

You must load this checkpoint with a 100-task config, e.g. B1K_TASK_SPACE=100. Loading it into a 50-task model will fail on a shape mismatch.

Stage counts follow the verified upstream rule:

num_stages = clip(ceil(avg_episode_length / 900), 5, 15)

For this model:

value
task_id 77
num_stages 5
stage-embedding rows 888 – 892

subtask_state at inference is the current stage index in 0 … num_stages-1 (so 0–4 here). The absolute embedding row is TASK_STAGE_OFFSETS[task_id] + subtask_state; the offsets are a cumulative sum over TASK_NUM_STAGES (100 entries, summing to 1120).


Running it

The evaluation path is a websocket policy server that the OmniGibson BEHAVIOR-1K evaluator connects to.

1. Get the code

git clone https://github.com/IliaLarchenko/behavior-1k-solution
cd behavior-1k-solution
git submodule update --init --recursive
uv sync

This checkpoint was produced by a fork of the above with the task table widened to 100. If you use stock upstream, you must apply the same widening or the parameter shapes will not match.

2. Download the checkpoint

huggingface-cli download <REPO_ID> \
  --include "task77_installing_a_modem/29000/*" \
  --local-dir ./ckpts

3. Serve the policy

export B1K_TASK_SPACE=100                       # 100-task embedding table
export XLA_PYTHON_CLIENT_MEM_FRACTION=0.9

uv run scripts/serve_b1k.py \
  --policy.config pi_behavior_b1k_fast \
  --policy.dir   ./ckpts/task77_installing_a_modem/29000 \
  --task_id 77 \
  --port 8000

--task_id 77 is what selects the task embedding. Omit it only if your observations already carry a task_index / task_id field, in which case it is read per-observation.

assets_base_dir must resolve so that norm_stats.json and fast_tokenizer/ are found under <assets>/IliaLarchenko/behavior_224_rgb/. The bundled assets/ directory already has that layout β€” point the config at it if the default path does not exist on your machine.

Eval-side execution parameters

serve_b1k.py wraps the raw policy in B1KPolicyWrapper, which does chunk scheduling and a few eval heuristics. Defaults:

arg default meaning
--actions_to_execute 26 actions consumed per inference
--actions_to_keep 4 overlap retained between chunks
--execute_in_n_steps 20 env steps per executed chunk
--history_len 3 observation history for stage voting
--votes_to_promote 2 consecutive votes before advancing a stage
--num_steps 20 flow-matching sampling steps
--apply_eval_tricks True correction rules + gripper variation checks

Set --apply_eval_tricks False for a clean measurement of the policy itself.

Loading programmatically

from b1k.policies import policy_config as _policy_config
from b1k.training import config as _config

policy = _policy_config.create_trained_policy(
    _config.get_config("pi_behavior_b1k_fast"),
    "./ckpts/task77_installing_a_modem/29000",
    sample_kwargs={"num_steps": 20},
)

action_chunk = policy.infer({
    "images": {...},            # three [224,224,3] float32 arrays
    "image_masks": {...},       # three bools
    "state": state_32,          # [32] float32
    "task_id": 77,
    "subtask_state": current_stage,   # 0..4
})["actions"]                   # [30, 32]

Training recipe

init IliaLarchenko/behavior_50t_checkpoint params, task/stage tables widened 50β†’100
GPUs 7 Γ— H200 (one card on the node was faulty and excluded)
global batch 224 (32 per GPU)
FSDP off β€” parameters replicated
steps 30,000 scheduled; stopped at 29,275, last checkpoint 29,000
LR schedule ramp 8.75e-7 β†’ peak 8.75e-5 over 2,000 warmup steps, cosine to 1.75e-6
LR scaling linear rule (Goyal et al.), 1.75Γ— over a BS-128 reference of 5e-5
optimiser AdamW (openpi defaults)
new params task_embeddings[77] and task_stage_embeddings[888:893] initialised from normal(0, 1/√features); everything else transferred

The FAST action tokenizer was not retrained. It was verified to transfer to the new tasks: 0.000 % alphabet overflow, no clipping, and round-trip MAE on the new task matching in-distribution controls.


Caveats β€” read before comparing numbers

  1. This is step 29,000, not 30,000. Training was stopped 725 steps early to free the machine for hardware fault diagnosis. Those steps were at the LR floor (~1.75e-6) and loss was already flat, so the practical difference is very small β€” but it is not the full schedule.

  2. Inference only. train_state/ is not included, so you cannot resume training from this upload.

  3. Base-velocity coordinate frame. Trained on the 2026 challenge demos after the upstream fix (commit e6c9756) that moved base_qvel from the world frame to the robot frame. Checkpoints trained on the older world-frame data saw a different input distribution for state dims 0:3 β€” losses are not directly comparable across that boundary.

  4. Single-task model. It has only been fine-tuned on task 77. The other 99 task embeddings are either inherited from the 50-task meta checkpoint (0–49) or still at random initialisation (50–99, except 77). Do not expect meaningful behaviour for any other task_id.

  5. subtask_accuracy = 1.0000 is on training data β€” it is not a generalisation estimate.