Find the defect without ever being shown one. Train only on good images of an industrial part, then flag -- and localise -- whatever departs from normal. A naive reconstruction autoencoder set head-to-head against an embedding memory bank (PatchCore-lite), on an AMD GPU via ROCm.
Metal nuts and screws with real defects (left), the model's anomaly heatmap (middle), and the ground-truth mask (right). The heat lands on the defect — from a backbone that was never shown a single defect, scoring by distance to remembered good patches.
Real inspection problems -- worn or cracked automotive parts, say -- share an awkward shape: good examples are everywhere, and every failure is different. Collecting a labelled set of every possible defect is hopeless. So you flip the problem: learn what normal looks like from good parts alone, and treat anything far from normal as a candidate defect. This is unsupervised industrial anomaly detection, and it's the same family of ideas behind medical screening models that learn healthy tissue and flag the rest.
There's no open dataset of worn car parts, so this lab uses the field's standard
benchmark -- MVTec AD --
starting with two metallic categories, metal_nut and screw, which are the
closest public stand-in for automotive parts and come with per-pixel defect
masks so we can score where the model looks, not just whether it fires.
Two methods, deliberately contrasted:
- Baseline -- reconstruction autoencoder. Learn to rebuild good images; wherever the rebuild is poor at test time, call it anomalous. Intuitive, and instructive precisely because it underperforms.
- The strong one -- embedding memory bank (PatchCore-lite). Push every good image through a frozen, pretrained CNN and store its patch embeddings in a memory bank. Score a test patch by its distance to the nearest normal patch. No weights are trained -- it's embeddings + nearest-neighbour search, the same machinery as metric learning, now pointed at defects. It also yields a clean anomaly heatmap.
Built to be learned from. Every module carries a didactic docstring, the
STUDY_GUIDE.mdruns a predict -> run -> check loop of experiments, andnotebooks/estudo_deteccao_defeito.ipynbis a fill-in-the-blank walkthrough with thesrc/package as the answer key.
| Category | Method | Image AUROC | Pixel AUROC | PRO | Notes |
|---|---|---|---|---|---|
| metal_nut | Autoencoder (baseline) | 0.341 | 0.729 | 0.362 | max-error score collapses below chance |
| metal_nut | PatchCore-lite | 0.992 | 0.964 | 0.927 | frozen backbone, no training |
| screw | Autoencoder (baseline) | 0.875 | 0.879 | 0.493 | scratches localise poorly (low PRO) |
| screw | PatchCore-lite | 0.920 | 0.990 | 0.954 | frozen backbone, no training |
# 1. Environment (Python 3.12 for the torch backend; core math runs on 3.10+).
python3.12 -m venv .venv && source .venv/bin/activate
pip install -e '.[dev]'
# 2. PyTorch + torchvision for your AMD GPU -- from the ROCm index, NOT PyPI.
# See requirements-torch-rocm.txt for the /tmp and gfx-override caveats.
pip install --index-url https://download.pytorch.org/whl/rocm6.4 torch torchvision
# 3. Data (one MVTec category), fit, evaluate.
python scripts/download_data.py --category metal_nut
python scripts/fit_memory_bank.py --category metal_nut
python scripts/train_autoencoder.py --category metal_nut
python scripts/compare.py --category metal_nut
# 4. Interactive demo.
streamlit run app/streamlit_app.pyTests run without the dataset or a GPU -- they use small synthetic fixtures:
pytestsrc/image_anomaly_lab/ backbones, detectors (autoencoder + memory_bank), evaluation
scripts/ download, fit, train, compare -- each a small CLI
app/streamlit_app.py upload -> heatmap overlay + score + pass/fail verdict
notebooks/ fill-in-the-blank study notebook
docs/GUIA_ANOMALIA.md study diary (Portuguese)
STUDY_GUIDE.md predict -> run -> check experiments
Greedy coreset subsampling, PaDiM (per-position Gaussian + Mahalanobis), the full 15-category sweep, and backbone fine-tuning are left as extensions.
GNU AGPL-3.0-or-later -- see LICENSE. Copyright (c) 2026 Flavio Manoel Santos Hemerli.
