[ArXiv]
Official PyTorch implementation of Safe Denoiser, as presented in our paper:
Training-Free Safe Denoisers For Safe Use of Diffusion Models (NeurIPS2025)
Mingyu Kim*1, Dongjun Kim*2,
Amman Yusuf1, Stefano Ermon2
and Mijung Park1
1UBC CS, 2Stanford CS
(*: Equally Contributed)
-
NudityTask (Ring-A-bell, UnlearnDiffAtk, MMA-Diffusion). -
Inappropriate Prob.Task (CoPro). - Negative Datapoints for {
Nudity,Inappropriate Prob.}.
- (Sep. 2025) Our paper has been accepted in NeurIPS 2025.
# create conda environment
conda create --name SafeDenoiser python=3.10
# activate env
conda activate SafeDenoiser
# install pytorch >= 2.10 (e.g cu121)
pip install torch==2.1.0+cu121 torchvision==0.16.0+cu121 --extra-index-url https://download.pytorch.org/whl/cu121
# install packages
pip install -r requirements.txtThis implementation utilizes the code bases of SAFREE.
For evaluation, this repository uses pretrained checkpoints from the following projects:
For convenience, we provide all required checkpoints as a single compressed archive.
- Download: Google Drive folder
Place pretrained.tar.gz at the repository root, then run:
mkdir -p pretrained
tar -xzvf pretrained.tar.gz -C pretrainedExpected directory structure:
pretrained/
├── classifier_model.onnx
├── diffusers-nudity-ESDu1-UNET.pt
├── diffusers-nudity-RECE-UNET.pt
├── Q16_prompts_finetuned.pt
├── Q16_prompts_official.p
├── Q16_prompts.p
├── ResNet18_0.945223.pth
├── sac+logos+ava1-l14-linearMSE.pth
└── vehicle_yolov5_best.pt
For the nudity task, we provide 515 nudity images generated by SD-v1.4, corresponding to the sexual category in I2P.
For the inappropriate task, we provide 3,000 images generated by SD-v1.4, covering all categories in I2P.
For convenience, the negative datapoints are released as two separate archives:
nudity.tar.gzinappropriate.tar.gz
Download: Google Drive folder
Place nudity.tar.gz and inappropriate.tar.gz under the repository root, then run:
# Extract inappropriate datapoints
tar -xzvf inappropriate.tar.gz -C datasets
# Extract nudity datapoints
tar -xzvf nudity.tar.gz -C datasetsExpected directory structure:
datasets/
├── ann_graham_lotz/
├── coco30k_10k_img/
├── inappropriate/
│ └── i2p/
│ ├── 0_violence-self-harm.png
│ ├── 1_self-harm.png
│ ├── 2_self-harm.png
│ ├── 3_self-harm.png
│ ├── 4_self-harm.png
│ └── ...
├── munch/
├── nudity/
│ └── i2p_sexual/
│ ├── 156_sexual-self-harm.png
│ ├── 203_shocking-sexual-harassment.png
│ ├── 245_shocking-sexual.png
│ ├── 614_shocking-sexual.png
│ ├── 643_shocking-sexual.png
│ └── ...
├── coco_30k_10k.csv
├── coco_30k.csv
├── CoPro_balanced_1k.csv
├── CoPro_balanced_10k.csv
├── i2p.csv
├── mma-diffusion-nsfw-adv-prompts.csv
├── nudity-ring-a-bell.csv
└── nudity.csv
Some experiments use a precomputed repellency projection reference (repellency_proj_ref.pt) to avoid recomputing it at runtime.
We provide these cache files as a Google Drive folder.
Download: Google Drive folder
Place the downloaded folder under the repository root so that the following paths exist:
caches/
├── sd/
│ ├── ann/
│ │ └── repellency_proj_ref.pt
│ ├── i2p/
│ │ └── repellency_proj_ref.pt
│ ├── i2p_sexual/
│ │ ├── repellency_proj_ref.pt
│ │ └── repellency_noisy_proj_ref_for_beta.pt
│ └── munch/
│ └── repellency_proj_ref.pt
└── sdv3/
└── i2p_sexual/
└── repellency_proj_ref.pt
For example, configs/nudity/safe_denoiser.yaml points to the cached reference as follows:
repellency:
proj_ref_path: "caches/sd/i2p_sexual/repellency_proj_ref.pt"
cache_proj_ref: TrueThis section provides minimal commands to reproduce the main evaluation runs. All runs assume that you have already downloaded and placed:
pretrained/checkpoints (see Checkpoints),- negative datapoints under
datasets/(see Negative Datapoints), - cached projection references under
caches/(optional but recommended; see Cached repellency projection references).
The script reads prompts from --data (CSV), generates images with the selected safety method (--erase_id), and evaluates nudity using NudeNet (--nudenet-path).
Outputs (generated images and logs/metrics) are saved to --save-dir.
--data: CSV file containing prompts for evaluation (e.g., Ring-A-Bell).--category: evaluation task type (e.g.,nudity).--task_config: task-specific config for Safe Denoiser / repellency settings (YAML).--erase_id: which safety method to run (e.g.,safree_neg_prompt_rep_threshold_time).--config: base config for prompt handling / negative prompt setup (JSON).--num_inference_steps: diffusion sampling steps.--guidance_scale: classifier-free guidance scale (CFG).--safe_level: safety strength for SLD-style baselines (kept for compatibility; only used by relevant methods).--nudenet-path,--nudity_thr: NudeNet checkpoint path and nudity threshold for evaluation.--save-dir: output directory.
This script evaluates the nudity task on different prompt sets by switching --data.
Supported prompt sets
- Ring-A-Bell:
datasets/nudity-ring-a-bell.csv - UnlearnDiffAtk:
datasets/nudity.csv - MMA-Diffusion:
datasets/mma-diffusion-nsfw-adv-prompts.csv
# Example: Ring-A-Bell
python run_nudity.py \
--nudenet-path=pretrained/classifier_model.onnx \
--nudity_thr=0.6 \
--num_inference_steps=50 \
--config=configs/base/vanilla/safree_neg_prompt_config.json \
--safe_level=MEDIUM \
--data=datasets/nudity-ring-a-bell.csv \
--category=nudity \
--task_config=configs/nudity/safe_denoiser.yaml \
--save-dir=results/safe_denoiser/sdv1/nudity \
--erase_id=safree_neg_prompt_rep_threshold_timeThis script evaluates the inappropriate probability task on CoPro prompts by setting --category=all and switching --data.
Supported prompt sets
- CoPro:
datasets/CoPro_balanced_10k.csv
# Example: CoPro (10k balanced)
python run_copro.py \
--nudenet-path=pretrained/classifier_model.onnx \
--nudity_thr=0.6 \
--num_inference_steps=50 \
--config=configs/base/vanilla/safree_neg_prompt_config.json \
--safe_level=MEDIUM \
--data=datasets/CoPro_balanced_10k.csv \
--category=all \
--task_config=configs/copro/safe_denoiser.yaml \
--save-dir=results/safe_denoiser/sdv1/copro \
--erase_id=safree_neg_prompt_rep_time \
--guidance_scale=7.5This run generates images from COCO-30k prompts by setting --category=coco.
It uses the same base setup as the nudity runs (same --config, sampling steps, and safety method), but switches the task to COCO prompts.
python run_coco30k.py \
--nudenet-path=pretrained/classifier_model.onnx \
--nudity_thr=0.6 \
--num_inference_steps=50 \
--config=configs/base/vanilla/safree_neg_prompt_config.json \
--safe_level=MEDIUM \
--category=coco \
--task_config=configs/coco/safe_denoiser.yaml \
--save-dir=results/safe_denoiser/sdv1/coco \
--erase_id=safree_neg_prompt_rep_threshold_time \
--guidance_scale=7.5This run generates images from the memorized prompt set for Ann Graham Lotz by setting
--category=artists-AnnGrahamLotz. Outputs are saved to the directory specified by --save-dir.
python run_ann_graham.py \
--nudenet-path=pretrained/classifier_model.onnx \
--nudity_thr=0.6 \
--num_inference_steps=50 \
--config=configs/base/vanilla/safree_neg_prompt_config.json \
--safe_level=MEDIUM \
--category=artists-AnnGrahamLotz \
--task_config=configs/ann_graham/safe_denoiser.yaml \
--save-dir=results/safe_denoiser/sdv1/ann_graham_lotz \
--erase_id=std_rep \
--seed=42 \
--guidance_scale=3.5This run generates images from the memorized prompt set for The Scream by setting
--category=artists-Munch. It uses the Ring-A-Bell prompt list (datasets/nudity-ring-a-bell.csv) and saves outputs to the directory specified by --save-dir.
python run_munch.py \
--nudenet-path=pretrained/classifier_model.onnx \
--nudity_thr=0.6 \
--num_inference_steps=50 \
--config=configs/base/vanilla/safree_neg_prompt_config.json \
--safe_level=MEDIUM \
--data=datasets/nudity-ring-a-bell.csv \
--category=artists-Munch \
--task_config=configs/munch/safe_denoiser.yaml \
--save-dir=results/safe_denoiser/sdv1/munch \
--erase_id=std_rep \
--seed=42 \
--guidance_scale=2.0This run evaluates the nudity task on Stable Diffusion 3 by switching --model_id and using the SDv3 task config.
# Example: Ring-A-Bell (SD-v3)
python run_nudity_sdv3.py \
--nudenet-path=pretrained/classifier_model.onnx \
--nudity_thr=0.6 \
--num_inference_steps=50 \
--config=configs/base/vanilla/safree_neg_prompt_config.json \
--safe_level=MEDIUM \
--data=datasets/nudity-ring-a-bell.csv \
--category=nudity \
--task_config=configs/nudity/safe_denoiser_sdv3.yaml \
--save-dir=results/safe_denoiser/sdv3/nudity \
--erase_id=safree_neg_prompt_rep_time \
--guidance_scale=2.5 \
--model_id=stabilityai/stable-diffusion-3-medium-diffusersThis run generates images from COCO-30k prompts by setting --category=coco.
It uses the SD-v3 model (--model_id) and the SDv3 task config, and saves outputs to the directory specified by --save-dir.
python run_coco30k.py \
--nudenet-path=pretrained/classifier_model.onnx \
--nudity_thr=0.6 \
--num_inference_steps=50 \
--config=configs/base/vanilla/safree_neg_prompt_config.json \
--safe_level=MEDIUM \
--data=datasets/nudity-ring-a-bell.csv \
--category=coco \
--task_config=configs/nudity/safe_denoiser_sdv3.yaml \
--save-dir=results/safe_denoiser/sdv3/coco_30k \
--erase_id=safree_neg_prompt_rep_time \
--guidance_scale=3.5 \
--model_id=stabilityai/stable-diffusion-3-medium-diffusersWe provide a simple evaluation script for COCO-30k generations that reports FID and CLIP Score.
Run:
python evaluate_coco30k_fid_clip.py --target_path <PATH_TO_GENERATED_RESULTS>--target_pathshould point to the same directory used in--save-dirduring the generation run.
# Evaluation (FID, CLIP Score)
python evaluate_coco30k_fid_clip.py \
--target_path results/safe_denoiser/sdv1/cocoWe provide a simple evaluation script for CoPro generations that reports AES Score and CLIP Score.
Run:
python evaluate_copro_aes_clip.py --target_path <PATH_TO_GENERATED_RESULTS>--target_pathshould point to the same directory used in--save-dirduring the generation run.
# Evaluation (AES, CLIP Score)
python evaluate_copro_aes_clip.py \
--target_path results/safe_denoiser/sdv1/copro@inproceedings{
kim2025trainingfree,
title={Training-Free Safe Denoisers for Safe Use of Diffusion Models},
author={Mingyu Kim and Dongjun Kim and Amman Yusuf and Stefano Ermon and Mijung Park},
booktitle={The Thirty-ninth Annual Conference on Neural Information Processing Systems},
year={2025},
url={https://openreview.net/forum?id=QQS7TudonJ}
}
We thank our anonymous reviewers for their constructive feedback, which has helped significantly improve our paper. We thank the Digital Research Alliance of Canada (Compute Canada) for its computational resources and services. M. Kim was supported by the Canada CIFAR AI Safety Catalyst grant. A. Yusuf was funded by the Canada Graduate Scholarships — Master’s program of the Natural Sciences and Engineering Research Council of Canada (NSERC). M. Park was supported in part by the Natural Sciences and Engineering Research Council of Canada (NSERC) and the Canada CIFAR AI Chairs program.