pymc-devs / pymc-devs/pytensor
MLX improvements: meta issue tracking backend perf and correctness
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 644
- Forks
- 208
- Avg merge
- 2d 14h
- Merged PRs (30d)
- 16
Description
Context
After running a focused benchmark sweep against mlx==0.31.2 (Apple Metal, M-series unified memory), the PyTensor MLX backend is competitive with hand-tuned MLX on compute-bound workloads (within 0–7% on large GEMM, batched matmul, LSTM step, RMSNorm+matmul, full transformer block) but leaves measurable performance and one correctness issue on the table. This meta issue groups the actionable findings; each item below is tracked in a sub-issue with reproducible test, current numbers, proposed change, and post-change numbers.
All measurements use mx.synchronize() between calls to defeat MLX's lazy compute, median-of-5 × 30 calls. Reported speed-ups are post-mx.compile.
Findings (one-liner each)
Correctness
- #2086 — Variadic
ScalarOpmx.stack(args)crashes on broadcast-shaped composite inputs - #2092 —
Convolve1ddispatch crashes whenBlockwisebroadcasts the kernel to(1, K)
Big perf wins (cross-backend or fused-kernel)
- #2087 —
TensorType.filterlacks fast-path for__dlpack__arrays — 4× regression onmx.arrayinput - #2088 — LayerNorm pattern not lowered to
mx.fast.layer_norm— leaves 2.4× speedup on the table - #2089 — RMSNorm pattern not lowered to
mx.fast.rms_norm— leaves 1.7× speedup on the table - #2090 — Attention pattern not lowered to
mx.fast.scaled_dot_product_attention— 1.3× forward speedup - #2091 —
pt.logsumexpnot mapped to nativemx.logsumexp— 1.5× speedup, simpler graph
Smaller perf wins / quality of life
- #2093 — Document
f.trust_input = Trueas MLX hot-loop perf tip — up to 12× onmx.arrayinput - #2094 —
Cast,DimShuffle(pure expand-dims),Argmax(single-axis) micro-optimizations
Headline numbers (post-fix, MLX 0.31.2)
| Workload | Current PT MLX | After all fixes + trust_input |
Raw mx.compile |
|---|---|---|---|
| Elementwise 2048² (mx input) | 5854 µs | 418 µs | 478 µs |
| Variadic add 5×512² (mx input) | 769 µs | 237 µs | n/a |
| Multi-head attention block | 774 µs | ~570 µs (with sdpa) | 567 µs |
| LayerNorm (B=8,S=512,D=2048) | 1067 µs | 442 µs | 442 µs |
| RMSNorm (B=8,S=512,D=2048) | 737 µs | 426 µs | 426 µs |
| Logsumexp (4,64,64,256) | 548 µs | 365 µs | 365 µs |
Methodology
- All scripts and outputs are reproducible from the per-sub-issue snippets.
- Measurements force
mx.synchronize()between calls to remove MLX async noise. - Numerics-equivalence verified before each speedup claim (
np.max(np.abs(pt - raw))reported in each sub-issue).
Recommended landing order
- First (correctness, no risk): #2086, #2092
- Then (broad perf, low risk): #2087, #2093
- Then (fused-kernel rewrites, medium effort): #2088, #2089, #2091
- Then (medium-effort with pattern guards): #2090
- Last (low risk, marginal): #2094
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
This is a meta issue covering sub-issues #2086–#2094 rather than naming a single file or entry point. Start with the correctness issues and their reproducible test snippets, then use the listed landing order to choose one focused task. Done means the selected sub-issue’s correctness or benchmark target is met and its reported post-change numbers are reproduced.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend, machine-learning, performance
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100