Torch Compile

`torch.compile` is the just-in-time graph compiler that PyTorch 2.0 wraps around an ordinary eager model to make it run as fused, optimized kernels: you write `model = torch.compile(model)` and change nothing else. The first call traces the model and compiles it; later calls run the compiled code. It keeps the debuggability of eager mode while recovering most of the speed that used to require hand-written kernels or a separate graph framework, and unlike the older TorchScript it almost never asks you to rewrite your model to make tracing succeed.

The frontend, TorchDynamo, captures a graph by hooking CPython itself. Using the frame-evaluation API (PEP 523), Dynamo intercepts the bytecode of your function and symbolically traces it into an FX graph of tensor operations. The important design choice is what happens when it hits something it cannot trace — data-dependent control flow, a `print`, a `.item()`, an unsupported library call. Instead of failing, Dynamo inserts a graph break: it compiles the graph up to that point, runs the offending line in normal eager Python, then resumes capturing a fresh graph afterward. This is why `torch.compile` is safe to drop onto arbitrary code; the worst case is simply less of the model gets fused.

AOTAutograd captures the backward pass ahead of time, so training compiles too. A plain graph capture only sees the forward computation, but most of the cost of training is in the backward pass. AOTAutograd traces forward and backward together into a joint graph, which lets the compiler fuse and schedule gradients as aggressively as activations and decide which intermediate tensors to save versus recompute. Beneath it, PrimTorch decomposes PyTorch's roughly two thousand operators into a small, stable set of about two hundred and fifty primitives, so a backend only has to implement the primitives rather than the entire sprawling API surface.

TorchInductor, the default backend, lowers that graph to real fused kernels. Inductor performs operator fusion, memory planning, and buffer reuse, then generates code: Triton for the GPU and vectorized C++/OpenMP for the CPU. This is the concrete link between the two most important compilation tools in PyTorch — the graph that Dynamo captured is ultimately emitted as Triton kernels, so `torch.compile` is, at the bottom, a Triton kernel generator wrapped in a Python-capture frontend. The fusion is where the speedup comes from: pointwise chains, normalizations, and activation functions collapse into single passes that keep data in registers instead of streaming it back and forth through HBM.

Guards and recompilation are the mental model you actually tune against. When Dynamo compiles a graph it installs *guards* on the properties it assumed — tensor shapes, dtypes, Python attribute values. If a later call violates a guard (a new sequence length, say), that specialization is invalid and Dynamo compiles a new one. Left unmanaged this causes recompilation storms, so `torch.compile` supports dynamic shapes to compile one shape-agnostic graph instead of one per size. The other lever is graph breaks: because each break caps how much can be fused, keeping `.item()`, host-side prints, and untraceable calls out of the hot path is the main way to make a compiled model faster, and `fullgraph=True` turns any graph break into a hard error so you can find them.

LayerWhat it doesProduces
TorchDynamocaptures Python bytecode into a graph; graph-breaks on the untraceableFX graph(s) + guards
AOTAutogradtraces the backward pass as well as the forwardjoint forward+backward graph
PrimTorchdecomposes ~2000 ops into ~250 primitive opscanonical operator set
TorchInductorfuses operations and generates kernelsTriton (GPU) / C++/OpenMP (CPU)
torch.compile — Dynamo to Inductor to Triton Kernels one decorator · TorchDynamo graph capture · AOTAutograd fwd+bwd · TorchInductor kernel fusion COMPILATION STACK @torch.compile(model) # one decorator TorchDynamo traces bytecode → FX graph + guards captured FX graph x w add mul relu out AOTAutograd captures forward + backward in one graph PrimTorch — ~2000 ops → 250 primitives TorchInductor pattern-match, fuse, lower to kernels Triton (GPU) C++ / OpenMP (CPU) GUARD → CACHE → EXECUTE First call — compile once compile (one-time cost) exec kernel written to disk cache after compile 2nd+ call — cache hit exec ~1.8× faster guard check (ns) + cached kernel Guards Dynamo inserts (checked each call): input.shape == compiled shape input.dtype (float32, float16...) device == cuda:0, contiguous layout no new closure variables captured Guard fails → recompile (avoid with): new batch size → dynamic=True new dtype → separate compiled kernel graph break → eager fallback on that op FUSION CUTS HBM TRIPS Eager — 3 op-by-op kernel launches add mul relu HBM — slow global memory 6 HBM read+write trips per fwd pass Compiled — 1 fused Inductor kernel SRAM — intermediates stay on-chip add → mul → relu (one kernel) 2 HBM trips: 1 read + 1 write ~3× fewer HBM trips Inductor fuses pointwise chains and emits a single fused Triton kernel Compile modes default — general-purpose fusion reduce-overhead — wraps in CUDA graphs max-autotune — autotuned Triton configs fullgraph=True — error on any graph break longer compile = faster inference runtime Graph breaks — what causes them print() or Python side effects data-dependent control flow (if tensor) unsupported ops (custom C++ extensions) in-place mutation on graph inputs torch._dynamo.explain(model) to diagnose What Inductor produces GPU: fused Triton kernels (OpenAI Triton) CPU: C++ + OpenMP with SIMD vectorization Typical speedup: 1.5–3× over eager Same model weights, same numerical outputs — only the execution path changes. Compilation result cached to disk across runs

Read `torch.compile` through a *capture-then-fuse* lens rather than a *magic-speed-flag* lens: Dynamo decides how much of your Python it can turn into a graph, AOTAutograd extends that to the backward pass, and Inductor turns the result into the same Triton kernels you could have written by hand — so the two things you actually control are how many graph breaks you leave in the hot path and how often guards force a recompile.

Take torch compile further

Ask the copilot about this term, or have our engineers assess it against your process.