The biggest single feature in PyTorch 2.x
torch.compile(model) is a one-line transformation that JIT-compiles your model into optimized fused kernels. Typical speedups: 1.5–3x on CUDA, often more for transformer-shaped models. The amazing part: you keep eager-mode debuggability everywhere outside the compiled region.
What's actually happening
- TorchDynamo intercepts the Python bytecode of your forward, captures the operations into an FX graph.
- AOTAutograd rewrites the graph to include backward operations.
- TorchInductor lowers the graph to optimized Triton/CUDA kernels (or C++ for CPU).
The graph is built lazily on the first call. If your code does something Dynamo can't capture (data-dependent control flow, custom Python objects in forward), it gracefully falls back to eager for that section — a "graph break". The compile won't fail outright; it'll just lose some speedup.
Three modes
- default — good balance of compile time and speedup.
mode="reduce-overhead"— minimizes Python overhead between kernel launches. Best for small models or small batch sizes.mode="max-autotune"— exhaustively searches kernel variants for max speed. Slow to compile (sometimes minutes), fastest to run.
What breaks the graph
- Data-dependent control flow on tensor values (
if x.sum() > 0) — usually OK if it's on a Python int / config. - Calls into untraced libraries (some OpenCV / PIL ops in forward).
- Mutating tensor values via Python attributes.
- Some custom autograd Functions (improving in PyTorch 2.x).