
Every fix for CUDA out of memory in VLA fine-tuning, in the order to try them, with real Isaac-GR00T and lerobot flags and which levers quietly change the policy you get.
What you need to know
- •The error line names your fix. A large 'reserved by PyTorch but unallocated' figure means fragmentation, and an allocator flag solves that for free.
- •Mixed-precision AdamW costs about 18 bytes per parameter before any activation exists: 6 for the weight copies, 8 for the Adam moments, 4 for the gradient. Roughly 54 GB for a 3 B model.
- •Order: free the card, fix the dtype, cut the batch, accumulate to restore it, checkpoint activations, freeze modules, go LoRA, shrink the inputs, tune the allocator, rent a bigger card.
- •About half change the policy you get. Batch size, freezing, LoRA, resolution and chunk size do. Allocator flags, empty_cache and dataloader workers do not.
- •Isaac-GR00T's hardware guide (main, 2026-08-24) puts the default fine-tune under 35 GB peak per GPU, and says --tune-llm or --tune-visual pushes past 80 GB.
- •In lerobot main, --accelerator.activation_checkpointing.mode is a documented placeholder. The flag that works is --policy.gradient_checkpointing, and only Pi0.5 defines it.
Read the error line before you touch anything
CUDA out of memory is not one error. PyTorch's allocator prints a five-part sentence and each part points at a different fix, so reading it is the difference between one config change and an afternoon of bisection. The wording comes from CUDACachingAllocator.cpp. Here it is, from a fine-tuning run that died on an 80 GB card.
torch.OutOfMemoryError: CUDA out of memory. Tried to allocate 2.34 GiB.
GPU 0 has a total capacity of 79.15 GiB of which 812.00 MiB is free.
Process 21874 has 78.35 GiB memory in use. Of the allocated memory
71.02 GiB is allocated by PyTorch, and 5.61 GiB is reserved by PyTorch
but unallocated. If reserved but unallocated memory is large try setting
PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True to avoid fragmentation.| Field | What it tells you |
|---|---|
| Tried to allocate X | Tens of GB means one tensor is wrong: resolution, chunk size, a stray concat. A small X means the card is full. |
| total capacity of Y | Which card you actually got. Spot markets hand out 40 GB A100s when you assumed 80. |
| of which Z is free | Z near zero with a small X is a capacity problem. Several GB free with a smaller failing X is fragmentation. |
| allocated by PyTorch | Live tensors: weights, gradients, optimizer state, activations. What batch size controls. |
| reserved but unallocated | Cached blocks the allocator cannot serve. Large here means set the allocator flag first. |
The PyTorch CUDA notes say the caching allocator keeps freed blocks so later allocations avoid a device synchronisation, and that this unused memory will still show as if used in nvidia-smi. Use memory_allocated() for live tensors, memory_reserved() for the allocator total. A few GB of gap is normal; tens of GB is fragmentation.
First check: is it the GPU at all?
Robot pipelines decode video on the CPU, in worker processes. A good share of reported out-of-memory failures on a LeRobot dataset never touched VRAM at all.
| What you see | Which memory | First change |
|---|---|---|
| torch.OutOfMemoryError with the five fields | GPU VRAM | Everything below |
| Process vanishes, exit code 137, no traceback | Host RAM, OS OOM killer | Fewer workers, smaller prefetch |
| DataLoader worker (pid N) killed by signal | Host RAM in a worker | num_workers and prefetch_factor down |
| Dies during loading, before step 1 | Host RAM during preload | GR00T: --num-shards-per-epoch. lerobot: --num_workers |
| Container restarts silently | Host RAM under a container limit | Raise the limit, not a trainer flag |
Isaac-GR00T's FinetuneConfig docstring for num_shards_per_epoch says reduce this number if vram is limited. The repo's hardware guide says the opposite: Reduce --num-shards-per-epoch if host memory (not VRAM) is limited. Both read from main on 2026-08-24, and the hardware guide matches the behaviour. Lower it hoping to fix a CUDA OOM and you change how much data the run sees per epoch, then hit the same wall.
Where the memory goes
Hugging Face's GPU memory anatomy page gives the per-parameter accounting for mixed-precision AdamW. It tells you which failures batch size can fix.
| Stored | Bytes per parameter | For a 3 B VLA | Scales with batch? |
|---|---|---|---|
| Weights, bf16 copy | 2 | 6 GB | No |
| Weights, fp32 master copy | 4 | 12 GB | No |
| Adam momentum, fp32 | 4 | 12 GB | No |
| Adam variance, fp32 | 4 | 12 GB | No |
| Gradients, fp32 | 4 | 12 GB | No |
| Subtotal, before any data | 18 | about 54 GB | No |
| Cached forward activations | varies | the rest of the card | Yes, near-linearly |
Two consequences. A full fine-tune of a 3 B vision-language-action model does not fit on 24 GB at any batch size, which is why GR00T N1.7 and Pi0.5 are 80 GB-tier here while SmolVLA and ACT are not. And only the last row responds to batch size, so a run that dies at batch 1 needs a structural change.
Published figures agree. openpi states above 22.5 GB for a LoRA fine-tune on an RTX 4090 and above 70 GB for a full one on an A100 80 GB or H100. NVIDIA's guide states a 40 GB minimum and puts the default recipe, which tunes the projector and diffusion head rather than the language backbone, under about 35 GB. The gap between 35 and 70 is entirely which modules carry gradients.

