Skip to content

About

Synthetic identity-conditioned face datasets for machine unlearning — 750 identities, Bench 224×224 + Raw 1024×1024 (75k portraits), InstantID + Juggernaut-XL-v9.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

SFHQ-VirtualID

Release notes: see CHANGELOG.md for the v1.0.0 (dev → main) release summary.

Bench on Hugging Face Raw on Hugging Face Bench DOI Raw DOI License

A reproducible pipeline for constructing synthetic, identity-conditioned face clusters from CC0 synthetic seed images, designed as a benchmark for machine unlearning. Each identity cluster is a deletion unit — all images of one synthetic identity share a split (retain / forget) and a per-image image_subset (train / holdout). Every identity contributes images to both training and evaluation — no identity-level test split that would make test accuracy structurally degenerate.

The project publishes two complementary datasets (see DATASET_CARD_BENCH.md and DATASET_CARD_RAW.md):

Release Resolution Contents Purpose
SFHQ-VirtualID-Bench 224×224 aligned crops Balanced (67,500) + imbalanced (36,064) Machine-unlearning benchmark (primary)
SFHQ-VirtualID-Raw 1024×1024 portraits Max-size (75,000, 100/id) General-purpose identity-conditioned faces

Dataset at a glance

Property Value
Source domain SFHQ (CC0 synthetic portraits)
Generation method InstantID + Juggernaut-XL-v9 + ControlNet
Output resolution 224×224 (Bench, aligned crops) / 1024×1024 (Raw, portraits)
Identities 750
Images per identity 90 (Bench balanced) / 100 (Raw) / variable (Bench imbalanced, ratio-based gradient)
Total images 67,500 (Bench balanced) / 36,064 (Bench imbalanced) / 75,000 (Raw)
Splits Retain 675, Forget 75 identities; per-image image_subset (train + holdout)
Forget protocol 15 steps, 75 forget identities — uniform 5/step (baseline) or seeded-Poisson batches (variant)
Labels (standard) identity_id, age_group, split, forget_step, forget_step_poisson, image_subset, arcface_similarity, laplacian_variance, detection_confidence (prompt metadata stripped from Bench)
Labels (imbalanced) plus popularity_bin, images_per_identity on the 224 variant
Metadata format CSV + Parquet
Intended task Machine unlearning (identity-level deletion)
Artifacts 3 datasets across 2 releases: Bench (224 balanced + imbalanced), Raw (1024 max-size)

Why this dataset?

Existing unlearning benchmarks either use real face photographs (creating ethical and privacy barriers) or treat images as independent samples (breaking the identity-consistency constraint that makes deletion meaningful). SFHQ- InstantID solves both problems:

  • Synthetic, not anonymous. Every face is generated by a fully synthetic pipeline — SFHQ seeds are CC0 AI-generated portraits, and InstantID + Juggernaut-XL-v9 introduce controlled identity-preserving variation. We do not claim the images are "anonymous" or "privacy-safe"; synthetic does not mean risk-free, and residual likeness or memorisation is possible.
  • Identity clusters are deletion units. All 90 images of identity 37 share the same identity_id, the same split, and (if forget) the same forget_step. An unlearning system must genuinely erase a person rather than scattered pixels.
  • Sequential forget protocol. 75 identity clusters are deleted over 15 steps, modelling real-world incremental deletion requests (GDPR / CCPA). Both schedules ship as columns in the same artifact:
    • forget_step (uniform baseline) — 5 identities per step, equal counts. Step index == cumulative forgotten count, so per-step curves are directly comparable with no batch-size confound.
    • poisson (variant) — per-step counts drawn from a seeded Poisson distribution (λ = 5), rebalanced to total 75. Models the arrival process of real deletion-request streams: occasional near-empty steps and occasional bursts (Ginart et al., 2019; arXiv:2012.01668; the streaming-forgetting framework of Shen et al., 2025, arXiv:2507.15280 shows step-to-step total variation drives unlearning difficulty). Evaluation MUST compare schedules by cumulative forgotten count, not step index, since step index no longer equals cumulative count. The schedule is a fixed dataset property (seeded, recorded in RELEASE_MANIFEST.json), not a runtime variable.
  • Imbalanced variant. A companion dataset_imbalanced.csv uses the same identities but prunes images to a 3-bin gradient (82:41:16 train counts with default ratios; configurable), with constant holdout per bin. Evaluators measure unlearning difficulty as a function of per-identity representation, mirroring real-world long-tail distributions.

Pipeline

flowchart TD
    A[SFHQ source images<br/>CC0 synthetic, ~90k] --> B[CLIP + KMeans<br/>diverse seed selection]
    B --> C[InstantID + Juggernaut-XL-v9<br/>identity-conditioned generation]
    C --> D[Merge 12-GPU shards]
    D --> E[ArcFace extraction on<br/>1024x1024 candidates]
    D --> F[MTCNN alignment<br/>sharpness + ArcFace gating]
    E --> G[Identity-level splits<br/>retain / forget]
    F --> G
    E --> J[dataset_raw.csv<br/>1024x1024 release artifact]
    G --> H[dataset.csv + parquet<br/>224x224 release artifact]
    G --> I[dataset_imbalanced.csv<br/>224x224 3-bin gradient]
Loading

Phase breakdown

Phase Script Resources Time Description
1. Download step1_download 1 CPU ~5 min Precomputed CLIP features + KMeans seed selection from SFHQ
2. Generate hpc_generate.sh 15× L40S GPU (exclusive) ~18 hr 750 identities (50/shard), 100 candidates each, 100 unique prompts
3. Merge hpc_merge.sh 1 CPU ~30 min Unify shards, remap identity IDs
4. Extract hpc_extract.sh 1× GPU ~2 hr ArcFace embeddings + demographics on 1024×1024 candidates (detection works on full portraits)
5. Preprocess hpc_preprocess.sh 1× GPU ~4 hr MTCNN detect + align, sharpness + ArcFace gating → 224×224 crops
6. Build hpc_build.sh 1 CPU ~15 min All three artifacts: 224 balanced/imbalanced + 1024 max-size

Extract runs on the 1024×1024 raw candidates (detection works on full portraits — it fails on tight 224 crops, which previously degraded all demographics to constants). Extract and preprocess are sibling steps: both consume the merge output and neither reads the other's output, so they can run in parallel on two GPUs to halve the wall time. The build step joins their outputs through the (identity_id, trial) key and produces four dataset pairs from a single pipeline run.

Configuration

Parameter Value Purpose
dataset.nidentities 750 Total identity clusters
dataset.imagesperidentity 90 Final images per identity
dataset.candidatesperidentity 100 Candidates generated per identity
dataset.forget_pct 0.10 Fraction of identities in forget set
dataset.forget_steps 15 Unlearning steps (balanced; both schedules ship as forget_step + forget_step_poisson columns)
dataset.holdout_frac 0.20 Fraction of each identity's images for holdout evaluation
dataset.min_holdout 5 Minimum holdout images per identity (floor)
dataset.skip_download false Skip Kaggle download if data exists locally
pipeline.instantid.base_model RunDiffusion/Juggernaut-XL-v9 Base SDXL model
pipeline.instantid.controlnet_conditioning_scale 0.80 ControlNet spatial control
pipeline.imgsize 224 Final crop resolution
pipeline.min_similarity_raw 0.40 ArcFace similarity floor — config default only; NOT enforced in v1.0.0 (arcface_similarity ships as a confound column)
pipeline.min_similarity_final 0.45 ArcFace similarity floor — config default only; NOT enforced in v1.0.0 (arcface_similarity ships as a confound column)
pipeline.blurthreshold 80.0 Laplacian variance sharpness floor

Size guards: nidentities ≥ 100 enforced for download and build steps (generate-only shards bypass this). forget_steps ≥ 5 enforced at build.

Hyperparameters (guidance_scale, ip_adapter_scale, num_inference_steps) are model-aware — resolved from MODEL_DEFAULTS in generate_identities.py based on the selected base_model. Juggernaut: 3.0 / 0.85 / 30; SDXL base: 5.5 / 0.90 / 25. Override via CLI (pipeline.instantid.guidance_scale=4.0).

Prompt system

Prompts are defined in src/prompts.py. A 20 × 5 = 100 grid of unique variation prompts combines

  • 20 composition tuples (pose + expression + setting + camera lens)
  • 5 lighting treatments (window, studio, daylight, golden hour, overcast)

Each identity gets a deterministically shuffled subset of 100 prompts from the pool, seeded by the identity's cluster ID. Every candidate in a shard receives a unique prompt — no two candidates share the same rendering instruction within an identity.

Full configuration in conf/config.yaml.

Quick start

Environment

# Create conda env (Python 3.10, CUDA 12.6)
conda create -n data_gen python=3.10 -y
conda activate data_gen
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124
pip install xformers --index-url https://download.pytorch.org/whl/cu124
pip install -r requirements.txt

Detailed HPC setup: [HPC CookBook.md](HPC CookBook.md).

Run on HPC (Slurm)

# Full pipeline (all 6 phases, chained with Slurm dependencies):
sbatch scripts/hpc_full_pipeline.sh

# Individual phases:
sbatch scripts/hpc_generate.sh       # 12-GPU array
sbatch scripts/hpc_merge.sh          # after generate completes
sbatch scripts/hpc_preprocess.sh     # after merge completes
sbatch scripts/hpc_extract.sh        # after extract completes
sbatch scripts/hpc_build.sh          # after extract completes

All data lands on Lustre scratch (/scratch/$USER/datagen/data/). Model caches stay on home storage.

Run locally (single machine)

cd src
# Precomputed CLIP features — use --skip-download after first run:
python main.py --config-name step1_download dataset.skip_download=false
python main.py --config-name step2_generate   # generate
python main.py --config-name step4_extract    # embeddings (on 1024 candidates)
python main.py --config-name step3_preprocess # align + filter (224 crops)
python main.py --config-name step5_build      # builds all four dataset pairs

Note the order: extract now runs on the raw 1024×1024 candidates (Step 4) before preprocess (Step 3), because InsightFace detection fails on tight 224 crops but works on full-resolution portraits. The step numbers follow the Hydra config filenames; the pipeline scripts chain them in the correct order automatically.

Each step accepts Hydra overrides; see conf/config.yaml for all tunables.

Output schema

dataset.csv / dataset.parquet

Column Type Description
image_path string Relative path: images/identity_NNN/crop_XXX.jpg
identity_id int (0–749) Synthetic identity cluster ID
age_group int (0–3) Proxy age label: 0=Young, 1=Adult, 2=Middle-Aged, 3=Senior. Per-image (see note below)
age int Raw InsightFace age estimate. Per-image (see note below)
gender int (0/1) InsightFace gender classifier output
split string retain or forget — identity-level role
forget_step int (0–14, -1) Step under the uniform schedule (5 ids/step; step index == cumulative forgotten count); -1 for retain
forget_step_poisson int (0–14, -1) Step under the seeded-Poisson schedule (variable ids/step, GDPR-arrival stress test; evaluate by cumulative count); -1 for retain
image_subset string train or holdout — per-image role (MUFAC-aligned)
arcface_similarity float [-1,1] Cosine similarity to identity's mean ArcFace embedding (confound control)
laplacian_variance float Sharpness score from quality filter (quality confound control)
detection_confidence float Face detector confidence (alignment quality control)

Both forget schedules ship in one artifact. forget_step is the MUFAC baseline (equal 5 ids/step — per-step curves are directly comparable). forget_step_poisson is the seeded arrival-model stress test (λ=5, rebalanced to total 75; occasional near-empty and burst steps). For cross-schedule comparisons, evaluate by cumulative forgotten count, not step index (Shen et al., 2025, arXiv:2507.15280). The schedule is a fixed dataset property (recorded in RELEASE_MANIFEST.json), not a runtime variable. Prompt metadata (pose…camera) is deliberately stripped from Bench — it ships only in the Raw release.

Per-image age labels (by design). age_group and age are estimated per image on the parent 1024×1024 candidate (InsightFace gender/age classifier), so a single identity can span multiple age groups — e.g. identity 558 ranges 23–65 across its images while remaining recognisably the same person. This is a deliberate realism property: the synthetic identity appears at different ages, and the per-image labels prevent an age classifier from shortcutting to identity (identity_id → constant age). Do not collapse to a per-identity constant when using the data.

All crops are stored as 224×224 uint8 BGR. Downstream classifiers using ImageNet-pretrained backbones (e.g. ResNet-18) must convert to RGB and normalise with ImageNet statistics — CROP_SIZE, IMAGENET_MEAN, IMAGENET_STD are exported from src/common.py. This matches the ImageNet training regime so pretrained features activate at full fidelity from epoch 1.

Critical invariant (MUFAC-aligned): Every identity_id maps to exactly one split (retain or forget), and every identity contributes both image_subset values (train + holdout) within that split. There is no identity-disjoint test split — the old unseen-identity test accuracy was structurally 0, and forgetting was measured on the same images used for unlearning. Now the holdout subset (18/id by default) is genuinely held out of training, giving meaningful retention, forgetting-generalisation, and forget-train vs forget-holdout gap metrics (see the MUFAC design in msc-project-core-implementation/.hermes/plans/dataset-split-redesign.md). Enforced by validate_release.py.

dataset_raw.csv / dataset_raw.parquet

Full-resolution 1024×1024 portrait dataset — the raw generation outputs before face alignment. All 100 portraits per identity, no quality trim, no splits (max-size reference). Designed as a general-purpose release for identity recognition, face generation evaluation, demographic bias studies, and erasure-transfer testing (does forgetting the 224 crop also hide identity in the full context?). Researchers can construct balanced subsets of up to 100 images/identity with their own train/holdout splits.

Column Type Description
image_path string Relative path: images/identity_NNN/portrait_YYY.jpg
identity_id int (0–749) Synthetic identity cluster ID
age_group int (0–3) Proxy age label
age int Raw InsightFace age estimate
gender int (0/1) InsightFace gender classifier
arcface_similarity float [-1,1] Cosine similarity to identity's mean portrait embedding
pose string Head/body position
expression string Facial expression
lighting string Lighting condition
setting string Background/scene
camera string Camera angle

No laplacian_variance or detection_confidence — these are crop-level quality metrics and are meaningless on raw portraits. No split / forget_step / forget_step_poisson / image_subset — the Raw release is max-size with no split protocol; split construction is left to the consumer.

The Raw release is max-size only (all 100 portraits per identity). The imbalanced variant is exclusive to the Bench (224) release.

Release summary (all artifacts)

Release Artifact Resolution Identities Images/id Total rows Purpose
Bench dataset.csv/.parquet 224×224 crops 750 90 (72 train + 18 holdout) 67,500 Dissertation unlearning benchmark
Bench dataset_imbalanced.csv/.parquet 224×224 crops 750 ratio-based (82:41:16 train; +18 holdout/id) 36,064 Long-tail stress test
Raw dataset_raw.csv/.parquet 1024×1024 portraits 750 100 75,000 General-purpose release

All three share identical identity_id and split labels (where present). Demographics (age, gender) are derived from detection on 1024×1024 portraits and are real — no longer degenerate from the CPU fallback path.

dataset_imbalanced.csv / dataset_imbalanced.parquet

An extra artifact produced alongside the balanced dataset. Shares the same identity pool and split assignment but prunes train images to a ratio-based 5:1 train gradient across three popularity bins, calibrated to the VGG-Face2 range (Cao et al., 2018; ~10:1 max-min, 5:1 inter-quartile; Wang et al., 2019 "Deep Face Recognition: A Survey"; Liu et al., 2019 "Large-Scale Long-Tailed Recognition in an Open World", CVPR). Configurable ratios — default 1.0:0.50:0.20 applied to the max train pool of candidatesperidentity − holdout = 100 − 18 = 82:

Bin Identities Train/ID Holdout/ID Total kept/ID Total images
High (top 10%) 75 82 18 100 7,500
Medium (30%) 225 41 18 59 13,275
Low (bottom 60%) 450 16 18 34 15,300

Holdout is the same per-identity reserve as the balanced release (max(min_holdout, round(imagesperidentity × holdout_frac)) = 18 with defaults), so probe stability is uniform across all popularity tiers. The gradient scales with the candidate pool: if a future release generates 550 candidates/identity targeting 500 images, holdout = 100 and max_train = 450, and the ratios re-derive train counts (guidance §2.2).

Column Type Description
image_path string Relative path: images/identity_NNN/crop_XXX.jpg
identity_id int (0–749) Synthetic identity cluster ID
age_group / age / gender int Proxy demographics (per-image)
split string retain / forget — identity-level role (SAME map as balanced)
image_subset string train / holdout (MUFAC-aligned; 18 holdout/id constant across bins)
arcface_similarity float [-1,1] Cosine sim to identity's mean embedding (confound control)
laplacian_variance / detection_confidence float Quality confound controls
popularity_bin string "high", "medium", or "low"
images_per_identity int Actual kept-image count per identity (100/59/34 — continuous difficulty axis)

No forget-schedule columns in imbalanced. The schedule axis lives in the balanced artifact (forget_step / forget_step_poisson); the imbalanced variant is a single-purpose long-tail stress test whose only experimental axis is the popularity gradient. Downstream: stratify by popularity_bin, and use the balanced artifact's split map to run the same 75 forget identities as a cross-dataset control.

Designed for stress-testing the long tail: high-popularity identities (celebrities) are over-learned and hardest to forget; low-popularity identities are under-learned and easiest to scrub. The ratio between high and low bins mirrors real-world face dataset distributions (5:1, VGG-Face2 range).

Imbalanced evaluation (MUFAC-aligned)

The imbalanced variant answers the question: "Does unlearning remain effective across the long-tail data distribution?" All evaluation gates use the holdout subset (never seen during training or unlearning). The recommended protocol (baseline gate → distance-to-oracle → budget sweep → balanced cross-check; see DATASET_CARD_BENCH.md §Intended use) guards the low-bin floor effect: report per-bin MIA AUC before unlearning, since a low-bin baseline near 0.5 means "never learned", not "scrubbed".

Metric Stratification Expectation Threshold
MIA AUC by popularity bin high / medium / low AUC near 0.50; no bin > 0.55 (mean) All bins
Forget-holdout accuracy by bin high / medium / low Uniformly low (=retrain oracle) in all bins All bins
Retain-holdout accuracy by bin high / medium / low High and stable; low-bin drop <= 5% vs high-bin All bins
Forget-train / forget-holdout gap per method x bin Gap <= 0.10; larger in low-bin = overfitting signal All bins
Probe identity accuracy by bin high / medium / low probes on holdout; directional: low-bin may be higher (less data, stronger memorisation) Report only
Statistical test Kruskal-Wallis H-test Retain p-value > 0.05 (no bin disproportionately harmed) Retain only

What is released / what is not

Released ✅ Withheld ❌
Aligned 224×224 face crops (crop_*.jpg) Raw SFHQ source images (data/seeds/)
1024×1024 candidate images (candidates/) ArcFace embedding vectors
dataset.csv + .parquet (224 balanced) Seed-to-output linkage table
dataset_imbalanced.csv + .parquet (224) Juggernaut-XL-v9 / InstantID / ControlNet / InsightFace model weights
dataset_raw.csv + .parquet (1024) Rejected / low-quality candidate images
datasetsummary*.json (all variants)
datasetsummary_raw.json
Checksums (checksums.sha256)
Schema (schema.json)
Release manifest (RELEASE_MANIFEST.json)

Model weights must be obtained from upstream sources by each user under the upstream licence terms. See THIRD_PARTY_NOTICES.md for exact revisions and licence URLs.

Limitations

  • Synthetic, not risk-free. Generated faces may retain artifacts, demographic bias, or unintended resemblance to real persons. The dataset must not be used for identification, biometric authentication, surveillance, impersonation, or decisions affecting individuals.
  • Proxy age labels. Age-group fields are model-estimated (InsightFace gender/age classifier) and must not be interpreted as verified demographic attributes.
  • Reconstruction risk. We do not distribute seed-to-output linkage, but residual similarity between a synthetic identity and its single SFHQ seed image is inherent to the InstantID method.

See DATASET_CARD_BENCH.md and DATASET_CARD_RAW.md for full composition, intended use, and privacy policy.

Reproducibility

Component Pinned value
Random seed 42 (configurable)
Shard seeds 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70
Python 3.10
PyTorch 2.6.0+cu124
Diffusers 0.39.0
CUDA 12.6
GPU NVIDIA L40S (46 GB)
SFHQ part 1 (~90k source images)

Exact model revisions are recorded in RELEASE_MANIFEST.json (a copy ships inside each release directory).

Citation

@dataset{sfhq_virtualid_bench,
  title     = {{SFHQ-VirtualID-Bench}: Synthetic Identity-Conditioned Aligned
               Face Crops for Machine Unlearning},
  author    = {Faiz Palwala},
  year      = {2026},
  version   = {1.0.0},
  doi       = {10.5281/zenodo.21877893},
  url       = {https://github.com/FaizPalwala/virtual-id-gen},
}

@dataset{sfhq_virtualid_raw,
  title     = {{SFHQ-VirtualID-Raw}: Full-Resolution Synthetic
               Identity-Conditioned Face Portraits},
  author    = {Faiz Palwala},
  year      = {2026},
  version   = {1.0.0},
  doi       = {10.5281/zenodo.21879130},
  url       = {https://github.com/FaizPalwala/virtual-id-gen},
}

See CITATION.cff for the complete metadata file.

Contributing

This is a research artifact. Bug reports and questions are welcome via GitHub Issues. For feature requests or extensions, please open a discussion first.

Licence

  • Code: MIT (see LICENSE).
  • Images and metadata: Non-commercial research use only, with an explicit prohibited-use clause. Revisit toward a more permissive licence after upstream model output-use terms are confirmed. See LICENSE for the full terms.
  • Third-party models: Not included. Each user must obtain Juggernaut-XL-v9, InstantID, ControlNet, and InsightFace weights from the upstream sources listed in THIRD_PARTY_NOTICES.md under those projects' own licence terms.

Related resources

Acknowledgements

This work was undertaken on the Aire HPC system at the University of Leeds, UK.


This dataset is a research artifact for machine unlearning evaluation. It is not intended for production identity systems, biometric authentication, or any application that makes decisions about people.

About

Synthetic identity-conditioned face datasets for machine unlearning — 750 identities, Bench 224×224 + Raw 1024×1024 (75k portraits), InstantID + Juggernaut-XL-v9.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages