
Adding GPUs to a VLA fine-tune changes batch size, learning rate and step count in ways the flags hide. What GR00T and LeRobot really do, and the distributed failures that cost a day.
Four GPUs, quarter of the wall clock. For a fine-tune on 50 teleop episodes of an SO-100, that is almost never what you get, and the reason is not physics. The flag called batch size means opposite things in the two trainers most people reach for. In LeRobot it is per worker, so adding GPUs multiplies your effective batch. In NVIDIA's Isaac-GR00T N1.7 it is global, so adding GPUs divides the work and leaves the effective batch where it was. Same word, same number, inverted result.
This page describes what the code does today, with the file it came from and the release it shipped in, because both projects moved their multi-GPU story in 2026 and most tutorials online describe the older one. Then the three failures that turn a distributed run into a lost day: a batch that no longer means what you think, a learning rate nobody scaled, and a collective that hangs until NCCL gives up. It ends with the honest part, which is that for a 50-episode policy on a low-cost arm, the second GPU is usually the wrong thing to buy.
The short version
- •LeRobot multiplies. Its docs give the formula: effective_batch_size = batch_size x dp_world_size x gradient_accumulation_steps. Four workers at --batch_size=8 train at 32.
- •Isaac-GR00T N1.7 divides. --global-batch-size 64 over --num-gpus 8 puts 8 samples on each card. Adding hardware changes the time per step, not the effective batch.
- •Neither scales the learning rate for you. LeRobot says so outright: it does not auto-scale the learning rate or the step count when the effective batch grows.
- •Bigger batches are a pretraining tool. GR00T N1's own paper trains at batch 16,384 and post-trains at 128 or 1024, explicitly to avoid overfitting in data-limited settings.
- •GR00T's fine-tune entry point changed file, flag name and flag meaning between the n1.5 release (15 December 2025) and the n1.7 release (18 April 2026). A guide written against the old one trains something else.
- •AY-Robots runs each job on one rented card sized by the model's VRAM requirement. The knobs below are for hardware you rent yourself; the platform's form has no GPU-count field, and this article says where that matters.
What your trainer means by batch size
Before any distributed flag, settle what the number in your config controls. There are three conventions in circulation among VLA trainers, and mixing them up is the single most common way a multi-GPU run produces a worse checkpoint than the single-GPU run it replaced.
| Trainer and version | The batch flag | What its scope is | Samples per optimizer update |
|---|---|---|---|
| LeRobot, main branch (August 2026) | --batch_size, default 8 | per data-parallel worker | batch_size x dp_world_size x gradient_accumulation_steps |
| LeRobot 0.5.1 (released 7 April 2026) | --batch_size, default 8 | per process | batch_size x num_processes |
| Isaac-GR00T, n1.7-release (18 April 2026) | --global-batch-size, default 64 | across all GPUs together | global_batch_size x gradient_accumulation_steps |
| Isaac-GR00T, n1.5-release (15 December 2025) | --batch-size, default 32 | per device | batch_size x num_gpus |
| openpi, JAX path | fsdp_devices in the training config | a sharding degree, not a batch | unchanged; only the memory is split |
The GR00T N1.7 line is the one that surprises people. In gr00t/experiment/experiment.py the per-device batch is literally global_batch_size // num_gpus, and a startup check in warn_configs asserts that the division is exact. Going from one H100 to eight does not train on more data per step. It trains the same 64 samples with 8 on each card, a throughput change and nothing else. To get the larger batch too, raise --global-batch-size yourself, which is what NVIDIA's hardware guide does when it pairs 4 to 8 cards with a global batch of 64 to 640.
LeRobot (main, Aug 2026)
effective_batch = batch_size x dp_world_size x gradient_accumulation_steps
# --batch_size=8, 4 workers, --accelerator.gradient_accumulation.steps=2 -> 64
Isaac-GR00T N1.7
per_device_train_batch_size = global_batch_size // num_gpus # experiment.py
accumulated_batch_size = global_batch_size x gradient_accumulation_steps
# --global-batch-size 64 --num-gpus 8 -> 8 per card, 64 per update
Hugging Face Trainer (what GR00T sits on)
effective_batch = per_device_train_batch_size x num_devices x gradient_accumulation_steps
openpi (JAX)
--fsdp-devices N shards parameters over N devices; the batch you configured stays the batchIn N1.7 you launch torchrun yourself and pass --num-gpus, and the code cross-checks them: if WORLD_SIZE is set and does not equal --num-gpus, it raises. The comment in experiment.py explains why the guard exists: num_gpus drives the per-device batch and the DeepSpeed gating, while the Hugging Face Trainer and the dataset sharding use the real WORLD_SIZE, so an 8-rank launch declared as num_gpus=1 would train at 8x the intended batch without a word of warning. There is a second assertion next to it: global_batch_size must be divisible by num_gpus. A global batch of 64 works on 8 cards and fails on 6.
When a second GPU actually helps
There are three separate reasons to add a card, and only one of them is speed. Being clear about which one you are chasing decides whether you want plain data parallelism, sharding, or neither.
- Memory, when the model does not fit. openpi puts a full Pi0.5 fine-tune above 70 GB and its LoRA path above 22.5 GB. Sharding with
--fsdp-devicesin openpi, or--parallelism.dp_shardin current LeRobot, spreads parameters, gradients and optimizer state across cards that could not hold the model alone. - Headroom for the expensive switches. GR00T's default fine-tune touches only the projector and the diffusion action head, under about 35 GB per GPU. NVIDIA's guide says
--tune-llmor--tune-visualneeds 80 GB or more per GPU. - Wall clock, once each card has enough work. NVIDIA's recommended setup is 4 to 8 H100 or L40 cards at a global batch of 64 to 640, the regime where collectives are small relative to compute.
- A large real batch without gradient accumulation, which matters when accumulation is not actually wired into your trainer.
- Data efficiency. Goyal et al. matched ImageNet accuracy at batch 8192 with a linear learning-rate rule and a warmup. Nobody has shown that transfers to 50 demonstrations of one task.
- A shorter queue. Multi-card nodes are scarcer and pricier per hour on spot markets, and a run that waits an hour for a node gave back the hour it saved.
- Reproducibility. GR00T's fine-tune CLI has no seed field at all, and its trainer warns when it reseeds the sharded dataset on resume: this will make the experiment non-reproducible. LeRobot's default seed is 1000 and is a real flag.
- Anything for a small policy. ACT at roughly 80 M parameters trained in about 5 hours on one 11 GB RTX 2080 Ti in the original paper. Distributing it is setup cost with no payoff.
Mapped onto the five policies you can train for an SO-100 class arm, the picture is lopsided. Only the ~3 B models sit in a regime where distribution changes the answer, and even there the first question is memory, not speed. The policy comparison page has the params, GPU tier and inference latency for each. The column that matters here is the middle one.
| Policy | Params | Single-card tier | What a second GPU realistically changes |
|---|---|---|---|
| ACT | ~80 M | RTX 4090 or any 24 GB card | Nothing worth the setup. The original paper trained it in about 5 hours on one 11 GB card. |
| SmolVLA | ~450 M | RTX 4090 or any 24 GB card | Only if you want a big batch. The paper used 4 GPUs for a global batch of 256 in pretraining and says outright the model can easily be trained on a single GPU. |
| GR00T N1.5 | ~3 B | A100 80 GB or H100 80 GB | Throughput, once the per-card batch is large enough to keep the card busy. Old flag semantics: --batch-size is per device. |
| GR00T N1.7 | ~3 B | A100 80 GB or H100 80 GB | Throughput, plus the headroom to enable --tune-llm or --tune-visual. --global-batch-size stays fixed as you add cards. |
| Pi0.5 | ~3 B | A100 80 GB or H100 80 GB | Memory first. openpi's full fine-tune floor is above 70 GB; fsdp_devices trades speed for fit. |