Pull the levers in this order
Order matters because the early levers are free and the late ones are not. Steps 1 to 5 cost time or nothing. From step 6 you are trading model quality, so do not start there just because the flag is easy to type.
- 1Free the card you already have
A dead notebook kernel or a crashed run will sit on 20 GB. On a rented pod this is the commonest reason a run OOMs at step 0 after working yesterday.
bashnvidia-smi --query-compute-apps=pid,process_name,used_memory --format=csv kill -9 <pid> # only processes you recognise as yours - 2Check the dtype default
lerobot's Pi0.5 config ships
dtype: str = "float32". Training a 3 B model in fp32 doubles weights and activations for no benefit on Ampere or newer. Check the default before you set anything: lerobot's GR00T config already shipsuse_bf16 = True, so there is nothing to turn on there, while the accelerator's ownmixed_precisionstill defaults to"no".bashlerobot-train --policy.type=pi05 --policy.dtype=bfloat16 ... # default is "float32" lerobot-train --accelerator.mixed_precision=bf16 ... # default is "no" # lerobot's groot policy is already use_bf16=True by default: # params stay FP32 and compute runs under BF16 autocast. - 3Halve the batch size
This tells you whether you are activation-bound or parameter-bound. If 32 dies and 16 runs, activations dominate. If batch 1 dies too, go to step 6.
bashpython gr00t/experiment/launch_finetune.py --global-batch-size 16 ... lerobot-train --batch_size=16 ... - 4Accumulate to restore the effective batch
Buys back the optimisation behaviour you gave away, at the cost of wall-clock time. GR00T's guide works an example: 4 GPUs, 8 accumulation steps, per-GPU batch 8 gives an effective global batch of 256.
bash# GR00T: global_batch_size is PRE-accumulation, and the class warns you python gr00t/experiment/launch_finetune.py \ --global-batch-size 16 --gradient-accumulation-steps 4 ... # lerobot main: it lives under the accelerator config lerobot-train --batch_size=16 --accelerator.gradient_accumulation.steps=4 ... - 5Turn on gradient checkpointing
Drop the cached activations and recompute them in the backward pass. Chen et al. 2016 took a 1000-layer residual network from 48 GB to 7 GB for about 30 percent extra running time; Hugging Face quotes about 20 percent for transformer fine-tunes.
bashlerobot-train --policy.type=pi05 --policy.gradient_checkpointing=true ... # raw PyTorch: use_reentrant has no default any more from torch.utils.checkpoint import checkpoint out = checkpoint(block, x, use_reentrant=False) - 6Freeze what you do not need to train
Here the trade starts. Both stacks freeze most of the backbone already, and un-freezing pushes GR00T past 80 GB. lerobot names the price: the frozen-VLM variant is less memory, at some cost in success rate.
bash# GR00T defaults: tune_llm=False, tune_visual=False, # tune_projector=True, tune_diffusion_model=True. # Adding --tune-llm or --tune-visual is what breaks a 40 GB card. lerobot-train --policy.type=pi05 \ --policy.freeze_vision_encoder=true --policy.train_expert_only=true ... - 7Switch to LoRA, if your version has it
Adapters cut optimizer state and gradients to the adapter parameters. Two version traps: in lerobot main PEFT is a top-level config, not a policy flag, so it is
--peft.*and it needs thepeftextra installed; and on the Isaac-GR00T side the N1.5 script had--lora-rankwhile the N1.7 FinetuneConfig has no LoRA fields at all.bash# lerobot main: PeftConfig is top-level (method_type defaults to LORA, r to 16). # Passing any --peft.* field is what turns PEFT on; there is no --policy.use_peft. lerobot-train --peft.method_type=LORA --peft.r=16 --peft.lora_alpha=32 ... # Isaac-GR00T, N1.5 branch only python scripts/gr00t_finetune.py --lora-rank 64 --lora-alpha 128 ... - 8Shrink the inputs, knowing the cost
Fewer cameras, smaller images and shorter chunks cut activations hard and change the task the model solves. GR00T N1.7 gates resolution behind two flags set together.
bashpython gr00t/experiment/launch_finetune.py \ --shortest-image-edge 224 --crop-fraction 0.9 ... lerobot-train --policy.chunk_size=25 --policy.n_action_steps=25 ... - 9Tune the allocator, which costs nothing
If the error showed several GB reserved-but-unallocated, this is your fix and none of the steps above were needed. In PyTorch 2.13 the variable is
PYTORCH_ALLOC_CONF.bashexport PYTORCH_ALLOC_CONF=expandable_segments:True # only if that is unavailable, and the docs call this a last resort: export PYTORCH_ALLOC_CONF=max_split_size_mb:512,garbage_collection_threshold:0.8 - 10Rent the right card
Nine levers in, you have spent real time and given away accuracy. Price that against the right GPU for a few hours: 4 to 12 USD on the 80 GB tier here, 1 to 3 USD on 24 GB.
bashuv run torchrun --nproc_per_node=8 --master_port=29500 \ gr00t/experiment/launch_finetune.py \ --base-model-path nvidia/GR00T-N1.7-3B \ --num-gpus 8 --global-batch-size 64 ...
Which levers silently change the run
Some flags are pure infrastructure. Others alter what the model learns, and the effect surfaces weeks later as a policy that behaves differently from the one you validated. Comparing two checkpoints means holding every row marked yes constant.
| Lever | Changes the policy? | Why |
|---|---|---|
| Allocator flags, empty_cache, fewer workers | No | Layout and scheduling only; empty_cache costs about 10 percent |
| FSDP sharding or CPU offload | No | Same maths, distributed. Slower per step |
| Gradient checkpointing | No, in principle | Same maths, recomputed. Determinism is not guaranteed if you move tensors across devices inside the function |
| bf16 instead of fp32 | Slightly | Different rounding; bf16 keeps fp32's range, so no loss scaling |
| 8-bit optimizer states | Slightly | bitsandbytes documents up to 75 percent less GPU memory with no accuracy loss |
| Smaller batch size | Yes | Noisier gradients, and your learning rate was tuned for the old batch |
| Gradient accumulation | Yes, if the loss is normalised wrongly | See the warning below |
| Freezing the vision encoder or the VLM | Yes | Frozen modules stop adapting to your scene |
| LoRA adapters | Yes | Lower-rank update, less capacity to move the backbone |
| Smaller images, fewer cameras, shorter chunks | Yes, a lot | The policy sees a different world and commits to a different horizon |
In October 2024 Hugging Face published a fix for exactly this: the Trainer averaged per-micro-batch losses instead of summing over all micro-batches and dividing by the total item count. For token-weighted objectives the two differ, so batch 4 with 4 accumulation steps did not match batch 16. It landed through PR 34191. On an older pinned Transformers, or a hand-written loop, verify the equivalence yourself.
The BatchNorm folklore does not apply here
There is a folk rule that lowering batch size breaks BatchNorm. Check before acting on it. lerobot's ACT builds its ResNet-18 backbone with FrozenBatchNorm2d, so the statistics are baked in, and GR00T, Pi0.5 and SmolVLA build on transformer backbones that normalise within each sample rather than across the batch. Across all five trainable policies here the batch-size risk is gradient noise, not normalisation.
That risk is real enough. The default in FinetuneConfig on main is a global batch of 64 at a learning rate of 1e-4, and those numbers were chosen together. Cut to batch 8 and keep 1e-4 and you have changed the optimisation problem, not just the footprint.
Freezing and LoRA: the honest trade
- Cuts optimizer state and gradients to the trainable subset, the largest fixed cost on the card
- openpi puts LoRA above 22.5 GB against above 70 GB full, moving a 3 B model onto a 24 GB card
- It is the default in both stacks, so leaving it on is no deviation from the tested recipe
- Faster per step, and adapters are small enough that ten variants cost nothing to keep
- A frozen vision encoder cannot adapt to your lighting, table or camera
- Low-rank updates run out of capacity first when the backbone must see something new
- GR00T N1.7's FinetuneConfig exposes no LoRA fields, so there you get freezing but not adapters
Isaac-GR00T N1.7 specifics
Read from NVIDIA/Isaac-GR00T on main on 2026-08-24. The entry point moved: N1.5 used scripts/gr00t_finetune.py, N1.7 uses gr00t/experiment/launch_finetune.py, a tyro CLI over FinetuneConfig. Tutorials written for N1.5 have half the flag names wrong.
| FinetuneConfig field | Default on main | Memory relevance |
|---|---|---|
| global_batch_size | 64 | Pre-accumulation, summed across all GPUs |
| gradient_accumulation_steps | 1 | Multiplies global_batch_size; the class warns when above 1 |
| tune_llm / tune_visual | False / False | Setting either True is the fastest route to an 80 GB requirement |
| tune_projector / tune_diffusion_model | True / True | The default recipe |
| dataloader_num_workers | 2 | Host RAM, not VRAM |
| num_shards_per_epoch | 100000 | Host RAM preloading, despite the field docstring |
| learning_rate | 1e-4 | Pair any batch-size change with a decision here |
Two details when hunting bytes. launch_finetune.py hard-codes load_bf16 = False and backbone_trainable_params_fp32 = True, so the profile is not simply everything in bf16. And the CLI exposes no seed: the Isaac-GR00T README says to expect 5 to 6 percent variance from non-deterministic augmentation, which is the floor for judging whether a memory change hurt your policy.

