Skip to content

Commit 867ccce

Browse files
authored
Update doc for PI0/PI0.5 (flagos-ai#1045)
### PR Category <!-- One of [ Train | Inference | Compress | Serve | RL | Core | Hardware | CICD | Tools | Others ] --> Others ### PR Types <!-- One of [ User Experience | New Features | Bug Fixes | Improvements | Performance | Breaking Change| Deprecations | Test Case | Docs | Others ] --> Docs ### PR Description <!-- Describe what you’ve done --> - Update README for PI0/PI0.5 - Add a script for dataset/model downloading
1 parent a1b25e2 commit 867ccce

12 files changed

Lines changed: 640 additions & 273 deletions

File tree

examples/pi0/README.md

Lines changed: 180 additions & 110 deletions
Large diffs are not rendered by default.

examples/pi0/conf/inference/pi0.yaml

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
engine:
22
# Model variant: "pi0" or "pi0.5"
33
model_variant: "pi0"
4-
model: path-to-your-pi0_base-model
5-
tokenizer: path-to-your-paligemma-3b-pt-224-tokenizer
4+
model: /workspace/models/lerobot/pi0_base
5+
tokenizer: /workspace/models/google/paligemma-3b-pt-224
66
# TODO: (yupu) Use the stat safetensors
7-
stat_path: path-to-your-dataset/meta/stats.json
7+
stat_path: /workspace/datasets/lerobot/aloha_mobile_cabinet/meta/stats.json
88
device: "cuda"
99

1010
generate:
1111
images:
12-
observation.images.cam_high: path-to-your-cam-high-image.jpg
13-
observation.images.cam_left_wrist: path-to-your-cam-left-wrist-image.jpg
14-
observation.images.cam_right_wrist: path-to-your-cam-right-wrist-image.jpg
15-
state_path: path-to-your-state-file.pt
16-
task_path: path-to-your-task-file.txt
12+
observation.images.cam_high: /path/to/cam_high_image.jpg
13+
observation.images.cam_left_wrist: /path/to/cam_left_wrist_image.jpg
14+
observation.images.cam_right_wrist: /path/to/cam_right_wrist_image.jpg
15+
state_path: /path/to/state_file.pt
16+
task_path: /path/to/task_file.txt
1717
# Optional rename_map to map input keys to policy expected keys
18+
# Check the features key in your dataset's meta/info.json file to determine the correct mapping
1819
rename_map:
1920
observation.images.cam_high: observation.images.base_0_rgb
2021
observation.images.cam_left_wrist: observation.images.left_wrist_0_rgb

examples/pi0/conf/serve/pi0.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
engine_args:
33
host: 0.0.0.0
44
port: 5000
5-
model: path-to-your-pi0_base-model
6-
tokenizer: path-to-your-paligemma-3b-pt-224-tokenizer
7-
stat_path: path-to-your-dataset/meta/stats.json
5+
model: /workspace/models/lerobot/pi0_base
6+
tokenizer: /workspace/models/google/paligemma-3b-pt-224
7+
stat_path: /workspace/datasets/lerobot/aloha_mobile_cabinet/meta/stats.json
88
device: "cuda"
99
images_keys:
1010
- observation.images.base_0_rgb

examples/pi0/conf/train/pi0.yaml

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,13 @@ system:
2020
shuffle: false
2121
grad_clip_norm: 1.0
2222
use_amp: false
23-
# TODO: (yupu) The following configs will be implemented later
24-
tensor_model_parallel_size: 1
25-
pipeline_model_parallel_size: 1
26-
context_parallel_size: 1
27-
wandb_enabled: false
28-
project_name: ${experiment.exp_name}
29-
exp_name: ${experiment.exp_name}
3023

3124
model:
3225
model_variant: pi0
3326
# Path to the pretrained pi0_base model checkpoint
34-
checkpoint_dir: path-to-your-pi0_base-model
27+
checkpoint_dir: /workspace/models/lerobot/pi0_base
3528
# Path to paligemma tokenizer
36-
tokenizer_path: path-to-your-paligemma-3b-pt-224-tokenizer
29+
tokenizer_path: /workspace/models/google/paligemma-3b-pt-224
3730
tokenizer_max_length: 48
3831
action_steps: 50
3932
# TODO(yupu): Support resuming from checkpoint
@@ -42,7 +35,7 @@ data:
4235
tolerance_s: 0.0001
4336
use_imagenet_stats: true
4437
# Path to the training data
45-
data_path: path-to-your-dataset
38+
data_path: /workspace/datasets/lerobot/aloha_mobile_cabinet
4639
# To match the input features naming from the dataset to the policy config
4740
# For example, for the aloha_mobile_cabinet dataset, the rename_map is:
4841
# rename_map: '{\"observation.images.cam_high\": \"observation.images.base_0_rgb\", \"observation.images.cam_left_wrist\": \"observation.images.left_wrist_0_rgb\", \"observation.images.cam_right_wrist\": \"observation.images.right_wrist_0_rgb\"}'

examples/pi0/download.py

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Download models or datasets from HuggingFace Hub or ModelScope to a user-defined folder.
4+
5+
Usage:
6+
# Download model from HuggingFace
7+
python download.py \
8+
--repo_id lerobot/pi0_base \
9+
--output_dir ~/models \
10+
--source huggingface
11+
# Downloads to: ~/models/lerobot/pi0_base
12+
13+
# Download dataset from HuggingFace
14+
python download.py \
15+
--repo_id lerobot/aloha_mobile_cabinet \
16+
--output_dir ~/datasets \
17+
--repo_type dataset \
18+
--source huggingface
19+
# Downloads to: ~/datasets/lerobot/aloha_mobile_cabinet
20+
"""
21+
22+
import argparse
23+
import sys
24+
25+
from pathlib import Path
26+
from typing import Optional
27+
28+
29+
def _prepare_download(repo_id: str, output_dir: Path, repo_type: str, source_name: str) -> Path:
30+
"""Prepare download directory and print info.
31+
32+
Returns:
33+
Final output directory path
34+
"""
35+
final_output_dir = output_dir / repo_id
36+
print(f"Downloading {repo_type} {repo_id} from {source_name}...")
37+
print(f"Output directory: {final_output_dir}")
38+
final_output_dir.mkdir(parents=True, exist_ok=True)
39+
return final_output_dir
40+
41+
42+
def _handle_download_error(e: Exception, repo_id: str, source: str) -> None:
43+
"""Handle download errors with helpful tips."""
44+
print(f"✗ Error downloading from {source}: {e}")
45+
if "401" in str(e) or "authentication" in str(e).lower():
46+
if source == "HuggingFace":
47+
print("\nTip: You may need to set a HuggingFace token:")
48+
print(" export HF_TOKEN=your_token_here")
49+
print(" or run: huggingface-cli login")
50+
else:
51+
print("\nTip: You may need to set ModelScope credentials:")
52+
print(" export MODELSCOPE_API_TOKEN=your_token_here")
53+
elif "404" in str(e) or "not found" in str(e).lower():
54+
print(f"\nTip: Repository '{repo_id}' not found. Check the repo ID.")
55+
sys.exit(1)
56+
57+
58+
def download_from_huggingface(
59+
repo_id: str,
60+
output_dir: Path,
61+
repo_type: str = "model",
62+
revision: Optional[str] = None,
63+
token: Optional[str] = None,
64+
) -> Path:
65+
"""Download model or dataset from HuggingFace Hub.
66+
67+
Args:
68+
repo_id: HuggingFace repository ID (e.g., "lerobot/pi0_base")
69+
output_dir: Base directory to save the repository
70+
(will be saved to output_dir/repo_id)
71+
repo_type: Type of repository - "model" or "dataset" (default: "model")
72+
revision: Git revision (branch, tag, or commit hash). Defaults to "main"
73+
token: HuggingFace token for private repos. If None, uses cached token
74+
75+
Returns:
76+
Path to downloaded repository directory
77+
"""
78+
try:
79+
from huggingface_hub import snapshot_download
80+
except ImportError:
81+
print("Error: huggingface_hub is not installed.")
82+
print("Install it with: pip install huggingface_hub")
83+
sys.exit(1)
84+
85+
final_output_dir = _prepare_download(repo_id, output_dir, repo_type, "HuggingFace Hub")
86+
87+
try:
88+
downloaded_path = snapshot_download(
89+
repo_id=repo_id,
90+
repo_type=repo_type,
91+
revision=revision,
92+
local_dir=str(final_output_dir),
93+
local_dir_use_symlinks=False,
94+
token=token,
95+
)
96+
downloaded_path = Path(downloaded_path)
97+
print(f"✓ Successfully downloaded to: {downloaded_path}")
98+
return downloaded_path
99+
except Exception as e:
100+
_handle_download_error(e, repo_id, "HuggingFace")
101+
return Path() # Never reached, but satisfies type checker
102+
103+
104+
def download_from_modelscope(
105+
repo_id: str, output_dir: Path, repo_type: str = "model", revision: Optional[str] = None
106+
) -> Path:
107+
"""Download model or dataset from ModelScope.
108+
109+
Args:
110+
repo_id: ModelScope repository ID (e.g., "lerobot/pi0_base")
111+
output_dir: Base directory to save the repository
112+
(will be saved to output_dir/repo_id)
113+
repo_type: Type of repository - "model" or "dataset" (default: "model")
114+
revision: Git revision (branch, tag, or commit hash). Defaults to "master"
115+
116+
Returns:
117+
Path to downloaded repository directory
118+
"""
119+
try:
120+
from modelscope.hub.snapshot_download import snapshot_download as ms_snapshot_download
121+
except ImportError:
122+
try:
123+
from modelscope import snapshot_download as ms_snapshot_download
124+
except ImportError:
125+
print("Error: modelscope is not installed.")
126+
print("Install it with: pip install modelscope")
127+
sys.exit(1)
128+
129+
final_output_dir = _prepare_download(repo_id, output_dir, repo_type, "ModelScope")
130+
131+
try:
132+
downloaded_path = ms_snapshot_download(
133+
model_id=repo_id,
134+
repo_type=repo_type,
135+
local_dir=str(final_output_dir),
136+
revision=revision,
137+
)
138+
downloaded_path = Path(downloaded_path)
139+
print(f"✓ Successfully downloaded to: {downloaded_path}")
140+
return downloaded_path
141+
except Exception as e:
142+
_handle_download_error(e, repo_id, "ModelScope")
143+
return Path() # Never reached, but satisfies type checker
144+
145+
146+
def main():
147+
parser = argparse.ArgumentParser(
148+
description="Download models or datasets from HuggingFace Hub or ModelScope",
149+
formatter_class=argparse.RawDescriptionHelpFormatter,
150+
epilog="""
151+
Examples:
152+
# Download model from HuggingFace (saves to ~/models/lerobot/pi0_base)
153+
python download.py --repo_id lerobot/pi0_base \\
154+
--output_dir ~/models --source huggingface
155+
156+
# Download dataset from HuggingFace (saves to ~/datasets/lerobot/aloha_mobile_cabinet)
157+
python download.py --repo_id lerobot/aloha_mobile_cabinet \\
158+
--output_dir ~/datasets --repo_type dataset --source huggingface
159+
160+
# Download from ModelScope (China users, saves to ~/models/lerobot/pi0_base)
161+
python download.py --repo_id lerobot/pi0_base \\
162+
--output_dir ~/models --source modelscope
163+
164+
# Download tokenizer (saves to ~/models/google/paligemma-3b-pt-224)
165+
python download.py --repo_id google/paligemma-3b-pt-224 \\
166+
--output_dir ~/models --source huggingface
167+
168+
Note: For private repositories, set HF_TOKEN environment variable:
169+
export HF_TOKEN=your_token_here
170+
""",
171+
)
172+
173+
parser.add_argument(
174+
"--repo_id",
175+
type=str,
176+
required=True,
177+
help="Repository ID (e.g., 'lerobot/pi0_base' or 'lerobot/aloha_mobile_cabinet')",
178+
)
179+
180+
parser.add_argument(
181+
"--output_dir",
182+
type=str,
183+
required=True,
184+
help=(
185+
"Base output directory (repository will be saved to output_dir/repo_id, "
186+
"e.g., '~/models' -> '~/models/lerobot/pi0_base')"
187+
),
188+
)
189+
190+
parser.add_argument(
191+
"--repo_type",
192+
type=str,
193+
choices=["model", "dataset"],
194+
default="model",
195+
help="Type of repository: 'model' or 'dataset' (default: model)",
196+
)
197+
198+
parser.add_argument(
199+
"--source",
200+
type=str,
201+
choices=["huggingface", "modelscope"],
202+
default="huggingface",
203+
help="Source to download from: 'huggingface' or 'modelscope' (default: huggingface)",
204+
)
205+
206+
args = parser.parse_args()
207+
208+
output_dir = Path(args.output_dir).expanduser().resolve()
209+
210+
if args.source == "huggingface":
211+
downloaded_path = download_from_huggingface(
212+
repo_id=args.repo_id,
213+
output_dir=output_dir,
214+
repo_type=args.repo_type,
215+
revision=None,
216+
token=None,
217+
)
218+
elif args.source == "modelscope":
219+
downloaded_path = download_from_modelscope(
220+
repo_id=args.repo_id, output_dir=output_dir, repo_type=args.repo_type, revision=None
221+
)
222+
else:
223+
raise ValueError(f"Unknown source: {args.source}")
224+
225+
repo_type_name = "Dataset" if args.repo_type == "dataset" else "Model"
226+
print(f"\n{repo_type_name} downloaded successfully to: {downloaded_path}")
227+
print("You can now use this path in your config file:")
228+
if args.repo_type == "dataset":
229+
print(f" data_path: {downloaded_path}")
230+
else:
231+
print(f" checkpoint_dir: {downloaded_path}")
232+
233+
234+
if __name__ == "__main__":
235+
main()

examples/pi0/dump_dataset_inputs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ def main():
279279
sample_names = [f"frame_{args.frame_index}"]
280280
elif args.episode_index is not None and args.frame_in_episode is not None:
281281
# Calculate global index
282-
episode_info = dataset.meta.episodes.iloc[args.episode_index]
282+
episode_info = dataset.meta.episodes[args.episode_index]
283283
global_idx = episode_info["dataset_from_index"] + args.frame_in_episode
284284
indices = [global_idx]
285285
sample_names = [f"episode_{args.episode_index}_frame_{args.frame_in_episode}"]

0 commit comments

Comments
 (0)