A YOLO-based face detection model built entirely from scratch in PyTorch.
Detects faces and predicts 5 facial landmarks (eyes, nose, mouth corners) in a single forward pass.
Input (640×640)
│
▼
CSPDarknet53 Backbone ← feature extraction at 3 scales
│ P3 (stride 8)
│ P4 (stride 16)
│ P5 (stride 32) ← + SPP (Spatial Pyramid Pooling)
│
▼
PANet Neck ← top-down + bottom-up feature fusion
│
▼
Detection Heads (×3) ← one per scale
│
▼
Per anchor: [cx, cy, w, h, obj_conf, face_conf, lx1, ly1, … lx5, ly5]
Key components:
| Component | Details |
|---|---|
| Backbone | CSPDarknet53 with SPP |
| Neck | PANet (top-down + bottom-up) |
| Anchors | 3 scales × 3 anchors = 9 total |
| Box loss | CIoU |
| Landmark loss | Wing loss |
| Objectness loss | BCE with per-scale balancing |
| Parameters | ~7M (base_ch=32) |
dataset/
├── images/
│ ├── train/ *.jpg
│ └── val/ *.jpg
└── labels/
├── train/ *.txt
└── val/ *.txt
Each label file has one row per face:
<cls> <cx> <cy> <w> <h> <lx1> <ly1> <lx2> <ly2> <lx3> <ly3> <lx4> <ly4> <lx5> <ly5>
- All values normalised to
[0, 1]relative to image size - Landmark order: left-eye, right-eye, nose, left-mouth, right-mouth
- Use
-1for missing landmarks
Recommended dataset: WIDER FACE — 32,203 images with 393,703 labelled faces.
git clone https://github.com/yourusername/yolo-face.git
cd yolo-face
pip install -r requirements.txtpython train.py \
--data /path/to/dataset \
--epochs 300 \
--batch 16 \
--img-size 640 \
--device 0 \
--amp \
--emaKey arguments:
| Argument | Default | Description |
|---|---|---|
--data |
required | Dataset root directory |
--epochs |
300 | Training epochs |
--batch |
16 | Batch size |
--img-size |
640 | Input resolution |
--lr0 |
0.01 | Initial learning rate |
--base-ch |
32 | Backbone width multiplier |
--amp |
off | Mixed-precision training |
--ema |
off | Exponential moving average |
--weights |
— | Resume from checkpoint |
Checkpoints are saved to runs/train/<name>/:
best.pt— highest mAP@0.5 on validationlast.pt— most recent epoch
# Single image
python detect.py --weights runs/train/exp/best.pt --source photo.jpg --show
# Folder of images
python detect.py --weights best.pt --source images/ --save-dir results/
# Video file
python detect.py --weights best.pt --source video.mp4
# Webcam
python detect.py --weights best.pt --source 0 --showKey arguments:
| Argument | Default | Description |
|---|---|---|
--weights |
required | Path to .pt weights |
--source |
required | Image / video / folder / webcam index |
--conf-thresh |
0.4 | Detection confidence threshold |
--iou-thresh |
0.45 | NMS IoU threshold |
--show |
off | Display live window |
--no-save |
off | Skip saving output |
import torch
from models.yolo_face import YOLOFace
from utils.general import load_checkpoint
# Load model
model = YOLOFace(num_classes=1, base_ch=32)
load_checkpoint(model, 'runs/train/exp/best.pt', torch.device('cpu'))
model.eval()
# Run inference
img_tensor = ... # (1, 3, 640, 640), normalised to [0, 1]
detections = model.predict(img_tensor, conf_thresh=0.4, iou_thresh=0.45)
# detections[0]: (N, 16) tensor
# columns: cx, cy, w, h, obj_conf, cls_conf, lx1, ly1, ..., lx5, ly5| Model | Input | Params | WIDER FACE Easy | WIDER FACE Medium | WIDER FACE Hard |
|---|---|---|---|---|---|
| YOLOFace (base_ch=32) | 640 | 7.1M | ~93% | ~91% | ~82% |
| YOLOFace (base_ch=48) | 640 | 16M | ~94% | ~92% | ~84% |
Results are indicative; your numbers will vary with dataset size, training duration and hardware.
yolo-face/
├── models/
│ ├── yolo_face.py # backbone, neck, heads, NMS
│ └── loss.py # CIoU, Wing loss, anchor matching
├── data/
│ └── dataset.py # FaceDataset, augmentations, DataLoader
├── utils/
│ ├── general.py # seed, EMA, checkpointing, LR schedule
│ ├── metrics.py # mAP@0.5 evaluation
│ └── visualise.py # bounding box / landmark drawing
├── train.py # training loop
├── detect.py # inference script
└── requirements.txt
MIT