Skip to content

Commit 9639244

Browse files
Merge branch 'main' into fix/utils/windows-path-support
2 parents f63b7aa + c43e552 commit 9639244

File tree

17 files changed

+249
-133
lines changed

17 files changed

+249
-133
lines changed

docs/source/markdown/get_started/anomalib.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ interfaces, and might be easier for those who would like to use anomalib off-the
5252

5353
```{literalinclude} ../../../../examples/api/01_getting_started/basic_training.py
5454
:language: python
55-
:lines: 10-34
55+
:lines: 10-53
5656
```
5757

5858
:::
@@ -61,6 +61,7 @@ interfaces, and might be easier for those who would like to use anomalib off-the
6161

6262
```{literalinclude} ../../../../examples/cli/01_getting_started/basic_training.sh
6363
:language: bash
64+
:lines: 10-33
6465
```
6566

6667
:::
@@ -81,6 +82,7 @@ Anomalib includes multiple inferencing scripts, including Torch, Lightning, Grad
8182

8283
```{literalinclude} ../../../../examples/api/01_getting_started/basic_inference.py
8384
:language: python
85+
:lines: 10-40
8486
```
8587

8688
:::
@@ -104,8 +106,9 @@ Anomalib includes multiple inferencing scripts, including Torch, Lightning, Grad
104106
:::{tab-item} API
105107
:sync: label-1
106108

107-
```{code-block} python
108-
109+
```{literalinclude} ../../../../examples/api/01_getting_started/basic_torch_inference.py
110+
:language: python
111+
:lines: 10-11
109112
```
110113

111114
:::
@@ -129,8 +132,9 @@ Anomalib includes multiple inferencing scripts, including Torch, Lightning, Grad
129132
:::{tab-item} API
130133
:sync: label-1
131134

132-
```{code-block} python
133-
135+
```{literalinclude} ../../../../examples/api/01_getting_started/basic_openvino_inference.py
136+
:language: python
137+
:lines: 10-28
134138
```
135139

136140
:::

