Face analysis has become essential in modern applications—from security systems and photo management to social media filters and identity verification. But building a robust face analysis pipeline traditionally meant juggling multiple libraries, dealing with complex dependencies, and wrestling with performance optimization across different hardware platforms.

UniFace is a comprehensive, production-ready face analysis library that brings together face detection, recognition, landmark detection, and attribute analysis under one unified API. Built on ONNX Runtime with automatic hardware acceleration support, UniFace delivers high-performance face analysis across Apple Silicon, NVIDIA GPUs, and CPU-only environments.

License Python PyPI Version CI Downloads


Core Capabilities

1. Face Detection

UniFace includes two state-of-the-art detection model families:

RetinaFace: Proven accuracy across diverse conditions with models ranging from ultra-lightweight (1.7MB) to high-accuracy variants. The default MNET_V2 model achieves 91.70% accuracy on the WIDER FACE Easy subset while remaining fast enough for real-time applications.

SCRFD: State-of-the-art speed-accuracy tradeoffs with the SCRFD_10G model achieving 95.16% accuracy on WIDER FACE Easy—perfect for applications demanding maximum precision.

import cv2
from uniface import RetinaFace

detector = RetinaFace()
image = cv2.imread("photo.jpg")
faces = detector.detect(image)

for face in faces:
    print(f"Confidence: {face['confidence']:.2f}")
    print(f"BBox: {face['bbox']}")
    print(f"Landmarks: {face['landmarks']}")

2. Face Recognition

Compare and identify faces using industry-standard embedding models:

ArcFace: State-of-the-art face recognition using additive angular margin loss, trained on MS1M-V2 (5.8M images, 85K identities). Available in both MobileNet (8MB) and ResNet50 (166MB) variants.

MobileFace: Lightweight alternatives optimized for mobile and edge devices, with models as small as 1MB.

from uniface import RetinaFace, ArcFace
import numpy as np

detector = RetinaFace()
recognizer = ArcFace()

# Compare two faces
faces1 = detector.detect(image1)
faces2 = detector.detect(image2)

emb1 = recognizer.get_normalized_embedding(image1, faces1[0]['landmarks'])
emb2 = recognizer.get_normalized_embedding(image2, faces2[0]['landmarks'])

similarity = np.dot(emb1, emb2.T)[0][0]
print(f"Similarity: {similarity:.4f}")

3. Facial Landmark Detection

Precise 106-point facial landmark localization for detailed face analysis and alignment. The landmarks cover face contour (33 points), eyebrows (18 points), nose (12 points), eyes (24 points), and mouth (19 points).

from uniface import RetinaFace, Landmark106

detector = RetinaFace()
landmarker = Landmark106()

faces = detector.detect(image)
landmarks = landmarker.get_landmarks(image, faces[0]['bbox'])
# Returns (106, 2) array of (x, y) coordinates

4. Attribute Analysis

Extract demographic and emotional attributes from detected faces:

Age & Gender Detection: Trained on CelebA dataset, providing age estimation and gender classification.

Emotion Detection: 7 or 8-class emotion recognition trained on AffectNet (Neutral, Happy, Sad, Surprise, Fear, Disgust, Anger, and optionally Contempt).

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"{gender}, {age} years old")

Installation & Hardware Acceleration

UniFace provides optimized installation options for different platforms:

Quick Install (All Platforms)

pip install uniface

Platform-Specific Optimization

Apple Silicon (M1/M2/M3/M4): The standard installation automatically includes ARM64 optimizations for Apple Silicon Macs. The base onnxruntime package has native Apple Silicon support built-in since version 1.13+.

NVIDIA GPUs: For CUDA acceleration on NVIDIA GPUs:

pip install uniface[gpu]

CPU-Only: Works out of the box on any platform with automatic optimization.

The library automatically detects and uses the best available execution provider—no configuration needed.


Model Selection Guide

UniFace provides a comprehensive model zoo with clear guidance for different use cases:

By Use Case

Mobile/Edge Devices: Use lightweight models like RetinaFace(MNET_025) (1.7MB) or MobileFace(MNET_V2) (4MB) for resource-constrained environments.

Real-Time Applications: Balance speed and accuracy with RetinaFace(MNET_V2) or SCRFD(SCRFD_500M) for webcam and video processing.

High-Accuracy Applications: Deploy SCRFD(SCRFD_10G) or ArcFace(RESNET) for security systems and identity verification where precision is paramount.

Server/Cloud Deployment: Leverage larger models with GPU acceleration for maximum throughput and accuracy in batch processing scenarios.

Model Families

Detection Models:

from uniface.detection import RetinaFace, SCRFD
from uniface.constants import RetinaFaceWeights, SCRFDWeights

# Fast detection (mobile/edge devices)
detector = RetinaFace(model_name=RetinaFaceWeights.MNET_025, conf_thresh=0.7)

# Balanced (recommended)
detector = RetinaFace(model_name=RetinaFaceWeights.MNET_V2)

# High accuracy (server/GPU)
detector = SCRFD(model_name=SCRFDWeights.SCRFD_10G_KPS, conf_thresh=0.5)

Recognition Models:

from uniface import ArcFace, MobileFace, SphereFace

# ArcFace (recommended for most use cases)
recognizer = ArcFace()  # Best accuracy

# MobileFace (lightweight for mobile/edge)
recognizer = MobileFace()  # Fast, small size

# SphereFace (angular margin approach)
recognizer = SphereFace()  # Alternative method

Performance Benchmarks

UniFace models deliver impressive accuracy on the WIDER FACE benchmark:

Face Detection Models (WIDER FACE Dataset)

Model Name Params Size Easy Medium Hard Use Case
MNET_025 0.4M 1.7MB 88.48% 87.02% 80.61% Mobile/Edge devices
MNET_V2 3.2M 3.5MB 91.70% 91.03% 86.60% Recommended default
RESNET34 24.8M 56MB 94.16% 93.12% 88.90% Maximum accuracy
SCRFD_500M 0.6M 2.5MB 90.57% 88.12% 68.51% Real-time applications
SCRFD_10G 4.2M 17MB 95.16% 93.87% 83.05% High accuracy + speed

Face Recognition Models

Model Name Backbone Params Size Use Case
MNET MobileNet 2.0M 8MB Balanced (recommended)
RESNET ResNet50 43.6M 166MB Maximum accuracy

Accuracy values from original papers: RetinaFace, SCRFD


Quick Start Examples

30-Second Face Detection

import cv2
from uniface import RetinaFace

# Load image
image = cv2.imread("photo.jpg")

# Initialize detector (models auto-download on first use)
detector = RetinaFace()

# Detect faces
faces = detector.detect(image)

# Print results
for i, face in enumerate(faces):
    print(f"Face {i+1}:")
    print(f"  Confidence: {face['confidence']:.2f}")
    print(f"  BBox: {face['bbox']}")
    print(f"  Landmarks: {len(face['landmarks'])} points")

Face Recognition with Similarity

import cv2
import numpy as np
from uniface import RetinaFace, ArcFace

# Initialize models
detector = RetinaFace()
recognizer = ArcFace()

# Load two images
image1 = cv2.imread("person1.jpg")
image2 = cv2.imread("person2.jpg")

# Detect faces
faces1 = detector.detect(image1)
faces2 = detector.detect(image2)

if faces1 and faces2:
    # Extract embeddings
    emb1 = recognizer.get_normalized_embedding(image1, faces1[0]['landmarks'])
    emb2 = recognizer.get_normalized_embedding(image2, faces2[0]['landmarks'])

    # Compute similarity (cosine similarity)
    similarity = np.dot(emb1, emb2.T)[0][0]

    # Interpret result
    if similarity > 0.6:
        print(f"Same person (similarity: {similarity:.3f})")
    else:
        print(f"Different people (similarity: {similarity:.3f})")

Similarity thresholds:

  • > 0.6: Same person (high confidence)
  • 0.4 - 0.6: Uncertain (manual review)
  • < 0.4: Different people

Production-Ready Features

Automatic Model Management: Models are automatically downloaded on first use and cached in ~/.uniface/models/. SHA-256 checksums ensure integrity.

