MLX-UniFace: Blazing-Fast Face Analysis on Apple Silicon
MLX-UniFace is a high-performance face analysis library optimized for Apple Silicon. It provides face detection, recognition, landmark detection, and attribute analysis with native MLX acceleration.
This is a fork of yakhyo/uniface with added MLX backend support for Apple Silicon Macs.
Why MLX-UniFace?
| Feature | MLX-UniFace | Original UniFace |
|---|---|---|
| Apple Silicon Native | Yes (MLX) | ONNX via CoreML |
| Unified Memory | Yes | No |
| Backend | MLX + ONNX fallback | ONNX only |
| M1/M2/M3/M4 Optimized | Yes | Partial |
Performance Benefits on Apple Silicon
- Unified Memory: No CPU-GPU data transfer overhead
- Native Acceleration: Optimized for Apple's Neural Engine and GPU
- Lazy Evaluation: Automatic graph optimization
- Numerical Parity: Identical results to ONNX (correlation = 1.0)
Installation
For Apple Silicon (Recommended)
pip install mlx-uniface
With MLX Backend (Explicit)
pip install mlx-uniface[mlx]
With ONNX Fallback
pip install mlx-uniface[onnx]
Install from Source
git clone https://github.com/CodeWithBehnam/mlx-uniface.git
cd mlx-uniface
pip install -e ".[mlx]"
Quick Start
Face Detection
import cv2
from uniface import RetinaFace
# Automatically uses MLX on Apple Silicon
detector = RetinaFace()
image = cv2.imread("image.jpg")
faces = detector.detect(image)
for face in faces:
bbox = face['bbox'] # [x1, y1, x2, y2]
confidence = face['confidence']
landmarks = face['landmarks'] # 5-point landmarks
print(f"Face detected with confidence: {confidence:.2f}")
Face Recognition
from uniface import ArcFace, RetinaFace
from uniface import compute_similarity
detector = RetinaFace()
recognizer = ArcFace()
# Detect and extract embeddings
faces1 = detector.detect(image1)
faces2 = detector.detect(image2)
embedding1 = recognizer.get_normalized_embedding(image1, faces1[0]['landmarks'])
embedding2 = recognizer.get_normalized_embedding(image2, faces2[0]['landmarks'])
# Compare faces
similarity = compute_similarity(embedding1, embedding2)
print(f"Similarity: {similarity:.4f}")
Age & Gender Detection
from uniface import RetinaFace, AgeGender
detector = RetinaFace()
age_gender = AgeGender()
faces = detector.detect(image)
gender, age = age_gender.predict(image, faces[0]['bbox'])
print(f"{'Female' if gender == 0 else 'Male'}, {age} years old")
Supported Models
Detection
| Model | Variants | MLX | ONNX |
|---|---|---|---|
| RetinaFace | MobileNet 0.25/0.5/v1/v2, ResNet18/34 | ✅ | ✅ |
| SCRFD | 500M, 10G | ✅ | ✅ |
| YOLOv5Face | S, M | ✅ | ✅ |
Recognition
| Model | Variants | MLX | ONNX |
|---|---|---|---|
| ArcFace | MobileNet, ResNet | ✅ | ✅ |
| MobileFace | v1, v2, v3 | ✅ | ✅ |
| SphereFace | Sphere20 | ✅ | ✅ |
Attributes
| Model | Output | MLX | ONNX |
|---|---|---|---|
| Landmark106 | 106-point landmarks | ✅ | ✅ |
| AgeGender | Age + Gender | ✅ | ✅ |
| Emotion | 7/8 emotions | ✅ | ✅ |
Backend Selection
MLX-UniFace automatically selects the best backend:
- Apple Silicon + MLX installed → Uses MLX (fastest)
- Otherwise → Uses ONNX Runtime
Force a Specific Backend
import os
os.environ['UNIFACE_BACKEND'] = 'mlx' # Force MLX
os.environ['UNIFACE_BACKEND'] = 'onnx' # Force ONNX
from uniface import RetinaFace
detector = RetinaFace() # Uses the specified backend
Check Current Backend
from uniface.backend import get_backend, Backend
backend = get_backend()
print(f"Using: {backend}") # Backend.MLX or Backend.ONNX
Benchmarks
Run benchmarks on your hardware:
# Quick benchmark
python scripts/test_mlx_detection.py
# Full benchmark with visualization
jupyter notebook notebooks/benchmark_mlx_vs_onnx.ipynb
Numerical Parity Verification
python scripts/verify_numerical_parity.py
Output:
✓ SUCCESS: MLX and ONNX outputs match within tolerance!
All outputs have correlation > 0.999
Development
Setup
git clone https://github.com/CodeWithBehnam/mlx-uniface.git
cd mlx-uniface
pip install -e ".[dev]"
Run Tests
pytest
Code Formatting
ruff format .
ruff check . --fix
Project Structure
mlx-uniface/
├── uniface/
│ ├── detection/ # Face detection (RetinaFace, SCRFD, YOLOv5)
│ │ ├── retinaface.py # ONNX implementation
│ │ ├── retinaface_mlx.py # MLX implementation
│ │ └── ...
│ ├── recognition/ # Face recognition (ArcFace, MobileFace)
│ ├── landmark/ # 106-point landmarks
│ ├── attribute/ # Age, Gender, Emotion
│ ├── nn/ # MLX neural network modules
│ │ ├── backbone.py # MobileNetV1/V2
│ │ ├── conv.py # Conv layers with fused BatchNorm
│ │ ├── fpn.py # Feature Pyramid Network
│ │ └── head.py # Detection heads
│ ├── backend.py # Backend auto-selection
│ ├── mlx_utils.py # MLX utilities
│ └── onnx_utils.py # ONNX utilities
├── scripts/
│ ├── convert_onnx_to_mlx.py # Weight conversion
│ ├── verify_numerical_parity.py # Accuracy validation
│ └── test_mlx_detection.py # End-to-end tests
├── notebooks/
│ └── benchmark_mlx_vs_onnx.ipynb
└── weights_mlx/ # Pre-converted MLX weights
Credits
- Original UniFace: yakhyo/uniface by Yakhyokhuja Valikhujaev
- MLX Framework: Apple MLX
- Model Architectures:
License
MIT License - see LICENSE for details.
Contributing
Contributions are welcome! Please open an issue or submit a pull request.
- Issues: GitHub Issues
- Original Project: yakhyo/uniface
Metadata
Release files for mlx-uniface 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| mlx_uniface-1.0.0.tar.gz | 79.0 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mlx_uniface-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 181.2 kB
Release files / mlx_uniface-1.0.0.tar.gz
| Download URL | mlx_uniface-1.0.0.tar.gz |
|---|---|
| Size | 79.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
75fc5177f9c09c601ffb19267770c9fc526b0733b1da3be5589c3fb2810ef10e
|
|
BLAKE2b-256 checksum How to use checksums |
b59bddce5a38764a117cc90a38c6846fd3c6682c794a6b50737acdc1869ac6d9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Dec 9, 2025.
Transparency logRelease files / mlx_uniface-1.0.0-py3-none-any.whl
| Download URL | mlx_uniface-1.0.0-py3-none-any.whl |
|---|---|
| Size | 102.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
42e5773e9b76db6cbe233161315e0572c3aed206cca7cd9138e3c8e5a8ca4e8a
|
|
BLAKE2b-256 checksum How to use checksums |
bd9c7dbdf2944f3cbdbb7a6e406593bc69270cd5516b41ceddc0334b458be6a5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Dec 9, 2025.
Transparency logSecurity for mlx-uniface 1.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for mlx_uniface-1.0.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Dec 9, 2025.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.