Official code for the paper:
LEAST: Loss Ensemble Style Transfer against Arbitrary Style Transfer Sunghwan Park, Jongseong Kim, Byunghoon Oh, Yohan Hwang, Jaewoo Lee, Junho Hong Human-centric Computing and Information Sciences (HCIS), Vol. 16, 2026. DOI: 10.22967/HCIS.2026.16.059
LEAST is a proactive protection method that shields an artist's work from unauthorized arbitrary style transfer (AST). It adds an imperceptible adversarial perturbation to a style image so that any off-the-shelf AST model which tries to imitate it produces a garbled, stylistically broken result.
Its core idea is a loss ensemble that simultaneously attacks the three major mathematical definitions of "style" inside the shared VGG-19 feature space — feature statistics (mean/std), Gram-matrix correlations, and raw feature maps — optimized with a full-spectrum PGD attack that applies no frequency constraint. This lets LEAST disrupt both low-frequency style components (e.g. the feature mean that high-frequency-only attacks cannot touch) and high-frequency texture components at once, yielding strong protection and state-of-the-art robustness to JPEG compression (97.5% retention).
This is a focused, lightweight reproduction of the LEAST method itself — not the full benchmark suite from the paper. The baseline protection methods (NSP, LAACA, SFA) that LEAST is compared against are intentionally not included.
Shipped here:
| Component | Included |
|---|---|
| Protection | LEAST (the proposed method) |
| AST targets | AdaIN, Gatys (VGG-based, no external repos) |
| Defenses | JPEG compression, Gaussian blur |
| Metrics | PSNR, SSIM, LPIPS |
| Experiments | Protection Performance, Image Damage, Robustness, Ablations |
The transformer-based targets from the paper (SANet, EFDM, StyTr², S2WAT) rely on third-party repositories and large weight files, so they are omitted to keep this release self-contained. Every experiment that is AdaIN/Gatys-based — including Table 1, Table 2, and Table 3 — is fully reproducible here.
# 1. Environment
conda create -n least python=3.12 -y
conda activate least
# 2. PyTorch (CUDA 12.1 build; experiments used torch 2.5.1 on an RTX 3090)
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121
# 3. Remaining dependencies
pip install -r requirements.txtLEAST and the AdaIN target share a normalised VGG-19 encoder; AdaIN also needs its decoder. Both are fetched from the official pytorch-AdaIN release:
bash scripts/download_weights.shThis populates weights/ with vgg_normalised.pth and adain_decoder.pth
(checksums are verified automatically). The Gatys target needs no weights.
The paper uses 160 style images — the 16 most frequent style classes of the
huggan/wikiart dataset, 10 images each:
pip install datasets # only needed for this step
python scripts/prepare_wikiart_dataset.pyThis writes data/style/wikiart/style_<id>_<idx>.jpg (seed = 42). The two
content images from the paper (lenna.jpg portrait, kbo.jpg landscape) are
already included under data/content/.
Protect a single target/dataset and measure protection performance:
python run_experiment.py \
--experiment protection_performance \
--nst AdaIN --protection LEAST \
--style-dir data/style/wikiartOr drive everything from a config file:
python run_experiment.py --config configs/protection_performance.yaml--experiment all runs protection-performance, image-damage, and robustness in
sequence. Use --device cpu or --image-size 256 if you hit GPU memory limits.
All commands below use the 160-image WikiArt set (--style-dir data/style/wikiart)
and the two paper content images.
| Paper result | Command |
|---|---|
| Table 1 — Image damage (Iₛ vs I_p) | python run_experiment.py --experiment image_damage --protection LEAST --style-dir data/style/wikiart |
| Protection perf. (AdaIN, Fig 4/5) | python run_experiment.py --experiment protection_performance --nst AdaIN --protection LEAST --style-dir data/style/wikiart |
| Robustness — JPEG (Fig 2) | python run_experiment.py --experiment robustness --nst AdaIN --protection LEAST --robustness JPEG --style-dir data/style/wikiart |
| Robustness — Gaussian blur (Fig 2) | python run_experiment.py --experiment robustness --nst AdaIN --protection LEAST --robustness GaussianBlur --style-dir data/style/wikiart |
| Table 2 — Loss-ensemble ablation | python run_ablation_study.py --nst AdaIN --style-dir data/style/wikiart |
| Table 3 — Frequency ablation | python run_freq_ablation.py --nst AdaIN --style-dir data/style/wikiart |
Results are written as JSON to results/. Each file ends with an "average"
summary entry containing the mean ± std of every metric.
| Result | LPIPS | PSNR (dB) | SSIM |
|---|---|---|---|
| Image damage — Iₛ vs I_p (Table 1) | 0.476 ± 0.150 | 25.21 ± 0.35 | 0.611 ± 0.113 |
| Loss ensemble F+G+S on AdaIN (Table 2) | 0.583 ± 0.054 | 12.82 ± 0.92 | 0.331 ± 0.041 |
| Full-spectrum on AdaIN (Table 3) | 0.583 ± 0.054 | 12.82 ± 0.92 | 0.331 ± 0.041 |
Small deviations are expected across GPU/driver/PyTorch versions.
LEAST maximizes a composite loss over the frozen VGG-19 features at layer
ReLU4_1, Φ(I):
L_total = λ₁ · L_stats + λ₂ · L_gram + λ₃ · L_feat
- L_stats — pushes the channel-wise mean/std of
Φ(I_p)away fromΦ(I_s)(attacks AdaIN / EFDM / LAACA, the low-frequency "mean" component). - L_gram — maximizes the distance between Gram matrices (attacks the Gatys texture/correlation definition of style).
- L_feat — maximizes MSE while minimizing cosine similarity of the raw feature maps (general disruption, inspired by NSP).
The perturbation δ (with ‖δ‖_∞ ≤ ε) is optimized by full-spectrum PGD
— the entire sign gradient is used with no frequency filtering:
δ_{t+1} = Clip_ε( δ_t + α · sign( ∇_δ L_total(δ_t) ) )
Default hyperparameters (see models/protection/least.py): ε = 16/255,
T = 100 steps, α = ε/10. The per-loss weights default to values that balance
the three gradient magnitudes during PGD, consistent with the paper's
equal-weighting rationale.
The ablation flags (use_feature, use_gram, use_stats, freq_mode) exposed
by the LEAST class are what run_ablation_study.py and run_freq_ablation.py
sweep to produce Tables 2 and 3.
LEAST/
├── run_experiment.py # main entry: protection_performance / image_damage / robustness / all
├── run_ablation_study.py # loss-ensemble ablation (Table 2)
├── run_freq_ablation.py # frequency ablation (Table 3)
├── run_wikiart_experiments.py # batch driver over the WikiArt set
├── configs/ # ready-to-run YAML configs
├── scripts/
│ ├── download_weights.sh # fetch vgg_normalised.pth + adain_decoder.pth
│ └── prepare_wikiart_dataset.py
├── models/
│ ├── nst/ # AST targets: AdaIN, Gatys
│ ├── protection/least.py # >>> LEAST <<<
│ └── robustness/ # JPEG, Gaussian blur
├── metrics/ # PSNR, SSIM, LPIPS
├── experiments/ # experiment runners
├── utils/ # registry, config, image + logging helpers
├── data/
│ ├── content/ # lenna.jpg, kbo.jpg (included)
│ └── style/wikiart/ # filled by prepare_wikiart_dataset.py
└── weights/ # filled by download_weights.sh
The framework uses a registry pattern: models self-register via decorators
(@PROTECTION_REGISTRY.register("LEAST"), etc.) and are discovered on import.
To add a new AST target, drop a NSTModel subclass in models/nst/, register
it, and import it in models/nst/__init__.py.
@article{park2026least,
title = {LEAST: Loss Ensemble Style Transfer against Arbitrary Style Transfer},
author = {Park, Sunghwan and Kim, Jongseong and Oh, Byunghoon and
Hwang, Yohan and Lee, Jaewoo and Hong, Junho},
journal = {Human-centric Computing and Information Sciences},
volume = {16},
year = {2026},
doi = {10.22967/HCIS.2026.16.059}
}The AdaIN target and the normalised VGG-19 weights are based on
naoto0804/pytorch-AdaIN (MIT).
The style images are sampled from the
huggan/wikiart dataset.
Released under the MIT License.