examples/api/01_getting_started/basic_inference.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,18 @@
88
"""
99

1010
# 1. Import required modules
11-
from pathlib import Path
12-
1311
from anomalib.data import PredictDataset
1412
from anomalib.engine import Engine
15-
from anomalib.models import EfficientAd
13+
from anomalib.models import Patchcore
1614

1715
# 2. Initialize the model and load weights
18-
model = EfficientAd()
16+
model = Patchcore()
1917
engine = Engine()
2018

2119
# 3. Prepare test data
2220
# You can use a single image or a folder of images
2321
dataset = PredictDataset(
24-
path=Path("path/to/test/images"),
22+
path="path/to/test/images",
2523
image_size=(256, 256),
2624
)
2725

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Copyright (C) 2025 Intel Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
"""Getting Started with Anomalib Inference using the Python API.
5+
6+
This example shows how to perform inference on a trained model
7+
using the Anomalib Python API.
8+
"""
9+
10+
# 1. Import required modules
11+
from anomalib.deploy import OpenVINOInferencer
12+
13+
# 2. Initialize the inferencer
14+
inferencer = OpenVINOInferencer(
15+
path="/path/to/openvino/model.bin",
16+
)
17+
18+
# 4. Get predictions
19+
predictions = inferencer.predict(
20+
image="/path/to/image.png",
21+
)
22+
23+
# 5. Access the results
24+
if predictions is not None:
25+
for prediction in predictions:
26+
anomaly_map = prediction.anomaly_map # Pixel-level anomaly heatmap
27+
pred_label = prediction.pred_label # Image-level label (0: normal, 1: anomalous)
28+
pred_score = prediction.pred_score # Image-level anomaly score
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright (C) 2025 Intel Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
"""Getting Started with Anomalib Inference using the Python API.
5+
6+
This example shows how to perform inference on a trained model
7+
using the Anomalib Python API.
8+
"""
9+
10+
# TorchInferencer is a legacy inferencer. Consider using Engine.predict() instead,
11+
# which provides a more modern and feature-rich interface for model inference.

examples/api/01_getting_started/basic_training.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99

1010
# 1. Import required modules
1111
from anomalib.data import MVTecAD
12+
from anomalib.deploy import ExportType
1213
from anomalib.engine import Engine
13-
from anomalib.models import EfficientAd
14+
from anomalib.models import Patchcore
1415

1516
# 2. Create a dataset
1617
# MVTecAD is a popular dataset for anomaly detection
@@ -19,15 +20,29 @@
1920
category="bottle", # MVTec category to use
2021
train_batch_size=32, # Number of images per training batch
2122
eval_batch_size=32, # Number of images per validation/test batch
22-
num_workers=8, # Number of parallel processes for data loading
2323
)
2424

2525
# 3. Initialize the model
26-
# EfficientAd is a good default choice for beginners
27-
model = EfficientAd()
26+
# Patchcore is a good choice for beginners
27+
model = Patchcore(
28+
num_neighbors=6, # Override default model settings
29+
)
2830

2931
# 4. Create the training engine
30-
engine = Engine(max_epochs=10) # Train for 10 epochs
32+
engine = Engine(
33+
max_epochs=1, # Override default trainer settings
34+
)
3135

3236
# 5. Train the model
37+
# This produces a lightning model (.ckpt)
3338
engine.fit(datamodule=datamodule, model=model)
39+
40+
# 6. Test the model performance
41+
test_results = engine.test(datamodule=datamodule, model=model)
42+
43+
# 7. Export the model
44+
# Different formats are available: Torch, OpenVINO, ONNX
45+
engine.export(
46+
model=model,
47+
export_type=ExportType.OPENVINO,
48+
)

examples/cli/01_getting_started/basic_training.sh

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,26 @@
88
# This example shows the basic steps to train an anomaly detection model.
99

1010
# 1. Basic Training
11-
# Train a model using default configuration (recommended for beginners)
11+
# Train and test a model using default configuration on MVTecAD bottle (default category)
1212
echo "Training with default configuration..."
13-
anomalib train --model efficient_ad
13+
anomalib train --model Patchcore --data anomalib.data.MVTecAD
1414

1515
# 2. Training with Basic Customization
16-
# Customize basic parameters like batch size and epochs
16+
# Customize basic parameters like batch size and epochs.
17+
# For example `EfficientAd` requires a train batch size of 1
1718
echo -e "\nTraining with custom parameters..."
18-
anomalib train --model efficient_ad \
19-
--data.train_batch_size 32 \
20-
--trainer.max_epochs 10
19+
anomalib train --model EfficientAd --data anomalib.data.MVTecAD \
20+
--data.category hazelnut \
21+
--data.train_batch_size 1 \
22+
--trainer.max_epochs 200
2123

22-
# 3. Using a Different Dataset
23-
# Train on a specific category of MVTecAD dataset
24-
echo -e "\nTraining on MVTecAD bottle category..."
25-
anomalib train --model efficient_ad \
26-
--data.category bottle
24+
# 3. Train with config file
25+
# Train with a custom config file
26+
echo -e "\nTraining with config file..."
27+
anomalib train --config path/to/config.yaml
28+
29+
# 4. Export a trained model into OpenVINO
30+
echo .e "\nExporting model into OpenVINO..."
31+
anomalib export --model Patchcore \
32+
--ckpt_path /path/to/model.ckpt \
33+
--export_type OPENVINO

src/anomalib/metrics/__init__.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,21 @@
3030
3131
Example:
3232
>>> from anomalib.metrics import AUROC, F1Score
33-
>>> auroc = AUROC()
34-
>>> f1 = F1Score()
35-
>>> labels = torch.tensor([0, 1, 0, 1])
36-
>>> scores = torch.tensor([0.1, 0.9, 0.2, 0.8])
37-
>>> auroc(scores, labels)
33+
>>> from anomalib.data import ImageBatch
34+
>>> import torch
35+
>>> # Initialize metrics with required fields
36+
>>> auroc = AUROC(fields=["pred_score", "gt_label"])
37+
>>> f1 = F1Score(fields=["pred_score", "gt_label"], threshold=0.5)
38+
>>> # Create sample batch
39+
>>> batch = ImageBatch(
40+
... image=torch.rand(4, 3, 32, 32),
41+
... pred_score=torch.tensor([0.1, 0.9, 0.2, 0.8]),
42+
... gt_label=torch.tensor([0, 1, 0, 1])
43+
... )
44+
>>> # Calculate metrics
45+
>>> auroc(batch)
3846
tensor(1.)
39-
>>> f1(scores, labels, threshold=0.5)
47+
>>> f1(batch)
4048
tensor(1.)
4149
"""
4250

src/anomalib/metrics/aupr.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,24 @@
1212
1313
Example:
1414
>>> from anomalib.metrics import AUPR
15+
>>> from anomalib.data import ImageBatch
1516
>>> import torch
16-
>>> # Create sample data
17-
>>> labels = torch.tensor([0, 0, 1, 1]) # Binary labels
18-
>>> scores = torch.tensor([0.1, 0.2, 0.8, 0.9]) # Anomaly scores
17+
>>> # Create sample batch
18+
>>> batch = ImageBatch(
19+
... image=torch.rand(4, 3, 32, 32),
20+
... pred_score=torch.tensor([0.1, 0.2, 0.8, 0.9]),
21+
... gt_label=torch.tensor([0, 0, 1, 1])
22+
... )
1923
>>> # Initialize and compute AUPR
20-
>>> metric = AUPR()
21-
>>> aupr_score = metric(scores, labels)
22-
>>> aupr_score
23-
tensor(1.0)
24+
>>> aupr = AUPR(fields=["pred_score", "gt_label"])
25+
>>> aupr(batch)
26+
tensor(0.8750)
2427
25-
The metric can also be updated incrementally with batches:
28+
The metric can also be updated incrementally:
2629
27-
>>> for batch_scores, batch_labels in dataloader:
28-
... metric.update(batch_scores, batch_labels)
29-
>>> final_score = metric.compute()
30+
>>> for batch in dataloader:
31+
... aupr.update(batch)
32+
>>> final_score = aupr.compute()
3033
3134
Note:
3235
The AUPR score ranges from 0 to 1, with 1 indicating perfect ranking of
@@ -53,17 +56,18 @@ class _AUPR(BinaryPrecisionRecallCurve):
5356
5457
Examples:
5558
To compute the metric for a set of predictions and ground truth targets:
56-
59+
>>> from anomalib.metrics.aupr import _AUPR
60+
>>> import torch
5761
>>> true = torch.tensor([0, 1, 1, 1, 0, 0, 0, 0, 1, 1])
5862
>>> pred = torch.tensor([0.59, 0.35, 0.72, 0.33, 0.73, 0.81, 0.30, 0.05, 0.04, 0.48])
5963
60-
>>> metric = AUPR()
64+
>>> metric = _AUPR()
6165
>>> metric(pred, true)
6266
tensor(0.4899)
6367
6468
It is also possible to update the metric state incrementally within batches:
6569
66-
>>> for batch in dataloader:
70+
>>> for pred, true in dataloader:
6771
... # Compute prediction and target tensors
6872
... metric.update(pred, true)
6973
>>> metric.compute()

src/anomalib/metrics/auroc.py

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,24 @@
1212
1313
Example:
1414
>>> from anomalib.metrics import AUROC
15+
>>> from anomalib.data import ImageBatch
1516
>>> import torch
16-
>>> # Create sample data
17-
>>> labels = torch.tensor([0, 0, 1, 1]) # Binary labels
18-
>>> scores = torch.tensor([0.1, 0.2, 0.8, 0.9]) # Anomaly scores
17+
>>> # Create sample batch
18+
>>> batch = ImageBatch(
19+
... image=torch.rand(4, 3, 32, 32),
20+
... pred_score=torch.tensor([0.1, 0.2, 0.8, 0.9]),
21+
... gt_label=torch.tensor([0, 0, 1, 1])
22+
... )
1923
>>> # Initialize and compute AUROC
20-
>>> metric = AUROC()
21-
>>> auroc_score = metric(scores, labels)
22-
>>> auroc_score
24+
>>> auroc = AUROC(fields=["pred_score", "gt_label"])
25+
>>> auroc(batch)
2326
tensor(1.0)
2427
25-
The metric can also be updated incrementally with batches:
28+
The metric can also be updated incrementally:
2629
27-
>>> for batch_scores, batch_labels in dataloader:
28-
... metric.update(batch_scores, batch_labels)
29-
>>> final_score = metric.compute()
30+
>>> for batch in dataloader:
31+
... auroc.update(batch)
32+
>>> final_score = auroc.compute()
3033
3134
Once computed, the ROC curve can be visualized:
3235
@@ -56,12 +59,11 @@ class _AUROC(BinaryROC):
5659
5760
Examples:
5861
To compute the metric for a set of predictions and ground truth targets:
59-
62+
>>> from anomalib.metrics.auroc import _AUROC
6063
>>> import torch
61-
>>> from anomalib.metrics import AUROC
6264
>>> preds = torch.tensor([0.13, 0.26, 0.08, 0.92, 0.03])
6365
>>> target = torch.tensor([0, 0, 1, 1, 0])
64-
>>> auroc = AUROC()
66+
>>> auroc = _AUROC()
6567
>>> auroc(preds, target)
6668
tensor(0.6667)
6769
@@ -148,4 +150,23 @@ def generate_figure(self) -> tuple[Figure, str]:
148150

149151

150152
class AUROC(AnomalibMetric, _AUROC): # type: ignore[misc]
151-
"""Wrapper to add AnomalibMetric functionality to AUROC metric."""
153+
"""Wrapper to add AnomalibMetric functionality to AUROC metric.
154+
155+
This class wraps the internal ``_AUROC`` metric to make it compatible with
156+
Anomalib's batch processing capabilities.
157+
158+
Example:
159+
>>> from anomalib.metrics import AUROC
160+
>>> from anomalib.data import ImageBatch
161+
>>> import torch
162+
>>> # Create sample batch
163+
>>> batch = ImageBatch(
164+
... image=torch.rand(4, 3, 32, 32),
165+
... pred_score=torch.tensor([0.1, 0.2, 0.8, 0.9]),
166+
... gt_label=torch.tensor([0, 0, 1, 1])
167+
... )
168+
>>> # Initialize and compute AUROC
169+
>>> auroc = AUROC(fields=["pred_score", "gt_label"])
170+
>>> auroc(batch)
171+
tensor(1.0)
172+
"""

0 commit comments

Comments
 (0)