-
Notifications
You must be signed in to change notification settings - Fork 2.3k
docs: add "Understanding PyTensor compilation" guide for PyMC users [first draft / RFC] #8326
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
drbenvincent
wants to merge
7
commits into
pymc-devs:main
Choose a base branch
from
drbenvincent:docs/pytensor-compilation-guide
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 6 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
a0f228b
docs: add "Understanding PyTensor compilation" core notebook page
drbenvincent 4b25f25
actual human edits
drbenvincent 6ae4246
run pre-commit to fix things
drbenvincent d853ee8
docs: trim PyTensor compilation guide to overview level
drbenvincent 86fca90
docs: clarify pm.Data mutability and recompilation trade-off
drbenvincent 8bba5b8
docs: broaden intro motivation bullet list
drbenvincent 9be7dc0
Update docs/source/learn/core_notebooks/pytensor_compilation.md
drbenvincent File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| flowchart TD | ||
| %% ============ PyMC layer ============ | ||
| subgraph PYMC["PyMC layer"] | ||
| A["PyMC model<br/>(pm.Model: priors, likelihood)"] | ||
| A --> B["Build symbolic graph<br/>logp / dlogp / random fns"] | ||
| B --> C["pytensor.function(inputs, outputs, mode=...)"] | ||
| end | ||
|
|
||
| %% ============ Graph prep ============ | ||
| subgraph PREP["Graph preparation (pure Python)"] | ||
| C --> D["clone graph, apply givens/updates,<br/>collect shared variables"] | ||
| D --> E["wrap in FunctionGraph"] | ||
| end | ||
|
|
||
| %% ============ Stage 1: rewriting ============ | ||
| subgraph REWRITE["STAGE 1 — Graph rewriting (pure Python, backend-agnostic)"] | ||
| E --> F["run optimizer pipeline (optdb)"] | ||
| F --> G["merge / useless"] | ||
| G --> H["canonicalize<br/>(equilibrium, fixed-point loop)"] | ||
| H --> I["stabilize<br/>numerically-stable forms"] | ||
| I --> J["specialize + fusion"] | ||
| J --> K["backend-specific rewrites<br/>+ inplace / destroy handler"] | ||
| K --> L["Rewritten FunctionGraph"] | ||
| end | ||
|
|
||
| %% ============ Backend selection ============ | ||
| L --> M{"Which backend (linker)?<br/>pm.sample(backend=...)<br/>or compile_kwargs mode=... / config.linker"} | ||
| M -->|"'numba' (default)"| NUMBA | ||
| M -->|"'c' (→ cvm)"| CBACK | ||
| M -->|"'jax'"| JAXB | ||
| M -->|"'pytorch'"| PTB | ||
| M -->|"'mlx' (Apple GPU)"| MLXB | ||
| M -->|"'py' / 'vm'"| PYB | ||
|
|
||
| %% ============ Stage 2: linking ============ | ||
| subgraph LINK["STAGE 2 — Linking (backend-specific)"] | ||
| subgraph NUMBA["Numba backend (default, pip-friendly)"] | ||
| N1["graph -> Python"] | ||
| N1 --> N2["numba.njit JIT via LLVM"] | ||
| N2 --> N3["on-disk cache<br/>(numba__cache=True)"] | ||
| end | ||
| subgraph CBACK["C / CVM backend (needs C++ compiler)"] | ||
| C1["generate C++ source"] | ||
| C1 --> C2["g++/clang++ subprocess"] | ||
| C2 --> C3["cached .so modules"] | ||
| end | ||
| subgraph JAXB["JAX backend"] | ||
| J1["graph -> JAX"] | ||
| J1 --> J2["jax.jit -> XLA"] | ||
| end | ||
| subgraph PTB["PyTorch backend"] | ||
| T1["graph -> PyTorch"] | ||
| T1 --> T2["torch.compile<br/>(TorchDynamo/Inductor)"] | ||
| end | ||
| subgraph MLXB["MLX backend (Apple Silicon GPU)"] | ||
| X1["graph -> MLX"] | ||
| X1 --> X2["mx.compile (lazy JIT)"] | ||
| end | ||
| subgraph PYB["Python VM backend"] | ||
| P1["Op.perform in pure Python"] | ||
| end | ||
| end | ||
|
|
||
| %% ============ Compiled artifact = PyTensor's final output (the boundary) ============ | ||
| N3 --> Z["Compiled callable — PyTensor's output<br/>θ (a point in parameter space) → logp(θ), ∇logp(θ)<br/>(observed data baked in as constants)"] | ||
| C3 --> Z | ||
| J2 --> Z | ||
| T2 --> Z | ||
| X2 --> Z | ||
| P1 --> Z | ||
|
|
||
| %% ============ Runtime: the sampler engine (NOT PyTensor) ============ | ||
| subgraph RUN["Runtime — MCMC sampling (the sampler engine, NOT PyTensor)"] | ||
| direction TB | ||
| LOOP["Sampler loop:<br/>propose θ → call the compiled logp/∇logp → accept/reject → repeat (many times)"] | ||
| LOOP --> ENG{"Which sampler engine?<br/>pm.sample(nuts_sampler=...)"} | ||
| ENG -->|"'pymc'"| SP1["PyMC NUTS<br/>pure-Python loop<br/>(calls a callable from any CPU backend, e.g. C / Numba)"] | ||
| ENG -->|"'nutpie' (default if installed)"| SP2["nutpie / nuts-rs<br/>Rust loop<br/>(needs a Numba or JAX callable)"] | ||
| ENG -->|"'numpyro'"| SP3["NumPyro NUTS<br/>JAX loop<br/>(needs a JAX callable)"] | ||
| ENG -->|"'blackjax'"| SP4["BlackJAX NUTS<br/>JAX loop<br/>(needs a JAX callable)"] | ||
| end | ||
|
|
||
| %% Connect the boundary artifact into the runtime AFTER the subgraph is declared, | ||
| %% targeting the already-declared LOOP node so Mermaid links into the cluster. | ||
| Z --> LOOP | ||
|
|
||
| classDef sampler fill:#fff3e0,stroke:#e65100,color:#000; | ||
| class LOOP,SP1,SP2,SP3,SP4 sampler; | ||
|
|
||
| classDef choice fill:#e3f2fd,stroke:#1565c0,color:#000; | ||
| class M,ENG choice; | ||
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my preference would be for these to be generated when we deploy the docs via sphinx hook, like what we do with the example gallery. That way we don't need to check in the diagram or image.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually why isn't this whole thing a notebook and let sphinx handle the conversion to markdown?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keeping checked-in
.mmd/.svgfor now (simplified source). Staying as.mdrather than converting to.ipynb— happy to revisit Sphinx-time generation in a follow-up if we add mermaid support to the docs build.