Visualization Utilities: Built-in drawing functions make it easy to visualize results:

from uniface.visualization import draw_detections

bboxes = [f['bbox'] for f in faces]
scores = [f['confidence'] for f in faces]
landmarks = [f['landmarks'] for f in faces]

draw_detections(image, bboxes, scores, landmarks, vis_threshold=0.6)
cv2.imwrite("output.jpg", image)

Real-World Use Cases

Face Search System

# Build database
database = {}
for person_id, image_path in person_images.items():
    image = cv2.imread(image_path)
    faces = detector.detect(image)
    if faces:
        embedding = recognizer.get_normalized_embedding(
            image, faces[0]['landmarks']
        )
        database[person_id] = embedding

# Search for a face
query_faces = detector.detect(query_image)
query_embedding = recognizer.get_normalized_embedding(
    query_image, query_faces[0]['landmarks']
)

# Find best match
best_match = max(database.items(),
                 key=lambda x: np.dot(query_embedding, x[1].T)[0][0])

Real-Time Webcam Detection

import cv2
from uniface import RetinaFace
from uniface.visualization import draw_detections

detector = RetinaFace()
cap = cv2.VideoCapture(0)

while True:
    ret, frame = cap.read()
    if not ret:
        break

    faces = detector.detect(frame)
    bboxes = [f['bbox'] for f in faces]
    scores = [f['confidence'] for f in faces]
    landmarks = [f['landmarks'] for f in faces]

    draw_detections(frame, bboxes, scores, landmarks)
    cv2.imshow("Face Detection", frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

Advanced Features

Age & Gender Detection

import cv2
from uniface import RetinaFace, AgeGender

# Initialize models
detector = RetinaFace()
age_gender = AgeGender()

# Load image
image = cv2.imread("photo.jpg")
faces = detector.detect(image)

# Predict attributes
for i, face in enumerate(faces):
    gender, age = age_gender.predict(image, face['bbox'])
    print(f"Face {i+1}: {gender}, {age} years old")

Batch Processing

import cv2
from pathlib import Path
from uniface import RetinaFace

detector = RetinaFace()

# Process all images in a folder
image_dir = Path("images/")
output_dir = Path("output/")
output_dir.mkdir(exist_ok=True)

for image_path in image_dir.glob("*.jpg"):
    print(f"Processing {image_path.name}...")
    image = cv2.imread(str(image_path))
    faces = detector.detect(image)
    print(f"  Found {len(faces)} face(s)")

    # Save results
    output_path = output_dir / image_path.name
    # ... draw and save ...

print("Done!")

Common Issues & Solutions

Check Hardware Acceleration:

import onnxruntime as ort
print("Available providers:", ort.get_available_providers())
# macOS M-series should show: ['CoreMLExecutionProvider', ...]
# NVIDIA GPU should show: ['CUDAExecutionProvider', ...]

Manual Model Download:

from uniface.model_store import verify_model_weights
from uniface.constants import RetinaFaceWeights

model_path = verify_model_weights(RetinaFaceWeights.MNET_V2)
print(f"Model downloaded to: {model_path}")

Open Source

UniFace is open source under the MIT license and actively maintained on GitHub. The project includes comprehensive documentation, Jupyter notebook examples, and training code repositories for model reproduction.

The library builds on proven research:

  • RetinaFace: Single-Shot Multi-Level Face Localisation in the Wild
  • SCRFD: Sample and Computation Redistribution for Efficient Face Detection
  • ArcFace: Additive Angular Margin Loss for Deep Face Recognition

Getting Started

Installation is straightforward:

# macOS (Apple Silicon) - automatically includes ARM64 optimizations
pip install uniface

# Linux/Windows with NVIDIA GPU
pip install uniface[gpu]

# CPU-only (all platforms)
pip install uniface

Then start detecting faces in seconds:

import cv2
from uniface import RetinaFace

detector = RetinaFace()
image = cv2.imread("photo.jpg")
faces = detector.detect(image)

for face in faces:
    print(f"Found face with confidence: {face['confidence']:.2f}")

Resources: