What Actually Happens When You Run a PyTorch Model?
In eager mode, each tensor operation in your Python code is a separate call into ATen, PyTorch's C++ core, which runs a precompiled C++ kernel on the CPU or a CUDA kernel on the GPU. With torch.compile, TorchDynamo captures runs of operations as an FX graph, and TorchInductor generates new kernels for it: C++ with OpenMP for CPUs, Triton for GPUs. On an NVIDIA GPU, Triton lowers each kernel through MLIR and LLVM IR to PTX, which NVIDIA's driver turns into the GPU's own machine code.
Showing torch.compile on an NVIDIA GPU: 12 stages, 12 steps.
Your program
Framework core
Kernel
Compiler
Intermediate representation
Hardware
Fallback for some operations
The selected path, step by step
Your model code runs in CPython interpreter: Your model is ordinary Python, executed by the CPython interpreter.
ATen CUDA kernels launched on NVIDIA GPU: The kernel is queued on the GPU; Python continues without waiting for it to finish.
CPython interpreter intercepted by TorchDynamo: With torch.compile, TorchDynamo hooks CPython's frame evaluation and rewrites the function's bytecode before it runs.
TorchDynamo captures FX graph: Sequences of PyTorch operations become an FX graph. Code that cannot be traced causes a graph break and runs in normal Python between graphs.
FX graph compiled by TorchInductor: The graph goes to the backend compiler; by default that is TorchInductor.
TorchInductor generates Triton kernels: For GPUs, Inductor generates Triton kernels.
TorchInductor some ops stay ATen CUDA kernels: Some operations stay ATen calls under torch.compile, for example certain matrix multiplications that remain cuBLAS calls.
Triton kernels compiled by Triton compiler: Each Triton kernel is compiled by the Triton compiler, which runs a series of MLIR passes.
Triton compiler lowers to LLVM IR: Triton lowers the kernel to LLVM IR and uses LLVM for code generation.
LLVM IR lowers to PTX: For NVIDIA GPUs the final stage of Triton's pipeline is PTX (for AMD GPUs it is AMDGCN instead).
PTX translated to GPU machine code: NVIDIA's translator and driver turn portable PTX into the machine code of the installed GPU.
GPU machine code launched on NVIDIA GPU: The compiled kernel is launched on the GPU, asynchronously, like any other CUDA kernel.
Where Python ends
In eager mode, Python's part ends at each operation's call into ATen: from there on, everything is precompiled C++ and CUDA that shipped inside PyTorch. Python is still in charge of the order of operations, one call at a time, so the interpreter's overhead is paid on every operation.
Under torch.compile, Python's part ends earlier for the code TorchDynamo can capture: the captured operations never run as individual Python calls again. They become an FX graph, then new code generated by TorchInductor, and on a GPU that code passes through three compiler stages (Triton, LLVM, PTX) before NVIDIA's driver produces machine code for the specific GPU. Code Dynamo cannot trace causes a graph break and still runs in normal Python between compiled graphs.
Either way the GPU work is asynchronous: Python queues kernels and moves on, which is why a GPU program can look fast until something forces it to wait for a result.
Every stage
Your model code
programming language
The nn.Module and training or inference loop you write in Python. Every tensor operation in it is a call into PyTorch.
Runs your Python bytecode. In eager mode it calls PyTorch one operation at a time; under torch.compile, TorchDynamo hooks into it before each frame runs.
A Python-level JIT compiler. It rewrites your function's bytecode so that runs of PyTorch operations are captured as a graph instead of executed one by one.
It rewrites Python bytecode to extract sequences of PyTorch operations into an FX Graph which is then compiled with a customizable backend.
The captured sequence of PyTorch operations, as a graph a backend compiler can optimize. Code Dynamo cannot trace causes a graph break and runs in normal Python between graphs.
It rewrites Python bytecode to extract sequences of PyTorch operations into an FX Graph which is then compiled with a customizable backend.
The default torch.compile backend. It generates new kernels for the graph: Triton for GPUs and C++ for CPUs. For training, AOT Autograd also captures the backward pass ahead of time.
Runs kernels launched from the CPU. Launches are queued, so Python usually returns before the GPU has finished.
By default, GPU operations are asynchronous. When you call a function that uses the GPU, the operations are enqueued to the particular device, but not necessarily executed until later.
Illustrative, documented paths for one PyTorch program in eager mode and under torch.compile with the default TorchInductor backend, on a CPU or an NVIDIA GPU. Not every PyTorch program takes these paths: other torch.compile backends, AMD and Intel GPUs, Apple MPS, CUDA graphs and custom operators are out of scope. TorchInductor's GPU path through Triton also serves AMD and Intel GPUs, ending in a different final format (for AMD, AMDGCN instead of PTX). Other torch.compile backends replace TorchInductor entirely.
How this page is checked
Every stage and step above quotes the source that supports it. The quotes were checked against PyTorch 2.15 documentation, Triton main README, NVIDIA PTX ISA documentation on 2026-11-10. The data is a versioned JSON file under the same CC BY 4.0 license as the dataset. Found something wrong or out of date? Open an issue with the better source.