Skip to content

Expose gradient accumulation in finetune.sh for low-VRAM fine-tuning#726

Open
maxwbuckley wants to merge 1 commit into
NVIDIA:mainfrom
maxwbuckley:finetune-grad-accum
Open

Expose gradient accumulation in finetune.sh for low-VRAM fine-tuning#726
maxwbuckley wants to merge 1 commit into
NVIDIA:mainfrom
maxwbuckley:finetune-grad-accum

Conversation

@maxwbuckley

@maxwbuckley maxwbuckley commented Jul 16, 2026

Copy link
Copy Markdown

What

examples/finetune.sh now forwards a GRADIENT_ACCUMULATION_STEPS environment variable (default 1zero behavior change) to launch_finetune.py. The --gradient_accumulation_steps flag was already fully plumbed through FinetuneConfigTrainingConfigTrainingArguments, but unreachable from the documented entry point except via the raw-args escape hatch. Also documents the resulting low-VRAM recipe in the script usage text and getting_started/hardware_recommendation.md.

Why

The single-GPU default (GLOBAL_BATCH_SIZE=32, no accumulation) sets the fine-tuning floor at 40 GB-class GPUs largely through activation memory. Since activation memory scales with the per-GPU micro-batch while optimization depends only on the effective batch (GLOBAL_BATCH_SIZE x GRADIENT_ACCUMULATION_STEPS), the standard trade

GLOBAL_BATCH_SIZE=8 GRADIENT_ACCUMULATION_STEPS=4 bash examples/finetune.sh ...

optimizes with the same effective batch of 32 at a fraction of the activation memory (at some throughput cost), bringing consumer 24–32 GB cards (RTX 4090/5090) into range for the default projector + action-head fine-tune. Weights, gradients, and optimizer state are unaffected.

Verification

  • Hermetic plumbing tests (included): finetune.sh is executed against a stubbed python on PATH and the exact argv asserted — default 1, env override forwarded, neighboring args untouched — plus FinetuneConfig validation of bad values (0, -1).
  • Equivalence tests (included): a deterministic model is trained through the real Gr00tTrainer twice — micro-batch 4 x 2 accumulation vs batch 8 x 1, identical initial weights and sample order — and final parameters asserted equal (allclose, fp32 summation-order tolerance), with a guard that training actually moved the weights. A second test asserts exactly k forwards per optimizer step, so a transformers/trainer change that breaks accumulation semantics fails loudly here.
  • Note on scope: the GR00T flow-matching loss draws fresh noise per forward, so full-model runs are statistically (not pathwise) equivalent across micro-batching — the trainer math validated here is exact.
  • tests/gr00t/experiment/ + tests/examples/ CPU suites: 35 passed. pre-commit clean.

🤖 Generated with Claude Code

examples/finetune.sh now forwards a GRADIENT_ACCUMULATION_STEPS environment
variable (default 1 — no behavior change) to launch_finetune.py, where the
--gradient_accumulation_steps flag was already fully plumbed through
FinetuneConfig and TrainingConfig but unreachable from the documented
entry point without the raw-args escape hatch.

This makes the standard low-VRAM trade available as a first-class recipe:
GLOBAL_BATCH_SIZE=8 GRADIENT_ACCUMULATION_STEPS=4 optimizes with the same
effective batch of 32 as the single-GPU default while activation memory
scales down with the micro-batch. Documented in the script usage text and
the hardware recommendation guide.

Tests cover both halves of the guarantee:
- Hermetic plumbing tests execute finetune.sh against a stubbed `python`
  and assert the exact argv (default 1, env override, neighboring args
  untouched), plus FinetuneConfig validation of bad values.
- Equivalence tests train a deterministic model through the real
  Gr00tTrainer twice — micro-batch 4 x 2 accumulation vs batch 8 x 1 —
  and assert parameter-level agreement and one optimizer step per k
  forwards, so a trainer/transformers change that breaks accumulation
  semantics fails loudly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant