Skip to content

Latest commit

Β 

History

164 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Facial Age Estimation Banner

πŸŽ‚ Facial Age Estimation β€” PyTorch

Production-ready deep learning pipeline for estimating age from face images.
Train, evaluate, and deploy in minutes β€” on CPU or GPU.

GitHub Stars GitHub Forks License: MIT Python 3.10+ PyTorch 2.0+ CI


πŸ“‹ Table of Contents


✨ Key Features

  • πŸ”₯ 5 Backbones β€” MobileNetV3-Large, EfficientNet-B0/B3, ResNet-50, ViT-S/14 DINOv2
  • πŸ“ Mean-Variance Loss (CVPR 2018) β€” models age as a probability distribution over [0–100], outperforming plain L1/MSE by 0.3–0.5 MAE
  • ⚑ AMP + AdamW β€” mixed-precision training with differential learning rates and OneCycleLR warmup
  • πŸ—‚οΈ Clean package layout β€” src/, scripts/, demo/, tests/, configs/ following standard PyTorch practices
  • πŸŽ›οΈ OmegaConf config β€” change any hyperparameter from the CLI without editing code
  • πŸ“Š Bias analysis β€” per-epoch breakdown of MAE by age group, gender, and ethnicity
  • πŸ–₯️ Gradio demo β€” upload a photo β†’ see predicted age + full probability distribution
  • πŸ“€ Export ready β€” TorchScript (trace) and ONNX with dynamic batch support
  • βœ… 37 unit tests + GitHub Actions CI

πŸš€ Quick Start

# 1. Clone
git clone https://github.com/Ebimsv/Facial_Age_estimation_PyTorch.git
cd Facial_Age_estimation_PyTorch

# 2. Install (set up PyTorch for your CUDA version first β€” see Installation section)
pip install -r requirements.txt

# 3. Prepare data (point to your UTKFace folder)
python scripts/prepare_data.py --dataset-dir dataset/utkcropped --plot

# 4. Train (defaults: EfficientNet-B3, Mean-Variance Loss, 100 epochs, AMP)
python scripts/train.py

# 5. Run the Gradio demo
python demo/app.py --checkpoint checkpoints/best_efficientnet_b3_*.pt

πŸ’‘ No GPU? The pipeline runs on CPU too β€” just set training.use_amp=false in configs/default.yaml.


πŸ“Š Results & Benchmarks

Evaluated on the UTKFace held-out test set (~2,000 images, ages 0–84).

Model #Params Input Size Loss MAE ↓ CS@5 ↑ Inference
MobileNetV3-Large 5.5M 224Γ—224 Mean-Variance TBD TBD ~5ms
EfficientNet-B0 5.3M 224Γ—224 Mean-Variance TBD TBD ~6ms
EfficientNet-B3 12M 224Γ—224 Mean-Variance TBD TBD ~8ms
ResNet-50 25.6M 224Γ—224 Mean-Variance TBD TBD ~12ms
ViT-S/14 DINOv2 22M 224Γ—224 Mean-Variance TBD TBD ~15ms
ResNet-50 (v1 baseline) 25.6M 128Γ—128 L1 4.73 β€” β€”

MAE = Mean Absolute Error in years (lower is better).
CS@5 = Cumulative Score β€” fraction of predictions within 5 years of ground truth (higher is better).
Results for the new models will be added after training. Run python scripts/evaluate.py --checkpoint <path> --bias to reproduce.

Inference example

πŸ—οΈ Architecture

How It Works

graph TD
    A[Face Image] --> B[Preprocessing\n224Γ—224 Β· Normalize]
    B --> C{Backbone}
    C --> D1[MobileNetV3-Large\n5.5M params]
    C --> D2[EfficientNet-B3\n12M params β˜…]
    C --> D3[ResNet-50\n25.6M params]
    C --> D4[ViT-S/14 DINOv2\n22M params]
    D1 & D2 & D3 & D4 --> E[Head\nDropout β†’ Linear β†’ GELU β†’ Linear]
    E --> F[101 Logits\nage classes 0 to 100]
    F --> G[Softmax\nAge Probability Distribution]
    G --> H[E_age = sum of p_i times i\nPredicted Age]
