Translator vs native speaker, made concrete
PyTorch MPS is the CUDA-API translation layer that lets PyTorch code written for NVIDIA hardware run on Apple Silicon's Metal backend. Every PyTorch operation gets dispatched to its Metal Performance Shaders equivalent (or falls back to CPU if no MPS implementation exists). The translation works; it just inherits the worldview that the GPU is a separate device with its own memory.
MLX is the framework written for Apple Silicon directly. The unified-memory model, lazy graph, function transforms — none of these had to be retrofitted onto an existing API; they're the framework's design center.
What this looks like in practice
- API surface — PyTorch MPS uses the same
torch.tensor,tensor.to('mps'), autograd-by-tape patterns you know. MLX usesmx.array, no.to(), autograd-by-function-transform. Different shapes for different costs. - Performance — for the same model, the gap between PyTorch MPS and MLX is small to moderate (sometimes one wins, sometimes the other). The leader changes between releases. Don't pick by performance unless you've measured your specific workload.
- Coverage — PyTorch MPS doesn't support 100% of PyTorch operations on Metal. The gap is closing every release, but you can still hit ops that fall back to CPU silently, killing performance. MLX has a smaller, fully-supported surface — you don't get the same model PyTorch has, but what you get works.
- Memory model — PyTorch MPS still has the .to(device) ritual baked into the API even though Apple Silicon doesn't need it. MLX's API matches the hardware.
When PyTorch MPS is the right call
- You have an existing PyTorch codebase and want to develop locally on Mac without rewriting it. The drop-in CUDA → MPS swap is what PyTorch MPS exists for.
- You depend on PyTorch-specific libraries (HuggingFace transformers, specific torch-only models). These haven't all been ported to MLX yet.
- You want bug-for-bug compatibility with cloud GPU training, so you can prototype on Mac and deploy on NVIDIA without behavior surprises.
When MLX is the right call
- You're starting fresh on Apple Silicon and don't have a PyTorch legacy to honor.
- You want the function-transform style (JAX-flavor —
mx.grad,mx.vmap, easy compile). - You want to fine-tune LLMs locally without renting GPUs (mlx-lm's LoRA workflow is more polished than the equivalent on PyTorch MPS).
- You're shipping to a Mac-only deployment and want native-shape APIs.
The honest middle ground
For research where you bounce between hosted GPU clusters and a Mac, PyTorch MPS keeps your code unified. For Mac-only work and especially Mac-only LLM workflows, MLX is the framework that wasn't designed for someone else's hardware first.