Skip to content

Commit cbc199b

Browse files
legitnullclaude
andauthored
[Train] Support FSDP2 checkpoint resume (#1149)
### PR Category <!-- One of [ Train | Inference | Compress | Serve | RL | Core | Hardware | CICD | Tools | Others ] --> Train ### PR Types <!-- One of [ User Experience | New Features | Bug Fixes | Improvements | Performance | Breaking Change| Deprecations | Test Case | Docs | Others ] --> Improvements ### PR Description <!-- Describe what you’ve done --> - Refactor to use standard `from_pretrained`, `save_pretrained` api - Reorganize qwen_gr00t into proper subpackage (qwen_gr00t/, vlm/qwenvl_backbone) - Add FSDP2 checkpoint resume support (model, optimizer, scheduler, RNG state) - vla serving script now supports arbitrary observation key names --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 840c9fa commit cbc199b

50 files changed

Lines changed: 3551 additions & 890 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/unit_tests_common.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ jobs:
168168
--retry-count 3
169169
170170
# TODO: temp solution to install newly added deps, remove once the new image is built
171-
pip install qwen_vl_utils==0.0.14 diffusers==0.36.0 websocket-client==1.8.0 websocket==0.2.1 websockets==15.0.1 msgpack==1.1.0
171+
pip install qwen_vl_utils==0.0.14 diffusers==0.36.0 websocket-client==1.8.0 websocket==0.2.1 websockets==15.0.1 msgpack==1.1.0 datasets==4.5.0
172172
173173
# Copy test data (keep existing logic)
174174
mkdir -p /opt/data

examples/gr00t_n1_5/conf/train/gr00t_n1_5.yaml

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ system:
1111
output_directory: ${experiment.exp_dir}
1212
save_checkpoint: true
1313
save_freq: 1000
14+
# Path to a checkpoint directory to resume training from (e.g. outputs/gr00t_n1_5_train/checkpoints/001000)
15+
# resume_from:
1416

1517
model:
1618
model_name: gr00t_n1_5
1719
# Path or HuggingFace model ID for the pretrained GR00T N1.5 model
1820
checkpoint_dir: /workspace/models/nvidia/GR00T-N1.5-3B
1921

20-
# Fine-tuning control (from groot_finetune_script.py)
22+
# Fine-tuning control
2123
tune_llm: true
2224
tune_visual: true
2325
tune_projector: true
@@ -27,6 +29,39 @@ model:
2729
# Embodiment tag to use for training (e.g. 'new_embodiment', 'gr1')
2830
embodiment_tag: new_embodiment
2931

32+
# Number of future action steps predicted per forward pass.
33+
# Determines action_delta_indices = [0, 1, ..., chunk_size - 1].
34+
chunk_size: 16
35+
36+
# Padding dimensions — shorter state/action sequences are zero-padded to these sizes
37+
max_state_dim: 64
38+
max_action_dim: 32
39+
40+
normalization_mapping:
41+
VISUAL: IDENTITY
42+
STATE: MIN_MAX
43+
ACTION: MIN_MAX
44+
45+
# LoRA fine-tuning (lora_rank: 0 disables LoRA)
46+
# lora_rank: 0
47+
# lora_alpha: 16
48+
# lora_dropout: 0.1
49+
# lora_full_model: false
50+
51+
# ============================================================
52+
# Module Freezing Configuration
53+
# ============================================================
54+
# Freezing logic: freeze_patterns are applied first, then keep_patterns override.
55+
# Patterns are regex matched against full parameter names.
56+
#
57+
# Common patterns for GR00T N1.5:
58+
# - "_groot_model\\.backbone\\..*" # Entire backbone (VLM + vision)
59+
# - "_groot_model\\.action_head\\..*" # Action diffusion head
60+
#
61+
# freeze:
62+
# freeze_patterns:
63+
# - "_groot_model\\.backbone\\..*"
64+
3065
optimizer:
3166
name: AdamW
3267
lr: 1.0e-4
@@ -42,10 +77,8 @@ model:
4277

4378
data:
4479
dataset_type: lerobot
45-
data_path: /workspace/IPEC-COMMUNITY/libero_goal_no_noops_1.0.0_lerobot/
80+
data_path: /workspace/datasets/IPEC-COMMUNITY/libero_goal_no_noops_1.0.0_lerobot/
4681
tolerance_s: 0.0001
47-
observation_delta_indices: null
48-
action_delta_indices: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
4982
preprocessor:
5083
name: policy_preprocessor
5184
steps:

examples/pi0/conf/train/pi0.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ model:
2222
# Path to paligemma tokenizer
2323
tokenizer_path: /workspace/models/google/paligemma-3b-pt-224
2424
tokenizer_max_length: 48
25-
action_steps: 50
2625

2726
optimizer:
2827
name: AdamW

examples/pi0_5/conf/serve.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ experiment:
77
exp_dir: outputs/${experiment.exp_name}
88
task:
99
type: serve
10-
entrypoint: flagscale/serve/run_serve_pi.py
10+
entrypoint: flagscale/serve/run_serve_qwen_gr00t.py
1111
runner:
1212
hostfile: null
1313
deploy:
14-
use_fs_serve: false
14+
use_fs_serve: true
1515
envs:
1616
CUDA_VISIBLE_DEVICES: 0
1717
CUDA_DEVICE_MAX_CONNECTIONS: 1

examples/pi0_5/conf/serve/pi0_5.yaml

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,13 @@
22
engine_args:
33
host: 0.0.0.0
44
port: 5000
5-
# Model variant: "pi0" or "pi0.5"
65
model_variant: "pi0.5"
7-
model: /workspace/models/lerobot/pi05_base
8-
tokenizer: /workspace/models/google/paligemma-3b-pt-224
9-
stat_path: /workspace/datasets/lerobot/aloha_mobile_cabinet/meta/stats.json
6+
model: /workspace/models/pi0_5_train/checkpoints/last/pretrained_model
107
device: "cuda"
11-
# By default, Pi0.5 uses quantiles for state and action normalization, if false, it uses mean and std instead
12-
use_quantiles: false
13-
images_keys:
14-
- observation.images.base_0_rgb
15-
- observation.images.left_wrist_0_rgb
16-
- observation.images.right_wrist_0_rgb
17-
# Only used for warmup
18-
images_shape: [3, 480, 640]
19-
state_key: observation.state
8+
# Maps client-sent observation keys to the keys the model was trained with.
9+
# Format: {key_from_client: key_expected_by_model}
10+
# rename_map:
11+
# "observation/image": "observation.images.image"
12+
# "observation/wrist_image": "observation.images.wrist_image"
13+
# "observation/state": "observation.state"
14+
# "prompt": "task"

examples/pi0_5/conf/train.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ experiment:
2222
before_start: echo "Starting PI0.5 Training"
2323
envs:
2424
LOGLEVEL: "INFO"
25-
CUDA_VISIBLE_DEVICES: "0,1"
25+
CUDA_VISIBLE_DEVICES: "0,1,2,3,4,5,6,7"
2626
CUDA_DEVICE_MAX_CONNECTIONS: 1
2727
WANDB_MODE: offline
2828
OTEL_SDK_DISABLED: true

examples/pi0_5/conf/train/pi0_5.yaml

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
system:
2-
batch_size: 1
3-
train_steps: 100000
2+
batch_size: 16
3+
train_steps: 30000
44
log_freq: 10
55
grad_clip_norm: 1.0
6-
use_amp: false
7-
shuffle: false
6+
use_amp: true
7+
shuffle: true
88
num_workers: 4
99

1010
checkpoint:
@@ -18,11 +18,12 @@ system:
1818
model:
1919
model_name: pi0.5
2020
# Path to the pretrained pi05_base model checkpoint
21-
checkpoint_dir: /workspace/models/lerobot/pi05_base
21+
checkpoint_dir: /workspace/models/lerobot/pi05_libero_base
2222
# Path to paligemma tokenizer
2323
tokenizer_path: /workspace/models/google/paligemma-3b-pt-224
2424
tokenizer_max_length: 200
25-
action_steps: 50
25+
gradient_checkpointing: true
26+
freeze_vision_encoder: false
2627

2728
optimizer:
2829
name: AdamW
@@ -37,14 +38,12 @@ model:
3738

3839
data:
3940
# Path to the training data
40-
data_path: /workspace/datasets/lerobot/aloha_mobile_cabinet
41+
data_path: /workspace/datasets/IPEC-COMMUNITY/libero_goal_no_noops_1.0.0_lerobot
4142
tolerance_s: 0.0001
4243
use_imagenet_stats: true
4344
# To match the input features naming from the dataset to the policy config
4445
# For example, for the aloha_mobile_cabinet dataset, the rename_map is:
4546
rename_map:
46-
observation.images.cam_high: observation.images.base_0_rgb
47-
observation.images.cam_left_wrist: observation.images.left_wrist_0_rgb
48-
observation.images.cam_right_wrist: observation.images.right_wrist_0_rgb
47+
"observation.images.wrist_image": "observation.images.image2"
4948
# By default, Pi0.5 uses quantiles for state and action normalization, if false, it uses mean and std instead
50-
use_quantiles: false
49+
use_quantiles: true

examples/qwen_gr00t/conf/serve/qwen_gr00t.yaml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,17 @@
33
host: 0.0.0.0
44
port: 5000
55
model_variant: QwenGr00t
6-
model: /workspace/models/qwen_gr00t_train/checkpoints/last
6+
model: /share/project/fengyupu/github/FlagScale_2/outputs/260320_qwen_gr00t_train_libero_goal_old_dataset/checkpoints/last
77
device: "cuda"
8+
# Maps client-sent observation keys to the keys the model was trained with.
9+
# Format: {key_from_client: key_expected_by_model}
10+
rename_map:
11+
"observation/image": "observation.images.image"
12+
"observation/wrist_image": "observation.images.wrist_image"
13+
"observation/state": "observation.state"
14+
"prompt": "task"
15+
serve_preprocessor:
16+
steps:
17+
- registry_name: image_resize_processor
18+
config:
19+
image_size: [224, 224]

examples/qwen_gr00t/conf/train/qwen_gr00t.yaml

Lines changed: 19 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,42 @@
11
system:
2-
batch_size: 16
2+
batch_size: 8
33
train_steps: 30000
44
log_freq: 1
55
grad_clip_norm: 1.0
66
use_amp: true
77
shuffle: true
88
num_workers: 4
9+
# Weight applied to VLM language modelling loss when co-training with vlm_data_path.
10+
# Set to 0 or omit vlm_data_path to disable co-training.
11+
vlm_loss_scale: 0.1
912

1013
checkpoint:
1114
output_directory: ${experiment.exp_dir}
1215
# Whether to save checkpoint
1316
save_checkpoint: true
1417
# Number of steps between checkpoints
15-
save_freq: 1000
16-
# TODO(yupu): Support resuming from checkpoint
18+
save_freq: 10000
19+
# Path to a checkpoint directory to resume training from (e.g. /path/to/checkpoints/005000)
20+
# resume_from:
1721

1822
model:
19-
# TODO: (yupu) the config layout is still a mess
2023
model_name: qwen_gr00t
21-
# Path to the checkpoint of the pretrained base VLM model, e.g. Qwen3-VL-4B-Instruct
22-
checkpoint_dir: /workspace/models/Qwen/Qwen3-VL-4B-Instruct/
2324
vlm:
2425
type: qwen3-vl
25-
qwenvl:
2626
base_vlm: /workspace/models/Qwen/Qwen3-VL-4B-Instruct/
2727
attn_implementation: flash_attention_2
28-
vl_hidden_dim: 2048
29-
dino:
30-
dino_backbone: dinov2_vits14
3128
action_model:
3229
# Whether to condition the action model on proprioceptive state (observation.state)
3330
use_state: false
34-
type: flow_matching
31+
type: gr00t_action_head
3532
action_model_type: DiT-B
36-
action_hidden_dim: 1024
3733
hidden_size: 1024
3834
add_pos_embed: True
3935
max_seq_len: 1024
4036
action_dim: 7
4137
state_dim: 7
4238
future_action_window_size: 7
4339
action_horizon: 8
44-
past_action_window_size: 0
4540
repeated_diffusion_steps: 4
4641
noise_beta_alpha: 1.5
4742
noise_beta_beta: 1.0
@@ -58,7 +53,13 @@ model:
5853
num_layers: 16
5954
output_dim: 1024
6055
positional_embeddings: None
61-
reduce_in_full_precision: True
56+
57+
prompt_template: "Your task is {instruction}. To identify the key objects for your task. Locate their bounding boxes in [x1,y1,x2,y2] format."
58+
59+
normalization_mapping:
60+
VISUAL: IDENTITY
61+
STATE: MIN_MAX
62+
ACTION: MIN_MAX
6263

6364
optimizer:
6465
name: AdamW
@@ -117,24 +118,11 @@ data:
117118
vision_root: ""
118119
action_key: eepose
119120
state_key: eepose
120-
# TODO: (yupu) Remove this once we have a proper dataset config
121-
vla_data:
122-
dataset_py: lerobot_datasets
123-
data_root_dir: playground/Datasets/
124-
data_mix: libero_goal_old
125-
action_type: delta_qpos
126-
CoT_prompt: Your task is {instruction}. To identify the key objects for your task. Locate their bounding boxes in [x1,y1,x2,y2] format.
127-
CoT_answer: bbox
128-
default_image_resolution: [3, 224, 224]
129-
load_all_data_for_training: True
130-
obs: ["image_0"]
131-
video_backend: torchvision_av
132121
# Path to the training data
133122
data_path: /workspace/datasets/IPEC-COMMUNITY/libero_goal_no_noops_1.0.0_lerobot/
123+
# Path to VLM co-training data (WDS/Energon format). Leave unset to disable co-training.
124+
# vlm_data_path: /workspace/datasets/vlm_cotrain/
134125
tolerance_s: 0.0001
135-
# TODO: (yupu) I think these indices should belong to the policy config, maybe put it in the model config?
136-
observation_delta_indices: [0]
137-
action_delta_indices: [0,1,2,3,4,5,6,7]
138126
preprocessor:
139127
name: policy_preprocessor
140128
steps:
@@ -151,18 +139,12 @@ data:
151139
config:
152140
eps: 1e-8
153141
features: {}
154-
norm_map:
155-
VISUAL: IDENTITY
156-
STATE: MIN_MAX
157-
ACTION: MIN_MAX
142+
# norm_map is injected at runtime from model.normalization_mapping
158143
postprocessor:
159144
name: policy_postprocessor
160145
steps:
161146
- registry_name: unnormalizer_processor
162147
config:
163148
eps: 1e-8
164149
features: {}
165-
norm_map:
166-
VISUAL: IDENTITY
167-
STATE: MIN_MAX
168-
ACTION: MIN_MAX
150+
# norm_map is injected at runtime from model.normalization_mapping

0 commit comments

Comments
 (0)