PyTorch models can spend extra time in Python dispatch and small operator calls after the eager model is already producing the right tensors. torch.compile wraps a function or nn.Module so PyTorch can trace tensor operations and send optimized graph regions to the compiler backend before repeated training or inference runs.
The inductor backend is the default starting point for PyTorch 2.x compilation because it balances compile overhead and runtime speed without rewriting the model class. The first compiled call can be slower while PyTorch builds the optimized path; later calls reuse cached compiled regions when shapes and control flow stay compatible.
A parity smoke test should run before the compiled callable replaces the eager path in real training or inference code. Matching output shapes and values proves the representative input still behaves the same, while separate profiling decides whether the compile overhead is worthwhile for the workload.
Related: How to install PyTorch with pip
Related: How to run the PyTorch profiler
Related: How to enable mixed precision in PyTorch
Steps to compile a PyTorch model:
- Create a compile smoke script.
- compile_smoke.py
import torch from torch import nn class TinyClassifier(nn.Module): def __init__(self): super().__init__() self.layers = nn.Sequential( nn.Linear(8, 16), nn.ReLU(), nn.Linear(16, 3), ) def forward(self, inputs): return self.layers(inputs) torch.manual_seed(7) model = TinyClassifier().eval() sample = torch.randn(4, 8) compiled_model = torch.compile(model, backend="inductor") with torch.inference_mode(): eager_output = model(sample) compiled_output = compiled_model(sample) second_compiled_output = compiled_model(sample) max_abs_diff = (eager_output - compiled_output).abs().max().item() print(f"torch={torch.__version__}") print(f"input_shape={tuple(sample.shape)}") print(f"eager_shape={tuple(eager_output.shape)}") print(f"compiled_shape={tuple(compiled_output.shape)}") print(f"second_run_shape={tuple(second_compiled_output.shape)}") print(f"max_abs_diff={max_abs_diff:.8f}") print(f"outputs_match={torch.allclose(eager_output, compiled_output, atol=1e-6)}")
torch.compile is available in PyTorch 2.0 and later. CPU compilation through inductor may need a C++ compiler in the active Python environment.
- Run the smoke script.
$ python compile_smoke.py torch=2.12.1+cpu input_shape=(4, 8) eager_shape=(4, 3) compiled_shape=(4, 3) second_run_shape=(4, 3) max_abs_diff=0.00000000 outputs_match=True
outputs_match=True and a zero max_abs_diff confirm the compiled callable preserved the eager model output for this input.
- Place the compile call after model construction and checkpoint loading in the real code path.
model = build_model() model.load_state_dict(torch.load("model.pt", weights_only=True)) model.eval() compiled_model = torch.compile(model, backend="inductor")
Keeping model and compiled_model as separate variables leaves an eager fallback available while the compiled path is being tested.
Related: How to save and load a PyTorch model - Run one warm-up call with a representative input before measuring latency.
with torch.inference_mode(): _ = compiled_model(example_batch)
The first compiled call includes tracing and compilation time. Measure later calls separately when comparing eager and compiled performance.
- Use the compiled callable in the target inference call after parity checks pass.
with torch.inference_mode(): predictions = compiled_model(example_batch)
Leave fullgraph at its default unless graph breaks must raise errors. Enforcing fullgraph=True can make ordinary Python control flow fail instead of allowing PyTorch to compile the capturable regions.
- Remove the temporary smoke script after moving the pattern into the project.
$ rm compile_smoke.py
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.