Fawkes is a privacy protection system developed by researchers at SANDLab, University of Chicago. It adds small, hard-to-see changes ("cloaks") to your photos so that facial recognition models trained on them learn the wrong face. For the original project see the project webpage and the paper "Fawkes: Protecting Personal Privacy against Unauthorized Deep Learning Models" (USENIX Security 2020).
This fork is a rewrite of the cloaking pipeline (version 2):
- cloaks push your face toward a target person you choose, the method described in the paper, instead of just away from itself;
- the perturbation is optimised against an ensemble of modern face recognisers (ArcFace IR-100, AdaFace IR-101, LVFace ViT-B) through the same landmark alignment those recognisers use;
- the optimisation is robust to blur, resizing and JPEG re-encoding;
- protection is measured on a public dataset against recognisers that were not used to build the cloaks (see Evaluation);
- runs on PyTorch (CPU is fine), TensorFlow is gone.
The reasons behind these choices, with sources, are in docs/DECISIONS.md.
The code in this repository is released under the BSD-3-Clause licence (see LICENSE);
it is a derivative of the original Fawkes by SANDLAB, University of Chicago, under the same licence.
The network definitions vendored in fawkes/arch/ come from InsightFace and CVLface (MIT, notices
kept in the file headers).
That licence covers the code only. The pretrained detector and recogniser weights the tool downloads from Hugging Face are not part of this repository and carry their own terms: every one of them is licensed for non-commercial research use only (see Model licences). In practice this means the tool as a whole may be used for personal privacy protection and academic research, but not commercially, regardless of the code licence.
fawkes -d ./imgs --mode subtle
or python3 -m fawkes -d ./imgs -m subtle. Without --target-dir Fawkes picks the target for you
(see Choosing a target); that needs the target pool, built once with
python -m fawkes.target_pool build (requires the eval extra for LFW).
Every image in ./imgs gets a <name>_cloaked.png next to it. Options:
-
-d,--directory: the directory with images to protect. -
-t,--target-dir: a directory with a few photos of the person your cloaked photos should resemble to a recogniser (default: picked automatically). See Choosing a target. -
--target-strategy:far(default) ornear, which of the matched pool identities the automatic target is. -
-m,--mode:low,subtle,mid(default) orhigh, the tradeoff between protection strength, visible change and run time:mode surrogates steps max pixel change DSSIM budget colour penalty age penalty s / face, GPU low AdaFace IR-101, ArcFace IR-100 60 16 0.012 - - 1.1 subtle + LVFace-B, LVFace-L, LVFace-S (transformers) 120 12 0.006 30 1 2.7 mid same five 120 24 0.012 30 2 3.3 high same five 200 20 0.017 30 3 8.3 subtleis for photos you want to post: at feed size the change is hard to see, and it protects less (see Evaluation).midandhighprotect more and are visible as a slight change of the face's shading. On an 8-core CPU without a GPU,lowtakes about 35 s per face; the other modes take several minutes (not measured since the step counts were raised).Every mode also penalises what is left of your own identity in the cloaked face (
--self-weight, see docs/DECISIONS.md). All butlowpenalise the colour part of the cloak, which is what shows as reddish or yellowish patches on the skin, and spend the DSSIM budget on luma detail instead (--chroma-weight, decision 12). All butlowalso penalise the apparent ageing of the face: without it the cloak draws folds and lines under the eyes that make people look years older (--age-weight, decision 13). -
--models: comma-separated surrogate keys overriding the mode (python -m fawkes.models list). -
--steps,--eps,--th,--no-eot,--self-weight: override the mode's steps, pixel bound, DSSIM budget, robustness views and residual penalty. -
--chroma-weight: penalty on the colour (Cb/Cr) part of the cloak (30 insubtle,midandhigh, 0 inlow). Higher values leave less visible tint and, above about 30, less protection;--chroma-epsis a hard bound on the colour change instead (0-255 units,0for a grey cloak), which costs more protection for the same tint (rounds 8 to 10 in eval/RESULTS.md). -
--batch-size: faces optimised together (default 8; larger batches are faster per face). -
--threads: CPU threads for PyTorch. -
--no-align: the inputs are already 112x112 aligned faces; skip detection. -
--format:png(default) orjpg. -
--debug: print per-face statistics.
Each column is one person (Barack Obama from Wikimedia Commons, and three people from
LFW), and each row is a mode. Every tile is one of the three
photos that person "posts", cloaked in that row's mode with the automatic target. The row labels give
the mode's protection rate from Evaluation on the two ResNet recognisers (buffalo_l /
antelopev2) and the two transformers (AdaFace ViT-B / LVFace-T). For low these are the 2026-09-12
run, which used a random target, and LVFace-T was not measured.
The lines under a tile are the output of a simple face classifier: buffalo_l embeddings, one reference per identity (the mean embedding of its photos), and a cosine threshold of 0.35.
- first line: the posted photo's cosine similarity to the person's reference, which is built from other, clean photos of them, and the probability the classifier gives the person. The probability is a nearest-reference classifier over all ten people and targets in the figure, softmax(64 × cosine); 64 is the scale ArcFace-type recognisers are trained with.
- target: the same for the target Fawkes picked, with the target's reference built from its LFW photos.
- trained on these: how many of the person's clean photos match a reference built from the row's three posted photos, as a scraper would build it. This is the protection Fawkes aims for.
In every cloaked row the posted photo is classified as the target with near certainty, and the scraper's
reference finds none of the real photos. This setting is easy for the cloak: the scraper sees only
cloaked photos, the classifier is a plain centroid, and the target's reference is built from the same
photos the cloak aimed at. With a trained classifier and other recognisers the protection is partial,
lowest in subtle. The cloak can also borrow a feature of the target: Tony Blair gets a faint
moustache from José María Aznar. Made with eval/illustrate.py.
A recogniser trained on your cloaked photos should learn the target's face, not yours.
Automatic (default). Fawkes groups the faces in your photos into people and picks a target for
each from a pool of about 420 public identities (LFW): the same apparent sex, a similar age and skin
tone, and, among those, the face least like yours (--target-strategy far). Differences in age, sex
or skin tone cost budget without changing identity: they are what made earlier cloaks look older or
tinted. A matched target also protects better (rounds 11 to 16 in eval/RESULTS.md).
A person Fawkes has cloaked before keeps their target in later runs, so every photo of you pushes
toward the same false identity (remembered in fawkes/model/target_pool/assignments.json; delete it
to start over).
Your own target (--target-dir). All of your photos are pushed toward the same target, so use
the same directory every time; the embedding is cached in <target-dir>/fawkes_target.npz.
- Use 3 to 10 photos of one person, each with exactly one clearly visible face. Photos with zero or several faces are skipped.
- Pick someone of your sex and roughly your age and skin tone who otherwise looks unlike you; a target much older than you makes the cloak draw age.
- Public figures work fine; their real photos are labelled as them, not as you.
- Run time on an 8-core CPU without a GPU is about 35 s per face in
lowand several minutes per face in the other modes; batching several faces is faster per face. A CUDA GPU is used automatically when PyTorch finds one (install with thecu128extra). - Most of your published photos need to be cloaked for the protection to work; a recogniser trained on mostly clean photos of you learns your real face regardless.
- Cloaks survive JPEG re-encoding by design, but do not resize or filter the output more than a social network would.
Cloaks are fixed once you publish a photo, but recognisers keep improving. Radiya-Dixit et al. (ICLR 2022) showed that a model trained after a cloaking tool is released, or trained specifically against it, can defeat any such tool, including the original Fawkes. The evaluation below measures transfer to strong recognisers of today that were not used to build the cloaks. It does not, and cannot, promise protection against future or adaptive models.
eval/harness.py downloads a subset of LFW, cloaks the training
photos of some identities (each toward its own target identity), trains a linear classifier on face
embeddings from held-out recognisers, and reports the protection rate: the fraction of clean
test photos of protected identities that the classifier gets wrong. 10 protected and 10 clean
identities, 10 training and 5 test photos each. The evaluators are the InsightFace packs most
deployments use (buffalo_l, a ResNet-50; antelopev2, a ResNet-100) and a vision transformer
(AdaFace ViT-B, WebFace4M); none of them is in the surrogate ensemble.
| cloaker | buffalo_l | antelopev2 | AdaFace ViT-B | LVFace-T | DSSIM face box | s / photo |
|---|---|---|---|---|---|---|
| none | 0.00 | 0.00 | 0.00 | 0.00 | 0 | - |
| Fawkes 1.0 (TensorFlow), mid | 0.00 | 0.00 | - | - | 0.015 | 15 (CPU) |
| Fawkes 1.0, mid, JPEG 75 | 0.00 | 0.00 | - | - | 0.015 | - |
| Fawkes 2, low | 0.74 | 0.90 | 0.20 | - | 0.012 | 35 (CPU), 1.1 (A100) |
| Fawkes 2, low, JPEG 75 | 0.70 | 0.84 | 0.22 | - | 0.012 | - |
| Fawkes 2, mid (three surrogates, 2026-09-12) | 0.74 | 0.84 | 0.32 | - | 0.012 | 56 (CPU), 1.0 (A100) |
| Fawkes 2, mid (no colour penalty, 2026-09-13) | 0.80 | 0.92 | 0.48 | 0.90 | 0.013 | 74 (CPU), 1.7 (A100) |
| Fawkes 2, mid (no colour penalty), JPEG 75 | 0.74 | 0.84 | 0.44 | 0.92 | 0.013 | - |
| Fawkes 2, mid | 0.86 | 0.94 | 0.46 | 0.94 | 0.013 | 78 (CPU), 1.3 (H100) |
| Fawkes 2, mid, JPEG 75 | 0.82 | 0.88 | 0.38 | 0.92 | 0.013 | - |
| Fawkes 2, high (three surrogates, 2026-09-12, rerun Z0) | 0.82 | 0.92 | 0.52 | 0.78 | 0.017 | about 190 (CPU), 2.8 (A100) |
| Fawkes 2, high (no colour penalty, 2026-09-13) | 0.86 | 0.92 | 0.70 | 0.96 | 0.016 | about 250 (CPU, estimated), 4.4 (A100) |
| Fawkes 2, high (no colour penalty), JPEG 75 | 0.86 | 0.90 | 0.68 | 0.96 | 0.016 | - |
| Fawkes 2, high | 0.92 | 0.98 | 0.64 | 0.94 | 0.016 | about 250 (CPU, estimated), 4.2 (A100) |
| Fawkes 2, high, JPEG 75 | 0.90 | 0.96 | 0.64 | 0.94 | 0.016 | - |
| Fawkes 2 (2026-09-25), subtle, automatic target | 0.56 | 0.68 | 0.26 | 0.61 | 0.007 | 2.7 (A100) |
| Fawkes 2 (2026-09-25), subtle, automatic target, JPEG 75 | 0.49 | 0.59 | 0.22 | 0.50 | 0.007 | - |
| Fawkes 2 (2026-09-25), mid, automatic target | 0.93 | 0.94 | 0.78 | 0.92 | 0.012 | 2.5 (A100) |
| Fawkes 2 (2026-09-25), mid, automatic target, JPEG 75 | 0.90 | 0.96 | 0.75 | 0.91 | 0.012 | - |
| Fawkes 2 (2026-09-25), high, automatic target | 0.96 | 0.99 | 0.85 | 0.97 | 0.017 | 3.9 (A100) |
| Fawkes 2 (2026-09-25), high, automatic target, JPEG 75 | 0.95 | 0.99 | 0.79 | 0.97 | 0.017 | - |
The original cloaks move the embeddings a little but every protected identity is still recognised.
Fawkes 2 defeats the classifier for most identities on the ResNet recognisers. On the transformer
evaluator mid / high went from 0.32 / 0.52 with three surrogates to 0.48 / 0.70 once the
ensemble gained two more transformers, and to 0.70 / 0.78 with the matched target; a fourth
evaluator, LVFace-T, is a transformer from the same family as three of the surrogates and is a
weaker test. The current modes also penalise the colour of the cloak (decision 12): the smooth
reddish and yellowish patches the earlier cloaks left on the skin are halved (the low-passed chroma
of the change inside the face box goes from 2.0 to 0.9 grey levels, 1.1 in the 2026-09-25 modes) at
equal or better protection, except for a few points on the transformer evaluator in high and under
JPEG in mid.
The 2026-09-25 modes (decision 13) add the matched automatic target and the age penalty; their rows
are the mean of two identity splits (round 17 in eval/RESULTS.md), with the automatic target instead
of the harness's random one. On a fifth evaluator, insightface's ViT-L trained on WebFace42M (shares
no data with the surrogates), they protect 0.60 / 0.88 / 0.95, and 0.34 / 0.85 / 0.92 under JPEG 75. The earlier rows cloak toward a random LFW
identity. subtle is the price of a cloak that is hard to see: on the author's photos every setting
that protected more than it also showed, and the strength at which nothing showed protected nothing.
Under 1:1 verification with the usual 0.3 cosine threshold, every cloaked photo in high fails to
match its own identity on all four evaluators, 99 percent in mid, and 96 percent in subtle (84
percent on AdaFace ViT-B). The table is for an adversary that trains on the cloaked photos and meets
clean ones; with the sides swapped (--clean-gallery: the adversary already holds clean photos and
meets a cloaked one), the 2026-09-13 cloaks give 0.80 / 0.91 / 0.55 / 0.97 in mid and 0.89 / 0.93
/ 0.71 / 1.00 in high. Each number is 50 test photos, so differences below about 0.06 are noise.
Every configuration tried on the way to these settings is in eval/RESULTS.md; the
reasoning is in docs/DECISIONS.md. See eval/README.md for the
metrics and how to run it.
From a clone of this repository, with uv (Python 3.12, locked
dependencies). PyTorch comes from one of two extras: cpu or cu128 (CUDA 12.8 wheels):
uv sync --extra cpu # or: uv sync --extra cu128
uv run fawkes -d ./imgs -t ./target --mode mid
Plain pip install torch . also works on Python 3.11 or newer. The face detector (17 MB) and the
surrogate weights (about 2.2 GB for subtle, mid and high, 500 MB for low) are downloaded
from Hugging Face on first use into fawkes/model/; python -m fawkes.models download prefetches
them.
Optional. The cloaker uses CUDA when torch can see it, else the CPU. Install with the cu128 extra
(pip users: a CUDA build of torch from pytorch.org); force
a device with --device or FAWKES_DEVICE. Without internet at run time, prefetch the weights with
python -m fawkes.models download and set HF_HUB_OFFLINE=1.
| key | model | source | licence |
|---|---|---|---|
| detector | SCRFD-10GF | InsightFace | non-commercial research |
| age penalty, target pool | genderage | InsightFace | non-commercial research |
| arcface_r100 | ArcFace IR-100, MS1MV3 | InsightFace arcface_torch | non-commercial research |
| adaface_ir101 | AdaFace IR-101, WebFace12M | CVLface | follows WebFace12M (research) |
| lvface_b | LVFace-B, Glint360K | ByteDance LVFace | non-commercial research |
| lvface_l | LVFace-L (ViT-L), Glint360K | ByteDance LVFace | non-commercial research |
| lvface_s | LVFace-S (ViT-S), Glint360K | ByteDance LVFace | non-commercial research |
| evaluators | w600k_r50, glintr100, AdaFace ViT-B, LVFace-T, ViT-L WebFace42M | InsightFace, CVLface, LVFace | research |
| held-out age judge (evaluation only) | MiVOLO v2 | MiVOLO, ONNX export | Apache-2.0 |
uv sync --extra cpu --extra eval
uv run pytest
Tests that need the surrogate weights run only when they are already in fawkes/model/. Tests that
need real photos run when FAWKES_TEST_IMAGES points to a directory of photos containing faces.
To protect a class in a dataset, move that label's images to a separate directory and run Fawkes on
it with --debug. If the images are already cropped and aligned to the 112x112 ArcFace template,
add --no-align. Keep the evaluators in eval/harness.py disjoint from the surrogates you cloak
with, or the numbers mean nothing.
@inproceedings{shan2020fawkes,
title={Fawkes: Protecting Personal Privacy against Unauthorized Deep Learning Models},
author={Shan, Shawn and Wenger, Emily and Zhang, Jiayun and Li, Huiying and Zheng, Haitao and Zhao, Ben Y},
booktitle={Proc. of {USENIX} Security},
year={2020}
}
