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.
Mode
Device

Showing torch.compile on an NVIDIA GPU: 12 stages, 12 steps.

Your model code runs in CPython interpreter CPython interpreter calls, one op at a time ATen dispatch ATen dispatch dispatches to ATen CPU kernels ATen dispatch dispatches to ATen CUDA kernels ATen CPU kernels runs on CPU ATen CUDA kernels launched on NVIDIA GPU CPython interpreter intercepted by TorchDynamo TorchDynamo captures FX graph FX graph compiled by TorchInductor TorchInductor generates C++/OpenMP kernels TorchInductor generates Triton kernels TorchInductor some ops fall back to ATen CPU kernels TorchInductor some ops stay ATen CUDA kernels C++/OpenMP kernels runs on CPU Triton kernels compiled by Triton compiler Triton compiler lowers to LLVM IR LLVM IR lowers to PTX PTX translated to GPU machine code GPU machine code launched on NVIDIA GPU Your model code programming language CPython interpreter runtime ATen dispatch framework component ATen CPU kernels kernel ATen CUDA kernels kernel TorchDynamo compiler FX graph intermediate representation TorchInductor compiler C++/OpenMP kernels kernel Triton kernels kernel language Triton compiler compiler LLVM IR intermediate representation PTX intermediate representation GPU machine code machine code CPU hardware NVIDIA GPU hardware

The selected path, step by step

  1. Your model code runs in CPython interpreter: Your model is ordinary Python, executed by the CPython interpreter.
  2. ATen CUDA kernels launched on NVIDIA GPU: The kernel is queued on the GPU; Python continues without waiting for it to finish.
  3. CPython interpreter intercepted by TorchDynamo: With torch.compile, TorchDynamo hooks CPython's frame evaluation and rewrites the function's bytecode before it runs.
  4. 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.
  5. FX graph compiled by TorchInductor: The graph goes to the backend compiler; by default that is TorchInductor.
  6. TorchInductor generates Triton kernels: For GPUs, Inductor generates Triton kernels.
  7. TorchInductor some ops stay ATen CUDA kernels: Some operations stay ATen calls under torch.compile, for example certain matrix multiplications that remain cuBLAS calls.
  8. Triton kernels compiled by Triton compiler: Each Triton kernel is compiled by the Triton compiler, which runs a series of MLIR passes.
  9. Triton compiler lowers to LLVM IR: Triton lowers the kernel to LLVM IR and uses LLVM for code generation.
  10. LLVM IR lowers to PTX: For NVIDIA GPUs the final stage of Triton's pipeline is PTX (for AMD GPUs it is AMDGCN instead).
  11. PTX translated to GPU machine code: NVIDIA's translator and driver turn portable PTX into the machine code of the installed GPU.
  12. 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.

In the atlas: Python

CPython interpreter

runtime

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.

In the atlas: Python

ATen dispatch

framework component

PyTorch's C++ tensor library. Each operation is looked up and sent to the implementation for the tensor's device and type.

In the atlas: PyTorch

ATen CPU kernels

kernel

Precompiled C++ implementations of each operation for the CPU, shipped inside the PyTorch library.

In the atlas: C++

ATen CUDA kernels

kernel

Precompiled GPU implementations of each operation. Some, such as matrix multiplications, call NVIDIA's cuBLAS library.

In the atlas: CUDA

TorchDynamo

compiler

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.

FX graph

intermediate representation

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.

TorchInductor

compiler

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.

C++/OpenMP kernels

kernel

On CPU, Inductor writes C++ kernels that use OpenMP to spread work across cores, usually fusing several operations into one kernel.

In the atlas: C++

Triton kernels

kernel language

On GPU, Inductor writes kernels in Triton, a Python-embedded language for GPU programming, usually fusing several operations into one kernel.

In the atlas: Triton

Triton compiler

compiler

Compiles each Triton kernel through a series of MLIR passes, then hands it to LLVM for code generation.

In the atlas: Triton

LLVM IR

intermediate representation