lerobot specifics: Pi0.5, SmolVLA, ACT
lerobot moved its runtime onto Hugging Face Accelerate, relocating several memory flags into an accelerator config that carries mixed precision, gradient accumulation, FSDP2 and DDP. Two sub-configs are unfinished, and that is the trap.
In src/lerobot/configs/accelerator.py on lerobot main, both ActivationCheckpointingConfig and CompileConfig carry the docstring a configured placeholder: wiring lands in a later round. So --accelerator.activation_checkpointing.mode=full is accepted, written into train_config.json, and changes nothing. The flag that works is --policy.gradient_checkpointing=true, and of the three lerobot-trained policies here (Pi0.5, SmolVLA, ACT) only Pi0.5 defines it. Read on 2026-08-24; check the file before relying on this.
# Pi0.5 on lerobot, memory-conscious. The docs describe the un-frozen
# version of this command as sized for a single 80 GB GPU.
lerobot-train \
--dataset.repo_id=$HF_USER/my_so100_dataset \
--policy.type=pi05 \
--policy.pretrained_path=lerobot/pi05_base \
--policy.dtype=bfloat16 \
--policy.gradient_checkpointing=true \
--policy.freeze_vision_encoder=true \
--policy.train_expert_only=true \
--policy.device=cuda \
--batch_size=16 \
--accelerator.gradient_accumulation.steps=4 \
--num_workers=4 --steps=30000 --seed=1000SmolVLA is the easy case: it ships freeze_vision_encoder = True and train_expert_only = True, and uses only the first 16 layers of the SmolVLM2 backbone. The Hugging Face guide suggests batch 64. If it still will not fit on 24 GB, look at resize_imgs_with_padding, which defaults to 512 by 512.
ACT rarely runs out of memory: at roughly 80 M parameters the whole 18-bytes-per-parameter budget is about 1.4 GB. When it does, the cause is action chunking and camera count. lerobot's ACT defaults are chunk_size 100 and n_action_steps 100 over a 512-dimensional transformer, Chunk size sets the number of decoder queries, and each camera runs the shared ResNet-18 once and flattens its feature map into extra encoder tokens, so cameras and chunk length grow the activations independently.
These commands describe lerobot main as of 2026-08-24; the latest PyPI release is 0.6.1. Older pins differ. The accelerator sub-config arrived with the Accelerate migration, so on lerobot==0.5.1 there is no --accelerator.gradient_accumulation.steps at all. lerobot has also removed GR00T N1.5 support. Print lerobot-train --help on the version you run rather than trusting a blog post, this one included.
Stop guessing: take a memory snapshot
If you have pulled four levers and still do not know where the memory went, measure it. PyTorch records every allocation with its Python stack and renders it as a browser timeline.
import torch
torch.cuda.memory._record_memory_history(max_entries=100_000)
try:
for step, batch in enumerate(loader):
train_one_step(batch)
if step == 5: # peak is reached early
break
finally:
torch.cuda.memory._dump_snapshot('oom.pickle')
torch.cuda.memory._record_memory_history(enabled=None)
print('allocated', torch.cuda.memory_allocated() / 2**30)
print('reserved ', torch.cuda.memory_reserved() / 2**30)
print('peak ', torch.cuda.max_memory_allocated() / 2**30)Read it for shape, not totals. A flat block that appears once and never moves is weights and optimizer state. A sawtooth rising through the forward and collapsing in the backward is activations. A staircase growing every step is a leak, usually a list of loss tensors that still carry their graph. No flag here fixes that; loss.detach() does.
Allocator settings that cost nothing
| Option | Documented default | When to reach for it |
|---|---|---|
| expandable_segments | False, experimental | First choice when allocation sizes change between iterations. The OOM message recommends it |
| max_split_size_mb | unlimited | A last resort, per the docs, for a workload aborting with many inactive split blocks |
| garbage_collection_threshold | 1.0 | Set 0.8 to reclaim old blocks before the card is full |
| roundup_power2_divisions | not set | Reduces churn when many nearby large sizes fragment the cache |
| backend | native | cudaMallocAsync is an alternative; it ignores the three options above |
PyTorch 2.13 documents the variable as PYTORCH_ALLOC_CONF and says PYTORCH_CUDA_ALLOC_CONF is its alias and is provided only for backward compatibility. Both work. Older guides, and the hint inside the OOM message, still use the CUDA-prefixed name.
Two ways to get a run that fits
You rent the GPU, install the trainer, convert the dataset and own every flag above. The right path if you are modifying the model or need a config nobody has packaged.
- 1Rent a card with headroom
The stated minimum is 40 GB and the default recipe peaks near 35. Renting exactly 40 leaves nothing for a second camera.
bashnvidia-smi --query-gpu=name,memory.total,driver_version --format=csv python -c "import torch; print(torch.__version__, torch.cuda.get_device_name(0))" - 2Install, then smoke-test for 50 steps
The hardware guide pins Python 3.12, CUDA 12.6+, PyTorch 2.7+ and uv. A run that OOMs at step 4000 because one episode has an extra camera stream costs the whole rental.
bashgit clone https://github.com/NVIDIA/Isaac-GR00T && cd Isaac-GR00T && uv sync export PYTORCH_ALLOC_CONF=expandable_segments:True uv run python gr00t/experiment/launch_finetune.py \ --base-model-path nvidia/GR00T-N1.7-3B \ --dataset-path /data/my_so100 \ --embodiment-tag NEW_EMBODIMENT \ --modality-config-path examples/SO100/so100_config.py \ --num-gpus 1 --max-steps 50 --global-batch-size 16 \ --dataloader-num-workers 4 --output-dir /tmp/smoke
A LeRobot v3.0 dataset crashes the GR00T loader and must be converted down to v2.1. That happens during loading and can look like a memory problem, because the process dies without a clean traceback. See the v3.0 rejection page before assuming VRAM.
The training form picks the model and dataset, and the backend rents a GPU by required VRAM. The card follows the model's requirement rather than what you clicked, so the failure that comes from renting 24 GB for a 3 B model does not arise. The training matrix lists every pairing.
| Policy | GPU tier requested | Batch size sent | Grad accum sent | Accumulation applies? |
|---|---|---|---|---|
| GR00T N1.7 | A100 or H100 80 GB | 32 | 1 | Yes |
| GR00T N1.5 | A100 or H100 80 GB | 1 | 16 | Yes |
| Pi0.5 | A100 or H100 80 GB | 1 | 16 | No, lerobot 0.5.1 has no such flag |
| SmolVLA | RTX 4090 or any 24 GB | 2 | 8 | No |
| ACT | RTX 4090 or any 24 GB | 8 | 1 | No |
That table holds a limitation, not a feature. For Pi0.5 and SmolVLA the form accepts a gradient accumulation value and the trainer does not apply it, because the pinned lerobot version has no flag to pass it to: the effective batch is the batch size. The training documentation and the out-of-memory failure page track this.
- The card matches the model's VRAM requirement, so the commonest cause is gone before you start
- Checkpoints stream to object storage as written, so a late failure loses less
- The v2.1 conversion GR00T needs is handled rather than left manual
- The same operations reach a terminal and agents, via the CLI and MCP server
- No arbitrary trainer flags. For an allocator variable or a custom freeze pattern, use the local path
- Gradient accumulation is inert for Pi0.5 and SmolVLA
- GR00T and Pi0.5 are cloud-only here; SmolVLA and ACT also run locally
- Spot pricing is a range: 4 to 12 USD on the 80 GB tier, 1 to 3 USD on 24 GB
When the answer is simply a bigger card
Engineers underrate this because it feels like giving up. Price it instead. Three hours fighting a 40 GB card, landing on a frozen vision encoder plus LoRA plus batch 4, gets you a policy worse than the reference recipe. The alternative was 8 more dollars. The levers above earn their keep when you are constrained by hardware you own. For a single policy on an SO-100, the cheapest fix is the right tier: 80 GB for GR00T or Pi0.5, or SmolVLA and ACT on 24 GB.
One caveat covers the subject. Fitting the run is not the same as getting a policy that works on the arm. A model that only fits because you froze the vision tower and halved the resolution can train to a low loss and still fail in your kitchen. That is low loss with no useful behaviour. Compare the constrained recipe against the reference one on rollouts, and use the benchmark arena for what the unconstrained versions reach.

