Makeup is not noise - it is a structured, aesthetically optimized corruption of the face manifold. Foundation merges skin micro-texture components, eyeliner redraws orbital boundary geometry, contouring introduces false gradient ridges, and lipstick obliterates the natural color gradient of the vermilion border.
Standard restoration networks fail here because they optimize:
This penalizes average pixel distance - encouraging blurred, topologically wrong outputs that look plausible but are structurally incorrect. A face can score high on PSNR yet have an eye whose boundary cycle is broken, a lip contour that is disconnected, or a pupil rendered as a filled disc instead of an annulus.
ITDF fixes this with topological supervision.
A Vision Transformer (ViT-B/16) encodes the makeup image into a spatial feature grid
For any continuous coordinate
with Fourier positional encoding
For direction
The Euler Characteristic Transform collects all curves:
Key theorem (Turner et al.): ECT is injective - two shapes with identical ECTs are identical. Minimizing ECC differences achieves topological matching, not merely approximates it.
Standard ECCs are piecewise-constant and block gradients. We introduce a smooth sigmoid relaxation:
The DECT loss over
Complexity:
Foundation (smooths gradients, uniform intensity shift) and lipstick (sharp gradient, saturated color) look similar under a single intensity filtration. We bifiltrate over intensity AND gradient magnitude simultaneously:
Stochastic line slicing gives a differentiable Wasserstein loss via Sinkhorn optimal transport (
Each block shows one identity: left - ground-truth bare face; top row - five distinct makeup inputs; bottom row - ITDF outputs. Across all five styles (natural, heavy eyeshadow, bold lip, contouring, full glam), the model consistently recovers the same bare-face structure - confirming that the many-to-one 1:5 training design successfully forces the network to learn identity topology, not cosmetic style.
Each panel shows Euler Characteristic Curves across one of the 9 filtration directions (
The orange curves consistently shift away from the blue (makeup) distribution and toward the bare-face pattern across all 9 directions. This is direct visual evidence that the DECT loss is active - it is not a passive regularizer but is genuinely reshaping the output topology. The gap is largest in the intensity direction (panel 9), where lipstick and eyeshadow create the strongest topological deviation.
This figure shows the mean integrated |ECC(input) − ECC(output)| across the validation set, separately for each of the 9 DECT directions.
The gap is uniform across all 8 spatial directions - there is no privileged orientation where the model performs better or worse. This confirms that the DECT loss provides balanced topological supervision across all filtration angles, not just along easy directions like horizontal/vertical. The intensity-only direction (Dir 9) shows a slightly larger gap, consistent with the observation that intensity-based artifacts (color shift from lipstick, foundation) are harder to fully resolve than spatial-gradient artifacts.
Each point is one validation sample. X-axis: makeup intensity (mean absolute color distance between makeup and bare face). Y-axis: ArcFace identity similarity between ITDF output and ground-truth bare face.
Two key observations:
- Light makeup (low intensity, left side) → consistently high identity similarity. The model has little to correct and does so accurately.
- Heavy makeup (high intensity, right side) → identity similarity spreads wider and drops for extreme cases. This is expected - theatrical or full-face coverage removes the texture cues the model relies on.
The relationship is approximately linear in log-intensity, suggesting:
with the model maintaining
Training loss curves over 40,000 iterations. The total loss (sum of all weighted components) decreases smoothly without instability. Key observations:
- L1 and LPIPS dominate the loss signal (58.7% and 40.6% of weighted total) and drive the initial rapid descent in the first 5,000 iterations.
- DECT raw loss decreases from 0.44 to 0.07 - an 84% reduction - confirming that the topological loss is not stuck and is genuinely being optimized throughout training.
- No loss spike or divergence occurs, validating the
$\tau$ -annealing schedule: starting at$\tau=1.0$ (smooth, stable gradients) and ending at$\tau=0.1$ (sharper, more precise topology matching).
ITDF encounters difficulty in three scenarios:
- Theatrical makeup (> 40% face coverage) - insufficient texture survives for reconstruction, outputs become blurred.
- Non-studio lighting - strong side-lighting or dark backgrounds cause domain shift relative to FFHQ-Makeup training distribution.
- Dataset annotation errors - several low-PSNR validation cases are caused by mismatched ground-truth pairs in FFHQ-Makeup (a makeup image from one identity paired with a bare face from a different individual), not by model failure. PSNR-based benchmarks underestimate true performance when ground-truth pair quality is imperfect.
| Metric | Train | Val |
|---|---|---|
| PSNR | 25.88 dB | 25.20 dB |
| SSIM | 0.794 | 0.790 |
| LPIPS | 0.260 | 0.273 |
| Identity Accuracy | 98.2% | 96.8% |
| Identity Similarity | 0.682 | 0.660 |
Train/val gap is small - PSNR drops only 0.68 dB, identity accuracy drops 1.4 pp - confirming the model generalizes well across the identity split.
Upload a makeup face → get bare face + identity score + ECC topology plot. Runs on free CPU (~35–70 seconds).
ITDF/
├── train.py # Training loop (AdamW, τ annealing, 40K iters)
├── evaluate.py # All 6 metrics (PSNR, SSIM, LPIPS, Betti, ArcFace)
├── requirements.txt
│
├── models/
│ ├── itdf.py # Full model (encoder + decoder)
│ ├── encoder.py # ViT-B/16 contextual encoder
│ ├── decoder.py # 5-layer SIREN implicit decoder
│ └── discriminator.py # PatchGAN discriminator
│
├── losses/
│ ├── dect_loss.py # ← KEY: Differentiable ECT loss O(NlogN)
│ ├── multiparameter_persistence.py # Bifiltration + Sinkhorn Wasserstein
│ └── combined_loss.py # Weighted total loss
│
├── data/
│ ├── ffhq_makeup_dataset.py # FFHQ-Makeup 1:5 pair construction
│ └── combined_dataset.py # Dataloader
│
└── configs/
└── default.yaml # All hyperparameters
pip install -r requirements.txtHardware: Single NVIDIA GPU ≥12 GB VRAM (tested: RTX 4090, 24 GB).
git clone https://github.com/priyadip/itdf.git
cd itdf
pip install -r requirements.txt# configs/default.yaml
data:
ffhq_dir: "data/FFHQ-Makeup"
img_size: 512data/FFHQ-Makeup/
├── 000001/
│ ├── bare.jpg
│ ├── makeup_01.jpg ... makeup_05.jpg
python train.py --config configs/default.yamlpython evaluate.py --config configs/default.yaml \
--checkpoint outputs/checkpoints/ckpt_final.ptimport torch, yaml, numpy as np
from PIL import Image
from models.itdf import ITDF
cfg = yaml.safe_load(open("configs/default.yaml"))
model = ITDF(cfg)
ckpt = torch.load("outputs/checkpoints/ckpt_final.pt", map_location="cpu")
model.load_state_dict(ckpt.get("model", ckpt), strict=False)
model.eval()
img = Image.open("makeup.jpg").convert("RGB").resize((512, 512))
x = torch.from_numpy(np.array(img, dtype=np.float32) / 127.5 - 1.0).permute(2,0,1).unsqueeze(0)
with torch.no_grad():
out = model(x)
arr = ((out.squeeze(0).permute(1,2,0).numpy() + 1.0) * 127.5).clip(0,255).astype("uint8")
Image.fromarray(arr).save("bare_face.png")Released under CC BY-NC-ND 4.0 - academic use only, no commercial use, no derivatives. See LICENSE and SECURITY.md for full terms and responsible use policy.
Model weights: private - request access on 🤗 Hugging Face