LLVM's intermediate representation. Triton uses LLVM to generate the device code.

In the atlas: LLVM

PTX

intermediate representation

NVIDIA's virtual instruction set, the last portable step. It is not yet the GPU's own machine code.

In the atlas: CUDA

GPU machine code

machine code

The instructions of one specific GPU architecture, produced from PTX by NVIDIA's translator and driver.

In the atlas: Machine Code

NVIDIA GPU

hardware

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.
    CUDA semantics (PyTorch 2.15 documentation) Project docs

Every step

FromStepToWhenWhat happensSource
Your model coderuns inCPython interpreterany mode · any deviceYour model is ordinary Python, executed by the CPython interpreter.Project docs
CPython interpretercalls, one op at a timeATen dispatchEager · any deviceIn eager mode each tensor operation is a separate call from Python into PyTorch's C++ core.Project docs
ATen dispatchdispatches toATen CPU kernelsEager · CPUFor CPU tensors, ATen picks the CPU implementation of the operation.Project docs
ATen dispatchdispatches toATen CUDA kernelsEager · NVIDIA GPUFor CUDA tensors, ATen picks the GPU implementation of the operation.Project docs
ATen CPU kernelsruns onCPUany mode · CPUThe precompiled C++ kernel runs on the CPU.Project docs
ATen CUDA kernelslaunched onNVIDIA GPUany mode · NVIDIA GPUThe kernel is queued on the GPU; Python continues without waiting for it to finish.Project docs
CPython interpreterintercepted byTorchDynamotorch.compile · any deviceWith torch.compile, TorchDynamo hooks CPython's frame evaluation and rewrites the function's bytecode before it runs.Project docs
TorchDynamocapturesFX graphtorch.compile · any deviceSequences of PyTorch operations become an FX graph. Code that cannot be traced causes a graph break and runs in normal Python between graphs.Project docs
Project docs
FX graphcompiled byTorchInductortorch.compile · any deviceThe graph goes to the backend compiler; by default that is TorchInductor.Project docs
TorchInductorgeneratesC++/OpenMP kernelstorch.compile · CPUFor CPU, Inductor generates C++ kernels parallelized with OpenMP.Project docs
Project docs
TorchInductorgeneratesTriton kernelstorch.compile · NVIDIA GPUFor GPUs, Inductor generates Triton kernels.Project docs
Project docs
TorchInductorsome ops fall back toATen CPU kernelstorch.compile · CPUOperations Inductor does not generate code for are still run by the existing ATen kernels.Project docs
TorchInductorsome ops stayATen CUDA kernelstorch.compile · NVIDIA GPUSome operations stay ATen calls under torch.compile, for example certain matrix multiplications that remain cuBLAS calls.Project docs
Project docs
C++/OpenMP kernelsruns onCPUtorch.compile · CPUThe compiled C++ kernels run on the CPU, split across cores by OpenMP.Project docs
Triton kernelscompiled byTriton compilertorch.compile · NVIDIA GPUEach Triton kernel is compiled by the Triton compiler, which runs a series of MLIR passes.Source repository
Triton compilerlowers toLLVM IRtorch.compile · NVIDIA GPUTriton lowers the kernel to LLVM IR and uses LLVM for code generation.Source repository
LLVM IRlowers toPTXtorch.compile · NVIDIA GPUFor NVIDIA GPUs the final stage of Triton's pipeline is PTX (for AMD GPUs it is AMDGCN instead).Source repository
PTXtranslated toGPU machine codetorch.compile · NVIDIA GPUNVIDIA's translator and driver turn portable PTX into the machine code of the installed GPU.Project docs
GPU machine codelaunched onNVIDIA GPUtorch.compile · NVIDIA GPUThe compiled kernel is launched on the GPU, asynchronously, like any other CUDA kernel.Project docs

What this does not show

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.

What these tools are written in is in the main atlas: Python, PyTorch, C++, CUDA, Triton, LLVM, Machine Code. More execution paths: How Does llama.cpp Run a Model on Your Hardware.

Explore the full graph →