Background
Sections
IntroductionModule 01 β€” Tensors 🧊01 Β· Creating Tensors 🧊02 Β· Indexing & Reshaping πŸ”ͺ03 Β· Tensor Math βž—04 Β· Device Placement πŸ–₯️⚑Module 02 β€” Autograd βš™οΈ01 Β· The Computational Graph πŸ•ΈοΈ02 Β· Backward Pass & Gradients ⬅️03 Β· Turning Autograd Off πŸ›‘04 Β· Gradient Gotchas πŸͺ€Module 03 β€” Neural Networks01 Β· The `nn.Module` Basics 🧱02 Β· Common Layers 🧩03 Β· Building a Network πŸ—οΈ04 Β· Inspecting Models πŸ”Module 04 β€” Data Handling πŸ—‚οΈ01 Β· Dataset Basics πŸ“‡02 Β· The DataLoader 🚚03 Β· Transforms 🎨04 Β· Splits & Built-in Datasets βœ‚οΈModule 05 β€” The Training Loop πŸ”01 Β· Loss Functions 🎯02 Β· Optimizers βš™οΈ03 Β· The Training Loop πŸ”04 Β· Evaluation & Metrics πŸ“ŠModule 06 β€” Saving & Loading πŸ’Ύ01 Β· `state_dict` Basics πŸ’Ύ02 Β· Checkpoints & Resuming ⏸️03 Β· Loading for Inference πŸš€04 Β· Best Model & Early Stopping πŸ…Module 07 β€” Computer Vision πŸ‘οΈ01 Β· Convolutions πŸ”²02 Β· CNN Architecture πŸ›οΈ03 Β· Transfer Learning πŸ”04 Β· Image Classification Project πŸ§ͺModule 08 β€” NLP & Transformers πŸ’¬01 Β· Text Data & Tokenization πŸ”€02 Β· Embeddings 🧭03 Β· Recurrent Layers & LSTMs πŸ”„04 Β· Intro to Transformers ⚑Module 09 β€” Ecosystem: PyTorch Lightning ⚑01 Β· Why Lightning? πŸ€”02 Β· The LightningModule 🧩03 Β· The Trainer πŸŽ›οΈ04 Β· DataModules & Callbacks 🧰Module 10 β€” Deployment & Optimization πŸš€01 Β· Exporting Models πŸ“¦02 Β· `torch.compile` ⚑03 Β· Inference Optimization πŸͺΆ04 Β· Serving & Next Steps πŸŽ“

03 Β· The Trainer πŸŽ›οΈ

4 min read

The LightningModule says what to do; the Trainer does it. This one object replaces every loop you've ever written β€” and unlocks GPUs, mixed precision, and logging by flipping a flag.


1. The 'Why'

With your model reorganized into a LightningModule (sub-module 02), something is conspicuously missing: the loop that actually runs it. That's deliberate β€” the loop is exactly the boilerplate Lightning promised to take away, and the Trainer is where it now lives. You hand the Trainer your LightningModule and your DataLoaders, call .fit(...), and it executes the entire training process: iterating epochs and batches, calling your training_step and validation_step, running zero_grad/backward/step, switching modes, moving data to the device, and driving the progress bar. The dozens of lines you wrote by hand in Module 05 collapse into essentially one call.

The deeper win is what the Trainer unlocks for free. Because Lightning owns the loop, it can inject powerful engineering features that would each be painful to hand-code correctly. Want to train on a GPU instead of CPU? Change one argument. Want mixed-precision (16-bit) training to run roughly twice as fast and use less memory? One argument. Multiple GPUs, gradient accumulation, a quick debugging run on a handful of batches, automatic logging to TensorBoard? All arguments to the same Trainer. This is the concrete return on the discipline of restructuring your code β€” you write your model once, and scaling from a laptop CPU to a multi-GPU server becomes a configuration change rather than a rewrite.


2. Core Concepts

Trainer runs everything. You configure it once (Trainer(...)), then call trainer.fit(model, train_loader, val_loader). It owns the epoch/batch loops and calls your LightningModule hooks at the right moments.

.fit, .validate, .test, .predict. fit trains (with validation); validate/test run those splits on a trained model; predict runs inference. Each maps to the corresponding *_step in your module.

Hardware & precision by flag. accelerator="gpu", devices=2, precision="16-mixed" β€” Lightning handles device placement, distribution, and autocasting. No manual .to(device) or AMP code.

Fast iteration flags. fast_dev_run=True runs a single batch to smoke-test your code; limit_train_batches=0.1 trains on 10% for a quick sanity check; max_epochs caps training length.

Logging is built in. self.log(...) calls in your module flow to a logger (TensorBoard by default) and the progress bar automatically β€” the metric tracking you did by hand in Module 05 is now free.


3. Code in Action

The whole training run in a few lines

import lightning as L
from torch.utils.data import DataLoader

model = LitClassifier()                          # from sub-module 02
train_loader = DataLoader(train_ds, batch_size=64, shuffle=True)
val_loader   = DataLoader(val_ds,   batch_size=64)

trainer = L.Trainer(max_epochs=10)               # configure the loop
trainer.fit(model, train_loader, val_loader)     # ...and run it β€” that's it

Scaling to hardware and precision by changing arguments

import lightning as L

trainer = L.Trainer(
    max_epochs=10,
    accelerator="auto",     # use GPU/MPS if available, else CPU β€” device-agnostic
    devices="auto",         # use all available devices
    precision="16-mixed",   # mixed precision: ~2x faster, less memory, one flag
)
trainer.fit(model, train_loader, val_loader)
# No manual .to(device), no autocast/GradScaler code β€” Lightning handles it.

Fast debugging and final evaluation

import lightning as L

# Smoke-test the whole pipeline on ONE batch before a long run
debug = L.Trainer(fast_dev_run=True)
debug.fit(model, train_loader, val_loader)       # catches bugs in seconds

# After training, evaluate on the test set (calls your test_step / validation_step)
trainer = L.Trainer(max_epochs=10)
trainer.fit(model, train_loader, val_loader)
trainer.test(model, test_loader)                 # reports logged test metrics

4. Common Pitfalls

Pitfall 1 β€” Re-adding manual device/precision code. Once the Trainer manages hardware, sprinkling .to(device) or hand-rolled AMP back into your module fights the framework and causes device errors. Configure hardware on the Trainer and keep the LightningModule device-agnostic.

Pitfall 2 β€” Skipping fast_dev_run before a long job. Launching a multi-hour run only to crash at the validation step wastes time. Run Trainer(fast_dev_run=True) first β€” it executes a single train/val/test batch and surfaces shape and logic bugs in seconds.

Pitfall 3 β€” Expecting to still call .backward() or loop yourself. Beginners sometimes wrap trainer.fit in their own for epoch loop or call optimizer methods manually. The Trainer is the loop; let it own epochs and optimization. Control training length with max_epochs, not an external loop.


5. Further Reading & Watch List


⬅️ Prev: 02 Β· The LightningModule Β· ➑️ Next: 04 Β· DataModules & Callbacks