AI Hints
Home›Deep Learning Tutorial›Faster, Smaller, Shipped
Deep Learning · Lesson 45 of 92

Training Faster

Mixed precision and more.

⏱ 2 min read▶ Video at 1:30:53🎓 Free
Watch this lesson in the Deep Learning courseWatch on YouTube ↗Full Deep Learning course

A large training run can cost thousands of dollars. So small efficiency gains can be worth real money. Three simple tricks are used in almost every serious project. They can double your speed, or let you train models that wouldn't otherwise fit into memory.

Training Faster
From the video: Training Faster
  • Runs can cost thousands
  • Small gains, real money
  • Three simple tricks

Mixed precision

Numbers usually take thirty two bits. But most of a network's work doesn't need that much accuracy. Using sixteen bits needs half the memory, and on a G P U it's much faster. Autocast does this automatically, using smaller numbers where it's safe. Run it. Inside autocast, the output uses sixteen bits, but the weights stay in thirty two bits, so nothing's lost. This often gives a big speedup, with almost no change to your code.

mixed.pypython
import torch
from torch import nn

x16 = torch.tensor(1.0, dtype=torch.float16)
x32 = torch.tensor(1.0, dtype=torch.float32)
print("Bytes per number:", x16.element_size(), "vs", x32.element_size())

model = nn.Linear(10, 2)
inputs = torch.rand(4, 10)

with torch.autocast(device_type="cpu", dtype=torch.bfloat16):
    out = model(inputs)

print("Inside autocast:", out.dtype)
print("Weights stay:   ", model.weight.dtype)
Output
Bytes per number: 2 vs 4
Inside autocast: torch.bfloat16
Weights stay:    torch.float32

Gradient accumulation

What if your G P U can only fit eight images at once, but you want a batch of sixty four? Run several small batches, adding up the gradients, and only update after all of them. We divide the loss by the number of steps, to keep the scale right. Run it. Same memory as eight, and the same effect as a batch of sixty four. Large language models are often trained in this way.

accumulate.pypython
import torch
from torch import nn

model = nn.Linear(8, 1)
opt = torch.optim.SGD(model.parameters(), lr=0.1)
x, y = torch.rand(64, 8), torch.rand(64, 1)
steps = 8

opt.zero_grad()
for i in range(steps):
    loss = ((model(x[i * 8:(i + 1) * 8]) - y[i * 8:(i + 1) * 8]) ** 2).mean() / steps
    loss.backward()
opt.step()

print("Real batch size:", 8)
print("Effective batch size:", 8 * steps)
print("One weight update done, memory stayed small")
Output
Real batch size: 8
Effective batch size: 64
One weight update done, memory stayed small

Gradient clipping

Sometimes one bad batch produces a huge gradient, and a single step can ruin hours of training. Clipping sets a speed limit. If the gradient is too large, it's scaled down, keeping its direction. Run it. A huge gradient gets reduced to exactly one. Almost every transformer uses this, usually with a limit of about one.

clip.pypython
import torch
from torch import nn

model = nn.Linear(4, 1)
x = torch.rand(4, 4) * 1000
loss = (model(x) ** 2).mean()
loss.backward()

before = model.weight.grad.norm().item()
nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
after = model.weight.grad.norm().item()

print(f"Gradient size before: {before:,.1f}")
print(f"Gradient size after:  {after:.3f}")
Output
Gradient size before: 634,175.4
Gradient size after:  1.000

Summary

Mixed precision for speed, accumulation for memory, and clipping for safety. Those three are in nearly all serious training code. Your model now trains well. But how do you make it fast and small, for real users?

Key takeaways
  • Mixed precision saves time
  • Accumulation fakes big batches
  • Clipping prevents disasters
Next up: Smaller and Faster Models — getting ready to ship