★ FOUR BRAND-NEW COURSES ANNOUNCED! ★ Machine Learning End To End  •  Hands-On Deep Learning with Python  •  Generative AI & LLMs with Python  •  AI Agents and Agentic AI with Python  ★  Open the “Educational” menu above to explore them ★  ★  NEW! 5. JOB ASSISTANCE: JD Report • Resume customization • AI Mock Interviews — FREE with course bundles, or just ₹499 / US$5. Single Payment. No Subscription. ★★ FOUR BRAND-NEW COURSES ANNOUNCED! ★ Machine Learning End To End  •  Hands-On Deep Learning with Python  •  Generative AI & LLMs with Python  •  AI Agents and Agentic AI with Python  ★  Open the “Educational” menu above to explore them ★  ★  NEW! 5. JOB ASSISTANCE: JD Report • Resume customization • AI Mock Interviews — FREE with course bundles, or just ₹499 / US$5. Single Payment. No Subscription. ★★ FOUR BRAND-NEW COURSES ANNOUNCED! ★ Machine Learning End To End  •  Hands-On Deep Learning with Python  •  Generative AI & LLMs with Python  •  AI Agents and Agentic AI with Python  ★  Open the “Educational” menu above to explore them ★  ★  NEW! 5. JOB ASSISTANCE: JD Report • Resume customization • AI Mock Interviews — FREE with course bundles, or just ₹499 / US$5. Single Payment. No Subscription. ★★ FOUR BRAND-NEW COURSES ANNOUNCED! ★ Machine Learning End To End  •  Hands-On Deep Learning with Python  •  Generative AI & LLMs with Python  •  AI Agents and Agentic AI with Python  ★  Open the “Educational” menu above to explore them ★  ★  NEW! 5. JOB ASSISTANCE: JD Report • Resume customization • AI Mock Interviews — FREE with course bundles, or just ₹499 / US$5. Single Payment. No Subscription. ★

Gradient accumulation: a big batch on a small GPU

Gradient accumulation: a big batch on a small GPU
23-10-2026  |  By Tejas Desai, Ecube Analytics  |  Generative AI: Build a Small GPT From Scratch (Chapter 3)  |  3 min read
READ 4TH OF 8 IN THIS SERIES

Gradient accumulation: a big batch on a small GPU

Build a Small GPT From Scratch · Part 4 of 8

Large batches make training steadier, but a free GPU can only hold a small one. Gradient accumulation closes the gap: run several small batches, add up their gradients, and update once.

The idea

The gradient of an average loss over 32 examples is the average of the gradients over smaller groups of them. So instead of pushing 32 examples through at once, you can run four batches of 8, keep adding their gradients together, and only then take one optimizer step. Memory is only needed for 8 examples at a time, yet the update is the one a batch of 32 would have produced.

Gradient accumulationFour micro-batches of eight examples each produce gradients that are averaged into one optimizer step.Four small batches, one updatebatch of 8micro-batch 1gradientbatch of 8micro-batch 2gradientbatch of 8micro-batch 3gradientbatch of 8micro-batch 4gradientadd up, divide by 4one gradient for 32 examplesoptimizer stepweights change onceMemory is paid for 8 examples at a time; the update behaves as if all 32 were seen together.
Four micro-batches of 8 add up to one update for 32 examples.

Checking it on a small problem

This is easy to believe and easy to get wrong, so here it is checked. On a small least-squares problem with 32 examples, the gradient from one big batch and the gradient from four accumulated micro-batches of 8 agree to numerical precision:

import numpy as np
rng = np.random.default_rng(0)
X = rng.normal(size=(32, 5)); y = X @ np.array([1., -2., .5, 0., 3.]) + rng.normal(scale=.1, size=32)
w = np.zeros(5)

def grad(Xb, yb, w):                          # gradient of the mean squared error over a batch
    return 2 * Xb.T @ (Xb @ w - yb) / len(yb)

big = grad(X, y, w)
acc = sum(grad(X[i:i+8], y[i:i+8], w) / 4 for i in range(0, 32, 8))        # divide by the number of micro-batches
bad = sum(grad(X[i:i+8], y[i:i+8], w) for i in range(0, 32, 8))            # forgot the division
print(np.allclose(big, acc), np.allclose(big, bad), np.allclose(bad, 4 * big))
# True False True

The third number shows the classic bug: forget to divide by the number of micro-batches and the gradient comes out exactly four times too large, which behaves like a learning rate four times too high.

In a training loop

In PyTorch the pattern is: scale each micro-batch loss by one over the number of micro-batches, call backward() every time (gradients add up in memory), and call the optimizer step and zero_grad() only after the last micro-batch. The cost of accumulation is time, not memory: you do four forward and backward passes per update instead of one. There is one subtlety: layers whose output depends on the whole batch, such as batch normalisation, do not accumulate this way, but the layer normalisation used in transformers does not depend on the batch and is unaffected.

Open in Colab Run the check yourself and try a different number of micro-batches.

Accumulation trades time for memory. It does not make a run faster; it makes a larger effective batch possible on small hardware.

Takeaways

  • Accumulating gradients over micro-batches gives the same update as one big batch.
  • Divide each loss by the number of micro-batches, or the gradient is too large by that factor.
  • It costs extra forward and backward passes, not extra memory.
  • It is how a free Colab GPU can imitate the batch sizes of bigger machines.

Next in the series (Part 5): Half the bytes: mixed precision and checkpoints

This blog is from chapter 3, course-2-generative-ai of 4 world-class courses on aibits.ecubeanalytics.com
← Previous Article 4 of 8 in this series Next →