C.W.K.
Stream
Lesson 03 of 06 · published

MLX vs PyTorch MPS — Translator vs Native Speaker

~14 min · pytorch-mps, comparison, performance

Level 0Curious
0 XP0/51 lessons0/15 achievements
0/100 XP to next level100 XP to go0% complete

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 uses mx.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.

Code

Same matmul in PyTorch MPS and MLX·python
# PyTorch MPS
import torch
device = torch.device("mps" if torch.backends.mps.is_available() else "cpu")
x = torch.randn(1024, 1024, device=device)
y = x @ x.T
print("PyTorch MPS:", tuple(y.shape), y.dtype, y.device)

# MLX
import mlx.core as mx
x_mlx = mx.random.normal((1024, 1024))
y_mlx = x_mlx @ x_mlx.T
mx.eval(y_mlx)
print("MLX        :", tuple(y_mlx.shape), y_mlx.dtype, mx.default_device())

# Verified outputs (2026-05-03):
#   PyTorch MPS: (1024, 1024) torch.float32 mps:0
#   MLX        : (1024, 1024) mlx.core.float32 Device(gpu, 0)

External links

Exercise

If you have torch installed in your env, run the same matmul on PyTorch MPS and MLX (the code block in this lesson does both). Time them with time.perf_counter(). Note the gap. Then change to a 4096×4096 matmul and re-time. Does the gap grow, shrink, or stay similar? Two sentences on what you observed.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.