Skip to main content

Overview

Training a single-backbone PatchCore model is the fastest way to get started. This guide uses WideResNet50 as the backbone, which provides excellent performance while remaining computationally efficient.
Recommended for:
  • First-time users learning PatchCore
  • Development and experimentation
  • Production systems with speed/memory constraints
  • Achieving 99.2% AUROC on MVTec AD

Quick Start

Train PatchCore on all MVTec AD categories with recommended settings:
Complete Training Command
# Set dataset path
datapath=/path/to/mvtec

# Define all 15 MVTec categories
datasets=('bottle' 'cable' 'capsule' 'carpet' 'grid' 'hazelnut' 
          'leather' 'metal_nut' 'pill' 'screw' 'tile' 'toothbrush' 
          'transistor' 'wood' 'zipper')

# Create dataset flags
dataset_flags=($(for dataset in "${datasets[@]}"; do echo '-d '$dataset; done))

# Run training
python bin/run_patchcore.py \
  --gpu 0 \
  --seed 0 \
  --save_patchcore_model \
  --log_group IM224_WR50_L2-3_P01_D1024-1024_PS-3_AN-1_S0 \
  --log_project MVTecAD_Results \
  results \
patch_core \
  -b wideresnet50 \
  -le layer2 \
  -le layer3 \
  --faiss_on_gpu \
  --pretrain_embed_dimension 1024 \
  --target_embed_dimension 1024 \
  --anomaly_scorer_num_nn 1 \
  --patchsize 3 \
sampler \
  -p 0.1 \
  approx_greedy_coreset \
dataset \
  --resize 256 \
  --imagesize 224 \
  "${dataset_flags[@]}" \
  mvtec $datapath
Don’t forget to:
  • Set PYTHONPATH before running: export PYTHONPATH=src
  • Replace /path/to/mvtec with your actual dataset path
  • Ensure MVTec AD is properly set up (see MVTec Setup)

Command Structure

The PatchCore training command has four main sections:
Global Settings
python bin/run_patchcore.py \
  --gpu 0                    # GPU device ID (use 0 for first GPU)
  --seed 0                   # Random seed for reproducibility
  --save_patchcore_model     # Save trained model to disk
  --log_group experiment_name # Name for this experiment
  --log_project project_name  # Project folder name
  results                    # Output directory
Key Parameters:
  • --gpu: Which GPU to use (supports multi-GPU with --gpu 0 --gpu 1)
  • --seed: Controls random initialization for reproducibility
  • --save_patchcore_model: Must include to save the model for inference
  • results: Base directory where outputs are stored

Step-by-Step Training

Let’s train on a single category first, then scale to all 15:
1

Set Environment

Setup
# Navigate to repository
cd /path/to/patchcore

# Set Python path
export PYTHONPATH=src

# Verify dataset
ls /path/to/mvtec/bottle/train/good
2

Train on Single Category

Start with one category (bottle) to verify setup:
Single Category Training
datapath=/path/to/mvtec

python bin/run_patchcore.py \
  --gpu 0 --seed 0 --save_patchcore_model \
  --log_group WR50_bottle_test \
  results \
patch_core \
  -b wideresnet50 \
  -le layer2 -le layer3 \
  --faiss_on_gpu \
  --pretrain_embed_dimension 1024 \
  --target_embed_dimension 1024 \
  --anomaly_scorer_num_nn 1 \
  --patchsize 3 \
sampler -p 0.1 approx_greedy_coreset \
dataset --resize 256 --imagesize 224 -d bottle mvtec $datapath
Expected output:
Computing support features...
Subsampling...
Inferring...
instance_auroc: 1.000
full_pixel_auroc: 0.984
anomaly_pixel_auroc: 0.984
3

Scale to All Categories

Once verified, train on all 15 categories:
All Categories
datapath=/path/to/mvtec
datasets=('bottle' 'cable' 'capsule' 'carpet' 'grid' 'hazelnut' 
          'leather' 'metal_nut' 'pill' 'screw' 'tile' 'toothbrush' 
          'transistor' 'wood' 'zipper')
dataset_flags=($(for dataset in "${datasets[@]}"; do echo '-d '$dataset; done))

python bin/run_patchcore.py \
  --gpu 0 --seed 0 --save_patchcore_model \
  --log_group IM224_WR50_baseline \
  results \
patch_core -b wideresnet50 -le layer2 -le layer3 --faiss_on_gpu \
  --pretrain_embed_dimension 1024 --target_embed_dimension 1024 \
  --anomaly_scorer_num_nn 1 --patchsize 3 \
sampler -p 0.1 approx_greedy_coreset \
dataset --resize 256 --imagesize 224 "${dataset_flags[@]}" mvtec $datapath
Training will process each category sequentially. Total time: ~1-2 hours on GPU.
4

Check Results

After training completes:
View Results
# Navigate to results directory
cd results/MVTecAD_Results/IM224_WR50_baseline_0

# View summary metrics
cat results.csv

# Check saved models
ls -lh models/
Each category will have a dedicated model directory.

Understanding Output Files

After training with --save_patchcore_model, you’ll see:
Output Structure
results/
└── MVTecAD_Results/
    └── IM224_WR50_baseline_0/
        ├── models/
   ├── mvtec_bottle/
   ├── nnscorer_search_index.faiss  # Nearest neighbor index
   └── patchcore_params.pkl         # Model parameters
   ├── mvtec_cable/
   ├── mvtec_capsule/
   └── [...]
        └── results.csv                           # Performance summary
nnscorer_search_index.faiss:
  • FAISS nearest-neighbor search index
  • Contains memory bank of training features
  • Size: 50-500 MB depending on sampling percentage
patchcore_params.pkl:
  • Model configuration (backbone, layers, dimensions)
  • Small file (~1 KB)
  • Needed to load model for inference
results.csv:
  • Performance metrics for each category
  • Columns: dataset_name, instance_auroc, full_pixel_auroc, anomaly_pixel_auroc

All CLI Arguments Explained

Here’s every argument used in the training command:
--gpu
int
default:"0"
GPU device ID. Use --gpu 0 for first GPU, --gpu 1 for second, etc.
--seed
int
default:"0"
Random seed for reproducibility. Same seed = same results.
--save_patchcore_model
flag
Save trained model to disk. Required if you want to use the model later.
--log_group
string
Experiment name. Creates a subdirectory with this name in results.
--log_project
string
default:"project"
Project folder name. Organizes experiments into projects.
-b, --backbone_names
string
required
Backbone network architecture. Options:
  • wideresnet50 (recommended)
  • wideresnet101
  • resnet50, resnet101
  • See Backbones for all options
-le, --layers_to_extract_from
string
required
Which layers to extract features from. Common choices:
  • WideResNet: layer2, layer3
  • ResNet: layer2, layer3
  • DenseNet: features.denseblock2, features.denseblock3
--pretrain_embed_dimension
int
default:"1024"
Dimensionality of features from backbone layers. Standard: 1024.
--target_embed_dimension
int
default:"1024"
Final embedding dimension after aggregation. Lower = less memory.
--patchsize
int
default:"3"
Neighborhood size for local aggregation. Typical: 3 or 5.
--anomaly_scorer_num_nn
int
default:"1"
Number of nearest neighbors for anomaly scoring. Usually 1, 3, or 5.
--faiss_on_gpu
flag
Use GPU for FAISS nearest neighbor search. Faster but uses GPU memory.
-p, --percentage
float
default:"0.1"
Coreset sampling percentage (0.01 = 1%, 0.1 = 10%).
--resize
int
default:"256"
Initial resize dimension before center crop.
--imagesize
int
default:"224"
Final image size after center crop (input to backbone).
-d, --subdatasets
string
required
MVTec category names. Repeat for each category: -d bottle -d cable ...

Configuration Presets

Try these proven configurations for different use cases:
# Quick training for testing (~5-10 min/category)
python bin/run_patchcore.py --gpu 0 --seed 0 --save_patchcore_model \
  --log_group dev_fast results \
patch_core -b wideresnet50 -le layer2 -le layer3 --faiss_on_gpu \
  --pretrain_embed_dimension 1024 --target_embed_dimension 1024 \
  --anomaly_scorer_num_nn 1 --patchsize 3 \
sampler -p 0.1 approx_greedy_coreset \
dataset --resize 256 --imagesize 224 -d bottle mvtec $datapath

# Expected: ~99% AUROC, 1-2 GB model size

Monitoring Training Progress

During training, you’ll see progress output:
Training Output
Command line arguments: bin/run_patchcore.py --gpu 0 ...
Evaluating dataset [mvtec_bottle] (1/15)...
Computing support features...: 100%|████████████| 209/209 [00:45<00:00]
Subsampling...: 100%|████████████████████████| 1679/1679 [01:23<00:00]
Inferring...: 100%|██████████████████████████| 63/63 [00:12<00:00]
Computing evaluation metrics.
instance_auroc: 1.000
full_pixel_auroc: 0.984
anomaly_pixel_auroc: 0.984
Saving PatchCore data.

-----

Evaluating dataset [mvtec_cable] (2/15)...
[...continues for each category...]

Troubleshooting

Problem: GPU doesn’t have enough memory.Solutions:
  1. Reduce batch size: dataset [...] --batch_size 1 mvtec $datapath
  2. Lower image resolution: Use 224 instead of 320
  3. Reduce target embedding dimension: --target_embed_dimension 512
  4. Use CPU for FAISS: Remove --faiss_on_gpu
Problem: Python can’t find the patchcore module.Solution:
export PYTHONPATH=src
# Or run with:
env PYTHONPATH=src python bin/run_patchcore.py [...]
Problem: Training takes much longer than expected.Causes & Solutions:
  • Not using GPU: Verify with nvidia-smi, add --faiss_on_gpu
  • High sampling percentage: Use -p 0.01 instead of -p 0.1
  • Too many workers: Reduce --num_workers 4 in dataset config

Next Steps

Ensemble Models

Combine multiple backbones for 99.6% AUROC

Configuration Reference

Deep dive into every parameter

Build docs developers (and LLMs) love