File size: 9,475 Bytes
2862f6e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# Data Augmentation

Utilities for augmenting and converting robot datasets: time scaling (frame extraction), space mirroring (left/right flip + merge), and converting HDF5 episode data into LeRobot-compatible datasets.

## Contents

| Script | Location | Description |
|--------|----------|-------------|
| **time_scaling.py** | `data_augment/time_scaling.py` | Extract every Nth frame from a LeRobot dataset (time-scale). Requires **lerobot** in the environment. |
| **space_mirroring.py** | `data_augment/space_mirroring.py` | Create mirrored dataset (swap left/right arms, flip videos) and/or merge datasets. |
| **convert_h5_lerobot.py** | `data_augment/utils/convert_h5_lerobot.py` | Convert HDF5 + videos → LeRobot format. Requires **mini_lerobot** (see below). |
| **merge_lerobot.py** | `data_augment/utils/merge_lerobot.py` | Merge LeRobot datasets (also used internally by space_mirroring and time_scaling). |
| **features.json** | `data_augment/utils/features.json` | Default feature schema for LeRobot output (used by convert_h5_lerobot). |

---

## Time scaling (`time_scaling.py`)

Extract every Nth frame from a LeRobot dataset (e.g. `extraction_factor=2` keeps frames 0, 2, 4, …), producing a shorter, “faster” episode. Optionally merge the extracted dataset with other sources, or use **split mode** to extract a portion of the data and merge with the rest.

**Requirement:** The **lerobot** package must be installed in the environment (e.g. `pip install lerobot` or your project’s env).

**Run from repository root:**

```bash
python train_deploy_alignment/data_augment/time_scaling.py --src_path <source_lerobot_path> --tgt_path <target_path> --repo_id <repo_id> [options]
```

**Required arguments:**

| Argument | Description |
|----------|-------------|
| `--src_path` | Path to source LeRobot dataset. |
| `--tgt_path` | Path to target (extracted) dataset. |
| `--repo_id` | Repository ID for the new dataset. |

**Optional arguments:**

| Argument | Default | Description |
|----------|--------|-------------|
| `--extraction_factor` | 2 | Keep every Nth frame (e.g. 2 → frames 0, 2, 4, …). |
| `--force` | false | Overwrite target if it already exists. |
| `--merge_src_paths` | — | Space-separated paths of additional datasets to merge with the extracted one. |
| `--merge_tgt_path` | `<tgt_path>_merged` | Output path for the merged dataset. |
| `--merge_repo_id` | `<repo_id>_merged` | Repository ID for the merged dataset. |
| `--merge_force` | false | Force merge even if conflicts exist. |
| `--split_ratio` | — | Float in (0, 1). Split mode: extract this fraction of data (time-scaled), keep the rest, then merge. Final dataset has `repo_id` + `_time_scaling`. |

**Examples:**

```bash
# Basic: extract every 2nd frame
python train_deploy_alignment/data_augment/time_scaling.py \
  --src_path /path/to/source --tgt_path /path/to/extracted --repo_id extracted_dataset \
  --extraction_factor 2

# With merge: extract then merge with another dataset
python train_deploy_alignment/data_augment/time_scaling.py \
  --src_path /path/to/source --tgt_path /path/to/extracted --repo_id extracted_dataset \
  --merge_src_paths /path/to/other_dataset --merge_tgt_path /path/to/merged --merge_repo_id merged_dataset

# Split mode: extract 30% of data (every 2nd frame), keep 70% original, merge into one dataset
python train_deploy_alignment/data_augment/time_scaling.py \
  --src_path /path/to/source --tgt_path /path/to/final --repo_id my_dataset \
  --split_ratio 0.3 --extraction_factor 2
```

---

## Space mirroring (`space_mirroring.py`)

Create a left/right mirrored version of a LeRobot dataset (swap left/right arm state and action dimensions, horizontally flip images/videos), and optionally merge original + mirrored into one dataset.

**Commands:** `create-mirror` (only mirror), `merge` (only merge), `full` (mirror then merge in one go).

**Run from repository root:**

```bash
python train_deploy_alignment/data_augment/space_mirroring.py <command> [options]
```

### Command: `full` (mirror + merge)

One-shot: create mirrored dataset, then merge with original.

```bash
python train_deploy_alignment/data_augment/space_mirroring.py full \
  --src-path /path/to/original \
  --mirror-path /path/to/mirrored \
  --merge-path /path/to/merged \
  --repo-id my_dataset \
  [--fps 30] [--robot-type agilex] [--left-dim 7] [--right-dim 7] [--num-workers 4] [--features-json /path/to/features.json] [--force]
```

| Argument | Default | Description |
|----------|--------|-------------|
| `--src-path` | required | Source (original) LeRobot dataset path. |
| `--mirror-path` | required | Output path for the mirrored dataset. |
| `--merge-path` | required | Output path for the merged (original + mirrored) dataset. |
| `--repo-id` | required | Dataset repo_id. |
| `--fps` | 30 | Video FPS. |
| `--robot-type` | agilex | Robot type (e.g. agilex, arx). |
| `--left-dim` | 7 | Left arm state/action dimension. |
| `--right-dim` | 7 | Right arm state/action dimension. |
| `--num-workers` | 4 | Parallel workers. |
| `--features-json` | — | Path to features.json (optional). |
| `--force` | false | Force merge if output exists. |

