2025-11-15 · 3 min read

LoRA on Apple Silicon with MLX

MLX is Apple's machine learning framework for M-series chips. It enables GPU-accelerated training and inference without external hardware. LoRA training on an M2 Pro is practical and fast.

Why MLX

MLX provides: - Unified memory (GPU and CPU share the same memory pool, no constant transfers) - Native M-series optimization (faster than PyTorch MPS in many cases) - Low compile overhead (good for iterative work) - Simplified distributed training on multiple GPUs (M1 Ultra, M2 Max with multiple cores)

Trade-off: smaller ecosystem than PyTorch. Some advanced techniques are missing.

Installation

pip install mlx mlx-lm

Converting HuggingFace checkpoint to MLX

python -m mlx_lm.convert \
  --hf-path Qwen/Qwen2.5-7B-Instruct \
  --mlx-path ./qwen25-7b-mlx \
  --quantize

The --quantize flag converts to 4-bit (or specify --quantize int8, --quantize fp16).

Result: a folder with MLX-native weights, typically 20–30% smaller than safetensors.

Training a LoRA

python -m mlx_lm.lora \
  --model ./qwen25-7b-mlx \
  --train \
  --data data/support_pairs.jsonl \
  --iters 500 \
  --batch-size 2 \
  --learning-rate 2e-4 \
  --lora-dims 8

Real M2 Pro example: 500 iterations on 200 support examples takes ~8 minutes (wall-clock, not GPU time).

Performance by M-series chip

Chip Max RAM Typical LoRA training time Notes
M2 (8 GB) 8 GB 15–20 min (3B model) Tight, only Q-bit models
M2 Pro (16 GB) 16 GB 8–10 min (7B model) Comfortable LoRA training
M2 Max (32 GB) 32 GB 5–7 min (7B model) Fast, can do larger ranks
M2 Ultra (128 GB) 128 GB 2–3 min (70B model) Enterprise-grade, rare

M2 Pro is the sweet spot for individual developers. M2 Max is overkill unless you're training multiple adapters concurrently.

Inference

from mlx_lm import load, generate

# Load quantized model + LoRA
model, tokenizer = load("./qwen25-7b-mlx")

# LoRA is automatically applied if in the model directory
response = generate(
    model,
    tokenizer,
    prompt="The system is down. ",
    max_tokens=50,
    temperature=0.7
)

print(response)

Throughput on M2 Pro: 15–20 tokens/second, similar to llama.cpp on CPU but with higher quality (model is fp16, not quantized).

Exporting to other formats

After training, export to safetensors for use in other ecosystems:

python export_lora.py --mlx-lora ./lora-output --output ./lora.safetensors

Then load in Diffusers, vLLM, or Ollama.

Hybrid: train on MLX, deploy elsewhere

  1. Train on MacBook Pro (fast, free)
  2. Export to safetensors
  3. Upload to ModelForgeLab registry
  4. Serve on cloud GPU (vLLM) or CPU (llama.cpp)

This workflow is common for small teams: iterate fast locally, deploy to production infrastructure.

Memory-constrained training

M2 with 8 GB is tight. Options:

# Use smaller model
python -m mlx_lm.lora \
  --model Phi-3-mini \  # 3.8B instead of 7B
  --train \
  --data data.jsonl \
  --batch-size 1 \  # reduce batch
  --lora-dims 4  # smaller rank

Phi-3-mini fits comfortably on 8 GB and trains in 5–8 minutes for 200 examples.

Known limitations

These are minor; for most use cases, MLX is competitive with PyTorch.

Real-world example: phi3-mini-sql-helper

# Convert
python -m mlx_lm.convert \
  --hf-path microsoft/Phi-3-mini-4k-instruct \
  --mlx-path ./phi3-mlx \
  --quantize int8

# Train
python -m mlx_lm.lora \
  --model ./phi3-mlx \
  --train \
  --data sql_examples.jsonl \
  --iters 300 \
  --batch-size 2 \
  --lora-dims 8

# Inference
python -c "
from mlx_lm import load, generate
model, tokenizer = load('./phi3-mlx')
print(generate(model, tokenizer, prompt='SELECT * FROM users WHERE ', max_tokens=30))
"

On M2 Pro: 5 minutes training, 100 tokens/second inference. Development loop is tight.

MLX vs PyTorch on MacBook

Aspect MLX PyTorch MPS
Throughput (training) 100% 70–80%
Throughput (inference) 100% 80–90%
Ease of setup Simple Requires MPS plugin
Community Growing Mature
Quantization training No No (QLoRA via bitsandbytes)

MLX is faster and simpler. PyTorch MPS is more mature if you need cutting-edge techniques.

When to use MLX

MLX removes the barrier to local training. A 7B LoRA trains faster on an M2 Pro than on a Tesla V100 in the cloud, with zero infrastructure cost.