Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Merge main to v2" #2466

Merged
merged 1 commit into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/source/markdown/guides/how_to/pipelines/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ This section contains tutorials on how to use different pipelines of Anomalib an
:margin: 1 1 0 0
:gutter: 1

:::{grid-item-card} {octicon}`stack` Tiled Ensemble
:link: ./tiled_ensemble
:link-type: doc

Learn more about how to use the tiled ensemble pipelines.
:::

:::{grid-item-card} {octicon}`gear` Custom Pipeline
:link: ./custom_pipeline
:link-type: doc
Expand Down
157 changes: 157 additions & 0 deletions docs/source/markdown/guides/how_to/pipelines/tiled_ensemble.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# Tiled ensemble

This guide will show you how to use **The Tiled Ensemble** method for anomaly detection. For more details, refer to the official [Paper](https://openaccess.thecvf.com/content/CVPR2024W/VAND/html/Rolih_Divide_and_Conquer_High-Resolution_Industrial_Anomaly_Detection_via_Memory_Efficient_CVPRW_2024_paper.html).

The tiled ensemble approach reduces memory consumption by dividing input images into a grid of tiles and training a dedicated model for each tile location.
It is compatible with any existing image anomaly detection model without the need for any modification of the underlying architecture.

![Tiled ensemble flow](../../../../images/tiled_ensemble/ensemble_flow.png)

```{note}
This feature is experimental and may not work as expected.
For any problems refer to [Issues](https://github.com/openvinotoolkit/anomalib/issues) and feel free to ask any question in [Discussions](https://github.com/openvinotoolkit/anomalib/discussions).
```

## Training

You can train a tiled ensemble using the training script located inside `tools/tiled_ensemble` directory:

```{code-block} bash

python tools/tiled_ensemble/train_ensemble.py \
--config tools/tiled_ensemble/ens_config.yaml
```

By default, the Padim model is trained on **MVTec AD bottle** category using image size of 256x256, divided into non-overlapping 128x128 tiles.
You can modify these parameters in the [config file](#ensemble-configuration).

## Evaluation

After training, you can evaluate the tiled ensemble on test data using:

```{code-block} bash

python tools/tiled_ensemble/eval.py \
--config tools/tiled_ensemble/ens_config.yaml \
--root path_to_results_dir

```

Ensure that `root` points to the directory containing the training results, typically `results/padim/mvtec/bottle/runX`.

## Ensemble configuration

Tiled ensemble is configured using `ens_config.yaml` file in the `tools/tiled_ensemble` directory.
It contains general settings and tiled ensemble specific settings.

### General

General settings at the top of the config file are used to set up the random `seed`, `accelerator` (device) and the path to where results will be saved `default_root_dir`.

```{code-block} yaml
seed: 42
accelerator: "gpu"
default_root_dir: "results"
```

### Tiling

This section contains the following settings, used for image tiling:

```{code-block} yaml

tiling:
tile_size: 256
stride: 256
```

These settings determine the tile size and stride. Another important parameter is image_size from `data` section later in the config. It determines the original size of the image.

Input image is split into tiles, where each tile is of shape set by `tile_size` and tiles are taken with step set by `stride`.
For example: having image_size: 512, tile_size: 256, and stride: 256, results in 4 non-overlapping tile locations.

### Normalization and thresholding

Next up are the normalization and thresholding settings:

```{code-block} yaml
normalization_stage: image
thresholding:
method: F1AdaptiveThreshold
stage: image
```

- **Normalization**: Can be applied per each tile location separately (`tile` option), after combining prediction (`image` option), or skipped (`none` option).

- **Thresholding**: Can also be applied at different stages, but it is limited to `tile` and `image`. Another setting for thresholding is the method used. It can be specified as a string or by the class path.

### Data

The `data` section is used to configure the input `image_size` and other parameters for the dataset used.

```{code-block} yaml
data:
class_path: anomalib.data.MVTec
init_args:
root: ./datasets/MVTec
category: bottle
train_batch_size: 32
eval_batch_size: 32
num_workers: 8
task: segmentation
transform: null
train_transform: null
eval_transform: null
test_split_mode: from_dir
test_split_ratio: 0.2
val_split_mode: same_as_test
val_split_ratio: 0.5
image_size: [256, 256]
```

Refer to [Data](../../reference/data/image/index.md) for more details on parameters.

### SeamSmoothing

This section contains settings for `SeamSmoothing` block of pipeline:

```{code-block} yaml
SeamSmoothing:
apply: True
sigma: 2
width: 0.1

```

SeamSmoothing job is responsible for smoothing of regions where tiles meet - called tile seams.

- **apply**: If True, smoothing will be applied.
- **sigma**: Controls the sigma of Gaussian filter used for smoothing.
- **width**: Sets the percentage of the region around the seam to be smoothed.

### TrainModels

The last section `TrainModels` contains the setup for model training:

```{code-block} yaml
TrainModels:
model:
class_path: Fastflow

metrics:
pixel: AUROC
image: AUROC

trainer:
max_epochs: 500
callbacks:
- class_path: lightning.pytorch.callbacks.EarlyStopping
init_args:
patience: 42
monitor: pixel_AUROC
mode: max
```

- **Model**: Specifies the model used. Refer to [Models](../../reference/models/image/index.md) for more details on the model parameters.
- **Metrics**: Defines evaluation metrics for pixel and image level.
- **Trainer**: _optional_ parameters, used to control the training process. Refer to [Engine](../../reference/engine/index.md) for more details.
322 changes: 49 additions & 273 deletions notebooks/700_metrics/701b_aupimo_advanced_i.ipynb

Large diffs are not rendered by default.

152 changes: 18 additions & 134 deletions notebooks/700_metrics/701c_aupimo_advanced_ii.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/anomalib/models/components/base/export_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def to_onnx(
dynamic_axes = (
{"input": {0: "batch_size"}, "output": {0: "batch_size"}}
if input_size
else {"input": {0: "batch_size", 2: "height", 3: "weight"}, "output": {0: "batch_size"}}
else {"input": {0: "batch_size", 2: "height", 3: "width"}, "output": {0: "batch_size"}}
)
onnx_path = export_root / "model.onnx"
# apply pass through the model to get the output names
Expand Down
43 changes: 43 additions & 0 deletions tools/tiled_ensemble/ens_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
seed: 42
accelerator: "gpu"
default_root_dir: "results"

tiling:
tile_size: [128, 128]
stride: 128

normalization_stage: image # on what level we normalize, options: [tile, image, none]
thresholding:
method: F1AdaptiveThreshold # refer to documentation for thresholding methods
stage: image # stage at which we apply threshold, options: [tile, image]

data:
class_path: anomalib.data.MVTec
init_args:
root: ./datasets/MVTec
category: bottle
train_batch_size: 32
eval_batch_size: 32
num_workers: 8
task: segmentation
transform: null
train_transform: null
eval_transform: null
test_split_mode: from_dir
test_split_ratio: 0.2
val_split_mode: same_as_test
val_split_ratio: 0.5
image_size: [256, 256]

SeamSmoothing:
apply: True # if this is applied, area around tile seams are is smoothed
sigma: 2 # sigma of gaussian filter used to smooth this area
width: 0.1 # width factor, multiplied by tile dimension gives the region width around seam which will be smoothed

TrainModels:
model:
class_path: Padim

metrics:
pixel: AUROC
image: AUROC
28 changes: 28 additions & 0 deletions tools/tiled_ensemble/eval.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""Run tiled ensemble prediction."""

# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

from pathlib import Path

from jsonargparse import ArgumentParser

from anomalib.pipelines.tiled_ensemble import EvalTiledEnsemble


def get_parser() -> ArgumentParser:
"""Create a new parser if none is provided."""
parser = ArgumentParser()
parser.add_argument("--config", type=str | Path, help="Configuration file path.", required=True)
parser.add_argument("--root", type=str | Path, help="Weights file path.", required=True)

return parser


if __name__ == "__main__":
args = get_parser().parse_args()

print("Running tiled ensemble test pipeline.")
# pass the path to root dir with checkpoints
test_pipeline = EvalTiledEnsemble(args.root)
test_pipeline.run(args)
17 changes: 17 additions & 0 deletions tools/tiled_ensemble/train.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""Run tiled ensemble training."""

# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

from anomalib.pipelines.tiled_ensemble import EvalTiledEnsemble, TrainTiledEnsemble

if __name__ == "__main__":
print("Running tiled ensemble train pipeline")
train_pipeline = TrainTiledEnsemble()
# run training
train_pipeline.run()

print("Running tiled ensemble test pipeline.")
# pass the root dir from train run to load checkpoints
test_pipeline = EvalTiledEnsemble(train_pipeline.root_dir)
test_pipeline.run()