Custom Face Recognition Model Training (ArcFace, Metric Learning)

Custom Face Recognition Model Training: From Dataset to Production

AI Development Areas

Frequently Asked Questions

Latest works

  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1285
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1241
  • image_logo-advance_0.webp
    B2B Advance company logo design
    696
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    983
  • image_logo-aider_0.webp
    AIDER company logo development
    919
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    1033

Custom Face Recognition Model Training: From Dataset to Production

Imagine: your company is growing, new employees arrive daily, and key-card access is insecure. You decide to implement face recognition. But a standard Softmax classifier won't cut it — it requires retraining on every new employee. The solution is training a custom model with ArcFace loss, which can generalize to unseen identities. Our team — AI engineers with 5+ years of experience in computer vision, completed 30+ face recognition projects. We guarantee accuracy of 99.5% on LFW.

ArcFace is the industry standard: 99.5% accuracy on LFW, compact embeddings, noise robustness. It outperforms Softmax by up to 10% in open-set tasks, especially when new identities appear after deployment. Below we describe the training setup: backbone selection, margin tuning, dataset processing.

ArcFace Loss: Math and Implementation

ArcFace adds an additive angular margin m to the angle between the embedding and the corresponding class center:

import torch import torch.nn as nn import torch.nn.functional as F import math class ArcFaceLoss(nn.Module): def __init__( self, embedding_size: int = 512, num_classes: int = 10000, margin: float = 0.5, # angular margin in radians (~28.6°) scale: float = 64.0 # logit scale ): super().__init__() self.margin = margin self.scale = scale # Trainable class centers (normalized) self.weight = nn.Parameter( torch.FloatTensor(num_classes, embedding_size) ) nn.init.xavier_uniform_(self.weight) self.cos_m = math.cos(margin) self.sin_m = math.sin(margin) self.th = math.cos(math.pi - margin) # threshold for numerical stability self.mm = math.sin(math.pi - margin) * margin def forward( self, embeddings: torch.Tensor, # (B, embedding_size), L2-normalized labels: torch.Tensor # (B,) ) -> torch.Tensor: # L2-normalize weights W = F.normalize(self.weight, dim=1) # cos(θ) = emb · W^T cosine = F.linear(embeddings, W) # (B, num_classes) sine = torch.sqrt(1.0 - cosine.pow(2).clamp(0, 1)) # cos(θ + m) = cos(θ)cos(m) - sin(θ)sin(m) phi = cosine * self.cos_m - sine * self.sin_m # Numerical stability: if θ > π - m, use cosine penalty phi = torch.where(cosine > self.th, phi, cosine - self.mm) # One-hot target mask one_hot = torch.zeros_like(cosine) one_hot.scatter_(1, labels.view(-1, 1), 1) # Replace logit only for the correct class output = one_hot * phi + (1.0 - one_hot) * cosine output *= self.scale return F.cross_entropy(output, labels) 

Backbone and Embedding: Which to Choose?

InsightFace / ArcFace typically uses ResNet-50/100 or IResNet. For production on mobile devices — MobileFaceNet:

import timm def build_face_recognition_model( backbone: str = 'resnet50', # 'resnet100', 'mobilenetv3_small' embedding_size: int = 512, pretrained: bool = True ) -> nn.Module: class FaceEmbedder(nn.Module): def __init__(self): super().__init__() self.backbone = timm.create_model( backbone, pretrained=pretrained, num_classes=0, # remove classifier head global_pool='avg' ) feat_dim = self.backbone.num_features self.bn = nn.BatchNorm1d(feat_dim) self.drop = nn.Dropout(p=0.4) self.fc = nn.Linear(feat_dim, embedding_size, bias=False) self.bn2 = nn.BatchNorm1d(embedding_size) def forward(self, x: torch.Tensor) -> torch.Tensor: feat = self.backbone(x) feat = self.bn(feat) feat = self.drop(feat) emb = self.fc(feat) emb = self.bn2(emb) return F.normalize(emb, dim=1) # L2-normalization return FaceEmbedder() 

Threshold Selection for Open-Set Recognition

In production, the system encounters new people not seen in training. We use cosine similarity threshold:

import numpy as np from scipy.spatial.distance import cosine class FaceRecognitionSystem: def __init__( self, model: nn.Module, threshold: float = 0.4 # cosine distance; tuned via ROC ): self.model = model.eval() self.threshold = threshold self.gallery: dict[str, np.ndarray] = {} # id → embedding def enroll(self, person_id: str, face_image: torch.Tensor) -> None: """Register a new face in the gallery""" with torch.no_grad(): emb = self.model(face_image.unsqueeze(0)) self.gallery[person_id] = emb.cpu().numpy().squeeze() def identify( self, face_image: torch.Tensor, top_k: int = 1 ) -> list[dict]: """Search gallery — 1:N identification""" with torch.no_grad(): query_emb = self.model(face_image.unsqueeze(0)) query_np = query_emb.cpu().numpy().squeeze() distances = { person_id: cosine(query_np, gallery_emb) for person_id, gallery_emb in self.gallery.items() } sorted_matches = sorted(distances.items(), key=lambda x: x[1]) results = [] for person_id, dist in sorted_matches[:top_k]: results.append({ 'identity': person_id if dist < self.threshold else 'unknown', 'distance': float(dist), 'confidence': float(1 - dist) }) return results 

The cosine distance threshold is tuned via ROC curve on your test set. Optimal threshold is 0.35–0.45 for most enterprise scenarios. We use TAR@FAR=0.1% as the target metric.

Why ArcFace is the Industry Standard?

ArcFace produces compact clusters without the complex triplet mining of FaceNet. It maintains accuracy even on noisy datasets. More details on the loss can be found in the ArcFace paper.

Metrics and Comparison of Loss Functions

Metric Value Application
TAR@FAR=0.1% 98.5%+ Phone unlock
TAR@FAR=0.01% 95%+ Physical access
TAR@FAR=0.001% 90%+ Forensics
1:1 Verification AUC > 0.998 Document verification

Loss function comparison:

Loss LFW Acc IJB-C TAR@FAR=0.1% Complexity Application
Softmax 98.8% 91.3% Low Closed set
CosFace 99.3% 94.1% Low Standard
ArcFace 99.5% 95.6% Low Standard
AdaFace 99.6% 96.8% Medium Low quality photos
ElasticFace 99.6% 96.4% Medium General

Process and Timeline

We don't just train a model — we build a complete solution. The process includes:

  1. Dataset analysis: quality assessment, quantity, recommendations.
  2. Data preparation: face alignment, augmentation (flip, rotation, blur), train/val/test split.
  3. Backbone and loss selection: from MobileNet to ResNet-100 based on your dataset and hardware.
  4. Training: balanced sampling, monitoring via Weights & Biases.
  5. Validation: TAR@FAR on your test set, ROC analysis.
  6. Quantization and export: INT8/FP16 for edge, ONNX for CPU.
  7. Deployment: Docker + Triton/ONNX, REST/gRPC API, documentation.
Stage Result
Dataset analysis Report: quality, quantity, recommendations
Data preparation Face alignment, augmentation, split
Model training Loss selection, backbone, hyperparams
Validation TAR@FAR on your test set
Deployment Docker + Triton/ONNX, REST API
Documentation API docs, operation guide
Support 3 months warranty maintenance

What's Included in the Work?

The deliverable includes:

  • Trained model with chosen backbone and loss (ArcFace by default).
  • API documentation, deployment instructions.
  • Docker image with model and testing scripts.
  • 3 months warranty support and updates.

Timelines:

  • Fine-tuning ArcFace on corporate data — 3–5 weeks.
  • Full 1:N system with gallery — 5–8 weeks.
  • Custom pipeline (detection + alignment + recognition) — 8–14 weeks.

Cost is calculated based on your dataset and requirements. For example, fine-tuning a model on a dataset of 10,000 identities starts at $5,000. A full system including detection and gallery is typically under $20,000. Contact us to discuss the details.

Typical Mistakes When Training Face Recognition Models

  • Using Softmax for open-set tasks — accuracy drops by 5–10%.
  • Not applying L2 normalization to embeddings — metric learning does not converge.
  • Forgetting face alignment — accuracy drops by 3–5%.
  • Setting the threshold too low — avalanche of false positives.

If you want a consultation on your dataset, contact us. Order custom face recognition model training — we'll evaluate the project within 1 day.

Pricing: Fine-tuning starts from $5,000, full 1:N system from $15,000. Get a free estimate within 24 hours.