https://blog.ml6.eu/a-practical-guide-to-anomaly-detection-using-anomalib-b2af78147934
https://openvinotoolkit.github.io/anomalib/how_to_guides/train_custom_data.html
위 글들을 참고해 Anomalib에서 제공하는 여러 모델들 중 calssification task 기반 모델인 PaDiM 모델을 돌려봤다.
아직 논문을 안읽어봐서 학습 과정에 대해서는 잘 모르겠지만..

위와 같은 결과를 얻어둔 상태다.
아직 config 파일을 만지는 법을 잘 몰라서, 논문 읽고 이해한 뒤 이후 작업을 진행할 예정이다.
https://velog.io/@ljwljy51/PaDiM
논문을 읽고, 작동 매커니즘은 파악을 했다. 그러나, 여전히 config 파일을 어떻게 만져야 할지 감이 안온다.

기본 튜토리얼을 보고 수정한 세팅에서 image_size 부분만 수정해주었다. 본 논문에서는 256x256으로 이미지를 resize해 사용하는데, 내가 사용할 데이터셋의 원본 이미지 사이즈는 64x128정도여서 사이즈를 이에 맞게 수정해주었다.

그 뒤, 위와 같은 성능을 얻었다. 수치는 좋게 나왔는데 여전히 왜 이렇게 잘 나오는지 잘 모르겠다.
직관적으로 생각해봤을 때, n_features값을 기존 값인 100에서 증가시켜줬을 때 성능이 좋아질 것이라고 예상했으나, 200으로 변경했음에도 불구하고 성능이 향상되지는 않았다.
model:
name: padim
backbone: resnet18
pre_trained: true
layers:
- layer1
- layer2
- layer3
normalization_method: min_max # options: [none, min_max, cdf]
n_features: 200

튜토리얼에서 제공하는 config 파일 옵션들이 기존에 제공하는 config 파일이랑 다른 부분이 많아서 처음에도 의아했는데, issue를 보다 보니 훈련 세팅을 또 다르게 줄 수 있었다.
https://github.com/openvinotoolkit/anomalib/issues/1238
https://github.com/openvinotoolkit/anomalib/issues/1067
위 링크는 normal dataset만으로 PaDiM 모델을 돌리고 싶을 때에 대한 세팅에 대해 나와있다. (근데 원래 normal image만 훈련때 사용하도록 된 거 아닌가?)
어쨌거나 위 세팅에 따라서도 해보자.
dataset:
name: module_anomalib
format: folder
root: ./datasets/module_anomalib/module_anomalib
normal_dir: normal # name of the folder containing normal images.
abnormal_dir: leaf # name of the folder containing abnormal images.
task: classification # classification or segmentation
mask_dir: null #optional
normal_test_dir: normal # optional
extensions: null
split_ratio: 0.2 # normal images ratio to create a test split
seed: 0
image_size: 256
train_batch_size: 32
eval_batch_size: 32
num_workers: 8
normalization: imagenet # data distribution to which the images will be normalized
test_split_mode: from_dir # options [from_dir, synthetic]
val_split_ratio: 0.5 # fraction of train/test images held out for validation (usage depends on val_split_mode)
transform_config:
train: null
eval: null
val_split_mode: same_as_test # determines how the validation set is created, options [same_as_test, from_test]
tiling:
apply: false
tile_size: null
stride: null
remove_border_count: 0
use_random_tiling: False
random_tile_count: 16
model:
name: padim
backbone: resnet18
pre_trained: true
layers:
- layer1
- layer2
- layer3
normalization_method: min_max # options: [none, min_max, cdf]
metrics:
image:
- F1Score
- AUROC
pixel:
- F1Score
- AUROC
threshold:
method: adaptive #options: [adaptive, manual]
manual_image: null
manual_pixel: null
위 내용 중, val_split_mode부분을 고쳐주니 성능이 훨씬 좋아졌다. 즉, 이전 세팅들에서는 저 부분이 from_test였는데, 그러면 val_split_ratio에 따라 훈련데이터 중 절반을 validation set으로 쓰고, 제공된 train set 중 절반의 데이터만 실질적으로 훈련 데이터로 사용된다.


model:
name: padim
backbone: wide_resnet50_2
pre_trained: true
layers:
- layer1
- layer2
- layer3
normalization_method: min_max # options: [none, min_max, cdf]
# n_features: 200
여전히 config파일을 어떻게 수정해야할지 옵션 사항들을 잘 몰랐지만, github issue들을 보면서 백본 옵션 중 하나인 wide resnet에 대한 글을 찾아 변경해주었다. 훈련 데이터셋에서 절반만 사용하고, 기본 튜토리얼의 옵션에서 백본만 바꿔줬는데도 F1score 1.0을 찍었다.

새로운 데이터셋을 추가해본 후 성능 상태다. 그다지 좋지 않다
결과 이미지들을 보니, 중간에 centercrop이 적용되어 가장자리부분의 anomaly detection이 잘 되지 않고 있었다. 그러나, Center crop을 아예 적용하지 않으면 더 성능이 떨어졌었다..

가장자리 anomaly detection 문제를 해결했다! 본 모델이 테스팅됐던 데이터셋인 MVTecAD 데이터셋 자체가 object가 중앙에 있는 형식이었기에, centercrop이 적용돼서 처리되어 현재 내 Task에서는 가장자리 anomaly에 대한 detection이 안됐었는데, config 파일을 다음과 같이 수정해줌으로써 성능을 높힐 수 있었다.
dataset:
name: module_anomalib
format: folder
#root: ./rgb_non_module_anomalib/module_anomalib
root: ./RGBmodule_anomalib/module_anomalib/module_anomalib
normal_dir: normal # name of the folder containing normal images.
abnormal_dir: leaf # name of the folder containing abnormal images.
task: classification # classification or segmentation
train_batch_size: 32
normal_test_dir: null
mask_dir: null
extensions: null
eval_batch_size: 32
num_workers: 8
image_size: 224 # dimensions to which images are resized (mandatory)
center_crop: 224 # dimensions to which images are center-cropped after resizing (optional)
normalization: imagenet # data distribution to which the images will be normalized: [none, imagenet]
transform_config:
train: null
eval: null
test_split_mode: from_dir # options: [from_dir, synthetic]
test_split_ratio: 0.2 # fraction of train images held out testing (usage depends on test_split_mode)
val_split_mode: same_as_test # options: [same_as_test, from_test, synthetic]
val_split_ratio: 0.5 # fraction of train/test images held out for validation (usage depends on val_split_mode)
tiling:
apply: false
tile_size: null
stride: null
remove_border_count: 0
use_random_tiling: False
random_tile_count: 16
위 내용에서 집중해서 봐야 하는 부분은 image_resize와 center_crop 부분이다. 원래 default setting은 이미지를 256x256 사이즈로 resize해준 뒤, 224x224 사이즈로 크롭을 적용해 input으로 넣어 학습한다. 그러나, 애초에 center crop이 적용되지 않도록 resize를 224 사이즈로 해주면 됐었다.
대체 이 간단한 문제를 왜 지금까지 해결을 못하고 있었는가..^^,,,,,,,
역시 논문을 잘 읽고 세팅을 "잘.." 해줘야 한다.
그렇게 달성한 최종 성능!


dataset:
name: module_anomalib
format: folder
root: ./RGBmodule_anomalib_mod
normal_dir: normal # name of the folder containing normal images.
abnormal_dir: leaf # name of the folder containing abnormal images.
task: classification # classification or segmentation
train_batch_size: 32
normal_test_dir: null
mask_dir: null
extensions: null
eval_batch_size: 32
num_workers: 8
image_size: 210 # dimensions to which images are resized (mandatory)
center_crop: 210 # dimensions to which images are center-cropped after resizing (optional)
normalization: imagenet # data distribution to which the images will be normalized: [none, imagenet]
transform_config:
train: null
eval: null
test_split_mode: from_dir # options: [from_dir, synthetic]
test_split_ratio: 0.2 # fraction of train images held out testing (usage depends on test_split_mode)
val_split_mode: same_as_test # options: [same_as_test, from_test, synthetic]
val_split_ratio: 0.5 # fraction of train/test images held out for validation (usage depends on val_split_mode)
tiling:
apply: false
tile_size: null
stride: null
remove_border_count: 0
use_random_tiling: False
random_tile_count: 16
model:
name: patchcore
backbone: wide_resnet50_2
pre_trained: true
layers:
- layer2
- layer3
coreset_sampling_ratio: 0.1
num_neighbors: 9
normalization_method: min_max # options: [null, min_max, cdf]
metrics:
image:
- F1Score
- AUROC
pixel:
- F1Score
- AUROC
threshold:
method: adaptive #options: [adaptive, manual]
manual_image: null
manual_pixel: null
visualization:
show_images: False # show images on the screen
save_images: True # save images to the file system
log_images: True # log images to the available loggers (if any)
image_save_path: null # path to which images will be saved
mode: full # options: ["full", "simple"]
project:
seed: 0
path: ./results
logging:
logger: [] # options: [comet, tensorboard, wandb, csv] or combinations.
log_graph: false # Logs the model graph to respective logger.
optimization:
export_mode: null # options: onnx, openvino
# PL Trainer Args. Don't add extra parameter here.
trainer:
enable_checkpointing: true
default_root_dir: null
gradient_clip_val: 0
gradient_clip_algorithm: norm
num_nodes: 1
devices: [0]
enable_progress_bar: true
overfit_batches: 0.0
track_grad_norm: -1
check_val_every_n_epoch: 1 # Don't validate before extracting features.
fast_dev_run: false
accumulate_grad_batches: 1
max_epochs: 1
min_epochs: null
max_steps: -1
min_steps: null
max_time: null
limit_train_batches: 1.0
limit_val_batches: 1.0
limit_test_batches: 1.0
limit_predict_batches: 1.0
val_check_interval: 1.0 # Don't validate before extracting features.
log_every_n_steps: 50
accelerator: auto # <"cpu", "gpu", "tpu", "ipu", "hpu", "auto">
strategy: null
sync_batchnorm: false
precision: 32
enable_model_summary: true
num_sanity_val_steps: 0
profiler: null
benchmark: false
deterministic: false
reload_dataloaders_every_n_epochs: 0
auto_lr_find: false
replace_sampler_ddp: true
detect_anomaly: false
auto_scale_batch_size: false
plugins: null
move_metrics_to_cpu: false
multiple_trainloader_mode: max_size_cycle