Every failure mode, with the fix that actually works
Out of memory is one entry in a longer list: the dataset rejected as v3.0, the job stuck in the queue, the arm that twitches and sags, the policy that freezes mid-motion. A diagnosis each, not a guess.
Open the failure-mode indexWhy does my run OOM at step 3000 after surviving the first 2000?▾
Three usual causes. A leak, where something accumulates tensors that still carry their autograd graph. Checkpoint saving, which briefly needs extra memory while state is gathered. Or a data outlier, where one episode has an extra camera stream. Take a snapshot for the first; check whether the failing step lands on your save_steps interval for the second.
Does lowering the batch size mean lowering the learning rate too?▾
If you want the same optimisation behaviour, yes, or use gradient accumulation to restore the effective batch instead. Isaac-GR00T ships a global batch of 64 with a learning rate of 1e-4, chosen together. Dropping to batch 8 while keeping 1e-4 gives noisier gradients at an unchanged step size. Accumulating is the lower-risk move because it leaves the recipe intact.
Is gradient checkpointing free?▾
Free in accuracy, not in time. Chen et al. 2016 reduced a 1000-layer residual network from 48 GB to 7 GB for about 30 percent extra runtime, and Hugging Face quotes 20 percent for transformer fine-tuning. One caveat from the PyTorch docs: the checkpointed function runs twice, and determinism is not guaranteed if you move tensors to another device inside it. Pass use_reentrant explicitly; it no longer has a default.
Can I train GR00T N1.7 on a 24 GB card at all?▾
Not with the supported recipe. NVIDIA's hardware guide states a 40 GB minimum and describes N1.7 as a 3 B parameter bfloat16 model whose default recipe peaks under about 35 GB per GPU. The arithmetic agrees: the fixed cost alone exceeds 24 GB before activations. On 24 GB, train SmolVLA or ACT instead.
Does expandable_segments have a downside?▾
The PyTorch docs mark it experimental and it defaults to False. The OOM message notes that with expandable segments enabled a process can instead exhaust virtual address space, because each segment reserves roughly nine eighths of device memory times the number of streams. That is rare with one or two streams, so for a single-process fine-tune it is the first thing to try.
Compact version: read the error, rule out host RAM, check your dtype, then work down the list and log every lever from the 'changes the policy' column. That log explains, weeks later, why the training run that fit on the card produced a different policy from the guide's. To skip the tuning, the GR00T N1.7 on SO-100 guide and the SmolVLA on SO-100 guide list what each run uses, and pricing shows what the right card costs. Still choosing a model? Start with the VLA overview and the SO-100 guide.
Sources
- Isaac-GR00T hardware recommendations: 40 GB fine-tuning minimum, under ~35 GB default peak, tune-llm/tune-visual cost, num-shards-per-epoch is host RAM
- Isaac-GR00T FinetuneConfig: global_batch_size 64, gradient_accumulation_steps 1, tune flags, no seed and no LoRA fields
- Isaac-GR00T N1.5 fine-tune script: lora_rank, lora_alpha, gradient_checkpointing=False
- lerobot AcceleratorConfig: gradient accumulation, mixed_precision default 'no', FSDP2, and the activation-checkpointing placeholder
- lerobot PeftConfig: top-level peft config, method_type LORA, r 16, lora_alpha
- lerobot Pi0.5 config: dtype defaults to float32, gradient_checkpointing, freeze_vision_encoder, train_expert_only
- lerobot Pi0.5 guide: the command sized for a single 80 GB GPU, and the frozen-VLM variant as less memory at some cost in success rate
- lerobot SmolVLA guide: batch size 64, start small and increase while loading stays short
- openpi: LoRA fine-tune above 22.5 GB on an RTX 4090, full fine-tune above 70 GB on an A100 80 GB or H100
- PYTORCH_ALLOC_CONF options and defaults, and the PYTORCH_CUDA_ALLOC_CONF alias
- PyTorch: Understanding CUDA memory usage, _record_memory_history and _dump_snapshot
- torch.utils.checkpoint: activation checkpointing, use_reentrant, and the determinism caveat
- Transformers GPU memory anatomy: 6 + 8 + 4 bytes per parameter for mixed-precision AdamW
- Transformers single-GPU training: gradient checkpointing about 20 percent slower, empty_cache about 10 percent
- bitsandbytes 8-bit optimizers: up to 75 percent less GPU memory, min_8bit_size 4096
Sources
- Isaac-GR00T hardware recommendations: 40 GB fine-tuning minimum, under ~35 GB default peak, tune-llm/tune-visual cost, num-shards-per-epoch is host RAM
- Isaac-GR00T FinetuneConfig: global_batch_size 64, gradient_accumulation_steps 1, tune flags, no seed and no LoRA fields
- Isaac-GR00T N1.5 fine-tune script: lora_rank, lora_alpha, gradient_checkpointing=False
- lerobot AcceleratorConfig: gradient accumulation, mixed_precision default 'no', FSDP2, and the activation-checkpointing placeholder
- lerobot PeftConfig: top-level peft config, method_type LORA, r 16, lora_alpha
- lerobot Pi0.5 config: dtype defaults to float32, gradient_checkpointing, freeze_vision_encoder, train_expert_only
- lerobot Pi0.5 guide: the command sized for a single 80 GB GPU, and the frozen-VLM variant as less memory at some cost in success rate
- lerobot SmolVLA guide: batch size 64, start small and increase while loading stays short
- openpi: LoRA fine-tune above 22.5 GB on an RTX 4090, full fine-tune above 70 GB on an A100 80 GB or H100
- PYTORCH_ALLOC_CONF options and defaults, and the PYTORCH_CUDA_ALLOC_CONF alias
- PyTorch: Understanding CUDA memory usage, _record_memory_history and _dump_snapshot
- torch.utils.checkpoint: activation checkpointing, use_reentrant, and the determinism caveat
- Transformers GPU memory anatomy: 6 + 8 + 4 bytes per parameter for mixed-precision AdamW
- Transformers single-GPU training: gradient checkpointing about 20 percent slower, empty_cache about 10 percent
- bitsandbytes 8-bit optimizers: up to 75 percent less GPU memory, min_8bit_size 4096
Ready for high-quality robotics data?
AY-Robots connects your robots to skilled operators worldwide.
Get Started