Buckets:
| # Multi-GPU Training | |
| LeRobot trains on multiple GPUs through [Hugging Face Accelerate](https://huggingface.co/docs/accelerate). Three data-parallel layouts are supported: | |
| | Layout | What it does | Config | | |
| | -------- | ------------------------------------------------------------- | ------------------------------------------------------- | | |
| | **DDP** | Replicates the full model on every GPU | default on any multi-GPU launch | | |
| | **FSDP** | Shards parameters, gradients, and optimizer state across GPUs | `--parallelism.dp_shard=N` | | |
| | **HSDP** | Shards within groups of GPUs, replicates across groups | `--parallelism.dp_replicate=R --parallelism.dp_shard=S` | | |
| ## Installation | |
| `accelerate` is included in the `training` extra: | |
| ```bash | |
| pip install 'lerobot[training]' | |
| ``` | |
| ## Launching | |
| Distributed training can be launched through both `torchrun` and `accelerate launch`. Accelerate is used as a plain launcher: it does not manage the training configuration, and every distributed training setting lives in LeRobot's own config system. | |
| With `torchrun`: | |
| ```bash | |
| torchrun --nproc-per-node=2 $(which lerobot-train) \ | |
| --dataset.repo_id=${HF_USER}/my_dataset \ | |
| --policy.type=act \ | |
| --policy.repo_id=${HF_USER}/my_trained_policy \ | |
| --output_dir=outputs/train/act_multi_gpu \ | |
| --job_name=act_multi_gpu \ | |
| --wandb.enable=true | |
| ``` | |
| With `accelerate launch` (as a plain launcher): | |
| ```bash | |
| accelerate launch --num_processes=2 $(which lerobot-train) \ | |
| --dataset.repo_id=${HF_USER}/my_dataset \ | |
| --policy.type=act \ | |
| --policy.repo_id=${HF_USER}/my_trained_policy \ | |
| --output_dir=outputs/train/act_multi_gpu \ | |
| --job_name=act_multi_gpu \ | |
| --wandb.enable=true | |
| ``` | |
| With no `--parallelism.*` flags, a multi-process launch runs plain DDP. Multi-node runs use the standard `torchrun --nnodes/--node-rank/--rdzv-endpoint` flags (or `accelerate launch --num_machines/--machine_rank/--main_process_ip`). | |
| > [!WARNING] | |
| > Accelerate's YAML config files (`accelerate launch --config_file some.yaml`, `accelerate config`) are not supported. They configure the engine through environment variables, bypassing LeRobot's configuration system, so `train_config.json` would no longer describe the settings a run actually used. `lerobot-train` therefore refuses to start when [accelerate environment variables](https://huggingface.co/docs/accelerate/usage_guides/fsdp) are set. Put the settings in `--parallelism.*` / `--accelerator.*` flags instead, or set `LEROBOT_ALLOW_ACCELERATE_ENV=1` to acknowledge the override and proceed anyway. | |
| ## Batch semantics, learning rate, and steps | |
| Each of the `dp_replicate × dp_shard` data-parallel workers loads its own `--batch_size` micro-batch every step, so one training step consumes `batch_size × dp_world_size` samples, and `× gradient_accumulation_steps` of those go into each optimizer update: | |
| ``` | |
| effective_batch_size = batch_size × dp_world_size × gradient_accumulation_steps | |
| ``` | |
| The training banner prints this factorization at startup. `--steps` counts loop steps (micro-batches per worker), not optimizer updates. | |
| Gradient accumulation is a first-class flag: | |
| ```bash | |
| torchrun --nproc-per-node=2 $(which lerobot-train) \ | |
| --batch_size=8 --accelerator.gradient_accumulation.steps=4 ... | |
| ``` | |
| **LeRobot does not auto-scale the learning rate or the number of steps** when the effective batch size grows. If you scale out and want equivalent training, please adjust manually, e.g. with 2 GPUs: double `--optimizer.lr` (linear scaling), or halve `--steps`. | |
| ## Sharded training (FSDP) | |
| If a model is too large to train with DDP, shard it with FSDP2: | |
| ```bash | |
| torchrun --nproc-per-node=4 $(which lerobot-train) \ | |
| --dataset.repo_id=${HF_USER}/my_dataset \ | |
| --policy.type=<your_policy> \ | |
| --parallelism.dp_shard=4 \ | |
| --accelerator.mixed_precision=bf16 \ | |
| --output_dir=outputs/train/my_policy_fsdp | |
| ``` | |
| `--parallelism.dp_shard=-1` shards over however many processes the launcher started. | |
| ### Wrap units | |
| FSDP shards the model in units (typically the repeated transformer block) and gathers one unit at a time during forward/backward. Policies declare their wrap units via `_fsdp_wrap_modules` on the policy class. For example, ACT declares `["ACTEncoderLayer", "ACTDecoderLayer"]` and FastWAM declares `["MoTLayer"]`. For a policy without a `_fsdp_wrap_modules` declaration, pass one of the flags below. You can specify the module class name explicitly, or use a size-based policy instead: | |
| ```bash | |
| --accelerator.fsdp.wrap_modules='["MyTransformerBlock"]' # explicit class names | |
| --accelerator.fsdp.min_num_params=1000000 # or: wrap every submodule above 1M params | |
| ``` | |
| If a policy doesn't declare `_fsdp_wrap_modules` and no `--accelerator.fsdp.wrap_modules` or `--accelerator.fsdp.min_num_params` is passed, the run fails at startup rather than silently wrapping only the root module (which would forfeit all sharding memory savings). | |
| Other sharding settings: | |
| - `--accelerator.fsdp.reshard_after_forward`: whether to keep each unit's parameters resident after forward. | |
| - `--accelerator.fsdp.cpu_offload`: keeps parameters, gradients and optimizer states on CPU. | |
| - `--accelerator.fsdp.ignored_modules`: a regex of module paths to keep unsharded. | |
| ### HSDP | |
| Hybrid Sharded Data Parallel: parameters, gradients and optimizer states are sharded across `dp_shard` ranks, and that sharding is replicated `dp_replicate` times. Parameter all-gathers and gradient reduce-scatters stay inside a shard group; only the all-reduce that synchronizes the replicas crosses between groups. The two degrees must multiply to the world size: | |
| ```bash | |
| # 16 GPUs = 2 nodes × 8: shard within each node, replicate across nodes | |
| torchrun --nnodes=2 --nproc-per-node=8 ... $(which lerobot-train) \ | |
| --parallelism.dp_replicate=2 --parallelism.dp_shard=8 ... | |
| ``` | |
| ## Checkpoints | |
| Every checkpoint contains a `pretrained_model/` directory and a `training_state/` directory: | |
| ```text | |
| 005000/ # the training step at that checkpoint | |
| ├── pretrained_model/ | |
| │ ├── config.json # policy config | |
| │ ├── train_config.json # the full training config | |
| │ ├── model.safetensors # full weights (checkpoint_format ∈ {safetensors, safetensors_dcp}, or any non-sharded run) | |
| │ ├── pytorch_model_fsdp_0/ # DCP weight shards (checkpoint_format ∈ {dcp, safetensors_dcp}) | |
| │ ├── policy_preprocessor.json # preprocessor config (when the run has a preprocessor) | |
| │ ├── policy_preprocessor_step_*.safetensors # state of the stateful preprocessor steps | |
| │ ├── policy_postprocessor.json # postprocessor config (when the run has a postprocessor) | |
| │ └── policy_postprocessor_step_*.safetensors # state of the stateful postprocessor steps | |
| └── training_state/ | |
| ├── training_step.json # step counter, topology, and batch semantics | |
| ├── rng_state.safetensors # rng states | |
| ├── scheduler_state.json # scheduler state (when the run has a scheduler) | |
| ├── optimizer_state.safetensors # full optimizer state (non-sharded runs) | |
| ├── optimizer_param_groups.json # optimizer param groups (non-sharded runs) | |
| └── optimizer_0/ # DCP optimizer shards (sharded runs) | |
| ``` | |
| During single-GPU or DDP training, the pipeline serializes each state dict into a single file: `model.safetensors` for the model and `optimizer_state.safetensors` for the optimizer. | |
| During sharded training, the optimizer state is saved as DCP shards under `training_state/optimizer_0/`, and the layout of the model under `pretrained_model/` can be configured through `--checkpoint_format`: | |
| | `--checkpoint_format` | Weights artifact | Use when | | |
| | ------------------------- | -------------------------------------------- | --------------------------------------------------------------------- | | |
| | `safetensors` _(default)_ | single `model.safetensors` only | you want every checkpoint immediately loadable with `from_pretrained` | | |
| | `dcp` | `pytorch_model_fsdp_0/` shard directory only | gathering the full weights makes saves and resumes too slow | | |
| | `safetensors_dcp` | both | you want fast resume _and_ immediately loadable checkpoints | | |
| Two things to know about gathered (`safetensors`) checkpoints from sharded runs: | |
| - **They store fp32 weights.** Under mixed precision training, FSDP keeps an fp32 master copy, and the checkpoint saves the master copy to make sure training resumes consistently. | |
| - The gather is collective (all ranks participate) but only the main process writes. | |
| ### Converting DCP checkpoints | |
| `lerobot-convert-dcp` merges a DCP shard directory into a regular `model.safetensors`, offline and without GPUs: | |
| ```bash | |
| lerobot-convert-dcp --checkpoint_dir=outputs/train/run/checkpoints/005000 | |
| lerobot-convert-dcp --checkpoint_dir=... --delete_dcp=true --push_to_hub=${HF_USER}/my_policy | |
| ``` | |
| `--push_to_hub` publishes the converted directory as a model repo. | |
| ### Resuming | |
| Resume with `--resume=true --config_path=.../checkpoints/last/pretrained_model/train_config.json`. Resuming from a DCP checkpoint supports resharding the model and optimizer state to the _current_ topology, which means you can resume with a different `dp_replicate/dp_shard` split. The data sampler can always resume at the right epoch and offset, but is only _sample-exact_ when the world size and batch size match the original run (a warning is logged otherwise). | |
| > [!NOTE] | |
| > FSDP checkpoints written by LeRobot 0.6.x and earlier used a different on-disk layout (a gathered full optimizer state) and **cannot be resumed**. | |
| ## Notes | |
| - Checkpoint saves and end-of-training publishes are collective (every rank enters them). Gathered weights, sidecar files and Hub uploads are written by the main process alone. | |
| - Metrics are reduced across ranks before logging: losses are averaged, and `samples/s` reports cluster-wide throughput. | |
| - Learning-rate scheduling is stepped once per training step regardless of the number of processes (`step_scheduler_with_optimizer=False` is baked in). | |
| For background on the underlying machinery, see the [Accelerate FSDP guide](https://huggingface.co/docs/accelerate/usage_guides/fsdp). To go deeper on large-scale training, check out the [Ultrascale Playbook](https://huggingface.co/spaces/nanotron/ultrascale-playbook). | |
Xet Storage Details
- Size:
- 10.7 kB
- Xet hash:
- f95d79406f9e3e6ec3c410cf55ef779096237684917545c906814eb0514630e8
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.