The learning rate and the step count, which nothing scales for you
Both trainers leave this to you, and LeRobot puts it in bold: it does not auto-scale the learning rate or the number of steps when the effective batch grows, and suggests that with 2 GPUs you either double --optimizer.lr or halve --steps. That is the linear scaling rule from Goyal et al.: multiply the learning rate by the same factor as the minibatch, and add a warmup so the first few hundred training steps do not blow up.
- If the effective batch grew by k, the linear rule says multiply the learning rate by k and keep a warmup. GR00T's warmup_ratio default is 0.05 with a cosine scheduler.
- If you would rather not touch the learning rate, divide the step count by k instead. Same samples seen, same schedule shape, fewer updates.
- Do not do both. Doubling the learning rate and halving the steps is a different run than either one, and it is the version people accidentally ship.
- Check the noise scale argument before scaling far. McCandlish et al. show that past a critical batch size, predicted by the gradient noise scale, extra batch buys wall clock and stops buying data efficiency. Its measured domains are MNIST, SVHN, CIFAR-10, ImageNet, Billion Word, Atari, Dota and autoencoders, none of them robot imitation, so on 50 episodes treat the threshold as unmeasured rather than known.
The strongest evidence that bigger is not automatically better comes from NVIDIA's own numbers. Table 6 of the GR00T N1 paper lists pretraining and post-training side by side: the batch drops by more than an order of magnitude while the learning rate does not move at all. The stated reason is one line, smaller batches in post-training to avoid overfitting when fine-tuning in data-limited settings.
| Hyperparameter | GR00T N1 pretraining | GR00T N1 post-training |
|---|---|---|
| Batch size | 16,384 | 128 or 1024 |
| Gradient steps | 200,000 | 20,000 to 60,000 |
| Learning rate | 1e-4 | 1e-4 |
| Optimizer / scheduler | AdamW, cosine | AdamW, cosine |
| Warmup ratio | 0.05 | 0.05 |
| Weight decay | 1e-5 | 1e-5 |
| Backbone vision encoder | unfrozen | unfrozen |
| Backbone text tokenizer | frozen | frozen |
The same paper reports up to 1024 H100 GPUs for a single model, and roughly 50,000 H100 GPU hours for GR00T-N1-2B pretraining. That is what produced the base checkpoint you are about to fine-tune. Your job on 50 episodes is the right-hand column above, not the left.
The manual path, with the commands that work today
Both sequences were read out of the upstream repositories in August 2026. Pin your version before copying anything: the flag names below are younger than most blog posts about them.
LeRobot: torchrun or accelerate launch, then DDP or FSDP
- 1Install the training extra
accelerate ships inside LeRobot's
trainingextra. It is used as a plain launcher only; every distributed setting lives in LeRobot's own config system.bashpip install 'lerobot[training]' - 2Launch plain DDP across two GPUs
With no
--parallelism.*flags, a multi-process launch is plain DDP: the full model is replicated on every card.--batch_sizestays per worker, so this run sees 16 samples per step, not 8.bashtorchrun --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 \ --batch_size=8 \ --output_dir=outputs/train/act_multi_gpu \ --job_name=act_multi_gpu \ --wandb.enable=true - 3Compensate for the batch you just doubled
Pick one of the two adjustments, not both. Doubling the learning rate keeps the update size comparable; halving the steps keeps the sample budget comparable.
bash# option A: linear learning-rate scaling torchrun --nproc-per-node=2 $(which lerobot-train) --optimizer.lr=2e-4 ... # option B: same learning rate, half the steps torchrun --nproc-per-node=2 $(which lerobot-train) --batch_size=8 --steps=50000 ... - 4Shard instead of replicate when the model will not fit
FSDP2 shards parameters, gradients and optimizer state.
--parallelism.dp_shard=-1shards over however many processes the launcher started. Mixed precision defaults tono, so ask for bf16 explicitly or you will train the shards in fp32.bashtorchrun --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 - 5Give FSDP a wrap unit if the policy does not declare one
Policies declare their wrap units on the class: ACT declares
["ACTEncoderLayer", "ACTDecoderLayer"]. If a policy declares nothing and you pass nothing, the run fails at startup rather than wrapping only the root module and giving up every byte of the saving.bash--accelerator.fsdp.wrap_modules='["MyTransformerBlock"]' # explicit class names --accelerator.fsdp.min_num_params=1000000 # or wrap anything above 1M params
Isaac-GR00T N1.7: you drive torchrun, and you tell it the count twice
- 1Clone with submodules and set up the environment
GR00T pins dependencies through
uvand needs git-lfs for the demo parquet files. The tested dGPU stack is Python 3.12, CUDA 12.6+, PyTorch 2.7+.bashsudo apt install git-lfs && git lfs install git clone --recurse-submodules https://github.com/NVIDIA/Isaac-GR00T cd Isaac-GR00T - 2Run the single-GPU baseline first
Get a working run on one card first. It is the reference the multi-GPU run has to match, and the run whose loss curve tells you whether the dataset is the problem.
bashCUDA_VISIBLE_DEVICES=0 uv run python \ gr00t/experiment/launch_finetune.py \ --base-model-path nvidia/GR00T-N1.7-3B \ --dataset-path demo_data/cube_to_bowl_5 \ --embodiment-tag NEW_EMBODIMENT \ --modality-config-path examples/SO100/so100_config.py \ --num-gpus 1 \ --output-dir /tmp/test_finetune \ --max-steps 2000 \ --global-batch-size 32 \ --dataloader-num-workers 4 - 3Scale out with torchrun, keeping the two counts equal
--nproc_per_nodeand--num-gpusmust match or the run raises before loading a frame. And--global-batch-size 32here means 4 samples per card on 8 GPUs, not 32.bashuv run torchrun --nproc_per_node=8 --master_port=29500 \ gr00t/experiment/launch_finetune.py \ --base-model-path nvidia/GR00T-N1.7-3B \ --dataset-path demo_data/cube_to_bowl_5 \ --embodiment-tag NEW_EMBODIMENT \ --modality-config-path examples/SO100/so100_config.py \ --num-gpus 8 \ --output-dir /tmp/test_finetune_8gpu \ --max-steps 2000 \ --global-batch-size 32 \ --dataloader-num-workers 4 - 4Use accumulation to buy batch you do not have cards for
NVIDIA's hardware guide gives the arithmetic directly: 4 GPUs, 8 accumulation steps and a per-GPU batch of 8 gives an effective global batch of 256. In GR00T that is
--global-batch-size 32 --gradient-accumulation-steps 8, and the trainer logs the resulting accumulated batch at startup.bashuv run torchrun --nproc_per_node=4 gr00t/experiment/launch_finetune.py \ --num-gpus 4 \ --global-batch-size 32 \ --gradient-accumulation-steps 8 \ --max-steps 10000 \ --save-steps 1000

Two routes to the same checkpoint
You rent or own a multi-GPU node, install the trainer, convert the dataset to the format that trainer wants, and drive torchrun. This is the only path if you want FSDP, more than one node, or a global batch above what one card holds.
- Provision a node with 2 to 8 cards of 40 GB or more and confirm the interconnect. NVLink and PCIe behave very differently under all-reduce.
- Install the trainer at a pinned version. LeRobot 0.6.1 was released 3 August 2026; the GR00T n1.7-release tag is dated 18 April 2026.
- Convert your LeRobot dataset to the version the trainer accepts. GR00T needs v2.0 or v2.1; a v3.0 dataset crashes its loader and has to be converted down.
- Run single-GPU first and record the loss curve. Without it you cannot tell a distributed bug from a data bug.
- Scale out, then fix the batch semantics: check whether the flag is per worker or global, and adjust learning rate or steps once.
- Watch the first hundred steps. If throughput per card fell, you are dataloader bound.
The commands are short. The time goes into CUDA and NCCL version matching, the dataset conversion, and the first run that hangs for ten minutes before telling you nothing. Reserve an afternoon for the first distributed run on any new node; later ones are cheap.
The training form picks a model, a dataset and the hyperparameters, and the backend rents a GPU on a spot market by required VRAM, runs the trainer, and writes checkpoints to object storage. There is no GPU-count field, because every run is sized to one card. That is a real limitation and it is also, for the workloads this platform targets, the cheaper answer.
| Policy | Batch size | Learning rate | Max steps | Gradient accumulation | Does accumulation apply? |
|---|---|---|---|---|---|
| GR00T N1.7 | 32 | 1e-4 | 20000 | 1 | yes |
| GR00T N1.5 | 1 | 1e-5 | 2000 | 16 | yes |
| Pi0.5 | 1 | 5e-5 | 30000 | 16 | no, lerobot 0.5.1 has no such flag |
| SmolVLA | 2 | 1e-4 | 20000 | 8 | no |
| ACT | 8 | 1e-5 | 100000 | 1 | no |
Those are the defaults the trainer really sends, and two rows are worth reading twice: on Pi0.5 and SmolVLA the accumulation number is inert, so the effective batch is 1 and 2, not 16 and 16. The training docs and the per-model guides such as GR00T N1.7 on SO-100 and SmolVLA on SO-100 carry the same numbers. A run on the A100 or H100 tier takes 3 to 6 hours at 1.20 to 2.00 USD per hour, roughly 4 to 12 USD; on the 24 GB tier, 2 to 5 hours and 1 to 3 USD.
A four-hour A100 run costs roughly 5 to 8 USD at 1.20 to 2.00 USD per hour. Perfect linear scaling on four cards would save three hours of wall clock and roughly nothing in money, because you pay four times the hourly rate for a quarter of the time. What you would actually spend is the afternoon of setup. Multi-GPU pays when the model does not fit, or when you are running the same fine-tune dozens of times a week.
The distributed failures that cost a day
Single-GPU training fails loudly. Distributed training fails quietly, or ten minutes later in a stack trace that names a collective and nothing about your code. These are the ones that show up on VLA fine-tunes, with what each actually is.
| Symptom | What it really is | What to do |
|---|---|---|
| ValueError at startup about num_gpus not matching WORLD_SIZE | GR00T N1.7 cross-checks the launcher world size against --num-gpus before loading anything | Set --num-gpus to the same value as --nproc_per_node. The guard exists because a mismatch silently rescales the effective batch. |
| AssertionError: global_batch_size must be divisible by num_gpus | GR00T computes the per-device batch with integer division | Choose a global batch that divides evenly by the card count. 64 works on 8 cards, fails on 6. |
| Run starts, then hangs and dies after exactly ten minutes | NCCL's default collective timeout is 10 minutes; other backends default to 30 | One rank took a different code path and never entered the collective. Look for rank-conditional logic around logging, evaluation and checkpoint saving. |
| Startup fails complaining about FSDP wrap units | LeRobot refuses to wrap only the root module rather than silently forfeiting the memory saving | Pass --accelerator.fsdp.wrap_modules with the block class name, or --accelerator.fsdp.min_num_params. |
| Throughput per card drops as you add cards | The dataloader, not the GPU, is the bottleneck. GR00T defaults to 2 workers, LeRobot to 4 | Raise --dataloader-num-workers or --num_workers and the per-card batch before adding more hardware. |
| Two GPUs requested, four processes appear | The n1.5 script re-launched itself under torchrun unless IS_TORCHRUN=1 was set, so wrapping it in your own torchrun nested the launchers | On n1.5 call the script directly with --num-gpus N. On n1.7 you always drive torchrun yourself. |
| Checkpoint from a sharded run will not load with from_pretrained | LeRobot can write DCP shards instead of a single safetensors file | Keep --checkpoint_format=safetensors, or run lerobot-convert-dcp offline to merge the shards. |
| Out of memory on card 0 only | Rank 0 carries the extra load of logging, gathered checkpoint writes and often the evaluation batch | See the out-of-memory failure page; reduce the per-device batch or move the gather off the critical path. |
LeRobot's current documentation states it plainly: --steps counts loop steps, that is micro-batches per worker, not optimizer updates. GR00T sits on the Hugging Face Trainer, whose global_step increments immediately after optimizer.step(), so --max-steps there counts optimizer updates. Put gradient accumulation on top: at accumulation 16, --max-steps 2000 in GR00T is 2000 updates over 32,000 micro-batches, while the same number in LeRobot main is 2000 micro-batches and 125 updates. Halve the step count on top of that because you added a GPU, and 1000 loop steps at accumulation 16 is 62 optimizer updates where you thought you were asking for 2000, then spend a day wondering why the loss plateaued high. Read the startup banner: LeRobot prints the batch factorization, and GR00T logs the accumulated batch size when accumulation is above 1.
# Ask NCCL what it is doing. INFO is usually enough; TRACE is very loud.
export NCCL_DEBUG=INFO
# Two GPUs on a host where peer-to-peer is broken or virtualised badly:
# force the fallback path and see whether the hang disappears.
export NCCL_P2P_DISABLE=1
# Multi-node on a box with several NICs: pin the interface NCCL is allowed to use.
export NCCL_SOCKET_IFNAME=eth0
# No InfiniBand, or an IB stack that is present but not usable:
export NCCL_IB_DISABLE=1
# Then reproduce on the smallest possible run.
torchrun --nproc-per-node=2 $(which lerobot-train) --steps=50 --batch_size=2 ...Two rules make these cheap. First, never debug a distributed run at full scale: reproduce with 50 steps and a batch of 2, because a hang at step 50 costs a minute and a hang at step 5000 costs an hour. Second, if the single-GPU run of the same config was never green, stop; you are debugging your dataset through a distributed launcher, the worst available microscope. The failure-mode index has the single-GPU versions of most of these, including a job that never leaves the queue and a loss that falls while the policy does nothing.
What moved upstream, and when
This is the part that dates fastest, so here is the state as of August 2026 with the release each change landed in. If a tutorial you are following uses a name from the left-hand column, it predates the current code.
| What changed | Before | Now | Dated by |
|---|---|---|---|
| GR00T fine-tune entry point | scripts/gr00t_finetune.py | gr00t/experiment/launch_finetune.py | n1.5-release 15 Dec 2025 to n1.7-release 18 Apr 2026 |
| GR00T batch flag | --batch-size, default 32, per device | --global-batch-size, default 64, across all GPUs | same window |
| GR00T launcher behaviour | the script re-executed itself under torchrun when num_gpus > 1 | you run torchrun; --num-gpus must equal WORLD_SIZE | same window |
| GR00T multi-GPU backend | plain DDP: the n1.5 script passed an empty DeepSpeed config | DeepSpeed ZeRO-2 by default when num_gpus > 1 and use_ddp is false | gr00t/configs/training/training_config.py on main |
| LeRobot sharding | DDP through accelerate only | FSDP2 and HSDP via --parallelism.dp_shard and --parallelism.dp_replicate | after 0.5.1, released 7 Apr 2026 |
| LeRobot accelerate YAML config | accelerate config was the documented option | refused at startup unless LEROBOT_ALLOW_ACCELERATE_ENV=1 | after 0.5.1 |
| LeRobot FSDP checkpoints | a gathered full optimizer state | DCP shards; 0.6.x and earlier FSDP checkpoints cannot be resumed | documented on main; 0.6.1 released 3 Aug 2026 |
The LeRobot YAML change breaks a habit. Older guides tell you to run accelerate config and answer the interactive questions. Current LeRobot refuses to start when accelerate environment variables are set, for a good reason: those variables configure the engine behind LeRobot's back, so the train_config.json saved next to your checkpoint would no longer describe the run that produced it. Put the settings in --parallelism.* and --accelerator.* flags instead.
Where more GPUs stop helping, including here
AY-Robots does not do multi-GPU training. The form picks model, dataset and hyperparameters, and the backend rents one card sized by the VRAM that model needs. If your plan is a 640-sample global batch across eight H100s, this is not the tool; rent a node and use the commands above. What the platform removes is the part that eats the day: environment setup, dataset format conversion, and checkpoint plumbing.
- For ACT and SmolVLA on 30 to 50 episodes, one 24 GB card finishes in 2 to 5 hours for 1 to 3 USD. There is no wall clock problem to solve.
- For GR00T N1.7 and Pi0.5, one 80 GB card finishes in 3 to 6 hours for 4 to 12 USD. Four cards buy back hours you were not going to spend watching it anyway.
- Multi-GPU pays when the model will not fit on the largest card you can get, when you run the same fine-tune dozens of times a week, or when you are pretraining rather than post-training. None of those describe a first SO-100 policy.
- What most often decides whether the policy works is upstream of all this: how many clean episodes you recorded and whether the cameras stayed consistent. That is covered in the data collection write-up.
One more limit, usually discovered after the training question is settled: distribution changes nothing about deployment. A trained vision-language-action model still runs one action step at a time, and on this platform that is 20 ms for ACT up to 485 ms for Pi0.5. Inference has to sit next to the servos for fast tasks; public-internet round trips turn a working policy into a hesitant one. Remote inference is viable for slow pick-and-place, not for fast reactive motion. For deployment numbers before you pick a model, the GR00T N1.7 against Pi0.5 comparison and the model arena with its 85 models and 332 benchmark results are the places to start. the VLA overview covers what these models do in the first place.
Train a policy on your own arm without building a cluster
Pick the model and the arm, and the guide gives you the dataset format, the defaults the trainer really sends, and what the run costs. One rented card per run, checkpoints written to storage, no NCCL debugging.
Open the training guidesQuestions people actually ask
Does adding a second GPU halve my fine-tune time?▾
Only if each card stays busy, and only where the batch flag is per worker. In LeRobot, two workers at --batch_size=8 process 16 samples per step: the wall clock per epoch roughly halves, but the effective batch doubled and you now have a learning-rate decision. In Isaac-GR00T N1.7, --global-batch-size is divided across the cards, so eight GPUs at --global-batch-size 32 put four samples on each; the step gets faster, the batch does not change. And if the dataloader cannot feed the cards, nothing gets faster at all. GR00T defaults to two dataloader workers and LeRobot to four, which is often the real ceiling.
Should I double the learning rate when I double the GPUs?▾
If the effective batch doubled, the linear scaling rule from Goyal et al. says yes, with a warmup so the early steps do not diverge. LeRobot's documentation suggests exactly that, or halving --steps instead. Pick one, not both. Note the counter-evidence for small datasets: NVIDIA's GR00T N1 paper keeps the learning rate at 1e-4 while dropping the batch from 16,384 in pretraining to 128 or 1024 in post-training, to avoid overfitting in data-limited settings. On 50 episodes you are in that regime.
Can I run multi-GPU training on AY-Robots?▾
No. Every run here is sized to a single rented GPU by the VRAM the model needs: the 80 GB tier for GR00T N1.5, GR00T N1.7 and Pi0.5, a 24 GB card for SmolVLA and ACT. The training form exposes batch size, learning rate, max steps, gradient accumulation and a few per-model extras, and no GPU count. For a 30 to 50 episode dataset that is the right shape and the cheaper one: roughly 1 to 3 USD per run on the 24 GB tier, 4 to 12 USD on the 80 GB tier. If you need sharding across cards, rent a node and use the upstream commands above.
FSDP or DDP for a 3B VLA?▾
DDP if the model fits, FSDP if it does not. DDP replicates the whole model on every card and communicates only gradients: simpler and faster per step. FSDP shards parameters, gradients and optimizer state, which is what lets a model train on cards that could not hold it, at the cost of gathering each unit during forward and backward. openpi describes fsdp_devices as reducing memory in exchange for slower training. In current LeRobot the switch is --parallelism.dp_shard, and you must give FSDP a wrap unit unless the policy class declares one.
My GR00T run refuses to start with a divisibility error. What is wrong?▾
N1.7 computes the per-device batch as global_batch_size divided by num_gpus with integer division, and asserts the division is exact before loading anything. A global batch of 64 works on 1, 2, 4 or 8 cards and fails on 3, 5 or 6. A second check sits next to it: if the launcher set WORLD_SIZE and it does not equal --num-gpus, the run raises, because that mismatch would silently rescale the effective batch.
My distributed run hangs and then dies after ten minutes. Where do I look?▾
Ten minutes is NCCL's default collective timeout in PyTorch; other backends default to thirty. The pattern almost always means one rank entered a collective the others did not, so start with anything that runs on one rank only: logging, evaluation, checkpoint saving, Hub uploads. Set NCCL_DEBUG=INFO and reproduce with a 50-step run at batch 2, not at full scale. On a two-GPU box where peer-to-peer is broken or badly virtualised, NCCL_P2P_DISABLE=1 is the quickest way to confirm it.
Sources
- NVIDIA/Isaac-GR00T: README, fine-tuning commands and hardware requirements for GR00T N1.7
- Isaac-GR00T hardware recommendation guide: fine-tuning table, global batch 64 to 640, VRAM per GPU
- Isaac-GR00T experiment.py: the num_gpus vs WORLD_SIZE guard and the global-to-per-device batch division
- Isaac-GR00T FinetuneConfig: global_batch_size 64, learning_rate 1e-4, max_steps 10000, no seed field
- Isaac-GR00T n1.5-release gr00t_finetune.py: the older per-device --batch-size and the torchrun self-relaunch
- Isaac-GR00T releases: n1.5-release 15 Dec 2025, n1.7-release 18 Apr 2026
- LeRobot multi-GPU training docs (main): DDP, FSDP2, HSDP, batch semantics and checkpoint formats
- LeRobot 0.5.1 multi-GPU training docs: accelerate launch and the no-auto-scaling statement
- LeRobot AcceleratorConfig: FSDP wrap policy, gradient accumulation, mixed_precision default
- openpi README: fsdp_devices, 70 GB full fine-tune floor, 22.5 GB LoRA, no multi-node in the JAX trainer
- GR00T N1: An Open Foundation Model for Generalist Humanoid Robots (Table 6 hyperparameters, 1024 H100 training)
- SmolVLA: A Vision-Language-Action Model for Affordable and Efficient Robotics (4 GPUs, global batch 256)
- Learning Fine-Grained Bimanual Manipulation with Low-Cost Hardware (ACT: 80M params, 5 hours on one 2080 Ti)
- Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour (the linear scaling rule and warmup)
- An Empirical Model of Large-Batch Training (gradient noise scale and the critical batch size)
Sources
- NVIDIA/Isaac-GR00T: README, fine-tuning commands and hardware requirements for GR00T N1.7
- Isaac-GR00T hardware recommendation guide: fine-tuning table, global batch 64 to 640, VRAM per GPU
- Isaac-GR00T experiment.py: the num_gpus vs WORLD_SIZE guard and the global-to-per-device batch division
- Isaac-GR00T FinetuneConfig: global_batch_size 64, learning_rate 1e-4, max_steps 10000, no seed field
- Isaac-GR00T n1.5-release gr00t_finetune.py: the older per-device --batch-size and the torchrun self-relaunch
- Isaac-GR00T releases: n1.5-release 15 Dec 2025, n1.7-release 18 Apr 2026
- LeRobot multi-GPU training docs (main): DDP, FSDP2, HSDP, batch semantics and checkpoint formats
- LeRobot 0.5.1 multi-GPU training docs: accelerate launch and the no-auto-scaling statement
- LeRobot AcceleratorConfig: FSDP wrap policy, gradient accumulation, mixed_precision default
- openpi README: fsdp_devices, 70 GB full fine-tune floor, 22.5 GB LoRA, no multi-node in the JAX trainer
- GR00T N1: An Open Foundation Model for Generalist Humanoid Robots (Table 6 hyperparameters, 1024 H100 training)
- SmolVLA: A Vision-Language-Action Model for Affordable and Efficient Robotics (4 GPUs, global batch 256)
- Learning Fine-Grained Bimanual Manipulation with Low-Cost Hardware (ACT: 80M params, 5 hours on one 2080 Ti)
- Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour (the linear scaling rule and warmup)
- An Empirical Model of Large-Batch Training (gradient noise scale and the critical batch size)
Ready for high-quality robotics data?
AY-Robots connects your robots to skilled operators worldwide.
Get Started