optifluence is the research codebase for OptiFluence: Principled Design of Privacy Canaries (ICML 2026).
@inproceedings{
yaghini2026optifluence,
title={OptiFluence: Principled Design of Privacy Canaries},
author={Mohammad Yaghini and Michael Aerni and Junrui Zhang and Nicolas Papernot and Florian Tram{\`e}r},
booktitle={Forty-third International Conference on Machine Learning},
year={2026},
url={https://openreview.net/forum?id=428khNRrGI}
}-
Install uv, then install all dependencies (Python version and packages are pinned by
pyproject.toml/uv.lock):uv sync
-
Create your environment file:
cp template.env .env
Set
DATA_ROOTto the directory where datasets should live (defaults tosrc/utils/dataif unset). MNIST, CIFAR-10, and CIFAR-100 are downloaded automatically on first use. HAM10000 must be downloaded manually into$DATA_ROOT/HAM10000/(containingHAM10000_images_part_1/,HAM10000_images_part_2/, andHAM10000_metadata.csv), either from the Harvard Dataverse or via Kaggle:kaggle datasets download -d kmader/skin-cancer-mnist-ham10000. -
If you are running on a Slurm cluster, you may need an account for
sbatch. The submit scripts add the#SBATCH --accountline only when this is set:export SLURM_ACCOUNT=<your-allocation>
Each dataset folder under src/experiments/ contains the id, mislabeled, adversarial, IF-Init, and OptiFluence canary experiments, plus ablations for CIFAR-10 and MNIST. We provide bash scripts that run all experiments; run each step in order and wait for its jobs to finish (squeue -u $USER) before launching the next:
cd src/experiments/<dataset> # mnist, cifar100, cifar10_resnet9, cifar10_ema, or ham10k
./submit_0_preselection.sh # step 0: influence-based canary preselection (IF-Init)
./submit_1_optimize.sh # step 1: optimize canaries (baseline canaries skip this step)
./submit_2_init_canaries.sh # step 2: initialize canaries
./submit_3_train_eval.sh # step 3: train target/shadow models
./submit_4_attack.sh # step 4: LiRA membership inference attackNotes:
- Step 0 writes the ranked canary indices to
preselection/canary_selection.json; steps 1-3 read the top-k indices from this file for theIF-InitandOptiFluenceexperiment groups (seed i uses the i-th index). cifar10_emareusescifar10_resnet9/preselection/canary_selection.json.- Step 3 submits one array job per experiment dir and is resumable: rerun the script after failures or timeouts and completed models are skipped.
- Step 4 writes attack results to
attack_results.npzinside each experiment directory. - To plot the results, see
examples/plots.ipynb.
The dp/, transferability/, and full_base_attack/ folders reuse canaries from the main experiments instead of optimizing their own, so steps 0-2 are replaced by a single copy script:
cd src/experiments/<experiment> # dp/mnist, dp/cifar10, transferability/mnist,
# transferability/cifar10, or full_base_attack
./copy_canaries.sh # copy canaries from the main experiments
./submit_3_train_eval.sh # train target/shadow models
./submit_4_attack.sh # LiRA membership inference attackRun the corresponding main experiment (e.g. mnist or cifar10_resnet9) through step 2 first, since copy_canaries.sh reads its canary files and submit_3_train_eval.sh reads its preselection/canary_selection.json.
dp/: the DP-SGD sweep; eachOptiFluence_<i>variant differs only in the noise multiplier in itsconfig.json(generate_eps.pymaps target epsilons to noise multipliers).transferability/: the same canary attacked across model architectures (CIFAR-10) or MLP widths (MNIST).full_base_attack/: ablation withsample_non_canaries=false, i.e. models train on the full non-canary pool instead of 50-50 splits.
All commands are run from the repository root with PYTHONPATH=src.
PYTHONPATH=src uv run python -m eval.eval_select \
--dir src/experiments/cifar10_resnet9/preselection \
--num_models 5This step is only needed for optimized canaries.
JAX_PLATFORMS=cuda PYTHONPATH=src uv run python -m eval.eval_optimize \
--dir src/experiments/cifar10_resnet9/OptiFluence_0 \
--canary_indices 0 --manual_canary_selection <CANARY_IDX>JAX_PLATFORMS=cuda PYTHONPATH=src uv run python -m eval.generate_baseline_canaries \
--dir src/experiments/cifar10_resnet9/OptiFluence_0 \
--manual_canary_selection <CANARY_IDX>The --model-indices range is end-exclusive and must cover all target + shadow models; e.g., for 1000 target + 128 shadow models, use --model-indices 0-1128.
JAX_PLATFORMS=cuda PYTHONPATH=src uv run python -m eval.eval_train \
--resume --no-store-models \
--dir src/experiments/cifar10_resnet9/OptiFluence_0 \
--model-indices <START_IDX>-<END_IDX> \
--manual_canary_selection <CANARY_IDX>PYTHONPATH=src uv run python -m eval.eval_attack \
--dir src/experiments/cifar10_resnet9/OptiFluence_0Results are written to attack_results.npz in the experiment directory.
Parts of this codebase are adapted from misleading-privacy-evals (attack utilities and evaluation design), CleverHans (adversarial example generation), and hlb-CIFAR10 (fast CIFAR training used for influence computation).
This project is licensed under the MIT License.