Loading

Why Mean-Variance Loss?

Instead of treating age as a single scalar, the model outputs a probability distribution over 101 age classes. This encodes the inherent ambiguity of facial aging and provides a richer training signal.

Loss = Ξ»_mean Γ— |E[age] βˆ’ true_age|   +   Ξ»_variance Γ— Var[age]
         ↑                                    ↑
  Penalise wrong mean              Penalise high uncertainty

This consistently outperforms L1/MSE regression by 0.3–0.5 MAE on UTKFace.
Reference: Pan et al., "Mean-Variance Loss for Deep Age Estimation from a Face", CVPR 2018.


πŸ“ Project Structure

Facial_Age_estimation_PyTorch/
β”œβ”€β”€ configs/
β”‚   └── default.yaml          # All hyperparameters β€” edit here, not in code
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ data/
β”‚   β”‚   β”œβ”€β”€ dataset.py        # UTKDataset (side-effect free, importable)
β”‚   β”‚   └── transforms.py     # Train / val / test transform factories
β”‚   β”œβ”€β”€ models/
β”‚   β”‚   └── age_estimator.py  # AgeEstimationModel (5 backbones)
β”‚   β”œβ”€β”€ training/
β”‚   β”‚   β”œβ”€β”€ losses.py         # MeanVarianceLoss + L1AgeLoss
β”‚   β”‚   └── trainer.py        # Trainer: AMP, AdamW, OneCycleLR, logging
β”‚   └── utils/
β”‚       β”œβ”€β”€ metrics.py        # AverageMeter, MAE, CS@5
β”‚       └── seed.py           # set_seed() for reproducibility
β”œβ”€β”€ scripts/
β”‚   β”œβ”€β”€ prepare_data.py       # Stratified CSV split from raw UTKFace
β”‚   β”œβ”€β”€ train.py              # Training entry point (CLI + OmegaConf)
β”‚   β”œβ”€β”€ evaluate.py           # Test-set eval + bias breakdown
β”‚   β”œβ”€β”€ inference.py          # Single-image / batch inference
β”‚   └── export_model.py       # TorchScript & ONNX export
β”œβ”€β”€ demo/
β”‚   └── app.py                # Gradio web demo
β”œβ”€β”€ tests/                    # 37 unit tests (pytest)
β”œβ”€β”€ notebooks/                # EDA notebooks (coming soon)
β”œβ”€β”€ pics/                     # Images used in README
β”œβ”€β”€ checkpoints/              # Saved model weights (git-ignored)
β”œβ”€β”€ csv_dataset/              # Pre-split CSV files
β”œβ”€β”€ .github/workflows/ci.yml  # GitHub Actions CI
β”œβ”€β”€ pyproject.toml
└── requirements.txt

πŸ“¦ Installation

Step 1 β€” Clone the repo

git clone https://github.com/Ebimsv/Facial_Age_estimation_PyTorch.git
cd Facial_Age_estimation_PyTorch

Step 2 β€” Install PyTorch (match your CUDA version from pytorch.org)

# CUDA 12.8 (RTX 40/50 series)
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu128

# CUDA 11.8
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118

# CPU only
pip install torch torchvision

Step 3 β€” Install project dependencies

pip install -r requirements.txt

# For the Gradio demo + W&B logging:
pip install gradio wandb

Step 4 β€” Verify

python -m pytest tests/ -v -k "not vit_small"
# Expected: 37 passed

πŸ“‚ Dataset

This project uses the UTKFace dataset β€” 20,000+ face images labelled with age (0–116), gender, and ethnicity.

Dataset Images Age Range Labels
UTKFace ~23,000 0 – 116 Age, Gender, Ethnicity
MORPH ~55,000 16 – 77 Age, Gender, Race
FG-NET 1,002 0 – 69 Age

Download: Get the cropped UTKFace version from Kaggle (utkcropped folder).

Dataset Preparation

# Creates: csv_dataset/{utkface_dataset,train_set,valid_set,test_set}.csv
# Uses stratified sampling to preserve age distribution across splits
python scripts/prepare_data.py \
    --dataset-dir dataset/utkcropped \
    --train-ratio 0.80 \
    --val-ratio 0.10 \
    --plot                    # saves split_distributions.png

Data Visualisation

Age Distribution Train / Val / Test Splits
age dist split dist
Gender Distribution Ethnicity Distribution
gender ethnicity

πŸŽ“ Training

Default Training

# Train EfficientNet-B3 with Mean-Variance Loss (recommended)
python scripts/train.py

CLI Overrides

Any value in configs/default.yaml can be overridden from the command line:

# Change backbone
python scripts/train.py model.name=resnet50

# Regression mode (L1 loss, 1 output node β€” for old checkpoints)
python scripts/train.py model.output_dim=1 loss.type=l1

# Longer training with W&B logging
python scripts/train.py training.epochs=150 logging.use_wandb=true

# Lower memory (if < 8GB VRAM)
python scripts/train.py training.batch_size=48 data.img_size=192

# Lightweight edge model
python scripts/train.py model.name=mobilenet_v3 training.batch_size=128

Key Config Options (configs/default.yaml)

model:
  name: "efficientnet_b3"   # mobilenet_v3 | efficientnet_b0/b3 | resnet50 | vit_small
  output_dim: 101           # 101 = Mean-Variance Loss | 1 = plain regression

training:
  epochs: 100
  batch_size: 96            # EfficientNet-B3 @ 224px, 8GB VRAM
  use_amp: true             # Mixed precision (strongly recommended)

loss:
  type: "mean_variance"     # mean_variance | l1

TensorBoard

tensorboard --logdir runs/
TensorBoard training curves

πŸ” Evaluation

# Standard evaluation on the test split
python scripts/evaluate.py --checkpoint checkpoints/best_efficientnet_b3_*.pt

# Demographic bias breakdown (age group, gender, ethnicity)
python scripts/evaluate.py --checkpoint checkpoints/best_efficientnet_b3_*.pt --bias

# Save per-image predictions to CSV
python scripts/evaluate.py --checkpoint checkpoints/best_*.pt \
    --bias --save-csv results/predictions.csv

Example output:

==================================================
  Split  : test  (n=2041)
  MAE    : 4.12 years
  CS@5   : 0.713  (71.3% within 5 years)
  CS@10  : 0.941  (94.1% within 10 years)
==================================================

── MAE by Gender ────────────────────────────────
Female    4.05
Male      4.19

── MAE by Ethnicity ─────────────────────────────
Asian     3.91
Black     4.44
Indian    4.28
White     4.02

Single Image Inference

python scripts/inference.py \
    --checkpoint checkpoints/best_*.pt \
    --image img_test/30_1_2.jpg \
    --output img_test/output.jpg

πŸ–₯️ Gradio Demo

# Local demo
python demo/app.py --checkpoint checkpoints/best_*.pt

# Share publicly via Gradio tunnel
python demo/app.py --checkpoint checkpoints/best_*.pt --share

The demo shows both the predicted age and the full probability distribution over all 101 age classes, giving you insight into model confidence.

πŸš€ A live demo on Hugging Face Spaces is coming soon!


πŸ“€ Export Model

# TorchScript (fastest for deployment β€” uses torch.jit.trace)
python scripts/export_model.py --checkpoint checkpoints/best_*.pt

# ONNX (for ONNX Runtime, TensorRT, OpenVINO, etc.)
python scripts/export_model.py --checkpoint checkpoints/best_*.pt --format onnx

πŸ“š Literature Review

Click to expand β€” 7 key papers reviewed
Paper Summary Key Idea Code
SwinFace (2023) Multi-task Swin Transformer for face analysis Multi-Level Channel Attention GitHub
Unraveling Age Estimation Puzzle (2022) Benchmark & analysis of what actually matters Data quality > model choice GitHub
MiVOLO (2023) ViT-based age + gender; works on occluded faces Uses body context, not just face GitHub
CORAL (2020) Ordinal regression for age estimation Rank-consistent binary subtasks GitHub
Deep Regression Forests (2018) End-to-end DRF for heterogeneous age features Joint data partition + abstraction GitHub
Mean-Variance Loss β˜… (2018) Distribution learning for age estimation Used in this repo Paper
FaceXFormer (2024) Unified transformer for all face analysis tasks Token-based multi-task decoder GitHub
Supported Datasets
Dataset Images Age Range Notes
UTKFace (used here) ~23,000 0–116 In-the-wild, diverse
MORPH 55,134 16–77 Mugshot style
CACD 163,446 β€” Celebrity, web-collected
FG-NET 1,002 0–69 Small, cross-age pairs
Adience 26,580 Age groups 8 coarse age groups

πŸ—ΊοΈ Roadmap

βœ… Completed

  • Professional package structure β€” src/, scripts/, demo/, tests/, configs/
  • OmegaConf YAML config β€” all hyperparameters in one file, CLI overrides
  • 5 backbone support β€” MobileNetV3-Large, EfficientNet-B0/B3, ResNet-50, ViT-S/14 DINOv2
  • Mean-Variance Loss (CVPR 2018) β€” distribution-based age estimation
  • Modern training pipeline β€” AMP, AdamW with differential LRs, OneCycleLR, gradient clipping
  • Stratified data splits β€” stratified train/val/test CSV generation
  • 37 unit tests β€” model, losses, transforms, dataset; all passing
  • GitHub Actions CI β€” automated lint + test on every push
  • Gradio demo β€” with age probability distribution visualisation
  • TorchScript + ONNX export
  • Bias evaluation β€” per age-group, gender, and ethnicity MAE breakdown
  • Single-image + batch inference script
  • pyproject.toml β€” proper packaging with optional extras
  • Comprehensive .gitignore β€” no accidental weight/dataset commits

πŸ”„ In Progress

  • Train EfficientNet-B3 on UTKFace and populate the results table with real MAE numbers
  • Hugging Face Spaces demo β€” live, always-on demo accessible from the README

πŸ“Œ Planned

  • GradCAM / Attention heatmaps β€” visualise which facial regions drive age predictions
  • Real-time webcam inference β€” scripts/webcam.py with OpenCV face detection
  • Cross-dataset evaluation β€” train on UTKFace, test on MORPH / FG-NET
  • EDA Jupyter Notebook β€” notebooks/01_EDA.ipynb with interactive plots
  • Pre-commit hooks β€” ruff + formatting checks enforced on commit
  • ONNX Runtime inference script β€” for CPU-only deployment
  • Benchmark on MORPH dataset β€” broader reproducibility

πŸ“ Citation

If you use this repository in your research, please cite:

@misc{mousavi2024facial,
  title     = {Facial Age Estimation with PyTorch},
  author    = {Mousavi, Ebrahim},
  year      = {2024},
  publisher = {GitHub},
  url       = {https://github.com/Ebimsv/Facial_Age_estimation_PyTorch}
}

The Mean-Variance Loss implemented in this repo:

@inproceedings{pan2018mean,
  title     = {Mean-Variance Loss for Deep Age Estimation from a Face},
  author    = {Pan, Hongyu and Han, Hu and Shan, Shiguang and Chen, Xilin},
  booktitle = {Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition},
  pages     = {5285--5294},
  year      = {2018}
}

🀝 Contributing

Contributions are welcome! Whether it's a new backbone, a better loss function, a bug fix, or improved documentation.

# Fork, clone, create a branch
git checkout -b feat/your-feature

# Install dev dependencies
pip install -r requirements-dev.txt
pre-commit install

# Make changes, then verify
ruff check src/ scripts/ tests/
python -m pytest tests/ -v

# Open a Pull Request πŸŽ‰

See CONTRIBUTING.md for detailed guidelines, including how to add a new backbone.


πŸ“„ License

This project is licensed under the MIT License β€” see LICENSE for details.


If this project helped you, please consider giving it a ⭐ β€” it means a lot!

Made with ❀️ by Ebi Mousavi

About

Age Estimation with PyTorch: Deep Learning for Predicting Age

Topics

Resources

Contributing

Stars

88 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages