PILAR
Code and reference results for Pyramidal Inhibitory Lightweight Autoassociative Reconstruction for Cost-Constrained Visual Anomaly Detection.
Published in Discover Artificial Intelligence (2026).
PILAR learns to reconstruct normal images or frozen pretrained features using a compact pyramidal encoder, lateral inhibition, a spatial bottleneck, and a reconstruction decoder. Anomaly scores are reconstruction residuals. Feature-PILAR-FCN uses ResNet18 in both training and inference; only the PILAR heads are trained.
This repository reproduces the paper's MVTec AD and VisA experiments, full-category
MVTec ablations, and complementary image and RGB reconstruction experiments.
The Python package is named lipnet; its models implement PILAR.
Code availability
This repository distributes the source code accompanying the published PILAR article. No trained checkpoints or dataset images are included. To run inference, first train a category-specific model with the commands below, or use your own compatible checkpoint. This release is not a hosted inference service.
- Main code repository: bjtf/PILAR on GitHub
- Download: pilar-source.zip, containing the Python package, experiment scripts, configurations, tests, reproduction guides and tabular reference results.
- Source version:
06eef17. The archive is a fixed snapshot; GitHub remains the main development repository. - Integrity: SOURCE_MANIFEST.json records the source commit and file hashes.
Download the archive using the link above, then extract it:
unzip pilar-source.zip
cd PILAR
Alternatively, obtain the same source version from GitHub:
git clone https://github.com/bjtf/PILAR.git
cd PILAR
git checkout 06eef17fc14a2e870f82d5ea297dcd1efcc3d897
Installation
Use Python 3.12 for the paper environment:
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements-paper.txt -e '.[test]'
python -m unittest discover -s tests -v
python analysis/verify_reference_results.py
requirements-paper.txt records the versions used by the main industrial
experiments. requirements.txt provides the separately tested compatibility
environment. See REPRODUCIBILITY.md for environment,
checkpoint, and evaluation details. The first feature experiment downloads
torchvision's ImageNet-1K V1 ResNet18 weights if they are not already cached.
Industrial experiments
Obtain MVTec AD and VisA under their original terms and keep their official layouts:
data/mvtec_ad/
bottle/train/good/...
bottle/test/good/...
bottle/test/<defect>/...
bottle/ground_truth/<defect>/...
...
data/visa/
split_csv/1cls.csv
candle/Data/Images/Normal/...
candle/Data/Images/Anomaly/...
candle/Data/Masks/Anomaly/...
...
The main commands train ten epochs per category, with input size 512×512, batch size 8, and five seeds. Training uses only normal images; evaluation uses the final checkpoint and the official test split.
python scripts/reproduce_paper.py \
--experiment mvtec --data-root data/mvtec_ad \
--device mps --output-dir runs/mvtec
python scripts/reproduce_paper.py \
--experiment visa --data-root data/visa \
--device mps --output-dir runs/visa
Use --device cuda for an NVIDIA GPU or --device cpu for CPU execution.
Device selection is explicit. Results may vary across hardware and library
versions; the reference experiments used Apple MPS.
The MVTec component ablations cover all 15 categories at seed 42:
python scripts/reproduce_paper.py \
--experiment mvtec-ablation --data-root data/mvtec_ad \
--device mps --output-dir runs/mvtec_ablation
This trains four alternatives: no inhibition, no hard residual term, layer 2 only, and layer 3 only. Compare them with the seed-42 result from the main MVTec campaign; that reference need not be trained a second time. There is no test-based checkpoint selection or hyperparameter search in these commands.
Each run writes resolved configuration and provenance, complete-epoch training
checkpoints, a final inference export, per-image scores, evaluation maps, and
category metrics. The campaign also writes category_metrics.csv,
image_scores.csv, and summary.json. See the reproduction guide for resuming
an interrupted run and evaluating an export without training.
Reference results
All values below are percentages, computed as a category macro within each seed and then mean ± sample standard deviation over five seeds.
| Dataset | Image-AUROC | Image-AP | Pixel-AUROC | AUPRO@30 |
|---|---|---|---|---|
| MVTec AD | 96.91 ± 0.10 | 98.86 ± 0.04 | 96.49 ± 0.04 | 92.63 ± 0.05 |
| VisA | 92.53 ± 0.07 | 92.41 ± 0.13 | 97.84 ± 0.04 | 90.30 ± 0.14 |
RESULTS.md maps the experiments to the reference data, including all category/seed metrics and 19,435 industrial image scores. The verifier checks completeness and recomputes image AUROC/AP from these scores.
To regenerate screening curves and the 73-subtype MVTec analysis:
python analysis/analyze_mvtec_feature_pilar_subtype_review_budget.py \
--output-dir results/generated/review_budget
To analyze a reproduced campaign, add --scores runs/mvtec/image_scores.csv
or the corresponding VisA file. Ranking ties use expected random ordering
within the tied block, without label-based tie breaking.
Inference and timing
Inference loads the trained heads, ResNet weights, and normal-training score statistics from a final export:
import torch
from lipnet.inference import PilarDetector
checkpoint = (
"runs/mvtec/mvtec/main/seed_42/details/wide64/hard_0p1x1/topk_0p01/"
"model_bottle_layer2+layer3_hard0p1x1_zscore.pt"
)
model = PilarDetector(checkpoint, device="mps")
rgb = torch.rand(1, 3, 512, 512) # CPU float32, RGB in [0, 1]
scores, maps = model.predict(rgb)
Measure the paper's PILAR timing protocol on completed seed-42 exports:
python scripts/benchmark_pilar.py \
--run runs/mvtec/mvtec/main/seed_42 --data-root data/mvtec_ad \
--output runs/timing --device mps
Run this without concurrent training. The timing scope starts at a resized CPU RGB tensor and ends at the score and 256×256 map on CPU. It includes normalization, transfers, feature extraction, reconstruction, and scoring; it excludes disk reads and metric calculation. Hardware-dependent measurements should be compared only under a shared protocol on the same device.
To regenerate the paper's fixed qualitative examples from the completed seed-42 MVTec run:
python scripts/generate_mvtec_qualitative.py \
--run runs/mvtec/mvtec/main/seed_42 --data_root data/mvtec_ad \
--output_dir runs/qualitative
This uses the final evaluation maps and writes PNG/PDF figures and an example selection manifest. It does not retrain a detector or select a different epoch.
Complementary experiments
Commands and the fixed configurations for MNIST, Fashion-MNIST, CIFAR-10, whole-image RGB, and patchwise RGB appear in docs/SUPPLEMENTARY_EXPERIMENTS.md. docs/ARTIFACT_SCOPE.md describes the files and external data dependencies.
Citation
If you use PILAR or this code in your research, please cite the published article:
Fernandes, B. J. T. Pyramidal inhibitory lightweight autoassociative reconstruction for cost-constrained visual anomaly detection. Discover Artificial Intelligence 6, 1829 (2026). https://doi.org/10.1007/s44163-026-02671-5
@article{Fernandes2026PILAR,
author = {Fernandes, Bruno J. T.},
title = {Pyramidal inhibitory lightweight autoassociative reconstruction for cost-constrained visual anomaly detection},
journal = {Discover Artificial Intelligence},
year = {2026},
volume = {6},
number = {1},
pages = {1829},
doi = {10.1007/s44163-026-02671-5},
url = {https://doi.org/10.1007/s44163-026-02671-5}
}
Citation metadata is also available in CITATION.cff. The PILAR source code is distributed under the MIT License. Datasets and externally downloaded backbone weights retain their respective terms. This repository does not distribute either dataset images or pretrained weights.