Skip to main content

anomalib-adding-a-model

Adds a new anomaly-detection model to anomalib under src/anomalib/models/. Use when implementing a new model architecture (image or video), wiring it into the AnomalibModule base class, registering it so get_model() and the CLI/config (jsonargparse) can discover it, and adding matching tests. Do not use for changes to existing model internals only (no new model), or for datamodule/dataset work (see anomalib-adding-a-datamodule).

소스 정보

저장소
open-edge-platform/anomalib
최근 소스 활동
2026년 8월 24일 13:28
감지된 SKILL.md 언어
영어
스타
6,252
포크
1,004

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
2 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
anomalib-adding-a-model
description
Adds a new anomaly-detection model to anomalib under src/anomalib/models/. Use when implementing a new model architecture (image or video), wiring it into the AnomalibModule base class, registering it so get_model() and the CLI/config (jsonargparse) can discover it, and adding matching tests. Do not use for changes to existing model internals only (no new model), or for datamodule/dataset work (see anomalib-adding-a-datamodule).
license
Apache-2.0
# Adding a New Model Models live under `src/anomalib/models/image/<model_name>/` (or `.../video/<model_name>/` for video models). Every model is a `LightningModule` subclass of `AnomalibModule` (`src/anomalib/models/components/base/anomalib_module.py`) that wraps a plain `torch.nn.Module`. ## Reference implementation Read `src/anomalib/models/image/padim/` first — it is the smallest complete example: - `torch_model.py` — `PadimModel(nn.Module)`: pure PyTorch forward pass. In training mode it returns intermediate embeddings; in eval mode it returns an `InferenceBatch(pred_score=..., anomaly_map=...)`. - `anomaly_map.py` — `AnomalyMapGenerator(nn.Module)`: post-processing (score/map computation) kept out of `torch_model.py` for clarity. Not all models need a separate file for this. - `lightning_model.py` — `Padim(MemoryBankMixin, AnomalibModule)`: the Lightning-facing wrapper. This is the class users construct (`Padim()`), pass to `Engine`, and reference from CLI/config as `anomalib.models.Padim`. - `__init__.py` — exports the Lightning class only: `from .lightning_model import Padim`. - `README.md` — usage + benchmark notes (see `model-doc-sync`/`model-sample-image-export` skills for docs work). Only mix in `MemoryBankMixin` (`src/anomalib/models/components/base/memory_bank_module.py`) if the model accumulates a memory bank / feature bank across training (as PaDiM and PatchCore do). Most models just subclass `AnomalibModule` directly. ## Required members on your `AnomalibModule` subclass ```python import torch from anomalib import LearningType from anomalib.data import Batch from anomalib.metrics import Evaluator from anomalib.models.components import AnomalibModule from anomalib.post_processing import PostProcessor from anomalib.pre_processing import PreProcessor from anomalib.visualization import Visualizer class MyModel(AnomalibModule): def __init__(self, some_param: int = 1, pre_processor: PreProcessor | bool = True, post_processor: PostProcessor | bool = True, evaluator: Evaluator | bool = True, visualizer: Visualizer | bool = True) -> None: super().__init__(pre_processor=pre_processor, post_processor=post_processor, evaluator=evaluator, visualizer=visualizer) self.model = MyTorchModel(some_param=some_param) @property def trainer_arguments(self) -> dict: """Default Trainer overrides for this model, e.g. {"max_epochs": 1} for training-free models.""" return {"max_epochs": 1, "num_sanity_val_steps": 0} @property def learning_type(self) -> LearningType: return LearningType.ONE_CLASS def training_step(self, batch: Batch, *args, **kwargs) -> torch.Tensor: # Training-free models (e.g. Padim) still return a dummy loss for Lightning. _ = self.model(batch.image) return torch.tensor(0.0, requires_grad=True, device=self.device) def validation_step(self, batch: Batch, *args, **kwargs) -> Batch: predictions = self.model(batch.image) return batch.update(**predictions._asdict()) def configure_optimizers(self) -> None: # Return None for training-free / statistical models (Padim does this). return None ``` `AnomalibModule` provides working defaults you can override only when the model needs something different: - `configure_pre_processor(image_size=None)` — resize + ImageNet normalization. - `configure_post_processor()` — thresholding/normalization for `ONE_CLASS` models. - `configure_evaluator()` — image/pixel AUROC and F1 metrics. - `configure_visualizer()` — default `ImageVisualizer`. `pre_processor` / `post_processor` / `evaluator` / `visualizer` constructor args each accept an instance, `True` (use the configured default), or `False` (disable). ## Registration — how the model becomes discoverable 1. Add the export in `src/anomalib/models/image/__init__.py` (or `video/__init__.py`): ```python from .my_model import MyModel ``` and add `"MyModel"` to `__all__` and to the `Available Models` docstring list at the top of the file. 2. Also add the import in `src/anomalib/models/__init__.py`, which explicitly imports all image (and video) models and defines the top-level `__all__`. Without this, `anomalib.models.MyModel` won't resolve. 3. That's the only registration needed. `list_models()` and `get_model()` (`src/anomalib/models/__init__.py`) discover models by walking `AnomalibModule.__subclasses__()` and matching on `cls.__name__` (case-insensitive) — there is no separate name-string registry to update. 4. `get_model()` also accepts a dict/`DictConfig`/`Namespace` with `class_path` + `init_args`, restricted to modules listed in `ALLOWED_MODULES` (same file) — you don't need to touch that set for models already under `anomalib.models`. 5. Once exported, the model is usable as `anomalib.models.MyModel`, from `get_model("MyModel")`, and from the CLI: `anomalib train --model MyModel --data anomalib.data.MVTecAD`. ## Tests Add `tests/unit/models/image/my_model/test_my_model.py` (or `.../video/my_model/...`). At minimum: - `get_model("MyModel")` (and the equivalent PascalCase/snake_case variants) returns a `MyModel` instance. - `model.trainer_arguments` is a `dict` and `model.learning_type` is the expected `LearningType`. - A synthetic batch through `training_step`/`validation_step` produces the expected shapes: image-level `pred_score` has shape `(batch_size,)` and pixel-level `anomaly_map` has shape `(batch_size, 1, H, W)` without crashing. See `tests/unit/models/test_model_utils.py` for the `get_model()` instantiation pattern used across the suite. ## Gotchas - Keep `torch_model.py` importable and testable without Lightning — the `nn.Module.forward` contract (train-mode returns raw tensors/embeddings, eval-mode returns `InferenceBatch`) is what the base class and visualizers expect. Don't put Lightning-specific logic there. - Training side effects (checkpointing, timing, compression, visualization) belong in `src/anomalib/callbacks/`-style Lightning callbacks or existing hooks — not inline in the model's `training_step`. - Public constructor arguments must stay explicit and typed (no untyped `**kwargs` passthrough) so `jsonargparse` can expose them on the CLI/config surface. - If the model becomes part of the public API, update the model's `README.md` and, if one exists, the matching page under `docs/source/markdown/guides/reference/models/`. ## Reviewer / self-check before opening a PR - [ ] Model exported from `src/anomalib/models/image/__init__.py` (or `video/__init__.py`) and `__all__` updated. - [ ] `trainer_arguments`, `learning_type`, `training_step`, `validation_step`, `configure_optimizers` implemented. - [ ] `get_model("MyModel")` and `anomalib.models.MyModel` both resolve. - [ ] Unit tests added under `tests/unit/models/`. - [ ] `README.md` added in the model folder. - [ ] `pre-commit run --all-files` and `pytest tests/unit/models/ -k my_model` pass.
GitHub에서 보기