### Command: `create-mirror` (mirror only)

```bash
python train_deploy_alignment/data_augment/space_mirroring.py create-mirror \
  --src-path /path/to/source --tgt-path /path/to/mirrored \
  [--left-dim 7] [--right-dim 7] [--num-workers 4]
```

### Command: `merge` (merge only)

```bash
python train_deploy_alignment/data_augment/space_mirroring.py merge \
  --src-paths /path/to/ds1 /path/to/ds2 --tgt-path /path/to/merged \
  --repo-id merged_dataset [--fps 30] [--robot-type agilex] [--features-json ...] [--force]
```

---

## Converting HDF5 to LeRobot (`convert_h5_lerobot.py`)

`convert_h5_lerobot.py` reads HDF5 episode files and existing per-camera videos, and writes a LeRobot-compatible dataset (parquet + video chunks + metadata) using **mini_lerobot**.

### 1. Mini LeRobot dependency

The script uses the local **mini_lerobot** package (lightweight LeRobot-compatible builder) and an **interface** module that lives next to it. Both must be available when running the script.

**Option A: Editable install + PYTHONPATH (recommended)**

From the repository root:

```bash
# Install mini_lerobot in editable mode (from data_augment/utils/mini_lerobot)
uv pip install -e train_deploy_alignment/data_augment/utils/mini_lerobot
# or: pip install -e train_deploy_alignment/data_augment/utils/mini_lerobot
```

Then run the converter with the **mini_lerobot** directory on `PYTHONPATH` so that `import interface` resolves to `utils/mini_lerobot/interface.py`:

```bash
cd train_deploy_alignment/data_augment/utils
export PYTHONPATH="${PYTHONPATH}:$(pwd)/mini_lerobot"
python convert_h5_lerobot.py --help
```

**Option B: Run from inside `mini_lerobot`**

```bash
cd train_deploy_alignment/data_augment/utils/mini_lerobot
uv pip install -e .   # or pip install -e .
# Run the script from utils with PYTHONPATH including mini_lerobot so "interface" is found
PYTHONPATH="$(pwd):$PYTHONPATH" python ../convert_h5_lerobot.py --help
```

**Dependencies installed with mini_lerobot** (from `utils/mini_lerobot/pyproject.toml`): `numpy`, `tqdm`, `pyarrow`, `av`, `tyro`, `h5py`, `mcap`, `opencv-python`, etc. No need to install them separately if you install mini_lerobot with `-e`.

### 2. Input layout expected by the script

- **`data_dir`**: Directory containing one subdir per `repo_id`, each with:
  - `*.hdf5` — episode files (e.g. `observations/qpos`, `observations/images/...`).
  - `video/cam_high/`, `video/cam_left_wrist/`, `video/cam_right_wrist/` — per-episode `.mp4` files named like the HDF5 stem (e.g. `episode_0.mp4`).
- The script validates that each episode’s video frame count matches the HDF5 length; episodes with missing or invalid videos are skipped.

### 3. Usage

From `train_deploy_alignment/data_augment/utils` (with `PYTHONPATH` set as above):

```bash
python convert_h5_lerobot.py <data_dir> <save_dir> <repo_ids> [options]
```

Examples:

```bash
# Single repo_id
python convert_h5_lerobot.py /path/to/raw_data /path/to/output my_repo_id

# Multiple repo_ids (comma-separated or repeated)
python convert_h5_lerobot.py /path/to/raw_data /path/to/output repo1 repo2

# With optional args
python convert_h5_lerobot.py /path/to/raw_data /path/to/output my_repo \
  --prompt "fold the cloth" \
  --save-repoid my_lerobot \
  --max-workers 8 \
  --features-json ./features.json
```

**Main arguments (tyro):**

| Argument | Description |
|----------|-------------|
| `data_dir` | Root directory containing `<repo_id>` subdirs with `.hdf5` and `video/` layout. |
| `save_dir` | Root directory for output; script writes `<save_dir>/<task>/<save_repoid>/`. |
| `repo_ids` | One or more subdir names under `data_dir` to convert. |
| `--prompt` | Task prompt string (default inferred from `data_dir.name`, e.g. "fold the cloth"). |
| `--save-repoid` | Output dataset repo id (default derived from `data_dir` name + `_lerobot`). |
| `--max-workers` | Parallel workers (default 8). |
| `--overwrite` | Overwrite existing output directory. |
| `--only-sync` | Only validate/sync, do not build dataset. |
| `--features-json` | Path to feature schema JSON (default: `utils/features.json`). |

Output is a LeRobot-style dataset under `<save_dir>/<task>/<save_repoid>/` (e.g. `data/chunk-*/`, `meta/`, `videos/`), suitable for use with this repo’s training pipelines.