[RFC] Fused RoIAlign Face Embedding Extractor & Numerically Stable Angular Margin Loss (`torchvision.ops` & `torchvision.losses`)
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 17.9k
- Forks
- 7.3k
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 13
Description
When scaling face recognition pipelines in PyTorch, developers hit two recurring infrastructure barriers:
NaNGradient Crashes in Angular Margin Losses: Standard Additive Angular Margin Loss (ArcFace) computes $\arccos(\theta)$ on normalized feature dot products. Floating-point imprecision in FP16/AMP (and extreme FP32 runs) routinely causes dot products to evaluate outside $[-1.0, 1.0]$ (e.g., $1.0000001$), generatingNaNautograd gradients.- CPU Memory Transfer Bottlenecks: Slicing face crops via Python loops (
img[:, y1:y2, x1:x2]) introduces severe VRAM-to-RAM host transfers, causes CPU overhead, and triggers graph breaks + re-compilations undertorch.compiledue to dynamic crop shapes.
We propose adding AdaptiveArcFaceLoss to standard loss layers and demonstrating a trace-safe zero-copy extraction workflow via roi_align:
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision.ops import roi_align
class AdaptiveArcFaceLoss(nn.Module):
"""
Numerically stable ArcFace Loss enforcing safe-clamping bounds on arccos inputs
to eliminate NaN gradient explosions in FP16/FP32 training.
"""
def __init__(self, in_features: int, num_classes: int, scale: float = 64.0, margin: float = 0.50):
super().__init__()
self.scale = scale
self.cos_m, self.sin_m = math.cos(margin), math.sin(margin)
self.th = math.cos(math.pi - margin)
self.mm = math.sin(math.pi - margin) * margin
self.weight = nn.Parameter(torch.empty(num_classes, in_features))
nn.init.xavier_uniform_(self.weight)
def forward(self, embeddings: torch.Tensor, labels: torch.Tensor) -> torch.Tensor:
# EPS Safeguard: Prevent float overflow outside [-1.0, 1.0] bounds
cosine = F.linear(F.normalize(embeddings), F.normalize(self.weight)).clamp(-1.0 + 1e-7, 1.0 - 1e-7)
sine = torch.sqrt((1.0 - torch.pow(cosine, 2)).clamp(0.0, 1.0))
phi = torch.where(cosine > self.th, cosine * self.cos_m - sine * self.sin_m, cosine - self.mm)
one_hot = torch.zeros_like(cosine).scatter_(1, labels.view(-1, 1).long(), 1.0)
logits = (one_hot * phi) + ((1.0 - one_hot) * cosine)
return F.cross_entropy(logits * self.scale, labels)
class VectorizedFaceExtractor(nn.Module):
"""
Fused GPU RoI crop & normalize wrapper operating zero-copy in VRAM.
"""
def __init__(self, backbone: nn.Module, target_size=(112, 112)):
super().__init__()
self.backbone = backbone
self.target_size = target_size
def forward(self, images: torch.Tensor, boxes: torch.Tensor, box_indices: torch.Tensor) -> torch.Tensor:
rois = torch.cat([box_indices.unsqueeze(1).float(), boxes], dim=1)
aligned = roi_align(images, rois, output_size=self.target_size, spatial_scale=1.0)
return F.normalize(self.backbone(aligned), p=2, dim=1)
- Key Technical Verification
Autograd Stability: clamp(-1 + 1e-7, 1 - 1e-7) guarantees valid, non-NaN backward passes under extreme FP16 scaling.
torch.compile Compatibility: Passes fullgraph=True without triggering graph breaks or dynamic shape re-compilations.
We have unit test suites and autograd boundary verification ready for a PR upon core team review.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing the proposed entry points in torchvision.ops and torchvision.losses, including roi_align and the suggested AdaptiveArcFaceLoss. Assess the numerical-stability and torch.compile claims against the proposed unit and autograd boundary tests; done means the API scope and verification requirements are agreed before implementation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- computer-vision, machine-learning
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100