From e3d32e4e3338947069446bc68997abe3ff415597 Mon Sep 17 00:00:00 2001 From: Patrick Godau Date: Thu, 19 Dec 2024 05:40:22 +0100 Subject: [PATCH 1/4] transfer from GitLab to GitHub --- .readthedocs.yaml | 25 + .gitattributes | 1 + .gitignore | 29 + CHANGELOG.md | 591 + CITATION.cff | 26 + CONTRIBUTING.md | 125 + Dockerfile | 50 + LICENSES/MIT.txt | 21 + MANIFEST.in | 7 + README.md | 142 + RELEASE.md | 54 + license_header.template | 2 + plugins/README.md | 7 + plugins/_template/CHANGELOG.md | 21 + plugins/_template/LICENSE.txt | 21 + plugins/_template/MANIFEST.in | 1 + plugins/_template/README.md | 30 + plugins/_template/pyproject.toml | 52 + plugins/_template/setup.cfg | 45 + plugins/_template/src/mml_TODO/__init__.py | 9 + plugins/_template/src/mml_TODO/activate.py | 25 + .../src/mml_TODO/configs/__init__.py | 6 + plugins/_template/tests/conftest.py | 14 + plugins/_template/tests/unit/test_dummy.py | 9 + plugins/data/CHANGELOG.md | 12 + plugins/data/LICENSE.txt | 21 + plugins/data/MANIFEST.in | 1 + plugins/data/README.md | 32 + plugins/data/pyproject.toml | 52 + plugins/data/setup.cfg | 49 + plugins/data/src/mml_data/__init__.py | 9 + plugins/data/src/mml_data/activate.py | 20 + plugins/data/src/mml_data/cli.py | 160 + plugins/data/src/mml_data/configs/__init__.py | 6 + .../data/src/mml_data/configs/tasks/all.yaml | 115 + .../src/mml_data/configs/tasks/all_clas.yaml | 95 + .../data/src/mml_data/configs/tasks/new.yaml | 23 + .../data/src/mml_data/creators/__init__.py | 21 + .../creators/classification/__init__.py | 13 + .../creators/classification/_template.py | 60 + .../classification/aptos_blindness.py | 83 + .../classification/barretts_esophagus.py | 68 + .../creators/classification/brain_tumor.py | 70 + .../classification/brain_tumor_type.py | 62 + .../classification/breast_ultrasound.py | 69 + .../creators/classification/caltech101.py | 68 + .../creators/classification/caltech256.py | 74 + .../creators/classification/cataract.py | 60 + .../cervical_cancer_screening.py | 87 + .../creators/classification/chexpert.py | 106 + .../creators/classification/cholec45.py | 129 + .../creators/classification/cholec80.py | 162 + .../mml_data/creators/classification/cifar.py | 105 + .../creators/classification/covid_ct.py | 139 + .../classification/covid_ct_crawled.py | 74 + .../creators/classification/covid_xray.py | 64 + .../creators/classification/deep_drid.py | 161 + .../creators/classification/derm7pt.py | 141 + .../creators/classification/emnist.py | 65 + .../creators/classification/hyper_kvasir.py | 147 + .../mml_data/creators/classification/ibean.py | 91 + .../classification/idle_frame_recognition.py | 62 + .../creators/classification/isic20.py | 119 + .../creators/classification/kvasir_capsule.py | 149 + .../creators/classification/lapgyn4.py | 184 + .../creators/classification/laryngeal.py | 123 + .../creators/classification/mednode.py | 65 + .../mml_data/creators/classification/mnist.py | 67 + .../mml_data/creators/classification/mura.py | 99 + .../creators/classification/nbi_infframes.py | 131 + .../creators/classification/nerthus.py | 76 + .../creators/classification/pneumonia.py | 80 + .../classification/shenzhen_tuberculosis.py | 74 + .../creators/classification/sklin2.py | 72 + .../creators/classification/stanford_dogs.py | 197 + .../creators/classification/suncolondb.py | 222 + .../mml_data/creators/classification/svhn.py | 70 + .../creators/segmentation/__init__.py | 13 + .../segmentation/crowd_source_instrument.py | 102 + .../endovis18_robotic_instrument.py | 155 + .../mml_data/creators/segmentation/enid.py | 328 + .../mml_data/creators/segmentation/glenda.py | 1183 + .../creators/segmentation/hyper_kvasir.py | 71 + .../creators/segmentation/image2image.py | 193 + .../segmentation/motion_based_recognition.py | 135 + .../src/mml_data/creators/segmentation/ph2.py | 322 + .../src/mml_data/creators/segmentation/voc.py | 142 + plugins/data/tests/conftest.py | 14 + plugins/data/tests/unit/test_dummy.py | 9 + plugins/dimensionality/CHANGELOG.md | 12 + plugins/dimensionality/LICENSE.txt | 21 + plugins/dimensionality/MANIFEST.in | 1 + plugins/dimensionality/README.md | 11 + plugins/dimensionality/pyproject.toml | 52 + plugins/dimensionality/setup.cfg | 48 + .../src/mml_dimensionality/__init__.py | 9 + .../src/mml_dimensionality/activate.py | 38 + .../mml_dimensionality/configs/__init__.py | 6 + .../mml_dimensionality/configs/mode/dim.yaml | 24 + .../src/mml_dimensionality/models/__init__.py | 6 + .../src/mml_dimensionality/models/knn.py | 85 + .../mml_dimensionality/scripts/__init__.py | 8 + .../scripts/dimensionality_scheduler.py | 93 + .../src/mml_dimensionality/scripts/mle.py | 122 + .../src/mml_dimensionality/scripts/utils.py | 20 + .../visualization/__init__.py | 68 + plugins/dimensionality/tests/conftest.py | 14 + .../unit/test_dimensionality_scheduler.py | 28 + plugins/drive/CHANGELOG.md | 12 + plugins/drive/LICENSE.txt | 21 + plugins/drive/README.md | 16 + plugins/drive/pyproject.toml | 52 + plugins/drive/setup.cfg | 47 + plugins/drive/src/mml_drive/__init__.py | 9 + plugins/drive/src/mml_drive/activate.py | 12 + plugins/drive/src/mml_drive/prepare_hook.py | 58 + plugins/drive/tests/conftest.py | 14 + plugins/drive/tests/unit/test_dummy.py | 9 + plugins/index.txt | 8 + plugins/lsf/CHANGELOG.md | 15 + plugins/lsf/LICENSE.txt | 21 + plugins/lsf/MANIFEST.in | 1 + plugins/lsf/README.md | 94 + plugins/lsf/pyproject.toml | 52 + plugins/lsf/setup.cfg | 47 + plugins/lsf/src/mml_lsf/__init__.py | 8 + plugins/lsf/src/mml_lsf/activate.py | 11 + plugins/lsf/src/mml_lsf/requirements.py | 47 + plugins/lsf/src/mml_lsf/runner.py | 305 + plugins/lsf/src/mml_lsf/workers.py | 80 + plugins/lsf/tests/conftest.py | 14 + plugins/lsf/tests/unit/test_dummy.py | 9 + plugins/similarity/CHANGELOG.md | 21 + plugins/similarity/LICENSE.txt | 21 + plugins/similarity/MANIFEST.in | 1 + plugins/similarity/README.md | 20 + plugins/similarity/pyproject.toml | 52 + plugins/similarity/setup.cfg | 50 + .../similarity/src/mml_similarity/__init__.py | 9 + .../similarity/src/mml_similarity/activate.py | 67 + .../src/mml_similarity/configs/__init__.py | 6 + .../mml_similarity/configs/distance/emd.yaml | 21 + .../mml_similarity/configs/distance/ens.yaml | 19 + .../mml_similarity/configs/distance/fed.yaml | 33 + .../mml_similarity/configs/distance/fid.yaml | 20 + .../mml_similarity/configs/distance/kld.yaml | 17 + .../mml_similarity/configs/distance/mmd.yaml | 23 + .../configs/distance/semantic.yaml | 16 + .../configs/mode/similarity.yaml | 15 + .../configs/plotting/distance.yaml | 25 + .../mml_similarity/configs/plotting/kam.yaml | 25 + .../mml_similarity/configs/plotting/tsne.yaml | 25 + .../configs/sampling/extraction_default.yaml | 18 + .../configs/sampling/extraction_minimal.yaml | 18 + .../configs/search_space/fed_search.yaml | 16 + .../configs/search_space/mmd_search.yaml | 13 + .../src/mml_similarity/scripts/__init__.py | 8 + .../abstract_task_distance_scheduler.py | 217 + .../scripts/ensemble_scheduler.py | 84 + .../scripts/feature_distances.py | 232 + .../mml_similarity/scripts/fed_scheduler.py | 180 + .../src/mml_similarity/scripts/fisher.py | 297 + .../scripts/sample_based_scheduler.py | 116 + .../scripts/semantic_scheduler.py | 47 + .../scripts/vector_distances.py | 39 + .../mml_similarity/visualization/__init__.py | 6 + .../mml_similarity/visualization/plot_2D.py | 386 + plugins/similarity/tests/conftest.py | 35 + .../tests/integration/test_dist_measures.py | 21 + .../tests/unit/test_fed_scheduler.py | 69 + plugins/sql/CHANGELOG.md | 12 + plugins/sql/LICENSE.txt | 21 + plugins/sql/MANIFEST.in | 1 + plugins/sql/README.md | 64 + plugins/sql/pyproject.toml | 52 + plugins/sql/setup.cfg | 47 + plugins/sql/src/mml_sql/__init__.py | 9 + plugins/sql/src/mml_sql/activate.py | 19 + plugins/sql/src/mml_sql/configs/__init__.py | 6 + plugins/sql/src/mml_sql/configs/hpo/sql.yaml | 42 + plugins/sql/tests/conftest.py | 14 + plugins/sql/tests/unit/test_dummy.py | 9 + plugins/suggest/CHANGELOG.md | 20 + plugins/suggest/LICENSE.txt | 21 + plugins/suggest/MANIFEST.in | 1 + plugins/suggest/README.md | 30 + plugins/suggest/pyproject.toml | 52 + plugins/suggest/setup.cfg | 48 + plugins/suggest/src/mml_suggest/__init__.py | 9 + plugins/suggest/src/mml_suggest/activate.py | 19 + .../src/mml_suggest/configs/__init__.py | 6 + .../src/mml_suggest/configs/mode/suggest.yaml | 42 + .../src/mml_suggest/scripts/__init__.py | 6 + .../mml_suggest/scripts/suggest_scheduler.py | 277 + plugins/suggest/tests/conftest.py | 14 + .../integration/test_suggest_scheduler.py | 56 + plugins/tags/CHANGELOG.md | 12 + plugins/tags/LICENSE.txt | 21 + plugins/tags/README.md | 13 + plugins/tags/pyproject.toml | 52 + plugins/tags/setup.cfg | 49 + plugins/tags/src/mml_tags/__init__.py | 9 + plugins/tags/src/mml_tags/activate.py | 25 + plugins/tags/src/mml_tags/cli.py | 22 + plugins/tags/src/mml_tags/tags/__init__.py | 6 + plugins/tags/src/mml_tags/tags/confuse.py | 48 + .../src/mml_tags/tags/redistribute_splits.py | 105 + .../tags/src/mml_tags/tags/shrink_train.py | 109 + plugins/tags/src/mml_tags/tags/subclass.py | 23 + plugins/tags/src/mml_tags/tags/subset.py | 64 + plugins/tags/tests/conftest.py | 14 + plugins/tags/tests/unit/test_dummy.py | 9 + pyproject.toml | 61 + setup.cfg | 107 + src/mml/__init__.py | 13 + src/mml/__main__.py | 321 + src/mml/api/__init__.py | 86 + src/mml/cli.py | 105 + src/mml/configs/__init__.py | 8 + src/mml/configs/arch/smp.yaml | 25 + src/mml/configs/arch/timm.yaml | 24 + src/mml/configs/augmentations/base_rand.yaml | 24 + .../configs/augmentations/baseline256.yaml | 18 + .../configs/augmentations/baseline512.yaml | 18 + src/mml/configs/augmentations/basic.yaml | 24 + src/mml/configs/augmentations/default.yaml | 53 + src/mml/configs/augmentations/kornia.yaml | 30 + .../augmentations/load_imagenet_aa.yaml | 15 + src/mml/configs/augmentations/no_norm.yaml | 11 + src/mml/configs/augmentations/none.yaml | 11 + .../configs/augmentations/randaugment.yaml | 20 + src/mml/configs/augmentations/v2.yaml | 18 + src/mml/configs/callbacks/cutmix.yaml | 17 + src/mml/configs/callbacks/default.yaml | 15 + src/mml/configs/callbacks/early.yaml | 32 + src/mml/configs/callbacks/mixup.yaml | 16 + src/mml/configs/callbacks/none.yaml | 11 + src/mml/configs/callbacks/stats.yaml | 19 + src/mml/configs/callbacks/swa.yaml | 18 + src/mml/configs/compile/default.yaml | 19 + src/mml/configs/config_mml.yaml | 92 + src/mml/configs/hpo/default.yaml | 61 + src/mml/configs/hpo/grid.yaml | 18 + src/mml/configs/hpo/sampler/grid.yaml | 12 + src/mml/configs/hpo/sampler/random.yaml | 12 + src/mml/configs/hpo/sampler/tpe.yaml | 12 + src/mml/configs/hydra/help/mml_help.yaml | 124 + .../hydra/hydra_logging/col_stdout.yaml | 24 + .../job_logging/col_stdout_and_file.yaml | 37 + .../job_logging/rich_stdout_and_file.yaml | 26 + .../hydra/job_logging/stdout_only.yaml | 21 + src/mml/configs/loaders/default.yaml | 43 + src/mml/configs/loaders/numpy.yaml | 18 + src/mml/configs/loaders/pillow.yaml | 18 + src/mml/configs/loaders/pillow_acc.yaml | 18 + src/mml/configs/loaders/scikit.yaml | 18 + src/mml/configs/loaders/torch.yaml | 18 + src/mml/configs/loaders/uni.yaml | 31 + .../logging/exp_logger/tensorboard.yaml | 27 + src/mml/configs/logging/log.yaml | 34 + src/mml/configs/logging/notifier/email.yaml | 26 + src/mml/configs/logging/notifier/none.yaml | 16 + src/mml/configs/logging/notifier/slack.yaml | 26 + src/mml/configs/logging/render/colorlog.yaml | 14 + src/mml/configs/logging/render/rich.yaml | 14 + src/mml/configs/loss/cls/ce.yaml | 12 + src/mml/configs/loss/default.yaml | 27 + src/mml/configs/loss/mlcls/bce.yaml | 12 + src/mml/configs/loss/mlcls/ce.yaml | 12 + src/mml/configs/loss/reg/huber.yaml | 16 + src/mml/configs/loss/seg/ce.yaml | 21 + src/mml/configs/loss/seg/dice.yaml | 21 + src/mml/configs/lr_scheduler/cosine.yaml | 17 + .../configs/lr_scheduler/cosine_restart.yaml | 17 + src/mml/configs/lr_scheduler/exponential.yaml | 17 + src/mml/configs/lr_scheduler/none.yaml | 12 + src/mml/configs/lr_scheduler/one_cycle.yaml | 22 + src/mml/configs/lr_scheduler/plateau.yaml | 29 + src/mml/configs/lr_scheduler/step.yaml | 21 + src/mml/configs/metrics/cls/default.yaml | 30 + src/mml/configs/metrics/default.yaml | 19 + src/mml/configs/metrics/mlcls/default.yaml | 15 + src/mml/configs/metrics/reg/default.yaml | 10 + src/mml/configs/metrics/seg/default.yaml | 13 + src/mml/configs/mode/clean.yaml | 32 + src/mml/configs/mode/create.yaml | 39 + src/mml/configs/mode/downgrade.yaml | 19 + src/mml/configs/mode/info.yaml | 41 + src/mml/configs/mode/post.yaml | 59 + src/mml/configs/mode/pp.yaml | 22 + src/mml/configs/mode/predict.yaml | 19 + src/mml/configs/mode/test.yaml | 19 + src/mml/configs/mode/tl.yaml | 30 + src/mml/configs/mode/train.yaml | 98 + src/mml/configs/mode/upgrade.yaml | 29 + src/mml/configs/optimizer/adam.yaml | 30 + src/mml/configs/optimizer/sgd.yaml | 30 + src/mml/configs/preprocessing/default.yaml | 25 + src/mml/configs/preprocessing/example.yaml | 23 + src/mml/configs/preprocessing/none.yaml | 14 + src/mml/configs/preprocessing/size224.yaml | 25 + src/mml/configs/preprocessing/size256.yaml | 25 + src/mml/configs/preprocessing/size336.yaml | 25 + src/mml/configs/preprocessing/size384.yaml | 25 + src/mml/configs/preprocessing/size512.yaml | 25 + src/mml/configs/preprocessing/size528.yaml | 25 + src/mml/configs/remove/all.yaml | 42 + src/mml/configs/remove/none.yaml | 21 + src/mml/configs/reuse/current.yaml | 20 + src/mml/configs/reuse/none.yaml | 11 + src/mml/configs/sampling/full.yaml | 41 + src/mml/configs/search_space/example.yaml | 20 + src/mml/configs/search_space/none.yaml | 10 + src/mml/configs/sys/cluster.yaml | 28 + src/mml/configs/sys/local.yaml | 23 + src/mml/configs/tasks/_template.yaml | 41 + src/mml/configs/tasks/fake.yaml | 46 + src/mml/configs/tasks/none.yaml | 47 + .../configs/tasks/pami_train_variants.yaml | 51 + src/mml/configs/trainer/default_trainer.yaml | 52 + src/mml/configs/tta/none.yaml | 10 + src/mml/configs/tta/rotate.yaml | 40 + src/mml/configs/tune/default.yaml | 32 + src/mml/core/__init__.py | 6 + src/mml/core/data_loading/__init__.py | 6 + .../data_loading/augmentations/__init__.py | 6 + .../augmentations/albumentations.py | 262 + .../augmentations/augmentation_module.py | 119 + .../data_loading/augmentations/imagenet.json | 85418 ++++++++++++++++ .../core/data_loading/augmentations/kornia.py | 140 + .../augmentations/mixup_cutmix.py | 227 + .../data_loading/augmentations/torchvision.py | 136 + src/mml/core/data_loading/file_manager.py | 822 + .../core/data_loading/lightning_datamodule.py | 383 + src/mml/core/data_loading/modality_loaders.py | 371 + src/mml/core/data_loading/task_attributes.py | 196 + src/mml/core/data_loading/task_dataset.py | 364 + src/mml/core/data_loading/task_description.py | 158 + src/mml/core/data_loading/task_struct.py | 397 + src/mml/core/data_loading/utils.py | 30 + src/mml/core/data_preparation/__init__.py | 8 + .../data_preparation/archive_extractors.py | 221 + src/mml/core/data_preparation/data_archive.py | 59 + src/mml/core/data_preparation/dset_creator.py | 401 + src/mml/core/data_preparation/fake_task.py | 84 + src/mml/core/data_preparation/registry.py | 97 + src/mml/core/data_preparation/task_creator.py | 838 + src/mml/core/data_preparation/utils.py | 367 + src/mml/core/models/__init__.py | 7 + src/mml/core/models/lightning_single_frame.py | 565 + src/mml/core/models/merger.py | 42 + src/mml/core/models/smp.py | 89 + src/mml/core/models/timm.py | 79 + src/mml/core/models/torch_base.py | 200 + src/mml/core/scripts/__init__.py | 6 + src/mml/core/scripts/callbacks.py | 141 + src/mml/core/scripts/decorators.py | 91 + src/mml/core/scripts/exceptions.py | 17 + src/mml/core/scripts/model_storage.py | 305 + src/mml/core/scripts/notifier.py | 264 + .../core/scripts/pipeline_configuration.py | 139 + src/mml/core/scripts/schedulers/__init__.py | 6 + .../core/scripts/schedulers/base_scheduler.py | 711 + .../scripts/schedulers/clean_scheduler.py | 158 + .../scripts/schedulers/create_scheduler.py | 137 + .../core/scripts/schedulers/info_scheduler.py | 214 + .../schedulers/postprocess_scheduler.py | 450 + .../schedulers/preprocess_scheduler.py | 184 + .../scripts/schedulers/train_scheduler.py | 501 + .../scripts/schedulers/transfer_scheduler.py | 115 + .../scripts/schedulers/upgrade_scheduler.py | 191 + src/mml/core/scripts/utils.py | 281 + src/mml/core/visualization/__init__.py | 6 + src/mml/core/visualization/cm.py | 40 + src/mml/core/visualization/logo.py | 21 + src/mml/core/visualization/mml_logo.txt | 11 + src/mml/core/visualization/predictions.py | 136 + src/mml/core/visualization/utils.py | 52 + src/mml/interactive/__init__.py | 100 + src/mml/interactive/loading.py | 110 + src/mml/interactive/planning.py | 427 + src/mml/template.env | 62 + src/mml/testing/__init__.py | 5 + src/mml/testing/dummy_fake_model_storage.json | 14 + src/mml/testing/dummy_fake_pipeline.yaml | 90 + src/mml/testing/dummy_fake_preds.pt | Bin 0 -> 272440 bytes src/mml/testing/dummy_meta_class.json | 112 + src/mml/testing/dummy_meta_seg.json | 112 + src/mml/testing/fixtures.py | 275 + tests/README.md | 14 + tests/conftest.py | 15 + tests/integration/conftest.py | 5 + tests/integration/core/test_clean_mode.py | 24 + tests/integration/core/test_create_mode.py | 11 + tests/integration/core/test_info_mode.py | 12 + tests/integration/core/test_post_mode.py | 58 + .../integration/core/test_preprocess_mode.py | 11 + tests/integration/core/test_train_mode.py | 43 + tests/manual/test_all_tags_correct.py | 93 + .../performance/test_dataset_loading_speed.py | 32 + .../test_file_manager_init_speed.py | 30 + tests/performance/test_meta_reading_speed.py | 22 + .../performance/test_scheduler_init_speed.py | 22 + tests/performance/test_training_speed.py | 23 + tests/unit/conftest.py | 53 + tests/unit/core/data_loading/conftest.py | 22 + .../core/data_loading/test_albumentations.py | 58 + .../core/data_loading/test_file_manager.py | 169 + .../data_loading/test_lightning_datamodule.py | 118 + .../core/data_loading/test_mixup_cutmix.py | 24 + .../core/data_loading/test_task_dataset.py | 116 + .../data_loading/test_task_description.py | 14 + .../core/data_loading/test_task_struct.py | 84 + .../test_archive_extractor.py | 26 + .../data_preparation/test_data_archive.py | 28 + .../data_preparation/test_dset_creator.py | 20 + .../core/data_preparation/test_prep_utils.py | 55 + .../data_preparation/test_task_creator.py | 209 + tests/unit/core/models/test_timm.py | 84 + .../unit/core/scripts/test_base_scheduler.py | 60 + tests/unit/core/scripts/test_model_storage.py | 22 + tests/unit/core/scripts/test_notifier.py | 25 + .../unit/core/scripts/test_train_scheduler.py | 34 + tests/unit/core/scripts/test_utils.py | 93 + tests/unit/interactive/test_planning.py | 77 + tests/unit/test_cli.py | 14 + 426 files changed, 116736 insertions(+) create mode 100644 .readthedocs.yaml create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 CITATION.cff create mode 100644 CONTRIBUTING.md create mode 100644 Dockerfile create mode 100644 LICENSES/MIT.txt create mode 100644 MANIFEST.in create mode 100644 README.md create mode 100644 RELEASE.md create mode 100644 license_header.template create mode 100644 plugins/README.md create mode 100644 plugins/_template/CHANGELOG.md create mode 100644 plugins/_template/LICENSE.txt create mode 100644 plugins/_template/MANIFEST.in create mode 100644 plugins/_template/README.md create mode 100644 plugins/_template/pyproject.toml create mode 100644 plugins/_template/setup.cfg create mode 100644 plugins/_template/src/mml_TODO/__init__.py create mode 100644 plugins/_template/src/mml_TODO/activate.py create mode 100644 plugins/_template/src/mml_TODO/configs/__init__.py create mode 100644 plugins/_template/tests/conftest.py create mode 100644 plugins/_template/tests/unit/test_dummy.py create mode 100644 plugins/data/CHANGELOG.md create mode 100644 plugins/data/LICENSE.txt create mode 100644 plugins/data/MANIFEST.in create mode 100644 plugins/data/README.md create mode 100644 plugins/data/pyproject.toml create mode 100644 plugins/data/setup.cfg create mode 100644 plugins/data/src/mml_data/__init__.py create mode 100644 plugins/data/src/mml_data/activate.py create mode 100644 plugins/data/src/mml_data/cli.py create mode 100644 plugins/data/src/mml_data/configs/__init__.py create mode 100644 plugins/data/src/mml_data/configs/tasks/all.yaml create mode 100644 plugins/data/src/mml_data/configs/tasks/all_clas.yaml create mode 100644 plugins/data/src/mml_data/configs/tasks/new.yaml create mode 100644 plugins/data/src/mml_data/creators/__init__.py create mode 100644 plugins/data/src/mml_data/creators/classification/__init__.py create mode 100644 plugins/data/src/mml_data/creators/classification/_template.py create mode 100644 plugins/data/src/mml_data/creators/classification/aptos_blindness.py create mode 100644 plugins/data/src/mml_data/creators/classification/barretts_esophagus.py create mode 100644 plugins/data/src/mml_data/creators/classification/brain_tumor.py create mode 100644 plugins/data/src/mml_data/creators/classification/brain_tumor_type.py create mode 100644 plugins/data/src/mml_data/creators/classification/breast_ultrasound.py create mode 100644 plugins/data/src/mml_data/creators/classification/caltech101.py create mode 100644 plugins/data/src/mml_data/creators/classification/caltech256.py create mode 100644 plugins/data/src/mml_data/creators/classification/cataract.py create mode 100644 plugins/data/src/mml_data/creators/classification/cervical_cancer_screening.py create mode 100644 plugins/data/src/mml_data/creators/classification/chexpert.py create mode 100644 plugins/data/src/mml_data/creators/classification/cholec45.py create mode 100644 plugins/data/src/mml_data/creators/classification/cholec80.py create mode 100644 plugins/data/src/mml_data/creators/classification/cifar.py create mode 100644 plugins/data/src/mml_data/creators/classification/covid_ct.py create mode 100644 plugins/data/src/mml_data/creators/classification/covid_ct_crawled.py create mode 100644 plugins/data/src/mml_data/creators/classification/covid_xray.py create mode 100644 plugins/data/src/mml_data/creators/classification/deep_drid.py create mode 100644 plugins/data/src/mml_data/creators/classification/derm7pt.py create mode 100644 plugins/data/src/mml_data/creators/classification/emnist.py create mode 100644 plugins/data/src/mml_data/creators/classification/hyper_kvasir.py create mode 100644 plugins/data/src/mml_data/creators/classification/ibean.py create mode 100644 plugins/data/src/mml_data/creators/classification/idle_frame_recognition.py create mode 100644 plugins/data/src/mml_data/creators/classification/isic20.py create mode 100644 plugins/data/src/mml_data/creators/classification/kvasir_capsule.py create mode 100644 plugins/data/src/mml_data/creators/classification/lapgyn4.py create mode 100644 plugins/data/src/mml_data/creators/classification/laryngeal.py create mode 100644 plugins/data/src/mml_data/creators/classification/mednode.py create mode 100644 plugins/data/src/mml_data/creators/classification/mnist.py create mode 100644 plugins/data/src/mml_data/creators/classification/mura.py create mode 100644 plugins/data/src/mml_data/creators/classification/nbi_infframes.py create mode 100644 plugins/data/src/mml_data/creators/classification/nerthus.py create mode 100644 plugins/data/src/mml_data/creators/classification/pneumonia.py create mode 100644 plugins/data/src/mml_data/creators/classification/shenzhen_tuberculosis.py create mode 100644 plugins/data/src/mml_data/creators/classification/sklin2.py create mode 100644 plugins/data/src/mml_data/creators/classification/stanford_dogs.py create mode 100644 plugins/data/src/mml_data/creators/classification/suncolondb.py create mode 100644 plugins/data/src/mml_data/creators/classification/svhn.py create mode 100644 plugins/data/src/mml_data/creators/segmentation/__init__.py create mode 100644 plugins/data/src/mml_data/creators/segmentation/crowd_source_instrument.py create mode 100644 plugins/data/src/mml_data/creators/segmentation/endovis18_robotic_instrument.py create mode 100644 plugins/data/src/mml_data/creators/segmentation/enid.py create mode 100644 plugins/data/src/mml_data/creators/segmentation/glenda.py create mode 100644 plugins/data/src/mml_data/creators/segmentation/hyper_kvasir.py create mode 100644 plugins/data/src/mml_data/creators/segmentation/image2image.py create mode 100644 plugins/data/src/mml_data/creators/segmentation/motion_based_recognition.py create mode 100644 plugins/data/src/mml_data/creators/segmentation/ph2.py create mode 100644 plugins/data/src/mml_data/creators/segmentation/voc.py create mode 100644 plugins/data/tests/conftest.py create mode 100644 plugins/data/tests/unit/test_dummy.py create mode 100644 plugins/dimensionality/CHANGELOG.md create mode 100644 plugins/dimensionality/LICENSE.txt create mode 100644 plugins/dimensionality/MANIFEST.in create mode 100644 plugins/dimensionality/README.md create mode 100644 plugins/dimensionality/pyproject.toml create mode 100644 plugins/dimensionality/setup.cfg create mode 100644 plugins/dimensionality/src/mml_dimensionality/__init__.py create mode 100644 plugins/dimensionality/src/mml_dimensionality/activate.py create mode 100644 plugins/dimensionality/src/mml_dimensionality/configs/__init__.py create mode 100644 plugins/dimensionality/src/mml_dimensionality/configs/mode/dim.yaml create mode 100644 plugins/dimensionality/src/mml_dimensionality/models/__init__.py create mode 100644 plugins/dimensionality/src/mml_dimensionality/models/knn.py create mode 100644 plugins/dimensionality/src/mml_dimensionality/scripts/__init__.py create mode 100644 plugins/dimensionality/src/mml_dimensionality/scripts/dimensionality_scheduler.py create mode 100644 plugins/dimensionality/src/mml_dimensionality/scripts/mle.py create mode 100644 plugins/dimensionality/src/mml_dimensionality/scripts/utils.py create mode 100644 plugins/dimensionality/src/mml_dimensionality/visualization/__init__.py create mode 100644 plugins/dimensionality/tests/conftest.py create mode 100644 plugins/dimensionality/tests/unit/test_dimensionality_scheduler.py create mode 100644 plugins/drive/CHANGELOG.md create mode 100644 plugins/drive/LICENSE.txt create mode 100644 plugins/drive/README.md create mode 100644 plugins/drive/pyproject.toml create mode 100644 plugins/drive/setup.cfg create mode 100644 plugins/drive/src/mml_drive/__init__.py create mode 100644 plugins/drive/src/mml_drive/activate.py create mode 100644 plugins/drive/src/mml_drive/prepare_hook.py create mode 100644 plugins/drive/tests/conftest.py create mode 100644 plugins/drive/tests/unit/test_dummy.py create mode 100644 plugins/index.txt create mode 100644 plugins/lsf/CHANGELOG.md create mode 100644 plugins/lsf/LICENSE.txt create mode 100644 plugins/lsf/MANIFEST.in create mode 100644 plugins/lsf/README.md create mode 100644 plugins/lsf/pyproject.toml create mode 100644 plugins/lsf/setup.cfg create mode 100644 plugins/lsf/src/mml_lsf/__init__.py create mode 100644 plugins/lsf/src/mml_lsf/activate.py create mode 100644 plugins/lsf/src/mml_lsf/requirements.py create mode 100644 plugins/lsf/src/mml_lsf/runner.py create mode 100644 plugins/lsf/src/mml_lsf/workers.py create mode 100644 plugins/lsf/tests/conftest.py create mode 100644 plugins/lsf/tests/unit/test_dummy.py create mode 100644 plugins/similarity/CHANGELOG.md create mode 100644 plugins/similarity/LICENSE.txt create mode 100644 plugins/similarity/MANIFEST.in create mode 100644 plugins/similarity/README.md create mode 100644 plugins/similarity/pyproject.toml create mode 100644 plugins/similarity/setup.cfg create mode 100644 plugins/similarity/src/mml_similarity/__init__.py create mode 100644 plugins/similarity/src/mml_similarity/activate.py create mode 100644 plugins/similarity/src/mml_similarity/configs/__init__.py create mode 100644 plugins/similarity/src/mml_similarity/configs/distance/emd.yaml create mode 100644 plugins/similarity/src/mml_similarity/configs/distance/ens.yaml create mode 100644 plugins/similarity/src/mml_similarity/configs/distance/fed.yaml create mode 100644 plugins/similarity/src/mml_similarity/configs/distance/fid.yaml create mode 100644 plugins/similarity/src/mml_similarity/configs/distance/kld.yaml create mode 100644 plugins/similarity/src/mml_similarity/configs/distance/mmd.yaml create mode 100644 plugins/similarity/src/mml_similarity/configs/distance/semantic.yaml create mode 100644 plugins/similarity/src/mml_similarity/configs/mode/similarity.yaml create mode 100644 plugins/similarity/src/mml_similarity/configs/plotting/distance.yaml create mode 100644 plugins/similarity/src/mml_similarity/configs/plotting/kam.yaml create mode 100644 plugins/similarity/src/mml_similarity/configs/plotting/tsne.yaml create mode 100644 plugins/similarity/src/mml_similarity/configs/sampling/extraction_default.yaml create mode 100644 plugins/similarity/src/mml_similarity/configs/sampling/extraction_minimal.yaml create mode 100644 plugins/similarity/src/mml_similarity/configs/search_space/fed_search.yaml create mode 100644 plugins/similarity/src/mml_similarity/configs/search_space/mmd_search.yaml create mode 100644 plugins/similarity/src/mml_similarity/scripts/__init__.py create mode 100644 plugins/similarity/src/mml_similarity/scripts/abstract_task_distance_scheduler.py create mode 100644 plugins/similarity/src/mml_similarity/scripts/ensemble_scheduler.py create mode 100644 plugins/similarity/src/mml_similarity/scripts/feature_distances.py create mode 100644 plugins/similarity/src/mml_similarity/scripts/fed_scheduler.py create mode 100644 plugins/similarity/src/mml_similarity/scripts/fisher.py create mode 100644 plugins/similarity/src/mml_similarity/scripts/sample_based_scheduler.py create mode 100644 plugins/similarity/src/mml_similarity/scripts/semantic_scheduler.py create mode 100644 plugins/similarity/src/mml_similarity/scripts/vector_distances.py create mode 100644 plugins/similarity/src/mml_similarity/visualization/__init__.py create mode 100644 plugins/similarity/src/mml_similarity/visualization/plot_2D.py create mode 100644 plugins/similarity/tests/conftest.py create mode 100644 plugins/similarity/tests/integration/test_dist_measures.py create mode 100644 plugins/similarity/tests/unit/test_fed_scheduler.py create mode 100644 plugins/sql/CHANGELOG.md create mode 100644 plugins/sql/LICENSE.txt create mode 100644 plugins/sql/MANIFEST.in create mode 100644 plugins/sql/README.md create mode 100644 plugins/sql/pyproject.toml create mode 100644 plugins/sql/setup.cfg create mode 100644 plugins/sql/src/mml_sql/__init__.py create mode 100644 plugins/sql/src/mml_sql/activate.py create mode 100644 plugins/sql/src/mml_sql/configs/__init__.py create mode 100644 plugins/sql/src/mml_sql/configs/hpo/sql.yaml create mode 100644 plugins/sql/tests/conftest.py create mode 100644 plugins/sql/tests/unit/test_dummy.py create mode 100644 plugins/suggest/CHANGELOG.md create mode 100644 plugins/suggest/LICENSE.txt create mode 100644 plugins/suggest/MANIFEST.in create mode 100644 plugins/suggest/README.md create mode 100644 plugins/suggest/pyproject.toml create mode 100644 plugins/suggest/setup.cfg create mode 100644 plugins/suggest/src/mml_suggest/__init__.py create mode 100644 plugins/suggest/src/mml_suggest/activate.py create mode 100644 plugins/suggest/src/mml_suggest/configs/__init__.py create mode 100644 plugins/suggest/src/mml_suggest/configs/mode/suggest.yaml create mode 100644 plugins/suggest/src/mml_suggest/scripts/__init__.py create mode 100644 plugins/suggest/src/mml_suggest/scripts/suggest_scheduler.py create mode 100644 plugins/suggest/tests/conftest.py create mode 100644 plugins/suggest/tests/integration/test_suggest_scheduler.py create mode 100644 plugins/tags/CHANGELOG.md create mode 100644 plugins/tags/LICENSE.txt create mode 100644 plugins/tags/README.md create mode 100644 plugins/tags/pyproject.toml create mode 100644 plugins/tags/setup.cfg create mode 100644 plugins/tags/src/mml_tags/__init__.py create mode 100644 plugins/tags/src/mml_tags/activate.py create mode 100644 plugins/tags/src/mml_tags/cli.py create mode 100644 plugins/tags/src/mml_tags/tags/__init__.py create mode 100644 plugins/tags/src/mml_tags/tags/confuse.py create mode 100644 plugins/tags/src/mml_tags/tags/redistribute_splits.py create mode 100644 plugins/tags/src/mml_tags/tags/shrink_train.py create mode 100644 plugins/tags/src/mml_tags/tags/subclass.py create mode 100644 plugins/tags/src/mml_tags/tags/subset.py create mode 100644 plugins/tags/tests/conftest.py create mode 100644 plugins/tags/tests/unit/test_dummy.py create mode 100644 pyproject.toml create mode 100644 setup.cfg create mode 100644 src/mml/__init__.py create mode 100644 src/mml/__main__.py create mode 100644 src/mml/api/__init__.py create mode 100644 src/mml/cli.py create mode 100644 src/mml/configs/__init__.py create mode 100644 src/mml/configs/arch/smp.yaml create mode 100644 src/mml/configs/arch/timm.yaml create mode 100644 src/mml/configs/augmentations/base_rand.yaml create mode 100644 src/mml/configs/augmentations/baseline256.yaml create mode 100644 src/mml/configs/augmentations/baseline512.yaml create mode 100644 src/mml/configs/augmentations/basic.yaml create mode 100644 src/mml/configs/augmentations/default.yaml create mode 100644 src/mml/configs/augmentations/kornia.yaml create mode 100644 src/mml/configs/augmentations/load_imagenet_aa.yaml create mode 100644 src/mml/configs/augmentations/no_norm.yaml create mode 100644 src/mml/configs/augmentations/none.yaml create mode 100644 src/mml/configs/augmentations/randaugment.yaml create mode 100644 src/mml/configs/augmentations/v2.yaml create mode 100644 src/mml/configs/callbacks/cutmix.yaml create mode 100644 src/mml/configs/callbacks/default.yaml create mode 100644 src/mml/configs/callbacks/early.yaml create mode 100644 src/mml/configs/callbacks/mixup.yaml create mode 100644 src/mml/configs/callbacks/none.yaml create mode 100644 src/mml/configs/callbacks/stats.yaml create mode 100644 src/mml/configs/callbacks/swa.yaml create mode 100644 src/mml/configs/compile/default.yaml create mode 100644 src/mml/configs/config_mml.yaml create mode 100644 src/mml/configs/hpo/default.yaml create mode 100644 src/mml/configs/hpo/grid.yaml create mode 100644 src/mml/configs/hpo/sampler/grid.yaml create mode 100644 src/mml/configs/hpo/sampler/random.yaml create mode 100644 src/mml/configs/hpo/sampler/tpe.yaml create mode 100644 src/mml/configs/hydra/help/mml_help.yaml create mode 100644 src/mml/configs/hydra/hydra_logging/col_stdout.yaml create mode 100644 src/mml/configs/hydra/job_logging/col_stdout_and_file.yaml create mode 100644 src/mml/configs/hydra/job_logging/rich_stdout_and_file.yaml create mode 100644 src/mml/configs/hydra/job_logging/stdout_only.yaml create mode 100644 src/mml/configs/loaders/default.yaml create mode 100644 src/mml/configs/loaders/numpy.yaml create mode 100644 src/mml/configs/loaders/pillow.yaml create mode 100644 src/mml/configs/loaders/pillow_acc.yaml create mode 100644 src/mml/configs/loaders/scikit.yaml create mode 100644 src/mml/configs/loaders/torch.yaml create mode 100644 src/mml/configs/loaders/uni.yaml create mode 100644 src/mml/configs/logging/exp_logger/tensorboard.yaml create mode 100644 src/mml/configs/logging/log.yaml create mode 100644 src/mml/configs/logging/notifier/email.yaml create mode 100644 src/mml/configs/logging/notifier/none.yaml create mode 100644 src/mml/configs/logging/notifier/slack.yaml create mode 100644 src/mml/configs/logging/render/colorlog.yaml create mode 100644 src/mml/configs/logging/render/rich.yaml create mode 100644 src/mml/configs/loss/cls/ce.yaml create mode 100644 src/mml/configs/loss/default.yaml create mode 100644 src/mml/configs/loss/mlcls/bce.yaml create mode 100644 src/mml/configs/loss/mlcls/ce.yaml create mode 100644 src/mml/configs/loss/reg/huber.yaml create mode 100644 src/mml/configs/loss/seg/ce.yaml create mode 100644 src/mml/configs/loss/seg/dice.yaml create mode 100644 src/mml/configs/lr_scheduler/cosine.yaml create mode 100644 src/mml/configs/lr_scheduler/cosine_restart.yaml create mode 100644 src/mml/configs/lr_scheduler/exponential.yaml create mode 100644 src/mml/configs/lr_scheduler/none.yaml create mode 100644 src/mml/configs/lr_scheduler/one_cycle.yaml create mode 100644 src/mml/configs/lr_scheduler/plateau.yaml create mode 100644 src/mml/configs/lr_scheduler/step.yaml create mode 100644 src/mml/configs/metrics/cls/default.yaml create mode 100644 src/mml/configs/metrics/default.yaml create mode 100644 src/mml/configs/metrics/mlcls/default.yaml create mode 100644 src/mml/configs/metrics/reg/default.yaml create mode 100644 src/mml/configs/metrics/seg/default.yaml create mode 100644 src/mml/configs/mode/clean.yaml create mode 100644 src/mml/configs/mode/create.yaml create mode 100644 src/mml/configs/mode/downgrade.yaml create mode 100644 src/mml/configs/mode/info.yaml create mode 100644 src/mml/configs/mode/post.yaml create mode 100644 src/mml/configs/mode/pp.yaml create mode 100644 src/mml/configs/mode/predict.yaml create mode 100644 src/mml/configs/mode/test.yaml create mode 100644 src/mml/configs/mode/tl.yaml create mode 100644 src/mml/configs/mode/train.yaml create mode 100644 src/mml/configs/mode/upgrade.yaml create mode 100644 src/mml/configs/optimizer/adam.yaml create mode 100644 src/mml/configs/optimizer/sgd.yaml create mode 100644 src/mml/configs/preprocessing/default.yaml create mode 100644 src/mml/configs/preprocessing/example.yaml create mode 100644 src/mml/configs/preprocessing/none.yaml create mode 100644 src/mml/configs/preprocessing/size224.yaml create mode 100644 src/mml/configs/preprocessing/size256.yaml create mode 100644 src/mml/configs/preprocessing/size336.yaml create mode 100644 src/mml/configs/preprocessing/size384.yaml create mode 100644 src/mml/configs/preprocessing/size512.yaml create mode 100644 src/mml/configs/preprocessing/size528.yaml create mode 100644 src/mml/configs/remove/all.yaml create mode 100644 src/mml/configs/remove/none.yaml create mode 100644 src/mml/configs/reuse/current.yaml create mode 100644 src/mml/configs/reuse/none.yaml create mode 100644 src/mml/configs/sampling/full.yaml create mode 100644 src/mml/configs/search_space/example.yaml create mode 100644 src/mml/configs/search_space/none.yaml create mode 100644 src/mml/configs/sys/cluster.yaml create mode 100644 src/mml/configs/sys/local.yaml create mode 100644 src/mml/configs/tasks/_template.yaml create mode 100644 src/mml/configs/tasks/fake.yaml create mode 100644 src/mml/configs/tasks/none.yaml create mode 100644 src/mml/configs/tasks/pami_train_variants.yaml create mode 100644 src/mml/configs/trainer/default_trainer.yaml create mode 100644 src/mml/configs/tta/none.yaml create mode 100644 src/mml/configs/tta/rotate.yaml create mode 100644 src/mml/configs/tune/default.yaml create mode 100644 src/mml/core/__init__.py create mode 100644 src/mml/core/data_loading/__init__.py create mode 100644 src/mml/core/data_loading/augmentations/__init__.py create mode 100644 src/mml/core/data_loading/augmentations/albumentations.py create mode 100644 src/mml/core/data_loading/augmentations/augmentation_module.py create mode 100644 src/mml/core/data_loading/augmentations/imagenet.json create mode 100644 src/mml/core/data_loading/augmentations/kornia.py create mode 100644 src/mml/core/data_loading/augmentations/mixup_cutmix.py create mode 100644 src/mml/core/data_loading/augmentations/torchvision.py create mode 100644 src/mml/core/data_loading/file_manager.py create mode 100644 src/mml/core/data_loading/lightning_datamodule.py create mode 100644 src/mml/core/data_loading/modality_loaders.py create mode 100644 src/mml/core/data_loading/task_attributes.py create mode 100644 src/mml/core/data_loading/task_dataset.py create mode 100644 src/mml/core/data_loading/task_description.py create mode 100644 src/mml/core/data_loading/task_struct.py create mode 100644 src/mml/core/data_loading/utils.py create mode 100644 src/mml/core/data_preparation/__init__.py create mode 100644 src/mml/core/data_preparation/archive_extractors.py create mode 100644 src/mml/core/data_preparation/data_archive.py create mode 100644 src/mml/core/data_preparation/dset_creator.py create mode 100644 src/mml/core/data_preparation/fake_task.py create mode 100644 src/mml/core/data_preparation/registry.py create mode 100644 src/mml/core/data_preparation/task_creator.py create mode 100644 src/mml/core/data_preparation/utils.py create mode 100644 src/mml/core/models/__init__.py create mode 100644 src/mml/core/models/lightning_single_frame.py create mode 100644 src/mml/core/models/merger.py create mode 100644 src/mml/core/models/smp.py create mode 100644 src/mml/core/models/timm.py create mode 100644 src/mml/core/models/torch_base.py create mode 100644 src/mml/core/scripts/__init__.py create mode 100644 src/mml/core/scripts/callbacks.py create mode 100644 src/mml/core/scripts/decorators.py create mode 100644 src/mml/core/scripts/exceptions.py create mode 100644 src/mml/core/scripts/model_storage.py create mode 100644 src/mml/core/scripts/notifier.py create mode 100644 src/mml/core/scripts/pipeline_configuration.py create mode 100644 src/mml/core/scripts/schedulers/__init__.py create mode 100644 src/mml/core/scripts/schedulers/base_scheduler.py create mode 100644 src/mml/core/scripts/schedulers/clean_scheduler.py create mode 100644 src/mml/core/scripts/schedulers/create_scheduler.py create mode 100644 src/mml/core/scripts/schedulers/info_scheduler.py create mode 100644 src/mml/core/scripts/schedulers/postprocess_scheduler.py create mode 100644 src/mml/core/scripts/schedulers/preprocess_scheduler.py create mode 100644 src/mml/core/scripts/schedulers/train_scheduler.py create mode 100644 src/mml/core/scripts/schedulers/transfer_scheduler.py create mode 100644 src/mml/core/scripts/schedulers/upgrade_scheduler.py create mode 100644 src/mml/core/scripts/utils.py create mode 100644 src/mml/core/visualization/__init__.py create mode 100644 src/mml/core/visualization/cm.py create mode 100644 src/mml/core/visualization/logo.py create mode 100644 src/mml/core/visualization/mml_logo.txt create mode 100644 src/mml/core/visualization/predictions.py create mode 100644 src/mml/core/visualization/utils.py create mode 100644 src/mml/interactive/__init__.py create mode 100644 src/mml/interactive/loading.py create mode 100644 src/mml/interactive/planning.py create mode 100644 src/mml/template.env create mode 100644 src/mml/testing/__init__.py create mode 100644 src/mml/testing/dummy_fake_model_storage.json create mode 100644 src/mml/testing/dummy_fake_pipeline.yaml create mode 100644 src/mml/testing/dummy_fake_preds.pt create mode 100644 src/mml/testing/dummy_meta_class.json create mode 100644 src/mml/testing/dummy_meta_seg.json create mode 100644 src/mml/testing/fixtures.py create mode 100644 tests/README.md create mode 100644 tests/conftest.py create mode 100644 tests/integration/conftest.py create mode 100644 tests/integration/core/test_clean_mode.py create mode 100644 tests/integration/core/test_create_mode.py create mode 100644 tests/integration/core/test_info_mode.py create mode 100644 tests/integration/core/test_post_mode.py create mode 100644 tests/integration/core/test_preprocess_mode.py create mode 100644 tests/integration/core/test_train_mode.py create mode 100644 tests/manual/test_all_tags_correct.py create mode 100644 tests/performance/test_dataset_loading_speed.py create mode 100644 tests/performance/test_file_manager_init_speed.py create mode 100644 tests/performance/test_meta_reading_speed.py create mode 100644 tests/performance/test_scheduler_init_speed.py create mode 100644 tests/performance/test_training_speed.py create mode 100644 tests/unit/conftest.py create mode 100644 tests/unit/core/data_loading/conftest.py create mode 100644 tests/unit/core/data_loading/test_albumentations.py create mode 100644 tests/unit/core/data_loading/test_file_manager.py create mode 100644 tests/unit/core/data_loading/test_lightning_datamodule.py create mode 100644 tests/unit/core/data_loading/test_mixup_cutmix.py create mode 100644 tests/unit/core/data_loading/test_task_dataset.py create mode 100644 tests/unit/core/data_loading/test_task_description.py create mode 100644 tests/unit/core/data_loading/test_task_struct.py create mode 100644 tests/unit/core/data_preparation/test_archive_extractor.py create mode 100644 tests/unit/core/data_preparation/test_data_archive.py create mode 100644 tests/unit/core/data_preparation/test_dset_creator.py create mode 100644 tests/unit/core/data_preparation/test_prep_utils.py create mode 100644 tests/unit/core/data_preparation/test_task_creator.py create mode 100644 tests/unit/core/models/test_timm.py create mode 100644 tests/unit/core/scripts/test_base_scheduler.py create mode 100644 tests/unit/core/scripts/test_model_storage.py create mode 100644 tests/unit/core/scripts/test_notifier.py create mode 100644 tests/unit/core/scripts/test_train_scheduler.py create mode 100644 tests/unit/core/scripts/test_utils.py create mode 100644 tests/unit/interactive/test_planning.py create mode 100644 tests/unit/test_cli.py diff --git a/ .readthedocs.yaml b/ .readthedocs.yaml new file mode 100644 index 0000000..959e625 --- /dev/null +++ b/ .readthedocs.yaml @@ -0,0 +1,25 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +version: 2 +build: + os: ubuntu-22.04 + tools: + python: "3.10" + +# build documentation in the docs/ directory with sphinx +sphinx: + configuration: docs/source/conf.py + builder: html + fail_on_warning: false + +# dependencies required to build docs +python: + install: + - method: pip + path: . + extra_requirements: + - docs \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..176a458 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..54b8e04 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +# local settings e.g. regarding paths, also contains tokens +src/mml/mml.env +# any potential virtual environment +venv/ +# intelliJ data +.idea/* +# dev install files +src/mml_core.egg-info/ +plugins/*/src/*.egg-info +# cache files +/**/__pycache__/ +/**/.pytest_cache/ +/**/.mypy_cache/ +/**/.coverage +# space to summarize your experiments +/notebooks/ +# report files +/unit_test_report.xml +/coverage_report.xml +# locally generated tox files +/.tox/ +# locally generated documentation +/docs/build/ +# pytest benchmark files +.benchmarks +# potential test builds +/build/ +#Visual Studio Code configuration Files +.vscode diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9f2a75c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,591 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 1.0.0 (12/19/2024): +The public release candidate for `mml`. + +### Features + - `use_best_params` now also accepts non-sql based multirun results + - extended documentation + - the initialization of `mml.interactive` is now guarded with helpful error messages + - open file limit errors are also guarded with helpful error messages (#126) + - refactors the `template.env` file with better documentation (and renaming) + +### Bug fixes + - `use_best_params` can now deal with config groups + - template plugin was refactored to avoid ??? in paths, ensuring Windows compatibility (#145) + - minor fixes in README, CONTRIBUTING and docs + +## 0.14.2 (11/15/2024): +This release publishes final preparations for the release of `mml`. + +### Features + - full CLI documentation and increased documentation coverage + - load function for `mml.interactive.AllTasksInfos` + - refactored the notification system and introduced `mml.core.scripts.notifier.BaseNotifier` + - meta file polishing + - ensure MIT license compatibility of plugins + +### Bug fixes + - `mml.core.scripts.utils.StrEnum` to be creatable from both key and value + +### API changes + - removed the `plotting` config group and added the `info` mode related settings to that file + +## 0.14.1 (09/23/2024): +This release publishes work in progress of the `mml` documentation. + +### Features + - added `sphinxcontrib-autoyaml` dependency and started CLI documentation in config files + +## 0.14.0 (08/29/2024): +This release introduces postprocessing and also extends prediction behaviour to comply with the `mml-suggest` plugin. +Other highlights are the extended reusability functionality, test time augmentation and the outsourcing of plugin +changelogs. + +### Features + - NEW: postprocessing scheduler - including quantification, calibration and automated ensembling + - NEW: test time augmentation in testing and predicting, activate e.g. via `tta=rotate` + - NEW: multi-project reusables (`reuse.parameters=[SOME_PROJ,OTHER_PROJ]`), global reusables (`MMLFileManager.instance().global_reusables`) and selecting specific version numbers (`reuse.parameters=SOME_PROJ#3`) + - extended predicting behaviour: now on validation, test and unlabelled split + - paths in model storage became relative - easing transferability of results between systems + - simplify the creating and loading of pipeline configurations + - new artefact: each run with return value produces a `return_val.txt` file at the end of `mml` + - disable progress bar in cluster mode + - individual CHANGELOG.md per plugin + - add test and unlabelled data to fake task + +### Bug fixes + - fix model checkpointing - now behaving correctly as documented and reducing training time + - fix incorrect detection of lightning tuning in lightningmodule + - fix progress bar import - now correctly displaying experiments + - fix some tests, including a better capture of warnings + - fix tarfile vulnerability in data archive extraction + +### API changes + - `reuse.clean_up` was moved to `remove`, so `reuse.clean_up.parameters=true` becomes `remove.parameters=true` + - `model_storage.py` moved from `mml.core.data_loading` to `mml.core.scripts` + - `find_data` in task creation now relies on `DataSplit` instead of string + - top level config `gpus` became `allow_gpu` (regulating non training usage of GPUs) + +## 0.13.3 (08/23/2024): +This release fixes a critical bug in preprocessing mode. + +### Bug fixes + - in the previous release preprocessing incorrectly produced corrupted images due to an obsolete float conversion + +## 0.13.2 (08/07/2024): +This release has two minor features added to model training/evaluation as well as some bug fixes. + +### Features + - loss weights may be passed from CLI (`loss.class_weights=[...]`) + - allow `mode.eval_on` to accept multiple tasks in `train` mode + +### Bug fixes + - `mml.interactive.planning.get_task_infos` deals properly with tagged tasks + +### Plugins + - mml-data fix incorrect import of `mml.interactive` + - add mml-drive to index + - mml-lsf worker setting is less greedy, exclusive process is dropped and connection is tested on startup + +## 0.13.1 (06/27/2024): +This release focuses on improving LSF Plugin experience as well as some bug fixes. + +### Bug fixes + - remove some artefacts in the docs + - remove inputtimeout dependency from upgrade scheduler + - fix batch size tuning + - fix randaugment augmentation + - fix load_imagenet_aa augmentation + +### Plugins + - LSF runner has received info, resubmit and retrieve functionality + +### Changed default values + - default_trainer config has changed (e.g. min_epochs) + - usage of persistent workers reintroduced, see lightning datamodule + +## 0.13.0 (06/21/2024): +This release comprises some restructurings, improved documentation and usability as well as intense preparations for +a release (e.g. license headers, removal of non-compliant code parts). A major usage change is omitting the `mode=` +part from CLI. Nice new features are regression task support, interactive job runners, support of torchvision +transforms, dependency updates and many more! + +### Features + - the `mode=MODE` part of calling mml has been replaced by simply calling `mml MODE` + - improved `mml --help` and plain `mml` cli calls + - major restructurings of the package + - decorators and exceptions have received individual modules `mml.core.scripts.decorators` (resp. `exceptions`) + - `mml.api.interactive` moved to `mml.interactive` + - introduced `AugmentationModules` in `mml.core.data_loading.augmentations`, now supporting `kornia`, `torchvision` and `albumentations` + - support for `TaskType.REGRESSION` + - more effective and consistent preprocessing of tagged tasks + - `ModelStorage` can now be updated (simply call `store()` without any arguments from a loaded `ModelStorage`) + - `JobRunner` class for interactive `MMLJobDescription` usage + - model head re-mapping, see `SingleFrameLightningModule.setup_redirection()` + - added linear probing via `mml tl mode.freeze=True ...` + - improved metrics tracker callback (now accessible through scheduler) + - a nice WIP Bar indicating MML computations without any logged output + - more modality loaders + - switched from flake8 to ruff linter (plus formatter) + - simplify `tox.ini` + - added license header to all code files + +### Bug fixes + - mixup and cutmix callbacks + - torch base checkpointing and backbone freezing + - continue mode logging directory + +### Plugins + - `mml-similarity` has seen some major make-over to be ready for release + - removed `dds` mode + - is called through single mode "similarity" and new config group "distance" + - fix some bugs that have been introduced through `mml-core` changes + - plus fix return value by task groups + - introduced `mml-drive` as IMSY internal feature for faster downloads + - `m̀ml-lsf` has received a remote cluster job runner + +## 0.12.0 (01/24/2024): +Mainly focuses on cleaning the MML backend. More generic task descriptions, additional Modality support as well as a +generic model concept are at the core of the release. It is important to note, that existing databases from previous +versions need to migrate (after upgrading `mml-core` run `mml mode=upgrade mode.version=0.11.1`) once. To undo this +you may call (`mml mode=downgrade mode.version=0.11.1` BEFORE downgrading `mml-core` package). + +### Features + - a new dataclass `TaskDescription` to replace `current_meta` dictionary of `TaskCreator` (#98) + - deprecate `TaskStruct.id` (#98) + - improved support for future `Modality`'s, e.g. video processing (#20) + - faster task tagging + - preprocessing of test data to allow for e.g. nested tasks + - a new mode `clean` to remove artefacts automatically and free disk space + - new modes `upgrade`/`downgrade` to support migrating between versions of breaking compatibility (#98) + - extended `ModelStorage` to hold task and fold information as well as creation time + - a new task tag `nested` to allow better validation strategies (#91) + - updated documentation + - cleaning of config artefacts + - updated dependencies, including removal of extras `[optuna]` and `[jupyter]` adding them as core dependencies + - a `mml --version` implementation (#97) + - renamed task attribute `Tag` to `Keyword` to avoid confusion with task tagging + - stable support for joint cpu and gpu augmentations (#28) + - finally a stable license (#46) + - refactoring models, allowing much more generic future extensions plus supporting multi-task in `mml-core` (#47) + - test time metric bootstrapping (#91) + - extend `info` mode to show information on existing trained models + - replaced `opt` scheduler by `train` scheduler, with cross-validation support (#91) + - implemented `transfer` scheduler in `mml-core` for transfer learning setups as inherited from `train` (#24) + - support for password-protected zip decryption during archive extraction + +### Bug fixes + - `MMLFileManager` now correctly determines latest file versions + - use a temp log path if creating `MMLFileManager` on the fly + +### Plugins + - `mml-tags` and `mml-data` have improved CLI, test via `mml-tags` or `mml-data --help` + - fixed some references in `mml-data` + - `mml-similarity` has additional visualization options, a fixed distance_measure abbreviation determination + - a new `mml-sql` plugin that supports SQL based hyperparameter optimization + - removed `mml-multi-task`, `mml-self-supervised` and `mml-student` plugins + - `mml-data` has received a new task `suncolondb-classification` + +### Additional Contributors + - Leon Mayer + +## 0.11.1 (06/06/2023): + +### Features + - add path information to the notification system `mml.core.scripts.notifier.py` + - `ModelStorage` now also holds references to the created predictions + +### Bug fixes + - docker handling in gitlab CI + - made temporary task file creation more parallelism safe in statistics calculation of new tasks + +### Plugins + - `mml-data` update `idle_action_recognition` download path + +## 0.11.0 (05/26/2023): + +### Features + - BETA: docker support (#17, #74) + - BETA: kornia image augmentations support (#28, #75) + - BETA: torch.compile support (#51) + - mml.api.interactive can now be provided a `MML_ENV_PATH` + - more efficient checkpointing strategy (#62) + - gitlab CI efficiency optimization + - scheduler post initialization hooks, allowing plugins to interactively adapt the configs + +### Bug fixes + - dependency version fixes + - minor documentation errors + - continue status command indexing + +## Plugins + - new plugin `mml-lsf` for DKFZ LSF cluster convenience features + - `mml-similarity` + - TSNE task visualization + - additional distance task colorization criteria + - `mml-tags` + - fix plugin activation + - `shrink_train` has become an 'incremental' subsetting strategy (controllable via seed option) + +### Additional Contributors + - Marco Hübner + - Dominik Michael + - Piotr Kalinowski + - Amine Yamlahi + +## 0.10.2 (05/03/2023): + +### Features + - new `mml` logo + - sped up task size calculations + - additional test benchmarks + - gitlab CI optimizations + - cleaning of project files, e.g. previously cached notebooks + +### Bug fixes + - documentation errors + +### Additional Contributors + - Marco Hübner + - Dominik Michael + - Piotr Kalinowski + - Amine Yamlahi + +## 0.10.1 (04/18/2023): + +### Features + - add `mml-env-setup` console script + +## 0.10.0 (04/17/2023): + +`0.10` marks splitting `mml` into `mml-core` and various plugins. + +### Features + - drastically improved docs, including runtime diagram, API documentation and a lot of guides for beginners + - more integration tests + - new `MML_ENV_PATH` environment variable to freely place your `.env` file + - README update + - plugins are loaded before hydra config compilation to allow for modified search paths + - file manager `clean_up` is now ready for parallel processing + - automatically set `torch.set_float32_matmul_precision('high')` for better tensorcore usage + - ansi art `mml` logo + - a lot cleaner set of default config files + - `mml.testing` and a `pytest` plugin to provide generic fixtures used in testing `mml` itself and plugins + +### API changes + - access task structs via `scheduler.get_struct` instead of `scheduler.task_factory.get_by_name` + - lightning `accelerator` and `devices` support instead of previous `gpus` + - `create`/`preprocess` and `optimization` have moved into `core` + - `mml-lib-init` has been renamed to `mml-copy-conf` + - removed `assets` and outsourced many others to plugins + - removed `mode.id` requirement for configs + - scheduler task dumping is now done automatically + +### Bug fixes + - some fixes related to the previous upgrades of `lightning`, `torchmetrics` and `torch` (logging, progress bar, ...) + - error handling with unset notification env variables + +## 0.9.0 (03/21/2023): + +### Features + - support python 3.9 and 3.10 + - support pytorch 2.0, lightning 2.0 and hydra 1.3 + - add `mml_data` and `mml_tags` plugins to outsource non-core components + - refactored task creators to ensure more safety measures and better error messages, including an `auto_complete` method + - added prediction subroutines to opt mode + - added caching option for smaller datasets, use `sampling.enable_caching` and `sampling.cache_max_size` to configure + - more tests, pylint analysis and badge + +### API changes + - dropped support for `AA` mode, may come back with `kornia` support + - refactored task tagging, new separators are `+` (tags) and `?` (params) + - minor renaming, e.g. + - `Scheduler` nas been renamed to `AbstractBaseScheduler` + - `api.notebooks` bas been renamed to `api.interactive` + - dropped support for dict-like task creators + - lightning callbacks have been moved from `cfg.callbacks` to `cfg.cbs` + +### Bug fixes + - class balanced sampling for multi-task learning + +## 0.8.1 (01/31/2023): + +### Features + - added task tag `redistribute` to change relative data splits + - added slack notifier, set env variable `MML_SLACK_WEBHOOK_URL` and activate `logging.slack` in the configs (#33) + - added email notifiers, set a bunch of env variables and activate `logging.email` (#33) + - increased test suite + - increased type hints + - added citation file `CITATION.cff` + +### API changes + - the scheduler's lock path became an attribute + - renamed `catch_time` from `mml.core.scripts.utils` + - split testing from returning task struct within `TaskStructFactory`'s `get_by_name` + +### Bug fixes + - fix incorrect generation of `breast_cancer_classification` task + - fix incorrect computation / logging of validation and test metrics + - some remaining `LeraningPhase` and `DataSplit` references + +## 0.8.0 (12/16/2022): + +### Features + - added `mode=dim` for dimensionality estimation of tasks + - a set of convenience features in `api.notebooks` for experiment planning + - `deprecated` and `beta` decorators + - visualization of predicted samples + - logging of confusion matrix + - increased test coverage + - increased loading speed for `ModelStorage` by switching from `.yaml` to `.json` + - better formatting of `warnings` + - performance improvements with `persistent_workers` + +### API changes + - introduced `LearningPhase` and `DataSplit` for use in datamodule and models + +### Bug fixes + - progress bar version shows active step naming + - loading of metric values when reusing models + - fixed a bug that occurred if continue mode was started without a previous model checkpoint being instantiated + - linked `batch_size` in `aa` mode correctly + - some fixes regarding the new path assignment strategy of `MMLFileManager` + +## 0.7.4 (09/21/2022): +Support `EMPTY_MASK_TOKEN` during `find_data()` + +### Bug fixes + - allow `EMPTY_MASK_TOKEN` in `TaskCreator` + +## 0.7.3 (09/21/2022): +Speed improvements for task creation. + +### Features + - `EMPTY_MASK_TOKEN` for empty segmentation masks + - faster fold checks + +## 0.7.2 (09/21/2022): +Fixes incapability to handle non-archived "downloaded" folders. + +### Features + - support unpacking of folders during dset creation + +## 0.7.1 (09/20/2022): +Fixes plugins usage of `mml`. + +### Bug fixes + - fixing incorrect iteration over `mml.plugins` + - move plugin loading into hydra decorated main + + +## 0.7.0 (09/19/2022): +This release focuses on the future library usage of `mml`. + +### Features + - drastically improved documentation + - `mml.api` for easier usage as a lib + - `mixup` and `cutmix` callbacks + - callbacks are now intended to be stacked in CLI e.g. `+callbacks=[cutmix,swa]` + - file manager paths greatly supports extendability, see `add_path_assignment` + - `mml.plugins` entry point for other packages + +### Bug fixes + - fixing task probabilities with different task sizes in `mode=multi` + +## 0.6.1 (08/26/2022): +Minor immediate fixes regarding packaging via gitlab. + +### Bug fixes + - gitlab CI deployment procedure + - installation as a package fix for `private.env` + +## 0.6.0 (08/26/2022): +This is a major step forward with MML. After moving to gitlab and setting up a complete CI infrastructure +much more convenience and continuity is to be expected. Some changes may cause backward incompatibility issues +(more detailed: git root folder has been shifted, variables in the private env config file have changed and a newer +hydra version is used)! +Thus it is recommended to install mml from scratch when switching version. + +### Features + - mml can be used as a library! See README.md for details + - new `mode=multi` for multi task learning + - new `mode=tl` for transfer learning + - new `mode=ss` for self-supervised learning + - new `mode=stud` for student learning + - new task type `MULTILABEL_CLASSIFICATION` for multi label classification tasks (even with soft labels) + - made setup fully declarative -> no `setup.py` anymore, but all `setup.cfg` and `pyproject.toml` + - new tasks and datasets that are added to `mml/create_tasks/data/preparation/classification` and `mml/create_tasks/data/preparation/segmentation` do not need to be added to the respective `__init__.py` files any more + - started with spinx documentation + - added ensembling of task similarities: new mode `ens` with input like `mode.sources=[proj_one_fed,proj_two_mmd,proj_one_kld]` + - added cholect45 tasks + - task similarity modes (e.g. `fed`, `mmd`, ...) now have a return value to allow for hpo + - errors are getting logged with backtrace, including the backtrace, warnings are logged as well + - training time of models is logged automatically in model storage + - new task tag --shrink_train, allows for keeping identical validation split in reduced tasks + - extended `mode=info` + +### API changes + - task `diabetic_retinopathy_diagnosis` has been renamed as `aptos19_blindness_detection` + - using the imagenet AA has become a pipeline component instead of a separate config file + +### Bug fixes + - added time information to active_step_naming to avoid tensorboard run overlay in `--multirun` calls + - resolved bug in preprocessing mode, that skipped preprocessing if no pivot was given + - some updated task creations, due to changed urls + - fixed deprecated stuff from pytorch lightning, albumentations, hydra, ... + - fixed race condition issued when multiple runs in parallel might request saving paths from file manager + +### Known Issues + - performance of segmentation models poorly (opt mode, voc12 task, dice loss) + - cross system support for model storage paths + + +## 0.5.0 (03/22/2022): + Mainly improved setup time, updated torch and torchvision version as well as a bunch of new tasks. + +### Features + - `mode=info` was extended by subroutine `sample_grid`, producing a grid view of one sample per task + - Faster MML setup time :) Introducing `load_meta_header` in `MMLFileManager` only partially parses .json files + - dropped torchmetrics version restriction, so feel free to use more recent versions + - started with some example notebooks in `notebooks/examples` to be continued + - lots of tasks added, see `config/tasks/new.yaml` + - use more recent `torch` and `torchvision` versions + +### API changes + +### Bug fixes + - `AA` mode now actually uses `arch.pretrained` (was previously not depending upon it) + +### Known Issues + - performance of segmentation models poorly (opt mode, voc12 task, dice loss) + - storing paths currently does not transfer between systems (e.g. storing a fim/features/modelstorage on the cluster and transfering it to a local machine) + + +## 0.4.1 (02/16/2022): + Some small improvements, mainly to avoid information leakage scenarios in `opt` mode. + +### Features + - new callback `mml.task_optimization.scripts.utils.DropAugmentations` that turns off augmentations as suggested in [here](https://openreview.net/pdf?id=ZcKPWuhG6wy) + - new augmentation `load_imagenet_aa` loads a (imagenet) pretrained aa augmentation pipeline (found in assets) + - `opt` mode also stores all metric progress in `ModelStorage` (via new `MetricCallback`) + - `infer` mode has new config value `alpha` for weighing in `samples_plus_distance` strategy + - class weights for losses are scaled more towards `1.0`, which stabilizes training and makes `lr` transferable + - added `lr_scheduler=step` config option + +### API changes + - new boolean config value `val_is_test` of mode `opt` determines information leakage of validation split on training + - some checks in `opt` mode try to avoid other forms of information leakage as from `EarlyStopping` callback based on `val` loss/metric + - default number of `trainer.max_epochs` has changed from `200` to `50` in `opt` mode + - `aa` mode only uses `train` split for training instead of previous `full_train` split + +### Bug fixes + +### Known Issues + - performance of segmentation models poorly (opt mode, voc12 task, dice loss) + - storing paths currently does not transfer between systems (e.g. storing a fim/features/modelstorage on the cluster and transfering it to a local machine) + - loading time at the beginning becomes a bit long, so probably do both: conditional import on mode (not import for all modes) and split meta info into meta / tuples / folds + +## 0.4.0 (02/08/2022): + +Since the package setup and arrangement changed, a fresh installation of your environment is necessary! See README! Also +rename your `local.env` to `personal.env`! Also make sure to set the kaggle credentials during this migration (see `example.env`). + +### Features + - added plotting criteria for the distance methods (e.g. plotting.distance.criteria=task_type) + - added a lot of tasks, see `mml/configs/tasks/new.yaml` for a full list + - segmentation encoder uses now same pretrained weights as classification encoder (ATTENTION: Since this uses a feature that has not been released yet atm you have to manually pip uninstall segmentation-models-pytorch and then pip install git+https://github.com/qubvel/segmentation_models.pytorch) + - added RandAugment as augmentation (see config/augmentations/randaugment) + - classification tasks now report more metrics + - installation of the auto-augment environment is now handled as package extra + - autoalbument fork is now used to support newer versions of timm and segmentation_models_pytorch (together with recent pytorch versions) + - new mml mode "infer" that uses similarity knowledge to generate pipeline blueprints for target tasks based on previous runs and task similarity + - new mml mode "crawl" is an alias for optimization mode without a pivot and lower number of epochs + - `ModelStorage` now wraps trained models and eases reuse of them, see `file_manager.py` for the details + - it is possible to directly download data via the kaggle api (see `dset_creator.py` for implementation and `covid_xray.py` for example usage) + - scheduler now acquire a lock to avoid race conditions within the same running folder + - AutoAugmentation is now able to store pipeline decoupled from preprocessing + +### API changes + - the setup has been extended with `setup.cfg`, `pyproject.toml` and more testing packages, requirements have been updatet + - new config option: `use_best_params` eases reuse optimal parameters of optuna hpo searches, see README + - the environments settings file has been renamed from `local.env` to `personal.env` better reflecting its purpose + - the storing of trained models is now wrapped as ModelStorage (see `mml.core.data_loading.file_manager.py` for details) + - previously named `quick_tune` routine of optimization mode is renamed to `train_fold` + - `additional_preparation_instructions` is now `after_preparation_hook` and `additional_finishing_instructions` is now `before_finishing_hook` of `Scheduler` + - the default preprocessing pipeline has changed to `default.yaml` (instead of `example.yaml`) + - because auto augmentation pipelines are now composed differently, this breaks backward compatibility with previously generated pipelines + - TEMP files folder moved from project level to run level + - `use_best_params` option does not require `hpo=optuna` any more + - unified optimization direction for metrics is now 'minimize' to ensure compatibility with default optuna setting + - reusables of the file manager are not longer based on `task.id` but on `task.name`, so they becom independent from dset and task numbering, which could be inconsistent across systems and preprocessings + - the run folders have now added milliseconds, to avoid racing conditions on the cluster + +### Bug fixes + - refactored endovis18 endoscopic instrument segmentation task + - fixed plotting after AA mode with preprocessed tasks + - improved error message if a task was not found + - if rar backend fails, a better error message is shown + - an inefficient list comprehension from task_dataset was replaced (caused high latency with big tasks) + - set pretrained default to true (this caused very inconsistent results for months) + - `inf` as returned value caused hyperparameter optimization to crash, this is prevented by setting the return value very high instead + - running `mode=pp` with multiple tasks in parallel on the same dataset caused race condition problems, which is avoided now + +### Known Issues + - performance of segmentation models poorly (opt mode, voc12 task, dice loss) + - storing paths currently does not transfer between systems (e.g. storing a fim/features/modelstorage on the cluster and transfering it to a local machine) + - loading time at the beginning becomes a bit long, so probably do both: conditional import on mode (not import for all modes) and split meta info into meta / tuples / folds + - `ReuseConfig` dataclass still used `tuned` attribute in contrast to hydra config attribute `fc-tuned` + +## 0.3.1 (11/03/2021): + +Minor bug fixes and performance improvements. + +### Features + +### API changes + +### Bug fixes + - Compatible with pytorch-lightning >= 1.4 + - fisher computation speed up + - fixed CE loss for segmentation + - feature extraction speed up (if GPU available) + - fixed incorrect registered tasks enid and glenda + - fixed "reuse" key error for models with tuned final classifier (fc-tuned) + - fixed plotting of task similarity to show correct domains + +### Known Issues + - performance of segmentation models poorly (opt mode, voc12 task, dice loss) + - endovis18 endoscopic instrument segmentation task needs refactoring + +## 0.3.0 (10/07/2021): + +This version marks the start of collaborative work on MML. + +### Features + - added import functionality ob arbitrary pytorch datasets (see mml.core.data_preparation.DsetCreator.extract_from_pytorch_datasets) + - added two example datasets for the above + - SVHN: mml.create_tasks.data_preparation.classification.svhn.py + - VOC: mml.create_tasks.data_preparation.segmentation.voc.py + - refactored unit tests (see tests.unit) + - many more datasets/tasks have been included + - support of weighted losses for class imbalanced datasets + +### API changes + - set_active_naming is fully handled by BaseScheduler instead of abstract method (see mml.core.scripts.base_scheduler.py) + - made file manager a singleton class (see mml.core.data_loading.file_manager) so once instantiated by the scheduler it may be called from every other spot + - transform masks (dataset creator function) now takes a dict transform instead of list + +### Bug fixes + +### Known Issues + - Fisher computation as part of FED mode is rather slow + - Feature extraction as part of e.g., MMD should be sped up as well + - CE Loss for Segmentation raises error + - performance of segmentation models poorly (opt mode, voc12 task, dice loss) + - endovis18 endoscopic instrument segmentation tsak needs refactoring \ No newline at end of file diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000..fe15395 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,26 @@ +cff-version: 1.2.0 +title: Medical Meta Learner +message: If you use the mml framework, please also consider citing our corresponding publications. +type: software +authors: + - given-names: Patrick + family-names: Godau + email: patrick.godau@dkfz-heidelberg.de + affiliation: German Cancer Research Center (DKFZ) + orcid: 'https://orcid.org/0000-0002-0365-7265' +identifiers: + - type: doi + value: 10.1007/978-3-030-87202-1_42 + description: Task fingerprinting +repository-code: "https://github.com/IMSY-DKFZ/mml" +url: 'https://fill-in-the-documentation.de' +abstract: >- + Code for generating task fingerprints, working with + various heterogeneous datasets and integration of timm, + pytorch lightning and hydra libraries. +keywords: + - Meta Learning + - task fingerprinting +license: MIT +version: 1.0.0 +date-released: '2024-12-19' diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..d143d62 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,125 @@ +# Contributing to MML + +First of all: Thank you for your interest in contributing to `MML`! This document provides guidelines and +instructions for contributing to this project. In case you have any questions, do not hesitate to get in touch with +the members of the core development team: + +[Patrick Godau](patrick.godau@dkfz-heidelberg.de) + + + +* [Contributing to MML](#contributing-to-mml) + * [Getting Started](#getting-started) + * [Development Process](#development-process) + * [Code Style](#code-style) + * [Testing](#testing) + * [Pull Request Process](#pull-request-process) + * [License](#license) + * [Contribution review and integration](#contribution-review-and-integration) + * [List of Contributors](#list-of-contributors) + + +## Getting Started + +1. Fork the repository +2. Clone your fork +3. Create a virtual environment +4. Install ``mml` in editable mode including the development dependencies: + ```bash + pip install -e ".[dev,docs]" + ``` + +## Development Process + +1. Open an issue and discuss the strategy on how to tackle it +2. Create a new branch for your feature (`feature/`) or bugfix (`fix/`), add the number of the issue (e.g. `feature/123`) + ```bash + git checkout -b feature/123 + ``` +2. Make your changes, following our coding standards +3. Add tests for any new functionality +4. Run the test suite: + ```bash + pytest + ``` +5. Update documentation as needed (see [`docs`](docs/README.md)) +6. Commit your changes: + ```bash + git add . + git commit -m "Description of changes" + ``` + +## Code Style + +We follow these coding standards: + + * [PEP 8](https://peps.python.org/pep-0008/) - Python style guide + * [type hints](https://peps.python.org/pep-0484/) for function arguments and return values + * document functions and classes using `Sphinx` [docstrings](https://sphinx-rtd-tutorial.readthedocs.io/en/latest/docstrings.html) + * maximum line length of 120 characters (set in [`pyproject.toml`](pyproject.toml)) + +We use the following tools for code quality: + + * `ruff` for code formatting + * `isort` for import sorting + * `pylint` for overall quality + +Run the full suite of checks with: + +```commandline +ruff check +ruff format +isort . +pylint src/mml --max-line-length 120 +``` + +## Testing + +Add positive and negative test cases. Mock dependencies appropriately. The `mml.testing` package provides a set of +`pytest.fixtures` you can leverage even when writing tests for plugins. + +## Pull Request Process + + * update the [CHANGELOG.md](CHANGELOG.md) following [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format + * make sure all tests pass and code quality checks succeed + * check documentation, including docstrings of added / changed classes and functions + * submit a pull request with a clear description of the changes, for this your pull request should: + * have a clear, descriptive title + * reference any related issues + * include a summary of changes + * note any backward compatibility breaking changes + +## License + +By contributing, you agree that your contributions will be licensed under the project's license (MIT). +All added or edited code shall be the own original work of the particular contributor. If you use some third-party +implementation, all such blocks/functions/modules shall be properly referred and if possible also agreed by code’s +author. For example - "This code is inspired from http://...". In case you are adding new dependencies, make sure that +they are compatible with the actual license (i.e. dependencies should be at least as permissive as +the MIT license). + +## Contribution review and integration +To ensure correctness and high quality of the submitted code, each contribution will be checked by the CI pipeline +and reviewed by a member of the core development team regarding among others the following aspects: +- The code is correct and implements the [described feature / fixes the described issue](#getting-started) +- The code follows our [coding style](#code-style) +- The code is [documented appropriately](docs/README.md) +- The code is covered by sensible [unit tests](#testing) that pass upon submission +- The contribution does not lead to side effects in other parts of the toolkit (e.g. failing tests) +Once the reviewer is content with the contribution, the changes will be integrated into the code base. + +## List of Contributors + +In the following table we list the people that have contributed to the MML toolkit. + +Main author (>99%): + +- [Patrick Godau](https://www.dkfz.de/en/imsy/team/people/Patrick_Scholz.html) + +Other contributors: + +- [Akriti Srivastava](https://de.linkedin.com/in/akriti-srivastava-76041a120) +- [Leon Mayer](https://www.dkfz.de/en/imsy/team/people/Leon_Mayer.html) +- [Dominik Michael](https://www.dkfz.de/en/imsy/team/people/Dominik_Michael.html) +- [Piotr Kalinowski](https://www.dkfz.de/en/imsy/team/people/Piotr_Kalinowski.html) +- [Amine Yamlahi](https://www.dkfz.de/en/imsy/team/people/Amine_ElYamlahi.html) \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e751b7f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,50 @@ +FROM nvidia/cuda:11.7.1-base-ubuntu22.04 + +# Avoid Docker build freeze due to region selection +ENV DEBIAN_FRONTEND=noninteractive +ENV TZ=Europe/Berlin +RUN apt update && apt -y install tzdata + +# Basic tools +RUN apt update && apt install -y \ + build-essential \ + wget \ + git + +# Setup Python via conda (throuh miniforge) +ENV PATH=/opt/conda/bin:$PATH +RUN wget -O Miniforge3.sh https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh \ + && bash Miniforge3.sh -b -p "/opt/conda" \ + && rm -f Miniforge3.sh \ + && . "opt/conda/etc/profile.d/conda.sh" \ + && conda update -y -n base conda \ + && conda activate \ + && conda install -y python=3.10 + +# Copy necessary files +WORKDIR /mml +COPY plugins/ plugins/ +COPY src/ src/ +COPY tests/ tests/ +COPY MANIFEST.in pyproject.toml README.md setup.cfg tox.ini ./ + +# Install mml (insert your extras like e.g. "[dev, docs]" here) +ENV EXTRAS="" +RUN pip install ."$EXTRAS" && cd plugins + +# Install plugins +CMD /bin/bash -c 'while IFS='' read -r LINE || [ -n "${LINE}" ]; do \ + cd ${LINE} \n\ + pip install . \n\ + cd .. \n\ + done' < index.txt + +# Adapt mml.env and set env path +ENV NUM_WORKERS=8 +RUN mkdir /data \ + && mkdir /results \ + && mml-env-setup \ + && sed -i -e 's/\/path\/to\/data/\/data/;s/\/path\/to\/results/\/results/;s/available_local_CPU_cores/'$NUM_WORKERS'/' mml.env +ENV MML_ENV_PATH=/mml/mml.env + +CMD ["/bin/bash"] \ No newline at end of file diff --git a/LICENSES/MIT.txt b/LICENSES/MIT.txt new file mode 100644 index 0000000..6a39552 --- /dev/null +++ b/LICENSES/MIT.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 German Cancer Research Center (DKFZ) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..06a9edd --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,7 @@ +recursive-include src/mml/configs *.yaml +recursive-include src/mml/testing *.json +include src/mml/testing/dummy_fake_preds.pt +include src/mml/testing/dummy_fake_pipeline.yaml +include src/mml/core/data_loading/augmentations/imagenet.json +include src/mml/template.env +include src/mml/core/visualization/mml_logo.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..a121024 --- /dev/null +++ b/README.md @@ -0,0 +1,142 @@ +
+ +# Medical Meta Learner + +![mml_logo.png](docs%2Fsource%2F_static%2Fmml_logo.png) + +(Please note: badges are not yet finalized and are currently prepared for GitHub transition) + +[![docs status](https://readthedocs.org/projects/mml/badge/?version=develop)](https://mml.readthedocs.io/en/develop/?badge=develop) +![build status](https://github.com/IMSY-DKFZ/mml/actions/workflows//badge.svg) +[![pypi Badge](https://img.shields.io/pypi/v/mml-core)](https://pypi.org/project/mml-core/) +[![license](https://img.shields.io/badge/License-MIT-green.svg?labelColor=gray)](https://github.com/ashleve/lightning-hydra-template#license) +![docker status](https://github.com///actions/workflows//badge.svg) +
+[![Python](https://img.shields.io/pypi/pyversions/mml-core.svg)](https://pypi.org/project/mml-core) +[![pytorch](https://img.shields.io/badge/PyTorch_2.0+-ee4c2c?logo=pytorch&logoColor=white)](https://pytorch.org/get-started/locally/) +[![lightning](https://img.shields.io/badge/-Lightning_2.0+-792ee5?logo=pytorchlightning&logoColor=white)](https://pytorchlightning.ai/) +[![hydra](https://img.shields.io/badge/Config-Hydra_1.3-89b8cd)](https://hydra.cc/)
+[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) +[![isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) +CodeCov +Pylint + +
+ +
+ +## About + +`mml` is a research-oriented Python package which aims to provide an easy and scalable +way of performing deep learning on multiple image tasks (see +[Meta-Learning](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=9428530)). + +It features: + * a clear methodology to store, load, refer, modify and combine RGB image datasets across task types (classification, segmentation, ...) + * a highly configurable CLI for the full deep learning pipeline + * a dedicated file management system, capable of continuing aborted experiments, reuse previous results and parallelize runs + * an api for interactive pre- and post-experiment exploration + * smooth integration of latest deep learning libraries ([lightning](https://github.com/Lightning-AI/lightning), [hydra](https://github.com/facebookresearch/hydra), [optuna](https://github.com/optuna/optuna), ...) + * easy expandability via plugins or directly hooking into runtime objects via scripts or notebooks + * good documentation, broad testing and ambitious goals + +Please read the [official documentation page](https://imsy.pages.dkfz.de/ise/mml) for more. +Main author: Patrick Godau, Deutsches Krebsforschungszentrum (DKFZ) Heidelberg + +Division of Intelligent Medical Systems + +Contact: patrick.godau@dkfz-heidelberg.de + +## Setup + + +Create a virtual environment (e.g. using [conda](https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html)) as follows: + +```commandline +conda create -n mml python=3.10 +conda activate mml +``` + +Now create a gitlab access token via [this link](https://git.dkfz.de/-/user_settings/personal_access_tokens?name=mmlToken&scopes=read_api), +everything is already pre-filled, simply create and copy the token. Afterward within your projects virtual environment +you can call + +```commandline +pip install --index-url https://mmlToken:@git.dkfz.de/api/v4/projects/89/packages/pypi/simple mml-core +``` + +and replace with your actual token. You may add extras appended to mml as described [below](#extras). + +### plugins + +Plugins extend `mml` functionality. See [here](https://imsy.pages.dkfz.de/ise/mml/api/plugins/overview.html) for a +list of available plugins. Use the previous `pip` and replace `mml-core` with one of the plugins to install. + +### local environment variables + +`mml` relies on a `mml.env` file for relevant environment variables. There are multiple possibilities to locate this: + + - within your project folder (e.g. for separation of `mml` installations), + - within your home folder or similar (e.g. for shared `mml` configs across installations) + +You can use `mml-env-setup` from the command line at the location you want to place your `mml.env` file: + +```commandline +mml-env-setup +``` + +Now you only need to pinpoint `mml` to your `mml.env` file. This can be done via an environment variable `MML_ENV_PATH` +that needs to be present in the environment before starting `MML`. If you use conda this simplifies to + +```commandline +conda env config vars set MML_ENV_PATH=/path/to/your/mml.env +# if your file is located at the current working directory, you may instead use +# pwd | conda env config vars set MML_ENV_PATH=$(=42", + "wheel", +] +build-backend = "setuptools.build_meta" + +[tool.pytest.ini_options] +addopts = "--strict-markers --benchmark-skip" +testpaths = [ + "tests", +] +markers = [ + "slow: marks tests as slow (deselect with '-m \"not slow\"')", + "gpu: marks tests as requiring a gpu to run", + "env: marks test that require the correct underlying mml.env file", + "plugin: marks tests that require the loading of plugins", + "serial", +] + +[tool.isort] +src_paths = ["src", "tests"] +profile = "black" +line_length = 120 + +[tool.mypy] +mypy_path = "src" +check_untyped_defs = true +disallow_any_generics = true +ignore_missing_imports = true +no_implicit_optional = true +show_error_codes = true +strict_equality = true +warn_redundant_casts = true +warn_return_any = true +warn_unreachable = true +warn_unused_configs = true +no_implicit_reexport = true +disallow_untyped_defs = true +warn_unused_ignores = true +allow_redefinition = true +warn_no_return = true + +[tool.ruff] +# Set the maximum line length +line-length = 120 \ No newline at end of file diff --git a/plugins/_template/setup.cfg b/plugins/_template/setup.cfg new file mode 100644 index 0000000..43f6829 --- /dev/null +++ b/plugins/_template/setup.cfg @@ -0,0 +1,45 @@ +[metadata] +name = mml-TODO +version = attr: mml_TODO.__version__ +description = This is the MML ??? plugin, providing ??? +long_description = file: README.md +long_description_content_type = text/markdown +author = Patrick Godau +author_email = patrick.godau@dkfz-heidelberg.de +license = MIT +url = https://git.dkfz.de/imsy/ise/mml +classifiers = + Natural Language :: English + Development Status :: 4 - Beta + Environment :: Console + Intended Audience :: Developers + Topic :: Scientific/Engineering :: Artificial Intelligence + Topic :: Scientific/Engineering :: Image Recognition + Topic :: Scientific/Engineering :: Information Analysis + Topic :: Scientific/Engineering :: Image Processing + Topic :: Software Development :: Libraries :: Application Frameworks + Topic :: Software Development :: Version Control :: Git + Operating System :: OS Independent + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.10 + Environment :: GPU + Intended Audience :: Science/Research + Typing :: Typed + License :: OSI Approved :: MIT License + +[options] +python_requires = >=3.10 +package_dir = + =src +packages = find: +zip_safe = no +include_package_data = True +install_requires = + mml-core>=1.0.0 + +[options.entry_points] +mml.plugins = + mml-TODO = mml_TODO.activate + +[options.packages.find] +where=src diff --git a/plugins/_template/src/mml_TODO/__init__.py b/plugins/_template/src/mml_TODO/__init__.py new file mode 100644 index 0000000..48c09a8 --- /dev/null +++ b/plugins/_template/src/mml_TODO/__init__.py @@ -0,0 +1,9 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +VERSION = (0, 1, 0) +__version__ = ".".join(map(str, VERSION)) +__all__ = ["__version__"] diff --git a/plugins/_template/src/mml_TODO/activate.py b/plugins/_template/src/mml_TODO/activate.py new file mode 100644 index 0000000..d10039a --- /dev/null +++ b/plugins/_template/src/mml_TODO/activate.py @@ -0,0 +1,25 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from hydra.core.config_search_path import ConfigSearchPath +from hydra.core.plugins import Plugins +from hydra.plugins.search_path_plugin import SearchPathPlugin + + +# register plugin configs +# ATTENTION: +# - this is not required if you are not providing any new entries in the "configs" folder next to this file +# - you may then remove the configs folder and the lines below +# - ANYWAY everything that should be registered/loaded from within MML automatically must be done from here +# - IF you provide configs, replace INSERTPLUGINNAME with a suitable string for your plugin +# - AND replace the "TODO" such that it matches with the name of this plugin +class MMLINSERTPLUGINNAMESearchPathPlugin(SearchPathPlugin): + def manipulate_search_path(self, search_path: ConfigSearchPath) -> None: + # Sets the search path for mml with copied config files + search_path.append(provider="mml-TODO", path="pkg://mml_TODO.configs") + + +Plugins.instance().register(MMLINSERTPLUGINNAMESearchPathPlugin) diff --git a/plugins/_template/src/mml_TODO/configs/__init__.py b/plugins/_template/src/mml_TODO/configs/__init__.py new file mode 100644 index 0000000..90ffb6c --- /dev/null +++ b/plugins/_template/src/mml_TODO/configs/__init__.py @@ -0,0 +1,6 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + diff --git a/plugins/_template/tests/conftest.py b/plugins/_template/tests/conftest.py new file mode 100644 index 0000000..b3c6299 --- /dev/null +++ b/plugins/_template/tests/conftest.py @@ -0,0 +1,14 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import pytest + + +# by default the fixture below overrides the no_plugins fixture from mml.testing.fixtures to allow plugin testing +# you may remove this deactivation, put it into another submodule conftest.py and/or use the "plugin" marker to +# deactivate plugin loading solely for specific tests +@pytest.fixture(autouse=True) +def no_plugins(monkeypatch, request): + yield diff --git a/plugins/_template/tests/unit/test_dummy.py b/plugins/_template/tests/unit/test_dummy.py new file mode 100644 index 0000000..6259249 --- /dev/null +++ b/plugins/_template/tests/unit/test_dummy.py @@ -0,0 +1,9 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + + +def test_dummy(): + pass diff --git a/plugins/data/CHANGELOG.md b/plugins/data/CHANGELOG.md new file mode 100644 index 0000000..8cd374d --- /dev/null +++ b/plugins/data/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +All notable changes to this plugin will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.6.0 (12/19/2024): +Public release version after last license compatibility fixes. + +## 0.5.0 (08/29/2024): +This release introduces this changelog. The core dependency has also been bumped. diff --git a/plugins/data/LICENSE.txt b/plugins/data/LICENSE.txt new file mode 100644 index 0000000..6a39552 --- /dev/null +++ b/plugins/data/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 German Cancer Research Center (DKFZ) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/plugins/data/MANIFEST.in b/plugins/data/MANIFEST.in new file mode 100644 index 0000000..cbf0e67 --- /dev/null +++ b/plugins/data/MANIFEST.in @@ -0,0 +1 @@ +recursive-include src/mml_data/configs *.yaml \ No newline at end of file diff --git a/plugins/data/README.md b/plugins/data/README.md new file mode 100644 index 0000000..c862448 --- /dev/null +++ b/plugins/data/README.md @@ -0,0 +1,32 @@ +# MML Data plugin + +This plugin provides a wide range of datasets and tasks, ready to be imported. + +> In order to create tasks 'mml' might automatically download data. It is your responsibility to take care of the +> individual licensing regulations of such data and comply with them. See the respective task creators for more details. + +## Install + +```commandline +pip install mml-data +``` + +Some of the tasks require the [kaggle API](https://github.com/Kaggle/kaggle-api), which requires some authentication +to be set up. Based on the documentation this can be done via a `kaggle.json` file at a location depending on your OS, +or as the MML internal solution add your [credentials](https://github.com/Kaggle/kaggle-api#api-credentials) to the +`mml.env` file. + +```commandline +export KAGGLE_USERNAME=your_kaggle_username +export KAGGLE_KEY=your_kaggle_api_key +``` + +## Usage + +Tasks can be created with the `create` mode as usual. Furthermore, mml-data provides some convenience functionality +to show and filter for available tasks. Type `mml-data --help` for more details. + +## Outdated URLs + +Dataset download links might become deprecated over time. Please report any outdated urls via the issue tracker and we +will try to fix those. \ No newline at end of file diff --git a/plugins/data/pyproject.toml b/plugins/data/pyproject.toml new file mode 100644 index 0000000..449c6a9 --- /dev/null +++ b/plugins/data/pyproject.toml @@ -0,0 +1,52 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +[build-system] +requires = [ + "setuptools>=42", + "wheel", +] +build-backend = "setuptools.build_meta" + +[tool.pytest.ini_options] +addopts = "--strict-markers --benchmark-skip" +testpaths = [ + "tests", +] +markers = [ + "slow: marks tests as slow (deselect with '-m \"not slow\"')", + "gpu: marks tests as requiring a gpu to run", + "env: marks test that require the correct underlying mml.env file", + "plugin: marks tests that require the loading of plugins", + "serial", +] + +[tool.isort] +src_paths = ["src", "tests"] +profile = "black" +line_length = 120 + +[tool.mypy] +mypy_path = "src" +check_untyped_defs = true +disallow_any_generics = true +ignore_missing_imports = true +no_implicit_optional = true +show_error_codes = true +strict_equality = true +warn_redundant_casts = true +warn_return_any = true +warn_unreachable = true +warn_unused_configs = true +no_implicit_reexport = true +disallow_untyped_defs = true +warn_unused_ignores = true +allow_redefinition = true +warn_no_return = true + +[tool.ruff] +# Set the maximum line length +line-length = 120 \ No newline at end of file diff --git a/plugins/data/setup.cfg b/plugins/data/setup.cfg new file mode 100644 index 0000000..7d304f5 --- /dev/null +++ b/plugins/data/setup.cfg @@ -0,0 +1,49 @@ +[metadata] +name = mml-data +version = attr: mml_data.__version__ +description = This is the MML data plugin, providing dataset and task implementation for a bunch of datasets. +long_description = file: README.md +long_description_content_type = text/markdown +author = Patrick Godau +author_email = patrick.godau@dkfz-heidelberg.de +license = MIT +url = https://git.dkfz.de/imsy/ise/mml +classifiers = + Natural Language :: English + Development Status :: 4 - Beta + Environment :: Console + Intended Audience :: Developers + Topic :: Scientific/Engineering :: Artificial Intelligence + Topic :: Scientific/Engineering :: Image Recognition + Topic :: Scientific/Engineering :: Information Analysis + Topic :: Scientific/Engineering :: Image Processing + Topic :: Software Development :: Libraries :: Application Frameworks + Topic :: Software Development :: Version Control :: Git + Operating System :: OS Independent + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Environment :: GPU + Intended Audience :: Science/Research + Typing :: Typed + License :: OSI Approved :: MIT License + +[options] +python_requires = >=3.8 +package_dir = + =src +packages = find: +zip_safe = no +include_package_data = True +install_requires = + mml-core>=1.0.0 + +[options.entry_points] +mml.plugins = + mml-data = mml_data.activate +console_scripts = + mml-data = mml_data.cli:cli + +[options.packages.find] +where=src diff --git a/plugins/data/src/mml_data/__init__.py b/plugins/data/src/mml_data/__init__.py new file mode 100644 index 0000000..1801a42 --- /dev/null +++ b/plugins/data/src/mml_data/__init__.py @@ -0,0 +1,9 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +VERSION = (0, 6, 0) +__version__ = ".".join(map(str, VERSION)) +__all__ = ["__version__"] diff --git a/plugins/data/src/mml_data/activate.py b/plugins/data/src/mml_data/activate.py new file mode 100644 index 0000000..8a2a6f4 --- /dev/null +++ b/plugins/data/src/mml_data/activate.py @@ -0,0 +1,20 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import mml_data.creators # noqa +from hydra.core.config_search_path import ConfigSearchPath +from hydra.core.plugins import Plugins +from hydra.plugins.search_path_plugin import SearchPathPlugin + + +# register plugin configs +class MMLDataSearchPathPlugin(SearchPathPlugin): + def manipulate_search_path(self, search_path: ConfigSearchPath) -> None: + # Sets the search path for mml with copied config files + search_path.append(provider="mml-data", path="pkg://mml_data.configs") + + +Plugins.instance().register(MMLDataSearchPathPlugin) diff --git a/plugins/data/src/mml_data/cli.py b/plugins/data/src/mml_data/cli.py new file mode 100644 index 0000000..49c6eff --- /dev/null +++ b/plugins/data/src/mml_data/cli.py @@ -0,0 +1,160 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import argparse +from pathlib import Path +from typing import Dict, List, Optional + +from prettytable.colortable import ColorTable, Themes + +import mml.core.data_preparation.fake_task +import mml.core.data_preparation.task_creator as task_creator_module +from mml.core.data_loading.task_attributes import Keyword, TaskType +from mml.core.data_preparation.registry import _DATASET_CREATORS, _TASK_TO_DSET, _TASKCREATORS +from mml.core.scripts.utils import TAG_SEP, load_env, load_mml_plugins +from mml.interactive import default_file_manager + + +def get_all_avail_meta_data() -> dict: + """ + Reads in meta-data of available task creators without actually installing those tasks. + """ + # here we will store coded meta + coded_meta = {} + + # this dummy creator will be mocked and used instead of the actual task creator, it stores passed kwargs + class DummyTaskCreator: + def __init__(self, **kwargs): + nonlocal coded_meta + kwargs.pop("dset_path", None) + coded_meta[kwargs["name"]] = kwargs + raise RuntimeError("Intended interruption.") + + # do the mocking + creator_backup = task_creator_module.TaskCreator + task_creator_module.TaskCreator = DummyTaskCreator + + # import all the task creators and iterate + load_mml_plugins() + dummy_dset_path = Path("/dummy") + for task_alias, task_creator in _TASKCREATORS.items(): + # we cannot prevent to import this creator before mocking, on the other hand it is not required anyway + if task_alias == mml.core.data_preparation.fake_task.task_name: + continue + try: + # this reads in all kwargs into coded_meta variable + task_creator(dummy_dset_path) + except RuntimeError: + pass + + # undo mocking + task_creator_module.TaskCreator = creator_backup + + return coded_meta + + +def get_all_installed_tasks() -> Dict[str, List[str]]: + """ + Gathers all installed tasks and clusters by variants thereof. + """ + task_variants = {} + load_env() + with default_file_manager() as fm: + # all installed tasks + all_tasks = list(fm.task_index.keys()) + base_tasks = [t for t in all_tasks if (" " not in t and TAG_SEP not in t)] + for task in base_tasks: + task_variants[task] = [ + t[len(task) + 1 :] for t in all_tasks if (t.startswith(task + " ") or t.startswith(t + TAG_SEP)) + ] + return task_variants + + +def list_tasks( + task_types: Optional[List[TaskType]] = None, + keywords: Optional[List[Keyword]] = None, + installed: bool = False, + variants: bool = False, +): + """ + Lists all available tasks with filters applied. + + :param Optional[List[TaskType]] task_types: only show tasks of any given type + :param Optional[List[Keyword]] keywords: only show tasks that are marked with all provided keywords + :param bool installed: only show tasks that are installed (via create mode) + :param bool variants: instead of the default columns, show installed variants of tasks + :return: prints a table with columns ['name', 'dataset', 'type', 'installed', 'license'] and filtered + available tasks, if variants is True, the columns will be ['name', 'installed', 'variants'] + """ + # get task via definition + coded_meta = get_all_avail_meta_data() + # get installed tasks + task_variants = get_all_installed_tasks() + # will be displayed to the terminal + table = ColorTable(theme=Themes.OCEAN) + # counts variants of tasks during the loop + var_counter = 0 + # define table columns + if variants: + table.field_names = ["name", "installed", "variants"] + else: + table.field_names = ["name", "dataset", "type", "installed", "license"] + # loop over task definitions + for task, meta in coded_meta.items(): + # omit non-installed tasks if required + if installed and task not in task_variants: + continue + # filter by task type + if task_types and meta["task_type"] not in task_types: + continue + # filter by keywords + if keywords and not all([t in meta["keywords"] for t in keywords]): + continue + # count variants if installed + if task in task_variants: + var_counter += len(task_variants[task]) + # add information to table + if variants: + table.add_row([task, task in task_variants, task_variants[task] if task in task_variants else "-"]) + else: + table.add_row([task, _TASK_TO_DSET[task], meta["task_type"].value, task in task_variants, meta["lic"].name]) + # print table and summary + print(table) + print( + f"Overall {len(_TASKCREATORS)} raw tasks available, from {len(_DATASET_CREATORS)} datasets. Filter matches " + f"{len(table.rows)} raw tasks with additional {var_counter} variants derived thereof." + ) + + +def cli(): + """ + Parse arguments to mml-data and call the list_tasks function to print task information. + """ + parser = argparse.ArgumentParser( + prog="mml-data", description="Print available mml tasks with certain filters applied." + ) + parser.add_argument("-i", "--installed", action="store_true", help="limit to installed tasks only") + parser.add_argument( + "-k", + "--keyword", + action="extend", + nargs="*", + type=Keyword, + help=f"limit to a mandatory combination of keywords, options: {Keyword.list()}", + ) + parser.add_argument( + "-t", + "--type", + action="extend", + nargs="*", + type=TaskType, + help=f"limit to a variety of task types, options: {TaskType.list()}", + ) + parser.add_argument( + "-v", "--variants", action="store_true", help="display all variants of the given task that are installed" + ) + args = parser.parse_args() + list_tasks(task_types=args.type, keywords=args.keyword, installed=args.installed, variants=args.variants) diff --git a/plugins/data/src/mml_data/configs/__init__.py b/plugins/data/src/mml_data/configs/__init__.py new file mode 100644 index 0000000..90ffb6c --- /dev/null +++ b/plugins/data/src/mml_data/configs/__init__.py @@ -0,0 +1,6 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + diff --git a/plugins/data/src/mml_data/configs/tasks/all.yaml b/plugins/data/src/mml_data/configs/tasks/all.yaml new file mode 100644 index 0000000..c9c4e22 --- /dev/null +++ b/plugins/data/src/mml_data/configs/tasks/all.yaml @@ -0,0 +1,115 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +task_list: + # classification + - 'lapgyn4_anatomical_structures' + - 'lapgyn4_surgical_actions' + - 'lapgyn4_instrument_count' + - 'lapgyn4_anatomical_actions' + - 'nerthus_bowel_cleansing_quality' + - 'stanford_dogs_image_categorization' + - 'laryngeal_tissues' + - 'laryngeal_tissues_original_folds' + - 'identify_nbi_infframes' + - 'svhn' + - 'idle_action_recognition' + - 'barretts_esophagus_diagnosis' + - 'aptos19_blindness_detection' + - 'brain_tumor_classification' + - 'mednode_melanoma_classification' + - 'brain_tumor_type_classification' + - 'chexpert_enlarged_cardiomediastinum' + - 'chexpert_cardiomegaly' + - 'chexpert_lung_opacity' + - 'chexpert_lung_lesion' + - 'chexpert_edema' + - 'chexpert_consolidation' + - 'chexpert_pneumonia' + - 'chexpert_atelectasis' + - 'chexpert_pneumothorax' + - 'chexpert_pleural_effusion' + - 'chexpert_pleural_other' + - 'chexpert_fracture' + - 'chexpert_support_devices' + - 'covid-19-chest-ct-image-augmentation_raw' + - 'covid-19-chest-ct-image-augmentation_Aug' + - 'covid-19-chest-ct-image-augmentation_CGAN' + - 'covid-19-chest-ct-image-augmentation_Aug&CGAN' + - 'hyperkvasir_anatomical-landmarks' + - 'hyperkvasir_pathological-findings' + - 'hyperkvasir_quality-of-mucosal-views' + - 'hyperkvasir_therapeutic-interventions' + - 'pneumonia_classification' + - 'ph2-melanocytic-lesions-classification' + - 'sklin2_skin_lesions' + - 'derm7pt_skin_lesions' + - 'caltech101_object_classification' + - 'caltech256_object_classification' + - 'cifar10_object_classification' + - 'cifar100_object_classification' + - 'mnist_digit_classification' + - 'emnist_digit_classification' + - 'cholec80_grasper_presence' + - 'cholec80_bipolar_presence' + - 'cholec80_hook_presence' + - 'cholec80_scissors_presence' + - 'cholec80_clipper_presence' + - 'cholec80_irrigator_presence' + - 'cholec80_specimenbag_presence' + - 'covid_xray_classification' + - 'isic20_melanoma_classification' + - 'deep_drid_dr_level' + - 'shenzen_chest_xray_tuberculosis' + - 'crawled_covid_ct_classification' + - 'deep_drid_quality' + - 'deep_drid_clarity' + - 'deep_drid_field' + - 'deep_drid_artifact' + - 'kvasir_capsule_anatomy' + - 'kvasir_capsule_content' + - 'kvasir_capsule_pathologies' + - 'cervix_type_classification' + - 'breast_cancer_classification_v2' + - 'eye_condition_classification' + - 'mura_xr_wrist' + - 'mura_xr_shoulder' + - 'mura_xr_humerus' + - 'mura_xr_hand' + - 'mura_xr_forearm' + - 'mura_xr_finger' + - 'mura_xr_elbow' + - 'bean_plant_disease_classification' + - 'cholect45_triplet' + - 'cholect45_instrument' + - 'cholect45_verb' + - 'cholect45_target' + - 'cholect45_triplet_soft' + # PLEASE INSERT NEW TASKS ALSO IN THE SEPARATE NEW.YAML CONFIG + + # segmentation + - 'motion-based-segmentation' + - 'crowdsourced-endoscopic-instrument-segmentation-crowd-only' + - 'image2image-raw' + - 'image2image-rand' + - 'image2image-cholec80' + - 'glenda_endometriosis_segmentation' + - 'endometrial_implants' + - 'endovissub18_robotic_instrument_seg' + - 'pascal_voc_challenge_2012' + - 'hyperkvasir_polyp_segmentation' + - 'ph2-melanocytic-lesions-segmentation' +# PLEASE INSERT NEW TASKS ALSO IN THE SEPARATE NEW.YAML CONFIG + +pivot: + name: False + tags: '' + +tagging: + all: False + variants: [ ] \ No newline at end of file diff --git a/plugins/data/src/mml_data/configs/tasks/all_clas.yaml b/plugins/data/src/mml_data/configs/tasks/all_clas.yaml new file mode 100644 index 0000000..6e0c505 --- /dev/null +++ b/plugins/data/src/mml_data/configs/tasks/all_clas.yaml @@ -0,0 +1,95 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# incorporating all classification tasks + +task_list: + - 'lapgyn4_anatomical_structures' + - 'lapgyn4_surgical_actions' + - 'lapgyn4_instrument_count' + - 'lapgyn4_anatomical_actions' + - 'nerthus_bowel_cleansing_quality' + - 'stanford_dogs_image_categorization' + - 'laryngeal_tissues' + - 'laryngeal_tissues_original_folds' + - 'identify_nbi_infframes' + - 'svhn' + - 'idle_action_recognition' + - 'barretts_esophagus_diagnosis' + - 'aptos19_blindness_detection' + - 'brain_tumor_classification' + - 'mednode_melanoma_classification' + - 'brain_tumor_type_classification' + - 'chexpert_enlarged_cardiomediastinum' + - 'chexpert_cardiomegaly' + - 'chexpert_lung_opacity' + - 'chexpert_lung_lesion' + - 'chexpert_edema' + - 'chexpert_consolidation' + - 'chexpert_pneumonia' + - 'chexpert_atelectasis' + - 'chexpert_pneumothorax' + - 'chexpert_pleural_effusion' + - 'chexpert_pleural_other' + - 'chexpert_fracture' + - 'chexpert_support_devices' + - 'covid-19-chest-ct-image-augmentation_raw' + - 'covid-19-chest-ct-image-augmentation_Aug' + - 'covid-19-chest-ct-image-augmentation_CGAN' + - 'covid-19-chest-ct-image-augmentation_Aug&CGAN' + - 'hyperkvasir_anatomical-landmarks' + - 'hyperkvasir_pathological-findings' + - 'hyperkvasir_quality-of-mucosal-views' + - 'hyperkvasir_therapeutic-interventions' + - 'pneumonia_classification' + - 'ph2-melanocytic-lesions-classification' + - 'sklin2_skin_lesions' + - 'derm7pt_skin_lesions' + - 'caltech101_object_classification' + - 'caltech256_object_classification' + - 'cifar10_object_classification' + - 'cifar100_object_classification' + - 'mnist_digit_classification' + - 'emnist_digit_classification' + - 'cholec80_grasper_presence' + - 'cholec80_bipolar_presence' + - 'cholec80_hook_presence' + - 'cholec80_scissors_presence' + - 'cholec80_clipper_presence' + - 'cholec80_irrigator_presence' + - 'cholec80_specimenbag_presence' + - 'covid_xray_classification' + - 'isic20_melanoma_classification' + - 'deep_drid_dr_level' + - 'shenzen_chest_xray_tuberculosis' + - 'crawled_covid_ct_classification' + - 'deep_drid_quality' + - 'deep_drid_clarity' + - 'deep_drid_field' + - 'deep_drid_artifact' + - 'kvasir_capsule_anatomy' + - 'kvasir_capsule_content' + - 'kvasir_capsule_pathologies' + # - 'cervix_type_classification' + - 'breast_cancer_classification_v2' + - 'eye_condition_classification' + - 'mura_xr_wrist' + - 'mura_xr_shoulder' + - 'mura_xr_humerus' + - 'mura_xr_hand' + - 'mura_xr_forearm' + - 'mura_xr_finger' + - 'mura_xr_elbow' + - 'bean_plant_disease_classification' +pivot: + name: False + tags: '' + +tagging: + all: False + variants: [ ] \ No newline at end of file diff --git a/plugins/data/src/mml_data/configs/tasks/new.yaml b/plugins/data/src/mml_data/configs/tasks/new.yaml new file mode 100644 index 0000000..462e12b --- /dev/null +++ b/plugins/data/src/mml_data/configs/tasks/new.yaml @@ -0,0 +1,23 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# config for recently added tasks. + +task_list: + - 'cholect45_triplet' + - 'cholect45_instrument' + - 'cholect45_verb' + - 'cholect45_target' + - 'cholect45_triplet_soft' +pivot: + name: False + tags: '' + +tagging: + all: False + variants: [ ] \ No newline at end of file diff --git a/plugins/data/src/mml_data/creators/__init__.py b/plugins/data/src/mml_data/creators/__init__.py new file mode 100644 index 0000000..d8107ba --- /dev/null +++ b/plugins/data/src/mml_data/creators/__init__.py @@ -0,0 +1,21 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging + +from mml.core.data_preparation.registry import _DATASET_CREATORS, _TASKCREATORS + +_pre_length = len(_DATASET_CREATORS), len(_TASKCREATORS) + +import mml_data.creators.classification # noqa: F401, E402 +import mml_data.creators.segmentation # noqa: F401, E402 + +logger = logging.getLogger(__name__) + +logger.debug( + f"Detected {len(_DATASET_CREATORS) - _pre_length[0]} dataset creators and " + f"{len(_TASKCREATORS) - _pre_length[1]} task creator functions from mml_data plugin." +) diff --git a/plugins/data/src/mml_data/creators/classification/__init__.py b/plugins/data/src/mml_data/creators/classification/__init__.py new file mode 100644 index 0000000..cac8930 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/__init__.py @@ -0,0 +1,13 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +modules = Path(__file__).parent.glob("*.py") +# this will automatically import all valid submodules, so the tasks are registered automatically +__all__ = [module.stem for module in modules if module.is_file() and not module.stem.startswith("_")] + +from . import * # noqa F403, F401, E402 diff --git a/plugins/data/src/mml_data/creators/classification/_template.py b/plugins/data/src/mml_data/creators/classification/_template.py new file mode 100644 index 0000000..a2c6973 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/_template.py @@ -0,0 +1,60 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +REFERENCE = """ +INSERT REFERENCE HERE +""" # noqa W291 + +dset_name = "template_dataset" +task_name = "template_task" + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + instructions = f""" + Download link is not available. Please download the dataset by clicking on the download button + manually via TEMPLATE_URL to download the "TEMPLATE" folder. + Once the download is complete place the downloaded folder 'TEMPLATE.zip' in + /DOWNLOADS/{dset_name} + """ # noqa W291 + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.verify_pre_download( + file_name="TEMPLATE.zip", data_kind=DataKind.TRAINING_DATA, instructions=instructions + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name=task_name, dset_name=dset_name) +def create_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="This is a template task.", + ref=REFERENCE, + url="template url", + instr="download via template url", + lic=License.UNKNOWN, + release="date or version number", + keywords=[Keyword.MEDICAL, Keyword.DERMATOSCOPY, Keyword.TISSUE_PATHOLOGY], + ) + data_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA / "TEMPLATE", classes=None + ) + task.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/aptos_blindness.py b/plugins/data/src/mml_data/creators/classification/aptos_blindness.py new file mode 100644 index 0000000..1e827c5 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/aptos_blindness.py @@ -0,0 +1,83 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +import pandas as pd + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """ +@misc{ +url = {https://www.kaggle.com/c/aptos2019-blindness-detection/data}, +title = {APTOS 2019 Blindness Detection challenge} +} +""" + +dset_name = "aptos_blindness" + + +@register_dsetcreator(dset_name=dset_name) +def create_dset() -> Path: + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.kaggle_download(competition="aptos2019-blindness-detection", data_kind=DataKind.TRAINING_DATA) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name="aptos19_blindness_detection", dset_name="aptos_blindness") +def create_aptos(dset_path: Path): + diabetic_retinopathy = TaskCreator( + dset_path=dset_path, + name="aptos19_blindness_detection", + task_type=TaskType.CLASSIFICATION, + desc="A large set of retina images taken using fundus photography under a " + "variety of imaging conditions. Each image is rated for the severity of " + "diabetic retinopathy on a scale of 0 to 4", + ref=REFERENCE, + url="https://www.kaggle.com/c/aptos2019-blindness-detection/data", + instr="download via https://www.kaggle.com/c/aptos2019-blindness-detection/data", + lic=License.UNKNOWN, + release="2018", + keywords=[Keyword.MEDICAL, Keyword.FUNDUS_PHOTOGRAPHY, Keyword.EYE], + ) + + idx_to_class = { + 0: "No Diabetic Retinopathy", + 1: "Mild", + 2: "Moderate", + 3: "Severe", + 4: "Proliferative Diabetic Retinopathy", + } + train_iterator = [] + train_matrix = pd.read_csv(dset_path / DataKind.TRAINING_DATA / "train.csv") + for _, row in train_matrix.iterrows(): + train_iterator.append( + { + Modality.SAMPLE_ID: row["id_code"], + Modality.IMAGE: dset_path / DataKind.TRAINING_DATA / "train_images" / f"{row['id_code']}.png", + Modality.CLASS: row["diagnosis"], + } + ) + unlabled_iterator = [] + unlabeled_matrix = pd.read_csv(dset_path / DataKind.TRAINING_DATA / "test.csv") + for _, row in unlabeled_matrix.iterrows(): + unlabled_iterator.append( + { + Modality.SAMPLE_ID: row["id_code"], + Modality.IMAGE: dset_path / DataKind.TRAINING_DATA / "test_images" / f"{row['id_code']}.png", + } + ) + diabetic_retinopathy.find_data( + train_iterator=train_iterator, unlabeled_iterator=unlabled_iterator, idx_to_class=idx_to_class + ) + diabetic_retinopathy.split_folds(n_folds=5, ensure_balancing=True) + diabetic_retinopathy.infer_stats() + diabetic_retinopathy.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/barretts_esophagus.py b/plugins/data/src/mml_data/creators/classification/barretts_esophagus.py new file mode 100644 index 0000000..054427e --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/barretts_esophagus.py @@ -0,0 +1,68 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """ +url = {https://aidasub-clebarrett.grand-challenge.org/home/}, +title = {Analysis of Images to Detect Abnormalities in Endoscopy (AIDA-E) challenge}, +published during the 2016 edition of The IEEE International Symposium on Biomedical Imaging (ISBI) +""" # noqa W291 + + +@register_dsetcreator(dset_name="barretts_esophagus") +def create_dset(): + instructions = """ + Download link is not available. Please download the dataset by clicking on the download button manually via + https://www.dropbox.com/sh/m4xkmwjv3dm5j4b/AADICJ7IsBFZfSfQUM5TeClma/CLE_barrett.zip + Once the download is complete place the downloaded folder 'CLE_barrett.zip' in + \\DOWNLOADS\\barretts_esophagus + """ + dset_creator = DSetCreator(dset_name="barretts_esophagus") + dset_creator.verify_pre_download( + file_name="CLE_barrett.zip", instructions=instructions, data_kind=DataKind.TRAINING_DATA + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name="barretts_esophagus_diagnosis", dset_name="barretts_esophagus") +def create_barretts(dset_path: Path): + barretts_diagnosis = TaskCreator( + dset_path=dset_path, + name="barretts_esophagus_diagnosis", + task_type=TaskType.CLASSIFICATION, + desc="Barretts esophagus dataset showing gastric metaplasia (GMP), " + "intestinal metaplasia or proper Barrett's esophagus (BAR), or neplasia (NPL)", + ref=REFERENCE, + url="https://aidasub-clebarrett.grand-challenge.org/home/", + instr="download via dropbox " + "https://www.dropbox.com/sh/m4xkmwjv3dm5j4b/AADICJ7IsBFZfSfQUM5TeClma/CLE_barrett.zip", + lic=License.UNKNOWN, + release="2016", + keywords=[Keyword.MEDICAL, Keyword.ENDOSCOPY, Keyword.CLE, Keyword.TISSUE_PATHOLOGY], + ) + data_iterator = [] + classes = ["GMP", "BAR", "NPL"] + idx_to_class = {ix: cls for ix, cls in enumerate(classes)} + for img_path in (dset_path / DataKind.TRAINING_DATA).iterdir(): + data_iterator.append( + { + Modality.SAMPLE_ID: img_path.name, + Modality.IMAGE: img_path, + Modality.CLASS: classes.index(img_path.name[:3]), + } + ) + barretts_diagnosis.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + barretts_diagnosis.split_folds(n_folds=5, ensure_balancing=True) + barretts_diagnosis.infer_stats() + barretts_diagnosis.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/brain_tumor.py b/plugins/data/src/mml_data/creators/classification/brain_tumor.py new file mode 100644 index 0000000..2532388 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/brain_tumor.py @@ -0,0 +1,70 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +import pandas as pd + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +# TODO refactor as automatic kaggle download +REFERENCE = """ +@misc{jakesh bohaju_2020, +title={Brain Tumor}, +url={https://www.kaggle.com/dsv/1370629}, +DOI={10.34740/KAGGLE/DSV/1370629}, +publisher={Kaggle}, +author={Jakesh Bohaju}, +year={2020} +} +""" # noqa W291 + +dset_name = "brain_tumor" + + +@register_dsetcreator(dset_name=dset_name) +def create_dset() -> Path: + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.kaggle_download(dataset="jakeshbohaju/brain-tumor", data_kind=DataKind.TRAINING_DATA) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name="brain_tumor_classification", dset_name="brain_tumor") +def create_bt_classification(dset_path: Path): + bt_classification = TaskCreator( + dset_path=dset_path, + name="brain_tumor_classification", + task_type=TaskType.CLASSIFICATION, + desc="Brain Tumor dataset containing scans with brain tumor and no brain tumor", + ref=REFERENCE, + url="https://www.kaggle.com/jakeshbohaju/brain-tumor", + instr="download via https://www.kaggle.com/jakeshbohaju/brain-tumor", + lic=License.CC_BY_NC_SA_4_0, + release="2020", + keywords=[Keyword.MEDICAL, Keyword.MRI_SCAN, Keyword.BRAIN, Keyword.TISSUE_PATHOLOGY], + ) + data_iterator = [] + idx_to_class = {0: "No Tumor", 1: "Tumor"} + data_matrix = pd.read_csv(dset_path / DataKind.TRAINING_DATA / "Brain Tumor.csv") + for _, row in data_matrix.iterrows(): + data_iterator.append( + { + Modality.SAMPLE_ID: row["Image"], + Modality.IMAGE: ( + dset_path / DataKind.TRAINING_DATA / "Brain Tumor" / "Brain Tumor" / f"{row['Image']}.jpg" + ), + Modality.CLASS: row["Class"], + } + ) + bt_classification.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + bt_classification.split_folds(n_folds=5, ensure_balancing=True) + bt_classification.infer_stats() + bt_classification.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/brain_tumor_type.py b/plugins/data/src/mml_data/creators/classification/brain_tumor_type.py new file mode 100644 index 0000000..2341cba --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/brain_tumor_type.py @@ -0,0 +1,62 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +REFERENCE = """ +@misc{cheng_2017, +title={brain tumor dataset}, +url={https://figshare.com/articles/dataset/brain_tumor_dataset/1512427/5}, +DOI={10.6084/m9.figshare.1512427.v5}, +abstractNote={This brain tumor dataset contains 3064 T1-weighted contrast-inhanced images with three kinds of brain +tumor. Detailed information of the dataset can be found in readme file.}, +publisher={figshare}, +author={Cheng, Jun}, +year={2017}, +month={Apr} +} +""" # noqa W291 + +classes = ["1", "2", "3"] +dset_name = "brain_tumor_type" + + +@register_dsetcreator(dset_name=dset_name) +def create_dset() -> Path: + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.kaggle_download(dataset="denizkavi1/brain-tumor", data_kind=DataKind.TRAINING_DATA) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name="brain_tumor_type_classification", dset_name="brain_tumor_type") +def create_bt_classification(dset_path: Path): + bt_classification = TaskCreator( + dset_path=dset_path, + name="brain_tumor_type_classification", + task_type=TaskType.CLASSIFICATION, + desc="The dataset containing samples of meningioma(1), glioma(2), " "pituitary tumor(3) brain tumor types", + ref=REFERENCE, + url="https://www.kaggle.com/denizkavi1/brain-tumor", + instr="download via https://www.kaggle.com/denizkavi1/brain-tumor", + lic=License.CC_BY_4_0, + release="2017", + keywords=[Keyword.MEDICAL, Keyword.MRI_SCAN, Keyword.BRAIN, Keyword.TISSUE_PATHOLOGY], + ) + data_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA, classes=classes + ) + bt_classification.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + bt_classification.split_folds(n_folds=5, ensure_balancing=True) + bt_classification.infer_stats() + bt_classification.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/breast_ultrasound.py b/plugins/data/src/mml_data/creators/classification/breast_ultrasound.py new file mode 100644 index 0000000..cec7c8d --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/breast_ultrasound.py @@ -0,0 +1,69 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +logger = logging.getLogger(__name__) + +REFERENCE = """ +@article{article, +author = {Al-Dhabyani, Walid and Gomaa, Mohammed and Khaled, Hussien and Fahmy, Aly}, +year = {2019}, +month = {11}, +pages = {104863}, +title = {Dataset of Breast Ultrasound Images}, +volume = {28}, +journal = {Data in Brief}, +doi = {10.1016/j.dib.2019.104863} +} +""" + +dset_name = "breast_ultrasound" +task_name = "breast_cancer_classification_v2" +classes = ["benign", "malignant", "normal"] + + +@register_dsetcreator(dset_name=dset_name) +def create_dset() -> Path: + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.kaggle_download( + dataset="aryashah2k/breast-ultrasound-images-dataset", data_kind=DataKind.TRAINING_DATA + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name=task_name, dset_name=dset_name) +def create_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="Breast Ultrasound Dataset is categorized into three classes: normal, benign, and malignant images", + ref=REFERENCE, + url="https://www.kaggle.com/datasets/aryashah2k/breast-ultrasound-images-dataset", + instr="download via kaggle (https://www.kaggle.com/datasets/aryashah2k/breast-ultrasound-images-dataset)", + lic=License.CC_0_1_0, + release="2019", + keywords=[Keyword.MEDICAL, Keyword.BREAST, Keyword.ULTRASOUND], + ) + data_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA / "Dataset_BUSI_with_GT", classes=classes + ) + cleaned_iterator = [d for d in data_iterator if "mask" not in d[Modality.SAMPLE_ID]] + logger.info(f"Removed {len(data_iterator) - len(cleaned_iterator)} mask items.") + task.find_data(train_iterator=cleaned_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/caltech101.py b/plugins/data/src/mml_data/creators/classification/caltech101.py new file mode 100644 index 0000000..6a80f45 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/caltech101.py @@ -0,0 +1,68 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from torchvision.datasets import Caltech101 + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +REFERENCE = """ +@inproceedings{FeiFei2004LearningGV, + title={Learning Generative Visual Models from Few Training Examples: An Incremental Bayesian Approach Tested on 101 Object Categories}, + author={Li Fei-Fei and Rob Fergus and Pietro Perona}, + booktitle={CVPR Workshops}, + year={2004} +} +""" + +dset_name = "caltech101" +task_name = "caltech101_object_classification" + + +# TODO The caltech101 download url has changed. extract_from_pytorch_dataset is not working anymore! + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + dset_creator = DSetCreator(dset_name=dset_name) + vision_dset = Caltech101(root=dset_creator.download_path, target_type="category", download=True) + dset_path = dset_creator.extract_from_pytorch_datasets( + datasets={"training": vision_dset}, task_type=TaskType.CLASSIFICATION, class_names=vision_dset.categories + ) + return dset_path + + +@register_taskcreator(task_name=task_name, dset_name=dset_name) +def create_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="Pictures of objects belonging to 101 categories. About 40 to 800 images per category. " + "Most categories have about 50 images. Collected in September 2003 by Fei-Fei Li, Marco " + "Andreetto, and Marc 'Aurelio Ranzato. The size of each image is roughly 300 x 200 " + "pixels.", + ref=REFERENCE, + url="http://www.vision.caltech.edu/Image_Datasets/Caltech101/", + instr="downloaded via torchvision dataset " + "(https://pytorch.org/vision/stable/datasets.html#torchvision.datasets.Caltech101)", + lic=License.UNKNOWN, + release="2004", + keywords=[Keyword.NATURAL_OBJECTS], + ) + train_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA, classes=None + ) + task.find_data(train_iterator=train_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/caltech256.py b/plugins/data/src/mml_data/creators/classification/caltech256.py new file mode 100644 index 0000000..f9f8ef5 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/caltech256.py @@ -0,0 +1,74 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from torchvision.datasets import Caltech256 + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +REFERENCE = """ +@inproceedings{Griffin2007Caltech256OC, + title={Caltech-256 Object Category Dataset}, + author={Gregory Griffin and Alex Holub and Pietro Perona}, + year={2007} +} +""" + +# TODO The caltech256 download url has changed. extract_from_pytorch_dataset is not working anymore! + +dset_name = "caltech256" +task_name = "caltech256_object_classification" + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + dset_creator = DSetCreator(dset_name=dset_name) + vision_dset = Caltech256(root=dset_creator.download_path, download=True) + artefact = dset_creator.download_path / "caltech256" / "256_ObjectCategories" / "056.dog" / "greg" / "vision309" + # there seems to be an empty folder that causes errors, so to be save we will remove it and reload the dataset + if artefact.exists(): + artefact.rmdir() + artefact.parent.rmdir() + vision_dset = Caltech256(root=dset_creator.download_path, download=False) + # Furthermore there is a bash script, that causes the same error + artefact = dset_creator.download_path / "caltech256" / "256_ObjectCategories" / "198.spider" / "RENAME2" + if artefact.exists(): + artefact.unlink() + vision_dset = Caltech256(root=dset_creator.download_path, download=False) + dset_path = dset_creator.extract_from_pytorch_datasets( + datasets={"training": vision_dset}, task_type=TaskType.CLASSIFICATION, class_names=vision_dset.categories + ) + return dset_path + + +@register_taskcreator(task_name=task_name, dset_name=dset_name) +def create_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="Collection of 30607 images from 256 categories", + ref=REFERENCE, + url="http://www.vision.caltech.edu/Image_Datasets/Caltech256/", + instr="downloaded via torchvision dataset " + "(https://pytorch.org/vision/stable/datasets.html#torchvision.datasets.Caltech256)", + lic=License.UNKNOWN, + release="2007", + keywords=[Keyword.NATURAL_OBJECTS], + ) + train_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA, classes=None + ) + task.find_data(train_iterator=train_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/cataract.py b/plugins/data/src/mml_data/creators/classification/cataract.py new file mode 100644 index 0000000..b8c0069 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/cataract.py @@ -0,0 +1,60 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +logger = logging.getLogger(__name__) + +REFERENCE = """ +@misc{jr2ngb, +title={Cataract dataset}, +url={https://www.kaggle.com/datasets/jr2ngb/cataractdataset}, +publisher={Kaggle} +} +""" + +dset_name = "cataract" +task_name = "eye_condition_classification" +classes = ["1_normal", "2_cataract", "2_glaucoma", "3_retina_disease"] + + +@register_dsetcreator(dset_name=dset_name) +def create_dset() -> Path: + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.kaggle_download(dataset="jr2ngb/cataractdataset", data_kind=DataKind.TRAINING_DATA) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name=task_name, dset_name=dset_name) +def create_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="The dataset contains 4 categories of eye condition i.e. normal, cataract, glaucoma, retina disease", + ref=REFERENCE, + url="https://www.kaggle.com/datasets/jr2ngb/cataractdataset", + instr="download via kaggle (https://www.kaggle.com/datasets/jr2ngb/cataractdataset)", + lic=License.UNKNOWN, + release="Unknown", + keywords=[Keyword.MEDICAL, Keyword.EYE, Keyword.CATARACT_SURGERY], + ) + data_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA / "dataset", classes=classes + ) + task.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/cervical_cancer_screening.py b/plugins/data/src/mml_data/creators/classification/cervical_cancer_screening.py new file mode 100644 index 0000000..9164739 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/cervical_cancer_screening.py @@ -0,0 +1,87 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +from pathlib import Path +from typing import List + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +logger = logging.getLogger(__name__) + +REFERENCE = """ +@misc{ +title={intel-mobileodt-cervical-cancer-screening}, +url={https://www.kaggle.com/c/intel-mobileodt-cervical-cancer-screening/data}, +publisher={Kaggle} +} +""" # noqa W291 + +dset_name = "cervical_screening" +task_name = "cervix_type_classification" +classes = ["Type_1", "Type_2", "Type_3"] + + +@register_dsetcreator(dset_name=dset_name) +def create_dset() -> Path: + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.kaggle_download( + competition="intel-mobileodt-cervical-cancer-screening", data_kind=DataKind.TRAINING_DATA + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +def get_sequences(dset_path: Path) -> List[Path]: + """ + Returns all sequence folder paths. + + :param dset_path: + :return: + """ + releases = ["train/train", "additional_Type_1_v2", "additional_Type_2_v2", "additional_Type_3_v2"] + folder_paths = [] + for rel in releases: + p = dset_path / DataKind.TRAINING_DATA / rel + folder_paths.append(p) + return folder_paths + + +@register_taskcreator(task_name=task_name, dset_name=dset_name) +def create_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="The dataset contains three different types of cervix which is helpful in identifying the " + "transformation zones", + ref=REFERENCE, + url="https://www.kaggle.com/c/intel-mobileodt-cervical-cancer-screening/data", + instr="download via kaggle (https://www.kaggle.com/c/intel-mobileodt-cervical-cancer-screening/data)", + lic=License.UNKNOWN, + release="Unknown", + keywords=[Keyword.MEDICAL, Keyword.GYNECOLOGY], + ) + train_iterator = [] + for seq in get_sequences(dset_path): + for class_folder in seq.iterdir(): + for img_path in class_folder.iterdir(): + train_iterator.append( + { + Modality.SAMPLE_ID: seq.name + img_path.stem, + Modality.IMAGE: img_path, + Modality.CLASS: classes.index(class_folder.name), + } + ) + idx_to_class = {classes.index(cl): cl for cl in classes} + task.find_data(train_iterator=train_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/chexpert.py b/plugins/data/src/mml_data/creators/classification/chexpert.py new file mode 100644 index 0000000..783a0db --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/chexpert.py @@ -0,0 +1,106 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +import pandas as pd + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import create_creator_func, register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """ +@misc{irvin2019chexpert, + title={CheXpert: A Large Chest Radiograph Dataset with Uncertainty Labels and Expert Comparison}, + author={Jeremy Irvin and Pranav Rajpurkar and Michael Ko and Yifan Yu and Silviana Ciurea-Ilcus and Chris Chute + and Henrik Marklund and Behzad Haghgoo and Robyn Ball and Katie Shpanskaya and Jayne Seekins and David A. Mong and + Safwan S. Halabi and Jesse K. Sandberg and Ricky Jones and David B. Larson and Curtis P. Langlotz and + Bhavik N. Patel and Matthew P. Lungren and Andrew Y. Ng}, + year={2019}, + eprint={1901.07031}, + archivePrefix={arXiv}, + primaryClass={cs.CV} +} +""" # noqa W291 +# labels in the csv: -1 uncertain, 0 negative, 1 positive, blank unmentioned +# -> ignore -1 cases, thus focus on certain pathologies only +TASKS = [ + "No Finding", + "Enlarged Cardiomediastinum", + "Cardiomegaly", + "Lung Opacity", + "Lung Lesion", + "Edema", + "Consolidation", + "Pneumonia", + "Atelectasis", + "Pneumothorax", + "Pleural Effusion", + "Pleural Other", + "Fracture", + "Support Devices", +] +# the no finding class is obsolete with regard to the specific pathologies +TASKS.remove("No Finding") + + +@register_dsetcreator(dset_name="chexpert") +def create_dset(): + instructions = """ + Download link is not available. Please download the dataset by clicking on the download button manually via + https://stanfordmlgroup.github.io/competitions/chexpert/ + Once the download is complete place the downloaded folder 'CheXpert-v1.0-small.zip' in + \\DOWNLOADS\\chexpert + """ + dset_creator = DSetCreator(dset_name="chexpert") + dset_creator.verify_pre_download( + file_name="CheXpert-v1.0-small.zip", data_kind=DataKind.TRAINING_DATA, instructions=instructions + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +def create_chexpert_subtask(task: str, dset_path: Path, alias: str) -> None: + assert task in TASKS + classify_chexpert = TaskCreator( + dset_path=dset_path, + name=alias, + task_type=TaskType.CLASSIFICATION, + desc="CheXpert is a large public dataset for chest radiograph interpretation", + ref=REFERENCE, + url="https://stanfordmlgroup.github.io/competitions/chexpert/", + instr="download via stanfordmlgroup.github.io/competitions/chexpert/", + lic=License.UNKNOWN, + release="2019", + keywords=[Keyword.MEDICAL, Keyword.X_RAY, Keyword.CHEST, Keyword.TISSUE_PATHOLOGY], + ) + train_iterator, test_iterator = [], [] + train_matrix = pd.read_csv(dset_path / DataKind.TRAINING_DATA / "CheXpert-v1.0-small" / "train.csv") + test_matrix = pd.read_csv(dset_path / DataKind.TRAINING_DATA / "CheXpert-v1.0-small" / "valid.csv") + for iterator, matrix in [(train_iterator, train_matrix), (test_iterator, test_matrix)]: + for _, row in matrix.iterrows(): + if row[task] in [0, 1]: + iterator.append( + { + Modality.SAMPLE_ID: row["Path"], + Modality.IMAGE: dset_path / DataKind.TRAINING_DATA / row["Path"], + Modality.CLASS: int(row[task]), + } + ) + classify_chexpert.find_data( + train_iterator=train_iterator, test_iterator=test_iterator, idx_to_class={0: "Negative", 1: "Positive"} + ) + classify_chexpert.split_folds(n_folds=5, ensure_balancing=True) + classify_chexpert.infer_stats() + classify_chexpert.push_and_test() + + +for task in TASKS: + alias = f"chexpert_{task.lower().replace(' ', '_')}" + creator_func = create_creator_func(create_func=create_chexpert_subtask, task=task, alias=alias) + register_taskcreator(task_name=alias, dset_name="chexpert")(creator_func) diff --git a/plugins/data/src/mml_data/creators/classification/cholec45.py b/plugins/data/src/mml_data/creators/classification/cholec45.py new file mode 100644 index 0000000..c5408f1 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/cholec45.py @@ -0,0 +1,129 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +import pandas as pd +import torch.nn.functional + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, RGBInfo, Sizes, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import create_creator_func, register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """ +@article{Nwoye2022RendezvousAM, + title={Rendezvous: Attention Mechanisms for the Recognition of Surgical Action Triplets in Endoscopic Videos}, + author={Chinedu Innocent Nwoye and Tong Yu and Cristians Gonzalez and Barbara Seeliger and Pietro Mascagni and Didier Mutter and Jacques Marescaux and Nicolas Padoy}, + journal={Medical image analysis}, + year={2022}, + volume={78}, + pages={102433} +} +""" # noqa W291 + +dset_name = "cholect45" + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + instructions = f""" + Download link is not available. Please download the dataset by filling in the form at + https://github.com/CAMMA-public/cholect45 to download the "XXXX" folder. + Once the download is complete place the downloaded folder 'XXX' in + /DOWNLOADS/{dset_name} + """ # noqa W291 + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.verify_pre_download( + file_name="CholecT45.zip", data_kind=DataKind.TRAINING_DATA, instructions=instructions + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +def create_cholec_triplet_task(dset_path: Path, alias: str, target: str): + task = TaskCreator( + dset_path=dset_path, + name=alias, + task_type=TaskType.MULTILABEL_CLASSIFICATION, + desc="https://cholectriplet2022.grand-challenge.org/", + ref=REFERENCE, + url="https://github.com/CAMMA-public/cholect45", + instr="download via https://github.com/CAMMA-public/cholect45", + lic=License.CC_BY_NC_SA_4_0, + release="2022", + keywords=[Keyword.MEDICAL, Keyword.ENDOSCOPY, Keyword.ENDOSCOPIC_INSTRUMENTS, Keyword.LAPAROSCOPY], + ) + data_iterator = [] + with open(dset_path / DataKind.TRAINING_DATA / "CholecT45" / "dict" / f"{target}.txt", "r") as file: + classes = [line[line.index(":") + 1 :].strip() for line in file.readlines()] + idx_to_class = {classes.index(cl): cl for cl in classes} + if alias.split("_")[-1] == "soft": + # original: /dkfz/cluster/gpu/data/OE0176/m246i/cholec45/resized/CholecT45/dataframes/O_swin_bas_False_100_5_0_sd00_tar100.csv + generated_soft_labels = pd.read_csv(dset_path / DataKind.TRAINING_DATA / "CholecT45" / "soft_labels.csv") + cols = ["nid"] + [f"{ix}" for ix in range(100)] + generated_soft_labels = generated_soft_labels[cols].set_index("nid") + # drop the empty class, there is no prediction aka soft label for that + del idx_to_class[len(classes) - 1] + classes = classes[:-1] + soft = True + else: + label_folder = dset_path / DataKind.TRAINING_DATA / "CholecT45" / f"{target}" + soft = False + fold_definition = [[] for _ in range(len(vid_folds))] + for vid_folder in (dset_path / DataKind.TRAINING_DATA / "CholecT45" / "data").iterdir(): + if not soft: + label_df = pd.read_csv(label_folder / f"{vid_folder.name}.txt", index_col=0, header=None) + video_ids = [] + for frame in vid_folder.iterdir(): + video_ids.append(vid_folder.name + frame.stem) + if not soft: + frame_labels = label_df.loc[int(frame.stem)] + frame_labels = frame_labels[frame_labels == 1].index.to_list() + data_iterator.append( + { + Modality.SAMPLE_ID: vid_folder.name + frame.stem, + Modality.IMAGE: frame, + Modality.CLASSES: tuple(elem - 1 for elem in frame_labels), + } + ) + else: + soft_labels = generated_soft_labels.loc[f"{vid_folder.name}/{frame.stem}.png"].values + soft_labels = tuple(torch.nn.functional.softmax(torch.tensor(soft_labels), dim=0).numpy().tolist()) + data_iterator.append( + { + Modality.SAMPLE_ID: vid_folder.name + frame.stem, + Modality.IMAGE: frame, + Modality.SOFT_CLASSES: soft_labels, + } + ) + fold = [vid_folder.name in fold for fold in vid_folds].index(True) + fold_definition[fold].extend(video_ids) + task.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + task.use_existing_folds(fold_definition=fold_definition) + task.set_stats( + means=RGBInfo(*[0.33762359619140625, 0.21954330801963806, 0.21322497725486755]), + sizes=Sizes(*[480, 1080, 854, 1920]), + stds=RGBInfo(*[0.25544214248657227, 0.21357162296772003, 0.20953822135925293]), + ) + task.push_and_test() + + +vid_folds = [ + ["VID79", "VID02", "VID51", "VID06", "VID25", "VID14", "VID66", "VID23", "VID50"], + ["VID80", "VID32", "VID05", "VID15", "VID40", "VID47", "VID26", "VID48", "VID70"], + ["VID31", "VID57", "VID36", "VID18", "VID52", "VID68", "VID10", "VID08", "VID73"], + ["VID42", "VID29", "VID60", "VID27", "VID65", "VID75", "VID22", "VID49", "VID12"], + ["VID78", "VID43", "VID62", "VID35", "VID74", "VID01", "VID56", "VID04", "VID13"], +] + +TASKS = ["triplet", "instrument", "verb", "target", "triplet_soft"] + +for task in TASKS: + alias = f"{dset_name}_{task}" + creator_func = create_creator_func(create_func=create_cholec_triplet_task, target=task.split("_")[0], alias=alias) + register_taskcreator(task_name=alias, dset_name=dset_name)(creator_func) diff --git a/plugins/data/src/mml_data/creators/classification/cholec80.py b/plugins/data/src/mml_data/creators/classification/cholec80.py new file mode 100644 index 0000000..ee978ce --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/cholec80.py @@ -0,0 +1,162 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +from pathlib import Path + +import cv2 +import pandas as pd + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, RGBInfo, Sizes, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import create_creator_func, register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +logger = logging.getLogger(__name__) + +REFERENCE = """ +@article{Twinanda2017EndoNetAD, + title={EndoNet: A Deep Architecture for Recognition Tasks on Laparoscopic Videos}, + author={Andru Putra Twinanda and S. Shehata and Didier Mutter and Jacques Marescaux and Michel de Mathelin and Nicolas Padoy}, + journal={IEEE Transactions on Medical Imaging}, + year={2017}, + volume={36}, + pages={86-97} +} +""" + +dset_name = "cholec80" +ALL_TASKS = ["Grasper", "Bipolar", "Hook", "Scissors", "Clipper", "Irrigator", "SpecimenBag"] +# be aware grasper and hook are quite common ~ 55% of frames but all others are roughly between 1% and 6% + +instructions = f""" +Download link is not available. Please download the dataset by registering via the request form at +http://camma.u-strasbg.fr/datasets, afterwards download the download the "cholec80.zip" folder. +Once the download is complete place the downloaded folder 'cholec80.zip' in +/DOWNLOADS/{dset_name} +""" # noqa W291 + + +@register_dsetcreator(dset_name=dset_name) +def create_cholec80(): + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.verify_pre_download( + file_name="cholec80.zip", data_kind=DataKind.TRAINING_DATA, instructions=instructions + ) + dset_path = dset_creator.unpack_and_store() + # now videos have to be processed, images are extracted according to 1fps annotation + video_root = dset_path / DataKind.TRAINING_DATA / "videos" + image_root = dset_path / DataKind.TRAINING_DATA / "images" + image_root.mkdir(exist_ok=True) + video_paths = sorted([p for p in video_root.iterdir() if p.suffix == ".mp4"]) + for ix, vid in enumerate(video_paths): + logger.info(f"Starting frame extraction of {vid.name}... ({ix + 1}/{len(video_paths)})") + target = image_root / vid.stem + target.mkdir(exist_ok=True) + cap = cv2.VideoCapture(str(vid)) + counter = 0 + while cap.isOpened(): + ret, frame = cap.read() + if ret is False: + break + if counter % 25 == 0: + cv2.imwrite(str(target / f"{counter}.jpg"), frame) + counter += 1 + cap.release() + logger.info("Done extracting! Now checking with annotations...") + for ix, vid_imgs in enumerate(image_root.iterdir()): + frames = [int(img.stem) for img in vid_imgs.iterdir()] + annotation_path = dset_path / DataKind.TRAINING_DATA / "tool_annotations" / (vid_imgs.name + "-tool.txt") + annotations = pd.read_csv(annotation_path, header=0, index_col=0, sep="\t") + assert annotations.columns.to_list() == [ + "Grasper", + "Bipolar", + "Hook", + "Scissors", + "Clipper", + "Irrigator", + "SpecimenBag", + ], f"Incorrect columns at video {vid_imgs.name}" + frames_not_annotated = [f for f in frames if f not in annotations.index] + annotations_without_frames = [f for f in annotations.index if f not in frames] + # remove frames without annotation raise error for annotations without frames + if len(annotations_without_frames) > 0: + msg = f"Within video {vid_imgs.name} the frames {annotations_without_frames} are missing!" + logger.error(msg) + raise RuntimeError(msg) + logger.debug(f"Within {vid_imgs.name} removing {len(frames_not_annotated)} frames without annotations...") + for f in frames_not_annotated: + frame_path = vid_imgs / f"{f}.jpg" + frame_path.unlink() + logger.debug(f"... done {ix} / {len(video_paths)}") + logger.debug("Cleaned all extracted frames") + # remove video files to save disk space + for vid in video_paths: + vid.unlink() + logger.info("Removed videos to save disk space.") + return dset_path + + +def create_cholec80_subtask(task: str, dset_path: Path, alias: str) -> None: + assert task in ALL_TASKS + task_creator = TaskCreator( + dset_path=dset_path, + name=alias, + task_type=TaskType.CLASSIFICATION, + desc="The Cholec80 dataset contains 80 videos of cholecystectomy surgeries performed " + "by 13 surgeons. The videos are captured at 25 fps. The dataset is labeled with " + "the phase (at 25 fps) and tool presence annotations (at 1 fps). The phases have " + "been defined by a senior surgeon in our partner hospital. Since the tools are " + "sometimes hardly visible in the images and thus difficult to be recognized " + "visually, we define a tool as present in an image if at least half of the tool " + "tip is visible.", + ref=REFERENCE, + url="http://camma.u-strasbg.fr/datasets/cholec80", + instr="download via http://www.cs.rug.nl/~imaging/databases/melanoma_naevi/", + lic=License.CC_BY_NC_SA_4_0, + release="2017", + keywords=[Keyword.MEDICAL, Keyword.ENDOSCOPY, Keyword.ENDOSCOPIC_INSTRUMENTS, Keyword.LAPAROSCOPY], + ) + all_vids = list((dset_path / DataKind.TRAINING_DATA / "images").iterdir()) + vids_split = {"train": all_vids[:40], "test": all_vids[40:]} + idx_to_class = {0: "not_present", 1: "present"} + data_iterators = {k: [] for k in vids_split} + for phase in vids_split: + # load annotations + for vid in vids_split[phase]: + # read out task annotations for given video as pandas series + annots = pd.read_csv( + dset_path / DataKind.TRAINING_DATA / "tool_annotations" / (vid.name + "-tool.txt"), + index_col=0, + header=0, + sep="\t", + )[task] + for frame in vid.iterdir(): + data_iterators[phase].append( + { + Modality.SAMPLE_ID: f"vid{vid.name}_frame{frame.stem}", + Modality.IMAGE: frame, + Modality.CLASS: int(annots.loc[int(frame.stem)]), + } + ) + task_creator.find_data( + train_iterator=data_iterators["train"], test_iterator=data_iterators["test"], idx_to_class=idx_to_class + ) + task_creator.split_folds(n_folds=5, ensure_balancing=True) + # stats are identical across tasks, save calculation time here + task_creator.set_stats( + means=RGBInfo(*[0.34170591831207275, 0.22947388887405396, 0.22436298429965973]), + stds=RGBInfo(*[0.2470075637102127, 0.2106027603149414, 0.20748572051525116]), + sizes=Sizes(*[480, 1080, 854, 1920]), + ) + task_creator.push_and_test() + + +for task in ALL_TASKS: + alias = f"{dset_name}_{task.lower()}_presence" + creator_func = create_creator_func(create_func=create_cholec80_subtask, task=task, alias=alias) + register_taskcreator(task_name=alias, dset_name=dset_name)(creator_func) diff --git a/plugins/data/src/mml_data/creators/classification/cifar.py b/plugins/data/src/mml_data/creators/classification/cifar.py new file mode 100644 index 0000000..40ffd0c --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/cifar.py @@ -0,0 +1,105 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from torchvision.datasets import CIFAR10, CIFAR100 + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +REFERENCE = """ +@inproceedings{Krizhevsky2009LearningML, + title={Learning Multiple Layers of Features from Tiny Images}, + author={Alex Krizhevsky}, + year={2009} +} +""" + +dset_names = ["cifar10", "cifar100"] +task_names = ["cifar10_object_classification", "cifar100_object_classification"] + + +@register_dsetcreator(dset_name=dset_names[0]) +def create_cifar10(): + dset_creator = DSetCreator(dset_name=dset_names[0]) + train_dset = CIFAR10(root=dset_creator.download_path, download=True, train=True) + test_dset = CIFAR10(root=dset_creator.download_path, download=True, train=False) + dset_path = dset_creator.extract_from_pytorch_datasets( + datasets={"training": train_dset, "testing": test_dset}, + task_type=TaskType.CLASSIFICATION, + class_names=train_dset.classes, + ) + return dset_path + + +@register_taskcreator(task_name=task_names[0], dset_name=dset_names[0]) +def create_cifar_10_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name=task_names[0], + task_type=TaskType.CLASSIFICATION, + desc="The CIFAR-10 dataset consists of 60000 32x32 colour images in 10 classes, with 6000 " + "images per class. There are 50000 training images and 10000 test images. ", + ref=REFERENCE, + url="https://www.cs.toronto.edu/~kriz/cifar.html", + instr="downloaded via torchvision dataset " + "(https://pytorch.org/vision/stable/datasets.html#torchvision.datasets.CIFAR10)", + lic=License.UNKNOWN, + release="2009", + keywords=[Keyword.NATURAL_OBJECTS], + ) + train_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA, classes=None + ) + task.find_data(train_iterator=train_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() + + +@register_dsetcreator(dset_name=dset_names[1]) +def create_cifar100(): + dset_creator = DSetCreator(dset_name=dset_names[1]) + train_dset = CIFAR100(root=dset_creator.download_path, download=True, train=True) + test_dset = CIFAR100(root=dset_creator.download_path, download=True, train=False) + dset_path = dset_creator.extract_from_pytorch_datasets( + datasets={"training": train_dset, "testing": test_dset}, + task_type=TaskType.CLASSIFICATION, + class_names=train_dset.classes, + ) + return dset_path + + +@register_taskcreator(task_name=task_names[1], dset_name=dset_names[1]) +def create_cifar_100_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name=task_names[1], + task_type=TaskType.CLASSIFICATION, + desc="This dataset is just like the CIFAR-10, except it has 100 classes containing 600 images " + "each. There are 500 training images and 100 testing images per class. The 100 classes in " + "the CIFAR-100 are grouped into 20 superclasses. Each image comes with a 'fine' label (the " + "class to which it belongs) and a 'coarse' label (the superclass to which it belongs).", + ref=REFERENCE, + url="https://www.cs.toronto.edu/~kriz/cifar.html", + instr="downloaded via torchvision dataset " + "(https://pytorch.org/vision/stable/datasets.html#torchvision.datasets.CIFAR100)", + lic=License.UNKNOWN, + release="2009", + keywords=[Keyword.NATURAL_OBJECTS], + ) + train_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA, classes=None + ) + task.find_data(train_iterator=train_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/covid_ct.py b/plugins/data/src/mml_data/creators/classification/covid_ct.py new file mode 100644 index 0000000..f5c3d55 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/covid_ct.py @@ -0,0 +1,139 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import create_creator_func, register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +# TODO refactor as kaggle download, also check reference 3 +# TODO check for ICC problems of some images +# -> solved manually by "find . -type f -name '*.png' - exec mogrify \{\} \;" +# -> mogrify is part of ImageMagick + +REFERENCE = """ +@Article{sym12040651, +AUTHOR = {Loey, Mohamed and Smarandache, Florentin and M. Khalifa, Nour Eldeen}, +TITLE = {Within the Lack of Chest COVID-19 X-ray Dataset: A Novel Detection Model Based on GAN and Deep Transfer Learning}, +JOURNAL = {Symmetry}, +VOLUME = {12}, +YEAR = {2020}, +NUMBER = {4}, +ARTICLE-NUMBER = {651}, +URL = {https://www.mdpi.com/2073-8994/12/4/651}, +ISSN = {2073-8994}, +DOI = {10.3390/sym12040651} +} +""" +REFERENCE_2 = """ +@article{article, +author = {Eldeen, Nour and Smarandache, Florentin and Loey, Mohamed}, +year = {2020}, +month = {08}, +pages = {}, +title = {A Study of the Neutrosophic Set Significance on Deep Transfer Learning Models: an Experimental Case on a Limited COVID-19 Chest X-ray Dataset}, +journal = {Cognitive Computation}, +doi = {10.1007/s12559-020-09802-9} +} +""" +REFERENCE_3 = """ +@unknown{unknown, +author = {Loey, Mohamed and Smarandache, Florentin and Khalifa, Nour}, +year = {2020}, +month = {04}, +pages = {}, +title = {A Deep Transfer Learning Model with Classical Data Augmentation and CGAN to Detect COVID-19 from Chest CT Radiography Digital Images}, +doi = {10.20944/preprints202004.0252.v3} +} +""" + +# NOTE: https://github.com/UCSD-AI4H/COVID-CT is the source of the raw data +"""@article{zhao2020COVID-CT-Dataset, + title={COVID-CT-Dataset: a CT scan dataset about COVID-19}, + author={Zhao, Jinyu and Zhang, Yichen and He, Xuehai and Xie, Pengtao}, + journal={arXiv preprint arXiv:2003.13865}, + year={2020} +}""" + +TASKS = ["raw", "Aug", "CGAN", "Aug&CGAN"] +dataset_name = "covid_chest_ct" + + +@register_dsetcreator(dset_name=dataset_name) +def create_dset() -> Path: + dset_creator = DSetCreator(dset_name=dataset_name) + dset_creator.kaggle_download( + dataset="mloey1/covid19-chest-ct-image-augmentation-gan-dataset", data_kind=DataKind.TRAINING_DATA + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +def create_covid_ct_classification(task: str, dset_path: Path, alias: str) -> None: + assert task in TASKS + if task == "Aug&CGAN": + task = "Aug+CGAN" + additional_tag = [Keyword.ARTIFICIAL] if task != "raw" else [] + creator = TaskCreator( + dset_path=dset_path, + name=alias, + task_type=TaskType.CLASSIFICATION, + desc="COVID-CT-Dataset is a CT Scan Dataset about COVID-19. The medical chest CT" + "images have been enriched using classical data augmentation and CGAN to " + "generate more CT images", + ref=REFERENCE + REFERENCE_2 + REFERENCE_3, + url="https://www.kaggle.com/datasets/mloey1/covid19-chest-ct-image-augmentation-gan-dataset", + instr="download dataset via " "https://www.kaggle.com/mloey1/covid19-chest-ct-image-augmentation-gan-dataset", + lic=License.DATABASE_CONTENTS_LICENSE_1_0, + release="2020 - version 4", + keywords=[Keyword.MEDICAL, Keyword.CHEST, Keyword.CT_SCAN, Keyword.TISSUE_PATHOLOGY] + additional_tag, + ) + classes = ["COVID", "NonCOVID"] + suffix = "" if task == "raw" else task.replace("+", "") + split_suffix = "" if task == "raw" else ("+" + task) + train_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path + / DataKind.TRAINING_DATA + / ("COVID-19" + suffix) + / ("COVID-19" + split_suffix) + / ("train" + split_suffix), + dup_id_flag=True, + classes=classes, + ) + # we will use the validation split as additional training data and split the folds ourselves + val_iterator, _ = get_iterator_and_mapping_from_image_dataset( + root=dset_path + / DataKind.TRAINING_DATA + / ("COVID-19" + suffix) + / ("COVID-19" + split_suffix) + / ("val" + split_suffix), + dup_id_flag=True, + classes=classes, + ) + # because there are even identical class + image names across train and val we add a "val" prefix + for val_item in val_iterator: + val_item[Modality.SAMPLE_ID] = "val_" + val_item[Modality.SAMPLE_ID] + test_iterator, _ = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA / ("COVID-19" + suffix) / ("COVID-19" + split_suffix) / "test", + dup_id_flag=True, + classes=classes, + ) + creator.find_data( + train_iterator=train_iterator + val_iterator, test_iterator=test_iterator, idx_to_class=idx_to_class + ) + creator.split_folds(n_folds=5, ensure_balancing=True) + creator.infer_stats() + creator.push_and_test() + + +for task in TASKS: + alias = f"covid-19-chest-ct-image-augmentation_{task}" + creator_func = create_creator_func(create_func=create_covid_ct_classification, task=task, alias=alias) + register_taskcreator(task_name=alias, dset_name=dataset_name)(creator_func) diff --git a/plugins/data/src/mml_data/creators/classification/covid_ct_crawled.py b/plugins/data/src/mml_data/creators/classification/covid_ct_crawled.py new file mode 100644 index 0000000..744af45 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/covid_ct_crawled.py @@ -0,0 +1,74 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +REFERENCE = """ +@article{zhao2020COVID-CT-Dataset, + title={COVID-CT-Dataset: a CT scan dataset about COVID-19}, + author={Zhao, Jinyu and Zhang, Yichen and He, Xuehai and Xie, Pengtao}, + journal={arXiv preprint arXiv:2003.13865}, + year={2020} +} +""" # noqa W291 + +dset_name = "covid_ct_crawled" +task_name = "crawled_covid_ct_classification" + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + instructions = f""" + Download link is not available. Please download the dataset by clicking on the download button + manually via https://github.com/UCSD-AI4H/COVID-CT/blob/master/Images-processed/CT_COVID.zip + and https://github.com/UCSD-AI4H/COVID-CT/blob/master/Images-processed/CT_NonCOVID.zip + to download the two zip folders. + Once the downloads are complete place the downloaded folders 'CT_COVID.zip' and 'CT_NonCOVID.zip' in + /DOWNLOADS/{dset_name} + """ # noqa W291 + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.verify_pre_download( + file_name="CT_NonCOVID.zip", data_kind=DataKind.TRAINING_DATA, instructions=instructions + ) + dset_creator.verify_pre_download( + file_name="CT_COVID.zip", data_kind=DataKind.TRAINING_DATA, instructions=instructions + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name=task_name, dset_name=dset_name) +def create_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="The COVID-CT-Dataset has 349 CT images containing clinical findings of COVID-19 from 216 " + "patients. The images are collected from COVID19-related papers from medRxiv, bioRxiv, " + "NEJM, JAMA, Lancet, etc. CTs containing COVID-19 abnormalities are selected by reading " + "the figure captions in the papers. All copyrights of the data belong to the authors and " + "publishers of these papers.", + ref=REFERENCE, + url="https://github.com/UCSD-AI4H/COVID-CT", + instr="download via https://github.com/UCSD-AI4H/COVID-CT/tree/master/Images-processed", + lic=License.UNKNOWN, + release="2020", + keywords=[Keyword.MEDICAL, Keyword.CT_SCAN, Keyword.CHEST, Keyword.TISSUE_PATHOLOGY], + ) + data_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA, classes=["CT_NonCOVID", "CT_COVID"] + ) + task.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/covid_xray.py b/plugins/data/src/mml_data/creators/classification/covid_xray.py new file mode 100644 index 0000000..c6153dd --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/covid_xray.py @@ -0,0 +1,64 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +logger = logging.getLogger(__name__) + +REFERENCE = """ +@misc{HematejaAluru2021, + title = {Covid19 X-Ray classification dataset on kaggle}, + howpublished = {\\url{https://www.kaggle.com/ahemateja19bec1025/covid-xray-dataset}}, + note = {Accessed: 2022-01-13} +} +""" + +dset_name = "covid_xray" +task_name = "covid_xray_classification" + + +@register_dsetcreator(dset_name=dset_name) +def create_dset() -> Path: + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.kaggle_download(dataset="ahemateja19bec1025/covid-xray-dataset", data_kind=DataKind.TRAINING_DATA) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name=task_name, dset_name=dset_name) +def create_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="This is the dataset that Aluru V N M Hemateja gathered from different sources for Covid " + "19 Detection. There are around 3000 images in those two files and there is a handling " + 'code in the Notebook named "Official" at the end. Please use the dataset wisely and only ' + "for good purposes.", + ref=REFERENCE, + url="https://www.kaggle.com/ahemateja19bec1025/covid-xray-dataset", + instr="download via kaggle (https://www.kaggle.com/ahemateja19bec1025/covid-xray-dataset)", + lic=License.CC_0_1_0, + release="2021 version 2", + keywords=[Keyword.MEDICAL, Keyword.X_RAY, Keyword.CHEST, Keyword.TISSUE_PATHOLOGY], + ) + data_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA / "DATA" / "DATA", classes=None + ) + class_name_remapper = {"0": "Without Covid", "1": "With Covid"} + idx_to_class = {k: class_name_remapper[v] for k, v in idx_to_class.items()} + task.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/deep_drid.py b/plugins/data/src/mml_data/creators/classification/deep_drid.py new file mode 100644 index 0000000..ba767e0 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/deep_drid.py @@ -0,0 +1,161 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +import numpy as np +import pandas as pd + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import create_creator_func, register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """ +@article{LIU2022100512, +title = {DeepDRiD: Diabetic Retinopathy—Grading and Image Quality Estimation Challenge}, +journal = {Patterns}, +pages = {100512}, +year = {2022}, +issn = {2666-3899}, +doi = {https://doi.org/10.1016/j.patter.2022.100512}, +url = {https://www.sciencedirect.com/science/article/pii/S2666389922001040}, +author = {Ruhan Liu and Xiangning Wang and Qiang Wu and Ling Dai and Xi Fang and Tao Yan and Jaemin Son and Shiqi Tang + and Jiang Li and Zijian Gao and Adrian Galdran and J.M. Poorneshwaran and Hao Liu and Jie Wang and Yerui Chen + and Prasanna Porwal and Gavin Siew {Wei Tan} and Xiaokang Yang and Chao Dai and Haitao Song and Mingang Chen + and Huating Li and Weiping Jia and Dinggang Shen and Bin Sheng and Ping Zhang}, +keywords = {diabetic retinopathy, screening, deep learning, artificial intelligence, challenge, retinal image, + image quality analysis, ultra-widefield, fundus image}, +} +""" # noqa W291 + +dset_name = "deep_drid" + +ALL_TASKS = ["quality", "dr_level", "clarity", "field", "artifact"] + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + instructions = f""" + Download link is not available. Please download the dataset by clicking on the Code -> Download ZIP + functionality of Github manually at https://github.com/deepdrdoc/DeepDRiD. + Once the download is complete place the downloaded folder 'DeepDRiD-master.zip' in + /DOWNLOADS/{dset_name} + """ # noqa W291 + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.verify_pre_download( + file_name="DeepDRiD-master.zip", data_kind=DataKind.TRAINING_DATA, instructions=instructions + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +def create_deep_drid_subtask(task: str, dset_path: Path, alias: str) -> None: + tags = [Keyword.MEDICAL, Keyword.FUNDUS_PHOTOGRAPHY, Keyword.EYE] + if task == "dr_level": + tags.append(Keyword.TISSUE_PATHOLOGY) + elif task in ["quality", "clarity", "artifact"]: + tags.append(Keyword.IMAGE_ARTEFACTS) + creator = TaskCreator( + dset_path=dset_path, + name=alias, + task_type=TaskType.CLASSIFICATION, + desc="TThe aim of this challenge is to evaluate algorithms for automated fundus image " + "quality estimation and grading of diabetic retinopathy.", + ref=REFERENCE, + url="https://isbi.deepdr.org/data.html", + instr="download via https://github.com/deepdrdoc/DeepDRiD", + lic=License.CC_BY_4_0, + release="2021", + keywords=tags, + ) + if task == "quality": + idx_to_class = {0: "insufficient", 1: "sufficient"} + columns = ["Overall quality"] + elif task == "dr_level": + idx_to_class = {0: "no retinopathy", 1: "mild NPDR", 2: "moderate NPDR", 3: "severe NPDR", 4: "PDR"} + columns = ["left_eye_DR_Level", "right_eye_DR_Level"] + elif task == "clarity": + idx_to_class = {1: "lev 1", 4: "lev 2", 6: "lev 3", 8: "lev 3 +", 10: "lev 3 ++"} + columns = ["Clarity"] + elif task == "field": + idx_to_class = { + 1: "no od and mac", + 4: "either od or mac", + 6: "od and mac", + 8: "od and mac +", + 10: "od and mac ++", + } + columns = ["Field definition"] + elif task == "artifact": + idx_to_class = { + 0: "no artifacts", + 1: "aortic not affected", + 4: "mac not affected", + 6: "between forth and half", + 8: "between half and full", + 10: "entire pp", + } + columns = ["Artifact"] + else: + raise ValueError(f"Task {task} not valid!") + + # read in meta data + train_df = pd.read_csv( + dset_path + / DataKind.TRAINING_DATA + / "DeepDRiD-master" + / "regular_fundus_images" + / "regular-fundus-training" + / "regular-fundus-training.csv" + ) + test_df = pd.read_csv( + dset_path + / DataKind.TRAINING_DATA + / "DeepDRiD-master" + / "regular_fundus_images" + / "regular-fundus-validation" + / "regular-fundus-validation.csv" + ) + # iterate over dfs + train_iterator, test_iterator = [], [] + for iterator, df, path_dir in [ + (train_iterator, train_df, "regular-fundus-training"), + (test_iterator, test_df, "regular-fundus-validation"), + ]: + for index, row in df.iterrows(): + vals = [row[column] for column in columns] + if np.isnan(vals[0]): + vals.pop(0) + val = vals[0] + assert not np.isnan(val) + iterator.append( + { + Modality.SAMPLE_ID: row["image_id"], + Modality.IMAGE: ( + dset_path + / DataKind.TRAINING_DATA + / "DeepDRiD-master" + / "regular_fundus_images" + / path_dir + / "Images" + / str(row["patient_id"]) + / f"{row['image_id']}.jpg" + ), + Modality.CLASS: int(val), + } + ) + creator.find_data(train_iterator=train_iterator, test_iterator=test_iterator, idx_to_class=idx_to_class) + creator.split_folds(n_folds=5, ensure_balancing=True) + creator.infer_stats() + creator.push_and_test() + + +for task in ALL_TASKS: + alias = f"{dset_name}_{task}" + creator_func = create_creator_func(create_func=create_deep_drid_subtask, task=task, alias=alias) + register_taskcreator(task_name=alias, dset_name=dset_name)(creator_func) diff --git a/plugins/data/src/mml_data/creators/classification/derm7pt.py b/plugins/data/src/mml_data/creators/classification/derm7pt.py new file mode 100644 index 0000000..8a2936e --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/derm7pt.py @@ -0,0 +1,141 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +import pandas as pd + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """ +@article{Kawahara2019SevenPointCA, + title={Seven-Point Checklist and Skin Lesion Classification Using Multitask Multimodal Neural Nets}, + author={Jeremy Kawahara and Sara Daneshvar and Giuseppe Argenziano and G. Hamarneh}, + journal={IEEE Journal of Biomedical and Health Informatics}, + year={2019}, + volume={23}, + pages={538-546} +} +""" + +dset_name = "derm7pt" +task_name = "derm7pt_skin_lesions" +instructions = f""" + It is necessary to register prior to downloading the data. Follow the link + https://derm.cs.sfu.ca/Download.html and register yourself. Afterwards use the download link + http://derm.cs.sfu.ca/restricted/release_v0.zip together with your credentials to get the data. + Once the download is complete place the downloaded folder 'release_v0.zip' in + /DOWNLOADS/{dset_name} + """ # noqa W291 + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.verify_pre_download( + file_name="release_v0.zip", data_kind=DataKind.TRAINING_DATA, instructions=instructions + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name=task_name, dset_name=dset_name) +def create_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="We provide a database for evaluating computerized image-based prediction " + "of the 7-point skin lesion malignancy checklist. The dataset includes over " + "2000 clinical and dermoscopy color images, along with corresponding " + "structured metadata tailored for training and evaluating computer aided " + "diagnosis (CAD) systems.", + ref=REFERENCE, + url="https://derm.cs.sfu.ca/Download.html", + instr=instructions, + lic=License.UNKNOWN, + release="2019 - v0", + keywords=[Keyword.MEDICAL, Keyword.DERMATOSCOPY, Keyword.TISSUE_PATHOLOGY], + ) + # merging infrequent classes according to https://github.com/jeremykawahara/derm7pt/blob/master/derm7pt/dataset.py#L475 + infrequent_mapper = {"basal cell carcinoma": "BCC", "seborrheic keratosis": "SK"} + infrequent_mapper.update( + { + infrequent: "NEV" + for infrequent in [ + "nevus", + "blue nevus", + "clark nevus", + "combined nevus", + "congenital nevus", + "dermal nevus", + "recurrent nevus", + "reed or spitz nevus", + ] + } + ) + infrequent_mapper.update( + { + infrequent: "MEL" + for infrequent in [ + "melanoma", + "melanoma", + "melanoma (in situ)", + "melanoma (less than 0.76 mm)", + "melanoma (0.76 to 1.5 mm)", + "melanoma (more than 1.5 mm)", + "melanoma metastasis", + ] + } + ) + infrequent_mapper.update( + { + infrequent: "MISC" + for infrequent in [ + "DF/LT/MLS/MISC", + "dermatofibroma", + "lentigo", + "melanosis", + "miscellaneous", + "vascular lesion", + ] + } + ) + meta_path = dset_path / DataKind.TRAINING_DATA / "release_v0" / "meta" + meta_info = pd.read_csv(meta_path / "meta.csv", header=0, index_col=0) + classes = sorted(list(set(infrequent_mapper.values()))) + indices = { + "train": pd.read_csv(meta_path / "train_indexes.csv")["indexes"].tolist(), + "val": pd.read_csv(meta_path / "valid_indexes.csv")["indexes"].tolist(), + "test": pd.read_csv(meta_path / "test_indexes.csv")["indexes"].tolist(), + } + data_iterator = {} + for split in ["train", "val", "test"]: + data_iterator[split] = [] + for idx in indices[split]: + data_iterator[split].append( + { + Modality.SAMPLE_ID: str(idx), + Modality.IMAGE: ( + dset_path / DataKind.TRAINING_DATA / "release_v0" / "images" / meta_info.iloc[idx]["derm"] + ), + Modality.CLASS: classes.index(infrequent_mapper[meta_info.iloc[idx]["diagnosis"]]), + } + ) + idx_to_class = {classes.index(cl): cl for cl in classes} + # we merge train and validation split to folderize later on ourselves + task.find_data( + train_iterator=data_iterator["train"] + data_iterator["val"], + test_iterator=data_iterator["test"], + idx_to_class=idx_to_class, + ) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/emnist.py b/plugins/data/src/mml_data/creators/classification/emnist.py new file mode 100644 index 0000000..efdf5c1 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/emnist.py @@ -0,0 +1,65 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from torchvision.datasets import EMNIST + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +REFERENCE = """ +@inproceedings{LeCun1998GradientbasedLA, + title={Gradient-based learning applied to document recognition}, + author={Yann LeCun and L{\'e}on Bottou and Yoshua Bengio and Patrick Haffner}, + year={1998} +} +""" + +dset_name = "emnist" +task_name = "emnist_digit_classification" + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + dset_creator = DSetCreator(dset_name=dset_name) + train_dset = EMNIST(root=dset_creator.download_path, train=True, download=True, split="balanced") + test_dset = EMNIST(root=dset_creator.download_path, train=False, download=True, split="balanced") + dset_path = dset_creator.extract_from_pytorch_datasets( + datasets={"training": train_dset, "testing": test_dset}, + task_type=TaskType.CLASSIFICATION, + class_names=train_dset.classes, + ) + return dset_path + + +@register_taskcreator(task_name=task_name, dset_name=dset_name) +def create_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="A variant of the full NIST dataset, which was called Extended MNIST (EMNIST), " + "and follows the same conversion paradigm used to create the MNIST dataset. ", + ref=REFERENCE, + url="https://www.westernsydney.edu.au/bens/home/reproducible_research/emnist", + instr="downloaded via torchvision dataset " + "(https://pytorch.org/vision/stable/datasets.html#torchvision.datasets.EMNIST)", + lic=License.UNKNOWN, + release="2017", + keywords=[Keyword.CHARS_DIGITS, Keyword.HANDWRITINGS], + ) + train_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA, classes=None + ) + task.find_data(train_iterator=train_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/hyper_kvasir.py b/plugins/data/src/mml_data/creators/classification/hyper_kvasir.py new file mode 100644 index 0000000..22a10d5 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/hyper_kvasir.py @@ -0,0 +1,147 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import create_creator_func, register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """ +@misc{borgli2020, +title = {Hyper-Kvasir: A Comprehensive Multi-Class Image and Video Dataset for Gastrointestinal Endoscopy}, +url = {osf.io/mkzcq}, +DOI = {10.31219/osf.io/mkzcq}, +publisher = {OSF Preprints}, +author = {Borgli, Hanna and Thambawita, Vajira and Smedsrud, Pia H and Hicks, Steven and Jha, Debesh and Eskeland, + Sigrun L and Randel, Kristin R and Pogorelov, Konstantin and Lux, Mathias and Nguyen, Duc T D and Johansen, + Dag and Griwodz, Carsten and Stensland, H{\aa}kon K and Garcia-Ceja, Enrique and Schmidt, Peter T and Hammer, + Hugo L and Riegler, Michael A and Halvorsen, P{\aa}l and de Lange, Thomas}, +year = {2019}, +month = {Dec}} +""" # noqa W291 + + +@register_dsetcreator(dset_name="hyperkvasir") +def create_hyperkvasir_labeled(): + dset_creator = DSetCreator(dset_name="hyperkvasir") + dset_creator.download( + url="https://datasets.simula.no/downloads/hyper-kvasir/hyper-kvasir-labeled-images.zip", + file_name="hyper-kvasir-labeled-images.zip", + data_kind=DataKind.TRAINING_DATA, + ) + dset_creator.download( + url="https://datasets.simula.no/downloads/hyper-kvasir/hyper-kvasir-unlabeled-images.zip", + file_name="hyper-kvasir-unlabeled-images.zip", + data_kind=DataKind.UNLABELED_DATA, + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +# these are all tasks provided by the hyperkvasir dataset, we split it up into 4 classification tasks +ALL_CLASSES = [ + "cecum", + "ileum", + "retroflex-rectum", + "hemorrhoids", + "polyps", + "ulcerative-colitis-grade-0-1", + "ulcerative-colitis-grade-1", + "ulcerative-colitis-grade-1-2", + "ulcerative-colitis-grade-2", + "ulcerative-colitis-grade-2-3", + "ulcerative-colitis-grade-3", + "bbps-0-1", + "bbps-2-3", + "impacted-stool", + "dyed-lifted-polyps", + "dyed-resection-margins", + "pylorus", + "retroflex-stomach", + "z-line", + "barretts", + "barretts-short-segment", + "esophagitis-a", + "esophagitis-b-d", +] +# the classification tasks are already defined as subfolders in the data +TASKS = ["anatomical-landmarks", "pathological-findings", "quality-of-mucosal-views", "therapeutic-interventions"] + + +def create_hyperkvasir_subtask(task: str, dset_path: Path, alias: str) -> None: + assert task in TASKS + tags = { + "anatomical-landmarks": [Keyword.ANATOMICAL_STRUCTURES], + "pathological-findings": [Keyword.TISSUE_PATHOLOGY], + "quality-of-mucosal-views": [], + "therapeutic-interventions": [], + }[task] + tags.extend([Keyword.MEDICAL, Keyword.GASTROSCOPY_COLONOSCOPY]) + creator = TaskCreator( + dset_path=dset_path, + name=alias, + task_type=TaskType.CLASSIFICATION, + desc="Hyper-Kvasir Dataset is a large image and video dataset from the gastrointestinal " "tract", + ref=REFERENCE, + url="https://datasets.simula.no/hyper-kvasir/", + instr="download zips of labeled and unlabeled images via website", + lic=License.CC_BY_4_0, + release="2020", + keywords=tags, + ) + classes = { + "anatomical-landmarks": ["cecum", "ileum", "retroflex-rectum", "pylorus", "retroflex-stomach", "z-line"], + "pathological-findings": [ + "hemorrhoids", + "polyps", + "ulcerative-colitis-grade-0-1", + "ulcerative-colitis-grade-1", + "ulcerative-colitis-grade-1-2", + "ulcerative-colitis-grade-2", + "ulcerative-colitis-grade-2-3", + "ulcerative-colitis-grade-3", + "barretts", + "barretts-short-segment", + "esophagitis-a", + "esophagitis-b-d", + ], + "quality-of-mucosal-views": ["bbps-0-1", "bbps-2-3", "impacted-stool"], + "therapeutic-interventions": ["dyed-lifted-polyps", "dyed-resection-margins"], + }[task] + data_iterator = [] + root = dset_path / DataKind.TRAINING_DATA / "labeled-images" + for tract in ["lower-gi-tract", "upper-gi-tract"]: + if (root / tract / task).exists(): + for class_folder in (root / tract / task).iterdir(): + assert class_folder.is_dir() + assert class_folder.name in classes + for img_path in class_folder.iterdir(): + data_iterator.append( + { + Modality.SAMPLE_ID: img_path.stem, + Modality.IMAGE: img_path, + Modality.CLASS: classes.index(class_folder.name), + } + ) + idx_to_class = {classes.index(cl): cl for cl in classes} + creator.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + creator.split_folds(n_folds=5, ensure_balancing=True) + creator.infer_stats() + creator.push_and_test() + + +for task in TASKS: + alias = f"hyperkvasir_{task}" + creator_func = create_creator_func(create_func=create_hyperkvasir_subtask, task=task, alias=alias) + register_taskcreator(task_name=alias, dset_name="hyperkvasir")(creator_func) + +# TODO create unlabeled task with unlabaled data +# @register_taskcreator(task_name='hyperkvasir_unlabaled', dset_name='hyperkvasir') +# def create_unlabeled(dset_path): +# pass diff --git a/plugins/data/src/mml_data/creators/classification/ibean.py b/plugins/data/src/mml_data/creators/classification/ibean.py new file mode 100644 index 0000000..83a7746 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/ibean.py @@ -0,0 +1,91 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """ +@ONLINE {beansdata, + author="Makerere AI Lab", + title="Bean disease dataset", + month="January", + year="2020", + url="https://github.com/AI-Lab-Makerere/ibean/" +} +""" + +classes = ["healthy", "bean_rust", "angular_leaf_spot"] + + +@register_dsetcreator(dset_name="ibean") +def create_dset(): + dset_creator = DSetCreator(dset_name="ibean") + dset_creator.download( + url="https://storage.googleapis.com/ibeans/train.zip", file_name="train.zip", data_kind=DataKind.TRAINING_DATA + ) + dset_creator.download( + url="https://storage.googleapis.com/ibeans/validation.zip", + file_name="validation.zip", + data_kind=DataKind.TRAINING_DATA, + ) + dset_creator.download( + url="https://storage.googleapis.com/ibeans/test.zip", file_name="test.zip", data_kind=DataKind.TESTING_DATA + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name="bean_plant_disease_classification", dset_name="ibean") +def create_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name="bean_plant_disease_classification", + task_type=TaskType.CLASSIFICATION, + desc="ibean dataset for bean plant disease classification. The data is of leaf" + "images representing 3 classes: the healthy class of images, and two " + "disease classes including Angular Leaf Spot and Bean Rust diseases.", + ref=REFERENCE, + url="https://github.com/AI-Lab-Makerere/ibean/", + instr="download individual train, validation and test dataset from" "github.com/AI-Lab-Makerere/ibean/", + lic=License.MIT, + release="2020", + keywords=[Keyword.NATURAL_OBJECTS], + ) + train_iterator = [] + test_iterator = [] + train_path = [dset_path / DataKind.TRAINING_DATA / "train", dset_path / DataKind.TRAINING_DATA / "validation"] + test_path = dset_path / DataKind.TESTING_DATA / "test" + for seq in train_path: + for class_folder in seq.iterdir(): + for img_path in class_folder.iterdir(): + if img_path.name == "healthy_train.120tore": # corrupted image + continue + train_iterator.append( + { + Modality.SAMPLE_ID: img_path.name, + Modality.IMAGE: img_path, + Modality.CLASS: classes.index(class_folder.name), + } + ) + for class_folder in test_path.iterdir(): + for img_path in class_folder.iterdir(): + test_iterator.append( + { + Modality.SAMPLE_ID: img_path.name, + Modality.IMAGE: img_path, + Modality.CLASS: classes.index(class_folder.name), + } + ) + idx_to_class = {classes.index(cl): cl for cl in classes} + task.find_data(train_iterator=train_iterator, test_iterator=test_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/idle_frame_recognition.py b/plugins/data/src/mml_data/creators/classification/idle_frame_recognition.py new file mode 100644 index 0000000..e541fe4 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/idle_frame_recognition.py @@ -0,0 +1,62 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +REFERENCE = """ +@inproceedings{inproceedings, +author = {Ghamsarian, Negin and Amirpour, Hadi and Timmerer, Christian and Taschwer, Mario and Schoeffmann, Klaus}, +year = {2020}, +month = {10}, +pages = {}, +title = {Relevance-Based Compression of Cataract Surgery Videos Using Convolutional Neural Networks}, +doi = {10.1145/3394171.3413658} +} +""" + + +@register_dsetcreator(dset_name="idle_action") +def create_frame_recognition(): + dset_creator = DSetCreator(dset_name="idle_action") + dset_creator.download( + url="ftp.itec.aau.at/datasets/ovid/CatRelevanceCompression/downloads/Idle_frame_recognition.zip", + file_name="Idle_frame_recognition.zip", + data_kind=DataKind.TRAINING_DATA, + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name="idle_action_recognition", dset_name="idle_action") +def create_idle_action_recognition(dset_path: Path): + frame_recognition = TaskCreator( + dset_path=dset_path, + name="idle_action_recognition", + task_type=TaskType.CLASSIFICATION, + desc="This dataset contains manual annotations of idle and action frames in " + "cataract surgery videos for idle-frame-recognition networks", + ref=REFERENCE, + url="http://ftp.itec.aau.at/datasets/ovid/CatRelevanceCompression/", + instr="download Idle_frame_recognition dataset via " "ftp.itec.aau.at/datasets/ovid/CatRelevanceCompression/", + lic=License.CC_BY_NC_4_0, + release="2020", + keywords=[Keyword.MEDICAL, Keyword.CATARACT_SURGERY, Keyword.EYE], + ) + classes = ["Action", "Idle"] + data_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA / "Idle_frame_recognition" / "Train", dup_id_flag=True, classes=classes + ) + frame_recognition.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + frame_recognition.split_folds(n_folds=5, ensure_balancing=True) + frame_recognition.infer_stats() + frame_recognition.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/isic20.py b/plugins/data/src/mml_data/creators/classification/isic20.py new file mode 100644 index 0000000..8766c44 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/isic20.py @@ -0,0 +1,119 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +from pathlib import Path + +import pandas as pd + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, RGBInfo, Sizes, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +logger = logging.getLogger(__name__) + +REFERENCE = """ +@article{Rotemberg2021APD, + title={A patient-centric dataset of images and metadata for identifying melanomas using clinical context}, + author={Veronica Rotemberg and Nicholas R. Kurtansky and Brigid Betz-Stablein and Liam J. Caffery and Emmanouil + Chousakos and Noel C. F. Codella and Marc Combalia and Stephen W. Dusza and Pascale Guitera and David + Gutman and Allan C. Halpern and Harald Kittler and Kivanç K{\"o}se and Steve G. Langer and Konstantinos + Liopryis and Josep Malvehy and Shenara Musthaq and Jabpani Nanda and Ofer Reiter and George Shih and + Alexander J. Stratigos and Philipp Tschandl and Jochen Weber and Hans Peter Soyer}, + journal={Scientific Data}, + year={2021}, + volume={8} +} +""" # noqa W291 + +dset_name = "isic20" +task_name = "isic20_melanoma_classification" + + +@register_dsetcreator(dset_name=dset_name) +def create_isic20() -> Path: + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.download( + url="https://isic-challenge-data.s3.amazonaws.com/2020/ISIC_2020_Training_Duplicates.csv", + file_name="ISIC_2020_Training_Duplicates.csv", + data_kind=DataKind.TRAINING_DATA, + ) + dset_creator.download( + url="https://isic-challenge-data.s3.amazonaws.com/2020/ISIC_2020_Training_JPEG.zip", + file_name="ISIC_2020_Training_JPEG.zip", + data_kind=DataKind.TRAINING_DATA, + ) + dset_creator.download( + url="https://isic-challenge-data.s3.amazonaws.com/2020/ISIC_2020_Training_GroundTruth.csv", + file_name="ISIC_2020_Training_GroundTruth.csv", + data_kind=DataKind.TRAINING_LABELS, + ) + dset_creator.download( + url="https://isic-challenge-data.s3.amazonaws.com/2020/ISIC_2020_Test_JPEG.zip", + file_name="ISIC_2020_Test_JPEG.zip", + data_kind=DataKind.TESTING_DATA, + ) # -> no ground truth yet + dset_path = dset_creator.unpack_and_store() + # remove duplicates + duplicates = pd.read_csv(dset_path / DataKind.TRAINING_DATA / "ISIC_2020_Training_Duplicates.csv")["image_name_2"] + counter = 0 + for dup in duplicates: + p = dset_path / DataKind.TRAINING_DATA / "train" / f"{dup}.jpg" + if p.exists(): + p.unlink() + counter += 1 + logger.info(f"Removed {counter} duplicates.") + return dset_path + + +@register_taskcreator(task_name=task_name, dset_name=dset_name) +def create_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="The dataset contains 33,126 dermoscopic training images of unique benign and malignant " + "skin lesions from over 2,000 patients. Each image is associated with one of these " + "individuals using a unique patient identifier. All malignant diagnoses have been " + "confirmed via histopathology, and benign diagnoses have been confirmed using either " + "expert agreement, longitudinal follow-up, or histopathology.", + ref=REFERENCE, + url="https://challenge2020.isic-archive.com/", + instr="download via kaggle (https://www.kaggle.com/c/siim-isic-melanoma-classification/data) " + "or homepage(https://challenge2020.isic-archive.com/)", + lic=License.CC_BY_NC_4_0, + release="2020", + keywords=[Keyword.MEDICAL, Keyword.DERMATOSCOPY, Keyword.TISSUE_PATHOLOGY], + ) + idx_to_class = {0: "benign", 1: "malignant"} + train_annotation = pd.read_csv( + dset_path / DataKind.TRAINING_LABELS / "ISIC_2020_Training_GroundTruth.csv", index_col=0 + )["target"] + train_iterator = [] + for img_path in (dset_path / DataKind.TRAINING_DATA / "train").iterdir(): + train_iterator.append( + { + Modality.SAMPLE_ID: img_path.stem, + Modality.IMAGE: img_path, + Modality.CLASS: int(train_annotation.at[img_path.stem]), + } + ) + test_iterator = [] + for img_path in (dset_path / DataKind.TESTING_DATA / "ISIC_2020_Test_Input").iterdir(): + if img_path.suffix != ".jpg": + continue + test_iterator.append({Modality.SAMPLE_ID: img_path.stem, Modality.IMAGE: img_path}) + task.find_data(train_iterator=train_iterator, test_iterator=test_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5, ensure_balancing=True) + # because of varying sizes and high resolution inference takes multiple hours, set stats instead + task.set_stats( + means=RGBInfo(*[0.8050940632820129, 0.6202492117881775, 0.5902113318443298]), + stds=RGBInfo(*[0.15143747627735138, 0.177970752120018, 0.20396198332309723]), + sizes=Sizes(*[480, 6000, 640, 6000]), + ) + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/kvasir_capsule.py b/plugins/data/src/mml_data/creators/classification/kvasir_capsule.py new file mode 100644 index 0000000..793f91a --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/kvasir_capsule.py @@ -0,0 +1,149 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.archive_extractors import unpack_files +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import create_creator_func, register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +REFERENCE = """ +@article{Smedsrud2021, + title = {{Kvasir-Capsule, a video capsule endoscopy dataset}}, + author = { + Smedsrud, Pia H and Thambawita, Vajira and Hicks, Steven A and + Gjestang, Henrik and Nedrejord, Oda Olsen and N{\ae}ss, Espen and + Borgli, Hanna and Jha, Debesh and Berstad, Tor Jan Derek and + Eskeland, Sigrun L and Lux, Mathias and Espeland, H{\aa}vard and + Petlund, Andreas and Nguyen, Duc Tien Dang and Garcia-Ceja, Enrique and + Johansen, Dag and Schmidt, Peter T and Toth, Ervin and + Hammer, Hugo L and de Lange, Thomas and Riegler, Michael A and + Halvorsen, P{\aa}l + }, + doi = {10.1038/s41597-021-00920-z}, + journal = {Scientific Data}, + number = {1}, + pages = {142}, + volume = {8}, + year = {2021} +} +""" + +dset_name = "kvasir_capsule" +ALL_TASKS = ["anatomy", "content", "pathologies"] + + +# TODO think about including the labeled videos similar to Cholec80 + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + instructions = f""" + Download link is not working as expected. Please download the dataset manually by following these + instructions: Go to https://osf.io/dv2ag/files/ and select the "labelled_images" folder in the + Google Drive section. Afterwards a "Download as zip" button pops up at the top, which needs to be + pressed. Once the download is complete place the downloaded folder 'labelled_images.zip' in + /DOWNLOADS/{dset_name} + """ # noqa W291 + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.verify_pre_download( + instructions=instructions, file_name="labelled_images.zip", data_kind=DataKind.TRAINING_DATA + ) + # the zip contains itself archives that need to be extracted, this requires some "hacky solution" + # first remove the originally selected archive from automatic processing + arch = dset_creator.archives.pop() + # then extract manually inside DOWNLOADS + unpack_files(archives=[arch], target=dset_creator.download_path) + for sub_folder in [ + "ampulla_of_vater", + "angiectasia", + "blood_fresh", + "blood_hematin", + "erosion", + "erythema", + "foreign_body", + "ileocecal_valve", + "lymphangiectasia", + "normal_clean_mucosa", + "pylorus", + "polyp", + "reduced_mucosal_view", + "ulcer", + ]: + second_instructions = f""" + This is an intermediate step, if errors occur, remove the intermediate folders in + {dset_creator.download_path} (except the labelled_images.zip) and restart.""" # noqa W291 + dset_creator.verify_pre_download( + instructions=second_instructions, data_kind=DataKind.TRAINING_DATA, file_name=f"{sub_folder}.tar.gz" + ) + # finally do the usual routine + dset_path = dset_creator.unpack_and_store() + return dset_path + + +def create_kvasir_capsule_subtask(task: str, dset_path: Path, alias: str) -> None: + tags = { + "anatomy": [Keyword.MEDICAL, Keyword.ENDOSCOPY, Keyword.CAPSULE_ENDOSCOPY, Keyword.ANATOMICAL_STRUCTURES], + "content": [Keyword.MEDICAL, Keyword.ENDOSCOPY, Keyword.CAPSULE_ENDOSCOPY], + "pathologies": [Keyword.MEDICAL, Keyword.ENDOSCOPY, Keyword.CAPSULE_ENDOSCOPY, Keyword.TISSUE_PATHOLOGY], + }[task] + creator = TaskCreator( + dset_path=dset_path, + name=alias, + task_type=TaskType.CLASSIFICATION, + desc="This is the official repository for the Kvasir-Capsule dataset, which is the largest " + "publicly released PillCAM dataset. In total, the dataset contains 47,238 labeled " + "images and 117 videos, where it captures anatomical landmarks and pathological and " + "normal findings. The results is more than 4,741,621 images and video frames all " + "together.", + ref=REFERENCE, + url="https://datasets.simula.no/kvasir-capsule/", + instr="download via https://osf.io/dv2ag/files/", + lic=License.CC_BY_4_0, + release="2021", + keywords=tags, + ) + # ATTENTION: For simplicity we drop classes below 200 samples! + classes = { + "anatomy": [ + "Pylorus", + # 'Ampulla of vater', # to few samples and one overlap with a pylorus sample + "Ileocecal valve", + ], + "content": [ + "Normal clean mucosa", + "Reduced mucosal view", + "Blood - fresh", + # 'Blood - hematin', # to few samples + "Foreign body", + ], + "pathologies": [ + "Normal clean mucosa", + # 'Erythema', # to few samples + "Angiectasia", + "Erosion", + "Ulcer", + "Lymphangiectasia", + # 'Polyp' # to few samples + ], + }[task] + data_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA, classes=classes + ) + creator.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + creator.split_folds(n_folds=5, ensure_balancing=True) + creator.infer_stats() + creator.push_and_test() + + +for task in ALL_TASKS: + alias = f"{dset_name}_{task}" + creator_func = create_creator_func(create_func=create_kvasir_capsule_subtask, task=task, alias=alias) + register_taskcreator(task_name=alias, dset_name=dset_name)(creator_func) diff --git a/plugins/data/src/mml_data/creators/classification/lapgyn4.py b/plugins/data/src/mml_data/creators/classification/lapgyn4.py new file mode 100644 index 0000000..fbcbeb8 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/lapgyn4.py @@ -0,0 +1,184 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# creates the 4 lapgyn datasets and tasks +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +REFERENCE = """ +@inproceedings{DBLP:conf/mmsys/LeibetsederPPKM18, + author = {Andreas Leibetseder and + Stefan Petscharnig and + Manfred J{\"{u}}rgen Primus and + Sabrina Kletz and + Bernd M{\"{u}}nzer and + Klaus Schoeffmann and + J{\"{o}}rg Keckstein}, + title = {Lapgyn4: a dataset for 4 automatic content analysis problems in the + domain of laparoscopic gynecology}, + booktitle = {Proceedings of the 9th {ACM} Multimedia Systems Conference, MMSys + 2018, Amsterdam, The Netherlands, June 12-15, 2018}, + pages = {357--362}, + publisher = {{ACM}}, + year = {2018}, + url = {https://doi.org/10.1145/3204949.3208127}, + doi = {10.1145/3204949.3208127}, + timestamp = {Wed, 21 Nov 2018 12:44:03 +0100}, + biburl = {https://dblp.org/rec/conf/mmsys/LeibetsederPPKM18.bib}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} +""" + +ADDITIONAL_REFERENCE = """ +@article{DBLP:journals/corr/TwinandaSMMMP16, + author = {Andru Putra Twinanda and + Sherif Shehata and + Didier Mutter and + Jacques Marescaux and + Michel de Mathelin and + Nicolas Padoy}, + title = {EndoNet: {A} Deep Architecture for Recognition Tasks on Laparoscopic + Videos}, + journal = {CoRR}, + volume = {abs/1602.03012}, + year = {2016}, + url = {http://arxiv.org/abs/1602.03012}, + archivePrefix = {arXiv}, + eprint = {1602.03012}, + timestamp = {Mon, 13 Aug 2018 16:46:10 +0200}, + biburl = {https://dblp.org/rec/journals/corr/TwinandaSMMMP16.bib}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} +""" + + +@register_dsetcreator(dset_name="lapgyn4") +def create_lapgyn(): + dset_creator = DSetCreator(dset_name="lapgyn4") + dset_creator.download( + url="http://ftp.itec.aau.at/datasets/LapGyn4/downloads/v1_2/LapGyn4_v1.2.zip", + file_name="LapGyn4_v1.2.zip", + data_kind=DataKind.TRAINING_DATA, + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name="lapgyn4_anatomical_structures", dset_name="lapgyn4") +def create_task_as(dset_path: Path): + anatomical_structures = TaskCreator( + dset_path=dset_path, + name="lapgyn4_anatomical_structures", + task_type=TaskType.CLASSIFICATION, + desc="anatomical structures subset of LapGyn4 dataset", + ref=REFERENCE, + url="http://ftp.itec.aau.at/datasets/LapGyn4/", + instr="download via ftp.itec.aau.at/datasets/LapGyn4/LapGyn4_v1.2.zip", + lic=License.CC_BY_NC_4_0, + release="v1.2", + keywords=[Keyword.LAPAROSCOPY, Keyword.ANATOMICAL_STRUCTURES, Keyword.MEDICAL, Keyword.GYNECOLOGY], + ) + classes = ["Colon", "Liver", "Ovary", "Oviduct", "Uterus"] + data_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA / "LapGyn4_v1.2" / "Anatomical_Structures", classes=classes + ) + anatomical_structures.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + anatomical_structures.split_folds(n_folds=5, ensure_balancing=True) + anatomical_structures.infer_stats() + anatomical_structures.push_and_test() + + +@register_taskcreator(task_name="lapgyn4_surgical_actions", dset_name="lapgyn4") +def create_task_sa(dset_path: Path): + surgical_actions = TaskCreator( + dset_path=dset_path, + name="lapgyn4_surgical_actions", + task_type=TaskType.CLASSIFICATION, + desc="surgical action subset of LapGyn4 dataset", + ref=REFERENCE, + url="http://ftp.itec.aau.at/datasets/LapGyn4/", + instr="download via ftp.itec.aau.at/datasets/LapGyn4/LapGyn4_v1.2.zip", + lic=License.CC_BY_NC_4_0, + release="v1.2", + keywords=[Keyword.LAPAROSCOPY, Keyword.ENDOSCOPIC_INSTRUMENTS, Keyword.MEDICAL, Keyword.GYNECOLOGY], + ) + classes = [ + "Coagulation", + "Cutting_Cold", + "Cutting_HF", + "Dissection_Blunt", + "Injection", + "Sling_Hysterectomy", + "Suction_Irrigation", + "Suturing", + ] + data_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA / "LapGyn4_v1.2" / "Surgical_Actions", classes=classes + ) + surgical_actions.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + surgical_actions.split_folds(n_folds=5, ensure_balancing=True) + surgical_actions.infer_stats() + surgical_actions.push_and_test() + + +@register_taskcreator(task_name="lapgyn4_instrument_count", dset_name="lapgyn4") +def create_task_ic(dset_path: Path): + instrument_count = TaskCreator( + dset_path=dset_path, + name="lapgyn4_instrument_count", + task_type=TaskType.CLASSIFICATION, + desc="instrument count subset of LapGyn4 dataset", + ref=REFERENCE + ADDITIONAL_REFERENCE, + url="http://ftp.itec.aau.at/datasets/LapGyn4/", + instr="download via ftp.itec.aau.at/datasets/LapGyn4/LapGyn4_v1.2.zip", + lic=License.CC_BY_NC_4_0, + release="v1.2", + keywords=[ + Keyword.LAPAROSCOPY, + Keyword.ENDOSCOPIC_INSTRUMENTS, + Keyword.INSTRUMENT_COUNT, + Keyword.MEDICAL, + Keyword.GYNECOLOGY, + ], + ) + classes = ["0", "1", "2", "3"] + data_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA / "LapGyn4_v1.2" / "Instrument_Count", classes=classes + ) + instrument_count.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + instrument_count.split_folds(n_folds=5, ensure_balancing=True) + instrument_count.infer_stats() + instrument_count.push_and_test() + + +@register_taskcreator(task_name="lapgyn4_anatomical_actions", dset_name="lapgyn4") +def create_task_aa(dset_path: Path): + anatomical_actions = TaskCreator( + dset_path=dset_path, + name="lapgyn4_anatomical_actions", + task_type=TaskType.CLASSIFICATION, + desc="anatomical actions subset of LapGyn4 dataset", + ref=REFERENCE, + url="http://ftp.itec.aau.at/datasets/LapGyn4/", + instr="download via ftp.itec.aau.at/datasets/LapGyn4/LapGyn4_v1.2.zip", + lic=License.CC_BY_NC_4_0, + release="v1.2", + keywords=[Keyword.LAPAROSCOPY, Keyword.ANATOMICAL_STRUCTURES, Keyword.MEDICAL, Keyword.GYNECOLOGY], + ) + classes = ["Suturing_Other", "Suturing_Ovary", "Suturing_Uterus", "Suturing_Vagina"] + data_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA / "LapGyn4_v1.2" / "Actions_on_Anatomy", classes=classes + ) + anatomical_actions.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + anatomical_actions.split_folds(n_folds=5, ensure_balancing=True) + anatomical_actions.infer_stats() + anatomical_actions.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/laryngeal.py b/plugins/data/src/mml_data/creators/classification/laryngeal.py new file mode 100644 index 0000000..2c7a408 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/laryngeal.py @@ -0,0 +1,123 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """ +@dataset{sara_moccia_2017_1003200, + author = {Sara Moccia and + Elena De Momi and + Leonardo S. Mattos}, + title = {Laryngeal dataset}, + month = oct, + year = 2017, + publisher = {Zenodo}, + doi = {10.5281/zenodo.1003200}, + url = {https://doi.org/10.5281/zenodo.1003200} +} +""" + + +@register_dsetcreator(dset_name="laryngeal") +def create_laryngeal(): + dset_creator = DSetCreator(dset_name="laryngeal") + dset_creator.download( + url="https://zenodo.org/record/1003200/files/laryngeal%20dataset.tar?download=1", + file_name="laryngeal dataset.tar", + data_kind=DataKind.TRAINING_DATA, + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name="laryngeal_tissues", dset_name="laryngeal") +def create_laryngeal_tissue(dset_path: Path): + laryngeal_tissue = TaskCreator( + dset_path=dset_path, + name="laryngeal_tissues", + task_type=TaskType.CLASSIFICATION, + desc="Laryngeal dataset for patches of healthy and early-stage cancerous laryngeal tissues", + ref=REFERENCE, + url="https://nearlab.polimi.it/medical/dataset/", + instr="download via zenodo.org/record/1003200/files/laryngeal%20dataset.tar?download=1", + lic=License.CC_BY_NC_4_0, + release="2017", + keywords=[Keyword.MEDICAL, Keyword.LARYNGOSCOPY, Keyword.TISSUE_PATHOLOGY, Keyword.ENDOSCOPY], + ) + classes = ["Hbv", "He", "IPCL", "Le"] + folds = ["FOLD 1", "FOLD 2", "FOLD 3"] + data_iterator = [] + for fold in folds: + root = dset_path / DataKind.TRAINING_DATA / "laryngeal dataset" / f"{fold}" + folders = [p.name for p in root.iterdir() if p.is_dir()] + assert all([cl in folders for cl in classes]), "some class folder is not existent" + for class_folder in root.iterdir(): + assert class_folder.is_dir() + if class_folder.name not in classes: + continue + for img_path in class_folder.iterdir(): + data_iterator.append( + { + Modality.SAMPLE_ID: img_path.stem, + Modality.IMAGE: img_path, + Modality.CLASS: classes.index(class_folder.name), + } + ) + idx_to_class = {classes.index(cl): cl for cl in classes} + laryngeal_tissue.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + laryngeal_tissue.split_folds(n_folds=5, ensure_balancing=True) + laryngeal_tissue.infer_stats() + laryngeal_tissue.push_and_test() + + +@register_taskcreator(task_name="laryngeal_tissues_original_folds", dset_name="laryngeal") +def create_laryngeal_tissue_original_folds(dset_path: Path): + laryngeal_tissue_original_folds = TaskCreator( + dset_path=dset_path, + name="laryngeal_tissues_original_folds", + task_type=TaskType.CLASSIFICATION, + desc="Laryngeal dataset for patches of healthy and early-stage cancerous laryngeal tissues", + ref=REFERENCE, + url="https://nearlab.polimi.it/medical/dataset/", + instr="download via zenodo.org/record/1003200/files/laryngeal%20dataset.tar?download=1", + lic=License.CC_BY_NC_4_0, + release="2017", + keywords=[Keyword.MEDICAL, Keyword.LARYNGOSCOPY, Keyword.TISSUE_PATHOLOGY, Keyword.ENDOSCOPY], + ) + classes = ["Hbv", "He", "IPCL", "Le"] + FOLDS = ["FOLD 1", "FOLD 2", "FOLD 3"] + data_iterator = [] + fold_definition = [] + for fold in FOLDS: + root = dset_path / DataKind.TRAINING_DATA / "laryngeal dataset" / f"{fold}" + folders = [p.name for p in root.iterdir() if p.is_dir()] + assert all([cl in folders for cl in classes]), "some class folder is not existent" + ids = [] + for class_folder in root.iterdir(): + assert class_folder.is_dir() + if class_folder.name not in classes: + continue + for img_path in class_folder.iterdir(): + ids.append(img_path.stem) + data_iterator.append( + { + Modality.SAMPLE_ID: img_path.stem, + Modality.IMAGE: img_path, + Modality.CLASS: classes.index(class_folder.name), + } + ) + fold_definition.append(ids) + idx_to_class = {classes.index(cl): cl for cl in classes} + laryngeal_tissue_original_folds.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + laryngeal_tissue_original_folds.use_existing_folds(fold_definition=fold_definition) + laryngeal_tissue_original_folds.infer_stats() + laryngeal_tissue_original_folds.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/mednode.py b/plugins/data/src/mml_data/creators/classification/mednode.py new file mode 100644 index 0000000..dd13ff7 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/mednode.py @@ -0,0 +1,65 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +REFERENCE = """ +@article{article, +author = {Giotis, Ioannis and Molders, Nynke and Land, Sander and Biehl, Michael and Jonkman, Marcel and Petkov, Nicolai}, +year = {2015}, +month = {05}, +pages = {}, +title = {MED-NODE: A Computer-Assisted Melanoma Diagnosis System using Non-Dermoscopic Images}, +volume = {42}, +journal = {Expert Systems with Applications}, +doi = {10.1016/j.eswa.2015.04.034} +} +""" + + +@register_dsetcreator(dset_name="mednode") +def create_mednode(): + dset_creator = DSetCreator(dset_name="mednode") + dset_creator.download( + url="http://www.cs.rug.nl/~imaging/databases/melanoma_naevi/complete_mednode_dataset.zip", + file_name="complete_mednode_dataset.zip", + data_kind=DataKind.TRAINING_DATA, + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name="mednode_melanoma_classification", dset_name="mednode") +def create_melanoma_classification(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name="mednode_melanoma_classification", + task_type=TaskType.CLASSIFICATION, + desc="The dataset consists of melanoma and naevus images from the digital image" + " archive of the Department of Dermatology of the University Medical " + "Center Groningen (UMCG)", + ref=REFERENCE, + url="http://www.cs.rug.nl/~imaging/databases/melanoma_naevi/", + instr="download via http://www.cs.rug.nl/~imaging/databases/melanoma_naevi/", + lic=License.UNKNOWN, + release="2015", + keywords=[Keyword.MEDICAL, Keyword.DERMATOSCOPY, Keyword.TISSUE_PATHOLOGY], + ) + classes = ["naevus", "melanoma"] + data_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA / "complete_mednode_dataset", classes=classes + ) + task.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/mnist.py b/plugins/data/src/mml_data/creators/classification/mnist.py new file mode 100644 index 0000000..224d84f --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/mnist.py @@ -0,0 +1,67 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from torchvision.datasets import MNIST + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +REFERENCE = """ +@inproceedings{LeCun1998GradientbasedLA, + title={Gradient-based learning applied to document recognition}, + author={Yann LeCun and L{\'e}on Bottou and Yoshua Bengio and Patrick Haffner}, + year={1998} +} +""" + +dset_name = "mnist" +task_name = "mnist_digit_classification" + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + dset_creator = DSetCreator(dset_name=dset_name) + train_dset = MNIST(root=dset_creator.download_path, train=True, download=True) + test_dset = MNIST(root=dset_creator.download_path, train=False, download=True) + dset_path = dset_creator.extract_from_pytorch_datasets( + datasets={"training": train_dset, "testing": test_dset}, + task_type=TaskType.CLASSIFICATION, + class_names=[str(ix) for ix in range(10)], + ) + return dset_path + + +@register_taskcreator(task_name=task_name, dset_name=dset_name) +def create_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="The MNIST database of handwritten digits, available from this page, has a training set " + "of 60,000 examples, and a test set of 10,000 examples. It is a subset of a larger set " + "available from NIST. The digits have been size-normalized and centered in a fixed-size " + "image. ", + ref=REFERENCE, + url="http://yann.lecun.com/exdb/mnist/", + instr="downloaded via torchvision dataset " + "(https://pytorch.org/vision/stable/datasets.html#torchvision.datasets.MNIST)", + lic=License.UNKNOWN, + release="1998", + keywords=[Keyword.CHARS_DIGITS, Keyword.HANDWRITINGS], + ) + train_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA, classes=None + ) + task.find_data(train_iterator=train_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/mura.py b/plugins/data/src/mml_data/creators/classification/mura.py new file mode 100644 index 0000000..15f9ed7 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/mura.py @@ -0,0 +1,99 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import create_creator_func, register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """ +@ARTICLE{2017arXiv171206957R, + author = {{Rajpurkar}, Pranav and {Irvin}, Jeremy and {Bagul}, Aarti and {Ding}, Daisy and {Duan}, Tony and + {Mehta}, Hershel and {Yang}, Brandon and {Zhu}, Kaylie and {Laird}, Dillon and {Ball}, Robyn L. and {Langlotz}, + Curtis and {Shpanskaya}, Katie and {Lungren}, Matthew P. and {Ng}, Andrew Y.}, + title = "{MURA: Large Dataset for Abnormality Detection in Musculoskeletal Radiographs}", + journal = {arXiv e-prints}, + keywords = {Physics - Medical Physics, Computer Science - Artificial Intelligence}, + year = 2017, + month = dec, + eid = {arXiv:1712.06957}, + pages = {arXiv:1712.06957}, +archivePrefix = {arXiv}, + eprint = {1712.06957}, + primaryClass = {physics.med-ph}, + adsurl = {https://ui.adsabs.harvard.edu/abs/2017arXiv171206957R}, + adsnote = {Provided by the SAO/NASA Astrophysics Data System} +} +""" # noqa W291 +# labels in the csv: 0 negative, 1 positive +TASKS = ["XR_WRIST", "XR_SHOULDER", "XR_HUMERUS", "XR_HAND", "XR_FOREARM", "XR_FINGER", "XR_ELBOW"] + + +@register_dsetcreator(dset_name="mura") +def create_dset(): + instructions = """ + Download link is not available. Please download the dataset by clicking on the download button manually via + https://stanfordmlgroup.github.io/competitions/mura/ + Once the download is complete place the downloaded folder 'MURA-v1.1.zip' in + \\DOWNLOADS\\mura + """ + dset_creator = DSetCreator(dset_name="mura") + dset_creator.verify_pre_download( + file_name="MURA-v1.1.zip", data_kind=DataKind.TRAINING_DATA, instructions=instructions + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +def create_mura_subtask(task: str, dset_path: Path, alias: str) -> None: + assert task in TASKS + classify_mura = TaskCreator( + dset_path=dset_path, + name=alias, + task_type=TaskType.CLASSIFICATION, + desc="MURA (musculoskeletal radiographs) is a large dataset of bone X-rays.", + ref=REFERENCE, + url="https://stanfordmlgroup.github.io/competitions/mura/", + instr="download via stanfordmlgroup.github.io/competitions/mura/", + lic=License.UNKNOWN, + release="2017", + keywords=[Keyword.MEDICAL, Keyword.X_RAY, Keyword.BONE, Keyword.TISSUE_PATHOLOGY], + ) + train_task_folder = dset_path / DataKind.TRAINING_DATA / "MURA-v1.1" / "train" / task + test_task_folder = dset_path / DataKind.TRAINING_DATA / "MURA-v1.1" / "valid" / task + train_iterator, test_iterator = [], [] + for iterator, task_folder in [(train_iterator, train_task_folder), (test_iterator, test_task_folder)]: + for patient in task_folder.iterdir(): + for study in patient.iterdir(): + if "negative" in study.name: + class_idx = 0 + else: + class_idx = 1 + for img_path in study.iterdir(): + if img_path.stem.startswith("._"): # there are three corrupted images in the wrist task + continue + iterator.append( + { + Modality.SAMPLE_ID: task + "_" + patient.name + "_" + study.name[:8] + img_path.name, + Modality.IMAGE: img_path, + Modality.CLASS: class_idx, + } + ) + classify_mura.find_data( + train_iterator=train_iterator, test_iterator=test_iterator, idx_to_class={0: "Negative", 1: "Positive"} + ) + classify_mura.split_folds(n_folds=5, ensure_balancing=True) + classify_mura.infer_stats() + classify_mura.push_and_test() + + +for task in TASKS: + alias = f"mura_{task.lower()}" + creator_func = create_creator_func(create_func=create_mura_subtask, task=task, alias=alias) + register_taskcreator(task_name=alias, dset_name="mura")(creator_func) diff --git a/plugins/data/src/mml_data/creators/classification/nbi_infframes.py b/plugins/data/src/mml_data/creators/classification/nbi_infframes.py new file mode 100644 index 0000000..7f51c0f --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/nbi_infframes.py @@ -0,0 +1,131 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import os +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """ +@dataset{sara_moccia_2018_1162784, + author = {Sara Moccia and + Gabriele Omodeo Vanone and + Elena De Momi and + Leonardo S. Mattos}, + title = {NBI-InfFrames}, + month = jan, + year = 2018, + publisher = {Zenodo}, + doi = {10.5281/zenodo.1162784}, + url = {https://doi.org/10.5281/zenodo.1162784} +} +""" + + +@register_dsetcreator(dset_name="nbi_infframes") +def create_nbi_infframes(): + dset_creator = DSetCreator(dset_name="nbi_infframes") + dset_creator.download( + url="https://zenodo.org/record/1162784/files/FRAMES.zip?download=1", + file_name="FRAMES.zip", + data_kind=DataKind.TRAINING_DATA, + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name="identify_nbi_infframes", dset_name="nbi_infframes") +def create_identify_nbi_infframes(dset_path: Path): + nbi_infframes = TaskCreator( + dset_path=dset_path, + name="identify_nbi_infframes", + task_type=TaskType.CLASSIFICATION, + desc="NBI-InfFrames dataset for the identification of informative endoscopic " "video frames.", + ref=REFERENCE, + url="https://nearlab.polimi.it/medical/dataset/", + instr="download via zenodo.org/record/1162784/files/FRAMES.zip?download=1", + lic=License.CC_BY_NC_4_0, + release="Version 1", + keywords=[Keyword.MEDICAL, Keyword.LARYNGOSCOPY, Keyword.IMAGE_ARTEFACTS, Keyword.ENDOSCOPY], + ) + classes = ["B", "I", "S", "U"] + folds = ["Fold1", "Fold2", "Fold3"] + data_iterator = [] + for fold in folds: + root = dset_path / DataKind.TRAINING_DATA / "FRAMES" / f"{fold}" + folders = [p.name for p in root.iterdir() if p.is_dir()] + assert all([cl in folders for cl in classes]), "some class folder is not existent" + for class_folder in root.iterdir(): + if class_folder.name != ".DS_Store": + assert class_folder.is_dir() + if class_folder.name not in classes: + continue + for img_path in class_folder.iterdir(): + head, tail = os.path.split(img_path) + if tail != ".DS_Store": + data_iterator.append( + { + Modality.SAMPLE_ID: img_path.stem, + Modality.IMAGE: img_path, + Modality.CLASS: classes.index(class_folder.name), + } + ) + idx_to_class = {classes.index(cl): cl for cl in classes} + nbi_infframes.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + nbi_infframes.split_folds(n_folds=5, ensure_balancing=True) + nbi_infframes.infer_stats() + nbi_infframes.push_and_test() + + +@register_taskcreator(task_name="identify_nbi_infframes_original_folds", dset_name="nbi_infframes") +def create_identify_nbi_infframes_original_folds(dset_path: Path): + nbi_infframes_original_folds = TaskCreator( + dset_path=dset_path, + name="identify_nbi_infframes_original_folds", + task_type=TaskType.CLASSIFICATION, + desc="NBI-InfFrames dataset for the identification of informative endoscopic " "video frames.", + ref=REFERENCE, + url="https://nearlab.polimi.it/medical/dataset/", + instr="download via zenodo.org/record/1162784/files/FRAMES.zip?download=1", + lic=License.CC_BY_NC_4_0, + release="Version 1", + keywords=[Keyword.MEDICAL, Keyword.LARYNGOSCOPY, Keyword.IMAGE_ARTEFACTS], + ) + classes = ["B", "I", "S", "U"] + folds = ["Fold1", "Fold2", "Fold3"] + data_iterator = [] + fold_definition = [] + for fold in folds: + root = dset_path / DataKind.TRAINING_DATA / "FRAMES" / f"{fold}" + folders = [p.name for p in root.iterdir() if p.is_dir()] + assert all([cl in folders for cl in classes]), "some class folder is not existent" + ids = [] + for class_folder in root.iterdir(): + if class_folder.name != ".DS_Store": + assert class_folder.is_dir() + if class_folder.name not in classes: + continue + for img_path in class_folder.iterdir(): + head, tail = os.path.split(img_path) + if tail != ".DS_Store": + ids.append(img_path.stem) + data_iterator.append( + { + Modality.SAMPLE_ID: img_path.stem, + Modality.IMAGE: img_path, + Modality.CLASS: classes.index(class_folder.name), + } + ) + fold_definition.append(ids) + idx_to_class = {classes.index(cl): cl for cl in classes} + nbi_infframes_original_folds.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + nbi_infframes_original_folds.use_existing_folds(fold_definition=fold_definition) + nbi_infframes_original_folds.infer_stats() + nbi_infframes_original_folds.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/nerthus.py b/plugins/data/src/mml_data/creators/classification/nerthus.py new file mode 100644 index 0000000..3e934f8 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/nerthus.py @@ -0,0 +1,76 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +REFERENCE = """ +@inproceedings{Pogorelov:2017:NBP:3083187.3083216, +author = {Pogorelov, Konstantin and Randel, Kristin Ranheim and de Lange, Thomas and Eskeland, Sigrun Losada and Griwodz, + Carsten and Johansen, Dag and Spampinato, Concetto and Taschwer, Mario and Lux, Mathias and Schmidt, + Peter Thelin and Riegler, Michael and Halvorsen, P{\aa}l}, +title = {Nerthus: A Bowel Preparation Quality Video Dataset}, +booktitle = {Proceedings of the 8th ACM on Multimedia Systems Conference}, +series = {MMSys'17}, +year = {2017}, +isbn = {978-1-4503-5002-0}, +location = {Taipei, Taiwan}, +pages = {170--174}, +numpages = {5}, +url = {http://doi.acm.org/10.1145/3083187.3083216}, +doi = {10.1145/3083187.3083216}, +acmid = {3083216}, +publisher = {ACM}, +address = {New York, NY, USA}, +} +""" # noqa W291 + + +@register_dsetcreator(dset_name="nerthus") +def create_nerthus(): + dset_creator = DSetCreator(dset_name="nerthus") + dset_creator.download( + url="https://datasets.simula.no/downloads/nerthus/nerthus.zip", + file_name="nerthus-dataset-frames.zip", + data_kind=DataKind.TRAINING_DATA, + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name="nerthus_bowel_cleansing_quality", dset_name="nerthus") +def create_nerthus_bowel_cleansing_quality(dset_path: Path): + bowel_cleansing_quality = TaskCreator( + dset_path=dset_path, + name="nerthus_bowel_cleansing_quality", + task_type=TaskType.CLASSIFICATION, + desc="Nerthus dataset for bowel cleansing quality", + ref=REFERENCE, + url="https://datasets.simula.no/nerthus/", + instr="download via datasets.simula.no/downloads/nerthus/nerthus.zip", + lic=License.UNKNOWN, + release="2017", + keywords=[Keyword.MEDICAL, Keyword.GASTROSCOPY_COLONOSCOPY, Keyword.ENDOSCOPY], + ) + classes = ["0", "1", "2", "3"] + data_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA / "nerthus-dataset-frames", classes=classes + ) + bowel_cleansing_quality.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + bowel_cleansing_quality.split_folds(n_folds=5, ensure_balancing=True) + bowel_cleansing_quality.infer_stats() + bowel_cleansing_quality.push_and_test() + + +if __name__ == "__main__": + dset_path = create_nerthus() + create_nerthus_bowel_cleansing_quality(dset_path) diff --git a/plugins/data/src/mml_data/creators/classification/pneumonia.py b/plugins/data/src/mml_data/creators/classification/pneumonia.py new file mode 100644 index 0000000..1eb6f5d --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/pneumonia.py @@ -0,0 +1,80 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +REFERENCE = """ +@article{KERMANY20181122, +title = {Identifying Medical Diagnoses and Treatable Diseases by Image-Based Deep Learning}, +journal = {Cell}, +volume = {172}, +number = {5}, +pages = {1122-1131.e9}, +year = {2018}, +issn = {0092-8674}, +doi = {https://doi.org/10.1016/j.cell.2018.02.010}, +url = {https://www.sciencedirect.com/science/article/pii/S0092867418301545}, +author = {Daniel S. Kermany and Michael Goldbaum and Wenjia Cai and Carolina C.S. Valentim and Huiying Liang and + Sally L. Baxter and Alex McKeown and Ge Yang and Xiaokang Wu and Fangbing Yan and Justin Dong and + Made K. Prasadha and Jacqueline Pei and Magdalene Y.L. Ting and Jie Zhu and Christina Li and Sierra Hewett + and Jason Dong and Ian Ziyar and Alexander Shi and Runze Zhang and Lianghong Zheng and Rui Hou and + William Shi and Xin Fu and Yaou Duan and Viet A.N. Huu and Cindy Wen and Edward D. Zhang and + Charlotte L. Zhang and Oulan Li and Xiaobo Wang and Michael A. Singer and Xiaodong Sun and Jie Xu and + Ali Tafreshi and M. Anthony Lewis and Huimin Xia and Kang Zhang}, +keywords = {artificial intelligence, transfer learning, deep learning, age-related macular degeneration, choroidal + neovascularization, diabetic retinopathy, diabetic macular edema, screening, optical coherence tomography, + pneumonia} +} +""" # noqa W291 + +dataset_name = "pneumonia" + + +@register_dsetcreator(dset_name=dataset_name) +def create_dset(): + dset_creator = DSetCreator(dset_name=dataset_name) + dset_creator.kaggle_download(dataset="tolgadincer/labeled-chest-xray-images", data_kind=DataKind.TRAINING_DATA) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +task_name = "pneumonia_classification" + + +@register_taskcreator(task_name=task_name, dset_name="pneumonia") +def create_covid_ct_classification(dset_path: Path): + covid_ct_classification = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="This dataset contains chest X-Ray images labeled as NORMAL or PNEUMONIA", + ref=REFERENCE, + url="https://www.kaggle.com/tolgadincer/labeled-chest-xray-images/", + instr="download dataset via https://www.kaggle.com/tolgadincer/labeled-chest-xray-images/download", + lic=License.CC_BY_4_0, + release="2018 v3", + keywords=[Keyword.MEDICAL, Keyword.CHEST, Keyword.X_RAY, Keyword.TISSUE_PATHOLOGY], + ) + classes = ["NORMAL", "PNEUMONIA"] + train_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA / "chest_xray" / "train", classes=classes + ) + test_iterator, _ = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA / "chest_xray" / "test", classes=classes + ) + covid_ct_classification.find_data( + train_iterator=train_iterator, test_iterator=test_iterator, idx_to_class=idx_to_class + ) + covid_ct_classification.split_folds(n_folds=5, ensure_balancing=True) + covid_ct_classification.infer_stats() + covid_ct_classification.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/shenzhen_tuberculosis.py b/plugins/data/src/mml_data/creators/classification/shenzhen_tuberculosis.py new file mode 100644 index 0000000..ac623b0 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/shenzhen_tuberculosis.py @@ -0,0 +1,74 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """ +@article{Jaeger2014TwoPC, + title={Two public chest X-ray datasets for computer-aided screening of pulmonary diseases.}, + author={Stefan Jaeger and Sema Candemir and S. Antani and Y{\`i}-Xi{\'a}ng J W{\'a}ng and Pu-Xuan Lu and George R. Thoma}, + journal={Quantitative imaging in medicine and surgery}, + year={2014}, + volume={4 6}, + pages={ + 475-7 + } +} +""" # noqa W291 + +dset_name = "shenzhen_xray_tb" +task_name = "shenzen_chest_xray_tuberculosis" + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.download( + url="http://openi.nlm.nih.gov/imgs/collections/ChinaSet_AllFiles.zip", + file_name="ChinaSet_AllFiles.zip", + data_kind=DataKind.TRAINING_DATA, + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name=task_name, dset_name=dset_name) +def create_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="The Shenzhen dataset was collected in collaboration with Shenzhen No.3 People’s " + "Hospital, Guangdong Medical College, Shenzhen, China. The chest X-rays are from " + "outpatient clinics and were captured as part of the daily hospital routine within " + "a 1-month period, mostly in September 2012, using a Philips DR Digital Diagnost " + "system. The set contains 662 frontal chest X-rays, of which 326 are normal cases " + "and 336 are cases with manifestations of TB, including pediatric X-rays (AP). The " + "X-rays are provided in PNG format. Their size can vary but is approximately 3K × 3K " + "pixels..", + ref=REFERENCE, + url="https://lhncbc.nlm.nih.gov/LHC-publications/pubs/TuberculosisChestXrayImageDataSets.html", + instr="download via http://openi.nlm.nih.gov/imgs/collections/ChinaSet_AllFiles.zip", + lic=License.UNKNOWN, + release="2014", + keywords=[Keyword.MEDICAL, Keyword.X_RAY, Keyword.CHEST, Keyword.TISSUE_PATHOLOGY], + ) + idx_to_class = {0: "normal", 1: "abnormal"} + train_iterator = [] + for img_path in sorted((dset_path / DataKind.TRAINING_DATA / "ChinaSet_AllFiles" / "CXR_png").glob("*.png")): + train_iterator.append( + {Modality.SAMPLE_ID: img_path.stem[:-2], Modality.IMAGE: img_path, Modality.CLASS: int(img_path.stem[-1])} + ) + task.find_data(train_iterator=train_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/sklin2.py b/plugins/data/src/mml_data/creators/classification/sklin2.py new file mode 100644 index 0000000..3fe552d --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/sklin2.py @@ -0,0 +1,72 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +REFERENCE = """ +@article{Faria2019LightFI, + title={Light Field Image Dataset of Skin Lesions}, + author={S{\'e}rgio M. M. Faria and Jose N. Filipe and Pedro M. M. Pereira and Luis M. N. Tavora and Pedro A. Amado + Assunç{\~a}o and Miguel O. Santos and Rui Fonseca-Pinto and Felicidade Santiago and Victoria Dominguez and Martinha + Henrique}, + journal={2019 41st Annual International Conference of the IEEE Engineering in Medicine and Biology Society (EMBC)}, + year={2019}, + pages={3905-3908} +} +""" # noqa W291 + +dset_name = "sklin2" +task_name = "sklin2_skin_lesions" + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + instructions = f""" + Download link is not available. Please download the dataset by clicking on the download button + manually via https://www.it.pt/AutomaticPage?id=3459 -> link at ther very top -> select SKLIN2_v1 -> + download the "Dermatoscopic" folder. + Once the download is complete place the downloaded folder 'Dermatoscopic.zip' in + /DOWNLOADS/{dset_name} + """ # noqa W291 + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.verify_pre_download( + file_name="Dermatoscopic.zip", data_kind=DataKind.TRAINING_DATA, instructions=instructions + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name=task_name, dset_name=dset_name) +def create_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="This dataset contains 250 light fields, captured with a focused plenoptic " + "camera and classified into eight clinical categories, according to the type " + "of lesion. Each light field is comprised of 81 different views of the same " + "lesion. The database also includes the dermatoscopic image of each lesion.", + ref=REFERENCE, + url="https://www.it.pt/AutomaticPage?id=3459", + instr="download via https://www.it.pt/AutomaticPage?id=3459", + lic=License.UNKNOWN, + release="2019 - v1", + keywords=[Keyword.MEDICAL, Keyword.DERMATOSCOPY, Keyword.TISSUE_PATHOLOGY], + ) + data_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA / "Dermatoscopic", classes=None + ) + task.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/classification/stanford_dogs.py b/plugins/data/src/mml_data/creators/classification/stanford_dogs.py new file mode 100644 index 0000000..589c95c --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/stanford_dogs.py @@ -0,0 +1,197 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +REFERENCE = """ +@inproceedings{KhoslaYaoJayadevaprakashFeiFei_FGVC2011, +author = {Aditya Khosla, Nityananda Jayadevaprakash, Bangpeng Yao and Li Fei-Fei}, +title = {Novel Dataset for Fine-Grained Image Categorization}, +booktitle = {First Workshop on Fine-Grained Visual Categorization, IEEE Conference on Computer Vision and Pattern Recognition}, +year = {2011}, +month ={June}, +address = {Colorado Springs, CO}, +} +""" + +ADDITIONAL_REFERENCE = """" +@INPROCEEDINGS{5206848, +author = {Deng, Jia and Dong, Wei and Socher, Richard and Li, Li-Jia and Kai Li and Li Fei-Fei}, +booktitle = {2009 IEEE Conference on Computer Vision and Pattern Recognition}, +title = {ImageNet: A large-scale hierarchical image database}, +year = {2009}, +pages = {248-255}, +doi = {10.1109/CVPR.2009.5206848}} +""" # noqa W291 + + +@register_dsetcreator(dset_name="stanford_dogs") +def create_stanford_dogs(): + dset_creator = DSetCreator(dset_name="stanford_dogs") + dset_creator.download( + url="http://vision.stanford.edu/aditya86/ImageNetDogs/images.tar", + file_name="images.tar", + data_kind=DataKind.TRAINING_DATA, + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name="stanford_dogs_image_categorization", dset_name="stanford_dogs") +def create_stanford_dogs_image_categorization(dset_path: Path): + dogs_categorization = TaskCreator( + dset_path=dset_path, + name="stanford_dogs_image_categorization", + task_type=TaskType.CLASSIFICATION, + desc="Stanford Dogs Dataset for Image Categorization", + ref=REFERENCE + "\n" + ADDITIONAL_REFERENCE, + url="http://vision.stanford.edu/aditya86/ImageNetDogs/", + instr="download via vision.stanford.edu/aditya86/ImageNetDogs/images.tar", + lic=License.UNKNOWN, + release="2011", + keywords=[Keyword.ANIMALS, Keyword.NATURAL_OBJECTS], + ) + classes = [ + "n02085620-Chihuahua", + "n02085782-Japanese_spaniel", + "n02085936-Maltese_dog", + "n02086079-Pekinese", + "n02086240-Shih-Tzu", + "n02086646-Blenheim_spaniel", + "n02086910-papillon", + "n02087046-toy_terrier", + "n02087394-Rhodesian_ridgeback", + "n02088094-Afghan_hound", + "n02088238-basset", + "n02088364-beagle", + "n02088466-bloodhound", + "n02088632-bluetick", + "n02089078-black-and-tan_coonhound", + "n02089867-Walker_hound", + "n02089973-English_foxhound", + "n02090379-redbone", + "n02090622-borzoi", + "n02090721-Irish_wolfhound", + "n02091032-Italian_greyhound", + "n02091134-whippet", + "n02091244-Ibizan_hound", + "n02091467-Norwegian_elkhound", + "n02091635-otterhound", + "n02091831-Saluki", + "n02092002-Scottish_deerhound", + "n02092339-Weimaraner", + "n02093256-Staffordshire_bullterrier", + "n02093428-American_Staffordshire_terrier", + "n02093647-Bedlington_terrier", + "n02093754-Border_terrier", + "n02093859-Kerry_blue_terrier", + "n02093991-Irish_terrier", + "n02094114-Norfolk_terrier", + "n02094258-Norwich_terrier", + "n02094433-Yorkshire_terrier", + "n02095314-wire-haired_fox_terrier", + "n02095570-Lakeland_terrier", + "n02095889-Sealyham_terrier", + "n02096051-Airedale", + "n02096177-cairn", + "n02096294-Australian_terrier", + "n02096437-Dandie_Dinmont", + "n02096585-Boston_bull", + "n02097047-miniature_schnauzer", + "n02097130-giant_schnauzer", + "n02097209-standard_schnauzer", + "n02097298-Scotch_terrier", + "n02097474-Tibetan_terrier", + "n02097658-silky_terrier", + "n02098105-soft-coated_wheaten_terrier", + "n02098286-West_Highland_white_terrier", + "n02098413-Lhasa", + "n02099267-flat-coated_retriever", + "n02099429-curly-coated_retriever", + "n02099601-golden_retriever", + "n02099712-Labrador_retriever", + "n02099849-Chesapeake_Bay_retriever", + "n02100236-German_short-haired_pointer", + "n02100583-vizsla", + "n02100735-English_setter", + "n02100877-Irish_setter", + "n02101006-Gordon_setter", + "n02101388-Brittany_spaniel", + "n02101556-clumber", + "n02102040-English_springer", + "n02102177-Welsh_springer_spaniel", + "n02102318-cocker_spaniel", + "n02102480-Sussex_spaniel", + "n02102973-Irish_water_spaniel", + "n02104029-kuvasz", + "n02104365-schipperke", + "n02105056-groenendael", + "n02105162-malinois", + "n02105251-briard", + "n02105412-kelpie", + "n02105505-komondor", + "n02105641-Old_English_sheepdog", + "n02105855-Shetland_sheepdog", + "n02106030-collie", + "n02106166-Border_collie", + "n02106382-Bouvier_des_Flandres", + "n02106550-Rottweiler", + "n02106662-German_shepherd", + "n02107142-Doberman", + "n02107312-miniature_pinscher", + "n02107574-Greater_Swiss_Mountain_dog", + "n02107683-Bernese_mountain_dog", + "n02107683-Bernese_mountain_dog", + "n02108000-EntleBucher", + "n02108089-boxer", + "n02108422-bull_mastiff", + "n02108551-Tibetan_mastiff", + "n02108915-French_bulldog", + "n02109047-Great_Dane", + "n02109525-Saint_Bernard", + "n02109961-Eskimo_dog", + "n02110063-malamute", + "n02110185-Siberian_husky", + "n02110627-affenpinscher", + "n02110806-basenji", + "n02110958-pug", + "n02111129-Leonberg", + "n02111277-Newfoundland", + "n02111500-Great_Pyrenees", + "n02111889-Samoyed", + "n02112018-Pomeranian", + "n02112137-chow", + "n02112350-keeshond", + "n02112706-Brabancon_griffon", + "n02113023-Pembroke", + "n02113186-Cardigan", + "n02113624-toy_poodle", + "n02113712-miniature_poodle", + "n02113799-standard_poodle", + "n02113978-Mexican_hairless", + "n02115641-dingo", + "n02115913-dhole", + "n02116738-African_hunting_dog", + ] + data_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA / "Images", classes=classes + ) + dogs_categorization.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + dogs_categorization.split_folds(n_folds=5, ensure_balancing=True) + dogs_categorization.infer_stats() + dogs_categorization.push_and_test() + + +if __name__ == "__main__": + dset_path = create_stanford_dogs() + create_stanford_dogs_image_categorization(dset_path) diff --git a/plugins/data/src/mml_data/creators/classification/suncolondb.py b/plugins/data/src/mml_data/creators/classification/suncolondb.py new file mode 100644 index 0000000..785e2b4 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/suncolondb.py @@ -0,0 +1,222 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +from pathlib import Path +from typing import Dict + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, RGBInfo, Sizes, TaskType +from mml.core.data_preparation.archive_extractors import ask_password +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +logger = logging.getLogger(__name__) + +REFERENCE = """ +@article{MISAWA2021960, +title = {Development of a computer-aided detection system for colonoscopy and a publicly accessible large colonoscopy video database (with video)}, +journal = {Gastrointestinal Endoscopy}, +volume = {93}, +number = {4}, +pages = {960-967.e3}, +year = {2021}, +issn = {0016-5107}, +doi = {https://doi.org/10.1016/j.gie.2020.07.060}, +url = {https://www.sciencedirect.com/science/article/pii/S0016510720346551}, +author = {Masashi Misawa and Shin-ei Kudo and Yuichi Mori and Kinichi Hotta and Kazuo Ohtsuka +and Takahisa Matsuda and Shoichi Saito and Toyoki Kudo and Toshiyuki Baba and Fumio Ishida and Hayato Itoh and Masahiro Oda and Kensaku Mori}, +} +""" + +dset_name = "SUNdatabase" +ALL_TASKS = ["polyp", "no_polyp"] + +instructions = f""" +Download link is not available. Please request access to the dataset on http://amed8k.sundatabase.org/, +afterwards download the six .zip files and place them in the /DOWNLOADS/{dset_name}. + +""" + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + """Creates dataset + + :param dset_name: Name of the dataset + :type dset_name: string + :return: Path to dataset directory + :rtype: PosixPath + """ + dset_creator = DSetCreator(dset_name=dset_name) + file_list = [ + "sundatabase_positive_part1.zip", + "sundatabase_positive_part2.zip", + "sundatabase_negative_part1.zip", + "sundatabase_negative_part2.zip", + "sundatabase_negative_part3.zip", + "sundatabase_negative_part4.zip", + ] + pwd = ask_password() # same password for all archives + for file_name in file_list: + archive = dset_creator.verify_pre_download( + file_name=file_name, data_kind=DataKind.TRAINING_DATA, instructions=instructions + ) + archive.password = pwd + archive.keep_top_level = True + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name="suncolondb-classification", dset_name=dset_name) +def create_task(dset_path: Path) -> None: + """Creates task for suncolondb classification + + :param dset_path: Path to dataset + :type dset_path: Path + """ + task_creator = TaskCreator( + dset_path=dset_path, + name="suncolondb-classification", + task_type=TaskType.CLASSIFICATION, + desc="The SUN database includes 49,136 polyp frames taken from " + "different 100 polyps, which were fully annotated with bounding " + "boxes. Non-polyp scenes of 109,554 frames are also included " + "in this database. In polyp-existing frames, each polyp is " + "annotated with a bounding box. The file formats of images, " + "and bounding boxes are jpeg and a text file, respectively. " + "In the text file, each row represents a bounding box of a " + "polyp, that is, " + '"Filename min_Xcoordinate,min_Ycoordinate,max_Xcorrdinate,max_Ycoordinate,class_id", ' + "where class_id of 0 and 1 represent polyp and non-polyp frames, " + "respectively.", + ref=REFERENCE, + url="http://amed8k.sundatabase.org/", + instr="request access via http://amed8k.sundatabase.org/", + lic=License.CUSTOM, + release="2020", + keywords=[Keyword.MEDICAL, Keyword.ENDOSCOPY, Keyword.TISSUE_PATHOLOGY], + ) + + # the subdirectories where the negative cases are stored + data_parts_negative = [ + "sundatabase_" + var for var in ["negative_part1", "negative_part2", "negative_part3", "negative_part4"] + ] + # the subdirectoreis where the positive cases are stored + data_parts_positive = ["sundatabase_" + var for var in ["positive_part1", "positive_part2"]] + + case_paths_neg = get_case_paths(data_parts_negative, dset_path, ispos=False) + case_paths_pos = get_case_paths(data_parts_positive, dset_path, ispos=True) + case_paths = case_paths_neg + case_paths_pos + + # load annotations + all_annotations = load_annotations(dset_path) + + data_iterators = get_data_iterators(case_paths, all_annotations) + + idx_to_class = {0: "not_present", 1: "present"} + task_creator.find_data( + train_iterator=data_iterators["train"], test_iterator=data_iterators["test"], idx_to_class=idx_to_class + ) + task_creator.split_folds(n_folds=5, ensure_balancing=True) + # stats are identical across tasks, save calculation time here + task_creator.set_stats( + means=RGBInfo(*[0.5652844309806824, 0.32137545943260193, 0.23057971894741058]), + stds=RGBInfo(*[0.2662612497806549, 0.21721985936164856, 0.16612227261066437]), + sizes=Sizes(*[1008, 1080, 1158, 1240]), + ) + task_creator.push_and_test() + pass + + +def get_case_paths(data_parts, dset_path, ispos): + """Returns list with paths of cases in subdirectories as well as whether they are positive or negative + + :param data_parts: list of directories where cases are saved + :type data_parts: list of strings + :param dset_path: path to dataset directory + :type dset_path: PosixPath + :param ispos: Whether the data_parts contain the positive samples + :type ispos: bool + :return: List of paths to all the cases in dataset, along with whether they are positive or negative + :rtype: list of [PosixPath, bool] + """ + case_paths = [] + for data_part in data_parts: + data_part_path = dset_path / "training_data" / data_part + for subdir in Path(data_part_path).iterdir(): + if subdir.is_dir() and subdir.name.startswith("case"): # exclude annotations + case_paths.append([subdir, ispos]) + return case_paths + + +def load_annotations(dset_path: Path) -> Dict[str, Dict[str, int]]: + """Load annotations and stores them in dict + + :param dset_path: path to directory + :type dset_path: PosixPath + :return: Dict contating one dict per video containing class values per frame + :rtype: Dict of dicts of ints + """ + all_annotations = {} + annotation_dir = dset_path / "training_data" / "sundatabase_positive_part1" / "annotation_txt" + anno_file_list = [file for file in Path(annotation_dir).iterdir() if file.is_file()] + for anno_file_name in anno_file_list: + case = anno_file_name.stem + all_annotations[case] = {} + anno_file_path = Path(annotation_dir) / anno_file_name + with open(anno_file_path, "r") as anno_file: + # line format: 'filename min_Xcoordinate,min_Ycoordinate, max_Xcoordinate, max_Ycoordinate, class_id' + for line in anno_file: + line_elements = line.strip().split(",") + file_name = line_elements[0].split(" ")[0] + if not file_name.endswith(".jpg"): + raise ValueError(f"File name {file_name} does not end with '.jpg'") + class_val = int(line_elements[-1]) + if class_val not in [0, 1]: + raise ValueError(f"Class value {class_val} has to be either 0 or 1.") + all_annotations[case][file_name] = class_val + return all_annotations + + +def get_data_iterators(case_paths, all_annotations): + """Splits the dataset into train and test and generates data iterators + + :param case_paths: list of paths and whether they are from positive or negative samples + :type case_paths: list of [PosixPath, bool] + :param all_annotations: Dict contating one dict per video containing class values per frame + :type all_annotations: Dict of dicts of ints + :return: Dict containing train and test sets, containing a list of identifier, path and class + :rtype: dict of list of dict + """ + # splits data along videos + vids_split = {"train": case_paths[:68], "test": case_paths[68:]} + data_iterators = {k: [] for k in vids_split} + for phase in vids_split: # loops over train/test + for vid in vids_split[phase]: # loops over videos + if vid[1] == 0: # videos without polyps + for frame in vid[0].iterdir(): # loops over frames + data_iterators[phase].append( + { + Modality.SAMPLE_ID: f'neg_vid{vid[0].stem}_frame{frame.stem.split("_")[-3]}_{frame.stem[-6:]}', + Modality.IMAGE: frame, + Modality.CLASS: 0, + } + ) + else: # videos with polyps + for frame in vid[0].iterdir(): # loops over frames + no_polyp = all_annotations[str(vid[0]).split("/")[-1]][frame.stem + ".jpg"] + if not no_polyp: # check whether frame contains polyp, if not, ignore + data_iterators[phase].append( + { + Modality.SAMPLE_ID: f"""pos_vid{vid[0].stem}_frame{frame.stem.split("_")[-4]} + _{frame.stem.split("_")[-3]}_{frame.stem[-4:]}""", + Modality.IMAGE: frame, + Modality.CLASS: 1, + } + ) + return data_iterators diff --git a/plugins/data/src/mml_data/creators/classification/svhn.py b/plugins/data/src/mml_data/creators/classification/svhn.py new file mode 100644 index 0000000..9f4a574 --- /dev/null +++ b/plugins/data/src/mml_data/creators/classification/svhn.py @@ -0,0 +1,70 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from torchvision.datasets import SVHN + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_and_mapping_from_image_dataset + +REFERENCE = """ +@inproceedings{Netzer2011ReadingDI, + title={Reading Digits in Natural Images with Unsupervised Feature Learning}, + author={Yuval Netzer and Tiejie Wang and Adam Coates and A. Bissacco and Bo Wu and A. Ng}, + year={2011} +} +""" + +dset_name = "svhn" +classes = [str(ix) for ix in range(10)] + + +@register_dsetcreator(dset_name=dset_name) +def create_street_view_house_numbers(): + dset_creator = DSetCreator(dset_name=dset_name) + train = SVHN(root=dset_creator.download_path, split="train", download=True) + test = SVHN(root=dset_creator.download_path, split="test", download=True) + # TODO see if extra may be added as unlabeled additional data + # extra = SVHN(root=dset_creator.download_path, split='extra', download=True) + dset_path = dset_creator.extract_from_pytorch_datasets( + datasets={"training": train, "testing": test}, task_type=TaskType.CLASSIFICATION, class_names=classes + ) + return dset_path + + +task_name = "svhn" + + +@register_taskcreator(task_name=task_name, dset_name=dset_name) +def create_svhn(dset_path: Path): + svhn = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="Street view house numbers classification", + ref=REFERENCE, + url="http://ufldl.stanford.edu/housenumbers/", + instr="downloaded via torchvision dataset (https://pytorch.org/vision/stable/datasets.html#svhn)", + lic=License.UNKNOWN, + release="2011", + keywords=[Keyword.CHARS_DIGITS, Keyword.NATURAL_OBJECTS], + ) + train_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TRAINING_DATA, classes=classes + ) + test_iterator, idx_to_class_2 = get_iterator_and_mapping_from_image_dataset( + root=dset_path / DataKind.TESTING_DATA, classes=classes + ) + assert all([a == b for a, b in zip(idx_to_class, idx_to_class_2)]) + svhn.find_data(train_iterator=train_iterator, test_iterator=test_iterator, idx_to_class=idx_to_class) + svhn.split_folds(n_folds=5, ensure_balancing=True) + svhn.infer_stats() + svhn.push_and_test() diff --git a/plugins/data/src/mml_data/creators/segmentation/__init__.py b/plugins/data/src/mml_data/creators/segmentation/__init__.py new file mode 100644 index 0000000..cac8930 --- /dev/null +++ b/plugins/data/src/mml_data/creators/segmentation/__init__.py @@ -0,0 +1,13 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +modules = Path(__file__).parent.glob("*.py") +# this will automatically import all valid submodules, so the tasks are registered automatically +__all__ = [module.stem for module in modules if module.is_file() and not module.stem.startswith("_")] + +from . import * # noqa F403, F401, E402 diff --git a/plugins/data/src/mml_data/creators/segmentation/crowd_source_instrument.py b/plugins/data/src/mml_data/creators/segmentation/crowd_source_instrument.py new file mode 100644 index 0000000..3e3a1f4 --- /dev/null +++ b/plugins/data/src/mml_data/creators/segmentation/crowd_source_instrument.py @@ -0,0 +1,102 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# creates the "endocsopic instrument segmentation with crowdsourced data" dataset and tasks +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """ +@InProceedings{10.1007/978-3-319-10470-6_55, +author="Maier-Hein, Lena +and Mersmann, Sven +and Kondermann, Daniel +and Bodenstedt, Sebastian +and Sanchez, Alexandro +and Stock, Christian +and Kenngott, Hannes Gotz +and Eisenmann, Mathias +and Speidel, Stefanie", +editor="Golland, Polina +and Hata, Nobuhiko +and Barillot, Christian +and Hornegger, Joachim +and Howe, Robert", +title="Can Masses of Non-Experts Train Highly Accurate Image Classifiers?", +booktitle="Medical Image Computing and Computer-Assisted Intervention -- MICCAI 2014", +year="2014", +publisher="Springer International Publishing", +address="Cham", +pages="438--445", +isbn="978-3-319-10470-6" +} +""" + +dset_name = "crowdsourced-EIS" +# make sure background goes first +class_mapping = {"background": (0, 0, 0), "instrument": (128, 0, 0)} + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.download( + url="https://opencas.webarchiv.kit.edu/data/AnnotatedImages.zip", + file_name="AnnotatedImages.zip", + data_kind=DataKind.TRAINING_DATA, + ) + dset_path = dset_creator.unpack_and_store() + masks = list((dset_path / DataKind.TRAINING_DATA).rglob("*_inst_GT*.bmp")) + out_base = dset_creator.transform_masks( + masks=masks, load="rgb", transform={class_mapping["background"]: 0, class_mapping["instrument"]: 1}, train=True + ) + assert out_base == dset_path / DataKind.TRAINING_LABELS / "transformed_masks", f"{out_base=}" + return dset_path + + +@register_taskcreator(task_name="crowdsourced-endoscopic-instrument-segmentation-crowd-only", dset_name=dset_name) +def create_crowd(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name="crowdsourced-endoscopic-instrument-segmentation-crowd-only", + task_type=TaskType.SEMANTIC_SEGMENTATION, + desc="segmenting endoscopic instruments with labels provided by the crowd", + ref=REFERENCE, + url="https://opencas.webarchiv.kit.edu/?q=InstrumentCrowd", + instr="download data archive via website", + lic=License.UNKNOWN, + release="2014", + keywords=[Keyword.LAPAROSCOPY, Keyword.MEDICAL, Keyword.ENDOSCOPIC_INSTRUMENTS], + ) + data_iterator = [] + for patient_id in [p.name for p in (dset_path / DataKind.TRAINING_DATA).iterdir() if p.is_dir()]: + for img_id in [ + p.stem + for p in (dset_path / DataKind.TRAINING_DATA / patient_id / "crowd").iterdir() + if p.is_file() and "_inst_GTcrowd" not in p.name and p.suffix == ".bmp" + ]: + data_iterator.append( + { + Modality.SAMPLE_ID: img_id, + Modality.IMAGE: dset_path / DataKind.TRAINING_DATA / patient_id / "crowd" / f"{img_id}.bmp", + Modality.MASK: ( + dset_path + / DataKind.TRAINING_LABELS + / "transformed_masks" + / patient_id + / "crowd" + / f"{img_id}_inst_GTcrowd.png" + ), + } + ) + task.find_data(train_iterator=data_iterator, idx_to_class={ix: cls for ix, cls in enumerate(class_mapping.keys())}) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/segmentation/endovis18_robotic_instrument.py b/plugins/data/src/mml_data/creators/segmentation/endovis18_robotic_instrument.py new file mode 100644 index 0000000..302d12d --- /dev/null +++ b/plugins/data/src/mml_data/creators/segmentation/endovis18_robotic_instrument.py @@ -0,0 +1,155 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import shutil +from itertools import chain +from pathlib import Path +from typing import List + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """ +@misc{allan20202018, + title={2018 Robotic Scene Segmentation Challenge}, + author={Max Allan and Satoshi Kondo and Sebastian Bodenstedt and Stefan Leger and Rahim Kadkhodamohammadi and + Imanol Luengo and Felix Fuentes and Evangello Flouty and Ahmed Mohammed and Marius Pedersen and Avinash Kori + and Varghese Alex and Ganapathy Krishnamurthi and David Rauber and Robert Mendel and Christoph Palm and Sophia + Bano and Guinther Saibro and Chi-Sheng Shih and Hsun-An Chiang and Juntang Zhuang and Junlin Yang and Vladimir + Iglovikov and Anton Dobrenkii and Madhu Reddiboina and Anubhav Reddy and Xingtong Liu and Cong Gao and Mathias + Unberath and Myeonghyeon Kim and Chanho Kim and Chaewon Kim and Hyejin Kim and Gyeongmin Lee and Ihsan Ullah and + Miguel Luna and Sang Hyun Park and Mahdi Azizian and Danail Stoyanov and Lena Maier-Hein and Stefanie Speidel}, + year={2020}, + eprint={2001.11190}, + archivePrefix={arXiv}, + primaryClass={cs.CV} +} +""" # noqa W291 + +dset_name = "endovis18_rob_instr" +class_mapping = { + (0, 0, 0): "background-tissue", + (0, 255, 0): "instrument-shaft", + (0, 255, 255): "instrument-clasper", + (125, 255, 12): "instrument-wrist", + (255, 55, 0): "kidney-parenchyma", + (24, 55, 125): "covered-kidney", + (187, 155, 25): "thread", + (0, 255, 125): "clamps", + (255, 255, 125): "suturing-needle", + (123, 15, 175): "suction-instrument", + (124, 155, 5): "small-intestine", + (12, 255, 141): "ultrasound-probe", +} + + +def get_sequences(dset_path: Path) -> List[Path]: + """ + Returns all sequence folder paths. + + :param dset_path: + :return: + """ + releases = [ + "miccai_challenge_2018_release_1", + "miccai_challenge_release_2", + "miccai_challenge_release_3", + "miccai_challenge_release_4", + ] + return [p for rel in releases for p in (dset_path / DataKind.TRAINING_DATA / rel).iterdir() if p.is_dir()] + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + instructions = """" + Download link is not available. Please download the dataset by clicking on the download buttons manually via + https://endovissub2018-roboticscenesegmentation.grand-challenge.org/Downloads/ + Download the three files under Training data release 1 and the two files under Training data release 2 + Once the download is complete place the 5 downloaded files 'miccai_challenge_2018_release_1.zip', + 'repairs.zip', 'miccai_challenge_release_2.zip', 'miccai_challenge_release_3.zip' and + 'miccai_challenge_release_4.zip' in \\DOWNLOADS\\endovis18_rob_instr + """ + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.verify_pre_download( + file_name="miccai_challenge_2018_release_1.zip", data_kind=DataKind.TRAINING_DATA, instructions=instructions + ) + dset_creator.verify_pre_download( + file_name="repairs.zip", data_kind=DataKind.TRAINING_DATA, instructions=instructions + ) + dset_creator.verify_pre_download( + file_name="miccai_challenge_release_2.zip", data_kind=DataKind.TRAINING_DATA, instructions=instructions + ) + dset_creator.verify_pre_download( + file_name="miccai_challenge_release_3.zip", data_kind=DataKind.TRAINING_DATA, instructions=instructions + ) + dset_creator.verify_pre_download( + file_name="miccai_challenge_release_4.zip", data_kind=DataKind.TRAINING_DATA, instructions=instructions + ) + dset_path = dset_creator.unpack_and_store() + # replace repaired image masks for sequences 1 and 4 of first release + repair_root = dset_path / DataKind.TRAINING_DATA / "repairs" + for file in repair_root.iterdir(): + seq = file.name.split("_")[1] + name = file.name[6:] + target = ( + dset_path / DataKind.TRAINING_DATA / "miccai_challenge_2018_release_1" / f"seq_{seq}" / "labels" / f"{name}" + ) + shutil.move(file, target) + # gather all masks and transform them accordingly + masks = list(chain(*[(seq / "labels").rglob("*.png") for seq in get_sequences(dset_path)])) + dset_creator.transform_masks( + masks=masks, + load="rgb", + transform={pix_val: idx for idx, pix_val in enumerate(class_mapping.keys())}, + train=True, + ) + return dset_path + + +@register_taskcreator(task_name="endovissub18_robotic_instrument_seg", dset_name=dset_name) +def create_task_glenda(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name="endovissub18_robotic_instrument_seg", + task_type=TaskType.SEMANTIC_SEGMENTATION, + desc="The dataset includes pixel wise segmentation of robotic instruments as well as anatomical " + "objects and non-robotic surgical instruments such as suturing needles and gauze", + ref=REFERENCE, + url="https://endovissub2018-roboticscenesegmentation.grand-challenge.org/Downloads/", + instr="download the data using the 5 links via website", + lic=License.UNKNOWN, + release="2018", + keywords=[Keyword.MEDICAL, Keyword.NEPHRECTOMY, Keyword.ENDOSCOPIC_INSTRUMENTS, Keyword.ANATOMICAL_STRUCTURES], + ) + data_iterator = [] + for seq in get_sequences(dset_path): + for img in (seq / "left_frames").iterdir(): + if not (img.is_file() and img.suffix == ".png"): + continue + data_iterator.append( + { + Modality.SAMPLE_ID: f"seq_{seq.name.split('_')[-1]}_{img.stem}", + Modality.IMAGE: img, + Modality.MASK: ( + dset_path + / DataKind.TRAINING_LABELS + / "transformed_masks" + / seq.parent.name + / seq.name + / "labels" + / f"{img.name}" + ), + } + ) + task.find_data( + train_iterator=data_iterator, idx_to_class={ix: cls for ix, cls in enumerate(class_mapping.values())} + ) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/segmentation/enid.py b/plugins/data/src/mml_data/creators/segmentation/enid.py new file mode 100644 index 0000000..6d6d183 --- /dev/null +++ b/plugins/data/src/mml_data/creators/segmentation/enid.py @@ -0,0 +1,328 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """" +@article{DBLP:conf/mta/LeibetsederS21, + author = {Andreas Leibetseder and + Klaus Schoeffmann and + J{\"{o}}rg Keckstein and + Simon Keckstein}, + title = {Endometriosis Detection and Localization in Laparoscopic Gynecology}, +} +""" + +dset_name = "enid" +class_mapping = { + (0, 0, 0): "background", # Background/No Pathology + (204, 81, 81): "Endo-Peritoneum", # endometriosis +} +# these values are borderline pixels, not directly mappable to one of the classes, they will be ignored +wrong = [ + [1, 0, 0], + [2, 1, 1], + [3, 1, 1], + [4, 2, 2], + [5, 2, 2], + [6, 2, 2], + [6, 3, 3], + [7, 3, 3], + [8, 3, 3], + [9, 3, 3], + [10, 4, 4], + [11, 4, 4], + [12, 5, 5], + [13, 5, 5], + [14, 5, 5], + [14, 6, 6], + [15, 6, 6], + [16, 6, 6], + [17, 7, 7], + [18, 7, 7], + [19, 8, 8], + [20, 8, 8], + [21, 8, 8], + [22, 9, 9], + [23, 9, 9], + [24, 9, 9], + [25, 10, 10], + [26, 10, 10], + [27, 11, 11], + [28, 11, 11], + [29, 11, 11], + [29, 12, 12], + [30, 12, 12], + [31, 12, 12], + [32, 13, 13], + [33, 13, 13], + [34, 14, 14], + [35, 14, 14], + [36, 14, 14], + [37, 15, 15], + [38, 15, 15], + [39, 16, 16], + [40, 16, 16], + [41, 16, 16], + [42, 17, 17], + [43, 17, 17], + [44, 17, 17], + [45, 18, 18], + [46, 18, 18], + [47, 19, 19], + [48, 19, 19], + [49, 19, 19], + [49, 20, 20], + [50, 20, 20], + [51, 20, 20], + [52, 21, 21], + [53, 21, 21], + [54, 22, 22], + [55, 22, 22], + [56, 22, 22], + [57, 22, 22], + [57, 23, 23], + [58, 23, 23], + [59, 23, 23], + [60, 24, 24], + [61, 24, 24], + [62, 25, 25], + [63, 25, 25], + [64, 25, 25], + [65, 26, 26], + [66, 26, 26], + [67, 27, 27], + [68, 27, 27], + [69, 27, 27], + [69, 28, 28], + [70, 28, 28], + [71, 28, 28], + [72, 28, 28], + [73, 29, 29], + [74, 29, 29], + [75, 30, 30], + [76, 30, 30], + [77, 30, 30], + [77, 31, 31], + [78, 31, 31], + [79, 31, 31], + [80, 32, 32], + [81, 32, 32], + [82, 33, 33], + [83, 33, 33], + [84, 33, 33], + [84, 34, 34], + [85, 34, 34], + [86, 34, 34], + [87, 34, 34], + [88, 35, 35], + [89, 35, 35], + [90, 36, 36], + [91, 36, 36], + [92, 36, 36], + [92, 37, 37], + [93, 37, 37], + [94, 37, 37], + [95, 38, 38], + [96, 38, 38], + [97, 39, 39], + [98, 39, 39], + [99, 39, 39], + [100, 40, 40], + [101, 40, 40], + [103, 41, 41], + [104, 41, 41], + [105, 42, 42], + [106, 42, 42], + [107, 42, 42], + [108, 43, 43], + [109, 43, 43], + [110, 44, 44], + [111, 44, 44], + [112, 44, 44], + [112, 45, 45], + [113, 45, 45], + [114, 45, 45], + [115, 46, 46], + [116, 46, 46], + [117, 47, 47], + [118, 47, 47], + [119, 47, 47], + [120, 47, 47], + [120, 48, 48], + [121, 48, 48], + [122, 48, 48], + [123, 49, 49], + [124, 49, 49], + [125, 50, 50], + [126, 50, 50], + [127, 50, 50], + [128, 51, 51], + [129, 51, 51], + [130, 52, 52], + [131, 52, 52], + [132, 53, 53], + [133, 53, 53], + [134, 53, 53], + [135, 53, 53], + [135, 54, 54], + [136, 54, 54], + [137, 54, 54], + [138, 55, 55], + [139, 55, 55], + [140, 56, 56], + [141, 56, 56], + [142, 56, 56], + [143, 57, 57], + [144, 57, 57], + [145, 58, 58], + [146, 58, 58], + [147, 58, 58], + [147, 59, 59], + [148, 59, 59], + [149, 59, 59], + [150, 59, 59], + [151, 60, 60], + [152, 60, 60], + [153, 61, 61], + [154, 61, 61], + [155, 61, 61], + [155, 62, 62], + [156, 62, 62], + [157, 62, 62], + [158, 63, 63], + [159, 63, 63], + [160, 64, 64], + [161, 64, 64], + [162, 64, 64], + [163, 65, 65], + [164, 65, 65], + [165, 65, 65], + [165, 66, 66], + [166, 66, 66], + [167, 66, 66], + [168, 67, 67], + [169, 67, 67], + [170, 67, 67], + [170, 68, 68], + [171, 68, 68], + [172, 68, 68], + [172, 69, 69], + [173, 69, 69], + [174, 69, 69], + [175, 69, 69], + [175, 70, 70], + [176, 70, 70], + [177, 70, 70], + [178, 71, 71], + [179, 71, 71], + [180, 71, 71], + [180, 72, 72], + [181, 72, 72], + [182, 72, 72], + [183, 72, 72], + [183, 73, 73], + [184, 73, 73], + [185, 73, 73], + [185, 74, 74], + [186, 74, 74], + [187, 74, 74], + [188, 74, 74], + [188, 75, 75], + [189, 75, 75], + [190, 75, 75], + [190, 76, 76], + [191, 76, 76], + [192, 76, 76], + [193, 76, 76], + [193, 77, 77], + [194, 77, 77], + [195, 77, 77], + [195, 78, 78], + [196, 78, 78], + [197, 78, 78], + [198, 78, 78], + [198, 79, 79], + [199, 79, 79], + [200, 79, 79], + [200, 80, 80], + [201, 80, 80], + [202, 80, 80], + [203, 80, 80], + [203, 81, 81], +] + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.download( + url="http://ftp.itec.aau.at/datasets/ENID/downloads/datasets/ENID_v1.0_dataset.zip", + file_name="ENID_v1.0_dataset.zip", + data_kind=DataKind.TRAINING_DATA, + ) + dset_path = dset_creator.unpack_and_store() + masks = list((dset_path / DataKind.TRAINING_DATA / "ENID_v1.0_dataset" / "annots").rglob("*.png")) + keys = list(class_mapping.keys()) + out_base = dset_creator.transform_masks( + masks=masks, + load="rgb", + transform={pix_val: idx for idx, pix_val in enumerate(keys)}, + train=True, + ignore=[tuple(ix) for ix in wrong], + ) + + assert out_base == dset_path / DataKind.TRAINING_LABELS / "transformed_masks", f"{out_base=}" + return dset_path + + +@register_taskcreator(task_name="endometrial_implants", dset_name=dset_name) +def create_task_enid(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name="endometrial_implants", + task_type=TaskType.SEMANTIC_SEGMENTATION, + desc="The dataset includes region-based annotations of a specific visual endometriosis " + "manifestation: dark endometrial implants. ", + ref=REFERENCE, + url="http://ftp.itec.aau.at/datasets/ENID", + instr="download data ENID_v1.0_dataset via website", + lic=License.CC_BY_NC_4_0, + release="2021", + keywords=[Keyword.LAPAROSCOPY, Keyword.MEDICAL, Keyword.GYNECOLOGY], + ) + data_iterator = [] + for img_id in [ + p.stem + for p in (dset_path / DataKind.TRAINING_DATA / "ENID_v1.0_dataset" / "frames").iterdir() + if p.is_file() and p.suffix == ".jpg" + ]: + data_iterator.append( + { + Modality.SAMPLE_ID: img_id, + Modality.IMAGE: dset_path / DataKind.TRAINING_DATA / "ENID_v1.0_dataset" / "frames" / f"{img_id}.jpg", + Modality.MASK: ( + dset_path + / DataKind.TRAINING_LABELS + / "transformed_masks" + / "ENID_v1.0_dataset" + / "annots" + / f"{img_id}.png" + ), + } + ) + task.find_data( + train_iterator=data_iterator, idx_to_class={ix: cls for ix, cls in enumerate(class_mapping.values())} + ) + task.split_folds(n_folds=5) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/segmentation/glenda.py b/plugins/data/src/mml_data/creators/segmentation/glenda.py new file mode 100644 index 0000000..c0ce9ba --- /dev/null +++ b/plugins/data/src/mml_data/creators/segmentation/glenda.py @@ -0,0 +1,1183 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """" +@inproceedings{DBLP:conf/mmm/LeibetsederKSKK20, + author = {Andreas Leibetseder and + Sabrina Kletz and + Klaus Schoeffmann and + Simon Keckstein and + J{\"{o}}rg Keckstein}, + title = {{GLENDA:} Gynecologic Laparoscopy Endometriosis Dataset}, + booktitle = {MultiMedia Modeling - 26th International Conference, {MMM} 2020, Daejeon, + South Korea, January 5-8, 2020, Proceedings, Part {II}}, + series = {Lecture Notes in Computer Science}, + volume = {11962}, + pages = {439--450}, + publisher = {Springer}, + year = {2020}, + url = {https://doi.org/10.1007/978-3-030-37734-2\\_36}, + doi = {10.1007/978-3-030-37734-2\\_36}, + timestamp = {Mon, 09 Nov 2020 15:46:42 +0100}, + biburl = {https://dblp.org/rec/conf/mmm/LeibetsederKSKK20.bib}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} +""" + +dset_name = "glenda" +class_mapping = { + (0, 0, 0): "background", # Background/No Pathology + (190, 62, 204): "6.1.1.1_Endo-Peritoneum", # Peritoneal endometriosis + (93, 89, 254): "6.1.1.2_Endo-Ovar", # Endometriosis on ovaries + (145, 210, 138): "6.1.1.3_Endo-TIE", + # Deep infiltrating endometriosis( found on specific locations such as the rectum, the rectovaginal space + # or uterine ligaments) + (238, 236, 50): "6.1.1.4_Endo-Uterus", # Uterine endometriosis or Adenomyosis +} +# these values are borderline pixels, not directly mappable to one of the classes, they will be ignored +wrongs = [ + [0, 0, 1], + [1, 0, 1], + [1, 0, 2], + [1, 1, 0], + [1, 1, 1], + [1, 1, 2], + [1, 1, 3], + [1, 1, 4], + [1, 2, 1], + [2, 1, 2], + [2, 2, 0], + [2, 2, 2], + [2, 2, 5], + [2, 2, 6], + [2, 3, 2], + [3, 1, 3], + [3, 2, 7], + [3, 3, 1], + [3, 3, 8], + [3, 3, 9], + [3, 4, 3], + [3, 5, 3], + [4, 1, 4], + [4, 1, 5], + [4, 3, 10], + [4, 4, 1], + [4, 4, 11], + [4, 4, 12], + [4, 6, 4], + [5, 2, 6], + [5, 5, 1], + [5, 5, 13], + [5, 5, 14], + [5, 5, 15], + [5, 7, 4], + [5, 7, 5], + [6, 2, 6], + [6, 6, 1], + [6, 6, 16], + [6, 6, 17], + [6, 8, 5], + [6, 9, 6], + [7, 2, 7], + [7, 2, 8], + [7, 6, 1], + [7, 6, 18], + [7, 7, 2], + [7, 7, 19], + [7, 7, 20], + [7, 10, 6], + [7, 11, 7], + [8, 3, 9], + [8, 7, 21], + [8, 8, 2], + [8, 8, 22], + [8, 8, 23], + [8, 11, 8], + [8, 12, 8], + [9, 3, 10], + [9, 8, 24], + [9, 9, 2], + [9, 9, 25], + [9, 9, 26], + [9, 13, 9], + [10, 3, 10], + [10, 3, 11], + [10, 9, 27], + [10, 10, 2], + [10, 10, 28], + [10, 14, 9], + [10, 15, 10], + [11, 4, 12], + [11, 10, 29], + [11, 10, 30], + [11, 11, 2], + [11, 11, 31], + [11, 16, 10], + [11, 16, 11], + [12, 4, 13], + [12, 11, 32], + [12, 11, 33], + [12, 12, 3], + [12, 12, 34], + [12, 17, 11], + [12, 18, 12], + [13, 4, 14], + [13, 12, 35], + [13, 13, 3], + [13, 13, 36], + [13, 13, 37], + [13, 19, 12], + [14, 5, 15], + [14, 13, 38], + [14, 14, 3], + [14, 14, 39], + [14, 20, 13], + [14, 21, 13], + [15, 5, 16], + [15, 14, 40], + [15, 14, 41], + [15, 15, 3], + [15, 15, 42], + [15, 21, 14], + [15, 22, 15], + [16, 5, 17], + [16, 5, 18], + [16, 15, 43], + [16, 15, 44], + [16, 16, 3], + [16, 16, 45], + [16, 23, 15], + [16, 24, 16], + [17, 6, 18], + [17, 16, 46], + [17, 16, 47], + [17, 17, 4], + [17, 17, 48], + [17, 25, 16], + [18, 6, 19], + [18, 17, 49], + [18, 17, 50], + [18, 18, 4], + [18, 25, 17], + [18, 26, 17], + [19, 6, 20], + [19, 6, 21], + [19, 18, 4], + [19, 18, 51], + [19, 18, 52], + [19, 18, 53], + [19, 27, 18], + [19, 28, 18], + [20, 7, 22], + [20, 19, 4], + [20, 19, 54], + [20, 19, 55], + [20, 19, 56], + [20, 20, 4], + [20, 29, 19], + [20, 30, 19], + [21, 7, 22], + [21, 20, 57], + [21, 20, 58], + [21, 21, 4], + [21, 21, 59], + [21, 30, 20], + [22, 7, 23], + [22, 7, 24], + [22, 21, 60], + [22, 21, 61], + [22, 22, 5], + [22, 31, 20], + [22, 32, 21], + [23, 8, 25], + [23, 22, 62], + [23, 22, 63], + [23, 22, 64], + [23, 23, 5], + [23, 33, 22], + [23, 34, 22], + [24, 8, 26], + [24, 23, 64], + [24, 23, 65], + [24, 23, 66], + [24, 24, 5], + [24, 34, 23], + [24, 35, 23], + [25, 8, 27], + [25, 24, 67], + [25, 24, 68], + [25, 24, 69], + [25, 25, 5], + [25, 36, 24], + [25, 37, 24], + [26, 8, 28], + [26, 25, 70], + [26, 25, 71], + [26, 26, 5], + [26, 38, 25], + [27, 9, 29], + [27, 25, 72], + [27, 26, 73], + [27, 26, 74], + [27, 27, 6], + [27, 39, 25], + [27, 39, 26], + [28, 9, 30], + [28, 26, 75], + [28, 27, 76], + [28, 27, 77], + [28, 28, 6], + [28, 40, 26], + [28, 41, 27], + [29, 9, 31], + [29, 9, 32], + [29, 27, 78], + [29, 28, 79], + [29, 28, 80], + [29, 29, 6], + [29, 42, 27], + [29, 43, 28], + [30, 10, 32], + [30, 10, 33], + [30, 29, 81], + [30, 29, 82], + [30, 30, 6], + [30, 43, 29], + [31, 10, 33], + [31, 29, 83], + [31, 30, 6], + [31, 30, 84], + [31, 30, 85], + [31, 44, 29], + [31, 45, 30], + [32, 10, 34], + [32, 30, 86], + [32, 31, 7], + [32, 31, 87], + [32, 31, 88], + [32, 46, 30], + [32, 47, 31], + [33, 11, 35], + [33, 11, 36], + [33, 31, 89], + [33, 32, 7], + [33, 32, 90], + [33, 32, 91], + [33, 33, 7], + [33, 48, 31], + [33, 48, 32], + [34, 11, 37], + [34, 32, 92], + [34, 33, 93], + [34, 34, 7], + [34, 49, 32], + [35, 11, 37], + [35, 33, 94], + [35, 33, 95], + [35, 34, 96], + [35, 35, 7], + [35, 50, 33], + [35, 51, 33], + [36, 12, 38], + [36, 12, 39], + [36, 34, 97], + [36, 34, 98], + [36, 35, 99], + [36, 36, 8], + [36, 52, 34], + [36, 53, 35], + [37, 12, 40], + [37, 35, 100], + [37, 35, 101], + [37, 36, 102], + [37, 37, 8], + [37, 53, 35], + [37, 54, 36], + [38, 12, 41], + [38, 36, 103], + [38, 37, 104], + [38, 38, 8], + [38, 55, 36], + [39, 13, 41], + [39, 13, 42], + [39, 37, 105], + [39, 37, 106], + [39, 38, 107], + [39, 39, 8], + [39, 56, 37], + [39, 57, 37], + [40, 13, 43], + [40, 38, 108], + [40, 38, 109], + [40, 39, 110], + [40, 40, 8], + [40, 57, 38], + [40, 58, 38], + [41, 13, 44], + [41, 39, 111], + [41, 39, 112], + [41, 40, 113], + [41, 41, 9], + [41, 59, 39], + [41, 60, 39], + [42, 14, 45], + [42, 40, 114], + [42, 40, 115], + [42, 41, 9], + [42, 61, 40], + [42, 62, 40], + [43, 14, 46], + [43, 41, 116], + [43, 41, 117], + [43, 41, 118], + [43, 42, 9], + [43, 62, 41], + [44, 14, 47], + [44, 42, 119], + [44, 42, 120], + [44, 42, 121], + [44, 43, 9], + [44, 63, 42], + [44, 64, 42], + [45, 15, 48], + [45, 15, 49], + [45, 43, 122], + [45, 43, 123], + [45, 43, 124], + [45, 44, 9], + [45, 65, 43], + [45, 66, 43], + [46, 15, 49], + [46, 44, 125], + [46, 44, 126], + [46, 45, 10], + [46, 46, 10], + [46, 66, 44], + [46, 67, 44], + [47, 15, 50], + [47, 45, 128], + [47, 45, 129], + [47, 47, 10], + [47, 68, 45], + [48, 16, 51], + [48, 16, 52], + [48, 46, 130], + [48, 46, 131], + [48, 46, 132], + [48, 48, 10], + [48, 69, 45], + [48, 70, 46], + [49, 16, 53], + [49, 47, 133], + [49, 47, 134], + [49, 47, 135], + [49, 49, 10], + [49, 71, 46], + [49, 71, 47], + [50, 16, 53], + [50, 16, 54], + [50, 48, 136], + [50, 48, 137], + [50, 48, 138], + [50, 50, 11], + [50, 72, 47], + [50, 73, 48], + [51, 17, 55], + [51, 49, 139], + [51, 49, 140], + [51, 51, 11], + [51, 74, 49], + [52, 17, 56], + [52, 49, 141], + [52, 50, 142], + [52, 50, 143], + [52, 52, 11], + [52, 75, 49], + [52, 75, 50], + [53, 17, 57], + [53, 50, 144], + [53, 51, 145], + [53, 51, 146], + [53, 53, 11], + [53, 76, 50], + [53, 77, 50], + [53, 77, 51], + [54, 18, 58], + [54, 51, 147], + [54, 52, 148], + [54, 52, 149], + [54, 53, 11], + [54, 78, 51], + [54, 79, 52], + [55, 18, 59], + [55, 52, 150], + [55, 53, 151], + [55, 54, 12], + [55, 80, 52], + [56, 18, 60], + [56, 18, 61], + [56, 53, 152], + [56, 54, 153], + [56, 54, 154], + [56, 55, 12], + [56, 80, 53], + [56, 81, 53], + [57, 19, 61], + [57, 54, 155], + [57, 55, 156], + [57, 55, 157], + [57, 56, 12], + [57, 82, 54], + [57, 83, 54], + [58, 19, 62], + [58, 55, 158], + [58, 56, 159], + [58, 56, 160], + [58, 57, 12], + [58, 84, 55], + [58, 84, 56], + [59, 19, 63], + [59, 19, 64], + [59, 56, 161], + [59, 57, 162], + [59, 58, 12], + [59, 85, 56], + [59, 86, 57], + [60, 20, 65], + [60, 57, 163], + [60, 57, 164], + [60, 58, 165], + [60, 59, 13], + [60, 60, 13], + [60, 87, 57], + [61, 20, 65], + [61, 58, 166], + [61, 58, 167], + [61, 59, 168], + [61, 61, 13], + [61, 88, 58], + [61, 89, 58], + [62, 20, 66], + [62, 20, 67], + [62, 59, 169], + [62, 59, 170], + [62, 60, 171], + [62, 62, 13], + [62, 89, 58], + [62, 89, 59], + [62, 90, 59], + [63, 21, 68], + [63, 60, 172], + [63, 60, 173], + [63, 63, 13], + [63, 91, 60], + [63, 92, 60], + [64, 21, 69], + [64, 61, 174], + [64, 61, 175], + [64, 62, 176], + [64, 64, 13], + [64, 93, 61], + [65, 21, 69], + [65, 21, 70], + [65, 62, 177], + [65, 62, 178], + [65, 63, 179], + [65, 65, 14], + [65, 94, 61], + [65, 94, 62], + [66, 22, 71], + [66, 63, 180], + [66, 63, 181], + [66, 64, 182], + [66, 65, 14], + [66, 95, 63], + [66, 96, 63], + [67, 22, 71], + [67, 22, 72], + [67, 64, 183], + [67, 64, 184], + [67, 66, 14], + [67, 97, 64], + [67, 98, 64], + [68, 22, 73], + [68, 65, 185], + [68, 65, 186], + [68, 65, 187], + [68, 67, 14], + [68, 98, 65], + [69, 23, 74], + [69, 66, 188], + [69, 66, 189], + [69, 66, 190], + [69, 68, 14], + [69, 99, 65], + [69, 100, 66], + [70, 23, 75], + [70, 67, 191], + [70, 67, 192], + [70, 69, 15], + [70, 101, 66], + [70, 102, 67], + [71, 23, 76], + [71, 23, 77], + [71, 68, 193], + [71, 68, 194], + [71, 70, 15], + [71, 103, 67], + [71, 103, 68], + [72, 23, 77], + [72, 68, 195], + [72, 69, 196], + [72, 69, 197], + [72, 71, 15], + [72, 104, 68], + [73, 24, 78], + [73, 24, 79], + [73, 70, 198], + [73, 70, 199], + [73, 70, 200], + [73, 72, 15], + [73, 73, 15], + [73, 106, 70], + [74, 24, 80], + [74, 71, 201], + [74, 71, 202], + [74, 71, 203], + [74, 74, 16], + [74, 107, 70], + [74, 107, 71], + [75, 24, 80], + [75, 72, 204], + [75, 72, 205], + [75, 75, 16], + [75, 108, 71], + [75, 109, 72], + [76, 25, 81], + [76, 25, 82], + [76, 72, 206], + [76, 73, 207], + [76, 73, 208], + [76, 76, 16], + [76, 110, 72], + [76, 111, 73], + [77, 25, 83], + [77, 73, 209], + [77, 74, 210], + [77, 74, 211], + [77, 77, 16], + [77, 112, 73], + [78, 25, 84], + [78, 74, 212], + [78, 75, 213], + [78, 75, 214], + [78, 77, 16], + [78, 112, 74], + [78, 113, 74], + [79, 26, 84], + [79, 26, 85], + [79, 75, 215], + [79, 76, 216], + [79, 78, 17], + [79, 114, 75], + [79, 115, 75], + [80, 26, 86], + [80, 76, 217], + [80, 76, 218], + [80, 77, 219], + [80, 79, 17], + [80, 116, 76], + [80, 116, 77], + [81, 26, 87], + [81, 77, 220], + [81, 78, 221], + [81, 78, 222], + [81, 80, 17], + [81, 117, 77], + [82, 27, 88], + [82, 78, 223], + [82, 79, 224], + [82, 79, 225], + [82, 81, 17], + [82, 118, 78], + [82, 119, 78], + [83, 27, 89], + [83, 79, 226], + [83, 80, 227], + [83, 82, 17], + [83, 120, 79], + [83, 121, 79], + [84, 27, 90], + [84, 80, 228], + [84, 80, 229], + [84, 81, 230], + [84, 83, 18], + [84, 121, 80], + [84, 122, 80], + [85, 28, 91], + [85, 28, 92], + [85, 81, 231], + [85, 81, 232], + [85, 82, 233], + [85, 84, 18], + [85, 123, 81], + [86, 28, 92], + [86, 82, 234], + [86, 82, 235], + [86, 83, 236], + [86, 85, 18], + [86, 86, 18], + [86, 124, 81], + [86, 125, 82], + [87, 28, 93], + [87, 29, 93], + [87, 83, 236], + [87, 83, 237], + [87, 83, 238], + [87, 84, 238], + [87, 84, 239], + [87, 87, 18], + [87, 126, 82], + [87, 126, 83], + [88, 29, 94], + [88, 29, 95], + [88, 84, 239], + [88, 84, 240], + [88, 84, 241], + [88, 85, 241], + [88, 85, 242], + [88, 88, 19], + [88, 127, 84], + [88, 128, 84], + [89, 29, 96], + [89, 85, 242], + [89, 85, 243], + [89, 85, 244], + [89, 86, 244], + [89, 89, 19], + [89, 129, 85], + [89, 130, 85], + [90, 29, 96], + [90, 86, 244], + [90, 86, 245], + [90, 86, 246], + [90, 86, 247], + [90, 87, 247], + [90, 89, 19], + [90, 130, 86], + [91, 30, 97], + [91, 30, 98], + [91, 87, 247], + [91, 87, 248], + [91, 87, 249], + [91, 90, 19], + [91, 131, 86], + [91, 132, 87], + [92, 30, 99], + [92, 88, 250], + [92, 88, 251], + [92, 88, 252], + [92, 91, 19], + [92, 133, 87], + [92, 134, 88], + [93, 30, 100], + [93, 89, 253], + [93, 92, 20], + [93, 135, 88], + [93, 135, 89], + [94, 31, 100], + [94, 31, 101], + [94, 93, 20], + [94, 136, 89], + [95, 94, 20], + [95, 137, 90], + [95, 138, 91], + [96, 31, 103], + [96, 31, 104], + [96, 95, 20], + [96, 139, 91], + [96, 139, 92], + [97, 32, 104], + [97, 96, 20], + [97, 140, 92], + [97, 141, 93], + [98, 32, 105], + [98, 97, 21], + [98, 142, 93], + [99, 32, 106], + [99, 32, 107], + [99, 98, 21], + [99, 99, 21], + [99, 143, 94], + [99, 144, 94], + [100, 33, 108], + [100, 100, 21], + [100, 144, 95], + [100, 145, 95], + [101, 33, 108], + [101, 100, 21], + [101, 146, 96], + [101, 147, 96], + [102, 33, 109], + [102, 33, 110], + [102, 101, 21], + [102, 148, 97], + [103, 34, 111], + [103, 102, 22], + [103, 148, 98], + [103, 149, 98], + [104, 34, 112], + [104, 103, 22], + [104, 150, 99], + [104, 151, 99], + [105, 34, 112], + [105, 34, 113], + [105, 104, 22], + [105, 152, 100], + [105, 153, 100], + [106, 35, 114], + [106, 105, 22], + [106, 153, 101], + [106, 154, 101], + [107, 35, 115], + [107, 106, 22], + [107, 155, 102], + [108, 35, 116], + [108, 107, 23], + [108, 156, 102], + [108, 157, 103], + [109, 36, 117], + [109, 108, 23], + [109, 158, 104], + [110, 36, 118], + [110, 109, 23], + [110, 159, 105], + [110, 160, 105], + [111, 36, 119], + [111, 36, 120], + [111, 110, 23], + [111, 161, 106], + [112, 37, 120], + [112, 111, 23], + [112, 112, 24], + [112, 162, 106], + [112, 162, 107], + [113, 37, 121], + [113, 112, 24], + [113, 163, 107], + [113, 164, 108], + [114, 37, 122], + [114, 37, 123], + [114, 113, 24], + [114, 165, 108], + [114, 166, 109], + [115, 38, 124], + [115, 114, 24], + [115, 167, 109], + [116, 38, 124], + [116, 115, 24], + [116, 167, 110], + [116, 168, 111], + [117, 38, 125], + [117, 38, 126], + [117, 116, 25], + [117, 169, 111], + [117, 170, 112], + [118, 39, 127], + [118, 117, 25], + [118, 171, 112], + [118, 171, 113], + [119, 39, 128], + [119, 172, 113], + [120, 39, 129], + [120, 40, 130], + [120, 119, 25], + [120, 173, 114], + [120, 174, 114], + [121, 39, 130], + [121, 120, 25], + [121, 175, 115], + [121, 176, 115], + [122, 40, 131], + [122, 121, 26], + [122, 176, 116], + [122, 177, 116], + [123, 40, 132], + [123, 122, 26], + [123, 178, 117], + [123, 179, 118], + [124, 40, 133], + [124, 40, 134], + [124, 123, 26], + [124, 180, 118], + [125, 41, 134], + [125, 41, 135], + [125, 124, 26], + [125, 180, 119], + [125, 181, 119], + [126, 41, 135], + [126, 124, 26], + [126, 125, 27], + [126, 182, 120], + [126, 183, 120], + [127, 41, 136], + [127, 126, 27], + [127, 184, 121], + [127, 185, 121], + [128, 42, 137], + [128, 42, 138], + [128, 127, 27], + [128, 185, 121], + [128, 185, 122], + [128, 186, 122], + [129, 42, 139], + [129, 128, 27], + [129, 186, 122], + [129, 187, 123], + [130, 42, 139], + [130, 129, 27], + [130, 188, 123], + [130, 188, 124], + [130, 189, 124], + [131, 43, 140], + [131, 43, 141], + [131, 130, 28], + [131, 189, 125], + [131, 190, 125], + [132, 43, 142], + [132, 131, 28], + [132, 190, 125], + [132, 191, 125], + [132, 191, 126], + [133, 43, 143], + [133, 132, 28], + [133, 192, 126], + [133, 193, 127], + [134, 44, 143], + [134, 44, 144], + [134, 133, 28], + [134, 194, 127], + [134, 194, 128], + [134, 195, 128], + [135, 44, 145], + [135, 134, 28], + [135, 195, 128], + [135, 196, 129], + [136, 44, 146], + [136, 135, 29], + [136, 196, 129], + [136, 197, 129], + [136, 197, 130], + [137, 44, 147], + [137, 45, 147], + [137, 136, 29], + [137, 198, 130], + [137, 199, 130], + [137, 199, 131], + [138, 45, 148], + [138, 136, 29], + [138, 199, 131], + [138, 200, 131], + [138, 200, 132], + [138, 201, 132], + [139, 45, 149], + [139, 137, 29], + [139, 138, 29], + [139, 201, 132], + [139, 202, 133], + [140, 46, 150], + [140, 46, 151], + [140, 139, 29], + [140, 202, 133], + [140, 203, 133], + [140, 203, 134], + [141, 46, 151], + [141, 140, 30], + [141, 203, 134], + [141, 204, 134], + [141, 205, 134], + [142, 46, 152], + [142, 141, 30], + [142, 205, 135], + [142, 206, 135], + [142, 206, 136], + [143, 47, 153], + [143, 47, 154], + [143, 142, 30], + [143, 207, 136], + [143, 208, 136], + [143, 208, 137], + [144, 47, 155], + [144, 143, 30], + [144, 208, 137], + [144, 209, 137], + [144, 209, 138], + [145, 47, 155], + [145, 47, 156], + [145, 144, 30], + [145, 209, 138], + [146, 48, 156], + [146, 48, 157], + [146, 145, 31], + [147, 48, 158], + [147, 146, 31], + [148, 48, 158], + [148, 48, 159], + [148, 147, 31], + [149, 49, 160], + [149, 148, 31], + [150, 49, 161], + [150, 148, 31], + [151, 49, 161], + [151, 49, 162], + [151, 49, 163], + [151, 149, 32], + [152, 50, 163], + [152, 150, 32], + [152, 151, 32], + [153, 50, 164], + [153, 152, 32], + [154, 50, 165], + [154, 50, 166], + [154, 153, 32], + [155, 51, 167], + [155, 154, 33], + [156, 51, 167], + [156, 155, 33], + [157, 51, 168], + [157, 51, 169], + [157, 156, 33], + [158, 51, 169], + [158, 52, 170], + [158, 157, 33], + [159, 52, 171], + [159, 158, 33], + [160, 52, 171], + [160, 52, 172], + [160, 159, 34], + [161, 53, 173], + [161, 159, 34], + [162, 53, 174], + [162, 160, 34], + [163, 53, 175], + [163, 53, 176], + [163, 161, 34], + [164, 54, 176], + [164, 162, 34], + [165, 54, 177], + [165, 163, 35], + [165, 164, 35], + [166, 54, 178], + [166, 54, 179], + [166, 165, 35], + [167, 54, 179], + [167, 54, 180], + [167, 55, 180], + [167, 166, 35], + [168, 55, 180], + [168, 55, 181], + [168, 167, 35], + [169, 55, 181], + [169, 55, 182], + [169, 168, 36], + [170, 55, 182], + [170, 55, 183], + [170, 56, 183], + [170, 169, 36], + [171, 56, 183], + [171, 56, 184], + [171, 170, 36], + [172, 56, 184], + [172, 56, 185], + [172, 171, 36], + [173, 56, 186], + [173, 57, 186], + [173, 171, 36], + [174, 57, 186], + [174, 57, 187], + [174, 172, 37], + [175, 57, 187], + [175, 57, 188], + [175, 173, 37], + [176, 57, 189], + [176, 174, 37], + [177, 58, 190], + [177, 58, 191], + [177, 175, 37], + [178, 58, 191], + [178, 58, 192], + [178, 176, 37], + [179, 58, 192], + [179, 177, 38], + [179, 178, 38], + [180, 59, 193], + [180, 59, 194], + [180, 179, 38], + [181, 59, 194], + [181, 59, 195], + [181, 180, 38], + [182, 59, 195], + [182, 59, 196], + [182, 60, 196], + [182, 181, 38], + [183, 60, 196], + [183, 60, 197], + [183, 182, 38], + [184, 60, 197], + [184, 60, 198], + [184, 183, 39], + [185, 60, 198], + [185, 60, 199], + [185, 183, 39], + [186, 61, 199], + [186, 61, 200], + [186, 184, 39], + [187, 61, 200], + [187, 61, 201], + [187, 185, 39], + [188, 61, 202], + [188, 186, 39], + [189, 62, 202], + [189, 62, 203], + [189, 187, 40], + [190, 62, 203], + [190, 188, 40], + [191, 189, 40], + [192, 190, 40], + [192, 191, 40], + [193, 192, 41], + [194, 193, 41], + [195, 194, 41], + [196, 195, 41], + [197, 195, 41], + [198, 196, 42], + [199, 197, 42], + [200, 198, 42], + [201, 199, 42], + [202, 200, 42], + [203, 201, 43], + [204, 202, 43], + [205, 203, 43], + [205, 204, 43], + [206, 205, 43], + [207, 206, 44], + [208, 207, 44], + [209, 207, 44], + [209, 208, 44], + [210, 208, 44], + [211, 209, 44], + [212, 210, 45], + [213, 211, 45], + [214, 212, 45], + [215, 213, 45], + [216, 214, 45], + [217, 215, 46], + [218, 216, 46], + [218, 217, 46], + [219, 217, 46], + [219, 218, 46], + [220, 218, 46], + [220, 219, 46], + [221, 219, 46], + [221, 220, 46], + [221, 220, 47], + [222, 220, 47], + [223, 221, 47], + [223, 222, 47], + [224, 222, 47], + [224, 223, 47], + [225, 223, 47], + [226, 224, 47], + [226, 224, 48], + [227, 225, 48], + [228, 226, 48], + [229, 227, 48], + [230, 228, 48], + [231, 229, 48], + [231, 229, 49], + [231, 230, 49], + [232, 230, 49], + [232, 231, 49], + [233, 231, 49], + [233, 232, 49], + [234, 232, 49], + [234, 233, 49], + [235, 233, 49], + [236, 234, 50], + [237, 235, 50], +] + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.download( + url="http://ftp.itec.aau.at/datasets//GLENDA/downloads//Glenda_v1.5_classes.zip", + file_name="Glenda_v1.5_classes.zip", + data_kind=DataKind.TRAINING_DATA, + ) + dset_path = dset_creator.unpack_and_store() + masks = list((dset_path / DataKind.TRAINING_DATA / "Glenda_v1.5_classes" / "annots").rglob("*.png")) + keys = list(class_mapping.keys()) + dset_creator.transform_masks( + masks=masks, + load="rgb", + transform={pix_val: idx for idx, pix_val in enumerate(keys)}, + train=True, + ignore=[tuple(vals) for vals in wrongs], + ) + return dset_path + + +@register_taskcreator(task_name="glenda_endometriosis_segmentation", dset_name=dset_name) +def create_task_glenda(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name="glenda_endometriosis_segmentation", + task_type=TaskType.SEMANTIC_SEGMENTATION, + desc="The dataset includes region-based annotations of 4 pathological endometriosis categories" + " as well as non pathological counter example images", + ref=REFERENCE, + url="http://ftp.itec.aau.at/datasets//GLENDA", + instr="download data Glenda_v1.5_classes and GLENDA_v1.5_no_pathology via website", + lic=License.CC_BY_NC_4_0, + release="2020", + keywords=[Keyword.LAPAROSCOPY, Keyword.MEDICAL, Keyword.GYNECOLOGY], + ) + data_iterator = [] + for img_id in [ + p.stem + for p in (dset_path / DataKind.TRAINING_DATA / "Glenda_v1.5_classes" / "frames").iterdir() + if p.is_file() and p.suffix == ".jpg" + ]: + data_iterator.append( + { + Modality.SAMPLE_ID: img_id, + Modality.IMAGE: dset_path / DataKind.TRAINING_DATA / "Glenda_v1.5_classes" / "frames" / f"{img_id}.jpg", + Modality.MASK: ( + dset_path + / DataKind.TRAINING_LABELS + / "transformed_masks" + / "Glenda_v1.5_classes" + / "annots" + / f"{img_id}.png" + ), + } + ) + task.find_data( + train_iterator=data_iterator, idx_to_class={ix: cls for ix, cls in enumerate(class_mapping.values())} + ) + task.split_folds(n_folds=5) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/segmentation/hyper_kvasir.py b/plugins/data/src/mml_data/creators/segmentation/hyper_kvasir.py new file mode 100644 index 0000000..9d4d1d9 --- /dev/null +++ b/plugins/data/src/mml_data/creators/segmentation/hyper_kvasir.py @@ -0,0 +1,71 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_from_segmentation_dataset + +REFERENCE = """ +@misc{borgli2020, +title = {Hyper-Kvasir: A Comprehensive Multi-Class Image and Video Dataset for Gastrointestinal Endoscopy}, +url = {osf.io/mkzcq}, +DOI = {10.31219/osf.io/mkzcq}, +publisher = {OSF Preprints}, +author = {Borgli, Hanna and Thambawita, Vajira and Smedsrud, Pia H and Hicks, Steven and Jha, Debesh and Eskeland, + Sigrun L and Randel, Kristin R and Pogorelov, Konstantin and Lux, Mathias and Nguyen, Duc T D and Johansen, + Dag and Griwodz, Carsten and Stensland, H{\aa}kon K and Garcia-Ceja, Enrique and Schmidt, Peter T and Hammer, + Hugo L and Riegler, Michael A and Halvorsen, P{\aa}l and de Lange, Thomas}, +year = {2019}, +month = {Dec}} +""" # noqa W291 + + +@register_dsetcreator(dset_name="hyperkvasir_seg") +def create_hyperkvasir_labeled(): + dset_creator = DSetCreator(dset_name="hyperkvasir_seg") + dset_creator.download( + url="https://datasets.simula.no/hyper-kvasir/hyper-kvasir-segmented-images.zip", + file_name="hyper-kvasir-segmented-images.zip", + data_kind=DataKind.TRAINING_DATA, + ) + dset_path = dset_creator.unpack_and_store() + masks = list((dset_path / DataKind.TRAINING_DATA / "segmented-images" / "masks").iterdir()) + blacks = [246, 247, 248, 249, 250, 251, 252, 253, 254, 255] + whites = [0, 1, 2, 3, 4, 5, 6, 7, 8] + transform = {(pix_val,): 0 for pix_val in blacks} + transform.update({(pix_val,): 1 for pix_val in whites}) + dset_creator.transform_masks(masks=masks, load="grayscale", train=True, transform=transform) + return dset_path + + +@register_taskcreator(task_name="hyperkvasir_polyp_segmentation", dset_name="hyperkvasir_seg") +def create_task(dset_path: Path) -> None: + creator = TaskCreator( + dset_path=dset_path, + name="hyperkvasir_polyp_segmentation", + task_type=TaskType.SEMANTIC_SEGMENTATION, + desc="Hyper-Kvasir Dataset is a large image and video dataset from the gastrointestinal " "tract", + ref=REFERENCE, + url="https://datasets.simula.no/hyper-kvasir/", + instr="download zips of segmented images via website", + lic=License.CC_BY_4_0, + release="2020", + keywords=[Keyword.MEDICAL, Keyword.GASTROSCOPY_COLONOSCOPY, Keyword.TISSUE_PATHOLOGY], + ) + train_iterator = get_iterator_from_segmentation_dataset( + images_root=dset_path / DataKind.TRAINING_DATA / "segmented-images" / "images", + masks_root=dset_path / DataKind.TRAINING_LABELS / "transformed_masks" / "segmented-images" / "masks", + path_matcher=lambda x: x.with_suffix(".png"), + ) + creator.find_data(train_iterator=train_iterator, idx_to_class={0: "background", 1: "polyp"}) + creator.split_folds(n_folds=5) + creator.infer_stats() + creator.push_and_test() diff --git a/plugins/data/src/mml_data/creators/segmentation/image2image.py b/plugins/data/src/mml_data/creators/segmentation/image2image.py new file mode 100644 index 0000000..863b4e6 --- /dev/null +++ b/plugins/data/src/mml_data/creators/segmentation/image2image.py @@ -0,0 +1,193 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# creates the image2image dataset and tasks +# TODO -> image2image requires 7zip extraction which we have not yet find a MIT compatible way of auto-extraction, +# hence this is not supported currently +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """ +@misc{pfeiffer2019generating, + title={Generating large labeled data sets for laparoscopic image processing tasks using unpaired image-to-image translation}, + author={Micha Pfeiffer and Isabel Funke and Maria R. Robu and Sebastian Bodenstedt and Leon Strenger and Sandy Engelhardt and Tobias Roß and Matthew J. Clarkson and Kurinchi Gurusamy and Brian R. Davidson and Lena Maier-Hein and Carina Riediger and Thilo Welsch and Jürgen Weitz and Stefanie Speidel}, + year={2019}, + eprint={1907.02882}, + archivePrefix={arXiv}, + primaryClass={cs.LG} +} +""" # noqa W291 + + +def get_idx_to_class(): + # from https://gitlab.com/nct_tso_public/laparoscopic-image-2-image-translation/-/blob/master/data.py + # but these are incorrect, after loading the labels appear to be 26, 77, 102, 128, 153, 179 + # idx_to_class = {0: 'Background', + # 89: 'Liver', + # 170: 'Fat', + # 149: 'Diaphragm', + # 188: 'Ligament', + # 218: 'Tool Shaft', + # 203: 'Tool Tip', + # 124: 'Gallbladder'} + idx_to_class = { + 26: "Background?", + 51: "Liver?", + 77: "Fat?", + 102: "Abdominal Wall?", + 128: "Tool Shaft?", + 153: "Tool Tip?", + 179: "Gallbladder?", + } + return idx_to_class + + +@register_dsetcreator(dset_name="image2image") +def create_image2image(): + raise RuntimeError( + "image2image dataset requires 7zip extraction which we have not yet find a MIT compatible way " + "of auto-extraction, hence this is not supported currently" + ) + dset_creator = DSetCreator(dset_name="image2image") + dset_creator.download( + url="http://opencas.dkfz.de/image2image/data/inputs.7z", file_name="inputs.7z", data_kind=DataKind.TRAINING_DATA + ) + dset_creator.download( + url="http://opencas.dkfz.de/image2image/data/stylernd.7z", + file_name="stylernd.7z", + data_kind=DataKind.TRAINING_DATA, + ) + dset_creator.download( + url="http://opencas.dkfz.de/image2image/data/styleFromCholec80.7z", + file_name="styleFromCholec80.7z", + data_kind=DataKind.TRAINING_DATA, + ) + dset_creator.download( + url="http://opencas.dkfz.de/image2image/data/labels.7z", + data_kind=DataKind.TRAINING_LABELS, + file_name="labels.7z", + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name="image2image-raw", dset_name="image2image") +def create_image2image_raw(dset_path: Path): + raw = TaskCreator( + dset_path=dset_path, + name="image2image-raw", + task_type=TaskType.SEMANTIC_SEGMENTATION, + desc="anatomical structures segmented from simulated laparoscopic images", + ref=REFERENCE, + url="http://opencas.dkfz.de/image2image/", + instr="download and via website", + lic=License.UNKNOWN, + release="2019", + keywords=[ + Keyword.LAPAROSCOPY, + Keyword.ANATOMICAL_STRUCTURES, + Keyword.ARTIFICIAL, + Keyword.MEDICAL, + Keyword.ENDOSCOPIC_INSTRUMENTS, + ], + ) + data_iterator = [] + img_root = dset_path / DataKind.TRAINING_DATA / "simulated" + mask_root = dset_path / DataKind.TRAINING_LABELS / "simulated" + for patient_id in [p.name for p in img_root.iterdir() if p.is_dir()]: + for img_id in [p.name for p in (img_root / patient_id / "inputs").iterdir() if p.is_file()]: + data_iterator.append( + { + Modality.SAMPLE_ID: f"{patient_id}_{img_id}", + Modality.IMAGE: img_root / patient_id / "inputs" / img_id, + Modality.MASK: mask_root / patient_id / "labels" / (img_id.replace("img", "lbl")), + } + ) + raw.find_data(train_iterator=data_iterator, idx_to_class=get_idx_to_class()) + raw.split_folds(n_folds=5, ensure_balancing=True) + raw.infer_stats() + raw.push_and_test() + + +@register_taskcreator(task_name="image2image-rand", dset_name="image2image") +def create_image2image_rand(dset_path: Path): + raw = TaskCreator( + dset_path=dset_path, + name="image2image-rand", + task_type=TaskType.SEMANTIC_SEGMENTATION, + desc="anatomical structures segmented from simulated laparoscopic images, used random styles", + ref=REFERENCE, + url="http://opencas.dkfz.de/image2image/", + instr="download and via website", + lic=License.UNKNOWN, + release="2019", + keywords=[ + Keyword.LAPAROSCOPY, + Keyword.ANATOMICAL_STRUCTURES, + Keyword.ARTIFICIAL, + Keyword.MEDICAL, + Keyword.ENDOSCOPIC_INSTRUMENTS, + ], + ) + data_iterator = [] + img_root = dset_path / DataKind.TRAINING_DATA / "stylernd" + mask_root = dset_path / DataKind.TRAINING_LABELS / "simulated" + for patient_id in [p.name for p in img_root.iterdir() if p.is_dir()]: + for img_id in [p.name for p in (img_root / patient_id / "style_00").iterdir() if p.is_file()]: + data_iterator.append( + { + Modality.SAMPLE_ID: f"{patient_id}_{img_id}", + Modality.IMAGE: img_root / patient_id / "style_00" / img_id, + Modality.MASK: mask_root / patient_id / "labels" / (img_id.replace("img", "lbl")), + } + ) + raw.find_data(train_iterator=data_iterator, idx_to_class=get_idx_to_class()) + raw.split_folds(n_folds=5, ensure_balancing=True) + raw.infer_stats() + raw.push_and_test() + + +@register_taskcreator(task_name="image2image-cholec80", dset_name="image2image") +def create_image2image_cholec80(dset_path: Path): + raw = TaskCreator( + dset_path=dset_path, + name="image2image-cholec80", + task_type=TaskType.SEMANTIC_SEGMENTATION, + desc="anatomical structures segmented from simulated laparoscopic images, used cholec80 styles", + ref=REFERENCE, + url="http://opencas.dkfz.de/image2image/", + instr="download and via website", + lic=License.UNKNOWN, + release="2019", + keywords=[ + Keyword.LAPAROSCOPY, + Keyword.ANATOMICAL_STRUCTURES, + Keyword.ARTIFICIAL, + Keyword.MEDICAL, + Keyword.ENDOSCOPIC_INSTRUMENTS, + ], + ) + data_iterator = [] + img_root = dset_path / DataKind.TRAINING_DATA / "styleFromCholec80" + mask_root = dset_path / DataKind.TRAINING_LABELS / "simulated" + for patient_id in [p.name for p in img_root.iterdir() if p.is_dir()]: + for img_id in [p.name for p in (img_root / patient_id / "style_00").iterdir() if p.is_file()]: + data_iterator.append( + { + Modality.SAMPLE_ID: f"{patient_id}_{img_id}", + Modality.IMAGE: img_root / patient_id / "style_00" / img_id, + Modality.MASK: mask_root / patient_id / "labels" / (img_id.replace("img", "lbl")), + } + ) + raw.find_data(train_iterator=data_iterator, idx_to_class=get_idx_to_class()) + raw.split_folds(n_folds=5, ensure_balancing=True) + raw.infer_stats() + raw.push_and_test() diff --git a/plugins/data/src/mml_data/creators/segmentation/motion_based_recognition.py b/plugins/data/src/mml_data/creators/segmentation/motion_based_recognition.py new file mode 100644 index 0000000..52f43e8 --- /dev/null +++ b/plugins/data/src/mml_data/creators/segmentation/motion_based_recognition.py @@ -0,0 +1,135 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# creates the "endocsopic instrument segmentation with crowdsourced data" dataset and tasks +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """ +@inproceedings{ BrostowSFC:ECCV08, + author = {Gabriel J. Brostow and Jamie Shotton and Julien Fauqueur and Roberto Cipolla}, + title = {Segmentation and Recognition Using Structure from Motion Point Clouds}, + booktitle = {ECCV (1)}, + year = {2008}, + pages = {44-57} +} + +@article{ BrostowFC:PRL2008, + author = "Gabriel J. Brostow and Julien Fauqueur and Roberto Cipolla", + title = "Semantic Object Classes in Video: A High-Definition Ground Truth Database", + journal = "Pattern Recognition Letters", + volume = "xx", + number = "x", + pages = "xx-xx", + year = "2008" +} +""" # noqa W291 + +dset_name = "motion-based-rec" +class_mapping = { + (0, 0, 0): "Void", # make sure background is first + (64, 128, 64): "Animal", + (192, 0, 128): "Archway", + (0, 128, 192): "Bicyclist", + (0, 128, 64): "Bridge", + (128, 0, 0): "Building", + (64, 0, 128): "Car", + (64, 0, 192): "CartLuggagePram", + (192, 128, 64): "Child", + (192, 192, 128): "Column_Pole", + (64, 64, 128): "Fence", + (128, 0, 192): "LaneMkgsDriv", + (192, 0, 64): "LaneMkgsNonDriv", + (128, 128, 64): "Misc_Text", + (192, 0, 192): "MotorcycleScooter", + (128, 64, 64): "OtherMoving", + (64, 192, 128): "ParkingBlock", + (64, 64, 0): "Pedestrian", + (128, 64, 128): "Road", + (128, 128, 192): "RoadShoulder", + (0, 0, 192): "Sidewalk", + (192, 128, 128): "SignSymbol", + (128, 128, 128): "Sky", + (64, 128, 192): "SUVPickupTruck", + (0, 0, 64): "TrafficCone", + (0, 64, 64): "TrafficLight", + (192, 64, 128): "Train", + (128, 128, 0): "Tree", + (192, 128, 192): "Truck_Bus", + (64, 0, 64): "Tunnel", + (192, 192, 0): "VegetationMisc", + (64, 192, 0): "Wall", +} + + +@register_dsetcreator(dset_name=dset_name) +def create_dset(): + dset_creator = DSetCreator(dset_name=dset_name) + dset_creator.download( + url="http://web4.cs.ucl.ac.uk/staff/g.brostow/MotionSegRecData/files/701_StillsRaw_full.zip", + file_name="701_StillsRaw_full.zip", + data_kind=DataKind.TRAINING_DATA, + ) + dset_creator.download( + url="http://web4.cs.ucl.ac.uk/staff/g.brostow/MotionSegRecData/data/LabeledApproved_full.zip", + file_name="LabeledApproved_full.zip", + data_kind=DataKind.TRAINING_LABELS, + ) + dset_path = dset_creator.unpack_and_store() + + masks = list((dset_path / DataKind.TRAINING_LABELS).rglob("*_L.png")) + masks.remove(dset_path / DataKind.TRAINING_LABELS / "Seq05VD_f02610_L.png") # this file contains invalid pixels + out_base = dset_creator.transform_masks( + masks=masks, + load="rgb", + transform={pix_val: idx for idx, pix_val in enumerate(class_mapping.keys())}, + train=True, + ) + assert out_base == dset_path / DataKind.TRAINING_LABELS / "transformed_masks", f"{out_base=}" + return dset_path + + +@register_taskcreator(task_name="motion-based-segmentation", dset_name=dset_name) +def create_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name="motion-based-segmentation", + task_type=TaskType.SEMANTIC_SEGMENTATION, + desc="segmenting 32 classes in driving scenes", + ref=REFERENCE, + url="http://web4.cs.ucl.ac.uk/staff/g.brostow/MotionSegRecData/", + instr="download zips of extracted images and painted class labels via website", + lic=License.UNKNOWN, + release="2008", + keywords=[Keyword.SCENES, Keyword.NATURAL_OBJECTS, Keyword.DRIVING], + ) + data_iterator = [] + for img_id in [ + p.stem + for p in (dset_path / DataKind.TRAINING_DATA / "701_StillsRaw_full").iterdir() + if p.is_file() and p.suffix == ".png" + ]: + if img_id == "Seq05VD_f02610": + # this is the invalid mask from above + continue + data_iterator.append( + { + Modality.SAMPLE_ID: img_id, + Modality.IMAGE: dset_path / DataKind.TRAINING_DATA / "701_StillsRaw_full" / f"{img_id}.png", + Modality.MASK: dset_path / DataKind.TRAINING_LABELS / "transformed_masks" / f"{img_id}_L.png", + } + ) + task.find_data( + train_iterator=data_iterator, idx_to_class={ix: cls for ix, cls in enumerate(class_mapping.values())} + ) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/segmentation/ph2.py b/plugins/data/src/mml_data/creators/segmentation/ph2.py new file mode 100644 index 0000000..e21f3cf --- /dev/null +++ b/plugins/data/src/mml_data/creators/segmentation/ph2.py @@ -0,0 +1,322 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator + +REFERENCE = """ +@inbook{inbook, +author = {Mendonça, Teresa and Ferreira, Pedro and Marçal, André and Barata, Catarina and Marques, Jorge and Rocha, Joana and Rozeira, Jorge}, +year = {2015}, +month = {09}, +pages = {419-439}, +title = {PH2: A Public Database for the Analysis of Dermoscopic Images}, +isbn = {978-1-4822-5326-9}, +doi = {10.1201/b19107-14} +} +} +""" + +dataset_name = "PH2" + + +def get_idx_to_class(): + idx_to_class = {0: "Background", 1: "Lesion"} + return idx_to_class + + +@register_dsetcreator(dset_name=dataset_name) +def create_dset(): + instructions = f""" + Download link is not available. Please download the dataset by clicking on the download button manually via + https://www.dropbox.com/s/k88qukc20ljnbuo/PH2Dataset.rar + Once the download is complete place the downloaded folder 'PH2Dataset.rar' in + /DOWNLOADS/{dataset_name} + """ + dset_creator = DSetCreator(dset_name=dataset_name) + dset_creator.verify_pre_download( + file_name="PH2Dataset.rar", data_kind=DataKind.TRAINING_DATA, instructions=instructions + ) + dset_path = dset_creator.unpack_and_store() + return dset_path + + +@register_taskcreator(task_name="ph2-melanocytic-lesions-segmentation", dset_name=dataset_name) +def create_seg_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name="ph2-melanocytic-lesions-segmentation", + task_type=TaskType.SEMANTIC_SEGMENTATION, + desc="This image database contains dermoscopic images of melanocytic lesions", + ref=REFERENCE, + url="https://www.fc.up.pt/addi/ph2%20database.html", + instr="download data PH2Dataset via website", + lic=License.UNKNOWN, + release="2015", + keywords=[Keyword.DERMATOSCOPY, Keyword.MEDICAL, Keyword.TISSUE_PATHOLOGY], + ) + data_iterator = [] + training_data_root = dset_path / DataKind.TRAINING_DATA / "PH2Dataset" / "PH2 Dataset images" + for image in training_data_root.iterdir(): + img_name = image.name + "_Dermoscopic_Image" + mask_name = image.name + "_lesion" + data_iterator.append( + { + Modality.SAMPLE_ID: image.name, + Modality.IMAGE: training_data_root / f"{image.name}" / f"{img_name}" / f"{image.name}.bmp", + Modality.MASK: training_data_root / f"{image.name}" / f"{mask_name}" / f"{mask_name}.bmp", + } + ) + task.find_data(train_iterator=data_iterator, idx_to_class=get_idx_to_class()) + task.split_folds(n_folds=5) + task.infer_stats() + task.push_and_test() + + +MELANOMA = [ + "IMD058", + "IMD061", + "IMD063", + "IMD064", + "IMD065", + "IMD080", + "IMD085", + "IMD088", + "IMD090", + "IMD091", + "IMD168", + "IMD211", + "IMD219", + "IMD240", + "IMD242", + "IMD284", + "IMD285", + "IMD348", + "IMD349", + "IMD403", + "IMD404", + "IMD405", + "IMD407", + "IMD408", + "IMD409", + "IMD410", + "IMD413", + "IMD417", + "IMD418", + "IMD419", + "IMD406", + "IMD411", + "IMD420", + "IMD421", + "IMD423", + "IMD424", + "IMD425", + "IMD426", + "IMD429", + "IMD435", +] +COMMON_NEVUS = [ + "IMD003", + "IMD009", + "IMD016", + "IMD022", + "IMD024", + "IMD025", + "IMD035", + "IMD038", + "IMD042", + "IMD044", + "IMD045", + "IMD050", + "IMD092", + "IMD101", + "IMD103", + "IMD112", + "IMD118", + "IMD125", + "IMD132", + "IMD134", + "IMD135", + "IMD144", + "IMD146", + "IMD147", + "IMD150", + "IMD152", + "IMD156", + "IMD159", + "IMD161", + "IMD162", + "IMD175", + "IMD177", + "IMD182", + "IMD198", + "IMD200", + "IMD010", + "IMD017", + "IMD020", + "IMD039", + "IMD041", + "IMD105", + "IMD107", + "IMD108", + "IMD133", + "IMD142", + "IMD143", + "IMD160", + "IMD173", + "IMD176", + "IMD196", + "IMD197", + "IMD199", + "IMD203", + "IMD204", + "IMD206", + "IMD207", + "IMD208", + "IMD364", + "IMD365", + "IMD367", + "IMD371", + "IMD372", + "IMD374", + "IMD375", + "IMD378", + "IMD379", + "IMD380", + "IMD381", + "IMD383", + "IMD384", + "IMD385", + "IMD389", + "IMD390", + "IMD392", + "IMD394", + "IMD395", + "IMD397", + "IMD399", + "IMD400", + "IMD402", +] +ATYPICAL_NEVUS = [ + "IMD002", + "IMD004", + "IMD013", + "IMD015", + "IMD019", + "IMD021", + "IMD027", + "IMD030", + "IMD032", + "IMD033", + "IMD037", + "IMD040", + "IMD043", + "IMD047", + "IMD048", + "IMD049", + "IMD057", + "IMD075", + "IMD076", + "IMD078", + "IMD120", + "IMD126", + "IMD137", + "IMD138", + "IMD139", + "IMD140", + "IMD149", + "IMD153", + "IMD157", + "IMD164", + "IMD166", + "IMD169", + "IMD171", + "IMD210", + "IMD347", + "IMD155", + "IMD376", + "IMD006", + "IMD008", + "IMD014", + "IMD018", + "IMD023", + "IMD031", + "IMD036", + "IMD154", + "IMD170", + "IMD226", + "IMD243", + "IMD251", + "IMD254", + "IMD256", + "IMD278", + "IMD279", + "IMD280", + "IMD304", + "IMD305", + "IMD306", + "IMD312", + "IMD328", + "IMD331", + "IMD339", + "IMD356", + "IMD360", + "IMD368", + "IMD369", + "IMD370", + "IMD382", + "IMD386", + "IMD388", + "IMD393", + "IMD396", + "IMD398", + "IMD427", + "IMD430", + "IMD431", + "IMD432", + "IMD433", + "IMD434", + "IMD436", + "IMD437", +] + + +@register_taskcreator(task_name="ph2-melanocytic-lesions-classification", dset_name=dataset_name) +def create_clas_task(dset_path: Path): + task = TaskCreator( + dset_path=dset_path, + name="ph2-melanocytic-lesions-classification", + task_type=TaskType.CLASSIFICATION, + desc="This image database contains dermoscopic images of melanocytic lesions", + ref=REFERENCE, + url="https://www.fc.up.pt/addi/ph2%20database.html", + instr="download data PH2Dataset via website", + lic=License.UNKNOWN, + release="2015", + keywords=[Keyword.DERMATOSCOPY, Keyword.MEDICAL, Keyword.TISSUE_PATHOLOGY], + ) + data_iterator = [] + training_data_root = dset_path / DataKind.TRAINING_DATA / "PH2Dataset" / "PH2 Dataset images" + idx_to_class = {0: "melanoma", 1: "common nevus", 2: "atypical nevus"} + for diagnosis, samples in zip([0, 1, 2], [MELANOMA, COMMON_NEVUS, ATYPICAL_NEVUS]): + for sample in samples: + img_folder = sample + "_Dermoscopic_Image" + data_iterator.append( + { + Modality.SAMPLE_ID: sample, + Modality.IMAGE: training_data_root / f"{sample}" / f"{img_folder}" / f"{sample}.bmp", + Modality.CLASS: diagnosis, + } + ) + task.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class) + task.split_folds(n_folds=5) + task.infer_stats() + task.push_and_test() diff --git a/plugins/data/src/mml_data/creators/segmentation/voc.py b/plugins/data/src/mml_data/creators/segmentation/voc.py new file mode 100644 index 0000000..66c6d20 --- /dev/null +++ b/plugins/data/src/mml_data/creators/segmentation/voc.py @@ -0,0 +1,142 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from torchvision.datasets import VOCSegmentation + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, TaskType +from mml.core.data_preparation.data_archive import DataKind +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import get_iterator_from_segmentation_dataset + +REFERENCE = """ +@misc{pascal-voc-2012, + author = "Everingham, M. and Van~Gool, L. and Williams, C. K. I. and Winn, J. and Zisserman, A.", + title = "The {PASCAL} {V}isual {O}bject {C}lasses {C}hallenge 2012 {(VOC2012)} {R}esults", + howpublished = "http://www.pascal-network.org/challenges/VOC/voc2012/workshop/index.html"} +""" + +VOC_CLASSES = [ + "background", + "aeroplane", + "bicycle", + "bird", + "boat", + "bottle", + "bus", + "car", + "cat", + "chair", + "cow", + "diningtable", + "dog", + "horse", + "motorbike", + "person", + "potted plant", + "sheep", + "sofa", + "train", + "tv/monitor", +] + +VOC_COLORMAP = [ + tuple(ix) + for ix in [ + [0, 0, 0], + [128, 0, 0], + [0, 128, 0], + [128, 128, 0], + [0, 0, 128], + [128, 0, 128], + [0, 128, 128], + [128, 128, 128], + [64, 0, 0], + [192, 0, 0], + [64, 128, 0], + [192, 128, 0], + [64, 0, 128], + [192, 0, 128], + [64, 128, 128], + [192, 128, 128], + [0, 64, 0], + [128, 64, 0], + [0, 192, 0], + [128, 192, 0], + [0, 64, 128], + ] +] + +dset_name = "VOC12" + + +@register_dsetcreator(dset_name=dset_name) +def create_voc12_dataset(): + dset_creator = DSetCreator(dset_name=dset_name) + train = VOCSegmentation(root=dset_creator.download_path, year="2012", image_set="train", download=True) + test = VOCSegmentation(root=dset_creator.download_path, year="2012", image_set="val", download=True) + dset_path = dset_creator.extract_from_pytorch_datasets( + datasets={"training": train, "testing": test}, task_type=TaskType.SEMANTIC_SEGMENTATION + ) + train_iterator = get_iterator_from_segmentation_dataset( + images_root=dset_path / DataKind.TRAINING_DATA, masks_root=dset_path / DataKind.TRAINING_LABELS + ) + test_iterator = get_iterator_from_segmentation_dataset( + images_root=dset_path / DataKind.TESTING_DATA, masks_root=dset_path / DataKind.TESTING_LABELS + ) + train_masks = [item[Modality.MASK] for item in train_iterator] + dset_creator.transform_masks( + masks=train_masks, + transform={pix_val: idx for idx, pix_val in enumerate(VOC_COLORMAP)}, + load="rgb", + train=True, + ignore=[(224, 224, 192)], + ) + test_masks = [item[Modality.MASK] for item in test_iterator] + dset_creator.transform_masks( + masks=test_masks, + transform={pix_val: idx for idx, pix_val in enumerate(VOC_COLORMAP)}, + load="rgb", + train=False, + ignore=[(224, 224, 192)], + ) + return dset_path + + +task_name = "pascal_voc_challenge_2012" + + +@register_taskcreator(task_name=task_name, dset_name=dset_name) +def create_voc12_task(dset_path: Path): + task_creator = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.SEMANTIC_SEGMENTATION, + desc="PASCAL VOC 2012 segmentation challenge images", + ref=REFERENCE, + url="http://host.robots.ox.ac.uk/pascal/VOC/voc2012/index.html", + instr="downloaded via torchvision dataset (https://pytorch.org/vision/stable/datasets.html#voc)", + lic=License.UNKNOWN, + release="2012", + keywords=[Keyword.NATURAL_OBJECTS], + ) + + train_iterator = get_iterator_from_segmentation_dataset( + images_root=dset_path / DataKind.TRAINING_DATA, + masks_root=dset_path / DataKind.TRAINING_LABELS / "transformed_masks", + ) + test_iterator = get_iterator_from_segmentation_dataset( + images_root=dset_path / DataKind.TESTING_DATA, + masks_root=dset_path / DataKind.TESTING_LABELS / "transformed_masks", + ) + idx_to_class = {ix: val for ix, val in enumerate(VOC_CLASSES)} + task_creator.find_data(train_iterator=train_iterator, test_iterator=test_iterator, idx_to_class=idx_to_class) + task_creator.split_folds(n_folds=5) + task_creator.infer_stats() + task_creator.push_and_test() diff --git a/plugins/data/tests/conftest.py b/plugins/data/tests/conftest.py new file mode 100644 index 0000000..b3c6299 --- /dev/null +++ b/plugins/data/tests/conftest.py @@ -0,0 +1,14 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import pytest + + +# by default the fixture below overrides the no_plugins fixture from mml.testing.fixtures to allow plugin testing +# you may remove this deactivation, put it into another submodule conftest.py and/or use the "plugin" marker to +# deactivate plugin loading solely for specific tests +@pytest.fixture(autouse=True) +def no_plugins(monkeypatch, request): + yield diff --git a/plugins/data/tests/unit/test_dummy.py b/plugins/data/tests/unit/test_dummy.py new file mode 100644 index 0000000..6259249 --- /dev/null +++ b/plugins/data/tests/unit/test_dummy.py @@ -0,0 +1,9 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + + +def test_dummy(): + pass diff --git a/plugins/dimensionality/CHANGELOG.md b/plugins/dimensionality/CHANGELOG.md new file mode 100644 index 0000000..bc2d9ed --- /dev/null +++ b/plugins/dimensionality/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +All notable changes to this plugin will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.3.1 (12/19/2024): +Fixes test and scheduler check for correctly set normalization. Public release version. + +## 0.3.0 (08/29/2024): +This release introduces this changelog. The core dependency has also been bumped. diff --git a/plugins/dimensionality/LICENSE.txt b/plugins/dimensionality/LICENSE.txt new file mode 100644 index 0000000..6a39552 --- /dev/null +++ b/plugins/dimensionality/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 German Cancer Research Center (DKFZ) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/plugins/dimensionality/MANIFEST.in b/plugins/dimensionality/MANIFEST.in new file mode 100644 index 0000000..f43259a --- /dev/null +++ b/plugins/dimensionality/MANIFEST.in @@ -0,0 +1 @@ +recursive-include src/mml_dimensionality/configs *.yaml \ No newline at end of file diff --git a/plugins/dimensionality/README.md b/plugins/dimensionality/README.md new file mode 100644 index 0000000..31ceaed --- /dev/null +++ b/plugins/dimensionality/README.md @@ -0,0 +1,11 @@ +# MML dimensionality plugin + +This plugin provides the possibility to estimate task dimensionality. + +# Install + +TODO + +# Usage + +TODO \ No newline at end of file diff --git a/plugins/dimensionality/pyproject.toml b/plugins/dimensionality/pyproject.toml new file mode 100644 index 0000000..449c6a9 --- /dev/null +++ b/plugins/dimensionality/pyproject.toml @@ -0,0 +1,52 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +[build-system] +requires = [ + "setuptools>=42", + "wheel", +] +build-backend = "setuptools.build_meta" + +[tool.pytest.ini_options] +addopts = "--strict-markers --benchmark-skip" +testpaths = [ + "tests", +] +markers = [ + "slow: marks tests as slow (deselect with '-m \"not slow\"')", + "gpu: marks tests as requiring a gpu to run", + "env: marks test that require the correct underlying mml.env file", + "plugin: marks tests that require the loading of plugins", + "serial", +] + +[tool.isort] +src_paths = ["src", "tests"] +profile = "black" +line_length = 120 + +[tool.mypy] +mypy_path = "src" +check_untyped_defs = true +disallow_any_generics = true +ignore_missing_imports = true +no_implicit_optional = true +show_error_codes = true +strict_equality = true +warn_redundant_casts = true +warn_return_any = true +warn_unreachable = true +warn_unused_configs = true +no_implicit_reexport = true +disallow_untyped_defs = true +warn_unused_ignores = true +allow_redefinition = true +warn_no_return = true + +[tool.ruff] +# Set the maximum line length +line-length = 120 \ No newline at end of file diff --git a/plugins/dimensionality/setup.cfg b/plugins/dimensionality/setup.cfg new file mode 100644 index 0000000..880d30b --- /dev/null +++ b/plugins/dimensionality/setup.cfg @@ -0,0 +1,48 @@ +[metadata] +name = mml-dimensionality +version = attr: mml_dimensionality.__version__ +description = This is the MML dimensionality plugin, providing task dimensionality estimation methods. +long_description = file: README.md +long_description_content_type = text/markdown +author = Patrick Godau +author_email = patrick.godau@dkfz-heidelberg.de +license = MIT +url = https://git.dkfz.de/imsy/ise/mml +classifiers = + Natural Language :: English + Development Status :: 4 - Beta + Environment :: Console + Intended Audience :: Developers + Topic :: Scientific/Engineering :: Artificial Intelligence + Topic :: Scientific/Engineering :: Image Recognition + Topic :: Scientific/Engineering :: Information Analysis + Topic :: Scientific/Engineering :: Image Processing + Topic :: Software Development :: Libraries :: Application Frameworks + Topic :: Software Development :: Version Control :: Git + Operating System :: OS Independent + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Environment :: GPU + Intended Audience :: Science/Research + Typing :: Typed + License :: OSI Approved :: MIT License + +[options] +python_requires = >=3.8 +package_dir = + =src +packages = find: +zip_safe = no +include_package_data = True +install_requires = + mml-core>=1.0.0 + +[options.entry_points] +; on loading the plugin the creators shall be registered, this is solved by the underlying __init__.py files +mml.plugins = + mml-dimensionality = mml_dimensionality.activate + +[options.packages.find] +where=src diff --git a/plugins/dimensionality/src/mml_dimensionality/__init__.py b/plugins/dimensionality/src/mml_dimensionality/__init__.py new file mode 100644 index 0000000..6ada5d3 --- /dev/null +++ b/plugins/dimensionality/src/mml_dimensionality/__init__.py @@ -0,0 +1,9 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +VERSION = (0, 3, 1) +__version__ = ".".join(map(str, VERSION)) +__all__ = ["__version__"] diff --git a/plugins/dimensionality/src/mml_dimensionality/activate.py b/plugins/dimensionality/src/mml_dimensionality/activate.py new file mode 100644 index 0000000..0afb4ac --- /dev/null +++ b/plugins/dimensionality/src/mml_dimensionality/activate.py @@ -0,0 +1,38 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +from hydra.core.config_search_path import ConfigSearchPath +from hydra.core.plugins import Plugins +from hydra.plugins.search_path_plugin import SearchPathPlugin + +from mml.core.data_loading.file_manager import MMLFileManager + +MMLFileManager.add_assignment_path( + obj_cls=int, + key="dimension", + path=Path("PROJ_PATH") / "DIMENSIONS" / "TASK_NAME" / "dims.txt", + enable_numbering=True, + reusable=True, +) +MMLFileManager.add_assignment_path( + obj_cls=None, + key="dimension_plot", + path=Path("PROJ_PATH") / "PLOTS" / "DIMENSION" / "dims_versus_perf.html", + enable_numbering=True, + reusable=False, +) + + +# register plugin configs +class MMLDimensionalitySearchPathPlugin(SearchPathPlugin): + def manipulate_search_path(self, search_path: ConfigSearchPath) -> None: + # Sets the search path for mml with copied config files + search_path.append(provider="mml-dimensionality", path="pkg://mml_dimensionality.configs") + + +Plugins.instance().register(MMLDimensionalitySearchPathPlugin) diff --git a/plugins/dimensionality/src/mml_dimensionality/configs/__init__.py b/plugins/dimensionality/src/mml_dimensionality/configs/__init__.py new file mode 100644 index 0000000..90ffb6c --- /dev/null +++ b/plugins/dimensionality/src/mml_dimensionality/configs/__init__.py @@ -0,0 +1,6 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + diff --git a/plugins/dimensionality/src/mml_dimensionality/configs/mode/dim.yaml b/plugins/dimensionality/src/mml_dimensionality/configs/mode/dim.yaml new file mode 100644 index 0000000..b3bc5e9 --- /dev/null +++ b/plugins/dimensionality/src/mml_dimensionality/configs/mode/dim.yaml @@ -0,0 +1,24 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - override /augmentations: no_norm + - override /sampling: extraction_default + +mode: + scheduler: + _target_: mml_dimensionality.scripts.dimensionality_scheduler.DimensionalityScheduler + subroutines: + - estimate + k: 25 + max_subsets: 5 + subset_min_size: 100 + inv_mle: true + +sampling: + sample_num: 1000 diff --git a/plugins/dimensionality/src/mml_dimensionality/models/__init__.py b/plugins/dimensionality/src/mml_dimensionality/models/__init__.py new file mode 100644 index 0000000..90ffb6c --- /dev/null +++ b/plugins/dimensionality/src/mml_dimensionality/models/__init__.py @@ -0,0 +1,6 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + diff --git a/plugins/dimensionality/src/mml_dimensionality/models/knn.py b/plugins/dimensionality/src/mml_dimensionality/models/knn.py new file mode 100644 index 0000000..580db05 --- /dev/null +++ b/plugins/dimensionality/src/mml_dimensionality/models/knn.py @@ -0,0 +1,85 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +""" +The method and partially also the code is reused from: +"The Intrinsic Dimensionaity of Images and Its Impact On Learning" +by Phillip Pope, Chen Zhu, Ahmed Abdelkader, Micah Goldblum, Tom Goldstein (ICLR 2021, spotlight) +code: https://github.com/ppope/dimensions +""" + +import torch + + +class KNNComputer(torch.nn.Module): + """ + Using this hack for data parallel + without checking for the sample itself + """ + + def __init__(self, sample_num: int, k: int = 1, cosine_dist=False): + super(KNNComputer, self).__init__() + + self.K = k + self.cosine_dist = cosine_dist + self.register_buffer("num_computed", torch.zeros([])) + + if k == 1: + self.register_buffer("min_dists", torch.full((sample_num,), float("inf"))) + self.register_buffer("nn_indices", torch.full((sample_num,), 0, dtype=torch.int64)) + else: + self.register_buffer("min_dists", torch.full((sample_num, k), float("inf"))) + self.register_buffer("nn_indices", torch.full((sample_num, k), 0, dtype=torch.int64)) + + def forward(self, x, x_idx_start, y, y_idx_start): + # update the min dist for existing examples... + x_bsize, y_bsize = x.size(0), y.size(0) + x = x.view(x_bsize, -1) + y = y.view(y_bsize, -1) + if self.cosine_dist: + x = x / x.norm(dim=1, keepdim=True) + y = y / y.norm(dim=1, keepdim=True) + dist = x.mm(y.t()) + + else: + # dist = torch.norm(x.unsqueeze(1) - y.unsqueeze(0), dim=2) + dist = torch.cdist(x, y, p=2, compute_mode="donot_use_mm_for_euclid_dist") + + if self.K == 1: + new_min_dist, nn_idxes = torch.min(dist, dim=1) + + self.min_dists[x_idx_start : x_idx_start + x_bsize] = torch.min( + new_min_dist, self.min_dists[x_idx_start : x_idx_start + x_bsize] + ) + self.nn_indices[x_idx_start : x_idx_start + x_bsize] = nn_idxes + y_idx_start + else: + comp = torch.cat([dist, self.min_dists[x_idx_start : x_idx_start + x_bsize]], dim=1) + # updated_min_dist, nn_idxes = torch.topk(comp, self.K, dim=1, largest=False) + # check for repeated images + sorted_dists, sorted_idxes = torch.sort(comp, dim=1, descending=False) + updated_dist_list, nn_idx_list = [], [] + for row in range(sorted_dists.shape[0]): + sidx = 1 + while sidx < sorted_dists.shape[1]: + if sorted_dists[row, sidx] == 0: + sidx += 1 + else: + break + updated_dist_list.append(sorted_dists[row, sidx - 1 : sidx - 1 + self.K]) + nn_idx_list.append(sorted_idxes[row, sidx - 1 : sidx - 1 + self.K]) + updated_min_dist = torch.stack(updated_dist_list) + nn_idxes = torch.stack(nn_idx_list) + + self.min_dists[x_idx_start : x_idx_start + x_bsize] = updated_min_dist + + sample_idxes = (nn_idxes < y_bsize).int() * (nn_idxes + y_idx_start) + ( + nn_idxes >= y_bsize + ).int() * self.nn_indices[x_idx_start : x_idx_start + x_bsize] + self.nn_indices[x_idx_start : x_idx_start + x_bsize] = sample_idxes + + def get_mean_nn_dist(self, sidx, eidx): + if self.K == 1: + return torch.mean(self.min_dists[sidx:eidx]) diff --git a/plugins/dimensionality/src/mml_dimensionality/scripts/__init__.py b/plugins/dimensionality/src/mml_dimensionality/scripts/__init__.py new file mode 100644 index 0000000..4518687 --- /dev/null +++ b/plugins/dimensionality/src/mml_dimensionality/scripts/__init__.py @@ -0,0 +1,8 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# automatically activate plugin when importing +import mml_dimensionality.activate # noqa diff --git a/plugins/dimensionality/src/mml_dimensionality/scripts/dimensionality_scheduler.py b/plugins/dimensionality/src/mml_dimensionality/scripts/dimensionality_scheduler.py new file mode 100644 index 0000000..08a65d0 --- /dev/null +++ b/plugins/dimensionality/src/mml_dimensionality/scripts/dimensionality_scheduler.py @@ -0,0 +1,93 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging + +import numpy as np +from mml_dimensionality.scripts.mle import calc_mle +from mml_dimensionality.visualization import plot_dimensions_versus_baseline +from omegaconf import DictConfig + +from mml.core.scripts.decorators import beta +from mml.core.scripts.exceptions import MMLMisconfigurationException +from mml.core.scripts.schedulers.base_scheduler import AbstractBaseScheduler +from mml.core.scripts.utils import LearningPhase + +logger = logging.getLogger(__name__) + + +@beta("Dimension estimation is in beta!") +class DimensionalityScheduler(AbstractBaseScheduler): + """ " + AbstractBaseScheduler implementation for the estimation of task dimensionality. Includes the following subroutines: + - estimate + + The method and partially also the code is reused from: + "The Intrinsic Dimensionaity of Images and Its Impact On Learning" + by Phillip Pope, Chen Zhu, Ahmed Abdelkader, Micah Goldblum, Tom Goldstein (ICLR 2021, spotlight) + code: https://github.com/ppope/dimensions + """ + + def __init__(self, cfg: DictConfig): + # initialize + super(DimensionalityScheduler, self).__init__(cfg=cfg, available_subroutines=["estimate", "plot"]) + if self.cfg.mode.k < 3: + raise MMLMisconfigurationException("mode.k must be at least 3.") + if self.cfg.augmentations.normalization is not None: + raise MMLMisconfigurationException( + "Must deactivate normalization for dimensionality estimation. " "Best set augmentations=no_norm." + ) + + def create_routine(self): + """ + This scheduler implements one subroutine, which estimates a task's dimensionality. + + :return: None + """ + # -- add preprocess command + if "estimate" in self.subroutines: + if self.pivot: + logger.info("Dimensionality mode with pivot task will only estimate this task!") + self.commands.append(self.estimate_task_dimensionality) + self.params.append([self.pivot]) + else: + for task in self.cfg.task_list: + self.commands.append(self.estimate_task_dimensionality) + self.params.append([task]) + + def before_finishing_hook(self): + if "plot" in self.subroutines and not self.pivot: + task_list = [] + # check if performances are available + for task in self.cfg.task_list: + struct = self.get_struct(task_name=task) + if len(struct.models) > 0: + task_list.append(struct) + else: + logger.error( + f"No performance found for task {task} to produce dimension versus performance plot, " + f"you may want to use reuse.models=SOME_PROJ_NAME to provide performances." + ) + + if len(task_list) > 0: + plot_path = self.fm.construct_saving_path(obj=None, key="dimension_plot") + plot_dimensions_versus_baseline(all_tasks=task_list, store_path=plot_path) + logger.info(f"Plotted task dimensionality against performance at {plot_path}.") + + def estimate_task_dimensionality(self, task_name: str): + logger.info("Starting estimating dimensionality data for task " + self.highlight_text(task_name)) + task_struct = self.get_struct(task_name) + datamodule = self.create_datamodule(task_structs=task_struct) + datamodule.setup(stage="fit") + dataset = datamodule.task_datasets[task_name][LearningPhase.TRAIN] + val = calc_mle(cfg=self.cfg, dataset=dataset) + dim = -1 if np.isnan(val) else int(val) + path = self.fm.construct_saving_path(obj=dim, key="dimension", task_name=task_struct.name) + with open(path, "w+") as f: + f.write(str(dim)) + task_struct.paths["dimension"] = path + self.task_factory.dump() + logger.info("Finished dimensionality estimation for task " + self.highlight_text(task_name)) diff --git a/plugins/dimensionality/src/mml_dimensionality/scripts/mle.py b/plugins/dimensionality/src/mml_dimensionality/scripts/mle.py new file mode 100644 index 0000000..8e50599 --- /dev/null +++ b/plugins/dimensionality/src/mml_dimensionality/scripts/mle.py @@ -0,0 +1,122 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +""" +The method and partially also the code is reused from: +"The Intrinsic Dimensionaity of Images and Its Impact On Learning" +by Phillip Pope, Chen Zhu, Ahmed Abdelkader, Micah Goldblum, Tom Goldstein (ICLR 2021, spotlight) +code: https://github.com/ppope/dimensions +""" + +import logging +import random +import warnings +from typing import Tuple + +import numpy as np +import torch +from mml_dimensionality.models.knn import KNNComputer +from torch.utils.data import DataLoader +from tqdm import tqdm + +from mml.core.data_loading.task_attributes import Modality +from mml.core.data_loading.task_dataset import TaskDataset + +logger = logging.getLogger(__name__) + + +def calc_mle(cfg, dataset: TaskDataset) -> float: + device = torch.device("cuda") if cfg.allow_gpu else torch.device("cpu") + subsets = create_random_subsets(data_set=dataset, subset_size=cfg.sampling.sample_num)[: cfg.mode.max_subsets] + if len(subsets[-1]) < cfg.mode.subset_min_size: + subsets = subsets[:-1] + if len(subsets) == 0: + logger.error( + f"Not enough samples to build a suitable subset. Current min size is " + f"{cfg.mode.subset_min_size}, but task only offers {len(dataset)} samples!" + ) + return float("Nan") + subset_dims = [] + for s_set in tqdm(subsets, desc="Iterate subsets"): + if len(s_set) < cfg.sampling.sample_num: + warnings.warn(f"Subset only has {len(s_set)} samples!") + model = run_knn( + dataset=s_set, k=cfg.mode.k, batch_size=cfg.sampling.batch_size, n_workers=cfg.num_workers, device=device + ) + dist = model.min_dists.cpu().numpy() + + mle_res, inv_mle_res = [], [] + for k in range(3, cfg.mode.k + 1): + mle_results, invmle_results = intrinsic_dim_sample_wise_double_mle(k, dist) + mle_res.append(mle_results.mean()) + inv_mle_res.append(1.0 / invmle_results.mean()) + logger.debug(f"Subset estimate for K={k}: MLE -> {mle_res[-1]}, INV-MLE -> {inv_mle_res[-1]}") + if cfg.mode.inv_mle: + subset_dims.append(inv_mle_res[-1]) + else: + subset_dims.append(mle_res[-1]) + subset_dims = [d for d in subset_dims if np.isfinite(d)] + if len(subset_dims) == 0: + raise RuntimeError( + "No valid subset dim found! Consider either increasing mode.max_subsets, " + "mode.subset_min_size or switching to mode.inv_mle=true" + ) + logger.debug(f"all subset estimates: {subset_dims}") + return sum(subset_dims) / len(subsets) + + +def run_knn(dataset: torch.utils.data.Subset, k: int, batch_size: int, n_workers: int, device: torch.device): + model = KNNComputer(sample_num=len(dataset), k=k + 1) + anchor_loader = DataLoader(dataset=dataset, batch_size=batch_size, shuffle=False, num_workers=n_workers) + new_image_loader = DataLoader(dataset=dataset, batch_size=batch_size, shuffle=False, num_workers=n_workers) + anchor_counter = 0 + model = model.to(device) + # ignoring the labels + with torch.no_grad(): + for a_batch in tqdm(anchor_loader, desc="Compute KNN", leave=False): + a_images = a_batch[Modality.IMAGE.value].to(device) + new_img_counter = 0 + for new_batch in new_image_loader: + new_images = new_batch[Modality.IMAGE.value].to(device) + # forward through model + model(a_images, anchor_counter, new_images, new_img_counter) + new_img_counter += new_images.size(0) + + # equiv_flag = (model.min_dists[anchor_start_idx:anchor_start_idx + a_images.size(0), + # 0] == 0) & (model.min_dists[ + # anchor_start_idx:anchor_start_idx + a_images.size(0), 1] == 0) + # if torch.any(equiv_flag): + # raise Exception("Identical data detected!") + + anchor_counter += a_images.size(0) + return model.cpu() + + +def create_random_subsets(data_set, subset_size): + indices = [i for i in range(len(data_set))] + random.shuffle(indices) + n_subsets = (len(data_set) // subset_size) + 1 + subset_idxes = [indices[i * subset_size : (i + 1) * subset_size] for i in range(n_subsets)] + + return [torch.utils.data.Subset(data_set, sidxes) for sidxes in subset_idxes] + + +def intrinsic_dim_sample_wise_double_mle(k: int, dist: np.ndarray) -> Tuple: + """ + Returns Levina-Bickel dimensionality estimation and the correction by MacKay-Ghahramani. + + :param int k: nearest neighbors to use + :param np.ndarray dist: array of the nearest distances + :return: 2 dimensionality estimates + """ + dist = dist[:, 1 : (k + 1)] + assert np.all(dist > 0) + d = np.log(dist[:, k - 1 : k] / dist[:, 0 : k - 1]) + d = d.sum(axis=1) / (k - 2) + inv_mle = d.copy() + d = 1.0 / d + mle = d + return mle, inv_mle diff --git a/plugins/dimensionality/src/mml_dimensionality/scripts/utils.py b/plugins/dimensionality/src/mml_dimensionality/scripts/utils.py new file mode 100644 index 0000000..9c5aa79 --- /dev/null +++ b/plugins/dimensionality/src/mml_dimensionality/scripts/utils.py @@ -0,0 +1,20 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + + +def load_dim(path: Path) -> int: + """ + Loads the dimensionality of a task, provided the storage path of that information. + + :param Path path: + :return: + """ + with open(path, "r") as file: + lines = file.readlines() + assert len(lines) == 1 + return int(lines[0]) diff --git a/plugins/dimensionality/src/mml_dimensionality/visualization/__init__.py b/plugins/dimensionality/src/mml_dimensionality/visualization/__init__.py new file mode 100644 index 0000000..08e6b56 --- /dev/null +++ b/plugins/dimensionality/src/mml_dimensionality/visualization/__init__.py @@ -0,0 +1,68 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path +from typing import List + +import pandas as pd +import plotly.express as px + +from mml.core.data_loading.task_attributes import Keyword +from mml.core.data_loading.task_struct import TaskStruct +from mml.core.scripts.model_storage import ModelStorage + + +def plot_dimensions_versus_baseline(all_tasks: List[TaskStruct], store_path: Path) -> None: + def load_dim(path: Path) -> int: + with open(path, "r") as file: + lines = file.readlines() + assert len(lines) == 1 + return int(lines[0]) + + def load_performance(models: List[ModelStorage]) -> float: + metric = "val/Recall" + return max([m.metrics[-1][metric] for m in models]) + + domain_list = [ + Keyword.DERMATOSCOPY, + Keyword.LARYNGOSCOPY, + Keyword.GASTROSCOPY_COLONOSCOPY, + Keyword.LAPAROSCOPY, + Keyword.NATURAL_OBJECTS, + Keyword.HANDWRITINGS, + Keyword.CATARACT_SURGERY, + Keyword.FUNDUS_PHOTOGRAPHY, + Keyword.MRI_SCAN, + Keyword.X_RAY, + Keyword.CT_SCAN, + Keyword.CLE, + Keyword.CAPSULE_ENDOSCOPY, + Keyword.ULTRASOUND, + ] + + def get_domain(task: TaskStruct) -> Keyword: + domain_candidates = [d for d in task.keywords if d in domain_list] + # TODO this is a hacky solution only so far + if task.name == "svhn": + domain_candidates.append(Keyword.NATURAL_OBJECTS) + if task.name == "mnist_digit_classification" or task.name == "emnist_digit_classification": + domain_candidates.append(Keyword.HANDWRITINGS) + if len(domain_candidates) != 1: + raise RuntimeError(f"{task} with {domain_candidates}") + return domain_candidates[0] + + task_infos = [ + { + "name": task.name, + "dimension": load_dim(task.paths["dimension"]), + "performance": load_performance(task.models), + "domain": get_domain(task).value, + } + for task in all_tasks + ] + df = pd.DataFrame(data=task_infos) + fig = px.scatter(data_frame=df, x="dimension", y="performance", color="domain", hover_name="name", trendline="ols") + fig.write_html(store_path) diff --git a/plugins/dimensionality/tests/conftest.py b/plugins/dimensionality/tests/conftest.py new file mode 100644 index 0000000..b3c6299 --- /dev/null +++ b/plugins/dimensionality/tests/conftest.py @@ -0,0 +1,14 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import pytest + + +# by default the fixture below overrides the no_plugins fixture from mml.testing.fixtures to allow plugin testing +# you may remove this deactivation, put it into another submodule conftest.py and/or use the "plugin" marker to +# deactivate plugin loading solely for specific tests +@pytest.fixture(autouse=True) +def no_plugins(monkeypatch, request): + yield diff --git a/plugins/dimensionality/tests/unit/test_dimensionality_scheduler.py b/plugins/dimensionality/tests/unit/test_dimensionality_scheduler.py new file mode 100644 index 0000000..2c30af9 --- /dev/null +++ b/plugins/dimensionality/tests/unit/test_dimensionality_scheduler.py @@ -0,0 +1,28 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import pytest +from mml_dimensionality.scripts.dimensionality_scheduler import DimensionalityScheduler +from omegaconf import OmegaConf + + +@pytest.mark.gpu +@pytest.mark.slow +@pytest.mark.parametrize("test_task_name", ["test_task_a", "test_task_d"]) +def test_train_probe_model(test_task_monkeypatch, mml_config, test_task_name) -> None: + OmegaConf.set_struct(mml_config, False) + mml_config.mode.subroutines = ["estimate"] + mml_config.mode.k = 5 + mml_config.mode.max_subsets = 2 + mml_config.mode.subset_min_size = 5 + mml_config.mode.inv_mle = True + mml_config.sampling.sample_num = 10 + mml_config.augmentations.normalization = None + mml_config.augmentations.pipeline = {} + OmegaConf.set_struct(mml_config, True) + scheduler = DimensionalityScheduler(cfg=mml_config) + scheduler.estimate_task_dimensionality(task_name=test_task_name) + assert "dimension" in test_task_monkeypatch[test_task_name].paths diff --git a/plugins/drive/CHANGELOG.md b/plugins/drive/CHANGELOG.md new file mode 100644 index 0000000..917bf45 --- /dev/null +++ b/plugins/drive/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +All notable changes to this plugin will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.2.1 (12/19/2024): +RPublic release version. + +## 0.2.0 (08/29/2024): +This release introduces this changelog. The core dependency has also been bumped. diff --git a/plugins/drive/LICENSE.txt b/plugins/drive/LICENSE.txt new file mode 100644 index 0000000..6a39552 --- /dev/null +++ b/plugins/drive/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 German Cancer Research Center (DKFZ) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/plugins/drive/README.md b/plugins/drive/README.md new file mode 100644 index 0000000..62cd723 --- /dev/null +++ b/plugins/drive/README.md @@ -0,0 +1,16 @@ +# MML drive plugin + +This plugin provides support for fast data installation via a shared network drives. It extends the create scheduler +to look for respective downloaded files there first. This might be useful if a team works jointly with `mml` and you +want to avoid redundant downloading of raw datasets. + +# Install + +After installing this plugin via `pip` you need to mount a network drive. On that network drive there needs to reside +the following file structure: `MedicalMetaLearner/DOWNLOADS`. You may copy contents of your local +`MML_DATA_PATH/DOWNLOADS` into that folder to provide the downloaded files to others. Every user that wants to download +is required to add `export MML_NW_DRIVE=path/to/drive/root` to their `mml.env` file. + +# Usage + +Just use `mml create` as usual. If the network drive offers a benefit, `mml` will download data from there. \ No newline at end of file diff --git a/plugins/drive/pyproject.toml b/plugins/drive/pyproject.toml new file mode 100644 index 0000000..449c6a9 --- /dev/null +++ b/plugins/drive/pyproject.toml @@ -0,0 +1,52 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +[build-system] +requires = [ + "setuptools>=42", + "wheel", +] +build-backend = "setuptools.build_meta" + +[tool.pytest.ini_options] +addopts = "--strict-markers --benchmark-skip" +testpaths = [ + "tests", +] +markers = [ + "slow: marks tests as slow (deselect with '-m \"not slow\"')", + "gpu: marks tests as requiring a gpu to run", + "env: marks test that require the correct underlying mml.env file", + "plugin: marks tests that require the loading of plugins", + "serial", +] + +[tool.isort] +src_paths = ["src", "tests"] +profile = "black" +line_length = 120 + +[tool.mypy] +mypy_path = "src" +check_untyped_defs = true +disallow_any_generics = true +ignore_missing_imports = true +no_implicit_optional = true +show_error_codes = true +strict_equality = true +warn_redundant_casts = true +warn_return_any = true +warn_unreachable = true +warn_unused_configs = true +no_implicit_reexport = true +disallow_untyped_defs = true +warn_unused_ignores = true +allow_redefinition = true +warn_no_return = true + +[tool.ruff] +# Set the maximum line length +line-length = 120 \ No newline at end of file diff --git a/plugins/drive/setup.cfg b/plugins/drive/setup.cfg new file mode 100644 index 0000000..357b3b7 --- /dev/null +++ b/plugins/drive/setup.cfg @@ -0,0 +1,47 @@ +[metadata] +name = mml-drive +version = attr: mml_drive.__version__ +description = This is the MML drive plugin, providing fast DKFZ indoor data sharing. +long_description = file: README.md +long_description_content_type = text/markdown +author = Patrick Godau +author_email = patrick.godau@dkfz-heidelberg.de +license = MIT +url = https://git.dkfz.de/imsy/ise/mml +classifiers = + Natural Language :: English + Development Status :: 4 - Beta + Environment :: Console + Intended Audience :: Developers + Topic :: Scientific/Engineering :: Artificial Intelligence + Topic :: Scientific/Engineering :: Image Recognition + Topic :: Scientific/Engineering :: Information Analysis + Topic :: Scientific/Engineering :: Image Processing + Topic :: Software Development :: Libraries :: Application Frameworks + Topic :: Software Development :: Version Control :: Git + Operating System :: OS Independent + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Environment :: GPU + Intended Audience :: Science/Research + Typing :: Typed + License :: OSI Approved :: MIT License + +[options] +python_requires = >=3.8 +package_dir = + =src +packages = find: +zip_safe = no +include_package_data = True +install_requires = + mml-core>=1.0.0 + +[options.entry_points] +mml.plugins = + mml-drive = mml_drive.activate + +[options.packages.find] +where=src diff --git a/plugins/drive/src/mml_drive/__init__.py b/plugins/drive/src/mml_drive/__init__.py new file mode 100644 index 0000000..2d0ddb5 --- /dev/null +++ b/plugins/drive/src/mml_drive/__init__.py @@ -0,0 +1,9 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +VERSION = (0, 2, 1) +__version__ = ".".join(map(str, VERSION)) +__all__ = ["__version__"] diff --git a/plugins/drive/src/mml_drive/activate.py b/plugins/drive/src/mml_drive/activate.py new file mode 100644 index 0000000..5e7dfed --- /dev/null +++ b/plugins/drive/src/mml_drive/activate.py @@ -0,0 +1,12 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from mml_drive.prepare_hook import prepare_exp + +from mml.core.scripts.schedulers.create_scheduler import CreateScheduler + +# replace default prepare exp definition +CreateScheduler.prepare_exp = prepare_exp diff --git a/plugins/drive/src/mml_drive/prepare_hook.py b/plugins/drive/src/mml_drive/prepare_hook.py new file mode 100644 index 0000000..0aebc10 --- /dev/null +++ b/plugins/drive/src/mml_drive/prepare_hook.py @@ -0,0 +1,58 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import os +import shutil +from pathlib import Path + +from mml.core.data_preparation.utils import WIPBar +from mml.core.scripts.exceptions import MMLMisconfigurationException +from mml.core.scripts.schedulers.create_scheduler import CreateScheduler + +logger = logging.getLogger(__name__) + + +def prepare_exp(self: CreateScheduler) -> None: + """ + New implementation of create schedulers prepare experiment method. + + :param CreateScheduler self: the scheduler instance + :return: + """ + try: + nw_drive = Path(os.getenv("MML_NW_DRIVE", None)) + except TypeError: + raise MMLMisconfigurationException("MML_NW_DRIVE environment variable is not set. Please add to your mml.env") + if not nw_drive.exists(): + raise FileNotFoundError(f"MML_NW_DRIVE (={nw_drive}) does not exist") + nw_downloads = nw_drive / "MedicalMetaLearner" / "DOWNLOADS" + if not nw_downloads.exists(): + raise RuntimeError("Did someone delete the MML network drive data?") + data_sets = [args[0] for idx, args in enumerate(self.params) if self.commands[idx].__name__ == "prepare_dataset"] + available_downloads = [p.name for p in nw_downloads.iterdir() if p.is_dir()] + for d_set in data_sets: + if d_set not in available_downloads: + logger.info(f"Network drive does not offer shortcut for dataset {d_set}") + continue + # check if kaggle download, these are not yet compatible with pre-copying + if (nw_downloads / d_set / "kaggle").exists(): + logger.info(f"Although data for {d_set} exists on the network drive will not download this kaggle dset.") + continue + # no we have to copy + logger.info(f"Found dataset {d_set} on the DKFZ network drive - will try to copy now.") + target_path = self.fm.get_download_path(dset_name=d_set) + if len(target_path.iterdir()) != 0: + # already existing downloads, will skip + logger.error( + f"Found existing download data (potentially from previous attempt) at {target_path}. " + f"This triggers to skip the data copy! If dset creation fails, you might want to " + f"clean delete {target_path} manually." + ) + with WIPBar() as bar: + bar.desc = "Copying dataset" + shutil.copytree(src=str(nw_downloads / d_set), dst=str(target_path), dirs_exist_ok=True) + logger.info(f"Successfully copied dataset {d_set} from network drive to local MML setup at {target_path}.") diff --git a/plugins/drive/tests/conftest.py b/plugins/drive/tests/conftest.py new file mode 100644 index 0000000..b3c6299 --- /dev/null +++ b/plugins/drive/tests/conftest.py @@ -0,0 +1,14 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import pytest + + +# by default the fixture below overrides the no_plugins fixture from mml.testing.fixtures to allow plugin testing +# you may remove this deactivation, put it into another submodule conftest.py and/or use the "plugin" marker to +# deactivate plugin loading solely for specific tests +@pytest.fixture(autouse=True) +def no_plugins(monkeypatch, request): + yield diff --git a/plugins/drive/tests/unit/test_dummy.py b/plugins/drive/tests/unit/test_dummy.py new file mode 100644 index 0000000..6259249 --- /dev/null +++ b/plugins/drive/tests/unit/test_dummy.py @@ -0,0 +1,9 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + + +def test_dummy(): + pass diff --git a/plugins/index.txt b/plugins/index.txt new file mode 100644 index 0000000..9de7e3d --- /dev/null +++ b/plugins/index.txt @@ -0,0 +1,8 @@ +data +drive +tags +similarity +dimensionality +lsf +sql +suggest \ No newline at end of file diff --git a/plugins/lsf/CHANGELOG.md b/plugins/lsf/CHANGELOG.md new file mode 100644 index 0000000..5957404 --- /dev/null +++ b/plugins/lsf/CHANGELOG.md @@ -0,0 +1,15 @@ +# Changelog + +All notable changes to this plugin will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.5.1 (12/19/2024): +Public release version. + +## 0.5.0 (08/29/2024): +This release introduces this changelog. The core dependency has also been bumped. + +### Bug fixes + - fix import in `__init__.py` preventing installation diff --git a/plugins/lsf/LICENSE.txt b/plugins/lsf/LICENSE.txt new file mode 100644 index 0000000..6a39552 --- /dev/null +++ b/plugins/lsf/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 German Cancer Research Center (DKFZ) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/plugins/lsf/MANIFEST.in b/plugins/lsf/MANIFEST.in new file mode 100644 index 0000000..0efa266 --- /dev/null +++ b/plugins/lsf/MANIFEST.in @@ -0,0 +1 @@ +recursive-include src/mml_???/configs *.yaml \ No newline at end of file diff --git a/plugins/lsf/README.md b/plugins/lsf/README.md new file mode 100644 index 0000000..778b872 --- /dev/null +++ b/plugins/lsf/README.md @@ -0,0 +1,94 @@ +# MML LSF plugin + +This plugin provides LSF cluster support on the specific setting of the DKFZ GPU cluster. + +# Install + +```commandline +pip install mml-lsf +``` + +If you want to use the submission features of `mml_lsf.runner.LSFJobRunner` you need to set up the following +(not required by any of the other features of this plugin): + + * install sshpass for providing ssh with password + ```commandline + sudo apt install sshpass + ``` + * set the following variables in your mml.env (alternatively provide them manually to `mml_lsf.runner.LSFJobRunner`) + * `export MML_AD_USER=...` + * `export MML_CLUSTER_HOST=...` (a LSF submission host) + * `export MML_CLUSTER_WORKER=...` (a cluster worker node) + +# Usage + +First and foremost it automatically ensures the number of workers used by MML to be conforming to +the node the job will be executed (see `mml_lsf.workers`). In addition, it provides a suitable implementation +for job planning on the LSF cluster, taking care of all necessary prefixes to the CLI (see +`mml_lsf.requirements`). Finally, it offers the `LSFJobRunner` to automatically submit job. Alternatively it is also +possible to submit via pre-rendering into a local file and ssh file tunneling. + +## Usage with `sshpass' + +```python +from mml.core.scripts.utils import load_env +from mml_lsf.requirements import LSFSubmissionRequirements +from mml_lsf.runner import LSFJobRunner +from mml.interactive.planning import MMLJobDescription + +# make sure to load mml.env variables +load_env() # if within a jupyter notebook, instead invoke mml.interactive.init() +# setup job requirements +reqs = LSFSubmissionRequirements( + num_gpus=1, + vram_per_gpu=11.0, + queue='gpu-lowprio', + mail='something@dkfz-heidelberg.de', # optional + script_name='mml.sh', # name of my runner script to load CUDA, conda env, etc and finally invoke mml + job_group='/USERNAME/JOB_GROUP_NAME', # optional, used e.g. to limit max number of jobs + interactive=True # optional, if True realtime updates are printed to terminal + ) +# setup runner, will prompt for password once +runner = LSFJobRunner() +job = MMLJobDescription(prefix_req=reqs, mode='info', config_options={}) # simple job "mml info" +job.run(runner=runner) # will submit job (no password prompt) +job2 = MMLJobDescription(prefix_req=reqs, mode='train', config_options={}) # another job "mml info" +job2.run(runner=runner) # will submit job (no password prompt) +``` + +## Usage with file tunneling + +```python +from mml_lsf.requirements import LSFSubmissionRequirements +from mml.interactive.planning import MMLJobDescription, write_out_commands + +# setup job requirements +reqs = LSFSubmissionRequirements( + num_gpus=1, + vram_per_gpu=11.0, + queue='gpu-lowprio', + mail='something@dkfz-heidelberg.de', # optional + script_name='mml.sh', # name of my runner script to load CUDA, conda env, etc and finally invoke mml + job_group='/USERNAME/JOB_GROUP_NAME', # optional, used e.g. to limit max number of jobs + interactive=False # setting True is not recommended for batched submission + ) + +# create batch of cmds +cmds = list() +# cmd 1 some dummy task +prep_cmds.append(MMLJobDescription(prefix_req=reqs, mode='train', config_options={'tasks': 'fake', 'proj': 'dummy'})) +# cmd 2 another dummy task +prep_cmds.append(MMLJobDescription(prefix_req=reqs, mode='train', config_options={'tasks': 'fake', 'proj': 'dummy'})) +# now write +write_out_commands(cmd_list=cmds, name='exp1') +# this creates a 'exp1.txt' at current working directory +``` + +Now submit these jobs via: + +```commandline +ssh AD_USER@SUBMISSION_HOST 'bash -s' < /path/to/exp1.txt +``` + + + diff --git a/plugins/lsf/pyproject.toml b/plugins/lsf/pyproject.toml new file mode 100644 index 0000000..449c6a9 --- /dev/null +++ b/plugins/lsf/pyproject.toml @@ -0,0 +1,52 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +[build-system] +requires = [ + "setuptools>=42", + "wheel", +] +build-backend = "setuptools.build_meta" + +[tool.pytest.ini_options] +addopts = "--strict-markers --benchmark-skip" +testpaths = [ + "tests", +] +markers = [ + "slow: marks tests as slow (deselect with '-m \"not slow\"')", + "gpu: marks tests as requiring a gpu to run", + "env: marks test that require the correct underlying mml.env file", + "plugin: marks tests that require the loading of plugins", + "serial", +] + +[tool.isort] +src_paths = ["src", "tests"] +profile = "black" +line_length = 120 + +[tool.mypy] +mypy_path = "src" +check_untyped_defs = true +disallow_any_generics = true +ignore_missing_imports = true +no_implicit_optional = true +show_error_codes = true +strict_equality = true +warn_redundant_casts = true +warn_return_any = true +warn_unreachable = true +warn_unused_configs = true +no_implicit_reexport = true +disallow_untyped_defs = true +warn_unused_ignores = true +allow_redefinition = true +warn_no_return = true + +[tool.ruff] +# Set the maximum line length +line-length = 120 \ No newline at end of file diff --git a/plugins/lsf/setup.cfg b/plugins/lsf/setup.cfg new file mode 100644 index 0000000..8b2dc3f --- /dev/null +++ b/plugins/lsf/setup.cfg @@ -0,0 +1,47 @@ +[metadata] +name = mml-lsf +version = attr: mml_lsf.__version__ +description = This is the MML LSF plugin, providing LSF cluster support on the specific setting of the DKFZ GPU cluster. +long_description = file: README.md +long_description_content_type = text/markdown +author = Patrick Godau +author_email = patrick.godau@dkfz-heidelberg.de +license = MIT +url = https://git.dkfz.de/imsy/ise/mml +classifiers = + Natural Language :: English + Development Status :: 4 - Beta + Environment :: Console + Intended Audience :: Developers + Topic :: Scientific/Engineering :: Artificial Intelligence + Topic :: Scientific/Engineering :: Image Recognition + Topic :: Scientific/Engineering :: Information Analysis + Topic :: Scientific/Engineering :: Image Processing + Topic :: Software Development :: Libraries :: Application Frameworks + Topic :: Software Development :: Version Control :: Git + Operating System :: OS Independent + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Environment :: GPU + Intended Audience :: Science/Research + Typing :: Typed + License :: OSI Approved :: MIT License + +[options] +python_requires = >=3.8 +package_dir = + =src +packages = find: +zip_safe = no +include_package_data = True +install_requires = + mml-core>=1.0.0 + +[options.entry_points] +mml.plugins = + mml-lsf = mml_lsf.activate + +[options.packages.find] +where=src diff --git a/plugins/lsf/src/mml_lsf/__init__.py b/plugins/lsf/src/mml_lsf/__init__.py new file mode 100644 index 0000000..e7ee789 --- /dev/null +++ b/plugins/lsf/src/mml_lsf/__init__.py @@ -0,0 +1,8 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +VERSION = (0, 5, 1) +__version__ = ".".join(map(str, VERSION)) +__all__ = ["__version__"] diff --git a/plugins/lsf/src/mml_lsf/activate.py b/plugins/lsf/src/mml_lsf/activate.py new file mode 100644 index 0000000..8c39cb5 --- /dev/null +++ b/plugins/lsf/src/mml_lsf/activate.py @@ -0,0 +1,11 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from mml_lsf.workers import check_lsf_workers + +from mml.core.scripts.schedulers.base_scheduler import AFTER_SCHEDULER_INIT_HOOKS + +AFTER_SCHEDULER_INIT_HOOKS.append(check_lsf_workers) diff --git a/plugins/lsf/src/mml_lsf/requirements.py b/plugins/lsf/src/mml_lsf/requirements.py new file mode 100644 index 0000000..c8a5a4a --- /dev/null +++ b/plugins/lsf/src/mml_lsf/requirements.py @@ -0,0 +1,47 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import dataclasses +from typing import List, Optional + +from mml.interactive.planning import DefaultRequirements, JobPrefixRequirements + + +@dataclasses.dataclass +class LSFSubmissionRequirements(JobPrefixRequirements): + """ + If starting an MML run on an LSF cluster system, use these requirements. + """ + + num_gpus: int + vram_per_gpu: float # in GB + queue: str + special_requirements: List[str] = dataclasses.field(default_factory=list) + undesired_hosts: List[str] = dataclasses.field(default_factory=list) + mail: Optional[str] = None + interactive: bool = False + script_name: Optional[str] = None # if mml is called via a script use ./scriptname instead of mml CLI + job_group: Optional[str] = None + + def get_prefix(self) -> str: + parts = ["bsub"] + for itm in self.special_requirements: + parts.append(f'-R "{itm}"') + for itm in self.undesired_hosts: + parts.append(f"-R \"select[hname!='{itm}']\"") + parts.append(f"-gpu num={self.num_gpus}:j_exclusive=yes:gmem={self.vram_per_gpu:.1f}G") + parts.append(f"-q {self.queue}") + if self.mail: + parts.append(f'-u "{self.mail}" -B -N') + if self.interactive: + parts.append("-I") + if self.job_group: + parts.append(f"-g {self.job_group}") + if self.script_name: + parts.append(f"./{self.script_name}") + else: + parts.append(DefaultRequirements().get_prefix()) + return " ".join(parts) diff --git a/plugins/lsf/src/mml_lsf/runner.py b/plugins/lsf/src/mml_lsf/runner.py new file mode 100644 index 0000000..3805af5 --- /dev/null +++ b/plugins/lsf/src/mml_lsf/runner.py @@ -0,0 +1,305 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import copy +import getpass +import os +import subprocess +from collections import Counter +from typing import Any, Callable, Dict, List, Optional, Sequence, Set + +import pandas as pd + +from mml.core.scripts.decorators import timeout +from mml.interactive import MMLJobDescription +from mml.interactive.planning import JobRunner + + +class LSFJobRunner(JobRunner): + """ + A runner that submits jobs to the DKFZ LSF. Under the hood it uses "sshpass" to provide ssh with your password + (install via "sudp apt install sshpass"). Also supports interactive jobs via + `~mml_lsf.requirements.LSFSubmissionRequirements`. A single prompt during runner init allows for multiple jobs + being submitted without typing in password every time. + + To set everything up please read the mml_lsf README.md. Be aware that sshpass may be a potential security risk, + although this implementation tries to hide the password via anonymous piping. See "SECURITY CONSIDERATIONS" in + the manpage of "sshpass" for more details. + + Be also aware that sshpass execution will result in an endless loop if the ECDSA host key matching causes trouble. + Please make sure the corresponding fingerprints match in advance. + """ + + def __init__(self, user_name: Optional[str] = None, host: Optional[str] = None): + """ + Sets up the configuration for the runner. May rely either on env variables from "mml.env" or receive values + directly. + + :param Optional[str] user_name: AD username, if not provided, will try to read MML_AD_USER which should be set + in mml.env + :param Optional[str] host: LSF submission host name, if not provided, will try to read MML_CLUSTER_HOST which + should be set in mml.env + """ + # check input variables and try to load from environment + if user_name is None: + if not os.getenv("MML_AD_USER", None): + raise ValueError("Either provide user_name or environment variable MML_AD_USER must be set in mml.env") + user_name = os.getenv("MML_AD_USER") + self.user_name = user_name + if host is None: + if not os.getenv("MML_CLUSTER_HOST", None): + raise ValueError("Either provide user or environment variable MML_CLUSTER_HOST must be set in mml.env") + host = os.getenv("MML_CLUSTER_HOST") + self.host = host + # will store submitted jobs + self._cache: Dict[int, MMLJobDescription] = {} + # received job information + self._info: Optional[pd.DataFrame] = None + # read in password once + self.__pw = getpass.getpass("AD Password:") + # confirm settings and network availability + self._test_connection() + + @property + def all_projects(self) -> Set[str]: + """ + Lists all unique projects that have been run by this runner. May be used in combination with the retrieve + method. + """ + return set( + [job.config_options["proj"] if "proj" in job.config_options else "default" for job in self._cache.values()] + ) + + def _sshpass_execute(self, cmds: List[str], process_callback: Optional[Callable] = None) -> Any: + """ + Run the commands via sshpass. Ensure cmds are split as expected by subprocess.Popen. + + :param cmds: list of commands to execute, e.g. ["ssh", "USER@HOST", "ls"] + :param process_callback: a callback while the process is running, will receive the running process as single + arg and may return something that will be returned by this method in the end. If none, will print the output. + :return: whatever is returned by process_callback + """ + if process_callback is None: + + def process_callback(process) -> None: + # read in output + for line in iter(process.stdout.readline, ""): + print(line, end="") + + if "sshpass" in cmds: + raise ValueError("Do not provide sshpass in commands.") + if len(cmds) == 0: + raise ValueError("No commands provided.") + # set up pipe + rpipe, wpipe = os.pipe() + try: + os.set_inheritable(rpipe, True) + os.set_blocking(wpipe, False) + try: + # put password into pipe + os.write(wpipe, self.__pw.encode()) + finally: + # make sure to close pipe + os.close(wpipe) + # use sshpass and start process + process = subprocess.Popen( + ["sshpass"] + cmds, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=True, + stdin=rpipe, + ) + callback_output = process_callback(process) + process.stdout.close() + return_code = process.wait() + if return_code != 0: + # may be due to error in ssh connection, or failing command + raise RuntimeError("sshpass execution failed.") + finally: + # make sure to close pipe + os.close(rpipe) + return callback_output + + def _test_connection(self) -> None: + """ + Run a dummy command via sshpass. Raises an error in case connection is not established. + """ + + @timeout(seconds=15) + def test_impl(): + """Timeout wrapped connection test execution.""" + try: + self._sshpass_execute(["ssh", f"{self.user_name}@{self.host}", "pwd"]) + except RuntimeError: + raise RuntimeError( + f"SSH connection failed. Username: {self.user_name}, Host: {self.host}. You may " + f"want to re-instantiate the runner to exclude a typo while entering the password." + ) + + try: + test_impl() + except TimeoutError: + raise RuntimeError( + "Connection timed out. Is the submission host reachable? Also ECDSA host key matching " + "may causes trouble. Please make sure the corresponding fingerprints match in advance." + ) + + def run(self, job: MMLJobDescription): + """ + Submits a given MMLJob to the LSF Cluster. Caches the job and also catches the LSF JOB ID (for non-interactive + jobs). + + :param MMLJobDescription job: job to be submitted + :return: the LSF return message(s) are printed, no value is returned + """ + cmds = ["ssh", f"{self.user_name}@{self.host}", job.render()] + + def extract_job_id(process): + job_id = "0" # backup job id (e.g. interactive jobs) + # print job output + for line in iter(process.stdout.readline, ""): + # a successful submission is answered with a message + # Job is submitted to queue . + if line.startswith("Job <") and "> is submitted to queue" in line: + job_id = line[line.find("<") + 1 : line.find(">")] + print(line, end="") + return job_id + + job_id = self._sshpass_execute(cmds=cmds, process_callback=extract_job_id) + + # now cache submission + self._cache[int(job_id)] = copy.deepcopy(job) + + def info(self) -> pd.DataFrame: + """ + Ask LSF about the status of submitted jobs. Shows some info about them. Be aware that the runner will only show + infos on jobs submitted by itself! + + Side effects: prints some general summary information, updates the internal _info dataframe + + :return: a reduced dataframe of self._info with only relevant entries + """ + if len(self._cache) == 0: + print("No jobs cached so far.") + return pd.DataFrame() + print(f"{len(self._cache)} jobs submitted with this runner. Retrieving updates...") + + cmds = ["ssh", f"{self.user_name}@{self.host}", "bjobs", "-a"] + + def parse_jobs(process): + # read in job output + all_jobs = [] + for line in iter(process.stdout.readline, ""): + # the header should look like + # JOBID USER STAT QUEUE FROM_HOST EXEC_HOST JOB_NAME SUBMIT_TIME + if line.startswith("JOBID"): + # header line + continue + # parse through output + parts = line.split(" ") + entry = [] + for part in parts: + stripped = part.strip() + if len(stripped) == 0: + continue + entry.append(stripped) + if len(entry) == 6: + # we omit job name and submit time, they are harder to parse + break + candidate = { + "job_id": int(entry[0]), + "user": entry[1], + "status": entry[2], + "queue": entry[3], + "from": entry[4], + "exec": entry[5], + } + if candidate["status"] == "PEND": + candidate["exec"] = "" # since the string is empty parts of the job name mix in + all_jobs.append(candidate) + return all_jobs + + all_jobs = self._sshpass_execute(cmds=cmds, process_callback=parse_jobs) + # now store information + new_info = pd.DataFrame(all_jobs) + new_info.set_index("job_id", inplace=True) + if self._info is None: + self._info = new_info + else: + # add rows for new entries + self._info = self._info.reindex(new_info.index.union(self._info.index)) + # update + self._info.update(new_info) + # show feedback + no_info = [] + has_info = [] + for job_id in self._cache: + if job_id not in self._info.index: + no_info.append(job_id) + else: + has_info.append(job_id) + relevant_info = self._info.loc[has_info] + if len(no_info) > 0: + print(f"CAUTION: No job info for job IDs {no_info} ({len(no_info)} jobs in total).") + if "EXIT" in relevant_info["status"].to_list(): + print( + "CAUTION: There are failed jobs (marked as status EXIT). You might want to re-submit " + "(use the resubmit method)." + ) + for status, count in Counter(relevant_info["status"].to_list()).items(): + print(f" - {status}: {count} jobs") + return relevant_info[["status", "queue", "exec"]] + + def resubmit(self) -> None: + """ + Allows to automatically re-submit failed jobs. The internal job cache is updated. + + :return: no return value + """ + if self._info is None: + print("No job info so far. Please call info() methids first.") + return + failed_ids = [] + for job_id in self._cache: + if job_id in self._info.index and self._info.loc[job_id]["status"] == "EXIT": + failed_ids.append(job_id) + if len(failed_ids) == 0: + print("No failed jobs.") + return + print(f"{len(failed_ids)} jobs failed jobs found. Try resubmitting...") + for job_id in failed_ids: + self.run(self._cache[job_id]) + # if this was successful, we remove the old entry + self._cache.pop(job_id) + print("All previously failed jobs re-submitted.") + + def retrieve(self, project: str, excludes: Sequence[str] = ("PARAMETERS", "hpo", "runs")) -> None: + """ + Retrieve results from the LSF cluster for a given project. + + :param project: name of the project to synchronize + :param excludes: subfolders to be excluded, usually these comprise intermediates, log files or very large files + :return: no return value + """ + if " " in project or "/" in project: + raise ValueError("Invalid project name.") + # try to load env variables + if not os.getenv("MML_CLUSTER_WORKER", None): + raise ValueError("Environment variable MML_CLUSTER_WORKER must be set in mml.env") + worker = os.getenv("MML_CLUSTER_WORKER") + if not os.getenv("MML_CLUSTER_RESULTS_PATH", None): + raise ValueError("Environment variable MML_CLUSTER_RESULTS_PATH must be set in mml.env") + cluster_path = os.getenv("MML_CLUSTER_RESULTS_PATH") + if not os.getenv("MML_RESULTS_PATH", None): + raise ValueError("Environment variable MML_RESULTS_PATH must be set in mml.env") + local_path = os.getenv("MML_RESULTS_PATH") + # build bash string + cmds = ["rsync", "-rtvu", "--stats"] + for dir in excludes: + cmds.append(f"--exclude={dir}") + cmds.append(f"{self.user_name}@{worker}:{cluster_path}/{project}/") + cmds.append(f"{local_path}/{project}") + print(f'Executing {" ".join(cmds)}') + self._sshpass_execute(cmds=cmds) diff --git a/plugins/lsf/src/mml_lsf/workers.py b/plugins/lsf/src/mml_lsf/workers.py new file mode 100644 index 0000000..9227671 --- /dev/null +++ b/plugins/lsf/src/mml_lsf/workers.py @@ -0,0 +1,80 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import os +import socket + +from hydra.core.hydra_config import HydraConfig +from omegaconf import OmegaConf + +from mml.core.scripts.schedulers.base_scheduler import AbstractBaseScheduler + +logger = logging.getLogger(__name__) + + +def get_allowed_n_proc(): + """ + Taken from: https://github.com/MIC-DKFZ/nnUNet/blob/master/nnunetv2/utilities/default_n_proc_DA.py + + This function is used to find the max number of processes allowed on different Systems. It is specific to + our cluster infrastructure at DKFZ. + + Interpret the output as the number of processes used for data augmentation PER GPU. + The way it is implemented here is simply a look-up table. We know the hostnames, CPU and GPU configurations of our + systems and set the numbers accordingly. For example, a system with 4 GPUs and 48 threads can use 12 threads per + GPU without overloading the CPU (technically 11 because we have a main process as well), so that's what we use. + """ + hostname = socket.gethostname() + logger.info(f"Hostname: {hostname}.") + if hostname in ["hdf19-gpu16", "hdf19-gpu17", "hdf19-gpu18", "hdf19-gpu19", "e230-AMDworkstation"]: + use_this = 16 + elif hostname.startswith("e230-dgx1"): + use_this = 10 + elif hostname.startswith("hdf18-gpu") or hostname.startswith("e132-comp"): + use_this = 16 + elif hostname.startswith("e230-dgx2"): + use_this = 6 + elif hostname.startswith("e230-dgxa100-"): + use_this = 28 + elif hostname.startswith("lsf22-gpu"): + use_this = 28 + elif hostname.startswith("hdf19-gpu") or hostname.startswith("e071-gpu"): + use_this = 12 + else: + use_this = 12 # default value + + use_this = min(use_this, os.cpu_count()) + return use_this + + +def check_lsf_workers(scheduler: AbstractBaseScheduler) -> None: + """ + Looks up the available workers for DKF LSF cluster nodes and sets accordingly. + + :param scheduler: the scheduler the hook runs upon + :return: + """ + # check if preprocessing id is set correctly (only necessary if started via hydra) + try: + hydra_cfg = HydraConfig.get() + except ValueError: + hydra_cfg = None + if hydra_cfg: + choices = OmegaConf.to_container(hydra_cfg.runtime.choices) + # if any(part.startswith('num_workers=') for part in hydra_cfg.overrides.task): + # logger.info('LSF cluster plugin detected CLI override for num_workers.') + if choices["sys"] == "local": + logger.info("LSF cluster plugin detected local system, no changes made to the number of workers.") + return + logger.info(f'LSF cluster plugin detected system: {choices["sys"]}.') + configured = scheduler.cfg.num_workers + allowed = get_allowed_n_proc() + if configured > allowed: + scheduler.cfg.num_workers = allowed + logger.info(f"LSF cluster plugin set CPU workers to {allowed} (previously: {configured}).") + else: + logger.info(f"No need to update CPU workers. Will stick to {configured}.") diff --git a/plugins/lsf/tests/conftest.py b/plugins/lsf/tests/conftest.py new file mode 100644 index 0000000..b3c6299 --- /dev/null +++ b/plugins/lsf/tests/conftest.py @@ -0,0 +1,14 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import pytest + + +# by default the fixture below overrides the no_plugins fixture from mml.testing.fixtures to allow plugin testing +# you may remove this deactivation, put it into another submodule conftest.py and/or use the "plugin" marker to +# deactivate plugin loading solely for specific tests +@pytest.fixture(autouse=True) +def no_plugins(monkeypatch, request): + yield diff --git a/plugins/lsf/tests/unit/test_dummy.py b/plugins/lsf/tests/unit/test_dummy.py new file mode 100644 index 0000000..6259249 --- /dev/null +++ b/plugins/lsf/tests/unit/test_dummy.py @@ -0,0 +1,9 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + + +def test_dummy(): + pass diff --git a/plugins/similarity/CHANGELOG.md b/plugins/similarity/CHANGELOG.md new file mode 100644 index 0000000..ba43fb2 --- /dev/null +++ b/plugins/similarity/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog + +All notable changes to this plugin will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.5.2 (12/19/2024): +Public release version. + +## 0.5.1 (11/15/2024): +Minor patch to reflect the removal of the `plotting` config group in `mml-core` + +## 0.5.0 (08/29/2024): +This release comprises a major refactoring of the similarity plugin to allow more increasing knowledge style, better +reusability and a focus on the pivot task. + +### Features + - automatic reuse of existing `features` and `fim` + - non necessarily predict all (n x n) distances but allow (1 x n) calculations by setting a pivot task + - easier inheriting of abstract task distance scheduler by implementing a default distance routine diff --git a/plugins/similarity/LICENSE.txt b/plugins/similarity/LICENSE.txt new file mode 100644 index 0000000..6a39552 --- /dev/null +++ b/plugins/similarity/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 German Cancer Research Center (DKFZ) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/plugins/similarity/MANIFEST.in b/plugins/similarity/MANIFEST.in new file mode 100644 index 0000000..c8d5949 --- /dev/null +++ b/plugins/similarity/MANIFEST.in @@ -0,0 +1 @@ +recursive-include src/mml_similarity/configs *.yaml \ No newline at end of file diff --git a/plugins/similarity/README.md b/plugins/similarity/README.md new file mode 100644 index 0000000..550ff19 --- /dev/null +++ b/plugins/similarity/README.md @@ -0,0 +1,20 @@ +# MML task similarity plugin + +This plugin provides a wide range of modes to compute task similarities. + +# Install + +```commandline +pip install mml-similarity +``` + +# Usage + +The new mode `similarity` offers to compute task distances. For example to compute the `Fisher embedding distance` +call + +```commandline +mml similarity distance=fed ... +``` + +Task distances can be leveraged by other plugins - e.g. `mml-suggest`. \ No newline at end of file diff --git a/plugins/similarity/pyproject.toml b/plugins/similarity/pyproject.toml new file mode 100644 index 0000000..449c6a9 --- /dev/null +++ b/plugins/similarity/pyproject.toml @@ -0,0 +1,52 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +[build-system] +requires = [ + "setuptools>=42", + "wheel", +] +build-backend = "setuptools.build_meta" + +[tool.pytest.ini_options] +addopts = "--strict-markers --benchmark-skip" +testpaths = [ + "tests", +] +markers = [ + "slow: marks tests as slow (deselect with '-m \"not slow\"')", + "gpu: marks tests as requiring a gpu to run", + "env: marks test that require the correct underlying mml.env file", + "plugin: marks tests that require the loading of plugins", + "serial", +] + +[tool.isort] +src_paths = ["src", "tests"] +profile = "black" +line_length = 120 + +[tool.mypy] +mypy_path = "src" +check_untyped_defs = true +disallow_any_generics = true +ignore_missing_imports = true +no_implicit_optional = true +show_error_codes = true +strict_equality = true +warn_redundant_casts = true +warn_return_any = true +warn_unreachable = true +warn_unused_configs = true +no_implicit_reexport = true +disallow_untyped_defs = true +warn_unused_ignores = true +allow_redefinition = true +warn_no_return = true + +[tool.ruff] +# Set the maximum line length +line-length = 120 \ No newline at end of file diff --git a/plugins/similarity/setup.cfg b/plugins/similarity/setup.cfg new file mode 100644 index 0000000..ff93bac --- /dev/null +++ b/plugins/similarity/setup.cfg @@ -0,0 +1,50 @@ +[metadata] +name = mml-similarity +version = attr: mml_similarity.__version__ +description = This is the MML similarity plugin, providing modes to compute task similarities. +long_description = file: README.md +long_description_content_type = text/markdown +author = Patrick Godau +author_email = patrick.godau@dkfz-heidelberg.de +license = MIT +url = https://git.dkfz.de/imsy/ise/mml +classifiers = + Natural Language :: English + Development Status :: 4 - Beta + Environment :: Console + Intended Audience :: Developers + Topic :: Scientific/Engineering :: Artificial Intelligence + Topic :: Scientific/Engineering :: Image Recognition + Topic :: Scientific/Engineering :: Information Analysis + Topic :: Scientific/Engineering :: Image Processing + Topic :: Software Development :: Libraries :: Application Frameworks + Topic :: Software Development :: Version Control :: Git + Operating System :: OS Independent + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Environment :: GPU + Intended Audience :: Science/Research + Typing :: Typed + License :: OSI Approved :: MIT License + +[options] +python_requires = >=3.8 +package_dir = + =src +packages = find: +zip_safe = no +include_package_data = True +install_requires = + mml-core>=1.0.0 + nngeometry @ git+https://github.com/tfjgeorge/nngeometry.git#egg=nngeometry + geomloss + opentsne + +[options.entry_points] +mml.plugins = + mml-similarity = mml_similarity.activate + +[options.packages.find] +where=src diff --git a/plugins/similarity/src/mml_similarity/__init__.py b/plugins/similarity/src/mml_similarity/__init__.py new file mode 100644 index 0000000..d36d139 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/__init__.py @@ -0,0 +1,9 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +VERSION = (0, 5, 2) +__version__ = ".".join(map(str, VERSION)) +__all__ = ["__version__"] diff --git a/plugins/similarity/src/mml_similarity/activate.py b/plugins/similarity/src/mml_similarity/activate.py new file mode 100644 index 0000000..9a82d65 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/activate.py @@ -0,0 +1,67 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +import numpy as np +import pandas as pd +import torch +from hydra.core.config_search_path import ConfigSearchPath +from hydra.core.plugins import Plugins +from hydra.plugins.search_path_plugin import SearchPathPlugin +from mml_similarity.scripts.sample_based_scheduler import SAMPLE_BASED_MODES + +from mml.core.data_loading.file_manager import MMLFileManager + +# set distance file and plotting file for all distance measures +for measure in ["fed", "ens", "semantic"] + SAMPLE_BASED_MODES: + MMLFileManager.add_assignment_path( + obj_cls=pd.DataFrame, + key=measure, + path=Path("PROJ_PATH") / "DISTANCES" / measure / "distances.csv", + enable_numbering=False, + reusable=MMLFileManager.GLOBAL_REUSABLE, + ) + MMLFileManager.add_assignment_path( + obj_cls=None, + key=f"2D_{measure}", + path=Path("PROJ_PATH") / "PLOTS" / "task_space" / f"graph-{measure}.png", + enable_numbering=True, + ) + +# the fed method requires to store fim and models tuned on the fc +MMLFileManager.add_assignment_path( + obj_cls=dict, + key="fim", + path=Path("PROJ_PATH") / "FIMS" / "TASK_NAME" / "fim.pkl", + enable_numbering=True, + reusable=True, +) +MMLFileManager.add_assignment_path( + obj_cls=torch.nn.Module, + key="fc_tuned", + path=Path("PROJ_PATH") / "FC_TUNED" / "TASK_NAME" / "fc_tuned.pth", + enable_numbering=True, + reusable=True, +) +# sample based methods require to extract features +MMLFileManager.add_assignment_path( + obj_cls=np.ndarray, + key="features", + path=Path("PROJ_PATH") / "FEATURES" / "TASK_NAME" / "features.npy", + enable_numbering=True, + reusable=True, +) + + +# register plugin configs +class MMLSimilaritySearchPathPlugin(SearchPathPlugin): + def manipulate_search_path(self, search_path: ConfigSearchPath) -> None: + # Sets the search path for mml with copied config files + search_path.append(provider="mml-similarity", path="pkg://mml_similarity.configs") + + +Plugins.instance().register(MMLSimilaritySearchPathPlugin) diff --git a/plugins/similarity/src/mml_similarity/configs/__init__.py b/plugins/similarity/src/mml_similarity/configs/__init__.py new file mode 100644 index 0000000..90ffb6c --- /dev/null +++ b/plugins/similarity/src/mml_similarity/configs/__init__.py @@ -0,0 +1,6 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + diff --git a/plugins/similarity/src/mml_similarity/configs/distance/emd.yaml b/plugins/similarity/src/mml_similarity/configs/distance/emd.yaml new file mode 100644 index 0000000..b032146 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/configs/distance/emd.yaml @@ -0,0 +1,21 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +distance: + name: emd + method: 'default' # either default, binned (uses bins) or sinkhorn (uses an interpolation mode + n_bins: 1000 # number of bins for the binned method + # _mode will be loaded from similarity mode and ignored otherwise, no need to modify directly + _mode: + scheduler: + _target_: mml_similarity.scripts.sample_based_scheduler.SampleBasedScheduler + subroutines: + - feature + - distance +arch: + pretrained: True \ No newline at end of file diff --git a/plugins/similarity/src/mml_similarity/configs/distance/ens.yaml b/plugins/similarity/src/mml_similarity/configs/distance/ens.yaml new file mode 100644 index 0000000..560a53c --- /dev/null +++ b/plugins/similarity/src/mml_similarity/configs/distance/ens.yaml @@ -0,0 +1,19 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +distance: + name: ens + sources: [ ] # requires a list of ensemble sources, e.g. [fed,mmd,fid], may be from other projects (reuse.fed=...) + weights: null # weigh different sources if null makes all sources weighted equally + normalize: True # if true tries to bring each source distance to the same value range before applying weights + # _mode will be loaded from similarity mode and ignored otherwise, no need to modify directly + _mode: + scheduler: + _target_: mml_similarity.scripts.ensemble_scheduler.EnsembleDistancesScheduler + subroutines: + - distance \ No newline at end of file diff --git a/plugins/similarity/src/mml_similarity/configs/distance/fed.yaml b/plugins/similarity/src/mml_similarity/configs/distance/fed.yaml new file mode 100644 index 0000000..b42759e --- /dev/null +++ b/plugins/similarity/src/mml_similarity/configs/distance/fed.yaml @@ -0,0 +1,33 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +distance: + name: fed + fim: + samples: 600 + empirical: False + ignore_bias: True + ignore_downsample: True + ignore_bn: False # added recently, defaults to previous behaviour + average_filters: True + final_fraction: 0.6 + nngeom: true + metric: cosine # cosine, euclidean, jensenshannon + prefix: '' + # _mode will be loaded from similarity mode and ignored otherwise, no need to modify directly + _mode: + scheduler: + _target_: mml_similarity.scripts.fed_scheduler.FEDScheduler + subroutines: + - tune + - fim + - distance +trainer: + min_epochs: 1 + max_epochs: 1 + check_val_every_n_epoch: 5 \ No newline at end of file diff --git a/plugins/similarity/src/mml_similarity/configs/distance/fid.yaml b/plugins/similarity/src/mml_similarity/configs/distance/fid.yaml new file mode 100644 index 0000000..bda6660 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/configs/distance/fid.yaml @@ -0,0 +1,20 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +distance: + name: fid + eps: 1e-6 + # _mode will be loaded from similarity mode and ignored otherwise, no need to modify directly + _mode: + scheduler: + _target_: mml_similarity.scripts.sample_based_scheduler.SampleBasedScheduler + subroutines: + - feature + - distance +arch: + pretrained: True \ No newline at end of file diff --git a/plugins/similarity/src/mml_similarity/configs/distance/kld.yaml b/plugins/similarity/src/mml_similarity/configs/distance/kld.yaml new file mode 100644 index 0000000..482a0cb --- /dev/null +++ b/plugins/similarity/src/mml_similarity/configs/distance/kld.yaml @@ -0,0 +1,17 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +distance: + name: kld + # _mode will be loaded from similarity mode and ignored otherwise, no need to modify directly + _mode: + scheduler: + _target_: mml_similarity.scripts.sample_based_scheduler.SampleBasedScheduler + subroutines: + - feature + - distance \ No newline at end of file diff --git a/plugins/similarity/src/mml_similarity/configs/distance/mmd.yaml b/plugins/similarity/src/mml_similarity/configs/distance/mmd.yaml new file mode 100644 index 0000000..97b6676 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/configs/distance/mmd.yaml @@ -0,0 +1,23 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +distance: + name: mmd + kernel: cauchy #["cauchy", "energy", "gaussian", "laplacian"] + blur: 0.05 + allow_gpu: ${allow_gpu} + chunk_size: 5000 + # _mode will be loaded from similarity mode and ignored otherwise, no need to modify directly + _mode: + scheduler: + _target_: mml_similarity.scripts.sample_based_scheduler.SampleBasedScheduler + subroutines: + - feature + - distance +arch: + pretrained: True \ No newline at end of file diff --git a/plugins/similarity/src/mml_similarity/configs/distance/semantic.yaml b/plugins/similarity/src/mml_similarity/configs/distance/semantic.yaml new file mode 100644 index 0000000..92081c0 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/configs/distance/semantic.yaml @@ -0,0 +1,16 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +distance: + name: semantic + # _mode will be loaded from similarity mode and ignored otherwise, no need to modify directly + _mode: + scheduler: + _target_: mml_similarity.scripts.semantic_scheduler.SemanticScheduler + subroutines: + - distance \ No newline at end of file diff --git a/plugins/similarity/src/mml_similarity/configs/mode/similarity.yaml b/plugins/similarity/src/mml_similarity/configs/mode/similarity.yaml new file mode 100644 index 0000000..87ec3ea --- /dev/null +++ b/plugins/similarity/src/mml_similarity/configs/mode/similarity.yaml @@ -0,0 +1,15 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - _self_ + - /distance: semantic + - /plotting: distance # use similarity plotting settings + - override /sampling: extraction_default + +mode: ${distance._mode} # pull up the config from distance._mode to top level config.mode (scheduler and subroutines) diff --git a/plugins/similarity/src/mml_similarity/configs/plotting/distance.yaml b/plugins/similarity/src/mml_similarity/configs/plotting/distance.yaml new file mode 100644 index 0000000..85b0ac6 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/configs/plotting/distance.yaml @@ -0,0 +1,25 @@ +#@package plotting + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +distance: + # generic part + # kamada or tsne + kamada_kawai: True + legend_size: 20 # <= 0 deactivates legend # colorization by... + criteria: null # maybe either null, medical, task_type, target or domain + node_size: 700 + # kamada kawai specific options + label_nodes: True + color_nodes: True + color_map: 'jet' # also 'hsv' + plot_edges: True + label_edges: True + edge_thresh: 0.65 # 0 for no edges, -1 for all edges, + # tsne specific options + draw_centers: False + draw_cluster_labels: False diff --git a/plugins/similarity/src/mml_similarity/configs/plotting/kam.yaml b/plugins/similarity/src/mml_similarity/configs/plotting/kam.yaml new file mode 100644 index 0000000..e3a8263 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/configs/plotting/kam.yaml @@ -0,0 +1,25 @@ +#@package plotting + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +distance: + # generic part + # kamada or tsne + kamada_kawai: True + legend_size: 20 # <= 0 deactivates legend # colorization by... + criteria: null # maybe either null, medical, task_type, target or domain + node_size: 700 + # kamada kawai specific options + label_nodes: False + color_nodes: True + color_map: 'jet' # also 'hsv' + plot_edges: True + label_edges: False + edge_thresh: 0.65 # 0 for no edges, -1 for all edges, + # tsne specific options + draw_centers: False + draw_cluster_labels: False \ No newline at end of file diff --git a/plugins/similarity/src/mml_similarity/configs/plotting/tsne.yaml b/plugins/similarity/src/mml_similarity/configs/plotting/tsne.yaml new file mode 100644 index 0000000..245cc39 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/configs/plotting/tsne.yaml @@ -0,0 +1,25 @@ +#@package plotting + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +distance: + # generic part + # kamada or tsne + kamada_kawai: False + legend_size: 10 # <= 0 deactivates legend # colorization by... + criteria: null # maybe either null, medical, task_type, target or domain + node_size: 48 + # kamada kawai specific options + label_nodes: False + color_nodes: True + color_map: 'jet' # also 'hsv' + plot_edges: True + label_edges: False + edge_thresh: 0.65 # 0 for no edges, -1 for all edges, + # tsne specific options + draw_centers: False + draw_cluster_labels: False \ No newline at end of file diff --git a/plugins/similarity/src/mml_similarity/configs/sampling/extraction_default.yaml b/plugins/similarity/src/mml_similarity/configs/sampling/extraction_default.yaml new file mode 100644 index 0000000..fc655d8 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/configs/sampling/extraction_default.yaml @@ -0,0 +1,18 @@ +#@package sampling + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +sample_num: 10000 +balanced: false +# batch size will be overwritten if trainer uses auto_batch_size +batch_size: 100 +# whether the final batch will be dropped at the end of the epoch if it has less than batch_size samples +drop_last: False +# enable caching of small datasets into RAM, this only works for already preprocessed datasets! +enable_caching: False +# sets a max_size of cache (in terms of images), avoid exploding RAM by keeping low +cache_max_size: 800 \ No newline at end of file diff --git a/plugins/similarity/src/mml_similarity/configs/sampling/extraction_minimal.yaml b/plugins/similarity/src/mml_similarity/configs/sampling/extraction_minimal.yaml new file mode 100644 index 0000000..9876fb3 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/configs/sampling/extraction_minimal.yaml @@ -0,0 +1,18 @@ +# @package sampling + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +sample_num: 200 +balanced: True +# do not use tune.batch_size +batch_size: 100 +# whether the final batch will be dropped at the end of the epoch if it has less than batch_size samples +drop_last: False +# enable caching of small datasets into RAM, this only works for already preprocessed datasets! +enable_caching: False +# sets a max_size of cache (in terms of images), avoid exploding RAM by keeping low +cache_max_size: 800 \ No newline at end of file diff --git a/plugins/similarity/src/mml_similarity/configs/search_space/fed_search.yaml b/plugins/similarity/src/mml_similarity/configs/search_space/fed_search.yaml new file mode 100644 index 0000000..432f2ab --- /dev/null +++ b/plugins/similarity/src/mml_similarity/configs/search_space/fed_search.yaml @@ -0,0 +1,16 @@ +# @package search_space + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# define range of hyperparameters for fed computation +sampling.sample_num: int(interval(5000, 15000)) +sampling.balanced: choice(true, false) +distance.fim.samples: int(interval(500, 2000)) +distance.fim.ignore_bias: choice(true, false) +distance.fim.ignore_downsample: choice(true, false) +distance.fim.average_filters: choice(true, false) +distance.fim.final_fraction: interval(0.2, 1.0) \ No newline at end of file diff --git a/plugins/similarity/src/mml_similarity/configs/search_space/mmd_search.yaml b/plugins/similarity/src/mml_similarity/configs/search_space/mmd_search.yaml new file mode 100644 index 0000000..2a90a72 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/configs/search_space/mmd_search.yaml @@ -0,0 +1,13 @@ +# @package search_space + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# define range of hyperparameters for mmd computation +sampling.sample_num: range(5000,15000) +sampling.balanced: choice(true, false) +distance.kernel: choice("cauchy", "energy", "gaussian", "laplacian") +distance.blur: interval(0.0, 1.0) \ No newline at end of file diff --git a/plugins/similarity/src/mml_similarity/scripts/__init__.py b/plugins/similarity/src/mml_similarity/scripts/__init__.py new file mode 100644 index 0000000..4b95ae5 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/scripts/__init__.py @@ -0,0 +1,8 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# automatically activate plugin when importing +import mml_similarity.activate # noqa diff --git a/plugins/similarity/src/mml_similarity/scripts/abstract_task_distance_scheduler.py b/plugins/similarity/src/mml_similarity/scripts/abstract_task_distance_scheduler.py new file mode 100644 index 0000000..6465b48 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/scripts/abstract_task_distance_scheduler.py @@ -0,0 +1,217 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import shutil +import warnings +from abc import ABC, abstractmethod +from collections import defaultdict +from itertools import combinations +from typing import List + +import numpy as np +import pandas as pd +from mml_similarity.visualization.plot_2D import plot_task_embedding +from omegaconf import DictConfig + +from mml.core.scripts.schedulers.base_scheduler import AbstractBaseScheduler +from mml.core.scripts.utils import TAG_SEP + +logger = logging.getLogger(__name__) + + +class AbstractTaskDistanceScheduler(AbstractBaseScheduler, ABC): + def __init__(self, cfg: DictConfig, available_subroutines: List[str]): + assert "distance" in available_subroutines + self.distance_measure = cfg.distance.name + super(AbstractTaskDistanceScheduler, self).__init__( + cfg=cfg, available_subroutines=available_subroutines + ["plot"] + ) + self.distance_file = self.fm.construct_saving_path(obj=pd.DataFrame(), key=self.distance_measure) + + def load_distances(self) -> pd.DataFrame: + """ + Convenience function to load distance file. + + :return: dataframe of distances + """ + assert self.distance_file.exists(), "Distance file not found!" + df = pd.read_csv(self.distance_file, index_col=0) + return df + + def create_default_distances_routine(self) -> None: + """ + To be leveraged in any inheriting scheduler to add all necessary distance computation commands. Simply implement + :meth:`compute_distance_impl` in the inheriting scheduler and call :meth:`create_default_distances_routine` as + part of :meth:`create_routine` when the `distance` subroutine may be translated to commands. + """ + # -- add distance computation commands + if "distance" in self.subroutines: + # pivot case - only compute cases involving transferring to pivot task + if self.pivot: + for source in self.cfg.task_list: + self.commands.append(self._compute_distance) + self.params.append([source, self.pivot]) + # non pivot variant of a symmetric distance, simplify to necessary computations + elif self.is_sym_distance(): + for source, target in combinations(self.cfg.task_list, 2): + self.commands.append(self._compute_distance) + self.params.append([source, target]) + # non pivot and non symmetric distance, need to add all possible computations + else: + for source in self.cfg.task_list: + for target in self.cfg.task_list: + self.commands.append(self._compute_distance) + self.params.append([source, target]) + + def _compute_distance(self, source: str, target: str) -> None: + """ + Method of AbstractTaskDistanceScheduler that will wrap :meth:`compute_distance_impl`. No need to manipulate + in downstream schedulers. If the scaffold provided does not suit, simply do not call + :meth:`create_default_distances_routine`. + + :param str source: source task name + :param str target: target task name + :return: None, will save the result of :meth:`compute_distance_impl` in the internal data frame + """ + logger.info( + "Starting distance computation for tasks " + + self.highlight_text(source) + + " -> " + + self.highlight_text(target) + ) + distance = self.compute_distance_impl(source_task_name=source, target_task_name=target) + # saving of distance + df = self.load_distances() + # x = row (=index) and y = column within dataframe represent distance from x to y + df.at[source, target] = distance + df.to_csv(self.distance_file) + logger.info( + "Successfully finished distance computation for tasks " + + self.highlight_text(source) + + " -> " + + self.highlight_text(target) + ) + + def compute_distance_impl(self, source_task_name: str, target_task_name: str) -> float: + """ + Computes the distance between two tasks. To be implemented in downstream scheduler. + + :param source_task_name: name of the source task + :param target_task_name: name of the target task + :return: float value to represent the distance between two tasks + """ + raise NotImplementedError( + 'If using "create_default_distances_routine" you must implement ' + '"compute_distance_impl" - do not manipulate the wrapper "_compute_distance"!' + ) + + def after_preparation_hook(self) -> None: + # load results file + if "distance" in self.subroutines: + # if in continue mode, the files may already exist with some results, so load and check + if self.continue_status: + # check if file matches experiment setting + df = self.load_distances() + logger.info( + f"Found existing results file and will continue using it! {sum(list(df.count()))} " + f"out of {df.shape[0] * df.shape[1]} entries already present." + ) + else: + if self.distance_file.exists(): + backup_path = self.fm.construct_saving_path( + obj=None, key="backup", file_name=self.distance_file.name + ) + shutil.copyfile(self.distance_file, backup_path) + warnings.warn( + f"Found existing distance file (type {self.distance_measure}). These are not " + f"versioned, but will be extended / overridden with repeated mml runs. The updated " + f"file is at {self.distance_file}, for your convenience a backup is stored at " + f"{backup_path}." + ) + else: + # first run for this distance measure in this project - create and save an empty frame + df = pd.DataFrame() + df.to_csv(self.distance_file) + + def before_finishing_hook(self) -> None: + if "distance" in self.subroutines: + # if skipped before in symmetric distance case, now fill the missing entries in result file + if self.is_sym_distance(): + logger.info("Filling in symmetric results in results dataframe.") + df = self.load_distances() + # adding indirectly given distances for symmetric case + for source in df.index: + for target in df.columns: + # x = row (=index) and y = column within dataframe represent distance from x to y + if source == target: + df.at[source, target] = 0.0 + elif not df.isna().at[source, target]: + df.at[target, source] = df.at[source, target] + elif not df.isna().at[target, source]: + df.at[source, target] = df.at[target, source] + # saving + df.to_csv(self.distance_file) + logger.info(f"Computed all distances. Results of may be found at: {self.distance_file}.") + if "plot" in self.subroutines: + # if chosen in the configs do a final plotting + plot_task_embedding( + distances=self.load_distances(), + structs=self.task_factory.container, + plot_config=self.cfg.plotting.distance, + distance_key=self.distance_measure, + ) + # determine return value that can be used for optimization, only available if no pivot was used + if "distance" in self.subroutines and not self.pivot: + # find identity, duplicates , subsets variants of tasks + task_groups = defaultdict(list) + for task in self.cfg.task_list: + if any( + [ + mod_string in task + for mod_string in [TAG_SEP + "identity", TAG_SEP + "duplicate", TAG_SEP + "subset"] + ] + ): + base_name = task[: task.find(TAG_SEP)] + else: + base_name = task + task_groups[base_name].append(task) + # check if there are actual groups for optimization + if all([len(group) == 1 for group in task_groups.values()]): + # no groups return a "bad" value + logger.debug("No task grouping detected, this prohibits optimizing upon task similarity.") + self.return_value = 1.0 + else: + # calculate mean distances within each group + intra_group_distances = {} + df = self.load_distances() + for base_name in task_groups: + group = task_groups[base_name] + if len(group) == 1: + continue + intra_group_distances[base_name] = [] + for task_1, task_2 in combinations(group, 2): + intra_group_distances[base_name].append(df.at[task_1, task_2]) + intra_group_distances[base_name].append(df.at[task_2, task_1]) + group_means = { + base_name: np.mean(intra_group_distances[base_name]) for base_name in intra_group_distances + } + logger.debug( + f"Detected {len(group_means)} task groups that comprise: " + f"{[task_groups[base_name] for base_name in group_means]}." + ) + # return value will be average group mean (should be small) divided by overall mean (should be high) + overall_mean = df.mask(np.eye(len(df.index), dtype=bool)).replace([np.inf], np.nan).mean().mean() + self.return_value = np.mean(list(group_means.values())) / overall_mean + + @abstractmethod + def is_sym_distance(self) -> bool: + """ + Helper function used to identify if distances have to be calculated in both directions. + + :return: (bool) True is indicating symmetric behaviour + """ + pass diff --git a/plugins/similarity/src/mml_similarity/scripts/ensemble_scheduler.py b/plugins/similarity/src/mml_similarity/scripts/ensemble_scheduler.py new file mode 100644 index 0000000..973b3c2 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/scripts/ensemble_scheduler.py @@ -0,0 +1,84 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +from typing import Dict + +import pandas as pd +import scipy +from mml_similarity.scripts.abstract_task_distance_scheduler import AbstractTaskDistanceScheduler +from omegaconf import DictConfig + +from mml.core.scripts.exceptions import MMLMisconfigurationException + +logger = logging.getLogger(__name__) + + +class EnsembleDistancesScheduler(AbstractTaskDistanceScheduler): + """ + AbstractBaseScheduler implementation for the ensembling of task similarities setup. Includes the following + subroutines: + - distance + + Not to be confused with the ensembling of models by the PostProcessingScheduler! + """ + + def __init__(self, cfg: DictConfig): + # initialize + super(EnsembleDistancesScheduler, self).__init__(cfg=cfg, available_subroutines=["distance"]) + self.source_distances: Dict[str, pd.DataFrame] = {} + # load distances + for dist in self.cfg.distance.sources: + if dist not in self.fm.global_reusables: + raise MMLMisconfigurationException( + f"Did not find {dist} in reusables. Make sure to set reuse.{dist} " f"accordingly." + ) + df = pd.read_csv(self.fm.global_reusables[dist], index_col=0) + if self.cfg.distance.normalize: + _data = scipy.stats.zscore(df.to_numpy().astype(float), axis=None, nan_policy="omit") + df = pd.DataFrame(_data, columns=df.columns, index=df.index) + self.source_distances[dist] = df + if len(self.source_distances) < 2: + raise MMLMisconfigurationException("At least two source distances are required to merge.") + # set weights accordingly + if self.cfg.distance.weights is None: + # no weights given, weigh equally + self.weights = [1.0] * len(self.source_distances) + else: + self.weights = self.cfg.distance.weights + if len(self.weights) != len(self.source_distances): + raise MMLMisconfigurationException("Lengths of weights and source distances does not match!") + if any(not isinstance(w, float) for w in self.weights): + raise MMLMisconfigurationException("Weights must all be floats!") + if any(w <= 0.0 for w in self.weights): + raise MMLMisconfigurationException("Non-positive weights are likely a typo!") + + def create_routine(self) -> None: + """ + This scheduler implements only a single subroutine that will be called once. + + :return: None + """ + # -- there is only a single command + self.create_default_distances_routine() + + def compute_distance_impl(self, source_task_name: str, target_task_name: str) -> float: + running_sum = 0.0 + for weight, (dist, df) in zip(self.weights, self.source_distances.items()): + try: + if df.isna().at[source_task_name, target_task_name]: + raise KeyError + val = df.at[source_task_name, target_task_name] + except KeyError: + raise RuntimeError( + f"Distance {source_task_name} -> {target_task_name} not yet computed for " f"distance {dist}." + ) + running_sum += weight * val + return running_sum + + def is_sym_distance(self) -> bool: + # may be incorrect depending on sources + return False diff --git a/plugins/similarity/src/mml_similarity/scripts/feature_distances.py b/plugins/similarity/src/mml_similarity/scripts/feature_distances.py new file mode 100644 index 0000000..9f4e7e3 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/scripts/feature_distances.py @@ -0,0 +1,232 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging + +import numpy as np +import scipy.linalg +import torch + +from mml.core.data_loading.task_attributes import Modality + +try: + from geomloss import SamplesLoss + + _GEOMLOSS_AVAILABLE = True +except ImportError: + SamplesLoss = None + _GEOMLOSS_AVAILABLE = False +from omegaconf import DictConfig +from scipy.stats import entropy, wasserstein_distance +from tqdm import tqdm + +from mml.core.data_loading.lightning_datamodule import MultiTaskDataModule +from mml.core.models.lightning_single_frame import SingleFrameLightningModule + +logger = logging.getLogger(__name__) + + +def sample_features( + model: SingleFrameLightningModule, datamodule: MultiTaskDataModule, device: torch.device = torch.device("cpu") +) -> np.ndarray: + """ + Uses the model as feature extractor and returns sampled features of the datamodule in a numpy array. + + :param SingleFrameLightningModule model: model to extract features from raw samples + :param MultiTaskDataModule datamodule: datamodule to sample images from + :param torch.device device: device to perform the extraction (cpu recommended) + :return: numpy array of features, should be 2-dimensional with shape [sample_num, num_features] + """ + if len(model.task_structs) != 1: + raise RuntimeError("For backward compatibility only single headed models are supported so far.") + task = list(model.task_structs.keys())[0] + model = model.to(device).eval() + features_list = [] + for batch, batch_idx, dataloader_idx in tqdm(iter(datamodule.train_dataloader())): + batch_images = batch[task][Modality.IMAGE.value].to(device) + features = model.forward_features(batch_images).detach().cpu().numpy() + # add features to list + features_list.append(features) + return np.concatenate(features_list, axis=0) + + +def compute_feature_distance( + features_1: np.ndarray, features_2: np.ndarray, distance_cfg: DictConfig, mode_id: str +) -> float: + """ + Wrapper function for all feature based computations. + + :param features_1: features of task 1 [sample_num, num_features] + :param features_2: features of task 2 [sample_num, num_features] + :param distance_cfg: distance config, determining computation parameters + :return: calculated distance + """ + fct_map = { + "mmd": calculate_maximum_mean_discrepancy, + "emd": calculate_wasserstein_distance, + "fid": calculate_frechet_inception_distance, + "kld": calculate_kullbach_leibler_divergence, + } + if mode_id not in fct_map: + raise ValueError(f"Mode {mode_id} is not a valid feature distance option!") + fct = fct_map[mode_id] + return fct(features_1, features_2, distance_cfg) + + +def calculate_maximum_mean_discrepancy( + features_1: np.ndarray, features_2: np.ndarray, distance_cfg: DictConfig +) -> float: + """ + Returns the Maximum Mean Discrepancy of the two data-samples. Splits the computation in chunks if sample num is + too large, afterward averages results. + """ + if features_1.shape[0] > distance_cfg.chunk_size: + logger.warning(f"High sample size {features_1.shape[0]} causes mmd calculation to be done chunk-wise.") + splits = (features_1.shape[0] // distance_cfg.chunk_size) + 1 + results = [] + device = torch.device("cuda") if distance_cfg.allow_gpu else torch.device("cpu") + for sub_source, sub_target in zip(np.array_split(features_1, splits), np.array_split(features_2, splits)): + source = torch.as_tensor(sub_source).to(device) + target = torch.as_tensor(sub_target).to(device) + if distance_cfg.kernel == "cauchy": + results.append(torch.mean(mmd_cauchy(source, target, a=distance_cfg.blur).view(-1)).item()) + elif distance_cfg.kernel in ["energy", "gaussian", "laplacian"]: + if not _GEOMLOSS_AVAILABLE: + raise ImportError("Did not find geomloss package. Please install >pip install geomloss<.") + mmd = SamplesLoss(loss=distance_cfg.kernel, blur=distance_cfg.blur, backend="auto") + results.append(mmd(source, target).item()) + else: + raise ValueError(f"Kernel {distance_cfg.kernel} not implemented for MMD computation.") + return torch.tensor(results).mean().item() + + +def mmd_cauchy(x: torch.Tensor, y: torch.Tensor, a: float) -> torch.Tensor: + """ + Maximum Mean Discrepancy Cauchy Kernel computation. Code by Tim Adler (& IWR). + + :param x: (samples x features) tensor + :param y: (samples x features) tensor + :param a: scalar parameter + :return: cauchy kernel maximum mean discrepancy + """ + xx, yy, zz = torch.mm(x, x.t()), torch.mm(y, y.t()), torch.mm(x, y.t()) + rx = xx.diag().unsqueeze(0).expand_as(xx) + ry = yy.diag().unsqueeze(0).expand_as(yy) + XX = a * (a + (rx.t() + rx - 2.0 * xx)) ** -1 + YY = a * (a + (ry.t() + ry - 2.0 * yy)) ** -1 + XY = a * (a + (rx.t() + ry - 2.0 * zz)) ** -1 + return XX + YY - 2.0 * XY + + +def calculate_frechet_inception_distance( + features_1: np.ndarray, features_2: np.ndarray, distance_cfg: DictConfig +) -> float: + """ + Returns the Frechet Inception Distance of two data-samples. Code adapted from torch-fidelity. + See https://github.com/toshas/torch-fidelity/blob/1e4eaa478fd42aeb31f8476ef7d5181ead9ead37/torch_fidelity/metric_fid.py + """ + assert len(features_1.shape) == 2 and len(features_2.shape) == 2 + mu1 = np.mean(features_1, axis=0) + mu2 = np.mean(features_2, axis=0) + sigma1 = np.cov(features_1, rowvar=False) + sigma2 = np.cov(features_2, rowvar=False) + assert mu1.shape == mu2.shape and mu1.dtype == mu2.dtype + assert sigma1.shape == sigma2.shape and sigma1.dtype == sigma2.dtype + + mu1 = np.atleast_1d(mu1) + mu2 = np.atleast_1d(mu2) + + sigma1 = np.atleast_2d(sigma1) + sigma2 = np.atleast_2d(sigma2) + + assert mu1.shape == mu2.shape, "Mean vectors have different lengths" + assert sigma1.shape == sigma2.shape, "Covariances have different dimensions" + + diff = mu1 - mu2 + + # Product might be almost singular + covmean, _ = scipy.linalg.sqrtm(sigma1.dot(sigma2), disp=False) + if not np.isfinite(covmean).all(): + logger.warning( + f"fid calculation produces singular product; adding {distance_cfg.eps} to diagonal of cov estimates" + ) + offset = np.eye(sigma1.shape[0]) * distance_cfg.eps + covmean = scipy.linalg.sqrtm((sigma1 + offset).dot(sigma2 + offset), disp=False) + + # Numerical error might give slight imaginary component + if np.iscomplexobj(covmean): + if not np.allclose(np.diagonal(covmean).imag, 0, atol=1e-3): + m = np.max(np.abs(covmean.imag)) + msg = f"Imaginary component {m}." + logger.error(msg) + raise ValueError(msg) + covmean = covmean.real + # compute fid and return + tr_covmean = np.trace(covmean) + fid = diff.dot(diff) + np.trace(sigma1) + np.trace(sigma2) - 2 * tr_covmean + return float(fid) + + +def calculate_wasserstein_distance(features_1: np.ndarray, features_2: np.ndarray, distance_cfg: DictConfig) -> float: + """ + Return wasserstein distance of two feature matrices. + """ + assert ( + len(features_1.shape) == len(features_2.shape) == 2 + ), "wasserstein distance computation expects (samples x features) array" + assert ( + features_1.shape[1] == features_2.shape[1] + ), "source and target data are expected to have identical feature shapes" + if distance_cfg.method == "sinkhorn": + if not _GEOMLOSS_AVAILABLE: + raise ImportError("Did not find geomloss package. Please install >pip install geomloss<.") + sinkhorn = SamplesLoss( + "sinkhorn", p=2, blur=0.05, scaling=0.8, backend="tensorized" + ) # todo optimize parameters + return sinkhorn(torch.as_tensor(features_1), torch.as_tensor(features_2)) + elif distance_cfg.method == "default": + total = 0 + for dim in range(features_1.shape[1]): + total += wasserstein_distance(features_1[:, dim], features_2[:, dim]) + return total / features_1.shape[1] + elif distance_cfg.method == "binned": + n_bins = 1000 + data_1 = torch.from_numpy(features_1) + data_2 = torch.from_numpy(features_2) + # create bins + hist1 = torch.zeros((data_1.shape[1], n_bins), dtype=torch.long) + hist2 = torch.zeros((data_2.shape[1], n_bins), dtype=torch.long) + for c in range(data_1.shape[1]): + hist1[c] = torch.histc(data_1[:, c].flatten(), bins=n_bins) + hist2[c] = torch.histc(data_2[:, c].flatten(), bins=n_bins) + # normalize + hist1 = hist1 / torch.sum(hist1, dim=1, dtype=torch.double, keepdim=True) + hist2 = hist2 / torch.sum(hist2, dim=1, dtype=torch.double, keepdim=True) + # see https://en.wikipedia.org/wiki/Earth_mover%27s_distance#Computing_the_EMD + diff = hist1 - hist2 + y = torch.cumsum(diff, dim=1) + return torch.mean(torch.sum(torch.abs(y), dim=1)).item() + else: + raise ValueError("distance.method must be either 'sinkhorn' or 'default' or 'binned'") + + +def calculate_kullbach_leibler_divergence( + features_1: np.ndarray, features_2: np.ndarray, distance_cfg: DictConfig +) -> float: + """ + Return kullbach leibler divergence of the feature means of two sample feature matrices. + See https://arxiv.org/pdf/1908.07630.pdf for details. + """ + assert ( + len(features_1.shape) == len(features_2.shape) == 2 + ), "kullbach leibler distance computation expects (samples x features) array" + assert ( + features_1.shape[1] == features_2.shape[1] + ), "source and target data are expected to have identical feature shapes" + # average features + source_avg = np.mean(features_1, axis=0) + target_avg = np.mean(features_2, axis=0) + return entropy(source_avg, target_avg) diff --git a/plugins/similarity/src/mml_similarity/scripts/fed_scheduler.py b/plugins/similarity/src/mml_similarity/scripts/fed_scheduler.py new file mode 100644 index 0000000..a083d5b --- /dev/null +++ b/plugins/similarity/src/mml_similarity/scripts/fed_scheduler.py @@ -0,0 +1,180 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging + +import torch +import torch.utils.data +from mml_similarity.scripts.abstract_task_distance_scheduler import AbstractTaskDistanceScheduler +from mml_similarity.scripts.fisher import compute_fisher_information_embedding, embedding_to_tensor +from mml_similarity.scripts.vector_distances import compute_task_distance +from omegaconf import DictConfig + +from mml.core.scripts.exceptions import MMLMisconfigurationException +from mml.core.scripts.utils import LearningPhase + +logger = logging.getLogger(__name__) + + +class FEDScheduler(AbstractTaskDistanceScheduler): + """ + AbstractBaseScheduler implementation for the FED setup. Includes the following subroutines: + - initial transfer phase for probe model specification + - fisher information matrix (diagonal) computation + - distance computation + - (plotting, not as full subroutine, but as part of the finish experiment routine) + """ + + def __init__(self, cfg: DictConfig): + # initialize + super(FEDScheduler, self).__init__(cfg=cfg, available_subroutines=["tune", "fim", "distance"]) + if len(self.cfg.augmentations.gpu) != 0: + raise MMLMisconfigurationException( + f"Distance computations for {self.distance_measure} do not support GPU" f" augmentations!" + ) + + def create_routine(self) -> None: + """ + This scheduler implements 3 subroutines (transfer, fim, distance). + + :return: None + """ + # -- add transfer learning commands + if "tune" in self.subroutines: + for task in self.cfg.task_list: + self.commands.append(self.train_probe_model) + self.params.append([task]) + # -- add fim computation commands + if "fim" in self.subroutines: + for task in self.cfg.task_list: + self.commands.append(self.compute_fim) + self.params.append([task]) + # -- add distance computation commands + self.create_default_distances_routine() + + # first individual command, routine for tuning a probe model + def train_probe_model(self, task_name: str) -> None: + """ + Computes a probe model to compute the fisher embedding. Trains the final classifier of a pretrained model. + If "fc_tuned" is already present in the task struct (by setting reuse.fc_tuned=PROJECT) for a project having + already computed the probe model this step is skipped and the present probe model is used for following + computations. + + :param str task_name: name of the task to train the probe model + :return: None, will update task_struct.paths["fc_tuned"] + """ + task_struct = self.get_struct(task_name) + if "fc_tuned" in task_struct.paths: + logger.info("Found existing probe model for task " + self.highlight_text(task_name)) + return + logger.info("Starting tuning for task " + self.highlight_text(task_name)) + data_module = self.create_datamodule(task_struct) + lit_model = self.create_model([task_struct]) + lit_model.model.freeze_backbone() + trainer = self.create_trainer(metrics_callback=False) + logger.debug("Tuning trainer...") + self.lightning_tune(trainer=trainer, model=lit_model, datamodule=data_module) + logger.debug("Fitting trainer...") + trainer.fit(model=lit_model, datamodule=data_module) + logger.debug("Saving model...") + path = self.fm.construct_saving_path(lit_model.model, key="fc_tuned", task_name=task_struct.name) + lit_model.model.save_checkpoint(param_path=path) + task_struct.paths["fc_tuned"] = path + logger.info("Successfully finished tuning for task " + self.highlight_text(task_name)) + + # second individual command, routine for computing the fisher information matrix (or subpart of it) + def compute_fim(self, task_name: str) -> None: + """ + Computes the fisher embedding based on a probe model. Requires "fc_tuned" to be present in the task struct. + If "fim" is already present in the task struct (by setting reuse.fim=PROJECT) for a project having + already computed the fisher embedding this step is skipped and the present fim is used for following + computations. + + :param str task_name: name of the task to compute the fim + :return: None, will update task_struct.paths["fim"] + """ + task_struct = self.get_struct(task_name) + if "fim" in task_struct.paths: + logger.info("Found existing fim for task " + self.highlight_text(task_name)) + return + logger.info("Starting fim computation for task " + self.highlight_text(task_name)) + if "fc_tuned" not in task_struct.paths: + raise RuntimeError( + f"Could not find probe model path in task_struct of task {task_name}. Please ensure to run the tune " + f"routine beforehand or set reuse accordingly." + ) + # loading model, need only torch.nn.Module not lightning module -> can drop this information + logger.debug("Loading model...") + path = task_struct.paths["fc_tuned"] + model = self.create_model([task_struct]).model + model.load_checkpoint(param_path=path) + logger.debug("Preparing data...") + data_module = self.create_datamodule(task_structs=task_struct) + data_module.setup(stage="fit") + loader_kwargs = data_module.get_loader_kwargs_from_cfg(phase=LearningPhase.TRAIN, task_name=task_name) + device = torch.device("cuda" if self.cfg.allow_gpu else "cpu") + embedding = compute_fisher_information_embedding( + fim_cfg=self.cfg.distance.fim, + model=model, + ds=data_module.task_datasets[task_name][LearningPhase.TRAIN], + loader_kwargs=loader_kwargs, + device=device, + task_type=task_struct.task_type, + ) + embedding_path = self.fm.construct_saving_path(embedding, key="fim", task_name=task_struct.name) + torch.save(embedding, embedding_path) + task_struct.paths["fim"] = embedding_path + logger.info("Successfully finished fim computation for task " + self.highlight_text(task_name)) + + # third individual command, routine for computing distances from the fisher information embedding + def compute_distance_impl(self, source_task_name: str, target_task_name: str) -> float: + """ + Computes the fisher embedding distance between two tasks. Requires "fim" to be present in both task structs. If + the fims do not match (e.g. they are based on different probe models) an error will be raised. + + :param str source_task_name: source task name + :param str target_task_name: target task name + :return: the fisher embedding distance between source and target task + """ + # load datasets + source_struct = self.get_struct(source_task_name) + target_struct = self.get_struct(target_task_name) + if any("fim" not in struct.paths for struct in [source_struct, target_struct]): + raise RuntimeError( + "Could not find fim path in task_struct of some task. Please ensure to run the fim " + "routine beforehand or set reuse accordingly." + ) + # load saved embeddings + source_embedding = torch.load(source_struct.paths["fim"]) + target_embedding = torch.load(target_struct.paths["fim"]) + # filter embeddings for prefix + source_embedding = {k: v for k, v in source_embedding.items() if k.startswith(self.cfg.distance.prefix)} + target_embedding = {k: v for k, v in target_embedding.items() if k.startswith(self.cfg.distance.prefix)} + # assure compatibility + assert set(source_embedding.keys()) == set( + target_embedding.keys() + ), f"Fisher embeddings of task {source_task_name} and task {target_task_name} are not matching!" + # computing the distance + distance = compute_task_distance( + embedding_to_tensor(source_embedding), + embedding_to_tensor(target_embedding), + metric=self.cfg.distance.metric, + ) + return distance + + def is_sym_distance(self) -> bool: + """ + Helper function used to identify if distances have to be calculated in both directions. For FEDScheduler, + this is depending on the distance metric applied on the embeddings. + + :return: (bool) True is indicating symmetric behaviour + """ + return { + "euclidean": True, + "cosine": True, + "normalized_euclidean": True, + "jensenshannon": True, + }[self.cfg.distance.metric] diff --git a/plugins/similarity/src/mml_similarity/scripts/fisher.py b/plugins/similarity/src/mml_similarity/scripts/fisher.py new file mode 100644 index 0000000..05d384d --- /dev/null +++ b/plugins/similarity/src/mml_similarity/scripts/fisher.py @@ -0,0 +1,297 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import time +from dataclasses import dataclass +from typing import Dict, List + +import torch +from hydra.core.config_store import ConfigStore +from nngeometry.layercollection import LayerCollection +from nngeometry.metrics import FIM_MonteCarlo +from nngeometry.object import PMatDiag +from torch import Tensor +from torch.distributions import Categorical +from torch.nn import Module +from torch.utils.data import DataLoader +from tqdm import tqdm + +from mml.core.data_loading.task_attributes import Modality, TaskType +from mml.core.data_loading.task_dataset import TaskDataset, TupelizedTaskDataset +from mml.core.data_preparation.utils import WIPBar +from mml.core.models.torch_base import BaseModel + +logger = logging.getLogger(__name__) + + +@dataclass +class FimConfig: + samples: int = 10000 + empirical: bool = False + ignore_bias: bool = True + ignore_downsample: bool = True + ignore_bn: bool = False + average_filters: bool = True + final_fraction: float = 0.6 + nngeom: bool = False + + +cs = ConfigStore.instance() +cs.store(name="fim_config", node=FimConfig) + + +def compute_fisher_information_embedding( + fim_cfg: FimConfig, + model: BaseModel, + ds: TaskDataset, + loader_kwargs: dict, + device: torch.device, + task_type: TaskType, +) -> Dict[str, Tensor]: + """ + Wrapper for computing the fisher information embedding of a task. + + :param fim_cfg: subnode of config to deal with settings on fim computation (should reside at cfg.mode.fim) + :param model: tuned model on the task (torch.nn.Module), needs to be a subclass of mml.core.models.torch_modules.base.BaseModel + :param loader_kwargs: kwargs for the data loader, e.g. specifying num_workers + :param ds: the dataset in use + :param device: torch device to compute on + :param task_type: TaskType of the task + :return: diagonal of the Fisher information matrix as dict + """ + assert task_type in [ + TaskType.CLASSIFICATION, + TaskType.SEMANTIC_SEGMENTATION, + ], f"Task_type {task_type} not supported during fim computation yet!" + + loader_kwargs["sampler"] = torch.utils.data.RandomSampler(ds, replacement=True, num_samples=fim_cfg.samples) + loader_kwargs["drop_last"] = False # make sure to use all samples + if fim_cfg.nngeom: + ds = TupelizedTaskDataset(ds) + loader = torch.utils.data.DataLoader(ds, **loader_kwargs) + param_names = select_embedding_params(fim_cfg, model) + func = nngeom_fim if fim_cfg.nngeom else fim_diag + embedding = func( + model, + data_loader=loader, + fim_params=param_names, + empirical=fim_cfg.empirical, + device=device, + task_type=task_type, + ) + return postprocess_embedding(fim_cfg, embedding) + + +def select_embedding_params(fim_cfg: FimConfig, model: BaseModel) -> List[str]: + """ + Chooses the parameter names to be considered as elements of the embedding. + + :param fim_cfg: subnode of config to deal with settings on fim computation (should reside at cfg.mode.fim) + :param model: tuned model on the task (torch.nn.Module), needs to be a subclass of mml.core.models.torch_modules.base.BaseModel + :return: list of str with names of the relevant parameters + """ + # first shrink to encoder params + encoder_pars = [ + name for name, param in model.named_parameters() if name.startswith("backbone.") and param.requires_grad + ] + # now, based on config drop some + to_drop = [] + # excluding bias terms + if fim_cfg.ignore_bias: + to_drop += [name for name in encoder_pars if "bias" in name] + # ignore downsample weights + if fim_cfg.ignore_downsample: + to_drop += [name for name in encoder_pars if "downsample" in name] + # ignore batchnorm weights + if fim_cfg.ignore_bn: + to_drop += [name for name in encoder_pars if ".bn." in name] + # only take into consideration a fraction based on the final model layers + if fim_cfg.final_fraction < 1: + # TODO: beware naming compatibility with other models + layers = [name for name, _ in model.backbone.named_children() if "fc" not in name and "pool" not in name] + layers_to_keep = layers[int(len(layers) * (1 - fim_cfg.final_fraction)) :] + logger.debug( + f"Fim final fraction results in keeping the following encoder layers: {layers_to_keep} and " + f"dropping these encoder layers: {[name for name in layers if name not in layers_to_keep]}" + ) + to_drop += [name for name in encoder_pars if name.split(".")[1] not in layers_to_keep] + # make sure to not drop multiple times by making a set + for name in set(to_drop): + encoder_pars.remove(name) + return encoder_pars + + +def embedding_to_tensor(embedding: Dict[str, Tensor]) -> Tensor: + """ + Transforms an embedding (dict of tensors) to a single tensor. + + :param embedding: any dict with tensor values + :return: a single tensor + """ + return torch.cat(tuple([t.view(-1) for t in embedding.values()])) + + +def postprocess_embedding(fim_cfg: FimConfig, embedding: Dict[str, Tensor]) -> Dict[str, Tensor]: + """ + Averaging convolutional layers if specified. Also sets precision and checks for NaN values. + + :param fim_cfg: subnode of config to deal with settings on fim computation (should reside at cfg.mode.fim) + :param embedding: embedding as produced by fim_diag function + :return: postprocessed embedding + """ + # if specified average filters within a convolution layer + if fim_cfg.average_filters: + # TODO: better alternative is to use actual layer class (gathered earlier) + conv_params = [ + name for name in embedding.keys() if "conv" in name and "weight" in name and embedding[name].dim() == 4 + ] + for conv_param in conv_params: + embedding[conv_param] = torch.mean(embedding[conv_param], dim=[2, 3]) # Average over kernel size + # finally setting precision and checking for missing values + for param in embedding.keys(): + embedding[param].to(torch.double) + if torch.max(torch.isnan(embedding[param])) == 1: + logger.error("Detected NaN value(s) in Fisher Embedding!") + return embedding + + +def nngeom_fim( + model: Module, + data_loader: DataLoader, + fim_params: List[str], + task_type: TaskType, + empirical: bool = False, + device: torch.device = None, +) -> Dict[str, Tensor]: + if empirical: + raise NotImplementedError + model.eval() + model.to(device) + with WIPBar() as bar: + bar.desc = "Computing FIM" + fim_layers = list(set(".".join(name.split(".")[:-1]) for name in fim_params)) + layer_col = LayerCollection() + for layer, mod in model.named_modules(): + if len(list(mod.children())) == 0 and len(list(mod.parameters())) > 0: + if layer in fim_layers: + layer_col.add_layer_from_model(model, mod) + variant = None + if task_type == TaskType.CLASSIFICATION: + variant = "classif_logits" + elif task_type == TaskType.SEMANTIC_SEGMENTATION: + variant = "segmentation_logits" + + def loading_func(*d): + return next(iter(model(d[0].to(device)).values())) + + diag_vals = FIM_MonteCarlo( + model=model, + loader=data_loader, + representation=PMatDiag, + device=device, + variant=variant, + function=loading_func, + layer_collection=layer_col, + ).get_diag() + fim = {name: None for name in fim_params} + _, module_to_layerid = layer_col.get_layerid_module_maps(model) + for layer, mod in model.named_modules(): + if layer not in fim_layers: + continue + collection_layer_id = module_to_layerid[mod] + idx = layer_col.p_pos[collection_layer_id] + size = layer_col.layers[collection_layer_id].numel() + vals = diag_vals[idx : idx + size] + param_counts = {layer + "." + name: param.numel() for name, param in mod.named_parameters()} + param_links = {layer + "." + name: param for name, param in mod.named_parameters()} + assert size == sum(param_counts.values()) + delimiter = 0 + for param_name, count in param_counts.items(): + if param_name in fim_params: + fim[param_name] = ( + vals[delimiter : delimiter + count].clone().detach().view_as(param_links[param_name]) + ) + delimiter += count + assert None not in fim.values(), "something went wrong..." + return fim + + +def fim_diag( + model: Module, + data_loader: DataLoader, + fim_params: List[str], + task_type: TaskType, + empirical: bool = False, + device: torch.device = None, +) -> Dict[str, Tensor]: + """ + Computes the diagonal elements of the fisher information matrix for a given task. + + :param model: tuned model for the task + :param data_loader: data loader for the task + :param fim_params: list of parameter names that should be considered + :param task_type: TaskType of the task + :param empirical: if activated uses the empirical fisher (uses true targets instead of sampled model estimations) + :param device: torch device to run computations on + :return: diagonal elements of the fisher as parameter name to value mapping + """ + model.eval() + model.to(device) + fim = {} + for name, param in model.named_parameters(): + if name in fim_params: + fim[name] = torch.zeros_like(param) + else: + param.requires_grad = False + # logging infos + tic = time.time() + seen, last = 0, 0 + # iterate once over loader + with tqdm(total=len(data_loader.sampler), desc="compute fisher") as pbar: + for batch in data_loader: + # extract batch + images = batch[Modality.IMAGE.value] + if empirical: + targets = ( + batch[Modality.CLASS.value] if task_type == TaskType.CLASSIFICATION else batch[Modality.MASK.value] + ) + # send to device + if device is not None: + images = images.to(device) + if empirical: + targets = targets.to(device) + # forward image + logits = next(iter(model(images).values())) + if empirical: + outdx = targets.unsqueeze(1) + elif task_type == TaskType.CLASSIFICATION: + outdx = Categorical(logits=logits).sample().unsqueeze(1).detach() + else: + outdx = None + raise NotImplementedError("SEMANTIC_SEGMENTATION FIM not yet implemented!") + samples = logits.gather(1, outdx) + + # iterate once over batch + for idx in range(images.size(0)): + model.zero_grad() + torch.autograd.backward(samples[idx], retain_graph=True) + for name, param in model.named_parameters(): + if name in fim_params: + fim[name] += param.grad**2 + fim[name].detach_() + seen += 1 + pbar.update(1) + if seen % 100 == 0: + toc = time.time() + fps = float(seen - last) / (toc - tic) + tic, last = toc, seen + logger.debug(f"Samples: {seen:5d} Fps: {fps:2.4f} samples/s.") + + # average fim_diag elements + for name, grad2 in fim.items(): + grad2 /= float(seen) + return fim diff --git a/plugins/similarity/src/mml_similarity/scripts/sample_based_scheduler.py b/plugins/similarity/src/mml_similarity/scripts/sample_based_scheduler.py new file mode 100644 index 0000000..0a9f0ef --- /dev/null +++ b/plugins/similarity/src/mml_similarity/scripts/sample_based_scheduler.py @@ -0,0 +1,116 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging + +import numpy as np +import torch +from mml_similarity.scripts.abstract_task_distance_scheduler import AbstractTaskDistanceScheduler +from mml_similarity.scripts.feature_distances import compute_feature_distance, sample_features +from omegaconf import DictConfig +from tqdm import tqdm + +from mml.core.scripts.exceptions import MMLMisconfigurationException + +logger = logging.getLogger(__name__) +SAMPLE_BASED_MODES = ["mmd", "kld", "emd", "fid"] + + +class SampleBasedScheduler(AbstractTaskDistanceScheduler): + """ + AbstractBaseScheduler implementation for the sampling statistics setup. Includes the following subroutines: + - feature extraction + - distance computation + - (plotting, not as full subroutine, but as part of the finish experiment routine) + """ + + def __init__(self, cfg: DictConfig): + # initialize + super(SampleBasedScheduler, self).__init__(cfg=cfg, available_subroutines=["feature", "distance"]) + self.extracted_features = None # holds the features, used to avoid repeatedly loading + if len(self.cfg.augmentations.gpu) != 0: + raise MMLMisconfigurationException( + f"Distance computations for {self.distance_measure} do not support GPU" f" augmentations!" + ) + + def create_routine(self): + """ + This scheduler implements 2 subroutines ('feature', 'distance'). + + :return: None + """ + # -- add feature extraction commands + if "feature" in self.subroutines: + for task in self.cfg.task_list: + self.commands.append(self.extract_features) + self.params.append([task]) + # -- add distance computation commands + self.create_default_distances_routine() + + # first individual command, routine for feature extraction + def extract_features(self, task_name: str) -> None: + """ + Extracts features based on some pretrained encoder model. + If "features" is already present in the task struct (by setting `reuse.features=PROJECT`) for a project having + already extracted the features this step is skipped and the present features are used for following + computations. + + :param str task_name: name of the task to extract features from + :return: None, will update task_struct.paths["features"] + """ + task_struct = self.get_struct(task_name) + if "features" in task_struct.paths: + logger.info("Found existing features for task " + self.highlight_text(task_name)) + return + logger.info("Starting feature extraction for dataset " + self.highlight_text(task_name)) + # gather features# feature extraction by pretrained model + datamodule = self.create_datamodule(task_structs=task_struct) + datamodule.setup(stage="fit") + model = self.create_model(task_structs=[task_struct]) + features = sample_features( + model=model, # type:ignore + datamodule=datamodule, + device=torch.device("cuda") if self.cfg["allow_gpu"] else torch.device("cpu"), + ) + # save features after extraction + path = self.fm.construct_saving_path(obj=features, key="features", task_name=task_struct.name) + np.save(path, features) + # add reference to dataset + task_struct.paths["features"] = path + logger.info("Successfully finished feature extraction for task " + self.highlight_text(task_name)) + + # third individual command, routine for computing distances from the reduced information matrix + def compute_distance_impl(self, source_task_name: str, target_task_name: str) -> float: + # load extracted features (numpy arrays) + if self.extracted_features is None: + self.extracted_features = {} + with tqdm(total=len(self.cfg.task_list), desc="Loading extracted features") as t: + for ix, task_name in enumerate(self.cfg.task_list): + t.set_postfix(task=task_name) + task_struct = self.get_struct(task_name) + if "features" not in task_struct.paths or not task_struct.paths["features"].exists(): + raise FileNotFoundError( + f"Task {task_name} does not have a valid feature path! Please ensure " + f"to run the feature extraction routine first or set reuse accordingly." + ) + self.extracted_features[task_name] = np.load(task_struct.paths["features"]) + t.update() + # check dimensions + shapes = [v.shape for v in self.extracted_features.values()] + if any([s != shapes[0] for s in shapes]): + logger.error(f"Found inconsistent shapes during loading of extracted features: {shapes}.") + logger.info("Loaded features.") + # compute distance + distance = compute_feature_distance( + features_1=self.extracted_features[source_task_name], + features_2=self.extracted_features[target_task_name], + distance_cfg=self.cfg.distance, + mode_id=self.distance_measure, + ) + return distance + + def is_sym_distance(self) -> bool: + return {"mmd": True, "emd": True, "fid": True, "kld": False}[self.distance_measure] diff --git a/plugins/similarity/src/mml_similarity/scripts/semantic_scheduler.py b/plugins/similarity/src/mml_similarity/scripts/semantic_scheduler.py new file mode 100644 index 0000000..55bb8c6 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/scripts/semantic_scheduler.py @@ -0,0 +1,47 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging + +from mml_similarity.scripts.abstract_task_distance_scheduler import AbstractTaskDistanceScheduler +from omegaconf import DictConfig + +logger = logging.getLogger(__name__) + + +class SemanticScheduler(AbstractTaskDistanceScheduler): + """ + AbstractBaseScheduler implementation for semantic simiarlity based upon task keywords. Includes the following + subroutines: + - distance computation + - (plotting, not as full subroutine, but as part of the finish experiment routine) + """ + + def __init__(self, cfg: DictConfig): + # initialize + super(SemanticScheduler, self).__init__(cfg=cfg, available_subroutines=["distance"]) + + def create_routine(self) -> None: + """ + This scheduler implements a single subroutine (distance). + + :return: None + """ + # -- add distance computation commands + self.create_default_distances_routine() + + def compute_distance_impl(self, source_task_name: str, target_task_name: str) -> float: + # load datasets + source_struct = self.get_struct(source_task_name) + target_struct = self.get_struct(target_task_name) + + union = set(source_struct.keywords).union(target_struct.keywords) + intersection = set(source_struct.keywords).intersection(target_struct.keywords) + + return 1 - (len(intersection) / len(union)) + + def is_sym_distance(self) -> bool: + return True diff --git a/plugins/similarity/src/mml_similarity/scripts/vector_distances.py b/plugins/similarity/src/mml_similarity/scripts/vector_distances.py new file mode 100644 index 0000000..a113aa3 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/scripts/vector_distances.py @@ -0,0 +1,39 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging + +import torch +import torch.nn.functional as Functional +from scipy.spatial.distance import jensenshannon +from torch import Tensor + +logger = logging.getLogger(__name__) + + +def compute_task_distance(emb_1: Tensor, emb_2: Tensor, metric: str = "cosine") -> float: + if metric == "cosine": + return cosine_distance(emb_1, emb_2) + elif metric == "euclidean": + return euclidean_distance(emb_1, emb_2, normalize=False) + elif metric == "normalized_euclidean": + return euclidean_distance(emb_1, emb_2, normalize=True) + elif metric == "jensenshannon": + return jensenshannon(emb_1.cpu().numpy(), emb_2.cpu().numpy()) + else: + logger.error(f"Invalid distance metric {metric} for distance computation.") + return float("NaN") + + +def cosine_distance(emb_1: Tensor, emb_2: Tensor) -> float: + return 1.0 - Functional.cosine_similarity(emb_1, emb_2, dim=0).item() + + +def euclidean_distance(emb_1: Tensor, emb_2: Tensor, normalize: bool = True) -> float: + if normalize: + emb_1 = Functional.normalize(emb_1, dim=0) + emb_2 = Functional.normalize(emb_2, dim=0) + return torch.linalg.vector_norm(emb_1 - emb_2, ord=2).item() diff --git a/plugins/similarity/src/mml_similarity/visualization/__init__.py b/plugins/similarity/src/mml_similarity/visualization/__init__.py new file mode 100644 index 0000000..90ffb6c --- /dev/null +++ b/plugins/similarity/src/mml_similarity/visualization/__init__.py @@ -0,0 +1,6 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + diff --git a/plugins/similarity/src/mml_similarity/visualization/plot_2D.py b/plugins/similarity/src/mml_similarity/visualization/plot_2D.py new file mode 100644 index 0000000..0f8c000 --- /dev/null +++ b/plugins/similarity/src/mml_similarity/visualization/plot_2D.py @@ -0,0 +1,386 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import warnings +from dataclasses import dataclass +from itertools import chain, combinations +from pathlib import Path +from string import ascii_lowercase, ascii_uppercase, digits +from typing import Dict, List, Optional, Tuple, Union + +import matplotlib.cm +import matplotlib.colors +import matplotlib.gridspec +import matplotlib.lines +import matplotlib.patches +import matplotlib.pyplot as plt +import networkx as nx +import numpy as np +import pandas as pd +from hydra.core.config_store import ConfigStore +from openTSNE import TSNE + +from mml.core.data_loading.file_manager import MMLFileManager +from mml.core.data_loading.task_attributes import Keyword, TaskType +from mml.core.data_loading.task_struct import TaskStruct, undup_names +from mml.core.scripts.utils import TAG_SEP +from mml.core.visualization.utils import COLORS + +logger = logging.getLogger(__name__) + + +@dataclass +class DistancePlotConfig: + kamada_kawai: bool = True + # kamada kawai parameters + label_nodes: bool = False + color_nodes: bool = True + color_map: str = "jet" # also 'hsv' + node_size: int = 700 + plot_edges: bool = True + label_edges: bool = False + edge_thresh: float = 0.65 # 0 for no edges, -1 for all edges + legend_size: int = 20 # <= 0 deactivates legend + # colorization by... + criteria: Optional[str] = None # maybe either None, medical, task_type, target or domain + # tsne parameters + draw_centers: bool = False + draw_cluster_labels: bool = False + + +cs = ConfigStore.instance() +cs.store(name="distance_plot_config", node=DistancePlotConfig) + + +def plot_task_embedding( + distances: Union[pd.DataFrame, Path], structs: List[TaskStruct], plot_config: DistancePlotConfig, distance_key: str +) -> Path: + if isinstance(distances, Path): + distances = pd.read_csv(distances, index_col=0, header=0) + all_tasks = distances.index.to_list() + if distances.columns.to_list() != all_tasks: + raise ValueError("Need all task distance pairs!") + task_subset = [struct.name for struct in structs] + if not set(task_subset).issubset(set(all_tasks)): + raise ValueError(f"Found tasks: {all_tasks}, incompatible subset {task_subset}") + to_drop = [t for t in all_tasks if t not in task_subset] + distances = distances.drop(to_drop, axis="index").drop(to_drop, axis="columns") + # assure same index for rows and columns + all_tasks = distances.index.to_list() + distances = distances[all_tasks] + # shift distances so that negative values become feasible + if (distances < 0).any().any(): + logger.warning("Found negative distance values, will shift distances to allow plotting.") + smallest = distances.min().min() + distances += 1.1 * (-smallest) + plot_path = MMLFileManager.instance().construct_saving_path(obj=None, key="2D_" + distance_key.lower()) + color_map, legend_map = create_color_mapping(task_list=structs, criteria=plot_config.criteria) + if plot_config.kamada_kawai: + fig = plot_kamada_kawai(distances=distances, plot_cfg=plot_config, color_map=color_map, legend_map=legend_map) + else: + fig = plot_tsne(distances=distances, plot_cfg=plot_config, color_map=color_map, legend_map=legend_map) + # saving the result + fig.savefig(str(plot_path)) + fig.clf() + plt.close() + logger.info(f"Plotted distance graph @{plot_path}.") + return plot_path + + +def plot_kamada_kawai( + distances: pd.DataFrame, + plot_cfg: DistancePlotConfig, + color_map: Optional[Dict[str, int]] = None, + legend_map: Optional[Dict[int, str]] = None, + border_map: Optional[Dict[str, str]] = None, +) -> plt.Figure: + """ + Returns a figure with a task graph generated from provided task distances. + + :param Union[pd.DataFrame, Path] distances: + :param Optional[Dict[str, int]] color_map: + :param Optional[Dict[int, str]] legend_map: + :param Optional[Dict[str, str]] border_map: (optional) give task nodes in the graph a certain border color + :return: + """ + + all_tasks = distances.index.to_list() + + if plot_cfg.color_nodes: + assert color_map is not None, "For coloring nodes provide a color_map" + assert all([t in color_map for t in all_tasks]), f"color map only supports {color_map.keys()}" + + mean = distances.mask(np.eye(len(distances.index), dtype=bool)).replace([np.inf], np.nan).mean().mean() + # check for symmetry + symmetric = distances.equals(distances.T) + # create graph and layout + G = nx.Graph(distances) if symmetric else nx.DiGraph(distances) + pos = nx.kamada_kawai_layout(G) + # start figure for plotting + fig = plt.figure(tight_layout=True, figsize=[12.0, 9.0]) + gs = matplotlib.gridspec.GridSpec(3, 1) if plot_cfg.label_nodes else matplotlib.gridspec.GridSpec(1, 1) + ax = fig.add_subplot(gs[0:2, 0]) + drawing_edges = ( + G.edges() + if plot_cfg.edge_thresh == -1 + else [(s, t) for s, t in G.edges() if distances.at[s, t] < plot_cfg.edge_thresh * mean] + ) + # color nodes by the color_map provided + if color_map is not None: + ordered_colors = [color_map.get(node, 0) for node in G.nodes()] + all_colors = list(set(color_map.values())) + # Color mapping + color_map = plt.get_cmap(plot_cfg.color_map) + normalizer = matplotlib.colors.Normalize(vmin=0, vmax=max(all_colors)) + scalar_map = matplotlib.cm.ScalarMappable(norm=normalizer, cmap=color_map) + # legend + if plot_cfg.legend_size > 0: + assert all([col in legend_map for col in all_colors]), "provide legend map for all entries of color_map" + handles = [] + for col in all_colors: + patch = matplotlib.patches.Patch(color=scalar_map.to_rgba(col), label=legend_map[col]) + handles.append(patch) + ax.legend(handles=handles, fontsize=plot_cfg.legend_size) + # draw colored nodes + nx.draw_networkx( + G, + pos, + cmap=color_map, + vmin=0, + vmax=max(all_colors), + node_color=ordered_colors, + arrows=False, + edgelist=drawing_edges if plot_cfg.plot_edges else None, + node_size=plot_cfg.node_size, + with_labels=False, + width=1.0 if plot_cfg.plot_edges else 0.0, + edgecolors=[border_map.get(node, 0) for node in G.nodes()] if border_map else None, + linewidths=1.75, + ) + else: + # color all nodes equal + nx.draw_networkx(G, pos, with_labels=False, width=1.0 if plot_cfg.plot_edges else 0.0) + unmoded_label_dict = {} + if plot_cfg.label_nodes: + ordered_node_labels = ascii_uppercase + ascii_lowercase + digits + unmoded_node_names = undup_names(list(G.nodes())) + # check if enough symbols to label every node in the Graph + if len(ordered_node_labels) < len(set(unmoded_node_names)): + logger.error( + f"Was unable to label nodes, was given {len(set(unmoded_node_names))} node names, but only " + f"support up to {len(ordered_node_labels)} node names. Skipped node labeling." + ) + else: + # define for every unmoded node some label + for ix, unmoded in enumerate(list(set(unmoded_node_names))): + unmoded_label_dict[unmoded] = ordered_node_labels[ix] + # now define labels for each node + node_labels = {} + for ix, node in enumerate(G.nodes): + node_labels[node] = unmoded_label_dict[unmoded_node_names[ix]] + nx.draw_networkx_labels(G, pos, labels=node_labels) + if plot_cfg.label_edges: + edge_labels = {} + for edge in drawing_edges: + edge_labels[(edge[0], edge[1])] = "{:.2f}".format(distances.at[edge[0], edge[1]]) + position = 0.5 if symmetric else 0.3 + nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, label_pos=position) + # turn on / off surrounding box of the graph and set width of boxlines + ax.axis("on") + for orient in ["top", "right", "left", "bottom"]: + ax.spines[orient].set_linewidth(5.0) + if plot_cfg.label_nodes: + # switch to labels part of the plot (lower figure) + ax = fig.add_subplot(gs[2, 0]) + text_lines = ["{}: {}".format(v, k) for k, v in unmoded_label_dict.items()] + lines_per_column = 15 + num_text_cols = int(len(text_lines) / lines_per_column) + 1 + for text_column in range(num_text_cols): + ax.text( + text_column * (1 / num_text_cols), + 0.5, + "Datasets:\n" + + "\n".join(text_lines[text_column * lines_per_column : (text_column + 1) * lines_per_column]) + + "\n", + ha="center", + va="center", + wrap=True, + ) + ax.axis("off") + # background color of the figure + fig.set_facecolor("w") + return fig + + +def create_color_mapping( + task_list: List[TaskStruct], + criteria: Optional[str] = None, + tag_groups: Optional[Dict[str, List[Keyword]]] = None, + task_clusters: Optional[Dict[str, List[str]]] = None, +) -> Tuple[Dict[str, int], Dict[int, str]]: + """ + Creates color map and legend map based on either criteria, self-defined tag_groups or task clusters + to cluster tasks. + + :param task_list: tasks to be color selected + :param criteria: one of the predefined cluster methods (medical, domain, task_type, tagged, size) + :param tag_groups: self provided clustering of keywords (keywords within a groups are OR connected) + :param task_clusters: self provided clustering of tasks + :return: tuple with color_map and legend_map as required by plot_2D + """ + # compatibility with hydra config + if criteria in ["None", "none"]: + warnings.warn( + DeprecationWarning( + "Using string None as argument to distance plotting criteria is deprecated. " + "In hydra CLI use null instead." + ) + ) + criteria = None + # input values check + assert sum([criteria is None, tag_groups is None, task_clusters is None]) >= 2, ( + "provide at most one of criteria," " tag_groups or task_clusters" + ) + if sum([criteria is None, tag_groups is None, task_clusters is None]) == 3: + # default behaviour in case nothing was given + criteria = "domain" + if criteria is not None: + # define tag groups + if criteria == "medical": + tag_groups = {"Medical": [Keyword.MEDICAL]} + elif criteria == "domain": + tag_groups = { + str(tag.value).capitalize(): [tag] + for tag in [ + Keyword.DERMATOSCOPY, + Keyword.LARYNGOSCOPY, + Keyword.GASTROSCOPY_COLONOSCOPY, + Keyword.LAPAROSCOPY, + Keyword.NATURAL_OBJECTS, + Keyword.HANDWRITINGS, + Keyword.CATARACT_SURGERY, + Keyword.FUNDUS_PHOTOGRAPHY, + Keyword.MRI_SCAN, + Keyword.X_RAY, + Keyword.CT_SCAN, + Keyword.CLE, + Keyword.ULTRASOUND, + Keyword.CAPSULE_ENDOSCOPY, + ] + } + elif criteria == "target": + tag_groups = { + str(tag.value).capitalize(): [tag] + for tag in [ + Keyword.ENDOSCOPIC_INSTRUMENTS, + Keyword.ANATOMICAL_STRUCTURES, + Keyword.TISSUE_PATHOLOGY, + Keyword.IMAGE_ARTEFACTS, + ] + } + elif criteria == "task_type": + task_clusters = { + task_type.value: [task.name for task in task_list if task.task_type == task_type] + for task_type in list(TaskType) + } + elif criteria == "tagged": + plain = [task.name for task in task_list if " " not in task.name and TAG_SEP not in task.name] + task_clusters = {"plain": plain, "modified": [task.name for task in task_list if task.name not in plain]} + elif criteria == "size": + task_clusters = { + "small": [t.name for t in task_list if t.num_samples < 1000], + "medium": [t.name for t in task_list if 1000 < t.num_samples < 10000], + "large": [t.name for t in task_list if t.num_samples > 10000], + } + else: + raise ValueError(f"criteria {criteria} is an invalid value") + if tag_groups is not None: + # convert tag groups to task clusters + task_clusters = { + group_name: [task.name for task in task_list if any([tag in task.keywords for tag in group_tags])] + for group_name, group_tags in tag_groups.items() + } + # check task clusters - completeness and uniqueness + for (name_a, cluster_a), (name_b, cluster_b) in combinations(task_clusters.items(), 2): + for duplicate in set(cluster_a).intersection(cluster_b): + logger.warning(f"Found duplicate task {duplicate} in {name_a} and {name_b}, will remove from {name_b}.") + cluster_b.remove(duplicate) + others = set([task.name for task in task_list]).difference(set(chain(*task_clusters.values()))) + if len(others) > 0: + task_clusters["Other"] = list(others) + # produce mappings + clusters = sorted(list(task_clusters.keys())) + legend_map = {ix: cluster_name for ix, cluster_name in enumerate(clusters)} + task_mapping = {name: cluster for cluster in task_clusters.keys() for name in task_clusters[cluster]} + color_map = {task.name: clusters.index(task_mapping[task.name]) for task in task_list} + return color_map, legend_map + + +def plot_tsne( + distances: Union[pd.DataFrame, Path], + plot_cfg: DistancePlotConfig, + color_map: Optional[Dict[str, int]] = None, + legend_map: Optional[Dict[int, str]] = None, +) -> plt.Figure: + """ + Adapted from https://github.com/pavlin-policar/openTSNE/blob/master/examples/utils.py + + :param distances: + :param plot_cfg: + :param color_map: + :param legend_map: + :return: + """ + # generate TSNE embedding + embedding = TSNE(metric="precomputed", random_state=42).fit(distances.to_numpy()) + # base plot + fig, ax = plt.subplots(figsize=(12, 9)) + y = [color_map[task_name] for task_name in distances.index] + classes = np.unique(list(color_map.values())) + colors = {ix: COLORS[ix % len(COLORS)] for ix in classes} + point_colors = list(map(colors.get, y)) + ax.scatter(embedding[:, 0], embedding[:, 1], c=point_colors, rasterized=True, s=float(plot_cfg.node_size)) + # plot mediods + if plot_cfg.draw_centers: + centers = [] + for yi in classes: + mask = yi == y + centers.append(np.median(embedding[mask, :2], axis=0)) + centers = np.array(centers) + center_colors = list(map(colors.get, classes)) + ax.scatter( + centers[:, 0], centers[:, 1], c=center_colors, s=float(plot_cfg.node_size) * 2, alpha=1, edgecolor="k" + ) + # Draw mediod labels + if plot_cfg.draw_cluster_labels: + for idx in classes: + ax.text( + centers[idx, 0], centers[idx, 1] + 2.2, legend_map[idx], fontsize=6, horizontalalignment="center" + ) + # Hide ticks and axis + ax.set_xticks([]), ax.set_yticks([]), ax.axis("off") + # legend + if plot_cfg.legend_size > 0: + legend_handles = [ + matplotlib.lines.Line2D( + [], + [], + marker="s", + color="w", + markerfacecolor=colors[ix], + ms=10, + alpha=1, + linewidth=0, + label=legend_map[ix], + markeredgecolor="k", + ) + for ix in classes + ] + ax.legend(handles=legend_handles, fontsize=plot_cfg.legend_size) + # background color of the figure + fig.set_facecolor("w") + return fig diff --git a/plugins/similarity/tests/conftest.py b/plugins/similarity/tests/conftest.py new file mode 100644 index 0000000..ebc4fe2 --- /dev/null +++ b/plugins/similarity/tests/conftest.py @@ -0,0 +1,35 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import pytest +from omegaconf import open_dict + + +# by default the fixture below overrides the no_plugins fixture from mml.testing.fixtures to allow plugin testing +# you may remove this deactivation, put it into another submodule conftest.py and/or use the "plugin" marker to +# deactivate plugin loading solely for specific tests +@pytest.fixture(autouse=True) +def no_plugins(monkeypatch, request): + yield + + +@pytest.fixture +def fed_config(mml_config): + with open_dict(mml_config): + mml_config.distance = {} + mml_config.distance.name = "fed" + mml_config.distance.metric = "cosine" + mml_config.distance.prefix = "" + mml_config.distance.fim = { + "samples": 10, + "empirical": False, + "ignore_bias": True, + "ignore_bn": False, + "ignore_downsample": True, + "average_filters": True, + "final_fraction": 0.6, + "nngeom": True, + } + yield mml_config diff --git a/plugins/similarity/tests/integration/test_dist_measures.py b/plugins/similarity/tests/integration/test_dist_measures.py new file mode 100644 index 0000000..1cfdc97 --- /dev/null +++ b/plugins/similarity/tests/integration/test_dist_measures.py @@ -0,0 +1,21 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import pytest + + +@pytest.mark.gpu +@pytest.mark.parametrize("dist_measure", ["kld", "emd", "fed", "fid", "mmd", "semantic"]) +def test_dist_measures_console(script_runner, fake_task, no_plugins, dist_measure): + ret = script_runner.run( + [ + "mml", + "similarity", + "tasks=fake", + f"distance={dist_measure}", + ], + print_result=True, + ) + assert ret.success diff --git a/plugins/similarity/tests/unit/test_fed_scheduler.py b/plugins/similarity/tests/unit/test_fed_scheduler.py new file mode 100644 index 0000000..931a347 --- /dev/null +++ b/plugins/similarity/tests/unit/test_fed_scheduler.py @@ -0,0 +1,69 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import pytest +import torch +from mml_similarity.scripts.fed_scheduler import FEDScheduler + + +@pytest.mark.gpu +def test_train_probe_model(test_task_monkeypatch, fed_config) -> None: + fed_config.mode.subroutines = ["tune"] + scheduler = FEDScheduler(cfg=fed_config) + scheduler.train_probe_model(task_name="test_task_a") + assert "fc_tuned" in test_task_monkeypatch["test_task_a"].paths + + +@pytest.mark.gpu +def test_compute_fim(test_task_monkeypatch, fed_config, tmp_path) -> None: + fed_config.mode.subroutines = ["fim"] + scheduler = FEDScheduler(cfg=fed_config) + # simulate saved tuned params + model = scheduler.create_model([test_task_monkeypatch["test_task_a"]]).model + save_path = tmp_path / "tmp.pth" + model.save_checkpoint(param_path=save_path) + test_task_monkeypatch["test_task_a"].paths["fc_tuned"] = save_path + scheduler.compute_fim(task_name="test_task_a") + assert "fim" in test_task_monkeypatch["test_task_a"].paths + + +def test_compute_distance(test_task_monkeypatch, fed_config, tmp_path) -> None: + fed_config.mode.subroutines = ["distance"] + fed_config.task_list = ["test_task_a", "test_task_b"] + scheduler = FEDScheduler(cfg=fed_config) + scheduler.after_preparation_hook() + # simulate saved fim + fim_a = { + "mod0": torch.tensor([[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]]), + "mod1": torch.tensor([3.1415]), + "mod2": torch.tensor( + [ + [[0.01, 0.02], [0.03, 0.04], [0.05, 0.06]], + [[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]], + [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], + ] + ), + } + fim_b = { + "mod0": torch.tensor([[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]]) + 1, + "mod1": torch.tensor([3.1415]) * 2, + "mod2": torch.tensor( + [ + [[0.01, 0.02], [0.03, 0.04], [0.05, 0.06]], + [[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]], + [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], + ] + ) + ** 2, + } + save_path_a = tmp_path / "fim_a.pkl" + save_path_b = tmp_path / "fim_b.pkl" + torch.save(fim_a, save_path_a) + torch.save(fim_b, save_path_b) + test_task_monkeypatch["test_task_a"].paths["fim"] = save_path_a + test_task_monkeypatch["test_task_b"].paths["fim"] = save_path_b + scheduler._compute_distance(source="test_task_a", target="test_task_b") + assert pytest.approx(0.0502121448516845) == scheduler.load_distances().at["test_task_a", "test_task_b"] diff --git a/plugins/sql/CHANGELOG.md b/plugins/sql/CHANGELOG.md new file mode 100644 index 0000000..f948e88 --- /dev/null +++ b/plugins/sql/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +All notable changes to this plugin will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.3.0 (12/19/2024): +Move `mysqlclient` away from pip dependencies, in order to resolve license issues. Public release version. + +## 0.2.0 (08/29/2024): +This release introduces this changelog. The core dependency has also been bumped. diff --git a/plugins/sql/LICENSE.txt b/plugins/sql/LICENSE.txt new file mode 100644 index 0000000..6a39552 --- /dev/null +++ b/plugins/sql/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 German Cancer Research Center (DKFZ) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/plugins/sql/MANIFEST.in b/plugins/sql/MANIFEST.in new file mode 100644 index 0000000..77163f4 --- /dev/null +++ b/plugins/sql/MANIFEST.in @@ -0,0 +1 @@ +recursive-include src/mml_sql/configs *.yaml \ No newline at end of file diff --git a/plugins/sql/README.md b/plugins/sql/README.md new file mode 100644 index 0000000..86cc0e2 --- /dev/null +++ b/plugins/sql/README.md @@ -0,0 +1,64 @@ +# MML SQL plugin + +This plugin provides SQL support for the optuna multiruns of MML. + +# Install + +Install the plugin with pip. In addition, you require the `mysqlclient` package. + +```commandline +pip install mysqlclient +``` + +You also need to prepare the sql backend and add some information to your mml.env file. + + +## set up my sql database + +Install MySQL and enter interactive MySQL session: + + +```commandline + sudo apt-get install mysql-server default-libmysqlclient-dev + sudo mysql -u root -p +``` + +Create MySQL user and database (you can use different names for database, user and password): + +```commandline + mysql> CREATE DATABASE IF NOT EXISTS mml_hpo; + mysql> CREATE USER 'mml_user'@'%' IDENTIFIED WITH mysql_native_password BY 'password123'; + mysql> GRANT ALL PRVILEGES ON mml_hpo.* TO 'mml_user'@'%'; + mysql> FLUSH PRIVILEGES; +``` + +## set up secrets + +This plugin expects the following secrets in the `mml.env` file (adapt to your previously chosen values): + +``` +export MML_MYSQL_USER=mml_user +export MML_MYSQL_PW=password123 +export MML_MYSQL_PORT=3306 +export MML_HOSTNAME_OF_MYSQL_HOST=localhost +export MML_MYSQL_DATABASE=mml_hpo +``` + +## grant access to other workstations + +This part is optional and only required if you want other machines to access your local database (e.g. from a remote cluster): + +```commandline + sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf + # change the line 'bind-adress = ...' to be a comment by adding a hashtag in front + # do not forget to save changes! + service mysql restart +``` + +# Usage + +Instead of `hpo=default` just use `hpo=sql` when starting your `mml ... --multirun`. + +# Note + +Since `mysqlclient` has a GPL-2.0 license this feature is outsourced to an internal plugin instead of `mml-core`. \ No newline at end of file diff --git a/plugins/sql/pyproject.toml b/plugins/sql/pyproject.toml new file mode 100644 index 0000000..449c6a9 --- /dev/null +++ b/plugins/sql/pyproject.toml @@ -0,0 +1,52 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +[build-system] +requires = [ + "setuptools>=42", + "wheel", +] +build-backend = "setuptools.build_meta" + +[tool.pytest.ini_options] +addopts = "--strict-markers --benchmark-skip" +testpaths = [ + "tests", +] +markers = [ + "slow: marks tests as slow (deselect with '-m \"not slow\"')", + "gpu: marks tests as requiring a gpu to run", + "env: marks test that require the correct underlying mml.env file", + "plugin: marks tests that require the loading of plugins", + "serial", +] + +[tool.isort] +src_paths = ["src", "tests"] +profile = "black" +line_length = 120 + +[tool.mypy] +mypy_path = "src" +check_untyped_defs = true +disallow_any_generics = true +ignore_missing_imports = true +no_implicit_optional = true +show_error_codes = true +strict_equality = true +warn_redundant_casts = true +warn_return_any = true +warn_unreachable = true +warn_unused_configs = true +no_implicit_reexport = true +disallow_untyped_defs = true +warn_unused_ignores = true +allow_redefinition = true +warn_no_return = true + +[tool.ruff] +# Set the maximum line length +line-length = 120 \ No newline at end of file diff --git a/plugins/sql/setup.cfg b/plugins/sql/setup.cfg new file mode 100644 index 0000000..555097e --- /dev/null +++ b/plugins/sql/setup.cfg @@ -0,0 +1,47 @@ +[metadata] +name = mml-sql +version = attr: mml_sql.__version__ +description = This is the MML SQL plugin, providing an SQL backend for mml multiruns. +long_description = file: README.md +long_description_content_type = text/markdown +author = Patrick Godau +author_email = patrick.godau@dkfz-heidelberg.de +license = MIT +url = https://git.dkfz.de/imsy/ise/mml +classifiers = + Natural Language :: English + Development Status :: 4 - Beta + Environment :: Console + Intended Audience :: Developers + Topic :: Scientific/Engineering :: Artificial Intelligence + Topic :: Scientific/Engineering :: Image Recognition + Topic :: Scientific/Engineering :: Information Analysis + Topic :: Scientific/Engineering :: Image Processing + Topic :: Software Development :: Libraries :: Application Frameworks + Topic :: Software Development :: Version Control :: Git + Operating System :: OS Independent + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Environment :: GPU + Intended Audience :: Science/Research + Typing :: Typed + License :: OSI Approved :: MIT License + +[options] +python_requires = >=3.8 +package_dir = + =src +packages = find: +zip_safe = no +include_package_data = True +install_requires = + mml-core>=1.0.0 + +[options.entry_points] +mml.plugins = + mml-sql = mml_sql.activate + +[options.packages.find] +where=src diff --git a/plugins/sql/src/mml_sql/__init__.py b/plugins/sql/src/mml_sql/__init__.py new file mode 100644 index 0000000..b24a6b3 --- /dev/null +++ b/plugins/sql/src/mml_sql/__init__.py @@ -0,0 +1,9 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +VERSION = (0, 3, 0) +__version__ = ".".join(map(str, VERSION)) +__all__ = ["__version__"] diff --git a/plugins/sql/src/mml_sql/activate.py b/plugins/sql/src/mml_sql/activate.py new file mode 100644 index 0000000..64f1bd4 --- /dev/null +++ b/plugins/sql/src/mml_sql/activate.py @@ -0,0 +1,19 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from hydra.core.config_search_path import ConfigSearchPath +from hydra.core.plugins import Plugins +from hydra.plugins.search_path_plugin import SearchPathPlugin + + +# register plugin configs +class MMLSQLSearchPathPlugin(SearchPathPlugin): + def manipulate_search_path(self, search_path: ConfigSearchPath) -> None: + # Sets the search path for mml with copied config files + search_path.append(provider="mml-sql", path="pkg://mml_sql.configs") + + +Plugins.instance().register(MMLSQLSearchPathPlugin) diff --git a/plugins/sql/src/mml_sql/configs/__init__.py b/plugins/sql/src/mml_sql/configs/__init__.py new file mode 100644 index 0000000..90ffb6c --- /dev/null +++ b/plugins/sql/src/mml_sql/configs/__init__.py @@ -0,0 +1,6 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + diff --git a/plugins/sql/src/mml_sql/configs/hpo/sql.yaml b/plugins/sql/src/mml_sql/configs/hpo/sql.yaml new file mode 100644 index 0000000..0bce724 --- /dev/null +++ b/plugins/sql/src/mml_sql/configs/hpo/sql.yaml @@ -0,0 +1,42 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# example hyperparameter optimization with optuna and mysql backend: +# mml train proj=test hpo=sql hpo/sampler=grid --multirun + +defaults: + - sampler: tpe + # necessary to avoid an interpolation error during config composition + - /search_space@hydra.sweeper.params: none + - _self_ + # override sweeper to Optuna! + - override /hydra/sweeper: optuna + +# basic optuna setup +hpo: + storage: mysql://${oc.env:MML_MYSQL_USER}:${oc.env:MML_MYSQL_PW}@${oc.env:MML_HOSTNAME_OF_MYSQL_HOST}:${oc.env:MML_MYSQL_PORT}/${oc.env:MML_MYSQL_DATABASE} + direction: minimize # this is the default setting expected by MML, all optimized metrics should be inverted if necessary to ensure this! + pruning: false # activate by default as soon as available, see (#19) + trials: 100 + +hydra: + # here we define Optuna hyperparameter search + # it optimizes for value returned from function with @hydra.main decorator + # learn more here: https://hydra.cc/docs/next/plugins/optuna_sweeper + sweeper: + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + # use the following line to make HPO deterministic, make sure to start jobs with different seed + # sampler.seed: ${seed} + study_name: ${proj}_${now:%Y-%m-%d_%H-%M-%S} + storage: ${hpo.storage} + n_jobs: 1 # jobs in parallel, as long as no parallel launcher is used make sure to proceed as in the README:.md + # 'minimize' or 'maximize' the objective + direction: ${hpo.direction} + # number of experiments that will be executed in a row by a single job (to parallelize see the README.md) + n_trials: ${hpo.trials} + params: ${search_space} \ No newline at end of file diff --git a/plugins/sql/tests/conftest.py b/plugins/sql/tests/conftest.py new file mode 100644 index 0000000..b3c6299 --- /dev/null +++ b/plugins/sql/tests/conftest.py @@ -0,0 +1,14 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import pytest + + +# by default the fixture below overrides the no_plugins fixture from mml.testing.fixtures to allow plugin testing +# you may remove this deactivation, put it into another submodule conftest.py and/or use the "plugin" marker to +# deactivate plugin loading solely for specific tests +@pytest.fixture(autouse=True) +def no_plugins(monkeypatch, request): + yield diff --git a/plugins/sql/tests/unit/test_dummy.py b/plugins/sql/tests/unit/test_dummy.py new file mode 100644 index 0000000..6259249 --- /dev/null +++ b/plugins/sql/tests/unit/test_dummy.py @@ -0,0 +1,9 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + + +def test_dummy(): + pass diff --git a/plugins/suggest/CHANGELOG.md b/plugins/suggest/CHANGELOG.md new file mode 100644 index 0000000..fb8b65d --- /dev/null +++ b/plugins/suggest/CHANGELOG.md @@ -0,0 +1,20 @@ +# Changelog + +All notable changes to this plugin will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.3.1 (12/19/2024): +Public release version. + +## 0.3.0 (08/29/2024): +This release has renamed this plugin from `mml-inference` to `mml-suggest` and drastically refactored functionality. + +### Features + - the procedure of bleuprint compilation has been completely refactored: + - use `suggest` mode to generate blueprints + - reuse multiple distance measures and determine distance preference relations per pipeline key + - cutoffs ensure top pipelines to be leveraged + - temperature allows to introduce randomness + - automatic inclusion of existing tasks - no need to compile task_list yourself diff --git a/plugins/suggest/LICENSE.txt b/plugins/suggest/LICENSE.txt new file mode 100644 index 0000000..6a39552 --- /dev/null +++ b/plugins/suggest/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 German Cancer Research Center (DKFZ) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/plugins/suggest/MANIFEST.in b/plugins/suggest/MANIFEST.in new file mode 100644 index 0000000..c24f775 --- /dev/null +++ b/plugins/suggest/MANIFEST.in @@ -0,0 +1 @@ +recursive-include src/mml_inference/configs *.yaml \ No newline at end of file diff --git a/plugins/suggest/README.md b/plugins/suggest/README.md new file mode 100644 index 0000000..cc80e92 --- /dev/null +++ b/plugins/suggest/README.md @@ -0,0 +1,30 @@ +# MML Suggest plugin + +This plugin provides a method to compile pipeline blueprints for new tasks. + +# Install + +> Note: this plugin depends on another plugin (mml-similarity) which is installed automatically - though +> this has no side effects. + +```commandline +pip install mml-suggest +``` + + +# Usage + +To leverage existing models and task distances these must be reused: + +```commandline +mml suggest pivot.name=my_target_task +reuse.fed=my_distance_project reuse.models=[some_proj,another_proj,...] +``` + +This will compile a pipeline blueprint for `my_target_task` based on the `fed` task similarities from +`my_distance_project` leveraging all models previously trained in the specified projects. + +To use the blueprint call + +```commandline +mml train pivot.name=my_target_task reuse.blueprint=my_blueprint_proj#the_blueprint_number mode.use_blueprint=true +``` \ No newline at end of file diff --git a/plugins/suggest/pyproject.toml b/plugins/suggest/pyproject.toml new file mode 100644 index 0000000..449c6a9 --- /dev/null +++ b/plugins/suggest/pyproject.toml @@ -0,0 +1,52 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +[build-system] +requires = [ + "setuptools>=42", + "wheel", +] +build-backend = "setuptools.build_meta" + +[tool.pytest.ini_options] +addopts = "--strict-markers --benchmark-skip" +testpaths = [ + "tests", +] +markers = [ + "slow: marks tests as slow (deselect with '-m \"not slow\"')", + "gpu: marks tests as requiring a gpu to run", + "env: marks test that require the correct underlying mml.env file", + "plugin: marks tests that require the loading of plugins", + "serial", +] + +[tool.isort] +src_paths = ["src", "tests"] +profile = "black" +line_length = 120 + +[tool.mypy] +mypy_path = "src" +check_untyped_defs = true +disallow_any_generics = true +ignore_missing_imports = true +no_implicit_optional = true +show_error_codes = true +strict_equality = true +warn_redundant_casts = true +warn_return_any = true +warn_unreachable = true +warn_unused_configs = true +no_implicit_reexport = true +disallow_untyped_defs = true +warn_unused_ignores = true +allow_redefinition = true +warn_no_return = true + +[tool.ruff] +# Set the maximum line length +line-length = 120 \ No newline at end of file diff --git a/plugins/suggest/setup.cfg b/plugins/suggest/setup.cfg new file mode 100644 index 0000000..14e2e91 --- /dev/null +++ b/plugins/suggest/setup.cfg @@ -0,0 +1,48 @@ +[metadata] +name = mml-suggest +version = attr: mml_suggest.__version__ +description = This is the MML suggest plugin, providing methods to compile pipelines from previous knowledge. +long_description = file: README.md +long_description_content_type = text/markdown +author = Patrick Godau +author_email = patrick.godau@dkfz-heidelberg.de +license = MIT +url = https://git.dkfz.de/imsy/ise/mml +classifiers = + Natural Language :: English + Development Status :: 4 - Beta + Environment :: Console + Intended Audience :: Developers + Topic :: Scientific/Engineering :: Artificial Intelligence + Topic :: Scientific/Engineering :: Image Recognition + Topic :: Scientific/Engineering :: Information Analysis + Topic :: Scientific/Engineering :: Image Processing + Topic :: Software Development :: Libraries :: Application Frameworks + Topic :: Software Development :: Version Control :: Git + Operating System :: OS Independent + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Environment :: GPU + Intended Audience :: Science/Research + Typing :: Typed + License :: OSI Approved :: MIT License + +[options] +python_requires = >=3.8 +package_dir = + =src +packages = find: +zip_safe = no +include_package_data = True +install_requires = + mml-core>=1.0.0 + mml-similarity + +[options.entry_points] +mml.plugins = + mml-suggest = mml_suggest.activate + +[options.packages.find] +where=src diff --git a/plugins/suggest/src/mml_suggest/__init__.py b/plugins/suggest/src/mml_suggest/__init__.py new file mode 100644 index 0000000..6ada5d3 --- /dev/null +++ b/plugins/suggest/src/mml_suggest/__init__.py @@ -0,0 +1,9 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +VERSION = (0, 3, 1) +__version__ = ".".join(map(str, VERSION)) +__all__ = ["__version__"] diff --git a/plugins/suggest/src/mml_suggest/activate.py b/plugins/suggest/src/mml_suggest/activate.py new file mode 100644 index 0000000..438c0b8 --- /dev/null +++ b/plugins/suggest/src/mml_suggest/activate.py @@ -0,0 +1,19 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from hydra.core.config_search_path import ConfigSearchPath +from hydra.core.plugins import Plugins +from hydra.plugins.search_path_plugin import SearchPathPlugin + + +# register plugin configs +class MMLSuggestSearchPathPlugin(SearchPathPlugin): + def manipulate_search_path(self, search_path: ConfigSearchPath) -> None: + # Sets the search path for mml with copied config files + search_path.append(provider="mml-suggest", path="pkg://mml_suggest.configs") + + +Plugins.instance().register(MMLSuggestSearchPathPlugin) diff --git a/plugins/suggest/src/mml_suggest/configs/__init__.py b/plugins/suggest/src/mml_suggest/configs/__init__.py new file mode 100644 index 0000000..90ffb6c --- /dev/null +++ b/plugins/suggest/src/mml_suggest/configs/__init__.py @@ -0,0 +1,6 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + diff --git a/plugins/suggest/src/mml_suggest/configs/mode/suggest.yaml b/plugins/suggest/src/mml_suggest/configs/mode/suggest.yaml new file mode 100644 index 0000000..42e3403 --- /dev/null +++ b/plugins/suggest/src/mml_suggest/configs/mode/suggest.yaml @@ -0,0 +1,42 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - override /preprocessing: none +mode: + scheduler: + _target_: mml_suggest.scripts.suggest_scheduler.SuggestScheduler + subroutines: + - suggest + distances: fed # str or list of str of distance.name to incorporate, make sure to set reuse.DISTANCE_NAME=PROJECT + # indicate per pipeline_key and distance measure a "correlation" + # if a (pipeline_key / distance) pair does not exist, will assume 1.0, may be overruled by high temperature value + relation: + arch: + fed: 2.0 + semantic: 2.0 + augmentations: + kld: 2.0 + n: 1 # number of blueprints to generate + # likelihood of ignoring the derived probabilities during sampling and uniformly choose a value by random choice + temperature: 0.05 + sim_cutoff: 0.1 # required quantile of similarity - only include source task within this quantile of task distance + perf_cutoff: 0.1 # required quantile of performance - only include models within this quantile of validation loss + # PipelineCfg + pipeline_keys: + - 'arch' + - 'augmentations' +# - 'cbs' -> most callbacks are more monitoring, aside swa and early are recommendable anyway + - 'loss' + - 'lr_scheduler' + - 'optimizer' + - 'preprocessing' + - 'sampling' + - 'trainer' +# - 'tta' -> tta influences test and predict, but not train and validation +# - 'tune' -> we exclude this as non-transferable and recommend to tune in general diff --git a/plugins/suggest/src/mml_suggest/scripts/__init__.py b/plugins/suggest/src/mml_suggest/scripts/__init__.py new file mode 100644 index 0000000..90ffb6c --- /dev/null +++ b/plugins/suggest/src/mml_suggest/scripts/__init__.py @@ -0,0 +1,6 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + diff --git a/plugins/suggest/src/mml_suggest/scripts/suggest_scheduler.py b/plugins/suggest/src/mml_suggest/scripts/suggest_scheduler.py new file mode 100644 index 0000000..9d696e3 --- /dev/null +++ b/plugins/suggest/src/mml_suggest/scripts/suggest_scheduler.py @@ -0,0 +1,277 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import itertools +import logging +import warnings +from typing import Dict, List, Union + +import numpy as np +import pandas as pd +import scipy +from omegaconf import DictConfig, OmegaConf + +from mml.core.models.lightning_single_frame import CONFIGS_ROUTES +from mml.core.scripts.decorators import beta +from mml.core.scripts.exceptions import MMLMisconfigurationException +from mml.core.scripts.pipeline_configuration import PipelineCfg +from mml.core.scripts.schedulers.base_scheduler import AbstractBaseScheduler +from mml.core.scripts.utils import ARG_SEP, TAG_SEP + +logger = logging.getLogger(__name__) + + +@beta("Suggest mode is in beta.") +class SuggestScheduler(AbstractBaseScheduler): + """ + AbstractBaseScheduler implementation for transferring task specific knowledge. Includes the following subroutines: + - suggest + """ + + def __init__(self, cfg: DictConfig): + # initialize + super(SuggestScheduler, self).__init__(cfg=cfg, available_subroutines=["suggest"]) + # some checks + if not self.pivot: + raise MMLMisconfigurationException("Suggest mode requires a pivot task") + # load distance files + self.distances: Dict[str, pd.DataFrame] = {} + for dist in [self.cfg.mode.distances] if isinstance(self.cfg.mode.distances, str) else self.cfg.mode.distances: + try: + distance_file = self.fm.global_reusables[dist] + except KeyError: + raise MMLMisconfigurationException( + f"Distance {dist} is not present in global artefacts. Make sure " + f"to set reuse.{dist}=SOME_PROJECT properly." + ) + df = pd.read_csv(distance_file, index_col=0) + if self.pivot not in df.columns: + raise RuntimeError(f"pivot task {self.pivot} not in distance {dist} (@ {distance_file})") + # normalize distances + _data = scipy.stats.zscore(df.to_numpy().astype(float), axis=None, nan_policy="omit") + if np.isnan(_data).all(): + warnings.warn( + f"Something went wrong while normalising distance {dist}. Will fall back to normalized " + f"instead of standardized transformation." + ) + _data = df.to_numpy().astype(float) / df.abs().max(axis=None) + if np.isnan(_data).all(): + raise RuntimeError( + f"Something went wrong while normalising distance {dist} - normalization " f"failed." + ) + self.distances[dist] = pd.DataFrame(_data, columns=df.columns, index=df.index) + if len(self.distances) == 0: + raise MMLMisconfigurationException("Must provide at least one valid value for mode.distances") + # assert source tasks are present in all distance files + if any([src not in dist.index for src in self.cfg.task_list for dist in self.distances.values()]): + raise RuntimeError("All source tasks need to be present in all distances.") + # auto-infer source tasks if not given + if len(self.cfg.task_list) == 1 and not (self.cfg.tagging.all or self.cfg.tagging.variants): + logger.info("No task_list given, will include all tasks from (all) distances.") + sources = None + for distance_df in self.distances.values(): + if sources is None: + sources = set(distance_df.index.tolist()) + else: + sources.intersection_update(distance_df.index.tolist()) + counter = 0 + for source in sources: + if source.split(TAG_SEP)[0] == self.pivot: # exclude pivot and pivot variants + continue + counter += 1 + self.cfg.task_list.extend(self.get_nested_variants(source)) + logger.info(f"Added all {counter} found tasks as potential source tasks (plus nested variants).") + + def get_nested_variants(self, task: str) -> List[str]: + """Checks for existing nested variants in the file manager index and adds them to a plain task.""" + variants = [t for t in self.fm.task_index if t.startswith(f"{task}{TAG_SEP}nested{ARG_SEP}")] + # we assume a single nesting does not "change" the task similarity, but exclude multi level tagging + variants = [t for t in variants if TAG_SEP not in t[t.find(f"{t}{TAG_SEP}nested{ARG_SEP}") :]] + variants.append(task) + return variants + + @staticmethod + def get_unnested_variant(task) -> str: + """Returns the unnested variant of a task. ALso works for non-nested tasks.""" + if f"{TAG_SEP}nested{ARG_SEP}" not in task: + return task + return "".join(task.split(f"{TAG_SEP}nested{ARG_SEP}")[:-1]) + + def create_routine(self): + """ + This scheduler implements only a single subroutine. + + :return: None + """ + if "suggest" in self.subroutines: + # -- add suggestion command + self.commands.append(self.suggest) + self.params.append([]) + + def suggest(self): + target_struct = self.get_struct(self.pivot) + sources_with_models = [s for s in self.cfg.task_list if len(self.get_struct(s).models) > 0 and s != self.pivot] + source_structs = {s: self.get_struct(s) for s in sources_with_models} + if len(source_structs) == 0: + raise RuntimeError( + "No source task with existing ModelStorage found. Have you set reuse.models=SOME_PROJECT?" + ) + # make distance suggestions more precise + all_unnested_sources = set(self.get_unnested_variant(src) for src in sources_with_models) + quantiles = {dist: np.nanquantile(df.values, q=self.cfg.mode.sim_cutoff) for dist, df in self.distances.items()} + distance_series = {dist: df[self.pivot] for dist, df in self.distances.items()} + sources_within_quantiles = {dist: series[series <= quantiles[dist]] for dist, series in distance_series.items()} + valid_source_pool = set( + itertools.chain(*[series.index.tolist() for series in sources_within_quantiles.values()]) + ) + if len(valid_source_pool) == 0: + raise RuntimeError( + "No source task is within reach. Consider adding more source tasks, lowering " + "cfg.mode.sim_cutoff and also make sure distance computations are completed." + ) + # prepare pipelines for each available model storage (for each of the source tasks, merging nested variants) + all_pipelines = {self.get_unnested_variant(src): {} for src in source_structs} + for src in source_structs: + unnested_src = self.get_unnested_variant(src) + for model_storage in source_structs[src].models: + pipeline = PipelineCfg.load(path=model_storage.pipeline, pipeline_keys=self.cfg.mode.pipeline_keys) + # loss interpretation is depending on some factors - we hash those and treat them individually + loss_config_str = OmegaConf.to_yaml( + pipeline.pipeline_cfg.loss[CONFIGS_ROUTES[source_structs[src].task_type]] + ) + if pipeline.pipeline_cfg.loss.class_weights: + loss_config_str += str(pipeline.pipeline_cfg.loss.class_weights) + elif pipeline.pipeline_cfg.loss.auto_activate_weighing and not pipeline.pipeline_cfg.sampling.balanced: + loss_config_str += "balanced_class_weights" + loss_id = hash(loss_config_str) + if loss_id not in all_pipelines[unnested_src]: + all_pipelines[unnested_src][loss_id] = [] + all_pipelines[unnested_src][loss_id].append((model_storage.performance, pipeline)) + for loss_id in all_pipelines[unnested_src]: + # only use best performing models + quantile_cutoff = np.nanquantile( + [elem[0] for elem in all_pipelines[unnested_src][loss_id]], q=self.cfg.mode.perf_cutoff + ) + all_pipelines[unnested_src][loss_id] = [ + (perf, pipeline) + for perf, pipeline in all_pipelines[unnested_src][loss_id] + if perf <= quantile_cutoff + ] + # sort ascending, such that best pipelines are positioned first + all_pipelines[unnested_src][loss_id].sort(key=lambda x: x[0]) + # now iterate over all pipeline keys and determine (1) which distance to use (2) which sources to use + sources_per_key = {key: {} for key in self.cfg.mode.pipeline_keys} + for pipeline_key in self.cfg.mode.pipeline_keys: + # set default preferences for this pipeline key + relation = {dist: 1.0 for dist in self.distances} + # load preferred relations + if pipeline_key in self.cfg.mode.relation: + for dist in self.cfg.mode.relation[pipeline_key]: + if dist in relation: # ignore preferences not available in current distances + relation[dist] = self.cfg.mode.relation[pipeline_key][dist] + # normalize to one + rel_sum = sum(relation.values()) + relation = {dist: val / rel_sum for dist, val in relation.items()} + # for each distance sample some source tasks + for dist, series in sources_within_quantiles.items(): + good_keys = series.index.intersection(all_unnested_sources) + for src, val in series.loc[good_keys].to_dict().items(): + # turn distance into likelihood by inverting + if src not in sources_per_key[pipeline_key]: + sources_per_key[pipeline_key][src] = -val * relation[dist] + else: + sources_per_key[pipeline_key][src] -= val * relation[dist] + # determine for each pipeline key the previous pipeline entries to use + pipelines_per_key = {key: [] for key in self.cfg.mode.pipeline_keys} + for pipeline_key in self.cfg.mode.pipeline_keys: + for source, weight in sources_per_key[pipeline_key].items(): + n_loss_ids = len(all_pipelines[source]) + for loss_id_pipeline_list in all_pipelines[source].values(): + list_length = len(loss_id_pipeline_list) + for list_idx, (perf, pipeline) in enumerate(loss_id_pipeline_list): + # position interpolates linearly between 1 and 0.1 + if list_length == 1: + weight_by_position = 0.5 + else: + weight_by_position = 1 - list_idx * (0.9 / (list_length - 1)) + pipelines_per_key[pipeline_key].append((weight_by_position * weight / n_loss_ids, pipeline)) + # normalize and sort per entry + _sum_weights = sum(elem[0] for elem in pipelines_per_key[pipeline_key]) + pipelines_per_key[pipeline_key] = [ + (w / _sum_weights, pipeline) for w, pipeline in pipelines_per_key[pipeline_key] + ] + pipelines_per_key[pipeline_key].sort(key=lambda x: x[0], reverse=True) # descending order + # find a "pivot" pipeline with the highest weight, this will be the starting point for merging + highest_prob_key = max(self.cfg.mode.pipeline_keys, key=lambda key: pipelines_per_key[key][0]) + prim_pipeline = pipelines_per_key[highest_prob_key][0][1] + for _ in range(self.cfg.mode.n): + new_pipeline = prim_pipeline.clone() + # start merging the pipeline - iterate over config elements in a stack + stack = self.cfg.mode.pipeline_keys + rng = np.random.default_rng() + while len(stack) > 0: + path = stack.pop() + # in case this is a dictionary we attach all sub-entry paths to the stack + if OmegaConf.is_dict(OmegaConf.select(new_pipeline.pipeline_cfg, path)): + stack.extend( + [path + "." + str(key) for key in OmegaConf.select(new_pipeline.pipeline_cfg, path).keys()] + ) + continue + # if no dict, the entries should be either lists or primitives, we extract the respective entries + entry_options = {} + for prob, pipeline in pipelines_per_key[path.split(".")[0]]: + val = OmegaConf.select(pipeline.pipeline_cfg, path, default=None) + if val in entry_options: + entry_options[val] += prob + else: + entry_options[val] = prob + if rng.random() < self.cfg.mode.temperature: + # trigger uniform sampling + entry_options = {entry: 1 / len(entry_options) for entry in entry_options} + sampled_entry = self._merge_values(entries=entry_options) + logging.debug(f"Updating {path} to {sampled_entry} (merged from {entry_options}).") + OmegaConf.update(new_pipeline.pipeline_cfg, key=path, value=sampled_entry) + # finally store blueprint + new_pipeline.store(task_struct=target_struct, as_blueprint=True) + logger.info(f"Successfully compiled {self.cfg.mode.n} pipeline blueprint(s).") + + @staticmethod + def _merge_values(entries: Dict[Union[None, str, float, int, list], float]) -> Union[None, str, float, int]: + """ + Merges potential entries within a pipeline. Expects all possible entry values with attached probability value. + Probabilities mus sum to one! + + :param Dict[Union[None, str, float, int, list], float] entries: dictionary with all possible entries as keys and + their respective probability as values. It is important that only a single type of entries is allowed (e.g. + all boolean, or all int) + :return: the chosen entry + """ + if not np.isclose(sum(entries.values()), 1): + raise ValueError("Probabilities do not sum to one!") + # remove Nones + sum_non_none = sum([prob for val, prob in entries.items() if val is not None]) + entries = {val: prob / sum_non_none for val, prob in entries.items() if val is not None} + types = [type(entry) for entry in entries.keys()] + # simple cases + if len(entries) == 0: + return None + if len(entries) == 1: + return next(iter(entries.keys())) + # for multiple values check consistency and chose a primary + assert all([t == types[0] for t in types]), f"inconsistent types {types}" + primary = max(entries.items(), key=lambda x: x[1])[0] + if isinstance(primary, bool): + # treated similarly to int, but converted back to boolean + return bool(sum([k * v for k, v in entries.items()]) > 0.5) + if isinstance(primary, float): + # float is returned as weighted mean + return sum([k * v for k, v in entries.items()]) + if isinstance(primary, int): + # int is also a weighted mean + return int(sum([k * v for k, v in entries.items()])) + if isinstance(primary, str) or isinstance(primary, list): + # str and list are sampled randomly based on weights + return np.random.default_rng().choice(list(entries.keys()), p=list(entries.values())) + raise NotImplementedError(f"did not implement merging for type {type(primary)}") diff --git a/plugins/suggest/tests/conftest.py b/plugins/suggest/tests/conftest.py new file mode 100644 index 0000000..b3c6299 --- /dev/null +++ b/plugins/suggest/tests/conftest.py @@ -0,0 +1,14 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import pytest + + +# by default the fixture below overrides the no_plugins fixture from mml.testing.fixtures to allow plugin testing +# you may remove this deactivation, put it into another submodule conftest.py and/or use the "plugin" marker to +# deactivate plugin loading solely for specific tests +@pytest.fixture(autouse=True) +def no_plugins(monkeypatch, request): + yield diff --git a/plugins/suggest/tests/integration/test_suggest_scheduler.py b/plugins/suggest/tests/integration/test_suggest_scheduler.py new file mode 100644 index 0000000..889bb26 --- /dev/null +++ b/plugins/suggest/tests/integration/test_suggest_scheduler.py @@ -0,0 +1,56 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import shutil + +import numpy as np +import pandas as pd +import pytest +from omegaconf import OmegaConf + +from mml.core.data_loading.task_struct import TaskStructFactory +from mml.core.scripts.model_storage import ModelStorage + + +@pytest.mark.gpu +def test_suggest_mode_console( + script_runner, test_task_monkeypatch, file_manager, dummy_fake_pipeline_path, dummy_fake_model_storage_path +): + # dump some models and pipelines + task_list = ["test_task_a"] + for char in "bc": + task = f"test_task_{char}" + task_list.append(task) + struct = TaskStructFactory.get_by_name(self=None, name=task) # this is monkeypatched by test_task_monkeypatch + for _ in range(3): + p = file_manager.construct_saving_path(OmegaConf.create({}), key="pipeline", task_name=task) + shutil.copy2(src=dummy_fake_pipeline_path, dst=p) + model = ModelStorage.from_json(dummy_fake_model_storage_path) + model.pipeline = p + model_path = file_manager.construct_saving_path( + model, key="models", task_name=task, file_name="model_storage.json" + ) + model.store(path=model_path) + struct.models.append(model) # provide models while side passing reuse functionality + df = pd.DataFrame(data=np.random.rand(len(task_list), len(task_list)), columns=task_list, index=task_list) + # ensure saving path is assigned + import mml_similarity.activate # noqa + + # store dummy distances + df.to_csv(file_manager.construct_saving_path(df, key="fed")) + # since file manager is already initialized, need to manually trigger reuse + file_manager.reuse_cfg = OmegaConf.create({"fed": file_manager.proj_path.name}) + file_manager._find_reusables() + ret = script_runner.run( + [ + "mml", + "suggest", + "pivot.name=test_task_a", # mml should deduce the other tasks as source tasks + # f"+reuse.fed={file_manager.proj_path.name}", # is triggered above + # f"reuse.models={file_manager.proj_path.name}", # is triggered above + ], + print_result=True, + ) + assert ret.success diff --git a/plugins/tags/CHANGELOG.md b/plugins/tags/CHANGELOG.md new file mode 100644 index 0000000..39f3f58 --- /dev/null +++ b/plugins/tags/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +All notable changes to this plugin will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.6.1 (12/19/2024): +Public release version. + +## 0.6.0 (08/29/2024): +This release introduces this changelog. The core dependency has also been bumped. diff --git a/plugins/tags/LICENSE.txt b/plugins/tags/LICENSE.txt new file mode 100644 index 0000000..6a39552 --- /dev/null +++ b/plugins/tags/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 German Cancer Research Center (DKFZ) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/plugins/tags/README.md b/plugins/tags/README.md new file mode 100644 index 0000000..decba67 --- /dev/null +++ b/plugins/tags/README.md @@ -0,0 +1,13 @@ +# MML Tag plugin + +This plugin provides some additional task tags, ready to be imported. + +# Install + +```commandline +pip install mml-tags +``` + +# Usage + +Type `mml-tags` for an overview on available tags and more details. \ No newline at end of file diff --git a/plugins/tags/pyproject.toml b/plugins/tags/pyproject.toml new file mode 100644 index 0000000..449c6a9 --- /dev/null +++ b/plugins/tags/pyproject.toml @@ -0,0 +1,52 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +[build-system] +requires = [ + "setuptools>=42", + "wheel", +] +build-backend = "setuptools.build_meta" + +[tool.pytest.ini_options] +addopts = "--strict-markers --benchmark-skip" +testpaths = [ + "tests", +] +markers = [ + "slow: marks tests as slow (deselect with '-m \"not slow\"')", + "gpu: marks tests as requiring a gpu to run", + "env: marks test that require the correct underlying mml.env file", + "plugin: marks tests that require the loading of plugins", + "serial", +] + +[tool.isort] +src_paths = ["src", "tests"] +profile = "black" +line_length = 120 + +[tool.mypy] +mypy_path = "src" +check_untyped_defs = true +disallow_any_generics = true +ignore_missing_imports = true +no_implicit_optional = true +show_error_codes = true +strict_equality = true +warn_redundant_casts = true +warn_return_any = true +warn_unreachable = true +warn_unused_configs = true +no_implicit_reexport = true +disallow_untyped_defs = true +warn_unused_ignores = true +allow_redefinition = true +warn_no_return = true + +[tool.ruff] +# Set the maximum line length +line-length = 120 \ No newline at end of file diff --git a/plugins/tags/setup.cfg b/plugins/tags/setup.cfg new file mode 100644 index 0000000..f4deb28 --- /dev/null +++ b/plugins/tags/setup.cfg @@ -0,0 +1,49 @@ +[metadata] +name = mml-tags +version = attr: mml_tags.__version__ +description = This is the MML tags plugin, providing additional task tagging options. +long_description = file: README.md +long_description_content_type = text/markdown +author = Patrick Godau +author_email = patrick.godau@dkfz-heidelberg.de +license = MIT +url = https://git.dkfz.de/imsy/ise/mml +classifiers = + Natural Language :: English + Development Status :: 4 - Beta + Environment :: Console + Intended Audience :: Developers + Topic :: Scientific/Engineering :: Artificial Intelligence + Topic :: Scientific/Engineering :: Image Recognition + Topic :: Scientific/Engineering :: Information Analysis + Topic :: Scientific/Engineering :: Image Processing + Topic :: Software Development :: Libraries :: Application Frameworks + Topic :: Software Development :: Version Control :: Git + Operating System :: OS Independent + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Environment :: GPU + Intended Audience :: Science/Research + Typing :: Typed + License :: OSI Approved :: MIT License + +[options] +python_requires = >=3.8 +package_dir = + =src +packages = find: +zip_safe = no +include_package_data = True +install_requires = + mml-core>=1.0.0 + +[options.entry_points] +mml.plugins = + mml-tags = mml_tags.activate +console_scripts = + mml-tags = mml_tags.cli:list_available_tags + +[options.packages.find] +where=src diff --git a/plugins/tags/src/mml_tags/__init__.py b/plugins/tags/src/mml_tags/__init__.py new file mode 100644 index 0000000..681612c --- /dev/null +++ b/plugins/tags/src/mml_tags/__init__.py @@ -0,0 +1,9 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +VERSION = (0, 6, 1) +__version__ = ".".join(map(str, VERSION)) +__all__ = ["__version__"] diff --git a/plugins/tags/src/mml_tags/activate.py b/plugins/tags/src/mml_tags/activate.py new file mode 100644 index 0000000..12a3e57 --- /dev/null +++ b/plugins/tags/src/mml_tags/activate.py @@ -0,0 +1,25 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from mml_tags.tags.confuse import confuse_task +from mml_tags.tags.redistribute_splits import redistribute_splits +from mml_tags.tags.shrink_train import shrink_train +from mml_tags.tags.subclass import subclass_task +from mml_tags.tags.subset import subset_task + +from mml.core.data_preparation.task_creator import TASK_CREATOR_TAG_MAP, TaskCreator + +TaskCreator.shrink_train = shrink_train +TaskCreator.confuse_task = confuse_task +TaskCreator.redistribute_splits = redistribute_splits +TaskCreator.subclass_task = subclass_task +TaskCreator.subset_task = subset_task + +TASK_CREATOR_TAG_MAP["shrink_train"] = "shrink_train" +TASK_CREATOR_TAG_MAP["redistribute_splits"] = "redistribute_splits" +TASK_CREATOR_TAG_MAP["confuse"] = "confuse_task" +TASK_CREATOR_TAG_MAP["subset"] = "subset_task" +TASK_CREATOR_TAG_MAP["subclass"] = "subclass_task" diff --git a/plugins/tags/src/mml_tags/cli.py b/plugins/tags/src/mml_tags/cli.py new file mode 100644 index 0000000..4d43dc9 --- /dev/null +++ b/plugins/tags/src/mml_tags/cli.py @@ -0,0 +1,22 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from mml_tags import __version__ + +from mml.core.data_preparation.task_creator import TASK_CREATOR_TAG_MAP, TaskCreator +from mml.core.scripts.utils import ARG_SEP, TAG_SEP, load_mml_plugins + + +def list_available_tags(): + load_mml_plugins() + print(f"mml_tags plugin, version {__version__}") + print(f"Available tags (total {len(TASK_CREATOR_TAG_MAP)}):") + for tag_id, tag_fct in TASK_CREATOR_TAG_MAP.items(): + print(f" * {tag_id}\n{getattr(TaskCreator, tag_fct).__doc__}\n") + print( + f"\nApply tags with with tag seperator {TAG_SEP} and argument seperator {ARG_SEP}. See configs/tasks for " + f"more details." + ) diff --git a/plugins/tags/src/mml_tags/tags/__init__.py b/plugins/tags/src/mml_tags/tags/__init__.py new file mode 100644 index 0000000..90ffb6c --- /dev/null +++ b/plugins/tags/src/mml_tags/tags/__init__.py @@ -0,0 +1,6 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + diff --git a/plugins/tags/src/mml_tags/tags/confuse.py b/plugins/tags/src/mml_tags/tags/confuse.py new file mode 100644 index 0000000..ae35d7b --- /dev/null +++ b/plugins/tags/src/mml_tags/tags/confuse.py @@ -0,0 +1,48 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +from itertools import chain + +import numpy as np + +from mml.core.data_loading.task_attributes import Modality, TaskType +from mml.core.data_preparation.task_creator import TaskCreator, implements_action +from mml.core.data_preparation.utils import TaskCreatorActions + +logger = logging.getLogger(__name__) + + +@implements_action(TaskCreatorActions.NONE) +def confuse_task(self: TaskCreator, val_string: str) -> None: + """ + Simple version of making a task confusing by setting a fraction of labels as random. + + :param val_string: string of a float within (0, 1), replace comma by underscore (e.g. 0_01 for 1%) + :return: None + """ + if self.current_meta.task_type != TaskType.CLASSIFICATION: + raise RuntimeError("confuse tag only valid for classification task") + percent = float(val_string.replace("_", ".")) * 100 + assert 0 < percent < 100, f"was given tag confuse with {val_string}, must be in range (0, 1)" + logger.info(f"Confusing {percent}% of training data of task {self.current_meta.name}.") + self.protocol(f"Confused with value {val_string}") + # ensure reproducibility + np.random.seed(42) + all_ids = list(chain(*self.current_meta.train_folds)) + confuse_ids = np.random.choice(a=all_ids, size=int(percent * len(all_ids) / 100), replace=False).tolist() + assert abs((len(confuse_ids) * 100 / len(all_ids)) - percent) <= 1, "confusing was not successful" + num_classes = len(set(self.current_meta.idx_to_class.values())) + for confuse_id in confuse_ids: + new_val = np.random.randint(num_classes) + old_val = self.current_meta.train_samples[confuse_id][Modality.CLASS.value] + self.current_meta.train_samples[confuse_id][Modality.CLASS.value] = new_val + self.current_meta.class_occ[self.current_meta.idx_to_class[old_val]] -= 1 + self.current_meta.class_occ[self.current_meta.idx_to_class[new_val]] += 1 + logger.debug( + f"Confused {len(confuse_ids)} out of {len(all_ids)} training_tuples equalling roughly " + f"{len(confuse_ids) * 100 / len(all_ids)}%." + ) diff --git a/plugins/tags/src/mml_tags/tags/redistribute_splits.py b/plugins/tags/src/mml_tags/tags/redistribute_splits.py new file mode 100644 index 0000000..fbdeb96 --- /dev/null +++ b/plugins/tags/src/mml_tags/tags/redistribute_splits.py @@ -0,0 +1,105 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +from collections import Counter + +from mml.core.data_loading.task_attributes import DataSplit, Modality, TaskType +from mml.core.data_preparation.task_creator import TaskCreator, implements_action +from mml.core.data_preparation.utils import TaskCreatorActions + +logger = logging.getLogger(__name__) + + +@implements_action(TaskCreatorActions.SET_STATS) +def redistribute_splits(self: TaskCreator, *new_distribution: str) -> None: + """ + Allows for redistribution of the train-validation-test splits of a task. + + Receives either 1, 2 or 3 arguments that are interpreted as train(:val) or train:val:test percentages. + Values must be floats (given as e.g. '0_25'), in case of 3 arguments they must sum 1, otherwise raises a + :exc:ValueError. + + If one value is provided the test split is left untouched, all train tuples are redistributed into folds, + whereas conserving the number of folds, but fold 1 ... fold n receive together the fraction of samples given + in the argument while fold 0 (which is interpreted as validation fold) receives the rest. Be aware that for + classification tasks balanced classes are tried to be ensured. + + If two values are provided the original test split is dropped, if the two values do not sum up to one, the + remaining fraction is (randomly) selected as new test set (from the original training split). For the rest the + method behaves as in the case with one argument - first value fraction will be distributed across folds 1, ..., + n and the second value fraction become fold 0. + + For the variant with three arguments ALL original samples (train and test) are put into a pool and test split + is resampled from this pool (based on the third value fraction). Afterward with the remaining samples the + procedure is identical to the other argument variants, except as the folds are built from the remaining pool. + + :param new_distribution: either one, two or three strings that represent floats for distributing samples + :return: None + """ + # log + logger.info(f"Redistributing data of task {self.current_meta.name} with {new_distribution=}.") + self.protocol(f"Redistributed with value(s) {new_distribution}.") + # check args + if len(new_distribution) < 1 or len(new_distribution) > 3: + raise ValueError("Redistribute tag must be provided with either 1, 2 or 3 arguments (split by ' ')") + new_distribution = [float(elem.replace("_", ".")) for elem in new_distribution] + drop_original_test = len(new_distribution) == 2 + if drop_original_test: + test_frac = 1 - sum(new_distribution) + if test_frac < 0 or test_frac >= 1: + raise ValueError("Redistribute tag with two arguments must sum within (0, 1].") + new_distribution.append(test_frac) + modify_test = len(new_distribution) == 3 + if modify_test and sum(new_distribution) != 1: + raise ValueError("Redistribute tag with three arguments must sum up to one.") + if not modify_test and (sum(new_distribution) <= 0 or sum(new_distribution) >= 1): + raise ValueError("Redistribute tag with one argument must be within (0, 1) excluding borders.") + if modify_test and self.current_meta.task_type != TaskType.CLASSIFICATION: + raise RuntimeError( + "Since class occurrences are changed if train/test set changes, this is currently " + "only available for classification tasks." + ) + if modify_test and self.fm.preprocessed_data in self.dset_path.parents: + raise RuntimeError( + "Since redistribute tag modifies the test data, this can only be run on a raw (none " + "preprocessed) version of a task. If this task already has been preprocessed with " + "some preprocessing id X, consider creating the task with some dummy preprocessing id " + "e.g. mml info (task settings as before) preprocessing=example and run your " + "original command afterwards." + ) + # set self.data['train'] and self.data['test'], recalculate class_occ if necessary + old_folds_n = len(self.current_meta.train_folds) + if modify_test: + all_ids = list(self.current_meta.train_samples.keys()) + all_samples = self.current_meta.train_samples + if not drop_original_test: + all_ids.extend(list(self.current_meta.test_samples.keys())) + all_samples.update(self.current_meta.test_samples) + # use split folds mechanism to extract the new test split balanced + self.data = {DataSplit.FULL_TRAIN: all_samples} + self.split_folds(n_folds=2, ensure_balancing=True, fold_0_fraction=new_distribution[2], ignore_state=True) + train_ids = self.current_meta.train_folds[1] + test_ids = self.current_meta.train_folds[0] + self.data = { + DataSplit.FULL_TRAIN: {s_id: all_samples[s_id] for s_id in train_ids}, + DataSplit.TEST: {s_id: all_samples[s_id] for s_id in test_ids}, + } + # update class occurrences + self.current_meta.class_occ = Counter( + [self.current_meta.idx_to_class[all_samples[s_id][Modality.CLASS]] for s_id in train_ids] + ) + else: + self.data = { + DataSplit.FULL_TRAIN: self.current_meta.train_samples, + DataSplit.TEST: self.current_meta.test_samplestest_tuples, + } + # calculate validation split and run self.split_folds + if modify_test: + fraction = new_distribution[1] / (new_distribution[0] + new_distribution[1]) + else: + fraction = 1 - new_distribution[0] + self.split_folds(n_folds=old_folds_n, ensure_balancing=True, fold_0_fraction=fraction, ignore_state=True) diff --git a/plugins/tags/src/mml_tags/tags/shrink_train.py b/plugins/tags/src/mml_tags/tags/shrink_train.py new file mode 100644 index 0000000..be24572 --- /dev/null +++ b/plugins/tags/src/mml_tags/tags/shrink_train.py @@ -0,0 +1,109 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging + +import numpy as np +import numpy.random + +from mml.core.data_loading.task_attributes import Modality, TaskType +from mml.core.data_preparation.task_creator import TaskCreator, implements_action +from mml.core.data_preparation.utils import TaskCreatorActions + +logger = logging.getLogger(__name__) + +MIN_OCC_PER_CLASS = 5 # constant representing the minimum occ per class + + +@implements_action(TaskCreatorActions.SET_STATS) +def shrink_train(self: TaskCreator, val_string: str, seed: str = "42") -> None: + """ + Alternative version of sub-setting a task. Every fold but fold 0 (which will be used for evaluation) + is deterministically shrunk to sum all remaining training samples to total val_string. + + MIN_OCC_PER_CLASS ensures (if sufficient samples of a class are available) a minimum number of samples of a + class. + + :param val_string: string of an int within [(num_folds - 1)*5*num_classes, (num_folds - 1) * num_samples / num_folds] + :return: None, influences current_meta attribute + """ + if self.current_meta.task_type != TaskType.CLASSIFICATION: + raise NotImplementedError(f"shrink_train is not implemented for task type {self.current_meta.task_type}") + new_total_class_occ = {val: 0 for val in set(self.current_meta.idx_to_class.values())} + num_folds = len(self.current_meta.train_folds) + max_samples = sum([len(fold) for fold in self.current_meta.train_folds[1:]]) + min_samples = (num_folds - 1) * MIN_OCC_PER_CLASS * len(new_total_class_occ) + remaining = int(val_string) + assert ( + min_samples <= remaining <= max_samples + ), f"was given tag subset with {val_string=}, must be in range [{min_samples}, {max_samples}]" + logger.info( + f"Shrinking training folds of task {self.current_meta.name} to {remaining} of training " + f"data (ensuring folds). Seed is: {seed}." + ) + self.protocol(f"Shrink training with value {val_string} and seed {seed}") + for fold_ix, fold in enumerate(self.current_meta.train_folds): + # skip first fold, this will be the validation / test split + if fold_ix == 0: + continue + # set random seed to ensure reproducibility + rng = numpy.random.default_rng(int(seed) + fold_ix * 42) + # calculate remaining size for this fold + size = remaining // (num_folds - 1) + if remaining % (num_folds - 1) > fold_ix: + size += 1 + assert 1 <= size <= len(fold), f"Size requirement for fold {fold_ix} not met, {size=} but {len(fold)=}." + # assert all classes have enough occurrences + pre_selection = set() + for cls in new_total_class_occ: + cls_samples = [ + sample_id + for sample_id in fold + if self.current_meta.idx_to_class[self.current_meta.train_samples[sample_id][Modality.CLASS.value]] + == cls + ] + if len(cls_samples) < MIN_OCC_PER_CLASS: + logger.warning(f"Only {len(cls_samples)} samples for class {cls} " f"(requires {MIN_OCC_PER_CLASS}).") + pre_selection.update(cls_samples) + else: + pre_selection.update(rng.choice(a=cls_samples, size=MIN_OCC_PER_CLASS, replace=False).tolist()) + # now fill the remaining gap + if size - len(pre_selection) <= 0: + raise RuntimeError("Too many classes to ensure sufficient samples per class in each fold.") + non_selected = [sample_id for sample_id in fold if sample_id not in pre_selection] + post_selection = rng.choice(a=non_selected, size=size - len(pre_selection), replace=False).tolist() + new_fold = np.random.permutation(list(pre_selection) + post_selection).tolist() + new_fold_class_occ = {val: 0 for val in set(self.current_meta.idx_to_class.values())} + for sample_id in new_fold: + new_fold_class_occ[ + self.current_meta.idx_to_class[self.current_meta.train_samples[sample_id][Modality.CLASS]] + ] += 1 + if not all([occ >= MIN_OCC_PER_CLASS for occ in new_fold_class_occ.values()]): + logger.warning( + f"not sufficient samples to guarantee {MIN_OCC_PER_CLASS} occ per class in " + f"fold {fold_ix}, resulting occ was {new_fold_class_occ}." + ) + else: + # successful shrinkage + logger.debug( + f"was able to guarantee {MIN_OCC_PER_CLASS} occ per class in fold {fold_ix}, " + f"resulting occ was {new_fold_class_occ}." + ) + logger.debug( + f"Shrunk fold {fold_ix} from {len(fold)} to {len(new_fold)} equalling roughly " + f"{len(new_fold) * 100 / len(fold):.2f}%." + ) + # Remove unused samples + unused = [sample_id for sample_id in self.current_meta.train_folds[fold_ix] if sample_id not in set(new_fold)] + for sample_id in unused: + self.current_meta.train_samples.pop(sample_id) + # update total class_occ + for k, v in new_fold_class_occ.items(): + new_total_class_occ[k] += v + # finally set the fold + self.current_meta.train_folds[fold_ix] = new_fold + # set new total class occ, this one ignores the validation split! + self.current_meta.class_occ = new_total_class_occ diff --git a/plugins/tags/src/mml_tags/tags/subclass.py b/plugins/tags/src/mml_tags/tags/subclass.py new file mode 100644 index 0000000..34c6fad --- /dev/null +++ b/plugins/tags/src/mml_tags/tags/subclass.py @@ -0,0 +1,23 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from typing import List + +from mml.core.data_preparation.task_creator import TaskCreator, implements_action +from mml.core.data_preparation.utils import TaskCreatorActions + + +@implements_action(TaskCreatorActions.NONE) +def subclass_task(self: TaskCreator, *classes_to_keep: List[str]) -> None: + """ + Restricts the task to the classes given. This may be either ... + :param classes_to_keep: + :return: + """ + # TODO implement functionality + # requires remapping in idx_to_class! + # requires new class_occ + raise NotImplementedError() diff --git a/plugins/tags/src/mml_tags/tags/subset.py b/plugins/tags/src/mml_tags/tags/subset.py new file mode 100644 index 0000000..3f45762 --- /dev/null +++ b/plugins/tags/src/mml_tags/tags/subset.py @@ -0,0 +1,64 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +from collections import Counter + +import numpy as np + +from mml.core.data_loading.task_attributes import Modality, TaskType +from mml.core.data_preparation.task_creator import TaskCreator, implements_action +from mml.core.data_preparation.utils import TaskCreatorActions + +logger = logging.getLogger(__name__) + + +@implements_action(TaskCreatorActions.SET_FOLDING) +def subset_task(self: TaskCreator, val_string: str) -> None: + """ + Simple version of subsetting a task. Every fold will be deterministically shrunk to roughly val_string + * 100 percent of samples. This process will not take class balance into consideration. + + :param val_string: string of a float within (0, 1), replace comma by underscore (e.g. 0_01 for 1%) + :return: False, since by sub-setting heavy stats shifts may occur + """ + percent = float(val_string.replace("_", ".")) * 100 + assert 0 < percent < 100, f"was given tag subset with {val_string=}, must be in range (0, 1)" + logger.info(f"Subsetting task {self.current_meta.name} to {percent}% of training data (ensuring folds).") + self.protocol(f"Subset with value {val_string}") + # set random seed to ensure reproducibility + np.random.seed(42) + for fold_ix, fold in enumerate(self.current_meta.train_folds): + # version 1 + size = int(percent * len(fold) / 100) + if size == 0: + msg = f"Subsetting to {percent}% would result in 0 samples within fold {fold_ix}" + logger.critical(msg) + raise RuntimeError(msg) + new_fold = np.random.choice(a=fold, size=size, replace=False).tolist() + assert abs((len(new_fold) * 100 / len(fold)) - percent) <= 1, "subsetting was not successful" + logger.debug( + f"Shrunk fold {fold_ix} from {len(fold)} to {len(new_fold)} equalling roughly " + f"{len(new_fold) * 100 / len(fold):.2f}%." + ) + # Remove unused samples + unused = [sample_id for sample_id in self.current_meta.train_folds[fold_ix] if sample_id not in set(new_fold)] + for sample_id in unused: + self.current_meta.train_samples.pop(sample_id) + # finally set the fold + self.current_meta.train_folds[fold_ix] = new_fold + # re-compute class occurrences + if self.current_meta.task_type == TaskType.CLASSIFICATION: + self.current_meta.class_occ = Counter( + [ + self.current_meta.idx_to_class[sample[Modality.CLASS]] + for sample in self.current_meta.train_samples.values() + ] + ) + # we might have lost some classes due to subsetting + for cls in self.current_meta.idx_to_class.values(): + if cls not in self.current_meta.class_occ: + self.current_meta.class_occ[cls] = 0 diff --git a/plugins/tags/tests/conftest.py b/plugins/tags/tests/conftest.py new file mode 100644 index 0000000..b3c6299 --- /dev/null +++ b/plugins/tags/tests/conftest.py @@ -0,0 +1,14 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import pytest + + +# by default the fixture below overrides the no_plugins fixture from mml.testing.fixtures to allow plugin testing +# you may remove this deactivation, put it into another submodule conftest.py and/or use the "plugin" marker to +# deactivate plugin loading solely for specific tests +@pytest.fixture(autouse=True) +def no_plugins(monkeypatch, request): + yield diff --git a/plugins/tags/tests/unit/test_dummy.py b/plugins/tags/tests/unit/test_dummy.py new file mode 100644 index 0000000..6259249 --- /dev/null +++ b/plugins/tags/tests/unit/test_dummy.py @@ -0,0 +1,9 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + + +def test_dummy(): + pass diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..d89fbe0 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,61 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +[build-system] +requires = [ + "setuptools>=42", + "wheel", +] +build-backend = "setuptools.build_meta" + +[tool.pytest.ini_options] +addopts = "-p pytest_cov --cov --cov-config=tox.ini --cov-append --strict-markers --junitxml=unit_test_report.xml --benchmark-skip" +testpaths = [ + "tests", +] +markers = [ + "slow: marks tests as slow (deselect with '-m \"not slow\"')", + "gpu: marks tests as requiring a gpu to run", + "env: marks test that require the correct underlying mml.env file", + "plugin: marks tests that require the loading of plugins", + "serial", +] + +filterwarnings = [ + # note the use of single quote below to denote "raw" strings in TOML + 'ignore:MMLFilemanager was not created by BaseScheduler:UserWarning', # often we mock the filemanager + 'ignore:.*not yet preprocessed. Pipeline contains.*:UserWarning', # warning of non-preprocessed data + 'ignore:.*does not have many workers.*:UserWarning', # warning for low number of workers + 'ignore:The number of training batches:UserWarning', # warning for low number of batches + 'ignore:THIS BEHAVIOUR CHANGED:UserWarning', # warning for mml behaviour changes +] + +[tool.isort] +src_paths = ["src", "tests"] +profile = "black" +line_length = 120 + +[tool.mypy] +mypy_path = "src" +check_untyped_defs = true +disallow_any_generics = true +ignore_missing_imports = true +no_implicit_optional = true +show_error_codes = true +strict_equality = true +warn_redundant_casts = true +warn_return_any = true +warn_unreachable = true +warn_unused_configs = true +no_implicit_reexport = true +disallow_untyped_defs = true +warn_unused_ignores = true +allow_redefinition = true +warn_no_return = true + +[tool.ruff] +# Set the maximum line length +line-length = 120 \ No newline at end of file diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..1eb4be4 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,107 @@ +[metadata] +name = mml-core +version = attr: mml.__version__ +description = This is the MML toolkit, targeting lifelong/continual/meta learning in Surgical Data Science. +long_description = file: README.md +long_description_content_type = text/markdown +author = Patrick Godau +author_email = patrick.scholz@dkfz-heidelberg.de +license = MIT +url = https://git.dkfz.de/imsy/ise/mml +classifiers = + Natural Language :: English + Development Status :: 4 - Beta + Environment :: Console + Environment :: GPU + Intended Audience :: Developers + Intended Audience :: Science/Research + Topic :: Scientific/Engineering :: Artificial Intelligence + Topic :: Scientific/Engineering :: Image Recognition + Topic :: Scientific/Engineering :: Information Analysis + Topic :: Scientific/Engineering :: Image Processing + Topic :: Software Development :: Libraries :: Application Frameworks + Topic :: Software Development :: Libraries :: Python Modules + Topic :: Software Development :: Version Control :: Git + Operating System :: OS Independent + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Typing :: Typed + License :: OSI Approved :: MIT License + +[options] +python_requires = >=3.8 +package_dir = + =src +packages = find: +zip_safe = no +include_package_data = True +install_requires = + torch + torchvision + torchmetrics + segmentation-models-pytorch==0.3.3 + plotly + statsmodels==0.13.5 + matplotlib + lightning + tensorboard + albumentations + pandas + hydra-core==1.3.2 + hydra-colorlog + hydra-optuna-sweeper>=1.2 + python-dotenv + rarfile + colorama + p-tqdm==1.4.0 + orjson==3.9.2 + ijson + scikit-learn + scikit-image + kaggle==1.5.15 + setuptools + Deprecated + pytest==7.4.0 + kornia + rich + prettytable + jupyter + humanize + psrcal==0.0.2 + quapy==0.1.9 + +[options.extras_require] +dev = + pytest-console-scripts + pytest-cov + pytest-benchmark + mypy + ruff + pylint + tox + isort + types-requests + types-Deprecated + add-license-header +docs = + sphinx + sphinx-rtd-theme + myst-nb + sphinxcontrib-autoyaml + lightning-fabric + +;[options.package_data] +;mml = py.typed + +[options.entry_points] +console_scripts = + mml = mml.cli:main + mml-env-setup = mml.cli:copy_mml_env_file + mml-copy-conf = mml.cli:copy_mml_configs +pytest11 = + mml-test-utils = mml.testing.fixtures + +[options.packages.find] +where = src diff --git a/src/mml/__init__.py b/src/mml/__init__.py new file mode 100644 index 0000000..3b87f52 --- /dev/null +++ b/src/mml/__init__.py @@ -0,0 +1,13 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import os + +# deactivate warning on non-up-to-date albumentations version +os.environ["NO_ALBUMENTATIONS_UPDATE"] = "1" + +VERSION = (1, 0, 0) +__version__ = ".".join(map(str, VERSION)) +__all__ = ["__version__"] diff --git a/src/mml/__main__.py b/src/mml/__main__.py new file mode 100644 index 0000000..42d2de7 --- /dev/null +++ b/src/mml/__main__.py @@ -0,0 +1,321 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import os +import platform +import shutil +import sys +import warnings +from pathlib import Path +from typing import List + +import cv2 +import hydra +import lightning # noqa +import matplotlib +import optuna +import torch +from hydra.core.hydra_config import HydraConfig +from hydra.core.utils import configure_log +from omegaconf import DictConfig, OmegaConf + +import mml +import mml.core.scripts.utils as script_utils # we need to import the module to be able to monkeypatch in tests +from mml.core.scripts.exceptions import MMLMisconfigurationException +from mml.core.scripts.notifier import BaseNotifier +from mml.core.visualization.logo import show_logo + +# prevent lightning to add console logger and prevent propagation +logging.getLogger().addHandler(logging.NullHandler()) +pl_logger = logging.getLogger("lightning") +if pl_logger.handlers: + pl_logger.removeHandler(pl_logger.handlers[0]) +pl_logger.setLevel(logging.NOTSET) + +logger = logging.getLogger("mml") + + +def wrapped_mml() -> float: + """ + Wraps the mml main function with environmental loading. So first sets constants of third party libraries and loads + MML env file as well as potential plugins. + + :return: forwards the return value of the scheduler, see :meth:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler.run` + """ + # ╔════════════════════════════╗ + # ║ ENVIRONMENT INITIALIZATION ║ + # ╚════════════════════════════╝ + # trade in precision for some speedup, see + # https://pytorch.org/docs/stable/generated/torch.set_float32_matmul_precision.html + torch.set_float32_matmul_precision("high") + # choose always non-interactive backend + matplotlib.use("Agg") + # Limit the number of threads when using OpenCV to avoid CPU bottlenecks on shared hardware + cv2.setNumThreads(1) + # Limit the number of threads when using pytorch to avoid CPU bottlenecks on shared hardware + torch.set_num_threads(1) + # load environment variables, must be done before decorating hydra + script_utils.load_env() + # load mml.plugins, this allows for added schedulers, tasks, ... + script_utils.load_mml_plugins() + # formatting of warnings, omit the newline and source code line in message + formatwarning_orig = warnings.formatwarning + warnings.formatwarning = lambda message, category, filename, lineno, line=None: formatwarning_orig( + message, category, filename, lineno, line="" + ).strip() + # load the correct root folder of the configs which is determined as variable in the env file (if not using default + # config folder from within mml) + if os.environ["MML_CONFIGS_PATH"] == "DEFAULT_CONF_PATH": + rel_config_path = "configs" + else: + from hydra.core.config_search_path import ConfigSearchPath + from hydra.core.plugins import Plugins + from hydra.plugins.search_path_plugin import SearchPathPlugin + + class MMLCoreConfigsSearchPathPlugin(SearchPathPlugin): + def manipulate_search_path(self, search_path: ConfigSearchPath) -> None: + # Sets the search path for mml with copied config files + search_path.append(provider="mml-conf-copy", path=f"file://{os.environ['MML_CONFIGS_PATH']}") + + Plugins.instance().register(MMLCoreConfigsSearchPathPlugin) + rel_config_path = None + + # ╔═══════════════════╗ + # ║ SPECIAL CLI CASES ║ + # ╚═══════════════════╝ + + # catch corner case of --version call (must be done before running hydra) + if "--version" in sys.argv: + print(f"mml-core {mml.__version__}") + print(" -------------") + for plugin, version in sorted(mml.core.scripts.utils.MML_PLUGINS_LOADED.items(), key=lambda x: x[0]): + print(f"{plugin} {version}") + sys.exit() + + # catch corner case of plain mml call without mode or other information + if len(sys.argv) == 1: + show_logo(indent=8) + print("╔═══════════════════════════════════════════════════════════╗") + print("║ For usage details you may ║") + print("║ * visit the docs (https://imsy.pages.dkfz.de/ise/mml) ║") + print('║ * call "mml --help" ║') + print("╚═══════════════════════════════════════════════════════════╝") + if os.getenv("MML_ENV_PATH", None): + print(f'MML_ENV_PATH has been set to {os.getenv("MML_ENV_PATH")}') + else: + print("MML_ENV_PATH has not been set") + print('For a list of installed plugins call "mml --version".') + sys.exit() + + # argv modification making "mml anything ARGS" -> "mml mode=anything ARGS" + if "mode=" in sys.argv[1]: + print('\nWARNING:\nYou may drop the "mode=" string as long as you place the value as first mml argument.\n\n') + elif len(sys.argv) >= 2 and any(arg.startswith("mode=") for arg in sys.argv[2:]): + print( + "\nWARNING:\nProviding mode as non first argument is deprecated and the api might remove support in " + 'the future. Please run for example as "mml info OVERRIDES" or "mml train OVERRIDES"\n\n' + ) + elif sys.argv[1].startswith("--") or sys.argv[1].startswith("-"): + # catch other corner cases e.g. mml --help, we do not want to raise awareness in these cases + pass + elif "=" in sys.argv[1]: + # options are given, but no mode has been provided + print( + "\nWARNING:\nYou did not provide a mode to mml. Will fallback to info mode. Please use " + '"mml info KWARGS" instead.\n\n' + ) + else: + # now we can expect the user to have intended that the argv[1] should be extended with mode= + sys.argv[1] = "mode=" + sys.argv[1] + + # ╔══════════════════════════════════╗ + # ║ INVOKE HYDRA FOR CFG COMPILATION ║ + # ╚══════════════════════════════════╝ + + # define main function, wrapped by hydra, which loads the config files and handles overwrites + @hydra.main(version_base=None, config_path=rel_config_path, config_name=os.environ["MML_CONFIG_NAME"]) + def mml_main(cfg: DictConfig) -> float: + """ + Hydra-wrapped main function. This function will be repeated in "multirun" scenarios. It's return value will + be used by hydra sweepers (e.g. in hyperparameter optimization scenarios). See + `hydra multirun `_ and + `hydra sweepers `_ for more on this. + + :param cfg: the omegaconf configuration compiled by hydra + :return: the return value of the scheduler, see :meth:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler.run` + """ + # ╔════════════════════╗ + # ║ MML INITIALIZATION ║ + # ╚════════════════════╝ + if cfg["use_best_params"] and cfg["continue"]: + raise MMLMisconfigurationException("use_best_params and continue functionality do not work together!") + # reuse optimized hyperparameters directly + if cfg["use_best_params"]: + # indicates to use existing hyperparameter optimization results, first try to load a summary yaml + hpo_path = Path(cfg["proj_path"]) / "hpo" / cfg["use_best_params"] / "optimization_results.yaml" + if hpo_path.exists(): + logger.debug(f"Found existing hpo results at {hpo_path}. Will load.") + hpo_results = OmegaConf.load(hpo_path) + best_params = hpo_results["best_params"] + else: + # summary yaml not found, study might not have finished, check whether a persistent storage exists + try: + loaded_study = optuna.load_study(study_name=cfg["use_best_params"], storage=cfg.hpo.storage) + except KeyError: + raise MMLMisconfigurationException( + "use_best_params was not able to load study. Here are some potential reasons this might have " + "failed:\n - study was interrupted, without persistent storage (see e.g. mml-sql) no " + "intermediate results are kept alive\n - without persistent storage no cross-project loading is " + "supported for now, is proj set correctly?\n - in case you tried a persistent storage, have you " + "configured hpo.storage correctly AND provided it to this call?\n - also consider typos in your " + "arg, you need either to name the exact optuna study OR the hpo folder of THIS project" + ) + best_params = loaded_study.best_params + # re-compose the config, we provide the optimized overrides first and then add the ones directly provided + # this ensures the latter outrule the former and allow modification of optimized param results + provided_overrides = OmegaConf.to_container(HydraConfig.get().overrides.task) + overrides = [key + "=" + val for key, val in best_params.items()] + provided_overrides + updated_cfg = hydra.compose( + config_name=os.environ["MML_CONFIG_NAME"], overrides=overrides, return_hydra_config=False + ) + cfg = updated_cfg + logger.info("-------------------------------------------------------------------------------------") + logger.info( + f"Loaded hpo results from study {cfg['use_best_params']} and merged {len(best_params)} params into config." + ) + for k, v in best_params.items(): + logger.info(f" > {k}={v}") + logger.info("-------------------------------------------------------------------------------------") + + # implements the continue functionality, despite the continue flag and project all other config + # specifications will be disregarded and instead overwritten by the loaded config + if cfg["continue"]: + if "hpo" in Path(os.getcwd()).parts: + raise ValueError("cannot continue in hyper-parameter-optimization (--multirun) mode") + # delete already created run folder + exp_path = Path(os.getcwd()) + single_day_event = len([p for p in exp_path.parent.iterdir() if p.is_dir()]) == 1 + del_path = exp_path.parent if single_day_event else exp_path + shutil.rmtree(del_path) + # if continuing latest detect that folder + if cfg["continue"] == "latest": + day_path = sorted([date for date in (Path(cfg.proj_path) / "runs").iterdir() if date.is_dir()])[-1] + time_path = sorted([time for time in day_path.iterdir() if time.is_dir()])[-1] + cfg["continue"] = day_path.name + "/" + time_path.name + else: + selected_path = Path(cfg["proj_path"]) / "runs" / cfg["continue"] + if not selected_path.exists(): + msg = f'Chosen value results in not existent path {selected_path}.' + logger.error(msg) + raise ValueError(msg) + # change cwd to selected run + os.chdir(str(Path(cfg["proj_path"]) / "runs" / cfg["continue"])) + # load stored cfg (but keep continue variable!) + cfg_path = Path(os.getcwd()) / ".hydra" / "config.yaml" + assert cfg_path.exists() + old_cfg = cfg.copy() + cfg = OmegaConf.load(cfg_path) + cfg["continue"] = old_cfg["continue"] + cfg["data_dir"] = old_cfg["data_dir"] + cfg["out_dir"] = old_cfg["out_dir"] + cfg["num_workers"] = old_cfg["num_workers"] + hydra_cfg = HydraConfig.get() + # this is the NEW hydra config, interestingly this allows to enable verbose mode afterward + configure_log(DictConfig(hydra_cfg.job_logging), hydra_cfg.verbose) + logger.info("-------------------------------------------------------------------------------------") + logger.info(f"Continuing from {os.getcwd()}.") + logger.info("-------------------------------------------------------------------------------------") + # resolve type + cfg["num_workers"] = int(cfg["num_workers"]) + # activate warnings logging (if configured) + logging.captureWarnings(cfg.logging.capture_warnings) + try: + hydra_cfg = HydraConfig.get() + choices = OmegaConf.to_container(hydra_cfg.runtime.choices) + mode = choices["mode"] + except ValueError: + mode = "unknown" + logger.info( + f"Started MML {mml.__version__} on Python {platform.python_version()} with mode {str(mode).upper()}." + ) + logger.info(f"Plugins loaded: {list(mml.core.scripts.utils.MML_PLUGINS_LOADED.keys())}") + # instantiate notifiers + all_notifiers: List[BaseNotifier] = [ + hydra.utils.instantiate(cfg.logging.notifier[elem]) for elem in cfg.logging.notifier if elem != "dummy" + ] + logger.debug(f"Instantiated {len(all_notifiers)} notifiers.") + for notifier in all_notifiers: + notifier.notify_on_start() + with script_utils.catch_time() as init_timer: + try: + scheduler = hydra.utils.instantiate(cfg.mode.scheduler, cfg) + except Exception as e: + logger.exception("MML failed during initialization!") + if isinstance(e, KeyboardInterrupt): + logger.info(f"Omitted notification for class {e.__class__}.") + else: + for notifier in all_notifiers: + notifier.notify_on_failure(error=e) + raise e + logger.info(f"MML init time was {init_timer.pretty_time}.") + # ╔═════════════╗ + # ║ MML RUNTIME ║ + # ╚═════════════╝ + # start scheduler + with script_utils.catch_time() as run_timer: + try: + try: + val = scheduler.run() + except OSError as e: + # Exception.add_note() is only available from python 3.11 so we have to raise a nested error + if isinstance(e, OSError) and "Too many open files:" in str(e): + raise OSError( + "Too many open files! Try increasing your open file limit (check 'ulimit -n' on " + "UNIX systems)." + ) from e + else: + raise + except Exception as e: + logger.exception("MML failed during runtime!") + if isinstance(e, KeyboardInterrupt) or isinstance(e, InterruptedError): + logger.info(f"Omitted notification for class {e.__class__}.") + else: + for notifier in all_notifiers: + notifier.notify_on_failure(error=e) + raise e + finally: + if scheduler.lock_path.exists(): + scheduler.lock_path.unlink() + logger.debug(f"Deleted run path lock at {scheduler.lock_path}.") + else: + warnings.warn(UserWarning(f"No lock path found at {scheduler.lock_path}.")) + logger.info(f"MML run time was {run_timer.pretty_time}.") + # check and report return value + if val is not None: + # optuna has issues with inf value to store in SQL database, replace with very large float if necessary + if val == float("inf"): + response = float("1.e5") + logger.error(f"Was returned {val}, will convert to {response} to ensure optuna usage.") + val = response + # log final return value of the scheduler + return_val_path = Path(os.getcwd()) / "return_val.txt" + with open(return_val_path, "w") as f: + f.write(str(val)) + logger.info(f"Return value is {val}.") + for notifier in all_notifiers: + notifier.notify_on_end(return_value=val) + return val + + # run main + return mml_main() + + +if __name__ == "__main__": + """ + This code part will be triggered if calling 'python -m mml' instead of cli interface 'mml'. Compare with 'cli.py'. + """ + wrapped_mml() diff --git a/src/mml/api/__init__.py b/src/mml/api/__init__.py new file mode 100644 index 0000000..f54463e --- /dev/null +++ b/src/mml/api/__init__.py @@ -0,0 +1,86 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# data loading imports +from mml.core.data_loading.file_manager import MMLFileManager, ReuseConfig +from mml.core.data_loading.lightning_datamodule import MultiTaskDataModule +from mml.core.data_loading.task_attributes import ( + EMPTY_MASK_TOKEN, + IMAGENET_MEAN, + IMAGENET_STD, + DataSplit, + Keyword, + License, + Modality, + RGBInfo, + Sizes, + TaskType, +) +from mml.core.data_loading.task_dataset import TaskDataset, TupelizedTaskDataset +from mml.core.data_loading.task_description import TaskDescription +from mml.core.data_loading.task_struct import TaskStruct +from mml.core.data_preparation.data_archive import DataArchive, DataKind + +# data preparation imports +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import create_creator_func, register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import ( + get_iterator_and_mapping_from_image_dataset, + get_iterator_from_segmentation_dataset, +) +from mml.core.models.lightning_single_frame import SingleFrameLightningModule + +# module imports +from mml.core.models.torch_base import BaseModel + +# script imports +from mml.core.scripts.model_storage import EnsembleStorage, ModelStorage +from mml.core.scripts.pipeline_configuration import PIPELINE_CONFIG_PARTS, PipelineCfg +from mml.core.scripts.schedulers.base_scheduler import AbstractBaseScheduler +from mml.core.scripts.utils import ARG_SEP, TAG_SEP, catch_time, load_env, load_mml_plugins, throttle_logging + +__all__ = [ + "MMLFileManager", + "ReuseConfig", + "MultiTaskDataModule", + "IMAGENET_MEAN", + "IMAGENET_STD", + "License", + "Keyword", + "TaskType", + "TaskDataset", + "TupelizedTaskDataset", + "TaskStruct", + "DSetCreator", + "get_iterator_and_mapping_from_image_dataset", + "get_iterator_from_segmentation_dataset", + "TaskCreator", + "SingleFrameLightningModule", + "BaseModel", + "AbstractBaseScheduler", + "PIPELINE_CONFIG_PARTS", + "PipelineCfg", + "catch_time", + "load_env", + "load_mml_plugins", + "throttle_logging", + "create_creator_func", + "register_dsetcreator", + "register_taskcreator", + "RGBInfo", + "Sizes", + "EMPTY_MASK_TOKEN", + "DataSplit", + "Modality", + "DataKind", + "DataArchive", + "TaskDescription", + "TAG_SEP", + "ARG_SEP", + "ModelStorage", + "EnsembleStorage", +] diff --git a/src/mml/cli.py b/src/mml/cli.py new file mode 100644 index 0000000..c82af74 --- /dev/null +++ b/src/mml/cli.py @@ -0,0 +1,105 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import os +import shutil +import sys +from pathlib import Path + +from mml.__main__ import wrapped_mml + + +def main() -> None: + """ + Command line convenience. Allows after setup to call 'mml CONFIG_OPTIONS' instead of 'python -m mml CONFIG_OPTIONS' + """ + wrapped_mml() + + +def copy_mml_env_file() -> None: + """ + This CLI command sets up an `mml.env` file at your current location, based on the `example.env` file shipped with + `mml`. + """ + if os.getenv("MML_ENV_PATH", None): + raise RuntimeError( + f"Found env variable 'MML_ENV_PATH', has mml already been configured? If you want to " + f"redo mml env init, make sure MML_ENV_PATH is unset (current " + f"value={os.getenv('MML_ENV_PATH')})." + ) + template_env = Path(__file__).parent / "template.env" + default_env_path = template_env.parent / "mml.env" + if default_env_path.exists(): + raise RuntimeError( + f"Found existing mml.env file at default location {default_env_path}. Please remove to " + f"redo mml env init." + ) + # copy and rename template + destination = Path(os.getcwd()) / "mml.env" + if destination.exists(): + raise RuntimeError( + f"Found existing mml.env file at current location {destination}. Please remove to " f"redo mml env init." + ) + shutil.copyfile(src=template_env, dst=destination) + # report + print(f"Created mml.env file successfully. Path={destination}") + print("Your next steps:") + print(" - modify at least MML_DATA_PATH, MML_RESULTS_PATH and MML_LOCAL_WORKERS accordingly") + print(f" - set MML_ENV_PATH variable in your environment (conda env config vars set MML_ENV_PATH={destination})") + print(" - if you created the file somewhere version controlled, make sure to gitignore this confidential file!") + + +def copy_mml_configs() -> None: + """ + This is a CLI command that sets up mml configs outside the mml package, the basic idea is to copy the default + configs to a location of desire and link that location in the "mml.env". + """ + destination = Path(os.getcwd()) / "configs" + source = Path(__file__).parent / "configs" + print("Copying MML configs. This copies the default configs to your current working dir.") + if destination.exists(): + print(f"Folder >configs< already exits at {destination}. Remove any artefacts and restart.") + sys.exit(1) + print(f"Are you sure to create a folder 'configs' at {destination}? [Y/n]") + answer = input() + if answer.lower() not in ["y", "n", ""]: + print("Invalid input, will cancel initialisation.") + sys.exit(1) + if answer.lower() == "n": + print("MML config copy canceled.") + sys.exit(0) + # copy configs folder + shutil.copytree(src=source, dst=destination) + print("Configs folder created successfully!") + # determine env file + template_env = Path(__file__).parent / "example.env" + assert template_env.exists(), "Template for env variables not found!" + if os.getenv("MML_ENV_PATH", None): + env_path = Path(os.getenv("MML_ENV_PATH")) + else: + env_path = template_env.parent / "mml.env" + if not env_path.exists(): + print("No mml.env file found, will create from template.") + shutil.copyfile(src=template_env, dst=env_path) + # read in config env file + with open(env_path, "r") as f: + lines = f.readlines() + # find line to modify + prefix = "export MML_CONFIGS_PATH" + try: + line_idx = [line.startswith(prefix) for line in lines].index(True) + except ValueError: + print(f"No line in {env_path.name} starts with {prefix}. Will add a line, make sure no mess up happened!") + lines.append(prefix) + line_idx = len(lines) + # modify line + lines[line_idx] = ( + f"{prefix}={destination.absolute()} # AUTO GENERATED FROM MML-COPY-CONF set back to " + f"DEFAULT_CONF_PATH to fall back to original configs location\n" + ) + with open(env_path, "w") as f: + f.writelines(lines) + print(f"Modified {env_path.name} successfully. Please test setup via calling from the CLI. ") diff --git a/src/mml/configs/__init__.py b/src/mml/configs/__init__.py new file mode 100644 index 0000000..f7328eb --- /dev/null +++ b/src/mml/configs/__init__.py @@ -0,0 +1,8 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# the configs has to be made a package, such that the CLI interface works see +# https://github.com/facebookresearch/hydra/tree/1.0_branch/examples/advanced/hydra_app_example/hydra_app/conf diff --git a/src/mml/configs/arch/smp.yaml b/src/mml/configs/arch/smp.yaml new file mode 100644 index 0000000..7bdfc63 --- /dev/null +++ b/src/mml/configs/arch/smp.yaml @@ -0,0 +1,25 @@ +# @package arch + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +_target_: mml.core.models.smp.SMPGenericModel +### +# default: unet +# - segmentation architecture, passed to smp.create_model(arch=...) +# - options are [unet, unetplusplus, manet, linknet, fpn, pspnet, deeplabv3, deeplapv3plus, pan] +arch: unet +### +# default: tu-resnet34 +# - the encoder backbone to use, passed to smp.create_model(encoder_name=...) +# - for a full list of supported backbones, see https://smp.readthedocs.io/en/latest/encoders.html +# - the <> prefix automatically tries to use a timm encoder, see https://smp.readthedocs.io/en/latest/encoders_timm.html +encoder: tu-resnet34 +### +# default: imagenet +# - weight initialization of the backbone, passed to smp.create_model(encoder_weights=...) +# - supported weights per backbone are found here: https://smp.readthedocs.io/en/latest/encoders.html +weights: imagenet diff --git a/src/mml/configs/arch/timm.yaml b/src/mml/configs/arch/timm.yaml new file mode 100644 index 0000000..be20825 --- /dev/null +++ b/src/mml/configs/arch/timm.yaml @@ -0,0 +1,24 @@ +# @package arch + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +_target_: mml.core.models.timm.TimmGenericModel +### +# default: resnet34 +# - the identifier of the model architecture in the timm library - to be passed to timm.create_model(model_name=...) +# - full list of models can be found here: https://huggingface.co/docs/timm/models +# - also note the timm.list_models() option (https://huggingface.co/docs/timm/reference/models#timm.list_models) +name: resnet34 +### +# default: true +# - boolean to indicate whether the model should be initialized with pretraiend weights (timm.create_model(pretrained=...) +# - results files for pretrained weights: https://github.com/huggingface/pytorch-image-models/tree/main/results +pretrained: true +### +# default: 0. +# - dropout rate, set to some value within [0, 1), will be used to initialize a torch.nn.Dropout layer at the beginning of each classifier head +drop_rate: 0. diff --git a/src/mml/configs/augmentations/base_rand.yaml b/src/mml/configs/augmentations/base_rand.yaml new file mode 100644 index 0000000..d428f0a --- /dev/null +++ b/src/mml/configs/augmentations/base_rand.yaml @@ -0,0 +1,24 @@ +# @package augmentations + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +normalization: imagenet # image_net mean and std values are used +cpu: + backend: albumentations + pipeline: + - name: RandomCrop + height: 224 + width: 224 + - name: HorizontalFlip + p: 0.5 + - name: RandAugment + number: 3 + magnitude: 4 + mode: all + p: 0.5 + cut_out: True +gpu: {} diff --git a/src/mml/configs/augmentations/baseline256.yaml b/src/mml/configs/augmentations/baseline256.yaml new file mode 100644 index 0000000..733e6e0 --- /dev/null +++ b/src/mml/configs/augmentations/baseline256.yaml @@ -0,0 +1,18 @@ +# @package augmentations + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +normalization: imagenet # image_net mean and std values are used +cpu: + backend: albumentations + pipeline: + - name: RandomCrop + height: 224 + width: 224 + - name: HorizontalFlip + p: 0.5 +gpu: { } diff --git a/src/mml/configs/augmentations/baseline512.yaml b/src/mml/configs/augmentations/baseline512.yaml new file mode 100644 index 0000000..906a563 --- /dev/null +++ b/src/mml/configs/augmentations/baseline512.yaml @@ -0,0 +1,18 @@ +# @package augmentations + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +normalization: imagenet # image_net mean and std values are used +cpu: + backend: albumentations + pipeline: + - name: RandomCrop + height: 448 + width: 448 + - name: HorizontalFlip + p: 0.5 +gpu: { } diff --git a/src/mml/configs/augmentations/basic.yaml b/src/mml/configs/augmentations/basic.yaml new file mode 100644 index 0000000..358472a --- /dev/null +++ b/src/mml/configs/augmentations/basic.yaml @@ -0,0 +1,24 @@ +# @package augmentations + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +normalization: imagenet # image_net mean and std values are used +cpu: + backend: albumentations + pipeline: + - name: ShiftScaleRotate + shift_limit: 0.05 + scale_limit: 0.05 + rotate_limit: 15 + p: 0.5 + - name: HorizontalFlip + p: 0.5 + - name: RandomBrightnessContrast + p: 0.5 + - name: CoarseDropout + p: 0.5 +gpu: { } diff --git a/src/mml/configs/augmentations/default.yaml b/src/mml/configs/augmentations/default.yaml new file mode 100644 index 0000000..69aad5c --- /dev/null +++ b/src/mml/configs/augmentations/default.yaml @@ -0,0 +1,53 @@ +# @package augmentations + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: imagenet +# - determines the normalization strategy for images +# - 'imagenet': the imagenet mean and std of RGB channels are used, this is recommended if using imagenet pretrained models +# - 'task': use mean and std of RGB channels for each task, this is recommended if training from scratch +# - 'pretraining': try to extract pretraining normalization from the model, this may be less reliable than 'imagenet' option +# - 'null': do not normalise, e.g. to be used if images shall only be plotted but not fed through a model +normalization: imagenet # image_net mean and std values are used +cpu: + ### + # default: albumentations + # - backend for cpu augmentations, currently supports albumentations (https://albumentations.ai/) and torchvision (https://pytorch.org/vision/stable/transforms.html#start-here) + # - the backend library determines the available transforms, which are listed in the cpu.pipeline config + backend: albumentations + ### + # default: [{name:RandomCrop,height:224,width:224},{name:ShiftScaleRotate,shift_limit:0.05,scale_limit:0.05,rotate_limit:15},{name:HorizontalFlip,p:0.5},{name:RandomBrightnessContrast,p:0.5},{name:CoarseDropout,p:0.5}] + # - the actual augmentation pipeline, listed as a sequence of dictionaries with a 'name' each and optional kwargs + # - available albumentations transforms are: https://albumentations.ai/docs/api_reference/full_reference/ + # - available torchvision transforms are: https://pytorch.org/vision/stable/transforms.html#v2-api-reference-recommended + # - currently nesting / containers are not supported! + # - formatting transformations (e.g. ToFloat / Normalize / ToTensor) are beeing taken care of mml automatically + # - albumentations backend two custom added transform named 'ImageNetAA' (auto augment generated pipeline, no kwargs) and 'RandAugment' (see :meth:`~mml.core.data_loading.augmentations.albumentations.AlbumentationsAugmentationModule.get_rand_augment`) + pipeline: + - name: RandomCrop + height: 224 + width: 224 + - name: ShiftScaleRotate + shift_limit: 0.05 + scale_limit: 0.05 + rotate_limit: 15 + p: 0.5 + - name: HorizontalFlip + p: 0.5 + - name: RandomBrightnessContrast + p: 0.5 + - name: CoarseDropout + p: 0.5 +### +# default: {} +# - gpu augmentations are structured similarly to cpu augmentations and require backend and pipeline specification +# - empty dictionary means no augmentations +# - supported backends are kornia and torchvision +# - available kornia transforms: https://kornia.readthedocs.io/en/latest/augmentation.html +# - nesting and containers are not supported either +gpu: { } diff --git a/src/mml/configs/augmentations/kornia.yaml b/src/mml/configs/augmentations/kornia.yaml new file mode 100644 index 0000000..7e48196 --- /dev/null +++ b/src/mml/configs/augmentations/kornia.yaml @@ -0,0 +1,30 @@ +# @package augmentations + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +normalization: imagenet # image_net mean and std values are used +cpu: { } +gpu: + backend: kornia + pipeline: + - name: RandomCrop + size: [224, 224] + - name: RandomAffine + translate: [0.05, 0.05] + scale: [0.05, 0.05] + degrees: 15 + p: 0.5 + - name: RandomHorizontalFlip + p: 0.5 + - name: RandomBrightness + brightness: [0.8, 1.2] + p: 0.5 + - name: RandomContrast + contrast: [0.8, 1.2] + p: 0.5 + - name: RandomErasing + p: 0.5 diff --git a/src/mml/configs/augmentations/load_imagenet_aa.yaml b/src/mml/configs/augmentations/load_imagenet_aa.yaml new file mode 100644 index 0000000..6defebb --- /dev/null +++ b/src/mml/configs/augmentations/load_imagenet_aa.yaml @@ -0,0 +1,15 @@ +# @package augmentations + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +normalization: imagenet +cpu: + backend: albumentations + pipeline: + - name: ImageNetAA + version: 0.5.2 +gpu: { } diff --git a/src/mml/configs/augmentations/no_norm.yaml b/src/mml/configs/augmentations/no_norm.yaml new file mode 100644 index 0000000..f745e32 --- /dev/null +++ b/src/mml/configs/augmentations/no_norm.yaml @@ -0,0 +1,11 @@ +# @package augmentations + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +normalization: null # no normalization +cpu: { } # no augmentations +gpu: { } \ No newline at end of file diff --git a/src/mml/configs/augmentations/none.yaml b/src/mml/configs/augmentations/none.yaml new file mode 100644 index 0000000..b8bb217 --- /dev/null +++ b/src/mml/configs/augmentations/none.yaml @@ -0,0 +1,11 @@ +# @package augmentations + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +normalization: imagenet # still uses IMAGENET normalization, use no_norm to deactivate even that +cpu: { } +gpu: { } diff --git a/src/mml/configs/augmentations/randaugment.yaml b/src/mml/configs/augmentations/randaugment.yaml new file mode 100644 index 0000000..5a38415 --- /dev/null +++ b/src/mml/configs/augmentations/randaugment.yaml @@ -0,0 +1,20 @@ +# @package augmentations + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +normalization: imagenet # image_net mean and std values are used +cpu: + backend: albumentations + pipeline: + # the randaugment transform can also be composed with other transforms in a pipeline + - name: RandAugment + number: 2 + magnitude: 6 + mode: all + p: 0.5 + cut_out: False +gpu: { } diff --git a/src/mml/configs/augmentations/v2.yaml b/src/mml/configs/augmentations/v2.yaml new file mode 100644 index 0000000..411fd04 --- /dev/null +++ b/src/mml/configs/augmentations/v2.yaml @@ -0,0 +1,18 @@ +# @package augmentations + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +normalization: imagenet # image_net mean and std values are used +cpu: { } +gpu: + backend: torchvision + pipeline: + - name: RandomResizedCrop + size: [224, 224] + antialias: True + - name: RandomHorizontalFlip + p: 0.5 diff --git a/src/mml/configs/callbacks/cutmix.yaml b/src/mml/configs/callbacks/cutmix.yaml new file mode 100644 index 0000000..e2c4f46 --- /dev/null +++ b/src/mml/configs/callbacks/cutmix.yaml @@ -0,0 +1,17 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +cbs: + ### + # - custom cutmix callback :class:`~mml.core.data_loading.augmentations.mixup_cutmix.CutMixCallback` + # - see docstring for kwargs + cutmix: + _target_: mml.core.data_loading.augmentations.mixup_cutmix.CutMixCallback + alpha: 0.4 + label_smoothing: 0.0 + minmax: null diff --git a/src/mml/configs/callbacks/default.yaml b/src/mml/configs/callbacks/default.yaml new file mode 100644 index 0000000..d4a767d --- /dev/null +++ b/src/mml/configs/callbacks/default.yaml @@ -0,0 +1,15 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# note that some callbacks (e.g. checkpointing) are handled by MML internally, no need to add those here +cbs: + ### + # - logs information on learning rate + # - details: https://lightning.ai/docs/pytorch/stable/api/lightning.pytorch.callbacks.LearningRateMonitor.html#learningratemonitor + lrm: + _target_: lightning.pytorch.callbacks.LearningRateMonitor diff --git a/src/mml/configs/callbacks/early.yaml b/src/mml/configs/callbacks/early.yaml new file mode 100644 index 0000000..6ea119f --- /dev/null +++ b/src/mml/configs/callbacks/early.yaml @@ -0,0 +1,32 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +cbs: + ### + # - enables early stopping (by default based on validation loss, but configurable) + # - many kwargs may be accessed e.g. via `+cbs.early.min_delta=0.001`, only some are documented here directly + # - details: https://lightning.ai/docs/pytorch/stable/api/lightning.pytorch.callbacks.EarlyStopping.html#earlystopping + early: + _target_: lightning.pytorch.callbacks.EarlyStopping + ### + # default: val/loss + # - the monitor parameter controls the metric that is observed and required to improve to prevent stopping + # - may be set to any metric that is measured (see :doc:`metrics`), but the task name needs to be inserted (e.g. val/mml_fake_task/MulticlassAccuracy) + monitor: 'val/loss' + ### + # default: min + # - either min or max + # - if adapting the monitor parameter it is important to also give the orientation of the metric + # - if "the bigger, the better" this mode should be max + mode: 'min' + ### + # default: 10 + # - controls the number of epochs awaiting improvement before training is stopped + # - note that trainer.min_epochs overrules stopping too early + # - if using lr_scheduler=plateau make sure EarlyStopping patience is larger than lr_scheduler.patience + patience: 10 diff --git a/src/mml/configs/callbacks/mixup.yaml b/src/mml/configs/callbacks/mixup.yaml new file mode 100644 index 0000000..2c64aae --- /dev/null +++ b/src/mml/configs/callbacks/mixup.yaml @@ -0,0 +1,16 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +cbs: + ### + # - custom mixup callback :class:`~mml.core.data_loading.augmentations.mixup_cutmix.MixUpCallback` + # - see docstring for kwargs + mixup: + _target_: mml.core.data_loading.augmentations.mixup_cutmix.MixUpCallback + alpha: 0.4 + label_smoothing: 0.0 diff --git a/src/mml/configs/callbacks/none.yaml b/src/mml/configs/callbacks/none.yaml new file mode 100644 index 0000000..7f5567a --- /dev/null +++ b/src/mml/configs/callbacks/none.yaml @@ -0,0 +1,11 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# - this configuration file will clear any callback (except the ones handled internally by mml) +cbs: { } diff --git a/src/mml/configs/callbacks/stats.yaml b/src/mml/configs/callbacks/stats.yaml new file mode 100644 index 0000000..98a06f6 --- /dev/null +++ b/src/mml/configs/callbacks/stats.yaml @@ -0,0 +1,19 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +cbs: + ### + # - collects statistics on the device + # - details: https://lightning.ai/docs/pytorch/stable/api/lightning.pytorch.callbacks.DeviceStatsMonitor.html#devicestatsmonitor + stats: + _target_: lightning.pytorch.callbacks.DeviceStatsMonitor +# throughput is not yet fully supported and tested, it will need to set batch_size_fn in create_trainer as well as +# some flops_per_batch estimate in the lightning module +# throughput: +# _target_: lightning.pytorch.callbacks.ThroughputMonitor +# batch_size_fn: null diff --git a/src/mml/configs/callbacks/swa.yaml b/src/mml/configs/callbacks/swa.yaml new file mode 100644 index 0000000..d04937d --- /dev/null +++ b/src/mml/configs/callbacks/swa.yaml @@ -0,0 +1,18 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +cbs: + ### + # - activates stochastic weight averaging + # - details: https://lightning.ai/docs/pytorch/stable/api/lightning.pytorch.callbacks.StochasticWeightAveraging.html#stochasticweightaveraging + swa: + _target_: lightning.pytorch.callbacks.StochasticWeightAveraging + ### + # default: 0.005 + # - the SWA learning rate to use + swa_lrs: 0.005 diff --git a/src/mml/configs/compile/default.yaml b/src/mml/configs/compile/default.yaml new file mode 100644 index 0000000..5da9669 --- /dev/null +++ b/src/mml/configs/compile/default.yaml @@ -0,0 +1,19 @@ +# @package compile + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: False +# - enables torch.compile on the model returned by base schedulers :meth:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler.create_model` +# - some recommendations can be found here https://lightning.ai/docs/fabric/2.4.0/advanced/compile.html +enable: False +### +# - the kwargs passed to https://pytorch.org/docs/main/generated/torch.compile.html#torch-compile +kwargs: + ### + # default: reduce-overhead + mode: reduce-overhead \ No newline at end of file diff --git a/src/mml/configs/config_mml.yaml b/src/mml/configs/config_mml.yaml new file mode 100644 index 0000000..679500f --- /dev/null +++ b/src/mml/configs/config_mml.yaml @@ -0,0 +1,92 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# This is the default main mml config file. You may create your personal alterations and set as default outside of this +# repository via the `copy-conf` functionality (see docs, or ``mml.cli.py``). + +# specify here default training configuration +defaults: + - _self_ + - sys: local + - tasks: none + - arch: timm + - optimizer: adam + - lr_scheduler: none + - loss: default + - metrics: default + - callbacks: default + - trainer: default_trainer + - reuse: none + - remove: none + - preprocessing: default + - augmentations: default + - logging: log + - sampling: full + - search_space: none + - hpo: default + - tune: default + - compile: default + - loaders: default + - tta: none + - mode: info # is done very last to allow overriding above defaults + - override hydra/hydra_logging: col_stdout + - override hydra/help: mml_help + +### +# default: default +# - the project name, this will be used as a top-level folder name in the results directory +# - it is recommended to separate independent experiments to different projects +# - the reuse functionality allows cross-project reusability +proj: default +proj_path: ${out_dir}/${proj} +### +# default: 42 +# - integer to seed the builtin random module, numpy and torch randomness through lightning.seed_everything +# - will be applied before every scheduler step (so potentially multiple times per mml call) +# - seeding of dataloader workers is taken care of by lightning +# - set to False or 0 if random seeding is desired, this reduces reproducibility +seed: 42 +### +# default: True +# - whether to allow gpu usage outside lightning training, e.g. for task creation or feature extraction +# - for all lightning related accelerator settings see :doc:`trainer` +allow_gpu: True +### +# default: False +# - the continue flag allows to resume aborted / interrupted mml experiments +# - it will skip already completed commands in the scheduler and load the latest checkpoint of any model training +# - either set to 'latest' or specify a run directory by date and time +# - note that activating this will ignore all currently given CLI options (except the proj) and load the original config +continue: False +### +# default: False +# - automatically load the best parameters of a previous hpo study, overwriting the currently specified values +# - supports two kinds of usages, a minimal but restricted way without persistent storage +# - provide the hpo identifier in the project of format %Y-%m-%d_%H-%M-%S_%f (e.g. 2024-12-03_12-28-46_362374) +# - this only works for studies that did not fail, the required summary is only generated at the end of the sweep +# - also requires to set the current proj to the respective one that conducted the hpo search +# - alternative set to study_name, requires a preserving hpo.storage (e.g. see mml-sql) to load the optuna.Study +# - this also works for partly failed / interrupted AND cross project studies +use_best_params: False + +hydra: + # output paths for hydra logs + run: + dir: ${proj_path}/runs/${now:%Y-%m-%d}/${now:%H-%M-%S-%f} + sweep: + dir: ${proj_path}/hpo/${now:%Y-%m-%d_%H-%M-%S_%f} + subdir: ${hydra.job.num} + job: + name: ${proj} + chdir: true + # environment variables that are universal for all users + # for system specific variables (like data paths) use mml.env file! + env_set: + OMP_NUM_THREADS: '1' + MKL_NUM_THREADS: '1' + OPENCV_FFMPEG_THREADS: '1' diff --git a/src/mml/configs/hpo/default.yaml b/src/mml/configs/hpo/default.yaml new file mode 100644 index 0000000..c3bdb34 --- /dev/null +++ b/src/mml/configs/hpo/default.yaml @@ -0,0 +1,61 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - sampler: tpe + # necessary to avoid an interpolation error during config composition + - /search_space@hydra.sweeper.params: none + - _self_ + # override sweeper to Optuna! + - override /hydra/sweeper: optuna + +### +# - this config uses the optuna sweeper plugin of hydra +# - the considered hyperparameters are given by the search_space config +# - will sequentially run hpo.trials many experiments and sample hps according to hpo/sampler +# - default sampler is tpe (https://optuna.readthedocs.io/en/stable/reference/samplers/generated/optuna.samplers.TPESampler.html) +# - other samplers are ``hpo/sampler=random`` (https://optuna.readthedocs.io/en/stable/reference/samplers/generated/optuna.samplers.RandomSampler.html) and ``hpo/sampler=grid`` (https://optuna.readthedocs.io/en/stable/reference/samplers/generated/optuna.samplers.GridSampler.html) +# - example: ``mml train proj=test search_space=example hpo/sampler=grid --multirun`` +# - more details can be found in `hydra's optuna sweeper documentation `_ +hpo: + ### + # default: null + # - the optuna storage to use, if null only a temporary in-memory storage will be created + # - see mml-sql for details on how to set up permanent storage + storage: null + ### + # default: minimize + # - direction of optimization, either minimize or maximize + # - must be set according to the kind of return value by the respective scheduler + direction: minimize + ### + # default: False + # - currently unused, intended for future pruning of hopeless runs + # - see https://github.com/facebookresearch/hydra/issues/1954 + pruning: false + ### + # default: 100 + # - number of trials, each trial is one mml call with (potentially) different sampled hyperparameters + trials: 100 + +hydra: + # here we define Optuna hyperparameter search + # it optimizes for value returned from function with @hydra.main decorator + # learn more here: https://hydra.cc/docs/next/plugins/optuna_sweeper + sweeper: + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + # use the following line to make HPO deterministic, make sure to start jobs with different seed + # sampler.seed: ${seed} + study_name: ${proj}_${now:%Y-%m-%d_%H-%M-%S} + storage: ${hpo.storage} + n_jobs: 1 # jobs in parallel, as long as no parallel launcher is used this should be 1 + # 'minimize' or 'maximize' the objective + direction: ${hpo.direction} + # number of experiments that will be executed in a row by a single job (to parallelize see the README.md) + n_trials: ${hpo.trials} + params: ${search_space} \ No newline at end of file diff --git a/src/mml/configs/hpo/grid.yaml b/src/mml/configs/hpo/grid.yaml new file mode 100644 index 0000000..2d9ee55 --- /dev/null +++ b/src/mml/configs/hpo/grid.yaml @@ -0,0 +1,18 @@ +# @package hpo + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# - this config corresponds to the default multirun variant of hydra +# - use colons to provide multiple values via CLI (the search_space config is not used!) +# - will sequentially run one exp for each possible combination of config values (using the colon syntax) +# - example: ``mml train tasks=fake proj=test hpo=grid optimizer.lr=0.001,0.01 --multirun`` +# - more details can be found in `hydra's multi-run documentation `_ +storage: null +direction: null +pruning: null +trials: null diff --git a/src/mml/configs/hpo/sampler/grid.yaml b/src/mml/configs/hpo/sampler/grid.yaml new file mode 100644 index 0000000..f890abb --- /dev/null +++ b/src/mml/configs/hpo/sampler/grid.yaml @@ -0,0 +1,12 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + # choose optuna hyperparameter sampler ('tpe', 'random', 'cmaes' or 'nsgaii', 'motpe') + # learn more here: https://optuna.readthedocs.io/en/stable/reference/samplers.html + - override /hydra/sweeper/sampler: grid \ No newline at end of file diff --git a/src/mml/configs/hpo/sampler/random.yaml b/src/mml/configs/hpo/sampler/random.yaml new file mode 100644 index 0000000..89e85ad --- /dev/null +++ b/src/mml/configs/hpo/sampler/random.yaml @@ -0,0 +1,12 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + # choose optuna hyperparameter sampler ('tpe', 'random', 'cmaes' or 'nsgaii', 'motpe') + # learn more here: https://optuna.readthedocs.io/en/stable/reference/samplers.html + - override /hydra/sweeper/sampler: random \ No newline at end of file diff --git a/src/mml/configs/hpo/sampler/tpe.yaml b/src/mml/configs/hpo/sampler/tpe.yaml new file mode 100644 index 0000000..11e8b09 --- /dev/null +++ b/src/mml/configs/hpo/sampler/tpe.yaml @@ -0,0 +1,12 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + # choose optuna hyperparameter sampler ('tpe', 'random', 'cmaes' or 'nsgaii', 'motpe') + # learn more here: https://optuna.readthedocs.io/en/stable/reference/samplers.html + - override /hydra/sweeper/sampler: tpe \ No newline at end of file diff --git a/src/mml/configs/hydra/help/mml_help.yaml b/src/mml/configs/hydra/help/mml_help.yaml new file mode 100644 index 0000000..6eb76b2 --- /dev/null +++ b/src/mml/configs/hydra/help/mml_help.yaml @@ -0,0 +1,124 @@ +# @package hydra.help + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +app_name: Medical Meta Learner +header: |- + ╔═════════════════════════════════════════════════════════╗ + ║ _____ ______ _____ ______ ___ ║ + ║ |\ _ \ _ \|\ _ \ _ \|\ \ ║ + ║ \ \ \\\__\ \ \ \ \\\__\ \ \ \ \ ║ + ║ \ \ \\|__| \ \ \ \\|__| \ \ \ \ ║ + ║ \ \ \ \ \ \ \ \ \ \ \ \ \____ ║ + ║ \ \__\ \ \__\ \__\ \ \__\ \_______\ ║ + ║ \|__| \|__|\|__| \|__|\|_______| ║ + ║ ____ _ _ __ _ _ ____ _ _ ║ + ║ ( _ \( \/ ) ( )( \/ )/ ___)( \/ ) ║ + ║ ) _ ( ) / )( / \/ \\___ \ ) / ║ + ║ (____/(__/ (__)\_)(_/(____/(__/ ║ + ╚═════════════════════════════════════════════════════════╝ + +footer: |- + MML was developed by the division of Intelligent Medical Systems + at the German Cancer Research Center (DKFZ)in Heidelberg, Germany. + The main author is Patrick Godau (patrick.godau@dkfz-heidelberg.de). + © 2024 Division of Intelligent Medical Systems, DKFZ + +template: |- + ${hydra.help.header} + + This help provides a basic overview on CLI of MML. You can find a lot more + details please in the documentation (https://imsy.pages.dkfz.de/ise/mml) or + ask for help at our issue tracker (https://git.dkfz.de/imsy/ise/mml/-/issues). + + Basic call pattern is + + mml [mode] [overrides] [hydra.overrides] [hydra-flags] + + Besides there are also the following mml-core CLIs (without any arguments): + * mml-env-setup - sets up an `mml.env` file at your current location + * mml-copy-conf - sets up mml configs outside the mml-core package + + ╔══════╗ + ║ mode ║ + ╚══════╝ + Available modes include: + * create - Installs datasets and tasks on the workstation. + * pp - Preprocesses tasks with the given "preprocessing". + * train - Trains, tests and/or predicts (single or multi-task). + * post - Postprocessing via calibration and ensembling. + * info - Provides information on tasks, trained models, etc.. + * clean - May be used the remove artefacts from mml. + * upgrade - Used to migrate mml results and data upwards. + * downgrade - Used to migrate mml results and data downwards. + + Note that mml plugins may add further modes. You can find all available + modes in the full list of config groups below (see overrides). + + See also: https://imsy.pages.dkfz.de/ise/mml/modes.html + + ╔═══════════╗ + ║ overrides ║ + ╚═══════════╝ + MML offers a flexible system to override experiment configuration from + the command line. It is powered by Hydra (https://hydra.cc) and more + details on the syntax can be found in the respective documentation + (https://hydra.cc/docs/advanced/override_grammar/basic/). In a nutshell + configuration options are grouped and one can either override a whole + group of options with existing config files (e.g. lr_scheduler=cosine) + or set values inside a config group (e.g. lr_scheduler.verbose=false). + + **Note**: + Hydra configuration is presented in a simplified manner above. There are + special cases of combining config files (e.g. callbacks=[early,mixup]), + accessing nested config files (e.g. loss/mlcls=ce) or adding new keys to + a configuration (e.g. +lr_scheduler.eta_min=0.01). + + The following is an overview of configuration groups available (including + group options provided by mml plugins. + + $APP_CONFIG_GROUPS + + The configuration groups and overrides will be compiled to a final single + job configuration (or multiple in --multirun mode as described below). + The final configuration can be displayed with the help of hydra-flags + (see below) and is also stored in the run folder inside the .hydra subdir. + + See also: https://imsy.pages.dkfz.de/ise/mml/usage.html#basics + And: https://imsy.pages.dkfz.de/ise/mml/cli/overview.html + + ╔═════════════════╗ + ║ hydra.overrides ║ + ╚═════════════════╝ + The same override style also let's you alter configurations that directly + influence the internal behaviour of hydra. The corresponding config groups + are: + + $HYDRA_CONFIG_GROUPS + + The most common use cases are for example: + * hydra.verbose=true - verbose mode, all logging.debug messages are print + + See also: https://hydra.cc/docs/configure_hydra/intro/ + + ╔═════════════╗ + ║ hydra-flags ║ + ╚═════════════╝ + hydra offers some functionality that is inherited by mml. The existing + options are: + + $FLAGS_HELP + + Noteworthy are + * --cfg=job - print the compiled config (without running mml) + * --multirun - used for hyperparameter search, starts multiple jobs + * --info - information on the defaults tree, config search paths, etc + + See also: https://hydra.cc/docs/advanced/hydra-command-line-flags/ + + ------- + ${hydra.help.footer} diff --git a/src/mml/configs/hydra/hydra_logging/col_stdout.yaml b/src/mml/configs/hydra/hydra_logging/col_stdout.yaml new file mode 100644 index 0000000..3d4d5dd --- /dev/null +++ b/src/mml/configs/hydra/hydra_logging/col_stdout.yaml @@ -0,0 +1,24 @@ +# @package hydra.hydra_logging + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# python logging configuration for tasks +version: 1 +formatters: + colorlog: + '()': 'colorlog.ColoredFormatter' + format: "[%(cyan)s%(asctime)s%(reset)s][%(purple)sHYDRA%(reset)s] %(message)s" +handlers: + console: + class: logging.StreamHandler + formatter: colorlog + stream: ext://sys.stdout +root: + level: INFO + handlers: [ console ] + +disable_existing_loggers: false \ No newline at end of file diff --git a/src/mml/configs/hydra/job_logging/col_stdout_and_file.yaml b/src/mml/configs/hydra/job_logging/col_stdout_and_file.yaml new file mode 100644 index 0000000..5a8946f --- /dev/null +++ b/src/mml/configs/hydra/job_logging/col_stdout_and_file.yaml @@ -0,0 +1,37 @@ +# @package hydra.job_logging + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# python logging configuration for tasks +version: 1 +formatters: + simple: + format: '[%(asctime)s][%(name)s][%(levelname)s] - %(message)s' + colorlog: + '()': 'colorlog.ColoredFormatter' + format: '[%(cyan)s%(asctime)s%(reset)s][%(blue)s%(name)s%(reset)s][%(log_color)s%(levelname)s%(reset)s] - %(message)s' + log_colors: + DEBUG: purple + INFO: green + WARNING: yellow + ERROR: red + CRITICAL: red +handlers: + console: + class: logging.StreamHandler + formatter: colorlog + stream: ext://sys.stdout + file: + class: logging.FileHandler + formatter: simple + # relative to the job log directory + filename: exp.log +root: + level: INFO + handlers: [ console, file ] + +disable_existing_loggers: false \ No newline at end of file diff --git a/src/mml/configs/hydra/job_logging/rich_stdout_and_file.yaml b/src/mml/configs/hydra/job_logging/rich_stdout_and_file.yaml new file mode 100644 index 0000000..43383a0 --- /dev/null +++ b/src/mml/configs/hydra/job_logging/rich_stdout_and_file.yaml @@ -0,0 +1,26 @@ +# @package hydra.job_logging + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# python logging configuration for tasks +version: 1 +formatters: + simple: + format: '[%(asctime)s][%(name)s][%(levelname)s] - %(message)s' +handlers: + console: + class: rich.logging.RichHandler + file: + class: logging.FileHandler + formatter: simple + # relative to the job log directory + filename: exp.log +root: + level: INFO + handlers: [ console, file ] + +disable_existing_loggers: false \ No newline at end of file diff --git a/src/mml/configs/hydra/job_logging/stdout_only.yaml b/src/mml/configs/hydra/job_logging/stdout_only.yaml new file mode 100644 index 0000000..fb1203a --- /dev/null +++ b/src/mml/configs/hydra/job_logging/stdout_only.yaml @@ -0,0 +1,21 @@ +# @package hydra.job_logging + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +version: 1 +formatters: + simple: + format: '[%(levelname)s] - %(message)s' +handlers: + console: + class: logging.StreamHandler + formatter: simple + stream: ext://sys.stdout +root: + handlers: [ console ] + +disable_existing_loggers: false \ No newline at end of file diff --git a/src/mml/configs/loaders/default.yaml b/src/mml/configs/loaders/default.yaml new file mode 100644 index 0000000..809a62f --- /dev/null +++ b/src/mml/configs/loaders/default.yaml @@ -0,0 +1,43 @@ +# @package loaders + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# enumerates the modality loaders that will be used to bring sample entries to tensor ready format +# keys must match a Modality + +### +# default: :class:`~mml.core.data_loading.modality_loaders.OpenCVImageLoader` +# - determines how the image modality is loaded +# - tries to use open CV for image loading +image: + _target_: mml.core.data_loading.modality_loaders.OpenCVImageLoader +### +# default: :class:`~mml.core.data_loading.modality_loaders.OpenCVMaskLoader` +# - determines how masks are loaded +# - tries to use open CV for mask loading +mask: + _target_: mml.core.data_loading.modality_loaders.OpenCVMaskLoader +### +# default: :class:`~mml.core.data_loading.modality_loaders.ClassLoader` +# - determines how the class modality is loaded +class: + _target_: mml.core.data_loading.modality_loaders.ClassLoader +### +# default: :class:`~mml.core.data_loading.modality_loaders.MultiLabelClassLoader` +# - determines how the classes modality is loaded +classes: + _target_: mml.core.data_loading.modality_loaders.MultiLabelClassLoader +### +# default: :class:`~mml.core.data_loading.modality_loaders.SoftLabelClassLoader` +# - determines how the soft_classes modality is loaded +soft_classes: + _target_: mml.core.data_loading.modality_loaders.SoftLabelClassLoader +### +# default: :class:`~mml.core.data_loading.modality_loaders.ValueLoader` +# - determines how the value modality is loaded +value: + _target_: mml.core.data_loading.modality_loaders.ValueLoader \ No newline at end of file diff --git a/src/mml/configs/loaders/numpy.yaml b/src/mml/configs/loaders/numpy.yaml new file mode 100644 index 0000000..c3dddfc --- /dev/null +++ b/src/mml/configs/loaders/numpy.yaml @@ -0,0 +1,18 @@ +# @package loaders + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - /loaders: default + - _self_ + +### +# default: :class:`~mml.core.data_loading.modality_loaders.NumpyArrayImageLoader` +# - determines how the image modality is loaded +# - tries to use numpy for image loading +image: + _target_: mml.core.data_loading.modality_loaders.NumpyArrayImageLoader diff --git a/src/mml/configs/loaders/pillow.yaml b/src/mml/configs/loaders/pillow.yaml new file mode 100644 index 0000000..90470bc --- /dev/null +++ b/src/mml/configs/loaders/pillow.yaml @@ -0,0 +1,18 @@ +# @package loaders + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - /loaders: default + - _self_ + +### +# default: :class:`~mml.core.data_loading.modality_loaders.PillowImageLoader` +# - determines how the image modality is loaded +# - tries to use Pillow for image loading +image: + _target_: mml.core.data_loading.modality_loaders.PillowImageLoader diff --git a/src/mml/configs/loaders/pillow_acc.yaml b/src/mml/configs/loaders/pillow_acc.yaml new file mode 100644 index 0000000..68cd9c6 --- /dev/null +++ b/src/mml/configs/loaders/pillow_acc.yaml @@ -0,0 +1,18 @@ +# @package loaders + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - /loaders: default + - _self_ + +### +# default: :class:`~mml.core.data_loading.modality_loaders.AcceleratedPillowImageLoader` +# - determines how the image modality is loaded +# - tries to use a modified Pillow routine for image loading +image: + _target_: mml.core.data_loading.modality_loaders.AcceleratedPillowImageLoader diff --git a/src/mml/configs/loaders/scikit.yaml b/src/mml/configs/loaders/scikit.yaml new file mode 100644 index 0000000..72e6a50 --- /dev/null +++ b/src/mml/configs/loaders/scikit.yaml @@ -0,0 +1,18 @@ +# @package loaders + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - /loaders: default + - _self_ + +### +# default: :class:`~mml.core.data_loading.modality_loaders.ScikitImageLoader` +# - determines how the image modality is loaded +# - tries to use scikit for image loading +image: + _target_: mml.core.data_loading.modality_loaders.ScikitImageLoader diff --git a/src/mml/configs/loaders/torch.yaml b/src/mml/configs/loaders/torch.yaml new file mode 100644 index 0000000..d6f764d --- /dev/null +++ b/src/mml/configs/loaders/torch.yaml @@ -0,0 +1,18 @@ +# @package loaders + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - /loaders: default + - _self_ + +### +# default: :class:`~mml.core.data_loading.modality_loaders.PureTorchvisionImageLoader` +# - determines how the image modality is loaded +# - tries to use torchvision for image loading +image: + _target_: mml.core.data_loading.modality_loaders.PureTorchvisionImageLoader diff --git a/src/mml/configs/loaders/uni.yaml b/src/mml/configs/loaders/uni.yaml new file mode 100644 index 0000000..3ffaca7 --- /dev/null +++ b/src/mml/configs/loaders/uni.yaml @@ -0,0 +1,31 @@ +# @package loaders + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# a universal loader strategy, covering as many formats as possible, while potentially sacrificing some performance + +defaults: + - /loaders: default + - _self_ + +### +# default: :class:`~mml.core.data_loading.modality_loaders.CombinedModalityLoader` +# - determines how the image modality is loaded +# - tries to use following modality loaders in order +# - :class:`~mml.core.data_loading.modality_loaders.PureTorchvisionImageLoader` +# - :class:`~mml.core.data_loading.modality_loaders.OpenCVImageLoader` +# - :class:`~mml.core.data_loading.modality_loaders.NumpyArrayImageLoader` +# - :class:`~mml.core.data_loading.modality_loaders.PillowImageLoader` +# - :class:`~mml.core.data_loading.modality_loaders.ScikitImageLoader` +image: + _target_: mml.core.data_loading.modality_loaders.CombinedModalityLoader + loaders: + - _target_: mml.core.data_loading.modality_loaders.PureTorchvisionImageLoader + - _target_: mml.core.data_loading.modality_loaders.OpenCVImageLoader + - _target_: mml.core.data_loading.modality_loaders.NumpyArrayImageLoader + - _target_: mml.core.data_loading.modality_loaders.PillowImageLoader + - _target_: mml.core.data_loading.modality_loaders.ScikitImageLoader diff --git a/src/mml/configs/logging/exp_logger/tensorboard.yaml b/src/mml/configs/logging/exp_logger/tensorboard.yaml new file mode 100644 index 0000000..4037855 --- /dev/null +++ b/src/mml/configs/logging/exp_logger/tensorboard.yaml @@ -0,0 +1,27 @@ +# package logging.exp_logger + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: :class:`~lightning.pytorch.loggers.tensorboard.TensorBoardLogger` +# - see `lighnting docs `_ +_target_: lightning.pytorch.loggers.tensorboard.TensorBoardLogger +### +# default: ${proj_path}/tensorboard +# - the directory to store the logs in (${proj_path} will be replaced by hydra +save_dir: ${proj_path}/tensorboard +### +# default: ${now:%Y-%m-%d}/${now:%H-%M-%S} +# - the experiment sub-directory +# - will be interpolated by hydra to current time +name: ${now:%Y-%m-%d}/${now:%H-%M-%S} +### +# default: None (literally) +# - to be specified during runtime +# - this will be the :attr:`~mml.core.scripts.schedulers.base_scheduler.BaseScheduler.active_step_naming` of the scheduler +# - see :meth:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler.create_trainer` for more on this +version: None diff --git a/src/mml/configs/logging/log.yaml b/src/mml/configs/logging/log.yaml new file mode 100644 index 0000000..aaf4cf1 --- /dev/null +++ b/src/mml/configs/logging/log.yaml @@ -0,0 +1,34 @@ +# @package logging + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - exp_logger: tensorboard + - render: colorlog + - notifier: none +### +# default: True +# - enables the highlight text feature of the base AbstractBaseScheduler, colouring specific parts of logs +# - see :meth:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler.highlight_text` +highlight_text: True +### +# default: True +# - capture emitted python warnings and log them as well +# - see `logging documentation `_ +capture_warnings: True +### +# default: 0 +# - logs example images with prediction and reference to oversee training progress (once per epoch and phase) +# - examples will be logged only to tensorboard logger currently +# - see :meth:`~mml.core.models.lightning_single_frame.SingleFrameLightningModule.log_images_prediction_reference` +samples: 0 +### +# default: false +# - whether to log the epochs confusion matrix +# - confusion matrix will be logged only to tensorboard logger currently +# - see :meth:`~mml.core.models.lightning_single_frame.SingleFrameLightningModule.log_confusion_matrix` +cm: false diff --git a/src/mml/configs/logging/notifier/email.yaml b/src/mml/configs/logging/notifier/email.yaml new file mode 100644 index 0000000..1987c9b --- /dev/null +++ b/src/mml/configs/logging/notifier/email.yaml @@ -0,0 +1,26 @@ +# @package logging.notifier + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + + +email: + ### + # default: :class:`~mml.core.scripts.notifier.EMailNotifier` + # - a notifier that sends email messages + _target_: mml.core.scripts.notifier.EMailNotifier + ### + # default: False + # - whether to send messages on mml start + on_start: False + ### + # default: False + # - whether to send messages on mml end + on_end: False + ### + # default: False + # - whether to send messages on mml failure + on_failure: True \ No newline at end of file diff --git a/src/mml/configs/logging/notifier/none.yaml b/src/mml/configs/logging/notifier/none.yaml new file mode 100644 index 0000000..8c87892 --- /dev/null +++ b/src/mml/configs/logging/notifier/none.yaml @@ -0,0 +1,16 @@ +# @package logging.notifier + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +dummy: + ### + # default: :class:`~mml.core.scripts.notifier.DummyNotifier` + # - a notifier that does not emit any message + _target_: mml.core.scripts.notifier.DummyNotifier + on_start: False + on_end: False + on_failure: False \ No newline at end of file diff --git a/src/mml/configs/logging/notifier/slack.yaml b/src/mml/configs/logging/notifier/slack.yaml new file mode 100644 index 0000000..c64bfb1 --- /dev/null +++ b/src/mml/configs/logging/notifier/slack.yaml @@ -0,0 +1,26 @@ +# @package logging.notifier + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + + +slack: + ### + # default: :class:`~mml.core.scripts.notifier.SlackNotifier` + # - a notifier that sends slack messages + _target_: mml.core.scripts.notifier.SlackNotifier + ### + # default: False + # - whether to send messages on mml start + on_start: False + ### + # default: False + # - whether to send messages on mml end + on_end: False + ### + # default: False + # - whether to send messages on mml failure + on_failure: True \ No newline at end of file diff --git a/src/mml/configs/logging/render/colorlog.yaml b/src/mml/configs/logging/render/colorlog.yaml new file mode 100644 index 0000000..dfd3509 --- /dev/null +++ b/src/mml/configs/logging/render/colorlog.yaml @@ -0,0 +1,14 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - override /hydra/job_logging: col_stdout_and_file + +logging: + render: + rich: False \ No newline at end of file diff --git a/src/mml/configs/logging/render/rich.yaml b/src/mml/configs/logging/render/rich.yaml new file mode 100644 index 0000000..f68b1af --- /dev/null +++ b/src/mml/configs/logging/render/rich.yaml @@ -0,0 +1,14 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - override /hydra/job_logging: rich_stdout_and_file + +logging: + render: + rich: True \ No newline at end of file diff --git a/src/mml/configs/loss/cls/ce.yaml b/src/mml/configs/loss/cls/ce.yaml new file mode 100644 index 0000000..55847a2 --- /dev/null +++ b/src/mml/configs/loss/cls/ce.yaml @@ -0,0 +1,12 @@ +# @package loss.cls + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: :class:`~torch.nn.CrossEntropyLoss` +# - pytorch cross entropy loss +_target_: torch.nn.CrossEntropyLoss diff --git a/src/mml/configs/loss/default.yaml b/src/mml/configs/loss/default.yaml new file mode 100644 index 0000000..0f791d4 --- /dev/null +++ b/src/mml/configs/loss/default.yaml @@ -0,0 +1,27 @@ +# @package loss + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - cls: ce + - mlcls: bce + - seg: dice + - reg: huber + +### +# default: true +# - automatically activates class weighing in case balanced sampling is turned off +# - see :meth:`~mml.core.models.lightning_single_frame.SingleFrameLightningModule.get_criteria` +auto_activate_weighing: true +### +# default: null +# - provide weight option to loss criterion directly +# - incompatible with `sampling.balanced` and `loss.auto_activate_weighing` +# - see :meth:`~mml.core.models.lightning_single_frame.SingleFrameLightningModule.get_criteria` +# +class_weights: null +# future options include a weighing schedule of tasks diff --git a/src/mml/configs/loss/mlcls/bce.yaml b/src/mml/configs/loss/mlcls/bce.yaml new file mode 100644 index 0000000..a2b11f0 --- /dev/null +++ b/src/mml/configs/loss/mlcls/bce.yaml @@ -0,0 +1,12 @@ +# @package loss.mlcls + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: :class:`~torch.nn.BCEWithLogitsLoss` +# - pytorch binary cross entropy loss +_target_: torch.nn.BCEWithLogitsLoss diff --git a/src/mml/configs/loss/mlcls/ce.yaml b/src/mml/configs/loss/mlcls/ce.yaml new file mode 100644 index 0000000..e5d45b8 --- /dev/null +++ b/src/mml/configs/loss/mlcls/ce.yaml @@ -0,0 +1,12 @@ +# @package loss.mlcls + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: :class:`~torch.nn.CrossEntropyLoss` +# - pytorch cross entropy loss +_target_: torch.nn.CrossEntropyLoss \ No newline at end of file diff --git a/src/mml/configs/loss/reg/huber.yaml b/src/mml/configs/loss/reg/huber.yaml new file mode 100644 index 0000000..aac0ab1 --- /dev/null +++ b/src/mml/configs/loss/reg/huber.yaml @@ -0,0 +1,16 @@ +# @package loss.reg + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: :class:`~torch.nn.HuberLoss` +# - pytorch huber loss +_target_: torch.nn.HuberLoss +### +# default: 1.0 +# - see `pytorch docs `_ +delta: 1.0 \ No newline at end of file diff --git a/src/mml/configs/loss/seg/ce.yaml b/src/mml/configs/loss/seg/ce.yaml new file mode 100644 index 0000000..a62d703 --- /dev/null +++ b/src/mml/configs/loss/seg/ce.yaml @@ -0,0 +1,21 @@ +# @package loss.seg + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: :class:`~torch.nn.HuberLoss` +# - pytorch huber loss +_target_: torch.nn.CrossEntropyLoss +### +# default: 255 +# - mml ignores the index 255 by default in segmentation +# - see `CrossEntropyLoss `_ +ignore_index: 255 +### +# default: 0.0 +# - allows for label smoothing if activated +label_smoothing: 0.0 \ No newline at end of file diff --git a/src/mml/configs/loss/seg/dice.yaml b/src/mml/configs/loss/seg/dice.yaml new file mode 100644 index 0000000..d23b2d8 --- /dev/null +++ b/src/mml/configs/loss/seg/dice.yaml @@ -0,0 +1,21 @@ +# @package loss.seg + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: :class:`~segmentation_models_pytorch.losses.DiceLoss` +# - segmentation models pytorch dice loss +# - see `source code `_ +_target_: segmentation_models_pytorch.losses.DiceLoss +### +# default: multiclass +# - loss mode 'binary', 'multiclass' or 'multilabel' +mode: 'multiclass' +### +# default: 255 +# - mml ignores the index 255 by default in segmentation +ignore_index: 255 diff --git a/src/mml/configs/lr_scheduler/cosine.yaml b/src/mml/configs/lr_scheduler/cosine.yaml new file mode 100644 index 0000000..7589105 --- /dev/null +++ b/src/mml/configs/lr_scheduler/cosine.yaml @@ -0,0 +1,17 @@ +# @package lr_scheduler + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: :class:`~torch.optim.lr_scheduler.CosineAnnealingLR` +# - cosine annealing learning rate scheduler +# - see `CosineAnnealingLR `_ +_target_: torch.optim.lr_scheduler.CosineAnnealingLR +### +# default: ${trainer.max_epochs} +# - resolved by hydra +T_max: ${trainer.max_epochs} diff --git a/src/mml/configs/lr_scheduler/cosine_restart.yaml b/src/mml/configs/lr_scheduler/cosine_restart.yaml new file mode 100644 index 0000000..16ceb2b --- /dev/null +++ b/src/mml/configs/lr_scheduler/cosine_restart.yaml @@ -0,0 +1,17 @@ +# @package lr_scheduler + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: :class:`~torch.optim.lr_scheduler.CosineAnnealingWarmRestarts` +# - cosine annealing learning rate scheduler with warm restarts +# - see `CosineAnnealingWarmRestarts `_ +_target_: torch.optim.lr_scheduler.CosineAnnealingWarmRestarts +### +# default: 25 +# - epochs until first restart +T_0: 25 diff --git a/src/mml/configs/lr_scheduler/exponential.yaml b/src/mml/configs/lr_scheduler/exponential.yaml new file mode 100644 index 0000000..878f8f1 --- /dev/null +++ b/src/mml/configs/lr_scheduler/exponential.yaml @@ -0,0 +1,17 @@ +# @package lr_scheduler + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: :class:`~torch.optim.lr_scheduler.ExponentialLR` +# - exponential learning rate scheduler +# - see `ExponentialLR `_ +_target_: torch.optim.lr_scheduler.ExponentialLR +### +# default: 0.99 +# - multiplicative factor of learning rate decay +gamma: 0.99 diff --git a/src/mml/configs/lr_scheduler/none.yaml b/src/mml/configs/lr_scheduler/none.yaml new file mode 100644 index 0000000..c141e6d --- /dev/null +++ b/src/mml/configs/lr_scheduler/none.yaml @@ -0,0 +1,12 @@ +# @package lr_scheduler + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: null +# - pseudo target to be caught within code and not to be instantiated +_target_: null diff --git a/src/mml/configs/lr_scheduler/one_cycle.yaml b/src/mml/configs/lr_scheduler/one_cycle.yaml new file mode 100644 index 0000000..5cc16a8 --- /dev/null +++ b/src/mml/configs/lr_scheduler/one_cycle.yaml @@ -0,0 +1,22 @@ +# @package lr_scheduler + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: :class:`~torch.optim.lr_scheduler.OneCycleLR` +# - one cycle learning rate scheduler +# - see `OneCycleLR `_ +_target_: torch.optim.lr_scheduler.OneCycleLR +### +# default: 0.001 +# - max learning rate +max_lr: 0.001 +### +# default: ${trainer.trainer.max_epochs} +# - number of epochs +# - inferred by hydra +epochs: ${trainer.trainer.max_epochs} \ No newline at end of file diff --git a/src/mml/configs/lr_scheduler/plateau.yaml b/src/mml/configs/lr_scheduler/plateau.yaml new file mode 100644 index 0000000..2d226b6 --- /dev/null +++ b/src/mml/configs/lr_scheduler/plateau.yaml @@ -0,0 +1,29 @@ +# @package lr_scheduler + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: :class:`~torch.optim.lr_scheduler.ReduceLROnPlateau` +# - reduce on plateau learning rate scheduler +# - see `ReduceLROnPlateau `_ +_target_: torch.optim.lr_scheduler.ReduceLROnPlateau +### +# default: min +# - direction of improvement (min for loss) +mode: min +### +# default: 0.1 +# - reduction factor if triggered by plateau +factor: 0.1 +### +# default: 5 +# - number of epochs to wait for improvement before triggering a reduction +patience: 5 +### +# default: 0.0001 +# - improvement threshold to determine if an improvement happened +threshold: 0.0001 \ No newline at end of file diff --git a/src/mml/configs/lr_scheduler/step.yaml b/src/mml/configs/lr_scheduler/step.yaml new file mode 100644 index 0000000..c096c54 --- /dev/null +++ b/src/mml/configs/lr_scheduler/step.yaml @@ -0,0 +1,21 @@ +# @package lr_scheduler + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: :class:`~torch.optim.lr_scheduler.StepLR` +# - step wise learning rate scheduler +# - see `StepLR `_ +_target_: torch.optim.lr_scheduler.StepLR +### +# default: 25 +# - epochs to wait +step_size: 25 +### +# default: 0.1 +# - multiplicative factor +gamma: 0.1 diff --git a/src/mml/configs/metrics/cls/default.yaml b/src/mml/configs/metrics/cls/default.yaml new file mode 100644 index 0000000..c912321 --- /dev/null +++ b/src/mml/configs/metrics/cls/default.yaml @@ -0,0 +1,30 @@ +# @package metrics.cls + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +- _target_: torchmetrics.classification.MulticlassAccuracy + average: macro + num_classes: 0 +- _target_: torchmetrics.classification.MulticlassF1Score + average: macro + num_classes: 0 +- _target_: torchmetrics.classification.MulticlassAveragePrecision + average: macro + num_classes: 0 +- _target_: torchmetrics.classification.MulticlassAUROC + average: macro + num_classes: 0 +- _target_: torchmetrics.classification.MulticlassMatthewsCorrCoef + num_classes: 0 +- _target_: torchmetrics.classification.MulticlassPrecision + num_classes: 0 + average: macro +- _target_: torchmetrics.classification.MulticlassRecall + num_classes: 0 + average: macro +- _target_: torchmetrics.classification.MulticlassCalibrationError + num_classes: 0 diff --git a/src/mml/configs/metrics/default.yaml b/src/mml/configs/metrics/default.yaml new file mode 100644 index 0000000..97c8492 --- /dev/null +++ b/src/mml/configs/metrics/default.yaml @@ -0,0 +1,19 @@ +# @package metrics + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - cls: default + - mlcls: default + - seg: default + - reg: default + +### +# default: 20 +# - allows to use bootstrapping upon metrics for testing phase +# - see `torchmetrics docs `_ +bootstrap: 20 \ No newline at end of file diff --git a/src/mml/configs/metrics/mlcls/default.yaml b/src/mml/configs/metrics/mlcls/default.yaml new file mode 100644 index 0000000..683fa26 --- /dev/null +++ b/src/mml/configs/metrics/mlcls/default.yaml @@ -0,0 +1,15 @@ +# @package metrics.mlcls + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +- _target_: torchmetrics.classification.MultilabelAveragePrecision + average: macro + num_classes: 0 +- _target_: torchmetrics.classification.MultilabelRankingAveragePrecision + num_classes: 0 +- _target_: torchmetrics.classification.MultilabelCoverageError + num_classes: 0 diff --git a/src/mml/configs/metrics/reg/default.yaml b/src/mml/configs/metrics/reg/default.yaml new file mode 100644 index 0000000..4a6610e --- /dev/null +++ b/src/mml/configs/metrics/reg/default.yaml @@ -0,0 +1,10 @@ +# @package metrics.reg + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +- _target_: torchmetrics.regression.MeanSquaredError +- _target_: torchmetrics.regression.SpearmanCorrCoef diff --git a/src/mml/configs/metrics/seg/default.yaml b/src/mml/configs/metrics/seg/default.yaml new file mode 100644 index 0000000..ecd2c25 --- /dev/null +++ b/src/mml/configs/metrics/seg/default.yaml @@ -0,0 +1,13 @@ +# @package metrics.seg + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +- _target_: torchmetrics.classification.Dice + average: macro + mdmc_average: samplewise + num_classes: 0 + ignore_index: 255 diff --git a/src/mml/configs/mode/clean.yaml b/src/mml/configs/mode/clean.yaml new file mode 100644 index 0000000..4cf3c39 --- /dev/null +++ b/src/mml/configs/mode/clean.yaml @@ -0,0 +1,32 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - override /preprocessing: none + +mode: + scheduler: + ### + # default: :class:`~mml.core.scripts.schedulers.clean_scheduler.CleanScheduler` + # - the clean scheduler assists in getting rid of file artifacts, reducing disk usage by mml + _target_: mml.core.scripts.schedulers.clean_scheduler.CleanScheduler + ### + # default: [temp,download] + # - "temp" routine removes temporary files that may remain as artefacts during task creation + # - "download" routine removes the downloads of a dataset + subroutines: + - temp + - download + ### + # default: false + # - if true won't ask for confirmation to delete files + force: False + ### + # default: false + # - if false only cares for tasks in task_list, otherwise all installed tasks will be considered + all: False diff --git a/src/mml/configs/mode/create.yaml b/src/mml/configs/mode/create.yaml new file mode 100644 index 0000000..827af5f --- /dev/null +++ b/src/mml/configs/mode/create.yaml @@ -0,0 +1,39 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - override /preprocessing: none + +mode: + scheduler: + ### + # default: :class:`~mml.core.scripts.schedulers.clean_scheduler.CreateScheduler` + # - the clean scheduler assists in getting rid of file artifacts, reducing disk usage by mml + _target_: mml.core.scripts.schedulers.create_scheduler.CreateScheduler + ### + # default: [dataset,task] + # - "dataset" routine creates the necessary datasets, comprising potential download and extraction + # - "task" routine creates the task description files and necessary transformation, requires datasets + # - only datasets/tasks non-present will trigger a computation so it is safe to keep both subroutines + subroutines: + - dataset + - task + ### + # default: 5 + # - changes the default value into how many splits the generated tasks should be distributed to + # - must be an integer larger 1 + # - only applies if the task creator uses the internal :meth:`~mml.core.data_preparation.task_creator.TaskCreator.split_folds` method + # - does not apply if :meth:`~mml.core.data_preparation.task_creator.TaskCreator.use_existing_folds` is used instead + n_folds: 5 + ### + # default: true + # - changes the default value whether the splitting into folds should respect class distributions + # - only applies to classification tasks + # - only applies if the task creator uses the internal :meth:`~mml.core.data_preparation.task_creator.TaskCreator.split_folds` method + # - does not apply if :meth:`~mml.core.data_preparation.task_creator.TaskCreator.use_existing_folds` is used instead + ensure_balancing: true \ No newline at end of file diff --git a/src/mml/configs/mode/downgrade.yaml b/src/mml/configs/mode/downgrade.yaml new file mode 100644 index 0000000..f9cd1a1 --- /dev/null +++ b/src/mml/configs/mode/downgrade.yaml @@ -0,0 +1,19 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# convenience config entry to call upgrade scheduler with downgrade subroutine +defaults: + - /mode@_global_: upgrade + - _self_ + +mode: + ### + # default: [downgrade] + # - "downgrade" undoes a compatibility upgrade back to `mode.version` + subroutines: + - downgrade diff --git a/src/mml/configs/mode/info.yaml b/src/mml/configs/mode/info.yaml new file mode 100644 index 0000000..c843393 --- /dev/null +++ b/src/mml/configs/mode/info.yaml @@ -0,0 +1,41 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - override /augmentations: no_norm +mode: + scheduler: + ### + # default: :class:`~mml.core.scripts.schedulers.clean_scheduler.InfoScheduler` + # - the info scheduler is intended to provide fast summarizing information on data / results + _target_: mml.core.scripts.schedulers.info_scheduler.InfoScheduler + ### + # default: [tasks,hpo,sample_grid,models] + # - "tasks" routine shows information on the tasks provided + # - "hpo" routine shows information on hpo results (see study_name parameter) + # - "samples" routine plots sample images for each task (and/or jointly) + # - "models" routine shows information on existing model descriptions for this project + subroutines: + - tasks + - hpo + - samples + - models + ### + # default: null + # - provide a specific optuna study name to receive detailed information + # - required for the hpo subroutine + # - will only resolve in a warning if not provided + study_name: null + ### + # default: True + # - generates a grid plot in tasks subroutine with each task corresponding to one cell + info_grid: True + ### + # default: True + # - generates a sample image in tasks subroutine for each task + info_individual: True diff --git a/src/mml/configs/mode/post.yaml b/src/mml/configs/mode/post.yaml new file mode 100644 index 0000000..615a7cb --- /dev/null +++ b/src/mml/configs/mode/post.yaml @@ -0,0 +1,59 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# post-processing routine +defaults: + - override /preprocessing: none + +mode: + scheduler: + ### + # default: :class:`~mml.core.scripts.schedulers.clean_scheduler.PostprocessScheduler` + # - the post scheduler postprocesses mml models by calibration and ensembling + _target_: mml.core.scripts.schedulers.postprocess_scheduler.PostprocessScheduler + ### + # default: [calibrate,ensemble] + # - "calibrate" routine calibrates model predictions + # - "ensemble" routine ensembles (calibrated) predictions + subroutines: + - calibrate + - ensemble + # calibration parameters + ### + # default: val + # - which prior to use for calibration + # - either test, val (based on respective splits), quantify (infers on unlabeled) or a list [p0, p1, ...] + # - if test or val the TRUE underlying priors of these datasplits are used + # - quantify uses `Adjusted Classify & Count `_ on the unlabeled split + # - if a list of floats these will be used directly + prior: val + # ensemble parameters + ### + # default: 0.5 + # - use this much of test data to select ensemble, remaining will be used as estimated performance + eval_frac: 0.5 + ### + # default: 1000 + # - how many ensemble candidates shall be tested + budget: 1000 + ### + # default: 10 + # - how many weight variations shall be tested, set to zero to weigh all ensemble member equal + weights_budget: 10 + ### + # default: 5 + # - largest possible ensemble to test (up to this many base model are ensembled) + max_ensemble_size: 5 + ### + # default: 0.3 + # - between 0 and 1, determines search order, larger means more random combinations to be tested + temperature: 0.3 + ### + # default: 0.5 + # - between 0 and 1, determines deviation of weights to be inspected, larger means higher + weights_temperature: 0.5 \ No newline at end of file diff --git a/src/mml/configs/mode/pp.yaml b/src/mml/configs/mode/pp.yaml new file mode 100644 index 0000000..a57d02b --- /dev/null +++ b/src/mml/configs/mode/pp.yaml @@ -0,0 +1,22 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - override /sampling: full + +mode: + scheduler: + ### + # default: :class:`~mml.core.scripts.schedulers.clean_scheduler.PreprocessScheduler` + # - the pp scheduler preprocesses the data (of all splits) for faster training and inference + _target_: mml.core.scripts.schedulers.preprocess_scheduler.PreprocessScheduler + ### + # default: [preprocess] + # - "preprocess" routine does the job and is the only subroutine for this scheduler + subroutines: + - preprocess \ No newline at end of file diff --git a/src/mml/configs/mode/predict.yaml b/src/mml/configs/mode/predict.yaml new file mode 100644 index 0000000..b869e69 --- /dev/null +++ b/src/mml/configs/mode/predict.yaml @@ -0,0 +1,19 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# convenience config entry to call train scheduler with predict subroutine +defaults: + - /mode@_global_: train + - _self_ + +mode: + ### + # default: [predict] + # - "predict" routine predicts samples, requires appropriate models to be loaded + subroutines: + - predict \ No newline at end of file diff --git a/src/mml/configs/mode/test.yaml b/src/mml/configs/mode/test.yaml new file mode 100644 index 0000000..1449dc2 --- /dev/null +++ b/src/mml/configs/mode/test.yaml @@ -0,0 +1,19 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# convenience config entry to call train scheduler with test subroutine +defaults: + - /mode@_global_: train + - _self_ + +mode: + ### + # default: [test] + # - "test" routine tests the loaded model on the test split of a task + subroutines: + - test diff --git a/src/mml/configs/mode/tl.yaml b/src/mml/configs/mode/tl.yaml new file mode 100644 index 0000000..12f45c5 --- /dev/null +++ b/src/mml/configs/mode/tl.yaml @@ -0,0 +1,30 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - train # this mode inherits all properties and config options from train mode +mode: + scheduler: + ### + # default: :class:`~mml.core.scripts.schedulers.clean_scheduler.TransferScheduler` + # - the tl scheduler enables transfer learning, aka finetuning from an existing pretrained model + _target_: mml.core.scripts.schedulers.transfer_scheduler.TransferScheduler + ### + # default: ??? + # - the task the pretrained model was trained on + pretrain_task: ??? + ### + # default: performance + # - strategy to select the model among all models that have been pretrained on the given task + # - model must be loaded via the reuse functionality! + # - one of performance (=best loss), created (=latest), random + model_selection: performance + ### + # default: False + # - if True freeze the backbone of the model and only learn head parameters (also called linear probing) + freeze: False \ No newline at end of file diff --git a/src/mml/configs/mode/train.yaml b/src/mml/configs/mode/train.yaml new file mode 100644 index 0000000..c90d057 --- /dev/null +++ b/src/mml/configs/mode/train.yaml @@ -0,0 +1,98 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - override /sampling: full + - override /lr_scheduler: none +mode: + scheduler: + ### + # default: :class:`~mml.core.scripts.schedulers.clean_scheduler.TrainingScheduler` + # - the train scheduler performs model training, as well as optionally testing and prediction + _target_: mml.core.scripts.schedulers.train_scheduler.TrainingScheduler + ### + # default: [train] + # - "train" routine trains models on the target task(s) + # - "predict" produces logits on test and unlabeled split that will be stored, these can be used for postprocessing + # - "test" evaluates without any postprocessing + subroutines: + - train +# - predict # produce logits that will be stored, these can be used for postprocessing +# - test # evaluate without any postprocessing +# training options + ### + # default: true + # - whether to use cross validation + # - if true will train one model for each split in the data (of the pivot task) + # - predict and test routines will be performed for each split separately + cv: true + ### + # default: true + # - whether to nest the pivot task (setting aside a fraction for testing) + # - will automatically create a tagged variant for each fold (see cross validation) + # - the original validation split of that fold will be excluded as test data + # - the remaining train data is redistributed into same number of folds as the previous total number of splits + # - nesting allows to set aside the original test data and rely on a fraction of left-out training data during the development phase + nested: true + ### + # default: true + # - set false to avoid exploding storage usage, incompatible with usage of predict or test + # - will deactivate any storing of model weights (except for the snaphots during training, see :meth:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler.create_trainer`) + # - you may alternatively set `remove.parameters=true` which will only delete model weights after the scheduler terminates successfully + store_parameters: true + ### + # default: true + # - if true selects the model state with the best validation score, otherwise uses final epoch model + store_best: true +# multitask options + ### + # default: false + # - whether to add additional tasks to be learned in parallel, set to false or any integer greater 1 + # - will add a model head for each additional task + # - make sure potential additional task's TaskType is supported by the model backbone + multitask: false + ### + # default: random + # - co tasks selection strategy, can be random, or an explicit list of co-tasks + # - (potential) co-tasks must be given in the task_list! + co_tasks: random + ### + # default: null + # - wighting of tasks in the overall loss + # - if null all tasks are weighted equally, if a list of floats pivot is first and co_tasks next + task_weights: null +# evaluation options + ### + # default: null + # - allows to predict/test on another task than the pivot one, + # - can also be a list of tasks, if so multiple predictions / tests are performed (one for each) + eval_on: null +# blueprint options + ### + # default: False + # - whether to use a (previously generated) blueprint to override some configurations + # - blueprint must be loaded (via reuse.blueprint) and assigned to the pivot task + # - see the ``suggest`` plugin for an example how to generate blueprints + use_blueprint: False + ### + # default: [arch,augmentations,cbs,loss,lr_scheduler,mode,optimizer,preprocessing,sampling,trainer,tta,tune] + # - these pipeline keys will be for one stored as a documentation of the training pipeline + # - on the other hand if using a blueprint, only these keys will be loaded to override the given sections + pipeline_keys: + - 'arch' + - 'augmentations' + - 'cbs' + - 'loss' + - 'lr_scheduler' + - 'mode' + - 'optimizer' + - 'preprocessing' + - 'sampling' + - 'trainer' + - 'tta' + - 'tune' diff --git a/src/mml/configs/mode/upgrade.yaml b/src/mml/configs/mode/upgrade.yaml new file mode 100644 index 0000000..5132be5 --- /dev/null +++ b/src/mml/configs/mode/upgrade.yaml @@ -0,0 +1,29 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +defaults: + - override /preprocessing: none + +mode: + scheduler: + ### + # default: :class:`~mml.core.scripts.schedulers.clean_scheduler.UpgradeScheduler` + # - the upgrade scheduler assists in migrating your database between different versions of ``mml`` + # - whenever a backward compatibility breaking version is released (with respect to data and/or results) this scheduler may resolve upcoming issues + _target_: mml.core.scripts.schedulers.upgrade_scheduler.UpgradeScheduler + ### + # default: [upgrade] + # - "upgrade" does a compatibility upgrade from `mode.version` + subroutines: + - upgrade + ### + # default: ??? + # - for the "upgrade" subroutine this marks the previous version + # - for the "downgrade" subroutine this marks the target version + # - is a required argument! Example ``mml upgrade mode.version=0.12.0`` + version: ??? diff --git a/src/mml/configs/optimizer/adam.yaml b/src/mml/configs/optimizer/adam.yaml new file mode 100644 index 0000000..0e315f6 --- /dev/null +++ b/src/mml/configs/optimizer/adam.yaml @@ -0,0 +1,30 @@ +#@package optimizer + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: :class:`~torch.optim.Adam` +# - the Adam optimizer +# - see `Adam `_ +_target_: torch.optim.Adam +### +# default: [ 0.9, 0.999 ] +# - coefficients used for computing running averages of gradient and its square +betas: [ 0.9, 0.999 ] +### +# default: 0.0005 +# - the initial learning rate +lr: 0.0005 +### +# default: 1e-08 +# - denominator summand for numerical stability +eps: 1e-08 +### +# default: 0 +# - L2 penalty +weight_decay: 0 +_convert_: "partial" diff --git a/src/mml/configs/optimizer/sgd.yaml b/src/mml/configs/optimizer/sgd.yaml new file mode 100644 index 0000000..e84ce2e --- /dev/null +++ b/src/mml/configs/optimizer/sgd.yaml @@ -0,0 +1,30 @@ +#@package optimizer + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: :class:`~torch.optim.SGD` +# - stochastic gradient descent optimizer +# - see `SGD `_ +_target_: torch.optim.SGD +### +# default: 0.0005 +# - the initial learning rate +lr: 0.0005 +### +# default: 0 +# - momentum factor +momentum: 0 +### +# default: 0 +# - L2 penalty +weight_decay: 0 +### +# default: 0 +# - dampening for momentum +dampening: 0 +_convert_: "partial" diff --git a/src/mml/configs/preprocessing/default.yaml b/src/mml/configs/preprocessing/default.yaml new file mode 100644 index 0000000..cea79e2 --- /dev/null +++ b/src/mml/configs/preprocessing/default.yaml @@ -0,0 +1,25 @@ +# @package preprocessing + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# specifies the pipeline to preprocess RGB images (e.g. scaling) +# the only preprocessing backend currently supported is albumentations +id: default # this id must match the file name! +### +# default: pipeline consists of +# - SmallestMaxSize(max_size=256) +# - PadIfNeeded(min_height=288,min_width=288) +# - Resize(height=256,width=256) +pipeline: + - name: SmallestMaxSize + max_size: 256 + - name: PadIfNeeded + min_height: 288 + min_width: 288 + - name: Resize + height: 256 + width: 256 diff --git a/src/mml/configs/preprocessing/example.yaml b/src/mml/configs/preprocessing/example.yaml new file mode 100644 index 0000000..cd2108a --- /dev/null +++ b/src/mml/configs/preprocessing/example.yaml @@ -0,0 +1,23 @@ +# @package preprocessing + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# specifies the pipeline to preprocess RGB images (e.g. scaling) + +id: example # this id must match the file name! +### +# default: pipeline consists of +# - PadIfNeeded(min_height=512,min_width=512) +# - Resize(height=256,width=256) +pipeline: + - name: PadIfNeeded + min_height: 512 + min_width: 512 + - name: Resize + height: 256 + width: 256 + diff --git a/src/mml/configs/preprocessing/none.yaml b/src/mml/configs/preprocessing/none.yaml new file mode 100644 index 0000000..7f709aa --- /dev/null +++ b/src/mml/configs/preprocessing/none.yaml @@ -0,0 +1,14 @@ +# @package preprocessing + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# this special pp represents no pp and should be left untouched +id: none # this id must match the file name! +### +# default: {} +# - an empty pipeline to neglect any preprocessing +pipeline: { } diff --git a/src/mml/configs/preprocessing/size224.yaml b/src/mml/configs/preprocessing/size224.yaml new file mode 100644 index 0000000..bbb1ee5 --- /dev/null +++ b/src/mml/configs/preprocessing/size224.yaml @@ -0,0 +1,25 @@ +# @package preprocessing + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# specifies the pipeline to preprocess RGB images (e.g. scaling) + +id: size224 # this id must match the file name! +### +# default: pipeline consists of +# - SmallestMaxSize(max_size=224) +# - PadIfNeeded(min_height=256,min_width=256) +# - Resize(height=224,width=224) +pipeline: + - name: SmallestMaxSize + max_size: 224 + - name: PadIfNeeded + min_height: 256 + min_width: 256 + - name: Resize + height: 224 + width: 224 \ No newline at end of file diff --git a/src/mml/configs/preprocessing/size256.yaml b/src/mml/configs/preprocessing/size256.yaml new file mode 100644 index 0000000..307abdb --- /dev/null +++ b/src/mml/configs/preprocessing/size256.yaml @@ -0,0 +1,25 @@ +# @package preprocessing + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# specifies the pipeline to preprocess RGB images (e.g. scaling) + +id: size256 # this id must match the file name! +### +# default: pipeline consists of +# - SmallestMaxSize(max_size=256) +# - PadIfNeeded(min_height=288,min_width=288) +# - Resize(height=256,width=256) +pipeline: + - name: SmallestMaxSize + max_size: 256 + - name: PadIfNeeded + min_height: 288 + min_width: 288 + - name: Resize + height: 256 + width: 256 \ No newline at end of file diff --git a/src/mml/configs/preprocessing/size336.yaml b/src/mml/configs/preprocessing/size336.yaml new file mode 100644 index 0000000..e2a3023 --- /dev/null +++ b/src/mml/configs/preprocessing/size336.yaml @@ -0,0 +1,25 @@ +# @package preprocessing + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# specifies the pipeline to preprocess RGB images (e.g. scaling) + +id: size336 # this id must match the file name! +### +# default: pipeline consists of +# - SmallestMaxSize(max_size=336) +# - PadIfNeeded(min_height=368,min_width=368) +# - Resize(height=336,width=336) +pipeline: + - name: SmallestMaxSize + max_size: 336 + - name: PadIfNeeded + min_height: 368 + min_width: 368 + - name: Resize + height: 336 + width: 336 \ No newline at end of file diff --git a/src/mml/configs/preprocessing/size384.yaml b/src/mml/configs/preprocessing/size384.yaml new file mode 100644 index 0000000..f2d3a7f --- /dev/null +++ b/src/mml/configs/preprocessing/size384.yaml @@ -0,0 +1,25 @@ +# @package preprocessing + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# specifies the pipeline to preprocess RGB images (e.g. scaling) + +id: size384 # this id must match the file name! +### +# default: pipeline consists of +# - SmallestMaxSize(max_size=384) +# - PadIfNeeded(min_height=416,min_width=416) +# - Resize(height=384,width=384) +pipeline: + - name: SmallestMaxSize + max_size: 384 + - name: PadIfNeeded + min_height: 416 + min_width: 416 + - name: Resize + height: 384 + width: 384 \ No newline at end of file diff --git a/src/mml/configs/preprocessing/size512.yaml b/src/mml/configs/preprocessing/size512.yaml new file mode 100644 index 0000000..9b9b903 --- /dev/null +++ b/src/mml/configs/preprocessing/size512.yaml @@ -0,0 +1,25 @@ +# @package preprocessing + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# specifies the pipeline to preprocess RGB images (e.g. scaling) + +id: size512 # this id must match the file name! +### +# default: pipeline consists of +# - SmallestMaxSize(max_size=512) +# - PadIfNeeded(min_height=574,min_width=574) +# - Resize(height=512,width=512) +pipeline: + - name: SmallestMaxSize + max_size: 512 + - name: PadIfNeeded + min_height: 574 + min_width: 574 + - name: Resize + height: 512 + width: 512 diff --git a/src/mml/configs/preprocessing/size528.yaml b/src/mml/configs/preprocessing/size528.yaml new file mode 100644 index 0000000..4c92139 --- /dev/null +++ b/src/mml/configs/preprocessing/size528.yaml @@ -0,0 +1,25 @@ +# @package preprocessing + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# specifies the pipeline to preprocess RGB images (e.g. scaling) + +id: size528 # this id must match the file name! +### +# default: pipeline consists of +# - SmallestMaxSize(max_size=528) +# - PadIfNeeded(min_height=592,min_width=592) +# - Resize(height=528,width=528) +pipeline: + - name: SmallestMaxSize + max_size: 528 + - name: PadIfNeeded + min_height: 592 + min_width: 592 + - name: Resize + height: 528 + width: 528 \ No newline at end of file diff --git a/src/mml/configs/remove/all.yaml b/src/mml/configs/remove/all.yaml new file mode 100644 index 0000000..0b33b77 --- /dev/null +++ b/src/mml/configs/remove/all.yaml @@ -0,0 +1,42 @@ +# @package remove + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# this is the "remove" functionality, remove files created according to keys after a successful mml run + +### +# default: True +# - backup files +backup: True +### +# default: True +# - training pipeline blueprints +blueprint: True +### +# default: True +# - model storage +models: True +### +# default: True +# - model weights +parameters: True +### +# default: True +# - training pipeline +pipeline: True +### +# default: True +# - model predictions +predictions: True +### +# default: True +# - grid of example images as produced by the info mode +sample_grid: True +### +# default: True +# - example images as produced by the info mode +img_examples: True diff --git a/src/mml/configs/remove/none.yaml b/src/mml/configs/remove/none.yaml new file mode 100644 index 0000000..b680c20 --- /dev/null +++ b/src/mml/configs/remove/none.yaml @@ -0,0 +1,21 @@ +# @package remove + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# this is the "remove" functionality, remove files created according to keys after a successful mml run +backup: False +blueprint: False +img_examples: False +models: False +parameters: False +pipeline: False +predictions: False +sample_grid: False + + + + diff --git a/src/mml/configs/reuse/current.yaml b/src/mml/configs/reuse/current.yaml new file mode 100644 index 0000000..7343877 --- /dev/null +++ b/src/mml/configs/reuse/current.yaml @@ -0,0 +1,20 @@ +# @package reuse + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# convenience version of reuse, when loading everything from the current project + +# this is the "reuse" functionality, load path/model attributes from previous runs or even other projects + +### +# default: ${proj} +# - loads blueprints from current project +blueprint: ${proj} +### +# default: ${proj} +# - loads models from current project +models: ${proj} diff --git a/src/mml/configs/reuse/none.yaml b/src/mml/configs/reuse/none.yaml new file mode 100644 index 0000000..f3bfa97 --- /dev/null +++ b/src/mml/configs/reuse/none.yaml @@ -0,0 +1,11 @@ +# @package reuse + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# this is the "reuse" functionality, load path/model attributes from previous runs or even other projects +blueprint: null +models: null diff --git a/src/mml/configs/sampling/full.yaml b/src/mml/configs/sampling/full.yaml new file mode 100644 index 0000000..453810b --- /dev/null +++ b/src/mml/configs/sampling/full.yaml @@ -0,0 +1,41 @@ +# @package sampling + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: 0 +# - number of samples per epoch +# - if 0 will use len(dataset) samples (even if balanced sampling is active) +sample_num: 0 +### +# default: false +# - if true will try to sample equally from each (target) class +# - if false samples randomly over the split +# - unbalanced sampling might activate weights in loss criterion, see loss.auto_activate_weighing +balanced: false +### +# default: 300 +# - number of samples used in one forward+backward pass +# - batch size will be overwritten if you activate tune.bs to automatically tune the batch size +batch_size: 300 +### +# default: false +# - whether the final (incomplete) batch will be dropped at the end of the epoch +# - directly passed to `DataLoader `_ +drop_last: False +### +# default: false +# - if true activates a caching mechanism which trades in RAM usage for less disk access +# - only works for already preprocessed datasets! +enable_caching: False +### +# default: 10000 +# - sets a max_size of cache (in terms of images), cache will be disabled if more images are in the datasets loaded +# - avoid exploding RAM by keeping low or downsize images during preprocess +# - from experience increasing above 10000 does not yield any more benefits, but this may be very case dependent +# - for full optimization consider experimenting with num_workers entry of the config +cache_max_size: 10000 \ No newline at end of file diff --git a/src/mml/configs/search_space/example.yaml b/src/mml/configs/search_space/example.yaml new file mode 100644 index 0000000..e6a953c --- /dev/null +++ b/src/mml/configs/search_space/example.yaml @@ -0,0 +1,20 @@ +# @package search_space + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# define range of hyperparameters +# see https://hydra.cc/docs/next/plugins/optuna_sweeper/ for detailed instructions + + +### +# default: choice(32, 64, 128) +# - searches these three variants of a batch size (adapting the "sampling.batch_size" config) +sampling.batch_size: choice(32, 64, 128) +### +# default: interval(0.0001, 0.2) +# - searches the given interval for a learning rate (adapting the "optimizer.lr" config) +optimizer.lr: interval(0.0001, 0.2) \ No newline at end of file diff --git a/src/mml/configs/search_space/none.yaml b/src/mml/configs/search_space/none.yaml new file mode 100644 index 0000000..0f53ca4 --- /dev/null +++ b/src/mml/configs/search_space/none.yaml @@ -0,0 +1,10 @@ +# @package search_space + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# define range of hyperparameters +# see https://hydra.cc/docs/next/plugins/optuna_sweeper/ for detailed instructions \ No newline at end of file diff --git a/src/mml/configs/sys/cluster.yaml b/src/mml/configs/sys/cluster.yaml new file mode 100644 index 0000000..ce3e25f --- /dev/null +++ b/src/mml/configs/sys/cluster.yaml @@ -0,0 +1,28 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: ${oc.env:MML_CLUSTER_DATA_PATH} +# - path to data folder +# - by default the environment variable is read +data_dir: ${oc.env:MML_CLUSTER_DATA_PATH} +### +# default: ${oc.env:MML_CLUSTER_RESULTS_PATH} +# - path to results (output) folder +# - by default the environment variable is read +out_dir: ${oc.env:MML_CLUSTER_RESULTS_PATH} +### +# default: ${oc.env:MML_CLUSTER_WORKERS} +# - number of max processes to spawn +# - by default the environment variable is read +num_workers: ${oc.env:MML_CLUSTER_WORKERS} +trainer: + ### + # default: False + # - disable progress bar for detached system + enable_progress_bar: False diff --git a/src/mml/configs/sys/local.yaml b/src/mml/configs/sys/local.yaml new file mode 100644 index 0000000..d90b0ee --- /dev/null +++ b/src/mml/configs/sys/local.yaml @@ -0,0 +1,23 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: ${oc.env:MML_DATA_PATH} +# - path to data folder +# - by default the environment variable is read +data_dir: ${oc.env:MML_DATA_PATH} +### +# default: ${oc.env:MML_CLUSTER_RESULTS_PATH} +# - path to results (output) folder +# - by default the environment variable is read +out_dir: ${oc.env:MML_RESULTS_PATH} +### +# default: ${oc.env:MML_LOCAL_WORKERS} +# - number of max processes to spawn +# - by default the environment variable is read +num_workers: ${oc.env:MML_LOCAL_WORKERS} diff --git a/src/mml/configs/tasks/_template.yaml b/src/mml/configs/tasks/_template.yaml new file mode 100644 index 0000000..d892542 --- /dev/null +++ b/src/mml/configs/tasks/_template.yaml @@ -0,0 +1,41 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + + +# list your desired tasks here, use the name specified during task creation to reference it +# you may add "tags" to tasks e.g. "task_alias_one+subset?0_05+confuse?0_1" shrinks the task to 5 percent of +# training samples and afterward replaces 10 percent of the labels by random assignments + +# Available tags are: +# identity -> does not change task, not necessary to be added for individual tasks, only necessary for tagging.variants +# nested -> nests the task, shifting validation split to test data and re-distributing the remaining splits into train+val +# (these tags are more for internal use, it is straightforward to implement additional tags, see the "mml-tags" plugin) + +# Note: keywords are separated with a '+' and following args are separated by a '?'. Any task name may never +# incorporate a ' '. A tagged task thus generally looks like task_alias+tag1?value1?value2+tag2+tag3?value1fortag3... + +task_list: + - 'abc' + - '123' + - 'foo' + +# a pivot task is one of the tasks provided above (or False for no task) and has a special role in some schedules +# the pivot task may be modified via keywords directly, this will automatically replace one non-modified version in +# the tasklist above +pivot: + name: False + tags: '+confuse?0_1' + +# convenience methods for tagging all tasks at once (all) or/and create variants (variants) so multiple differently +# tagged versions of each task, use '+identity' to keep an unmodified variant +tagging: + all: '+subset?0_05+confuse?0_1' + variants: + - '+identity' + - '+subset?0_05' + - '+confuse?0_1' \ No newline at end of file diff --git a/src/mml/configs/tasks/fake.yaml b/src/mml/configs/tasks/fake.yaml new file mode 100644 index 0000000..71c558a --- /dev/null +++ b/src/mml/configs/tasks/fake.yaml @@ -0,0 +1,46 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: [] +# - the task list determines which :class:`~mml.core.data_loading.task_struct.TaskStruct` are available in the scheduler +# - must be provided straight as "task_list=[task_1,task_2,...]" -> do NOT call "tasks.task_list=..." +task_list: [] + +pivot: + ### + # default: 'mml_fake_task' + # - the pivot task is a special highlighted task + # - the mml_fake_task is a dummy classification task for testing purposes + # - it will be added to the list of available tasks automatically + # - must be provided straight as "pivot.name=task_1" -> do NOT call "tasks.pivot.name=..." + name: 'mml_fake_task' + ### + # default: '' + # - allows to attach (multiple) tags to the pivot task + # - use as '+TAG_1?PAR_1?PAR_2+TAG_2+TAG_3?PAR_3' (+ separates tags and ? allows to provide parameters to tags) + # - will be attached to the pivot task automatically + # - must be provided straight as "pivot.tags=+tag_1+tag_2" -> do NOT call "tasks.pivot.tags=..." + tags: '' + + +tagging: + ### + # default: '' + # - convenience methods for tagging all tasks at once + # - usage is identical to pivot.tags + # - if a pivot task is provided make sure to have adapted pivot.name or pivot.tags identical + # - must be provided straight as "tagging.all=+tag_1+tag_2" -> do NOT call "tasks.tagging.all=..." + all: '' + ### + # default: [] + # - creates variants for all tasks, so multiple differently tagged versions of each task + # - will result in n_tasks * n_tags tasks to be present + # - use '+identity' to keep an unmodified variant + # - must be provided straight as "tagging.variants=[+tag_1,+tag_2]" -> do NOT call "tasks.tagging.variants=..." + variants: [ ] \ No newline at end of file diff --git a/src/mml/configs/tasks/none.yaml b/src/mml/configs/tasks/none.yaml new file mode 100644 index 0000000..f52122b --- /dev/null +++ b/src/mml/configs/tasks/none.yaml @@ -0,0 +1,47 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# Convenience config for no tasks, e.g. useful for info mode upon some hpo study. + + +### +# default: [] +# - the task list determines which :class:`~mml.core.data_loading.task_struct.TaskStruct` are available in the scheduler +# - must be provided straight as "task_list=[task_1,task_2,...]" -> do NOT call "tasks.task_list=..." +task_list: [ ] + +pivot: + ### + # default: False + # - the pivot task is a special highlighted task + # - it will be added to the list of available tasks automatically + # - must be provided straight as "pivot.name=task_1" -> do NOT call "tasks.pivot.name=..." + name: False + ### + # default: '' + # - allows to attach (multiple) tags to the pivot task + # - use as '+TAG_1?PAR_1?PAR_2+TAG_2+TAG_3?PAR_3' (+ separates tags and ? allows to provide parameters to tags) + # - will be attached to the pivot task automatically + # - must be provided straight as "pivot.tags=+tag_1+tag_2" -> do NOT call "tasks.pivot.tags=..." + tags: '' + +tagging: + ### + # default: '' + # - convenience methods for tagging all tasks at once + # - usage is identical to pivot.tags + # - if a pivot task is provided make sure to have adapted pivot.name or pivot.tags identical + # - must be provided straight as "tagging.all=+tag_1+tag_2" -> do NOT call "tasks.tagging.all=..." + all: False + ### + # default: [] + # - creates variants for all tasks, so multiple differently tagged versions of each task + # - will result in n_tasks * n_tags tasks to be present + # - use '+identity' to keep an unmodified variant + # - must be provided straight as "tagging.variants=[+tag_1,+tag_2]" -> do NOT call "tasks.tagging.variants=..." + variants: [ ] \ No newline at end of file diff --git a/src/mml/configs/tasks/pami_train_variants.yaml b/src/mml/configs/tasks/pami_train_variants.yaml new file mode 100644 index 0000000..3069524 --- /dev/null +++ b/src/mml/configs/tasks/pami_train_variants.yaml @@ -0,0 +1,51 @@ +# @package _global_ + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# train task set for PAMI 2022 + +task_list: + - 'lapgyn4_anatomical_structures' + - 'lapgyn4_surgical_actions' + - 'lapgyn4_instrument_count' + - 'lapgyn4_anatomical_actions' + # - 'sklin2_skin_lesions' # too few samples + # - 'identify_nbi_infframes' # too few samples + - 'laryngeal_tissues' + - 'nerthus_bowel_cleansing_quality' + - 'stanford_dogs_image_categorization' + - 'svhn' + - 'caltech101_object_classification' + - 'caltech256_object_classification' + - 'cifar10_object_classification' + - 'cifar100_object_classification' + - 'mnist_digit_classification' + - 'emnist_digit_classification' + - 'hyperkvasir_anatomical-landmarks' + - 'hyperkvasir_pathological-findings' + - 'hyperkvasir_quality-of-mucosal-views' + - 'hyperkvasir_therapeutic-interventions' + - 'cholec80_grasper_presence' + - 'cholec80_bipolar_presence' + - 'cholec80_hook_presence' + - 'cholec80_scissors_presence' + - 'cholec80_clipper_presence' + - 'cholec80_irrigator_presence' + - 'cholec80_specimenbag_presence' +# - 'derm7pt_skin_lesions' # too few samples + +pivot: + name: False + tags: '' + +tagging: + all: False + variants: + - '+identity' + - '+subset?0_75' + - '+subset?0_50' + - '+subset?0_15' \ No newline at end of file diff --git a/src/mml/configs/trainer/default_trainer.yaml b/src/mml/configs/trainer/default_trainer.yaml new file mode 100644 index 0000000..0e34f2b --- /dev/null +++ b/src/mml/configs/trainer/default_trainer.yaml @@ -0,0 +1,52 @@ +# @package trainer + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: :class:`lightning.Trainer` +# - the trainer is instantiated by the scheduler through :meth:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler.create_trainer` +# - any kwargs accepted by :class:`~lightning.Trainer` can be provided as `trainer.KWARG=VALUE` +# - callbacks are determined separately through :doc:`callbacks` (see there for details on checkpointing) +# - the experiment logger is determined through :doc:`logging` +# - see `Trainer `_ in the lightning documentation +_target_: lightning.Trainer +### +# default: True +# - deactivate if image sizes change over time or to reduce memory consumption +benchmark: True +### +# default: 16-mixed +# - deactivate if not supported by hardware or high precision is required +precision: 16-mixed +### +# default: 10 +# - will block "early stopping" and similar from interrupting the training until this number of epochs is reached +min_epochs: 10 +### +# default: 50 +# - will stop training once this number of epochs is reached +max_epochs: 50 +### +# default: true +# - prints a model summary at the beginning of each fitting +enable_model_summary: true +### +# default: 0 +# - as it is set to zero, no sanity check is performed to reduce time +num_sanity_val_steps: 0 +### +# default: null +# - will stop training once the given training duration is reached +max_time: null +### +# default: auto +# - determine the hardware accelerator, "auto" will choose depending on available hardware +accelerator: auto +### +# default: 1 +# - number of hardware devices, currently mml is not yet optimized for multi-GPU usage +devices: 1 diff --git a/src/mml/configs/tta/none.yaml b/src/mml/configs/tta/none.yaml new file mode 100644 index 0000000..b648e65 --- /dev/null +++ b/src/mml/configs/tta/none.yaml @@ -0,0 +1,10 @@ +# @package tta + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +mode: mean +variations: {} diff --git a/src/mml/configs/tta/rotate.yaml b/src/mml/configs/tta/rotate.yaml new file mode 100644 index 0000000..0d76e3a --- /dev/null +++ b/src/mml/configs/tta/rotate.yaml @@ -0,0 +1,40 @@ +# @package tta + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +### +# default: mean +# - sets the mode of the :class:`~mml.core.models.merger.PredictionMerger` +# - currently only "mean" is supported +mode: mean +variations: + ### + # default: {name: RandomHorizontalFlip, p: 0.0} + # - perform no augmentation + identity: + - name: RandomHorizontalFlip + p: 0.0 + ### + # default: {name: RandomRotation, p: 1.0, degrees: [ 90, 90 ]} + # - rotate by 90 degrees + rot90: + - name: RandomRotation + degrees: [ 90, 90 ] + p: 1.0 + ### + # default: {name: RandomRotation, p: 1.0, degrees: [ 270, 270 ]} + # - rotate by 270 degrees + rot270: + - name: RandomRotation + degrees: [ 270, 270 ] + p: 1.0 + ### + # default: {name: RandomHorizontalFlip, p: 1.0} + # - flip the image horizontally + hflip: + - name: RandomHorizontalFlip + p: 1.0 diff --git a/src/mml/configs/tune/default.yaml b/src/mml/configs/tune/default.yaml new file mode 100644 index 0000000..925ed10 --- /dev/null +++ b/src/mml/configs/tune/default.yaml @@ -0,0 +1,32 @@ +# @package tune + +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# use lightning tuner to find learning rate and/or maximal batch size +# see https://lightning.ai/docs/pytorch/stable/api/lightning.pytorch.tuner.tuning.Tuner.html + + +### +# default: true +# - activate the learning rate tuning +# - happens before the actual fitting procedure through :meth:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler.lightning_tune` +lr: true +### +# default: false +# - activate the batch size tuning +# - happens before the actual fitting procedure through :meth:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler.lightning_tune` +bs: false +### +# default: {} +# - any additional kwargs to the learning rate finder +# - see `lr_find `_ +lr_kwargs: {} +### +# default: {} +# - any additional kwargs to the batch size finder +# - see `scale_batch_size `_ +bs_kwargs: {} \ No newline at end of file diff --git a/src/mml/core/__init__.py b/src/mml/core/__init__.py new file mode 100644 index 0000000..90ffb6c --- /dev/null +++ b/src/mml/core/__init__.py @@ -0,0 +1,6 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + diff --git a/src/mml/core/data_loading/__init__.py b/src/mml/core/data_loading/__init__.py new file mode 100644 index 0000000..90ffb6c --- /dev/null +++ b/src/mml/core/data_loading/__init__.py @@ -0,0 +1,6 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + diff --git a/src/mml/core/data_loading/augmentations/__init__.py b/src/mml/core/data_loading/augmentations/__init__.py new file mode 100644 index 0000000..90ffb6c --- /dev/null +++ b/src/mml/core/data_loading/augmentations/__init__.py @@ -0,0 +1,6 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + diff --git a/src/mml/core/data_loading/augmentations/albumentations.py b/src/mml/core/data_loading/augmentations/albumentations.py new file mode 100644 index 0000000..757f01e --- /dev/null +++ b/src/mml/core/data_loading/augmentations/albumentations.py @@ -0,0 +1,262 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import hashlib +from typing import Any, Dict, List, Optional + +import albumentations as A +import numpy as np +from albumentations.pytorch import ToTensorV2 +from omegaconf import ListConfig, OmegaConf + +from mml.core.data_loading.augmentations.augmentation_module import ( + IMAGENET_AA_PATH, + AugmentationModule, + DataFormat, + Transform, +) +from mml.core.data_loading.file_manager import MMLFileManager +from mml.core.data_loading.task_attributes import RGBInfo + +ALBUMENTATIONS_VALID_MODALITIES = ["image", "mask"] + + +class AlbumentationsAugmentationModule(AugmentationModule): + """ + Albumentations augmentation module. + + Basic supported dict entries are ['image', 'mask', 'bboxes', 'keypoints']. + + An AutoAlbument generated pipeline is available via the Identifier "ImageNetAA" (no parameters). "RandAugment" with + parameters is also provided on top. See :meth:`get_rand_augment` for details. + + Note that once bboxes and keypoints will be supported than composition will include the respective parameters + https://albumentations.ai/docs/api_reference/core/composition/. Futhermore "additional_targets" might need to be + defined. To check whether a certain augmentation supports a specific target type see + https://albumentations.ai/docs/getting_started/transforms_and_targets/. + """ + + def __init__( + self, + device: str, + cfg: ListConfig, + is_first: bool, + is_last: bool, + means: Optional[RGBInfo], + stds: Optional[RGBInfo], + floatify: bool = False, + tensorize: bool = True, + ): + self.tensorize = tensorize + self.floatify = floatify + if floatify and not tensorize: + raise ValueError("floatify is to ensure float tensors are moved to device") + super().__init__(device=device, cfg=cfg, is_first=is_first, is_last=is_last, means=means, stds=stds) + + def _build_pipeline(self): + transforms = self.from_cfg(self.cfg) + norm_trans = [] + _is_float = False + if self.means is None and self.stds is None: + if self.is_last: + # no normalization requested, but this is the last transform, we need to make sure to have float values + norm_trans.append(A.ToFloat(max_value=255)) + _is_float = True + elif sum([x is None for x in [self.means, self.stds]]) == 1: + raise RuntimeError( + "Was presented either only STD or only MEAN normalization values. " "Require either none or both!" + ) + else: + # default case: requested normalization + norm_trans.append(A.Normalize(mean=self.means.get_rgb(), std=self.stds.get_rgb())) + _is_float = True + # if this is the last transform before moving to gpu we need to make sure to have float tensors + # to support lightning precision + if self.floatify and not _is_float: + norm_trans.append(A.ToFloat(max_value=255)) + if self.tensorize: + norm_trans.append(ToTensorV2()) + self.pipeline = A.Compose([*transforms, *norm_trans]) + + def _forward_impl(self, inpt: Dict[str, Any]) -> Dict[str, Any]: + # albumentations only handles single sample inputs, receive a dict and return a dict + clone = {mod: inpt[mod] for mod in ALBUMENTATIONS_VALID_MODALITIES if mod in inpt} + outpt = self.pipeline(**clone) + outpt.update({k: v for k, v in inpt.items() if k not in ALBUMENTATIONS_VALID_MODALITIES}) + return outpt + + def _sanity_check(self, inpt: Any) -> None: + # albumentations sanity checks + assert self.device == "cpu" + assert self.data_format == DataFormat.SINGLE_SAMPLE_DICT + + def __hash__(self): + """MD5 Hash value of the pipeline.""" + path = MMLFileManager.instance().construct_saving_path(None, key="temp", file_name="hash_dump.json") + A.save(self.pipeline, str(path)) + block_size = 65536 + hasher = hashlib.md5() + with open(str(path), "rb") as file: + buf = file.read(block_size) + while len(buf) > 0: + hasher.update(buf) + buf = file.read(block_size) + return hasher.hexdigest() + + @staticmethod + def from_cfg(aug_config: ListConfig) -> List[Transform]: + """ + Takes a config and returns a list of corresponding transforms. + + :param DictConfig aug_config: see configs/augmentations/default.yaml for an example, the "cpu" attribute is what + has to be passed to this function. + :return: a list of albumentation transforms + """ + aug_config = OmegaConf.to_container(aug_config, resolve=True) + transforms = [] + for transform_args in aug_config: + transform_name = transform_args.pop("name") + if transform_name == "RandAugment": + transform = AlbumentationsAugmentationModule.get_rand_augment(**transform_args) + elif transform_name == "ImageNetAA": + transform: Transform = A.load(IMAGENET_AA_PATH) # type: ignore + else: + transform = A.from_dict( # type: ignore + { + "transform": { + "__class_fullname__": "albumentations.augmentations.transforms." + transform_name, + **transform_args, + } + } + ) + transforms.append(transform) + return transforms + + @staticmethod + def compose_albumentations_transforms( + pp_trans: List[A.BasicTransform], + aug_trans: List[A.BasicTransform], + mean: Optional[RGBInfo] = None, + std: Optional[RGBInfo] = None, + ) -> A.Compose: + """ + Composes transforms from preprocessing, data augmentation, normalization and tensorization. + + :param pp_trans: list of preprocessing transforms, can be empty + :param aug_trans: list of data augmentation transforms, can be empty + :param mean: mean channel values to normalize input data + :param std: standard deviation values per channel to normalize input data + :return: a composed albumentation pipeline + """ + norm_trans = [] + if mean is None and std is None: + norm_trans.append(A.ToFloat(max_value=255)) + elif sum([x is None for x in [mean, std]]) == 1: + raise RuntimeError( + "Was presented either only STD or only MEAN normalization values. " "Require either none or both!" + ) + else: + mean = mean.get_rgb() + std = std.get_rgb() + norm_trans.append( + A.Normalize( + mean=mean, + std=std, + ) + ) + return A.Compose([*pp_trans, *aug_trans, *norm_trans, ToTensorV2()]) + + @staticmethod + def get_rand_augment( + number: int, magnitude: int, p: float = 1.0, mode: str = "all", cut_out: bool = False + ) -> A.BaseCompose: + """ + Gets RandAugment transform. For details see https://arxiv.org/abs/1909.13719. + + :param number: number of transforms to be applied (excluding cut_out if active) + :param magnitude: int between 0 and 9 determining strength of transformation + :param p: probability to apply RandAugment + :param mode: either 'geo' for geometrical transforms, 'color' for color transforms or 'all' for both of them + :param cut_out: indicating if cutout should be applied + :return: an albumentations transform + """ + MAX_MAGNITUDE = 10 + assert 0 < magnitude < MAX_MAGNITUDE, f"magnitude range is 1 - 9, was given {magnitude}" + assert mode in ["geo", "color", "all"], f"incorrect RandAugment mode {mode}, provide one of [color, geo, all]" + + ops = [ # 0 - geometrical + A.Affine( + translate_percent=( + float(-np.linspace(0, 1, MAX_MAGNITUDE)[magnitude]), + float(np.linspace(0, 1, MAX_MAGNITUDE)[magnitude]), + ), + p=p, + cval_mask=255, + ), + A.Affine( + rotate=( + float(-np.linspace(0, 45, MAX_MAGNITUDE)[magnitude]), + float(np.linspace(0, 45, MAX_MAGNITUDE)[magnitude]), + ), + p=p, + cval_mask=255, + ), + A.Affine( + scale=( + 1 + float(-np.linspace(0, 0.5, MAX_MAGNITUDE)[magnitude]), + 1 + float(np.linspace(0, 0.5, MAX_MAGNITUDE)[magnitude]), + ), + p=p, + cval_mask=255, + keep_ratio=True, + ), + A.Affine( + shear=( + float(-np.linspace(0, 35, MAX_MAGNITUDE)[magnitude]), + float(np.linspace(0, 35, MAX_MAGNITUDE)[magnitude]), + ), + p=p, + cval_mask=255, + ), + # 4 - Color Based + A.InvertImg(p=p), + A.Equalize(p=p), + A.Solarize(threshold=float(np.linspace(0, 256, MAX_MAGNITUDE)[magnitude]), p=p), + A.Posterize(num_bits=int(np.linspace(0, 8, MAX_MAGNITUDE)[magnitude]), p=p), + A.RandomBrightnessContrast( + brightness_limit=float(np.linspace(0, 0.8, MAX_MAGNITUDE)[magnitude]), contrast_limit=0.0, p=p + ), + A.RandomBrightnessContrast( + contrast_limit=float(np.linspace(0, 0.8, MAX_MAGNITUDE)[magnitude]), brightness_limit=0.0, p=p + ), + A.Sharpen( + alpha=(0.1, float(np.linspace(0.1, 0.9, MAX_MAGNITUDE)[magnitude])), + lightness=(0.4, float(np.linspace(0.4, 1.0, MAX_MAGNITUDE)[magnitude])), + p=p, + ), + ] + + if mode == "geo": + ops = ops[:4] + elif mode == "color": + ops = ops[5:] + else: + ops = ops + transforms = A.SomeOf(transforms=ops, n=number, replace=True, p=1) + if cut_out: + transforms = A.Sequential( + transforms=[ + transforms, + A.CoarseDropout( + num_holes_range=(4, 8), + hole_height_range=(0.05, float(np.linspace(0.05, 0.2, MAX_MAGNITUDE)[magnitude])), + hole_width_range=(0.05, float(np.linspace(0.05, 0.2, MAX_MAGNITUDE)[magnitude])), + mask_fill_value=255, + p=p, + ), + ] + ) + return transforms diff --git a/src/mml/core/data_loading/augmentations/augmentation_module.py b/src/mml/core/data_loading/augmentations/augmentation_module.py new file mode 100644 index 0000000..9a301e9 --- /dev/null +++ b/src/mml/core/data_loading/augmentations/augmentation_module.py @@ -0,0 +1,119 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from abc import ABC, abstractmethod +from pathlib import Path +from typing import Any, Callable, Dict, List, Optional, Union + +import torch +from omegaconf import ListConfig, OmegaConf + +from mml.core.data_loading.task_attributes import RGBInfo +from mml.core.scripts.utils import StrEnum + +IMAGENET_AA_PATH = Path(__file__).parent / "imagenet.json" +Transform = Callable[[Dict[str, Any]], Dict[str, Any]] + + +class DataFormat(StrEnum): + SINGLE_SAMPLE_DICT = "single_sample_dict" # Dict[str, Union[torch.Tensor, str]] where tensor is single sample + BATCHED_SAMPLE_DICTS = "batched_sample_dicts" # Dict[str, Union[torch.Tensor, List[str]]] where tensor is batched + MULTI_TASK_SAMPLE_DICTS = "multitask_sample_dicts" # Dict[str, Dict[str ,Union[torch.Tensor, List[str]]]] (batched) + + +class AugmentationModule(ABC): + def __init__( + self, + device: str, + cfg: Union[ListConfig, List[Dict[str, Any]]], + is_first: bool, + is_last: bool, + means: Optional[RGBInfo], + stds: Optional[RGBInfo], + ): + self.data_format = None + self.device = device + self.cfg = OmegaConf.create(cfg) + self.is_first = is_first + self.is_last = is_last + self.means = means + self.stds = stds + self.pipeline = None + self._build_pipeline() + if self.pipeline is None: + raise RuntimeError("AugmentationModule instantiated incorrectly!") + + def __len__(self): + return len(self.pipeline) + + def __call__(self, *args, **kwargs) -> Dict[str, Any]: + """The intended way to use AugmentationModule is to call with data argument.""" + if self.device == "cpu": + inpt = kwargs + elif self.device == "gpu": + inpt = args[0] # batch and dataloader_idx on gpu + else: + raise RuntimeError("invalid device!") + # during first call interpret data format and sanity check + if self.data_format is None: + self.data_format = self.get_data_format(inpt) + self._sanity_check(inpt) + return self._forward_impl(inpt) + + @abstractmethod + def _build_pipeline(self): + """Read in config.""" + pass + + @abstractmethod + def _forward_impl(self, inpt: Any) -> Any: + """Apply augmentation on input.""" + pass + + @abstractmethod + def _sanity_check(self, inputs: Any) -> None: + """Make sure the input fits to the pipeline.""" + pass + + @staticmethod + def get_data_format(inpt: Any) -> DataFormat: + """Checks the input data format.""" + # check if valid format at all + if not isinstance(inpt, dict): + raise ValueError(f"Input data format {inpt} is not a dict") + entry = next(iter(inpt.values())) + # check if multi level dict for multi task samples + if isinstance(entry, dict): + return DataFormat.MULTI_TASK_SAMPLE_DICTS + # next check if dict contains batched elements + for vals in inpt.values(): + if isinstance(vals, list): + return DataFormat.BATCHED_SAMPLE_DICTS + if isinstance(vals, torch.Tensor): + if vals.ndim == 4: + return DataFormat.BATCHED_SAMPLE_DICTS + # otherwise this is a single sample dict + return DataFormat.SINGLE_SAMPLE_DICT + + +class AugmentationModuleContainer: + def __init__(self, modules: List[AugmentationModule]): + self.modules = modules + if not all(isinstance(mod, AugmentationModule) for mod in self.modules): + raise ValueError("only AugmentationModules may be passed to AugmentationModuleContainer.") + if any(mod.device != "cpu" for mod in self.modules): + raise ValueError("container can only be initialized with cpu device!") + if len(self.modules) == 0: + raise ValueError("requires at least one module to be passed!") + + def __call__(self, *args, **kwargs) -> Dict[str, Any]: + """Pass as kwargs through each module.""" + for mod in self.modules: + kwargs = mod(**kwargs) + return kwargs + + def __len__(self) -> int: + return sum(len(mod) for mod in self.modules) diff --git a/src/mml/core/data_loading/augmentations/imagenet.json b/src/mml/core/data_loading/augmentations/imagenet.json new file mode 100644 index 0000000..cc857e0 --- /dev/null +++ b/src/mml/core/data_loading/augmentations/imagenet.json @@ -0,0 +1,85418 @@ +{ + "__version__": "0.5.2", + "transform": { + "__class_fullname__": "albumentations.core.composition.Compose", + "p": 1.0, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1531621623502193e-05, + "r_shift_limit": [ + -44, + -44 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.012608357657867053, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 25, + 25 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.009833934658906418, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 110, + 110 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.5622159360998324, + "brightness_limit": [ + 0.01333153247833252, + 0.01333153247833252 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0042053392604198825, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.5675790309906006, + 1.5675790309906006 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.678823156102862e-10, + "threshold": [ + 136, + 136 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.3012102179864576e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.703417173037482e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 180.0, + 180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.810972410286951e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 2.0554094314575195, + 2.0554094314575195 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0004405099702026877, + "max_holes": 16, + "max_height": 162, + "max_width": 162, + "min_holes": 16, + "min_height": 162, + "min_width": 162, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.464622399518638e-05, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.41054140837622477 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00022514659355721972, + "r_shift_limit": [ + 78, + 78 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.7893662089482128e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 38, + 38 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.436884179059139e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 79, + 79 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.8531575023865355e-08, + "brightness_limit": [ + -1.0, + -1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.333909201016393e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.690110350452556e-08, + "threshold": [ + 209, + 209 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.18033507498752321 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.448264795552592e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.982666680972047e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.5098114013671875, + -0.5098114013671875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.530659982429385e-06, + "shift_limit_x": [ + 0.001235365867614746, + 0.001235365867614746 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.420508746017955e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0010864734649658203, + -0.0010864734649658203 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.2089460143913207e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.714104652404785, + 5.714104652404785 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.04504312178579e-11, + "max_holes": 16, + "max_height": 114, + "max_width": 114, + "min_holes": 16, + "min_height": 114, + "min_width": 114, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.8893970549503933e-10, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8193924686541048 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.9077283085430287e-08, + "r_shift_limit": [ + -28, + -28 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0024502134802849296, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.688331691106096e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -80, + -80 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.317109490185755e-06, + "brightness_limit": [ + 0.27456724643707275, + 0.27456724643707275 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00023127071188355774, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.3465018272399902, + 1.3465018272399902 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.4619203442672753e-12, + "threshold": [ + 100, + 100 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.6854546578979352e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.804856611756515e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.70272156748603e-09, + "shift_limit_x": [ + -0.0006415843963623047, + -0.0006415843963623047 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.15714848041534424, + 0.15714848041534424 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3913903842727198e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9855073690414429, + 0.9855073690414429 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00029594728644415785, + "max_holes": 16, + "max_height": 107, + "max_width": 107, + "min_holes": 16, + "min_height": 107, + "min_width": 107, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.025845790574729577, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9711643323244614 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.2295419984959945e-09, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.6586623387271603e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -215, + -215 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.9211565293261993e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -195, + -195 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.780344153761801e-05, + "brightness_limit": [ + -0.24987083673477173, + -0.24987083673477173 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.7019544265202278e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 7.244138240814209, + 7.244138240814209 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0010707853361964226, + "threshold": [ + 39, + 39 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.350674146279772e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.848151213820984e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.9985859394073486, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 2.1841278076171875, + 2.1841278076171875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4434806416829815e-07, + "shift_limit_x": [ + -0.004922330379486084, + -0.004922330379486084 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2562503860537198e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.19466817378997803, + 0.19466817378997803 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5977531504254806e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.881097316741943, + 5.881097316741943 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0112848142697242e-07, + "max_holes": 16, + "max_height": 70, + "max_width": 70, + "min_holes": 16, + "min_height": 70, + "min_width": 70, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00012407428657787087, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.00015329126808438787 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.859014281515973e-05, + "r_shift_limit": [ + 94, + 94 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.08846206963062286, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -36, + -36 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -72, + -72 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0.9422070980072021, + 0.9422070980072021 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0012262874515727162, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1567435264587402, + 1.1567435264587402 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 93, + 93 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.443762311907571e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.512729310477637e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.990620347926841e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -150.28854370117188, + -150.28854370117188 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.840154291769327e-08, + "shift_limit_x": [ + -0.8844317197799683, + -0.8844317197799683 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.828570885113105e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.7652267217636108, + -0.7652267217636108 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.1367802619934082, + 1.1367802619934082 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 102, + "max_width": 102, + "min_holes": 16, + "min_height": 102, + "min_width": 102, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.910252535295857 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.8778135892136385e-06, + "r_shift_limit": [ + 58, + 58 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -43, + -43 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 11, + 11 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.000839468914148378, + "brightness_limit": [ + -0.2550484538078308, + -0.2550484538078308 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.020573222078946518, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.9749754667282104, + 0.9749754667282104 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.5914483366335478e-10, + "threshold": [ + 126, + 126 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.5324081968574815e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.677646875631552e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.491632151455433e-11, + "shift_limit_x": [ + -0.7272960543632507, + -0.7272960543632507 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.0962708767144896e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6515117287635803, + -0.6515117287635803 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.165689908034628e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.914821982383728, + 0.914821982383728 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.022395607608887813, + "max_holes": 16, + "max_height": 143, + "max_width": 143, + "min_holes": 16, + "min_height": 143, + "min_width": 143, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.012470382721734896, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9437184380941768 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.474872886871153e-06, + "r_shift_limit": [ + 117, + 117 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.216721221044339e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.715928997068336e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -93, + -93 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.766330023950847e-10, + "brightness_limit": [ + -0.5644567012786865, + -0.5644567012786865 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.0172954989638847e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.142600655555725, + 1.142600655555725 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.270003046542019e-13, + "threshold": [ + 105, + 105 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 8.453784882645986e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.0584121229639367e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.13457888740220092, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -4.8032379150390625, + -4.8032379150390625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.4704107807546836e-07, + "shift_limit_x": [ + -0.0012812614440917969, + -0.0012812614440917969 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.075537420028741e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.2791386842727661, + 0.2791386842727661 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.6744259516766054e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.150312423706055, + 8.150312423706055 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.926036309635814e-11, + "max_holes": 16, + "max_height": 204, + "max_width": 204, + "min_holes": 16, + "min_height": 204, + "min_width": 204, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.036535239267912e-13, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8654160210004961 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4348968764155996e-11, + "r_shift_limit": [ + -178, + -178 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.3707887048149487e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -143, + -143 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.7160129612776997e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 87, + 87 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.6535423412660087e-07, + "brightness_limit": [ + -1.0, + -1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.0813433680617166e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 5.525184631347656, + 5.525184631347656 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.00036504733725450933, + "threshold": [ + 10, + 10 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 8.792176170923778e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.1283468666078988e-05 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5353101408195335e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 92.05426025390625, + 92.05426025390625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.4887008333535163e-08, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.9995003938674927, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.06387174129486084, + 0.06387174129486084 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.972118094082576e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.466055870056152, + 5.466055870056152 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.439312269539797e-06, + "max_holes": 16, + "max_height": 135, + "max_width": 135, + "min_holes": 16, + "min_height": 135, + "min_width": 135, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.080606631552918e-09, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 2.2536842685605407e-05 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.521259845909272e-10, + "r_shift_limit": [ + -185, + -185 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.2862331369263983e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -39, + -39 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.68683558596685e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -76, + -76 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.767203897944395e-08, + "brightness_limit": [ + -0.4139025807380676, + -0.4139025807380676 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.327724118184225e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.960552453994751, + 0.960552453994751 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.152094309583321e-13, + "threshold": [ + 81, + 81 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.2057520141763385e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.09651857840895595, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 4.328948974609375, + 4.328948974609375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.845444352747487e-14, + "shift_limit_x": [ + -0.7667784690856934, + -0.7667784690856934 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0725760015879658e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6709336042404175, + -0.6709336042404175 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.6182761862002164e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.283939361572266, + 4.283939361572266 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0739005397660434e-06, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.112693875905954e-14, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9034801798561736 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.002099875842100779, + "r_shift_limit": [ + 85, + 85 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.6477710479420884e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -60, + -60 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.006217776950653231, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -30, + -30 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + -0.2089337706565857, + -0.2089337706565857 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.8907334676466717e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.49553012522992e-11, + "threshold": [ + 43, + 43 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.2380899331922915e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.004286513115935e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -135.464599609375, + -135.464599609375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.1309882504367867e-13, + "shift_limit_x": [ + 0.0019332170486450195, + 0.0019332170486450195 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6073518991470337, + -0.6073518991470337 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.764191746711731, + 0.764191746711731 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 99, + "max_width": 99, + "min_holes": 16, + "min_height": 99, + "min_width": 99, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1618948167307579e-08, + "max_holes": 2, + "max_height": 14, + "max_width": 14, + "min_holes": 2, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9916823319057572 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.06256631761789322, + "r_shift_limit": [ + -83, + -83 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.013078567129873209, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -85, + -85 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.087981765008841e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -34, + -34 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0018563933202542932, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.3380846660694068e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 3.0550718307495117, + 3.0550718307495117 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.748152423048018e-11, + "threshold": [ + 76, + 76 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.4822998046875, + -0.4822998046875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.2197816951738007e-06, + "shift_limit_x": [ + -0.6707065105438232, + -0.6707065105438232 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.303836350363671e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.004130661487579346, + -0.004130661487579346 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.265258315725015e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.513463973999023, + 7.513463973999023 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.2020007139384837e-07, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.007778831279180165, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9147143469074585 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.021867308660893814, + "r_shift_limit": [ + 42, + 42 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.602107940412337e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -61, + -61 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.485461926786229e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -35, + -35 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.082871092864023e-09, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.007794616209851446, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1429438591003418, + 1.1429438591003418 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0003727491130121052, + "threshold": [ + 229, + 229 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.3163256207955534e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.0414240722519554e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3615717655616455e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 115.20477294921875, + 115.20477294921875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0558632533376694e-10, + "shift_limit_x": [ + 0.7239068746566772, + 0.7239068746566772 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.9000875353813171, + -0.9000875353813171 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.309861365828801e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9984788298606873, + 0.9984788298606873 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.438470279418411e-06, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0002642724616199951, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.969632191835905 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.096602742609818e-05, + "r_shift_limit": [ + -93, + -93 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.0296389976560346e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 75, + 75 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.380163080708191e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -51, + -51 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.001277297661344795, + "brightness_limit": [ + -0.24049341678619385, + -0.24049341678619385 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0007406387910655482, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.464843988418579, + 1.464843988418579 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 8.071714508264306e-07, + "threshold": [ + 29, + 29 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.2917340432175372e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -171.74928283691406, + -171.74928283691406 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.15467727184295654, + 0.15467727184295654 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.681804346493523e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.032384395599365234, + 0.032384395599365234 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2275725929636201e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.012450933456421, + 1.012450933456421 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.986260252540025e-09, + "max_holes": 16, + "max_height": 119, + "max_width": 119, + "min_holes": 16, + "min_height": 119, + "min_width": 119, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1152895420896505e-07, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.997906334784248 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1895630460419162e-05, + "r_shift_limit": [ + -70, + -70 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.6973447082189942e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 33, + 33 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.13527350259589, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -5, + -5 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.033011171741476275, + "brightness_limit": [ + -0.19261044263839722, + -0.19261044263839722 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.05567525853085442, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1674458980560303, + 1.1674458980560303 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.9515643463640507e-08, + "threshold": [ + 107, + 107 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.1085518152629864e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.2892239458563477e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3837877510525232e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 3.7396240234375, + 3.7396240234375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3911983565151331e-08, + "shift_limit_x": [ + -0.008443593978881836, + -0.008443593978881836 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.899505441826932e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.00015413761138916016, + 0.00015413761138916016 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.1742440462112427, + 1.1742440462112427 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 64, + "max_width": 64, + "min_holes": 16, + "min_height": 64, + "min_width": 64, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.007759360068287757, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.768267058173173 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.492279818164857e-08, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.062063686549663544, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -41, + -41 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.08441309211074843, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -16, + -16 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.429526539615608e-07, + "brightness_limit": [ + -0.20283633470535278, + -0.20283633470535278 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.611883558542315e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.3184677362442017, + 1.3184677362442017 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.185925166423328e-09, + "threshold": [ + 25, + 25 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.3786328853235303e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.7954605617916518e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 180.0, + 180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.339182237487153e-09, + "shift_limit_x": [ + -0.5059983730316162, + -0.5059983730316162 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.43175578117370605, + 0.43175578117370605 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.128572414951868e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.24948787689209, + 7.24948787689209 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1182234120697163e-07, + "max_holes": 16, + "max_height": 191, + "max_width": 191, + "min_holes": 16, + "min_height": 191, + "min_width": 191, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.002899517231497728, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8506205560319499 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.9144096600517953e-07, + "r_shift_limit": [ + -92, + -92 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.008335466496646404, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.3894654774722964e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.706541162911344e-06, + "brightness_limit": [ + -0.2869013547897339, + -0.2869013547897339 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.772806305132488e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.00031815554588030676, + "threshold": [ + 216, + 216 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.1500768871124997e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 127.61447143554688, + 127.61447143554688 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.36777743371631e-06, + "shift_limit_x": [ + 0.0018056631088256836, + 0.0018056631088256836 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1787341016634914e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.74730384349823, + -0.74730384349823 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.293353802905855e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.7803010940551758, + 1.7803010940551758 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.663561908637047e-05, + "max_holes": 16, + "max_height": 114, + "max_width": 114, + "min_holes": 16, + "min_height": 114, + "min_width": 114, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 7, + "max_height": 14, + "max_width": 14, + "min_holes": 7, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9912267191717136 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.546355508263787e-07, + "r_shift_limit": [ + 45, + 45 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.496991780028872e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 10, + 10 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.9619728464994027e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -81, + -81 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.850673382265016e-11, + "brightness_limit": [ + 0.3048436641693115, + 0.3048436641693115 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.596959047837957e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.9876471757888794, + 0.9876471757888794 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.619392166680524e-07, + "threshold": [ + 213, + 213 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.40983207949359e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.6269622817304324e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.2916388512615171, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -41.57106018066406, + -41.57106018066406 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2896703197194622e-13, + "shift_limit_x": [ + -0.3167349100112915, + -0.3167349100112915 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7200466579984335e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.25634753704071045, + 0.25634753704071045 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.3439582620162795e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.802253723144531, + 8.802253723144531 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.916278878745729e-11, + "max_holes": 16, + "max_height": 214, + "max_width": 214, + "min_holes": 16, + "min_height": 214, + "min_width": 214, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.6684942806003093e-11, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7083598673128457 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.967826211485499e-05, + "r_shift_limit": [ + 80, + 80 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.011736919172108173, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00017338462657558694, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.07055074288480156, + "brightness_limit": [ + -0.19312125444412231, + -0.19312125444412231 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.6213765144348145, + 0.6213765144348145 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 235, + 235 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 8.184193940267112e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.166619453118309e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.390549163866953e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -99.24921417236328, + -99.24921417236328 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0739160389341804e-10, + "shift_limit_x": [ + -0.5108672380447388, + -0.5108672380447388 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4543119934815225e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.014696478843688965, + 0.014696478843688965 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.755869069858632e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.9874789714813232, + 3.9874789714813232 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0006857922174634615, + "max_holes": 16, + "max_height": 156, + "max_width": 156, + "min_holes": 16, + "min_height": 156, + "min_width": 156, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.25924887097338, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6575709874253092 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0069740362792783395, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1851137903915818e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 103, + 103 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.011278618950760044, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 45, + 45 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0009743338193999862, + "brightness_limit": [ + -0.14755529165267944, + -0.14755529165267944 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0007224774609937007, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2345157861709595, + 1.2345157861709595 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.000530090682133319, + "threshold": [ + 167, + 167 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.7290145655671977e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.562844721037264e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -62.645530700683594, + -62.645530700683594 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0620295246393821e-11, + "shift_limit_x": [ + -0.5757838487625122, + -0.5757838487625122 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.65178029121271e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 2.1871488094329834, + 2.1871488094329834 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.726268229839447e-06, + "max_holes": 16, + "max_height": 143, + "max_width": 143, + "min_holes": 16, + "min_height": 143, + "min_width": 143, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.2923793932868154e-08, + "max_holes": 7, + "max_height": 14, + "max_width": 14, + "min_holes": 7, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9795127594725265 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.856052345608412e-06, + "r_shift_limit": [ + 117, + 117 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.514189390927712e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 253, + 253 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.9453307849011485e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.115298813594872e-11, + "brightness_limit": [ + -0.3303220272064209, + -0.3303220272064209 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.2710216557896403e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.098122524690808e-09, + "threshold": [ + 67, + 67 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 7.740123267375241e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.4907581644927e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.399843261473234e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.007579283646167e-06, + "shift_limit_x": [ + 0.830859899520874, + 0.830859899520874 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.377091340943017e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0037125349044799805, + 0.0037125349044799805 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.2928375076057108, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9881334900856018, + 0.9881334900856018 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.493781888783112e-11, + "max_holes": 16, + "max_height": 140, + "max_width": 140, + "min_holes": 16, + "min_height": 140, + "min_width": 140, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.181288231313561e-11, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.707128475793773 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0046262738126452985, + "r_shift_limit": [ + 68, + 68 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0035411903477913648, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.691377267787247e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0037640913053322844, + "brightness_limit": [ + -0.1599644422531128, + -0.1599644422531128 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.807314384458087e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.4847731627949685e-10, + "threshold": [ + 159, + 159 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.309887686201972e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 109.74517822265625, + 109.74517822265625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0536305079122835e-06, + "shift_limit_x": [ + 0.9664607048034668, + 0.9664607048034668 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.248263727045324e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.4684147834777832, + -0.4684147834777832 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3705642518271307e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.792794227600098, + 4.792794227600098 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0001063969614316573, + "max_holes": 16, + "max_height": 173, + "max_width": 173, + "min_holes": 16, + "min_height": 173, + "min_width": 173, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.009871231225746069, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9780189545218819 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.062020863199221e-11, + "r_shift_limit": [ + -126, + -126 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.221663752761425e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -200, + -200 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.9743614971970986e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -255, + -255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2478900769002787e-09, + "brightness_limit": [ + -0.4478186368942261, + -0.4478186368942261 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.337944738656282e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.00534942649339e-09, + "threshold": [ + 153, + 153 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.063724073980505e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.16444728997345e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.280695437195079e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -171.48951721191406, + -171.48951721191406 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7076716891955574e-13, + "shift_limit_x": [ + -0.000751197338104248, + -0.000751197338104248 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.37362553528801357, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -1.0, + -1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.290127358490682e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.395214080810547, + 4.395214080810547 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.4535635705517666e-07, + "max_holes": 16, + "max_height": 77, + "max_width": 77, + "min_holes": 16, + "min_height": 77, + "min_width": 77, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.3548024460286906e-08, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6262709398911633 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0032458746946678607, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.01359463855624199, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -67, + -67 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0004338036107107285, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 60, + 60 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.002102461071129061, + "brightness_limit": [ + -0.29935377836227417, + -0.29935377836227417 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.4184685162906085e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 105, + 105 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.629440642030618e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.1069670993450246e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -150.23080444335938, + -150.23080444335938 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.93799733500504e-06, + "shift_limit_x": [ + 0.010417580604553223, + 0.010417580604553223 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.1852092283935204e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.002792954444885254, + 0.002792954444885254 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.00037954984239884845, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.1041475534439087, + 1.1041475534439087 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.435576608505723e-09, + "max_holes": 16, + "max_height": 108, + "max_width": 108, + "min_holes": 16, + "min_height": 108, + "min_width": 108, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.7646818340077302e-05, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9802114334349117 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.995332990202018e-06, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.6823226733542328e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 23, + 23 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.37959458330219e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -74, + -74 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.490374646951984e-10, + "brightness_limit": [ + -1.0, + -1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.234778856705137e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.44580381930013e-11, + "threshold": [ + 117, + 117 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.00555638606481e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.553029769740931 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.669303231462426e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -160.03990173339844, + -160.03990173339844 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2202547054585018e-07, + "shift_limit_x": [ + 0.6006333827972412, + 0.6006333827972412 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.025451192377328e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.3506736159324646, + -0.3506736159324646 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.7342207247492893e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.640933036804199, + 5.640933036804199 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.477442532816816e-09, + "max_holes": 16, + "max_height": 90, + "max_width": 90, + "min_holes": 16, + "min_height": 90, + "min_width": 90, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.5470732790015367e-06, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.44695726095471444 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0043110048159034076, + "r_shift_limit": [ + 50, + 50 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.002241177333406008, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 30, + 30 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.502987958203067e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 22, + 22 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.735221837785438e-10, + "brightness_limit": [ + -0.19688278436660767, + -0.19688278436660767 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00014997288644960464, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.6850416660308838, + 0.6850416660308838 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0006869093306475851, + "threshold": [ + 233, + 233 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.2603485477644985e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.677000360100968e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -137.04693603515625, + -137.04693603515625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.457377883391694e-13, + "shift_limit_x": [ + 0.002378702163696289, + 0.002378702163696289 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.5765025615692139, + -0.5765025615692139 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.812011977360988e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0082604885101318, + 1.0082604885101318 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.935676509187526e-05, + "max_holes": 16, + "max_height": 190, + "max_width": 190, + "min_holes": 16, + "min_height": 190, + "min_width": 190, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.002769816801041658, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9897752380896995 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.42524249621335386, + "r_shift_limit": [ + -5, + -5 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.16235850577191e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0005441512837829621, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -41, + -41 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.06426606542602897, + "brightness_limit": [ + 0.028052806854248047, + 0.028052806854248047 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.5987357230928328e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.867468357086182, + 6.867468357086182 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.073848773933517e-10, + "threshold": [ + 167, + 167 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.3588642261525097e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.4632567917306e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0981027565553255e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 47.604095458984375, + 47.604095458984375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.006497194708639e-08, + "shift_limit_x": [ + -0.7448338270187378, + -0.7448338270187378 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8144369125366211, + -0.8144369125366211 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.447948580362288e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.70706844329834, + 8.70706844329834 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.003951560924957187, + "max_holes": 16, + "max_height": 104, + "max_width": 104, + "min_holes": 16, + "min_height": 104, + "min_width": 104, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.456525573298961e-08, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5059947854274299 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.005567649061979013, + "r_shift_limit": [ + 34, + 34 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.7837139704272e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 117, + 117 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.237186464005728e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.726740705038537e-07, + "brightness_limit": [ + -0.22214633226394653, + -0.22214633226394653 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00024117259343917063, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.0100716352462769, + 1.0100716352462769 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.8643774441704465e-05, + "threshold": [ + 186, + 186 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 7.146993498979068e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.011319945872652e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2340977698908318e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 78.67636108398438, + 78.67636108398438 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.7694469690322876, + 0.7694469690322876 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.6950591849815553e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 10.0, + 10.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0720184937523289e-07, + "max_holes": 16, + "max_height": 219, + "max_width": 219, + "min_holes": 16, + "min_height": 219, + "min_width": 219, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.022809172035293868, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9713254197581687 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0576999909380977e-08, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5163711416240884e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 77, + 77 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.3109373664976706e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.39037656784057617, + 0.39037656784057617 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.9699278293771182e-11, + "threshold": [ + 171, + 171 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.092061366977254e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.607792278854401e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -168.34744262695312, + -168.34744262695312 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.9375964403152466, + 0.9375964403152466 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.1342694119518896e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.569176435470581, + -0.569176435470581 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.7456473589909875e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.49557113647461, + 9.49557113647461 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.8180575459003385e-07, + "max_holes": 16, + "max_height": 78, + "max_width": 78, + "min_holes": 16, + "min_height": 78, + "min_width": 78, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.9526498389016596e-11, + "max_holes": 13, + "max_height": 14, + "max_width": 14, + "min_holes": 13, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.999999416451575 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.952303980122021e-08, + "r_shift_limit": [ + -95, + -95 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.002291829325258732, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0015426039489140897, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -28, + -28 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.4394039690008723e-05, + "brightness_limit": [ + -0.2979734539985657, + -0.2979734539985657 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.940978942043881e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.38014947901463e-05, + "threshold": [ + 247, + 247 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.1850928996466303e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 8.55612843031176e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -109.61638641357422, + -109.61638641357422 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.573824563953012e-08, + "shift_limit_x": [ + 0.0010429620742797852, + 0.0010429620742797852 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.1514488421697417e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.7831265926361084, + 0.7831265926361084 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.221015904495469e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.051968097686768, + 7.051968097686768 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.869219693965777e-11, + "max_holes": 16, + "max_height": 198, + "max_width": 198, + "min_holes": 16, + "min_height": 198, + "min_width": 198, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0035575950382368826, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9925544186981766 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0011359383876637374, + "r_shift_limit": [ + 92, + 92 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0016869752167762708, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -65, + -65 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.618297649744407e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -41, + -41 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0015044221939910368, + "brightness_limit": [ + -0.21964317560195923, + -0.21964317560195923 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.5901670863465874e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.836751213241566e-12, + "threshold": [ + 115, + 115 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 8.69312777430323e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.984515495014769e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.014001071997879366, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.012237548828125, + -0.012237548828125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3103454949908028e-05, + "shift_limit_x": [ + -0.010226845741271973, + -0.010226845741271973 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.959382430792702e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.004587888717651367, + 0.004587888717651367 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.6534101550387104e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9991414546966553, + 0.9991414546966553 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.049848862730745e-10, + "max_holes": 16, + "max_height": 125, + "max_width": 125, + "min_holes": 16, + "min_height": 125, + "min_width": 125, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.639838506814471e-08, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9816460423472545 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.975842448556208e-06, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -3, + -3 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.223884731500168e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -123, + -123 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2840799278128657e-11, + "brightness_limit": [ + -0.7453576326370239, + -0.7453576326370239 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.06084730873461e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 5.146101951599121, + 5.146101951599121 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.6748730810919324e-08, + "threshold": [ + 171, + 171 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.8397619407072978e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 9.620151179127372e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.9999961853027344, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 3.93115234375, + 3.93115234375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.52996409988607e-11, + "shift_limit_x": [ + 0.5289818048477173, + 0.5289818048477173 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.7772113787016353e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8312612771987915, + -0.8312612771987915 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2931265354274295e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.8534717559814453, + 3.8534717559814453 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.0768657908117822e-13, + "max_holes": 16, + "max_height": 158, + "max_width": 158, + "min_holes": 16, + "min_height": 158, + "min_width": 158, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.993039885676419e-09, + "max_holes": 13, + "max_height": 14, + "max_width": 14, + "min_holes": 13, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 9.680846562165613e-07 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.303104226777157e-12, + "r_shift_limit": [ + -99, + -99 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5214961289167769e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -73, + -73 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.7758902141768178e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 59, + 59 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.450646509230214e-12, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.408544238134507e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 8.03568172454834, + 8.03568172454834 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.4314210683147007e-05, + "threshold": [ + 189, + 189 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 8.032534052169867e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9184556820952644e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.4095458984375, + 0.4095458984375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.37263455365075515, + "shift_limit_x": [ + 0.13315892219543457, + 0.13315892219543457 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.3452183055284844e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8640317916870117, + -0.8640317916870117 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.9564847946167, + 8.9564847946167 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.980760801234828e-07, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.689037864970293e-09, + "max_holes": 7, + "max_height": 14, + "max_width": 14, + "min_holes": 7, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6273500064804662 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.163123423007663e-08, + "r_shift_limit": [ + 120, + 120 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.000145779873563949, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 164, + 164 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.6217470009886843e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -69, + -69 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.785877380835203e-11, + "brightness_limit": [ + -0.33552461862564087, + -0.33552461862564087 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.270653293732222e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.9249308109283447, + 1.9249308109283447 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.753635933252377e-09, + "threshold": [ + 129, + 129 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.0222346624947173e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.759493883488251e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.5037841796875, + -0.5037841796875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.281783556489384e-10, + "shift_limit_x": [ + 0.00018334388732910156, + 0.00018334388732910156 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.8476788068721532, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.018045663833618164, + 0.018045663833618164 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.652792981291366e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.988791286945343, + 0.988791286945343 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.475025854082508e-06, + "max_holes": 16, + "max_height": 138, + "max_width": 138, + "min_holes": 16, + "min_height": 138, + "min_width": 138, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.665644158310776e-06, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.15216562532914524 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0002838141172109374, + "r_shift_limit": [ + 36, + 36 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.331782191495751e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 0, + 0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.778967970038843e-06, + "brightness_limit": [ + -0.38033145666122437, + -0.38033145666122437 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00014681237639847713, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1958823204040527, + 1.1958823204040527 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.001027237254633273, + "threshold": [ + 245, + 245 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 9.49651984462577e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.8026743547547297e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0665851316195328e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 2.6986083984375, + 2.6986083984375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.8320166287531238e-12, + "shift_limit_x": [ + -0.7012209892272949, + -0.7012209892272949 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.5296311378479, + 7.5296311378479 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.1394173275119282e-07, + "max_holes": 16, + "max_height": 136, + "max_width": 136, + "min_holes": 16, + "min_height": 136, + "min_width": 136, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.7646255776344183e-05, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9985147835231605 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.5409550735948265, + "r_shift_limit": [ + -9, + -9 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.04856807268639862, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -109, + -109 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.011685283379258338, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -65, + -65 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.000564041081815958, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.63773287557738e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.96541827917099, + 0.96541827917099 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.5440966356289634e-09, + "threshold": [ + 130, + 130 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.657069134960767e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.645077677222359e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0227103921401712e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 110.16162109375, + 110.16162109375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.565089861860006e-08, + "shift_limit_x": [ + -0.4468369483947754, + -0.4468369483947754 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5119416850274746e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.631951093673706, + -0.631951093673706 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4572137592785712e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.846192359924316, + 8.846192359924316 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.396728512999639e-06, + "max_holes": 16, + "max_height": 81, + "max_width": 81, + "min_holes": 16, + "min_height": 81, + "min_width": 81, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0326692979902532, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.3654477880125331 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.6109260609338597e-06, + "r_shift_limit": [ + -98, + -98 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4536279957511056e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 73, + 73 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0002768577252679205, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 72, + 72 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.8231272219064892e-08, + "brightness_limit": [ + 0.3476743698120117, + 0.3476743698120117 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.217742953946952e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 25, + 25 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.4076282760166533e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.972983831878367e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -101.92623138427734, + -101.92623138427734 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9858790569815937e-12, + "shift_limit_x": [ + -0.5983944535255432, + -0.5983944535255432 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.4394872694498897, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.017333030700683594, + -0.017333030700683594 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.842792292632052e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9977966547012329, + 0.9977966547012329 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0007318302233121077, + "max_holes": 16, + "max_height": 104, + "max_width": 104, + "min_holes": 16, + "min_height": 104, + "min_width": 104, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.668673364649378e-05, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.559463497282819 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0006129440735094249, + "r_shift_limit": [ + -68, + -68 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.7984923025236533e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -53, + -53 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.313180416008557e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -25, + -25 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.775758059465032e-08, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.5420981889149573e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.393099308013916, + 1.393099308013916 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.237607423668288e-10, + "threshold": [ + 219, + 219 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.007961302071272e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -2.202911376953125, + -2.202911376953125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.7058719939578895e-11, + "shift_limit_x": [ + 0.5413061380386353, + 0.5413061380386353 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.059692273863336e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.7305346727371216, + -0.7305346727371216 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.743291114081406e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.681495666503906, + 9.681495666503906 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.492804975542202e-07, + "max_holes": 16, + "max_height": 183, + "max_width": 183, + "min_holes": 16, + "min_height": 183, + "min_width": 183, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.2095993501046589, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7897759549215977 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -200, + -200 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.60447014085469e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 107, + 107 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 10, + 10 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.841934590347365e-09, + "brightness_limit": [ + -0.4115169644355774, + -0.4115169644355774 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.691037658026594e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 60, + 60 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.1513798109840592e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.660449745721093e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.9999984502792358, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.4990997314453125, + -0.4990997314453125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.103016887189948e-08, + "shift_limit_x": [ + 0.012333273887634277, + 0.012333273887634277 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3370063016535417e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.902468154261582e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9876134395599365, + 0.9876134395599365 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.69391668431485e-12, + "max_holes": 16, + "max_height": 124, + "max_width": 124, + "min_holes": 16, + "min_height": 124, + "min_width": 124, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.686044868800675e-07, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 7.435952797951728e-07 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.315574549486809e-10, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.16641640757532272, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 0, + 0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.8233856865680796e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -55, + -55 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.9479843995077475e-05, + "brightness_limit": [ + 0.1496570110321045, + 0.1496570110321045 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.1673296730502886e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.001932281581117537, + "threshold": [ + 216, + 216 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.1067829674316764e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.644934171104314e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 38.88447570800781, + 38.88447570800781 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4164460134476631e-05, + "shift_limit_x": [ + 0.004245162010192871, + 0.004245162010192871 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.860680920109773e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.9735277891159058, + 0.9735277891159058 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.056587417345707e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.56558895111084, + 5.56558895111084 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.809857617657447e-05, + "max_holes": 16, + "max_height": 135, + "max_width": 135, + "min_holes": 16, + "min_height": 135, + "min_width": 135, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.005033882999785744, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.826517339439946 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1387959517481709e-07, + "r_shift_limit": [ + 107, + 107 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.14215957863129e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.967387860574604e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 74, + 74 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.605669010426011e-08, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0006160979974083602, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.4463545083999634, + 0.4463545083999634 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.692739038415772e-07, + "threshold": [ + 89, + 89 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.5696072801794533e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.0856614445029035e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9038924176911624e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.1758880615234375, + 0.1758880615234375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.962309626728933e-06, + "shift_limit_x": [ + 0.0013744831085205078, + 0.0013744831085205078 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.14848900890672212, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0672987699508667, + 0.0672987699508667 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.100720833024839e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.717555046081543, + 8.717555046081543 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.4123330276560595e-10, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00018493980955616718, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8506588418664004 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.4468890790442117, + "r_shift_limit": [ + 9, + 9 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0016261860033845443, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -35, + -35 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.0740825306619847e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 55, + 55 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.008389989065193615, + "brightness_limit": [ + -0.11852377653121948, + -0.11852377653121948 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.443753493647715e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 7.385619163513184, + 7.385619163513184 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.900875929237076e-12, + "threshold": [ + 20, + 20 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.209047750294679e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.4919555272691525e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.374404992395716e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -130.19338989257812, + -130.19338989257812 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.6095708566307015e-06, + "shift_limit_x": [ + 0.9534622430801392, + 0.9534622430801392 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.9799158573150635, + -0.9799158573150635 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2866675423901478e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0138075351715088, + 1.0138075351715088 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.228101628421821e-08, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.028579777106642723, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5144423302746877 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.8577042337810783e-07, + "r_shift_limit": [ + -96, + -96 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.9801953831841956e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 57, + 57 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4105184307744564e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 133, + 133 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.9116876484592815e-11, + "brightness_limit": [ + 0.046587467193603516, + 0.046587467193603516 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.092634205724567e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 4.42413854598999, + 4.42413854598999 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.4568012136852273e-10, + "threshold": [ + 149, + 149 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 9.256892258172825e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.4285449688010175e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.9315597025242694e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.041656494140625, + 0.041656494140625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.6513676132444494e-11, + "shift_limit_x": [ + -0.5274703502655029, + -0.5274703502655029 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.6991368424604758, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.2043684720993042, + -0.2043684720993042 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.1232548694939516e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 2.734781503677368, + 2.734781503677368 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.6803766049520217e-13, + "max_holes": 16, + "max_height": 199, + "max_width": 199, + "min_holes": 16, + "min_height": 199, + "min_width": 199, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.23174844033951e-13, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.30084756103248433 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.033174591472242554, + "r_shift_limit": [ + 79, + 79 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.025976601083176565, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 23, + 23 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.072690869146755e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 51, + 51 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00027999162744299366, + "brightness_limit": [ + -0.08276349306106567, + -0.08276349306106567 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.6871902346611023, + 0.6871902346611023 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.148583872260926e-09, + "threshold": [ + 89, + 89 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.645181347712306e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.8831379845853688e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.7379682815706634e-09, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2079833952150774e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -1.0, + -1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.246760627919929e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.1424055099487305, + 6.1424055099487305 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.476011472964616e-07, + "max_holes": 16, + "max_height": 187, + "max_width": 187, + "min_holes": 16, + "min_height": 187, + "min_width": 187, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.04207607408719305, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8984691709429555 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.685773481265642e-05, + "r_shift_limit": [ + 95, + 95 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.515051811180155e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 81, + 81 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.005407389714152666, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -19, + -19 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.20268911980779958, + "brightness_limit": [ + 0.11611485481262207, + 0.11611485481262207 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.422292586310473e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.4637352228164673, + 1.4637352228164673 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 40, + 40 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.0744939690824303e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2445779681065328e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.7430572509765625, + 0.7430572509765625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.481112676926782e-08, + "shift_limit_x": [ + -0.04436618089675903, + -0.04436618089675903 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.02037334442138672, + 0.02037334442138672 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.059917003481852e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.834701538085938, + 8.834701538085938 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.002059595779768303, + "max_holes": 16, + "max_height": 142, + "max_width": 142, + "min_holes": 16, + "min_height": 142, + "min_width": 142, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00416950688789508, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7856081125865508 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.0320686193108404e-08, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.240395258784526e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -47, + -47 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.835001345839703e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 105, + 105 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0.47670233249664307, + 0.47670233249664307 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.63233937438035e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 5.129998207092285, + 5.129998207092285 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 9.02345839125328e-13, + "threshold": [ + 165, + 165 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.78473351819578e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.316867223138503e-15, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 107.41012573242188, + 107.41012573242188 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.012643218040466309, + -0.012643218040466309 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.376345591067317e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8702159523963928, + -0.8702159523963928 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4171228281679147e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0228809118270874, + 1.0228809118270874 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.214996136355301e-07, + "max_holes": 16, + "max_height": 184, + "max_width": 184, + "min_holes": 16, + "min_height": 184, + "min_width": 184, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.185310469880416e-05, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9999776937708471 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.94249045955113e-08, + "r_shift_limit": [ + -42, + -42 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.560282708627444e-14, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.803404069060217e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.468185120680044e-06, + "brightness_limit": [ + -0.5450156927108765, + -0.5450156927108765 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.2415680758872836e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 8.24526596069336, + 8.24526596069336 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.5744616576469884e-06, + "threshold": [ + 163, + 163 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.9291241099200107 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.396547697023786e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.4881688087091496e-15, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -49.71278381347656, + -49.71278381347656 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0831646690689922e-08, + "shift_limit_x": [ + 0.038068175315856934, + 0.038068175315856934 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7165694177191284e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.9602394104003906, + -0.9602394104003906 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1904046134362937e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.7978675365448, + 3.7978675365448 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.0767479327332694e-06, + "max_holes": 16, + "max_height": 107, + "max_width": 107, + "min_holes": 16, + "min_height": 107, + "min_width": 107, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.3935335010247586e-10, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.07086365885362822 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.04407128797070703, + "r_shift_limit": [ + 44, + 44 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.013642437221197845, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 79, + 79 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.006590541381991721, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -36, + -36 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.002475943427238947, + "brightness_limit": [ + 0.2888904809951782, + 0.2888904809951782 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.679334366669778e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 9.014942169189453, + 9.014942169189453 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.002838393614549614, + "threshold": [ + 157, + 157 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.1751136743071242e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.8790827281378724e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0271506457889606e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -1.072967529296875, + -1.072967529296875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0207647071517684e-06, + "shift_limit_x": [ + 0.6464214324951172, + 0.6464214324951172 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.914637162826548e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.65147465467453, + -0.65147465467453 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3325824907354524e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.28635835647583, + 7.28635835647583 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.051855725608719e-05, + "max_holes": 16, + "max_height": 198, + "max_width": 198, + "min_holes": 16, + "min_height": 198, + "min_width": 198, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 15, + "max_height": 14, + "max_width": 14, + "min_holes": 15, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9303466400840186 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.004433281657775234, + "r_shift_limit": [ + -63, + -63 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0007519870603987372, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 89, + 89 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.01381940424138417, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 72, + 72 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0039906265612899006, + "brightness_limit": [ + -0.12119954824447632, + -0.12119954824447632 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.898958952370989e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.007128628290916e-06, + "threshold": [ + 146, + 146 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.521235794238215e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -4.125946044921875, + -4.125946044921875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.5530359299830866e-11, + "shift_limit_x": [ + 0.0010265111923217773, + 0.0010265111923217773 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.194375097689237e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0036628246307373047, + -0.0036628246307373047 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.23667996349803e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.004469871520996, + 8.004469871520996 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.3851784785753876e-05, + "max_holes": 16, + "max_height": 98, + "max_width": 98, + "min_holes": 16, + "min_height": 98, + "min_width": 98, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.78664584725759e-09, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.976946139136505 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.581025289050343e-11, + "r_shift_limit": [ + 67, + 67 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.1537576701622978e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -193, + -193 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.4236235824149554e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -227, + -227 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.3308658724633517e-09, + "brightness_limit": [ + -0.5685690641403198, + -0.5685690641403198 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.079705452345196e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 3.481144428253174, + 3.481144428253174 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.549183655043541e-08, + "threshold": [ + 116, + 116 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.9999992847442627 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.1203994757992768e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0727465774376506e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 58.69270324707031, + 58.69270324707031 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.990720180297348e-13, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.126726978330089e-15, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.31541013717651367, + 0.31541013717651367 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.8615522542100556e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.2193217277526855, + 7.2193217277526855 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.46695104750916e-13, + "max_holes": 16, + "max_height": 39, + "max_width": 39, + "min_holes": 16, + "min_height": 39, + "min_width": 39, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.063437138807068e-09, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 6.432739120265651e-07 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.05400072405541345, + "r_shift_limit": [ + -16, + -16 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00020488610767771184, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -62, + -62 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.663475264239135e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -67, + -67 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.000867610870813218, + "brightness_limit": [ + 0.1484001874923706, + 0.1484001874923706 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.014604819120160872, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.9854591488838196, + 0.9854591488838196 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 29, + 29 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.3839659569017906e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.3142940663429095e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.2666473388671875, + 0.2666473388671875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1814452450983053e-08, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6001195907592773, + -0.6001195907592773 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7670180494883754e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.321659564971924, + 5.321659564971924 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.466622040892124e-08, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.930283813662188 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.702443127755032e-08, + "r_shift_limit": [ + 66, + 66 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00020506957122632015, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 82, + 82 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.004336759180778721, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.3155752788957044e-07, + "brightness_limit": [ + 0.2849562168121338, + 0.2849562168121338 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0003777686098561314, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.0425441265106201, + 1.0425441265106201 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.896429611233954e-05, + "threshold": [ + 83, + 83 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.1307376219348838e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -56.092681884765625, + -56.092681884765625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.894080835117048e-07, + "shift_limit_x": [ + 0.9287163019180298, + 0.9287163019180298 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.305749554733767e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.4787871837615967, + 0.4787871837615967 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4538308105174149e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.280232429504395, + 8.280232429504395 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.6685083735999695e-06, + "max_holes": 16, + "max_height": 101, + "max_width": 101, + "min_holes": 16, + "min_height": 101, + "min_width": 101, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.005580121016945133, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.98946760472016 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.5370650881948552e-09, + "r_shift_limit": [ + 51, + 51 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.005518212777546827, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 35, + 35 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.013842982628990197, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 43, + 43 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.0952309999549962e-07, + "brightness_limit": [ + -0.294680118560791, + -0.294680118560791 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.6246784126733114e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 8.634607315063477, + 8.634607315063477 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.85963398295202e-08, + "threshold": [ + 232, + 232 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.1630042000874338e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.058838805977595e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -80.94689178466797, + -80.94689178466797 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.176052924751787e-09, + "shift_limit_x": [ + -0.03541886806488037, + -0.03541886806488037 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9073804491983635e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8580971360206604, + -0.8580971360206604 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.246455669403076, + 5.246455669403076 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00020751278008665237, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0003878501041940513, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9800168407659484 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00018427021668679204, + "r_shift_limit": [ + -53, + -53 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.521581519821265e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 39, + 39 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 39, + 39 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.006100108996678205, + "brightness_limit": [ + -0.14098775386810303, + -0.14098775386810303 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.160140037359899e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.5168845653533936, + 1.5168845653533936 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 9.926845722739705e-14, + "threshold": [ + 148, + 148 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.798740058827947e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 89.50704956054688, + 89.50704956054688 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.130338581350835e-10, + "shift_limit_x": [ + 0.8882700204849243, + 0.8882700204849243 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.122788140502346e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8891685605049133, + -0.8891685605049133 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.99999993922529e-09, + 9.99999993922529e-09 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1170402176422129e-08, + "max_holes": 16, + "max_height": 50, + "max_width": 50, + "min_holes": 16, + "min_height": 50, + "min_width": 50, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.544576369094812e-09, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.993644002646347 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1264155266886364e-09, + "r_shift_limit": [ + 78, + 78 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.123219807096814e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -28, + -28 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.3473391092776936e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 56, + 56 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.8639318776084044e-11, + "brightness_limit": [ + 0.2962977886199951, + 0.2962977886199951 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.4468372235257359e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.55133056640625, + 1.55133056640625 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.115254752585644e-14, + "threshold": [ + 63, + 63 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.094247572694692e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 39.40992736816406, + 39.40992736816406 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.2123831594481514e-07, + "shift_limit_x": [ + -0.9676019549369812, + -0.9676019549369812 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.900695667108492e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.048189640045166016, + 0.048189640045166016 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.012222499747044e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 10.0, + 10.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.9091921545595284e-07, + "max_holes": 16, + "max_height": 81, + "max_width": 81, + "min_holes": 16, + "min_height": 81, + "min_width": 81, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.9812303307998163e-10, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9999034329599787 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0012273159979774295, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00034867387061632803, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -36, + -36 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.569196781729882e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 61, + 61 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0001525331541430662, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.3733632702627727e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.1366307698440416e-06, + "threshold": [ + 99, + 99 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -87.33753204345703, + -87.33753204345703 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.509031471941121e-07, + "shift_limit_x": [ + -0.9615246057510376, + -0.9615246057510376 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.866104490437191e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.4448190927505493, + -0.4448190927505493 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.1299961423606407e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.8444113731384277, + 0.8444113731384277 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.63971932547851e-11, + "max_holes": 16, + "max_height": 189, + "max_width": 189, + "min_holes": 16, + "min_height": 189, + "min_width": 189, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.002075217098892218, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9961948634174832 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.014472908645837945, + "r_shift_limit": [ + -31, + -31 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.001880630247442061, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -27, + -27 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00018092393366491225, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.336710659327226e-05, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.10226549659895134, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.3584635257720947, + 1.3584635257720947 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.008434393674116247, + "threshold": [ + 222, + 222 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.6451436266010704e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.6151843977645336e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 180.0, + 180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0004933193439502805, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.04895591735839844, + 0.04895591735839844 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 2.40798282623291, + 2.40798282623291 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.1632310605593966e-09, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0911183342345332, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7811205875840915 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0006965723967321952, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.241452799809745e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 68, + 68 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1544920715269471e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 70, + 70 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.07369369942450277, + "brightness_limit": [ + -0.16859537363052368, + -0.16859537363052368 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0001520210740649751, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.306509017944336, + 1.306509017944336 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.8965096574616642e-12, + "threshold": [ + 13, + 13 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.1859883224051604e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.250701994986273e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.236610437813713e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.3920745849609375, + 0.3920745849609375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.823725020838422e-11, + "shift_limit_x": [ + -0.004442572593688965, + -0.004442572593688965 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.506615400314331, + 0.506615400314331 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.4401810966544557e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.409881591796875, + 5.409881591796875 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.420720383136763e-06, + "max_holes": 16, + "max_height": 198, + "max_width": 198, + "min_holes": 16, + "min_height": 198, + "min_width": 198, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.5745457218516282e-06, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.925451835141412 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.823331940701384e-05, + "r_shift_limit": [ + 59, + 59 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.03484966235571241, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -4, + -4 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0009276689197094956, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 104, + 104 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.032637111842632294, + "brightness_limit": [ + -0.13365119695663452, + -0.13365119695663452 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00012090090655249991, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2977089881896973, + 1.2977089881896973 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.4509681505296972e-06, + "threshold": [ + 194, + 194 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.609315582721086e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.115735153640673e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 171.35162353515625, + 171.35162353515625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.992568431264955e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.875957727432251, + -0.875957727432251 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.828301359525303e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.019051551818848, + 5.019051551818848 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.200875510917347e-08, + "max_holes": 16, + "max_height": 139, + "max_width": 139, + "min_holes": 16, + "min_height": 139, + "min_width": 139, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.06949500072291137, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8619098019120621 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.024009700292946135, + "r_shift_limit": [ + 56, + 56 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0005900768653201507, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 90, + 90 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0576703763084927, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 3, + 3 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.060854359539116665, + "brightness_limit": [ + 0.10459744930267334, + 0.10459744930267334 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.812598113209822e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.3754873275756836, + 1.3754873275756836 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.9295710522838645e-12, + "threshold": [ + 41, + 41 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.537430145616364e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.203616847071345e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.2921105186720707e-11, + "shift_limit_x": [ + -0.009588003158569336, + -0.009588003158569336 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.725634414591181e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0031699538230895996, + -0.0031699538230895996 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.747262439313592e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.800654411315918, + 4.800654411315918 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.006319162682722146, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.121829733506595e-08, + "max_holes": 15, + "max_height": 14, + "max_width": 14, + "min_holes": 15, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8505521353673218 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.710384329214988e-10, + "r_shift_limit": [ + -64, + -64 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00031553869013090097, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 99, + 99 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.2600423815456452e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -35, + -35 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.3774044893883824e-07, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0005154216090565572, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.8479320779842857e-05, + "threshold": [ + 128, + 128 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.2277864986738845e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.7294066416631546e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.04300221622202671, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 180.0, + 180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.763549456780641e-13, + "shift_limit_x": [ + 0.38754069805145264, + 0.38754069805145264 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.1922435760498047, + -0.1922435760498047 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.1920740526057446e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.047825813293457, + 3.047825813293457 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0006086019236045959, + "max_holes": 16, + "max_height": 103, + "max_width": 103, + "min_holes": 16, + "min_height": 103, + "min_width": 103, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.878638341113343e-09, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9555382123102045 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0001445515036404936, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.968744729759138e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -41, + -41 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.000916658329397399, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 46, + 46 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.5935418949493412e-08, + "brightness_limit": [ + 0.3518686294555664, + 0.3518686294555664 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2905345697708188e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 7.045400142669678, + 7.045400142669678 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.423180964715883e-08, + "threshold": [ + 111, + 111 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.3416105195131753e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.231488833973405e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -112.19564056396484, + -112.19564056396484 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.637039807820848e-12, + "shift_limit_x": [ + -0.007590353488922119, + -0.007590353488922119 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.088226426607508e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.5341955423355103, + 0.5341955423355103 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.2032633506406243e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.734774589538574, + 6.734774589538574 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0001719972597461622, + "max_holes": 16, + "max_height": 123, + "max_width": 123, + "min_holes": 16, + "min_height": 123, + "min_width": 123, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.988265455771753, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.010461230994119997 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.095281596495026e-09, + "r_shift_limit": [ + -35, + -35 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.672043508128248e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -49, + -49 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.848300228463406e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -30, + -30 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.02735182947770043, + "brightness_limit": [ + -0.1510930061340332, + -0.1510930061340332 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 5.202260494232178, + 5.202260494232178 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 8.050642446419684e-09, + "threshold": [ + 24, + 24 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 8.648657207860844e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.687065693851972e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.040252685546875, + 0.040252685546875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.848960378772418e-12, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.8106606006622314, + 0.8106606006622314 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 2.7996373176574707, + 2.7996373176574707 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.5197659751255486e-10, + "max_holes": 16, + "max_height": 147, + "max_width": 147, + "min_holes": 16, + "min_height": 147, + "min_width": 147, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9725990411403928 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.7416010323972915e-10, + "r_shift_limit": [ + -48, + -48 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0005362037938395348, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 66, + 66 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.0089488675290518e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.323940399648563e-07, + "brightness_limit": [ + -0.15855717658996582, + -0.15855717658996582 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.7000610828399658, + 0.7000610828399658 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.7335531484008705e-09, + "threshold": [ + 31, + 31 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.2685176513195995e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 104.57162475585938, + 104.57162475585938 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.942336071392464e-13, + "shift_limit_x": [ + 0.8363974094390869, + 0.8363974094390869 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.531963778300345e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.004269719123840332, + -0.004269719123840332 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.23259918111766e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0075889825820923, + 1.0075889825820923 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 71, + "max_width": 71, + "min_holes": 16, + "min_height": 71, + "min_width": 71, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.000726143217056538, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9986417498367103 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.010121954501903e-09, + "r_shift_limit": [ + -67, + -67 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0014030854950822236, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 10, + 10 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.1784792087267757, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 6, + 6 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.015518232374761798, + "brightness_limit": [ + 0.09741771221160889, + 0.09741771221160889 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.183404321620507e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.0522202752882679e-09, + "threshold": [ + 139, + 139 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 173.93222045898438, + 173.93222045898438 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.019662439823150635, + -0.019662439823150635 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.5835321545600891, + -0.5835321545600891 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.393180411851472e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.069845676422119, + 7.069845676422119 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 129, + "max_width": 129, + "min_holes": 16, + "min_height": 129, + "min_width": 129, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8045992671889537 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.09379703527548244, + "r_shift_limit": [ + -44, + -44 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.001156268098710729, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -61, + -61 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.767978088171635e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 116, + 116 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.3183808633572356e-08, + "brightness_limit": [ + 0.3611578941345215, + 0.3611578941345215 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.513098838360415e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.6280649900436401, + 1.6280649900436401 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0002387817978384693, + "threshold": [ + 156, + 156 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.2011002316797508e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.512595210969539e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 165.0135498046875, + 165.0135498046875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.293544215164921e-13, + "shift_limit_x": [ + 0.0029807090759277344, + 0.0029807090759277344 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8186834454536438, + -0.8186834454536438 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.00017609409635604978, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0054771900177002, + 1.0054771900177002 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00020656378183048218, + "max_holes": 16, + "max_height": 78, + "max_width": 78, + "min_holes": 16, + "min_height": 78, + "min_width": 78, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.5446778862520496, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.3596866162498987 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.2161269588863425e-08, + "r_shift_limit": [ + 15, + 15 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.781458944905304e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.546546200180588e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -123, + -123 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0007702269715093232, + "brightness_limit": [ + -1.0, + -1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.409942934927473e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 5.9375691413879395, + 5.9375691413879395 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.3192322003240325e-10, + "threshold": [ + 89, + 89 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.4519236495029375 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.8159476190087515e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 63.63377380371094, + 63.63377380371094 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.3148594947911866e-11, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4856974243886713e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.9863909482955933, + 0.9863909482955933 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.3753215576158555e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.161473274230957, + 8.161473274230957 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.386681428429885e-12, + "max_holes": 16, + "max_height": 144, + "max_width": 144, + "min_holes": 16, + "min_height": 144, + "min_width": 144, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.125264837217068e-07, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5473041993351884 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.3730132985347536e-11, + "r_shift_limit": [ + -45, + -45 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.599111945906493e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 152, + 152 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0004141652125430606, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 27, + 27 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.002991937179114265, + "brightness_limit": [ + 0.2714262008666992, + 0.2714262008666992 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.889908910523659e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.269797682762146, + 1.269797682762146 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0009012550195469649, + "threshold": [ + 111, + 111 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.221867534825553e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 46.74761962890625, + 46.74761962890625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.5872868299484253, + 0.5872868299484253 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.16561375877992113, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.04629659652709961, + -0.04629659652709961 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.633096045154359e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.477261066436768, + 5.477261066436768 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.430119032298408e-11, + "max_holes": 16, + "max_height": 97, + "max_width": 97, + "min_holes": 16, + "min_height": 97, + "min_width": 97, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.1251088459948583e-07, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8299794083746952 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.122854497520049e-12, + "r_shift_limit": [ + -61, + -61 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.7377863790131594e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -71, + -71 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5163654441229388e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -255, + -255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.3593410205992405e-09, + "brightness_limit": [ + -0.9712724089622498, + -0.9712724089622498 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.155711694985287e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.6978508234024048, + 0.6978508234024048 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 9.56511778389905e-13, + "threshold": [ + 250, + 250 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.404308356865491e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.188088979842828e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9508476594137097e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 1.2721405029296875, + 1.2721405029296875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.551115992981402e-09, + "shift_limit_x": [ + -0.01459205150604248, + -0.01459205150604248 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.1816937069887672, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -1.0, + -1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.455576971066791e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.507124900817871, + 9.507124900817871 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.034635825204063e-10, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.400771160647355e-07, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8183055850942875 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.268607785216385e-05, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.431459621658858e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 37, + 37 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4211074332529691e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 81, + 81 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.187473435559569e-05, + "brightness_limit": [ + -0.386476993560791, + -0.386476993560791 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.828908856121776e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.4495660618792094e-05, + "threshold": [ + 196, + 196 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.006657395348145e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.965149289679523e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.9997771382331848, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 9.06573486328125, + 9.06573486328125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.4577706886671923e-07, + "shift_limit_x": [ + -0.0026907920837402344, + -0.0026907920837402344 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.5180712938308716, + 0.5180712938308716 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.256782102164225e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.218353748321533, + 4.218353748321533 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.299160147994583e-06, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.359642465543955e-08, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.00012280268010378403 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.1964397300169537e-06, + "r_shift_limit": [ + -123, + -123 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0008978685549927423, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 51, + 51 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00013031865160786915, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -32, + -32 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0001483534142607823, + "brightness_limit": [ + 0.2961416244506836, + 0.2961416244506836 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.845306237292207e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.624815940856934, + 6.624815940856934 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.00014553319391282654, + "threshold": [ + 153, + 153 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.119860564982619e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2296572675198812e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.838226318359375, + 0.838226318359375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5806983044113206e-08, + "shift_limit_x": [ + -0.9871377944946289, + -0.9871377944946289 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4097624959177209e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -1.0, + -1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.410622330256717e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.5271034240722656, + 3.5271034240722656 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 143, + "max_width": 143, + "min_holes": 16, + "min_height": 143, + "min_width": 143, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.998672120485511 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.002175323805271079, + "r_shift_limit": [ + 104, + 104 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0016759345088878524, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.92881105482804e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 38, + 38 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + -0.6022398471832275, + -0.6022398471832275 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.058283864225743e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0005612609991270806, + "threshold": [ + 227, + 227 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.7252872694350966e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.6042374837363688e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.208648681640625, + -0.208648681640625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3233093709396336e-06, + "shift_limit_x": [ + -0.977367639541626, + -0.977367639541626 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.608745794030567e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8589932918548584, + -0.8589932918548584 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.6853998190685304e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0003734827041626, + 1.0003734827041626 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.045400848525288e-06, + "max_holes": 16, + "max_height": 168, + "max_width": 168, + "min_holes": 16, + "min_height": 168, + "min_width": 168, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.3775440281734134e-06, + "max_holes": 15, + "max_height": 14, + "max_width": 14, + "min_holes": 15, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9955771823000389 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.005077131412672298, + "r_shift_limit": [ + 112, + 112 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 35, + 35 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.004051514077403839, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.173160783672741e-07, + "brightness_limit": [ + -0.29526352882385254, + -0.29526352882385254 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.1499802554765137e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.1569457687118612e-08, + "threshold": [ + 18, + 18 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 9.078491934143144e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.0628289665585726e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 156.39840698242188, + 156.39840698242188 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.9886506976540357e-06, + "shift_limit_x": [ + 0.03472757339477539, + 0.03472757339477539 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.713392725212356e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0055114030838012695, + 0.0055114030838012695 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.4927790452745026e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.289056777954102, + 8.289056777954102 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 94, + "max_width": 94, + "min_holes": 16, + "min_height": 94, + "min_width": 94, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0006428190340832668, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9902234182235249 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1108943104824351e-11, + "r_shift_limit": [ + -9, + -9 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.839071075328698e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 51, + 51 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0008872177205234422, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00019727057305836057, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.933461864126427e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.8908558487892151, + "threshold": [ + 27, + 27 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.319367854685995e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.857222151800756e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.07730648283706998, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.74972562162074e-08, + "shift_limit_x": [ + 0.33685314655303955, + 0.33685314655303955 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.190263469428364e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.618374228477478, + 0.618374228477478 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.8978038696553112e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.162137031555176, + 9.162137031555176 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.005922512045207218, + "max_holes": 16, + "max_height": 33, + "max_width": 33, + "min_holes": 16, + "min_height": 33, + "min_width": 33, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.667143845150012e-06, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.02475325218557567 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4364801866190825e-06, + "r_shift_limit": [ + -129, + -129 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0017926368046594643, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.952569846253027e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0009325032295541824, + "brightness_limit": [ + -0.9634945392608643, + -0.9634945392608643 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.041945763441288086, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.243931283852957e-07, + "threshold": [ + 53, + 53 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.216210907692677e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.00029053383516587476 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9806284758125825e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 74.23355102539062, + 74.23355102539062 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.659252197509241e-05, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.11980659340553768, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.5946624279022217, + -0.5946624279022217 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.003585716833940711, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 10.0, + 10.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.26208270928908917, + "max_holes": 16, + "max_height": 69, + "max_width": 69, + "min_holes": 16, + "min_height": 69, + "min_width": 69, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.04780834248633781, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5216644523491187 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.12583570182323456, + "r_shift_limit": [ + -135, + -135 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0006610492390465433, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.140789655412687e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -41, + -41 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.004011422369656875, + "brightness_limit": [ + 0.16341280937194824, + 0.16341280937194824 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.3316496457771681e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 4.58292293548584, + 4.58292293548584 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.2009501915599685e-05, + "threshold": [ + 130, + 130 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.64836737695117e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.5693623347970457e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0011521829316950075, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 63.27845764160156, + 63.27845764160156 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.9760811924934387, + -0.9760811924934387 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.06667287887431073, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6368659734725952, + -0.6368659734725952 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.2210173089752383e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.2917163372039795, + 3.2917163372039795 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 116, + "max_width": 116, + "min_holes": 16, + "min_height": 116, + "min_width": 116, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.15599748194950536, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6455622674739019 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.1049013669083353e-11, + "r_shift_limit": [ + -171, + -171 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.729726763394146e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -219, + -219 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.9729764145451525e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.07746392700337879, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.001011002918067723, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 7.243293762207031, + 7.243293762207031 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.9113135146566975, + "threshold": [ + 81, + 81 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.1935067030529022e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.044572199001813e-05 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2795731779687426e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -116.55543518066406, + -116.55543518066406 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4128655221472613e-13, + "shift_limit_x": [ + -0.30645304918289185, + -0.30645304918289185 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0228325885699338e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.05155622959136963, + 0.05155622959136963 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.316171886110964e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.32851505279541, + 7.32851505279541 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.135630738048967e-10, + "max_holes": 16, + "max_height": 211, + "max_width": 211, + "min_holes": 16, + "min_height": 211, + "min_width": 211, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.7800689571626946e-12, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.01017812685133579 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.107588595730874e-05, + "r_shift_limit": [ + 133, + 133 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.09645565241581355, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 13, + 13 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.927459304084804e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 76, + 76 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.236720849449188e-10, + "brightness_limit": [ + 0.22349166870117188, + 0.22349166870117188 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.602560019631437e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.413628527843938e-13, + "threshold": [ + 67, + 67 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2143891611697741e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -145.1663818359375, + -145.1663818359375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.764300314355046e-06, + "shift_limit_x": [ + 0.8602849245071411, + 0.8602849245071411 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.639429951054502e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.573377628154918e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.164137363433838, + 7.164137363433838 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.86482899848852e-07, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.46696129226138794, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.4364076361893714 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.2178720750824295e-09, + "r_shift_limit": [ + 59, + 59 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.9912771597219017e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -57, + -57 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0003520621364979763, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -53, + -53 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.006358930823756576, + "brightness_limit": [ + 0.2626572847366333, + 0.2626572847366333 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.64186070248747e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 8.274420738220215, + 8.274420738220215 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.1698184598442226e-06, + "threshold": [ + 102, + 102 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.5327771599512513e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.392219073968998e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -6.058990478515625, + -6.058990478515625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.06590995751240403, + "shift_limit_x": [ + 0.08929646015167236, + 0.08929646015167236 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.959756201182612e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.009247899055480957, + 0.009247899055480957 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.747070789337158, + 3.747070789337158 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0001542129375637193, + "max_holes": 16, + "max_height": 70, + "max_width": 70, + "min_holes": 16, + "min_height": 70, + "min_width": 70, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.9590310327076259e-07, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9272178192762064 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0425449740519473e-07, + "r_shift_limit": [ + 128, + 128 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.189203958732221e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.775513208988833e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -82, + -82 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.0414642112044144e-11, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.55778276760033e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.0816152095794678, + 1.0816152095794678 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.1381486028875453e-11, + "threshold": [ + 199, + 199 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.583968235255719e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.2569924404985407e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.4714045250761185e-15, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.41908531775311175, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.812692989357639e-15, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6288659572601318, + -0.6288659572601318 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.258279591573777e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.199827194213867, + 8.199827194213867 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.2659842713176687e-10, + "max_holes": 16, + "max_height": 32, + "max_width": 32, + "min_holes": 16, + "min_height": 32, + "min_width": 32, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.9828226909956896e-07, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.580912787791682 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.2990296182905495e-07, + "r_shift_limit": [ + 108, + 108 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0938858068423798, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 34, + 34 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.04298614300700443, + "brightness_limit": [ + -0.15956580638885498, + -0.15956580638885498 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0006066504194240409, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.3125097751617432, + 1.3125097751617432 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 8.405636418324316e-08, + "threshold": [ + 6, + 6 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.889338514204233e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.690485485837171e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.258334359549481e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.335784912109375, + 0.335784912109375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.4754880304037035e-05, + "shift_limit_x": [ + 0.006566047668457031, + 0.006566047668457031 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.348491173697974e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.5121694803237915, + -0.5121694803237915 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.326374053955078, + 7.326374053955078 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0005930818066649073, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.8870523439904472e-06, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8618541593037379 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0006930868839845061, + "r_shift_limit": [ + -78, + -78 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.859239171231188e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 73, + 73 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.290321891159771e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.8437549830601684e-10, + "brightness_limit": [ + 0.3243004083633423, + 0.3243004083633423 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.7050636542061581e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.4617408514022827, + 1.4617408514022827 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.902981479198772e-09, + "threshold": [ + 126, + 126 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.16873073867709376 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.273499274376612e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.577680205440268e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.1016845703125, + 0.1016845703125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.6066471338272095, + 0.6066471338272095 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.151149386759905e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.926982045173645, + -0.926982045173645 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.119398539794805e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.1075592041015625, + 5.1075592041015625 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.3643249420231404e-08, + "max_holes": 16, + "max_height": 94, + "max_width": 94, + "min_holes": 16, + "min_height": 94, + "min_width": 94, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.4734554368517096e-09, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8305636595706613 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.6618942285779994, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -1, + -1 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.005918358127822432, + "brightness_limit": [ + -0.1468178629875183, + -0.1468178629875183 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.124584907798045e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.3772532939910889, + 1.3772532939910889 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 166, + 166 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.090242146913018e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.1275468455917465e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 7.5305938720703125, + 7.5305938720703125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.7338741364100697e-07, + "shift_limit_x": [ + -0.801611065864563, + -0.801611065864563 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1055917383070159e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0025671720504760742, + 0.0025671720504760742 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.8052452055545142e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.99999993922529e-09, + 9.99999993922529e-09 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.254009526381445e-07, + "max_holes": 16, + "max_height": 83, + "max_width": 83, + "min_holes": 16, + "min_height": 83, + "min_width": 83, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.020449394552251476, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.31173416938619425 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.010305599935279353, + "r_shift_limit": [ + 59, + 59 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0003970827721760505, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -37, + -37 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.3129170912248995e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.570279045608338e-06, + "brightness_limit": [ + 0.35517942905426025, + 0.35517942905426025 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.07516759275558371, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1677331924438477, + 1.1677331924438477 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.8491140141645097e-06, + "threshold": [ + 61, + 61 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.540341622975305e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.9895547915479933e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -156.82618713378906, + -156.82618713378906 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.880042743074021e-09, + "shift_limit_x": [ + -0.8512485027313232, + -0.8512485027313232 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7154703508455845e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.329768627698576e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9704892635345459, + 0.9704892635345459 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00019042802956895782, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.001952720443910927, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9119370388149208 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.759252101706627e-09, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.798158526506219e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.8904490785086298e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 65, + 65 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.013848826666439e-08, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 8.91899585723877, + 8.91899585723877 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 127, + 127 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.736510096943793e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.814874355586668e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.1878915941915245e-14, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0004576978835881401, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.9671236276626587, + -0.9671236276626587 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.474504218473965e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.228621482849121, + 5.228621482849121 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.5737725342932526e-11, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1424002811483937e-12, + "max_holes": 7, + "max_height": 14, + "max_width": 14, + "min_holes": 7, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9995419039610841 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.217266670267528e-11, + "r_shift_limit": [ + 139, + 139 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1487170953224325e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.091828015896203e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.339440379924202e-12, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.710771323564705e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.6595247983932495, + 0.6595247983932495 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.0328747625656592e-13, + "threshold": [ + 43, + 43 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.9983071290687222e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.235700432735979e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.12634193978222186, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -10.307540893554688, + -10.307540893554688 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.926182039708789e-09, + "shift_limit_x": [ + 0.021807432174682617, + 0.021807432174682617 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.703920311095692e-15, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.16035699844360352, + 0.16035699844360352 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3212331520092718e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.086735725402832, + 4.086735725402832 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.5482378726471174e-06, + "max_holes": 16, + "max_height": 92, + "max_width": 92, + "min_holes": 16, + "min_height": 92, + "min_width": 92, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.4354168065895586e-11, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8736511795884108 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.125353443218167e-08, + "r_shift_limit": [ + 82, + 82 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.020892051642518172, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 12, + 12 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.5907521445599786e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 44, + 44 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00023917573925301763, + "brightness_limit": [ + -0.20734435319900513, + -0.20734435319900513 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.140005233603915e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2769200801849365, + 1.2769200801849365 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.455707957540975e-09, + "threshold": [ + 201, + 201 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.3697394126519925e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.234832763671875, + 0.234832763671875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.393332154964899e-09, + "shift_limit_x": [ + -0.014130115509033203, + -0.014130115509033203 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.193862931374058e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.7498301267623901, + -0.7498301267623901 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0538603286627406e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.988048076629639, + 4.988048076629639 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.152426141749867e-10, + "max_holes": 16, + "max_height": 104, + "max_width": 104, + "min_holes": 16, + "min_height": 104, + "min_width": 104, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00237274653561223, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9764497941949419 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.7179110741822365e-12, + "r_shift_limit": [ + 34, + 34 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.500228812464284e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.3181915799739172e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -54, + -54 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.387315580207537e-12, + "brightness_limit": [ + -0.25789856910705566, + -0.25789856910705566 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.0070062839151461e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.3079407215118408, + 1.3079407215118408 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.4825419466610373e-07, + "threshold": [ + 237, + 237 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.144545092843942e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.3795645117268607e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.3635772078374934e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -4.572723388671875, + -4.572723388671875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.6248971685993325, + "shift_limit_x": [ + -0.06903499364852905, + -0.06903499364852905 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1283434333853815e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.5498030185699463, + -0.5498030185699463 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.488216476474247e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9987091422080994, + 0.9987091422080994 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.499920490998182e-06, + "max_holes": 16, + "max_height": 78, + "max_width": 78, + "min_holes": 16, + "min_height": 78, + "min_width": 78, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.245701838310456e-06, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.37509422730466313 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.013209494558685808, + "r_shift_limit": [ + 56, + 56 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0034563785884529352, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0003830022302911684, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -64, + -64 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.099463299313307e-05, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.061727887017921e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 7.387712478637695, + 7.387712478637695 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0015611373984603105, + "threshold": [ + 252, + 252 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.730123063186864e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.1659978645581526e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 166.95010375976562, + 166.95010375976562 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7042500985553488e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.040013670921325684, + 0.040013670921325684 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5498179779879643e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0330591201782227, + 1.0330591201782227 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00023219395243585794, + "max_holes": 16, + "max_height": 190, + "max_width": 190, + "min_holes": 16, + "min_height": 190, + "min_width": 190, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.618822771679538e-06, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.981081730684407 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.65336645546205e-07, + "r_shift_limit": [ + -70, + -70 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.1352519655224608e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -50, + -50 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00034406777298971736, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -55, + -55 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.43586367100322e-09, + "brightness_limit": [ + 0.26902151107788086, + 0.26902151107788086 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.017191558920334e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2792373895645142, + 1.2792373895645142 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.797951686584185e-09, + "threshold": [ + 24, + 24 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.172509045720516e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.581641374934711e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.30937959027986e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.306182861328125, + 0.306182861328125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.6139098307583204, + "shift_limit_x": [ + 0.05328035354614258, + 0.05328035354614258 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.594214760021623e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.130291219336748e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.216315746307373, + 6.216315746307373 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0004863239983227269, + "max_holes": 16, + "max_height": 94, + "max_width": 94, + "min_holes": 16, + "min_height": 94, + "min_width": 94, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.881565376759484e-09, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.38522643003294643 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.216402896805736e-06, + "r_shift_limit": [ + -76, + -76 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.620630477153784e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0020464312268341778, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 56, + 56 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + -0.31213611364364624, + -0.31213611364364624 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.9323808544903558e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.0922182410508287e-10, + "threshold": [ + 94, + 94 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.7912739487800043e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2971478571410882e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.0095977783203125, + 0.0095977783203125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.1432790704245494e-13, + "shift_limit_x": [ + 0.6151012182235718, + 0.6151012182235718 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0004459997943824373, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0001309514045715332, + -0.0001309514045715332 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.10762882232666, + 6.10762882232666 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.3898620995606535e-05, + "max_holes": 16, + "max_height": 188, + "max_width": 188, + "min_holes": 16, + "min_height": 188, + "min_width": 188, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.013341099799157208, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9841221457343483 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.07711532711982727, + "r_shift_limit": [ + -4, + -4 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0016004904854553248, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -50, + -50 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.6240952515440262e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 27, + 27 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + -0.013184726238250732, + -0.013184726238250732 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.0519134977803333e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2438857555389404, + 1.2438857555389404 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.381902125893981e-09, + "threshold": [ + 174, + 174 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.3093097929095267e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.934214885223478e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 128.3829345703125, + 128.3829345703125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.889971137046814, + 0.889971137046814 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.18407094478607178, + 0.18407094478607178 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.901719093322754, + 7.901719093322754 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0002439827490837293, + "max_holes": 16, + "max_height": 115, + "max_width": 115, + "min_holes": 16, + "min_height": 115, + "min_width": 115, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.921038115978321 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.152009473053115e-12, + "r_shift_limit": [ + 44, + 44 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0900047429961716e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -11, + -11 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0092876930276073e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -102, + -102 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2560963750813618e-09, + "brightness_limit": [ + -0.8887532949447632, + -0.8887532949447632 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.3648492097854614, + 1.3648492097854614 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.6633426125056344e-07, + "threshold": [ + 184, + 184 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.4429195532250036e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.9763666671985392e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.806169761553458e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -60.141448974609375, + -60.141448974609375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.068250128629261e-11, + "shift_limit_x": [ + -0.0003482699394226074, + -0.0003482699394226074 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.6470862134429893, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.018942713737487793, + 0.018942713737487793 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.930485878835587e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.156022071838379, + 6.156022071838379 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.4399444963625387e-07, + "max_holes": 16, + "max_height": 78, + "max_width": 78, + "min_holes": 16, + "min_height": 78, + "min_width": 78, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.566668378823971e-11, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.35291269179199103 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.023256987207208257, + "r_shift_limit": [ + 71, + 71 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0001732617583191376, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 144, + 144 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.051222582373232406, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -41, + -41 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0009170135208616051, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.548465687035261e-06, + "threshold": [ + 84, + 84 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.6325530349678106e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.07696533203125, + 0.07696533203125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2629416817847648e-12, + "shift_limit_x": [ + 0.4397900104522705, + 0.4397900104522705 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7883628510365267e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.5609369277954102, + 0.5609369277954102 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.741344451904297, + 8.741344451904297 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.012064993049731854, + "max_holes": 16, + "max_height": 177, + "max_width": 177, + "min_holes": 16, + "min_height": 177, + "min_width": 177, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0005345710166279397, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9118250405554507 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4289256620823063e-08, + "r_shift_limit": [ + -19, + -19 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.878797047972133e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -87, + -87 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1900676530625376e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 16, + 16 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.607295684567554e-08, + "brightness_limit": [ + -0.7293243408203125, + -0.7293243408203125 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.8041902572533096e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 9.534704807462503e-09, + "threshold": [ + 235, + 235 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.67480679441183e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.3986491745908524e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.285481335303924e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -107.84115600585938, + -107.84115600585938 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.8866484698321822e-06, + "shift_limit_x": [ + -0.5079514980316162, + -0.5079514980316162 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.5388664870420712, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.7435612678527832, + -0.7435612678527832 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.170909414089342e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0008165836334229, + 1.0008165836334229 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.636182172176735e-10, + "max_holes": 16, + "max_height": 72, + "max_width": 72, + "min_holes": 16, + "min_height": 72, + "min_width": 72, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.2760608477602407e-11, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.46111723288397444 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.675903216217292e-10, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.528577264077811e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -82, + -82 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.121210252150189e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.005881766256100179, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.9036539070796735e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 5.246695518493652, + 5.246695518493652 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.0921464354812763e-09, + "threshold": [ + 171, + 171 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.937708714402567e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.6146901364022314e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.8200225830078125, + -0.8200225830078125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0405288677459229e-13, + "shift_limit_x": [ + 0.6375064849853516, + 0.6375064849853516 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.022848310760797852, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.10262453556060791, + -0.10262453556060791 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.4307490632314204e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.002005577087402, + 6.002005577087402 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.321711959632806e-09, + "max_holes": 16, + "max_height": 179, + "max_width": 179, + "min_holes": 16, + "min_height": 179, + "min_width": 179, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.2387884528770746e-06, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9711440237195751 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.51825971769004e-08, + "r_shift_limit": [ + 77, + 77 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.383964706669636e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0024681520645750132, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -27, + -27 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.3150435695718646e-05, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00020893165660442956, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.5994126796722412, + 1.5994126796722412 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0004007725871806936, + "threshold": [ + 141, + 141 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.4808017286056713e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.2302475955825925e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -12.885360717773438, + -12.885360717773438 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.047661871294444e-08, + "shift_limit_x": [ + -0.31794625520706177, + -0.31794625520706177 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5648899329571668e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.7359716296195984, + -0.7359716296195984 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.176151785823075e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 10.0, + 10.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.120316248874382e-09, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.1646780042197665e-06, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9968946617225928 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5573994720315133e-09, + "r_shift_limit": [ + -80, + -80 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.5829371942183945e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -58, + -58 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.846760561083534e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.0887243891871982e-05, + "brightness_limit": [ + 0.229483962059021, + 0.229483962059021 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.914303443231612e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2896536588668823, + 1.2896536588668823 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.424086870922859e-13, + "threshold": [ + 155, + 155 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 9.918400994249475e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.002948409731898e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.745388104396651e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.3077239990234375, + 0.3077239990234375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.004868782852789244, + "shift_limit_x": [ + -0.09110361337661743, + -0.09110361337661743 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.1417428121024965e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.8314809203147888, + 0.8314809203147888 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.004745624481881e-08, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.769860574801828e-06, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9951139413846006 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.004512607380959155, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.15155864088885274, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -13, + -13 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 19, + 19 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0002704305633501828, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.957086325808762e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.0099939107894897, + 1.0099939107894897 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.6813725233838506e-08, + "threshold": [ + 153, + 153 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.591677678659755e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 119.78759765625, + 119.78759765625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.06058335304260254, + -0.06058335304260254 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.4781200913587025e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.4575091600418091, + 0.4575091600418091 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.5820826527350624e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.196455478668213, + 3.196455478668213 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.7415879195601884e-09, + "max_holes": 16, + "max_height": 145, + "max_width": 145, + "min_holes": 16, + "min_height": 145, + "min_width": 145, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0005469855165170581, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8430116835638054 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.005816212818007038, + "r_shift_limit": [ + 30, + 30 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.04177181486370918, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 4, + 4 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.4044806283209823, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -10, + -10 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.104351126670412e-05, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.015877394935369993, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1221858263015747, + 1.1221858263015747 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.953618546722609e-11, + "threshold": [ + 11, + 11 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.696727487708446e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 6.27520751953125, + 6.27520751953125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.583188322052699e-07, + "shift_limit_x": [ + 0.010248899459838867, + 0.010248899459838867 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.772051822867639e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.2260441542472566e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.99999993922529e-09, + 9.99999993922529e-09 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.3296699258047247e-08, + "max_holes": 16, + "max_height": 142, + "max_width": 142, + "min_holes": 16, + "min_height": 142, + "min_width": 142, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.019518975168466568, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5124633581672076 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.253513476055289e-10, + "r_shift_limit": [ + -52, + -52 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.572835528422167e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 144, + 144 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.25933796577085e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -45, + -45 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2874805780855084e-06, + "brightness_limit": [ + -0.3612363934516907, + -0.3612363934516907 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.9568008711104915e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.463768662630395e-10, + "threshold": [ + 141, + 141 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.998789451068236e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.6233725486420633e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.9991866132460778, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -5.6714630126953125, + -5.6714630126953125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0704053028436425e-11, + "shift_limit_x": [ + 0.023776769638061523, + 0.023776769638061523 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9430884766504347e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.5931714773178101, + -0.5931714773178101 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.2617205578269244e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.437659740447998, + 5.437659740447998 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00048768708824120655, + "max_holes": 16, + "max_height": 141, + "max_width": 141, + "min_holes": 16, + "min_height": 141, + "min_width": 141, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.165573422802251e-08, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.00032399818303785466 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0005279168339425502, + "r_shift_limit": [ + -61, + -61 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.11976162552727665, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -21, + -21 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.05556332692503929, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -40, + -40 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.025743461314040816, + "brightness_limit": [ + 0.1468421220779419, + 0.1468421220779419 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.236649212553262e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 7.35645866394043, + 7.35645866394043 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.4004044518414305e-08, + "threshold": [ + 118, + 118 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.898614867999553e-05 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 9.880425047920272e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.457039198682572e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.8282878994941711, + -0.8282878994941711 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.251970661481685e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0046482086181640625, + 0.0046482086181640625 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.211532408255394e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.014737606048584, + 7.014737606048584 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0032048170380937213, + "max_holes": 16, + "max_height": 115, + "max_width": 115, + "min_holes": 16, + "min_height": 115, + "min_width": 115, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.010114801577128185, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7850517483554521 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.417601011144362e-11, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.460357804348411e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.3395960912369913e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -63, + -63 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0003854952576196058, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.4774885944020068e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.478917121887207, + 1.478917121887207 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.0706882678215134e-05, + "threshold": [ + 114, + 114 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.626408464369407e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.1457346391509852e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2451629410339118e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.529754638671875, + 0.529754638671875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0161031961335028e-08, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.06533779898448433, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6335872411727905, + -0.6335872411727905 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3505349753426684e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.349654197692871, + 7.349654197692871 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.134957546927278e-08, + "max_holes": 16, + "max_height": 136, + "max_width": 136, + "min_holes": 16, + "min_height": 136, + "min_width": 136, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.126925724658189e-07, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9341697535324636 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.044688402330544e-08, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.058646161280863e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -210, + -210 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.5812201504160984e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 216, + 216 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.967060427105676e-10, + "brightness_limit": [ + 0.43409502506256104, + 0.43409502506256104 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.356212019484515e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.400437831878662, + 1.400437831878662 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 9.475327599612974e-09, + "threshold": [ + 241, + 241 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.9999990463256836 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.300017202907859e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4172763196582872e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 18.718292236328125, + 18.718292236328125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.6867570903420567e-08, + "shift_limit_x": [ + 0.38465213775634766, + 0.38465213775634766 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.978262443264658e-15, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.5356479287147522, + -0.5356479287147522 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9306324437664913e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.5046892166137695, + 7.5046892166137695 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.907801781606669e-13, + "max_holes": 16, + "max_height": 19, + "max_width": 19, + "min_holes": 16, + "min_height": 19, + "min_width": 19, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.807022324752863e-14, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 7.401320135658196e-07 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.01893597424243687, + "r_shift_limit": [ + -45, + -45 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 38, + 38 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.586981537587199e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.014113301252301036, + "brightness_limit": [ + 0.1561129093170166, + 0.1561129093170166 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.1284532400410799e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2628710269927979, + 1.2628710269927979 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0009624699964931316, + "threshold": [ + 197, + 197 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.6793722563303976e-05 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.562645619129289e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.025632194716205e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.469879150390625, + 0.469879150390625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1307652444380397e-08, + "shift_limit_x": [ + -0.5140781402587891, + -0.5140781402587891 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.8097274426951746e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.004068195819854736, + -0.004068195819854736 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3464637232681223e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.605375289916992, + 8.605375289916992 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.295435446315018e-05, + "max_holes": 16, + "max_height": 199, + "max_width": 199, + "min_holes": 16, + "min_height": 199, + "min_width": 199, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0006759982965281464, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9652716174032682 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.805670864737222e-06, + "r_shift_limit": [ + 52, + 52 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00023902245760126783, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00046639582483837955, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 0, + 0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00196558443575634, + "brightness_limit": [ + -0.20557349920272827, + -0.20557349920272827 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.103665928768381e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 8.652626991271973, + 8.652626991271973 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.0372580082839503e-10, + "threshold": [ + 25, + 25 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.2657576826166877e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.866352292756361e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.252397154892959e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -120.755615234375, + -120.755615234375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.427920517584797e-11, + "shift_limit_x": [ + -0.5314724445343018, + -0.5314724445343018 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.8373512029647827, + 0.8373512029647827 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.311041831970215, + 5.311041831970215 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0004539279311303046, + "max_holes": 16, + "max_height": 158, + "max_width": 158, + "min_holes": 16, + "min_height": 158, + "min_width": 158, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00025603891621130137, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9966140724626603 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.717310715263592e-08, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.219035832758731e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.3075829481951135e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 81, + 81 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.5359457469303296e-05, + "brightness_limit": [ + 0.4134030342102051, + 0.4134030342102051 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.6611786064045026e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.1671944826257303e-09, + "threshold": [ + 217, + 217 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.3663677523631543e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.1667108430423987, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 8.608535766601562, + 8.608535766601562 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0659710862106204e-10, + "shift_limit_x": [ + -0.7656596302986145, + -0.7656596302986145 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.60587228376026e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0002548098564147949, + -0.0002548098564147949 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.2702562802354253e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.3951640129089355, + 5.3951640129089355 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.752045386554563e-05, + "max_holes": 16, + "max_height": 169, + "max_width": 169, + "min_holes": 16, + "min_height": 169, + "min_width": 169, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.2592508873165274e-07, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8331742539520144 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.30176510498391984, + "r_shift_limit": [ + -48, + -48 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.008630800674333916, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -13, + -13 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1875778838723065e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.06446819223965239, + "brightness_limit": [ + -0.11244261264801025, + -0.11244261264801025 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.2990471475418084e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.435891151428223, + 6.435891151428223 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.032703455571907e-06, + "threshold": [ + 132, + 132 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.052303772116776e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.586712537277176e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.4892954315772025e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.562164306640625, + -0.562164306640625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2448511672347206e-06, + "shift_limit_x": [ + 0.009053826332092285, + 0.009053826332092285 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.603630556924338e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.3014260530471802, + 0.3014260530471802 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.6386022567749023, + 1.6386022567749023 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 189, + "max_width": 189, + "min_holes": 16, + "min_height": 189, + "min_width": 189, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.72353531912883e-05, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6250987830863128 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.029369605115014963, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.567536061665401e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 20, + 20 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.7829047270871159e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 33, + 33 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.02777932382476289, + "brightness_limit": [ + -0.16687428951263428, + -0.16687428951263428 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.31506815706067925, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1744065284729004, + 1.1744065284729004 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.002994982028005244, + "threshold": [ + 57, + 57 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.3234600887178157e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 4.57073974609375, + 4.57073974609375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.3251062035560608, + -0.3251062035560608 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.1164221713967716e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.002332448959350586, + 0.002332448959350586 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.685201530442571e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.012800693511963, + 1.012800693511963 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.5676132727113212e-05, + "max_holes": 16, + "max_height": 111, + "max_width": 111, + "min_holes": 16, + "min_height": 111, + "min_width": 111, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.010352573182207e-07, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.62476919022155 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0020065465982932462, + "r_shift_limit": [ + 32, + 32 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.2849313239207021, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -8, + -8 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00045084345038048923, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -56, + -56 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.002833611873850561, + "brightness_limit": [ + 0.053304433822631836, + 0.053304433822631836 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 7.7808308601379395, + 7.7808308601379395 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 8.041708111202868e-13, + "threshold": [ + 61, + 61 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 7.634451944673832e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.13248058228757e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.903282734223467e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.2909393310546875, + 0.2909393310546875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9266878452973437e-06, + "shift_limit_x": [ + -0.9576289057731628, + -0.9576289057731628 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.248449448950243e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.9455262422561646, + 0.9455262422561646 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.667344549181733e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.6414260864257812, + 3.6414260864257812 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.008665801036937815, + "max_holes": 16, + "max_height": 25, + "max_width": 25, + "min_holes": 16, + "min_height": 25, + "min_width": 25, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.629617768649698e-05, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7010889982200181 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00016299906822412908, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0011348035326346623, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 41, + 41 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.260069227672174e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -31, + -31 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.588008938023495e-08, + "brightness_limit": [ + -1.0, + -1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.3341166602806535e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.6086636781692505, + 1.6086636781692505 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0008638626531245475, + "threshold": [ + 243, + 243 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.673975069994346e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.506784836434226e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 180.0, + 180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.00019400958335353408, + "shift_limit_x": [ + -0.6158512830734253, + -0.6158512830734253 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.859290717417714e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.606500506401062, + -0.606500506401062 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.4900407396309e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9882224798202515, + 0.9882224798202515 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.8593552363450756e-06, + "max_holes": 16, + "max_height": 106, + "max_width": 106, + "min_holes": 16, + "min_height": 106, + "min_width": 106, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.4189294299200035e-05, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.997602561070383 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00017886534477163946, + "r_shift_limit": [ + 80, + 80 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00046599012324367167, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 91, + 91 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1281875369318281e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 45, + 45 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.029496140328989e-07, + "brightness_limit": [ + -0.20895779132843018, + -0.20895779132843018 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.8699450572797394e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 7.579221248626709, + 7.579221248626709 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0019671543408318892, + "threshold": [ + 241, + 241 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.214677864748221e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 77.97116088867188, + 77.97116088867188 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.6768885318236604e-09, + "shift_limit_x": [ + 0.0002548694610595703, + 0.0002548694610595703 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.094133460177367e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.25645196437835693, + 0.25645196437835693 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.4643785678859903e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.422214984893799, + 6.422214984893799 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.042336124926805496, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0020421606205412723, + "max_holes": 13, + "max_height": 14, + "max_width": 14, + "min_holes": 13, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9530088688119744 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0005124053849415097, + "r_shift_limit": [ + -61, + -61 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.002417723968961477, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 38, + 38 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0035943695924604002, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 34, + 34 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.7255010220651457e-07, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 3.717583417892456, + 3.717583417892456 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 76, + 76 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.4132582023375334e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 5.4296112060546875, + 5.4296112060546875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0221315305022904e-05, + "shift_limit_x": [ + 0.8160057067871094, + 0.8160057067871094 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.594295027222529e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.00046885013580322266, + 0.00046885013580322266 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.460638267666811e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.6468505859375, + 5.6468505859375 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.424090217568235e-10, + "max_holes": 16, + "max_height": 142, + "max_width": 142, + "min_holes": 16, + "min_height": 142, + "min_width": 142, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0005837803419971588, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9928813254684615 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.016100434862671875, + "r_shift_limit": [ + 20, + 20 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.9365158257750014e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 22, + 22 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -19, + -19 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0585916021514703, + "brightness_limit": [ + -0.14804697036743164, + -0.14804697036743164 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.428464889040283e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.866783618927002, + 1.866783618927002 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.314727939137853e-07, + "threshold": [ + 102, + 102 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.9089415119075574e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.4283343017364355e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.948202206160187e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -131.672119140625, + -131.672119140625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.04744136333465576, + 0.04744136333465576 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.9463785886764526, + -0.9463785886764526 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0169413089752197, + 1.0169413089752197 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0003711287133947687, + "max_holes": 16, + "max_height": 130, + "max_width": 130, + "min_holes": 16, + "min_height": 130, + "min_width": 130, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0020913117966965267, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9228453417995602 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + 171, + 171 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4147359954145915e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 89, + 89 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0008782806264073795, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 75, + 75 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.002701000029705747, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00024885154562070966, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.5305655002593994, + 1.5305655002593994 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.266087734624037e-08, + "threshold": [ + 56, + 56 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.040889699087095e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -108.7667465209961, + -108.7667465209961 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.860333290746161e-05, + "shift_limit_x": [ + -0.0024681687355041504, + -0.0024681687355041504 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.27959745002167e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0038393139839172363, + -0.0038393139839172363 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.485901355743408, + 5.485901355743408 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.731639355862004e-09, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.2142979156410995e-07, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9960689444462321 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.847699516999203e-05, + "r_shift_limit": [ + -61, + -61 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0005171000775748384, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -42, + -42 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.1088743992740515e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 94, + 94 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.579637704118627e-06, + "brightness_limit": [ + -0.10346382856369019, + -0.10346382856369019 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.594511567956983e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.8773151636123657, + 0.8773151636123657 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.18930755282911e-08, + "threshold": [ + 188, + 188 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.2478852489093163e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.307463732298995e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.64126380840259e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 134.16058349609375, + 134.16058349609375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7537170366516627e-13, + "shift_limit_x": [ + -0.9582552313804626, + -0.9582552313804626 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.1144525946211889e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.009568929672241211, + -0.009568929672241211 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.0008886525458236e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.879642486572266, + 5.879642486572266 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 141, + "max_width": 141, + "min_holes": 16, + "min_height": 141, + "min_width": 141, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.001491019017677092, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9978991311871381 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.619312104153883e-07, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.5485942799075596e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.076017418729181e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -40, + -40 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + -0.9421690106391907, + -0.9421690106391907 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.524890639498698e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.8781323385747958e-08, + "threshold": [ + 235, + 235 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.11337177997642e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.5164010231880626e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 21.11859130859375, + 21.11859130859375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.10240330942585896, + "shift_limit_x": [ + -0.1288049817085266, + -0.1288049817085266 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.727056203773444e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8257803320884705, + -0.8257803320884705 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.5741582794301374e-15, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.165175437927246, + 9.165175437927246 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.30251440216363e-15, + "max_holes": 16, + "max_height": 165, + "max_width": 165, + "min_holes": 16, + "min_height": 165, + "min_width": 165, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.98841616949737e-12, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.897596015948158 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.145718728189107e-10, + "r_shift_limit": [ + -67, + -67 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0482763430737758e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 106, + 106 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.345368870713623e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -92, + -92 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.859830478135299e-13, + "brightness_limit": [ + 0.1570425033569336, + 0.1570425033569336 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.0637254628440267e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.3665801286697388, + 1.3665801286697388 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.156907170264562e-06, + "threshold": [ + 118, + 118 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.356101208424395e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.0459756246684604e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.01908925732722e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 71.85017395019531, + 71.85017395019531 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.130407847382096e-06, + "shift_limit_x": [ + 0.8354930877685547, + 0.8354930877685547 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.740390872199697, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.07858288288116455, + 0.07858288288116455 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.153603754493346e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.4372053146362305, + 6.4372053146362305 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.01160636730492115, + "max_holes": 16, + "max_height": 146, + "max_width": 146, + "min_holes": 16, + "min_height": 146, + "min_width": 146, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.2879932528887305e-13, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.24798672962348267 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.489250324281909e-08, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4448814543022139e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -103, + -103 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.276763162342929e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.327080026312225e-12, + "brightness_limit": [ + 0.026410222053527832, + 0.026410222053527832 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.749440874571431e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.5014695163821528e-11, + "threshold": [ + 3, + 3 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.4255564012159394e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.689138287856582e-16 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2921574350504999e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.4337615966796875, + 0.4337615966796875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.6780969406464976, + "shift_limit_x": [ + -0.09480005502700806, + -0.09480005502700806 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.1713760155155156e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.00020998716354370117, + -0.00020998716354370117 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.403812461382195e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.716150283813477, + 8.716150283813477 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.187644389621655e-09, + "max_holes": 16, + "max_height": 25, + "max_width": 25, + "min_holes": 16, + "min_height": 25, + "min_width": 25, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.4096200751423143e-06, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.3218945096697575 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0381207389020953e-09, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4559958182420985e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.2736569700545528e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -169, + -169 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.002430998215168345, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.4418119589493214e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.279064822109513e-12, + "threshold": [ + 137, + 137 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.3197893164429896e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0183830697136553e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.03387451171875, + -0.03387451171875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.7835458836953109, + "shift_limit_x": [ + 0.9400173425674438, + 0.9400173425674438 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.6667108259897066e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.00034415721893310547, + 0.00034415721893310547 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.7169099064411054e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.83379077911377, + 8.83379077911377 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0120406444492612e-13, + "max_holes": 16, + "max_height": 87, + "max_width": 87, + "min_holes": 16, + "min_height": 87, + "min_width": 87, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.910617343238831e-07, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.21402259090073794 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.7905633667396834e-09, + "r_shift_limit": [ + -120, + -120 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.133652959003048e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 49, + 49 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.678931331056186e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -64, + -64 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.55150230701118e-13, + "brightness_limit": [ + -0.3615054488182068, + -0.3615054488182068 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.1854225085205619e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 62, + 62 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.7818020474103823e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.9999949932098389, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 6.735504150390625, + 6.735504150390625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.8312265872955322, + -0.8312265872955322 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.598847389501232e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.020502686500549316, + 0.020502686500549316 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3411039905602602e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.4360835552215576, + 3.4360835552215576 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.607571594430697e-09, + "max_holes": 16, + "max_height": 53, + "max_width": 53, + "min_holes": 16, + "min_height": 53, + "min_width": 53, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.197301703674823e-08, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 3.9801297826436155e-06 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.811654356052795e-08, + "r_shift_limit": [ + -49, + -49 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00018817091768141836, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -61, + -61 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00927891398437275, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 19, + 19 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.6665936143283171e-09, + "brightness_limit": [ + -1.0, + -1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.340197432224058e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 2.2335190773010254, + 2.2335190773010254 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.887288429872945e-06, + "threshold": [ + 107, + 107 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.227311312030236e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.6267211666935783e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.9815673828125, + 0.9815673828125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.77898640166463e-06, + "shift_limit_x": [ + 0.9656897783279419, + 0.9656897783279419 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8263997435569763, + -0.8263997435569763 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.629860559100889e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.099557876586914, + 7.099557876586914 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00021527882240660913, + "max_holes": 16, + "max_height": 112, + "max_width": 112, + "min_holes": 16, + "min_height": 112, + "min_width": 112, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.439317265877727e-05, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9902511743951131 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0066135399973424325, + "r_shift_limit": [ + 70, + 70 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0003598106410190368, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -64, + -64 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5858054933109487e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -255, + -255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.0929527048507093e-07, + "brightness_limit": [ + -0.27874886989593506, + -0.27874886989593506 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.0965522039954852e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2301827669143677, + 1.2301827669143677 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.229867192593245e-08, + "threshold": [ + 218, + 218 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5486989249137084e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -83.78449249267578, + -83.78449249267578 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.9813783434784578e-12, + "shift_limit_x": [ + -0.0009657144546508789, + -0.0009657144546508789 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.0319243229617106e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.7596901059150696, + -0.7596901059150696 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.9893476497847384e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.312911510467529, + 4.312911510467529 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.469866691914152e-05, + "max_holes": 16, + "max_height": 217, + "max_width": 217, + "min_holes": 16, + "min_height": 217, + "min_width": 217, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.588013335490867e-05, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9929252883184249 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.028851708047795e-12, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0472546897917272e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 54, + 54 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0006925069345065787, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.383302261804379e-05, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.493500961912827e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.6139557340794884e-09, + "threshold": [ + 158, + 158 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.849580296673542e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.120738177478293e-15 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.3225512925603567e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.555145263671875, + -0.555145263671875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7944742530719673e-08, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.13775634765625, + 0.13775634765625 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.518807798606509e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.099759101867676, + 4.099759101867676 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.144525975344113e-09, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.5940662143936645e-10, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.999263613261616 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.006046540016734e-09, + "r_shift_limit": [ + -59, + -59 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.15768539887571e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 63, + 63 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.955272310471743e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -49, + -49 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.047560935519752e-10, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.831955230396689e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.654793102545682e-08, + "threshold": [ + 253, + 253 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.051645536387631e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.149033230642134e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0516541758633863e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 62.2572021484375, + 62.2572021484375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.04784105802250327, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.615331791281915e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.7119776010513306, + 0.7119776010513306 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.069213588329086e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.003697395324707, + 1.003697395324707 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.2181758424795585e-09, + "max_holes": 16, + "max_height": 86, + "max_width": 86, + "min_holes": 16, + "min_height": 86, + "min_width": 86, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.90604088129262e-11, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9521571615668033 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.056079635204487666, + "r_shift_limit": [ + -38, + -38 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.008139016240374275, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -58, + -58 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00527354605164021, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 55, + 55 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.2240985420016613e-05, + "brightness_limit": [ + 0.5010356903076172, + 0.5010356903076172 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.02554738203431428, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.4763364791870117, + 1.4763364791870117 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.53530131592878e-07, + "threshold": [ + 166, + 166 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.5820165614915148e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 9.039002427956502e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.489098356714742e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -49.29205322265625, + -49.29205322265625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.3614828897075226e-07, + "shift_limit_x": [ + 0.9570320844650269, + 0.9570320844650269 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.6749712228775024, + 0.6749712228775024 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.925961971282959, + 0.925961971282959 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.0283225188840456e-09, + "max_holes": 16, + "max_height": 168, + "max_width": 168, + "min_holes": 16, + "min_height": 168, + "min_width": 168, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.8882385928882286e-05, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9048783052937147 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.2929822577411145e-06, + "r_shift_limit": [ + 96, + 96 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.767813350849974e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -67, + -67 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.2488441529776904e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -70, + -70 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00012084120274401429, + "brightness_limit": [ + 0.456676721572876, + 0.456676721572876 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.125280329792336e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.1494343573213616e-10, + "threshold": [ + 124, + 124 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.3094542527179574e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.3233893451712328e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.38702198664603316, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 4.1527099609375, + 4.1527099609375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.7396970987319946, + 0.7396970987319946 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.717974621384792e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0021419525146484375, + 0.0021419525146484375 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.838595390319824, + 5.838595390319824 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.51770587904639e-06, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6127495515684005 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.882662654809766e-13, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.1946552887760996e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 121, + 121 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -107, + -107 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.395736275387525e-12, + "brightness_limit": [ + 0.2724059820175171, + 0.2724059820175171 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.1929580725885215e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 7.585568428039551, + 7.585568428039551 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.411265844312572e-09, + "threshold": [ + 101, + 101 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.9559692370771684e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -171.13050842285156, + -171.13050842285156 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.1467283806430908, + "shift_limit_x": [ + -0.07617026567459106, + -0.07617026567459106 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.6135146429952928e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0028085708618164062, + 0.0028085708618164062 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.483386993408203, + 7.483386993408203 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.004475180315028748, + "max_holes": 16, + "max_height": 132, + "max_width": 132, + "min_holes": 16, + "min_height": 132, + "min_width": 132, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.765621418910941e-12, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8487918321589024 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -214, + -214 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.6808770649537558e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -48, + -48 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4106505835849285e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -53, + -53 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.001275911113420361, + "brightness_limit": [ + 0.3860512971878052, + 0.3860512971878052 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.014129842522600189, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.171901822090149, + 1.171901822090149 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 95, + 95 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 9.483315377285214e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.93379402369769e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.9867706298828125, + -0.9867706298828125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.623073920919401e-12, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.5276601314544678, + -0.5276601314544678 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 2.2166199684143066, + 2.2166199684143066 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0822288390721821e-07, + "max_holes": 16, + "max_height": 126, + "max_width": 126, + "min_holes": 16, + "min_height": 126, + "min_width": 126, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.336207873237072e-07, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9845628010276436 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0034552471295414833, + "r_shift_limit": [ + -75, + -75 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0028759467132054295, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -61, + -61 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.611170372613378e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 53, + 53 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + -0.12132060527801514, + -0.12132060527801514 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.002107454197192604, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.857050895690918, + 0.857050895690918 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.1129641255433892e-11, + "threshold": [ + 36, + 36 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.524914535129822e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.6536109164695586e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.301198104252269e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -43.60646057128906, + -43.60646057128906 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.816127854600985e-11, + "shift_limit_x": [ + -0.004250288009643555, + -0.004250288009643555 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.1245943364400475e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.05739426612854004, + 0.05739426612854004 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.419322973481002e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0071852207183838, + 1.0071852207183838 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.915158364699525e-06, + "max_holes": 16, + "max_height": 36, + "max_width": 36, + "min_holes": 16, + "min_height": 36, + "min_width": 36, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.01922267925135479, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9723246627491786 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.125842631816422e-05, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0012726998545624646, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -67, + -67 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00117212767801652, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.005264733232388741, + "brightness_limit": [ + -0.22720950841903687, + -0.22720950841903687 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.697787791961668e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.62114143371582, + 6.62114143371582 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 63, + 63 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7607394493440943e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 115.01910400390625, + 115.01910400390625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.9157602787017822, + -0.9157602787017822 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1394905254027672e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8096714019775391, + -0.8096714019775391 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.7714031934738159, + 0.7714031934738159 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.000377677561576242, + "max_holes": 16, + "max_height": 122, + "max_width": 122, + "min_holes": 16, + "min_height": 122, + "min_width": 122, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.9646934231475605e-05, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9917718444721484 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0012910677087276667, + "r_shift_limit": [ + 89, + 89 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0027420073203909823, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -45, + -45 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.223072509489889e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -47, + -47 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0.8431664705276489, + 0.8431664705276489 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.018959250301122665, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.0941725969314575, + 1.0941725969314575 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.855668275129041e-08, + "threshold": [ + 215, + 215 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.1484591915566827e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -132.04293823242188, + -132.04293823242188 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.05042928457260132, + -0.05042928457260132 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.05900096893310547, + 0.05900096893310547 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0280267719417371e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0164175033569336, + 1.0164175033569336 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.17519591949983e-06, + "max_holes": 16, + "max_height": 121, + "max_width": 121, + "min_holes": 16, + "min_height": 121, + "min_width": 121, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0003694540195636267, + "max_holes": 13, + "max_height": 14, + "max_width": 14, + "min_holes": 13, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9766185774483745 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.002529861720974441, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1706429305251464e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.289578536432088e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -49, + -49 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.8469272668501314e-06, + "brightness_limit": [ + 0.23510980606079102, + 0.23510980606079102 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.0711861886953285e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.0660471085444385e-08, + "threshold": [ + 186, + 186 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.61070909877559e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.5021486612602646e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2652324435295737e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.342071533203125, + 0.342071533203125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.919352658753823e-11, + "shift_limit_x": [ + -0.026469767093658447, + -0.026469767093658447 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.07302566529491e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.028903603553771973, + 0.028903603553771973 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.6505427382200477e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.186232566833496, + 9.186232566833496 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.6259171822737288e-09, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0926021205415255, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9048587917187785 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.848064460936401e-06, + "r_shift_limit": [ + -237, + -237 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.46847349994616e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 112, + 112 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.197890127575665e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 54, + 54 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.242946941877373e-11, + "brightness_limit": [ + -0.3901402950286865, + -0.3901402950286865 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.468995426072672e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.8239827156066895, + 6.8239827156066895 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.0737815167888134e-06, + "threshold": [ + 141, + 141 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.803318465416517e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.5232798946145775e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.589424823405772e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -79.55714416503906, + -79.55714416503906 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.018095693164365e-12, + "shift_limit_x": [ + 0.3835117816925049, + 0.3835117816925049 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.5013971713610843, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.29124706983566284, + -0.29124706983566284 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.090935986485877e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.832881927490234, + 8.832881927490234 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.241767376070879e-06, + "max_holes": 16, + "max_height": 142, + "max_width": 142, + "min_holes": 16, + "min_height": 142, + "min_width": 142, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.230709362394942e-13, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.49858363610284484 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.6426250765041805e-12, + "r_shift_limit": [ + -119, + -119 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.004048780571696664, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00022118774359114468, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 234, + 234 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.1926361303392038e-05, + "brightness_limit": [ + -0.47353988885879517, + -0.47353988885879517 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.867875114748097e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 4.203094959259033, + 4.203094959259033 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.539912250013433e-07, + "threshold": [ + 184, + 184 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.5818539426988756e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.034646051248797e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9680459364234834e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1018290158948609e-11, + "shift_limit_x": [ + 0.755095362663269, + 0.755095362663269 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.7375330400287261, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.905456327363379e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.8909225463867188, + 3.8909225463867188 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.230188548921433e-07, + "max_holes": 16, + "max_height": 207, + "max_width": 207, + "min_holes": 16, + "min_height": 207, + "min_width": 207, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.331992275673107e-06, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.25817865593900624 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.001548714226925256, + "r_shift_limit": [ + 140, + 140 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.01684640534222126, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00522108708227545, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -48, + -48 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.01078731438264402, + "brightness_limit": [ + -0.01418071985244751, + -0.01418071985244751 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0023900497123213876, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.4409814080087813, + "threshold": [ + 242, + 242 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.056353746384469e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 159.62722778320312, + 159.62722778320312 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.7197995283060255e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.9241691827774048, + -0.9241691827774048 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.805973604744247e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.7398457527160645, + 5.7398457527160645 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.000525854102264682, + "max_holes": 16, + "max_height": 156, + "max_width": 156, + "min_holes": 16, + "min_height": 156, + "min_width": 156, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0542207570205268e-06, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5216972065055656 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.014926919641147562, + "r_shift_limit": [ + 29, + 29 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.101470028060152e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -105, + -105 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.005173396032756461, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 189, + 189 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0010221193664682743, + "brightness_limit": [ + -0.11933684349060059, + -0.11933684349060059 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.035689351436533734, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.7059803009033203, + 1.7059803009033203 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0029152882957992066, + "threshold": [ + 153, + 153 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.5141163254394478e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.567365465190236e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 139.20114135742188, + 139.20114135742188 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.00011185241865968587, + "shift_limit_x": [ + 0.0016826391220092773, + 0.0016826391220092773 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.42560825414359e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6494360566139221, + -0.6494360566139221 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.324591591500437e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9956756830215454, + 0.9956756830215454 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.80301113579915e-05, + "max_holes": 16, + "max_height": 212, + "max_width": 212, + "min_holes": 16, + "min_height": 212, + "min_width": 212, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.6045358492460053, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.3355560192491036 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + 10, + 10 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00041082375146569636, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 60, + 60 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00014188382192514837, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.290507939597067e-09, + "brightness_limit": [ + -0.20888501405715942, + -0.20888501405715942 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.6408314060970463e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 246, + 246 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 7.036175319687702e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.983643399535592e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.8631749607301663e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -83.93453979492188, + -83.93453979492188 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.516826940674628e-11, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.5196561222646173e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.5904891490936279, + 0.5904891490936279 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.847711270229411e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.870820999145508, + 4.870820999145508 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.769557773056464e-06, + "max_holes": 16, + "max_height": 194, + "max_width": 194, + "min_holes": 16, + "min_height": 194, + "min_width": 194, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.876645015579282e-09, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9994220562126288 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.2274319412548887e-10, + "r_shift_limit": [ + -143, + -143 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.495053014686056e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 93, + 93 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5878865229193613e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 86, + 86 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.533196348693705e-10, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.9913455846524103e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.585982775923456e-13, + "threshold": [ + 98, + 98 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.3009263286101913e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.1099917213486405e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.448357744922913e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 4.0191497802734375, + 4.0191497802734375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.9443672433626773, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.396968039280197e-16, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6695092916488647, + -0.6695092916488647 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.116060291938102e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.855262756347656, + 7.855262756347656 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.75171693896006e-07, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.7048816043177137e-09, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.05563220633301891 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00913655012845993, + "r_shift_limit": [ + 102, + 102 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.030236002176327048, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 67, + 67 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.059831836297425056, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 69, + 69 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.05722688710689883, + "brightness_limit": [ + -0.21764612197875977, + -0.21764612197875977 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.770152646711508e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 9.12096303977444e-06, + "threshold": [ + 212, + 212 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 7.081622985107548e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 10.238265991210938, + 10.238265991210938 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.009478372302276e-11, + "shift_limit_x": [ + 0.004080533981323242, + 0.004080533981323242 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.4436655624154146e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.9410802125930786, + 0.9410802125930786 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.299130143508044e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.426084995269775, + 7.426084995269775 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 112, + "max_width": 112, + "min_holes": 16, + "min_height": 112, + "min_width": 112, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.3482327846757979e-05, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8435390300901132 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00014249823288992047, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.988940212554227e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 73, + 73 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0002331221828169791, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -46, + -46 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.152756774385908e-06, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.1215110308911358e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0001604984748253286, + "threshold": [ + 227, + 227 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.3206356925935375e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.7742880892699684e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0004238313391929649, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 1.1249237060546875, + 1.1249237060546875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.1369239711077626e-09, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8370623588562012, + -0.8370623588562012 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.903326660698406e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.766495704650879, + 7.766495704650879 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 168, + "max_width": 168, + "min_holes": 16, + "min_height": 168, + "min_width": 168, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0007566856709959394, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9982748483129023 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0005059759132564068, + "r_shift_limit": [ + -63, + -63 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00034431913882560297, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -76, + -76 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0019436977062045335, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 105, + 105 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.6266780953182208e-08, + "brightness_limit": [ + -0.14522814750671387, + -0.14522814750671387 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.6032659778887703e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 3.6557860374450684, + 3.6557860374450684 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.5816603198091935e-08, + "threshold": [ + 124, + 124 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.7190036236631387e-05 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.849768614317524e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 7.984405517578125, + 7.984405517578125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.905135071871084e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.00032460689544677734, + 0.00032460689544677734 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 2.959704875946045, + 2.959704875946045 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.15210091753585e-08, + "max_holes": 16, + "max_height": 139, + "max_width": 139, + "min_holes": 16, + "min_height": 139, + "min_width": 139, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.219518890825414e-07, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9971692504807778 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.06517105851803517, + "r_shift_limit": [ + -60, + -60 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1622400056248035e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 30, + 30 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -23, + -23 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.5153770842832879e-05, + "brightness_limit": [ + -0.14043009281158447, + -0.14043009281158447 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0012616365261130386, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.161137580871582, + 1.161137580871582 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.192160735981985e-05, + "threshold": [ + 141, + 141 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 8.907013547920999e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.2309222645936062e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.509124755859375, + 0.509124755859375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.060012035499966e-06, + "shift_limit_x": [ + -0.012537777423858643, + -0.012537777423858643 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.016465936636407e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.846000075340271, + 0.846000075340271 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.946949398367538e-08, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0083330861571002e-06, + "max_holes": 15, + "max_height": 14, + "max_width": 14, + "min_holes": 15, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9335129093901651 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.99586391978652e-06, + "r_shift_limit": [ + 103, + 103 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.6037481266023665e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 63, + 63 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.2172302419352968e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -53, + -53 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0.11731076240539551, + 0.11731076240539551 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0009273637309970828, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.966535747051239, + 0.966535747051239 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 93, + 93 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.8952370054651285e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.3761466165462218e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.5257334846822615e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -70.2061996459961, + -70.2061996459961 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.859655610422448e-10, + "shift_limit_x": [ + 0.6731040477752686, + 0.6731040477752686 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.5849645137786865, + 0.5849645137786865 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 10.0, + 10.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0001615309883605115, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.001151693942393478, + "max_holes": 13, + "max_height": 14, + "max_width": 14, + "min_holes": 13, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9977471320901731 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.008381355807979052, + "r_shift_limit": [ + 162, + 162 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.037375130559169634, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 26, + 26 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.3443706090329215e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -31, + -31 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.762940200124218e-06, + "brightness_limit": [ + -0.14533334970474243, + -0.14533334970474243 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.0584199984573603e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 180, + 180 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2161741295933076e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 8.16607666015625, + 8.16607666015625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.6652538776397705, + 0.6652538776397705 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.1009942687786653e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.5485676527023315, + -0.5485676527023315 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0681251512470205e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.731809616088867, + 7.731809616088867 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.110974863715642e-08, + "max_holes": 16, + "max_height": 120, + "max_width": 120, + "min_holes": 16, + "min_height": 120, + "min_width": 120, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.4487452646881008e-05, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9542226296186722 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.317272382137901e-06, + "r_shift_limit": [ + -216, + -216 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.003600538555514e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -189, + -189 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.127130724456985e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -135, + -135 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.249167080836472e-12, + "brightness_limit": [ + 0.03016972541809082, + 0.03016972541809082 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.575798997227149e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 2.21125864982605, + 2.21125864982605 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.557448955923787e-07, + "threshold": [ + 163, + 163 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.7723420527157145 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.111590948277259e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -97.48252868652344, + -97.48252868652344 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.064910084806614e-09, + "shift_limit_x": [ + 0.8991886377334595, + 0.8991886377334595 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.47739148139953613, + -0.47739148139953613 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.770152921889978e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0062919855117798, + 1.0062919855117798 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1052162825196534e-08, + "max_holes": 16, + "max_height": 167, + "max_width": 167, + "min_holes": 16, + "min_height": 167, + "min_width": 167, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.6756176846630128e-08, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.22764786072482646 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.714352268630821e-08, + "r_shift_limit": [ + -155, + -155 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5092678441971265e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.448255804817866e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -89, + -89 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.639955556165859e-09, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.2785708683395746e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.7622281312942505, + 1.7622281312942505 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.3262798270839903e-10, + "threshold": [ + 148, + 148 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.3581144123407156e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.7212731789059426e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2955523514890726e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 38.674346923828125, + 38.674346923828125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.1641719133642853e-14, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.8779655998738178, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.018152236938476562, + -0.018152236938476562 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.260171180536123e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.769003391265869, + 6.769003391265869 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.5036152412368489e-05, + "max_holes": 16, + "max_height": 192, + "max_width": 192, + "min_holes": 16, + "min_height": 192, + "min_width": 192, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.056466176535462e-11, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.12201869260851606 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0017866607522591949, + "r_shift_limit": [ + 58, + 58 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.1977931508409765e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 72, + 72 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.530324694055924e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 46, + 46 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.790707187005122e-10, + "brightness_limit": [ + -0.2863624691963196, + -0.2863624691963196 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.383816744467528e-13, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 8.184784889221191, + 8.184784889221191 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.2640711805714572e-10, + "threshold": [ + 178, + 178 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.790864567756879e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 9.896279149673282e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.17800213072644766, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -7.7600555419921875, + -7.7600555419921875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3901136731499218e-08, + "shift_limit_x": [ + -0.6545312404632568, + -0.6545312404632568 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.595344969232696e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8644506335258484, + -0.8644506335258484 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.723937757856293e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.5600366592407227, + 3.5600366592407227 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.7776840308331163e-06, + "max_holes": 16, + "max_height": 172, + "max_width": 172, + "min_holes": 16, + "min_height": 172, + "min_width": 172, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.515863910074429e-09, + "max_holes": 2, + "max_height": 14, + "max_width": 14, + "min_holes": 2, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8202072531121634 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.282886984922523e-08, + "r_shift_limit": [ + 95, + 95 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00891876077855458, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -58, + -58 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.003846266138103488, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 28, + 28 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.966149373443954e-08, + "brightness_limit": [ + -0.30149322748184204, + -0.30149322748184204 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00012818921411666094, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.2047630354879023e-11, + "threshold": [ + 116, + 116 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.589336715980814e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.425608958429738e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.6056751362691095e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -6.3445892333984375, + -6.3445892333984375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.84399999488434e-07, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.30976104736328125, + 0.30976104736328125 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.4534451961517334, + 3.4534451961517334 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.02485219042721032, + "max_holes": 16, + "max_height": 93, + "max_width": 93, + "min_holes": 16, + "min_height": 93, + "min_width": 93, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.4064441634170919, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5558093672187421 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0011039384792419296, + "r_shift_limit": [ + 32, + 32 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.8888078927993774, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -40, + -40 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.023395735338513912, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -20, + -20 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.26741776324714e-07, + "brightness_limit": [ + 0.1899571418762207, + 0.1899571418762207 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.030792767659274967, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.0747801065444946, + 1.0747801065444946 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.309106034503355e-11, + "threshold": [ + 49, + 49 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.9990151365119426e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.12345852753044e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0001028294973170231, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -1.36785888671875, + -1.36785888671875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3381111745234511e-06, + "shift_limit_x": [ + -0.7564910650253296, + -0.7564910650253296 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.87359820936645e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.3269231915473938, + -0.3269231915473938 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4201008344431952e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.406876087188721, + 7.406876087188721 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00025411785085685534, + "max_holes": 16, + "max_height": 52, + "max_width": 52, + "min_holes": 16, + "min_height": 52, + "min_width": 52, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.43645763218521e-08, + "max_holes": 13, + "max_height": 14, + "max_width": 14, + "min_holes": 13, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.05554083288677314 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.010738446555613734, + "r_shift_limit": [ + -26, + -26 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.03647761891414136, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -3, + -3 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.05938664524308912, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 2, + 2 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.009753421880304813, + "brightness_limit": [ + 0.1001964807510376, + 0.1001964807510376 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.005201848765348904, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1685223579406738, + 1.1685223579406738 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.460210340424185e-10, + "threshold": [ + 197, + 197 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 29.245407104492188, + 29.245407104492188 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.747533901361709e-10, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.4955495490443697e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.1947302222251892, + -0.1947302222251892 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1858883161971456e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9851436614990234, + 0.9851436614990234 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.918510680243133e-05, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.416103751904012e-06, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8783602974210921 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.424528496580965e-05, + "r_shift_limit": [ + 29, + 29 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.9803522825241089, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 25, + 25 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -158, + -158 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.1244136932229128e-07, + "brightness_limit": [ + -0.09752380847930908, + -0.09752380847930908 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.078324299897502e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 8.867889404296875, + 8.867889404296875 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 8.33541285443645e-06, + "threshold": [ + 96, + 96 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.1713676471707264e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.586638983288126e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 39.70600891113281, + 39.70600891113281 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.7832352519035339, + -0.7832352519035339 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.801696728019662e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0038788914680480957, + -0.0038788914680480957 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.961458206176758, + 6.961458206176758 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.591736456467502e-07, + "max_holes": 16, + "max_height": 177, + "max_width": 177, + "min_holes": 16, + "min_height": 177, + "min_width": 177, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00010888043681276695, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.019471191282026123 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.268050869671906e-10, + "r_shift_limit": [ + 43, + 43 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0001823106392374596, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -16, + -16 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -55, + -55 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.615582077135809e-09, + "brightness_limit": [ + -0.24534833431243896, + -0.24534833431243896 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.530133247375488, + 6.530133247375488 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.742666311512161e-06, + "threshold": [ + 164, + 164 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 8.838793245040141e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.771028094116838e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.1798553466796875, + -0.1798553466796875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3641209605044042e-05, + "shift_limit_x": [ + 0.0017317533493041992, + 0.0017317533493041992 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.5794551372528076, + 0.5794551372528076 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9081673546978827e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9978127479553223, + 0.9978127479553223 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00046210932359743925, + "max_holes": 16, + "max_height": 120, + "max_width": 120, + "min_holes": 16, + "min_height": 120, + "min_width": 120, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0018630320679325352, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.997453029578713 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.015944632977312967, + "r_shift_limit": [ + -38, + -38 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.06198294460773468, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -9, + -9 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.339487892529587e-09, + "brightness_limit": [ + 0.13387739658355713, + 0.13387739658355713 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.090821613522995e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.529181718826294, + 1.529181718826294 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.148708724300001e-09, + "threshold": [ + 2, + 2 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.0466781744264608e-05 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.535440106875289e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -177.6691131591797, + -177.6691131591797 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7974185219333182e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0006302595138549805, + -0.0006302595138549805 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3417157990635506e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 2.421030044555664, + 2.421030044555664 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0184482092480895e-05, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.018187983510053e-06, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9220260617271872 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.5976684214130737e-09, + "r_shift_limit": [ + 135, + 135 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.943069651470015e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 90, + 90 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.167308746881665e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -57, + -57 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.904759592419712e-07, + "brightness_limit": [ + 0.47589361667633057, + 0.47589361667633057 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2375528702372168e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.522657538935486e-12, + "threshold": [ + 7, + 7 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.166024486091881e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.1551562645586777e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2213756952761978e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -135.0050048828125, + -135.0050048828125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.30145669515057705, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2383716197843407e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.4539520740509033, + 0.4539520740509033 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.394414712817719e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.99999993922529e-09, + 9.99999993922529e-09 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.028576266311808e-08, + "max_holes": 16, + "max_height": 130, + "max_width": 130, + "min_holes": 16, + "min_height": 130, + "min_width": 130, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1821713689511392e-14, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6985408810552943 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.97808572851788e-08, + "r_shift_limit": [ + 82, + 82 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0010609568326998692, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -56, + -56 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.001167235241828525, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 62, + 62 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.006201017347782917, + "brightness_limit": [ + 0.17783117294311523, + 0.17783117294311523 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00027139892701537327, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.5504051446914673, + 1.5504051446914673 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 236, + 236 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.224525591951014e-05 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.147547025399696, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 5.0226593017578125, + 5.0226593017578125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.8923933477387787e-11, + "shift_limit_x": [ + 0.02010929584503174, + 0.02010929584503174 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0889657012040454e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.960472583770752, + 0.960472583770752 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.707468471081197e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9932225942611694, + 0.9932225942611694 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1065326192905901e-07, + "max_holes": 16, + "max_height": 102, + "max_width": 102, + "min_holes": 16, + "min_height": 102, + "min_width": 102, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.092015034250045e-06, + "max_holes": 15, + "max_height": 14, + "max_width": 14, + "min_holes": 15, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.843728857747337 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.402869676947837e-06, + "r_shift_limit": [ + 159, + 159 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.9993765500481864e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -171, + -171 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.575498400457054e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 81, + 81 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.571563305685753e-11, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.940754145834944e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.1149608203044605e-07, + "threshold": [ + 1, + 1 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.9435649858011459 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.939942658857976e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0959838079357473e-13, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9657531878344575e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.029906868934631348, + 0.029906868934631348 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.3909725335994497e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 10.0, + 10.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.511977249958844e-09, + "max_holes": 16, + "max_height": 204, + "max_width": 204, + "min_holes": 16, + "min_height": 204, + "min_width": 204, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.322776266520067e-07, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.056427602218845574 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.278889581001033e-11, + "r_shift_limit": [ + -84, + -84 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0025490887481312e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -163, + -163 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.373546179606176e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.5584911074707206e-14, + "brightness_limit": [ + -0.40790408849716187, + -0.40790408849716187 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2989265087526292e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 9.81441714229692e-13, + "threshold": [ + 222, + 222 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.322057974277446e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.4720896863285944 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.83511799557817e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.9692535400390625, + -0.9692535400390625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.228186437315617e-11, + "shift_limit_x": [ + -0.0011623501777648926, + -0.0011623501777648926 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.148350150631219e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.718000411987305, + 8.718000411987305 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.067651601981501e-13, + "max_holes": 16, + "max_height": 200, + "max_width": 200, + "min_holes": 16, + "min_height": 200, + "min_width": 200, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.5690264122425618e-10, + "max_holes": 15, + "max_height": 14, + "max_width": 14, + "min_holes": 15, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5278972146637875 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1326085960666506e-11, + "r_shift_limit": [ + 64, + 64 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.410722710878411e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 97, + 97 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.6451043113457482e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -127, + -127 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.181239283719424e-07, + "brightness_limit": [ + -0.37551480531692505, + -0.37551480531692505 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.209275947456896e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 8.137649536132812, + 8.137649536132812 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 8.208249946891464e-13, + "threshold": [ + 197, + 197 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.9059529789347334e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.737365204558223e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.1181991429690625e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -93.60671997070312, + -93.60671997070312 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.671972006093017e-12, + "shift_limit_x": [ + 0.13015484809875488, + 0.13015484809875488 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.1695914449742162, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -1.0, + -1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.999544669358686e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.4851861000061035, + 6.4851861000061035 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 199, + "max_width": 199, + "min_holes": 16, + "min_height": 199, + "min_width": 199, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8304082152199839 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.211409513225351e-12, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.00149414957568e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -247, + -247 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.1939738839620826e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -221, + -221 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.046566120391238e-10, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.5236648180508224e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 3.113809585571289, + 3.113809585571289 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.04170085862278938, + "threshold": [ + 26, + 26 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.0113963739805255e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 8.47676710691303e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5234092162383276e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -3.3250274658203125, + -3.3250274658203125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5636761324293786e-10, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.9582896828651428, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -1.0, + -1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.452592182831118e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.603158950805664, + 5.603158950805664 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.328110380375885e-10, + "max_holes": 16, + "max_height": 122, + "max_width": 122, + "min_holes": 16, + "min_height": 122, + "min_width": 122, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.6732102452586763e-10, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 8.174979292396856e-07 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.005224951860429261, + "r_shift_limit": [ + -23, + -23 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.6495583346845007e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.2868563068138203e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 95, + 95 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.789058959574078e-05, + "brightness_limit": [ + 0.43627142906188965, + 0.43627142906188965 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.250199497077021e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.0823803677340038e-05, + "threshold": [ + 143, + 143 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.52369321163744e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.725806847977033e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.4594218085773e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -164.74212646484375, + -164.74212646484375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.022403717041015625, + 0.022403717041015625 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.19622719287872314, + 0.19622719287872314 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.975626953988482e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.787587642669678, + 7.787587642669678 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0001454815695287907, + "max_holes": 16, + "max_height": 205, + "max_width": 205, + "min_holes": 16, + "min_height": 205, + "min_width": 205, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.23789143562316895, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7566741760274027 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.04557354551192283, + "r_shift_limit": [ + 80, + 80 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0011278186899783549, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.6457706210012447e-05, + "brightness_limit": [ + -0.19019001722335815, + -0.19019001722335815 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.3821584508045116e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.3430671691894531, + 0.3430671691894531 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.47074204683303833, + "threshold": [ + 232, + 232 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.088708668638434e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 156.80987548828125, + 156.80987548828125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.75609787328432e-11, + "shift_limit_x": [ + 0.6336385011672974, + 0.6336385011672974 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8089025020599365, + -0.8089025020599365 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.774538959136176e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.710808753967285, + 5.710808753967285 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0003971368381925945, + "max_holes": 16, + "max_height": 172, + "max_width": 172, + "min_holes": 16, + "min_height": 172, + "min_width": 172, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 7, + "max_height": 14, + "max_width": 14, + "min_holes": 7, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.4821405465330204 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -180, + -180 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.234527742299611e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 16, + 16 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.5783452963406535e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.6983950238312952e-12, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.3169518059582545e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.864591360092163, + 1.864591360092163 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.2968629214734082e-05, + "threshold": [ + 175, + 175 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.71528269155408e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 148.21551513671875, + 148.21551513671875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.655037515979719e-10, + "shift_limit_x": [ + -0.9212983846664429, + -0.9212983846664429 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.2652574835925634, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -1.0, + -1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.035893685239626e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.814194679260254, + 6.814194679260254 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.048555610263054e-06, + "max_holes": 16, + "max_height": 160, + "max_width": 160, + "min_holes": 16, + "min_height": 160, + "min_width": 160, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.752990158434539e-13, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7346803307896809 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.564500804557405e-08, + "r_shift_limit": [ + -60, + -60 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.02022092416882515, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.004960235436673344, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 197, + 197 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + -0.3643009066581726, + -0.3643009066581726 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00027855850428402766, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 192, + 192 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.5992695090642656e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.839006663617703e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.868549230057086e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -119.65447235107422, + -119.65447235107422 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.757787976691593e-10, + "shift_limit_x": [ + 0.0010951757431030273, + 0.0010951757431030273 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.8164106852260226e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.006735622882843018, + -0.006735622882843018 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.9817501528120403e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.099548816680908, + 3.099548816680908 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.583563915133015e-06, + "max_holes": 16, + "max_height": 156, + "max_width": 156, + "min_holes": 16, + "min_height": 156, + "min_width": 156, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.451384417271584e-08, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9745313746632482 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.7132770382312604e-09, + "r_shift_limit": [ + -180, + -180 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.654243808298055e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -49, + -49 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.4831222906720107e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 254, + 254 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.033394178972933e-05, + "brightness_limit": [ + -0.9615594744682312, + -0.9615594744682312 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.008574032979659e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.4847196662997778e-06, + "threshold": [ + 223, + 223 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.2653194922540206e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.8056253771499939 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.491609441290715e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -121.26683044433594, + -121.26683044433594 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.554353887821455e-12, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.810425878600773e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.05111575126647949, + 0.05111575126647949 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5229519042820616e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.277960777282715, + 8.277960777282715 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.538070516611028e-11, + "max_holes": 16, + "max_height": 18, + "max_width": 18, + "min_holes": 16, + "min_height": 18, + "min_width": 18, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.3117166664383475e-07, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.194339015989058 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0030349087158213495, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.000493967701757983, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -103, + -103 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.434393547464216e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 81, + 81 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.780303415938448e-11, + "brightness_limit": [ + 0.24730825424194336, + 0.24730825424194336 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.384396216975048e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 3.314882278442383, + 3.314882278442383 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.165312833785944e-05, + "threshold": [ + 40, + 40 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.111934318478186e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.4038915932609965e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.756049873116929e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -128.44264221191406, + -128.44264221191406 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.12882057342046238, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.710493226186941e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.742919921875, + 0.742919921875 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.5678124823752965e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.876371383666992, + 4.876371383666992 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.8534094829231064e-05, + "max_holes": 16, + "max_height": 143, + "max_width": 143, + "min_holes": 16, + "min_height": 143, + "min_width": 143, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0001701940972875654, + "max_holes": 15, + "max_height": 14, + "max_width": 14, + "min_holes": 15, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8673999266170394 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.008031433239056085, + "r_shift_limit": [ + -77, + -77 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0003157507447153693, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0011520048083200618, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 73, + 73 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.584283404463849e-06, + "brightness_limit": [ + -1.0, + -1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.05229401809234e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.3081140518188477, + 1.3081140518188477 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.662822531855516e-06, + "threshold": [ + 131, + 131 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 8.54668139121254e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.943760039581715e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 4.752532958984375, + 4.752532958984375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5234566455128436e-09, + "shift_limit_x": [ + 0.0010138750076293945, + 0.0010138750076293945 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.8812474434537413e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.5699881315231323, + -0.5699881315231323 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.00025938750505936567, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.99999993922529e-09, + 9.99999993922529e-09 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00033036296818254873, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9899018680957317 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00426512555198677, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.002166051481315337, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.801902700762726e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -255, + -255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.565561190349369e-05, + "brightness_limit": [ + 0.47299933433532715, + 0.47299933433532715 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0006398025150111813, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2690770626068115, + 1.2690770626068115 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.004467241127883881, + "threshold": [ + 208, + 208 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.5220998394495366e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.253444417114205e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.584549108791189e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.591274823478522e-08, + "shift_limit_x": [ + 0.3098357915878296, + 0.3098357915878296 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.3632031768110596e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.3580058813095093, + -0.3580058813095093 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0008908110619797183, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.052532196044922, + 6.052532196044922 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0007096787130154922, + "max_holes": 16, + "max_height": 191, + "max_width": 191, + "min_holes": 16, + "min_height": 191, + "min_width": 191, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9867950135832038 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.845882608535049e-13, + "r_shift_limit": [ + -170, + -170 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5633891437391291e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 53, + 53 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.541126194799867e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -210, + -210 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.915714527023959e-09, + "brightness_limit": [ + 0.6339565515518188, + 0.6339565515518188 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.603496421714757e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 9.061256408691406, + 9.061256408691406 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 8.096617654915249e-07, + "threshold": [ + 141, + 141 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.660344747852274e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.025453484998376e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.24531192369786936, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -4.9124298095703125, + -4.9124298095703125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.5693296611978597e-11, + "shift_limit_x": [ + 0.0034705400466918945, + 0.0034705400466918945 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.907618780679811e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0033982396125793457, + -0.0033982396125793457 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.0506267507629e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.673539161682129, + 6.673539161682129 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.260945921389938e-09, + "max_holes": 16, + "max_height": 161, + "max_width": 161, + "min_holes": 16, + "min_height": 161, + "min_width": 161, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.050921983601934e-12, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.754687156693334 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.215117531403302e-11, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.376285345740938e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 9, + 9 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.0085013948378205e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -63, + -63 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.877746672408151e-06, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 5.175235271453857, + 5.175235271453857 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.712995727637227e-07, + "threshold": [ + 100, + 100 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.2407454978699176e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.1211848079856092e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -48.50837707519531, + -48.50837707519531 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.5642631121565446e-06, + "shift_limit_x": [ + 0.0026952028274536133, + 0.0026952028274536133 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.6458889164960482, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0331578254699707, + 0.0331578254699707 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.105619882709431e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0024584531784058, + 1.0024584531784058 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.274917611121761e-11, + "max_holes": 16, + "max_height": 197, + "max_width": 197, + "min_holes": 16, + "min_height": 197, + "min_width": 197, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.6919102317007518e-06, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.3540993929727615 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0006916196716599821, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.04829453011568452, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -72, + -72 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5964018057805317e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -58, + -58 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2255696994689937e-08, + "brightness_limit": [ + 0.3108394145965576, + 0.3108394145965576 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.554685566563657e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.7287561893463135, + 0.7287561893463135 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.4168703303371056e-06, + "threshold": [ + 170, + 170 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.511537393119341e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3367122154094572e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -143.45834350585938, + -143.45834350585938 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.8324544429779053, + -0.8324544429779053 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.2856936454772949, + -0.2856936454772949 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.780176394419719e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.875234603881836, + 8.875234603881836 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.042874572307277e-05, + "max_holes": 16, + "max_height": 135, + "max_width": 135, + "min_holes": 16, + "min_height": 135, + "min_width": 135, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0008033348863042411, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.950176698715667 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.004095836322301594, + "r_shift_limit": [ + -85, + -85 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.058908966818469e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.8732679342812144e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 47, + 47 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.3964954423883846e-09, + "brightness_limit": [ + 0.27684855461120605, + 0.27684855461120605 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0011187777389273235, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.8378657698631287, + 0.8378657698631287 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.27671389787159e-10, + "threshold": [ + 12, + 12 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.961044016240383e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.0805825992549526e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.168059433367269e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 3.8511199951171875, + 3.8511199951171875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.931840033187391e-09, + "shift_limit_x": [ + 0.0003129243850708008, + 0.0003129243850708008 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.849175214767456, + -0.849175214767456 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0066456608566963e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.288748264312744, + 5.288748264312744 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.7474727804535377e-05, + "max_holes": 16, + "max_height": 178, + "max_width": 178, + "min_holes": 16, + "min_height": 178, + "min_width": 178, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.004438166281344191, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9902871357723593 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.027044531588831466, + "r_shift_limit": [ + 57, + 57 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.04421549379699985, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -16, + -16 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.18189940035948737, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -66, + -66 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0037937689046629863, + "brightness_limit": [ + 0.2235884666442871, + 0.2235884666442871 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.556296292316362e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.111791197312615e-11, + "threshold": [ + 68, + 68 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.695559314093695e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.374371586332042e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.8470088550860923e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -62.33941650390625, + -62.33941650390625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.064778708429183e-07, + "shift_limit_x": [ + -0.9297978281974792, + -0.9297978281974792 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.3490636348724365, + 0.3490636348724365 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.67866517033155e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.146727561950684, + 4.146727561950684 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.017930328583157795, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.016331011492293546, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7087842777850364 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0001763983886506476, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.346887839619214e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -43, + -43 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.02747253922963111, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 18, + 18 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.7710334245221444e-05, + "brightness_limit": [ + -0.0766669511795044, + -0.0766669511795044 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.012209475476151033, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.235635757446289, + 1.235635757446289 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.131056388746441e-08, + "threshold": [ + 220, + 220 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.552563235414874e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 9.983977177078552e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.25480177519043e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -112.51652526855469, + -112.51652526855469 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.756874310968454e-10, + "shift_limit_x": [ + 0.8433232307434082, + 0.8433232307434082 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0930025844612645e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.4285769462585449, + 0.4285769462585449 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.489561080932617, + 7.489561080932617 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00018808399190074765, + "max_holes": 16, + "max_height": 62, + "max_width": 62, + "min_holes": 16, + "min_height": 62, + "min_width": 62, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.007522429999579083, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9524131609256244 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0021693518715169557, + "r_shift_limit": [ + 127, + 127 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 123, + 123 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.3661388328451747e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -33, + -33 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.001684136202306022, + "brightness_limit": [ + -0.07973092794418335, + -0.07973092794418335 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.1789018788526605e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.0235164165496826, + 1.0235164165496826 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.597434919739702e-08, + "threshold": [ + 30, + 30 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 7.691228386661247e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.2169372802075934e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.70046337656061e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -108.49107360839844, + -108.49107360839844 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.464195932245678e-07, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.760059177612305e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.44796305894851685, + -0.44796305894851685 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.1876007318496704, + 1.1876007318496704 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.643004420922046e-07, + "max_holes": 16, + "max_height": 129, + "max_width": 129, + "min_holes": 16, + "min_height": 129, + "min_width": 129, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.301761894551565e-08, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9961449745079705 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.100819921794787e-06, + "r_shift_limit": [ + 17, + 17 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.729218575131536e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -57, + -57 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.69722124157545e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -52, + -52 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.065490372271087e-07, + "brightness_limit": [ + 0.4050905704498291, + 0.4050905704498291 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.8216874040836466e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1817011833190918, + 1.1817011833190918 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.2016281557218546e-12, + "threshold": [ + 201, + 201 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 9.431807720605635e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.628881876667664e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.701582045985882e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 36.38459777832031, + 36.38459777832031 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.5445297109286571, + "shift_limit_x": [ + -0.012952625751495361, + -0.012952625751495361 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.300232005786689e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8900346755981445, + -0.8900346755981445 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0174453020587059e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.353939056396484, + 4.353939056396484 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.715607502776117e-10, + "max_holes": 16, + "max_height": 193, + "max_width": 193, + "min_holes": 16, + "min_height": 193, + "min_width": 193, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.7628088719527625e-11, + "max_holes": 7, + "max_height": 14, + "max_width": 14, + "min_holes": 7, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.45540896199183056 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.804055669618251e-07, + "r_shift_limit": [ + -38, + -38 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.000010742854736e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -119, + -119 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4584561371778897e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -255, + -255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.0586283129613585e-14, + "brightness_limit": [ + -0.19978773593902588, + -0.19978773593902588 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.8371407882989384e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.3148716057406086e-13, + "threshold": [ + 178, + 178 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.7734291702639666 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0199850943175284e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 75.953857421875, + 75.953857421875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.7343398916551875e-07, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.465406353877089e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6161322593688965, + -0.6161322593688965 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.477727963566971e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.177037715911865, + 5.177037715911865 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.190997545163169e-11, + "max_holes": 16, + "max_height": 123, + "max_width": 123, + "min_holes": 16, + "min_height": 123, + "min_width": 123, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.49902439723096e-14, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.22656981048674263 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.902006241443676e-09, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.5048839374597526e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -67, + -67 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 12, + 12 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0004096816770120526, + "brightness_limit": [ + 0.3226989507675171, + 0.3226989507675171 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.1686565945314049e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.2128877099543007e-09, + "threshold": [ + 13, + 13 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.9139075006052134e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.097004122060057e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.198455810546875, + 0.198455810546875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1321274937113618e-08, + "shift_limit_x": [ + -0.4171692132949829, + -0.4171692132949829 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4526050267352946e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9090828824091596e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9908493757247925, + 0.9908493757247925 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.758465466210188e-06, + "max_holes": 16, + "max_height": 198, + "max_width": 198, + "min_holes": 16, + "min_height": 198, + "min_width": 198, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.144892644480195e-06, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9995736834395439 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.232251145838329e-05, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.644078943689809e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -50, + -50 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -200, + -200 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00633692053459034, + "brightness_limit": [ + -0.10366028547286987, + -0.10366028547286987 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.03407955352571923, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.276656150817871, + 1.276656150817871 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.867185673940516e-09, + "threshold": [ + 127, + 127 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 7.514228757446126e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.64896248219974e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 1.5213470458984375, + 1.5213470458984375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.8670553207154737e-12, + "shift_limit_x": [ + 0.8568977117538452, + 0.8568977117538452 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.796328226247071e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.39935022592544556, + -0.39935022592544556 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.6844902020468973e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9996740818023682, + 0.9996740818023682 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.005183472215491536, + "max_holes": 16, + "max_height": 160, + "max_width": 160, + "min_holes": 16, + "min_height": 160, + "min_width": 160, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0172816981813968, + "max_holes": 2, + "max_height": 14, + "max_width": 14, + "min_holes": 2, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9370386703786069 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.2714332722528225e-06, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0010810193671407023, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -51, + -51 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.02067624330055806, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 0, + 0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.9422396418369707e-08, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.5113461017608643, + 1.5113461017608643 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.084464559182889e-06, + "threshold": [ + 172, + 172 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.126964942447915e-15 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.313464539941419e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.1604461669921875, + -0.1604461669921875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.710338418143368e-07, + "shift_limit_x": [ + -0.702006995677948, + -0.702006995677948 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.7151907682418823, + 0.7151907682418823 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.489201734706192e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.55807876586914, + 9.55807876586914 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0192028658485971e-05, + "max_holes": 16, + "max_height": 42, + "max_width": 42, + "min_holes": 16, + "min_height": 42, + "min_width": 42, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.416641206583021e-05, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9781931745108374 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.2581764458605e-06, + "r_shift_limit": [ + 114, + 114 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1990278533360681e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.081284295347177e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -61, + -61 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.423429206270671e-07, + "brightness_limit": [ + 0.3130606412887573, + 0.3130606412887573 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.627944006818297e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.0109663413513356e-08, + "threshold": [ + 76, + 76 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 8.601194925612632e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.492808783083572e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.0767364501953125, + 0.0767364501953125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5438310188609814e-11, + "shift_limit_x": [ + 0.0006906986236572266, + 0.0006906986236572266 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.8816055490464052, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.016312003135681152, + -0.016312003135681152 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.1380314986882525e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.114367485046387, + 8.114367485046387 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1398373937661168e-08, + "max_holes": 16, + "max_height": 175, + "max_width": 175, + "min_holes": 16, + "min_height": 175, + "min_width": 175, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.1386728733467807e-08, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.11829939352315877 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0013581789757020624, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.824374354700448e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -27, + -27 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.0558034074052664e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.004710078902896431, + "brightness_limit": [ + -0.0957798957824707, + -0.0957798957824707 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.8686321955717796e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 2.1185789108276367, + 2.1185789108276367 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.000158416438168843, + "threshold": [ + 160, + 160 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 9.21583937582011e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.856004580995346e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 180.0, + 180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.4322693071308095e-08, + "shift_limit_x": [ + -0.6371574401855469, + -0.6371574401855469 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.013002381211584e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.001618027687072754, + 0.001618027687072754 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.6985728247021954e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.986514091491699, + 7.986514091491699 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.2097384286839297e-11, + "max_holes": 16, + "max_height": 143, + "max_width": 143, + "min_holes": 16, + "min_height": 143, + "min_width": 143, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.03751180708068724, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9561977929013996 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00034232196210512086, + "r_shift_limit": [ + -48, + -48 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.030418527573159e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 91, + 91 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.0605791595226797e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0005156436937711201, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00017638642649583404, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.3842404814225788e-10, + "threshold": [ + 19, + 19 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.0179148030483025e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.3700753992005547e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.4237473848185602e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.1088714599609375, + -0.1088714599609375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.470634673053894e-10, + "shift_limit_x": [ + -0.6480283737182617, + -0.6480283737182617 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.6745632886886597, + 0.6745632886886597 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.49520289071645074, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9880795478820801, + 0.9880795478820801 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.914385727111851e-07, + "max_holes": 16, + "max_height": 152, + "max_width": 152, + "min_holes": 16, + "min_height": 152, + "min_width": 152, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.767238045433428e-07, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5036455232640895 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.5667610149231863e-06, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.277481757980214e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 61, + 61 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.253890648050294e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 88, + 88 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.8104859279148677e-07, + "brightness_limit": [ + -0.36178290843963623, + -0.36178290843963623 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.65494771444752e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.062054599874407e-10, + "threshold": [ + 234, + 234 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.29603764746498484 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.400517530238946e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.384188744403424e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 166.44631958007812, + 166.44631958007812 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5733040661432392e-07, + "shift_limit_x": [ + 9.679794311523438e-05, + 9.679794311523438e-05 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.5575385306213177e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.433538556098938, + 0.433538556098938 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.58329220076739e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.552127838134766, + 8.552127838134766 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.761275656687717e-07, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.870112776958982e-08, + "max_holes": 13, + "max_height": 14, + "max_width": 14, + "min_holes": 13, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7039493190892483 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.982180844922492e-12, + "r_shift_limit": [ + -41, + -41 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.3606014963239926e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.759112135168587e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 8, + 8 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0029857902455038554, + "brightness_limit": [ + 0.26430249214172363, + 0.26430249214172363 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.702737639192492e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.1196044134245526e-11, + "threshold": [ + 203, + 203 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.767766047074739e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.0188338077648033e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.408704701731505e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.5985870361328125, + -0.5985870361328125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.7366241216659546, + 0.7366241216659546 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.3971900969383171, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0832747220993042, + 0.0832747220993042 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.964591108377406e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0020699501037598, + 1.0020699501037598 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.217912364438709e-06, + "max_holes": 16, + "max_height": 197, + "max_width": 197, + "min_holes": 16, + "min_height": 197, + "min_width": 197, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.959422993938625e-10, + "max_holes": 2, + "max_height": 14, + "max_width": 14, + "min_holes": 2, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5997388989134684 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + 189, + 189 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.165004045513342e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 61, + 61 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.562823265268079e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -69, + -69 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.003351203909437994, + "brightness_limit": [ + 0.20557308197021484, + 0.20557308197021484 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.005781385239929104, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.3020262718200684, + 1.3020262718200684 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.595858255645242e-07, + "threshold": [ + 110, + 110 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.306498605411236e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5344478791473835e-10, + "shift_limit_x": [ + -0.011149764060974121, + -0.011149764060974121 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.41178417205810547, + 0.41178417205810547 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.5638174775676163e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.984514594078064, + 0.984514594078064 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.394325672928971e-08, + "max_holes": 16, + "max_height": 107, + "max_width": 107, + "min_holes": 16, + "min_height": 107, + "min_width": 107, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00015245321382468483, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9906656871962152 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.42775698441559484, + "r_shift_limit": [ + 1, + 1 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.7203947907284177e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -149, + -149 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 108, + 108 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.294023211336592e-08, + "brightness_limit": [ + -0.36461079120635986, + -0.36461079120635986 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.5097607510984071e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 5.718698978424072, + 5.718698978424072 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.897058499375801e-07, + "threshold": [ + 219, + 219 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.5107865295347542e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.271169811430206e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.656037834782657e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 2.0773162841796875, + 2.0773162841796875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.010999560356140137, + 0.010999560356140137 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3222797678395142e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.003280162811279297, + 0.003280162811279297 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.0803391126065293e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.114819526672363, + 5.114819526672363 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.2274979789619336e-08, + "max_holes": 16, + "max_height": 193, + "max_width": 193, + "min_holes": 16, + "min_height": 193, + "min_width": 193, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.2736147667242203e-08, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5722267908382404 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.722572210324131e-11, + "r_shift_limit": [ + -230, + -230 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.1906381728582057e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 82, + 82 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.10961106785598e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 80, + 80 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.045697374962281e-10, + "brightness_limit": [ + 0.4778100252151489, + 0.4778100252151489 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.7984219297330323e-13, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 7.463321208953857, + 7.463321208953857 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.98430419002294e-12, + "threshold": [ + 125, + 125 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.80661595324218e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.6267537647994565e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.5473319066371118, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -3.2136993408203125, + -3.2136993408203125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.9032911062240601, + -0.9032911062240601 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3416461361030903e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.4298556447029114, + -0.4298556447029114 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.929533713386056e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.378659248352051, + 7.378659248352051 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.576189698861274e-07, + "max_holes": 16, + "max_height": 119, + "max_width": 119, + "min_holes": 16, + "min_height": 119, + "min_width": 119, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.198104465349497e-11, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.4526678010779245 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.886245794671721e-08, + "r_shift_limit": [ + 28, + 28 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.2588358493645345e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.002588797219472541, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 33, + 33 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0005632941159233185, + "brightness_limit": [ + 0.5329434871673584, + 0.5329434871673584 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0071556651750834255, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.425194501876831, + 1.425194501876831 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.529034308188747e-09, + "threshold": [ + 34, + 34 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.276978702578211e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.527633639167908e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4974189809135418e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -78.81338500976562, + -78.81338500976562 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2459265762818122e-07, + "shift_limit_x": [ + -0.6305489540100098, + -0.6305489540100098 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.9397457022525795e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.004349112510681152, + 0.004349112510681152 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.594504341458967e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.820394515991211, + 4.820394515991211 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.548816332847772e-05, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.35120552718669096, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6384309742323842 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.088298016328758e-12, + "r_shift_limit": [ + -71, + -71 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.570689251205702e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 62, + 62 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.515628977801782e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -107, + -107 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.677837398175011e-07, + "brightness_limit": [ + -0.2504872679710388, + -0.2504872679710388 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.6255758017020048e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1378283500671387, + 1.1378283500671387 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.68163362897032e-07, + "threshold": [ + 55, + 55 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.7030225987310332e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.4800468261912707e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.343276066501577e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -116.44975280761719, + -116.44975280761719 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.5835155834068928, + "shift_limit_x": [ + -0.028813600540161133, + -0.028813600540161133 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.11209303140640259, + -0.11209303140640259 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.046918869018555, + 9.046918869018555 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.036004528984427e-07, + "max_holes": 16, + "max_height": 39, + "max_width": 39, + "min_holes": 16, + "min_height": 39, + "min_width": 39, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.203470998689486e-13, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.41648216009868855 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.7330192124025737e-08, + "r_shift_limit": [ + -110, + -110 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.23634026836276156, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 1, + 1 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.556149003403526e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.018651578575372696, + "brightness_limit": [ + 0.14056718349456787, + 0.14056718349456787 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.01644837818037226, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.0045692920684814, + 1.0045692920684814 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 8.647442006603424e-07, + "threshold": [ + 190, + 190 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.2735123493311007e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.675817682920028e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.674407958984375, + 0.674407958984375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.317683704314292e-08, + "shift_limit_x": [ + 0.9279991388320923, + 0.9279991388320923 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.8169154388487372e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -1.0, + -1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.38377395282879e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.99949711561203, + 0.99949711561203 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.424656092372726e-10, + "max_holes": 16, + "max_height": 131, + "max_width": 131, + "min_holes": 16, + "min_height": 131, + "min_width": 131, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.052724629325012984, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6757574015992005 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.12809218432342195, + "r_shift_limit": [ + -47, + -47 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1306862895368552e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 46, + 46 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.001759963951106086, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -45, + -45 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.252798654671425e-07, + "brightness_limit": [ + 0.2765101194381714, + 0.2765101194381714 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1318024396896362, + 1.1318024396896362 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.188036595073307e-05, + "threshold": [ + 186, + 186 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.638886662575635e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.7415682866410162e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.7932395597847248e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.0141448974609375, + 0.0141448974609375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.297650501606766e-09, + "shift_limit_x": [ + 0.00047338008880615234, + 0.00047338008880615234 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0969665970442919e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.5638489127159119, + -0.5638489127159119 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.1098201026750604e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.3002691864967346, + 0.3002691864967346 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.189985507244891e-09, + "max_holes": 16, + "max_height": 222, + "max_width": 222, + "min_holes": 16, + "min_height": 222, + "min_width": 222, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.17514983054492106, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6949768689540947 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.1414292529845753e-11, + "r_shift_limit": [ + -156, + -156 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.6042588632451332e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4493778375026497e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -73, + -73 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.040901988505455e-10, + "brightness_limit": [ + -0.28261780738830566, + -0.28261780738830566 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.653565157157663e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.0516245365142822, + 1.0516245365142822 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.910134894994128e-06, + "threshold": [ + 88, + 88 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.0377540104190375e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.2602462650332029, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -2.254791259765625, + -2.254791259765625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.9788525023877245e-07, + "shift_limit_x": [ + 0.9722554683685303, + 0.9722554683685303 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4143361803061863e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.005352020263671875, + -0.005352020263671875 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1149816678994724e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.63671875, + 9.63671875 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.2607069886982e-06, + "max_holes": 16, + "max_height": 111, + "max_width": 111, + "min_holes": 16, + "min_height": 111, + "min_width": 111, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.810571109368729e-14, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7397451979869817 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.3868920421112045e-05, + "r_shift_limit": [ + 131, + 131 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.3242793172943098e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -228, + -228 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.603429758558313e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -255, + -255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.4520743982227025e-11, + "brightness_limit": [ + 0.6689014434814453, + 0.6689014434814453 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 4.275632858276367, + 4.275632858276367 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.006737301126122475, + "threshold": [ + 92, + 92 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.6304255085240205e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.875390813062959e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5379502629259698e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.5841064453125, + 0.5841064453125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.8410681034653266e-10, + "shift_limit_x": [ + 0.9620062112808228, + 0.9620062112808228 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.8222299482691398, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.07224440574645996, + 0.07224440574645996 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.764590891082955e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.3704023361206055, + 5.3704023361206055 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.3707303810377376e-07, + "max_holes": 16, + "max_height": 58, + "max_width": 58, + "min_holes": 16, + "min_height": 58, + "min_width": 58, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.522550767693113e-13, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.17101853830447067 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.03909015457336862, + "r_shift_limit": [ + -39, + -39 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0026708823821428584, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00206336585497037, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -55, + -55 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0004541513518630941, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.0345213284316107e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.3668814768480885e-09, + "threshold": [ + 26, + 26 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.6816700138350327e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.0503267025805574e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 111.28317260742188, + 111.28317260742188 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.06644141674041748, + 0.06644141674041748 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.501362460220724e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -1.0, + -1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.735037220793769e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9878737330436707, + 0.9878737330436707 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.8118820743231777e-05, + "max_holes": 16, + "max_height": 43, + "max_width": 43, + "min_holes": 16, + "min_height": 43, + "min_width": 43, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.014205308897761837, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9414850563996618 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.8339248030654116e-15, + "r_shift_limit": [ + -57, + -57 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.672475875470774e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.4863892518773872e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 15, + 15 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.837342893492262e-09, + "brightness_limit": [ + -0.3948936462402344, + -0.3948936462402344 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.944009102594117e-13, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.5082511305809021, + 0.5082511305809021 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.065004583167047e-06, + "threshold": [ + 74, + 74 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.384606966701142e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.767354808794688e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.317004966440572e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 106.64447021484375, + 106.64447021484375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.46806315754667693, + "shift_limit_x": [ + 0.03709220886230469, + 0.03709220886230469 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.595752784227653e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.664459228515625, + -0.664459228515625 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.105399300196366e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.247203826904297, + 6.247203826904297 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.0621819573114542e-11, + "max_holes": 16, + "max_height": 195, + "max_width": 195, + "min_holes": 16, + "min_height": 195, + "min_width": 195, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.548579783827383e-08, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5319289648248964 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.004252667845705549, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.001778443957320297, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.9527807762973566e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -75, + -75 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0005046556730601073, + "brightness_limit": [ + -0.20065635442733765, + -0.20065635442733765 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.217167778996085e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.479070300577096e-09, + "threshold": [ + 169, + 169 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.441533293820453e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0020217152146805445 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.422530363518554, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 8.719253540039062, + 8.719253540039062 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.929409988014471e-12, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9909843218535173e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -1.0, + -1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 10.0, + 10.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0925048051974682e-10, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0004353623662609607, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5684546965732352 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0575367358412054e-05, + "r_shift_limit": [ + -171, + -171 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.9353607058292255e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.432248158141446e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -68, + -68 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.723027619691577e-11, + "brightness_limit": [ + 0.20120680332183838, + 0.20120680332183838 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 4.1875505447387695, + 4.1875505447387695 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.032558822699654e-12, + "threshold": [ + 155, + 155 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.405373577174432e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.2523643286184698e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.693601596244835e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.0199127197265625, + 0.0199127197265625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.6888366747293126, + "shift_limit_x": [ + 0.02576124668121338, + 0.02576124668121338 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.263671719860828e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.001611948013305664, + 0.001611948013305664 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.389550141539401e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.160516738891602, + 8.160516738891602 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.2579540685395572e-09, + "max_holes": 16, + "max_height": 90, + "max_width": 90, + "min_holes": 16, + "min_height": 90, + "min_width": 90, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.2649670896243919e-11, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.31109665438789147 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.07481906563043594, + "r_shift_limit": [ + -90, + -90 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.04115899838153636, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -56, + -56 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.07721561973063062, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -37, + -37 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.020285578755310674, + "brightness_limit": [ + -0.26198601722717285, + -0.26198601722717285 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.134054856342405e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.4257895946502686, + 1.4257895946502686 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 11, + 11 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.115468893199642e-05 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.041727118599738e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -2.4445648193359375, + -2.4445648193359375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.854691743850708, + 0.854691743850708 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.0962453839531974e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0001655128052834142, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.009828805923462, + 1.009828805923462 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.532378613948822, + "max_holes": 16, + "max_height": 201, + "max_width": 201, + "min_holes": 16, + "min_height": 201, + "min_width": 201, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.635744141507505e-05, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.2537567351979597 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.6826802944174844e-08, + "r_shift_limit": [ + 55, + 55 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.358635744725936e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 104, + 104 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.3071673203934138e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 202, + 202 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.005813415986007597, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.8536038994789124, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 2.6594197750091553, + 2.6594197750091553 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.1289988170972194, + "threshold": [ + 67, + 67 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 9.126686714958782e-05 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.054264204546477e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 180.0, + 180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.2270873377881486e-11, + "shift_limit_x": [ + 0.008837461471557617, + 0.008837461471557617 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.30902905744032e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.00048607587814331055, + -0.00048607587814331055 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7265772361319437e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.535273551940918, + 6.535273551940918 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 26, + "max_width": 26, + "min_holes": 16, + "min_height": 26, + "min_width": 26, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.387635569209664e-05, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.011446350772366776 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.0085257901314435e-09, + "r_shift_limit": [ + 18, + 18 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.9395072139028698e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -214, + -214 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00024967210593250175, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 170, + 170 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.5880156920558627e-08, + "brightness_limit": [ + -0.45264244079589844, + -0.45264244079589844 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00046046239852165147, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.2558587350722165e-12, + "threshold": [ + 43, + 43 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.737580090055419e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.841824386522607e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.30393458351600344, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -5.70367431640625, + -5.70367431640625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.603945415378213e-12, + "shift_limit_x": [ + 0.39523017406463623, + 0.39523017406463623 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.082938650790256e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.5393818616867065, + 0.5393818616867065 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.1989326641057996e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0331224203109741, + 1.0331224203109741 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.00658184271051e-13, + "max_holes": 16, + "max_height": 214, + "max_width": 214, + "min_holes": 16, + "min_height": 214, + "min_width": 214, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.8237917280286032e-10, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6953552423533753 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.138251833801534e-09, + "r_shift_limit": [ + -57, + -57 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.435857464430266e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0342492173289718e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -36, + -36 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0036828303709626198, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.096295302140384e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.229704737663269, + 1.229704737663269 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.252668626134608e-12, + "threshold": [ + 56, + 56 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.129169101577526e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.2994384765625, + -0.2994384765625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.717782947985433e-09, + "shift_limit_x": [ + 0.9209070205688477, + 0.9209070205688477 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.098448937724154e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6546100378036499, + -0.6546100378036499 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.8821163177490234, + 0.8821163177490234 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.4775800054030396e-05, + "max_holes": 16, + "max_height": 60, + "max_width": 60, + "min_holes": 16, + "min_height": 60, + "min_width": 60, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.2938674632863264e-08, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9962922016814633 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00859156768756697, + "r_shift_limit": [ + 62, + 62 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.02426004123230463, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 9, + 9 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -2, + -2 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00013571743300595102, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.011425210162997246, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.9756687879562378, + 0.9756687879562378 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0006903878865098523, + "threshold": [ + 83, + 83 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.525710489852235e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.0122502863847724e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.866433080089487e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 158.70904541015625, + 158.70904541015625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.7560072439582435e-09, + "shift_limit_x": [ + -0.6367702484130859, + -0.6367702484130859 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.8430558120622224e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.191385349933494e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.056117534637451, + 7.056117534637451 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.022879767129293738, + "max_holes": 16, + "max_height": 112, + "max_width": 112, + "min_holes": 16, + "min_height": 112, + "min_width": 112, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.5095524191856384, + "max_holes": 7, + "max_height": 14, + "max_width": 14, + "min_holes": 7, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.4224648446880652 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.8343358636244925e-06, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 44, + 44 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.568435819865446e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -111, + -111 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0010198979506500089, + "brightness_limit": [ + -1.0, + -1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.059875376228068e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.559318200758611e-11, + "threshold": [ + 190, + 190 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.86541038541453e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.5208968020153009, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 180.0, + 180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.461960243510913e-11, + "shift_limit_x": [ + 0.01123654842376709, + 0.01123654842376709 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0983399088196027e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.017115813079368e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.445459842681885, + 7.445459842681885 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0811567889036796e-05, + "max_holes": 16, + "max_height": 98, + "max_width": 98, + "min_holes": 16, + "min_height": 98, + "min_width": 98, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.8894078323766945e-05, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.4780007026424379 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.03418586597348e-12, + "r_shift_limit": [ + 56, + 56 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.304892756812918e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 11, + 11 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.752093177966609e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 98, + 98 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.4235421223357823e-12, + "brightness_limit": [ + -0.7244253158569336, + -0.7244253158569336 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.3270844552976901e-13, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.008533575477401e-13, + "threshold": [ + 54, + 54 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.6855283379554749 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.003777057701613e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.326809017475446e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 73.76901245117188, + 73.76901245117188 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.7936077160515522e-12, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.133767968397592e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.914821445941925, + -0.914821445941925 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.99999993922529e-09, + 9.99999993922529e-09 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.6096466120779755e-09, + "max_holes": 16, + "max_height": 169, + "max_width": 169, + "min_holes": 16, + "min_height": 169, + "min_width": 169, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1540299942794682e-12, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.31447165644752706 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.732793890072345e-07, + "r_shift_limit": [ + 87, + 87 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00369855565237609, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -21, + -21 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0023998337490034327, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -34, + -34 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.018544722576663286, + "brightness_limit": [ + 0.1084127426147461, + 0.1084127426147461 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.606453238076568e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 5.689282417297363, + 5.689282417297363 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 8.065756951225467e-09, + "threshold": [ + 238, + 238 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.115090537431843e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.899999863107454e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.0423583984375, + 0.0423583984375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.7611201405525208, + -0.7611201405525208 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.717413809949642e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.00046837329864501953, + 0.00046837329864501953 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 2.4467759132385254, + 2.4467759132385254 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.000522022430575822, + "max_holes": 16, + "max_height": 154, + "max_width": 154, + "min_holes": 16, + "min_height": 154, + "min_width": 154, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.9078149896352915e-09, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9748298684502352 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00016586177862903517, + "r_shift_limit": [ + 116, + 116 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.709988802279648e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -47, + -47 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0020767105743288994, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -32, + -32 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.03805364548003931, + "brightness_limit": [ + -0.17178159952163696, + -0.17178159952163696 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2048757932275201e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.7890569381506793e-07, + "threshold": [ + 180, + 180 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 8.155014377197754e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.758322937586777e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.834695807036597e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 2.4060516357421875, + 2.4060516357421875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.748211957513388e-07, + "shift_limit_x": [ + 0.013191938400268555, + 0.013191938400268555 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.4064539670944214, + 0.4064539670944214 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.611789692564086e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9125426411628723, + 0.9125426411628723 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.4491742190925076e-10, + "max_holes": 16, + "max_height": 111, + "max_width": 111, + "min_holes": 16, + "min_height": 111, + "min_width": 111, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.337002831377349e-10, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.959642700400668 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.9520585498547085e-08, + "r_shift_limit": [ + -174, + -174 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.736467291159435e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -30, + -30 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00033932576741500103, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -51, + -51 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0001450715834737798, + "brightness_limit": [ + -0.18670815229415894, + -0.18670815229415894 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.7949248540843355e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.752694129943848, + 6.752694129943848 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.1981362001814653e-12, + "threshold": [ + 149, + 149 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.998597791704526e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.661790842401471e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.27431206544339837, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -4.5012359619140625, + -4.5012359619140625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4194625867793823e-08, + "shift_limit_x": [ + 0.006016373634338379, + 0.006016373634338379 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.2177960269943063e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.5903817415237427, + -0.5903817415237427 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.143268585205078, + 4.143268585205078 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.718236239322916e-09, + "max_holes": 16, + "max_height": 164, + "max_width": 164, + "min_holes": 16, + "min_height": 164, + "min_width": 164, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.296603386461106e-07, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7251963969488391 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0004033669560694897, + "r_shift_limit": [ + -44, + -44 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.009842276129378158, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -36, + -36 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.461163113465971e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -45, + -45 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0006637546047075227, + "brightness_limit": [ + -0.15801745653152466, + -0.15801745653152466 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.051911777144813875, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2153507471084595, + 1.2153507471084595 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.003192884786819672, + "threshold": [ + 228, + 228 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.0435221035117092e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.12312275023486e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -6.1766357421875, + -6.1766357421875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.434958705439092e-14, + "shift_limit_x": [ + -0.10421574115753174, + -0.10421574115753174 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.957721715753411e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6947251558303833, + -0.6947251558303833 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2770223856061266e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.99999993922529e-09, + 9.99999993922529e-09 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0003468538747300378, + "max_holes": 16, + "max_height": 222, + "max_width": 222, + "min_holes": 16, + "min_height": 222, + "min_width": 222, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9335831957252246 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.1623310602168253, + "r_shift_limit": [ + 3, + 3 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.1884273001138581, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 4, + 4 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0014498733965131877, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2827406243375126e-06, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.8681438898608313e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.4480472803115845, + 1.4480472803115845 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0003742307744587364, + "threshold": [ + 24, + 24 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.289699629429379e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.8951648846877337e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0266392847169306e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.2817535400390625, + -0.2817535400390625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.010008096694946289, + -0.010008096694946289 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9238441336549445e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9808284640312195, + 0.9808284640312195 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0001145665500610453, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.012515504685883805, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6347833936724105 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.03729176877333318, + "r_shift_limit": [ + 34, + 34 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.57957758529655e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.052086965210524916, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -28, + -28 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.048548815953215696, + "brightness_limit": [ + 0.11266613006591797, + 0.11266613006591797 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.189894262171886e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.1684882297566215e-10, + "threshold": [ + 81, + 81 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.4442618099254403e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.488103688793736e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 99.521728515625, + 99.521728515625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.286300693902024e-12, + "shift_limit_x": [ + -0.669377326965332, + -0.669377326965332 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.3855487108230591, + -0.3855487108230591 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.239325240562189e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.701196670532227, + 5.701196670532227 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.3513004332380557e-09, + "max_holes": 16, + "max_height": 170, + "max_width": 170, + "min_holes": 16, + "min_height": 170, + "min_width": 170, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00012560937438845735, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8619454818179875 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.1433352102050217e-06, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.3315408412909165e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -62, + -62 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.6100545830824778e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -51, + -51 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.496986068855887e-05, + "brightness_limit": [ + -0.23446005582809448, + -0.23446005582809448 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.7645664909624417e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.210782051086426, + 6.210782051086426 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.115692642816539e-06, + "threshold": [ + 33, + 33 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.06029523194334585 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.805410686308358e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.103997533855044e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.016387939453125, + 0.016387939453125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0632199218971536e-06, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.975630278999292e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.5455919504165649, + 0.5455919504165649 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.444034307203366e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.533926486968994, + 5.533926486968994 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00019620936654973775, + "max_holes": 16, + "max_height": 113, + "max_width": 113, + "min_holes": 16, + "min_height": 113, + "min_width": 113, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.93148421044052e-07, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9393779283585676 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.9665683461514504e-08, + "r_shift_limit": [ + 43, + 43 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0011921592205023784, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -38, + -38 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0011389672561170627, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.443544042886517e-06, + "brightness_limit": [ + 0.18587613105773926, + 0.18587613105773926 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00038628241364455085, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.9733343720436096, + 0.9733343720436096 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 8.689242877498707e-13, + "threshold": [ + 174, + 174 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 9.236802363249617e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.16645560591691e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.3267886176724454e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.535675048828125, + 0.535675048828125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.968013365528407e-08, + "shift_limit_x": [ + -0.0007678866386413574, + -0.0007678866386413574 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.730378503505244e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0017783045768737793, + -0.0017783045768737793 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.494112029537674e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0119349956512451, + 1.0119349956512451 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.07187987971217558, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.015375804666714066, + "max_holes": 7, + "max_height": 14, + "max_width": 14, + "min_holes": 7, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9100152864047872 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.4440035009198411, + "r_shift_limit": [ + -1, + -1 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.9019260032833727e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 108, + 108 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.03400602538939168, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -39, + -39 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.005281329620629549, + "brightness_limit": [ + -0.18917536735534668, + -0.18917536735534668 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.512076377868652, + 6.512076377868652 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.0823494535468245e-08, + "threshold": [ + 100, + 100 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.492283766427828e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.1081616282084675e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.167519588351763e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -75.8642349243164, + -75.8642349243164 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.9722363948822021, + -0.9722363948822021 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.504036825013841e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0130348801612854, + -0.0130348801612854 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.173837242045251e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.146169185638428, + 6.146169185638428 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.002034276089589282, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0022998040930584107, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5123307958041323 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00012808085781370725, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.2630465106319944e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 44, + 44 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.9310361879366e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 73, + 73 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.0359904701415872e-06, + "brightness_limit": [ + 0.3939100503921509, + 0.3939100503921509 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.7954351201926274e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 8.907909393310547, + 8.907909393310547 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.6644586641220583e-05, + "threshold": [ + 123, + 123 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.3636728250331023e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.19052565509298347 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.807382972051868e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -4.899017333984375, + -4.899017333984375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3105735416757572e-07, + "shift_limit_x": [ + 0.9325933456420898, + 0.9325933456420898 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.10756981372833252, + -0.10756981372833252 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2869959879858016e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.53109073638916, + 8.53109073638916 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.542546031750217e-07, + "max_holes": 16, + "max_height": 113, + "max_width": 113, + "min_holes": 16, + "min_height": 113, + "min_width": 113, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.863376952393312e-10, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8092575353500466 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.01820899359881878, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.001080439354426914, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.02047782482825422, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 76, + 76 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.002032645053032786, + "brightness_limit": [ + -0.17412102222442627, + -0.17412102222442627 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.7389661963736571e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.474600076675415, + 1.474600076675415 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.143904271023278e-05, + "threshold": [ + 53, + 53 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 9.937517751191485e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 75.07084655761719, + 75.07084655761719 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.86969451995564e-10, + "shift_limit_x": [ + -0.9821086525917053, + -0.9821086525917053 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.3703252772321913e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.49004626274108887, + 0.49004626274108887 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.106870651245117, + 7.106870651245117 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0005233825711879574, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.039980214067158126, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9176632224190351 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.00136876932811e-06, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.514657803480617e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1721187014746543e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -88, + -88 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.041677972388121e-10, + "brightness_limit": [ + -1.0, + -1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.877553942386718e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 193, + 193 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.7984080276200666e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 53.942718505859375, + 53.942718505859375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.06092649282737739, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.275785902401688e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0340961217880249, + 0.0340961217880249 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.015264512835303e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.592376232147217, + 3.592376232147217 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.2547974708252474e-09, + "max_holes": 16, + "max_height": 186, + "max_width": 186, + "min_holes": 16, + "min_height": 186, + "min_width": 186, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.93900457421265 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0006216364077012045, + "r_shift_limit": [ + -28, + -28 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.822239567565651e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.8538467327364242e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 100, + 100 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.10440866927962533, + "brightness_limit": [ + 0.041353464126586914, + 0.041353464126586914 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.0145843124690992e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.3014740943908691, + 1.3014740943908691 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.3209793987415728e-08, + "threshold": [ + 175, + 175 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.7620027121088525e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.617573860400048e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -34.63606262207031, + -34.63606262207031 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.201321401797471e-10, + "shift_limit_x": [ + 0.6155514717102051, + 0.6155514717102051 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.596296880781276e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0025202035903930664, + 0.0025202035903930664 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.432024607478059e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.99999993922529e-09, + 9.99999993922529e-09 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.4311277611496674e-08, + "max_holes": 16, + "max_height": 73, + "max_width": 73, + "min_holes": 16, + "min_height": 73, + "min_width": 73, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.949237387372779e-06, + "max_holes": 13, + "max_height": 14, + "max_width": 14, + "min_holes": 13, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8948968695340972 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.019103433846175966, + "r_shift_limit": [ + -7, + -7 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0005581122882420964, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00034178582067646845, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -41, + -41 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.10879452910824e-10, + "brightness_limit": [ + -0.3885647654533386, + -0.3885647654533386 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.043422756574785115, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2490605115890503, + 1.2490605115890503 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.1106251067956208e-07, + "threshold": [ + 228, + 228 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 9.933802217430551e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 40.939117431640625, + 40.939117431640625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.5153821706771851, + -0.5153821706771851 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.508234844541669e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.01061403751373291, + -0.01061403751373291 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.1528714622639195e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.60398268699646, + 1.60398268699646 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.171980821698741e-05, + "max_holes": 16, + "max_height": 127, + "max_width": 127, + "min_holes": 16, + "min_height": 127, + "min_width": 127, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.49447744668078997, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.4420846328504089 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.405496401899809e-05, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.90748127785155e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -86, + -86 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.154201674540839e-14, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 99, + 99 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.072758965891339e-06, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.131224154288814e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.28756353130941e-15, + "threshold": [ + 94, + 94 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.2000675130478344e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.302839265679301e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.9059072085410662, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -1.67236328125, + -1.67236328125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.1996055262394784e-15, + "shift_limit_x": [ + -0.608318567276001, + -0.608318567276001 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.7710075974464417, + -0.7710075974464417 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1710856662088746e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.480175971984863, + 8.480175971984863 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.877024466124237e-07, + "max_holes": 16, + "max_height": 216, + "max_width": 216, + "min_holes": 16, + "min_height": 216, + "min_width": 216, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.84769144378931e-13, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.09407106847596214 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.314150958042076e-11, + "r_shift_limit": [ + 98, + 98 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.496947063145853e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 113, + 113 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.494889928743984e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 208, + 208 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.7766328527010535e-12, + "brightness_limit": [ + -0.2581579089164734, + -0.2581579089164734 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.1317973630601455e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 9.133700370788574, + 9.133700370788574 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.2469787697973059e-11, + "threshold": [ + 107, + 107 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.4025221961673066e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.1812141238492832e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.5168545533919726, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -4.233734130859375, + -4.233734130859375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5459822041942924e-09, + "shift_limit_x": [ + -0.0013855695724487305, + -0.0013855695724487305 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.5970017910003662, + 0.5970017910003662 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.773556813164294e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.030984401702881, + 6.030984401702881 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.31085940690653e-06, + "max_holes": 16, + "max_height": 163, + "max_width": 163, + "min_holes": 16, + "min_height": 163, + "min_width": 163, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.506417013733757e-11, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.4831430588272919 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.506101356429434e-13, + "r_shift_limit": [ + -52, + -52 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.548713168360156e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -124, + -124 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 161, + 161 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.140777572511113e-10, + "brightness_limit": [ + -1.0, + -1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.1777987532362698e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.933015823364258, + 6.933015823364258 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.0119971538098185e-13, + "threshold": [ + 107, + 107 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.410578745855046e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0521123201851894e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -123.92623901367188, + -123.92623901367188 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.2853827476501465, + 0.2853827476501465 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.11555151101834937, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0773951250371413e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.956918716430664, + 3.956918716430664 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.4481994396865915e-07, + "max_holes": 16, + "max_height": 162, + "max_width": 162, + "min_holes": 16, + "min_height": 162, + "min_width": 162, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.0606480370502155e-08, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8844461948963095 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.05089928393502019, + "r_shift_limit": [ + 33, + 33 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.025386037304997444, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -46, + -46 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.03171745548757765, + "brightness_limit": [ + 0.1767714023590088, + 0.1767714023590088 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.000999238109216094, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.250837802886963, + 1.250837802886963 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0014264806625015336, + "threshold": [ + 67, + 67 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.8439848284303068e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.932358015911052e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 158.08502197265625, + 158.08502197265625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.518452207477822e-07, + "shift_limit_x": [ + 0.0020728111267089844, + 0.0020728111267089844 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.553117374628699e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.011360764503479004, + 0.011360764503479004 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.027852652914254e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.785038471221924, + 5.785038471221924 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.905646634304751e-09, + "max_holes": 16, + "max_height": 128, + "max_width": 128, + "min_holes": 16, + "min_height": 128, + "min_width": 128, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8895352035974229 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.869707359577818e-05, + "r_shift_limit": [ + -142, + -142 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.2739636123024766e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 29, + 29 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.281542868739151e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -49, + -49 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.24653300073026e-11, + "brightness_limit": [ + -0.3153538703918457, + -0.3153538703918457 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2061915727050176e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1447781324386597, + 1.1447781324386597 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.5403257833102206e-12, + "threshold": [ + 116, + 116 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 7.598302052830133e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.473632669201594e-05 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.8711295815751123e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -59.550758361816406, + -59.550758361816406 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1311500199865367e-09, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.25187026443322935, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5690407408275013e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.439790725708008, + 5.439790725708008 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.006700386758893728, + "max_holes": 16, + "max_height": 142, + "max_width": 142, + "min_holes": 16, + "min_height": 142, + "min_width": 142, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.266974865282154e-11, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7413653496494148 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + 67, + 67 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.018704080805438394, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -75, + -75 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.004237764684146078, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -32, + -32 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.5249288377380793e-07, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.496336293498533e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.003318334006617296, + "threshold": [ + 234, + 234 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.2573887348920015e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.831125890148286e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2046901424358712e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 5.973663330078125, + 5.973663330078125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.6703346967697144, + 0.6703346967697144 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6019811630249023, + -0.6019811630249023 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.008739795212016e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.617938041687012, + 8.617938041687012 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.5069108164346474, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.847398847285849e-05, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.4667742893818121 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.9158122416795256e-06, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.1390504572164275, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -19, + -19 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.003046242571949173, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 38, + 38 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0019492553948136926, + "brightness_limit": [ + 0.0955362319946289, + 0.0955362319946289 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.5164373117609364e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 25, + 25 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.0938422345186845e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.8351322449718253e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.8149337179991735e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -1.5936279296875, + -1.5936279296875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.324336842933158e-06, + "shift_limit_x": [ + 0.7152857780456543, + 0.7152857780456543 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0286692248098646e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.004098653793334961, + -0.004098653793334961 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.474065481202177e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.1074957847595215, + 3.1074957847595215 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.008535843342542648, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.931394094564152e-06, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8473364239376476 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00114494675958407, + "r_shift_limit": [ + 72, + 72 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0485729063863946e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -4, + -4 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0015725268829771544, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -44, + -44 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.6031014937142405e-05, + "brightness_limit": [ + -0.09523028135299683, + -0.09523028135299683 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.59393666668273e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.8297559761880465e-10, + "threshold": [ + 108, + 108 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.2566628837189217e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.655261017618646e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -84.30325317382812, + -84.30325317382812 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.84195955470912e-07, + "shift_limit_x": [ + -0.001112222671508789, + -0.001112222671508789 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.10396584035225e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.9305758476257324, + 0.9305758476257324 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0332209971965645e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.440990924835205, + 7.440990924835205 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.170066012712555e-06, + "max_holes": 16, + "max_height": 130, + "max_width": 130, + "min_holes": 16, + "min_height": 130, + "min_width": 130, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00017577996236535325, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9970539376646396 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.09864032481097151, + "r_shift_limit": [ + -9, + -9 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0006516974671846101, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -45, + -45 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.01660614146025252, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -35, + -35 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.868066695645334e-08, + "brightness_limit": [ + -0.16928702592849731, + -0.16928702592849731 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00022478473351204842, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2585809230804443, + 1.2585809230804443 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.955059552600731e-09, + "threshold": [ + 124, + 124 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.0907536015733961e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.402545787827681e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.5843032149799536e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 2.960906982421875, + 2.960906982421875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.841775535474582e-10, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1105938429625256e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8100710511207581, + -0.8100710511207581 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.4346270143194097e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.531067371368408, + 6.531067371368408 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.633693387014022e-07, + "max_holes": 16, + "max_height": 195, + "max_width": 195, + "min_holes": 16, + "min_height": 195, + "min_width": 195, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.006286268588896304, + "max_holes": 15, + "max_height": 14, + "max_width": 14, + "min_holes": 15, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.877561566705066 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5181306720690529e-06, + "r_shift_limit": [ + 14, + 14 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.0839846232311174e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.000588233567607975, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 71, + 71 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.3028465548468723e-06, + "brightness_limit": [ + -0.46180546283721924, + -0.46180546283721924 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.7410293266002554e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.629036653112191e-06, + "threshold": [ + 6, + 6 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.1028378606091686e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.492438649136161e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.011338089944024e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -75.44966888427734, + -75.44966888427734 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7048038703163753e-09, + "shift_limit_x": [ + -0.5499807596206665, + -0.5499807596206665 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.1285486260403612, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.009032130241394043, + 0.009032130241394043 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.7152371602015304e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.960114479064941, + 7.960114479064941 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 132, + "max_width": 132, + "min_holes": 16, + "min_height": 132, + "min_width": 132, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.000562754459307313, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.870288101175505 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.702791985852116e-13, + "r_shift_limit": [ + 190, + 190 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.0765331091340054e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -191, + -191 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.8942910051824656e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.656093076577358e-11, + "brightness_limit": [ + -0.08028322458267212, + -0.08028322458267212 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.0674470226425493e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 5.06143045425415, + 5.06143045425415 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.3097570867512303e-08, + "threshold": [ + 219, + 219 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.339687246709967e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.260765471148493e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.5657335198523694e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.03778076171875, + 0.03778076171875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.48959798488751005, + "shift_limit_x": [ + 0.10697877407073975, + 0.10697877407073975 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.628404199677265e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0005385875701904297, + 0.0005385875701904297 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.790200714142507e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.579516410827637, + 8.579516410827637 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.259640612735891e-10, + "max_holes": 16, + "max_height": 206, + "max_width": 206, + "min_holes": 16, + "min_height": 206, + "min_width": 206, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.998343307136485e-08, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5104019384791376 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.7951239596716434e-11, + "r_shift_limit": [ + -127, + -127 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.30127567504211e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -88, + -88 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0564349671423969e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -84, + -84 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.4076027589310856e-07, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.5657042610837136e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2887017726898193, + 1.2887017726898193 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.3207001164330787e-11, + "threshold": [ + 197, + 197 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.527094912400107e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.511295544175642e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.345252143589945e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.3425445556640625, + -0.3425445556640625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.6244668666358137, + "shift_limit_x": [ + -0.4918532371520996, + -0.4918532371520996 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.275879330385969e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.00011754035949707031, + 0.00011754035949707031 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.6336621143564588e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.939145565032959, + 4.939145565032959 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.647087974797513e-10, + "max_holes": 16, + "max_height": 17, + "max_width": 17, + "min_holes": 16, + "min_height": 17, + "min_width": 17, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.678479342451459e-12, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.3755329840489976 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.012863255891245928, + "r_shift_limit": [ + 31, + 31 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 48, + 48 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.008374514527642596, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -29, + -29 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.80478758519628e-05, + "brightness_limit": [ + 0.21636736392974854, + 0.21636736392974854 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.210874823712289e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.6899925219956164e-05, + "threshold": [ + 23, + 23 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.093689668041949e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.0555267333984375, + -0.0555267333984375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.9723327251057005e-08, + "shift_limit_x": [ + 0.4730861186981201, + 0.4730861186981201 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.5682353973388672, + 0.5682353973388672 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2852165889245818e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.971037864685059, + 4.971037864685059 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 219, + "max_width": 219, + "min_holes": 16, + "min_height": 219, + "min_width": 219, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0011596991823753788, + "max_holes": 7, + "max_height": 14, + "max_width": 14, + "min_holes": 7, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9775304456885775 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5212506871694747e-11, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.339876798263123e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -185, + -185 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.458976286806941e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 147, + 147 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.073679535710616e-09, + "brightness_limit": [ + 0.24433398246765137, + 0.24433398246765137 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2603449138687363e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.6265516277597466e-13, + "threshold": [ + 186, + 186 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.518552089629921e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 9.196598022592427e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1195715111650604e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 95.26553344726562, + 95.26553344726562 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.7991055968621197, + "shift_limit_x": [ + -0.5956560373306274, + -0.5956560373306274 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.967819002329399e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.682119369506836, + 9.682119369506836 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.5422286583654053e-14, + "max_holes": 16, + "max_height": 76, + "max_width": 76, + "min_holes": 16, + "min_height": 76, + "min_width": 76, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.0712557597760303e-14, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.20089433253907452 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0005488646605931978, + "r_shift_limit": [ + -47, + -47 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1588723119617344e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 57, + 57 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0003715357298449129, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 189, + 189 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.865561613541825e-05, + "brightness_limit": [ + -0.21941161155700684, + -0.21941161155700684 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.436954591276356e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 9.264272689819336, + 9.264272689819336 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.088654600711643e-09, + "threshold": [ + 146, + 146 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.8997269782708623e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2930579532041957e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.6205596923828125, + 0.6205596923828125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.009320771178795262, + "shift_limit_x": [ + 0.025328993797302246, + 0.025328993797302246 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3646985407919363e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.015245466328736e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.146920204162598, + 6.146920204162598 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.0234699594885336e-09, + "max_holes": 16, + "max_height": 203, + "max_width": 203, + "min_holes": 16, + "min_height": 203, + "min_width": 203, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.691878850863457e-06, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9896738998188774 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.002588037246754271, + "r_shift_limit": [ + -31, + -31 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.911357263363069e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -53, + -53 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.014755859039723873, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -33, + -33 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.279318571696633e-07, + "brightness_limit": [ + -0.15069890022277832, + -0.15069890022277832 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.83124793960182e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.07640540599823, + 1.07640540599823 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.00022032480728995107, + "threshold": [ + 204, + 204 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 8.782919106690731e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -5.6599273681640625, + -5.6599273681640625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2799573746337316e-07, + "shift_limit_x": [ + -0.9940876364707947, + -0.9940876364707947 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.010605096817016602, + 0.010605096817016602 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.983273330316681e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.238329887390137, + 7.238329887390137 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.378928830543934e-08, + "max_holes": 16, + "max_height": 67, + "max_width": 67, + "min_holes": 16, + "min_height": 67, + "min_width": 67, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.918241696437247e-08, + "max_holes": 7, + "max_height": 14, + "max_width": 14, + "min_holes": 7, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9824078951814972 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.70991735359197e-05, + "r_shift_limit": [ + 70, + 70 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0004262373795073781, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.986428565031619e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 69, + 69 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0031577150993342684, + "brightness_limit": [ + 0.1499471664428711, + 0.1499471664428711 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.914380531303214e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.346573937562012e-10, + "threshold": [ + 126, + 126 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.0996216334394605e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -151.53799438476562, + -151.53799438476562 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.09187960624694824, + 0.09187960624694824 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.11687294933965e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.8932034969329834, + 0.8932034969329834 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.233610949584877e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.485941410064697, + 4.485941410064697 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.893673962553576e-08, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.682542614078775e-08, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9963570801386334 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.015324374156372778, + "r_shift_limit": [ + -19, + -19 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.7646869988551996e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00022892931962332358, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 123, + 123 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0010092747783845557, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.1547567129419776e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 4.127987861633301, + 4.127987861633301 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.167392491998692e-11, + "threshold": [ + 158, + 158 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.3260354729595454e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0028015970826316683 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 54.0943603515625, + 54.0943603515625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.661976869527713e-07, + "shift_limit_x": [ + 0.95421302318573, + 0.95421302318573 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2216207969370172e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.626687687261301e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.7872436046600342, + 0.7872436046600342 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.364552123106528e-10, + "max_holes": 16, + "max_height": 147, + "max_width": 147, + "min_holes": 16, + "min_height": 147, + "min_width": 147, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.008327368591756e-08, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9806322657034822 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.4605071219513074e-13, + "r_shift_limit": [ + -220, + -220 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.89365989430011e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -76, + -76 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.879630226907805e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -62, + -62 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2772257827476565e-06, + "brightness_limit": [ + 0.23953282833099365, + 0.23953282833099365 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.907703313769757e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.150741100311279, + 6.150741100311279 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 8.781521215023799e-11, + "threshold": [ + 219, + 219 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.3628717423717944 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.926606116908569e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.953798123656317e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.7975616455078125, + 0.7975616455078125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.493614823223066e-09, + "shift_limit_x": [ + 0.5785723924636841, + 0.5785723924636841 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.6789595907900815e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.46895575523376465, + 0.46895575523376465 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2124483751230677e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.025160074234009, + 3.025160074234009 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.9168740259349524e-12, + "max_holes": 16, + "max_height": 116, + "max_width": 116, + "min_holes": 16, + "min_height": 116, + "min_width": 116, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.48413949917655e-08, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6371218409524723 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.098308520697163e-07, + "r_shift_limit": [ + -70, + -70 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.4591786915564634e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.966824217205785e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00041281198676085956, + "brightness_limit": [ + -0.19630539417266846, + -0.19630539417266846 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.231527562354124e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 169, + 169 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 9.195965078676686e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 99.55902099609375, + 99.55902099609375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2458338005671976e-06, + "shift_limit_x": [ + 0.2559809684753418, + 0.2559809684753418 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.021126525976081e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8184626698493958, + -0.8184626698493958 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 10.0, + 10.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.376062412559878e-07, + "max_holes": 16, + "max_height": 180, + "max_width": 180, + "min_holes": 16, + "min_height": 180, + "min_width": 180, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0018187864425460443, + "max_holes": 2, + "max_height": 14, + "max_width": 14, + "min_holes": 2, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9977348421354297 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.551658055874973e-06, + "r_shift_limit": [ + 41, + 41 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.7123940529934715e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -55, + -55 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.498781838763237e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -40, + -40 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.152086375572639e-08, + "brightness_limit": [ + -0.05126458406448364, + -0.05126458406448364 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0004326898714846483, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2002726793289185, + 1.2002726793289185 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.861566242316624e-12, + "threshold": [ + 158, + 158 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.4482518220229544e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.0035616676749111e-15 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.645849479217748e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.131683349609375, + 0.131683349609375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.9972025955127156e-08, + "shift_limit_x": [ + 0.006563425064086914, + 0.006563425064086914 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.561087826401172e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0001800060272216797, + 0.0001800060272216797 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.129073143005371, + 7.129073143005371 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 114, + "max_width": 114, + "min_holes": 16, + "min_height": 114, + "min_width": 114, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.408209569814646e-05, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9993991266911836 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.02832452766597271, + "r_shift_limit": [ + 44, + 44 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.15361065165757992, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 2, + 2 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.8858293978182605e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 100, + 100 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.617204897628668e-05, + "brightness_limit": [ + 0.26258671283721924, + 0.26258671283721924 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.6665191897829838e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 24, + 24 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.7484004157358913e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.492473043542522e-15 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.580928023708985e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -107.83641815185547, + -107.83641815185547 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3515723005162901e-12, + "shift_limit_x": [ + -0.573889970779419, + -0.573889970779419 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5423311049094223e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.006101131439208984, + -0.006101131439208984 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.437326777554216e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0602478981018066, + 1.0602478981018066 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.9503151381504722e-05, + "max_holes": 16, + "max_height": 132, + "max_width": 132, + "min_holes": 16, + "min_height": 132, + "min_width": 132, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.894301734121372e-05, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8178811329539313 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.0752244235802813e-07, + "r_shift_limit": [ + 125, + 125 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.065664204106857e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -67, + -67 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.073822752976903e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -76, + -76 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.4825065671751666e-13, + "brightness_limit": [ + -0.5932604074478149, + -0.5932604074478149 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.3313715944931144e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.9398775677067746e-11, + "threshold": [ + 86, + 86 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.12613475241553118 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.147773071817932e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.554390035635713e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 100.34713745117188, + 100.34713745117188 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.10818743705749512, + 0.10818743705749512 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.172807131107149e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.680864691734314, + -0.680864691734314 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5183562939687671e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0015926361083984, + 1.0015926361083984 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.6711925817315895e-13, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.903933815243097e-08, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8738649459281769 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00018844012563624599, + "r_shift_limit": [ + -2, + -2 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.8598070825894507e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 49, + 49 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -7, + -7 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.163101078205302e-07, + "brightness_limit": [ + -0.19518828392028809, + -0.19518828392028809 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.023065744699965474, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.0800312757492065, + 1.0800312757492065 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.385752018906726e-08, + "threshold": [ + 72, + 72 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.402675341625745e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 9.108306745439994e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.28463843327478e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.3246917724609375, + 0.3246917724609375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.167267264940725e-14, + "shift_limit_x": [ + 0.9559990167617798, + 0.9559990167617798 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.826397141605207e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.509141374999322e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9949036836624146, + 0.9949036836624146 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00028993415727036204, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.016239489653373518, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9602138414504265 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.970245535585013e-07, + "r_shift_limit": [ + 92, + 92 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.626384764658481e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -96, + -96 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.532804565740475e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 44, + 44 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.162164185540355e-10, + "brightness_limit": [ + -0.253639280796051, + -0.253639280796051 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.880495099165738e-13, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.210319995880127, + 6.210319995880127 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 9.0036811899682e-12, + "threshold": [ + 176, + 176 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 9.026105785832788e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.2889770360119407e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.265628455749792e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 128.03570556640625, + 128.03570556640625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.13001113521355734, + "shift_limit_x": [ + -0.032296955585479736, + -0.032296955585479736 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.47420406341552734, + 0.47420406341552734 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.9350879081658947e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9839644432067871, + 0.9839644432067871 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.520323558313381e-11, + "max_holes": 16, + "max_height": 130, + "max_width": 130, + "min_holes": 16, + "min_height": 130, + "min_width": 130, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.012364634010905e-06, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8699826187759641 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.03586921294913559, + "r_shift_limit": [ + 82, + 82 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.366826630488727e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 50, + 50 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0020034729968756437, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -53, + -53 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.993540192619548e-06, + "brightness_limit": [ + -0.20907729864120483, + -0.20907729864120483 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.105415143853933e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.482830047607422, + 6.482830047607422 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 157, + 157 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.473172359776233e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.1877373816919349e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.4406092417722763e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -69.25070190429688, + -69.25070190429688 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.38901056870678e-12, + "shift_limit_x": [ + 0.36622488498687744, + 0.36622488498687744 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.04015171527862549, + 0.04015171527862549 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.216920714121174e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.548566818237305, + 8.548566818237305 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.043799400250939424, + "max_holes": 16, + "max_height": 64, + "max_width": 64, + "min_holes": 16, + "min_height": 64, + "min_width": 64, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00014494628963492712, + "max_holes": 13, + "max_height": 14, + "max_width": 14, + "min_holes": 13, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9180964240841395 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.1213405285487476e-05, + "r_shift_limit": [ + -88, + -88 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.866444822338063e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.538219311831441e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -66, + -66 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.851575753614574e-05, + "brightness_limit": [ + -0.3782992959022522, + -0.3782992959022522 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2137114794690663e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.699994087219238, + 6.699994087219238 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.7265805701800285e-06, + "threshold": [ + 3, + 3 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.4211732865382644e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.6740335597259516e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.343139125659909e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 89.26846313476562, + 89.26846313476562 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.8071030028215205, + "shift_limit_x": [ + -0.08001679182052612, + -0.08001679182052612 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.610286879491413e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.3592405319213867, + 0.3592405319213867 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.897736416554303e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.715662002563477, + 8.715662002563477 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.659120224993176e-10, + "max_holes": 16, + "max_height": 76, + "max_width": 76, + "min_holes": 16, + "min_height": 76, + "min_width": 76, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.6380773466666745e-07, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.1927151817409819 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.5372454341634653e-07, + "r_shift_limit": [ + 14, + 14 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.467456677932931e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.1669755700112125e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 18, + 18 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.879149945681211e-13, + "brightness_limit": [ + 0.25280117988586426, + 0.25280117988586426 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.1110705431927438e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.4959393739700317, + 1.4959393739700317 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.399831529848959e-08, + "threshold": [ + 106, + 106 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.031028389222842e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.3343802930035598e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.5952582978479377, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 3.8200225830078125, + 3.8200225830078125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.042630910873413086, + 0.042630910873413086 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.439062264902605e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.004018306732177734, + 0.004018306732177734 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.498301595950136e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.0533342361450195, + 5.0533342361450195 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00026700631133280694, + "max_holes": 16, + "max_height": 217, + "max_width": 217, + "min_holes": 16, + "min_height": 217, + "min_width": 217, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.131120534640731e-11, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.4044730835054381 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.2271774227417609, + "r_shift_limit": [ + -7, + -7 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.028674152854335055, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -80, + -80 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.026667287539625e-08, + "brightness_limit": [ + -0.3569694757461548, + -0.3569694757461548 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 3.7416303157806396, + 3.7416303157806396 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 9.413144228178129e-10, + "threshold": [ + 121, + 121 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.8793372578332026e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 36.134918212890625, + 36.134918212890625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.07084167003631592, + 0.07084167003631592 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.015424549579620361, + -0.015424549579620361 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.985045206235213e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.994796752929688, + 8.994796752929688 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.0806932432976588e-08, + "max_holes": 16, + "max_height": 66, + "max_width": 66, + "min_holes": 16, + "min_height": 66, + "min_width": 66, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7441483035657612 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.447903966192486e-07, + "r_shift_limit": [ + 71, + 71 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00038275503583760223, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 39, + 39 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.024501956304404438, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -31, + -31 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + -0.6109625101089478, + -0.6109625101089478 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.732013805940909e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 186, + 186 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.604818762167976e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.029062782771598e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.5195159194837824e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -54.07508087158203, + -54.07508087158203 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.943110842661782e-06, + "shift_limit_x": [ + 0.07320666313171387, + 0.07320666313171387 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.313259989235582e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.004107058048248291, + -0.004107058048248291 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.1139708757400513, + 1.1139708757400513 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.6702706655614182e-05, + "max_holes": 16, + "max_height": 107, + "max_width": 107, + "min_holes": 16, + "min_height": 107, + "min_width": 107, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.458403738142953e-07, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9750959069990041 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0013585594779328414, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.697991191515683e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -50, + -50 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.717774111084229e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.528931764720635e-08, + "brightness_limit": [ + -0.31449371576309204, + -0.31449371576309204 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.6441719415371343e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.492732827301504e-08, + "threshold": [ + 86, + 86 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.2772960002158629e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.228883389031939e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 116.93194580078125, + 116.93194580078125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.900404219271559e-12, + "shift_limit_x": [ + -0.7811325192451477, + -0.7811325192451477 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.008336663246154785, + -0.008336663246154785 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.906858152834525e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9920212030410767, + 0.9920212030410767 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.831898034139345e-05, + "max_holes": 16, + "max_height": 187, + "max_width": 187, + "min_holes": 16, + "min_height": 187, + "min_width": 187, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.6859180528017645e-06, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9985121188797532 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.452385344764472e-10, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -236, + -236 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.290563258059463e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.415957520101596e-13, + "brightness_limit": [ + 0.22013628482818604, + 0.22013628482818604 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.6025518785208406e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.135903216446411e-12, + "threshold": [ + 136, + 136 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.465544618770362e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.525210748767658e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.7158518882745213, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -8.001708984375, + -8.001708984375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.470833820690746e-14, + "shift_limit_x": [ + 0.0022736787796020508, + 0.0022736787796020508 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.331465926709905e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.7979684472084045, + -0.7979684472084045 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.434468652643622e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.862270832061768, + 4.862270832061768 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.310063271791286e-06, + "max_holes": 16, + "max_height": 96, + "max_width": 96, + "min_holes": 16, + "min_height": 96, + "min_width": 96, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.4086802047310649e-12, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.2841457946714323 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0010410298511981386, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.1114078446471678e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -43, + -43 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.285798423364284e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -255, + -255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.612106560986922e-05, + "brightness_limit": [ + -1.0, + -1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.092458756919708e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.3942165106256065e-09, + "threshold": [ + 3, + 3 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.0472828148614643e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 8.79095458984375, + 8.79095458984375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.596462129159701e-09, + "shift_limit_x": [ + -0.8586363196372986, + -0.8586363196372986 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.490009442249203e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.00017762184143066406, + -0.00017762184143066406 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.371134668500123e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0234612226486206, + 1.0234612226486206 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.2206594006174826e-05, + "max_holes": 16, + "max_height": 85, + "max_width": 85, + "min_holes": 16, + "min_height": 85, + "min_width": 85, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.190859984336184e-06, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9988653002012758 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.9229873295599818e-09, + "r_shift_limit": [ + 65, + 65 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.222659794300577e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.445976084336451e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 48, + 48 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.695870826369363e-11, + "brightness_limit": [ + -1.0, + -1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.1029764930955049e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.6349174976348877, + 1.6349174976348877 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.78768402969678e-09, + "threshold": [ + 55, + 55 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.5361723729734864e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.459508436946747e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -174.26138305664062, + -174.26138305664062 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.498703297066692e-14, + "shift_limit_x": [ + -0.561456561088562, + -0.561456561088562 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.453379605189629e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.45948612689971924, + 0.45948612689971924 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.725290620346427e-15, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.69279408454895, + 3.69279408454895 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.842890036135839e-09, + "max_holes": 16, + "max_height": 81, + "max_width": 81, + "min_holes": 16, + "min_height": 81, + "min_width": 81, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.075244417874648e-08, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9999981808450228 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.088844575725441e-10, + "r_shift_limit": [ + -127, + -127 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.99829716877683e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.582188132219491e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -194, + -194 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.1392919411370457e-12, + "brightness_limit": [ + 0.3643345832824707, + 0.3643345832824707 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.1173172560486472e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.554200582564883e-09, + "threshold": [ + 5, + 5 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.960934984106965e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.124349753195896e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.4690216600460504e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 180.0, + 180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.47295142532357204, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.926476994553368e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.23670780658721924, + 0.23670780658721924 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.5717100183569847e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0360171794891357, + 1.0360171794891357 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.4055580508832166e-11, + "max_holes": 16, + "max_height": 192, + "max_width": 192, + "min_holes": 16, + "min_height": 192, + "min_width": 192, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.85742348371479e-11, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5270363467383501 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.014024226926267147, + "r_shift_limit": [ + 59, + 59 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.575966506420836e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -55, + -55 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.002752494066953659, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -72, + -72 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.004367474856526166, + "brightness_limit": [ + -0.0037078261375427246, + -0.0037078261375427246 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.2419163304319873e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 247, + 247 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.0923949151638392e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.093422778495029e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4241934183735464e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 180.0, + 180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.467546972458978e-11, + "shift_limit_x": [ + 0.4311944246292114, + 0.4311944246292114 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.842373026196762e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0036056041717529297, + 0.0036056041717529297 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.287642240524292, + 3.287642240524292 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.736330216544466e-06, + "max_holes": 16, + "max_height": 164, + "max_width": 164, + "min_holes": 16, + "min_height": 164, + "min_width": 164, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.15590529666267994, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8229109118907476 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00024121003996069312, + "r_shift_limit": [ + -206, + -206 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.081315250227505e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.1481898700724864, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -7, + -7 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.097028306877396e-08, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.0190873211029126e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.590441861236947e-07, + "threshold": [ + 35, + 35 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.1409317914334865e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.569759230843345e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -99.90779113769531, + -99.90779113769531 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3003089187938406e-09, + "shift_limit_x": [ + 0.6742254495620728, + 0.6742254495620728 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.004412293434143066, + 0.004412293434143066 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.112385630607605, + 1.112385630607605 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0005323282322554634, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8510056665076542 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.7277344939147272e-12, + "r_shift_limit": [ + 77, + 77 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0502807885385098e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 71, + 71 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.069090045396457e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.636225555046167e-08, + "brightness_limit": [ + 0.29661643505096436, + 0.29661643505096436 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.7792978733065305e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.721525980783017e-12, + "threshold": [ + 172, + 172 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.283616327929668e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.837875385247108e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.5217801003631515e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.083709716796875, + -0.083709716796875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.1815128259024556e-07, + "shift_limit_x": [ + -0.0012677907943725586, + -0.0012677907943725586 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.6049862569711024, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.02582573890686035, + 0.02582573890686035 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.209875137704728e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.652524948120117, + 8.652524948120117 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.2593286170554503e-12, + "max_holes": 16, + "max_height": 20, + "max_width": 20, + "min_holes": 16, + "min_height": 20, + "min_width": 20, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.416301313756992e-08, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.39501315458895947 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.7793022751728667e-06, + "r_shift_limit": [ + -173, + -173 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.956291693870002e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 13, + 13 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.255428479399694e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 210, + 210 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.999745786190033, + "brightness_limit": [ + -0.43651729822158813, + -0.43651729822158813 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.627387945446704e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.5088036060333252, + 0.5088036060333252 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.391390155107102e-07, + "threshold": [ + 253, + 253 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.1573715474347702e-05 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.8691689581709038e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 154.404296875, + 154.404296875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4157077246200767e-08, + "shift_limit_x": [ + 0.044777512550354004, + 0.044777512550354004 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.059651970863342285, + -0.059651970863342285 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.317861415085837e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.684831619262695, + 8.684831619262695 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.3519972009193271e-06, + "max_holes": 16, + "max_height": 10, + "max_width": 10, + "min_holes": 16, + "min_height": 10, + "min_width": 10, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0262481976546108e-05, + "max_holes": 13, + "max_height": 14, + "max_width": 14, + "min_holes": 13, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.00016142770396498918 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0024184005812173254, + "r_shift_limit": [ + -155, + -155 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00731475605680304, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -93, + -93 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0006340664475469257, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.778759165662021e-10, + "brightness_limit": [ + 0.5669324398040771, + 0.5669324398040771 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.698248922278237e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.432809902428247e-06, + "threshold": [ + 242, + 242 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.161531305332682e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.9431416143049392e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 1.958038330078125, + 1.958038330078125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.449772041344973e-12, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.23806045519877017, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.04123187065124512, + 0.04123187065124512 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.421215057373047, + 8.421215057373047 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.7811941327442263e-08, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.441947146546034e-07, + "max_holes": 2, + "max_height": 14, + "max_width": 14, + "min_holes": 2, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7515384967060978 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.5938258253109985e-09, + "r_shift_limit": [ + -203, + -203 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -240, + -240 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.71213987293387e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -190, + -190 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0.12339818477630615, + 0.12339818477630615 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.9030736684799194, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 4.390736103057861, + 4.390736103057861 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.08357256650924683, + "threshold": [ + 83, + 83 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.014477544258316e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.3836972123825616e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.030860654507721e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.0889434814453125, + -0.0889434814453125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1662296749758682e-08, + "shift_limit_x": [ + 0.0035605430603027344, + 0.0035605430603027344 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.009795049919687937, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.04256486892700195, + 0.04256486892700195 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3997372731090671e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.18229866027832, + 8.18229866027832 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 34, + "max_width": 34, + "min_holes": 16, + "min_height": 34, + "min_width": 34, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.883453812663211e-10, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.0035586292120090013 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.000491111233692932, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0037892147557589406, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 112, + 112 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.05294978301017039, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 91, + 91 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.3561028838157654, + "brightness_limit": [ + 0.25907349586486816, + 0.25907349586486816 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0875811028148954, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 2.5051560401916504, + 2.5051560401916504 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.00021517362571538134, + "threshold": [ + 26, + 26 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.4258737716680236e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.4010984010640243e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.029144470962432e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 5.670989990234375, + 5.670989990234375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.818363357133403e-08, + "shift_limit_x": [ + -0.0014861822128295898, + -0.0014861822128295898 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.9922705174173e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6176258325576782, + -0.6176258325576782 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.296730337283877e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.135885238647461, + 5.135885238647461 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 22, + "max_width": 22, + "min_holes": 16, + "min_height": 22, + "min_width": 22, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.9022253309331656e-08, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.49877394920845874 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.4308672567284624e-10, + "r_shift_limit": [ + -247, + -247 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.070747575036842e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 152, + 152 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.797220682113318e-15, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -123, + -123 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.8156167736241048e-14, + "brightness_limit": [ + -0.28845101594924927, + -0.28845101594924927 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.161398811514771e-14, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.336657524108887, + 6.336657524108887 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.320713708684297e-13, + "threshold": [ + 231, + 231 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.81388070968905e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.9982773739124687e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.3329886346057e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -82.4740219116211, + -82.4740219116211 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.9999994039535522, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.9806847256371864e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8749405741691589, + -0.8749405741691589 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.871436274852206e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.200648307800293, + 9.200648307800293 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.344658730119286e-08, + "max_holes": 16, + "max_height": 98, + "max_width": 98, + "min_holes": 16, + "min_height": 98, + "min_width": 98, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.776951280641211e-14, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 5.156731561761774e-07 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.14903173361335575, + "r_shift_limit": [ + 10, + 10 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.103634402343576e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -26, + -26 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0002683730679235545, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.006353637546319846, + "brightness_limit": [ + 0.2327672243118286, + 0.2327672243118286 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.264970289665764e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.579487323760986, + 6.579487323760986 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.6679877096318596e-06, + "threshold": [ + 54, + 54 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.66539713002844e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.115570897221192e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.627638746188448e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.254119873046875, + 0.254119873046875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.925199031829834, + -0.925199031829834 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.325982517534754e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -1.0, + -1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.7503557205200195, + 7.7503557205200195 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.187263405462132e-10, + "max_holes": 16, + "max_height": 141, + "max_width": 141, + "min_holes": 16, + "min_height": 141, + "min_width": 141, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0040801237476398855, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8402543362607906 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.222405352932243e-08, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5352596823653952e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -57, + -57 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.631033668702698e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 71, + 71 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0005624107376303485, + "brightness_limit": [ + -0.19278377294540405, + -0.19278377294540405 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.6923206569524818e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1371722221374512, + 1.1371722221374512 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.246049286336059e-10, + "threshold": [ + 128, + 128 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.938503653402432e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.412491618111068e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 161.09869384765625, + 161.09869384765625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.048492283799399516, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.4987234065453744e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.008002161979675293, + 0.008002161979675293 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.1933612556283076e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.99999993922529e-09, + 9.99999993922529e-09 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.1320118739634516e-05, + "max_holes": 16, + "max_height": 210, + "max_width": 210, + "min_holes": 16, + "min_height": 210, + "min_width": 210, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.56579439539928e-05, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9508645255079959 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.011004197336061616, + "r_shift_limit": [ + 34, + 34 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0014538366173240252, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 32, + 32 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0040308707393705845, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -35, + -35 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.946002571831412e-07, + "brightness_limit": [ + -0.2197059988975525, + -0.2197059988975525 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.1066179169297422e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1769263744354248, + 1.1769263744354248 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.972148173258444e-07, + "threshold": [ + 201, + 201 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 9.0085766714602e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.2289876787729703e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.681182861328125, + -0.681182861328125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2531657202949778e-08, + "shift_limit_x": [ + 0.6052230596542358, + 0.6052230596542358 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.3730051517486572, + 0.3730051517486572 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.5119250234028166e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.937774658203125, + 3.937774658203125 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.8114632632107134e-06, + "max_holes": 16, + "max_height": 212, + "max_width": 212, + "min_holes": 16, + "min_height": 212, + "min_width": 212, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0011650115810220019, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.982339457253897 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.6950621851356034e-08, + "r_shift_limit": [ + -61, + -61 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5235045004190532e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1300090980816702e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 52, + 52 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.8673551817891595e-06, + "brightness_limit": [ + 0.5521212816238403, + 0.5521212816238403 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.8986419193551787e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 9.317255020141602, + 9.317255020141602 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.1916121977899425e-13, + "threshold": [ + 209, + 209 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.7916087565526773e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 50.600433349609375, + 50.600433349609375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.62900733586746e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6676952838897705, + -0.6676952838897705 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.7601014679444447, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0100593566894531, + 1.0100593566894531 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.151086866714137e-12, + "max_holes": 16, + "max_height": 73, + "max_width": 73, + "min_holes": 16, + "min_height": 73, + "min_width": 73, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.199542433917628e-11, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.23989648347502557 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5979612994891125e-06, + "r_shift_limit": [ + 48, + 48 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.807508175199002e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -84, + -84 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.037327516324631e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.393972169873317e-10, + "brightness_limit": [ + -0.231037437915802, + -0.231037437915802 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.681078530111112e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2201091051101685, + 1.2201091051101685 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.4889178361184602e-13, + "threshold": [ + 196, + 196 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.8662862524694145e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.99567923035776e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.9999964237213135, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -9.2796630859375, + -9.2796630859375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.139414844652094e-13, + "shift_limit_x": [ + 0.9401082992553711, + 0.9401082992553711 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.307891245434958e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.9742501974105835, + 0.9742501974105835 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 2.341143846511841, + 2.341143846511841 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.70874017491779e-10, + "max_holes": 16, + "max_height": 118, + "max_width": 118, + "min_holes": 16, + "min_height": 118, + "min_width": 118, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.777219971376088e-11, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 1.2125981055932655e-06 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0011985521143187822, + "r_shift_limit": [ + -36, + -36 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.002398289450711022, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 86, + 86 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0001528254232596206, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.7935334444734284e-08, + "brightness_limit": [ + 0.3435593843460083, + 0.3435593843460083 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.006671446048010399, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.311067819595337, + 1.311067819595337 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.0390125166401484e-12, + "threshold": [ + 26, + 26 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.594369464694176e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.457177488532625e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -5.196624755859375, + -5.196624755859375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.4609087109565735, + -0.4609087109565735 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.229589869316034e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0014028549194335938, + -0.0014028549194335938 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.61371870837261e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.187512397766113, + 7.187512397766113 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0017230831562633636, + "max_holes": 16, + "max_height": 158, + "max_width": 158, + "min_holes": 16, + "min_height": 158, + "min_width": 158, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.465863525552783e-05, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9877968312599578 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.3303995340402725e-05, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1630827594612088e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -29, + -29 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.3151247211652415e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 75, + 75 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.724052810661631e-07, + "brightness_limit": [ + 0.4297335147857666, + 0.4297335147857666 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.431117189051872e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.0827397312376707e-06, + "threshold": [ + 87, + 87 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.965940529844356e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.782101446876121e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9905854496005922e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.185302734375, + -0.185302734375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.6845001333793976e-13, + "shift_limit_x": [ + -0.9287970662117004, + -0.9287970662117004 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.6564277410507202, + 0.6564277410507202 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 10.0, + 10.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.585790454852109e-09, + "max_holes": 16, + "max_height": 223, + "max_width": 223, + "min_holes": 16, + "min_height": 223, + "min_width": 223, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0007466968180019906, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9991634372508622 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.005341273627225196, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -85, + -85 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.192663793655648e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -24, + -24 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.7843531193292022e-09, + "brightness_limit": [ + -0.047692179679870605, + -0.047692179679870605 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0002730183769017458, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.584318912842982e-07, + "threshold": [ + 35, + 35 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.1321846908822172e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7724776424037166e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 5.101654052734375, + 5.101654052734375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.620935814674768e-09, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6789312362670898, + -0.6789312362670898 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.76651668548584, + 8.76651668548584 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.014641540411242993, + "max_holes": 16, + "max_height": 136, + "max_width": 136, + "min_holes": 16, + "min_height": 136, + "min_width": 136, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.7625266164703864e-06, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9797402405934713 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.0831194246826405e-08, + "r_shift_limit": [ + -172, + -172 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.174475905751278e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 72, + 72 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.864847257857443e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -35, + -35 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.0808102373787163e-05, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00026291272409526695, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 2.011270761489868, + 2.011270761489868 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.121022966738764e-11, + "threshold": [ + 216, + 216 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.336378169726736e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.866774531839772e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 14.92913818359375, + 14.92913818359375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.005747675895690918, + 0.005747675895690918 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.3018010868439376, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.027438759803771973, + 0.027438759803771973 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.4683065857664863e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.744891166687012, + 6.744891166687012 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.3283250922046836e-09, + "max_holes": 16, + "max_height": 193, + "max_width": 193, + "min_holes": 16, + "min_height": 193, + "min_width": 193, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6978547161991614 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.3213660322322024e-11, + "r_shift_limit": [ + 234, + 234 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.6252911354998e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 210, + 210 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.208142681345493e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.062283681158016e-11, + "brightness_limit": [ + -0.42035752534866333, + -0.42035752534866333 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.7038703896812137e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.484928157963548e-10, + "threshold": [ + 197, + 197 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.0499393792424527e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.761543222974638e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.1369342332281417e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -1.562347412109375, + -1.562347412109375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.9260683961874676, + "shift_limit_x": [ + -0.8490320444107056, + -0.8490320444107056 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9690501395137317e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.07958018779754639, + 0.07958018779754639 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.519542285454919e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.320453643798828, + 9.320453643798828 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.869305171022288e-09, + "max_holes": 16, + "max_height": 154, + "max_width": 154, + "min_holes": 16, + "min_height": 154, + "min_width": 154, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.77257565152031e-10, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.07393009371608261 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.92424004057269e-06, + "r_shift_limit": [ + 83, + 83 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.234448623378658e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 86, + 86 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.692368948011982e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 225, + 225 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2572643214800003e-10, + "brightness_limit": [ + 0.6322062015533447, + 0.6322062015533447 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.699261937098171e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.0974457266584698e-07, + "threshold": [ + 160, + 160 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.0655290173646924e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 8.70181722014376e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.4436935287090056e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -106.55009460449219, + -106.55009460449219 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.9363078404807155, + "shift_limit_x": [ + -0.44073671102523804, + -0.44073671102523804 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.89408013864597e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.7942038774490356, + 0.7942038774490356 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.725553050452099e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 10.0, + 10.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.094794779325726e-12, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.4742665089300962e-12, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.06368428014837435 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.537823294963746e-08, + "r_shift_limit": [ + -47, + -47 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -83, + -83 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.013109870538412505, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 48, + 48 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.186283539087538e-06, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.883426068512725e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.4108978509902954, + 1.4108978509902954 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.653484222983791e-11, + "threshold": [ + 20, + 20 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.105003368738428e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.08691818978938e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.097381591796875, + -0.097381591796875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.8306223750114441, + -0.8306223750114441 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.44068068265914917, + -0.44068068265914917 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.032015800476074, + 5.032015800476074 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.004360597175353836, + "max_holes": 16, + "max_height": 137, + "max_width": 137, + "min_holes": 16, + "min_height": 137, + "min_width": 137, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.254804457050828e-06, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9825160539310065 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.036228420247971016, + "r_shift_limit": [ + 38, + 38 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.016865052725386076, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 25, + 25 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.024671198235472147, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -23, + -23 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.016709765270179977, + "brightness_limit": [ + -0.017844021320343018, + -0.017844021320343018 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.959374049402967e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.5250946283340454, + 1.5250946283340454 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.6232486616917884e-08, + "threshold": [ + 219, + 219 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.2509613574876943e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.679752594882958e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -1.4484100341796875, + -1.4484100341796875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.001040195833997698, + "shift_limit_x": [ + 0.007558345794677734, + 0.007558345794677734 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.6836490631103516, + 0.6836490631103516 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.5354991811191974e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.02040433883667, + 7.02040433883667 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0034031976809286157, + "max_holes": 16, + "max_height": 149, + "max_width": 149, + "min_holes": 16, + "min_height": 149, + "min_width": 149, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.22469668331289228, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.676382258725573 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.032969455604553444, + "r_shift_limit": [ + 31, + 31 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.5876481323976108, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 8, + 8 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.3438764923582973e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 23, + 23 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.08965053579291382, + "brightness_limit": [ + 0.1073678731918335, + 0.1073678731918335 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.4637312165405791e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.650674710783476e-11, + "threshold": [ + 108, + 108 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.418715344495898e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1990626358101391e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -1.661346435546875, + -1.661346435546875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.054420411586761475, + -0.054420411586761475 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.34434211254119873, + 0.34434211254119873 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.9823220984347846e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9978195428848267, + 0.9978195428848267 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 98, + "max_width": 98, + "min_holes": 16, + "min_height": 98, + "min_width": 98, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0015832052445966943, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.2880707715195674 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.253904214944416e-08, + "r_shift_limit": [ + -53, + -53 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 45, + 45 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.5936228294108455e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -50, + -50 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.309700648607386e-08, + "brightness_limit": [ + -0.40641146898269653, + -0.40641146898269653 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.3984058390116723e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 8.752663612365723, + 8.752663612365723 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.3181240226720547e-11, + "threshold": [ + 177, + 177 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.4334597168313458e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.310739927418456e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 97.0159912109375, + 97.0159912109375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.9632004268819107e-07, + "shift_limit_x": [ + -0.002178668975830078, + -0.002178668975830078 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.8781017281884615, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.08135616779327393, + -0.08135616779327393 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3712324433162764e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.553297519683838, + 3.553297519683838 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1837222574715584e-12, + "max_holes": 16, + "max_height": 106, + "max_width": 106, + "min_holes": 16, + "min_height": 106, + "min_width": 106, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.48725172279079e-12, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.12188370671049864 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.19452656192934e-05, + "r_shift_limit": [ + 37, + 37 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00013219112480604336, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 48, + 48 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.923292088138844e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -116, + -116 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0.7465497255325317, + 0.7465497255325317 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.4608337741765353e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 5.19270658493042, + 5.19270658493042 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.93323903338399e-12, + "threshold": [ + 214, + 214 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 9.583145223057185e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.2697303081984579, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -4.5892486572265625, + -4.5892486572265625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.490498572413694e-08, + "shift_limit_x": [ + -0.0009624958038330078, + -0.0009624958038330078 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.300990358083751e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.005621910095214844, + -0.005621910095214844 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.50901985168457, + 7.50901985168457 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.90709318226945e-10, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0403996675322326e-09, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7300622793034615 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.265269901629336e-11, + "r_shift_limit": [ + -120, + -120 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00032228742358081375, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 90, + 90 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.022863886625445e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 67, + 67 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00010930553820641571, + "brightness_limit": [ + -0.21601027250289917, + -0.21601027250289917 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.63676287111446e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.0601742267608643, + 1.0601742267608643 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.772423129177933e-12, + "threshold": [ + 124, + 124 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.5440388228438843e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.5813926534779633e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.294750643234703e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.0370635986328125, + -0.0370635986328125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.14721263808164053, + "shift_limit_x": [ + -0.09705406427383423, + -0.09705406427383423 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.903388212838293e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0001582503318786621, + -0.0001582503318786621 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3652197544610628e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.031460762023926, + 4.031460762023926 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.2122617279253497e-09, + "max_holes": 16, + "max_height": 51, + "max_width": 51, + "min_holes": 16, + "min_height": 51, + "min_width": 51, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00020739166840548495, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8520878624989447 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.049009811288087235, + "r_shift_limit": [ + 23, + 23 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.2348558410559787e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -32, + -32 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.3684577185360255e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 67, + 67 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.07253661751747131, + "brightness_limit": [ + -0.18269020318984985, + -0.18269020318984985 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.04895339161157608, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2433586120605469, + 1.2433586120605469 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0001738158894700817, + "threshold": [ + 180, + 180 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.2623714247669794e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 9.585614081622325e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 141.54107666015625, + 141.54107666015625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.5301157169507353e-09, + "shift_limit_x": [ + -0.5103826522827148, + -0.5103826522827148 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.3729553529276658e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0008609294891357422, + 0.0008609294891357422 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.648986250485788e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0235823392868042, + 1.0235823392868042 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.564986728742952e-07, + "max_holes": 16, + "max_height": 69, + "max_width": 69, + "min_holes": 16, + "min_height": 69, + "min_width": 69, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0033707812472655585, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8259413720150421 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00229424251809629, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.7327409514166206e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.13659252566549007, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 2, + 2 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.1923524309738815e-07, + "brightness_limit": [ + 0.36307573318481445, + 0.36307573318481445 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.250925020032943e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.0756158828735352, + 1.0756158828735352 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 9.559893544393067e-06, + "threshold": [ + 185, + 185 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.529797720896151e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.619569630224034e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.6758154292093458e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 173.43588256835938, + 173.43588256835938 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.473009178203413e-06, + "shift_limit_x": [ + 0.0008263587951660156, + 0.0008263587951660156 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.105339399129164e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.00021129846572875977, + -0.00021129846572875977 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.478322259294419e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.943615913391113, + 6.943615913391113 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 210, + "max_width": 210, + "min_holes": 16, + "min_height": 210, + "min_width": 210, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0003104474833192962, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8607757978142012 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.463340409015498e-07, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -77, + -77 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5180675266577307e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -53, + -53 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.561932548329239e-06, + "brightness_limit": [ + -0.7333488464355469, + -0.7333488464355469 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2971900195535618e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.3473310470581055, + 6.3473310470581055 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.6331616825112854e-11, + "threshold": [ + 160, + 160 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 9.634039907231076e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.151425330209624e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.815372472849623e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 56.81114196777344, + 56.81114196777344 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.2363252123986772, + "shift_limit_x": [ + 0.05007672309875488, + 0.05007672309875488 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1216065494965878e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.004643082618713379, + -0.004643082618713379 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.709087862574961e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.2739715576171875, + 7.2739715576171875 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.7732376136336825e-06, + "max_holes": 16, + "max_height": 187, + "max_width": 187, + "min_holes": 16, + "min_height": 187, + "min_width": 187, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.763252344483476e-09, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7636500690601749 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.1898090289588075e-11, + "r_shift_limit": [ + -43, + -43 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.484549593702876e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.3811408928226967e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 83, + 83 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + -0.1085321307182312, + -0.1085321307182312 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.0583100984726673e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.4339368343353271, + 1.4339368343353271 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.00021390740874035856, + "threshold": [ + 124, + 124 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.981431180795787e-05 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.7171081665101345e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.3255020260439315e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 62.06571960449219, + 62.06571960449219 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.6078708462393236e-10, + "shift_limit_x": [ + 0.003370523452758789, + 0.003370523452758789 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.00965561426517e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0007154941558837891, + 0.0007154941558837891 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.1381645281156585, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.4212870597839355, + 1.4212870597839355 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.570088379989696e-09, + "max_holes": 16, + "max_height": 56, + "max_width": 56, + "min_holes": 16, + "min_height": 56, + "min_width": 56, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00011173259415504441, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8614496355143824 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.958374926209262e-11, + "r_shift_limit": [ + 82, + 82 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.248548195064064e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.8176230896377738e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -51, + -51 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.84825387977601e-05, + "brightness_limit": [ + 0.3704019784927368, + 0.3704019784927368 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0007127022866891645, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.291479767652495e-08, + "threshold": [ + 143, + 143 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.0635312243827578e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.00041244140726628964, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.90484619140625, + 0.90484619140625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9698492608274736e-11, + "shift_limit_x": [ + 0.02960503101348877, + 0.02960503101348877 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.27353504077441926, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.12427568435668945, + 0.12427568435668945 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.154734689935547e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9845567345619202, + 0.9845567345619202 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.426186871788498e-08, + "max_holes": 16, + "max_height": 68, + "max_width": 68, + "min_holes": 16, + "min_height": 68, + "min_width": 68, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1191194639799123e-10, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7251490365950142 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.131515083514415e-09, + "r_shift_limit": [ + -44, + -44 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00010539166396483779, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -255, + -255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.864768099937909e-05, + "brightness_limit": [ + -0.3045654296875, + -0.3045654296875 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.6639701080505713e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0006688055000267923, + "threshold": [ + 193, + 193 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.328512865722868e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3215886881964534e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -1.1669921875, + -1.1669921875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.519332536073289e-05, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.0185525175477606e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0019524097442626953, + 0.0019524097442626953 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.926887957226699e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.29024600982666, + 5.29024600982666 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.8614646871128026e-05, + "max_holes": 16, + "max_height": 207, + "max_width": 207, + "min_holes": 16, + "min_height": 207, + "min_width": 207, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.716430768033624e-05, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9990059840848375 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.680568301149631e-07, + "r_shift_limit": [ + -104, + -104 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.829020411794085e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.85781337430835e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.5832514181939624e-08, + "brightness_limit": [ + -0.5747126340866089, + -0.5747126340866089 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.5806113182472035e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 9.548723220825195, + 9.548723220825195 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.000261066618697757, + "threshold": [ + 9, + 9 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.5978563073719925e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.7228563013746054 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.2063750263484095e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -175.9344482421875, + -175.9344482421875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0614895609675266e-10, + "shift_limit_x": [ + -0.04937446117401123, + -0.04937446117401123 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1723691214789935e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6889354586601257, + -0.6889354586601257 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.310977786449455e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.491077899932861, + 7.491077899932861 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0003965079556893514, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.621596431977223e-07, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.2764837931110449 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00022276747148761156, + "r_shift_limit": [ + -25, + -25 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.9318923515164126e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 119, + 119 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.10623090011581837, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -21, + -21 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00600245099999297, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.9408910900650615e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 179, + 179 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.102623143204053e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 180.0, + 180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.03243374824523926, + 0.03243374824523926 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.591675156182985e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2442937381826915e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.742027282714844, + 4.742027282714844 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.001430364275809795, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.73670941247465e-06, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.885999832242835 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5822731909929444e-11, + "r_shift_limit": [ + -254, + -254 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.676734796007812e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 148, + 148 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.838121754725664e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0165981687605381, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.4747315602252242e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.5279266420500665e-06, + "threshold": [ + 43, + 43 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.5826069168680945 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.3224152084319018e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.321779749846611e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.380096435546875, + -0.380096435546875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.0752132665365934e-06, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.886324879273749e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8300493359565735, + -0.8300493359565735 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0799190118332727e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.309404373168945, + 8.309404373168945 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.05302171862828442, + "max_holes": 16, + "max_height": 163, + "max_width": 163, + "min_holes": 16, + "min_height": 163, + "min_width": 163, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0716304079353054e-13, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.3477658792280345 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.482895006026983e-09, + "r_shift_limit": [ + -10, + -10 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.484368081269831e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 58, + 58 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.061756818040177e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 246, + 246 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.021118071200603e-06, + "brightness_limit": [ + -0.4536174535751343, + -0.4536174535751343 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.2464791081691967e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.57529878616333, + 1.57529878616333 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.4983313485979514e-07, + "threshold": [ + 247, + 247 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.116066327257749e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -40.18937683105469, + -40.18937683105469 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.05971076667933e-09, + "shift_limit_x": [ + -0.03184354305267334, + -0.03184354305267334 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.8600869219680121, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.1947495937347412, + 0.1947495937347412 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.544554910984614e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.861926555633545, + 3.861926555633545 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.0979860004398285e-14, + "max_holes": 16, + "max_height": 39, + "max_width": 39, + "min_holes": 16, + "min_height": 39, + "min_width": 39, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.5095069356825595e-15, + "max_holes": 15, + "max_height": 14, + "max_width": 14, + "min_holes": 15, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.13990765163616758 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.2917654459880072e-05, + "r_shift_limit": [ + -50, + -50 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.935351404489655e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -66, + -66 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.338051763503535e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -223, + -223 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2861498532856785e-09, + "brightness_limit": [ + 0.28200089931488037, + 0.28200089931488037 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00013241440550430458, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 5.579436302185059, + 5.579436302185059 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.747602872292843e-06, + "threshold": [ + 165, + 165 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.042427833828551e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.7211189308320826e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.6247370004037428e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.599639892578125, + -0.599639892578125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0358388773900576e-06, + "shift_limit_x": [ + -0.5778015851974487, + -0.5778015851974487 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.010066321237394e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.6566892862319946, + 0.6566892862319946 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.561140537261963, + 7.561140537261963 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.318024204280472e-05, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.004979546734672824, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9948128241003239 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.334318031451854e-05, + "r_shift_limit": [ + 81, + 81 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.6801890351489085e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 87, + 87 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00411309863225906, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 65, + 65 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.6127615489098927e-05, + "brightness_limit": [ + 0.23226702213287354, + 0.23226702213287354 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00033569589140824974, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.97422621851249e-12, + "threshold": [ + 17, + 17 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -108.63634490966797, + -108.63634490966797 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.15207428780216e-09, + "shift_limit_x": [ + 0.2907142639160156, + 0.2907142639160156 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.5629924735619996e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.027712106704711914, + 0.027712106704711914 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9445576685864198e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.620899200439453, + 4.620899200439453 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 184, + "max_width": 184, + "min_holes": 16, + "min_height": 184, + "min_width": 184, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.022902135777337573, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9725302796149267 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.014498102533875068, + "r_shift_limit": [ + 71, + 71 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 175, + 175 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.7288033879317979, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 5, + 5 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.010930508432515751, + "brightness_limit": [ + -0.3515458106994629, + -0.3515458106994629 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.9866264341041437e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.002832543971949625, + "threshold": [ + 10, + 10 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.542436955296216e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.197475956622875e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.2656569017467116e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -1.637603759765625, + -1.637603759765625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.0679764569461344e-11, + "shift_limit_x": [ + 0.005929708480834961, + 0.005929708480834961 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.251008327004138e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0021418333053588867, + 0.0021418333053588867 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.4861254774453796e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 2.5100514888763428, + 2.5100514888763428 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.596626202484639e-05, + "max_holes": 16, + "max_height": 91, + "max_width": 91, + "min_holes": 16, + "min_height": 91, + "min_width": 91, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.546160099257475e-05, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.24284132080834464 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.9264771670584213e-10, + "r_shift_limit": [ + 36, + 36 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.697030874918481e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -186, + -186 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.2530688918540873e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -127, + -127 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.921380165891229e-13, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.3319108855977744e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2380154132843018, + 1.2380154132843018 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.711133632374852e-13, + "threshold": [ + 225, + 225 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.0573918735940758e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.9337276805738015e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.7638170484321908e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -44.77520751953125, + -44.77520751953125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.610984212900446e-10, + "shift_limit_x": [ + -0.9013475179672241, + -0.9013475179672241 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.6178159418233561e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.39739739894866943, + 0.39739739894866943 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.3812276266541872, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0290087461471558, + 1.0290087461471558 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.2249283365406427e-08, + "max_holes": 16, + "max_height": 111, + "max_width": 111, + "min_holes": 16, + "min_height": 111, + "min_width": 111, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.344223166940369e-14, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6187723324012279 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0027441844102591706, + "r_shift_limit": [ + 87, + 87 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0005007093529729376, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 69, + 69 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.847931321769572e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -60, + -60 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.01102511037803744, + "brightness_limit": [ + -0.189059317111969, + -0.189059317111969 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.563842479410533e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.3512108325958252, + 1.3512108325958252 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.9509170474069993e-06, + "threshold": [ + 164, + 164 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.398276176258662e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.249026584296863e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 147.50103759765625, + 147.50103759765625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.960468305847136e-10, + "shift_limit_x": [ + -0.8973681330680847, + -0.8973681330680847 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.728540491284834e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.64321368932724, + -0.64321368932724 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.6089724066194126e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.705970764160156, + 9.705970764160156 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.6793894359148072e-06, + "max_holes": 16, + "max_height": 104, + "max_width": 104, + "min_holes": 16, + "min_height": 104, + "min_width": 104, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00022495946905110031, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9854989793731637 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.01882522739470005, + "r_shift_limit": [ + -45, + -45 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.02679490505592419, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -27, + -27 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4053483699582542e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 58, + 58 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0.20340919494628906, + 0.20340919494628906 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.8488721234195564e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 5.46405029296875, + 5.46405029296875 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0018005295847710323, + "threshold": [ + 232, + 232 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.045405299059675e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.033498349558616e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -132.6158447265625, + -132.6158447265625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.6989850877143034e-12, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.467298255629369e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6770433783531189, + -0.6770433783531189 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.00046876204294310497, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9817285537719727, + 0.9817285537719727 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0010070664936457918, + "max_holes": 16, + "max_height": 96, + "max_width": 96, + "min_holes": 16, + "min_height": 96, + "min_width": 96, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.05430534595311176, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.896759658230414 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.585589775446509e-06, + "r_shift_limit": [ + -23, + -23 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.576654355237972e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.5417430418116425, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 13, + 13 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.021642752985557845, + "brightness_limit": [ + 0.11966001987457275, + 0.11966001987457275 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.16136930819757467, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1614222526550293, + 1.1614222526550293 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.002371059430745129, + "threshold": [ + 52, + 52 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.2381309356598505e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.5414619182692363e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.613808266776007e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -103.36395263671875, + -103.36395263671875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.816739210155154e-10, + "shift_limit_x": [ + 0.0008805990219116211, + 0.0008805990219116211 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.015470504760742188, + 0.015470504760742188 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4506332434446158e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.72033977508545, + 9.72033977508545 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.0376203417222445e-06, + "max_holes": 16, + "max_height": 73, + "max_width": 73, + "min_holes": 16, + "min_height": 73, + "min_width": 73, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00016944235549599257, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.27268915576941233 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.16914015285119266, + "r_shift_limit": [ + 4, + 4 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.01591380453383251, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 83, + 83 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00010611456003837422, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -49, + -49 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.1139596910166245e-06, + "brightness_limit": [ + 0.32762575149536133, + 0.32762575149536133 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.444880872071068e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1230970621109009, + 1.1230970621109009 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.00014577046014500016, + "threshold": [ + 219, + 219 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.1633652181974777e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 174.57327270507812, + 174.57327270507812 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.830849759656857e-13, + "shift_limit_x": [ + 0.9512306451797485, + 0.9512306451797485 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.5060126781463623, + 0.5060126781463623 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5415948505632307e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.8941142559051514, + 0.8941142559051514 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 202, + "max_width": 202, + "min_holes": 16, + "min_height": 202, + "min_width": 202, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00010035656656496878, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8145872767865279 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.42585839005205e-09, + "r_shift_limit": [ + 60, + 60 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.074626762303963e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -14, + -14 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.1912039009245395e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -57, + -57 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2417900742465941e-11, + "brightness_limit": [ + -0.34730052947998047, + -0.34730052947998047 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.7212770708193287e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.8596280813217163, + 0.8596280813217163 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.596598483008133e-08, + "threshold": [ + 90, + 90 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.2283753340511627e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 8.97332464503858e-16 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.778879038712613e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 85.2559814453125, + 85.2559814453125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.471669152214502e-10, + "shift_limit_x": [ + -0.9217223525047302, + -0.9217223525047302 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.596482625138961, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.06269073486328125, + 0.06269073486328125 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.1132143371881118e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.2160422801971436, + 3.2160422801971436 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.422515945638756e-11, + "max_holes": 16, + "max_height": 143, + "max_width": 143, + "min_holes": 16, + "min_height": 143, + "min_width": 143, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.554645646509733e-08, + "max_holes": 7, + "max_height": 14, + "max_width": 14, + "min_holes": 7, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.40351711597092854 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.2898087277025155e-08, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.940851216258398e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 72, + 72 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.705176623454587e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 15, + 15 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0035060961663713197, + "brightness_limit": [ + -0.12297874689102173, + -0.12297874689102173 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.5943587502711948e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 7.177958965301514, + 7.177958965301514 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.2957422624577226e-05, + "threshold": [ + 2, + 2 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.276258807938749e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2398151550165118e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.6485748291015625, + -0.6485748291015625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.437853486347766e-12, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.09944093206783844, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.05226767063140869, + 0.05226767063140869 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.772054672241211, + 4.772054672241211 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.3841171601475194e-06, + "max_holes": 16, + "max_height": 116, + "max_width": 116, + "min_holes": 16, + "min_height": 116, + "min_width": 116, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.2160870262256426e-09, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.897027606267028 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.006607259623706341, + "r_shift_limit": [ + 56, + 56 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -160, + -160 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.199688391451944e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -13, + -13 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0003088322790652208, + "brightness_limit": [ + -0.14390796422958374, + -0.14390796422958374 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2560070292850535e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.992195725440979, + 1.992195725440979 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.441689903390894e-07, + "threshold": [ + 80, + 80 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.315022994677748e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.466221193423198e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 1.109527587890625, + 1.109527587890625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.219950858443018e-10, + "shift_limit_x": [ + 0.0001329183578491211, + 0.0001329183578491211 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1490989921864755e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.7327988147735596, + -0.7327988147735596 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.236174251901856e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.636330604553223, + 6.636330604553223 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00015298937839745494, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1927877406957645e-05, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9929052499987852 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4437092838505466e-07, + "r_shift_limit": [ + -80, + -80 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.9842541172096773e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 91, + 91 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00010145934036818842, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 34, + 34 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.3330636191505086e-10, + "brightness_limit": [ + -0.22016090154647827, + -0.22016090154647827 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.43094260333455e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 9.990278244018555, + 9.990278244018555 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.000626301609572e-08, + "threshold": [ + 239, + 239 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 9.175981392945727e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.83579135000432e-15 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.5429772917519433e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 101.62042236328125, + 101.62042236328125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.066173723887941e-13, + "shift_limit_x": [ + -0.5367082357406616, + -0.5367082357406616 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.3999569790049762, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.035869598388671875, + -0.035869598388671875 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5650170588355734e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.4512507915496826, + 3.4512507915496826 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.2657201190569585e-06, + "max_holes": 16, + "max_height": 72, + "max_width": 72, + "min_holes": 16, + "min_height": 72, + "min_width": 72, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00011792575108225678, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5997519063665804 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.002865022838773809, + "r_shift_limit": [ + 58, + 58 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.18285110592842102, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 0, + 0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0021740132873344087, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 32, + 32 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0013882407317195589, + "brightness_limit": [ + -0.11613839864730835, + -0.11613839864730835 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.1018311443810784e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.9909716248512268, + 0.9909716248512268 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 28, + 28 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.754212085070432e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.436810381399063e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3072823798556213e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -3.6247406005859375, + -3.6247406005859375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.3565834164619446, + -0.3565834164619446 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.692820010941915e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6993721723556519, + -0.6993721723556519 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.1114537410808321e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9888375997543335, + 0.9888375997543335 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.384349470845924e-07, + "max_holes": 16, + "max_height": 176, + "max_width": 176, + "min_holes": 16, + "min_height": 176, + "min_width": 176, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.006816811365723263, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8039043567177917 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.961142792048127e-14, + "r_shift_limit": [ + -69, + -69 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.602732884447676e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 1, + 1 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.7322500256819748e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -63, + -63 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.1748603543741575e-09, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.545770410505767e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 9.135987670171933e-12, + "threshold": [ + 155, + 155 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.3538131008262526e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7936257179368973e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -3.2841339111328125, + -3.2841339111328125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.8584144115447998, + -0.8584144115447998 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.7312153088115281, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.01902240514755249, + -0.01902240514755249 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.886552325773392e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9945353269577026, + 0.9945353269577026 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.344857799216527e-11, + "max_holes": 16, + "max_height": 140, + "max_width": 140, + "min_holes": 16, + "min_height": 140, + "min_width": 140, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.400279395896059e-12, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.2687827214250389 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.0235091647241144e-08, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0003643464172725652, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 53, + 53 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.006585759899069954, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 10, + 10 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.8474652271610976e-06, + "brightness_limit": [ + -0.2231336236000061, + -0.2231336236000061 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.627629384930892e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.107009589081992e-05, + "threshold": [ + 185, + 185 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.640622752795725e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.00112131903675e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -1.8789825439453125, + -1.8789825439453125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.45416831970214844, + -0.45416831970214844 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5288202131911696e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -1.0, + -1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.657626161556517e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.878785610198975, + 6.878785610198975 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.508950475112889e-12, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.006429833711638e-07, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9929742024101622 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0426092005823978e-05, + "r_shift_limit": [ + 170, + 170 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4040584219714158e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 76, + 76 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -36, + -36 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.008850799579592727, + "brightness_limit": [ + -0.1767895221710205, + -0.1767895221710205 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.930199820983481e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0009796194499358535, + "threshold": [ + 223, + 223 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.6137838452711876e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.1889733230583506e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -1.0412139892578125, + -1.0412139892578125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.307069799467522e-07, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.400295608250982e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0020215511322021484, + 0.0020215511322021484 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.014203457783204532, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0915682315826416, + 1.0915682315826416 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.727547334590885e-05, + "max_holes": 16, + "max_height": 205, + "max_width": 205, + "min_holes": 16, + "min_height": 205, + "min_width": 205, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.851674609516131e-07, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9758533081809455 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.548115683992876e-05, + "r_shift_limit": [ + 71, + 71 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0972330986407837e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 78, + 78 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.470909221143489e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 3, + 3 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0010453860895083544, + "brightness_limit": [ + -0.33861762285232544, + -0.33861762285232544 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.972394511483764e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.0634000301361084, + 1.0634000301361084 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.8431572456042733e-08, + "threshold": [ + 123, + 123 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.2084107292714594e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.164631181389776e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 180.0, + 180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.271681638326453e-08, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.49378203492764783, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.1385718584060669, + 0.1385718584060669 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.983680725097656, + 7.983680725097656 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.89791649233124e-12, + "max_holes": 16, + "max_height": 73, + "max_width": 73, + "min_holes": 16, + "min_height": 73, + "min_width": 73, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.4596614355805147e-10, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5050768748684565 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.3319116905500116e-06, + "r_shift_limit": [ + 59, + 59 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.906250332716846e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 64, + 64 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.9632935214867736e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.845727196983945e-07, + "brightness_limit": [ + -0.24340850114822388, + -0.24340850114822388 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 2.2269465923309326, + 2.2269465923309326 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.1163180403434663e-10, + "threshold": [ + 212, + 212 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.944032717136568e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.000866893428075e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.550624200843373e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.355255126953125, + 0.355255126953125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.838044970107156e-08, + "shift_limit_x": [ + 0.9966976642608643, + 0.9966976642608643 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1351117056961605e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.7205856442451477, + -0.7205856442451477 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.3173533451147339, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9822182655334473, + 0.9822182655334473 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.7298835461365673e-10, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.156709592548051e-07, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6825977142692474 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.596745715761838e-06, + "r_shift_limit": [ + -110, + -110 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.6293216697176846e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -90, + -90 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -255, + -255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0008038519581525516, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.1994705999711452e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1957489252090454, + 1.1957489252090454 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.377664936580282e-10, + "threshold": [ + 167, + 167 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.268354995162304e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.09257942482466142, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.7776031494140625, + -0.7776031494140625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9438037750865188e-10, + "shift_limit_x": [ + -0.9365544319152832, + -0.9365544319152832 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.943266596257125e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -1.0, + -1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.014423879050987e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.6079578399658203, + 3.6079578399658203 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0006104328126797579, + "max_holes": 16, + "max_height": 205, + "max_width": 205, + "min_holes": 16, + "min_height": 205, + "min_width": 205, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.557662400990631e-07, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9059983693860383 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1069901939553262e-10, + "r_shift_limit": [ + -108, + -108 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4326430077180408e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -104, + -104 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.2784032606284907e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 96, + 96 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.077353232136546e-07, + "brightness_limit": [ + -0.3539274334907532, + -0.3539274334907532 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.033560924020125e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.36159610748291, + 6.36159610748291 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.657435551156423e-10, + "threshold": [ + 48, + 48 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.9086387438565211 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 8.148980230493774e-15 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7274365701828307e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -50.78782653808594, + -50.78782653808594 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.405931403266004e-15, + "shift_limit_x": [ + 0.0012532472610473633, + 0.0012532472610473633 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.624108949630005e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.2934197187423706, + 0.2934197187423706 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.659707493136727e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.713840484619141, + 4.713840484619141 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.116445873691341e-12, + "max_holes": 16, + "max_height": 28, + "max_width": 28, + "min_holes": 16, + "min_height": 28, + "min_width": 28, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.948182902808335e-10, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.09136059693305976 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00022291024172492457, + "r_shift_limit": [ + 43, + 43 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0006398322900598649, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.760294613775367e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.03920668826687601, + "brightness_limit": [ + -0.358528196811676, + -0.358528196811676 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.868288919494768e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.8129700422286987, + 0.8129700422286987 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.000720118070678781, + "threshold": [ + 5, + 5 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.8424653469118587e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.173235336704198e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.499023059960176e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.21612548828125, + -0.21612548828125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.304696067584538e-07, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.719652075101363e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8161738514900208, + -0.8161738514900208 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 10.0, + 10.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.854435044118553e-11, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00018832065965340445, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9589234215930185 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00035892142802181753, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 195, + 195 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4344333783066716e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 2, + 2 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + -0.14668679237365723, + -0.14668679237365723 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00022054032722336123, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.420596944928987e-06, + "threshold": [ + 60, + 60 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.8833842627597647e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4530594953903694e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 6.525787353515625, + 6.525787353515625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.854005043756216e-07, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.3099562170926138, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.86836702883916e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 2.2525100708007812, + 2.2525100708007812 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.036094496254506225, + "max_holes": 16, + "max_height": 176, + "max_width": 176, + "min_holes": 16, + "min_height": 176, + "min_width": 176, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.668817137832542e-08, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6533613539364678 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4430371814782684e-09, + "r_shift_limit": [ + -157, + -157 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.854833582503641e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -131, + -131 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.805388762047316e-14, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -82, + -82 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0016288808313024566, + "brightness_limit": [ + -1.0, + -1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.2284913524835424e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.322981714161234e-12, + "threshold": [ + 128, + 128 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.4542928154567557e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.182153116573098e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.473969636199042e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.3077850341796875, + 0.3077850341796875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.9974991679191589, + "shift_limit_x": [ + 0.009221792221069336, + 0.009221792221069336 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.128404750111654e-15, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.47896504402160645, + 0.47896504402160645 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.5515468032875586e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.849860191345215, + 4.849860191345215 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.028941813918796e-08, + "max_holes": 16, + "max_height": 107, + "max_width": 107, + "min_holes": 16, + "min_height": 107, + "min_width": 107, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1576596317274756e-13, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.0008704217469371889 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00015761566967661955, + "r_shift_limit": [ + -66, + -66 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0015296611378805003, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0001694465029410822, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.023474568501114845, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.2520270260344864e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.02062864482529747, + "threshold": [ + 151, + 151 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.874410175572198e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.470841585064998e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 106.93438720703125, + 106.93438720703125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2755412293519849e-10, + "shift_limit_x": [ + -0.9015569090843201, + -0.9015569090843201 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0879758255011807e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8674215078353882, + -0.8674215078353882 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9528029561042786, + 0.9528029561042786 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.022267991928460962, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.35114056149453e-10, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9317717305538762 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0028393249958753586, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.228214707205676e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 45, + 45 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.440003315836084e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -62, + -62 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.54667635410837e-07, + "brightness_limit": [ + -1.0, + -1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2704321374807184e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 5.986118793487549, + 5.986118793487549 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0005285466103552017, + "threshold": [ + 131, + 131 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.9685577793527926 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.367430153098039e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.409470954233773e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.984917563504465e-12, + "shift_limit_x": [ + 0.5327054262161255, + 0.5327054262161255 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.7820796853355585e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.598484218120575, + -0.598484218120575 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.244317270762214e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.760372638702393, + 7.760372638702393 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.964897480666412e-11, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.932610261804791e-10, + "max_holes": 2, + "max_height": 14, + "max_width": 14, + "min_holes": 2, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.028057369756844586 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.4930504896275227e-05, + "r_shift_limit": [ + -97, + -97 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1518740061492157e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 10, + 10 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.006764451521911297, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -79, + -79 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0004189431706998724, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00011523842947828988, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0066398361844653975, + "threshold": [ + 48, + 48 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.00030958665383735984 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.249062777732365e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -5.556854248046875, + -5.556854248046875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0012266754986993353, + "shift_limit_x": [ + -0.7710492014884949, + -0.7710492014884949 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.005088718954296356, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.020278453826904297, + 0.020278453826904297 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.7919207499478918e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.123357057571411, + 3.123357057571411 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.0957292666349974e-10, + "max_holes": 16, + "max_height": 172, + "max_width": 172, + "min_holes": 16, + "min_height": 172, + "min_width": 172, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.12841801296993083, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8509645275716436 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.2959952091808553, + "r_shift_limit": [ + 18, + 18 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.004891468245746544, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 81, + 81 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0015212432966617284, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -62, + -62 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.946829526268608e-08, + "brightness_limit": [ + 0.16466939449310303, + 0.16466939449310303 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00022804436266251824, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 4.251823902130127, + 4.251823902130127 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 152, + 152 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.4794334908004885e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.118055545400387e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.986740850652241e-06, + "shift_limit_x": [ + -9.649991989135742e-05, + -9.649991989135742e-05 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.582050883501042e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.004372298717498779, + -0.004372298717498779 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.252377739885471e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.1135814189910889, + 1.1135814189910889 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.3223481061344373e-08, + "max_holes": 16, + "max_height": 181, + "max_width": 181, + "min_holes": 16, + "min_height": 181, + "min_width": 181, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0003092214458656744, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6970506439758029 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.79005474491046e-08, + "r_shift_limit": [ + 19, + 19 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0008935406421154563, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0008117067824952723, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.012251467444002628, + "brightness_limit": [ + 0.4034998416900635, + 0.4034998416900635 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0021128731314092875, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 8.489028930664062, + 8.489028930664062 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.4185572823400596e-07, + "threshold": [ + 165, + 165 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.826438419491859e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.1589288223483372e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 18.0775146484375, + 18.0775146484375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.7225821018218994, + 0.7225821018218994 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2983290089372819e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9945898652076721, + 0.9945898652076721 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00023961838340192526, + "max_holes": 16, + "max_height": 92, + "max_width": 92, + "min_holes": 16, + "min_height": 92, + "min_width": 92, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9836852490927555 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.011854617497442321, + "r_shift_limit": [ + 28, + 28 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00016922699977848545, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0010531231291149162, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 61, + 61 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.725395385946513e-05, + "brightness_limit": [ + 0.12235784530639648, + 0.12235784530639648 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.112585336637112e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.067967176437378, + 1.067967176437378 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 74, + 74 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 7.791248817159452e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.119474035565536e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3543994290906885e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -74.64105987548828, + -74.64105987548828 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.26235830783843994, + -0.26235830783843994 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.8140165740641558e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.7504702806472778, + -0.7504702806472778 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7285625707119873e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.819273948669434, + 8.819273948669434 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0003384747344125534, + "max_holes": 16, + "max_height": 106, + "max_width": 106, + "min_holes": 16, + "min_height": 106, + "min_width": 106, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1991804317312894e-06, + "max_holes": 15, + "max_height": 14, + "max_width": 14, + "min_holes": 15, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9864232052705623 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0005884302443381756, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00045660508189097546, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 48, + 48 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4380269990205141e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -46, + -46 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + -0.2994273900985718, + -0.2994273900985718 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.8650824099949036e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 94, + 94 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.955069591832986e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.4736127519708273e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.5440243482589722, + -0.5440243482589722 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.6847332623405893e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.871779918670654, + 7.871779918670654 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.999043988217046e-07, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0015859503764659166, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9973544334714979 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.108920794737843e-07, + "r_shift_limit": [ + -58, + -58 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0103325587992531, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -43, + -43 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.589747003842827e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -45, + -45 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0009445184052596922, + "brightness_limit": [ + 0.17835044860839844, + 0.17835044860839844 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2761787741762413e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2699590921401978, + 1.2699590921401978 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 25, + 25 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.5112950379556676e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5232072678186521e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 106.53411865234375, + 106.53411865234375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.106505733639766e-05, + "shift_limit_x": [ + 0.0018646717071533203, + 0.0018646717071533203 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.468956747044104e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.005164146423339844, + 0.005164146423339844 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7956349106770445e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.311003684997559, + 7.311003684997559 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1955671815229657e-05, + "max_holes": 16, + "max_height": 183, + "max_width": 183, + "min_holes": 16, + "min_height": 183, + "min_width": 183, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0038054149609842713, + "max_holes": 13, + "max_height": 14, + "max_width": 14, + "min_holes": 13, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9848382582868916 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0004438382800187636, + "r_shift_limit": [ + -78, + -78 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0005172416614737316, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 137, + 137 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00042212022655290643, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.020657223619966247, + "brightness_limit": [ + 0.13793814182281494, + 0.13793814182281494 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.8788148640408245e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 4.485957145690918, + 4.485957145690918 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.657282626835169e-06, + "threshold": [ + 26, + 26 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.947027196374983e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.918588019380158e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -27.620986938476562, + -27.620986938476562 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.405217774498528e-05, + "shift_limit_x": [ + -0.0009709596633911133, + -0.0009709596633911133 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.33758819103240967, + 0.33758819103240967 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.178346349891189e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.998055458068848, + 6.998055458068848 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.012225578199748e-08, + "max_holes": 16, + "max_height": 100, + "max_width": 100, + "min_holes": 16, + "min_height": 100, + "min_width": 100, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.321331957780325e-05, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9778704826898033 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.008086068015386472, + "r_shift_limit": [ + 72, + 72 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0002451171817803022, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -71, + -71 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.010434956209461888, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -32, + -32 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.003687712721080205, + "brightness_limit": [ + 0.3458521366119385, + 0.3458521366119385 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.518851359289043e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.00010856695204513635, + "threshold": [ + 128, + 128 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 8.02094309924271e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.838154148175516e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 115.99542236328125, + 115.99542236328125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.274294324266365e-10, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.537628844116225e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8980655670166016, + -0.8980655670166016 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.804042816162109, + 4.804042816162109 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0017362627138941544, + "max_holes": 16, + "max_height": 101, + "max_width": 101, + "min_holes": 16, + "min_height": 101, + "min_width": 101, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.006175625170810495, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9695256640320175 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.6196794358408484e-05, + "r_shift_limit": [ + -88, + -88 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.2535272640494169e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -28, + -28 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.3917020400358061e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.758386092163208e-10, + "brightness_limit": [ + -0.04399669170379639, + -0.04399669170379639 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.998882727587471e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.5789011716842651, + 0.5789011716842651 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.5301054667063027e-11, + "threshold": [ + 117, + 117 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.3812856918441143e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.1529931059781864e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -8.171310424804688, + -8.171310424804688 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.202818781760119e-10, + "shift_limit_x": [ + -0.5860891342163086, + -0.5860891342163086 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.1408148557760425e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.010373353958129883, + -0.010373353958129883 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4406080082944698e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.253268241882324, + 5.253268241882324 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.850729905754226e-12, + "max_holes": 16, + "max_height": 176, + "max_width": 176, + "min_holes": 16, + "min_height": 176, + "min_width": 176, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.7985970663578143e-06, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9999660395672404 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.3703179314413324e-09, + "r_shift_limit": [ + -3, + -3 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.8917517749679983e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.0716567307531107e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 100, + 100 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.730795917085917e-11, + "brightness_limit": [ + -0.317144513130188, + -0.317144513130188 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.1999600976031992e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.7920244336128235, + 0.7920244336128235 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.226697587408125e-05, + "threshold": [ + 245, + 245 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.0646211265922825e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.807947024298642e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -76.62747955322266, + -76.62747955322266 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.9745995596865953, + "shift_limit_x": [ + 0.07273697853088379, + 0.07273697853088379 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.398383791338902e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.4743320345878601, + -0.4743320345878601 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.190480053608894e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.954122543334961, + 6.954122543334961 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.655590551951688e-10, + "max_holes": 16, + "max_height": 105, + "max_width": 105, + "min_holes": 16, + "min_height": 105, + "min_width": 105, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0916041054191996e-10, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.02533319177248472 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.165645745064314e-05, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.318526262937425e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -70, + -70 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.096159422264963e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.1746038979707461e-06, + "brightness_limit": [ + -0.08809101581573486, + -0.08809101581573486 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.499635389838349e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 8.481718063354492, + 8.481718063354492 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.032274141565843e-12, + "threshold": [ + 150, + 150 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.799407565668385e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0204419567794479e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -163.25961303710938, + -163.25961303710938 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.8996184758630537e-09, + "shift_limit_x": [ + -0.006741046905517578, + -0.006741046905517578 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.9072877168655396, + 0.9072877168655396 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.146662011837961e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.6258327960968018, + 3.6258327960968018 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1970645043333464e-07, + "max_holes": 16, + "max_height": 71, + "max_width": 71, + "min_holes": 16, + "min_height": 71, + "min_width": 71, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.140623716566809e-07, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9999265239723242 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.023612733484178028, + "r_shift_limit": [ + 64, + 64 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.03515653274504693, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -33, + -33 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.001234472557698027, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 63, + 63 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.03604487011332491, + "brightness_limit": [ + 0.01671302318572998, + 0.01671302318572998 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.0673150427464861e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.3582119941711426, + 1.3582119941711426 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.9035718943796474e-11, + "threshold": [ + 149, + 149 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.647603906661072e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.8488586808382915e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 77.2408447265625, + 77.2408447265625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.45842952062773e-07, + "shift_limit_x": [ + -0.9929887056350708, + -0.9929887056350708 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.3854580783477613e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.5786327123641968, + 0.5786327123641968 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.1147899627685547, + 1.1147899627685547 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.493178457699686e-06, + "max_holes": 16, + "max_height": 215, + "max_width": 215, + "min_holes": 16, + "min_height": 215, + "min_width": 215, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0010647619686052073, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9028731855892306 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -42, + -42 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.003285367274656892, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.05590935168330624, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -31, + -31 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00881258205538471, + "brightness_limit": [ + 0.3205970525741577, + 0.3205970525741577 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.3914974137237221e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.446076244313051e-07, + "threshold": [ + 228, + 228 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -115.76251983642578, + -115.76251983642578 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.6541666696119873e-08, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.4504995346069336, + 0.4504995346069336 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3245754643059338e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.94747257232666, + 6.94747257232666 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0357274169467264e-09, + "max_holes": 16, + "max_height": 211, + "max_width": 211, + "min_holes": 16, + "min_height": 211, + "min_width": 211, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.641944995840814e-07, + "max_holes": 7, + "max_height": 14, + "max_width": 14, + "min_holes": 7, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9319908301356726 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.051083539860145244, + "r_shift_limit": [ + -33, + -33 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.2256454312577778e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 86, + 86 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.031691929793555396, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 16, + 16 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.937981589373715e-06, + "brightness_limit": [ + 0.2777808904647827, + 0.2777808904647827 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 9.727256774902344, + 9.727256774902344 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.2595849664135284e-05, + "threshold": [ + 26, + 26 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.1763466009568316e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.6541782238705197e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9014245143407918e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -67.07622528076172, + -67.07622528076172 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0245697879805804e-10, + "shift_limit_x": [ + 0.043137550354003906, + 0.043137550354003906 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.4750356674194336, + 0.4750356674194336 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.71236323656769e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.922677993774414, + 7.922677993774414 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 146, + "max_width": 146, + "min_holes": 16, + "min_height": 146, + "min_width": 146, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.726277293035224e-08, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9171849401372938 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.771760514075016e-12, + "r_shift_limit": [ + 62, + 62 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -168, + -168 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.897178045419959e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.639010249971176e-05, + "brightness_limit": [ + 0.16889548301696777, + 0.16889548301696777 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.1808463234694489e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.3846356868743896, + 1.3846356868743896 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.4483439289161526e-09, + "threshold": [ + 204, + 204 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.50938279325419e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.1481582735320434e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0104059901280221e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -97.1659164428711, + -97.1659164428711 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.3096240303559483, + "shift_limit_x": [ + -0.06647729873657227, + -0.06647729873657227 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.205244867106011e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8752449154853821, + -0.8752449154853821 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.0253032505671707e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.993778645992279, + 0.993778645992279 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.444669251197367e-07, + "max_holes": 16, + "max_height": 221, + "max_width": 221, + "min_holes": 16, + "min_height": 221, + "min_width": 221, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.506165182046053e-12, + "max_holes": 7, + "max_height": 14, + "max_width": 14, + "min_holes": 7, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.690357073898151 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + 58, + 58 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00028598924272094095, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -69, + -69 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.6260093757666141, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 9, + 9 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.683282117592171e-05, + "brightness_limit": [ + -0.2351168394088745, + -0.2351168394088745 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.273819659080201e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.0362677574157715, + 6.0362677574157715 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.62809421843704e-11, + "threshold": [ + 119, + 119 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 8.431543063848219e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.107019840662038e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 157.05633544921875, + 157.05633544921875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.0158812410593006e-10, + "shift_limit_x": [ + -0.632915735244751, + -0.632915735244751 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.499958704075761e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0019190311431884766, + 0.0019190311431884766 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.660884141921997, + 3.660884141921997 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00018053842046921072, + "max_holes": 16, + "max_height": 118, + "max_width": 118, + "min_holes": 16, + "min_height": 118, + "min_width": 118, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.8054401193034954e-08, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.3734567169298617 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.1651489078067243e-05, + "r_shift_limit": [ + 44, + 44 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.279035404459102e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -43, + -43 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.07935731461601314, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -10, + -10 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0021293389626318715, + "brightness_limit": [ + -0.3052375912666321, + -0.3052375912666321 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.139158784614558e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.9037584662437439, + 0.9037584662437439 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.918549425969095e-10, + "threshold": [ + 20, + 20 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.706686005285603e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.719582940345713e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -153.21572875976562, + -153.21572875976562 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.9023606777191162, + 0.9023606777191162 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.746063498468902e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.7153587341308594, + -0.7153587341308594 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2801894970366924e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.434674263000488, + 5.434674263000488 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.2906150568309638e-06, + "max_holes": 16, + "max_height": 151, + "max_width": 151, + "min_holes": 16, + "min_height": 151, + "min_width": 151, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.918424988587606 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.931950125022013e-09, + "r_shift_limit": [ + 72, + 72 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0002766411678601019, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00015120244467601088, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -48, + -48 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.906758050292813e-12, + "brightness_limit": [ + 0.0849313735961914, + 0.0849313735961914 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.31764388583672e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 9.857807269118722e-10, + "threshold": [ + 247, + 247 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 6.032616737258717e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.2005724811465637e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.2681884765625, + -0.2681884765625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.11530155451163804, + "shift_limit_x": [ + -0.050142526626586914, + -0.050142526626586914 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.03848886489868164, + -0.03848886489868164 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0998349774334087e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.088305473327637, + 9.088305473327637 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0529275981121485e-09, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.948766366666605e-06, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8842510655733613 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.0170028330634405e-07, + "r_shift_limit": [ + -138, + -138 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.413705775434732e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -58, + -58 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0032579450663709764, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 71, + 71 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.883345030543351e-07, + "brightness_limit": [ + 0.2187201976776123, + 0.2187201976776123 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.901605129968556e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.5006046295166016, + 1.5006046295166016 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.5564761295341033e-05, + "threshold": [ + 60, + 60 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 8.66252367548925e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -24.398880004882812, + -24.398880004882812 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.2534628702073387e-10, + "shift_limit_x": [ + 0.6319872140884399, + 0.6319872140884399 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.607193972015665e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.00846707820892334, + -0.00846707820892334 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 10.0, + 10.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.000727517468235666, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.893865322559137e-05, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.995938234178656 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.4590240496709773e-09, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.981717223334546e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -48, + -48 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.254596524056746e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 94, + 94 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.002635772107169032, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.841568222560701e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 8.67695140838623, + 8.67695140838623 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.246238972940755e-09, + "threshold": [ + 40, + 40 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.4472660251512206e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.537319930727888e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 24.117523193359375, + 24.117523193359375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.28303267662685e-12, + "shift_limit_x": [ + -0.274496853351593, + -0.274496853351593 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.37223583459854126, + -0.37223583459854126 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.8940677471488456, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9600318670272827, + 0.9600318670272827 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.3851801489075646e-13, + "max_holes": 16, + "max_height": 138, + "max_width": 138, + "min_holes": 16, + "min_height": 138, + "min_width": 138, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.459012937073477e-13, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.10328848535229096 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.009063177292723e-09, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.0050413429106677e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 34, + 34 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.02213882420472002, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -39, + -39 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.769690243236255e-07, + "brightness_limit": [ + -1.0, + -1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.2477742283851757e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 8.480948448181152, + 8.480948448181152 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.1042327450837009e-11, + "threshold": [ + 32, + 32 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.3088897011419645e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.7263474374120714e-05 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4492829605400841e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -49.00929260253906, + -49.00929260253906 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.387903094291687, + 0.387903094291687 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.150235872797272e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.7626900672912598, + -0.7626900672912598 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.691827774047852, + 7.691827774047852 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.874765076888126e-08, + "max_holes": 16, + "max_height": 167, + "max_width": 167, + "min_holes": 16, + "min_height": 167, + "min_width": 167, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.01183941404039629, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9659840664897476 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0011749593122492227, + "r_shift_limit": [ + -47, + -47 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.772185581523113e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -105, + -105 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.11377021797153208, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -6, + -6 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.01546096205720554, + "brightness_limit": [ + 0.9990272521972656, + 0.9990272521972656 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 3.0096232891082764, + 3.0096232891082764 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.016294186722900506, + "threshold": [ + 139, + 139 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.9954031071926044e-05 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.05733954906463623, + 0.05733954906463623 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.425355989688339e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -1.0, + -1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.424339049964498e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.851186752319336, + 8.851186752319336 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.9881505077542013e-06, + "max_holes": 16, + "max_height": 140, + "max_width": 140, + "min_holes": 16, + "min_height": 140, + "min_width": 140, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.07239450598455743, + "max_holes": 13, + "max_height": 14, + "max_width": 14, + "min_holes": 13, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7808746241281139 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5729023478792625e-08, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.7779748353925388e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 144, + 144 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.86527378893193e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -255, + -255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.1852372650590637e-05, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.025102574397526e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 2.0755844116210938, + 2.0755844116210938 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.985366570125981e-08, + "threshold": [ + 92, + 92 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.4552033791285055 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0195248625336095e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -44.578704833984375, + -44.578704833984375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.133145315344874e-13, + "shift_limit_x": [ + -0.5340121984481812, + -0.5340121984481812 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.574554412570457e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -1.0, + -1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.983885220781497e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.230986595153809, + 6.230986595153809 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0407090057184072e-07, + "max_holes": 16, + "max_height": 136, + "max_width": 136, + "min_holes": 16, + "min_height": 136, + "min_width": 136, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.647734875045479e-08, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5447156810980506 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.15908213776837243, + "r_shift_limit": [ + -54, + -54 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 19, + 19 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0015179154621056679, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 56, + 56 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + -0.3167344331741333, + -0.3167344331741333 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.598263166687462e-10, + "threshold": [ + 28, + 28 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.0040861529088079e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.2114380357703305e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.635056908912471e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 130.20062255859375, + 130.20062255859375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.694790415883229e-09, + "shift_limit_x": [ + -0.6100050806999207, + -0.6100050806999207 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.231830837397396e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.013039231300354004, + 0.013039231300354004 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.807095793321657e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.1150617599487305, + 7.1150617599487305 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1086531310339686e-05, + "max_holes": 16, + "max_height": 132, + "max_width": 132, + "min_holes": 16, + "min_height": 132, + "min_width": 132, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.683693491997932e-05, + "max_holes": 13, + "max_height": 14, + "max_width": 14, + "min_holes": 13, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8393319160924493 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.205258227763588e-08, + "r_shift_limit": [ + -83, + -83 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.1192426499376964, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 0, + 0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0003879769129621069, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.3989583012311637e-06, + "brightness_limit": [ + -0.249492347240448, + -0.249492347240448 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.810305791886447e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.0492386099115006e-11, + "threshold": [ + 66, + 66 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.927056300835038e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.1309691219133134e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.3792088330284597e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -11.260665893554688, + -11.260665893554688 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1636944870733645e-07, + "shift_limit_x": [ + -0.9228034019470215, + -0.9228034019470215 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.8556595870076122e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.7824314832687378, + -0.7824314832687378 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.235587120056152, + 8.235587120056152 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.3585512891588022e-09, + "max_holes": 16, + "max_height": 213, + "max_width": 213, + "min_holes": 16, + "min_height": 213, + "min_width": 213, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.004473573210300452, + "max_holes": 15, + "max_height": 14, + "max_width": 14, + "min_holes": 15, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8758360856909981 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00020796097170367248, + "r_shift_limit": [ + 92, + 92 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.020200135437304367, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -40, + -40 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.821629864760863e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -50, + -50 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.000305584047982024, + "brightness_limit": [ + 0.3291947841644287, + 0.3291947841644287 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00013326274170966101, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.5940031409263611, + 0.5940031409263611 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.6575449233631766e-08, + "threshold": [ + 177, + 177 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 9.158990126635015e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.03059845629753477 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.85135052330877e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -1.7409210205078125, + -1.7409210205078125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.959561824798584, + -0.959561824798584 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.6511154174804688, + 0.6511154174804688 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.867079289822649e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.9967265129089355, + 3.9967265129089355 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 96, + "max_width": 96, + "min_holes": 16, + "min_height": 96, + "min_width": 96, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00028926487276374063, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9482505042142083 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0004912117402763004, + "r_shift_limit": [ + -88, + -88 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.578304856680757e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -181, + -181 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -65, + -65 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.468875731104203e-14, + "brightness_limit": [ + -0.6303600072860718, + -0.6303600072860718 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.3187407931002895e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.3045679857167924e-12, + "threshold": [ + 62, + 62 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.89747507389084e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.1542563887032616e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.438059222572515e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -41.58015441894531, + -41.58015441894531 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.6159572005271912, + -0.6159572005271912 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.518026892361283e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.9666076898574829, + 0.9666076898574829 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.576924205745456e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.094806671142578, + 7.094806671142578 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 131, + "max_width": 131, + "min_holes": 16, + "min_height": 131, + "min_width": 131, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00027562714084141196, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.999217073779844 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.08972495564831462, + "r_shift_limit": [ + -79, + -79 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.9291848689995792e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 35, + 35 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.004248649347573519, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -39, + -39 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0005935496493902903, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.926751397647163e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.9952023029327393, + 1.9952023029327393 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0015064259266425878, + "threshold": [ + 64, + 64 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.0525670390714077e-05 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.2153307408701795e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.601409912109375, + -0.601409912109375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.02348494529724121, + -0.02348494529724121 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3442749841058837e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0047969818115234375, + -0.0047969818115234375 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.14427149295806885, + 0.14427149295806885 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.3341118549793944e-05, + "max_holes": 16, + "max_height": 128, + "max_width": 128, + "min_holes": 16, + "min_height": 128, + "min_width": 128, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9038427572308512 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.030095113441348076, + "r_shift_limit": [ + 57, + 57 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.8477917421244718e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 65, + 65 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 0, + 0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.6474732295882235e-05, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00024744225076641507, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.062737976785394e-05, + "threshold": [ + 225, + 225 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.387250084779498e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.507874347632607e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.9956239320049232e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.6807098388671875, + -0.6807098388671875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.543450564127508e-07, + "shift_limit_x": [ + -0.9694173336029053, + -0.9694173336029053 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.921514917878644e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0027151107788085938, + -0.0027151107788085938 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.035705397436201e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.261268138885498, + 4.261268138885498 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 66, + "max_width": 66, + "min_holes": 16, + "min_height": 66, + "min_width": 66, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.003926286276704438, + "max_holes": 7, + "max_height": 14, + "max_width": 14, + "min_holes": 7, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.965645183662565 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.130361895068046e-08, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0007131777674849321, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.650902300930125e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.9723490907453794e-08, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.789274527029422e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.612015249451926e-09, + "threshold": [ + 59, + 59 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.399592918141072e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.3155952122715646e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.592764786258904e-15, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 126.04660034179688, + 126.04660034179688 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.9225485324859619, + 0.9225485324859619 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0394464957492952e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.8714116811752319, + 0.8714116811752319 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.5091417179011886e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.738229274749756, + 5.738229274749756 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.901884224175906e-08, + "max_holes": 16, + "max_height": 94, + "max_width": 94, + "min_holes": 16, + "min_height": 94, + "min_width": 94, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0035267639726180855, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9956934019397355 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.22448538667158857, + "r_shift_limit": [ + -15, + -15 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.04659796540207317, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -15, + -15 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.452364672117011e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.001659034353446498, + "brightness_limit": [ + 0.3871138095855713, + 0.3871138095855713 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.458386367213067e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.2683907849707755e-08, + "threshold": [ + 37, + 37 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.387684400358103e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.942469020820306e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.038830354276923e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 1.0308074951171875, + 1.0308074951171875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.00010665467936764664, + "shift_limit_x": [ + -1.1861324310302734e-05, + -1.1861324310302734e-05 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.106898174022214e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.5471868515014648, + 0.5471868515014648 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.269941932007536e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.199048042297363, + 7.199048042297363 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.4649255182536751e-08, + "max_holes": 16, + "max_height": 178, + "max_width": 178, + "min_holes": 16, + "min_height": 178, + "min_width": 178, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.006837854627519846, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7203006411578012 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.48917045947365345, + "r_shift_limit": [ + 0, + 0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.002057674990795233, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -44, + -44 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00020831269867050035, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -43, + -43 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.0049523458510842e-06, + "brightness_limit": [ + 0.563461184501648, + 0.563461184501648 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.005886041848374157, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2767891883850098, + 1.2767891883850098 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.0133367547716951e-09, + "threshold": [ + 215, + 215 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.700897784543942e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.2201825968394666e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1806433830469247e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.395660400390625, + 0.395660400390625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0983268792426088e-06, + "shift_limit_x": [ + 0.2017732858657837, + 0.2017732858657837 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.3640918978516884e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.012386798858642578, + 0.012386798858642578 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.053770065307617, + 7.053770065307617 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0005548616541424245, + "max_holes": 16, + "max_height": 119, + "max_width": 119, + "min_holes": 16, + "min_height": 119, + "min_width": 119, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.3863785894505596e-08, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5020968468545113 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0004579118410674918, + "r_shift_limit": [ + 78, + 78 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0010357610881328583, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 68, + 68 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0017874703748761156, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -44, + -44 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0005530600319616497, + "brightness_limit": [ + 0.2650878429412842, + 0.2650878429412842 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.23358528651602e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.073451280593872, + 1.073451280593872 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 8.197030994824914e-07, + "threshold": [ + 60, + 60 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.9638267473589087e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.3327678629059225e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 5.3490142822265625, + 5.3490142822265625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.923856510798669e-13, + "shift_limit_x": [ + -0.0004031062126159668, + -0.0004031062126159668 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.862201230322308e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0003660917282104492, + 0.0003660917282104492 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.431046009063721, + 4.431046009063721 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.042584259877913e-05, + "max_holes": 16, + "max_height": 196, + "max_width": 196, + "min_holes": 16, + "min_height": 196, + "min_width": 196, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.501792592351327e-05, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9960071952764006 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.824913896506324e-06, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0538177871053152e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 67, + 67 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.8050348175688485e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -55, + -55 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.902883945789624e-06, + "brightness_limit": [ + -0.3328549861907959, + -0.3328549861907959 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.591723530507203e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1543525457382202, + 1.1543525457382202 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.4795937784382726e-13, + "threshold": [ + 145, + 145 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.998671428371094e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.121967022464599e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.910225425965253e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -55.934165954589844, + -55.934165954589844 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.25786914950235484, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4194782443878777e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0004811286926269531, + 0.0004811286926269531 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.053984320237202e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.940011978149414, + 4.940011978149414 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.1396925138085617e-10, + "max_holes": 16, + "max_height": 111, + "max_width": 111, + "min_holes": 16, + "min_height": 111, + "min_width": 111, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.2990154785175179e-10, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7421124959710633 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.3490601211977678e-08, + "r_shift_limit": [ + 254, + 254 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.080803275836094e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 48, + 48 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.781057583436697e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -57, + -57 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00012438428624752043, + "brightness_limit": [ + 0.2665907144546509, + 0.2665907144546509 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.482442871298681e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.889902729516886e-08, + "threshold": [ + 168, + 168 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.9130637804346167e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.489187007779071, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -5.3299102783203125, + -5.3299102783203125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.475354675298874e-14, + "shift_limit_x": [ + 0.9744470119476318, + 0.9744470119476318 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.1111629428910559e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.00017523765563964844, + 0.00017523765563964844 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.956838365106678e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.698184967041016, + 9.698184967041016 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.9200365607527194e-06, + "max_holes": 16, + "max_height": 183, + "max_width": 183, + "min_holes": 16, + "min_height": 183, + "min_width": 183, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.790589933037552e-10, + "max_holes": 15, + "max_height": 14, + "max_width": 14, + "min_holes": 15, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5106786824281584 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.06339756137464114, + "r_shift_limit": [ + 51, + 51 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.828792270217822e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 23, + 23 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0003996603965053455, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.01567909774002374, + "brightness_limit": [ + -0.15590369701385498, + -0.15590369701385498 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.831064123471921e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 9.315984725952148, + 9.315984725952148 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 6.0610225195594815e-06, + "threshold": [ + 28, + 28 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.629691273536214e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.795384933185958e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.16168212890625, + -0.16168212890625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.11809921264648438, + -0.11809921264648438 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.1548975706100464, + 0.1548975706100464 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 2.403074026107788, + 2.403074026107788 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.814117148036041e-11, + "max_holes": 16, + "max_height": 73, + "max_width": 73, + "min_holes": 16, + "min_height": 73, + "min_width": 73, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.046196380323945796, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8742521341186853 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.980937352699297e-08, + "r_shift_limit": [ + -59, + -59 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.581587628216646e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 62, + 62 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.937129989720913e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 49, + 49 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.069906708505992e-05, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.8770987632364764e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 2.4403674602508545, + 2.4403674602508545 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.0609389711647113e-09, + "threshold": [ + 113, + 113 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.691974689917723e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -153.3560028076172, + -153.3560028076172 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5162668590808367e-10, + "shift_limit_x": [ + 0.9348058700561523, + 0.9348058700561523 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.356273394697207e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.3679385185241699, + 0.3679385185241699 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.8644628524780273, + 3.8644628524780273 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.387110371812061e-09, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.856317562167533e-05, + "max_holes": 6, + "max_height": 14, + "max_width": 14, + "min_holes": 6, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.999949791731585 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0038116711657494307, + "r_shift_limit": [ + -88, + -88 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.013616593628749563, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 30, + 30 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1389902196952571e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -53, + -53 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0006780058516549989, + "brightness_limit": [ + -0.266224205493927, + -0.266224205493927 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 8.375717163085938, + 8.375717163085938 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0002522726687981952, + "threshold": [ + 230, + 230 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.8419777793522646e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.5243682861328125, + 0.5243682861328125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.8875130414962769, + 0.8875130414962769 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.02557241916656494, + 0.02557241916656494 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0097874402999878, + 1.0097874402999878 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.4136828188735542e-06, + "max_holes": 16, + "max_height": 129, + "max_width": 129, + "min_holes": 16, + "min_height": 129, + "min_width": 129, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.002224594012083969, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9794143099997411 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.443197351977463e-06, + "r_shift_limit": [ + -254, + -254 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0885291424693658e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.1441608690644194e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -255, + -255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.002397643513988801, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.4929773783737936e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 9.227677345275879, + 9.227677345275879 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.9228406803383988e-06, + "threshold": [ + 1, + 1 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.345349275491139e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.7827991495875625e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.5590040767986035e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -90.68226623535156, + -90.68226623535156 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.20704068718256963, + "shift_limit_x": [ + 0.13800084590911865, + 0.13800084590911865 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.374362946020346e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.6864919662475586, + -0.6864919662475586 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.6068044343275855e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.623380184173584, + 4.623380184173584 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.212330053260946e-05, + "max_holes": 16, + "max_height": 116, + "max_width": 116, + "min_holes": 16, + "min_height": 116, + "min_width": 116, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.148518806857398e-11, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7904910698743206 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.239354901067092e-09, + "r_shift_limit": [ + 64, + 64 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.184225362155238e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 61, + 61 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0012022857420292687, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -57, + -57 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00010914681792964856, + "brightness_limit": [ + 0.3570725917816162, + 0.3570725917816162 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.4546180519904252e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 5.227165222167969, + 5.227165222167969 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.3305946561667266e-09, + "threshold": [ + 30, + 30 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.786391699185875e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2220603420613134e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 2.8782501220703125, + 2.8782501220703125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.88112736264679e-08, + "shift_limit_x": [ + 0.9516434669494629, + 0.9516434669494629 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.21857217627986e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.02928769588470459, + 0.02928769588470459 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.2979488695332293, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0640010833740234, + 1.0640010833740234 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00030687134130857885, + "max_holes": 16, + "max_height": 176, + "max_width": 176, + "min_holes": 16, + "min_height": 176, + "min_width": 176, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0012824593073447882, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6991495058255893 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.925303331388582e-09, + "r_shift_limit": [ + 113, + 113 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.04832983760912413, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 3, + 3 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00014279699826147407, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -56, + -56 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.4441019491327e-05, + "brightness_limit": [ + -0.1427215337753296, + -0.1427215337753296 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.2213315477260294e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.167734146118164, + 1.167734146118164 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 192, + 192 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 9.708896829983303e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -27.806655883789062, + -27.806655883789062 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4031756331583347e-09, + "shift_limit_x": [ + 0.00034940242767333984, + 0.00034940242767333984 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.3219914436340332, + 0.3219914436340332 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.3375937158140965e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9191569089889526, + 0.9191569089889526 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.733401145951745e-05, + "max_holes": 16, + "max_height": 212, + "max_width": 212, + "min_holes": 16, + "min_height": 212, + "min_width": 212, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.007214352073608543, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9442109572779922 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.383702658306937e-08, + "r_shift_limit": [ + 20, + 20 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0018701994141043787, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 59, + 59 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.6650454476111707e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.517861603907269e-07, + "brightness_limit": [ + 0.07660770416259766, + 0.07660770416259766 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.7354860305786133, + 1.7354860305786133 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0008200001428589968, + "threshold": [ + 241, + 241 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.5130024642190116e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 8.780076080980546e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.901201178173744e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -71.22199249267578, + -71.22199249267578 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.6160184549601315e-14, + "shift_limit_x": [ + -0.35478007793426514, + -0.35478007793426514 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.5471676588058472, + -0.5471676588058472 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.161830315799291e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9774258136749268, + 0.9774258136749268 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.1465105165915525e-08, + "max_holes": 16, + "max_height": 145, + "max_width": 145, + "min_holes": 16, + "min_height": 145, + "min_width": 145, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9973088229028283 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00042242013864582373, + "r_shift_limit": [ + -65, + -65 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.4051773496034776e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 58, + 58 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.07085844712536238, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 25, + 25 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.013094780853186161, + "brightness_limit": [ + -0.09367263317108154, + -0.09367263317108154 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0204439904466458, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.1176502704620361, + 1.1176502704620361 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 8.802001136205481e-05, + "threshold": [ + 121, + 121 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.1368092697313299e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.890844501714279e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 2.820159912109375, + 2.820159912109375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.5857539176940918, + -0.5857539176940918 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.59278221526653e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.929911115591494e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.910610198974609, + 5.910610198974609 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.744905810922982e-11, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.026179737237119305, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8689121416063039 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0008187065401000643, + "r_shift_limit": [ + -97, + -97 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0015618081048822396, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0007690905651583022, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.5141383700168245e-05, + "brightness_limit": [ + -0.36125367879867554, + -0.36125367879867554 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00027665771382654435, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.242607683857132e-07, + "threshold": [ + 251, + 251 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.577829954260053e-05 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -163.36607360839844, + -163.36607360839844 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.7833607196807861, + -0.7833607196807861 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.21994876861572266, + 0.21994876861572266 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.099758065528139e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9896594285964966, + 0.9896594285964966 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.8999082446098328, + "max_holes": 16, + "max_height": 214, + "max_width": 214, + "min_holes": 16, + "min_height": 214, + "min_width": 214, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.015221001307978765, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.08138344715321255 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0015403087932347181, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0003042791913264731, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.8151170738249465e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 131, + 131 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + -0.7657099962234497, + -0.7657099962234497 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.006213673567732503, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 2.620926856994629, + 2.620926856994629 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 251, + 251 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.00026332843117415905 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0011386981998084134 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.00029416853953100064, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.009086155332624912, + "shift_limit_x": [ + -0.41028153896331787, + -0.41028153896331787 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.7809694151821915, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.11016488075256348, + 0.11016488075256348 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.446845419302944e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.591068744659424, + 3.591068744659424 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0003731637400230456, + "max_holes": 16, + "max_height": 1, + "max_width": 1, + "min_holes": 16, + "min_height": 1, + "min_width": 1, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.020920872676457e-07, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.1998160787246268 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0008385450386165019, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0012399264654249786, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0025784149381185006, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 84, + 84 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0.6004734039306641, + 0.6004734039306641 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.7020856672044957e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 6.718296527862549, + 6.718296527862549 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.5546517606141193e-07, + "threshold": [ + 238, + 238 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.302341400669516e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.068704686178981e-05 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 170.06515502929688, + 170.06515502929688 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.0498470761765235e-09, + "shift_limit_x": [ + -0.3629928231239319, + -0.3629928231239319 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.9905297160148621, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.10024607181549072, + 0.10024607181549072 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.475307067380945e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.168127536773682, + 5.168127536773682 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00029813060881157295, + "max_holes": 16, + "max_height": 90, + "max_width": 90, + "min_holes": 16, + "min_height": 90, + "min_width": 90, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.9423122927506248e-05, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.004453285386038286 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.137568962523389e-05, + "r_shift_limit": [ + -84, + -84 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.2976525114530708e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 120, + 120 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.8321781180672095e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 136, + 136 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.3095745198604717e-08, + "brightness_limit": [ + -0.4051496386528015, + -0.4051496386528015 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.9998021721839905, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 9.032419204711914, + 9.032419204711914 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 9.082400500641351e-08, + "threshold": [ + 210, + 210 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.263454324584788e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2606152333021594e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -60.42036437988281, + -60.42036437988281 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.9696814060541903e-08, + "shift_limit_x": [ + -0.9065501689910889, + -0.9065501689910889 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.55319725020877e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.03576374053955078, + 0.03576374053955078 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.103941954561759e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.1473307609558105, + 1.1473307609558105 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.482395123914269e-12, + "max_holes": 16, + "max_height": 47, + "max_width": 47, + "min_holes": 16, + "min_height": 47, + "min_width": 47, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.641877398076613e-07, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.0001352502441783754 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.439784072587797e-06, + "r_shift_limit": [ + 69, + 69 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.335398123044739e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 48, + 48 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00012886062473063502, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -69, + -69 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.0975482115969589e-08, + "brightness_limit": [ + 0.3035203218460083, + 0.3035203218460083 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.824854850382792e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.0969675779342651, + 1.0969675779342651 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 9.08389303200881e-06, + "threshold": [ + 112, + 112 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 9.535839506464145e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7460125012782524e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 2.865631103515625, + 2.865631103515625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.47673749923706055, + -0.47673749923706055 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.039489922587942e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.7075124979019165, + -0.7075124979019165 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.32159147100977137, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0579569339752197, + 1.0579569339752197 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.813367092513775e-05, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.99846983149366e-06, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6782069058244056 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4845511308488313e-09, + "r_shift_limit": [ + -30, + -30 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.30379399088172e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -62, + -62 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.52085350760082e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -56, + -56 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.5587606833110466e-06, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.585931102991336e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.019139713816759e-05, + "threshold": [ + 125, + 125 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.23800688543207e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.061104093227886125 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.6603482400294532e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.0855712890625, + 0.0855712890625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.865940241077667e-14, + "shift_limit_x": [ + -0.6957136988639832, + -0.6957136988639832 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.821752220350174e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.4750988483428955, + 0.4750988483428955 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3376671506302323e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.462601661682129, + 5.462601661682129 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.7453290365953703e-05, + "max_holes": 16, + "max_height": 137, + "max_width": 137, + "min_holes": 16, + "min_height": 137, + "min_width": 137, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.4985717381798936e-07, + "max_holes": 5, + "max_height": 14, + "max_width": 14, + "min_holes": 5, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9387359802943057 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.9349350268824166e-07, + "r_shift_limit": [ + 94, + 94 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.7514325697941194e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.414346793092487e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -55, + -55 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.005009321713778658, + "brightness_limit": [ + 0.2701854705810547, + 0.2701854705810547 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.067026224218129e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2063212394714355, + 1.2063212394714355 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.226646499310007e-09, + "threshold": [ + 194, + 194 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.273952804648078e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.0761643280079758e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.2123492045865163, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 1.6441650390625, + 1.6441650390625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4229475176954385e-09, + "shift_limit_x": [ + -0.003386855125427246, + -0.003386855125427246 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3498823436273029e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.7503014802932739, + -0.7503014802932739 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.670519310354726e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.1311616897583, + 9.1311616897583 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.362185282427915e-10, + "max_holes": 16, + "max_height": 155, + "max_width": 155, + "min_holes": 16, + "min_height": 155, + "min_width": 155, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.661907436073008e-08, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7826203994529459 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.696901173818599e-10, + "r_shift_limit": [ + 80, + 80 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.271836842544524e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -61, + -61 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.2944214264418175e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -94, + -94 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.628833196669727e-07, + "brightness_limit": [ + 0.027324914932250977, + 0.027324914932250977 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.970746421704462e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.3525141477584839, + 1.3525141477584839 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.342571236987765e-12, + "threshold": [ + 195, + 195 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.104336221704395e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.6562029739538298e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.0457763671875, + 0.0457763671875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.5180341985201053, + "shift_limit_x": [ + -0.07026427984237671, + -0.07026427984237671 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.4032670939208e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.45277154445648193, + 0.45277154445648193 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.8041182413885068e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.325820922851562, + 8.325820922851562 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.347712014580657e-05, + "max_holes": 16, + "max_height": 70, + "max_width": 70, + "min_holes": 16, + "min_height": 70, + "min_width": 70, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0682435352145901e-07, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.4819298962728218 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.2657206545509648e-10, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.805422488517706e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.488396501630375e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 56, + 56 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.394975378555462e-08, + "brightness_limit": [ + -0.21477460861206055, + -0.21477460861206055 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.7727757021955251e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.064168733462436e-07, + "threshold": [ + 197, + 197 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.09827555834247992 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.8253670678985856e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.371755313275226e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.457183837890625, + -0.457183837890625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.9299567997446703e-07, + "shift_limit_x": [ + -0.5888853073120117, + -0.5888853073120117 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.8703369833828135e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.8097629547119141, + 0.8097629547119141 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.519363672507171e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 2.7410671710968018, + 2.7410671710968018 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0003440143114328588, + "max_holes": 16, + "max_height": 112, + "max_width": 112, + "min_holes": 16, + "min_height": 112, + "min_width": 112, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 4, + "max_height": 14, + "max_width": 14, + "min_holes": 4, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9012399362475325 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4492527498077834e-06, + "r_shift_limit": [ + 86, + 86 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.2703068427544242, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -8, + -8 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.013529932193308336, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.46803824754638e-05, + "brightness_limit": [ + 1.0, + 1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.2550848126411438, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.8319664001464844, + 1.8319664001464844 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.23314566564053507, + "threshold": [ + 205, + 205 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9952491179349433e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 180.0, + 180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7275546183679745e-06, + "shift_limit_x": [ + -0.8116886019706726, + -0.8116886019706726 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.7057607531911896e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.9682549238204956, + 0.9682549238204956 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.478924585656455e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.78306770324707, + 8.78306770324707 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.634454742298371e-07, + "max_holes": 16, + "max_height": 154, + "max_width": 154, + "min_holes": 16, + "min_height": 154, + "min_width": 154, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00467953447973618, + "max_holes": 8, + "max_height": 14, + "max_width": 14, + "min_holes": 8, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.22316435959409064 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.12361287086504547, + "r_shift_limit": [ + 3, + 3 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0009646351764895089, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 103, + 103 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.03452827663824509, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -46, + -46 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.0446572772391077e-08, + "brightness_limit": [ + -0.15524893999099731, + -0.15524893999099731 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.3371224257608147e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.608176827430725, + 1.608176827430725 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.4071716112120711, + "threshold": [ + 221, + 221 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.0433797030224656e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 9.778134811719297e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -105.3961410522461, + -105.3961410522461 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + -0.027214407920837402, + -0.027214407920837402 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0002278307849867267, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0074498653411865234, + -0.0074498653411865234 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.750408348891863e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 7.959484577178955, + 7.959484577178955 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.914496709600761e-09, + "max_holes": 16, + "max_height": 173, + "max_width": 173, + "min_holes": 16, + "min_height": 173, + "min_width": 173, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.002863220010872247, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.4306183755638716 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.9125614416993926e-11, + "r_shift_limit": [ + 22, + 22 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.5674468367070115e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.999384486224499e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -104, + -104 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.842056181917207e-10, + "brightness_limit": [ + -0.2380083203315735, + -0.2380083203315735 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.524761312797607e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.3295612992059795e-10, + "threshold": [ + 116, + 116 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.10532583034636e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.7131658058075624e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.6485187491332631, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -180.0, + -180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0185512068344027e-11, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.0567830632389213e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.010126650333404541, + -0.010126650333404541 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2417403030534003e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.07407283782959, + 8.07407283782959 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00015401309164052735, + "max_holes": 16, + "max_height": 81, + "max_width": 81, + "min_holes": 16, + "min_height": 81, + "min_width": 81, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.11224163591133e-12, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.3513194806526181 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.150141708593972e-08, + "r_shift_limit": [ + -40, + -40 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.290831069557122e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.01734074525199203, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -38, + -38 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00017473561533579499, + "brightness_limit": [ + -0.2243524193763733, + -0.2243524193763733 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.6370626328139775e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.6300338506698608, + 1.6300338506698608 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.2837254129657123e-05, + "threshold": [ + 146, + 146 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.0640193443636973e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.9728546142578125, + -0.9728546142578125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.063557607112173e-07, + "shift_limit_x": [ + 0.6662313938140869, + 0.6662313938140869 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.3618576894818657e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.4446955919265747, + -0.4446955919265747 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2127455331441023e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9958469867706299, + 0.9958469867706299 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00016889951075427234, + "max_holes": 16, + "max_height": 152, + "max_width": 152, + "min_holes": 16, + "min_height": 152, + "min_width": 152, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.982289397078741 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.4258513916403254e-06, + "r_shift_limit": [ + -71, + -71 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.009504379571420252, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 59, + 59 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0031220590441364826, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0.8258432149887085, + 0.8258432149887085 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 2.6415791511535645, + 2.6415791511535645 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.2905703581714533e-07, + "threshold": [ + 74, + 74 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.812307210610677e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.3935436103608003e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 16.079132080078125, + 16.079132080078125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0112478367925206e-11, + "shift_limit_x": [ + 0.862102746963501, + 0.862102746963501 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.910255937562863e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0027581453323364258, + 0.0027581453323364258 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.525730948673335e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.125173568725586, + 6.125173568725586 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.7661537939285865e-06, + "max_holes": 16, + "max_height": 224, + "max_width": 224, + "min_holes": 16, + "min_height": 224, + "min_width": 224, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.006414693917277725, + "max_holes": 15, + "max_height": 14, + "max_width": 14, + "min_holes": 15, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9809451871126023 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.6256484687439634e-09, + "r_shift_limit": [ + -168, + -168 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.1992519771431e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 99, + 99 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.630032569945158e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 7, + 7 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.06131676387512e-12, + "brightness_limit": [ + -0.49036598205566406, + -0.49036598205566406 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.8068666889348557e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.051340766492361e-12, + "threshold": [ + 78, + 78 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.6873582227494716e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.3839593698417616 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.361016447786554e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -114.7049789428711, + -114.7049789428711 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.711278391474627e-07, + "shift_limit_x": [ + 0.7705802917480469, + 0.7705802917480469 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 9.976401999180706e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.02938711643218994, + 0.02938711643218994 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3370595529504563e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.69009780883789, + 8.69009780883789 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.636993242087605e-11, + "max_holes": 16, + "max_height": 187, + "max_width": 187, + "min_holes": 16, + "min_height": 187, + "min_width": 187, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.4262029092693148e-11, + "max_holes": 13, + "max_height": 14, + "max_width": 14, + "min_holes": 13, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6160362090641389 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.2974558861900158e-05, + "r_shift_limit": [ + -59, + -59 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.013169117586156465, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -57, + -57 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0024030197519227248, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -58, + -58 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.012020191168926386, + "brightness_limit": [ + 0.3254823684692383, + 0.3254823684692383 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 4.081583023071289, + 4.081583023071289 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.008620780870803202, + "threshold": [ + 234, + 234 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.0915629988050719e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 153.66091918945312, + 153.66091918945312 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.08858045882526078, + "shift_limit_x": [ + 0.0482020378112793, + 0.0482020378112793 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5110045606983423e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0009021759033203125, + 0.0009021759033203125 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.8383346769771735e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.926413536071777, + 8.926413536071777 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.003442909335717559, + "max_holes": 16, + "max_height": 140, + "max_width": 140, + "min_holes": 16, + "min_height": 140, + "min_width": 140, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.6152032381978247e-05, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8717228653904985 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.009762041371359942, + "r_shift_limit": [ + 99, + 99 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1746629462083862e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 9.939895646435878e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -60, + -60 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0009933149637232838, + "brightness_limit": [ + -0.40056174993515015, + -0.40056174993515015 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.2206612029446963e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.38419331628355e-06, + "threshold": [ + 20, + 20 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 6.462943348811684e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.034238673624008786 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -80.67227172851562, + -80.67227172851562 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.26783227920532227, + 0.26783227920532227 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.9601385593414307, + -0.9601385593414307 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.582691567587874e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.99999993922529e-09, + 9.99999993922529e-09 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.028910163673572e-05, + "max_holes": 16, + "max_height": 163, + "max_width": 163, + "min_holes": 16, + "min_height": 163, + "min_width": 163, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.00010057534348879328, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9547290366075345 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.262616605042311e-11, + "r_shift_limit": [ + -68, + -68 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.629403331138034e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 235, + 235 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.5226542021678075e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 85, + 85 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + -0.11179864406585693, + -0.11179864406585693 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.4005049342458165e-09, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.246137771131656e-13, + "threshold": [ + 42, + 42 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.0597175997982373e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 7.078117748404902e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.10134380169782631, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -5.1053924560546875, + -5.1053924560546875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.01467865480756e-07, + "shift_limit_x": [ + -0.47012943029403687, + -0.47012943029403687 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4610320208423885e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.7710566520690918, + 0.7710566520690918 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.186468509021195e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.0496855974197388, + 1.0496855974197388 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.617276334123352e-12, + "max_holes": 16, + "max_height": 120, + "max_width": 120, + "min_holes": 16, + "min_height": 120, + "min_width": 120, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.392597870716446e-12, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8986470583977398 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.02462733460149258, + "r_shift_limit": [ + -50, + -50 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0072551075679614e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -27, + -27 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.6457355409086405e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0007714284290605278, + "brightness_limit": [ + -0.21109521389007568, + -0.21109521389007568 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.438608458141258e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.945313401320082e-05, + "threshold": [ + 140, + 140 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.5493642160396324e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.0130037907877574e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7825215975316502e-06, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 2.97113037109375, + 2.97113037109375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.4335049314127805e-08, + "shift_limit_x": [ + -0.0048236846923828125, + -0.0048236846923828125 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.985078168660069e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0002592802047729492, + -0.0002592802047729492 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.056931782918594e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 2.9512901306152344, + 2.9512901306152344 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 74, + "max_width": 74, + "min_holes": 16, + "min_height": 74, + "min_width": 74, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.5133431965913077e-07, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9744158566775177 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00021937988028499118, + "r_shift_limit": [ + 114, + 114 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0003228191184006281, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 87, + 87 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.103419641059729e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -48, + -48 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.1562356728194492e-07, + "brightness_limit": [ + -0.24566549062728882, + -0.24566549062728882 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.301280691374241e-08, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 7.061033896891335e-07, + "threshold": [ + 87, + 87 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.1802427374763265e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.2486823663667203e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.3911895751953125, + 0.3911895751953125 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3071099982244337e-11, + "shift_limit_x": [ + 0.0014206171035766602, + 0.0014206171035766602 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.1198986982130393e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0007655024528503418, + -0.0007655024528503418 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.13045749220721348, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9779313206672668, + 0.9779313206672668 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.57817454060129e-10, + "max_holes": 16, + "max_height": 57, + "max_width": 57, + "min_holes": 16, + "min_height": 57, + "min_width": 57, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.33913464813208e-07, + "max_holes": 15, + "max_height": 14, + "max_width": 14, + "min_holes": 15, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8689987043042028 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.351664680754766e-05, + "r_shift_limit": [ + 255, + 255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.9930683768192247e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -42, + -42 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.004845160498666845, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 37, + 37 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.14704297482967377, + "brightness_limit": [ + 0.03966045379638672, + 0.03966045379638672 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.021234506467985526, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.3213346004486084, + 1.3213346004486084 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.6474008711818357e-08, + "threshold": [ + 229, + 229 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.926628430457477e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.465425261821263e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.145355224609375, + 0.145355224609375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.2484780796193565e-08, + "shift_limit_x": [ + 0.7073103189468384, + 0.7073103189468384 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.365903236261013e-05, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.002674698829650879, + 0.002674698829650879 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.615768432617188, + 9.615768432617188 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.007650530549080159, + "max_holes": 16, + "max_height": 141, + "max_width": 141, + "min_holes": 16, + "min_height": 141, + "min_width": 141, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.198455621166147, + "max_holes": 3, + "max_height": 14, + "max_width": 14, + "min_holes": 3, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.6206290182881045 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.09407030884470435, + "r_shift_limit": [ + 12, + 12 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.324810640348513e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.02590750266945685, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -16, + -16 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.010307582353593414, + "brightness_limit": [ + -0.20577073097229004, + -0.20577073097229004 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.453359396486243e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 9.256058728006312e-06, + "threshold": [ + 150, + 150 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.4777989194597295e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.2282282857101384e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.3119608662466015e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.3931732177734375, + -0.3931732177734375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.9749281406402588, + 0.9749281406402588 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.5319122159411217e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.8489999771118164, + -0.8489999771118164 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.957010269165039, + 6.957010269165039 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.04460141042799082, + "max_holes": 16, + "max_height": 135, + "max_width": 135, + "min_holes": 16, + "min_height": 135, + "min_width": 135, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.2975226403111364, + "max_holes": 9, + "max_height": 14, + "max_width": 14, + "min_holes": 9, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.5275752279037837 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.389415496897874e-07, + "r_shift_limit": [ + -34, + -34 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.262575710946468e-14, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -41, + -41 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.7320397516806925e-10, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 23, + 23 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.958616946103341e-10, + "brightness_limit": [ + -0.26819390058517456, + -0.26819390058517456 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.40148620271086e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 8.900824546813965, + 8.900824546813965 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.1405011589307465e-13, + "threshold": [ + 195, + 195 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.128572091834912e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.2569963823161446e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.750699749019834e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -0.1110687255859375, + -0.1110687255859375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.2243122688995964e-10, + "shift_limit_x": [ + 0.0019922256469726562, + 0.0019922256469726562 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.6320047941183589, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.013814449310302734, + 0.013814449310302734 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.3788488210110035e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 3.3505654335021973, + 3.3505654335021973 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 102, + "max_width": 102, + "min_holes": 16, + "min_height": 102, + "min_width": 102, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.572328175520695e-08, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.367994929763065 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00033460125008148364, + "r_shift_limit": [ + -38, + -38 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00011035277083354302, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.4036855719941804e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -47, + -47 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.7140338865194735e-09, + "brightness_limit": [ + 0.9987471103668213, + 0.9987471103668213 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.463941925431229e-11, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.176269815169008e-11, + "threshold": [ + 111, + 111 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.379652741354118e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.8388277556519795e-15 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -123.39701843261719, + -123.39701843261719 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3956032334645025e-14, + "shift_limit_x": [ + 1.0, + 1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.7384611236006207e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0017429590225219727, + 0.0017429590225219727 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.554920001229081e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.902059078216553, + 5.902059078216553 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.3459461333624433e-08, + "max_holes": 16, + "max_height": 124, + "max_width": 124, + "min_holes": 16, + "min_height": 124, + "min_width": 124, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.246907724779302e-09, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9995531566120492 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.493097728262228e-09, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.015164951155304807, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 40, + 40 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.011616257910134209, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -31, + -31 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00026166448948394816, + "brightness_limit": [ + 0.3970203399658203, + 0.3970203399658203 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.030010322108864784, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2639309167861938, + 1.2639309167861938 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.1269066530039075e-05, + "threshold": [ + 214, + 214 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.644332267574473e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -82.60848999023438, + -82.60848999023438 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.333620548248291, + 0.333620548248291 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.12240862846374512, + 0.12240862846374512 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.474388366751184e-08, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9606794118881226, + 0.9606794118881226 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0, + "max_holes": 16, + "max_height": 57, + "max_width": 57, + "min_holes": 16, + "min_height": 57, + "min_width": 57, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.028924052664921263, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9139914367234473 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.962215798843986e-09, + "r_shift_limit": [ + 28, + 28 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 171, + 171 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.9268867555356e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -52, + -52 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.0684949265309559e-08, + "brightness_limit": [ + -0.27409517765045166, + -0.27409517765045166 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.307778523683488e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.292883276939392, + 1.292883276939392 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.8052240024719074e-09, + "threshold": [ + 151, + 151 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.3443984768891984e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.6878283551330767e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 103.27297973632812, + 103.27297973632812 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.310496656861884e-07, + "shift_limit_x": [ + 0.5505261421203613, + 0.5505261421203613 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.10985338347543472, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.4487550284361987e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.010100364685059, + 8.010100364685059 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.593628324697165e-12, + "max_holes": 16, + "max_height": 40, + "max_width": 40, + "min_holes": 16, + "min_height": 40, + "min_width": 40, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.345855160342895e-11, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.890145770964593 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0036118990751976, + "r_shift_limit": [ + 71, + 71 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.423038539004044e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 38, + 38 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.4249928318231697e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -51, + -51 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0007614543428644538, + "brightness_limit": [ + 0.24916362762451172, + 0.24916362762451172 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.173217755752561e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 4.186330318450928, + 4.186330318450928 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0002402962971148337, + "threshold": [ + 76, + 76 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.958169242378319e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -143.19566345214844, + -143.19566345214844 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.949420357671377e-07, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0711767234015781, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 1.0, + 1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.682674367924129e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.681167602539062, + 8.681167602539062 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.67115756235511e-08, + "max_holes": 16, + "max_height": 132, + "max_width": 132, + "min_holes": 16, + "min_height": 132, + "min_width": 132, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 7.042718286786564e-09, + "max_holes": 7, + "max_height": 14, + "max_width": 14, + "min_holes": 7, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9241213088038477 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.0894623118454092e-09, + "r_shift_limit": [ + 76, + 76 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.1488012204337263e-13, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 7.4179114077371916e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -81, + -81 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.4589736695405815e-06, + "brightness_limit": [ + 0.3727039098739624, + 0.3727039098739624 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.8547831654708122e-06, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 5.7825212478637695, + 5.7825212478637695 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.4687396055413e-10, + "threshold": [ + 11, + 11 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 3.386710952107584e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 5.5970837281566414e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.560897640742437e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0.398529052734375, + 0.398529052734375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.6522872101659871, + "shift_limit_x": [ + -0.03874856233596802, + -0.03874856233596802 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.030832849640327e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.7245926856994629, + 0.7245926856994629 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.7570594767073684e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 4.5287089347839355, + 4.5287089347839355 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1448805617837688e-07, + "max_holes": 16, + "max_height": 121, + "max_width": 121, + "min_holes": 16, + "min_height": 121, + "min_width": 121, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.123516047951011e-08, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.347708200673744 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.76436361426114e-07, + "r_shift_limit": [ + -50, + -50 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0013283519742700867, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 18, + 18 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.39615181194071e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 60, + 60 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.5702993589455753e-06, + "brightness_limit": [ + 0.23136067390441895, + 0.23136067390441895 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.994075265741309e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.0, + "threshold": [ + 134, + 134 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.612224032769783e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.7596341828281197e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -1.45166015625, + -1.45166015625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.05885612964630127, + 0.05885612964630127 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0376057593433135e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.001959562301635742, + 0.001959562301635742 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.80108920948206e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.754938125610352, + 5.754938125610352 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0006651472754439294, + "max_holes": 16, + "max_height": 55, + "max_width": 55, + "min_holes": 16, + "min_height": 55, + "min_width": 55, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.001352179377264895, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.996527568918408 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.45919360997639e-09, + "r_shift_limit": [ + -124, + -124 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -227, + -227 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.464400556471805e-11, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -255, + -255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.983246888318102e-13, + "brightness_limit": [ + 0.2529134750366211, + 0.2529134750366211 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 7.973318950473991e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.5029174089431763, + 0.5029174089431763 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.0581065415794728e-05, + "threshold": [ + 60, + 60 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.2787544834618494 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.6242285351964024e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5188134824603965e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 180.0, + 180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.019439258551312e-11, + "shift_limit_x": [ + -0.0062105655670166016, + -0.0062105655670166016 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.353264888035221e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0007877349853515625, + -0.0007877349853515625 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.308111926060586e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.608778476715088, + 5.608778476715088 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.4448180217084086e-11, + "max_holes": 16, + "max_height": 59, + "max_width": 59, + "min_holes": 16, + "min_height": 59, + "min_width": 59, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.583791343605457e-10, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7212249282243635 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.3265632815742897e-13, + "r_shift_limit": [ + -82, + -82 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.547725991727835e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 83, + 83 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.0445704959934935e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -12, + -12 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0010358200355534974, + "brightness_limit": [ + 0.18884217739105225, + 0.18884217739105225 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.004484232057019505, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.2825120687484741, + 1.2825120687484741 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.7584107336223797e-08, + "threshold": [ + 51, + 51 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.210258183756643e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.157631323526424e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 119.37045288085938, + 119.37045288085938 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.03401723774702581, + "shift_limit_x": [ + 0.10491299629211426, + 0.10491299629211426 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.528111216562361e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.0014089345932006836, + 0.0014089345932006836 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.801311200721951e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.9967777729034424, + 0.9967777729034424 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.5701242624618156e-08, + "max_holes": 16, + "max_height": 167, + "max_width": 167, + "min_holes": 16, + "min_height": 167, + "min_width": 167, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.711663336315902e-11, + "max_holes": 13, + "max_height": 14, + "max_width": 14, + "min_holes": 13, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9604618567185593 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.273999063394854e-07, + "r_shift_limit": [ + -66, + -66 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.610843978945614e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -255, + -255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.283906602115285e-12, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 255, + 255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0001253905356861651, + "brightness_limit": [ + 0.3792961835861206, + 0.3792961835861206 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.2678235358520854e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.403031826019287, + 1.403031826019287 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.3964228501518982e-10, + "threshold": [ + 213, + 213 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.6733969638202205e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.5062452677439364e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -75.87667083740234, + -75.87667083740234 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.4969450287175186e-12, + "shift_limit_x": [ + 0.5777503252029419, + 0.5777503252029419 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.982763955814079e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.00014102458953857422, + 0.00014102458953857422 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.5856940748809158, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.01252019405365, + 1.01252019405365 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 9.65372916048621e-12, + "max_holes": 16, + "max_height": 199, + "max_width": 199, + "min_holes": 16, + "min_height": 199, + "min_width": 199, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.4775485787235787e-07, + "max_holes": 11, + "max_height": 14, + "max_width": 14, + "min_holes": 11, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.41413697486918133 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.5490839879176516e-08, + "r_shift_limit": [ + -60, + -60 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0016959855669181345, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 33, + 33 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.3606842230728944e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -53, + -53 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.7262249840658726e-06, + "brightness_limit": [ + -0.27171027660369873, + -0.27171027660369873 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 9.165079904879486e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.0739339590072632, + 1.0739339590072632 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 9.009874638819576e-06, + "threshold": [ + 108, + 108 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.3939489561147658e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.84393748663829e-08 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -68.66020202636719, + -68.66020202636719 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.713325638152587e-09, + "shift_limit_x": [ + -0.0005080699920654297, + -0.0005080699920654297 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.637530904243794e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.5117287039756775, + -0.5117287039756775 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 8.733469936707303e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.338388442993164, + 8.338388442993164 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.9010805245243714e-05, + "max_holes": 16, + "max_height": 131, + "max_width": 131, + "min_holes": 16, + "min_height": 131, + "min_width": 131, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.9768948850247909, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.02133889238699782 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.899917849324442e-10, + "r_shift_limit": [ + -94, + -94 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.498995189983244e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 68, + 68 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00014312259442030538, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 97, + 97 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.898607869195261e-06, + "brightness_limit": [ + -0.22384941577911377, + -0.22384941577911377 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0013115536186801488, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.4028459787368774, + 1.4028459787368774 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 5.638141762671044e-05, + "threshold": [ + 120, + 120 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 2.4683012752092975e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 1.0497642534362345e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.2847843139163123e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -135.37258911132812, + -135.37258911132812 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.20423077728974093, + "shift_limit_x": [ + -0.0815434455871582, + -0.0815434455871582 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.45832109451293945, + -0.45832109451293945 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.500242966447809e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.927706241607666, + 5.927706241607666 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.3727331261939e-11, + "max_holes": 16, + "max_height": 180, + "max_width": 180, + "min_holes": 16, + "min_height": 180, + "min_width": 180, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 6.179368533756392e-06, + "max_holes": 1, + "max_height": 14, + "max_width": 14, + "min_holes": 1, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7942500848662126 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.6274227932687583e-09, + "r_shift_limit": [ + -56, + -56 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.554404777023377e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -63, + -63 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.875540403126701e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -58, + -58 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 8.326498167142427e-05, + "brightness_limit": [ + 0.3116375207901001, + 0.3116375207901001 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.9893091384619076e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 10.0, + 10.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 1.3740116167196627e-10, + "threshold": [ + 124, + 124 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 8.015186928951786e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.7629953585391913e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -124.01145935058594, + -124.01145935058594 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.338924256021653e-07, + "shift_limit_x": [ + -0.6099905371665955, + -0.6099905371665955 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.9576742292030627e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.0026874542236328125, + -0.0026874542236328125 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.229980972893491e-11, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.774413108825684, + 5.774413108825684 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0006440022372646084, + "max_holes": 16, + "max_height": 87, + "max_width": 87, + "min_holes": 16, + "min_height": 87, + "min_width": 87, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.4223824966156623e-09, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9992369156541928 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0016732253117037188, + "r_shift_limit": [ + 74, + 74 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 8.674173817812462e-09, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 34, + 34 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 6.428895839528633e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -255, + -255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.00032114514033310115, + "brightness_limit": [ + -0.23146820068359375, + -0.23146820068359375 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.04653303967981515, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.8666556477546692, + 0.8666556477546692 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.2037167196084593e-05, + "threshold": [ + 187, + 187 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 4.1199956192506155e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 3.762401892855196e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 126.1395263671875, + 126.1395263671875 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.969864164485125e-13, + "shift_limit_x": [ + 0.0024214982986450195, + 0.0024214982986450195 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.5019683570772728e-10, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.7365906238555908, + -0.7365906238555908 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.9479799270629883, + 1.9479799270629883 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 8.089254290392141e-05, + "max_holes": 16, + "max_height": 159, + "max_width": 159, + "min_holes": 16, + "min_height": 159, + "min_width": 159, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.866333587118035e-06, + "max_holes": 7, + "max_height": 14, + "max_width": 14, + "min_holes": 7, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9513024918833783 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 2.820477515006942e-10, + "r_shift_limit": [ + -252, + -252 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 126, + 126 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -255, + -255 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.3801360384823056e-06, + "brightness_limit": [ + 0.3442639112472534, + 0.3442639112472534 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.4174249887683606e-12, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 3.2331874647235706e-12, + "threshold": [ + 75, + 75 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.7825561577862115e-10 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.9999790191650391 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 132.52044677734375, + 132.52044677734375 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.586303941455088e-06, + "shift_limit_x": [ + -0.550622284412384, + -0.550622284412384 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.0341352509533926e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.05921471118927002, + -0.05921471118927002 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 4.614577700241902e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.325510501861572, + 5.325510501861572 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.1203264067425167e-13, + "max_holes": 16, + "max_height": 115, + "max_width": 115, + "min_holes": 16, + "min_height": 115, + "min_width": 115, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.072358509408265e-13, + "max_holes": 10, + "max_height": 14, + "max_width": 14, + "min_holes": 10, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 1.7013926327469342e-05 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0001273370329429313, + "r_shift_limit": [ + -7, + -7 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.8230936831384864e-05, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 162, + 162 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 4.59328106784245e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 135, + 135 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 6.202987335466524e-08, + "brightness_limit": [ + -1.0, + -1.0 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.7864686250686646, + 0.7864686250686646 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.3110334601703104e-11, + "threshold": [ + 27, + 27 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.8123948680021636e-13 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.772085105441036 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.3143250499995255e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 180.0, + 180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.915852246078538e-11, + "shift_limit_x": [ + 4.0531158447265625e-05, + 4.0531158447265625e-05 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.133348475999655e-13, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.00042998790740966797, + -0.00042998790740966797 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.546355802413739e-14, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 9.99999993922529e-09, + 9.99999993922529e-09 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.4445399461961882e-07, + "max_holes": 16, + "max_height": 145, + "max_width": 145, + "min_holes": 16, + "min_height": 145, + "min_width": 145, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 2.9656156163621397e-05, + "max_holes": 15, + "max_height": 14, + "max_width": 14, + "min_holes": 15, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.22769486825076624 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.09566547753260002, + "r_shift_limit": [ + 28, + 28 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.03272665892079418, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 58, + 58 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.01507774506520132, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -30, + -30 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0009059663817836613, + "brightness_limit": [ + -0.1456393003463745, + -0.1456393003463745 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.0019366890399127035, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.9741490483283997, + 0.9741490483283997 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 0.01196705706306439, + "threshold": [ + 86, + 86 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 9.499136268308166e-11 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.426009267266326e-12, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 180.0, + 180.0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.0632388965718374e-11, + "shift_limit_x": [ + -0.4898988604545593, + -0.4898988604545593 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.7333576170855143e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.9305527210235596, + -0.9305527210235596 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.352859020233154, + 5.352859020233154 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.4573611744844923e-05, + "max_holes": 16, + "max_height": 195, + "max_width": 195, + "min_holes": 16, + "min_height": 195, + "min_width": 195, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0647792973735477, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.7769261615685397 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.00017687756860561288, + "r_shift_limit": [ + -255, + -255 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0031216094383366283, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 255, + 255 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.012785686063081503, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 107, + 107 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.004218548443031628, + "brightness_limit": [ + -0.12947916984558105, + -0.12947916984558105 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.3504560599770446e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 0.0, + 0.0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 8.04697152457449e-06, + "threshold": [ + 65, + 65 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 8.780471990650239e-06 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 80.86965942382812, + 80.86965942382812 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.0106104098741984e-12, + "shift_limit_x": [ + -0.0008970499038696289, + -0.0008970499038696289 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -1.0, + -1.0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.685604879703418e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 6.839564323425293, + 6.839564323425293 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 3.5693466386553345e-05, + "max_holes": 16, + "max_height": 142, + "max_width": 142, + "min_holes": 16, + "min_height": 142, + "min_width": 142, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.907715701044916e-07, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9796437631963681 + } + ] + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.Sequential", + "p": 0.01, + "transforms": [ + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.023652232769643122, + "r_shift_limit": [ + 64, + 64 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 96, + 96 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.04922289882657438, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 6, + 6 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 0.04447934776544571, + "brightness_limit": [ + -0.17974156141281128, + -0.17974156141281128 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.545653470892745e-05, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.464644432067871, + 1.464644432067871 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.2081282929790267e-07, + "threshold": [ + 126, + 126 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.091855248033188e-09 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 7.714502368026002e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -83.56507873535156, + -83.56507873535156 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0.82171630859375, + 0.82171630859375 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 6.271354576550873e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.01177835464477539, + 0.01177835464477539 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.5726467218835876e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 5.460862159729004, + 5.460862159729004 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.0710658835357863e-07, + "max_holes": 16, + "max_height": 185, + "max_width": 185, + "min_holes": 16, + "min_height": 185, + "min_width": 185, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.012823748930418155, + "max_holes": 12, + "max_height": 14, + "max_width": 14, + "min_holes": 12, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8697757149114077 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0003767616199761327, + "r_shift_limit": [ + -58, + -58 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 252, + 252 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 3.2266209544482754e-08, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -40, + -40 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.632093936642903e-08, + "brightness_limit": [ + -0.16642391681671143, + -0.16642391681671143 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 2.5944950904922874e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 9.599757194519043, + 9.599757194519043 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 4.69077861050539e-10, + "threshold": [ + 167, + 167 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 1.7323997520235496e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 4.660329579932853e-12 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 3.6789063391949123e-07, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 61.286285400390625, + 61.286285400390625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.3639712354156351e-12, + "shift_limit_x": [ + -0.002731621265411377, + -0.002731621265411377 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.7114416360855103, + 0.7114416360855103 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.8054304718971252, + 0.8054304718971252 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.4164409379351594e-07, + "max_holes": 16, + "max_height": 222, + "max_width": 222, + "min_holes": 16, + "min_height": 222, + "min_width": 222, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 4.4163502031212573e-10, + "max_holes": 16, + "max_height": 14, + "max_width": 14, + "min_holes": 16, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.9996226390802282 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.011288081215221624, + "r_shift_limit": [ + 59, + 59 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.0006353130269976665, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -34, + -34 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 5.006321365506796e-06, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + 90, + 90 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 4.0352414988213385e-07, + "brightness_limit": [ + 0.2886776924133301, + 0.2886776924133301 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 3.347629270622443e-10, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.102547526359558, + 1.102547526359558 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.1276175807412623e-11, + "threshold": [ + 219, + 219 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 2.4065016863203516e-14 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -60.37004089355469, + -60.37004089355469 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 5.7033367972572613e-08, + "shift_limit_x": [ + -1.0, + -1.0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0.9486069679260254, + 0.9486069679260254 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 1.7544365940664421e-09, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 8.404634475708008, + 8.404634475708008 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 1.6366759426437159e-10, + "max_holes": 16, + "max_height": 129, + "max_width": 129, + "min_holes": 16, + "min_height": 129, + "min_width": 129, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.0019849186218159898, + "max_holes": 14, + "max_height": 14, + "max_width": 14, + "min_holes": 14, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.986086217982914 + } + ] + }, + { + "__class_fullname__": "albumentations.core.composition.OneOf", + "p": 1, + "transforms": [ + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.01434053894009557, + "r_shift_limit": [ + -57, + -57 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 0.13504295961671975, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + 20, + 20 + ], + "b_shift_limit": [ + -0.0, + 0.0 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RGBShift", + "p": 1.2007853231525504e-07, + "r_shift_limit": [ + -0.0, + 0.0 + ], + "g_shift_limit": [ + -0.0, + 0.0 + ], + "b_shift_limit": [ + -40, + -40 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 5.084795835676786e-07, + "brightness_limit": [ + 0.26469433307647705, + 0.26469433307647705 + ], + "contrast_limit": [ + 0, + 0 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.RandomBrightnessContrast", + "p": 1.3527939883301817e-07, + "brightness_limit": [ + 0, + 0 + ], + "contrast_limit": [ + 1.4791370630264282, + 1.4791370630264282 + ], + "brightness_by_max": true + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.Solarize", + "p": 2.1351227752306617e-06, + "threshold": [ + 200, + 200 + ] + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", + "p": 5.434054934278076e-07 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.VerticalFlip", + "p": 0.0 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + -2.48883056640625, + -2.48883056640625 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 2.565728214513057e-07, + "shift_limit_x": [ + 0.9562153816223145, + 0.9562153816223145 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.0, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + -0.3084474205970764, + -0.3084474205970764 + ], + "scale_limit": [ + 0.0, + 0.0 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", + "p": 0.00018515809280805762, + "shift_limit_x": [ + 0, + 0 + ], + "shift_limit_y": [ + 0, + 0 + ], + "scale_limit": [ + 1.008091926574707, + 1.008091926574707 + ], + "rotate_limit": [ + 0, + 0 + ], + "interpolation": 1, + "border_mode": 4 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 5.446242638689629e-10, + "max_holes": 16, + "max_height": 214, + "max_width": 214, + "min_holes": 16, + "min_height": 214, + "min_width": 214, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.augmentations.transforms.CoarseDropout", + "p": 0.03803251848555078, + "max_holes": 7, + "max_height": 14, + "max_width": 14, + "min_holes": 7, + "min_height": 14, + "min_width": 14, + "fill_value": 0, + "mask_fill_value": 255 + }, + { + "__class_fullname__": "albumentations.core.transforms_interface.NoOp", + "p": 0.8123951253815967 + } + ] + } + ] + } + ] + } + ], + "bbox_params": null, + "keypoint_params": null, + "additional_targets": {} + } +} \ No newline at end of file diff --git a/src/mml/core/data_loading/augmentations/kornia.py b/src/mml/core/data_loading/augmentations/kornia.py new file mode 100644 index 0000000..e480b60 --- /dev/null +++ b/src/mml/core/data_loading/augmentations/kornia.py @@ -0,0 +1,140 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from typing import Any, List, Optional + +import kornia as K +import torch +from hydra.utils import instantiate +from omegaconf import ListConfig, OmegaConf + +from mml.core.data_loading.augmentations.augmentation_module import AugmentationModule, DataFormat +from mml.core.data_loading.task_attributes import Modality, RGBInfo + +KORNIA_VALID_MODALITIES = ["image", "mask", "bbox", "keypoints"] + + +class KorniaAugmentationModule(AugmentationModule): + """ + Kornia augmentation module. + + Basic supported dict entries are ['image', 'mask', 'bbox', 'keypoints'] + """ + + def __init__( + self, + device: str, + cfg: ListConfig, + is_first: bool, + is_last: bool, + means: Optional[RGBInfo], + stds: Optional[RGBInfo], + ): + self.data_keys = None + super().__init__(device=device, cfg=cfg, is_first=is_first, is_last=is_last, means=means, stds=stds) + self.run_inverse = False + + def _build_pipeline(self): + transforms = self.from_cfg(self.cfg) + norm_trans = [] + if self.means is None and self.stds is None: + pass + elif sum([x is None for x in [self.means, self.stds]]) == 1: + raise RuntimeError( + "Was presented either only STD or only MEAN normalization values. " "Require either none or both!" + ) + else: + norm_trans.append(K.augmentation.Normalize(mean=self.means.get_rgb(), std=self.stds.get_rgb())) + aug = K.augmentation.container.AugmentationSequential(*transforms, *norm_trans) + # deactivate gradients of augmentations forward + aug.forward = torch.no_grad()(aug.forward) + self.pipeline = aug + + def _forward_impl(self, inpt: Any) -> Any: + if self.data_format == DataFormat.BATCHED_SAMPLE_DICTS: + inpt = {"dummy": inpt} + for task in inpt: + sub_batch = inpt[task] + # use order from dataset + aug_modalities = [mod for mod in sub_batch if mod in KORNIA_VALID_MODALITIES] + if Modality.MASK.value in aug_modalities: + # kornia requires mask to be float and same dimensions as image + sub_batch[Modality.MASK.value] = sub_batch[Modality.MASK.value].unsqueeze(1).float() + # disassemble batch + batch_list = [sub_batch[mod] for mod in aug_modalities] + # augment + if self.run_inverse: + augmented = self.pipeline.inverse(*batch_list, data_keys=aug_modalities) + else: + augmented = self.pipeline(*batch_list, data_keys=aug_modalities) + # re-assemble + if len(aug_modalities) == 1: + # kornia treats this case differently and returns tensor instead of list + sub_batch.update({aug_modalities[0]: augmented}) + else: + sub_batch.update({mod: augmented[ix] for ix, mod in enumerate(aug_modalities)}) + if Modality.MASK.value in aug_modalities: + # undo kornia requirement of mask to be float and same dimensions as image + sub_batch[Modality.MASK.value] = sub_batch[Modality.MASK.value].squeeze(1).long() + if self.data_format == DataFormat.BATCHED_SAMPLE_DICTS: + inpt = inpt["dummy"] + return inpt + + def inverse(self, inpt: Any) -> Any: + """ + API to use the feature of kornia augmentations to invertible. Reverts the last augmentation. Useful for TTA. + + :param inpt: a transformed batch (potentially after inference by a model) + :return: the model results with undone geometry + """ + self.run_inverse = True + outpt = self.__call__(inpt) + self.run_inverse = False + return outpt + + def _sanity_check(self, inpt: Any) -> None: + assert self.device == "gpu", "so far only gpu is supported for KorniaAugmentationModule" + assert self.data_format in [DataFormat.MULTI_TASK_SAMPLE_DICTS, DataFormat.BATCHED_SAMPLE_DICTS] + modalities = [] + if self.data_format == DataFormat.MULTI_TASK_SAMPLE_DICTS: + for task in inpt: + modalities.extend(list(inpt[task].keys())) + else: + modalities = list(inpt.keys()) + modalities = [ + mod + for mod in modalities + if mod + not in [Modality.CLASS.value, Modality.CLASSES.value, Modality.SOFT_CLASSES.value, Modality.SAMPLE_ID.value] + ] + if any([mod not in KORNIA_VALID_MODALITIES for mod in modalities]): + raise ValueError(f"Some modality might not be supported by kornia backend: {modalities}") + self.data_keys = modalities + + @staticmethod + def from_cfg(aug_config: ListConfig) -> List[K.augmentation.AugmentationBase2D]: + """ + Takes a config and returns a list of corresponding transforms. + + :param DictConfig aug_config: see configs/augmentations/kornia.yaml for an example + :return: a list of kornia transforms + """ + aug_config = OmegaConf.to_container(aug_config, resolve=True) + transforms = [] + for transform_args in aug_config: + transform_name = transform_args.pop("name") + if transform_name == "RandAugment": + transform = K.auto.RandAugment(**transform_args) + elif transform_name == "AutoAugment": + transform = K.auto.AutoAugment(**transform_args) + elif transform_name == "TrivialAugment": + transform = K.auto.TrivialAugment(**transform_args) + else: + _dict = {"_target_": "kornia.augmentation._2d." + transform_name} + _dict.update(**transform_args) + transform = instantiate(_dict) + transforms.append(transform) + return transforms diff --git a/src/mml/core/data_loading/augmentations/mixup_cutmix.py b/src/mml/core/data_loading/augmentations/mixup_cutmix.py new file mode 100644 index 0000000..383207c --- /dev/null +++ b/src/mml/core/data_loading/augmentations/mixup_cutmix.py @@ -0,0 +1,227 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +""" +Adapted from + https://github.com/veritable-tech/pytorch-lightning-spells/blob/master/pytorch_lightning_spells/callbacks.py +Which was adapted from + https://github.com/rwightman/pytorch-image-models/blob/8c9814e3f500e8b37aae86dd4db10aba2c295bd2/timm/data/mixup.py +Which was partly adapted from + https://github.com/clovaai/CutMix-PyTorch + + Papers: + MixUp: Beyond Empirical Risk Minimization (https://arxiv.org/abs/1710.09412) + CutMix: Regularization Strategy to Train Strong Classifiers with Localizable Features (https://arxiv.org/abs/1905.04899) + + References: + `rwightman/pytorch-image-models/` + `veritable-tech/pytorch-lightning-spells` +""" + +import logging +import warnings +from typing import Dict, List, Optional, Tuple + +import lightning +import numpy as np +import torch +from torchmetrics import MetricCollection + +from mml.core.data_loading.task_attributes import Modality, TaskType +from mml.core.data_loading.task_struct import TaskStruct + +logger = logging.getLogger(__name__) + + +class MixingCallback(lightning.Callback): + def __init__(self, alpha: float = 0.4, label_smoothing: float = 0.0): + """ + Base class for MML data mixing callbacks. + + :param float alpha: controls the mixing factor (between 0 and 1) + :param float label_smoothing: if greater than 0 activates label smoothing + """ + super().__init__() + self.alpha = alpha + self.label_smoothing = label_smoothing + self.target_modalities: Dict[str, str] = {} + self.num_classes: Dict[str, int] = {} + + def setup( + self, trainer: lightning.Trainer, pl_module: lightning.LightningModule, stage: Optional[str] = None + ) -> None: + """ + During set up the task structs are inspected for compatibility and the number of classes is extracted. Due to + data mixing during training the torchmetrics train metrics are deactivated. + """ + task_structs: List[TaskStruct] = trainer.datamodule.task_structs + for struct in task_structs: + task = struct.name + if struct.task_type != TaskType.CLASSIFICATION: + warnings.warn(f"DataMixing not supported for task type {struct.task_type} yet") + continue + self.target_modalities[task] = pl_module.targets[task] + self.num_classes[task] = struct.num_classes + logger.info(f"Deactivating train metrics for classification task {task} due to data mixing.") + pl_module.train_metrics[task] = MetricCollection([]) + + def smooth_one_hot(self, x: torch.Tensor, task: str) -> torch.Tensor: + """ + One hot encoding for a tasks targets with smoothing controlled via + :attr:`~mml.core.data_loading.augmentations.mixup_cutmix.MixingCallback.label_smoothing`. + + :param torch.Tensor x: batched task targets + :param str task: name of the task + :return: one hot encoded task targets, smoothed if + :attr:`~mml.core.data_loading.augmentations.mixup_cutmix.MixingCallback.label_smoothing` > 0 + """ + off_value = self.label_smoothing / self.num_classes[task] + on_value = 1.0 - self.label_smoothing + off_value + x = x.long().view(-1, 1) + return torch.full((x.size()[0], self.num_classes[task]), off_value, device=x.device).scatter_(1, x, on_value) + + def mixup_targets(self, targets: torch.Tensor, lambdas: np.ndarray, task: str) -> torch.Tensor: + """ + Takes care of mixing targets. + + :param torch.Tensor targets: batched task targets, first target will be mixed with last, second with second + to last, etc. + :param np.ndarray lambdas: actual fractions of each mix + :param str task: name of the task + :return: (optionally) smoothed and then mixed targets + """ + y1 = self.smooth_one_hot(targets, task=task) + y2 = self.smooth_one_hot(targets.flip(0), task=task) + lam = targets.new(lambdas).view(-1, *[1 for _ in range(len(y1.size()) - 1)]) + return y1 * lam + y2 * (1.0 - lam) + + +class CutMixCallback(MixingCallback): + def __init__(self, alpha: float = 0.4, label_smoothing: float = 0.0, minmax: Optional[Tuple[float, float]] = None): + """ + Callback that performs CutMix augmentation on training batches. Incorporates two strategies: + * bounding box sizes are either controlled via a beta ditribution controlled by parameter alpha + * or if set minmax controls relative bbox ratios and the distribution is more uniformly + + :param float alpha: if minmax is None this value controls the beta distribution + :param float label_smoothing: if greater than 0 activates label smoothing + :param Optional[Tuple[float, float]] minmax: min and max bbox ratios (as percent of image size), + typical values for minmax are in the .2-.3 for min and .8-.9 range for max. + """ + super().__init__(alpha=alpha, label_smoothing=label_smoothing) + self.ratio_minmax = minmax + + def on_train_batch_start( + self, + trainer: lightning.Trainer, + pl_module: lightning.LightningModule, + batch: Dict[str, Dict[str, torch.Tensor]], + batch_idx: int, + ) -> None: + """Will be triggered on each training batch.""" + for task in batch: + images: torch.Tensor = batch[task][Modality.IMAGE.value] + targets: torch.Tensor = batch[task][self.target_modalities[task]] + images_flipped = images.flip(0).clone() + lambdas = np.random.beta(self.alpha, self.alpha, images.size(0)) + for i in range(images.shape[0]): + (yl, yh, xl, xh), lambd_tmp = self.get_bbox_and_lam(images.shape, lambdas[i]) + lambdas[i] = lambd_tmp + # fill in the cut regions + images[i, :, yl:yh, xl:xh] = images_flipped[i, :, yl:yh, xl:xh] + new_targets = self.mixup_targets(targets, lambdas, task=task) + batch[task][Modality.IMAGE.value] = images + batch[task][self.target_modalities[task]] = new_targets + + def get_bbox_and_lam( + self, img_shape: Tuple, lam: float + ) -> Tuple[Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray], np.ndarray]: + """Generate bbox and apply lambda correction.""" + if self.ratio_minmax is not None: + yl, yu, xl, xu = self.rand_bbox_minmax(img_shape) + else: + yl, yu, xl, xu = self.rand_bbox(img_shape, lam) + bbox_area = (yu - yl) * (xu - xl) + lam = 1.0 - bbox_area / float(img_shape[-2] * img_shape[-1]) + return (yl, yu, xl, xu), lam + + def rand_bbox( + self, img_shape: Tuple, lam: float, margin: float = 0.0, count: Optional[int] = None + ) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: + """ + Standard CutMix bounding-box. Generates a random square bbox based on lambda value. This implementation includes + support for enforcing a border margin as percent of bbox dimensions. + + :param img_shape: image shape as tuple + :param lam: cutmix lambda value + :param margin: percentage of bbox dimension to enforce as margin (reduce amount of box outside image) + :param count: number of bbox to generate + :return: + """ + ratio = np.sqrt(1 - lam) + img_h, img_w = img_shape[-2:] + cut_h, cut_w = int(img_h * ratio), int(img_w * ratio) + margin_y, margin_x = int(margin * cut_h), int(margin * cut_w) + cy = np.random.randint(0 + margin_y, img_h - margin_y, size=count) + cx = np.random.randint(0 + margin_x, img_w - margin_x, size=count) + yl = np.clip(cy - cut_h // 2, 0, img_h) + yh = np.clip(cy + cut_h // 2, 0, img_h) + xl = np.clip(cx - cut_w // 2, 0, img_w) + xh = np.clip(cx + cut_w // 2, 0, img_w) + return yl, yh, xl, xh + + def rand_bbox_minmax( + self, img_shape: Tuple[float, float, float], count: Optional[int] = None + ) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: + """ + Alternative min-max cutmix bounding-box. Inspired by Darknet cutmix implementation, generates a random + rectangular bbox based on min/max percent values applied to each dimension of the input image. + + :param img_shape: image shape as tuple + :param count: number of bbox to generate + :return: bounding box positions for the full batch + """ + assert len(self.ratio_minmax) == 2 + img_h, img_w = img_shape[-2:] + cut_h = np.random.randint(int(img_h * self.ratio_minmax[0]), int(img_h * self.ratio_minmax[1]), size=count) + cut_w = np.random.randint(int(img_w * self.ratio_minmax[0]), int(img_w * self.ratio_minmax[1]), size=count) + yl = np.random.randint(0, img_h - cut_h, size=count) + xl = np.random.randint(0, img_w - cut_w, size=count) + yu = yl + cut_h + xu = xl + cut_w + return yl, yu, xl, xu + + +class MixUpCallback(MixingCallback): + def __init__(self, alpha: float = 0.4, label_smoothing: float = 0.0): + """ + Callback that performs MixUp augmentation on training batches. + + :param float alpha: controls the mixing factor (between 0 and 1) + :param float label_smoothing: if greater than 0 activates label smoothing + """ + super().__init__(alpha=alpha, label_smoothing=label_smoothing) + + def on_train_batch_start( + self, + trainer: lightning.Trainer, + pl_module: lightning.LightningModule, + batch: Dict[str, Dict[str, torch.Tensor]], + batch_idx: int, + ) -> None: + """Will be triggered on each training batch.""" + for task in batch: + images: torch.Tensor = batch[task][Modality.IMAGE.value] + targets: torch.Tensor = batch[task][self.target_modalities[task]] + images_flipped = images.flip(0).clone() + lambdas = np.random.beta(self.alpha, self.alpha, images.size(0)) + # Create the tensor and expand (for batch inputs) + lambdas_tensor = images.new(lambdas).view(-1, *[1 for _ in range(len(images.size()) - 1)]) + # Combine input batch + new_images = images * lambdas_tensor + images_flipped * (1 - lambdas_tensor) + new_targets = self.mixup_targets(targets, lambdas, task=task) + batch[task][Modality.IMAGE.value] = new_images + batch[task][self.target_modalities[task]] = new_targets diff --git a/src/mml/core/data_loading/augmentations/torchvision.py b/src/mml/core/data_loading/augmentations/torchvision.py new file mode 100644 index 0000000..c38f022 --- /dev/null +++ b/src/mml/core/data_loading/augmentations/torchvision.py @@ -0,0 +1,136 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from typing import Any, Dict, List, Optional + +import torch +from hydra.utils import instantiate +from omegaconf import ListConfig, OmegaConf +from torchvision import tv_tensors +from torchvision.transforms import v2 + +from mml.core.data_loading.augmentations.augmentation_module import AugmentationModule, DataFormat +from mml.core.data_loading.task_attributes import Modality, RGBInfo + + +class TorchvisionAugmentationModule(AugmentationModule): + """ + Torchvision V2 augmentation module. + """ + + def __init__( + self, + device: str, + cfg: ListConfig, + is_first: bool, + is_last: bool, + means: Optional[RGBInfo], + stds: Optional[RGBInfo], + num_classes: Optional[int] = None, + ): + self.num_classes = num_classes + super().__init__(device=device, cfg=cfg, is_first=is_first, is_last=is_last, means=means, stds=stds) + # prevent collating and precision conversions to change type + tv_tensors.set_return_type("TVTensor") + + def _build_pipeline(self): + t_list = [] + if self.device == "cpu": + # first format transforms on cpu + t_list.extend([v2.ToDtype(torch.uint8, scale=True)]) + t_list.extend(self.from_cfg(self.cfg, on_cpu=self.device == "cpu", num_classes=self.num_classes)) + if self.means is None and self.stds is None: + if self.is_last or self.device == "cpu": # need to transfer floats + t_list.append(v2.ToDtype(torch.float32, scale=True)) + elif sum([x is None for x in [self.means, self.stds]]) == 1: + raise RuntimeError( + "Was presented either only STD or only MEAN normalization values. " "Require either none or both!" + ) + else: + # Normalize expects float input + t_list.append(v2.ToDtype(torch.float32, scale=True)) + t_list.append(v2.Normalize(mean=self.means.get_rgb(), std=self.stds.get_rgb())) + if self.is_last: + t_list.append(v2.ToPureTensor()) + aug = v2.Compose(t_list) + # see if necessary, should be deactivated by default + # deactivate gradients of augmentations forward + # aug.forward = torch.no_grad()(aug.forward) + self.pipeline = aug + + def _forward_impl(self, inpt: Any) -> Any: + if self.data_format == DataFormat.BATCHED_SAMPLE_DICTS or self.data_format == DataFormat.SINGLE_SAMPLE_DICT: + inpt = {"dummy": inpt} + outpt = self.pipeline(apply_tv_tensor_types(inpt)) + if self.data_format == DataFormat.BATCHED_SAMPLE_DICTS or self.data_format == DataFormat.SINGLE_SAMPLE_DICT: + outpt = outpt["dummy"] + return outpt + + def _sanity_check(self, inpt: Any) -> None: + pass + + @staticmethod + def from_cfg(aug_config: ListConfig, on_cpu: bool, num_classes: Optional[int] = None) -> List[v2.Transform]: + """ + Takes a config and returns a list of corresponding transforms. + + :param DictConfig aug_config: see configs/augmentations/torchvision.yaml for an example, both the "cpu" and the + "gpu" attribute may be passed to this function. + :param bool on_cpu: determines if the transforms will be performed on cpu (single sample in a worker) or gpu + (batched) + :param Optional[int] num_classes: optional parameter required for MixUp and CutMix transforms + :return: a list of torchvision v2 transforms + """ + aug_config = OmegaConf.to_container(aug_config, resolve=True) + transforms = [] + for transform_args in aug_config: + transform_name = transform_args.pop("name") + if transform_name in ["CutMix", "MixUp"]: + if on_cpu: + raise ValueError("CutMix and MixUp transforms need to be performed in batched mode on gpu!") + if not num_classes: + raise ValueError("CutMix and MixUp transforms require the num_classes parameter to be given.") + transform_args["num_classes"] = num_classes + transform_args["labels_getter"] = mixup_cutmix_labels_getter + _dict = {"_target_": "torchvision.transforms.v2." + transform_name} + _dict.update(**transform_args) + transform = instantiate(_dict) + transforms.append(transform) + return transforms + + +def mixup_cutmix_labels_getter(batch: Dict[str, Dict[str, torch.Tensor]]) -> torch.Tensor: + """ + Helper function to extract labels from a batch for torchvision v2 MixUp and CutMix transforms. + See https://pytorch.org/vision/main/auto_examples/transforms/plot_cutmix_mixup.html#non-standard-input-format. + + :param Dict[str, Dict[str, torch.Tensor]] batch: full batch as returned by dataloader, expects a single task + :return: classification labels of the single task + """ + task_batch = next(iter(batch.values())) + for modality_cand in [Modality.CLASS, Modality.CLASSES, Modality.SOFT_CLASSES]: + if modality_cand.value in task_batch: + return task_batch[modality_cand.value] + raise RuntimeError( + f"Mixup_cutmix_labels_getter did not find a suitable target in batch with keys:" f" {task_batch.keys()}." + ) + + +def apply_tv_tensor_types(inpt: Dict[str, Dict[str, Any]]) -> Dict[str, Dict[str, Any]]: + """ + Turns plain tensors organised in Modality Dict structure to corresponding TV-Tensors. + + See https://pytorch.org/vision/stable/tv_tensors.html + + :param Dict[str, Dict[str, Any]] inpt: input, must be in DataFormat.MULTI_TASK_SAMPLE_DICTS + :return: same batch, but all tensors are wrapped by corresponding tv_tensors + """ + for task in inpt: + if Modality.IMAGE.value in inpt[task]: + inpt[task][Modality.IMAGE.value] = tv_tensors.Image(inpt[task][Modality.IMAGE.value], requires_grad=False) + if Modality.MASK.value in inpt[task]: + inpt[task][Modality.MASK.value] = tv_tensors.Mask(inpt[task][Modality.MASK.value], requires_grad=False) + return inpt diff --git a/src/mml/core/data_loading/file_manager.py b/src/mml/core/data_loading/file_manager.py new file mode 100644 index 0000000..3653f31 --- /dev/null +++ b/src/mml/core/data_loading/file_manager.py @@ -0,0 +1,822 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import dataclasses +import logging +import os.path +import shutil +import warnings +from pathlib import Path +from typing import Dict, List, Optional, Union + +import ijson +import orjson +import torch +from lightning.pytorch.callbacks import ModelCheckpoint +from omegaconf import Container, DictConfig + +from mml.core.data_loading.task_description import ( + ALL_HEADER_KEYS, + ALL_TASK_DESCRIPTION_KEYS, + STRUCT_REQ_HEADER_KEYS, + TaskDescription, +) +from mml.core.scripts.exceptions import MMLMisconfigurationException, TaskNotFoundError +from mml.core.scripts.model_storage import EnsembleStorage, ModelStorage +from mml.core.scripts.utils import Singleton, catch_time + +logger = logging.getLogger(__name__) + +# prefixes for files / folders representing tasks and datasets +DSET_PREFIX = "DSET" +TASK_PREFIX = "TASK" + +# reusable number tag, call mml with reuse.key=projectREUSABLE_NUMBER_TAGinteger to load a specific file number +# (e.g. reuse.ensemble=test_proj#3) +REUSABLE_NUMBER_TAG = "#" + +# default strategies to determine file paths for certain computed artefacts +# key : (type, path, enable_numbering, reusable) +DEFAULT_ASSIGNMENTS = { + "parameters": (ModelCheckpoint, Path("PROJ_PATH") / "PARAMETERS" / "TASK_NAME" / "model.pth", True, True), + "img_examples": (None, Path("PROJ_PATH") / "IMG_EXAMPLES" / "TASK_NAME" / "examples.png", True, False), + "blueprint": (Container, Path("PROJ_PATH") / "BLUEPRINTS" / "TASK_NAME" / "blueprint.yaml", True, True), + "pipeline": (Container, Path("PROJ_PATH") / "PIPELINES" / "TASK_NAME" / "pipeline.yaml", True, True), + "models": (ModelStorage, Path("PROJ_PATH") / "MODELS" / "TASK_NAME" / "FILE_NAME", True, True), + "ensemble": (EnsembleStorage, Path("PROJ_PATH") / "ENSEMBLES" / "TASK_NAME" / "FILE_NAME", True, True), + "predictions": (dict, Path("PROJ_PATH") / "PREDICTIONS" / "TASK_NAME" / "FILE_NAME", True, False), + "sample_grid": (torch.Tensor, Path("PROJ_PATH") / "PLOTS" / "sample_grid" / "grid.png", True, False), + "backup": (None, Path("PROJ_PATH") / "BACKUP" / "FILE_NAME", True, False), + "temp": (None, Path("TEMP_PATH") / "FILE_NAME", True, False), +} + + +# configuration or reusing certain artefacts, +# during runtime this is an OmegaConf DictConfig and may contain additional entries +@dataclasses.dataclass +class ReuseConfig: + blueprint: Optional[Union[str, List[str]]] = None + models: Optional[Union[str, List[str]]] = None + parameters: Optional[Union[str, List[str]]] = None + + +# configuration for removing certain artefacts, +# during runtime this is an OmegaConf DictConfig and may contain additional entries +@dataclasses.dataclass +class RemoveConfig: + img_examples: bool = False + blueprint: bool = False + parameters: bool = False + pipeline: bool = False + predictions: bool = False + models: bool = False + sample_grid: bool = False + backup: bool = False + + +class MMLFileManager(Singleton): + """ + This class keeps track of the file structure of MML. It ensures a consistent checkpointing and loading strategy, + provides aggregated listings, and handles requests for files. + """ + + # this will store all path assignments see "add_assignment_path" for more details + _path_assignments = {} + # will store artefacts not attachable to a specific task + GLOBAL_REUSABLE = "_TOP_LEVEL_" + + def __init__( + self, + data_path: Path, + proj_path: Path, + log_path: Path, + reuse_cfg: Optional[Union[DictConfig, ReuseConfig]] = None, + remove_cfg: Optional[Union[DictConfig, RemoveConfig]] = None, + ): + """ + The file manager is a singleton class and usually is only generated once. Afterward it may be called from + anywhere via `MMLFileManager.instance()`, refer to :class:`~mml.core.scripts.utils.Singleton` for more + details on this. + + :param ~pathlib.Path data_path: path to MML data + :param ~pathlib.Path proj_path: path to current experiment root + :param ~pathlib.Path log_path: path to current experiment run root + :param ReuseConfig reuse_cfg: (optional) a configuration on which files of the project should be reused + :param RemoveConfig remove_cfg: (optional) a configuration on which files of the project should be deleted + """ + # base paths + self.data_path = data_path # rather large files storage -> stores datasets + self.proj_path = proj_path # rather small and aggregated files -> stores exp results + self.log_path = log_path # subdir of proj path representing current experiment run + if any([not path.exists() for path in [self.data_path, self.proj_path.parent]]): + raise MMLMisconfigurationException( + f"Some path was not found! Ensure existing:\n - {self.data_path}\n" + f" - {self.proj_path.parent}\n Please check your " + f"mml.env file or create these paths!" + ) + if REUSABLE_NUMBER_TAG in self.proj_path.stem: + raise MMLMisconfigurationException(f"project name must not contain {REUSABLE_NUMBER_TAG}!") + # data path file system + self.raw_data = self.data_path / "RAW" + self.preprocessed_data = self.data_path / "PREPROCESSED" + self.download_data = self.data_path / "DOWNLOADS" + self.temp_data = self.log_path / "TEMP" + self.checkpoint_path = self.log_path / "CHECKPOINTS" + self.task_dump_path = self.log_path / "task_dump.json" + # if reuse and remove cfg are dataclasses we need to transform to DictConfig but leave untouched if they are + # already DictConfigs - this would break omegaconf interpolation resolving + self.reuse_cfg = DictConfig(dataclasses.asdict(reuse_cfg)) if isinstance(reuse_cfg, ReuseConfig) else reuse_cfg + if self.reuse_cfg and "clean_up" in self.reuse_cfg: + raise MMLMisconfigurationException("reuse.clean_up=... is no longer supported. Use remove=... instead.") + self.remove_cfg = ( + DictConfig(dataclasses.asdict(remove_cfg)) if isinstance(remove_cfg, RemoveConfig) else remove_cfg + ) + # create base of data path if not existent + for p in [self.raw_data, self.preprocessed_data, self.download_data, self.temp_data, self.checkpoint_path]: + p.mkdir(exist_ok=True) + # init overview on created paths (for later remove) + self.created_paths_file = self.log_path / "created_paths.txt" + self.created_paths_file.touch(exist_ok=True) + # create index and reusables + self.task_index: Dict[str, Dict[str, Path]] = {} + self.reusables: Dict[str, Dict[str, Union[Path, List[ModelStorage]]]] = {} + self.reload_task_index() + self._find_reusables() + + @property + def results_root(self) -> Path: + """The root path of the current systems results.""" + return self.proj_path.parent + + @property + def global_reusables(self) -> Dict[str, Path]: + """Global reusables are not attached to a specific task.""" + if self.GLOBAL_REUSABLE not in self.reusables: + logger.debug("No global reusables found.") + return {} + return self.reusables[self.GLOBAL_REUSABLE] + + def get_download_path(self, dset_name: str) -> Path: + """ + Creates and returns a download path for some name dataset name. This will point to the same download path + if called again, via this mechanism detecting existing downloads and continuing downloads is possible. + + :param str dset_name: string (ideally representing the dataset) + :return: empty directory to store downloaded data + :rtype: ~pathlib.Path + """ + candidate = self.download_data / dset_name + if candidate.exists(): + logger.info(f"Found and reuse already existing download folder for dataset {dset_name} @ {candidate}.") + candidate.mkdir(exist_ok=True, parents=False) + return candidate + + def get_dataset_path( + self, dset_name: Optional[str] = None, raw_path: Optional[Path] = None, preprocessing: Optional[str] = None + ) -> Path: + """ + Creates and/or returns a correct dataset directory for the given preprocessing ID. Note that this should only + be called once for the raw case, but can be called multiple times for (even identical) preprocessing IDs. + + :param Optional[str] dset_name: name of the dataset (provide this in case a new raw dataset is created) + :param Optional[~pathlib.Path] raw_path: existing path to the raw version of a dataset (provide this in case + a preprocessing is desired) + :param Optional[str] preprocessing: preprocessing ID, None for raw data + + :raises AssertionError: in case exactly one of preprocessing and raw_path is given + :raises AssertionError: in case not exactly one of raw_path and dset_name is given + :raises FileExistsError: in case dset_name has been given before + + :return: path to store dataset files + :rtype: ~pathlib.Path + """ + assert preprocessing not in ["None", "none"], ( + "Use None value instead none string to call " "get_dataset_path for raw data." + ) + assert (raw_path is None) == (preprocessing is None), "See usage of get_dataset_path." + assert (dset_name is None) != (raw_path is None), "See usage of get_dataset_path." + base = self.raw_data if preprocessing is None else self.preprocessed_data / preprocessing + base.mkdir(exist_ok=True) + if preprocessing: + dset_name = self.undo_prefix(raw_path.name) + # check if this dataset has already (partly) being preprocessed + existing = self.get_all_dset_names() + if preprocessing in existing: + if dset_name in existing[preprocessing]: + warnings.warn( + UserWarning( + f"Dataset {dset_name} has already partly existing preprocessing {preprocessing}. " + f"This could be because of a previous run on the same task or a related task on the" + f" same dataset. Be aware that data might be overwritten, which can cause problems " + f"if you manipulated the preprocessing pipeline of this ID or use random augmentations " + f"on different modalities that are partly shared with other tasks!" + ) + ) + return existing[preprocessing][dset_name] + candidate = base / f"{DSET_PREFIX}_{dset_name}" + if candidate.exists(): + raise FileExistsError( + f"Dataset {dset_name} already present at {candidate}! Please choose a different name." + ) + candidate.mkdir(parents=False, exist_ok=False) + return candidate + + def get_all_dset_names(self) -> Dict[str, Dict[str, Path]]: + """ + Returns all found dataset names. Datasets are clustered by their preprocessing. + + :return: dict with preprocessing key and dict value that itself corresponds to dataset names as key and root + path as value, note that the literal string none is used for not preprocessed data + :rtype: Dict[str, Dict[str, Path]] + """ + all_dsets = {"none": {}} + # first scan RAW folder -> preprocessing id is none in that case + for dataset in self.raw_data.iterdir(): + if not dataset.is_dir() or DSET_PREFIX not in dataset.name: + continue + all_dsets["none"][self.undo_prefix(dataset.name)] = dataset + # now preprocessed folder + for preprocess in self.preprocessed_data.iterdir(): + if not preprocess.is_dir(): + continue + all_dsets[preprocess.name] = {} + for dataset in preprocess.iterdir(): + if not dataset.is_dir() or DSET_PREFIX not in dataset.name: + continue + all_dsets[preprocess.name][self.undo_prefix(dataset.name)] = dataset + return all_dsets + + def get_task_path(self, dset_path: Path, task_alias: str) -> Path: + """ + Creates and returns a correct task file path. + + :param dset_path: dataset path of the task + :param task_alias: name of the task (is used as abbreviation internally and initialises dir name) + :return: path to put task .json file + """ + assert dset_path.exists(), f"Invalid dataset path {dset_path}, use get_dataset_path to create a valid path." + if self.raw_data in dset_path.parents: + preprocessed = "none" + elif self.preprocessed_data in dset_path.parents: + preprocessed = list(dset_path.relative_to(self.preprocessed_data).parents)[-2].name + else: + raise ValueError(f"Given dset_path {dset_path} neither extends raw nor preprocessed paths!") + if task_alias in self.task_index: + if preprocessed in self.task_index[task_alias]: + raise ValueError(f"Alias {task_alias} already used in preprocessed {preprocessed}!") + cleaned = task_alias.replace(" ", "_").replace("--", "") + candidate = dset_path / f"{TASK_PREFIX}_{cleaned}.json" + if candidate.exists(): + raise FileExistsError(f"TaskFile @ {candidate} already exists.") + return candidate + + def reload_task_index(self) -> None: + """ + Scans self.raw_data and self.preprocessed_data for all available tasks, thereby creates a library + concerning aliases and also preprocessings. Task index is a dict with dicts, hierarchy is name -> + preprocessing -> (relative) path. + + :return: None + """ + with catch_time() as timer: + task_index = {} + # first scan RAW folder -> preprocessing id is none in that case + for dataset in self.raw_data.iterdir(): + if not dataset.is_dir(): + continue + for task in dataset.glob("*.json"): + # will ignore e.g. temp files + if TASK_PREFIX not in task.stem: + continue + alias = self.load_task_description_header(task).name + if alias == "": + continue + if alias in task_index: + logger.warning( + f"Duplicated task name {alias} at {task} and {task_index[alias]['none']}, " + f"this overwrites one of them in (more or less) random order!" + ) + task_index[alias] = {"none": task.relative_to(self.data_path)} + # now preprocessed folder + for preprocess in self.preprocessed_data.iterdir(): + if not preprocess.is_dir(): + continue + for dataset in preprocess.iterdir(): + if not dataset.is_dir(): + continue + for task in dataset.glob("*json"): + if TASK_PREFIX not in task.stem: + continue + alias = self.load_task_description_header(task).name + if alias == "": + continue + if alias in task_index: + if preprocess.name in task_index[alias]: + logger.warning( + f"Duplicated task name {alias} at {task} and {task_index[alias][preprocess.name]}, " + f"this overwrites one of them in (more or less) random order!" + ) + task_index[alias][preprocess.name] = task.relative_to(self.data_path) + else: + task_index[alias] = {preprocess.name: task.relative_to(self.data_path)} + self.task_index = task_index + logger.debug(f"(Re)loaded task index and found {len(self.task_index)} aliases in {timer.elapsed:5.2f} seconds.") + + def add_to_task_index(self, path: Path) -> None: + """ + Adds a single task path to the task index. + + :param path: path to .json to be added + :return: None + """ + assert path.exists() + assert path.suffix == ".json" + task_name = self.load_task_description_header(path).name + preprocess = ( + "none" if self.raw_data in path.parents else list(path.relative_to(self.preprocessed_data).parents)[-2].name + ) + if task_name not in self.task_index: + self.task_index[task_name] = {} + assert preprocess not in self.task_index[task_name] + self.task_index[task_name][preprocess] = path + logger.debug(f"Added task {task_name} with preprocessing {preprocess} to task index.") + + @staticmethod + def load_task_description(path: Path) -> TaskDescription: + """ + Returns TaskDescription of given task. + + :param Path path: path to .json file + :return: loaded TaskDescription with all meta information + """ + if not path.exists(): + raise FileNotFoundError(f"Meta task file not found at {path}!") + with open(str(path), "rb") as f: + data_dict = orjson.loads(f.read()) + if any([key not in data_dict for key in ALL_TASK_DESCRIPTION_KEYS]): + raise RuntimeError( + f"Task keys ({data_dict.keys()}) do not cover all required keys " f"({ALL_TASK_DESCRIPTION_KEYS})." + ) + task_description = TaskDescription.from_json(data_dict) + logger.debug(f"Successfully loaded task description from {path}.") + return task_description + + @staticmethod + def write_task_description(path: Path, task_description: TaskDescription, omit_warning: bool = False) -> None: + """ + Stores meta information of a task at the given path. + + :param Path path: path to store .json file + :param TaskDescription task_description: TaskDescription of a task + :param bool omit_warning: if True will raise no warning even if the file already exists + :return: None + """ + logger.info(f"Writing task description at {path}.") + if path.exists() and not omit_warning: + warnings.warn(f"Overwriting existing task meta information at {path}!", UserWarning) + data_dict = task_description.to_json() + with catch_time() as writing_timer: + try: + with open(str(path), "wb") as f: + f.write(orjson.dumps(data_dict)) + # if writing description fails remove the created file again + except Exception as e: + if path.exists(): + path.unlink() + raise e + logger.debug(f"Task description writing time was {writing_timer.pretty_time}.") + + @staticmethod + def load_task_description_header(path: Path) -> TaskDescription: + """ + Similar to load_meta, but recovers only the header information necessary to construct TaskStruct, without the + details regarding folds and sample paths. Useful for large .json files to save time on MML initialisation. + + :param Path path: path to .json file + :return: TaskDescription with only meta information + """ + if not path.exists(): + raise FileNotFoundError(f"Task description file not found at {path}!") + data_dict = {} + with open(str(path), "rb") as f: + for key, value in ijson.kvitems(f, "", use_float=True, buf_size=32768): + if key in ALL_HEADER_KEYS: + data_dict[key] = value + # after loading all required keys, stop parsing the json -> this is what saves time here + if len(data_dict) == len(ALL_HEADER_KEYS): + break + if any([key not in data_dict for key in ALL_HEADER_KEYS]): + raise RuntimeError( + f"Task keys ({data_dict.keys()}) do not cover all required keys ({ALL_HEADER_KEYS}). " + f"Did you miss to migrate your database after an mml-core update?" + ) + task_description = TaskDescription.from_json(data_dict) + logger.debug(f"Successfully loaded task description header from {path}.") + return task_description + + def get_task_info(self, task_name: str, preprocess: str) -> dict: + """ + Locates (if possible) the preprocessed task with provided name. Falls back to raw data in case preprocess is + not available. Returns dict that can be used to construct a TaskStruct object. + + :param str task_name: name of the task + :param str preprocess: a preprocess id (e.g. 'none' for raw task) + :return: kwargs required for TaskStruct + """ + if task_name not in self.task_index: + raise TaskNotFoundError(f"Task {task_name} not listed in task index!") + if preprocess not in self.task_index[task_name]: + # if saved preprocess is not available, load raw version instead + if "none" not in self.task_index[task_name]: + raise TaskNotFoundError(f"No valid loading for task {task_name} given preprocess {preprocess}.") + logger.debug(f"Falling back to loading non-preprocessed data for task {task_name}.") + preprocess = "none" + target_path = self.data_path / self.task_index[task_name][preprocess] + # for rather large .json files only partly parse, else orjson is faster than partial parsing + if os.path.getsize(target_path) > 2**14: + task_description = self.load_task_description_header(target_path) + else: + task_description = self.load_task_description(target_path) + info_kwargs = {"preprocessed": preprocess, "relative_root": self.task_index[task_name][preprocess]} + for key in STRUCT_REQ_HEADER_KEYS: + info_kwargs[key] = getattr(task_description, key) + return info_kwargs + + def _find_reusables(self) -> None: + """ + Scans projects based on the reuse_cfg for existing results that may be recycled. Reusables are stored as + a dict with task name keys (and the global reusable key) and dicts corresponding to what may be reused (e.g. + 'blueprint' or 'pipeline') and values are paths to the respective files. + + :return: None + """ + if self.reuse_cfg is None: + logger.debug("File manager has no reuse config to find reusables.") + return + base_proj_path = self.proj_path.parent + reusables: Dict[str, Dict[str, Union[Path, List[ModelStorage]]]] = {} + # warn for unregistered reuse configuration entries + for attribute in self.reuse_cfg: + if attribute.split(REUSABLE_NUMBER_TAG)[0] not in self._path_assignments: + warnings.warn( + f"You specified reuse of {attribute} but no path has been assigned. Make sure to import " + f"any necessary package that defines this path assignment. Nothing will be reused for " + f"now.", + UserWarning, + ) + # iterate through registered path assignments and check for reuse config entry + for key, assignment in self._path_assignments.items(): + attr_cls, assigned_path, attr_numbering, attr_reusable = assignment + # check if path is designed reusable + if not attr_reusable: + continue + # get and check reuse source project + proj_or_projs = getattr(self.reuse_cfg, key, None) + # no reuse specified + if proj_or_projs is None: + continue + # reuse may be either one or multiple projects + if isinstance(proj_or_projs, str): + proj_or_projs = [proj_or_projs] + else: + warnings.warn( + "Requested multi-project reusables. For all but model reusing this will lead to the " + "behaviour that projects are inspected in order as listed and multiple present artefacts " + "may override each other. Model artefacts are ALL loaded and placed in a single list." + ) + for proj_plus_number in proj_or_projs: + proj = proj_plus_number.split(REUSABLE_NUMBER_TAG)[0] + number = ( + int(proj_plus_number.split(REUSABLE_NUMBER_TAG)[1]) + if REUSABLE_NUMBER_TAG in proj_plus_number + else None + ) + if number is not None and not attr_numbering: + raise ValueError( + f"path assignment for {key} does not have numbering enabled - you may not use " + f"{REUSABLE_NUMBER_TAG} within reuse.{key}=..." + ) + proj_path = base_proj_path / proj + if not proj_path.exists(): + raise MMLMisconfigurationException( + f"specified project {proj} for reuse of {key} not found " f"(@{proj_path})." + ) + if attr_reusable == self.GLOBAL_REUSABLE: + # global reusable -> follow path into folder + # remove project and file name + final_path_folder = proj_path / Path(*assigned_path.parts[1:]).parent + # check for non-existing or empty directory + if not final_path_folder.exists() or next(final_path_folder.iterdir(), None) is None: + warnings.warn(f"Specified project {proj} for reuse of {key} seems to have none such") + continue + if number is not None: + number_map = {int(p.stem.split("_")[-1]): p for p in final_path_folder.iterdir()} + if number not in number_map: + raise ValueError( + f"no file with number {number} found in proj {proj} for reusing key {key}." + f" Folder is {final_path_folder}." + ) + latest_file = number_map[number] + else: + latest_file = max(final_path_folder.iterdir(), key=os.path.getctime) + assert latest_file.is_file() + if self.GLOBAL_REUSABLE not in reusables: + reusables[self.GLOBAL_REUSABLE] = {} + reusables[self.GLOBAL_REUSABLE][key] = latest_file + logger.debug(f"Found global reusable {key} from project {proj} @ {latest_file}.") + else: + # otherwise task specific reusables, follow individual task paths + attr_path = proj_path / assigned_path.parts[1] + if not attr_path.exists(): + warnings.warn(f"Specified project {proj} for reuse of {key} seems to have none such") + else: + for task_path in attr_path.iterdir(): + if "%" in task_path.name: + # these are old style "task_id" based paths + warnings.warn( + 'Loading reusables with old style path assignments ("task_id"). Backward ' + "compatibility may break in the future!", + DeprecationWarning, + ) + task_name = "_".join(task_path.name.split("%")[-1].split("_")[1:]) + else: + # new style "task_name" based paths + task_name = task_path.name + if task_name not in reusables: + reusables[task_name] = {} + if key == "models": + if number is not None: + raise MMLMisconfigurationException( + "May not specify a specific model to reuse -" "all models will be loaded." + ) + if "models" not in reusables[task_name]: + reusables[task_name]["models"] = [] + for storage_path in task_path.iterdir(): + assert storage_path.is_file() + storage = ModelStorage.from_json(storage_path, results_root=self.results_root) + reusables[task_name]["models"].append(storage) + logger.debug(f"Found reusable model from project {proj} @ {storage_path}.") + else: + # check for non-existing or empty directory + if not task_path.exists() or next(task_path.iterdir(), None) is None: + continue + if number is not None: + number_map = {int(p.stem.split("_")[-1]): p for p in task_path.iterdir()} + import IPython + + IPython.embed() + if number not in number_map: + raise ValueError( + f"no file with number {number} found in proj {proj} for reusing key {key}." + f" Folder is {task_path}." + ) + latest_file = number_map[number] + else: + latest_file = max(task_path.iterdir(), key=os.path.getctime) + assert latest_file.is_file() + reusables[task_name][key] = latest_file + logger.debug(f"Found reusable {key} from project {proj} @ {latest_file}.") + self.reusables = reusables + + @classmethod + def add_assignment_path( + cls, + obj_cls: Optional[type], + key: str, + path: Union[Path, str], + enable_numbering: bool = True, + reusable: Union[bool, str] = False, + ) -> None: + """ + Adds a custom path assignment to the file manager. A necessary location to do the assignment is before the + initialization of the file manager (note this is a class method), which could be just before starting the + :func:`~mml.cli.main` inside your code or the 'activate.py' of your plugin. + Once the assignment is done, a new path can be requested via the :meth:`construct_saving_path` method. + Furthermore, the path assignments control the reuse functionality of the file manager. + + :param Optional[type] obj_cls: the class of objects you want to create a path for, this is used for + double-checking during usage, provide None if you want to omit this step + :param str key: the key you want to refer your path to, this must be unique, raises :exc:`KeyError` if the + key is already in use + :param Union[~pathlib.Path, str] path: the desired path to store the data, it must start either with `PROJ_PATH` + or `TEMP_PATH`, which will later be replaced with the file managers attr:`proj_path` respectively + :attr:`temp_data` otherwise raises a :exc:`ValueError`. The path may use the following further + special tokens, that will be replaced during actual path creation: `TASK_NAME` and `FILE_NAME`. + `TASK_NAME` is a placeholder that will be replaced during + :meth:`construct_saving_path` and is necessary for the reuse functionality (see `reusable` below). + `FILE_NAME` will + allow naming the file during the actual call to :meth:`construct_saving_path` and is only allowed as the + last part of the path. + :param bool enable_numbering: boolean deciding if the path is static or will dynamically increase when a file + already exists. Default: ``True`` + :param Union[bool, str] reusable: if True the paths should be reusable. This allows to set + ``reuse.key=project`` (or even ``reuse.key=[project1,project2]`` to load from multiple projects, where the + last found artefact persists) when starting :mod:`mml` and automatically attach the latest path under + `PROJ_PATH//TASK_NAME` to each task structs + `:attr:`~mml.core.data_loading.task_struct.TaskStruct.paths` dictionary with ``key`` as a key. This + requires path to fit the format `PROJ_PATH//TASK_NAME/`, where `` is + required to be capitalized by convention, otherwise a raises an ValueError. If the string + `:attr:`~mml.core.data_loading.file_manager.MMLFileManager.GLOBAL_REUSABLE` is used + instead any found reusable is attached to the `_TOP_LEVEL_` entry + to be reached via `:attr:`~mml.core.data_loading.file_manager.MMLFileManager.global_reusables` property. + This does not require the path format previously specified. + :raises KeyError: if key is already used for a path construction + :raises ValueError: If either + * path does not start with `PROJ_PATH` or `TEMP_PATH` + * the path has no suffix to indicate a file type (exception if `FILE_NAME` is the last path segment) + * `FILE_NAME` is used as a non-final part of the path + * the cls argument is neither None nor a class + * reusable=True but path does not match the described requirements + * ``..`` or ``~`` in path + * plus some more checks + + :return: None + """ + if key in cls._path_assignments: + raise KeyError(f"Key {key} already used by file manager for path assignments.") + path = Path(path) + if path.parts[0] != "PROJ_PATH" and path.parts[0] != "TEMP_PATH": + raise ValueError("assignment path must start with either PROJ_PATH or TEMP_PATH") + if not path.name == "FILE_NAME" and path.suffix == "": + raise ValueError("assignment path must end either with FILE_NAME or provide a suffix") + if "FILE_NAME" in path.parts[:-1]: + raise ValueError("FILE_NAME may be only used as a token for the last part of the path") + if obj_cls is not None and not isinstance(obj_cls, type): + raise ValueError(f"given cls={obj_cls} is not a class nor None") + # does reusability apply? + global_reusable = False + if not isinstance(reusable, bool): + if reusable != cls.GLOBAL_REUSABLE: + raise ValueError(f"reusable must either be boolean or equal {cls.GLOBAL_REUSABLE}") + if path.parts[0] != "PROJ_PATH": + raise ValueError("Reusable must be non-temporary - use PROJ_PATH as first path entry.") + if "TASK_NAME" in path.parts: + raise ValueError("Global reusable must be task independent!") + global_reusable = True + if reusable and not global_reusable: + reusable_err_msg = ( + "Reusable path assignment requested, but path does not match requirements! Read " "documentation." + ) + if len(path.parts) != 4: + raise ValueError(reusable_err_msg) + # automatically attachable reusables must match this pattern + base, attr_id, task_name, file_name = tuple(path.parts) + if base != "PROJ_PATH" or not attr_id.isupper() or task_name != "TASK_NAME": + raise ValueError(reusable_err_msg) + # some sneaky corner cases + if key in ["checkpoints"]: + raise ValueError("Checkpoints are handled from within the scheduler.") + all_tokens = ["PROJ_PATH", "TEMP_PATH", "FILE_NAME", "TASK_NAME"] + for part in path.parts: + if any([token in part and not token == part for token in all_tokens]): + raise ValueError(f"Token misuse in path {path}!") + for token in all_tokens: + if path.parts.count(token) > 1: + raise ValueError(f"Token {token} is used multiple times in path {path}!") + if "-" in key or ":" in key: + raise ValueError("Avoid using - or : in key, use _ instead!") + if "~" in path.parts or ".." in path.parts: + raise ValueError("Avoid using ~ or .. in path!") + if REUSABLE_NUMBER_TAG in path.stem: + raise ValueError(f"file name must not contain {REUSABLE_NUMBER_TAG}!") + cls._path_assignments[key] = (obj_cls, path, enable_numbering, reusable) + + def construct_saving_path( + self, obj: object, key: str, task_name: Optional[str] = None, file_name: Optional[str] = None + ) -> Path: + """ + All file savings are organised here to avoid unwanted interactions from different applications. + + :param Any obj: object to be saved (if the object itself are files, simply give None) + :param str key: string, must be in the DEFAULT_ASSIGNMENTS or manually assigned previously + (see :meth:`add_assignment_path`) + :param Optional[str] task_name: (optional) name of the task, only necessary if TASK_NAME in the assignment + pattern + :param Optional[str] file_name: (optional) file name, only necessary if FILE_NAME in the assignment pattern + :return: path to save the object + """ + if task_name is not None and "%" in task_name: + raise ValueError("Constructing saving path with task_id is deprecated. Please use task_name instead!") + if key not in self._path_assignments: + raise KeyError( + f"Wanted to construct saving path with key {key}, which is unknown. Did you miss to " + f"add_assignment_path?" + ) + if file_name is not None and REUSABLE_NUMBER_TAG in file_name: + raise ValueError(f"symbol {REUSABLE_NUMBER_TAG} is not allowed in file name!") + obj_class, path, enable_numbering, _ = self._path_assignments[key] + if obj_class is not None: + assert isinstance(obj, obj_class), ( + f"Expected obj with type {obj_class} for saving key {key}, but got " f"{type(obj)}." + ) + if "TASK_NAME" in path.parts and task_name is None: + raise ValueError(f"Must provide task_name for {key=}") + if "FILE_NAME" in path.parts and file_name is None: + raise ValueError(f"Must provide file_name for {key=}") + # parse special elements of path + assignment_tokens = { + "PROJ_PATH": str(self.proj_path), + "TEMP_PATH": str(self.temp_data), + "FILE_NAME": file_name, + "TASK_NAME": task_name, + } + for token, replacement in assignment_tokens.items(): + if replacement is not None: # capture non set file_name and/or task_name + path = Path(str(path).replace(token, replacement)) + # create file structure above + path.parent.mkdir(exist_ok=True, parents=True) + # number file if requested + if enable_numbering: + logger.debug(f"Saving some {key} at {path}! This triggers an enumeration number to avoid overwriting!") + path_found = False + retries = 0 + while not path_found: + if retries > 10: + raise RuntimeError(f"Was not able to create path for {obj=} {key=} {task_name=} {file_name=}.") + nums = [ + int(p.stem.split("_")[-1]) for p in path.parent.iterdir() if path.stem in p.stem and "_" in p.stem + ] + nums += [0] # assure nums is not empty + new_name = path.stem + "_" + str(max(nums) + 1).zfill(4) + path.suffix + path = path.parent / new_name + try: + path.touch(exist_ok=False) + path_found = True + except FileExistsError: + logger.error(f"Race condition for storing at {path} encountered. Will retry") + retries += 1 + # log created path + with open(self.created_paths_file, "a") as file: + file.write(f"{key}:{path}\n") + return path + + def remove_intermediates(self) -> None: + """ + Based on the clean_up settings of the reuse_config deletes intermediate results within this project to minimize + disk storage. Other intermediates like the checkpoints path and the temp path are also cleared. + + :return: None + """ + # clean up config + if self.remove_cfg: + clean_up_keys = set([k for k, v in self.remove_cfg.items() if bool(v)]) + for key in clean_up_keys: + if key not in self._path_assignments: + warnings.warn(f"Requested deletion of paths with key {key} but this has never been registered!") + with open(self.created_paths_file, "r") as file: + created_paths = file.readlines() + found_keys = set() + unlinked_counter = 0 + for line in created_paths: + key, path = line.strip().split(":") + if key in clean_up_keys: + found_keys.add(key) + Path(path).unlink() + unlinked_counter += 1 + # generate report + logger.info(f"A total of {len(created_paths)} paths have been created during this run.") + if unlinked_counter > 0: + logger.info(f"File manager removed {unlinked_counter} files of types {found_keys}.") + not_found = clean_up_keys - found_keys + if not_found: + logger.info(f"Although requested {not_found} cleanup, no paths were created!") + else: + logger.info("HINT: Specify reuse.clean_up config to reduce memory requirements.") + # checkpoints are auto deleted + shutil.rmtree(self.checkpoint_path) + logger.debug("Removed CHECKPOINTS folder.") + # temp folder is auto deleted + shutil.rmtree(self.temp_data) + logger.debug("Removed TEMP folder.") + + @staticmethod + def undo_prefix(dir_name: str) -> str: + """ + Reverts the application of task/dset prefix adding. + + :param dir_name: string to be applied on + :return: non-prefixed string + """ + return "_".join(dir_name.split("_")[1:]) + + def get_pp_definition(self, preprocessing: str) -> Path: + """ + Return a definition copy of a created preprocessing folder. Can be used to check whether a preprocessing + definition has changed since it's processing. If no file has been created so far a new one will be created. + + :param preprocessing: the ID of the preprocessing + :return: path to a file to store a preprocessing definition + """ + if preprocessing == "none": + raise ValueError("No preprocessing definition will be created for unpreprocessed data!") + path = self.preprocessed_data / preprocessing / "_definition.yaml" + path.parent.mkdir(exist_ok=True) + return path + + +# add default assignments when this file is loaded +for key, assignment in DEFAULT_ASSIGNMENTS.items(): + obj_cls, path, numbering, reuse = assignment + MMLFileManager.add_assignment_path(obj_cls=obj_cls, key=key, path=path, enable_numbering=numbering, reusable=reuse) diff --git a/src/mml/core/data_loading/lightning_datamodule.py b/src/mml/core/data_loading/lightning_datamodule.py new file mode 100644 index 0000000..0904138 --- /dev/null +++ b/src/mml/core/data_loading/lightning_datamodule.py @@ -0,0 +1,383 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import warnings +from pathlib import Path +from typing import Any, Dict, List, Optional, Tuple, Union + +import hydra.utils +import lightning +import torch +from lightning.pytorch.utilities import CombinedLoader +from omegaconf import DictConfig +from torch.utils.data import DataLoader +from torchvision import tv_tensors + +from mml.core.data_loading.augmentations.albumentations import AlbumentationsAugmentationModule +from mml.core.data_loading.augmentations.augmentation_module import AugmentationModule, AugmentationModuleContainer +from mml.core.data_loading.augmentations.kornia import KorniaAugmentationModule +from mml.core.data_loading.augmentations.torchvision import TorchvisionAugmentationModule +from mml.core.data_loading.modality_loaders import ModalityLoader +from mml.core.data_loading.task_attributes import IMAGENET_MEAN, IMAGENET_STD, DataSplit, Modality, RGBInfo, TaskType +from mml.core.data_loading.task_dataset import TaskDataset +from mml.core.data_loading.task_struct import TaskStruct +from mml.core.scripts.exceptions import MMLMisconfigurationException +from mml.core.scripts.utils import LearningPhase, catch_time + +logger = logging.getLogger(__name__) + + +class MultiTaskDataModule(lightning.LightningDataModule): + def __init__(self, task_structs: List[TaskStruct], cfg: DictConfig, fold: int = 0): + logger.debug("Initializing Lightning datamodule.") + super().__init__() + self.task_structs: List[TaskStruct] = task_structs + self.cfg = cfg + self.roots: Dict[str, Path] = { + struct.name: Path(self.cfg.data_dir) / struct.relative_root for struct in self.task_structs + } + self.fold: int = fold + # attach batch size as attribute, this allows lightning to tune + self.batch_size: Optional[int] = self.cfg.sampling.batch_size + # variable storing the datasets after setup + self.task_datasets: Dict[str, Dict[LearningPhase, TaskDataset]] = { + struct.name: {} for struct in self.task_structs + } + # check that preprocessing matches caching option + self.do_cache = {struct.name: self.cfg.sampling.enable_caching for struct in self.task_structs} + _cache_counter = 0 + for struct in self.task_structs: + if self.do_cache[struct.name]: + if struct.preprocessed != self.cfg.preprocessing.id: + logger.error( + f"Requested caching on dataset {struct.name} but data is not preprocessed! " f"Will deactivate" + ) + self.do_cache[struct.name] = False + else: + if _cache_counter + struct.num_samples > self.cfg.sampling.cache_max_size: + logger.info( + f"No caching for {struct.name}, since cache would likely exceed " + f"sampling.cache_max_size." + ) + self.do_cache[struct.name] = False + else: + _cache_counter += struct.num_samples + logger.debug(f"Cache information: {self.do_cache}") + # new backend functionality + self.has_gpu_augs = len(self.cfg.augmentations.gpu) > 0 + # will store gpu augmentations per device + self.gpu_train_augs: Optional[AugmentationModule] = None + self.gpu_test_augs: Optional[AugmentationModule] = None + # control predict split + self.predict_on = DataSplit.TEST + + def prepare_data(self, *args, **kwargs): + pass + + def setup(self, stage: str) -> None: + logger.debug("Datamodule setup started") + with catch_time() as timer: + if stage == "fit": + # prepare train and validation splits + for struct in self.task_structs: + self.task_datasets[struct.name][LearningPhase.TRAIN] = TaskDataset( + root=self.roots[struct.name], + split=DataSplit.TRAIN, + fold=self.fold, + transform=self.get_cpu_transforms(struct=struct, phase=LearningPhase.TRAIN), + caching_limit=self.cfg.sampling.cache_max_size + if (self.do_cache[struct.name] and self.cfg.sampling.enable_caching) + else 0, + loaders=self.get_modality_loaders(), + ) + self.task_datasets[struct.name][LearningPhase.VAL] = TaskDataset( + root=self.roots[struct.name], + split=DataSplit.VAL, + fold=self.fold, + transform=self.get_cpu_transforms(struct=struct, phase=LearningPhase.VAL), + caching_limit=self.cfg.sampling.cache_max_size + if (self.do_cache[struct.name] and self.cfg.sampling.enable_caching) + else 0, + loaders=self.get_modality_loaders(), + ) + # if requested cache datasets + if self.do_cache[struct.name] and self.cfg.sampling.enable_caching: + # fill initial cache + for phase in [LearningPhase.TRAIN, LearningPhase.VAL]: + self.task_datasets[struct.name][phase].fill_cache(num_workers=self.cfg.num_workers) + # prepare test split + elif stage == "test": + for struct in self.task_structs: + # no caching for test dataset! + self.task_datasets[struct.name][LearningPhase.TEST] = TaskDataset( + root=self.roots[struct.name], + split=DataSplit.TEST, + fold=0, + transform=self.get_cpu_transforms(struct=struct, phase=LearningPhase.TEST), + loaders=self.get_modality_loaders(), + ) + elif stage == "predict": + for struct in self.task_structs: + # no caching for predict dataset! + self.task_datasets[struct.name][LearningPhase.TEST] = TaskDataset( + root=self.roots[struct.name], + split=self.predict_on, + fold=self.fold, + # always use test pipeline during predictions + transform=self.get_cpu_transforms(struct=struct, phase=LearningPhase.TEST), + loaders=self.get_modality_loaders(), + ) + # prepare gpu augmentations (per GPU device) + if self.has_gpu_augs: + self._set_gpu_transforms() + logger.debug(f"MultiTaskDataModule setup time: {timer.minutes:.0f}m {timer.seconds:.2f}s") + + def train_dataloader(self, *args, **kwargs) -> CombinedLoader: + return self._get_dataloader(phase=LearningPhase.TRAIN) + + def val_dataloader(self, *args, **kwargs) -> CombinedLoader: + return self._get_dataloader(phase=LearningPhase.VAL) + + def test_dataloader(self, *args, **kwargs) -> CombinedLoader: + return self._get_dataloader(phase=LearningPhase.TEST) + + def predict_dataloader(self, *args, **kwargs) -> CombinedLoader: + return self._get_dataloader(phase=None, predict=True) + + def _get_dataloader(self, phase: Optional[LearningPhase], predict: bool = False) -> CombinedLoader: + """ + Unifies the pytorch lightning dataloader functionalities. Produces a CombinedLoader. + + :param phase phase: learning phase to construct loader for, ignored if predict is true + :param bool predict: if true phase is ignored and self.predict_on is used to deduce the loader + """ + if phase is None and predict is False: + raise ValueError("Must provide phase if not in predict mode") + if predict: + if phase is not None: + warnings.warn("Calling _get_dataloader with predict=True will ignore phase kwarg and use TEST phase.") + phase = LearningPhase.TEST + loader_kwargs = { + struct.name: self.get_loader_kwargs_from_cfg(phase=phase, task_name=struct.name) + for struct in self.task_structs + } + return CombinedLoader( + { + struct.name: DataLoader(self.task_datasets[struct.name][phase], **loader_kwargs[struct.name]) + for struct in self.task_structs + }, + mode="max_size_cycle" if (phase == LearningPhase.TRAIN) else "sequential", + ) + + def get_cpu_transforms( + self, struct: TaskStruct, phase: LearningPhase = LearningPhase.TRAIN + ) -> Union[AugmentationModule, AugmentationModuleContainer]: + # preprocessing is always an albumentations pipeline + pp_tfs = [] + if self.cfg.preprocessing.id != struct.preprocessed: + if struct.preprocessed != "none": + raise RuntimeError("Preprocessing on the fly only available from none (raw).") + pp_tfs = self.cfg.preprocessing.pipeline + warnings.warn( + f"Task {struct.name} not yet preprocessed. Pipeline contains {len(pp_tfs)}" + f" transforms. If you want to speed up training, preprocess this task beforehand." + ) + means, stds = self.get_image_normalization(struct=struct) + if "backend" not in self.cfg.augmentations.cpu: + # no cpu augmentations requested, only pp augmentations + return AlbumentationsAugmentationModule( + cfg=pp_tfs, + device="cpu", + is_first=True, + is_last=not self.has_gpu_augs, + means=None if self.has_gpu_augs else means, + stds=None if self.has_gpu_augs else stds, + floatify=True, + tensorize=True, + ) + # otherwise there are cpu augmentations (at least for training) + if phase != LearningPhase.TRAIN: + aug_tfs = [] + else: + aug_tfs = self.cfg.augmentations.cpu.pipeline + # check if cpu backend matches pp backend + if self.cfg.augmentations.cpu.backend == "albumentations": + # now we can merge pp and aug transforms into one composed albumentations pipeline + return AlbumentationsAugmentationModule( + cfg=pp_tfs + aug_tfs, + device="cpu", + is_first=True, + is_last=not self.has_gpu_augs, + means=None if self.has_gpu_augs else means, + stds=None if self.has_gpu_augs else stds, + floatify=True, + tensorize=True, + ) + module_class = { + "torchvision": TorchvisionAugmentationModule, + }[self.cfg.augmentations.cpu.backend] + + kwargs = { + "means": None if self.has_gpu_augs else means, + "stds": None if self.has_gpu_augs else stds, + "is_first": len(pp_tfs) == 0, + "is_last": not self.has_gpu_augs, + "device": "cpu", + } + if "backend" in self.cfg.augmentations.cpu and self.cfg.augmentations.cpu.backend == "torchvision": + if "MixUp" in aug_tfs or "CutMix" in aug_tfs: + if any(task.task_type != TaskType.CLASSIFICATION for task in self.task_structs): + raise MMLMisconfigurationException("MixUp and CutMix only applicable for classification tasks.") + if len(self.task_structs) > 1: + raise MMLMisconfigurationException("MixUp and CutMix only applicable for single tasks.") + kwargs["num_classes"] = self.task_structs[0].num_classes + aug_module = module_class(cfg=aug_tfs, **kwargs) + # no preprocessing necessary + if len(pp_tfs) == 0: + return aug_module + # last scenario, we have to combine preprocessing with a non-albumentations cpu backend + pp_module = AlbumentationsAugmentationModule( + cfg=pp_tfs, + device="cpu", + is_first=True, + is_last=False, + means=None, + stds=None, + floatify=False, + tensorize=True, + ) + return AugmentationModuleContainer(modules=[pp_module, aug_module]) + + def _set_gpu_transforms(self): + """Might be called during setup (for each device individually) to generate gpu transforms.""" + mean, std = self.get_image_normalization(struct=self.task_structs[0]) + module_class = {"kornia": KorniaAugmentationModule, "torchvision": TorchvisionAugmentationModule}[ + self.cfg.augmentations.gpu.backend + ] + kwargs = {"means": mean, "stds": std, "is_first": False, "is_last": True, "device": "gpu"} + if self.cfg.augmentations.gpu.backend == "torchvision": + if "MixUp" in self.cfg.augmentations.gpu.pipeline or "CutMix" in self.cfg.augmentations.gpu.pipeline: + if any(task.task_type != TaskType.CLASSIFICATION for task in self.task_structs): + raise MMLMisconfigurationException("MixUp and CutMix only applicable for classification tasks.") + if len(self.task_structs) > 1: + raise MMLMisconfigurationException("MixUp and CutMix only applicable for single tasks.") + kwargs["num_classes"] = self.task_structs[0].num_classes + self.gpu_train_augs = module_class(cfg=self.cfg.augmentations.gpu.pipeline, **kwargs) + self.gpu_test_augs = module_class(cfg={}, **kwargs) + + def on_after_batch_transfer(self, batch: Any, dataloader_idx: int) -> Any: + """Enables gpu augmentations after batch has been transferred to device.""" + if self.has_gpu_augs: + if self.trainer.training: + batch = self.gpu_train_augs(batch) + else: + batch = self.gpu_test_augs(batch) + return batch + + def get_image_normalization(self, struct: TaskStruct) -> Tuple[Optional[RGBInfo], Optional[RGBInfo]]: + """ + Returns the applied / required image normalization information. + + :return: tuple of means and stds for each of the channels, in case no normalization is applied returns None + for both + :rtype: Tuple[Optional[~mml.core.data_loading.task_attributes.RGBInfo], + Optional[~mml.core.data_loading.task_attributes.RGBInfo]] + """ + if self.cfg.augmentations.normalization == "imagenet": + means = IMAGENET_MEAN + stds = IMAGENET_STD + elif self.cfg.augmentations.normalization == "task": + if self.has_gpu_augs: + raise MMLMisconfigurationException("GPU Augmentations require uniform normalization across tasks.") + means = struct.means + stds = struct.stds + elif self.cfg.augmentations.normalization == "pretraining": + # check model availability + if not self.trainer.lightning_module: + raise RuntimeError( + "Model not yet available for normalization config pretraining. Please open an issue." + ) + means = self.trainer.lightning_module.model.required_mean + stds = self.trainer.lightning_module.model.required_std + elif self.cfg.augmentations.normalization is None: + means = None + stds = None + warnings.warn(f"Deactivated normalization for task {struct.name}.", UserWarning) + else: + raise MMLMisconfigurationException( + f"Config value {self.cfg.augmentations.normalization} unknown for " + f". Valid values are `imagenet`, " + f"`task` and `null` (for no normalization)." + ) + return means, stds + + def get_loader_kwargs_from_cfg(self, task_name: str, phase: LearningPhase = LearningPhase.TRAIN) -> Dict[str, Any]: + kwargs = { + "num_workers": self.cfg.num_workers // len(self.task_structs), + "pin_memory": True, + "drop_last": self.cfg.sampling.drop_last, + } + if kwargs["num_workers"] > 0: + kwargs["persistent_workers"] = ( + True + # it seems like there is some issue with deleting registered open files https://github.com/pytorch/pytorch/issues/91252 + ) + # during training + if phase == LearningPhase.TRAIN: + ds: TaskDataset = self.task_datasets[task_name][LearningPhase.TRAIN] + if self.cfg.sampling.balanced: + weights = self.get_dataset_balancing_weights(ds) + num_samples = len(ds) if self.cfg.sampling.sample_num == 0 else self.cfg.sampling.sample_num + kwargs["sampler"] = torch.utils.data.WeightedRandomSampler(weights, num_samples=num_samples) + elif self.cfg.sampling.sample_num != 0: + kwargs["sampler"] = torch.utils.data.RandomSampler( + ds, replacement=True, num_samples=self.cfg.sampling.sample_num + ) + else: + kwargs["shuffle"] = True + # do not rely on config batch size, since lightning tuner might have determined datamodule attribute + kwargs["batch_size"] = self.batch_size // len(self.task_structs) + # if self.v2_gpu_train_augs is not None: + # kwargs['collate_fn'] = tv_tensor_collate + return kwargs + + @staticmethod + def get_dataset_balancing_weights(ds: TaskDataset) -> torch.Tensor: + class_weights = torch.tensor(1.0) / torch.tensor([ds.class_occ[cl] for cl in ds.classes], dtype=torch.float) + if ds.task_type == TaskType.CLASSIFICATION: + # calc weights + all_mapped_classes = [ds.loaders[Modality.CLASS].load(entry=s[Modality.CLASS]) for s in ds.samples] + extracted_labels = torch.tensor(all_mapped_classes) + weights = class_weights[extracted_labels] + elif ds.task_type == TaskType.MULTILABEL_CLASSIFICATION: + modality_kind = Modality.CLASSES if Modality.CLASSES in ds.modalities else Modality.SOFT_CLASSES + extracted_labels = [ds.loaders[modality_kind].load(entry=s[modality_kind]) for s in ds.samples] + if modality_kind == Modality.CLASSES: + empty_occ = sum([frame_labels.sum() == 0 for frame_labels in extracted_labels]) + empty_weight = torch.tensor(1.0) / torch.tensor(empty_occ, dtype=torch.float) + weights = torch.tensor( + [class_weights[elem].mean() if elem.sum() > 0 else empty_weight for elem in extracted_labels] + ) + elif modality_kind == Modality.SOFT_CLASSES: + extracted_labels = torch.stack(extracted_labels).float() + # replace missing classes with at least the value one (simulating a single occurrence) + class_weights = torch.nan_to_num(class_weights, nan=None, posinf=1.0) + weights = torch.matmul(extracted_labels, class_weights) + else: + raise RuntimeError("Balanced sampling only supported for (multilabel) classification tasks!") + return weights + + def get_modality_loaders(self) -> Dict[Modality, ModalityLoader]: + """Creates ModalityLoader instances from the config.""" + loader_dict = {} + for k, v in self.cfg.loaders.items(): + loader_dict[Modality(k)] = hydra.utils.instantiate(v) + return loader_dict + + def teardown(self, stage: Optional[str] = None) -> None: + # unset potentially set torchvision setting + tv_tensors.set_return_type("Tensor") diff --git a/src/mml/core/data_loading/modality_loaders.py b/src/mml/core/data_loading/modality_loaders.py new file mode 100644 index 0000000..5fcbc65 --- /dev/null +++ b/src/mml/core/data_loading/modality_loaders.py @@ -0,0 +1,371 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +from abc import ABC, abstractmethod +from pathlib import Path +from typing import TYPE_CHECKING, Any, List, Optional + +import cv2 +import numpy as np +import skimage.io +import torch +import torch.nn.functional +from PIL import Image +from torchvision.io import ImageReadMode, read_image +from torchvision.tv_tensors import Image as TVImage + +from mml.core.data_loading.task_attributes import Modality, ModalityEntry, TaskType +from mml.core.scripts.decorators import beta + +if TYPE_CHECKING: + from mml.core.data_loading.task_dataset import TaskDataset + +logger = logging.getLogger(__name__) + + +class ModalityLoader(ABC): + """ + A modality loader provides the implementation to load entries of the sample dicts for a specific modality. + """ + + def __init__(self, modality: Modality, suffixes: Optional[List[str]], entry_type: Optional[type]): + """ + This init stores supported file suffixes and the modality. They are used for the default matches implementation. + + :param Modality modality: the modality this loader supports + :param Optional[List[str]] suffixes: a list of supported file suffixes, used for loader matching. Provide None + to support "all" suffixes. + :param Optional[type] entry_type: if given, entries must be of this type to match + """ + self.modality = modality + self.suffixes = suffixes + self.entry_type = entry_type + + @abstractmethod + def setup(self, task_dataset: "TaskDataset") -> None: + pass + + @abstractmethod + def load(self, entry: ModalityEntry) -> Any: + """ + The load function is the main routine that will be called with the corresponding entry of a samples modality + within. + """ + pass + + def matches(self, entry: ModalityEntry) -> bool: + """ + This method may be used to find the correct loader for a modality. It is given the entry and + returns True if those can be handled or False if the loader does not support the provided kinds. + + :param ModalityEntry entry: the entry in the sample description corresponding to the modality + :return: whether the loader accepts or rejects this + """ + if self.entry_type and not isinstance(entry, self.entry_type): + return False + if isinstance(entry, str) and self.suffixes: + return any(entry.lower().endswith(suf) for suf in self.suffixes) + return True + + +class OpenCVImageLoader(ModalityLoader): + def __init__(self): + """Default loader for images.""" + self.base_path: Optional[Path] = None # will be setup later + super().__init__(modality=Modality.IMAGE, suffixes=[".bmp", ".jpeg", ".jpg", ".png"], entry_type=str) + # for supported file types see + # https://docs.opencv.org/4.8.0/d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56 + + def load(self, entry: ModalityEntry) -> Any: + path = self.base_path / entry + return cv2.cvtColor(cv2.imread(str(path)), cv2.COLOR_BGR2RGB) + + def setup(self, task_dataset: "TaskDataset") -> None: + self.base_path = task_dataset.root.parent + + +class PillowImageLoader(ModalityLoader): + def __init__(self): + """Another loader for images.""" + self.base_path: Optional[Path] = None # will be setup later + super().__init__(modality=Modality.IMAGE, suffixes=[".bmp", ".jpeg", ".jpg", ".png"], entry_type=str) + # for supported file types see + # https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html + + def load(self, entry: ModalityEntry) -> Any: + path = self.base_path / entry + return self.transform(Image.open(path).convert("RGB")) + + def setup(self, task_dataset: "TaskDataset") -> None: + self.base_path = task_dataset.root.parent + + @staticmethod + def transform(image: Image.Image) -> np.ndarray: + return np.asarray(image) + + +class AcceleratedPillowImageLoader(PillowImageLoader): + """ + Extended Pillow ImageLoader based on the article "Fast import of Pillow images to NumPy / OpenCV arrays" + by Alex Karpinsky, see https://uploadcare.com/blog/fast-import-of-pillow-images-to-numpy-opencv-arrays/ + """ + + @staticmethod + def transform(image: Image.Image) -> np.ndarray: + image.load() + # unpack data + e = Image._getencoder(image.mode, "raw", image.mode) + e.setimage(image.im) + + # NumPy buffer for the result + shape, typestr = Image._conv_type_shape(image) + data = np.empty(shape, dtype=np.dtype(typestr)) + mem = data.data.cast("B", (data.data.nbytes,)) + + bufsize, s, offset = 65536, 0, 0 + while not s: + _, s, d = e.encode(bufsize) + mem[offset : offset + len(d)] = d + offset += len(d) + if s < 0: + raise RuntimeError("encoder error %d in tobytes" % s) + return data + + +class PureTorchvisionImageLoader(ModalityLoader): + def __init__(self): + """Another loader for images based purely on torchvision (no pillow).""" + self.base_path: Optional[Path] = None # will be setup later + super().__init__(modality=Modality.IMAGE, suffixes=[".jpeg", ".jpg", ".png"], entry_type=str) + # for supported file types see + # https://pytorch.org/vision/stable/generated/torchvision.io.read_image.html#torchvision.io.read_image + + def load(self, entry: ModalityEntry) -> Any: + path = self.base_path / entry + return TVImage(read_image(path=str(path), mode=ImageReadMode.RGB), requires_grad=False) + + def setup(self, task_dataset: "TaskDataset") -> None: + self.base_path = task_dataset.root.parent + + +class NumpyArrayImageLoader(ModalityLoader): + def __init__(self): + """Loads images stored as numpy arrays.""" + self.base_path: Optional[Path] = None # will be setup later + super().__init__(modality=Modality.IMAGE, suffixes=[".npy"], entry_type=str) + + @beta("Numpy loading is in beta stage. Not tested yet.") + def load(self, entry: ModalityEntry) -> Any: + path = self.base_path / entry + return np.load(path) + + def setup(self, task_dataset: "TaskDataset") -> None: + self.base_path = task_dataset.root.parent + + +class ScikitImageLoader(ModalityLoader): + def __init__(self): + """Scikit-Image loader for images.""" + self.base_path: Optional[Path] = None # will be setup later + super().__init__(modality=Modality.IMAGE, suffixes=None, entry_type=str) + # supported file types depend on the plugins available + # https://scikit-image.org/docs/stable/api/skimage.io.html#skimage.io.imread + + def load(self, entry: ModalityEntry) -> Any: + path = self.base_path / entry + return skimage.io.imread(path) + + def setup(self, task_dataset: "TaskDataset") -> None: + self.base_path = task_dataset.root.parent + + +class OpenCVMaskLoader(ModalityLoader): + """Default loader for segmentation masks. Adds greyscale interpretation and class mapping on top of image + loading.""" + + def __init__(self): + self.base_path: Optional[Path] = None # will be setup later + self.array_mapper = None # will be setup later + super().__init__(modality=Modality.MASK, suffixes=[".bmp", ".jpeg", ".jpg", ".png"], entry_type=str) + # for supported file types see + # https://docs.opencv.org/4.8.0/d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56 + + def load(self, entry: ModalityEntry) -> Any: + path = self.base_path / entry + return self.array_mapper[np.asarray(cv2.imread(str(path), cv2.IMREAD_GRAYSCALE))] + + def setup(self, task_dataset: "TaskDataset") -> None: + if task_dataset.task_type != TaskType.SEMANTIC_SEGMENTATION: + # prevent misuse + logger.debug( + f"Will skip index mapper setup for OpenCVMaskLoader since given task type " f"{task_dataset.task_type}." + ) + return + self.base_path = task_dataset.root.parent + dict_mapper = {raw: task_dataset.classes.index(cls) for raw, cls in task_dataset.raw_idx_to_class.items()} + k = np.array(list(dict_mapper.keys())) + v = np.array(list(dict_mapper.values())) + self.array_mapper = np.zeros(256, dtype=v.dtype) + self.array_mapper[k] = v + # the 255 integer represents ignored pixels, generally unsure (e.g. boundaries in the VOC dataset) + self.array_mapper[255] = 255 + + +class NonMappingOpenCVMaskLoader(ModalityLoader): + """Special loader of masks, that does not implement a class mapping. Used during preprocessing.""" + + def __init__(self): + self.base_path: Optional[Path] = None # will be setup later + super().__init__(modality=Modality.MASK, suffixes=[".bmp", ".jpeg", ".jpg", ".png"], entry_type=str) + # for supported file types see + # https://docs.opencv.org/4.8.0/d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56 + + def load(self, entry: ModalityEntry) -> Any: + path = self.base_path / entry + return np.asarray(cv2.imread(str(path), cv2.IMREAD_GRAYSCALE)) + + def setup(self, task_dataset: "TaskDataset") -> None: + if task_dataset.task_type != TaskType.SEMANTIC_SEGMENTATION: + # prevent misuse + logger.debug( + f"Will skip index mapper setup for OpenCVMaskLoader since given task type " f"{task_dataset.task_type}." + ) + return + self.base_path = task_dataset.root.parent + + +class ClassLoader(ModalityLoader): + """Loads a simple class entry.""" + + def __init__(self): + self.index_mapper = None # will be setup later + super().__init__(modality=Modality.CLASS, suffixes=None, entry_type=int) + + def load(self, entry: ModalityEntry) -> Any: + return torch.tensor(self.index_mapper[entry]) + + def setup(self, task_dataset: "TaskDataset") -> None: + if task_dataset.task_type != TaskType.CLASSIFICATION: + # prevent misuse + logger.debug( + f"Will skip index mapper setup for ClassLoader since given task type " f"{task_dataset.task_type}." + ) + return + self.index_mapper = {raw: task_dataset.classes.index(cls) for raw, cls in task_dataset.raw_idx_to_class.items()} + + +class MultiLabelClassLoader(ModalityLoader): + """Loads multi-label classification entries and one-hot encodes them.""" + + def __init__(self): + self.array_mapper = None # will be setup later + self.num_classes = None # will be setup later + super().__init__(modality=Modality.CLASSES, suffixes=None, entry_type=list) + + def load(self, entry: ModalityEntry) -> Any: + labels = torch.tensor(self.array_mapper[entry]) + if labels.numel() == 0: + # no label present + return torch.zeros(len(self.num_classes), dtype=torch.float16) + else: + return torch.nn.functional.one_hot(labels, num_classes=len(self.num_classes)).sum( + dim=0, dtype=torch.float16 + ) + + def setup(self, task_dataset: "TaskDataset") -> None: + if task_dataset.task_type != TaskType.MULTILABEL_CLASSIFICATION: + # prevent misuse + logger.debug( + f"Will skip index mapper setup for MultiLabelClassLoader since given task type " + f"{task_dataset.task_type}." + ) + return + self.num_classes = len(task_dataset.classes) + dict_mapper = {raw: task_dataset.classes.index(cls) for raw, cls in task_dataset.raw_idx_to_class.items()} + k = np.array(list(dict_mapper.keys())) + v = np.array(list(dict_mapper.values())) + self.array_mapper = np.zeros(self.num_classes, dtype=v.dtype) + self.array_mapper[k] = v + + +class SoftLabelClassLoader(ModalityLoader): + """Loads soft-label classification entries.""" + + def __init__(self): + self.matrix_mapper = None # will be setup later + super().__init__(modality=Modality.SOFT_CLASSES, suffixes=None, entry_type=list) + + def load(self, entry: ModalityEntry) -> Any: + return torch.tensor(self.matrix_mapper.dot(np.asarray(entry))) + + def setup(self, task_dataset: "TaskDataset") -> None: + if task_dataset.task_type != TaskType.MULTILABEL_CLASSIFICATION: + # prevent misuse + logger.debug( + f"Will skip index mapper setup for SoftLabelClassLoader since given task type " + f"{task_dataset.task_type}." + ) + return + num_classes = len(task_dataset.classes) + dict_mapper = {raw: task_dataset.classes.index(cls) for raw, cls in task_dataset.raw_idx_to_class.items()} + k = np.array(list(dict_mapper.keys())) + v = np.array(list(dict_mapper.values())) + array_mapper = np.zeros(num_classes, dtype=v.dtype) + array_mapper[k] = v + # for soft labels we generate a mapping matrix + self.matrix_mapper = np.zeros((num_classes, len(array_mapper))) + self.matrix_mapper[array_mapper, np.arange(array_mapper.size)] = 1 + + +class ValueLoader(ModalityLoader): + """Loads a simple value entry.""" + + def __init__(self): + super().__init__(modality=Modality.VALUE, suffixes=None, entry_type=float) + + def load(self, entry: ModalityEntry) -> Any: + return torch.tensor(entry).unsqueeze(0) + + def setup(self, task_dataset: "TaskDataset") -> None: + pass + + +class CombinedModalityLoader(ModalityLoader): + """Combines multiple modality loaders to support diverse data setups.""" + + def __init__(self, loaders: List[ModalityLoader]): + if len(loaders) == 0: + raise ValueError("Must provide at least one loader.") + _mod = loaders[0].modality + if any(loader.modality != _mod for loader in loaders): + raise RuntimeError("Combined modality loaders only supports consistent modality.") + self._loaders = loaders + super().__init__(modality=_mod, suffixes=None, entry_type=None) # implements its own .matches() method + + def load(self, entry: ModalityEntry) -> Any: + for loader in self._loaders: + if loader.matches(entry=entry): + return loader.load(entry=entry) + raise RuntimeError(f"Unable to find a suitable loader for {entry=}.") + + def setup(self, task_dataset: "TaskDataset") -> None: + for loader in self._loaders: + loader.setup(task_dataset=task_dataset) + + def matches(self, entry: ModalityEntry) -> bool: + return any(loader.matches(entry=entry) for loader in self._loaders) + + +# these are the backward compatible defaults that will be used in task dataset if no loaders are provided +DEFAULT_MODALITY_LOADERS = { + Modality.IMAGE: OpenCVImageLoader, + Modality.MASK: OpenCVMaskLoader, + Modality.CLASS: ClassLoader, + Modality.CLASSES: MultiLabelClassLoader, + Modality.SOFT_CLASSES: SoftLabelClassLoader, + Modality.VALUE: ValueLoader, +} diff --git a/src/mml/core/data_loading/task_attributes.py b/src/mml/core/data_loading/task_attributes.py new file mode 100644 index 0000000..caaf6f1 --- /dev/null +++ b/src/mml/core/data_loading/task_attributes.py @@ -0,0 +1,196 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from dataclasses import dataclass +from typing import List, Union + +from mml.core.scripts.utils import StrEnum + +# these are the kind of values assigned to modalities in the task description samples +ModalityEntry = Union[int, List[int], List[float], str] + +# these are the acceptable keywords for kornia augmentations +EMPTY_MASK_TOKEN = "EMPTY_MASK_TOKEN" + + +class Modality(StrEnum): + """ + The modalities represent the possible keys of a loaded sample from a dataset. E.g. {'image': 'some/path/file.png', + 'class': 3}. Note that while TaskDescription stores the Modality as enum in its samples, the loaded batch will + contain the str representations! + """ + + # supported types + IMAGE = "image" # (str) default RGB image + MASK = "mask" # (str) grayscale mask, used e.g. in instance or semantic segmentation + CLASS = "class" # (int) multi or binary whole image classification label + CLASSES = "classes" # (List[int]) multi-label classification labels + SOFT_CLASSES = "soft_classes" # (List[float]) allows soft labels [0, 1] for a multi-class / multi-label setup + VALUE = "value" # (float) regression target value + # future possibilities, not supported yet + BBOX = "bbox" + KEYPOINTS = "keypoints" + VIDEO_CLIP = "video_clip" + THREE_D_IMAGE = "three_d_image" + # meta information, not necessarily given + TASK = "task" # (str) the name of the task the sample is loaded from + SAMPLE_ID = "sample_id" # (str) the id of the sample + + +class TaskType(StrEnum): + """ + Defines the type of task. Different task types usually require completely different architectures and/or training + procedures. This is aligned with the torchvision.models split at + https://pytorch.org/docs/stable/torchvision/models.html + """ + + CLASSIFICATION = "classification" + REGRESSION = "regression" + SEMANTIC_SEGMENTATION = "semantic_segmentation" + DETECTION = "detection" + VIDEO_CLASS = "video_classification" + NO_TASK = "no_task" # for completely unlabeled datasets + UNKNOWN = "unknown" + DEFAULT = "unknown" + MULTILABEL_CLASSIFICATION = "multilabel_classification" + + def requires(self) -> List[List[Modality]]: + """ + Returns the necessary modalitie(s) for this kind of task. First list level is OR and second level is AND. So + if returns [[A, B], [C, D]] either [A and B] or [C and D] are required. + """ + assignment = { + TaskType.CLASSIFICATION: [[Modality.CLASS, Modality.IMAGE]], + TaskType.SEMANTIC_SEGMENTATION: [[Modality.MASK, Modality.IMAGE]], + TaskType.MULTILABEL_CLASSIFICATION: [ + [Modality.CLASSES, Modality.IMAGE], + [Modality.SOFT_CLASSES, Modality.IMAGE], + ], + TaskType.NO_TASK: [[Modality.IMAGE]], + TaskType.REGRESSION: [[Modality.IMAGE, Modality.VALUE]], + } + if self in assignment: + return assignment[self] + else: + return [[]] + + +class Keyword(StrEnum): + """ + Keyword labels of a task. Refers e.g. to the shown entities within the images. + """ + + # domains + MEDICAL = "medical" + ANIMALS = "animals" + BUILDINGS = "buildings" + ARTIFICIAL = "artificial" + NATURAL_OBJECTS = "natural_objects" + HANDWRITINGS = "handwritings" + SCENES = "scenes" + FACES = "faces" + DRIVING = "driving" + DERMATOSCOPY = "dermatoscopy" + CATARACT_SURGERY = "cataract_surgery" + LARYNGOSCOPY = "laryngoscopy" + LAPAROSCOPY = "laparoscopy" + GASTROSCOPY_COLONOSCOPY = "gastroscopy_colonoscopy" + ENDOSCOPY = "endoscopy" + NEPHRECTOMY = "Nephrectomy" + FUNDUS_PHOTOGRAPHY = "fundus_photography" + ULTRASOUND = "ultrasound" + MRI_SCAN = "mri_scan" + X_RAY = "x_ray" + CT_SCAN = "ct_scan" + CLE = "confocal laser endomicroscopy" + CAPSULE_ENDOSCOPY = "capsule endoscopy" + COLPOSCOPY = "colposcopy" + # task type + ENDOSCOPIC_INSTRUMENTS = "endoscopic instruments" + INSTRUMENT_COUNT = "counting endoscopic instruments" + ANATOMICAL_STRUCTURES = "anatomical structures" + TISSUE_PATHOLOGY = "tissue_pathology" + IMAGE_ARTEFACTS = "image_artefacts" + CHARS_DIGITS = "chars_or_digits" + # body locations + CHEST = "chest" + BRAIN = "brain" + EYE = "eye" + BREAST = "breast" + BONE = "bone" + GYNECOLOGY = "Gynecology" + + +class License(StrEnum): + """ + License for distribution of a task (data). + """ + + # there is no such thing as no license -> strict limitations apply here! + UNKNOWN = "unknown" + # Use when license is specific to data set + CUSTOM = "License defined in TaskCreator description" + # https://creativecommons.org/licenses/by-nc/4.0/ + CC_BY_NC_4_0 = "Creative Commons Attribution-NonCommercial 4.0 International" + # https://creativecommons.org/licenses/by/4.0/ + CC_BY_4_0 = "Creative Commons Attribution 4.0 International" + # https://creativecommons.org/licenses/by-nc-sa/4.0/ + CC_BY_NC_SA_4_0 = "Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International" + # https://opendatacommons.org/licenses/dbcl/1-0/ + DATABASE_CONTENTS_LICENSE_1_0 = "Open Data Commons DbCL v1.0" + # https://creativecommons.org/publicdomain/zero/1.0/ + CC_0_1_0 = "CC0 1.0 Universal (CC0 1.0) Public Domain Dedication" + # https://choosealicense.com/licenses/mit/ + MIT = "Massachusetts Institute of Technology" + + +@dataclass +class Sizes: + """ + Small dataclass storing information about the dimensionality of a set of images. + """ + + min_height: int = 0 + max_height: int = 0 + min_width: int = 0 + max_width: int = 0 + + def to_list(self) -> List[int]: + return [self.min_height, self.max_height, self.min_width, self.max_width] + + +@dataclass +class RGBInfo: + """ + Small dataclass storing information about image channels (mostly mean and std). + """ + + r: float = 0.0 + g: float = 0.0 + b: float = 0.0 + + def get_rgb(self) -> List[float]: + return [self.r, self.g, self.b] + + def to_list(self) -> List[float]: + return self.get_rgb() + + +IMAGENET_MEAN = RGBInfo(0.485, 0.456, 0.406) +IMAGENET_STD = RGBInfo(0.229, 0.224, 0.225) + + +class DataSplit(StrEnum): + """ + Represents parts of a dataset that are loaded together. May be selected joint by a fold number to determine the + exact samples that are available for iteration over a :class:`~mml.core.data_loading.task_dataset.TaskDataset`. + """ + + TRAIN = "TRAIN" + FULL_TRAIN = "FULL_TRAIN" + VAL = "VAL" + TEST = "TEST" + UNLABELLED = "UNLABELLED" diff --git a/src/mml/core/data_loading/task_dataset.py b/src/mml/core/data_loading/task_dataset.py new file mode 100644 index 0000000..af3136b --- /dev/null +++ b/src/mml/core/data_loading/task_dataset.py @@ -0,0 +1,364 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import ctypes +import logging +import multiprocessing as mp +import warnings +from itertools import chain +from pathlib import Path +from typing import Any, Dict, List, Optional, Tuple, Union + +import albumentations as A +import numpy as np +from torch.utils.data import DataLoader +from torch.utils.data.dataset import Dataset +from tqdm import tqdm + +from mml.core.data_loading.augmentations.augmentation_module import AugmentationModule, AugmentationModuleContainer +from mml.core.data_loading.file_manager import MMLFileManager +from mml.core.data_loading.modality_loaders import DEFAULT_MODALITY_LOADERS, ModalityLoader +from mml.core.data_loading.task_attributes import EMPTY_MASK_TOKEN, DataSplit, Modality, TaskType +from mml.core.data_loading.task_description import SampleDescription + +logger = logging.getLogger(__name__) +_ERROR_RETRY = 0 # may be set higher to allow for corrupted samples + + +class TaskDataset(Dataset): + """ + The TaskDataset class represents a loadable dataset, handling folds, data loading, different modalities of a task + as well as non-batched transforms. After initialization, it may be directly given to some (multithreaded) + dataloader. + """ + + def __init__( + self, + root: Union[Path, str], + split: DataSplit = DataSplit.TRAIN, + fold: int = 0, + transform: Optional[Union[AugmentationModule, AugmentationModuleContainer]] = None, + caching_limit: int = 0, + loaders: Optional[Dict[Modality, ModalityLoader]] = None, + ): + """ + The TaskDataset initialization loads all meta information on the task and selects active split + fold. This + choice can later be changed by the 'select_samples' method. + + :param Path root: Path to TASKXXX_name.json file of task to load. + :param DataSplit split: one of 'train', 'val', 'full_train' and 'test' + :param int fold: irrelevant if 'test' split, inactive fold in 'train' split and only active fold in 'val' split + :param Optional[A.Compose] transform: :mod:albumentation compose transform to be applied on samples + :param int caching_limit: this corresponds to the number of max images cached + :param Optional[Dict[Modality, ModalityLoader]]: a dict of ModalityLoaders for this task, if None are given a + default set of loaders is used + """ + # class basics + self.root = Path(root) + # load and parse meta information + self.task_type = None + self.raw_idx_to_class = None + self.classes = None + self.modalities: Optional[Dict[Modality, str]] = None + self.class_occ = None + self.samples: List[SampleDescription] = [] + self._sample_ids: List[str] = [] + self.task_description = MMLFileManager.load_task_description(self.root) + self._parse_meta() + # caching option variables init + self.caching_limit = caching_limit + self.allow_caching = caching_limit > 0 + self.shared_array = None + self._use_cache: bool = False # after cache has been created and filled enable via self.enable_cache + # prepare data loading + self.transform = transform + self._consecutive_errors: int = 0 + # setup loaders + if loaders is None: + # select default loaders for backward compatibility + loaders = {mod: DEFAULT_MODALITY_LOADERS[mod]() for mod in self.modalities} + self.loaders = loaders + if any(mod not in self.loaders for mod in self.modalities): + raise ValueError("No loader found for some modality.") + for loader in self.loaders.values(): + loader.setup(self) + # select samples (done last, triggers caching if activated) + self.active_fold: Optional[Tuple[DataSplit, int]] = None + self.select_samples(split, fold) # needs to be done after cache variables are set + + def _create_cache(self) -> None: + """ + Creates the array in memory to store images. Is called after samples have been selected. + """ + # gather dimensions, therefore loading a sample with temporally disabled transforms + tmp_bkp = self.transform + self.transform = None + # temporary dict, to allow loading without an underlying array + self.shared_array = {} + sample_image = self[0][Modality.IMAGE.value] + h, w, c = sample_image.shape + # create array + shared_array_base = mp.Array(ctypes.c_ubyte, len(self) * c * h * w) + shared_array = np.ctypeslib.as_array(shared_array_base.get_obj()) + self.shared_array = shared_array.reshape(len(self), h, w, c) + # array cannot be used (it is still empty!) + self._use_cache = False + # resetting transforms + self.transform = tmp_bkp + logger.debug(f"Created cache array for {self.task_description.name}.") + + def enable_cache(self) -> None: + """ + After cache has been created and filled, enable caching to speed up training. + :return: + """ + if self.allow_caching: + logger.info(f"Caching activated for {self.task_description.name}.") + self._use_cache = True + else: + logger.error("Requested cache enabling without allowing cache during dataset init!") + + def disable_cache(self) -> None: + """ + Deactivates the usage of the internal image cache. + :return: + """ + self._use_cache = False + logger.info(f"Caching DE-activated for {self.task_description.name}.") + + def fill_cache(self, num_workers: int = 0) -> None: + """ + + :return: + """ + if self.allow_caching: + self._use_cache = False + # disable transforms + tmp_bkp = self.transform + self.transform = None + # create a simple dataloader that needs no sampler nor batching / collating /memory pinning / ... + dl = DataLoader( + self, + batch_size=None, + shuffle=False, + sampler=None, + batch_sampler=None, + num_workers=num_workers, + collate_fn=None, + pin_memory=False, + drop_last=False, + worker_init_fn=None, + persistent_workers=False, + ) + # iterate once along dataset + for _ in tqdm(dl, desc="Caching"): + pass + # re-enable transforms + self.transform = tmp_bkp + # activate cache usage + self.enable_cache() + logger.info(f"Cached {len(self)} samples.") + else: + logger.error( + "No caching allowed, you might need to raise sampling.cache_max_size in the configs to allow " + "larger datasets caching. Also make sure to set a caching limit greater than zero to this " + "TaskDataset." + ) + + def __repr__(self) -> str: + return f"TaskDataSet(root={self.root}, split={self.active_fold[0]}, fold={self.active_fold[1]})" + + def _parse_meta(self) -> None: + """ + Find, check and load task_type, classes, modalities, class_to_idx, class_occ. + + :return: None + """ + self.task_type = self.task_description.task_type + if self.task_type not in TaskType: + raise RuntimeError(f"Task type {self.task_type}, has to be of type TaskType.") + # ensure sorted modality to always load image before mask (necessary for EMPTY_MASK_TOKEN)! + self.modalities = {k: self.task_description.modalities[k] for k in sorted(self.task_description.modalities)} + if any([mod not in Modality for mod in self.modalities]): + raise ValueError(f"Invalid modalities in meta_info! Accepted keys must be of type {Modality}!") + self.raw_idx_to_class = self.task_description.idx_to_class + # sort by keys (preserves e.g. 0 to be the background class in segmentation) + self.classes = self.get_classes_from_idx_dict(self.raw_idx_to_class) + self.class_occ = self.task_description.class_occ + if len(self.task_description.train_samples) > 0 and len(self.class_occ) != len(self.classes): + raise RuntimeError("Class occurrences do not match the number of classes.") + + def select_samples(self, split: DataSplit, fold: int) -> None: + """ + Chooses the actual samples from the task meta information. Handles splits, folds and subsets. + + :param DataSplit split: either 'train', 'val', 'full_train', 'unlabelled' or 'test' + :param int fold: irrelevant if 'test' split, inactive fold in 'train' split and only active fold in 'val' split + :return: None + """ + if 0 > fold or fold > len(self.task_description.train_folds): + raise ValueError( + f"Invalid fold number {fold}, has to be in range 0 - " f"{len(self.task_description.train_folds)}." + ) + if not isinstance(split, DataSplit): + raise TypeError(f"Invalid split {split}, needs to be compatible to DataSplit class.") + if split == DataSplit.TEST: + self.allow_caching = False + logger.debug( + "Deactivated caching for test data (commonly passed once and mml assumes not to be " "preprocessed)." + ) + self.samples = self.task_description.test_samples.values() + self._sample_ids = list(self.task_description.test_samples.keys()) + elif split == DataSplit.TRAIN: + data_ids = list( + chain( + *self.task_description.train_folds[0:fold], + *self.task_description.train_folds[fold + 1 : len(self.task_description.train_folds) + 1], + ) + ) + self.samples = [self.task_description.train_samples[data_id] for data_id in data_ids] + self._sample_ids = data_ids + elif split == DataSplit.FULL_TRAIN: + self.samples = self.task_description.train_samples.values() + self._sample_ids = list(self.task_description.train_samples.keys()) + elif split == DataSplit.UNLABELLED: + self.samples = self.task_description.unlabeled_samples.values() + self._sample_ids = list(self.task_description.unlabeled_samples.keys()) + elif split == DataSplit.VAL: + # val split + try: + data_ids = self.task_description.train_folds[fold] + except IndexError: + # no val split present + data_ids = [] + self.samples = [self.task_description.train_samples[data_id] for data_id in data_ids] + self._sample_ids = list(data_ids) + else: + ValueError(f"Was not given any valid DataSplit. Options are: {DataSplit.list()}") + self.samples = list(self.samples) + self.active_fold = (split, fold) + logger.debug( + f"Selected samples based on split {split} and fold {fold}. " f"Total sample num is {len(self.samples)}." + ) + if len(self.samples) != len(self._sample_ids): + raise RuntimeError(f"{len(self.samples)=} {len(self._sample_ids)=}") + # each sample selection process requires potential re-caching + self._use_cache = False + if self.allow_caching and len(self) > self.caching_limit: + logger.error("Dataset size exceeds caching limit, will deactivate.") + self.allow_caching = False + if self.allow_caching: + # cache must be recreated after samples have been selected + self._create_cache() + + def __getitem__(self, index: int) -> Dict[str, Any]: + """ + Main entry point for data loading. Returns loaded and transformed modalities. + + :param index: sample index int + :return: dict with modality keys and loaded + transformed objects as values + """ + try: + sample = self.load_sample(index) + except Exception as e: + logger.warning( + f"Skipped sample (index {index}). Exception: {str(e)}.\n" f"Loading data was: {self.samples[index]}." + ) + self._consecutive_errors += 1 + if self._consecutive_errors < _ERROR_RETRY: + return self.__getitem__((index + 1) % len(self)) + else: + raise e + self._consecutive_errors = 0 + if self.transform is not None: + sample = self.transform(**sample) + try: + sample["sample_id"] = self._sample_ids[index] + except IndexError: + # sample ids not available in most test setups + warnings.warn(f"Wanted to look up sample id outside {len(self._sample_ids)} (requested {index})") + sample["sample_id"] = "NA" + return sample + + def __len__(self) -> int: + return len(self.samples) + + def load_sample(self, index: int) -> Dict[str, Any]: + """ + Loads all necessary components. This based on the active modalities and the information provided there. + Be aware that for preprocessing the raw_index_mapping is removed by default (set to None). Handle this + separately. + + :param index: int within range(len(self.samples)) + :return: dict with modality key (str) and obj + """ + loading_dict: SampleDescription = self.samples[index] + sample_dict = {} + # only load modalities requested for this task + for mod in self.modalities: + # treat image separately to deal with cache + if mod == Modality.IMAGE: + # load the image + if self._use_cache: + # use cache if activated + sample_dict[mod] = self.shared_array[index] + else: + # else load image + sample_dict[mod] = self.loaders[Modality.IMAGE].load(entry=loading_dict[mod]) + # and store image in cache if desired (still unmodified from transforms) + if self.allow_caching: + self.shared_array[index] = sample_dict[mod] + # do not load anything else but image in case of unlabeled data + elif self.active_fold[0] == DataSplit.UNLABELLED: + continue + # next special case of empty segmentation mask token + elif mod == Modality.MASK and loading_dict[mod] == EMPTY_MASK_TOKEN: + # use image as template, but only single channel + sample_dict[mod] = np.zeros_like(sample_dict[Modality.IMAGE][:, :, 0]) + else: + # default case, search for applicable modality loader any load entry + sample_dict[mod] = self.loaders[mod].load(entry=loading_dict[mod]) + # finally all modalities will be represented with their corresponding strings in the loaded batch, this enables + # usage of kwarg unpacking ("**") + sample_dict = {mod.value: item for mod, item in sample_dict.items()} + return sample_dict + + @staticmethod + def get_classes_from_idx_dict(idx_to_class: Dict[int, str]) -> List[str]: + """ + Transforms the idx_to_class dict of a task to the actual list of classes. + + :param idx_to_class: index to class mapping as provided in task meta information + :return: class list, ordered by increasing idx + """ + if not all([isinstance(k, int) for k in idx_to_class.keys()]): + raise ValueError("Only integer keys allowed.") + if not all([isinstance(v, str) for v in idx_to_class.values()]): + raise ValueError("Only string values allowed.") + return list(dict.fromkeys([idx_to_class[key] for key in sorted(list(idx_to_class.keys()))])) + + +class TupelizedTaskDataset(Dataset): + def __init__(self, task_dataset: TaskDataset, transform: Optional[A.Compose] = None): + """ + Turns the output of a TaskDataset to tuples (which are dicts by default). + Also allows to overwrite the transform. + + :param TaskDataset task_dataset: TaskDataset instance + :param transform: (optional) if not None, overwrites the dataset transform + """ + self.ds = task_dataset + self.mod_order = [mod for mod in Modality if mod in self.ds.modalities] + if transform is not None: + self.ds.transform = transform + + def __len__(self): + return len(self.ds) + + def __getitem__(self, index): + sample = self.ds.__getitem__(index) + items = [sample[mod] for mod in self.mod_order] + return tuple(items) diff --git a/src/mml/core/data_loading/task_description.py b/src/mml/core/data_loading/task_description.py new file mode 100644 index 0000000..2ae5f15 --- /dev/null +++ b/src/mml/core/data_loading/task_description.py @@ -0,0 +1,158 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +from copy import deepcopy +from dataclasses import dataclass, field +from typing import Any, Dict, List, Optional + +from mml.core.data_loading.task_attributes import Keyword, License, Modality, ModalityEntry, RGBInfo, Sizes, TaskType + +logger = logging.getLogger(__name__) + +# entries required to construct a TaskStruct +STRUCT_REQ_HEADER_KEYS = [ + "name", + "task_type", + "keywords", + "modalities", + "means", + "stds", + "sizes", + "idx_to_class", + "class_occ", +] +# plus additional entries that are not yet part of the data +ALL_HEADER_KEYS = STRUCT_REQ_HEADER_KEYS + [ + "description", + "creation_protocol", + "reference", + "url", + "download", + "license", + "release", +] +# now these are all entries +ALL_TASK_DESCRIPTION_KEYS = ALL_HEADER_KEYS + ["unlabeled_samples", "train_folds", "train_samples", "test_samples"] + +SampleDescription = Dict[Modality, ModalityEntry] + + +@dataclass +class TaskDescription: + """ + A task description holding the meta information on task background as well as the actual links to samples. + """ + + # provided + name: Optional[str] = None # renamed from alias + description: str = "" + creation_protocol: str = "" + reference: str = "" + url: str = "" + download: str = "" + license: License = License.UNKNOWN + release: str = "" + task_type: TaskType = TaskType.UNKNOWN + keywords: List[Keyword] = field(default_factory=list) # renamed from tags + # inferred + means: RGBInfo = field(default_factory=RGBInfo) + stds: RGBInfo = field(default_factory=RGBInfo) + sizes: Sizes = field(default_factory=Sizes) + modalities: Dict[Modality, str] = field(default_factory=dict) + idx_to_class: Dict[int, str] = field(default_factory=dict) + class_occ: Dict[str, int] = field(default_factory=dict) + # created + unlabeled_samples: Dict[str, SampleDescription] = field(default_factory=dict) # renamed + train_folds: List[List[str]] = field(default_factory=list) + train_samples: Dict[str, SampleDescription] = field(default_factory=dict) # renamed + test_samples: Dict[str, SampleDescription] = field(default_factory=dict) # renamed + + def to_json(self) -> Dict[str, Any]: + """ + Helper to transform a TaskDescription into a json compatible dict. + + :return: (dic) A dictionary without any custom classes as values to be saved in json format. + """ + json_data = {} + for key in ALL_TASK_DESCRIPTION_KEYS: + value = getattr(self, key) + # transform plain StrEnum to str + if key in ["task_type", "license"]: + value = value.value + # transform listed StrEnum to str + elif key in ["keywords"]: + value = [elem.value for elem in value] + # transform dict StrEnum to str + elif key in ["modalities"]: + value = {k.value: v for k, v in value.items()} + # transform RGBInfo and Sizes + elif key in ["means", "stds", "sizes"]: + value = value.to_list() + # transform nested StrEnum to str + elif key in ["unlabeled_samples", "train_samples", "test_samples"]: + value = { + top_k: {low_k.value: low_v for low_k, low_v in top_v.items()} for top_k, top_v in value.items() + } + # json only allows str keys + elif key in ["idx_to_class"]: + value = {str(k): v for k, v in value.items()} + json_data[key] = value + return json_data + + @classmethod + def from_json(cls, data_dict: Dict[str, Any]) -> "TaskDescription": + """ + Counterpart for the to_json function: Replaces enum values with their entities and creates a TaskDescription. + + :param Dict[str, Any] data_dict: a dictionary without any custom classes as values to be saved in json format. + :return: a TaskDescription with entries as encoded in the data_dict + """ + data_dict = deepcopy(data_dict) + cls_kwargs = {} + for key in data_dict: + if key not in ALL_TASK_DESCRIPTION_KEYS: + raise KeyError(f"Key {key} not part of a TaskDescription!") + value = data_dict[key] + # transform plain StrEnum + if key in ["task_type", "license"]: + C = {"task_type": TaskType, "license": License}[key] + value = C(value) + # transform listed StrEnum + elif key in ["keywords"]: + value = [Keyword(elem) for elem in value] + # transform dict StrEnum + elif key in ["modalities"]: + value = {Modality(k): v for k, v in value.items()} + # transform RGBInfo and Sizes + elif key in ["means", "stds", "sizes"]: + C = {"means": RGBInfo, "stds": RGBInfo, "sizes": Sizes}[key] + value = C(*value) + # transform nested StrEnum to str + elif key in ["unlabeled_samples", "train_samples", "test_samples"]: + value = { + top_k: {Modality(low_k): low_v for low_k, low_v in top_v.items()} for top_k, top_v in value.items() + } + elif key in ["idx_to_class"]: + value = {int(k): v for k, v in value.items()} + cls_kwargs[key] = value + return cls(**cls_kwargs) + + @property + def num_samples(self) -> int: + """ + The number or training (or unlabeled) samples. + """ + # list lookup is faster than dict length computation + train_cases = sum(map(len, self.train_folds)) + if train_cases > 0: + return train_cases + # we might have an unlabeled task if no train folds are defined + elif len(self.unlabeled_samples) > 0: + return len(self.unlabeled_samples) + # we return zero if neither are found, but log error + logger.error(f"Asked for number of samples of task {self.name}, but did not find any samples") + return 0 diff --git a/src/mml/core/data_loading/task_struct.py b/src/mml/core/data_loading/task_struct.py new file mode 100644 index 0000000..7e86da7 --- /dev/null +++ b/src/mml/core/data_loading/task_struct.py @@ -0,0 +1,397 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import functools +import logging +import warnings +from pathlib import Path +from typing import Callable, Dict, List, Optional, Tuple, Union + +import orjson +from omegaconf import DictConfig + +from mml.core.data_loading.file_manager import MMLFileManager +from mml.core.data_loading.task_attributes import Keyword, Modality, RGBInfo, Sizes, TaskType +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.scripts.decorators import deprecated +from mml.core.scripts.exceptions import TaskNotFoundError +from mml.core.scripts.model_storage import ModelStorage +from mml.core.scripts.utils import TAG_SEP, catch_time + +logger = logging.getLogger(__name__) + + +class TaskStruct: + """ + Object to handle tasks on a meta level in the framework. Contains basic information on location of data and + links to intermediate and final results. Will be instantiated by the TaskFactory. During runtime results + corresponding to the dataset will also be stored within the object (such as trained models, calculated FIM and + performance). + """ + + def __init__( + self, + name: str, + task_type: TaskType, + means: RGBInfo, + stds: RGBInfo, + sizes: Sizes, + class_occ: Dict[str, int], + keywords: List[Keyword], + idx_to_class: Dict[int, str], + modalities: Dict[Modality, str], + relative_root: str, + preprocessed: str, + ): + # this used later on to identify the task + self.name = name + + # permanent task attributes e.g. holds task type, mean and std of train set, relative root path, etc. + self.task_type = task_type + self.means = means + self.stds = stds + self.sizes = sizes + self.class_occ = class_occ + self.relative_root = Path(relative_root) # relative to MMLFileManager.data_path + self.preprocessed = preprocessed + self.keywords = keywords + self.idx_to_class = idx_to_class + self.modalities = modalities + if self.target and self.target not in self.modalities: + warnings.warn(f"Corrupted target for task {self.name}: {self.target}") + # non-permanent attributes, these correspond to experiment specific settings, e.g. a performance, a model + # trained for the task, auto-augmentation, checkpoints, FIM, features, heads, etc... + # be aware that in order to store and load them they should only consist of (stacked) default builtin types! + # e.g. str, int, dict, list, ... + self.paths: Dict[str, Path] = {} + self.models: List[ModelStorage] = [] + + logger.debug(f"Created TaskStruct-object for task {self.name}.") + + @staticmethod + def non_permanent_task_attributes() -> Dict[str, Tuple[Callable, Callable]]: + """ + Returns a dict of task attributes that are not part of the task meta information but are computed by MML. + The value within the dict is a tuple of callables representing and instantiating the object (to be compatible + with yaml safe loading and dumping). + + :return: dict with str keys, which are the names of task struct attributes that might be set during MML runtime + and tuple vals corresponding to (representer, instantiator) + """ + attrs = {} + + # paths attr + def path_representer(path_attr: Dict[str, Path]) -> Dict[str, str]: + return {k: str(v) for k, v in path_attr.items()} + + def path_instantiator(path_repr: Dict[str, str]) -> Dict[str, Path]: + return {k: Path(v) for k, v in path_repr.items()} + + attrs["paths"] = (path_representer, path_instantiator) + + # models attr + def models_representer(model_attr: List[ModelStorage]) -> List[str]: + paths = [str(m._stored) for m in model_attr] + if any(p is None for p in paths): + raise RuntimeError( + "Models that are attached to TaskStructs can only be dumped after a scheduler step " + "if the model has been stored before." + ) + return paths + + def models_instantiator(model_repr: List[str]) -> List[ModelStorage]: + return [ModelStorage.from_json(path=Path(path)) for path in model_repr] + + attrs["models"] = (models_representer, models_instantiator) + return attrs + + @functools.cached_property + def num_samples(self) -> int: + """ + Number of training (or unlabeled) samples. See also + `~mml.core.data_loading.task_description.TaskDescription.num_samples`. + :rtype: int + """ + # loading only supported with file manager + if not MMLFileManager.exists(): + raise RuntimeError("TaskStruct supports num_samples only with initiated MMLFileManager.") + fm = MMLFileManager.instance() + return fm.load_task_description(fm.data_path / self.relative_root).num_samples + + @property + def num_classes(self) -> int: + return len(set(self.idx_to_class.values())) + + @property + def target(self) -> Optional[Modality]: + if self.task_type == TaskType.CLASSIFICATION: + return Modality.CLASS + elif self.task_type == TaskType.SEMANTIC_SEGMENTATION: + return Modality.MASK + elif self.task_type == TaskType.MULTILABEL_CLASSIFICATION: + return Modality.CLASSES if Modality.CLASSES in self.modalities else Modality.SOFT_CLASSES + elif self.task_type == TaskType.REGRESSION: + return Modality.VALUE + elif self.task_type == TaskType.NO_TASK: + return None + else: + raise RuntimeError("Unable to determine target!") + + @property + @deprecated(reason="task_struct.id is deprecated, use task.name instead", version="0.12.0") + def id(self) -> str: + return self.name + + def __str__(self) -> str: + infos = [ + f"Task name: {self.name}", + f"Task type: {self.task_type}", + f"Num classes: {self.num_classes}", + f"Means: {self.means}", + f"Stds: {self.stds}", + f"Sizes: {self.sizes}", + f"Class occ: {self.class_occ}", + f"Preprocessed: {self.preprocessed}", + f"Task keywords: {[kw.value for kw in self.keywords]}", + ] + for attr in self.non_permanent_task_attributes().keys(): + infos.append(f"{attr}: {getattr(self, attr)}") + return "\n".join(infos) + + def __repr__(self): + return f"TaskStruct({self.name})" + + +class TaskStructFactory: + """ + Manages to load all necessary TaskStructs for an experiment. Stores created objects and aggregates information (like + sizes) across multiple tasks. + """ + + def __init__(self, cfg: DictConfig, load: bool = False): + self.cfg = cfg + self.fm = MMLFileManager.instance() + self.container = [] + self.sizes = Sizes() + self.reset_sizes() + # load old factory dump + if load: + self.loading_old_dump() + + def reset_sizes(self) -> None: + """ + Sets the internal sizes back. + + :return: None + """ + self.sizes.min_height = 100000 + self.sizes.max_height = 0 + self.sizes.min_width = 100000 + self.sizes.max_width = 0 + + def set_task_struct_defaults(self, task_struct: TaskStruct): + """ + Based on reuse configs this sets the defaults within the task struct regarding previous results. Currently + only supports Path and ModelStorage objects! + + :param TaskStruct task_struct: task_struct of the task that values should be loaded + :return: None + """ + if task_struct.name in self.fm.reusables: + for k, v in self.fm.reusables[task_struct.name].items(): + if k == "models": + assert isinstance(v, list) + for storage in v: + assert isinstance(storage, ModelStorage) + task_struct.models = v + logger.debug(f"Attached {len(v)} reusable models to {task_struct.name}.") + else: + assert isinstance(v, Path) + assert v.exists() + task_struct.paths[k] = v + logger.debug(f"Set {k} path of {task_struct.name} to {v}.") + else: + logger.debug(f"No reusable for task {task_struct.name}") + + def loading_old_dump(self) -> None: + """ + Loading is useful if an experiment was aborted and is re-initialized. + + :return: None + """ + + logger.info(f"Loading task dump from {self.fm.task_dump_path}.") + if not self.fm.task_dump_path.exists(): + raise FileNotFoundError( + f"Specified exp folder ({self.fm.task_dump_path.parent}) requested for loading " + f"TaskFactory dump is not existing or has incorrectly saved dump (requires " + f"{self.fm.task_dump_path.name} file)." + ) + with open(str(self.fm.task_dump_path), "rb") as f: + all_tasks_dict = orjson.loads(f.read()) + logger.info(f"Starting loading of {len(all_tasks_dict)} tasks...") + for name, task_dict in all_tasks_dict.items(): + created = self.create_task_struct(name, return_ref=True) + for attr, (_, instantiator) in TaskStruct.non_permanent_task_attributes().items(): + if attr in task_dict.keys(): + setattr(created, attr, instantiator(task_dict[attr])) + # report sizes + logger.debug(f"Sizes of factory are: {self.sizes}.") + logger.info(f"Successfully loaded. Container includes {len(self.container)} task structs.") + + def dump(self, clear_container=False) -> None: + """ + Stores current tasks and their attributes. + + :param clear_container: if true deletes currently loaded tasks afterwards + :return: None + """ + all_tasks_dict = {} + for task in self.container: + task_dict = {} + for attr, (representer, _) in TaskStruct.non_permanent_task_attributes().items(): + if getattr(task, attr) is not None: + task_dict[attr] = representer(getattr(task, attr)) + all_tasks_dict[task.name] = task_dict + with open(str(self.fm.task_dump_path), "wb") as f: + f.write(orjson.dumps(all_tasks_dict)) + logger.debug(f"Dumped {len(all_tasks_dict)} tasks @ {self.fm.task_dump_path}.") + if clear_container: + self.container = [] + self.reset_sizes() + + def create_task_struct(self, name: str, return_ref=False) -> Union[None, TaskStruct]: + """ + Creates a task struct object via loading necessary information from the meta info json file and adding + reusable information (e.g. intermediate results from previous experiments) as adaption of the already + preprocessed version of the task. Finally, the task struct is added to the internal container. + + :param name: name of the task to be created + :param return_ref: if true returns a reference to the created struct, else returns None + :return: either the created task struct or None + """ + if self.check_exists(name=name): + logger.error(f"Task struct {name} to produce already present in the factory container.") + if return_ref: + return self.get_by_name(name=name) + else: + return + # make sure to remove duplicate tag + undup_name = undup_names([name])[0] + # next check if this is a base task that has not yet been created + if (TAG_SEP not in undup_name) and (undup_name not in self.fm.task_index): + # the task is not a tagged one and the base is not present, raise error + raise TaskNotFoundError( + f"Was not able to locate task {undup_name}. You may need to call " + f" with your current task setting." + ) + # next check if this is a tagged task with missing entry with respect to preprocessing + if (TAG_SEP in undup_name) and ( + undup_name not in self.fm.task_index or self.cfg.preprocessing.id not in self.fm.task_index[undup_name] + ): + if undup_name not in self.fm.task_index: + # task not yet present at all in task index of the file manager, try to auto generate base task + logger.info(f"Task {undup_name} not existent yet. Will try to create.") + try: + with catch_time() as timer: + path = TaskCreator(dset_path=Path("")).auto_create_tagged( + full_alias=undup_name, preprocessing="none" + ) + logger.debug(f"Task created successfully within {timer.elapsed:5.2f} seconds.") + except TaskNotFoundError: + raise RuntimeError(f"Unable to auto_create {undup_name} with pp {self.cfg.preprocessing.id}.") + # add to task index of file manager + self.fm.add_to_task_index(path) + # check for inconsistencies + if "none" not in self.fm.task_index[undup_name]: + raise RuntimeError( + f"MML detected a tagged task ({undup_name}) that exists with some " + f"preprocessing(s) ({list(self.fm.task_index[undup_name].keys())}), but " + f"no raw version has been found. This may be either because the raw version " + f"has been removed or you used a previous version of MML to create this " + f"tagged task. From MML 0.13.0 on tagged preprocessing will only be created " + f"with a base tagged task. Consider removing all preprocessed version of " + f"this task to create from scratch " + f"({list(self.fm.task_index[undup_name].values())})." + ) + # next check if we need to create a preprocessed version + if self.cfg.preprocessing.id not in self.fm.task_index[undup_name]: + base_task = undup_name[: undup_name.find(TAG_SEP)] + if self.cfg.preprocessing.id in self.fm.task_index[base_task]: + # this indicates the case that we can leverage existing preprocessing! + # preprocessed tagged task not yet present in task index of the file manager + logger.info( + f"Generating description of {undup_name} for preprocessing {self.cfg.preprocessing.id}." + ) + try: + with catch_time() as timer: + path = TaskCreator.auto_create_tagged( + full_alias=undup_name, preprocessing=self.cfg.preprocessing.id + ) + logger.debug(f"Task created successfully within {timer.elapsed:5.2f} seconds.") + except TaskNotFoundError: + raise RuntimeError(f"Unable to auto_create {undup_name} with pp {self.cfg.preprocessing.id}.") + # add to task index of file manager + self.fm.add_to_task_index(path) + # generate struct from meta info provided by file manager + def_kwargs = self.fm.get_task_info(task_name=undup_name, preprocess=self.cfg.preprocessing.id) + if def_kwargs["name"] != name: + raise RuntimeError(f'Received incorrect task information for task {name} (got {def_kwargs["name"]}).') + new_task = TaskStruct(**def_kwargs) + self.container.append(new_task) + # apply defaults to task struct + self.set_task_struct_defaults(new_task) + # update sizes + self.sizes.min_height = min(self.sizes.min_height, new_task.sizes.min_height) + self.sizes.max_height = max(self.sizes.max_height, new_task.sizes.max_height) + self.sizes.min_width = min(self.sizes.min_width, new_task.sizes.min_width) + self.sizes.max_width = max(self.sizes.max_width, new_task.sizes.max_width) + logger.debug(f"New factory sizes are: {self.sizes}") + if return_ref: + return new_task + + def get_by_name(self, name: str) -> TaskStruct: + """ + Returns the internally stored task_struct corresponding to >name<. Raises an error if not found (or returns + only false if >test< is true). + + :param name: task name + :param test: if true does not raise an error + :return: either the task_struct or False if not found and in test mode + """ + for task in self.container: + if task.name == name: + return task + msg = f"Was not able to find requested dataset {name} in the container of produced task structs." + raise TaskNotFoundError(msg) + + def check_exists(self, name: str) -> bool: + """ + Checks whether a given task is present in the container. + + :param str name: task name + :return: True iff task is within container + :rtype: bool + """ + try: + self.get_by_name(name=name) + except TaskNotFoundError: + return False + return True + + +def undup_names(moded_names_list): + """ + This function removes the "duplicate"-suffixes of tasks that is added if some tasks are present for multiple times. + + :param moded_names_list: list of strings, task names potentially including the "duplicate"-suffix + :return: list of strings, tasks names without the suffix (if suffix is not present the name stays equal) + """ + return list( + map( + lambda x: str(x)[: (lambda y: None if y == -1 else y)(str(x).find(f"{TAG_SEP}duplicate"))], moded_names_list + ) + ) diff --git a/src/mml/core/data_loading/utils.py b/src/mml/core/data_loading/utils.py new file mode 100644 index 0000000..e988d91 --- /dev/null +++ b/src/mml/core/data_loading/utils.py @@ -0,0 +1,30 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import torch +from torch.nn.functional import one_hot + + +def one_hot_mask(mask: torch.Tensor, num_classes: int) -> torch.Tensor: + """ + Expects a batched segmentation mask (B x H x W) and returns a batched one-hot encoding like (B x C x H x W). Handles + pseudo entry 255 within. + + :param torch.Tensor mask: the mask to be transformed (B x H x W), values must be below num_classes + :param int num_classes: the number of classes + :raises ValError: if mask values are outside [0, ..., num_classes - 1] + :return: a batched one-hot encoding like (B x C x H x W) + :rtype: torch.Tensor + """ + if mask.max() >= num_classes or mask.min() < 0: + raise ValueError("Mask values must be within 0 and num_classes - 1.") + # replace 255 value with pseudo-class + target_remapped = torch.where(mask == 255, num_classes, mask) + # one-hot encode with pseudo-class + target_one_hot = one_hot(target_remapped, num_classes=num_classes + 1).permute(0, 3, 1, 2) + # remove pseudo class + target_one_hot = target_one_hot[:, :-1] + return target_one_hot diff --git a/src/mml/core/data_preparation/__init__.py b/src/mml/core/data_preparation/__init__.py new file mode 100644 index 0000000..a515177 --- /dev/null +++ b/src/mml/core/data_preparation/__init__.py @@ -0,0 +1,8 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# make sure dummy task is registered +import mml.core.data_preparation.fake_task # noqa F401 diff --git a/src/mml/core/data_preparation/archive_extractors.py b/src/mml/core/data_preparation/archive_extractors.py new file mode 100644 index 0000000..7febc49 --- /dev/null +++ b/src/mml/core/data_preparation/archive_extractors.py @@ -0,0 +1,221 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import platform +import shutil +import subprocess +import tarfile +import warnings +from getpass import getpass +from pathlib import Path +from typing import Callable, List, Optional +from zipfile import ZipFile + +from rarfile import RarCannotExec, RarFile + +from mml.core.data_preparation.data_archive import DataArchive +from mml.core.data_preparation.utils import WIPBar +from mml.core.scripts.decorators import timeout + +logger = logging.getLogger(__name__) + + +def default_file_copy(archive: DataArchive, folder: Path) -> None: + """ + Default extraction is to fall back to a simple copy for files (e.g. sometimes plain .csv files are shared). + + :param DataArchive archive: DataArchive to extract. + :param Path folder: target folder. + :return: + """ + shutil.copy2(str(archive.path), str(folder)) + + +def default_folder_copy(archive: DataArchive, folder: Path) -> None: + """ + Default extraction is to fall back to a simple copy for folders (e.g. for very small datasets). + + :param DataArchive archive: DataArchive to extract. + :param Path folder: target folder. + :return: + """ + if not archive.keep_top_level: + raise RuntimeError("Please set DataArchive.keep_top_level to true for plain folder extraction.") + try: + shutil.copytree(src=str(archive.path), dst=str(folder)) + except FileExistsError: + raise RuntimeError( + f"Apparently folder {archive.path.name} is used multiple times during unpacking/copying " + f"at target path {folder}. Make sure to use each target only once!" + ) + + +def zip_extractor(archive: DataArchive, folder: Path) -> None: + """ + Extraction for ZIP files. + + :param DataArchive archive: DataArchive to extract. + :param Path folder: target folder. + :return: + """ + with ZipFile(archive.path) as myzip: + # simple case first: no encryption + if not is_encrypted(zipfile=myzip): + myzip.extractall(path=folder) + else: + logger.info(f"trying to decrypt archive {archive.path.name} ...") + if not archive.password: + archive.password = ask_password(file=archive.path) + # check OS + os_type = platform.system() + if os_type not in ["Linux", "Darwin"]: # Darwin for macOS + warnings.warn( + f"Unsupported OS type: {os_type} for fast zip extraction. If extraction is too slow, " + f"cancel process and manually extract {myzip.filename} into {folder}." + ) + myzip.extractall(path=folder, pwd=archive.password.encode()) + else: + # UNIX file system allows to call "unzip" as a subprocess for way faster extraction + command = ["unzip", "-P", archive.password, archive.path, "-d", folder] + try: + subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + except subprocess.CalledProcessError: + logger.error("Wrong Password! Try again.") + raise RuntimeError("Wrong Password! Restart and try again.") + except FileNotFoundError: + warnings.warn( + "'unzip' command not installed. You may want to install it (e.g. 'sudo apt install " + "unzip' for ubuntu/debian/mint) and then restart. In the meantime will fall back to " + "slow extraction." + ) + myzip.extractall(path=folder, pwd=archive.password.encode()) + + +def rar_extractor(archive: DataArchive, folder: Path) -> None: + """ + Extraction for RAR files. + + :param DataArchive archive: DataArchive to extract. + :param Path folder: target folder. + :return: + """ + try: + with RarFile(archive.path) as myrar: + myrar.extractall(path=folder) + except RarCannotExec: + raise RuntimeError( + "It seems like there is a backend issue regarding the rarfile package. For debian based " + "systems you might want to <>. For windows users see: " + "https://rarfile.readthedocs.io/faq.html#how-can-i-get-it-work-on-windows" + ) + + +def tar_extractor(archive: DataArchive, folder: Path) -> None: + """ + Extraction for TAR files. + + :param DataArchive archive: DataArchive to extract. + :param Path folder: target folder. + :return: + """ + with tarfile.open(archive.path, "r") as mytar: + # check for CVE-2001-1267 - see https://github.com/advisories/GHSA-gw9q-c7gh-j9vm + for member in mytar.getmembers(): + path = (folder / member.name).resolve() + if folder not in path.parents: + raise RuntimeError(f"{member=} has a suspicious path structure!") + mytar.extractall(path=folder) + + +# maps file suffix to extractor function, plugins may add extractors +ARCHIVE_EXTRACTOR_FUNCTIONS = { + ".zip": zip_extractor, + ".tgz": tar_extractor, + ".tar": tar_extractor, + ".gz": tar_extractor, + ".rar": rar_extractor, +} + + +def unpack_files(archives: List[DataArchive], target: Path) -> None: + """ + Extracts and copies archives to the target folder. Supports zip, rar and tar archives. Also copies non-archive files + as well as folders. + + :param List[DataArchive] archives: List of data archives. + :param Path target: Target folder path. + :return: None + """ + if not target.exists(): + raise FileNotFoundError(f"Extraction root folder {target} has to exist!") + logger.info(f"starting extracting {len(archives)} file(s) to {target} ...") + # extract files (or copy if not stored as archives) + with WIPBar() as bar: + bar.desc = "Extracting archives" + for ix, arch in enumerate(archives): + if not arch.path.exists(): + raise FileNotFoundError(f"Did not find file {arch.path}!") + extract_dir = target / arch.path.stem if arch.keep_top_level else target + if arch.path.suffix in ARCHIVE_EXTRACTOR_FUNCTIONS: + func: Callable[[DataArchive, Path], None] = ARCHIVE_EXTRACTOR_FUNCTIONS[arch.path.suffix] + logger.debug(f"extracting archive {arch} with extractor {func.__name__}") + func(arch, extract_dir) + else: + logger.info( + f"No specific extractor found for archive {arch}, will copy. Please ensure no extraction is " + f"necessary. Otherwise add an extractor to ARCHIVE_EXTRACTOR_FUNCTIONS in {__name__}." + ) + if arch.path.is_file(): + default_file_copy(archive=arch, folder=extract_dir) + else: + default_folder_copy(archive=arch, folder=extract_dir) + if len(archives) > 1: + # report on extraction progress in case of multiple archives + logger.info(f"Done {arch.path.name} ({ix + 1}/{len(archives)}).") + logger.info(f"successfully extracted all files to {target}") + + +@timeout(seconds=300) +def ask_password(file: Optional[Path] = None) -> str: + """Lets user input a password to decrypt a data file + + :param file: The file to unpack + :type file: Optional[Path] + :return: password + :rtype: str + """ + if file: + msg = f"Please enter the password to decrypt the file '{file.name}: " + else: + msg = "Please enter the password to decrypt file(s): " + try: + pwd = getpass(prompt=msg) + except TimeoutError: + logger.error( + "No input provided for necessary password, during dataset creation. Please restart and provide " "password!" + ) + raise + return pwd + + +def is_encrypted(zipfile: ZipFile) -> bool: + """Checks whether a ZipFile is password protected + + :param zipfile: file to check + :type zipfile: ZipFile + :return: True if password protected, False otherwise + :rtype: bool + """ + pwd_required = False + for zinfo in zipfile.infolist(): + # Read encryption status: https://hg.python.org/cpython/file/2.7/Lib/zipfile.py#l986 + is_encrypted = zinfo.flag_bits & 0x1 + if is_encrypted: + pwd_required = True + logger.info("Zip File is password protected") + break + return pwd_required diff --git a/src/mml/core/data_preparation/data_archive.py b/src/mml/core/data_preparation/data_archive.py new file mode 100644 index 0000000..ff6882d --- /dev/null +++ b/src/mml/core/data_preparation/data_archive.py @@ -0,0 +1,59 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import hashlib +import logging +from dataclasses import dataclass +from pathlib import Path +from typing import Optional + +from mml.core.scripts import utils as core_utils + +logger = logging.getLogger(__name__) + + +class DataKind(core_utils.StrEnum): + """ + Kinds of data. Used to somehow sort into distinct top level folders. If multiple kinds are mixed, MIXED should be + used as default. Usage is not enforced but may help to structure any data storage. + """ + + MIXED = "mixed_data" + UNLABELED_DATA = "unlabeled_data" + TRAINING_DATA = "training_data" + TRAINING_LABELS = "training_labels" + TESTING_DATA = "testing_data" + TESTING_LABELS = "testing_labels" + + +@dataclass +class DataArchive: + """A simple dataclass holding information about an data archive (e.g. a zipfile).""" + + path: Path # path to the archive + kind: DataKind = DataKind.MIXED # datakind + md5sum: Optional[str] = None # is there a md5 sum? + password: Optional[str] = None # is there a password encryption? + keep_top_level: bool = False # should an additional layer be created during extraction? + + def check_hash(self) -> None: + """ + Checks if the optional md5sum of the DataArchive matches the actual files md5sum. + """ + if self.md5sum is None: + return + block_size = 65536 + hasher = hashlib.md5() + with open(str(self.path), "rb") as file: + buf = file.read(block_size) + while len(buf) > 0: + hasher.update(buf) + buf = file.read(block_size) + if hasher.hexdigest() != self.md5sum: + raise RuntimeError( + f"incorrect md5sum for file {self.path.name}, should be {self.md5sum} but is " f"{hasher.hexdigest()}" + ) + logger.info(f"file {self.path.name} has correct hash!") diff --git a/src/mml/core/data_preparation/dset_creator.py b/src/mml/core/data_preparation/dset_creator.py new file mode 100644 index 0000000..fb54382 --- /dev/null +++ b/src/mml/core/data_preparation/dset_creator.py @@ -0,0 +1,401 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import os +import shutil +import tempfile +from functools import partial +from pathlib import Path +from typing import Callable, Dict, List, Optional + +import cv2 +import numpy as np +from p_tqdm import p_umap +from PIL import Image +from torch.utils.data import Dataset +from tqdm import tqdm + +import mml.core.data_preparation.utils as prep_utils +import mml.core.scripts.utils as core_utils +from mml.core.data_loading.file_manager import DSET_PREFIX, MMLFileManager +from mml.core.data_loading.task_attributes import Modality, TaskType +from mml.core.data_preparation.archive_extractors import unpack_files +from mml.core.data_preparation.data_archive import DataArchive, DataKind +from mml.core.scripts.exceptions import MMLMisconfigurationException + +logger = logging.getLogger(__name__) + +try: + from kaggle import api as kaggle_api + + _kaggle_available = True +except OSError: + _kaggle_available = False + kaggle_api = None + + +class DSetCreator: + """ + The dataset creator handles all relevant steps to prepare the dataset on your device. This includes: + - downloading the data and checking hashes + - extracting the data from archives + - alternatively extract data from existing pytorch datasets + - storing the data at the correct spots (unlabeled, train and test data) + - optionally transforming masks of segmentation data + + Main usage: + (a) Based on use case: + (i) call .download() / .kaggle_download() / .verify_pre_download() function to download/register files + (ii) call .unpack_and_store() to unpack files and move them to the correct spot + OR: + (i) create / import a pytorch dataset + (ii) call .extract_from_pytorch_datasets to extract that data + (b) (optionally) turn the masks of segmentation tasks to the correct format with .transform_masks() + """ + + def __init__(self, dset_name: str, download_path: Optional[Path] = None, dset_path: Optional[Path] = None): + """ + Creator class for datasets. + + :param dset_name: name of the dataset (should be short, since is used in directory names) + :param download_path: (optional) a path to already downloaded files + :param dset_path: (optional) a path to an already created dset folder + """ + # the instance calls correctly detects an existing file manager, but falls back on creating one in case + # there has not been created one yet + core_utils.load_env() + self.fm = MMLFileManager.instance( + data_path=Path(os.getenv("MML_DATA_PATH")), proj_path=Path(os.getcwd()), log_path=Path(tempfile.mkdtemp()) + ) + self.dset_name = dset_name + if len(self.dset_name) > 20: + raise ValueError("please use a shorter dset name to prevent long directory names") + if " " in self.dset_name: + raise ValueError("please avoid blanks in dset name") + logger.debug(f"Creating dataset {self.dset_name}.") + if download_path is not None: + if not download_path.exists(): + raise FileNotFoundError(f"Download path {download_path} not existing.") + if download_path.is_file(): + raise NotADirectoryError("Download path must be a directory.") + self.download_path = download_path + else: + self.download_path = self.fm.get_download_path(dset_name=self.dset_name) + self.archives: List[DataArchive] = [] + if dset_path is not None: + if not dset_path.exists() or DSET_PREFIX not in dset_path.stem: + raise ValueError(f"Incorrect dset_path given: {dset_path}") + self.dset_path = dset_path + + def download( + self, url: str, file_name: str, data_kind: DataKind = DataKind.MIXED, md5: Optional[str] = None + ) -> DataArchive: + """ + Downloads files from the web to your local drive. + + :param str url: URL to download from + :param str file_name: name of the file + :param DataKind data_kind: (optional) type of the data + :param Optional[str] md5: (optional) md5 sum of the downloaded obj + :return: a reference to the created archive, may be used to modify keep_top_dir before extraction + """ + if data_kind not in DataKind: + raise ValueError(f"data_kind {data_kind} invalid") + prep_utils.download_file(path_to_store=self.download_path, download_url=url, file_name=file_name) + archive = DataArchive(path=self.download_path / file_name, md5sum=md5, kind=data_kind) + archive.check_hash() + if archive.path in [arch.path for arch in self.archives]: + raise RuntimeError(f"File {file_name} already assigned!") + self.archives.append(archive) + return archive + + def kaggle_download( + self, competition: Optional[str] = None, dataset: Optional[str] = None, data_kind: DataKind = DataKind.MIXED + ) -> List[DataArchive]: + """ + Downloads all the data of a kaggle competition or dataset. Either specify competition XOR dataset parameter! + Currently only a single kaggle download is supported per dataset! + + :param competition: (optional) kaggle competition identifier, mutually exclusive with dataset parameter + :param dataset: (optional) kaggle dataset identifier, mutually exclusive with competition parameter + :param DataKind data_kind: (optional) type of the data + :return: a List of references to the created archives, may be used to modify keep_top_dir before extraction + """ + if not _kaggle_available: + raise MMLMisconfigurationException( + "Kaggle authentication failed. Make sure to provide " + "credential either through mml.env file or otherwise " + "(see https://github.com/Kaggle/kaggle-api)." + ) + if data_kind not in DataKind: + raise ValueError(f"data_kind {data_kind} invalid") + target = self.download_path / "kaggle" + if target.exists(): + raise RuntimeError( + "Current kaggle download does not support rerun or multiple downloads from kaggle " "to one dataset." + ) + target.mkdir() + if sum((bool(competition), bool(dataset))) != 1: + raise ValueError("give either competition or dataset") + if competition: + logger.info(f"Downloading kaggle competition {competition} to {target}.") + kaggle_api.competition_download_files(competition=competition, path=target, force=False, quiet=False) + logger.info(f"Successfully downloaded {competition} kaggle competition.") + if dataset: + logger.info(f"Downloading kaggle dataset {dataset} to {target}.") + kaggle_api.dataset_download_files(dataset=dataset, path=target, force=False, quiet=False, unzip=False) + logger.info(f"Successfully downloaded {dataset} kaggle dataset.") + # no information on file names provided, assume all new files are relevant + archives = [] + for file in target.iterdir(): + if file not in [arch.path for arch in self.archives]: + archives.append(DataArchive(path=file, kind=data_kind)) + if len(archives) == 0: + raise FileNotFoundError("Kaggle download failed...") + self.archives.extend(archives) + return archives + + def verify_pre_download( + self, file_name: str, instructions: str, data_kind: DataKind = DataKind.MIXED, md5: Optional[str] = None + ) -> DataArchive: + """ + Verifies a file that has been previously downloaded is present and adds it to internal archive list. This + is useful if e.g. downloading requires credentials / registering or the data is non-public. + + :param str file_name: name of the downloaded file or folder + :param str instructions: how to get the data + :param DataKind data_kind: (optional) kind of the data + :param str md5: (optional) md5 sum of the downloaded obj, only effective for non-folder files + :return: a reference to the created archive, may be used to modify keep_top_dir before extraction + """ + if data_kind not in DataKind: + raise ValueError(f"data_kind {data_kind} invalid") + path = self.download_path / file_name + if not path.exists(): + raise ValueError( + f"file {file_name} not found at {self.download_path}, please follow these " + f"instructions: {instructions}." + ) + if md5 and path.is_dir(): + raise IsADirectoryError( + f"Hash checking only supported for archived folders or files. {file_name} is not " f"a file" + ) + archive = DataArchive(path=path, md5sum=md5, kind=data_kind) + archive.check_hash() + if archive.path in [arch.path for arch in self.archives]: + raise RuntimeError(f"File {file_name} already assigned!") + self.archives.append(archive) + return archive + + def unpack_and_store(self, clear_download_folder: bool = False) -> Path: + """ + Unpacks all files and stores them at the correct spot. + + :param clear_download_folder: if True deletes the download folder + :return: the dataset root path (to be used by TaskCreator) + """ + if self.dset_path is not None: + raise RuntimeError("dset_path should not be given beforehand if unpacking new data!") + self.dset_path = self.fm.get_dataset_path(dset_name=self.dset_name, preprocessing=None) + for sub in DataKind.list(): + sub_path = self.dset_path / sub + archives = [arch for arch in self.archives if arch.kind == sub] + if len(archives) == 0: + continue + sub_path.mkdir(exist_ok=True) + unpack_files(archives=archives, target=sub_path) + if clear_download_folder: + shutil.rmtree(self.download_path) + logger.debug("Removed download folder.") + logger.debug("Done with dataset creation!") + return self.dset_path + + def extract_from_pytorch_datasets( + self, + datasets: Dict[str, Dataset], + task_type: TaskType, + allow_transforms: bool = False, + class_names: Optional[List[str]] = None, + ) -> Path: + """ + Can be used to store an existing dataset (e.g. imported from some other repository or from torchvision). Expects + (image, class) tuples for classification and (image, mask) tuples for semantic segmentation to return over + __getitem__. Unlabeled dataset is expected to return no tuple, but only image. + + :param datasets: dict of datasets to be stored, keys must be from [training, testing, unlabeled] + :param task_type: task type of the dataset + :param allow_transforms: if the transform attribute is present and unequal to None whether to raise an error + :param class_names: optional list of class names to store data with class name directories + :return: the dataset root path (to be used by TaskCreator) + """ + assert self.dset_path is None, "dset_path should not be given beforehand if storing new data" + self.dset_path = self.fm.get_dataset_path(dset_name=self.dset_name, preprocessing=None) + # check datasets + for key, dataset in datasets.items(): + assert len(dataset) > 0, f"Was provided with empty dataset {key}." + assert key in ["training", "testing", "unlabeled"], f"invalid key {key}" + if not allow_transforms: + if hasattr(dataset, "transform"): + assert ( + dataset.transform is None + ), "dataset has a transform applied, set allow_transforms True if desired" + if hasattr(dataset, "target_transform"): + assert ( + dataset.target_transform is None + ), "dataset has a target_transform applied, set allow_transforms True if desired" + # iterate over samples, load these and store correctly at readable format and intuitive place + id_iterator = 0 # used as IDs + for key, dataset in datasets.items(): + unlabeled = key == "unlabeled" + sub = DataKind.UNLABELED_DATA if unlabeled else DataKind(key + "_data") + sub_path = self.dset_path / sub.value + sub_path.mkdir(exist_ok=False) + if task_type == TaskType.SEMANTIC_SEGMENTATION and not unlabeled: + sub_masks = DataKind(key + "_labels") + sub_masks_path = self.dset_path / sub_masks.value + sub_masks_path.mkdir(exist_ok=False) + for sample in tqdm(dataset, desc=f"Extracting {key} data"): + id_iterator += 1 + # unpack sample + if unlabeled: + image = sample + else: + # try to unpack + if isinstance(sample, tuple): + image, target = sample + elif isinstance(sample, dict): + if Modality.IMAGE.value not in sample or any(k not in Modality for k in sample): + raise ValueError( + f"Dataset loads as dictionary, but keys are not compliant with MML " + f"Modality options. Available options are: {Modality.list()}" + ) + image = sample[Modality.IMAGE.value] + if task_type == TaskType.CLASSIFICATION: + target = sample[Modality.CLASS.value] + elif task_type == TaskType.SEMANTIC_SEGMENTATION: + target = sample[Modality.MASK.value] + else: + raise NotImplementedError(f"Task type {task_type} is not suitable for dict extraction yet.") + # first handle image object + if isinstance(image, Image.Image): + # PIL image + image = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR) + elif isinstance(image, np.ndarray): + # numpy array as returned by cv2 + pass + else: + raise TypeError(f"image returned is of type {type(image)}") + if len(image.shape) != 3: + # TODO probably convert greyscale images here? + raise ValueError(f"image is not well formatted, has shape {image.shape}") + img_folder = sub_path + if task_type == TaskType.CLASSIFICATION and not unlabeled: + img_folder /= str(target).zfill(3) if class_names is None else class_names[target] + img_folder.mkdir(exist_ok=True) + image_path = img_folder / (str(id_iterator).zfill(6) + ".png") + cv2.imwrite(str(image_path), image) + # handle segmentation mask + if task_type == TaskType.SEMANTIC_SEGMENTATION and not unlabeled: + # target object should be a mask + if isinstance(target, Image.Image): + # PIL image + target = cv2.cvtColor(np.asarray(target.convert(mode="RGB")), cv2.COLOR_RGB2BGR) + elif isinstance(target, np.ndarray): + # numpy array as returned by cv2 + pass + else: + raise TypeError(f"target returned is of type {type(image)}") + if id_iterator == 1: + logger.info(f"targets of this dataset have shape {target.shape}") + cv2.imwrite(str(sub_masks_path / (str(id_iterator).zfill(6) + ".png")), target) + return self.dset_path + + def transform_masks( + self, + masks: List[Path], + transform: Dict[tuple, int], + load: str = "rgb", + train: bool = True, + ignore: Optional[List[tuple]] = None, + ) -> Path: + """ + Takes the job of transforming masks to the frameworks format (cv2 readable greyscale images). Will write the + transformed masks to dataset root -> training_labels / testing_labels -> transformed_masks -> same relative path + as before (to mask within one of the data subfolders). + + :param masks: list of paths to the mask files + :param transform: dict defining the transformation (mapping of mask values to classes) + :param load: mode defining the loading of a file + :param train: bool indicating if treated data is train or test + :param ignore: list of mask values that should be mapped to the ignored value of 255 (similar to transform) + :return: base folder for the transformed masks + """ + # TODO in the future this might e.g. also include multi instance -> semantic segmentation + # storing base path + data_kind = DataKind.TRAINING_LABELS if train else DataKind.TESTING_LABELS + out_base = self.dset_path / data_kind.value / "transformed_masks" + out_base.mkdir(exist_ok=True, parents=True) + # transform mapping + if ignore is None: + ignore = [] + + example = list(transform.keys())[0] + + assert all( + [len(mask_value) == len(example) for mask_value in list(transform.keys()) + ignore] + ), "tuples used as transform (or ignore) keys require identical shape" + assert all( + [0 <= val < 255 for val in transform.values()] + ), f"was provided with incorrect classes ({transform.values()}) to fit into greyscale." + assert all([key not in ignore for key in transform.keys()]), "provided mask values are not unique" + + mapping = transform.copy() + mapping.update({idxs: 255 for idxs in ignore}) + + def mapper(*args): + return mapping.__getitem__(args) + + vmapper = np.vectorize(mapper) + logger.info(f"transforming {len(masks)} masks...") + success = p_umap( + partial(mask_transform, dset_path=self.dset_path, out_base=out_base, load=load, vmapper=vmapper), masks + ) + logger.info(f"{sum(success)} of {len(success)} masks transformed successfully.") + return out_base + + +def mask_transform(mask_path: Path, dset_path: Path, out_base: Path, load: str, vmapper: Callable) -> bool: + """ + Parallelizable part of mask transform. Params keep names from within DsetCreator.transform_mask. + + :return: boolean indicating success of saving the transformed mask + """ + assert dset_path in mask_path.parents, ( + f"path {mask_path} not within dataset, make sure to unpack " f"before transforming" + ) + # loading + mask = None # IDE related + if load == "rgb": + mask = cv2.cvtColor(cv2.imread(str(mask_path)), cv2.COLOR_BGR2RGB) + elif load == "grayscale": + mask = cv2.imread(str(mask_path), cv2.IMREAD_GRAYSCALE)[:, :, np.newaxis] + else: + ValueError(f"Loading mode {load} not supported.") + # transforming + try: + mask = vmapper(*np.split(mask, indices_or_sections=mask.shape[2], axis=2)) + except KeyError as error: + logger.error(f"A key ({error}) is not present in the transform mapping! Mask can be found at {mask_path}.") + raise error + # saving + path = out_base + for part in mask_path.relative_to(dset_path).parts[1:]: + path /= part + path.parent.mkdir(exist_ok=True, parents=True) + path = path.with_suffix(".png") + success = cv2.imwrite(filename=str(path), img=mask) + return success diff --git a/src/mml/core/data_preparation/fake_task.py b/src/mml/core/data_preparation/fake_task.py new file mode 100644 index 0000000..10cd409 --- /dev/null +++ b/src/mml/core/data_preparation/fake_task.py @@ -0,0 +1,84 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +""" +Provides a fake task for testing purposes. +""" + +import string +from pathlib import Path + +from torch.utils.data import Dataset +from torchvision.datasets import FakeData + +from mml.core.data_loading.task_attributes import Keyword, License, TaskType +from mml.core.data_preparation.dset_creator import DSetCreator +from mml.core.data_preparation.registry import register_dsetcreator, register_taskcreator +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.data_preparation.utils import ( + get_iterator_and_mapping_from_image_dataset, + get_iterator_from_unlabeled_dataset, +) + +dset_name = "mml_fake_dataset" +task_name = "mml_fake_task" +num_classes = 10 +classes = [char for char in string.ascii_uppercase[:num_classes]] + + +@register_dsetcreator(dset_name=dset_name) +def create_fake_dset() -> Path: + dset_creator = DSetCreator(dset_name=dset_name) + fake_train = FakeData(size=1000, num_classes=num_classes) + fake_test = FakeData(size=500, num_classes=num_classes) + + class UnlabeledFakeData(Dataset): + def __init__(self, size: int): + self.internal = FakeData(size=size, num_classes=2) + + def __len__(self): + return len(self.internal) + + def __getitem__(self, idx: int): + return self.internal[idx][0] + + fake_unlabeled = UnlabeledFakeData(size=300) + dset_path = dset_creator.extract_from_pytorch_datasets( + datasets={"training": fake_train, "testing": fake_test, "unlabeled": fake_unlabeled}, + task_type=TaskType.CLASSIFICATION, + class_names=classes, + ) + return dset_path + + +@register_taskcreator(task_name=task_name, dset_name=dset_name) +def create_fake_task(dset_path: Path) -> Path: + task = TaskCreator( + dset_path=dset_path, + name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="Fake task, based on torchvision.datasets.FakeData.", + ref="No reference.", + url="No url.", + instr="No instr.", + lic=License.UNKNOWN, + release="2004", + keywords=[Keyword.ARTIFICIAL], + ) + train_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / "training_data", classes=classes + ) + test_iterator, _ = get_iterator_and_mapping_from_image_dataset(root=dset_path / "testing_data", classes=classes) + unlabeled_iterator = get_iterator_from_unlabeled_dataset(root=dset_path / "unlabeled_data") + task.find_data( + train_iterator=train_iterator, + test_iterator=test_iterator, + unlabeled_iterator=unlabeled_iterator, + idx_to_class=idx_to_class, + ) + task.split_folds(n_folds=5, ensure_balancing=True) + task.infer_stats() + return task.push_and_test() diff --git a/src/mml/core/data_preparation/registry.py b/src/mml/core/data_preparation/registry.py new file mode 100644 index 0000000..6554b9d --- /dev/null +++ b/src/mml/core/data_preparation/registry.py @@ -0,0 +1,97 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path +from typing import Any, Callable, Dict, Union + +_DATASET_CREATORS: Dict[str, Callable[[], Path]] = {} +_TASKCREATORS: Dict[str, Callable[[Path], None]] = {} +_TASK_TO_DSET: Dict[str, str] = {} + + +def register_dsetcreator(dset_name: str) -> Callable[[Callable[[], Path]], Callable[[], Path]]: + """ + Registers a dataset creator. + + :param dset_name: the dataset to be linked with + :return: identical creator, but has been linked + """ + + def decorator(dset_creation_func: Callable[[], Path]) -> Callable[[], Path]: + _DATASET_CREATORS[dset_name] = dset_creation_func + return dset_creation_func + + return decorator + + +def register_taskcreator( + task_name: str, dset_name: str +) -> Callable[[Callable[[Path], None]], Callable[[Path], Union[None, Path]]]: + """ + Registers a task creator. + + :param task_name: the task name to be linked with + :param dset_name: the dataset to be linked with + :return: + """ + + def decorator(task_creation_func: Callable[[Path], None]) -> Callable[[Path], Union[None, Path]]: + _TASKCREATORS[task_name] = task_creation_func + _TASK_TO_DSET[task_name] = dset_name + return task_creation_func + + return decorator + + +def create_creator_func(create_func: Callable[..., None], **kwargs: Any) -> Callable[[Path], None]: + """ + Convenience function if multiple task creation function shall be created dynamically. + + :param create_func: the actual creation function that takes more kwargs than solely the dset_path + :param kwargs: the kwarg values + :return: a static function, independent of any globals for generation at runtime + """ + + def func(dset_path: Path) -> None: + create_func(dset_path=dset_path, **kwargs) + + return func + + +def get_dset_for_task(task_name: str) -> str: + """ + Appropriate way to receive the dataset from a task. + + :param task_name: name of the task + :return: name of the dataset + """ + if task_name not in _TASK_TO_DSET: + raise KeyError(f"Task {task_name} has no registered link to a dataset.") + return _TASK_TO_DSET[task_name] + + +def get_task_creator(task_name: str) -> Callable[[Path], None]: + """ + Appropriate way to receive the creator for a task. + + :param task_name: name of the task + :return: task creator function + """ + if task_name not in _TASKCREATORS: + raise KeyError(f"Task {task_name} has no registered link to a task creator.") + return _TASKCREATORS[task_name] + + +def get_dset_creator(dset_name: str) -> Callable[[], Path]: + """ + Appropriate way to receive the creator for a dataset + + :param dset_name: dataset name + :return: dataset create function + """ + if dset_name not in _DATASET_CREATORS: + raise KeyError(f"Dataset {dset_name} has no registered link to a dataset creator.") + return _DATASET_CREATORS[dset_name] diff --git a/src/mml/core/data_preparation/task_creator.py b/src/mml/core/data_preparation/task_creator.py new file mode 100644 index 0000000..9453376 --- /dev/null +++ b/src/mml/core/data_preparation/task_creator.py @@ -0,0 +1,838 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import functools +import logging +import os +import tempfile +import warnings +from collections import Counter +from datetime import datetime +from itertools import chain, combinations +from pathlib import Path +from typing import Any, Callable, Dict, List, Optional + +import cv2 +import numpy as np +import torch +import torch.utils.data +from tqdm import tqdm + +import mml.core.scripts.utils # keep like this to allow monkeypatching load_env fixture +from mml.core.data_loading.file_manager import MMLFileManager +from mml.core.data_loading.task_attributes import ( + EMPTY_MASK_TOKEN, + DataSplit, + Keyword, + License, + Modality, + RGBInfo, + Sizes, + TaskType, +) +from mml.core.data_loading.task_dataset import TaskDataset +from mml.core.data_loading.task_description import SampleDescription, TaskDescription +from mml.core.data_preparation.utils import TaskCreatorActions, TaskCreatorState, calc_means_stds_sizes +from mml.core.scripts.exceptions import InvalidTransitionError, TaskNotFoundError + +logger = logging.getLogger(__name__) + +DEFAULT_N_FOLDS = 5 +DEFAULT_ENSURE_BALANCED = True + + +def implements_action(action: TaskCreatorActions): + """ + This is a decorator to simplify state management of the task creator. It also adds a "secret" + kwarg to most task creator methods, if this is set no state check is done. + + :param action: the action that the following function implements + :return: a decorator + """ + + def actual_decorator(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + # extract task creator instance "self" as first argument of method + self, *args = args + traverse = True + if not isinstance(self, TaskCreator): + raise TypeError('"implements_action" decorator may only be applied to methods of TaskCreator!') + if "ignore_state" in kwargs and bool(kwargs["ignore_state"]): + # no traversal! + kwargs.pop("ignore_state") + traverse = False + if traverse: + # test if traverse is legal (saves time compared to waiting and raising after func call) + self._state.traverse(action=action) + # run and return result + result = func(self, *args, **kwargs) + if traverse: + # do actual transition + self._state = self._state.traverse(action=action) + return result + + return wrapper + + return actual_decorator + + +class TaskCreator: + """ + Usage: + + (1) Creating a new task: + (a) instantiate class with all available meta information + (b) call find_data to locate data of the task + (c) call split_folds (or use_existing_folds) to prepare folds + (d) call infer_stats to calc and set means, stds and sizes of train data (use set_stats if already known) + (e) call push_and_test to save + + (2) Modifying an existing task: + (a) instantiate with correct dset_path + (b) call load_existent with existing task_path + (c) call any of the modification functions (optionally also multiple times) + (d) if necessary call infer_stats to set means, stds and sizes of train data + (e) call push_and_test to save + + (3) Auto creation based on task tags: + (a) instantiate with arbitrary dset_path + (b) call auto_create_tagged with the full name and also the preprocessing + (c) raises a RuntimeError if not possible, else will create the task and return the path + """ + + def __init__( + self, + dset_path: Path, + name: str = "default", + task_type: TaskType = TaskType.UNKNOWN, + desc: str = "", + ref: str = "", + url: str = "", + instr: str = "", + lic: License = License.UNKNOWN, + release: str = "", + keywords: Optional[List[Keyword]] = None, + ): + """ + Everything it needs to create a task. Use a new instance for each new task. + + :param dset_path: path to dataset root + :param name: name of the task to be created + :param task_type: task type of the task + :param desc: a short description of the task + :param ref: a reference (most likely some bibtex citation) + :param url: an url linked to the task + :param instr: instructions to download the task (data) + :param lic: the license corresponding to the data of the task + :param release: either a release date or some version of the task + :param keywords: keywords associated to the task + """ + # the instance calls correctly detects an existing file manager, but falls back on creating one in case + # there has not been created one yet + mml.core.scripts.utils.load_env() + self.fm = MMLFileManager.instance( + data_path=Path(os.getenv("MML_DATA_PATH")), proj_path=Path(os.getcwd()), log_path=Path(tempfile.mkdtemp()) + ) + if name in self.fm.task_index.keys(): + logger.warning(f"Task name {name} already used with prepossessings " f"{self.fm.task_index[name].keys()}.") + if any( + [symbol in name for symbol in [" ", "%", mml.core.scripts.utils.TAG_SEP, mml.core.scripts.utils.ARG_SEP]] + ): + raise ValueError( + f'The following symbols are not allowed within (raw) task aliases: ' + f'{[" ", "%", mml.core.scripts.utils.TAG_SEP, mml.core.scripts.utils.ARG_SEP]}' + ) + if name == self.fm.GLOBAL_REUSABLE: + raise ValueError("Invalid task name!") + self.current_meta = TaskDescription( + name=name, + description=desc, + reference=ref, + url=url, + download=instr, + license=lic, + release=release, + task_type=task_type, + keywords=[] if keywords is None else keywords, + ) + self.protocol("Started") + self.data: Optional[Dict[DataSplit, Dict[str, SampleDescription]]] = None # stores data paths + self.dset_path = Path(dset_path) + # internal state control mechanism + self._state: TaskCreatorState = TaskCreatorState.INIT + + def __repr__(self): + return f"TaskCreator(dset_path={self.dset_path}, _state={self._state})" + + def protocol(self, msg: str) -> None: + """ + Method to log any processing to the creation_protocol of the meta information. + + :param str msg: message to be logged, will be formatted with datetime and appended to the creation_protocol + :return: + """ + msg += f" @ {datetime.now().strftime('%d/%m/%Y %H:%M:%S')}; " + self.current_meta.creation_protocol += msg + + @implements_action(TaskCreatorActions.LOAD) + def load_existent(self, task_path: Path) -> None: + """ + Loads an existent task .json, useful prior to modifications (e.g. tagging or preprocessing). + + :param Path task_path: path to task .json file + :return: None + """ + if task_path.suffix != ".json": + raise ValueError(f"requires .json file, was given {task_path.suffix}.") + if not task_path.exists(): + raise FileNotFoundError(f"given task_path {task_path} does not exist!") + if self.dset_path not in task_path.parents: + raise ValueError(f"Invalid dset {self.dset_path} with given task path {task_path}.") + self.current_meta = self.fm.load_task_description(task_path) + self.protocol(f"Copied from {task_path.name}") + self.data = None # ensure no modifications on this attribute, already present in meta info + + @implements_action(TaskCreatorActions.FIND_DATA) + def find_data( + self, + train_iterator: Optional[List[SampleDescription]] = None, + test_iterator: Optional[List[SampleDescription]] = None, + unlabeled_iterator: Optional[List[SampleDescription]] = None, + idx_to_class: Optional[Dict[int, str]] = None, + ) -> None: + """ + Correctly identifies data tuples yielded by the provided data iterators. + + :param Optional[List[SampleDescription]] train_iterator: all train data, provided as + dicts with (optional) keys from `~mml.core.data_loading.task_attributes.Modality`, where + `Modality.SAMPLE_ID` is required and the corresponding value has to be unique. + Some further potential entries are `Modality.CLASS` with `int` value, + and `Modality.MASK` with Path to some (greyscale) image, both with vals in idx_to_class. + :param Optional[List[SampleDescription]] test_iterator: + test data iterator, same type as train_iterator + :param Optional[List[SampleDescription]] unlabeled_iterator: + unlabeled data iterator, same type as train_iterator + :param Optional[Dict[int, str]] idx_to_class: dict mapping ints to class names (e.g. + {0 -> background, 1 -> instrument}), may also be non-continuous (e.g. {0 -> background, 3 -> instrument}) + for subclassing or mapping indices to the same class (e.g. + {0 -> background, 1 -> instrument, 3 -> instrument}) for merging classes, please + use index 0 for background in segmentation tasks (all unused values will be mapped to 0). In case of only + unlabelled data this is not necessary (otherwise it is). + :return: None + """ + # validate args + if self.data is not None: + raise RuntimeError("Adding data to already existent data in TaskCreator is invalid!") + self.data = {} + if not train_iterator and not unlabeled_iterator and not test_iterator: + raise ValueError("Must provide at least one of train, test or unlabeled iterator.") + if (train_iterator or test_iterator) and not idx_to_class: + raise ValueError("If given train/test iterator must provide idx_to_class.") + if idx_to_class and not all( + [isinstance(key, int) and isinstance(value, str) for key, value in idx_to_class.items()] + ): + raise TypeError("idx_to_class must be of type Dict[int, str].") + if self.current_meta.task_type == TaskType.UNKNOWN: + raise RuntimeError("Must provide task_type before reading in data.") + if ( + self.current_meta.task_type + in [TaskType.CLASSIFICATION, TaskType.SEMANTIC_SEGMENTATION, TaskType.MULTILABEL_CLASSIFICATION] + and len(set(idx_to_class.values())) < 2 + ): + raise ValueError("task requires at least 2 classes") + # scan over iterators + for iterator, data_split in zip( + [train_iterator, test_iterator, unlabeled_iterator], + [DataSplit.FULL_TRAIN, DataSplit.TEST, DataSplit.UNLABELLED], + ): + if iterator is None: + continue + if len(iterator) == 0: + raise ValueError(f"{data_split} iterator has length zero") + data = {} + if idx_to_class: + class_occ = {val: 0 for val in set(idx_to_class.values())} + else: + class_occ = {} + for data_dict in tqdm(iterator, desc=f"Scanning {data_split} data"): + # STEP ONE: validate sample ID + if not isinstance(data_dict, dict): + raise TypeError(f"The {data_split} iterator has to yield dicts.") + if Modality.SAMPLE_ID not in data_dict: + raise ValueError( + f"Modality.SAMPLE_ID key not present in some element of iterator {data_split}, " + f"element: {data_dict}." + ) + if not isinstance(data_dict[Modality.SAMPLE_ID], str): + raise TypeError( + f"Modality.SAMPLE_ID value to be a string, was given " + f"{data_dict[Modality.SAMPLE_ID]} of type {type(data_dict[Modality.SAMPLE_ID])}." + ) + data_id = data_dict.pop(Modality.SAMPLE_ID) + if data_id in data: + raise ValueError(f"Modality.SAMPLE_ID values have to be unique, found existing {data_id}.") + data[data_id] = {} + # STEP TWO: validate present and required modalities (only for train) + modalities = data_dict.keys() + if any([mod not in Modality for mod in modalities]): + raise TypeError( + f"iterator dicts have to provide keys from within {Modality}, was given " f"{modalities}." + ) + if data_split != DataSplit.UNLABELLED: + # check if required modalities are present in train & test data + if not any( + [ + all([mod in modalities for mod in mod_list]) + for mod_list in self.current_meta.task_type.requires() + ] + ): + raise RuntimeError( + f"For task type {self.current_meta.task_type} at least one of the " + f"following combinations of modalities must be fully provided for any " + f"sample: {self.current_meta.task_type.requires()}." + ) + # STEP THREE: validate individual modality entries + for modality, value in data_dict.items(): + # SUB-STEP + if modality not in self.current_meta.modalities.keys(): + self.current_meta.modalities[modality] = "" + if isinstance(value, Path): + if self.dset_path not in value.parents: + raise ValueError("Data should always be stored within dataset!") + # make path relative to dset_path (saves storage, since redundant) + value = value.relative_to(self.dset_path) + if value.suffix not in self.current_meta.modalities[modality]: + self.current_meta.modalities[modality] += f"{value.suffix}; " + self.verify_modality_entry( + modality=modality, value=value, idx_to_class=idx_to_class, class_occ=class_occ + ) + if isinstance(value, Path): + # write paths as strings into task description + value = str(value) + data[data_id][modality] = value + self.data[data_split] = data + # check if some class is missing in some data split + if 0 in class_occ.values() and data_split != DataSplit.UNLABELLED: + warnings.warn( + f"classes {[name for name, val in class_occ.items() if val == 0]} " + f"not present in data for data split {data_split}!" + ) + if data_split == DataSplit.FULL_TRAIN: + # in case of soft labels we produce integer counts anyway for consistency + class_occ = {k: int(v) for k, v in class_occ.items()} + self.current_meta.class_occ = class_occ + logger.info(f"Found {len(data)} items in {data_split}.") + self.protocol(f"Found {len(data)} items of {data_split}") + self.current_meta.idx_to_class = idx_to_class + + @implements_action(TaskCreatorActions.SET_FOLDING) + def split_folds( + self, + n_folds: int = DEFAULT_N_FOLDS, + ensure_balancing: bool = DEFAULT_ENSURE_BALANCED, + fold_0_fraction: Optional[float] = None, + seed: int = 42, + ) -> None: + """ + Splits the found data into folds for cross validation. It is necessary to call either this or the + use_existing folds method before infer_stats. + + This method requires the following attributes to be set: + - self.data[DataSplit.FULL_TRAIN] + - self.current_meta.task_type + - self.current_meta.class_occ + - self.current_meta.idx_to_class + + This method sets the following attributes: + - self.current_meta.train_folds + - self.current_meta.train_samples + - self.current_meta.test_samples + - self.current_meta.unlabeled_samples + - self.data + + WARNING: The splitting of folds happens deterministic to ensure reproducibility. One implication of this is + that tasks with identical number of training samples (and identical values for n_folds) will also be split + identical (with respect to the order of the samples in self.data[DataSplit.FULL_TRAIN]). For classification + tasks this can be prohibited by using ensure_balancing (since sampling then also happens at class level) or + in general by using the seed parameter. + + :param n_folds: number of folds to split into + :param ensure_balancing: indicates if classes should be balanced across folds (only for classification tasks) + :param Optional[float] fold_0_fraction: if set the first fold (usually used as validation split) will receive + that fraction of samples, the rest will be distributed evenly across remaining folds. If None all folds + will have the same size. When a value is provided it must be within (0, 1), but chosen such that least + one sample (per class if ensure_balancing is active) is contained in each fold. + :param int seed: controls the determinism behind splitting, default: 42 + :return: None + """ + if n_folds < 2: + raise ValueError(f"Splitting requires at least n_folds = 2, was provided {n_folds}.") + if DataSplit.FULL_TRAIN in self.data: + if fold_0_fraction is None: + fold_0_fraction = 1 / n_folds + if not 0 < fold_0_fraction < 1: + raise ValueError("fold_0_fraction must be within (0, 1) but cannot be 0 or 1 itself!") + if ensure_balancing and self.current_meta.task_type != TaskType.CLASSIFICATION: + warnings.warn( + f"ensure_balancing only possible for TaskType classification, have " + f"{self.current_meta.task_type}, will be ignored!" + ) + ensure_balancing = False + if ensure_balancing: + # check at least one sample of the smallest class is contained in each fold + smallest_class, smallest_occ = min(self.current_meta.class_occ.items(), key=lambda x: x[1]) + all_occs = sum(self.current_meta.class_occ.values()) + if smallest_occ / all_occs * len(self.data[DataSplit.FULL_TRAIN]) * fold_0_fraction < 1: + raise ValueError( + f"fold_0_fraction of {fold_0_fraction} results in no sample of class {smallest_class} " + f"in fold 0. It is necessary to increase value of fold_0_fraction, reduce number " + f"of folds or disable balancing. {smallest_occ=} {all_occs=} {len(self.data[DataSplit.FULL_TRAIN])}" + ) + if ( + smallest_occ + / all_occs + * len(self.data[DataSplit.FULL_TRAIN]) + * (1 - fold_0_fraction) + / (n_folds - 1) + < 1 + ): + raise ValueError( + f"fold_0_fraction of {fold_0_fraction} results in no sample of class {smallest_class} " + f"in at least one of the folds [1, ..., n_folds]. It is necessary to decrease value of" + f" fold_0_fraction, reduce number of folds or disable balancing." + ) + # define class pools + class_pools = { + class_ix: [ + k for k, elem in self.data[DataSplit.FULL_TRAIN].items() if elem[Modality.CLASS] == class_ix + ] + for class_ix in self.current_meta.idx_to_class.keys() + } + else: + # check that at least one sample is contained in each fold + if fold_0_fraction * len(self.data[DataSplit.FULL_TRAIN]) < 1: + raise ValueError( + f"fold_0_fraction of {fold_0_fraction} results in no sample in fold 0. It is " + f"necessary to increase value of fold_0_fraction or reduce number of folds." + ) + if (1 - fold_0_fraction) * len(self.data[DataSplit.FULL_TRAIN]) < n_folds - 1: + raise ValueError( + f"fold_0_fraction of {fold_0_fraction} results in no sample in at least one of the " + f"folds [1, ..., n_folds]. It is necessary to decrease value of fold_0_fraction." + ) + # use a single pseudo class pool instead + class_pools = {"all": list(self.data[DataSplit.FULL_TRAIN].keys())} + # do the actual splitting, first every pool itself is split + splits = {} + for pool_id, pool in class_pools.items(): + length_fold_0 = round(fold_0_fraction * len(pool)) + mod = (len(pool) - length_fold_0) % (n_folds - 1) + lengths = [length_fold_0] + [ + (len(pool) - length_fold_0) // (n_folds - 1) + offset + for offset in [1] * mod + [0] * (n_folds - 1 - mod) + ] + splits[pool_id] = torch.utils.data.random_split( + pool, lengths, generator=torch.Generator().manual_seed(seed) + ) + # now join pools for each fold + joined_pools = list() + for fold_idx in range(n_folds): + # pools are concatenated + joined = list(chain(*[list(splits[pool_id][fold_idx]) for pool_id in class_pools.keys()])) + # now pools are shuffled, so that no class ordering happens (in case balancing was chosen) + # seed computation is for backward compatibility + np.random.default_rng(seed=3 * (seed - 1) + fold_idx).shuffle(joined) + joined_pools.append(joined) + # finally store in metadata + self.current_meta.train_folds = joined_pools + self.current_meta.train_samples = self.data[DataSplit.FULL_TRAIN] + self.current_meta.test_samples = self.data[DataSplit.TEST] if DataSplit.TEST in self.data else {} + self.current_meta.unlabeled_samples = ( + self.data[DataSplit.UNLABELLED] if DataSplit.UNLABELLED in self.data else {} + ) + self.protocol(f"Split into {n_folds} folds") + self.data = None + + @implements_action(TaskCreatorActions.SET_FOLDING) + def use_existing_folds(self, fold_definition: List[List[str]]) -> None: + """ + Replacement for the split_folds function in case there are already predefined folds. + + :param List[List[str]] fold_definition: list of lists of data ids, each list within the main list represents + one fold, data ids must match the ones provided to find_data + :return: None + """ + logger.debug("Checking provided folds compatibility ...") + assert DataSplit.FULL_TRAIN in self.data, "Call find data on train type before calling fold splitting." + assert 2 <= len(fold_definition), f"Splitting requires at least 2 folds, was provided {len(fold_definition)}." + # check folds are disjoint, themselves and across + set_folds = [set(fold) for fold in fold_definition] + for ix in range(len(fold_definition)): + assert len(set_folds[ix]) == len(fold_definition[ix]), f"Duplicate ids in fold {ix} (zero indexed)" + for fold_1, fold_2 in combinations(set_folds, 2): + assert fold_1.isdisjoint(fold_2), "Shared ids between folds!" + # check folds are valid keys + valid_ids = set(self.data[DataSplit.FULL_TRAIN].keys()) + all_ids = set(chain(*fold_definition)) + assert all([data_id in valid_ids for data_id in all_ids]), "Invalid id provided!" + # check if ids are unused + assert all( + [data_id in all_ids for data_id in valid_ids] + ), "There are unused ids, please provide complete folderization or decrease data provided to find_data." + logger.debug("Provided folds are compatible!") + self.current_meta.train_folds = fold_definition + self.current_meta.train_samples = self.data[DataSplit.FULL_TRAIN] + self.current_meta.test_samples = self.data[DataSplit.TEST] if DataSplit.TEST in self.data else {} + self.current_meta.unlabeled_samples = ( + self.data[DataSplit.UNLABELLED] if DataSplit.UNLABELLED in self.data else {} + ) + self.protocol(f"Manually provided {len(fold_definition)} folds") + self.data = None + + @implements_action(TaskCreatorActions.SET_STATS) + def infer_stats( + self, + sizes: bool = True, + mean_and_std: bool = True, + const_size: bool = False, + device: Optional[torch.device] = None, + ) -> None: + """ + Calculates the training data stats. For improved speed indicating a constant size of images helps. + + :param bool sizes: if the image sizes should be gathered + :param bool mean_and_std: if the mean and standard deviation of color channels should be gathered + :param bool const_size: if images are known to have constant size, this helps flag improves speed + :param torch.device device: if provided use this device, otherwise infer device based on availability + :return: None + """ + assert self.data is None, "Call split_folds/use_existing_folds before calling infer stats." + temp_json = self.dset_path / "temp.json" + counter = 0 + while temp_json.exists(): + logger.warning(f"Temp file {temp_json} detected, will try to avoid collision with other runs on data.") + temp_json = self.dset_path / f"temp_{counter}.json" + counter += 1 + temp_json.touch(exist_ok=False) + self.fm.write_task_description(path=temp_json, task_description=self.current_meta, omit_warning=True) + if device is None: + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + stats = calc_means_stds_sizes( + temp_json, sizes=sizes, means=mean_and_std, stds=mean_and_std, device=device, const_size=const_size + ) + if sizes: + self.current_meta.sizes = stats["sizes"] + if mean_and_std: + self.current_meta.stds = stats["stds"] + self.current_meta.means = stats["means"] + temp_json.unlink() + self.protocol(f"Inferred stats {'sizes' if sizes else ''} {'mean and std' if mean_and_std else ''}") + + @implements_action(TaskCreatorActions.SET_STATS) + def set_stats( + self, means: Optional[RGBInfo] = None, stds: Optional[RGBInfo] = None, sizes: Optional[Sizes] = None + ) -> None: + """ + Alternative to :meth:`infer_stats` with provided means, stds and sizes. May also only set a subset of those (or + even None). + + :param Optional[RGBInfo] means: task RGB channel means + :param Optional[RGBInfo] stds: task RGB channel stds + :param Optional[Sizes] sizes: task image dimensions + :return: None + """ + if self.data is not None: + raise RuntimeError("Call split folds before calling set stats.") + if means: + self.current_meta.means = means + if stds: + self.current_meta.stds = stds + if sizes: + self.current_meta.sizes = sizes + self.protocol(f"Set stats {'sizes' if sizes else ''} {'mean' if means else ''} {'std' if stds else ''}") + + @implements_action(TaskCreatorActions.FINISH) + def push_and_test(self) -> Path: + """ + Final step of task creation. Flushes the created task description and runs a test to load it. + + :return: the path of the written .json task description + :rtype: `Path` + """ + if len(self.current_meta.train_samples) > 0 and set(self.current_meta.idx_to_class.values()) != set( + self.current_meta.class_occ.keys() + ): + raise RuntimeError("Inconsistent classes across idx_to_class and class_occ") + if self.current_meta.task_type == TaskType.CLASSIFICATION and sum(self.current_meta.class_occ.values()) != len( + self.current_meta.train_samples + ): + raise RuntimeError("Class occurrences are incorrect.") + if self.current_meta.name == "default": + raise RuntimeError("Task Creator was given no task name!") + path = self.fm.get_task_path(dset_path=self.dset_path, task_alias=self.current_meta.name) + if path.exists(): + raise FileExistsError(f"Overwriting meta info at {path} not supported!") + self.protocol(f"Finished as {self.current_meta.name}") + self.fm.write_task_description(path, self.current_meta) + # decide on existing split + if self.current_meta.train_samples: + split = DataSplit.TRAIN + elif self.current_meta.unlabeled_samples: + split = DataSplit.UNLABELLED + else: + split = DataSplit.TEST + self.current_meta = None # prohibit reuse + # check loading + logger.info(f"Testing the loading of {path}...") + with mml.core.scripts.utils.catch_time() as ds_timer: + ds = TaskDataset(root=path, split=split) + with mml.core.scripts.utils.catch_time() as sample_timer: + _ = ds[0] + logger.info( + f"Testing of {path} finished, dataset loading time was {ds_timer.elapsed:5.2f} seconds, " + f"sample loading time was {sample_timer.elapsed:5.2f} seconds." + ) + return path + + def auto_complete(self) -> Path: + """ + Shortcut for finishing task creation. + + :return: the task path as returned by :meth:`push_and_test`. + """ + if self._state == TaskCreatorState.DATA_FOUND: + self.split_folds() + if self._state == TaskCreatorState.FOLDS_SPLIT: + self.infer_stats() + if self._state == TaskCreatorState.STATS_SET: + return self.push_and_test() + raise InvalidTransitionError(f"Auto-complete not available with state {self._state}.") + + # TASK MODIFICATION + @implements_action(TaskCreatorActions.NONE) + def identity(self, *args) -> None: + """ + Dummy tag to create identical instances of a task. In contrast to naming the same task twice in the task_list, + which will load from the same .json task description the identity tagged version creates a fresh task + description. + + :param args: all args are ignored + :return: None + """ + self.protocol(f"Identity with {args}") + + @implements_action(TaskCreatorActions.SET_STATS) + def nested_validation(self, fold_str: str, new_folds_str: str = "5") -> None: + """ + This tag will create a nested task, useful for cross-validation techniques. It drops any previous test samples, + and re-declares the specified fold as new test data. Afterward, the remaining train samples are re-shuffled and + distributed into new folds according to the new_folds argument. + + :param str fold_str: the fold to be re-declared as test data + :param str new_folds_str: the number of new folds created from the remaining train data + :return: None + """ + # log + logger.info(f"Nesting data of task {self.current_meta.name} with {fold_str}.") + self.protocol(f"Nested data with fold {fold_str}.") + # check args + fold_int = int(fold_str) + new_folds_int = int(new_folds_str) + old_folds_n = len(self.current_meta.train_folds) + if fold_int < 0 or fold_int >= old_folds_n: + raise ValueError(f"Invalid fold specified: {fold_int}. Must be in range [0, {old_folds_n - 1}].") + if new_folds_int < 2: + raise ValueError(f"Must at least create 2 folds for the nested task. Was given {new_folds_int}.") + # to the shifting + train_ids = list( + chain(*[self.current_meta.train_folds[fold_ix] for fold_ix in range(old_folds_n) if fold_ix != fold_int]) + ) + test_ids = self.current_meta.train_folds[fold_int] + self.data = { + DataSplit.FULL_TRAIN: {s_id: self.current_meta.train_samples[s_id] for s_id in train_ids}, + DataSplit.TEST: {s_id: self.current_meta.train_samples[s_id] for s_id in test_ids}, + } + # update class occurrences + self.current_meta.class_occ = Counter( + [ + self.current_meta.idx_to_class[self.current_meta.train_samples[s_id][Modality.CLASS]] + for s_id in train_ids + ] + ) + self.split_folds(n_folds=new_folds_int, ensure_balancing=True, ignore_state=True) + + # ON THE FLY TAG SUPPORT (these are modification keywords in the name) + @staticmethod + def auto_create_tagged(full_alias: str, preprocessing: str = "none") -> Path: + # start with a plain task creator + creator = TaskCreator(Path("")) + if preprocessing != "none": + # there must be an existing base version of this tagged task, transfer this to the correct preprocessing + if "none" not in creator.fm.task_index[full_alias]: + raise TaskNotFoundError(f"No base task is available for {full_alias}.") + # load base task + rel_task_path = creator.fm.task_index[full_alias]["none"] + creator.dset_path = (creator.fm.data_path / rel_task_path).parent + creator.load_existent(task_path=creator.fm.data_path / rel_task_path) + # switch base path + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=UserWarning, module="mml.core.data_loading.file_manager") + creator.dset_path = creator.fm.get_dataset_path(raw_path=creator.dset_path, preprocessing=preprocessing) + # infer stats + creator.infer_stats() + creator.protocol(msg=f"Preprocessing transferred from base to {preprocessing}.") + return_path = creator.push_and_test() + return return_path + # second case, there is no base tagged task present yet, check for existing components + splitted = full_alias.split(mml.core.scripts.utils.TAG_SEP) + max_ix = -1 + for ix in range(len(splitted)): + prefix = mml.core.scripts.utils.TAG_SEP.join(splitted[: ix + 1]).strip() + if prefix in creator.fm.task_index.keys() and "none" in creator.fm.task_index[prefix]: + max_ix = ix + if max_ix == -1: + raise TaskNotFoundError(f"Alias {full_alias} can not be created, because no base was found!") + # load base task into creator + base = mml.core.scripts.utils.TAG_SEP.join(splitted[: max_ix + 1]).strip() + rel_task_path = creator.fm.task_index[base]["none"] + logger.debug(f"Auto creating tagged task {full_alias} from base {base} in preprocessing {preprocessing}.") + creator.dset_path = (creator.fm.data_path / rel_task_path).parent + creator.load_existent(task_path=creator.fm.data_path / rel_task_path) + # run tag processing on remaining tags + remaining_tags = full_alias.split(mml.core.scripts.utils.TAG_SEP)[max_ix + 1 :] + for tag_string in remaining_tags: + tag_string = tag_string.strip() + if "." in tag_string: + raise ValueError("make sure to avoid dot <.> in tags, underscore <_> is used as decimal separator.") + tag, *values = tag_string.split(mml.core.scripts.utils.ARG_SEP) + func = creator.map_tag(tag) + func(*values) + creator.current_meta.name += f"{mml.core.scripts.utils.TAG_SEP}{tag_string}" + # complete any remaining inference as well as testing and pushing + path = creator.auto_complete() + logger.info(f"Auto created {full_alias} from {base}.") + return path + + def map_tag(self, tag: str) -> Callable: + """ + Correct way to resolve a task name tag to the corresponding modifier method. + + :param str tag: a string that can be appended to a task name e.g. 'identity' (appended as '+identity') + :return: + """ + if tag not in TASK_CREATOR_TAG_MAP.keys(): + raise ValueError( + f"Tag presented ({tag}) was invalid! Valid keywords are: {list(TASK_CREATOR_TAG_MAP.keys())}" + ) + else: + return getattr(self, TASK_CREATOR_TAG_MAP[tag]) + + def verify_modality_entry( + self, modality: Modality, value: Any, idx_to_class: Dict[int, str], class_occ: Dict[str, int] + ) -> None: + """ + Extendable method to verify that the entries of a modality are well formatted. Extracts a potential verificator + from the global `MODALITY_VERIFIER_MAP` dictionary and runs the verificator. To support new modalities modify + this global dictionary. + + :param modality: + :param value: + :param idx_to_class: + :param class_occ: + :return: + """ + if modality not in MODALITY_VERIFIER_MAP: + logger.debug(f"Skipped verification of modality {modality}.") + return + verifier_func = MODALITY_VERIFIER_MAP[modality] + verifier_func(creator=self, value=value, idx_to_class=idx_to_class, class_occ=class_occ) + logger.debug(f"Verified modality {modality}.") + + +# this is the map that resolves tagged task aliases to the respective modifiers +# use the mml-tags plugin to enable more tags +TASK_CREATOR_TAG_MAP = {"identity": "identity", "nested": "nested_validation"} + + +def verify_class_modality( + creator: TaskCreator, value: Any, idx_to_class: Dict[int, str], class_occ: Dict[str, int] +) -> None: + if not isinstance(value, int): + raise TypeError(f"Provide int values for Modality.CLASS key instead of {type(value)}.") + if value not in idx_to_class: + raise ValueError(f"class value {value} not present in idx_to_class") + class_occ[idx_to_class[value]] += 1 + + +def verify_classes_modality( + creator: TaskCreator, value: Any, idx_to_class: Dict[int, str], class_occ: Dict[str, int] +) -> None: + if not isinstance(value, tuple): + raise TypeError(f"Provide tuple values for Modality.CLASSES key instead of {type(value)}.") + if any([element not in idx_to_class for element in value]): + raise ValueError(f"some class of {value} not present in idx_to_class") + for elem in value: + class_occ[idx_to_class[elem]] += 1 + + +def verify_softclasses_modality( + creator: TaskCreator, value: Any, idx_to_class: Dict[int, str], class_occ: Dict[str, int] +) -> None: + if not isinstance(value, tuple): + raise TypeError(f"Provide tuple values for Modality.SOFT_CLASSES key instead of " f"{type(value)}.") + if len(value) != len(idx_to_class): + ValueError(f"length of soft labels {value} does not match idx_to_class") + for elem_idx, elem in enumerate(value): + class_occ[idx_to_class[elem_idx]] += elem + + +def verify_value_modality( + creator: TaskCreator, value: Any, idx_to_class: Dict[int, str], class_occ: Dict[str, int] +) -> None: + if not isinstance(value, float): + raise TypeError(f"Provide float values for Modality.VALUE key instead of {type(value)}.") + if min(idx_to_class) > value or max(idx_to_class) < value: + raise ValueError(f"value {value} must be in bounds of idx_to_class (provide min/max)") + if value.is_integer() and class_occ: + # it might be possible that we can gather class occ + try: + class_occ[idx_to_class[int(value)]] += 1 + except KeyError: + warnings.warn( + f"Tried to create a class occurrence map for regression task, since " + f"discovered an integer as value, but value is not present in " + f"idx_to_class, value was {value}, will skip class occurrence gathering" + ) + class_occ.clear() # delete entries to prevent constant warnings + + +def verify_mask_modality( + creator: TaskCreator, value: Any, idx_to_class: Dict[int, str], class_occ: Dict[str, int] +) -> None: + if value == EMPTY_MASK_TOKEN: + # this is the special case of an empty mask + mask = np.zeros(shape=(1, 1), dtype=np.intc) + else: + if not isinstance(value, Path): + raise TypeError(f"Masks should be provided as paths, not {type(value)}.") + mask = cv2.imread(str(creator.dset_path / value), cv2.IMREAD_GRAYSCALE) + for pixel_val in np.unique(mask): + # skip the ignore value of 255 + if pixel_val == 255: + continue + if pixel_val not in idx_to_class: + raise ValueError(f"mask value {pixel_val} not in idx_to_class.") + class_occ[idx_to_class[pixel_val]] += 1 + + +MODALITY_VERIFIER_MAP = { + Modality.CLASS: verify_class_modality, + Modality.CLASSES: verify_classes_modality, + Modality.SOFT_CLASSES: verify_softclasses_modality, + Modality.VALUE: verify_value_modality, + Modality.MASK: verify_mask_modality, +} diff --git a/src/mml/core/data_preparation/utils.py b/src/mml/core/data_preparation/utils.py new file mode 100644 index 0000000..73aaa27 --- /dev/null +++ b/src/mml/core/data_preparation/utils.py @@ -0,0 +1,367 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import os +from enum import IntEnum +from pathlib import Path +from threading import Event, Thread +from typing import Callable, Dict, List, Optional, Tuple, Union + +import requests +import torch +from albumentations.pytorch import ToTensorV2 +from PIL import Image +from torch.utils.data import DataLoader +from tqdm import tqdm +from tqdm.contrib.logging import tqdm_logging_redirect + +import mml.core +from mml.core.data_loading.task_attributes import DataSplit, Modality, RGBInfo, Sizes +from mml.core.data_loading.task_dataset import TaskDataset +from mml.core.data_loading.task_description import SampleDescription +from mml.core.scripts.exceptions import InvalidTransitionError +from mml.core.scripts.utils import Singleton + +logger = logging.getLogger(__name__) + + +def download_file(path_to_store: Path, download_url: str, file_name: str) -> None: + """ + Downloads file and places it accordingly. Skips finished downloads. + + :param Path path_to_store: + :param str download_url: + :param str file_name: + :return: None + """ + if not path_to_store.exists() or not path_to_store.is_dir(): + raise ValueError(f"Invalid path {path_to_store}, must be existing dir.") + if (path_to_store / file_name).exists() and "wip_" != file_name[:4]: + logger.warning(f"File {file_name} already present in {path_to_store}. Skipping download!") + return + logger.info(f"Downloading {file_name} to {path_to_store}.") + # use a temporary file while downloading, so above test won't accept interrupted downloads + tmp_file_name = "wip_" + file_name + with requests.get(download_url, stream=True) as r: + r.raise_for_status() + total_size_in_bytes = int(r.headers.get("content-length", 0)) + # progress bar inspired by https://stackoverflow.com/questions/37573483/progress-bar-while-download-file-over-http-with-requests/37573701#37573701 + progress = tqdm(total=total_size_in_bytes, unit="iB", unit_scale=True) + with open(str(path_to_store / tmp_file_name), "wb") as f: + for chunk in r.iter_content(chunk_size=8192): + progress.update(len(chunk)) + f.write(chunk) + progress.close() + if total_size_in_bytes != 0 and progress.n != total_size_in_bytes: + logger.error(f"Something went wrong during download of {file_name}.") + # rename finished download to actual file name + (path_to_store / tmp_file_name).rename(path_to_store / file_name) + logger.info(f"Successfully downloaded {file_name} to {path_to_store}.") + + +def calc_means_stds_sizes( + task_path: Path, + means: bool = True, + stds: bool = True, + sizes: bool = True, + const_size: bool = False, + device: torch.device = torch.device("cuda"), +) -> Dict[str, Union[Sizes, RGBInfo]]: + """ + Calculates means, stds and/or sizes of a task. Requires at most 2 runs through the dataset. Might take some time. + + :param task_path: path to task .json file. + :param means: if means should be calculated + :param stds: if stds should be calculated + :param sizes: if sizes should be calculated + :param const_size: if images have constant size (allows for faster loading, if 'sizes' is True and finds constant + sizes, this is detected internally) + :param device: device to be used for computations + :return: dict with possible keys 'sizes', 'means', 'stds' and Sizes / RGBInfo values + """ + logger.info("Calculating mean, std and size. This may take a couple of minutes.") + ds = TaskDataset(root=task_path, split=DataSplit.FULL_TRAIN, transform=ToTensorV2()) + if len(ds) == 0: + # if task is primarily unlabeled we gather those stats + ds = TaskDataset(root=task_path, split=DataSplit.UNLABELLED, transform=ToTensorV2()) + info = {} + if sizes: + img_files = [ds.root.parent / sample[Modality.IMAGE] for sample in ds.samples] + min_height, max_height, min_width, max_width = 100000, 0, 100000, 0 + for file_path in tqdm(img_files, desc="Gathering sizes"): + # use Pillow since we only need lazy loading to gather size information + img = Image.open(file_path) + min_height = min(min_height, img.height) + max_height = max(max_height, img.height) + min_width = min(min_width, img.width) + max_width = max(max_width, img.width) + if const_size: + break + info["sizes"] = Sizes(min_height=min_height, max_height=max_height, min_width=min_width, max_width=max_width) + if min_height == max_height and min_width == max_width: + const_size = True + logger.debug(f"Sizes are {info['sizes']}.") + if means or stds: + loader = DataLoader(dataset=ds, batch_size=100 if const_size else 1) + counter = 0 + channel_sum = torch.zeros(3, dtype=torch.double, device=device) + channel_sq = torch.zeros(3, dtype=torch.double, device=device) + for batch in tqdm(loader, desc="Gathering mean and std"): + images = (batch[Modality.IMAGE.value] / 255).to(torch.double).to(device) + counter += images.size()[0] + channel_sum += images.mean(dim=[2, 3]).sum(dim=0) + channel_sq += images.square().mean(dim=[2, 3]).sum(dim=0) + _means = channel_sum / counter + _stds = torch.sqrt(channel_sq / (counter - 1) - (counter * _means.square() / (counter - 1))) + # _stds = torch.sqrt((channel_sq - (channel_sum.square() / counter)) / (counter - 1)) + if means: + info["means"] = RGBInfo(*_means.to(torch.float).cpu().numpy().tolist()) + if stds: + info["stds"] = RGBInfo(*_stds.to(torch.float).cpu().numpy().tolist()) + logger.debug(f"Means are {info['means']}. Stds are {info['stds']}.") + return info + + +def get_iterator_and_mapping_from_image_dataset( + root: Path, dup_id_flag: Optional[bool] = False, classes: Optional[List[str]] = None +) -> Tuple[List[SampleDescription], Dict[int, str]]: + """ + Utility func for the reoccurring case, that classification datasets are ordered as in + :class:`~torchvision.datasets.ImageFolder`. The iterator will store the file stem of the image as id. + + :param Path root: root path + :param Optional[bool] dup_id_flag: (optional) flag for same filenames in different classes + :param Optional[List[str]] classes: (optional) list defining classes, if not given any dir will be used as class + :return: data iterator and idx_to_class as used for TaskCreator.find_data + """ + if classes is None: + classes = sorted([p.name for p in root.iterdir() if p.is_dir()]) + else: + folders = [p.name for p in root.iterdir() if p.is_dir()] + assert all([cl in folders for cl in classes]), "some class folder is not existent" + idx_to_class = {classes.index(cl): cl for cl in classes} + data_iterator = [] + for class_folder in root.iterdir(): + assert class_folder.is_dir() + if class_folder.name not in classes: + continue + for img_path in class_folder.iterdir(): + if dup_id_flag: + data_iterator.append( + { + Modality.SAMPLE_ID: class_folder.name + img_path.stem, + Modality.IMAGE: img_path, + Modality.CLASS: classes.index(class_folder.name), + } + ) + else: + data_iterator.append( + { + Modality.SAMPLE_ID: img_path.stem, + Modality.IMAGE: img_path, + Modality.CLASS: classes.index(class_folder.name), + } + ) + return data_iterator, idx_to_class + + +def get_iterator_from_segmentation_dataset( + images_root: Path, masks_root: Path, path_matcher: Callable[[Path], Path] = lambda x: x +) -> List[SampleDescription]: + """ + Utility func for the reoccuring case, that segmentation datasets are ordered as follows: there are two separate + folders containing the images and labels respectively. There is also some similar structure / pattern in the naming + of these. The iterator will store the file stem of the image as id. + + :param images_root: root path of image data + :param masks_root: root path of mask data + :param path_matcher: (optional) function to get the (relative) mask path from the (relative) image path, relative + corresponds to the provided root paths, default value is the identity function + :return: data iterator as used for TaskCreator.find_data + """ + assert images_root.exists() and masks_root.exists(), f"{images_root=}, {masks_root=}" + unmatched_counter = 0 + data_iterator = [] + for root, _, files in os.walk(str(images_root)): + for file in files: + image_path = Path(root) / file + mask_path = masks_root / path_matcher(image_path.relative_to(images_root)) + if mask_path.exists(): + data_iterator.append( + { + Modality.SAMPLE_ID: str(image_path.relative_to(images_root)), + Modality.IMAGE: image_path, + Modality.MASK: mask_path, + } + ) + else: + logger.debug(f"unable to match {image_path=} to mask, was given {mask_path=}") + unmatched_counter += 1 + logger.info(f"Was able to match {len(data_iterator)} items, encountered {unmatched_counter} unmatchable images.") + return data_iterator + + +def get_iterator_from_unlabeled_dataset(root: Path) -> List[SampleDescription]: + """ + Utility func for the reoccurring case, that unlaballed data is simply organised in a single folder. The iterator + will store the file stem of the image as id. + + :param Path root: root path + :return: data iterator as used for TaskCreator.find_data + """ + data_iterator = [] + for img_path in root.iterdir(): + data_iterator.append( + { + Modality.SAMPLE_ID: img_path.stem, + Modality.IMAGE: img_path, + } + ) + return data_iterator + + +class TaskCreatorActions(mml.core.scripts.utils.StrEnum): + """ + Abstract action that can be done on a task creator. + """ + + FIND_DATA = "find_data" + LOAD = "load" + MODIFY = "modify" + SET_STATS = "set_stats" + SET_FOLDING = "set_folds" + FINISH = "finish" + NONE = "none" + + +class TaskCreatorState(IntEnum): + """ + Abstract states a task creator can be in. Default traversal path is: + INIT --find_data--> DATA_FOUND --set_folding--> FOLDS_SPLIT --infer/set_stats--> STATS_SET --finish--> FINISHED + """ + + INIT = 0 # default start state + DATA_FOUND = 1 # ensure data samples are read in (i.e. self.data is set) + FOLDS_SPLIT = 2 # ensure samples are stored and folds are split (e.g. self.current_meta.train_folds) + STATS_SET = 3 # ensure folds are split and means, stds and sizes are set in current_meta + FINISHED = 4 # ultimate state, creator has reached "end-of-life" + + def traverse(self, action: TaskCreatorActions) -> "TaskCreatorState": + """ + Implements the legal traversals of states and actions within a task creator. + + :param TaskCreatorActions action: The action that is tried to be applied on the current state. + :return: The follow-up state of the task creator. + """ + if self == TaskCreatorState.FINISHED: + raise InvalidTransitionError( + "TaskCreator already finished. It is considered better practice to create a " "new one." + ) + elif action == TaskCreatorActions.NONE: + return self + elif action == TaskCreatorActions.FIND_DATA: + return TaskCreatorState.DATA_FOUND + elif self == TaskCreatorState.INIT and action == TaskCreatorActions.LOAD: + return TaskCreatorState.STATS_SET + elif self >= TaskCreatorState.DATA_FOUND and action == TaskCreatorActions.SET_FOLDING: + return TaskCreatorState.FOLDS_SPLIT + elif self >= TaskCreatorState.FOLDS_SPLIT and action == TaskCreatorActions.SET_STATS: + return TaskCreatorState.STATS_SET + elif self >= TaskCreatorState.STATS_SET and action == TaskCreatorActions.FINISH: + return TaskCreatorState.FINISHED + else: + raise InvalidTransitionError(f"Invalid traversal from {self} with action {action}.") + + +class WIPBar(Singleton): + """ + A singleton class that shows a loading loop managed by a thread (e.g. while data is copied). + Description can be updated during loading and in the end will print either a success or failure message, + depending on whether an exception was raised. Exception handling can be done either inside or outside + the context. Does not interfere with itself if used in a nested fashion, but the user + is responsible for updating the description after each inner loop closes. + + Usage: + + .. code-block:: python + + with WIPBar() as bar: + bar.desc = 'Copying' + shutil.copytree(...) + bar.desc = 'Extracting' + zipfile ... + # continue without WIPBar + + """ + + def __init__(self): + self.desc = None + self.success_message = None + self.failed_message = None + self.symbols = ["⣾", "⣷", "⣯", "⣟", "⡿", "⢿", "⣻", "⣽"] + # alternative: ['▘', '▌', '▙', '█', '▟', '▐', '▝', ' '] + self.failed = False + self.__bar = None + self.__counter = 0 # counts open nestings + self.__StopEvent = Event() # used to signal to end the thread + self.__thread: Optional[Thread] = None # this thread will update the bar text + self.__context_mgr = None # this mgr keeps track of the logging redirect + self.reset_messages() + + def __enter__(self): + # whenever we enter we expect to reset previous failures and kill events + self.failed = False + self.__StopEvent.clear() + self.__counter += 1 + # create bar and handle logging + if self.__bar is None: + self.__context_mgr = tqdm_logging_redirect(bar_format="{elapsed} {desc}", desc="", leave=True) + self.__bar: tqdm = self.__context_mgr.__enter__() + # start thread if not running yet + if self.__thread is None: + self.__thread = Thread(target=self.__update, daemon=True) + self.__thread.start() + return self + + def reset_messages(self): + self.desc = "" + self.success_message = "✅ Success" + self.failed_message = "❌ Failed" + + def __exit__(self, exc_type, exc_val, exc_tb): + self.__counter -= 1 + # check if an exception was raised + if (exc_tb, exc_val, exc_tb) != (None, None, None): + self.failed = True + if self.__counter == 0: + # signal the thread to terminate + self.__StopEvent.set() + # and wait to terminate + if self.__thread: + self.__thread.join() + # reset thread and bar + self.__thread = None + self.__bar.close() + self.__bar = None + self.reset_messages() + self.__context_mgr.__exit__(exc_type, exc_val, exc_tb) + + def __update(self): + """ + Implements the loop inside the thread to show a repeating pattern of symbols. + """ + i = 0 + while True: + i = (i + 1) % len(self.symbols) + self.__bar.set_description_str(self.symbols[i] + " " + self.desc) + # check for interruption and exit if signaled + if self.__StopEvent.wait(0.2): + break + if self.failed: + self.__bar.set_description_str(self.desc + " " + self.failed_message) + else: + self.__bar.set_description_str(self.desc + " " + self.success_message) diff --git a/src/mml/core/models/__init__.py b/src/mml/core/models/__init__.py new file mode 100644 index 0000000..2c99d0c --- /dev/null +++ b/src/mml/core/models/__init__.py @@ -0,0 +1,7 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# from .model_specs import ModelSpecifications diff --git a/src/mml/core/models/lightning_single_frame.py b/src/mml/core/models/lightning_single_frame.py new file mode 100644 index 0000000..c921e74 --- /dev/null +++ b/src/mml/core/models/lightning_single_frame.py @@ -0,0 +1,565 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import warnings +from typing import Any, Dict, List, Optional, Tuple + +import hydra.utils +import lightning +import numpy as np +import torch.nn +from hydra.errors import InstantiationException +from hydra.utils import instantiate +from lightning.pytorch.callbacks import BatchSizeFinder +from lightning.pytorch.loggers import TensorBoardLogger +from lightning.pytorch.tuner.lr_finder import _LRCallback +from lightning.pytorch.utilities import rank_zero_only +from omegaconf import DictConfig +from torchmetrics import Metric, MetricCollection +from torchmetrics.classification import MulticlassConfusionMatrix +from torchmetrics.wrappers import BootStrapper + +from mml.core.data_loading.augmentations.kornia import KorniaAugmentationModule +from mml.core.data_loading.lightning_datamodule import MultiTaskDataModule +from mml.core.data_loading.task_attributes import Modality, TaskType +from mml.core.data_loading.task_dataset import TaskDataset +from mml.core.data_loading.task_struct import TaskStruct +from mml.core.models.merger import PredictionMerger +from mml.core.scripts.exceptions import MMLMisconfigurationException +from mml.core.scripts.utils import LearningPhase +from mml.core.visualization.cm import render_confusion_matrix +from mml.core.visualization.predictions import render_predictions +from mml.core.visualization.utils import undo_image_normalization + +logger = logging.getLogger(__name__) + +# determines the config parts in loss and metrics that correspond to the task types +CONFIGS_ROUTES = { + TaskType.CLASSIFICATION: "cls", + TaskType.MULTILABEL_CLASSIFICATION: "mlcls", + TaskType.SEMANTIC_SEGMENTATION: "seg", + TaskType.REGRESSION: "reg", +} + + +class SingleFrameLightningModule(lightning.LightningModule): + """ + The default MML lightning module supporting frame wise training and inference. + """ + + def __init__(self, task_structs: List[TaskStruct], cfg: DictConfig, weights: Optional[List[float]] = None): + super(SingleFrameLightningModule, self).__init__() + # save hyperparameters + self.save_hyperparameters() + self.cfg = cfg + if weights is None: + weights = [1.0] * len(task_structs) + if len(task_structs) != len(weights): + raise ValueError(f"Number of weights ({len(weights)} does not match number of tasks {len(task_structs)}.") + self.weights = torch.as_tensor(weights) + self.task_structs = {struct.name: struct for struct in task_structs} + self.targets: Dict[str, str] = { # type: ignore + name: struct.target.value for name, struct in self.task_structs.items() if struct.target is not None + } + # construct model + self.model = hydra.utils.instantiate(self.cfg.arch) + for struct in self.task_structs.values(): + self.model.add_head(task_struct=struct) + # construct criterion + self.criteria = self.get_criteria() + # construct metrics + metric_lists = {name: self.get_metrics(struct) for name, struct in self.task_structs.items()} + metric_collections = {name: MetricCollection(metrics) for name, metrics in metric_lists.items()} + for metric_collection in metric_collections.values(): + metric_collection.persistent(mode=True) + self.train_metrics = torch.nn.ModuleDict( + { + task_name: metric_collections[task_name].clone(prefix=f"train/{task_name}/") + for task_name in self.task_structs + } + ) + self.val_metrics = torch.nn.ModuleDict( + { + task_name: metric_collections[task_name].clone(prefix=f"val/{task_name}/") + for task_name in self.task_structs + } + ) + if self.cfg.metrics.bootstrap: + # wrap in bootstrapper, needs to proceed with dict to avoid duplicate naming of bootstrapper in collection + wrapped_metric_lists = { + name: {met._get_name(): BootStrapper(met, num_bootstraps=self.cfg.metrics.bootstrap) for met in metrics} + for name, metrics in metric_lists.items() + } + wrapped_collections = {name: MetricCollection(metrics) for name, metrics in wrapped_metric_lists.items()} + for metric_collection in wrapped_collections.values(): + metric_collection.persistent(mode=True) + self.test_metrics = torch.nn.ModuleDict( + { + task_name: wrapped_collections[task_name].clone(prefix=f"test/{task_name}/") + for task_name in self.task_structs + } + ) + else: + self.test_metrics = torch.nn.ModuleDict( + { + task_name: metric_collections[task_name].clone(prefix=f"test/{task_name}/") + for task_name in self.task_structs + } + ) + # this attribute is used for auto_lr_finder of lightning + self.lr = None + # create confusion matrices + self.train_cms = torch.nn.ModuleDict() + self.val_cms = torch.nn.ModuleDict() + self.test_cms = torch.nn.ModuleDict() + if self.cfg.logging.cm: + for name, struct in self.task_structs.items(): + if struct.task_type not in [TaskType.SEMANTIC_SEGMENTATION, TaskType.CLASSIFICATION]: + warnings.warn(f"{struct.task_type} does not support logging.cm configuration.") + else: + cm = MulticlassConfusionMatrix(num_classes=struct.num_classes, normalize=None) + self.train_cms[name] = cm + self.val_cms[name] = cm.clone() + self.test_cms[name] = cm.clone() + # mapping of model heads, allows to infer on tasks other than trained for + self._task_to_head_mapping = {task_name: task_name for task_name in self.task_structs} + # fix for multi-dataloader loss aggregation + self.loss_list = [] + # test time augmentation + if len(self.cfg.tta.variations) > 0: + self.tta_pipelines = { + key: KorniaAugmentationModule( + device="gpu", cfg=pipeline, is_first=False, is_last=False, means=None, stds=None + ) + for key, pipeline in self.cfg.tta.variations.items() + } + else: + self.tta_pipelines = {} + + def forward(self, x: torch.Tensor) -> Dict[str, torch.Tensor]: + """ + Default forward method, this is not used from within pytorch lightning itself. It is provided to the outside + as inference option. + + :param torch.Tensor x: plain batch or single image (no modality dict!) + :return: dict with one entry per model head and corresponding prediction logits + """ + return self.model(x) + + def forward_features(self, x: torch.Tensor) -> torch.Tensor: + """ + Special forward method generating embeddings for images, this is not used from within pytorch lightning itself. + It is provided to the outside as embedding generator option. + + :param torch.Tensor x: plain batch or single image (no modality dict!) + :return: tensor of shape num_samples x num_features # TODO verify + """ + return self.model.forward_features(x) + + @property + def is_tuning(self) -> bool: + """ + Checks if the model is currently being tuned, which allows to modify some operations. + """ + return bool( + [cb for cb in self.trainer.callbacks if isinstance(cb, BatchSizeFinder) or isinstance(cb, _LRCallback)] + ) + + def push_and_sort( + self, + batch: Dict[str, Dict[str, torch.Tensor]], + raise_on_error: bool = True, + perform_tta: bool = False, + ) -> Tuple[Dict[str, torch.Tensor], Dict[str, torch.Tensor]]: + """ + The lightning internal used "forward" method for dict based dataloaders. It deals with the dict input of the + combined dataloader in any mode but "sequential" and resolves the modalities as well as tasks. + + :param Dict[str, Dict[str, torch.Tensor]] batch: a batch of format {task_name: {modality_name: tensor_values}} + :param bool raise_on_error: if False accepts missing targets in the batch (e.g. during test step) + :param bool perform_tta: if True performs multiple forward passes with augmented batch variants and merges them + :return: a tuple consisting of logits dict and targets dict which with keys for each task + :rtype: Tuple[Dict[str, torch.Tensor], Dict[str, torch.Tensor]] + """ + if perform_tta and len(self.tta_pipelines) > 0: + # only augment images through TTA + task_imgs = { + task: {Modality.IMAGE.value: batch[task][Modality.IMAGE.value]} for task in batch if batch[task] + } + logits = {} + for task in task_imgs: + merger = PredictionMerger(mode=self.cfg.tta.mode, modality=Modality.from_str(self.targets[task])) + for pipeline in self.tta_pipelines.values(): + variation = pipeline(task_imgs[task]) + predicted_logits = self.model(variation[Modality.IMAGE.value])[self._task_to_head_mapping[task]] + if self.targets[task] in [Modality.MASK.value, Modality.BBOX.value, Modality.KEYPOINTS.value]: + # if necessary undo geometric variation + predicted_logits = pipeline.inverse({self.targets[task]: predicted_logits}) + merger.update(predicted_logits) + logits[task] = merger.compute() + else: + logits = { + task: self.model(batch[task][Modality.IMAGE.value])[self._task_to_head_mapping[task]] + for task in batch + if batch[task] + } + try: + targets = {task: batch[task][self.targets[task]] for task in logits if task in self.targets} + except KeyError: + if raise_on_error: + raise + else: + targets = None + return logits, targets + + def reformat_batch_from_sequential( + self, batch: Dict[str, torch.Tensor], dataloader_idx: int + ) -> Dict[str, Dict[str, torch.Tensor]]: + """ + Prepares the batch format of "sequential" mode combined loader to default format. + + :param Dict[str, torch.Tensor] batch: a batch of format {modality_name: tensor_values} + :param int dataloader_idx: index of the dataloader + :return: a batch of format {task_name: {modality_name: tensor_values}} + :rtype: Dict[str, Dict[str, torch.Tensor]] + """ + datamodule: MultiTaskDataModule = self.trainer.datamodule + task_name = datamodule.task_structs[dataloader_idx].name + return {task_name: batch} + + @rank_zero_only + def log_images_prediction_reference( + self, + batch: Dict[str, Dict[str, torch.Tensor]], + logits: Dict[str, torch.Tensor], + targets: Dict[str, torch.Tensor], + phase: LearningPhase, + ) -> None: + """ + Logging utility for showing image examples together with reference and model predictions. + + :param Dict[str, Dict[str, torch.Tensor]] batch: batch as provided by dataloader (batch[task][modality]) + :param Dict[str, torch.Tensor] logits: logits as provided by model :meth:step + :param Dict[str, torch.Tensor] targets: targets as provided by :meth:step + :param LearningPhase phase: may be either train, val or test, used to access underlying + :class:~mml.core.data_loading:task_dataset:TaskDataset and as a logging prefix + :return: + """ + if self.is_tuning: + return + datamodule: MultiTaskDataModule = self.trainer.datamodule + images = {task: batch[task][Modality.IMAGE.value] for task in batch} + for task in batch: + # catch empty task batch (e.g. during validation) + if batch[task] is None: + continue + # reduce plotting number + n = min(self.cfg.logging.samples, images[task].size(dim=0)) + if n <= 0: + return + images = images[task][:n] + logits = logits[task][:n] + targets = targets[task][:n] + # undo image normalization + mean, std = datamodule.get_image_normalization(struct=self.task_structs[task]) + raw_images = undo_image_normalization(images=images, means=mean, stds=std) + # render figure + fig = render_predictions( + raw_images=raw_images, + logits=logits, + targets=targets, + classes=datamodule.task_datasets[task][phase].classes, + task_type=self.task_structs[task].task_type, + ) + # log figure + if isinstance(self.logger, TensorBoardLogger): + self.logger.experiment.add_figure( + tag=f"{phase}/{task}/prediction", figure=fig, global_step=self.trainer.global_step, close=True + ) + else: + logger.error(f"Unable to log prediction examples for {type(self.logger)} logger type.") + break + + def compute_and_log_loss( + self, logits: Dict[str, torch.Tensor], targets: Dict[str, torch.Tensor], phase: LearningPhase + ) -> torch.Tensor: + # generate loss tensor hardware-agnostic + present_task = next(iter(logits.keys())) + loss = torch.zeros(1).to(logits[present_task]) + # compute loss across tasks, incorporating task weights + n_tasks = 0 + for task_name, weight in zip(self.task_structs, self.weights): + if task_name in targets and targets[task_name].size(dim=0) > 0: + n_tasks += 1 + task_loss = self.criteria[task_name](logits[task_name], targets[task_name]) + loss += weight * task_loss + self.log( + f"{phase.value}/{task_name}/loss", + task_loss, + batch_size=logits[task_name].size(0), + add_dataloader_idx=False, + ) + loss /= n_tasks # for fair comparison between train (all tasks present in batch) and val/test (single task) + if phase == LearningPhase.TRAIN: + self.log(f"{phase.value}/loss", loss, batch_size=sum([b.size(0) for b in logits.values()]), prog_bar=True) + # no add_dataloader_idx=False possible here, we log the aggregated loss in on_validation/test_epoch_end + # see https://github.com/Lightning-AI/pytorch-lightning/issues/11126#issuecomment-1504866597 + else: + self.loss_list.append(loss.item()) + return loss + + def compute_and_log_metrics( + self, logits: Dict[str, torch.Tensor], targets: Dict[str, torch.Tensor], phase: LearningPhase + ): + task_metrics = { + LearningPhase.TRAIN: self.train_metrics, + LearningPhase.VAL: self.val_metrics, + LearningPhase.TEST: self.test_metrics, + }[phase] + for task in logits: + if self.cfg.metrics.bootstrap and phase == LearningPhase.TEST: + # logging of bootstrapped metrics requires distinction between mean and std, only updating here and + # logging on test epoch end + task_metrics[task].update(logits[task], targets[task]) + else: + # default metric logging + task_metrics[task](logits[task], targets[task]) + task_metrics[task](logits[task], targets[task]) + self.log_dict(task_metrics[task], batch_size=logits[task].size(0), add_dataloader_idx=False) + + def _generic_step( + self, batch: Dict[str, Dict[str, torch.Tensor]], batch_idx: int, phase: LearningPhase + ) -> torch.Tensor: + """ + High level computational procedures during a batch passing. + + :param Dict[str, Dict[str, torch.Tensor]] batch: a batch as provided by `MultiTaskDataModule` + :param int batch_idx: the index of the batch within one epoch + :param LearningPhase phase: the current phase of the step + :return: the loss computed on the batch + """ + # pass forward, do TTA only during testing + logits, targets = self.push_and_sort(batch, raise_on_error=True, perform_tta=phase == LearningPhase.TEST) + # compute loss + loss = self.compute_and_log_loss(logits, targets, phase=phase) + # compute metrics + self.compute_and_log_metrics(logits=logits, targets=targets, phase=phase) + # log predictions of first batch from each epoch + if batch_idx == 0: + self.log_images_prediction_reference(batch=batch, logits=logits, targets=targets, phase=phase) + phase_cms = { + LearningPhase.TRAIN: self.train_cms, + LearningPhase.VAL: self.val_cms, + LearningPhase.TEST: self.test_cms, + }[phase] + for task in self.task_structs: + if task in self.train_cms: + phase_cms[task].update(logits[task], targets[task]) + # return loss to pass backward by lightning + return loss + + def training_step(self, batch: Dict[str, Dict[str, torch.Tensor]], batch_idx: int) -> torch.Tensor: + return self._generic_step(batch=batch, batch_idx=batch_idx, phase=LearningPhase.TRAIN) + + def validation_step(self, batch: Dict[str, torch.Tensor], batch_idx: int, dataloader_idx: int = 0) -> torch.Tensor: + batch = self.reformat_batch_from_sequential(batch=batch, dataloader_idx=dataloader_idx) + return self._generic_step(batch=batch, batch_idx=batch_idx, phase=LearningPhase.VAL) + + def test_step(self, batch: Dict[str, torch.Tensor], batch_idx: int, dataloader_idx: int = 0) -> torch.Tensor: + batch = self.reformat_batch_from_sequential(batch=batch, dataloader_idx=dataloader_idx) + return self._generic_step(batch=batch, batch_idx=batch_idx, phase=LearningPhase.TEST) + + def log_confusion_matrix(self, phase: LearningPhase) -> None: + """ + Logging utility for showing the confusion matrix of each epoch. Each logging also resets the cm in preparation + for the next epoch. + + :param LeaningPhase phase: currently active learning phase to separate train, val and test + :return: + """ + # check config + if not self.cfg.logging.cm or self.is_tuning: + return + + phase_cms = { + LearningPhase.TRAIN: self.train_cms, + LearningPhase.VAL: self.val_cms, + LearningPhase.TEST: self.test_cms, + }[phase] + for task in self.task_structs: + if task not in phase_cms: + continue + # compute and reset cm + cm = phase_cms[task].compute() + phase_cms[task].reset() + # render figure + datamodule: MultiTaskDataModule = self.trainer.datamodule + fig = render_confusion_matrix( + cm=cm.detach().cpu().numpy(), classes=datamodule.task_datasets[task][phase].classes + ) + # log figure + if isinstance(self.logger, TensorBoardLogger): + self.logger.experiment.add_figure( + tag=f"{phase}/{task}/cm", figure=fig, global_step=self.trainer.global_step, close=True + ) + else: + logger.error(f"Unable to log prediction examples for {type(self.logger)} logger type.") + break + + def on_train_epoch_end(self) -> None: + self.log_confusion_matrix(phase=LearningPhase.TRAIN) + + def on_validation_epoch_end(self) -> None: + self.log_confusion_matrix(phase=LearningPhase.VAL) + avg_loss = np.mean(self.loss_list) # we ignore weighing by batch_size for now + self.log("val/loss", avg_loss, add_dataloader_idx=False) + if isinstance(self.logger, TensorBoardLogger): + # for hparams view in tensorboard + # (see also https://lightning.ai/docs/pytorch/stable/extensions/logging.html#logging-hyperparameters) + self.log("hp_metric", avg_loss, add_dataloader_idx=False) + self.loss_list.clear() + + def on_test_epoch_end(self) -> None: + self.log_confusion_matrix(phase=LearningPhase.TEST) + avg_loss = np.mean(self.loss_list) # we ignore weighing by batch_size for now + self.log("test/loss", avg_loss, add_dataloader_idx=False) + self.loss_list.clear() + if self.cfg.metrics.bootstrap: + # actual logging of values + for task, collection in self.test_metrics.items(): + try: + self.log_dict(collection.compute(), add_dataloader_idx=False) + collection.reset() + except ValueError: + logger.info( + f"No metrics available for {task}. This may be due to evaluatio.n on a different task " + f"or previous multitask model being evaluated solely on one task" + ) + + def predict_step(self, batch: Dict[str, torch.Tensor], batch_idx: int, dataloader_idx: int = 0) -> Any: + # if only a single task is used for sequential loading no dataloader_idx will be passed, so default is required + batch = self.reformat_batch_from_sequential(batch=batch, dataloader_idx=dataloader_idx) + logits, targets = self.push_and_sort(batch, raise_on_error=False, perform_tta=True) + try: + sample_ids = {task: batch[task]["sample_id"] for task in batch} + except KeyError: + warnings.warn("No image ids found during prediction") + sample_ids = None + return { + task: { + "logits": logits[task], + "targets": targets[task] if targets is not None else None, + "sample_ids": sample_ids[task], + } + for task in batch + if batch[task] + } + + def configure_optimizers(self): + # docstring is provided by lighting + # instantiate optimizer (and lr_scheduler if present) from cfg + if self.lr: + logger.info(f"Using learning rate {self.lr}.") + optim = instantiate(self.cfg.optimizer, lr=self.lr, params=self.parameters()) + else: + optim = instantiate(self.cfg.optimizer, params=self.parameters()) + if self.cfg.lr_scheduler["_target_"]: + lr_scheduler = instantiate(self.cfg.lr_scheduler, optimizer=optim) + return {"optimizer": optim, "lr_scheduler": lr_scheduler, "monitor": "val/loss"} + return optim + + def get_metrics(self, struct: TaskStruct) -> List[Metric]: + """ + Generates a collection of metrics, suited for the given task, based on the configs. + + :param TaskStruct struct: struct of the task + :return: a list of torchmetrics metrics + :rtype: List[torchmetrics.Metric] + """ + # check task type + route = CONFIGS_ROUTES[struct.task_type] + # create Metrics + mets = [] + for entry in self.cfg.metrics[route]: + if "num_classes" in entry: + mets.append(hydra.utils.instantiate(entry, num_classes=struct.num_classes)) + else: + mets.append(hydra.utils.instantiate(entry)) + return mets + + def get_criteria(self) -> torch.nn.ModuleDict: + """ + Generates the criteria modules. These correspond to the loss functions of each task. This is run once at the + initialisation of the lightning module. + + :return: a dict of task to loss module + """ + criteria = {} + for name, struct in self.task_structs.items(): + criterion_cfg = self.cfg.loss[CONFIGS_ROUTES[struct.task_type]] + if self.cfg.loss.class_weights: + if self.cfg.sampling.balanced: + warnings.warn( + "provided criterion class weights but balanced sampling is activated please ensure" + " this behaviour is intended!" + ) + if self.cfg.loss.auto_activate_weighing: + raise MMLMisconfigurationException( + "provided criterion class weights but auto_activate_weighing is enabled." + ) + criteria[name] = instantiate(criterion_cfg, weight=torch.tensor(self.cfg.loss.class_weights)) + elif not self.cfg.sampling.balanced and self.cfg.loss.auto_activate_weighing: + logger.info("Since sampling is unbalanced will try to auto activate loss weights for classes.") + classes = TaskDataset.get_classes_from_idx_dict(struct.idx_to_class) + class_weights = torch.tensor(max(struct.class_occ.values())) / torch.tensor( + [struct.class_occ[cl] for cl in classes], dtype=torch.float + ) + try: + criteria[name] = instantiate(criterion_cfg, weight=class_weights) + except InstantiationException as err: + logger.debug(err) + logger.warning( + f"Criterion {criterion_cfg['_target_']} does not accept weights. Will " + f"fall back to ignoring class imbalances." + ) + criteria[name] = instantiate(criterion_cfg) + else: + criteria[name] = instantiate(criterion_cfg) + return torch.nn.ModuleDict(criteria) + + @staticmethod + def get_monitor_metric() -> Tuple[str, str]: + """Returns the monitoring metric. This is used by Lightning to determine best model after training.""" + return "val/loss", "min" + + def setup_redirection(self, head: str, task: str) -> None: + """ + Sets up a redirection to use model head "old" for data from task "new". This also includes preparation to + use metrics and cm logging with "new" task name. + + :param str head: the existing model head name (likely learned before) + :param str task: the new task that shall be passed through the old head + :return: + """ + logger.info(f"Redirecting data of task {task} through model head {head}.") + if head not in self.task_structs: + raise ValueError(f"Task {head} has no existing head.") + if task in self.train_metrics: + raise ValueError(f"Task {task} has already been redirected!") + # data redirection + self._task_to_head_mapping[task] = head + # setup cm + for phase_cms in [self.train_cms, self.val_cms, self.test_cms]: + if head in phase_cms: + phase_cms[task] = phase_cms[head].clone() + # setup metric + for phase_metrics in [self.train_metrics, self.val_metrics, self.test_metrics]: + if head in phase_metrics: + phase_metrics[task] = phase_metrics[head].clone() + phase_metrics[task].prefix = phase_metrics[task].prefix.replace(f"/{head}/", f"/{task}/") + # setup target + self.targets[task] = self.targets[head] diff --git a/src/mml/core/models/merger.py b/src/mml/core/models/merger.py new file mode 100644 index 0000000..1ddd370 --- /dev/null +++ b/src/mml/core/models/merger.py @@ -0,0 +1,42 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import torch + +from mml.core.data_loading.task_attributes import Modality +from mml.core.scripts.decorators import beta + + +@beta("Test Time Augmentation and PredictionMerger are in beta.") +class PredictionMerger: + def __init__(self, mode: str, modality: Modality): + """Merges the logits of predictions by variations introduced via test time augmentation (TTA).""" + if mode not in ["mean"]: + raise ValueError(f"PredictionMerger mode {mode} is not supported") + self.mode = mode + self.modality = modality + self.n = 0 + self.merged = None + + def update(self, prediction: torch.Tensor) -> None: + """Add a prediction to the merger.""" + self.n += 1 + if self.merged is None: + self.merged = prediction + elif self.mode == "mean": + if self.modality in [Modality.CLASS, Modality.SOFT_CLASSES, Modality.CLASSES, Modality.MASK]: + self.merged += prediction + else: + raise ValueError(f"PredictionMerger mode {self.mode} does not support modality {self.modality}") + + def compute(self) -> torch.Tensor: + """Let the merger compute the merged result.""" + if self.merged is None: + raise RuntimeError("PredictionMerger has seen no predictions") + if self.mode == "mean": + return self.merged / self.n + else: + raise RuntimeError(f"PredictionMerger mode {self.mode} is not supported") diff --git a/src/mml/core/models/smp.py b/src/mml/core/models/smp.py new file mode 100644 index 0000000..cf03b03 --- /dev/null +++ b/src/mml/core/models/smp.py @@ -0,0 +1,89 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +from typing import Any, Dict, Optional + +import segmentation_models_pytorch as smp +import torch +import torch.nn as nn +from segmentation_models_pytorch.base import ClassificationHead, SegmentationHead, initialization + +from mml.core.data_loading.task_attributes import RGBInfo, TaskType +from mml.core.models.torch_base import BaseHead, BaseModel + +logger = logging.getLogger(__name__) + + +class SMPGenericModel(BaseModel): + def __init__(self, **kwargs): + self.arch_name: Optional[str] = None # architecture, set during _init_model + self.encoder_name: Optional[str] = None # encoder, set during _init_model + self.weights: Optional[str] = None # encoder pretraining weights, set during _init_model + self.feature_channels: Optional[int] = None # encoder output size, set during _init_model + self.out_channels: Optional[int] = None # decoder output size, set during _init_model + super(SMPGenericModel, self).__init__(**kwargs) + # only used for feature extraction + self.pooling = nn.AdaptiveAvgPool2d(1) + + def forward(self, x: torch.Tensor) -> Dict[str, torch.Tensor]: + features = self.backbone.encoder(x) + decoder_output = self.backbone.decoder(*features) + return { + name: head(decoder_output if head.task_type == TaskType.SEMANTIC_SEGMENTATION else features[-1]) + for name, head in self.heads.items() + } + + def forward_features(self, x: torch.Tensor) -> torch.Tensor: + return self.pooling(self.backbone.encoder(x)[-1]).squeeze(3).squeeze(2) + + def _init_model(self, arch: str, weights: Optional[str], encoder: str = "resnet34", **kwargs: Any) -> None: + model = smp.create_model( + arch=arch, + encoder_name=encoder, + encoder_weights=weights, + in_channels=3, + classes=1, # default segmentation head will be discarded + ) + settings = smp.encoders.encoders[encoder]["pretrained_settings"][weights if weights else "imagenet"] + self.input_size = settings.get("input_size") + if weights: + self.required_mean = RGBInfo(*settings.get("mean")) + self.required_std = RGBInfo(*settings.get("std")) + self.arch_name = arch + self.encoder_name = encoder + self.weights = weights + self.backbone = model + self.feature_channels = self.backbone.encoder.out_channels[-1] + self.out_channels = self.backbone.segmentation_head[1].in_channels + + def _create_head(self, task_type: TaskType, num_classes: int, **kwargs: Any) -> BaseHead: + return SMPHead( + task_type=task_type, + num_classes=num_classes, + num_features=self.out_channels if task_type == TaskType.SEMANTIC_SEGMENTATION else self.feature_channels, + ) + + def supports(self, task_type: TaskType) -> bool: + """SMP support classification and segmentation tasks.""" + return task_type in [ + TaskType.CLASSIFICATION, + TaskType.MULTILABEL_CLASSIFICATION, + TaskType.SEMANTIC_SEGMENTATION, + ] + + +class SMPHead(BaseHead): + def __init__(self, task_type: TaskType, num_classes: int, num_features: int): + super().__init__(task_type=task_type, num_classes=num_classes) + if task_type == TaskType.SEMANTIC_SEGMENTATION: + self.head = SegmentationHead(in_channels=num_features, out_channels=num_classes, activation="softmax2d") + else: + self.head = ClassificationHead(in_channels=num_features, classes=num_classes) + initialization.initialize_head(self.head) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.head(x) diff --git a/src/mml/core/models/timm.py b/src/mml/core/models/timm.py new file mode 100644 index 0000000..d760fbb --- /dev/null +++ b/src/mml/core/models/timm.py @@ -0,0 +1,79 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from typing import Any, Dict, Optional + +import timm +import timm.data +import torch +import torch.nn as nn +from huggingface_hub.utils import HfHubHTTPError + +from mml.core.data_loading.task_attributes import RGBInfo, TaskType +from mml.core.models.torch_base import BaseHead, BaseModel + + +class TimmGenericModel(BaseModel): + def __init__(self, **kwargs): + self.out_channels: Optional[int] = None # number of backbone output features, set during _init_model + self.name: str = kwargs["name"] # backbone name + self.drop_rate: float = kwargs["drop_rate"] # heads dropout rate + super().__init__(**kwargs) # init requires all kwargs to be stored + + def forward_features(self, x: torch.Tensor) -> torch.Tensor: + return self.backbone(x) + + def forward(self, x: torch.Tensor) -> Dict[str, torch.Tensor]: + features = self.backbone(x) # type: ignore[union-attr] + return {name: head(features) for name, head in self.heads.items()} + + def _init_model(self, name: str, pretrained: bool, drop_rate: float) -> None: + try: + self.backbone = timm.create_model( + model_name=name, + pretrained=pretrained, + num_classes=0, # create heads individually + in_chans=3, # maybe support other channel nums in future + ) + except HfHubHTTPError: + raise RuntimeError( + "Huggingface hub appears to be down, you may check: https://status.huggingface.co/ " + "to re-assure. If the specified backbone has been loaded before you may prepend " + "HF_HUB_OFFLINE=1 to your mml call (or to your environment variables via " + "export HF_HUB_OFFLINE=1) and try to rerun." + ) + if pretrained: + cfg = timm.data.resolve_data_config(model=self.backbone) + self.required_mean = RGBInfo(*cfg["mean"]) + self.required_std = RGBInfo(*cfg["std"]) + self.input_size = cfg["input_size"] + else: + self.input_size = self.backbone.default_cfg["input_size"] + self.out_channels = self.backbone.num_features + + def _create_head(self, task_type: TaskType, num_classes: int, **kwargs: Any) -> BaseHead: + return TimmHead( + task_type=task_type, num_classes=num_classes, num_features=self.out_channels, drop_rate=self.drop_rate + ) + + def supports(self, task_type: TaskType) -> bool: + """TimmModel support classification tasks.""" + return task_type in [TaskType.CLASSIFICATION, TaskType.MULTILABEL_CLASSIFICATION, TaskType.REGRESSION] + + +class TimmHead(BaseHead): + def __init__(self, task_type: TaskType, num_classes: int, num_features: int, drop_rate: float): + super().__init__(task_type=task_type, num_classes=num_classes) + self.drop = nn.Dropout(drop_rate) + # only a single head for regression tasks + n_heads = 1 if task_type == TaskType.REGRESSION else num_classes + self.linear = nn.Linear(num_features, n_heads, bias=True) + nn.init.xavier_uniform_(self.linear.weight) + nn.init.constant_(self.linear.bias, 0) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.drop(x) + return self.linear(x) diff --git a/src/mml/core/models/torch_base.py b/src/mml/core/models/torch_base.py new file mode 100644 index 0000000..62d0fc7 --- /dev/null +++ b/src/mml/core/models/torch_base.py @@ -0,0 +1,200 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from __future__ import annotations + +import logging +from abc import ABC, abstractmethod +from pathlib import Path +from typing import Any, Dict, List, Optional, Union + +import hydra.utils +import torch + +from mml.core.data_loading.task_attributes import RGBInfo, TaskType +from mml.core.data_loading.task_struct import TaskStruct + +logger = logging.getLogger(__name__) + + +class BaseModel(torch.nn.Module, ABC): + def __init__(self, **kwargs): + """ + The base class for MML models. Derived classes must implement the following methods: + - :meth:`_init_model` - for backbone initialization + - :meth:`_create_head` - for head creation + - :meth:`supports` - reporting supported task types + - :meth:`forward` - the models forward pass through backbone and all heads + - :meth:`forward_features` - alternative usage as feature extractor + """ + super(BaseModel, self).__init__() + # model requirements + self.required_mean: Optional[RGBInfo] = None # mean expected by model + self.required_std: Optional[RGBInfo] = None # std expected by model + self.input_size = (None, None, None) # channel, height, width - will be defined during init + # nn modules + self.backbone: Union[torch.nn.Module, None] = None + self.heads = torch.nn.ModuleDict({}) + # for freezing functionality + self._frozen_params: List[str] = [] + # store init kwargs + self._init_kwargs: Dict[str, Any] = kwargs # stores stuff that needs to be persistent when re-initializing + self._head_init_kwargs: List[Dict[str, Any]] = [] # stores init kwargs of heads + # actually init backbone + self._init_model(**kwargs) + logger.debug("Model initialised.") + + @abstractmethod + def _init_model(self, **kwargs: Any) -> None: + """ + This shall implement the backbone module as well as potentially load pretrained weights thereof. + """ + raise NotImplementedError + + @abstractmethod + def _create_head(self, task_type: TaskType, num_classes: int, **kwargs: Any) -> BaseHead: + """ + This shall implement the creation of heads. Given a certain task type the head must be able to be attached + to the backbone as implemented by the forward method. + """ + raise NotImplementedError + + @abstractmethod + def supports(self, task_type: TaskType) -> bool: + """ + Whether the model supports a given task type. + + :param TaskType task_type: + :return: true iff task type is supported by model + """ + pass + + @abstractmethod + def forward(self, x: torch.Tensor) -> Dict[str, torch.Tensor]: + """ + Model forward functionality. Passes input through the backbone once and forwards output through each head. + :param torch.tensor x: input tensor + :return: a dictionary, with one entry per head, key is head name and value is head output + """ + pass + + @abstractmethod + def forward_features(self, x: torch.Tensor) -> torch.Tensor: + """ + Feature extraction functionality. Only forwards features through the backbone and post-processes them to 1D. + :param torch.tensor x: input tensor + :return: a 1D tensor + """ + pass + + def add_head(self, task_struct: TaskStruct, **kwargs: Any) -> None: + """ + The functionality used to add heads to a model. + + :param TaskStruct task_struct: struct for the task to add a head for + :param Any kwargs: additional kwargs that will be forwarded + """ + if task_struct.name in self.heads: + raise KeyError(f"You cannot register a head with already present name ({task_struct.name}).") + if not self.supports(task_type=task_struct.task_type): + raise RuntimeError(f"Task type {task_struct.task_type} not supported by model.") + init_kwargs = {"task_type": task_struct.task_type, "num_classes": task_struct.num_classes} + init_kwargs.update(kwargs) + self.heads[task_struct.name] = self._create_head(**init_kwargs) + self._head_init_kwargs.append(init_kwargs) + logger.debug( + f"Added head {task_struct.name} of task type {task_struct.task_type} with " + f"{task_struct.num_classes} classes." + ) + + def count_parameters(self, only_trainable: bool = True) -> Dict[str, int]: + """ + Gives information on parameter count of the model. + + :param bool only_trainable: if True, only counts parameters that requires_grad. + :return: a dict with component names as key (backbone or name of heads) and parameter count as value + """ + info_dict = {} + for name, module in [("backbone", self.backbone)] + list(self.heads.items()): + if module is None: + info_dict[name] = 0 + else: + info_dict[name] = sum(p.numel() for p in module.parameters() if p.requires_grad or not only_trainable) + return info_dict + + def freeze_backbone(self) -> None: + """ + Freezes all backbone parameters. + """ + for name, par in self.backbone.named_parameters(): # type: ignore[union-attr] + if par.requires_grad: + par.requires_grad = False + self._frozen_params.append(name) + logger.debug(f"Froze {len(self._frozen_params)} parameters of model.") + + def unfreeze_backbone(self) -> None: + """ + Unfreezes previously frozen backbone parameters. + """ + for name, par in self.backbone.named_parameters(): # type: ignore[union-attr] + if name in self._frozen_params: + par.requires_grad = True + logger.debug(f"Unfroze {len(self._frozen_params)} params of model.") + self._frozen_params = [] + + @staticmethod + def load_checkpoint(param_path: Union[Path, str]) -> "BaseModel": + """ + Load from a checkpoint. + + :param Union[Path, str] param_path: path to load checkpoint from + :return: + """ + state = torch.load(param_path) + model: BaseModel = hydra.utils.instantiate(dict(_target_=state["__target__"], **state["__init_kwargs__"])) + model.backbone.load_state_dict(state["backbone"]) # type: ignore[union-attr] + model._frozen_params = state["__frozen_params__"] + for head_name, init_kwargs in zip(state["__head_names__"], state["__head_init_kwargs__"]): + head = model._create_head(**init_kwargs) + model.heads[head_name] = head + head.load_state_dict(state[head_name]) + logger.info("Loaded checkpoint!") + logger.debug(f"@ {param_path}") + return model + + def save_checkpoint(self, param_path: Union[Path, str]) -> None: + """ + Save a model checkpoint. + + :param Union[Path, str] param_path: path to store checkpoint + :return: + """ + state = {name: head.state_dict() for name, head in self.heads.items()} + state.update( + { + "backbone": self.backbone.state_dict(), # type: ignore[union-attr] + "__head_names__": list(self.heads.keys()), + "__init_kwargs__": self._init_kwargs, + "__target__": self.__class__, + "__frozen_params__": self._frozen_params, + "__head_init_kwargs__": self._head_init_kwargs, + } + ) + torch.save(state, param_path) + logger.info("Saved checkpoint!") + logger.debug(f"@ {param_path}") + + +class BaseHead(torch.nn.Module, ABC): + def __init__(self, task_type: TaskType, num_classes: int, **kwargs: Any): + """The base class for MML model heads.""" + super(BaseHead, self).__init__() + self.task_type = task_type + self.num_classes = num_classes + + @abstractmethod + def forward(self, x: torch.Tensor) -> torch.Tensor: + pass diff --git a/src/mml/core/scripts/__init__.py b/src/mml/core/scripts/__init__.py new file mode 100644 index 0000000..90ffb6c --- /dev/null +++ b/src/mml/core/scripts/__init__.py @@ -0,0 +1,6 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + diff --git a/src/mml/core/scripts/callbacks.py b/src/mml/core/scripts/callbacks.py new file mode 100644 index 0000000..2d37844 --- /dev/null +++ b/src/mml/core/scripts/callbacks.py @@ -0,0 +1,141 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import copy +import logging +import os +from pathlib import Path +from typing import Any, Dict, List + +import lightning +import torch +from lightning.pytorch.callbacks import ModelCheckpoint, RichProgressBar, TQDMProgressBar + +from mml.core.scripts.utils import LearningPhase + +logger = logging.getLogger(__name__) + + +class StopAfterKeyboardInterrupt(lightning.Callback): + """ + Ensures pytorch lightning to really shut down after keyboard interrupt. This is the new variant of this Callback + aimed to be used by most recent pytorch lightning versions. + """ + + def on_exception( + self, trainer: "lightning.Trainer", pl_module: "lightning.LightningModule", exception: BaseException + ) -> None: + if trainer.interrupted and isinstance(exception, KeyboardInterrupt): + raise InterruptedError( + "Trainer has been interrupted by keyboard! " + "Will stop running MML - no graceful shutdown, ongoing epoch results are lost! " + "Run MML in continue mode to start from the checkpoint of last epochs end." + ) + + +class MetricsTrackerCallback(lightning.Callback): + """ + Keeps track of all metrics, at the end of each epoch. + """ + + def __init__(self): + self.metrics: List[Dict[str, float]] = [] + + def state_dict(self) -> Dict[str, Any]: + return {"metrics": self.metrics} + + def load_state_dict(self, state_dict: Dict[str, Any]) -> None: + self.metrics = state_dict["metrics"] + + def on_train_epoch_end(self, trainer: "lightning.Trainer", pl_module: "lightning.LightningModule") -> None: + self.copy_metrics(trainer=trainer, phase=LearningPhase.TRAIN) + + def on_validation_epoch_end(self, trainer: "lightning.Trainer", pl_module: "lightning.LightningModule") -> None: + self.copy_metrics(trainer=trainer, phase=LearningPhase.VAL) + + # we need to gather test metrics only at the end (after module.test_epoch_end) to wait for bootstrapped computation + def on_test_end(self, trainer: "lightning.Trainer", pl_module: "lightning.LightningModule") -> None: + self.copy_metrics(trainer=trainer, phase=LearningPhase.TEST) + + def copy_metrics(self, trainer: lightning.Trainer, phase: LearningPhase) -> None: + phase_metrics = copy.deepcopy(trainer.callback_metrics) # Dict[str, torch.Tensor] + phase_metrics = { + name: metric_tensor.item() + for name, metric_tensor in phase_metrics.items() + if name.startswith(str(phase.value)) + } + logger.debug(f"{phase=}, logged metrics {phase_metrics.keys()}") + if len(self.metrics) == trainer.current_epoch: + # first time copying for this epoch + self.metrics.append(phase_metrics) + elif len(self.metrics) == trainer.current_epoch + 1: + # updating this epoch, for example adding train to val metrics + self.metrics[trainer.current_epoch].update(phase_metrics) + else: + # we might have missed some epochs? + diff = trainer.current_epoch - len(self.metrics) + logger.error(f"There is a discrepancy of {diff} between metrics recorded and the current epoch!") + for _ in range(diff): + self.metrics.append({}) + self.metrics.append(phase_metrics) + + +class MMLRichProgressBar(RichProgressBar): + """ + Slight modification of the Lightning rich progress bar, showing the correct experiment name. + """ + + def get_metrics(self, trainer, model): + # don't show the version number + items = super().get_metrics(trainer, model) + items.pop("v_num", None) + items["exp"] = "/".join(Path(os.getcwd()).parts[-2:]) + return items + + +class MMLTQDMProgressBar(TQDMProgressBar): + """ + Slight modification of the Lightning tqdm progress bar, showing the correct experiment name. + """ + + def __init__(self, refresh_rate=1): + super().__init__(refresh_rate=refresh_rate) + self.experiment_name = "/".join(Path(os.getcwd()).parts[-2:]) + + def get_metrics(self, trainer, model): + # don't show the version number + items = super().get_metrics(trainer, model) + items.pop("v_num", None) + items["exp"] = self.experiment_name + return items + + +class MMLModelCheckpoint(ModelCheckpoint): + """ + Slight modification of the lightning ModelCheckpoint (see + https://github.com/Lightning-AI/pytorch-lightning/issues/20245). + """ + + def _save_last_checkpoint(self, trainer: "lightning.Trainer", monitor_candidates: Dict[str, torch.Tensor]) -> None: + """Only update last checkpoint in case there has just been a new checkpoint.""" + if self._last_global_step_saved == trainer.global_step: + super()._save_last_checkpoint(trainer=trainer, monitor_candidates=monitor_candidates) + + def on_train_epoch_end(self, trainer: "lightning.Trainer", pl_module: "lightning.LightningModule") -> None: + """Save a checkpoint at the end of the training epoch.""" + if not self._should_skip_saving_checkpoint(trainer) and self._should_save_on_train_epoch_end(trainer): + monitor_candidates = self._monitor_candidates(trainer) + if self._every_n_epochs >= 1 and (trainer.current_epoch + 1) % self._every_n_epochs == 0: + self._save_topk_checkpoint(trainer, monitor_candidates) + self._save_last_checkpoint(trainer, monitor_candidates) + + def on_validation_end(self, trainer: "lightning.Trainer", pl_module: "lightning.LightningModule") -> None: + """Save a checkpoint at the end of the validation stage.""" + if not self._should_skip_saving_checkpoint(trainer) and not self._should_save_on_train_epoch_end(trainer): + if self._every_n_epochs >= 1 and (trainer.current_epoch + 1) % self._every_n_epochs == 0: + monitor_candidates = self._monitor_candidates(trainer) + self._save_topk_checkpoint(trainer, monitor_candidates) + self._save_last_checkpoint(trainer, monitor_candidates) diff --git a/src/mml/core/scripts/decorators.py b/src/mml/core/scripts/decorators.py new file mode 100644 index 0000000..6d5c0b3 --- /dev/null +++ b/src/mml/core/scripts/decorators.py @@ -0,0 +1,91 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import functools +import inspect +import warnings +from _thread import interrupt_main +from threading import Timer +from typing import Any, Callable, Type, Union + +from deprecated.sphinx import deprecated, versionadded, versionchanged + +__all__ = ["deprecated", "versionadded", "versionchanged", "beta", "timeout"] + + +def beta(message: str = "BETA:"): + """ + The beta decorator is used to indicate that a particular feature is in Beta. A callable or type that has + been marked as beta will give a ``UserWarning`` when it is called or instantiated. Adopted from + :func:`~flash.core.utilities.stability.beta`. + + :param str message: The message to include in the warning. + """ + + def decorator(_callable: Union[Callable, Type]): + # if called on a class, recursively call on the class init method + if inspect.isclass(_callable): + _callable.__init__ = decorator(_callable.__init__) + return _callable + + @functools.wraps(_callable) + def wrapper(*args, **kwargs): + _raise_beta_warning(message, _callable.__qualname__) + return _callable(*args, **kwargs) + + return wrapper + + return decorator + + +@functools.lru_cache() +def _raise_beta_warning(message: str, source: str): + # lru_cache decorator is used to only warn once for each message / obj + warnings.warn( + f"{message} The API and functionality of {source} may change without warning in future releases.", + category=UserWarning, + ) + + +def _signal_main(*args, **kwargs) -> None: + """This function is executed on the Timer thread to signal the timeout back to the main process.""" + interrupt_main() + + +def timeout(seconds: int) -> Callable: + """ + A decorator to wrap functions that shall have a timeout attached. Will raise TimeoutError if the execution + takes longer than the specified number of seconds. + + :param int seconds: timeout in seconds + :return: the wrapped function + """ + + def decorator(_callable: Callable) -> Callable: + @functools.wraps(_callable) + def wrapper(*args, **kwargs) -> Any: + # set up timer + timer = Timer(seconds, _signal_main) + timer.start() + # invoke underlying function + try: + value = _callable(*args, **kwargs) + # re-interpret the interruption as timeout + except KeyboardInterrupt: + if timer.finished.is_set(): + raise TimeoutError( + f"Execution of {_callable.__qualname__} took to long (limit: {seconds} " f"seconds)." + ) + else: + raise + # make sure to delete timer anyway + finally: + timer.cancel() + return value + + return wrapper + + return decorator diff --git a/src/mml/core/scripts/exceptions.py b/src/mml/core/scripts/exceptions.py new file mode 100644 index 0000000..7f068ce --- /dev/null +++ b/src/mml/core/scripts/exceptions.py @@ -0,0 +1,17 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + + +class MMLMisconfigurationException(Exception): + """Exception used to inform users of misuse with MML.""" + + +class InvalidTransitionError(Exception): + """Raised whenever a transition between states of a class is invalid.""" + + +class TaskNotFoundError(Exception): + """Raised when there is an unsolvable error to find a certain task.""" diff --git a/src/mml/core/scripts/model_storage.py b/src/mml/core/scripts/model_storage.py new file mode 100644 index 0000000..0480318 --- /dev/null +++ b/src/mml/core/scripts/model_storage.py @@ -0,0 +1,305 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import datetime +import logging +import warnings +from dataclasses import dataclass, field +from pathlib import Path +from typing import TYPE_CHECKING, Dict, List, Optional, Set + +import orjson + +if TYPE_CHECKING: + from mml.core.data_loading.task_struct import TaskStruct + +logger = logging.getLogger(__name__) + + +@dataclass +class ModelStorage: + """ + Lightweight wrapper for everything to reproduce, load and compare trained models. Basically consists of a path to + a saved pipeline, a path to saved parameters and a performance value, indicating validation metric after training. + + :param Path pipeline: path to a stored `~mml.core.scipts.pipeline_configuration.PipelineCfg` + :param Path parameters: path to stored model parameters + :param float performance: validation score of the model, usually best/last epoch loss value, might be used for model selection + :param float training_time: training time in seconds + :param Optional[str] task: in simple supervised settings this may indicate the target task trained for + :param Optional[int] fold: may indicate the fold number used + :param Dict[str, Path] predictions: (optional) predictions that have been made with this model + :param list metrics: (optional) detailed training and validation metrics + """ + + pipeline: Path + parameters: Path + performance: float + training_time: float = -1.0 + created: Optional[datetime.datetime] = None + task: Optional[str] = None + fold: Optional[int] = None + predictions: Dict[str, Path] = field(default_factory=dict) + metrics: list = field(default_factory=lambda: []) + _stored: Optional[Path] = None + + def __str__(self): + return f"ModelStorage(task={self.task}, fold={self.fold}, created={self.created})" + + def __repr__(self): + return self.__str__() + + def store( + self, task_struct: Optional["TaskStruct"] = None, path: Optional[Path] = None, fold: Optional[int] = None + ) -> Path: + """ + Saves the model storage. If struct is given it creates a new path and returns it, if path is given otherwise + uses that if None is given it tries to look up if the storage has been loaded previously and will update that + location. + + :param Optional[TaskStruct] task_struct: task struct corresponding to the task the model was trained on, will be + used to determine the path. + :param Optional[Path] path: (optional) if a path already exists for this storage, overwrite it, raises an error + if the presented path does not exist yet + :param Optional[int] fold: (optional) if a fold is specified and path is None, the file name will be + fold_{fold}.json, otherwise the file name falls back to model_storage.json. + :return: the path the storage was saved to + """ + if path is None and task_struct is None and self._stored: + path = self._stored + logger.debug("Found previous location of ModelStorage. Will update that location.") + if sum([path is None, task_struct is None]) in [0, 2]: + raise ValueError("Provide either path or task_struct argument exclusively for a newly created ModelStorage") + if task_struct and self.task is not None and self.task != task_struct.name: + warnings.warn(f"Storing model given struct from {task_struct.name} but model task was set to {self.task}!") + if fold and self.fold is not None and self.fold != fold: + warnings.warn(f"Storing model given fold {fold} but model fold was set to {self.fold} before!") + + # import locally to avoid circular import + from mml.core.data_loading.file_manager import MMLFileManager + + fm = MMLFileManager.instance() + + if ( + (fm.results_root not in self.parameters.parents) + or (fm.results_root not in self.pipeline.parents) + or any(fm.results_root not in pred.parents for pred in self.predictions.values()) + ): + raise RuntimeError("Error while checking file path hierarchy.") + + if path is None: + # check for valid task_name + path = fm.construct_saving_path( + obj=self, + key="models", + task_name=task_struct.name, + file_name=f"fold_{fold}.json" if fold else "model_storage.json", + ) + else: + if path.exists(): + path.unlink() + logger.info(f"Updating model storage at {path}.") + else: + raise FileNotFoundError("Provided path for Model Storage does not exist.") + if self.created is None: + self.created = datetime.datetime.now().replace(microsecond=0) + data = { + "pipeline": str(self.pipeline.relative_to(fm.results_root)), + "parameters": str(self.parameters.relative_to(fm.results_root)), + "performance": self.performance, + "training_time": self.training_time, + "task": self.task, + "fold": self.fold, + "created": self.created.isoformat(timespec="seconds"), + "metrics": self.metrics, + "predictions": {k: str(v.relative_to(fm.results_root)) for k, v in self.predictions.items()}, + } + # use orjson to store and load + with open(str(path), "wb") as f: + f.write(orjson.dumps(data)) + logger.debug(f"Dumped model storage at {path}.") + self._stored = path + return path + + @classmethod + def from_json(cls, path: Path, results_root: Optional[Path] = None) -> "ModelStorage": + """ + Counterpart to saving the storage. Creates the storage object from a file. + + :param Path path: path to load the storage from + :param Path results_root: the current systems' results root, if not provided will be tried to be inferred + :return: a model storage dataclass + """ + # may not be inferred while the first run of reusables is processed + if results_root is None: + # import locally to avoid circular import + from mml.core.data_loading.file_manager import MMLFileManager + + fm = MMLFileManager.instance() + results_root = fm.results_root + # read in data + with open(str(path), "rb") as f: + data = orjson.loads(f.read()) + # backward compatibility + if "predictions" not in data: + data["predictions"] = {} + if "task" not in data: + data["task"] = None + if "fold" not in data: + data["fold"] = None + if "created" not in data: + data["created"] = None + return cls( + pipeline=results_root / data["pipeline"], + parameters=results_root / data["parameters"], + performance=data["performance"], + training_time=data["training_time"], + task=data["task"], + fold=data["fold"], + created=datetime.datetime.fromisoformat(data["created"]) if data["created"] else None, + metrics=data["metrics"], + predictions={k: results_root / v for k, v in data["predictions"].items()}, + _stored=path, + ) + + +@dataclass +class EnsembleStorage: + """ + An EnsembleStorage represents a collection of models that are applied jointly on a task. + """ + + performance: float + weights: List[float] = field(default_factory=list) + members: List[Path] = field(default_factory=list) + predictions: Dict[str, Path] = field(default_factory=dict) + metrics: dict = field(default_factory=dict) + search_params: dict = field(default_factory=dict) + _stored: Optional[Path] = None + + def get_members(self) -> List[ModelStorage]: + """ + Loads the actual ModelStorage members of the Ensemble from disk. + :return: list of ModelStorage instances + """ + return [ModelStorage.from_json(path=path) for path in self.members] + + @property + def tasks(self) -> Set[str]: + """ + Tasks of the members. + """ + loaded_members = self.get_members() + return set([member.task for member in loaded_members]) + + @property + def folds(self) -> List[int]: + """ + Folds used by the members. + """ + loaded_members = self.get_members() + tasks = set([member.task for member in loaded_members]) + if len(tasks) != 1 or None in tasks: + warnings.warn("Since Ensemble members have been training on inconsistent tasks, folds has no real meaning!") + return [member.fold for member in loaded_members] + + def store( + self, task_struct: Optional["TaskStruct"] = None, path: Optional[Path] = None, file_name: str = "ensemble.json" + ) -> Path: + """ + Saves the model ensemble. If struct is given it creates a new path and returns it, if path is given otherwise + uses that if None is given it tries to look up if the storage has been loaded previously and will update that + location. + + :param Optional[TaskStruct] task_struct: task struct corresponding to the task the ensemble was optimised on, + will be used to determine the path. Either task_struct or path must be provided. + :param Optional[Path] path: (optional) if a path already exists for this storage, overwrite it, raises an error + if the presented path does not exist yet + :param str file_name: only relevant for task_struct variant, determines the naming of the json file + :return: the path the storage was saved to + """ + if path is None and task_struct is None and self._stored: + path = self._stored + logger.debug("Found previous location of EnsembleStorage. Will update that location.") + if sum([path is None, task_struct is None]) in [0, 2]: + raise ValueError("Provide either path or task_struct argument exclusively.") + if len(self.members) == 0: + raise RuntimeError("No members to store for this Ensemble.") + if len(self.weights) == 0: + logger.info("No weights set for model ensemble, will use uniform weighing.") + self.weights = [1 / len(self.members)] * len(self.members) + if len(self.members) != len(self.weights): + raise RuntimeError("Weight count does not match number of members.") + loaded_members = self.get_members() + all_tasks = set([member.task for member in loaded_members]) + if len(all_tasks) != 1: + warnings.warn(f"Ensemble might have been trained for multiple tasks! ({all_tasks}") + if task_struct and all_tasks and task_struct.name not in all_tasks: + warnings.warn( + f"Storing ensemble given struct from {task_struct.name} but ensemble has no member " + f"associated to that task (only to {all_tasks})!" + ) + + # import locally to avoid circular import + from mml.core.data_loading.file_manager import MMLFileManager + + fm = MMLFileManager.instance() + + if any(fm.results_root not in member.parents for member in self.members) or any( + fm.results_root not in pred.parents for pred in self.predictions.values() + ): + raise RuntimeError("Error while checking file path hierarchy.") + + if path is None: + if Path(file_name).suffix != ".json": + raise ValueError('File name must have suffix ".json".') + # check for valid task_name + path = fm.construct_saving_path(obj=self, key="ensemble", task_name=task_struct.name, file_name=file_name) + else: + if path.exists(): + path.unlink() + logger.info(f"Updating ensemble storage at {path}.") + else: + raise FileNotFoundError("Provided path for Ensemble Storage does not exist.") + data = { + "performance": self.performance, + "weights": self.weights, + "members": [str(member.relative_to(fm.results_root)) for member in self.members], + "predictions": {k: str(v.relative_to(fm.results_root)) for k, v in self.predictions.items()}, + "metrics": self.metrics, + "search_params": self.search_params, + } + # use orjson to store and load + with open(str(path), "wb") as f: + f.write(orjson.dumps(data)) + logger.debug(f"Dumped ensemble storage at {path}.") + self._stored = path + return path + + @classmethod + def from_json(cls, path: Path) -> "EnsembleStorage": + """ + Counterpart to saving the storage. Creates the storage object from a file. + + :param path: path to load the storage from + :return: an ensemble storage dataclass + """ + # import locally to avoid circular import + from mml.core.data_loading.file_manager import MMLFileManager + + fm = MMLFileManager.instance() + + with open(str(path), "rb") as f: + data = orjson.loads(f.read()) + return cls( + members=[fm.results_root / entry for entry in data["members"]], + weights=data["weights"], + performance=data["performance"], + predictions={k: fm.results_root / v for k, v in data["predictions"].items()}, + metrics=data["metrics"], + search_params=data["search_params"], + _stored=path, + ) diff --git a/src/mml/core/scripts/notifier.py b/src/mml/core/scripts/notifier.py new file mode 100644 index 0000000..700446a --- /dev/null +++ b/src/mml/core/scripts/notifier.py @@ -0,0 +1,264 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +""" +Module to send notifications of MML execution via various media to the user. +""" + +import datetime +import email.message +import json +import logging +import os +import smtplib +import socket +import ssl +import traceback +import warnings +from abc import ABC, abstractmethod +from typing import Optional + +import requests +from hydra.core.hydra_config import HydraConfig +from omegaconf import OmegaConf + +import mml +from mml.core.data_loading.file_manager import MMLFileManager + +logger = logging.getLogger(__name__) + + +class BaseNotifier(ABC): + def __init__(self, on_start: bool = False, on_end: bool = False, on_failure: bool = True): + """ + The notifier base class provides utilities to send messages for mml events. + + :param on_start: emit message on mml start + :param on_end: emit message on (successful) mml end + :param on_failure: emit message on mml failure (except keyboard interrupt / user caused SIGTERM signal) + """ + self.do_on_start = on_start + self.do_on_end = on_end + self.do_on_failure = on_failure + + @abstractmethod + def emit_message(self, text: str) -> None: + """ + Abstract method that must implement the message delivery mechanism for inherited classes. + + :param text: the text to be sent + :return: + """ + pass + + @staticmethod + def is_master() -> bool: + """ + Checks if the current process is the master process - used e.g. in Multi-GPU settings to prevent sending + multiple messages from each node / process. + + :return: + """ + if "RANK" in os.environ: + master_process = int(os.environ["RANK"]) == 0 + else: + master_process = True + return master_process + + def notify_on_failure(self, error: BaseException) -> None: + """ + The notification wrapper function to be called from outside in case MML fails. + + :param Exception error: an error that caused MML to fail + :return: + """ + # skip notification if either not requested or not on master node + if not (self.do_on_failure and self.is_master()): + return + text = self.get_message_header() + f"Here's the error:\n\n {error}\n\nTraceback:\n\n{traceback.format_exc()}" + self.emit_message(text=text) + + def notify_on_start(self) -> None: + """ + The notification wrapper function to be called from outside in case MML starts. + + :return: + """ + # skip notification if either not requested or not on master node + if not (self.do_on_start and self.is_master()): + return + text = "Now running:\n\n" + self.get_message_header() + self.emit_message(text=text) + + def notify_on_end(self, return_value: Optional[float]) -> None: + """ + The notification wrapper function to be called from outside in case MML end. + + :param Optional[float] return_value: the return value of the scheduler + :return: + """ + # skip notification if either not requested or not on master node + if not (self.do_on_end and self.is_master()): + return + text = f"Finished (returned {return_value}):\n\n" + self.get_message_header() + self.emit_message(text=text) + + @staticmethod + def search_overrides() -> str: + """ + For enriching messages the used overrides to call MML are tried to be read from the hydra config. If reading is + not successful the returned string is a message describing the failed attempt to read + + :return: if successful the string that can be used to reproduce the MML call, otherwise a failure description + """ + + try: + hydra_cfg = HydraConfig.get() + except ValueError: + hydra_cfg = None + if hydra_cfg: + overrides = OmegaConf.to_container(hydra_cfg.overrides) + return str(overrides) + else: + # If hydra was not used, return this failure string + return "Failed to read CLI overrides to MML! Hydra config seems to have been not set." + + @staticmethod + def search_run_path() -> str: + """ + For enriching messages the run path of the current experiment is tried to be read from various sources. + + :return: if successful the experiment path is extracted, otherwise a fallback notification + """ + msg = "Run path analysis: " + # first try to get file manager + try: + fm = MMLFileManager.instance() + except TypeError: + fm = None + if fm: + msg += "\n > FileManager - " + str(fm.log_path) + return msg + else: + msg += "\n > FileManager - not instantiated" + # second try to get hydra config + try: + hydra_cfg = HydraConfig.get() + except ValueError: + hydra_cfg = None + if hydra_cfg: + msg += "\n > Hydra - " + hydra_cfg.runtime.output_dir + return msg + else: + msg += "\n > Hydra - not instantiated" + # third pick up current working directory + msg += "\n > CWD - " + os.getcwd() + return msg + + def get_message_header(self) -> str: + """ + Helper to return uniform message header for all kinds of messages. + + :return: A header string to be used by notifiers. + """ + return ( + f"MML version {mml.__version__}, on {socket.gethostname()}, " + f"reporting at {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n" + f"Overrides: {self.search_overrides()}\n" + f"{self.search_run_path()}\n" + ) + + +class EMailNotifier(BaseNotifier): + def emit_message(self, text: str) -> None: + """ + A function to send a simple email notification. + + All email settings are read from the mml.env environment variables (thus they have to be set beforehand): + MML_SMTP_SERVER + MML_SMTP_SERVER_PORT + MML_SENDER_EMAIL + MML_RECEIVER_EMAIL + MML_MAIL_PASSWORD=NO_PASSWORD (set to NO_PASSWORD if there is no password necessary, otherwise set password) + + :param text: message to be sent via email + :return: + """ + logger.info("Sending email notification...") + try: + server = smtplib.SMTP(os.environ["MML_SMTP_SERVER"], port=int(os.environ["MML_SMTP_SERVER_PORT"])) + server.ehlo() + server.starttls(context=ssl.create_default_context()) + server.ehlo() + if os.environ["MML_MAIL_PASSWORD"] != "NO_PASSWORD": + server.login(os.environ["MML_SENDER_EMAIL"], os.environ["MML_MAIL_PASSWORD"]) + msg = email.message.EmailMessage() + msg["Subject"] = "[MML] - notification" + msg["From"] = os.environ["MML_SENDER_EMAIL"] + msg["To"] = os.environ["MML_RECEIVER_EMAIL"] + msg.set_content(text) + server.send_message(msg) + logger.info("Email notification sent!") + except Exception as e: + logger.error( + "Error during sending of mail notification! Have you configured mml.env for mail notifications?" + ) + logger.error(e) + finally: + server.quit() + + +class SlackNotifier(BaseNotifier): + def emit_message(self, text: str) -> None: + """ + A function to send a simple slack notification. All slack settings are read from the mml.env environment + variables (thus they have to be set beforehand). + + A slack app has to be created via the web interface and added to the workspace. Here are some example settings: + + .. code-block:: text + + display_information: + name: MML Monitoring + description: Alerts from the mml monitoring system. + background_color: "#8B0000" + features: + bot_user: + display_name: MML Monitoring Alert + always_online: true + oauth_config: + scopes: + bot: + - incoming-webhook + settings: + org_deploy_enabled: false + socket_mode_enabled: false + token_rotation_enabled: false + + Generate the webhook and store it inside the mml.env under "MML_SLACK_WEBHOOK_URL" to enable the notifier. + + :param text: message to be sent via slack + :return: + """ + logger.info("Sending slack notification...") + dump = {"username": "MML GPU Monitor", "text": text, "icon_emoji": ":information:"} + try: + requests.post(os.environ["MML_SLACK_WEBHOOK_URL"], json.dumps(dump)) + logger.info("Slack notification sent!") + except Exception as e: + logger.error( + "Error during sending of Slack notification! Have you configured mml.env for Slack notifications?" + ) + logger.error(e) + + +class DummyNotifier(BaseNotifier): + def emit_message(self, text: str) -> None: + """The dummy notifier does not emit any message. It may be used in testing or to avoid being messaged.""" + warnings.warn( + "Dummy notifier does not emit any message! Please configure a different notifier to receive " + "mml notifications." + ) diff --git a/src/mml/core/scripts/pipeline_configuration.py b/src/mml/core/scripts/pipeline_configuration.py new file mode 100644 index 0000000..b8853eb --- /dev/null +++ b/src/mml/core/scripts/pipeline_configuration.py @@ -0,0 +1,139 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import warnings +from contextlib import contextmanager +from copy import deepcopy +from pathlib import Path +from typing import List, Optional + +from omegaconf import DictConfig, OmegaConf + +from mml.core.data_loading.file_manager import MMLFileManager +from mml.core.data_loading.task_struct import TaskStruct + +logger = logging.getLogger(__name__) + + +class PipelineCfg: + def __init__(self, pipeline_cfg: DictConfig, restrict_keys: Optional[List[str]] = None) -> None: + """ + PipelineCfg holds relevant configuration elements of a training pipeline to store, reproduce and leverage + knowledge at a later point. The intended usage is by invoking :meth:`from_cfg` on the full mml config, which + will produce a masked copy only focussing on a subset of config keys. + + :param DictConfig pipeline_cfg: a config + :param Optional[List[str]] restrict_keys: which config keys to focus upon + """ + self.pipeline_cfg = pipeline_cfg + self.pipeline_keys = [] + restrict_keys = PIPELINE_CONFIG_PARTS if restrict_keys is None else restrict_keys + for key in restrict_keys: + if not isinstance(key, str): + raise ValueError("provide pipeline keys as strings") + if not hasattr(self.pipeline_cfg, key): + warnings.warn(f"requested key {key} not found in pipeline_cfg, will be ignored") + continue + self.pipeline_keys.append(key) + if len(self.pipeline_keys) == 0: + raise ValueError("(valid) pipeline keys are empty") + # reduce pipeline_config, this is a fallback if called directly upon a full config, but also in case at some + # point only a subset of an existing pipeline configuration is intended to be reused + self.pipeline_cfg = OmegaConf.masked_copy(self.pipeline_cfg, keys=self.pipeline_keys) + + @classmethod + def from_cfg(cls, current_cfg: DictConfig, restrict_keys: Optional[List[str]] = None) -> "PipelineCfg": + """ + Extracts relevant pipeline keys from current config determined by restrict_keys. + + :param DictConfig current_cfg: the FULL config to derive the pipeline configuration from + :param Optional[List[str]] restrict_keys: which config keys to focus upon + :return: + """ + pipeline_keys = PIPELINE_CONFIG_PARTS if restrict_keys is None else restrict_keys + if not all([isinstance(key, str) and hasattr(current_cfg, key) for key in pipeline_keys]): + raise ValueError(f"keys {pipeline_keys} contains a value, which might be not present in the current config") + return cls(pipeline_cfg=OmegaConf.masked_copy(current_cfg, keys=pipeline_keys), restrict_keys=pipeline_keys) + + @contextmanager + def activate(self, current_cfg: DictConfig) -> None: + """ + To be used as a config manager, activates this pipeline upon the currently active mml config. When the context + exits, the original configuration is restored. + + :param DictConfig current_cfg: the currently active mml config + :return: no return value, the mml config is modified in place + """ + # create backup for later restoration + old = deepcopy(current_cfg) + # set config elements based on keys + for key in self.pipeline_keys: + if key in self.pipeline_cfg: + OmegaConf.update(current_cfg, key=key, value=self.pipeline_cfg[key], merge=False, force_add=False) + logger.debug(f"Activated key {key} from pipeline configuration.") + # yield to do training etc. + yield + # restore old configuration + for key in self.pipeline_keys: + OmegaConf.update(current_cfg, key=key, value=old[key], merge=False, force_add=False) + logger.debug("Deactivated pipeline configuration.") + + def store(self, task_struct: TaskStruct, as_blueprint: bool = False) -> Path: + """ + Store this pipeline. Requires a task struct to determine task name. If blueprint is set, this will be stored in + the BLUEPRINTS folder instead of PIPELINES. This allows for easier re-usage. + + :param TaskStruct task_struct: struct of the task this pipeline has or should be applied upon + :param bool as_blueprint: if true store as blueprint otherwise as pipeline + :return: the path to the stored file + """ + # stores pipeline_cfg + key = "blueprint" if as_blueprint else "pipeline" + path = MMLFileManager.instance().construct_saving_path( + obj=self.pipeline_cfg, key=key, task_name=task_struct.name + ) + # do not resolve to not overwrite + OmegaConf.save(config=self.pipeline_cfg, f=path, resolve=False) + return path + + @classmethod + def load(cls, path: Path, pipeline_keys: Optional[List[str]] = None) -> "PipelineCfg": + """ + Load a stores pipeline configuration (or blueprint) from path. + + :param Path path: the path to the stored file + :param Optional[List[str]] pipeline_keys: which config keys to focus upon + :return: the loaded pipeline configuration (restricted to provided pipeline keys) + """ + loaded = OmegaConf.load(path) + logger.debug(f"Loaded pipeline from {path}.") + return cls(pipeline_cfg=loaded, restrict_keys=pipeline_keys) + + def clone(self) -> "PipelineCfg": + """ + Convenience method to deepcopy the configuration. + + :return: a deepcopy of the configuration + """ + return deepcopy(self) + + +# these are the default keys if none are specified, they comprise all relevant aspects for reproducing a model training +PIPELINE_CONFIG_PARTS = [ + "arch", + "augmentations", + "cbs", + "loss", + "lr_scheduler", + "mode", + "optimizer", + "preprocessing", + "sampling", + "trainer", + "tta", + "tune", +] diff --git a/src/mml/core/scripts/schedulers/__init__.py b/src/mml/core/scripts/schedulers/__init__.py new file mode 100644 index 0000000..90ffb6c --- /dev/null +++ b/src/mml/core/scripts/schedulers/__init__.py @@ -0,0 +1,6 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + diff --git a/src/mml/core/scripts/schedulers/base_scheduler.py b/src/mml/core/scripts/schedulers/base_scheduler.py new file mode 100644 index 0000000..fe448e4 --- /dev/null +++ b/src/mml/core/scripts/schedulers/base_scheduler.py @@ -0,0 +1,711 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import abc +import copy +import datetime +import logging +import os +import warnings +from pathlib import Path +from typing import Callable, List, Optional, Tuple, Union + +import lightning +import torch +from colorama import Back, Fore, Style +from hydra.core.hydra_config import HydraConfig +from hydra.utils import instantiate +from lightning.pytorch.callbacks import ModelCheckpoint +from lightning.pytorch.tuner import Tuner +from lightning_fabric.utilities.seed import seed_everything +from omegaconf import DictConfig, OmegaConf + +from mml.core.data_loading.file_manager import MMLFileManager +from mml.core.data_loading.lightning_datamodule import MultiTaskDataModule +from mml.core.data_loading.task_attributes import Modality +from mml.core.data_loading.task_struct import TaskStruct, TaskStructFactory +from mml.core.models.lightning_single_frame import SingleFrameLightningModule +from mml.core.scripts.callbacks import ( + MetricsTrackerCallback, + MMLModelCheckpoint, + MMLRichProgressBar, + MMLTQDMProgressBar, + StopAfterKeyboardInterrupt, +) +from mml.core.scripts.exceptions import MMLMisconfigurationException +from mml.core.scripts.utils import ARG_SEP, TAG_SEP, catch_time, throttle_logging + +logger = logging.getLogger(__name__) + + +class AbstractBaseScheduler(metaclass=abc.ABCMeta): + """ + This is the base class of a scheduler for a possible series of experiments. Based on a special order of routines + one can implement a derived scheduler class for an own setup. The scheduler itself keeps track of the status, + datasets, manages file savings and loading, provides routines for the inclusion of dataloaders & models. + """ + + def __init__(self, cfg: DictConfig, available_subroutines: List[str]): + """ + Creates the schedule. Can be started afterward with the .run() method. + + :param cfg: configs of the current run + :param available_subroutines: available subroutines of inherited scheduler + """ + self.cfg = cfg + logger.debug("Creating schedule...") + subroutines = list(self.cfg.mode.subroutines) + if not isinstance(subroutines, list): + raise TypeError( + f"Please hand in subroutines for the scheduler as a list type. You gave type " f"{type(subroutines)}." + ) + if len(subroutines) == 0: + raise ValueError("Please hand in non-empty subroutines list for the scheduler.") + if not set(subroutines).issubset(set(available_subroutines)): + raise MMLMisconfigurationException( + f"Allowed subroutines for Scheduler are only {available_subroutines}, " f"but gave {subroutines}." + ) + self.subroutines = subroutines + # the active step naming variable will always be updated to the actual scheduler step and used for logging + self.active_step_naming = "init" + # try to acquire running lock + self.lock_path = Path(os.getcwd()) / "lock.tmp" + if self.lock_path.exists(): + msg = ( + f"Was not able to acquire the lock {self.lock_path}. This might be due to either a currently running " + f"instance on that path or some ungraceful disruption on that run. If you want to continue exactly " + f"this experiment run, make sure to avoid running conditions with any other scheduler on that " + f"folder and manually delete the lock file ({self.lock_path}). If you do not insist on this specific " + f"run folder just start MML again with the same config options as before (a new run folder will " + f"be created automatically)." + ) + logger.error(msg) + raise RuntimeError(msg) + self.lock_path.touch(exist_ok=False) + # file management and continue status (if continue the internal logs will + self.continue_status = bool(self.cfg["continue"]) + # be aware to call this FileManager before any other file related classes (it is a singleton class) + if MMLFileManager.exists(): + warnings.warn( + "MMLFileManager was not created by BaseScheduler, but existed previously. In case of " + "running multiple schedulers, make sure to correctly tear down the file manager (" + "usually during finish_exp) by calling clear_instance() on the file manager." + ) + self.fm = MMLFileManager.instance( + proj_path=Path(self.cfg["proj_path"]), + data_path=Path(self.cfg["data_dir"]), + log_path=Path(os.getcwd()), + reuse_cfg=self.cfg.reuse, + remove_cfg=self.cfg.remove, + ) + # the return value will be returned by the 'run' method, allowing for blackbox optimisation, it is recommended + # to set this in the subroutine finishing instructions + self.return_value = None + # apply tagging.all and tagging.variants to tasks: + if self.cfg.tagging.all: + if not self.cfg.tagging.all.startswith(TAG_SEP): + raise MMLMisconfigurationException( + f'tagging.all="{self.cfg.tagging.all}" does not start with "{TAG_SEP}".' + ) + self.cfg.task_list = [task + self.cfg.tagging.all for task in self.cfg.task_list] + logger.debug(f"Tagged all tasks with {self.cfg.tagging.all}.") + if self.cfg.tagging.variants: + all_tasks = [] + for variant in self.cfg.tagging.variants: + if not variant.startswith(TAG_SEP): + raise MMLMisconfigurationException( + f'tagging.variants entry "{variant}" does not start with "{TAG_SEP}".' + ) + # identity tag does not need to be fed forward + if variant == f"{TAG_SEP}identity": + all_tasks.extend(self.cfg.task_list) + continue + all_tasks.extend([task + variant for task in self.cfg.task_list]) + logger.debug(f"Created task variant {variant} for all tasks.") + self.cfg.task_list = all_tasks + # check if tasks contain duplicates and guarantee different namings of tasks + tmp_tasklist = self.cfg.task_list.copy() + if len(set(tmp_tasklist)) < len(tmp_tasklist): + mod_dic = {x: 0 for x in tmp_tasklist} + for ix in range(len(tmp_tasklist)): + mod_dic[tmp_tasklist[ix]] += 1 + if tmp_tasklist.count(tmp_tasklist[ix]) > 1: + tmp_tasklist[ix] += f"{TAG_SEP}duplicate{ARG_SEP}" + str(mod_dic[tmp_tasklist[ix]]) + self.cfg.task_list = tmp_tasklist + logger.info(f"Found {sum(mod_dic.values())} duplicates in task list and modified their names.") + # setting of pivot dataset + self.pivot = self.cfg.pivot.name + if self.pivot: + # handle pivot specific tags + new_name = (self.pivot + self.cfg.pivot.tags).strip() + # replace tags in tasks / add to tasks + if self.pivot not in self.cfg.task_list: + self.cfg.task_list.append(new_name) + logger.info(f"Added pivot task {new_name} to task_list.") + else: + warnings.warn( + "Pivot has also been found in task_list, this avoids any tagging.all and " + "tagging.variants configuration. But it applies pivot.tags." + ) + self.cfg.task_list[self.cfg.task_list.index(self.pivot)] = new_name + self.pivot = new_name + logger.info("Pivot task is " + self.highlight_text(self.pivot) + ".") + + for task in self.cfg.task_list: + if " " in task: + raise MMLMisconfigurationException( + f"Tagging syntax has changed. Avoid whitespace inside tags and use " + f"{TAG_SEP} to separate tags, as well as {ARG_SEP} to seperate " + f"arguments, e.g. task_name{TAG_SEP}tag1{TAG_SEP}tag2{ARG_SEP}" + f"arg1oftag2{ARG_SEP}arg2oftag2{TAG_SEP}tag3." + ) + # create TaskStructFactory + self.task_factory = TaskStructFactory(self.cfg, load=False) + + # managing the scheduler + self.commands: List[Callable[[...], None]] = [] + self.params: List[List[...]] = [] + self.planned_schedule = self.fm.log_path / "scheduler_plan.txt" + self.status_log = self.fm.log_path / "scheduler_log.txt" + # create commands and params + # -- prepare experiment + self.commands.append(self.prepare_exp) + self.params.append([]) + # -- scheduler specific commands + self.create_routine() + # -- finish experiment + self.commands.append(self.finish_exp) + self.params.append([]) + + if len(self.commands) != len(self.params): + raise RuntimeError( + "Commands and Params length do not match in schedule creation. Please check your " + "create_routine implementation." + ) + # create string version of schedule + coms = [command.__name__ for command in self.commands] + pars = [str(param) for param in self.params] + schedule_lines = ["method: " + coms[ix] + " / " + pars[ix] + "\n" for ix in range(len(coms))] + + # if not continue - give warning and overwrite old scheduler plan and add to log (with marker) + if not self.continue_status: + # write out schedule + with open(self.planned_schedule, "w") as file: + file.writelines(schedule_lines) + # append to status log + with open(self.status_log, "a") as file: + file.writelines( + [ + "HEADER\n", + "Timepoint of beginning\n", + datetime.datetime.now().strftime("%Y-%m-%d/%H-%M-%S") + "\n", + "START\n", + ] + ) + else: + # this is "continue" mode, first check if there has been a previous run of the experiment + if not self.planned_schedule.exists(): + raise FileNotFoundError( + f"Did not find any planned schedule (should be at {self.planned_schedule}). " + f"Has this run finished already?" + ) + # load previous schedule + with open(self.planned_schedule, "r") as file: + previous_lines = file.readlines() + # compare schedules - first the lengths + if len(previous_lines) != len(schedule_lines): + msg = ( + f"Continue mode failed: Old schedule has length {len(previous_lines)} but actual settings " + f"require schedule of length {len(schedule_lines)}." + ) + logger.error(msg) + raise ValueError(msg) + # next compare content + unmatching = [ + self.compare_schedule_entries(previous_lines[ix], schedule_lines[ix]) + for ix in range(len(previous_lines)) + ] + if any(unmatching): + dif_ix = unmatching.index(True) + msg = ( + f"Content of previous schedule and actual schedule differ at {unmatching.count(True)} places. " + f"First difference is {previous_lines[dif_ix]} (previous) versus {schedule_lines[dif_ix]} " + f"(now) in line {dif_ix}." + ) + logger.error(msg) + raise ValueError(msg) + # we will not need previous schedule anymore + del previous_lines + logger.info("Previously canceled schedule matches current one!") + # schedules seem to match, find correct position in schedule, start with loading status log + with open(self.status_log, "r") as file: + status_lines = file.readlines() + status_lines = [line.strip() for line in status_lines] + # calculate already processed steps + counter = 0 + runtime_counter = 1 + for ix in range(1, len(status_lines)): + if "method:" == status_lines[ix][:7]: + counter += 1 + elif "CONTINUE" == status_lines[ix][:8]: + # if already (successfully) continued, be aware that the initial experiment preparation is added + if len(status_lines) > ix + 1: + runtime_counter += 1 + logger.info( + f"Evaluated existing previous runs. Found {runtime_counter} previous runs and {counter}/" + f"{len(self.commands)} commands completed so far." + ) + # skip already executed commands (and corresponding params) + self.commands = self.commands[counter:] + self.params = self.params[counter:] + # add preparation at the beginning of the experiment + self.commands = [self.prepare_exp] + self.commands + self.params = [[]] + self.params + # append continuation to status log + with open(self.status_log, "a") as file: + file.writelines( + [ + "HEADER\n", + "Timepoint of continuation\n", + datetime.datetime.now().strftime("%Y-%m-%d/%H-%M-%S") + "\n", + "CONTINUE\n", + ] + ) + # hold callback references + self.metrics_callback: Optional[MetricsTrackerCallback] = None + self.checkpoint_callback: Optional[ModelCheckpoint] = None + # finalize initialisation + self._run_after_init_hooks() + self._run_checks() + logger.debug("Finished initialization of scheduler...") + + def _run_after_init_hooks(self): + """ + Runs some global hooks. These can be set by plugins to modify default behaviour of any scheduler. + + .. code-block:: python + + from mml.core.script.base_scheduler import AFTER_SCHEDULER_INIT_HOOKS + + def my_hook(scheduler: AbstractBaseScheduler) -> None: + print(scheduler.cfg) + + AFTER_SCHEDULER_INIT_HOOKS.append(my_hook) + + :return: + """ + for hook in AFTER_SCHEDULER_INIT_HOOKS: + logger.info(f"Executing after init hook: {hook.__name__}") + hook(self) + + def _run_checks(self): + """ + This is where some basic checks are made if configs / setup make sense. + :return: + """ + # check if preprocessing id is set correctly (only necessary if started via hydra) + try: + hydra_cfg = HydraConfig.get() + except ValueError: + hydra_cfg = None + if hydra_cfg: + choices = OmegaConf.to_container(hydra_cfg.runtime.choices) + if Path(choices["preprocessing"]).stem != self.cfg.preprocessing.id: + raise MMLMisconfigurationException( + f'Preprocessing config id {self.cfg.preprocessing.id} does not match' + f' config file name {choices["preprocessing"]}!' + ) + # check if preprocessing pipeline matches + if self.cfg.preprocessing.id != "none": + storage_definition_path = self.fm.get_pp_definition(preprocessing=self.cfg.preprocessing.id) + if storage_definition_path.exists(): + storage_pipeline = OmegaConf.load(storage_definition_path) + if storage_pipeline != self.cfg.preprocessing.pipeline: + raise MMLMisconfigurationException( + f"Found a missmatch in preprocessing configurations.\n" + f"Preprocessing ID is : {self.cfg.preprocessing.id}.\n" + f"Existing preprocessing folder defines this pipeline as:\n" + f"{storage_pipeline}\n" + f"Current preprocessing config defines pipeline as:" + f"{self.cfg.preprocessing.pipeline}." + ) + # ensure torch.compile is not used in conjunction witch learning rate tuning + if self.cfg.tune.lr and self.cfg.compile.enable: + raise MMLMisconfigurationException( + f"Tune lr {self.cfg.tune.lr} currently not supported with compile enable" + f" {self.cfg.compile.enable} due to torch compile checkpointing issue." + f" To be resolved in a future version!" + ) + + def set_active_naming(self, command_ix) -> None: + """ + Defines the active_step_naming attribute for the given command index. + + :param command_ix: index of the command + :return: None + """ + prefix = self.commands[command_ix].__name__ + "--" + "_".join([str(param) for param in self.params[command_ix]]) + suffix = "_" + datetime.datetime.now().strftime("%Y-%m-%d--%H-%M-%S") + if self.continue_status and self.fm.checkpoint_path.exists(): + # in case of continuing we need to reuse the old timestamp (for loading last model checkpoint) + previous_active_steps = sorted([p for p in self.fm.checkpoint_path.iterdir() if p.name.startswith(prefix)]) + if len(previous_active_steps) > 0 and (previous_active_steps[-1] / "last.ckpt").exists(): + suffix = "_" + previous_active_steps[-1].name.split("_")[-1] + assert (self.fm.checkpoint_path / (prefix + suffix)).exists() + else: + warnings.warn(f"Not successful to find a model checkpoint at {self.fm.checkpoint_path} with {prefix=}.") + self.active_step_naming = prefix + suffix + + # next there are some virtual methods that must/may be overwritten + @abc.abstractmethod + def create_routine(self) -> None: + """ + Adds commands and parameters to the schedule. May e.g. be in the form of: + + .. code-block:: python + + if 'xyz' in self.subroutines: + for task in self.cfg.task_list: + self.commands.append(self.MY_IMPLEMENTED_ROUTINE) + self.params.append([task]) + + :return: None + """ + pass + + def after_preparation_hook(self) -> None: + """ + This hook is usually used if the scheduler itself contains data that is + modified across subroutines. To ensure the capability to use the continue flag, this routine may search for + a dumped version and load it. See mml.task_similarity.scripts.abstract_task_distance_scheduler for an example + usage. + """ + pass + + def before_finishing_hook(self): + """ + Final hook at the end of an experiment, depending on the subroutines executed. Example could be some results + plotting. See mml_similarity.scripts.abstract_task_distance_scheduler for an example usage. + """ + pass + + # main routine + def run(self) -> float: + """ + The run routine starts the schedule and logs the process (within a file at self.status_log). + + :return: self.return_value (which might be set during runtime) + """ + for ix, command in enumerate(self.commands): + # undo continue status after preparation + if self.continue_status and ix >= 2: + self.continue_status = False + # set active_step_naming (used for logging) + self.set_active_naming(ix) + # seed the step + if self.cfg.seed: + with throttle_logging(logging.INFO): + seed_everything(self.cfg.seed, workers=True) + logger.debug(f"Random seeding with seed {self.cfg.seed} performed.") + # run the command with parameters + logger.debug( + f"Trying to run command ({ix + 1}/{len(self.commands)}): {command.__name__} with params: " + f"{self.params[ix]}" + ) + with catch_time() as timer: + command(*self.params[ix]) + logger.debug(f"Command run successfully within {timer.pretty_time}.") + # reset callback references + self.metrics_callback = None + self.checkpoint_callback = None + # backup all current tasks + if command.__name__ != "finish_exp": + self.task_factory.dump(clear_container=False) + # log after successful command (except for continued exp_prep command) + if command.__name__ == "prepare_exp" and self.continue_status: + logger.debug("Skipping status logging of continued experiment preparation!") + else: + with open(self.status_log, "a") as file: + file.write("method: " + command.__name__ + " / " + str(self.params[ix]) + "\n") + return self.return_value + + def prepare_exp(self) -> None: + """ + First command of any experiment. Mainly handles loading of task structs and seeding of experiment. Specific + preparation might also be done with the >additional_preparation_instructions<. USE THAT INSTEAD AND DO NOT + OVERWRITE THIS FUNCTION UNLESS YOU KNOW WHAT YOU DO. + + :return: None + """ + # prepare TaskStructFactory (only if unloaded) + assert len(self.task_factory.container) == 0, "TaskFactory should be empty prior to loading tasks!" + if self.continue_status: + logger.info("Trying to prepare loading to continue experiment...") + # restore previous task structs + self.task_factory.loading_old_dump() + # assert compliance + assert set([task.name for task in self.task_factory.container]) == set( + self.cfg.task_list + ), f"Loading of {len(self.cfg.task_list)} tasks failed. Inconsistent tasks from loading path {os.getcwd()}!" + else: + logger.info("Preparing experiment ...") + # create task struct for every task in task list + for task in self.cfg.task_list: + self.task_factory.create_task_struct(name=task, return_ref=False) + # loading additional resources dependent on routines + self.after_preparation_hook() + logger.info("Starting experiment!") + + def finish_exp(self) -> None: + """ + Last command of any experiment, this is how every experiment finishes. Ensures dumping of task factory, + unlinks the planned schedule, removes intermediate results if specified in config and allows also for + specific instructions of any subclass via the >additional_finishing_instructions< interface. USE THAT INSTEAD + AND DO NOT OVERWRITE THIS FUNCTION UNLESS YOU KNOW WHAT YOU DO. + + :return: None + """ + # call finishing instructions, e.g. plotting of results or deleting artifacts + self.before_finishing_hook() + # tear down the file manager + self.fm.remove_intermediates() + self.fm.clear_instance() + # clear the planed schedule file + self.planned_schedule.unlink() + logger.info("Successfully finished all experiments!") + + def create_trainer( + self, monitor: Optional[Tuple[str, str]] = None, metrics_callback: bool = False + ) -> lightning.Trainer: + """ + Creates a trainer from `cfg.trainer` with callbacks from `cfg.cbs`. By default, + uses two :class:`~mml.core.scripts.callbacks.MMLModelCheckpoint` callbacks that behave as follows: + + * at least every 30 minutes a checkpoint is stored to ensure resume compatibility, + * if monitor is given will keep the best model stored based thereof, regularly checking at the end of + each epochs validation + * if monitor is None only the very last epoch will be stored (besides the temporal check) + + The non-time based checkpoint may be accessed through :attr:`checkpoint_callback`. + + :param Optional[Tuple[str, str]] monitor: (optional) a tuple of metric name and mode (min or max) to be + monitored by model checkpoint (saves best model) and early stopping callback (if activated in cfg) + :param bool metrics_callback: (optional) if true creates and also a metric callback + :return: trainer instance, the callbacks can be accessed through the scheduler attributes + :attr:`metrics_callback` and :attr:`checkpoint_callback` + :rtype: Union[Tuple[pl.Trainer, ModelCheckpoint], Tuple[pl.Trainer, ModelCheckpoint, MetricsTrackerCallback]] + """ + cbs = [] + # if not monitoring a specific metric, only save last epoch + cpt_cb = MMLModelCheckpoint( + monitor=monitor[0] if monitor else None, + dirpath=self.get_checkpoints_dir(), + filename="epoch{epoch:02d}-val_loss{val/loss:.2f}", + auto_insert_metric_name=False, + save_last="link", + mode=monitor[1] if monitor else "min", + save_top_k=1, + save_on_train_epoch_end=False, + enable_version_counter=False, + ) + if self.checkpoint_callback: + logger.error( + "Checkpoint callback already initiated! You will only be able to access the latest " + "ModelCheckpoint through scheduler.checkpoint_callback!" + ) + self.checkpoint_callback = cpt_cb + cbs.append(cpt_cb) + # always ensure storing every 30 minutes + time_ckpt_cb = MMLModelCheckpoint( + dirpath=self.get_checkpoints_dir(), + filename="temp_backup", + save_last="link", + train_time_interval=datetime.timedelta(minutes=30), + enable_version_counter=False, + ) + cbs.append(time_ckpt_cb) + # handle interruptions gracefully + cbs.append(StopAfterKeyboardInterrupt()) + if ( + "enable_progress_bar" in self.cfg.trainer and self.cfg.trainer.enable_progress_bar + ) or "enable_progress_bar" not in self.cfg.trainer: + if self.cfg.logging.render.rich: + cbs.append(MMLRichProgressBar()) + else: + cbs.append(MMLTQDMProgressBar()) + if metrics_callback: + if self.metrics_callback: + logger.error( + "Metrics callback already initiated! You will only be able to access the latest " + "MetricsTrackerCallback through scheduler.metrics_callback!" + ) + met_cb = MetricsTrackerCallback() + self.metrics_callback = met_cb + cbs.append(met_cb) + for cb_id in self.cfg.cbs: + cb_conf = self.cfg.cbs[cb_id] + if "_target_" in cb_conf: + logger.debug(f"Instantiating callback <{cb_conf._target_}>") + cbs.append(instantiate(cb_conf)) + else: + logger.error(f"Invalid callback configuration: <{cb_conf}> for callback {cb_id}.") + if self.cfg.hpo.pruning: + # TODO + # this will be possible as soon as pruning is supported by hydra optuna sweeper, see + # https://github.com/facebookresearch/hydra/issues/1954 + # from optuna.integration.pytorch_lightning import PyTorchLightningPruningCallback + # prun_cb = PyTorchLightningPruningCallback(trial=None, monitor='val/loss') + # cbs.append(prun_cb) + warnings.warn("Pruning not yet supported by optuna hpo.", UserWarning) + if self.continue_status: + resume = self.get_checkpoints_dir() / "last.ckpt" + if not resume.exists(): + # seems like no checkpoint was saved + resume = None + logger.warning("Resuming from checkpoint not possible, since no training checkpoint was found!") + else: + resume = None + # set up logging + if "_target_" in self.cfg.logging.exp_logger: + if "TensorBoardLogger" in self.cfg.logging.exp_logger["_target_"]: + # set version for tensorboard logger + exp_logger = instantiate(self.cfg.logging.exp_logger, version=self.active_step_naming) + else: + # else only instantiate + exp_logger = instantiate(self.cfg.logging.exp_logger) + else: + # no exp logger specified + exp_logger = None + trainer = instantiate(self.cfg.trainer, logger=exp_logger, callbacks=cbs, enable_checkpointing=True) + if resume: + trainer.ckpt_path = resume + return trainer + + def lightning_tune( + self, + trainer: lightning.Trainer, + model: lightning.LightningModule, + datamodule: Optional[lightning.LightningDataModule], + train_dataloaders=None, + ) -> None: + """ + Tune a model / datamodule based on configs.tune setting. + + :param trainer: the lightning trainer + :param model: the lightning model + :param datamodule: the lightning datamodule + :param train_dataloaders: alternative method to provide the data, set datamodule to None in this case + :return: none, tuned values are stored inside model / datamodule + """ + if self.continue_status and (self.get_checkpoints_dir() / "last.ckpt").exists(): + # this assumes that there is at least ONE checkpoint available, which has tuning results stored + # if cancelling happened during first epoch we do not have this information + logger.info("Tuning skipped for continue mode.") + return + if self.cfg.tune.lr or self.cfg.tune.bs: + tuner = Tuner(trainer=trainer) + # disable caching + _old_caching = self.cfg.sampling.enable_caching + self.cfg.sampling.enable_caching = False + if _old_caching: + logger.info("Caching disabled while tuning.") + if self.cfg.tune.bs: + logger.info("Starting batch size optimization.") + tuner.scale_batch_size( + model=model, datamodule=datamodule, train_dataloaders=train_dataloaders, **self.cfg.tune.bs_kwargs + ) + if self.cfg.tune.lr: + logger.info("Starting learning rate optimization.") + tuner.lr_find( + model=model, datamodule=datamodule, train_dataloaders=train_dataloaders, **self.cfg.tune.lr_kwargs + ) + # restore caching state + self.cfg.sampling.enable_caching = _old_caching + + def get_checkpoints_dir(self): + """ + Path to store checkpoints currently. + + :return: Path to a folder to store training checkpoints + """ + return self.fm.checkpoint_path / self.active_step_naming + + def create_model( + self, task_structs: List[TaskStruct], task_weights: Optional[List[float]] = None + ) -> lightning.LightningModule: + """ + Creates a pytorch lightning module. + + :param List[TaskStruct] task_structs: list of task structs to construct lightning module + :param Optional[List[float]] task_weights: (optional) list of task weights to weigh loss + :return: LightningModule instance + """ + if any([Modality.IMAGE not in struct.modalities for struct in task_structs]): + raise NotImplementedError( + f"For now mml-core only supports single frame modules. Support of {Modality.VIDEO_CLIP} is planned." + ) + duplicate_structs = [copy.deepcopy(struct) for struct in task_structs] + for struct in duplicate_structs: + struct.models = [] # models might cause hparams saving issues with pytorch lightning + model = SingleFrameLightningModule(task_structs=duplicate_structs, cfg=self.cfg, weights=task_weights) + if self.cfg.compile.enable: + model.model = torch.compile(model.model, **self.cfg.compile.kwargs) + # deactivate strict loading for more compatibility + model.strict_loading = False + return model + + def get_struct(self, task_name: str) -> TaskStruct: + """ + Convenience function to access a task struct. + + :param str task_name: name of the task + :return: the corresponding task struct + """ + return self.task_factory.get_by_name(task_name) + + def create_datamodule( + self, task_structs: Union[TaskStruct, List[TaskStruct]], fold: int = 0 + ) -> MultiTaskDataModule: + """ + Creates a pytorch lightning datamodule. + + :param Union[TaskStruct, List[TaskStruct]] task_structs: task struct(s) to create datamodule from + :param int fold: fold to be used + :return: datamodule instance + """ + if isinstance(task_structs, TaskStruct): + task_structs = [task_structs] + return MultiTaskDataModule(task_structs=task_structs, cfg=self.cfg, fold=fold) + + def highlight_text(self, text: str) -> str: + """ + Helper function in highlighting text within terminal. May be turned of by the logging.highlight_task_names + config option. + + :param text: text to be highlighted + :return: modified text if highlighting is active, else plain input text + """ + if self.cfg.logging.highlight_text and not self.cfg.logging.render.rich: + return Fore.YELLOW + Back.CYAN + Style.BRIGHT + text + Style.RESET_ALL + else: + return text + + @staticmethod + def compare_schedule_entries(entry_1: str, entry_2: str) -> bool: + """ + Helper function in comparsion of schedules. + + :param entry_1: line of a schedule (command and args) + :param entry_2: line of a schedule (command and args) + :return: true if lines are compatible, else false + """ + pos_1 = entry_1.find("object at") + pos_2 = entry_1.find(" / ") + return entry_1[:pos_1] != entry_2[:pos_1] or entry_1[pos_2:] != entry_2[pos_2:] + + +# these hooks can be accessed by plugins to modify default scheduler behaviour +AFTER_SCHEDULER_INIT_HOOKS: List[Callable[[AbstractBaseScheduler], None]] = [] diff --git a/src/mml/core/scripts/schedulers/clean_scheduler.py b/src/mml/core/scripts/schedulers/clean_scheduler.py new file mode 100644 index 0000000..4577f90 --- /dev/null +++ b/src/mml/core/scripts/schedulers/clean_scheduler.py @@ -0,0 +1,158 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import shutil +import sys + +import humanize +from _collections import OrderedDict +from omegaconf import DictConfig + +from mml.core.data_preparation.registry import get_dset_for_task +from mml.core.scripts.schedulers.base_scheduler import AbstractBaseScheduler +from mml.core.scripts.utils import TAG_SEP + +logger = logging.getLogger(__name__) + + +class CleanScheduler(AbstractBaseScheduler): + """ + AbstractBaseScheduler implementation for the cleaning of files. Includes the following subroutines: + - temp + - download + """ + + def __init__(self, cfg: DictConfig): + # initialize + super(CleanScheduler, self).__init__(cfg=cfg, available_subroutines=["temp", "download"]) + logger.info( + "Clean mode helps removing file artefacts, cleaning your MML setup but also may disrupt running " + "MML processes. Please ensure not to run in parallel with any other MML command. By default " + "clean runs with mode.force=false and requires interactive approval, you may choose to set " + "force=true to omit this interactive part." + ) + self.sizes = [] + + def prepare_exp(self) -> None: + """ + We skip task struct creation, since it is not needed or may not be finished. + """ + logger.debug("Skip task struct creation.") + + def create_routine(self): + """ + This scheduler implements two subroutines, one for temp files cleaning and one for downloads cleaning. + + :return: None + """ + + if self.cfg.mode.all: + task_list = [task.split(TAG_SEP)[0] for task in self.fm.task_index.keys()] + # for backward compatibility with previous tag separators + task_list = [task.split(" ")[0] for task in task_list] + else: + task_list = [task.split(TAG_SEP)[0] for task in self.cfg.task_list] + # remove duplicates (e.g. via multiple existing tagged variants of a task) + task_list = list(OrderedDict.fromkeys(task_list)) + # -- add temp commands + if "temp" in self.subroutines: + for task in task_list: + self.commands.append(self.remove_temp_files) + self.params.append([task]) + # -- add download commands + if "download" in self.subroutines: + # run only once per dset + all_dsets = dict() # use dict instead of set zo ensure order + for task in task_list: + try: + dset = get_dset_for_task(task) + all_dsets[dset] = None + except KeyError: + logger.error("No registered dset link for task {}".format(task)) + for dset in all_dsets: + self.commands.append(self.remove_downloads) + self.params.append([dset]) + + def remove_temp_files(self, task_name: str) -> None: + """ + Routine to remove temporary files that may remain as artefacts during task creation. They are located inside + the data path either below RAW or PREPROCESSED inside the dataset folders and are named temp.json or temp_X.json + with integer X. + + :param str task_name: name of the task to remove temp files (will concern both RAW and PREPROCESSED variants) + :return: None + """ + logger.info("Starting removing of temp files for " + self.highlight_text(task_name)) + # collect all files + to_remove = [] + dset_roots = [self.fm.raw_data] + list(self.fm.preprocessed_data.iterdir()) + for root in dset_roots: + for dset_path in root.iterdir(): + # glob over possible files + for file_path in dset_path.glob("temp*.json"): + try: + if self.fm.load_task_description_header(file_path).name == task_name: + to_remove.append(file_path) + except RuntimeError: + # potentially the task description is formatted in an old way + to_remove.append(file_path) + if len(to_remove) > 0: + logger.warning(f"Found {len(to_remove)} temp files for task {task_name}. Will remove now.") + else: + logger.info(f"Found no temp file for task {task_name}.") + for tmp_file in to_remove: + if not self.cfg.mode.force: + print(f"Are you sure to remove {tmp_file}? [Y/n]") + answer = input() + if answer.lower() not in ["y", "n", ""]: + print("Invalid input, will cancel clean scheduler.") + self.log_cumulative_sizes() + sys.exit(1) + if answer.lower() == "n": + print(f"Will not remove {tmp_file}.") + continue + self.sizes.append(tmp_file.stat().st_size) + tmp_file.unlink() + logger.info("Finished removing temp files for " + self.highlight_text(task_name)) + + def remove_downloads(self, dset_name: str) -> None: + """ + Routine to remove the downloads of a dataset. May remove data for multiple tasks at once! Make sure that + original download data is still available later on for full reproducibility. + + :param str dset_name: name of the dset + :return: None + """ + logger.info("Starting removing downloads for " + self.highlight_text(dset_name)) + d_path = self.fm.get_download_path(dset_name=dset_name) + # gather size + size = sum(f.stat().st_size for f in d_path.glob("**/*") if f.is_file()) + logger.warning( + f"Will remove {humanize.naturalsize(size, gnu=True)} bytes in downloads for dataset " + f"{dset_name} at {d_path}." + ) + do_remove = True + if not self.cfg.mode.force: + print(f"Are you sure to remove {d_path}? [Y/n]") + answer = input() + if answer.lower() not in ["y", "n", ""]: + print("Invalid input, will cancel clean scheduler.") + self.log_cumulative_sizes() + sys.exit(1) + if answer.lower() == "n": + print(f"Will not remove {d_path}.") + do_remove = False + if do_remove: + self.sizes.append(size) + shutil.rmtree(d_path) + logger.info("Finished removing downloads for " + self.highlight_text(dset_name)) + + def log_cumulative_sizes(self) -> None: + logger.info(f"Cumulative sizes for removed files are {humanize.naturalsize(sum(self.sizes), gnu=True)} bytes.") + + def before_finishing_hook(self): + self.log_cumulative_sizes() diff --git a/src/mml/core/scripts/schedulers/create_scheduler.py b/src/mml/core/scripts/schedulers/create_scheduler.py new file mode 100644 index 0000000..5624422 --- /dev/null +++ b/src/mml/core/scripts/schedulers/create_scheduler.py @@ -0,0 +1,137 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +from pathlib import Path + +from _collections import OrderedDict +from omegaconf import DictConfig + +import mml.core.data_preparation.task_creator +from mml.core.data_preparation.registry import ( + _DATASET_CREATORS, + _TASKCREATORS, + get_dset_creator, + get_dset_for_task, + get_task_creator, +) +from mml.core.scripts.exceptions import MMLMisconfigurationException +from mml.core.scripts.schedulers.base_scheduler import AbstractBaseScheduler +from mml.core.scripts.utils import TAG_SEP + +logger = logging.getLogger(__name__) + + +class CreateScheduler(AbstractBaseScheduler): + """ + AbstractBaseScheduler implementation for the Dataset and Task creation process. Includes the following subroutines: + - dataset + - task + """ + + def __init__(self, cfg: DictConfig): + # initialize + super(CreateScheduler, self).__init__(cfg=cfg, available_subroutines=["dataset", "task"]) + assert self.cfg.preprocessing.id == "none", ( + f"Create mode only possible for preprocessing=none, gave " + f"{self.cfg.preprocessing.id}. Use pp mode to create preprocessed" + f" version afterwards." + ) + # when starting mml from __main__.py plugins are already loaded, but here we check for other ways of starting + if len(_TASKCREATORS) == 0 or len(_DATASET_CREATORS) == 0: + raise RuntimeError( + "Was not able to find any task creators and/or dataset creators! If you rely on plugins " + "to provide data or task creators make sure to call " + "mml.core.scripts.utils.load_mml_plugins() before." + ) + if not isinstance(self.cfg.mode.n_folds, int) or self.cfg.mode.n_folds < 2: + raise MMLMisconfigurationException("mode.n_folds must be an integer larger 1!") + mml.core.data_preparation.task_creator.DEFAULT_N_FOLDS = self.cfg.mode.n_folds + if not isinstance(self.cfg.mode.ensure_balancing, bool): + raise MMLMisconfigurationException("mode.n_folds must be a boolean!") + mml.core.data_preparation.task_creator.DEFAULT_ENSURE_BALANCED = self.cfg.mode.ensure_balancing + + def prepare_exp(self) -> None: + """ + Prepare experiment expects tasks to be present and loads these into task factory container. Here this should + be avoided. + """ + logger.info("Starting task creation!") + + def create_routine(self): + """ + This scheduler implements two subroutines, one for dataset preparation and one for task preparation. + + :return: None + """ + # determine + filtered_tasks = [] + for task in self.cfg.task_list: + if TAG_SEP in task: + logger.critical( + f"Task {task} is a tagged task and should not be created via create scheduler!" + f"Please create the base task and run any other mode with the tagged version to " + f"create the tagged task." + ) + continue + if task in self.fm.task_index.keys() and "none" in self.fm.task_index[task]: + logger.info( + f"Skipping creation of task {task} because there already seems to be a RAW version of " f"that." + ) + continue + filtered_tasks.append(task) + # -- add download commands + if "dataset" in self.subroutines: + all_dsets_req = list(OrderedDict.fromkeys([get_dset_for_task(task) for task in filtered_tasks])) + for dset in all_dsets_req: + self.commands.append(self.prepare_dataset) + self.params.append([dset]) + # -- add task creation commands + if "task" in self.subroutines: + for task in filtered_tasks: + self.commands.append(self.create_task) + self.params.append([task]) + + def prepare_dataset(self, dset_name): + logger.info("Starting preparing dataset " + self.highlight_text(dset_name)) + all_dsets = self.fm.get_all_dset_names() + if dset_name in all_dsets["none"]: + logger.info( + f"Dataset {dset_name} already downloaded and prepared. If you encounter problems with this " + f"dataset, delete {all_dsets['none'][dset_name]} and rerun." + ) + dset_path = all_dsets["none"][dset_name] + else: + dset_creator = get_dset_creator(dset_name=dset_name) + # run creator + output = dset_creator() + if isinstance(output, Path): + logger.debug(f"Dataset created @ {output}.") + dset_path = output + else: + raise RuntimeError( + f"Registered creator {dset_creator.__name__} for dataset {dset_name} did not " + f"provide a path, but {type(output)}." + ) + logger.debug(f"Find dataset {dset_name} @ {dset_path}.") + logger.info("Finished preparing dataset " + self.highlight_text(dset_name)) + + def create_task(self, task_name): + logger.info("Starting preparing task " + self.highlight_text(task_name)) + all_dsets = self.fm.get_all_dset_names() + dset_name = get_dset_for_task(task_name=task_name) + assert dset_name in all_dsets["none"], f"Dataset {dset_name} not available to start preparing {task_name}." + dset_path = all_dsets["none"][dset_name] + task_creator = get_task_creator(task_name) + output = task_creator(dset_path=dset_path) + if output is None or isinstance(output, Path): + logger.debug(f"Task {task_name} fully created by task creator f{task_creator.__name__}.") + else: + raise RuntimeError( + f"Registered creator {task_creator.__name__} for task {task_name} output did not match expectations, " + f"it provided {type(output)}." + ) + logger.info("Finished preparing task " + self.highlight_text(task_name)) diff --git a/src/mml/core/scripts/schedulers/info_scheduler.py b/src/mml/core/scripts/schedulers/info_scheduler.py new file mode 100644 index 0000000..0b64c3c --- /dev/null +++ b/src/mml/core/scripts/schedulers/info_scheduler.py @@ -0,0 +1,214 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +from pathlib import Path + +import numpy as np +import optuna +import torch +from omegaconf import DictConfig +from PIL import Image +from prettytable.colortable import ColorTable, Themes +from torchvision.utils import make_grid +from tqdm import tqdm + +from mml.core.data_loading.task_attributes import DataSplit, Modality, TaskType +from mml.core.data_loading.task_dataset import TaskDataset +from mml.core.scripts.exceptions import MMLMisconfigurationException +from mml.core.scripts.schedulers.base_scheduler import AbstractBaseScheduler +from mml.core.scripts.utils import LearningPhase, throttle_logging + +logger = logging.getLogger(__name__) + + +class InfoScheduler(AbstractBaseScheduler): + """ + AbstractBaseScheduler implementation for receiving information on a project. Includes the following subroutines: + - tasks (show information on tasks) + - hpo (show information on hpo results) + - samples (plots sample images for each task (and/or jointly)) + - models (show information on existing model descriptions) + """ + + def __init__(self, cfg: DictConfig): + # initialize + super(InfoScheduler, self).__init__(cfg=cfg, available_subroutines=["tasks", "hpo", "samples", "models"]) + self.total_sample_sum = 0 + + def create_routine(self): + """ + This scheduler implements two subroutines, one for task information and one for hpo study information. + + :return: None + """ + # -- add task info commands + if "tasks" in self.subroutines: + for task in self.cfg.task_list: + self.commands.append(self.info_task) + self.params.append([task]) + # -- add study info commands + if "hpo" in self.subroutines: + if self.cfg.mode.study_name: + # was given a single study + self.commands.append(self.info_study) + self.params.append([self.cfg.mode.study_name]) + else: + # show all available studies for this project + logger.info("Was given no study name to search for, so showing all studies with project prefix.") + study_summaries = optuna.study.get_all_study_summaries(storage=self.cfg.hpo.storage) + logger.debug(f"Found {len(study_summaries)} studies in database.") + filtered_studies = [ + study.study_name for study in study_summaries if str(study.study_name).startswith(self.cfg.proj) + ] + for study_name in filtered_studies: + self.commands.append(self.info_study) + self.params.append([study_name]) + # -- add sample plotting command + if "samples" in self.subroutines: + self.commands.append(self.plot_samples) + self.params.append([]) + # -- add MODEL info command + if "models" in self.subroutines: + self.commands.append(self.info_models) + self.params.append([]) + + def after_preparation_hook(self): + pass + + def before_finishing_hook(self): + logger.info(f"Total number of all samples: {self.total_sample_sum}.") + + def prepare_exp(self) -> None: + # no need to prepare tasks if only looking at hpo results + if "tasks" in self.subroutines or "sample_grid" in self.subroutines or "models" in self.subroutines: + super(InfoScheduler, self).prepare_exp() + + def info_task(self, task_name: str) -> None: + logger.info("Starting info on task " + self.highlight_text(task_name)) + task_struct = self.get_struct(task_name) + logger.info(str(task_struct)) + dataset = TaskDataset( + root=Path(self.cfg.data_dir) / task_struct.relative_root, split=DataSplit.FULL_TRAIN, fold=0, transform=None + ) + logger.info(f"Num samples (full train set): {len(dataset)}") + self.total_sample_sum += len(dataset) + if dataset.task_type == TaskType.CLASSIFICATION: + dataset.select_samples(split=DataSplit.VAL, fold=0) + class_occ = {} + for sample in dataset.samples: + _cl = sample[Modality.CLASS] + if _cl in class_occ: + class_occ[_cl] += 1 + else: + class_occ[_cl] = 1 + logger.info(f"Default validation class occurrences are: {class_occ}") + logger.info("Finished info on task " + self.highlight_text(task_name)) + + def info_study(self, study_name: str) -> None: + logger.info("Starting info on study " + self.highlight_text(study_name)) + try: + loaded_study = optuna.load_study(study_name=study_name, storage=self.cfg.hpo.storage) + except KeyError: + raise MMLMisconfigurationException( + f"Study {study_name} not found! Adapt mode.study_name config, " + f"and check your hpo.storage settings to make studies persistent. " + f"See https://docs.sqlalchemy.org/en/20/core/engines.html for details." + f"Create the study from scratch with mml ... " + f"hydra.sweeper.study_name=YOUR_STUDY_NAME " + f"hpo.storage=YOUR_STORAGE_SETTING --multirun." + ) + df = loaded_study.trials_dataframe() + logger.info(f"Detailed study info:\n{df.drop(columns='number').to_string()}") + logger.info(f"Statistics of study:\n{df.drop(columns=['number', 'duration']).describe().T.to_string()}") + top = ( + df.drop( + columns=[ + "number", + "duration", + "datetime_start", + "datetime_complete", + "state", + "system_attrs_search_space", + ] + ) + .sort_values(by="value", ascending=self.cfg.hpo.direction == "minimize", ignore_index=True) + .head(5) + .T.to_string() + ) + logger.info(f"Top entries:\n{top}") + if len(loaded_study.get_trials(states=(optuna.trial.TrialState.COMPLETE,))) > 0: + best_params = loaded_study.best_params + best_val = loaded_study.best_value + logger.info(f"Best params: {best_params}") + logger.info(f"Best value: {best_val}") + else: + logger.info("No complete trial corresponding to this study has been found.") + logger.info("Finished info on study " + self.highlight_text(study_name)) + + def plot_samples(self) -> None: + logger.info("Starting plotting sample grid of all tasks.") + if len(self.cfg.task_list) == 0: + logger.error("No tasks selected to show samples from.") + return + img_samples = {} + # sort by sample size + task_sizes = {struct.name: sum(struct.class_occ.values()) for struct in self.task_factory.container} + task_list = sorted(task_sizes.items(), key=lambda x: x[1]) + for task_name in tqdm([t[0] for t in task_list], desc="Loading samples"): + task_struct = self.get_struct(task_name=task_name) + datamodule = self.create_datamodule(task_structs=task_struct) + # suppress warning of non-normalized image usage + with throttle_logging(level=logging.WARNING, package="mml.core.data_loading.lightning_datamodule"): + datamodule.setup(stage="fit") + img_samples[task_name] = datamodule.task_datasets[task_name][LearningPhase.TRAIN][-1][Modality.IMAGE] * 255 + if self.cfg.mode.info_grid: # gridplot + proportion = 11 / 5 # width to height proportion + grid = make_grid(tensor=list(img_samples.values()), nrow=int(np.sqrt(len(img_samples) * proportion))) + path = self.fm.construct_saving_path(obj=grid, key="sample_grid") + ndarr = grid.permute(1, 2, 0).to("cpu", torch.uint8).numpy() + im = Image.fromarray(ndarr) + im.save(path) + logger.info(f"Finished plotting sample grid. Can be found at {path}.") + if self.cfg.mode.info_individual: # individual samples plots + for task_name, img_tensor in img_samples.items(): + path = self.fm.construct_saving_path(obj=img_tensor, key="img_examples", task_name=task_name) + ndarr = img_tensor.permute(1, 2, 0).to("cpu", torch.uint8).numpy() + im = Image.fromarray(ndarr) + im.save(path) + logger.info("Finished plotting individual samples for each task.") + + def info_models(self): + if len(self.cfg.task_list) == 0: + logger.error("No tasks selected to show models from.") + return + logger.info( + "Model info shows only loaded models (not all existing!). Use reuse.models=... to select a " + "project to load models from." + ) + table = ColorTable(theme=Themes.OCEAN) + table.field_names = ["task", "created", "fold", "performance", "training (secs)", "params?", "preds?"] + no_model_tasks = [] + for task in self.cfg.task_list: + task_models = self.get_struct(task).models + if len(task_models) == 0: + no_model_tasks.append(task) + continue + for ix, model in enumerate(task_models): + table.add_row( + [ + model.task, + model.created, + model.fold, + f"{model.performance:.8f}" if model.performance else "x", + int(model.training_time), + "y" if model.parameters and model.parameters.exists() else "n", + len(model.predictions), + ], + divider=ix + 1 == len(task_models), + ) + print(table) + logger.info(f"No models found for {len(no_model_tasks)} tasks ({no_model_tasks}).") diff --git a/src/mml/core/scripts/schedulers/postprocess_scheduler.py b/src/mml/core/scripts/schedulers/postprocess_scheduler.py new file mode 100644 index 0000000..f345275 --- /dev/null +++ b/src/mml/core/scripts/schedulers/postprocess_scheduler.py @@ -0,0 +1,450 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import importlib +import itertools +import logging +import warnings +from typing import Dict, List, Optional, Tuple + +import numpy as np +import omegaconf +import quapy +import quapy.data.datasets +import sklearn.base +import torch +import torch.nn as nn +from omegaconf import DictConfig +from psrcal.calibration import AffineCalLogLoss, calibrate +from quapy.method.aggregative import ACC +from torchmetrics import BootStrapper, MetricCollection +from tqdm import tqdm + +from mml.core.data_loading.task_attributes import DataSplit, TaskType +from mml.core.scripts.decorators import beta +from mml.core.scripts.exceptions import MMLMisconfigurationException +from mml.core.scripts.model_storage import EnsembleStorage, ModelStorage +from mml.core.scripts.schedulers.base_scheduler import AbstractBaseScheduler +from mml.core.scripts.utils import ARG_SEP, TAG_SEP, LearningPhase + +importlib.reload(warnings) + +logger = logging.getLogger(__name__) + + +@beta("Postprocessing mode is in beta.") +class PostprocessScheduler(AbstractBaseScheduler): + """ + Scheduler for post-processing predictions, supports the following sub-routines: + - calibrate + - ensemble + """ + + def __init__(self, cfg: DictConfig): + if not cfg.pivot.name: + raise MMLMisconfigurationException("Must provide a pivot task for post-processing!") + self.models: Dict[str, List[ModelStorage]] = {} # will hold relevant model storages + self.eval_logits: Dict[Tuple[str, int], torch.Tensor] = {} # will hold loaded predictions for speed + self.eval_labels: Optional[torch.Tensor] = None # will hold evaluation labels + super(PostprocessScheduler, self).__init__(cfg=cfg, available_subroutines=["calibrate", "ensemble"]) + if self.cfg.mode.eval_frac < 0 or self.cfg.mode.eval_frac >= 1: + raise MMLMisconfigurationException( + f"mode.eval_frac={self.cfg.mode.eval_frac} is not valid! Should be " f"strictly between 0 and 1!" + ) + if self.cfg.mode.temperature >= 1 or self.cfg.mode.weights_temperature >= 1: + raise MMLMisconfigurationException("ensemble search temperatures must be below 1!") + if self.cfg.mode.temperature < 0 or self.cfg.mode.weights_temperature < 0: + raise MMLMisconfigurationException("ensemble search temperatures must be at least 0!") + + def after_preparation_hook(self): + # checks: only support classification pivots for now - not even multiclass or regression + struct = self.get_struct(self.pivot) + if struct.task_type != TaskType.CLASSIFICATION: + raise MMLMisconfigurationException("Only classification tasks are supported for post-processing!") + + def create_routine(self): + """ + This scheduler implements two sub-routines, calibration as well as combined selection and prediction for + ensembles. The routine takes care of finding any relevant previous predictions in this project. + """ + # predictions on the pivot task may be done from models trained upon any other task (!) + all_models = { + task: self.fm.reusables[task]["models"] for task in self.fm.reusables if "models" in self.fm.reusables[task] + } + # models must have a corresponding prediction entry to match the current pivot + for task in all_models: + relevant_models = [m for m in all_models[task] if self.pivot in m.predictions] + if len(relevant_models) > 0: + self.models[task] = sorted(relevant_models, key=lambda m: m.created) + if len(self.models) == 0: + raise RuntimeError( + "No models available for post-processing! You may reuse existing models via " + "reuse.models=SOME_PROJECT or short reuse=current for reusing models from the current " + "project. To train models run mml train with your current pivot task." + ) + if "calibrate" in self.subroutines: + for task in self.models: + for model_idx, model in enumerate(self.models[task]): + self.commands.append(self.calibrate_predictions) + self.params.append([task, model_idx]) + if "ensemble" in self.subroutines: + self.commands.append(self.select_ensemble) + self.params.append([]) + + def calibrate_predictions(self, task: str, model_index: int): + logger.info(f"Calibrating predictions {model_index} for task " + self.highlight_text(task)) + model = self.models[task][model_index] + # also consider nested predictions + predictions = [ + pred + for pred in model.predictions + if pred == self.pivot or pred.startswith(f"{self.pivot}{TAG_SEP}nested{ARG_SEP}") + ] + for pred in predictions: + # load prediction + all_splits_prediction = torch.load(model.predictions[pred]) + # we use the validation split as base for inferring calibration parameters + if DataSplit.VAL.value not in all_splits_prediction: + raise RuntimeError( + f"No predictions have been made on validation data for model @ {model._stored}" + f"and prediction on {pred} (@ {model.predictions[pred]})." + ) + all_logits = {} + all_labels = {} + for split in [DataSplit.VAL, DataSplit.TEST, DataSplit.UNLABELLED]: + if split.value not in all_splits_prediction or len(all_splits_prediction[split.value]) == 0: + continue + all_logits[split] = torch.stack([item["logits"] for item in all_splits_prediction[split.value]]).float() + if split != DataSplit.UNLABELLED: + all_labels[split] = torch.tensor([item["target"] for item in all_splits_prediction[split.value]]) + if self.cfg.mode.prior == "test": + # derive optimal priors from test data + prior = torch.bincount(all_labels[DataSplit.TEST]) + # to avoid any zero division we assume a minimum probability + prior = np.clip(prior, a_min=1e-8, a_max=None) + # scaling for convergence stability + prior = prior / prior.sum() + elif self.cfg.mode.prior == "quantify": + use_as_train_split = DataSplit.TEST + if DataSplit.UNLABELLED not in all_logits: + warnings.warn( + "Calibration prior quantify expects predictions on unlabeled split! Any prediction " + "without unlabeled split (e.g. from nested training) will fall back to calibrate" + "according to the validation split prevalences" + ) + prior = None + else: + if DataSplit.TEST not in all_logits: + warnings.warn( + "No test set predictions found - will fall back to val set in order to quantify " + "unlabeled data prevalences." + ) + use_as_train_split = DataSplit.VAL + # convert data to qp format + qp_train_data = quapy.data.LabelledCollection( + torch.softmax(all_logits[use_as_train_split], dim=1), + all_labels[use_as_train_split], + classes=list(range(self.get_struct(self.pivot).num_classes)), + ) + qp_test_data = quapy.data.LabelledCollection( + [], [], classes=list(range(self.get_struct(self.pivot).num_classes)) + ) + qp_dset = quapy.data.base.Dataset(training=qp_train_data, test=qp_test_data) + + # define dummy classifier to be used with quapy + class IdentityClassifier(sklearn.base.BaseEstimator, sklearn.base.ClassifierMixin): + def __init__(self, n_classes=2): + self.n_classes = n_classes + self.classes_ = np.arange(n_classes) + + def fit(self, X, y=None): + return self + + def predict_proba(self, X): + return X + + def predict(self, X): + probas = self.predict_proba(X) + return np.argmax(probas, axis=1) + + identity_class = IdentityClassifier(self.get_struct(self.pivot).num_classes) + quapy_model = ACC(identity_class) + quapy_model.fit(qp_dset.training) + prior = quapy_model.quantify(torch.softmax(all_logits[DataSplit.UNLABELLED], dim=1)) + # to avoid any zero division we assume a minimum probability + prior = np.clip(prior, a_min=1e-8, a_max=None) + prior = prior / np.sum(prior) + elif isinstance(self.cfg.mode.prior, list): + # use given priors + prior = self.cfg.mode.prior + elif self.cfg.mode.prior == "val": + # infer priors on validation data, psrcal infers them + prior = None + else: + raise MMLMisconfigurationException(f"Invalid prior strategy {self.cfg.mode.prior}") + # update both unlabelled, and test predictions if existing + calibrated_splits = [split for split in all_logits if split != DataSplit.VAL] + if len(calibrated_splits) > 1: + stacked_test_logits = torch.cat([all_logits[split] for split in calibrated_splits]) + else: + stacked_test_logits = all_logits[calibrated_splits[0]] + # calibrate and return updated predictions + cal_logits, _ = calibrate( + trnscores=all_logits[DataSplit.VAL], + trnlabels=all_labels[DataSplit.VAL], + tstscores=stacked_test_logits, + calclass=AffineCalLogLoss, + bias=True, + priors=prior, + quiet=True, + ) + # de-stack returned logits + if len(calibrated_splits) > 1: + split_calibrated_logits = torch.split( + cal_logits.detach(), + split_size_or_sections=[all_logits[split].size(0) for split in calibrated_splits], + ) + cal_logits = {split: logits for split, logits in zip(calibrated_splits, split_calibrated_logits)} + else: + cal_logits = {calibrated_splits[0]: cal_logits.detach()} + # store updated predictions + for split, logits in cal_logits.items(): + for case_idx, case_logits in enumerate(logits): + all_splits_prediction[split.value][case_idx]["calibrated"] = case_logits + torch.save(obj=all_splits_prediction, f=model.predictions[pred]) + + def select_ensemble(self): + pivot_struct = self.get_struct(self.pivot) + # determine evaluation samples + datamodule = self.create_datamodule(task_structs=pivot_struct) + datamodule.setup(stage="test") + task_dataset = datamodule.task_datasets[self.pivot][LearningPhase.TEST] + all_test_ids = task_dataset._sample_ids + num_eval_samples = int(self.cfg.mode.eval_frac * len(all_test_ids)) + assert 0 < num_eval_samples < len(all_test_ids), "Rounding lead to invalid number of eval samples" + rng = np.random.default_rng(seed=self.cfg.seed) + eval_ids = rng.choice(all_test_ids, size=num_eval_samples, replace=False) + logger.info( + f"Will perform ensemble selection based on {len(eval_ids)} samples from test split " + f"({len(eval_ids) / len(all_test_ids):.2%})." + ) + # use the loss function with optional class weights, but need to ensure no unintended weighing is performed + with omegaconf.open_dict(self.cfg): + self.cfg.sampling.balanced = False + self.cfg.loss.auto_activate_weighing = False + lightning_module = self.create_model(task_structs=[pivot_struct]) + evaluate_criteria = lightning_module.get_criteria()[self.pivot] + logger.info(f"Will perform ensemble selection based on {evaluate_criteria}.") + single_results = {} + with tqdm(total=sum(map(len, self.models.values())), desc="Evaluating single models:") as pbar: + for task in self.models: + for model_idx, model in enumerate(self.models[task]): + preds = torch.load(model.predictions[self.pivot]) + # re-arrange test split based on ID + test_preds = {item["sample_id"]: item for item in preds[DataSplit.TEST.value]} + try: + # test for calibrated logits + logits = torch.stack([test_preds[sample_id]["calibrated"] for sample_id in eval_ids]).float() + except KeyError: + warnings.warn( + "Found uncalibrated predictions. It is recommended to perform post-hoc re-calibration." + ) + logits = torch.stack([test_preds[sample_id]["logits"] for sample_id in eval_ids]).float() + labels = torch.tensor([test_preds[sample_id]["target"] for sample_id in eval_ids]) + # store extracted predictions for later re-use + self.eval_logits[(task, model_idx)] = logits + if self.eval_labels is None: + self.eval_labels = labels + else: + if not torch.equal(labels, self.eval_labels): + raise RuntimeError("Difference in reference detected!") + single_results[(task, model_idx)] = evaluate_criteria(logits, labels).item() + pbar.update() + logger.info(f"Evaluated {len(single_results)} individual models.") + # these will keep the best result in memory + best_ensemble = None + best_performance = None + best_weights = None + # determine budget and search space + remaining_budget = self.cfg.mode.budget + sorted_task_idx_pairs = sorted(single_results.keys(), key=lambda x: single_results[x]) + search_space = { + ensemble_size: list(itertools.combinations(sorted_task_idx_pairs, ensemble_size)) + for ensemble_size in range(2, self.cfg.mode.max_ensemble_size + 1) + } + # perform ensemble search + with tqdm(total=self.cfg.mode.budget, desc="Testing ensembles") as bar: + while remaining_budget > 0: + # select sub search space + remaining_ensemble_sizes = [ + ensemble_size for ensemble_size in search_space if len(search_space[ensemble_size]) > 0 + ] + if len(remaining_ensemble_sizes) == 0: + logger.info( + "No more ensemble combinations available for searching - you may increase " + "mode.weights_budget to search more weighted combinations of extisting models or " + "train and predict more." + ) + break + ensemble_size = rng.choice(remaining_ensemble_sizes) + # select models + if rng.random() > self.cfg.mode.temperature: + # keep the order of single model testing + ensemble_models = search_space[ensemble_size].pop(0) + else: + # do a "wild" guess + ensemble_models = search_space[ensemble_size].pop(rng.integers(len(search_space[ensemble_size]))) + # in case of weight optimization we sample multiple times + if self.cfg.mode.weights_budget > 0: + # give default preference to better models + alpha = np.asarray([1 / single_results[(task, model_idx)] for task, model_idx in ensemble_models]) + weight_variations = rng.dirichlet( + alpha=alpha * (1 - self.cfg.mode.weights_temperature), size=self.cfg.mode.weights_budget + ).tolist() + else: + weight_variations = [1 / ensemble_size] * ensemble_size + for weights in weight_variations: + # mix predictions + mixed_logits = torch.sum( + torch.stack( + [ + weight * self.eval_logits[(task, model_idx)] + for weight, (task, model_idx) in zip(weights, ensemble_models) + ] + ), + dim=0, + ) + performance = evaluate_criteria(mixed_logits, self.eval_labels).item() + # create ensemble + if best_performance is None or best_performance > performance: # lower is better + best_performance = performance + best_weights = weights + best_ensemble = ensemble_models + remaining_budget -= 1 + bar.update() + logger.info("Done with ensemble search. Will perform full prediction.") + # now we generate the full predictions on test and unlabeled, need to load these first + full_test_labels = None + all_final_logits = {DataSplit.TEST: [], DataSplit.UNLABELLED: []} + unlabeles_sample_ids = None + for task, model_idx in best_ensemble: + preds = torch.load(self.models[task][model_idx].predictions[self.pivot]) + for split in [DataSplit.TEST, DataSplit.UNLABELLED]: + # re-arrange split based on ID + try: + split_preds = {item["sample_id"]: item for item in preds[split.value]} + except KeyError: + warnings.warn( + f"No predictions for split {split} found for model @ {model._stored}" + f"and prediction on {self.pivot} (@ {model.predictions[self.pivot]})." + ) + continue + if len(split_preds) == 0: + warnings.warn( + f"No predictions for split {split} found for model @ {model._stored}" + f"and prediction on {self.pivot} (@ {model.predictions[self.pivot]})." + ) + continue + if split == DataSplit.UNLABELLED and unlabeles_sample_ids is None: + unlabeles_sample_ids = list(split_preds.keys()) + sample_id_order = {DataSplit.UNLABELLED: unlabeles_sample_ids, DataSplit.TEST: all_test_ids}[split] + try: + # test for calibrated logits + logits = torch.stack( + [split_preds[sample_id]["calibrated"] for sample_id in sample_id_order] + ).float() + except KeyError: + logits = torch.stack([split_preds[sample_id]["logits"] for sample_id in sample_id_order]).float() + # gather logits + all_final_logits[split].append(logits) + # ensure test set labels match + if split == DataSplit.TEST: + labels = torch.tensor([split_preds[sample_id]["target"] for sample_id in all_test_ids]) + # compare labels + if full_test_labels is None: + full_test_labels = labels + else: + if not torch.equal(labels, full_test_labels): + raise RuntimeError("Difference in reference detected!") + assert all( + len(all_final_logits[split]) in [0, len(best_ensemble)] for split in [DataSplit.TEST, DataSplit.UNLABELLED] + ), "Some models make predictions that other do not!" + # merge predictions + mixed_logits = {} + for split in [DataSplit.TEST, DataSplit.UNLABELLED]: + if len(all_final_logits[split]) == 0: + continue + mixed_logits[split] = torch.sum( + torch.stack([weight * logits for weight, logits in zip(best_weights, all_final_logits[split])]), dim=0 + ) + if DataSplit.TEST in mixed_logits: + # assess performance on remaining test data + indxs = [all_test_ids.index(elem) for elem in all_test_ids if elem not in eval_ids] + assess_logits = mixed_logits[DataSplit.TEST][indxs] + assess_labels = full_test_labels[indxs] + # construct metrics + evaluate_metrics = lightning_module.get_metrics(pivot_struct) + if self.cfg.metrics.bootstrap: + # wrap in bootstrapper, needs to proceed with dict to avoid duplicate naming of bootstrapper in collection + evaluate_metrics = { + met._get_name(): BootStrapper(met, num_bootstraps=self.cfg.metrics.bootstrap) + for met in evaluate_metrics + } + evaluate_metrics = MetricCollection(evaluate_metrics) + evaluation = {k: v.item() for k, v in evaluate_metrics(assess_logits, assess_labels).items()} + logger.info( + f"Evaluation on {len(all_test_ids) - len(eval_ids)} samples from test split " + f"({(len(all_test_ids) - len(eval_ids)) / len(all_test_ids):.2%})." + ) + if self.cfg.metrics.bootstrap: + for metric in evaluate_metrics.keys(): + logger.info( + f"{metric} = {evaluation[str(metric) + '_mean']:.2f} ± {evaluation[str(metric) + '_std']:.2f}" + ) + else: + for metric, value in evaluation.items(): + logger.info(f"{metric} = {value:.2f}") + else: + evaluation = {} + # correct prediction format + ensemble_prediction = {} + for split in [DataSplit.TEST, DataSplit.UNLABELLED]: + if split not in mixed_logits: + # no predictions here + continue + probabilities = nn.functional.softmax(mixed_logits[split], dim=1) + ensemble_prediction[split] = [] + sample_id_order = {DataSplit.UNLABELLED: unlabeles_sample_ids, DataSplit.TEST: all_test_ids} + for sample_idx, sample_id in enumerate(sample_id_order): + sample = { + "logits": mixed_logits[split][sample_idx], + "sample_id": sample_id, + "probabilities": probabilities[sample_idx], + } + if split == DataSplit.TEST: + sample["target"] = full_test_labels[sample_idx] + ensemble_prediction[split].append(sample) + # store prediction + pred_path = self.fm.construct_saving_path( + obj=ensemble_prediction, key="predictions", task_name=self.pivot, file_name="preds-ensembled.pt" + ) + torch.save(ensemble_prediction, pred_path) + logger.info(f"Predictions are stored @ {pred_path}.") + # store ensemble + search_params = omegaconf.OmegaConf.to_container(self.cfg.mode, resolve=True) + search_params.pop("scheduler") + search_params.pop("subroutines") + search_params.pop("prior") + search_params["seed"] = self.cfg.seed + storage = EnsembleStorage( + performance=best_performance, + weights=best_weights, + members=[self.models[task][model_idx]._stored for task, model_idx in best_ensemble], + predictions={self.pivot: pred_path}, + metrics=evaluation, + search_params=search_params, + ) + ensemble_path = storage.store(task_struct=pivot_struct) + logger.info(f"Ensemble storage stored @ {ensemble_path}.") diff --git a/src/mml/core/scripts/schedulers/preprocess_scheduler.py b/src/mml/core/scripts/schedulers/preprocess_scheduler.py new file mode 100644 index 0000000..768cf8f --- /dev/null +++ b/src/mml/core/scripts/schedulers/preprocess_scheduler.py @@ -0,0 +1,184 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import warnings +from copy import deepcopy +from functools import partial +from pathlib import Path +from typing import Dict + +import cv2 +import pandas as pd +import torch +from omegaconf import DictConfig, OmegaConf +from p_tqdm import p_umap + +from mml.core.data_loading.augmentations.albumentations import AlbumentationsAugmentationModule +from mml.core.data_loading.modality_loaders import DEFAULT_MODALITY_LOADERS, NonMappingOpenCVMaskLoader +from mml.core.data_loading.task_attributes import EMPTY_MASK_TOKEN, DataSplit, Modality +from mml.core.data_loading.task_dataset import TaskDataset +from mml.core.data_preparation.task_creator import TaskCreator +from mml.core.scripts.schedulers.base_scheduler import AbstractBaseScheduler +from mml.core.scripts.utils import TAG_SEP, multi_threaded_p_tqdm + +logger = logging.getLogger(__name__) + + +class PreprocessScheduler(AbstractBaseScheduler): + """ + AbstractBaseScheduler implementation for the process of preprocessing data. Includes the following subroutines: + - preprocess + """ + + def __init__(self, cfg: DictConfig): + # initialize + super(PreprocessScheduler, self).__init__(cfg=cfg, available_subroutines=["preprocess"]) + # store target preprocessing pipeline (will be overwritten later)) + self.pp_id = deepcopy(self.cfg.preprocessing.id) + self.pp_pipeline = deepcopy(self.cfg.preprocessing.pipeline) + + def create_routine(self): + """ + This scheduler implements one subroutine, which preprocesses a task's data. + + :return: None + """ + # -- add preprocess command + if "preprocess" in self.subroutines: + if self.pivot: + logger.info("Preprocess mode with pivot task will only pp this task!") + self.commands.append(self.preprocess_task) + self.params.append([self.pivot]) + else: + for task in self.cfg.task_list: + self.commands.append(self.preprocess_task) + self.params.append([task]) + + def after_preparation_hook(self): + # delete pp info from config after (!) task structs are created + self.cfg.preprocessing.id = "none" + self.cfg.preprocessing.pipeline = {} + + def before_finishing_hook(self): + pass + + def preprocess_task(self, task_name: str): + logger.info("Starting preprocessing data for task " + self.highlight_text(task_name)) + task_struct = self.get_struct(task_name) + # assert preprocessing not already exists + if task_struct.preprocessed != "none": + logger.warning( + f"Task {task_name} is already preprocessed with {task_struct.preprocessed}, will skip " + f"computations. Delete {self.fm.data_path / task_struct.relative_root} if you want to redo " + f"the calculations." + ) + return + + if TAG_SEP in task_name: + # check if base task has been preprocessed + base_name = task_name.split(TAG_SEP)[0] + if self.pp_id not in self.fm.task_index[base_name]: + msg = ( + f"Task {task_name} is a tagged task and should not be preprocessed directly! " + f"Please preprocess the base task ({base_name}) and rerun preprocessing the tagged version " + f"afterwards." + ) + logger.error(msg) + return + logger.info( + f"{task_name} as a tagged task has already preprocessed base version for preprocessing " + f"{self.pp_id}. No image preprocessing necessary. To auto create the tagged preprocessing " + f"simply refer to the tagged task and its preprocessing in any mml call and it will be " + f"created on the fly." + ) + return + # if this is a base task, then the images have to be preprocessed + # prepare data loading + warnings.warn("THIS BEHAVIOUR CHANGED: Test data is now also to be preprocessed!") + pp_transform = AlbumentationsAugmentationModule( + device="cpu", cfg=self.pp_pipeline, is_first=True, is_last=False, tensorize=False, means=None, stds=None + ) # need to set is_last=False to prevent float conversion + loaders = {mod: DEFAULT_MODALITY_LOADERS[mod]() for mod in task_struct.modalities} + if Modality.MASK in loaders: + loaders[Modality.MASK] = (NonMappingOpenCVMaskLoader(),) # prevent mappings + task_dataset = TaskDataset( + root=self.fm.data_path / task_struct.relative_root, + split=DataSplit.FULL_TRAIN, + transform=None, + loaders=loaders, + ) + task_dataset.modalities = { + k: v for k, v in task_dataset.modalities.items() if k in [Modality.IMAGE, Modality.MASK] + } # load at max images and masks + # prepare storage + source_base = (self.fm.data_path / task_struct.relative_root).parent + target_base = self.fm.get_dataset_path(raw_path=source_base, preprocessing=self.pp_id) + storage_definition_path = self.fm.get_pp_definition(preprocessing=self.pp_id) + if not storage_definition_path.exists(): + # write pipeline definition to preprocessing folder + OmegaConf.save(self.pp_pipeline, storage_definition_path, resolve=True) + # start multithreaded preprocessing + with multi_threaded_p_tqdm(): + for split in [DataSplit.FULL_TRAIN, DataSplit.TEST, DataSplit.UNLABELLED]: + logger.info(f"Preprocessing split: {split}") + task_dataset.select_samples(split=split, fold=0) + if len(task_dataset) > 0: + exist_results = p_umap( + partial(preprocess_and_store, ds=task_dataset, target_base=target_base, transform=pp_transform), + range(len(task_dataset)), + num_cpus=self.cfg.num_workers, + ) + logger.info(f"Existing {split} files found:\n{pd.DataFrame(data=exist_results).sum().to_string()}") + else: + logger.info(f"No samples in split: {split}") + # adapt task meta info + task_creator = TaskCreator(dset_path=(self.fm.data_path / task_struct.relative_root).parent) + task_creator.load_existent(self.fm.data_path / task_struct.relative_root) + task_creator.dset_path = target_base + task_creator.infer_stats(device=torch.device("cuda") if self.cfg.allow_gpu else torch.device("cpu")) + task_creator.protocol(msg=f"Preprocessed with id={self.pp_id}") + task_creator.push_and_test() + logger.info("Finished preprocessing the data for task " + self.highlight_text(task_name)) + + +def preprocess_and_store( + index: int, ds: TaskDataset, target_base: Path, transform: AlbumentationsAugmentationModule +) -> Dict[str, bool]: + """ + Function to preprocess and store a single data tuple of a dataset. + + :param ds: dataset + :param target_base: root path to store preprocessed data + :param index: index of data tuple to be preprocessed + :param transform: an albumentations transform module to be applied on loaded data + :return: dict with modality keys and boolean indicating whether a file already existed beforehand + """ + pp_elements = transform(**ds.load_sample(index)) + exists = {mod: False for mod in pp_elements.keys()} + path_info = ds.samples[index] + for mod, pp_item in pp_elements.items(): + if mod in [Modality.CLASS, Modality.SOFT_CLASSES, Modality.CLASSES, Modality.SAMPLE_ID, Modality.TASK]: + # no preprocessing needed here + continue + if mod not in [Modality.IMAGE, Modality.MASK]: + raise NotImplementedError(f"Preprocessing not supported for modality {mod}.") + # ignore dummy mask tokens + if mod == Modality.MASK and path_info[Modality.MASK] == EMPTY_MASK_TOKEN: + continue + if not isinstance(path_info[mod], str): + raise TypeError(f"Only able to process paths, represented as strings, was given {type(path_info[mod])}") + path = target_base / path_info[mod] + if path.exists(): + # default is to overwrite existing files + exists[mod] = True + path.parent.mkdir(parents=True, exist_ok=True) + img = pp_elements[mod] + if len(img.shape) == 3 and img.shape[2] == 3: + # since loading converts opencv BGR format to RGB we have to undo this here before saving color images + img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) + cv2.imwrite(filename=str(path), img=img) + return exists diff --git a/src/mml/core/scripts/schedulers/train_scheduler.py b/src/mml/core/scripts/schedulers/train_scheduler.py new file mode 100644 index 0000000..ff616ed --- /dev/null +++ b/src/mml/core/scripts/schedulers/train_scheduler.py @@ -0,0 +1,501 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import random +import shutil +import warnings +from typing import List, Optional + +import lightning +import numpy as np +import torch +from omegaconf import DictConfig, ListConfig + +from mml.core.data_loading.task_attributes import DataSplit +from mml.core.scripts.exceptions import MMLMisconfigurationException +from mml.core.scripts.model_storage import ModelStorage +from mml.core.scripts.pipeline_configuration import PipelineCfg +from mml.core.scripts.schedulers.base_scheduler import AbstractBaseScheduler +from mml.core.scripts.utils import ARG_SEP, TAG_SEP, LearningPhase, catch_time + +logger = logging.getLogger(__name__) + + +class TrainingScheduler(AbstractBaseScheduler): + """ + New version of the former "optimization" scheduler. Supports the following features: + - model training + - model prediction + - model testing + + In addition to the standard hooks (after_preparation_hook, before_finishing_hook) it provides additional hooks that + may be overridden by inheriting schedulers: + - before_training_hook + - after_training_hook + + It further allows for task nesting and cross validation. + """ + + def __init__(self, cfg: DictConfig): + # check compliance to new train scheduler behaviour + if not cfg.pivot.name: + raise MMLMisconfigurationException( + "Train mode (and all inherited ones) requires a pivot task to be set " + "from mml version 0.12.0 onwards." + ) + if ("nested" in cfg.pivot.name or "nested" in cfg.pivot.tags) and cfg.mode.nested: + warnings.warn( + "TrainingScheduler takes care of task nesting itself. Currently you are introducing DOUBLE " + "nesting by setting mode.nested=true and choosing an already nested pivot task." + ) + # initialize + self.n_folds: int = -1 # will be set during create_routine + super(TrainingScheduler, self).__init__(cfg=cfg, available_subroutines=["train", "predict", "test"]) + self.monitored_performances: List[float] = [] # final loss values observed during validation + # interpretation and checking for multitask options + self.co_tasks: List[str] = [] + if self.cfg.mode.multitask: + if self.cfg.mode.multitask == 1: + raise MMLMisconfigurationException( + "To enable multitask learning set mode.multitask to the TOTAL " + "number of task to be learned jointly." + ) + if self.cfg.mode.co_tasks == "random": + choices = [task for task in self.cfg.task_list if not task.startswith(self.pivot)] + if len(choices) < self.cfg.mode.multitask - 1: + raise MMLMisconfigurationException("Available tasks are not enough to support sufficient co-tasks.") + self.co_tasks = random.sample(population=choices, k=self.cfg.mode.multitask - 1) + logger.info(f"Randomly selected co-learning tasks: {self.co_tasks}") + else: + # was given explicit co tasks, check if compatible + if any(task not in self.cfg.task_list for task in self.cfg.mode.co_tasks): + raise MMLMisconfigurationException("Co task not present in cfg.task_list!") + if len(set(self.cfg.mode.co_tasks)) != len(self.cfg.mode.co_tasks): + raise MMLMisconfigurationException( + "mode.co_tasks supports identical co-tasks only if " + "you use the identity tag (task_name+identity) to " + "create a virtual duplicate." + ) + if any(task.startswith(self.pivot) for task in self.cfg.mode.co_tasks): + raise MMLMisconfigurationException("Should not use pivot (or derivative) as co-task.") + self.co_tasks = self.cfg.mode.co_tasks + logger.info(f"Configured co-learning tasks: {self.co_tasks}") + # these are some information leakage backup checks + if not self.cfg.mode.nested and self.cfg.mode.cv: + # check lr scheduler leakage + if ( + self.cfg.lr_scheduler["_target_"] is not None + and "ReduceLROnPlateau" in self.cfg.lr_scheduler["_target_"] + ): + raise MMLMisconfigurationException( + "Using ReduceLROnPlateau LR-scheduler without activating mode.nested=true leads to " + "information leakage from val split on training and should be avoided. Either activate" + " nesting or change the LR-scheduler, e.g. with ." + ) + # check early stopping leakage + for cb in self.cfg.cbs.values(): + if "EarlyStopping" in cb["_target_"] and "val" in cb["monitor"]: + raise MMLMisconfigurationException( + "Using EarlyStopping callback without activating mode.nested=true leads to" + "information leakage from val split on training and should be avoided. Either deactivate this " + "callback (e.g. ), choose a different monitor value (not depending on the val " + "split) or activate nesting." + ) + # checks regarding the storing of model parameters + if not self.cfg.mode.store_parameters and "train" in self.subroutines and "predict" in self.subroutines: + raise MMLMisconfigurationException("Predictions after training require mode.store_parameters=True!") + + if ( + self.cfg.mode.store_parameters + and "check_val_every_n_epoch" in self.cfg.trainer + and self.cfg.trainer.check_val_every_n_epoch > self.cfg.trainer.max_epochs + ): + raise MMLMisconfigurationException( + f"It seems like you only validate every {self.cfg.trainer.check_val_every_n_epoch} epochs, but " + f'only train for max {self.cfg.trainer.max_epochs} although requested "mode.store_parameters".' + ) + + if self.cfg.mode.store_parameters and self.cfg.mode.cv: + warnings.warn( + f"Cross-Validation will store {self.n_folds} model parameters. To reduce memory consumption " + f"you may consider either setting mode.store_parameters=false (which will omit storing the " + f"model parameters) or reuse.clean_up.parameters=true (which deletes the model parameters " + f"at the end of the experiment." + ) + # more checks + if self.cfg.mode.cv and "test" in self.subroutines: + warnings.warn( + "Chose both cross validation and testing (on hold out test set). Note that only one CV model " + "will be evaluated!" + ) + if not self.cfg.mode.nested and "test" in self.subroutines: + warnings.warn( + "You are testing on the `actual` test set! To ensure unbiased fair evaluation this should only " + "be done on the very end of model development." + "You may chose mode.nested=true so the testing subroutine will be performed NOT on the (potential) " + "official task test split, but on the hold-out fold." + ) + if self.cfg.mode.eval_on: + if not (isinstance(self.cfg.mode.eval_on, list) or isinstance(self.cfg.mode.eval_on, ListConfig)): + raise MMLMisconfigurationException("Must provide mode.eval_on as list of tasks, gave.") + if any(t not in self.cfg.task_list for t in self.cfg.mode.eval_on): + raise MMLMisconfigurationException( + f"Chose to evaluate on {self.cfg.mode.eval_on} but one of these tasks is not given in the task_list" + ) + if ( + self.cfg.reuse.models + and "train" in self.subroutines + and any(sub in self.subroutines for sub in ["test", "predict"]) + ): + raise MMLMisconfigurationException( + "Reusing existing models combined with training. This may lead to undetermined behaviour during " + "testing/predicting" + ) + + def create_routine(self): + """ + This scheduler implements three sub-routines, training, testing and prediction. + The routine takes care of cross validation and nesting. + """ + # calculate the number of available pivot folds + try: + pivot_description = self.fm.load_task_description( + self.fm.data_path / self.fm.task_index[self.pivot]["none"] + ) + except KeyError: + raise RuntimeError( + f"Task {self.pivot} not found in task index. You may need to call info or create mode before passing " + f"as pivot task to train." + ) + self.n_folds = len(pivot_description.train_folds) + # derive folds to loop over + if self.cfg.mode.cv: + folds = list(range(self.n_folds)) + else: + folds = [0] + # adapt task list, depending on the nesting and cv mode configurations, happens before prepare_exp struct + # construction, but after the modifications of tasks and pivot by the auto tagging tasks options + if self.cfg.mode.nested: + for fold in folds: + self.cfg.task_list.append(f"{self.pivot}{TAG_SEP}nested{ARG_SEP}{fold}") + + eval_tasks = self.cfg.mode.eval_on or [None] # None means predict on self + + # -- add training commands + if "train" in self.subroutines: + for fold in folds: + self.commands.append(self.train_fold) + if self.cfg.mode.nested: + self.params.append([f"{self.pivot}{TAG_SEP}nested{ARG_SEP}{fold}", 0]) + else: + self.params.append([self.pivot, fold]) + if "predict" in self.subroutines: + # predicts on the test split (which is original val split for nested tasks) + for fold in folds: + for eval_on in eval_tasks: + self.commands.append(self.predict_fold) + if self.cfg.mode.nested: + self.params.append([f"{self.pivot}{TAG_SEP}nested{ARG_SEP}{fold}", 0, eval_on]) + # also add predictions on test set of original pivot (not nested) - to be used in postprocessing + if eval_on is None: + self.commands.append(self.predict_fold) + self.params.append([f"{self.pivot}{TAG_SEP}nested{ARG_SEP}{fold}", 0, self.pivot]) + else: + self.params.append([self.pivot, fold, eval_on]) + if "test" in self.subroutines: + for eval_on in eval_tasks: + self.commands.append(self.test_task) + if self.cfg.mode.nested: + self.params.append([f"{self.pivot}{TAG_SEP}nested{ARG_SEP}0", eval_on]) + else: + self.params.append([self.pivot, eval_on]) + + def after_preparation_hook(self): + if self.cfg.mode.eval_on: + # compare pivot and eval tasks for compatibility + for eval_task in self.cfg.mode.eval_on: + pivot_struct = self.get_struct(self.pivot) + eval_struct = self.get_struct(eval_task) + if pivot_struct.task_type != eval_struct.task_type: + raise MMLMisconfigurationException( + f"Invalid task type for evaluation! Pivot task has type " + f"{pivot_struct.task_type} but evaluation task {eval_task} has type " + f"{eval_struct.task_type}." + ) + if pivot_struct.num_classes != eval_struct.num_classes: + raise MMLMisconfigurationException( + f"Invalid number of classes for evaluation! Pivot task has " + f"{pivot_struct.num_classes} classes but evaluation {eval_task} task has " + f"{eval_struct.num_classes} classes." + ) + + def before_finishing_hook(self): + # return the task loss (averaged over folds if mode.cv is active) + self.return_value = np.mean(self.monitored_performances) + # gather further metrics on training + with open(self.planned_schedule, "r") as schedule_file: + planned_schedule = schedule_file.readlines() + train_runs = [line for line in planned_schedule if self.train_fold.__name__ in line] + # if neither predict nor test are applied we want to show validation results + if len(train_runs) > 0 and "test" not in self.subroutines and "predict" not in self.subroutines: + args = [] + for line in train_runs: + # store args as tuples task_name, fold in a list for all calls + args.append(elem.strip(" '") for elem in line.split("/")[-1].strip(" []\n").split(",")) + # for each of the trained models we will evaluate the validation if test + aggregated_metrics = {} + logger.info(f"Will try to aggregate validation results over {len(args)} training runs.") + for task_name, fold in args: + struct = self.get_struct(task_name) + model_candidates = [model for model in struct.models if model.fold == int(fold)] + if len(model_candidates) != 1: + # this can happen if reuse was used beforehand + logger.error( + f"Ambiguous model choices for {task_name} and {fold}! Will skip while aggregating" f" results." + ) + continue + model = model_candidates[0] + # check if recorded metrics have validation entry + val_idxs = [ + idx + for idx, metric_dict in enumerate(model.metrics) + if any(k.startswith(LearningPhase.VAL) for k in metric_dict) + ] + if len(val_idxs) == 0: + logger.error( + f"No validation metrics for task {task_name} and fold {fold}! Will skip while " + f"aggregating results." + ) + continue + for metric_name, metric_value in model.metrics[val_idxs[-1]].items(): + if metric_name in aggregated_metrics: + aggregated_metrics[metric_name].append(metric_value) + else: + aggregated_metrics[metric_name] = [metric_value] + # compute stats and show + if len(aggregated_metrics) == 0: + logger.error("No validation metrics found!") + else: + logger.info("Aggregated validation results over training:") + for metric, values in aggregated_metrics.items(): + logger.info(f"{metric} : {np.mean(values):.2f} ± {np.std(values):.2f}") + + def before_training_hook( + self, + datamodule: lightning.LightningDataModule, + model: lightning.LightningModule, + trainer: lightning.Trainer, + fold: int, + task_name: str, + ) -> None: + """ + This hook allows of setup modification before the model fitting starts (and also before lightning tuning). + Allows to modify weights, data, trainer callbacks, etc. May be overwritten as part of inheriting from + TrainScheduler. + + :param lightning.LightningDataModule datamodule: the prepared datamodule (no setup run yet) + :param lightning.LightningModule model: the prepared model + :param lightning.Trainer trainer: the prepared trainer + :param int fold: the current fold + :param str task_name: the current task + :return: None + """ + pass + + def after_training_hook( + self, + datamodule: lightning.LightningDataModule, + model: lightning.LightningModule, + trainer: lightning.Trainer, + fold: int, + task_name: str, + ) -> None: + """ + This hook allows of setup modification after the model fitting ended (and potential lightning tuning). + Allows to modify weights, data, trainer callbacks, etc. May be overwritten as part of inheriting from + TrainScheduler. + + :param lightning.LightningDataModule datamodule: the datamodule used + :param lightning.LightningModule model: the trained model + :param lightning.Trainer trainer: the used trainer + :param int fold: the used fold + :param str task_name: the pivot task + :return: None + """ + pass + + def train_fold(self, task_name: str, fold: int) -> None: + logger.info("Starting training for task " + self.highlight_text(task_name) + f" and fold {fold}.") + pivot_struct = self.get_struct(task_name) + co_structs = [self.get_struct(task_name=task_name) for task_name in self.co_tasks] + if self.cfg.mode.use_blueprint: + if "blueprint" in pivot_struct.paths: + pipeline = PipelineCfg.load( + path=pivot_struct.paths["blueprint"], pipeline_keys=self.cfg.mode.pipeline_keys + ) + logger.info(f"Found blueprint pipeline for task {task_name}, will evaluate that.") + else: + raise RuntimeError(f"Was not able to find appropriate blueprint pipeline for task {task_name}!") + else: + pipeline = PipelineCfg.from_cfg(current_cfg=self.cfg, restrict_keys=self.cfg.mode.pipeline_keys) + with pipeline.activate(current_cfg=self.cfg): + # preparation + datamodule = self.create_datamodule(task_structs=[pivot_struct] + co_structs, fold=fold) + module = self.create_model( + task_structs=[pivot_struct] + co_structs, task_weights=self.cfg.mode.task_weights + ) + module.train() # see https://github.com/Lightning-AI/pytorch-lightning/releases/tag/2.2.0 + trainer = self.create_trainer( + monitor=(f"val/{task_name}/loss", "min") if self.cfg.mode.store_best else None, metrics_callback=True + ) + self.before_training_hook( + datamodule=datamodule, model=module, trainer=trainer, fold=fold, task_name=task_name + ) + # tuning and training + with catch_time() as training_timer: + self.lightning_tune(trainer=trainer, model=module, datamodule=datamodule) + trainer.fit(model=module, datamodule=datamodule) + self.after_training_hook( + datamodule=datamodule, model=module, trainer=trainer, fold=fold, task_name=task_name + ) + # create another pipeline from the current one (within blueprint keys activated and without restrictions) + # to ensures storing the full superset of configuration from a potential partially masked blueprint training + pipeline_path = PipelineCfg.from_cfg(current_cfg=self.cfg).store( + task_struct=pivot_struct, as_blueprint=False + ) + # output processing + if self.cfg.mode.store_best: + if self.checkpoint_callback.best_model_score is None: + best_score = 1000 # catch fast_dev_run + else: + best_score = self.checkpoint_callback.best_model_score.item() + else: + try: + best_score = self.metrics_callback.metrics[-2][f"val/{task_name}/loss"] + except KeyError: + raise RuntimeError( + 'Unable to find "val/{task_name}/loss" in recorded metrics of the last epoch,' + "make sure to activate validation with lightning trainer." + ) + self.monitored_performances.append(best_score) + parameters_path = self.fm.construct_saving_path( + self.checkpoint_callback, key="parameters", task_name=pivot_struct.name + ) + if self.cfg.mode.store_parameters: + # copy parameter file from the (temporary) checkpoint directory to the correct parameters directory + cpt_path = ( + self.checkpoint_callback.best_model_path + if self.cfg.mode.store_best + else self.checkpoint_callback.last_model_path + ) + shutil.copy2(src=cpt_path, dst=parameters_path) + else: + parameters_path.unlink() + logger.info("mode.store_parameters is set false, so no parameters will be stored!") + storage = ModelStorage( + pipeline=pipeline_path, + parameters=parameters_path, + fold=fold, + task=task_name, + performance=best_score, + metrics=self.metrics_callback.metrics, + training_time=training_timer.elapsed, + ) + storage.store(task_struct=pivot_struct, fold=fold) + pivot_struct.models.append(storage) + logger.info("Finished training for task " + self.highlight_text(task_name) + f" and fold {fold}.") + + def predict_fold(self, task_name: str, fold: int, eval_on: Optional[str] = None) -> None: + logger.info("Starting predicting for task " + self.highlight_text(task_name) + f" and fold {fold}.") + task_struct = self.get_struct(task_name) + # find model storage + choices = [storage for storage in task_struct.models if storage.fold == fold] + if len(choices) == 0: + raise RuntimeError(f"Did not find any existing model storage for task {task_name} and fold {fold}.") + # sort ascending + choices.sort(key=lambda x: x.created) + storage = choices[-1] + logger.info(f"Found {len(choices)} matching model storages, used the latest from {storage.created}.") + pipeline = PipelineCfg.load(path=storage.pipeline) + with pipeline.activate(current_cfg=self.cfg): # activate pipeline to have identical model creation + module = self.create_model(task_structs=[task_struct]) + if eval_on and eval_on != task_name: + eval_task = self.get_struct(eval_on) + eval_task_name = eval_on + logger.info("Will predict on task " + self.highlight_text(eval_task_name) + "!") + module.setup_redirection(head=task_name, task=eval_task_name) + else: + eval_task_name = task_name + eval_task = task_struct + datamodule = self.create_datamodule(task_structs=eval_task, fold=fold) + trainer = self.create_trainer() + split_batched_predictions = {} + with catch_time() as predict_timer: + for split in [DataSplit.TEST, DataSplit.VAL, DataSplit.UNLABELLED]: + # switch prediction split + logger.info(f"Predicting split {split.name}.") + datamodule.predict_on = split + split_batched_predictions[split] = trainer.predict( + model=module, dataloaders=datamodule, return_predictions=True, ckpt_path=storage.parameters + ) + if split_batched_predictions[split] is not None: + logger.info( + f"Predicted {len(split_batched_predictions[split])} batches for split {split.name}." + ) + logger.debug(f"Prediction time was {predict_timer.pretty_time}.") + # reformat predictions as dict -> image_id : prediction for each data split and combine them + split_unbatched_predictions = {} + for data_split, pred_dict_list in split_batched_predictions.items(): + split_unbatched_predictions[data_split.name] = [] + if pred_dict_list is None: + warnings.warn(f"No predictions found for {data_split}!") + continue + for batch in pred_dict_list: + for sample_idx in range(batch[eval_task_name]["logits"].size(0)): + predict_dict = {"logits": batch[eval_task_name]["logits"][sample_idx]} + if batch[eval_task_name]["targets"] is not None: + predict_dict.update({"target": batch[eval_task_name]["targets"][sample_idx]}) + if batch[eval_task_name]["sample_ids"] is not None: + predict_dict.update({"sample_id": batch[eval_task_name]["sample_ids"][sample_idx]}) + split_unbatched_predictions[data_split.name].append(predict_dict) + preds_path = self.fm.construct_saving_path( + split_unbatched_predictions, key="predictions", task_name=eval_task.name, file_name=f"preds-fold-{fold}.pt" + ) + torch.save(split_unbatched_predictions, preds_path) + storage.predictions[eval_task_name] = preds_path + storage.store() + logger.info("Finished predicting for task " + self.highlight_text(task_name) + f" and fold {fold}.") + + def test_task(self, task_name: str, eval_on: Optional[str] = None) -> None: + logger.info("Starting testing for task " + self.highlight_text(task_name)) + task_struct = self.get_struct(task_name) + # find model storage + if len(task_struct.models) == 0: + raise RuntimeError(f"Did not find any existing model storage for task {task_name}.") + # sort ascending + choices = sorted(task_struct.models, key=lambda x: x.created) + storage = choices[-1] + logger.info(f"Found {len(choices)} matching model storages, used the latest from {storage.created}.") + pipeline = PipelineCfg.load(path=storage.pipeline) + with pipeline.activate(current_cfg=self.cfg): + module = self.create_model(task_structs=[task_struct]) + if eval_on and eval_on != task_name: + eval_task = self.get_struct(eval_on) + eval_task_name = eval_on + logger.info("Will test on task" + self.highlight_text(eval_task_name) + "!") + module.setup_redirection(head=task_name, task=eval_task_name) + else: + eval_task = task_struct + datamodule = self.create_datamodule(task_structs=eval_task) + trainer = self.create_trainer(metrics_callback=True) + with catch_time() as test_timer: + trainer.test(model=module, datamodule=datamodule, ckpt_path=storage.parameters) + logger.debug(f"Testing time was {test_timer.pretty_time}.") + storage.metrics += self.metrics_callback.metrics + storage.store() + logger.info(f"Results: {self.metrics_callback.metrics}") + logger.info("Finished testing for task " + self.highlight_text(task_name)) diff --git a/src/mml/core/scripts/schedulers/transfer_scheduler.py b/src/mml/core/scripts/schedulers/transfer_scheduler.py new file mode 100644 index 0000000..2d86aa1 --- /dev/null +++ b/src/mml/core/scripts/schedulers/transfer_scheduler.py @@ -0,0 +1,115 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import random + +import lightning +import torch +from omegaconf import DictConfig + +from mml.core.scripts.exceptions import MMLMisconfigurationException +from mml.core.scripts.schedulers.train_scheduler import TrainingScheduler + +logger = logging.getLogger(__name__) + + +class TransferScheduler(TrainingScheduler): + """ + Inherited from TrainingScheduler this scheduler supports the same subroutines: + - model training + - model prediction + - model testing + + But it adds the option to finetune an existing model by choosing a mode.pretrain_task in the config. + """ + + def __init__(self, cfg: DictConfig): + super().__init__(cfg=cfg) + if self.cfg.mode.pretrain_task not in self.cfg.task_list: + raise MMLMisconfigurationException( + f"Current pretraining source {self.cfg.mode.pretrain_task} was not " + f"found within tasks. Make sure consistency." + ) + + def before_training_hook( + self, + datamodule: lightning.LightningDataModule, + model: lightning.LightningModule, + trainer: lightning.Trainer, + fold: int, + task_name: str, + ) -> None: + """ + Implements the weight loading logic. + """ + # load pretrained weights + source_task_struct = self.get_struct(self.cfg.mode.pretrain_task) + if len(source_task_struct.models) == 0: + raise MMLMisconfigurationException( + f"No previous trained model for task {self.cfg.mode.pretrain_task} " + f"found, either change mode.pretrain_task value or run train " + f"on the pretrain task beforehand in this project or use the " + f"reuse.models option to load from a previous project." + ) + logger.info( + f"Found {len(source_task_struct.models)} existing models for pretraining task " + f"{self.cfg.mode.pretrain_task}." + ) + if self.cfg.mode.model_selection == "performance": + storage = min(source_task_struct.models, key=lambda x: x.performance) + logger.info(f"Chose pretrain model based on performance (best: {storage.performance}).") + elif self.cfg.mode.model_selection == "random": + select_idx = random.randrange(len(source_task_struct.models)) + storage = source_task_struct.models[select_idx] + logger.info(f"Chose pretrain model randomly (rolled: {select_idx}).") + elif self.cfg.mode.model_selection == "created": + storage = max(source_task_struct.models, key=lambda x: x.created) + logger.info(f"Chose pretrain model based on creation date (latest: {storage.created}).") + else: + raise MMLMisconfigurationException("mode.model_selection must be one of [performance, random, created].") + state = torch.load(f=storage.parameters)["state_dict"] + # remove metrics and heads + to_be_removed = [] + for key in state.keys(): + if any( + [ + key.startswith(prefix) + for prefix in [ + "model.heads", + "train_metrics", + "val_metrics", + "test_metrics", + "train_cms", + "val_cms", + "test_cms", + ] + ] + ): + to_be_removed.append(key) + for key in to_be_removed: + del state[key] + # load module and continue with training + model.load_state_dict(state_dict=state, strict=False) + logger.info(f"Successfully loaded pretrain weights from task {self.cfg.mode.pretrain_task}.") + if self.cfg.mode.freeze: + model.model.freeze_backbone() + logger.info("Froze model backbone and continue with linear probing of model heads.") + + def after_training_hook( + self, + datamodule: lightning.LightningDataModule, + model: lightning.LightningModule, + trainer: lightning.Trainer, + fold: int, + task_name: str, + ) -> None: + """ + If necessary unfreezes the model backbone. + """ + if self.cfg.mode.freeze: + model.model.unfreeze_backbone() + logger.info("Unfroze model backbone after linear probing of model heads.") diff --git a/src/mml/core/scripts/schedulers/upgrade_scheduler.py b/src/mml/core/scripts/schedulers/upgrade_scheduler.py new file mode 100644 index 0000000..b720750 --- /dev/null +++ b/src/mml/core/scripts/schedulers/upgrade_scheduler.py @@ -0,0 +1,191 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import tempfile +import warnings +from pathlib import Path +from typing import List, Tuple + +import omegaconf.listconfig +import orjson +from omegaconf import DictConfig, OmegaConf +from rich.progress import track + +import mml +from mml.core.data_loading.file_manager import TASK_PREFIX, MMLFileManager +from mml.core.data_loading.task_description import ALL_TASK_DESCRIPTION_KEYS +from mml.core.scripts.exceptions import MMLMisconfigurationException +from mml.core.scripts.schedulers.base_scheduler import AbstractBaseScheduler +from mml.core.scripts.utils import ask_confirmation + +logger = logging.getLogger(__name__) + + +class UpgradeScheduler(AbstractBaseScheduler): + """ + AbstractBaseScheduler implementation for the Dataset and MML Upgrade process. Includes the following subroutines: + - upgrade + - downgrade + For upgrade we always assume to upgrade to the currently installed version of MML. For downgrade, we assume that + previously MML has been upgraded to the currently installed version and is now downgraded to the specified version + in cfg.mode.version. + """ + + def __init__(self, cfg: DictConfig): + # make sure to create MMLFileManager beforehand to avoid RunTimeErrors during super.__init__ + MMLFileManager( + proj_path=Path(tempfile.mkdtemp()), + data_path=Path(tempfile.mkdtemp()), + log_path=Path(tempfile.mkdtemp()), + reuse_cfg=None, # nothing to reuse here + remove_cfg=None, # nothing to remove either + ) + # assert correct configuration + if OmegaConf.is_missing(cfg.mode, "version"): + raise MMLMisconfigurationException( + "You are up/downgrading the mml setup without specifying a version! " + "In case of upgrading please provide a source version, in case of " + "downgrading please provide a target version. If in doubt, please " + "read the documentation!" + ) + if ( + not isinstance(cfg.mode.version, omegaconf.listconfig.ListConfig) + and len(cfg.mode.version) == 3 + and all([isinstance(elem, int) for elem in cfg.mode.version]) + ): + raise MMLMisconfigurationException("Specify source/target version as list of three int.") + # tuple variant for better compatibility + if isinstance(cfg.mode.version, list): + self.version = tuple(cfg.mode.version) + elif isinstance(cfg.mode.version, str): + self.version = tuple([int(x) for x in cfg.mode.version.split(".")]) + else: + raise MMLMisconfigurationException("Provide mode.version either as list (aka [x,y,z]) or as str (x.y.z).") + if len(self.version) != 3: + raise MMLMisconfigurationException("Provide mode.version as major - minor - patch (list or str).") + if "upgrade" in list(cfg.mode.subroutines) and "downgrade" in list(cfg.mode.subroutines): + raise MMLMisconfigurationException("Upgrade mode may either be used to upgrade or to downgrade.") + self.upgrading = "upgrade" in list(cfg.mode.subroutines) + # initialize + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + super(UpgradeScheduler, self).__init__(cfg=cfg, available_subroutines=["upgrade", "downgrade"]) + # since self.fm does not help with correct paths, we store the correct ones as well for the use in the scheduler + self.data_path = Path(self.cfg["data_dir"]) + + def prepare_exp(self) -> None: + """ + Prepare experiment expects tasks to be present and loads these into task factory container. Here this should + be avoided. + """ + logger.debug("Skipping experiment setup!") + + def create_routine(self) -> None: + """ + This scheduler implements two subroutines, one for dataset preparation and one for task preparation. + + :return: None + """ + # determine necessary patches from dict of all available patches + # pattern: Key=Version of chance - Value: function to up AND downgrade + patches = {(0, 12, 0): self.upgrade_0_12} + # sort and filter according to subroutine + patch_ids: List[Tuple[int, int, int]] = sorted( + filter(lambda x: self.version < x <= mml.VERSION, patches.keys()), reverse=not self.upgrading + ) + # -- add commands + for patch_id in patch_ids: + self.commands.append(patches[patch_id]) + self.params.append([]) + if len(patch_ids) == 0: + logger.info("No patches necessary!") + else: + # ensure user is aware of implications + msg = ( + f'You are about to {"upgrade" if self.upgrading else "downgrading"} your MML environment, ' + f'from version {self.version if self.upgrading else mml.VERSION} to version ' + f'{mml.VERSION if self.upgrading else self.version}. Although the effects should be revertible it ' + f'is recommended to create a backup of your data and/or results! Do you want to continue? ' + f'Please type "y"' + ) + try: + confirmed = ask_confirmation(self.highlight_text(msg)) + except TimeoutError: + logger.error("No input provided for necessary response, will kill this run!") + raise + if not confirmed: + raise RuntimeError('Stopped MML up/downgrade scheduler. To up/downgrade rerun and answer "y".') + + def upgrade_0_12(self) -> None: + """ + This performs the necessary updates to results and data from 0.11 to 0.12 version of mml-core. + Iterate over all installed tasks and update the keys: tags, train_tuples, unlabeled_tuples, test_tuples + """ + logger.info("Now rolling patch 0.12") + all_task_descriptions = self._get_all_task_descriptions() + logger.info(f"Found {len(all_task_descriptions)} task descriptions to update.") + # processing each task description + for description_path in track(all_task_descriptions, description="Updating task descriptions..."): + # load + with open(str(description_path), "rb") as f: + data_dict = orjson.loads(f.read()) + # replace (format is new : old) + replacements = { + "keywords": "tags", + "train_samples": "train_tuples", + "name": "alias", + "unlabeled_samples": "unlabeled_tuples", + "test_samples": "test_tuples", + } + # ensuring correct order for fast loading of header + new_data_dict = {} + # some keys got deprecated, will be added when downgrading (this causes information loss during upgrading) + if not self.upgrading: + for key in ["task_id", "orig_performance", "top_performance"]: + new_data_dict[key] = ( + description_path.parent.name + "%" + description_path.stem if key == "task_id" else "" + ) + # these are all remaining entries (sorted via the new definition) + for key in ALL_TASK_DESCRIPTION_KEYS: + # these keys have been renamed + if key in replacements: + current = replacements[key] if self.upgrading else key + target = key if self.upgrading else replacements[key] + else: + current = target = key + if current not in data_dict: + raise RuntimeError(f"Did not find {current} in {description_path}.") + new_data_dict[target] = data_dict[current] + # write + with open(str(description_path), "wb") as f: + f.write(orjson.dumps(new_data_dict)) + print(description_path) + logger.info("Done rolling patch 0.12.") + + def _get_all_task_descriptions(self) -> List[Path]: + """ + Helper function ro receive all task descriptions of the installation. + + :return: List of paths to all .json files defining task descriptions. + """ + # gather all TASK descriptions + all_task_descriptions = [] + for dataset in (self.data_path / "RAW").iterdir(): + if not dataset.is_dir(): + continue + all_task_descriptions.extend(list(dataset.glob("".join(["[" + c + "]" for c in TASK_PREFIX]) + "*.json"))) + # now preprocessed folder + for preprocess in (self.data_path / "PREPROCESSED").iterdir(): + if not preprocess.is_dir(): + continue + for dataset in preprocess.iterdir(): + if not dataset.is_dir(): + continue + all_task_descriptions.extend( + list(dataset.glob("".join(["[" + c + "]" for c in TASK_PREFIX]) + "*.json")) + ) + return all_task_descriptions diff --git a/src/mml/core/scripts/utils.py b/src/mml/core/scripts/utils.py new file mode 100644 index 0000000..e2cc467 --- /dev/null +++ b/src/mml/core/scripts/utils.py @@ -0,0 +1,281 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import os +import sys +import time +from enum import Enum +from pathlib import Path +from types import TracebackType +from typing import Any, ClassVar, Dict, List, Optional, Type, TypeVar + +import p_tqdm.p_tqdm as p_tqdm +from dotenv import load_dotenv +from pathos.multiprocessing import ProcessPool +from pathos.threading import ThreadPool + +import mml +from mml.core.scripts.decorators import timeout +from mml.core.scripts.exceptions import MMLMisconfigurationException + +T = TypeVar("T") +TSingleton = TypeVar("TSingleton", bound="Singleton") + +__all__ = [ + "catch_time", + "throttle_logging", + "load_env", + "multi_threaded_p_tqdm", + "Singleton", + "LearningPhase", + "load_mml_plugins", + "TAG_SEP", + "ARG_SEP", + "ask_confirmation", +] + +logger = logging.getLogger(__name__) + +TAG_SEP = "+" +ARG_SEP = "?" +# provides information on loaded plugins +MML_PLUGINS_LOADED = {} + + +class catch_time: + """ + Timing utility context manager. Usage: + + .. code-block: python + + with catch_time() as timer: + # some code + + access time via `timer.pretty_time` afterward, e.g. for logging. + """ + + def __enter__(self) -> "catch_time": + self.elapsed = time.monotonic() + # self.time = datetime.datetime.now().replace(microsecond=0) + return self + + def __exit__( + self, exc_type: Optional[Type[BaseException]], exc: Optional[BaseException], traceback: Optional[TracebackType] + ) -> None: + self.elapsed = time.monotonic() - self.elapsed + self.hours, rest = divmod(self.elapsed, 3600) + self.minutes, self.seconds = divmod(rest, 60) + self.pretty_time = f"{self.hours}h {self.minutes}m {self.seconds:5.2f}s" + + +class throttle_logging: + """ + Logging utility context manager. Usage: + + .. code-block: python + + with throttle_logging(logging.SOME_LEVEL, (optional) package): + # some code that will only propagate logging above (excluding) specified level (of package if given) + + afterwards logging continues as before. The context manager checks if the root logger is in DEBUG mode and prevents + throttling in that case. + """ + + def __init__(self, level: int = logging.INFO, package: Optional[str] = None): + self.level = level + self.logger = logging.getLogger(package) if package else None + self.stored_level = self.logger.level if self.logger else None + + def __enter__(self) -> "throttle_logging": + if logging.root.level > logging.DEBUG: + if self.logger: + self.logger.setLevel(self.level + 1) + else: + logging.disable(self.level) + return self + + def __exit__( + self, exc_type: Optional[Type[BaseException]], exc: Optional[BaseException], traceback: Optional[TracebackType] + ) -> None: + if self.logger: + self.logger.setLevel(self.stored_level) # type: ignore + else: + logging.disable(logging.NOTSET) + + +def load_env() -> None: + """ + Loads the `mml.env` variables. Make sure to have renamed and adapted `example.env` beforehand. If an + environment variable `MML_ENV_PATH` is given this file is preferred, else the default path inside the `mml` + package is used. + + :return: None + """ + if os.getenv("MML_ENV_PATH", None): + dotenv_path = Path(os.getenv("MML_ENV_PATH")) + logger.debug(f"MML_ENV_PATH provided, will try to load env variables from {dotenv_path}.") + else: + dotenv_path = Path(mml.__file__).parent / "mml.env" + logger.debug(f"No MML_ENV_PATH provided, will try to load env variables from default path ({dotenv_path}).") + if dotenv_path.exists(): + load_dotenv(dotenv_path=dotenv_path) + if not Path(os.getenv("MML_DATA_PATH")).exists(): + raise MMLMisconfigurationException("Invalid MML_DATA_PATH, have you modified the mml.env entry?") + if not Path(os.getenv("MML_RESULTS_PATH")).exists(): + raise MMLMisconfigurationException("Invalid MML_RESULTS_PATH, have you modified the mml.env entry?") + try: + _ = int(os.getenv("MML_LOCAL_WORKERS")) + except ValueError: + raise MMLMisconfigurationException("Invalid MML_LOCAL_WORKERS, have you modified the mml.env entry?") + if not Path(os.getenv("MML_DATA_PATH")).exists(): + raise MMLMisconfigurationException("Invalid MML_DATA_PATH, have you modified the mml.env entry?") + else: + raise MMLMisconfigurationException( + f".env file not found at {dotenv_path}! Please follow the documentation " f"instructions to setup MML." + ) + + +class multi_threaded_p_tqdm: + """ + Switches the internally used pool type of p_tqdm package from ProcessPool to ThreadPool. + """ + + def __enter__(self) -> None: + p_tqdm.Pool = ThreadPool + + def __exit__( + self, exc_type: Optional[Type[BaseException]], exc: Optional[BaseException], traceback: Optional[TracebackType] + ) -> None: + p_tqdm.Pool = ProcessPool + + +class _SingletonMeta(type): + """ + This is a helper Metaclass to implement the Singleton class. + """ + + _instances: ClassVar[Dict[Type[T], T]] = {} + + def __call__(cls: Type[T], *args: Any, **kwargs: Any) -> T: + if cls not in cls._instances: + cls._instances[cls] = super(_SingletonMeta, cls).__call__(*args, **kwargs) + return cls._instances[cls] + + +class Singleton(metaclass=_SingletonMeta): + """ + The actual Singleton class to inherit from. Make sure to have Singleton as the leftmost base class. + """ + + @classmethod + def clear_instance(cls) -> None: + """ + Clears the cached instance of the singleton. Be aware, that this does not affect references to the "old" + instance, but any further call of "instance" or Class() will create a new instance, that will be returned from + any further call. + + :return: + """ + cls._instances.pop(cls) + + @classmethod + def instance(cls: Type[TSingleton], *args: Any, **kwargs: Any) -> TSingleton: + """ + Convenience function that does the same as Class(), but makes the singleton property more readable in code. + + :param args: any init args, be aware that these are ignored if there already exists an instance + :param kwargs: any init kwargs, be aware that these are ignored if there already exists an instance + :return: either a new instance (first call) or a reference to the already existing instance + """ + return cls.__call__(*args, **kwargs) + + @classmethod + def exists(cls) -> bool: + return cls in cls._instances + + +class StrEnum(str, Enum): + """ + Type of any enumerator with allowed comparison to string invariant to cases. + + Adopted from :class:`~pytorch_lightning.utilities.enums.LightningEnum`. + """ + + @classmethod + def from_str(cls, value: str) -> Optional["StrEnum"]: + for enum_key, enum_val in cls.__members__.items(): + if enum_val.lower() == value.lower() or enum_key.lower() == value.lower(): + return cls[enum_key] + raise ValueError(f"No match found for value {value} in enum {cls.__name__}") + + def __str__(self) -> str: + return self.value.lower() + + def __eq__(self, other: object) -> bool: + other = other.value if isinstance(other, Enum) else str(other) + return self.value.lower() == other.lower() + + def __hash__(self) -> int: + # re-enable hashtable so it can be used as a dict key or in a set + return hash(self.value.lower()) + + @classmethod + def list(cls) -> List[str]: + """ + Lists all members of a StrEnum class. + """ + return list(map(lambda c: c.value, cls)) + + +class LearningPhase(StrEnum): + TRAIN = "train" + VAL = "val" + TEST = "test" + + @staticmethod + def all_phases() -> List["LearningPhase"]: + return [LearningPhase.TRAIN, LearningPhase.VAL, LearningPhase.TEST] + + +def load_mml_plugins() -> None: + """ + This function allows to load mml plugins. These are other installed packages that provide a 'mml.plugins' entry + point. See https://packaging.python.org/en/latest/guides/creating-and-discovering-plugins/#using-package-metadata + for details on this mechanism. + """ + if sys.version_info < (3, 10): + from importlib_metadata import entry_points, version + else: + from importlib.metadata import entry_points, version + # load registered plugins + discovered_plugins = entry_points(group="mml.plugins") + if len(discovered_plugins) > 0: + # usually logger is not yet configured by hydra, so plugins are also stored in global variable later on + logger.info(f"Discovered plugins: {[p.name for p in discovered_plugins]}!") + for plugin in discovered_plugins: + logger.debug(f"Loading plugin {plugin.name}.") + _ = plugin.load() + logger.debug(f"Successfully loaded plugin {plugin.name}.") + global MML_PLUGINS_LOADED + MML_PLUGINS_LOADED.update({p.name: version(p.module.split(".")[0]) for p in discovered_plugins}) + + +@timeout(seconds=60) +def ask_confirmation(message: str = "") -> bool: + """ + Lets user confirm a message. + + :param message: The message to be confirmed + :return: bool indicating whether the message has been confirmed + :rtype: bool + """ + print(message) + response = input(">>") + if response.lower().strip() != "y": + return False + else: + return True diff --git a/src/mml/core/visualization/__init__.py b/src/mml/core/visualization/__init__.py new file mode 100644 index 0000000..90ffb6c --- /dev/null +++ b/src/mml/core/visualization/__init__.py @@ -0,0 +1,6 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + diff --git a/src/mml/core/visualization/cm.py b/src/mml/core/visualization/cm.py new file mode 100644 index 0000000..2a271a6 --- /dev/null +++ b/src/mml/core/visualization/cm.py @@ -0,0 +1,40 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import itertools +from typing import List + +import matplotlib.pyplot as plt +import numpy as np +import numpy.typing as npt + + +def render_confusion_matrix(cm: npt.NDArray[np.float64], classes: List[str]) -> plt.Figure: + """ + Returns a matplotlib figure containing the plotted confusion matrix. + + :param ~np.ndarray cm: the n by n confusion matrix with integer entries + :param List[str] classes: list of class names (same order as in the axes of the cm) + :return: matplotlib figure rendered the cm + """ + # plot background on true counts (interpretable from color bar) + fig = plt.figure(figsize=(8, 8)) + plt.imshow(cm, interpolation="nearest", cmap=plt.cm.Blues) + plt.title("Confusion matrix") + plt.colorbar() + # name rows and columns + tick_marks = np.arange(len(classes)) + plt.xticks(tick_marks, classes, rotation=45) + plt.yticks(tick_marks, classes) + # normalize each row (true class) and print relative values into cm cells + cm = np.around(cm.astype("float") / cm.sum(axis=1)[:, np.newaxis], decimals=2) + for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])): + plt.text(j, i, cm[i, j], horizontalalignment="center", color="red") + # name axes + plt.ylabel("True label") + plt.xlabel("Predicted label") + plt.tight_layout() + return fig diff --git a/src/mml/core/visualization/logo.py b/src/mml/core/visualization/logo.py new file mode 100644 index 0000000..dfe6b3a --- /dev/null +++ b/src/mml/core/visualization/logo.py @@ -0,0 +1,21 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + + +def show_logo(indent: int = 0): + """ + Prints the mml logo in ascii art to the terminal. + + :param int indent: specifies the number of blanks prepended + :return: + """ + logo_path = Path(__file__).parent / "mml_logo.txt" + with open(logo_path, "r") as file: + lines = file.readlines() + for line in lines: + print(" " * indent + line.rstrip()) diff --git a/src/mml/core/visualization/mml_logo.txt b/src/mml/core/visualization/mml_logo.txt new file mode 100644 index 0000000..450f664 --- /dev/null +++ b/src/mml/core/visualization/mml_logo.txt @@ -0,0 +1,11 @@ + _____ ______ _____ ______ ___ +|\ _ \ _ \|\ _ \ _ \|\ \ +\ \ \\\__\ \ \ \ \\\__\ \ \ \ \ + \ \ \\|__| \ \ \ \\|__| \ \ \ \ + \ \ \ \ \ \ \ \ \ \ \ \ \____ + \ \__\ \ \__\ \__\ \ \__\ \_______\ + \|__| \|__|\|__| \|__|\|_______| + ____ _ _ __ _ _ ____ _ _ + ( _ \( \/ ) ( )( \/ )/ ___)( \/ ) + ) _ ( ) / )( / \/ \\___ \ ) / + (____/(__/ (__)\_)(_/(____/(__/ \ No newline at end of file diff --git a/src/mml/core/visualization/predictions.py b/src/mml/core/visualization/predictions.py new file mode 100644 index 0000000..8fb4991 --- /dev/null +++ b/src/mml/core/visualization/predictions.py @@ -0,0 +1,136 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +"""Functions that allow nice plotting of model predictions.""" + +from itertools import cycle +from typing import List, Optional, Sequence, Union + +import numpy as np +import torch +from matplotlib import pyplot as plt +from torchvision.transforms import functional as F +from torchvision.utils import draw_segmentation_masks + +from mml.core.data_loading.task_attributes import TaskType +from mml.core.data_loading.utils import one_hot_mask +from mml.core.visualization.utils import COLORS + + +def render_predictions( + raw_images: torch.Tensor, logits: torch.Tensor, targets: torch.Tensor, classes: List[str], task_type: TaskType +) -> plt.Figure: + """ + Wrapper function to access task prediction renderers. + + :param torch.Tensor raw_images: non-normalized but potentially augmented (e.g. rotated) images + :param torch.Tensor logits: prediction logits + :param torch.Tensor targets: underlying targets + :param List[str] classes: class strings (order must match target indices) + :param TaskType task_type: the corresponding tasks task type + :return: a matplotlib figure that shows some model predictions + """ + if task_type not in PREDICTION_RENDERERS: + raise RuntimeError(f"Could not render predictions of task type {task_type}.") + func = PREDICTION_RENDERERS[task_type] + return func(raw_images=raw_images, logits=logits, targets=targets, classes=classes) + + +def render_classification_predictions( + raw_images: torch.Tensor, logits: torch.Tensor, targets: torch.Tensor, classes: List[str] +) -> plt.Figure: + """ + Implements prediction rendering for classification tasks. + """ + normalized_preds = torch.nn.functional.softmax(logits, dim=1) + grid = [] + for img_idx in range(raw_images.size(0)): + img = raw_images[img_idx] + row_list = [] + # raw image + row_list.append(img) + # reference + row_list.append(classes[targets[img_idx].cpu().item()]) + # iterate over classes + for cls_idx in range(len(classes)): + row_list.append(f"{normalized_preds[img_idx][cls_idx].cpu().item():.2f}") + grid.append(row_list) + return render_labeled_grid(img_grid=grid, col_labels=["Image", "Reference"] + classes) + + +def render_segmentation_predictions( + raw_images: torch.Tensor, logits: torch.Tensor, targets: torch.Tensor, classes: List[str] +) -> plt.Figure: + """ + Implements prediction rendering for segmentation tasks. + """ + color_cycle = cycle(COLORS) + color_list = [next(color_cycle) for _ in classes] + normalized_masks = torch.nn.functional.softmax(logits, dim=1) + one_hot_targets = one_hot_mask(mask=targets, num_classes=logits.size(1)).to(dtype=torch.bool, device="cpu") + grid = [] + for img_idx in range(raw_images.size(0)): + img = raw_images[img_idx] + row_list = [] + # raw image + row_list.append(img) + # reference + reference = draw_segmentation_masks( + image=(img * 255).to(dtype=torch.uint8, device="cpu"), + masks=one_hot_targets[img_idx], + alpha=0.8, + colors=color_list, + ) + row_list.append(reference) + # iterate over classes + for cls_idx in range(len(classes)): + row_list.append(normalized_masks[img_idx][cls_idx]) + grid.append(row_list) + return render_labeled_grid(img_grid=grid, col_labels=["Image", "Reference"] + classes) + + +def render_labeled_grid( + img_grid: Sequence[Sequence[Union[torch.Tensor, np.ndarray, str]]], col_labels: Optional[List[str]] +) -> plt.Figure: + """ + Takes a grid of images and strings and returns a matplotlib figure. + + :param Sequence[Sequence[Union[torch.Tensor, np.ndarray, str]]] img_grid: list of lists, containing images as + numpy arrays or torch tensors and potentially strings + :param Optional[List[str]] col_labels: (optional) labels for the columns of the grid + :return: a matplotlib figure with given column titles and rendered images / text + :rtype: plt.Figure + """ + if col_labels is None: + col_labels = [None for _ in img_grid[0]] + assert all([len(col_labels) == len(img_grid[i]) for i in range(len(img_grid))]) + fig, axs = plt.subplots(ncols=len(img_grid[0]), nrows=len(img_grid), squeeze=False) + for row_idx, row_imgs in enumerate(img_grid): + for col_idx, img in enumerate(row_imgs): + # transform tensors to array + if isinstance(img, torch.Tensor): + img = img.detach() + img = F.to_pil_image(img) + img = np.asarray(img) + if isinstance(img, np.ndarray): + axs[row_idx, col_idx].imshow(np.asarray(img)) + elif isinstance(img, str): + axs[row_idx, col_idx].text(0.5, 0.5, img, horizontalalignment="center", verticalalignment="center") + axs[row_idx, col_idx].set(xticklabels=[], yticklabels=[], xticks=[], yticks=[]) + if col_labels[col_idx] and row_idx == 0: + axs[0, col_idx].set_title( + label=col_labels[col_idx], rotation=45, fontsize="small", fontstretch="condensed" + ) + fig.subplots_adjust(hspace=0, wspace=0) + return fig + + +# access this dict from outside to provide additional rendering or modify existing ones +PREDICTION_RENDERERS = { + TaskType.CLASSIFICATION: render_classification_predictions, + TaskType.MULTILABEL_CLASSIFICATION: render_classification_predictions, + TaskType.SEMANTIC_SEGMENTATION: render_segmentation_predictions, +} diff --git a/src/mml/core/visualization/utils.py b/src/mml/core/visualization/utils.py new file mode 100644 index 0000000..7a2f80a --- /dev/null +++ b/src/mml/core/visualization/utils.py @@ -0,0 +1,52 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import torch + +from mml.core.data_loading.task_attributes import RGBInfo + +# list of easily distinguishable colors +COLORS = [ + "#e6194b", + "#3cb44b", + "#4363d8", + "#f58231", + "#911eb4", + "#46f0f0", + "#ffe119", + "#f032e6", + "#bcf60c", + "#fabebe", + "#008080", + "#e6beff", + "#9a6324", + "#fffac8", + "#800000", + "#aaffc3", + "#808000", + "#ffd8b1", + "#000075", + "#808080", + "#ffffff", + "#000000", +] + + +def undo_image_normalization(images: torch.Tensor, means: RGBInfo, stds: RGBInfo) -> torch.Tensor: + """ + Undoes the augmentation step of image normalization. This allows to visualize already augmented images. + + :param torch.Tensor images: batch of images + :param ~mml.core.data_loading.task_attributes.RGBInfo means: channel means used to normalize + :param ~mml.core.data_loading.task_attributes.RGBInfo stds: channel stds used to normalize + :return: batch of images, interpretable for matplotlib, BUT: not clipped nor stretched to [0,255] range + :rtype: torch.Tensor + """ + raw_images = images.clone() + mean = torch.tensor(means.get_rgb()).view(3, 1, 1).to(raw_images.device) + std = torch.tensor(stds.get_rgb()).view(3, 1, 1).to(raw_images.device) + raw_images.mul_(std).add_(mean) + return raw_images diff --git a/src/mml/interactive/__init__.py b/src/mml/interactive/__init__.py new file mode 100644 index 0000000..32ed4a6 --- /dev/null +++ b/src/mml/interactive/__init__.py @@ -0,0 +1,100 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +""" +The "mml.interactive" module contains helpers for using mml within interactive sessions, such as the REPL or a jupyter +notebook. +""" + +import os +import warnings +from pathlib import Path +from typing import Optional + +from mml.core.scripts.utils import load_env, load_mml_plugins +from mml.core.visualization.logo import show_logo + +_MML_INTERACTIVE_INITIALIZED = False + + +def init(env_path: Optional[Path] = None): + """ + The init function loads environment variables and mml plugins. It is recommended as first function call after + imports within a jupyter notebook or any other interactive session to plan, process or analyze any mml experiments. + + :param Optional[Path] env_path: as jupyter sometimes struggles to load `MML_ENV_PATH` it may be provided here + :return: + """ + global _MML_INTERACTIVE_INITIALIZED + if not _MML_INTERACTIVE_INITIALIZED: + # export MML_ENV_PATH if provided + if env_path: + if not env_path.exists(): + raise ValueError("Provided env_path does not exist, please provide existing mml.env path!") + else: + os.environ["MML_ENV_PATH"] = str(env_path) + else: + if "MML_ENV_PATH" not in os.environ: + warnings.warn( + 'Did not provide a "env_path", neither found set "MML_ENV_PATH" variable, ' + 'you might need to provide "env_path" to "init" in order to use "mml" ' + "interactively in a jupyter/ipython setting." + ) + # try to load everything + load_env() + load_mml_plugins() + show_logo() + _MML_INTERACTIVE_INITIALIZED = True + print("Interactive MML API initialized.") + else: + print("MML API already initialized.") + + +def _check_init() -> None: + """ + This function is intended to warn users if they approach functionality that requires initialization, but they missed + to do so. + + :raises: RuntimeError - in case no initialization took place + """ + # to capture the case that mml.interactive is used with already loaded env (e.g. in tests) we check for one entry + if not _MML_INTERACTIVE_INITIALIZED and not os.getenv("MML_DATA_PATH"): + raise RuntimeError("To use mml.interactive you need to call mml.interactive.init first.") + + +from mml.interactive.loading import ( # noqa: E402 + default_file_manager, + get_task_structs, + load_project_models, + merge_project_models, +) +from mml.interactive.planning import ( # noqa: E402 + AllTasksInfos, + DefaultRequirements, + EmbeddedJobRunner, + JobPrefixRequirements, + JobRunner, + MMLJobDescription, + SubprocessJobRunner, + get_task_infos, + write_out_commands, +) + +__all__ = [ + "load_project_models", + "AllTasksInfos", + "DefaultRequirements", + "JobPrefixRequirements", + "get_task_infos", + "MMLJobDescription", + "init", + "write_out_commands", + "merge_project_models", + "default_file_manager", + "get_task_structs", + "JobRunner", + "EmbeddedJobRunner", + "SubprocessJobRunner", +] diff --git a/src/mml/interactive/loading.py b/src/mml/interactive/loading.py new file mode 100644 index 0000000..4c5bdca --- /dev/null +++ b/src/mml/interactive/loading.py @@ -0,0 +1,110 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import contextlib +import os +from pathlib import Path +from typing import Dict, Generator, Iterable, List, Optional, Sequence, Union + +import omegaconf +from omegaconf import DictConfig + +from mml.core.data_loading.file_manager import MMLFileManager, ReuseConfig +from mml.core.data_loading.task_struct import TaskStruct, TaskStructFactory +from mml.core.scripts.model_storage import ModelStorage +from mml.interactive import _check_init + + +def load_project_models(project: str) -> Dict[str, List[ModelStorage]]: + """ + Loading utility to get all models of a given project. + + :param str project: name of the project, what has been inserted with 'proj=...' + :return: dict with task name keys and a list of all corresponding ModelStorages + """ + _check_init() + proj_path = Path(f"{os.getenv('MML_RESULTS_PATH')}/{project}") + tmp_log_path = proj_path / "tmp_log" + tmp_log_path.mkdir(exist_ok=True) + r_conf = ReuseConfig(models=f"{project}") + fm = MMLFileManager( + data_path=Path(f"{os.getenv('MML_DATA_PATH')}"), proj_path=proj_path, log_path=tmp_log_path, reuse_cfg=r_conf + ) + all_reusables = fm.reusables + MMLFileManager.clear_instance() + return {task_name: task_reusables["models"] for task_name, task_reusables in all_reusables.items()} + + +def merge_project_models(project_models_list: Iterable[Dict[str, List[ModelStorage]]]) -> Dict[str, List[ModelStorage]]: + """ + Merges models loaded from multiple projects. + + :param project_models_list: list of dicts, as returned by multiple calls from func::load_project_models + :return: merged list, as if all models were trained in one single project + """ + out = {} + for project_models in project_models_list: + for task, model_list in project_models.items(): + if task in out: + out[task].extend(model_list) + else: + out[task] = model_list + return out + + +@contextlib.contextmanager +def default_file_manager( + reuse_config: Optional[Union[DictConfig, ReuseConfig]] = None, +) -> Generator[MMLFileManager, None, None]: + """ + Convenience method to get a MMLFileManager instance. To be used in a with statement: + + .. code-block:: python + + with default_file_manager() as fm: + fm.do_something (e.g. extract information) + ... + + continue code with extracted information (without fm) + + :return: + """ + _check_init() + proj_path = Path(f"{os.getenv('MML_RESULTS_PATH')}/default") + tmp_log_path = proj_path / "tmp_log" + tmp_log_path.mkdir(exist_ok=True) + if reuse_config is None: + reuse_config = ReuseConfig() + try: + yield MMLFileManager( + data_path=Path(f"{os.getenv('MML_DATA_PATH')}"), + proj_path=proj_path, + log_path=tmp_log_path, + reuse_cfg=reuse_config, + ) + finally: + MMLFileManager.clear_instance() + + +def get_task_structs(tasks: Union[str, Sequence[str]], preprocessing: str = "default") -> List[TaskStruct]: + """ + Create a task struct on the fly. + + :param str tasks: task name or sequence of task names + :param str preprocessing: the preprocessing id of the task (default: 'default') + :return: the corresponding task struct + :rtype: TaskStruct + """ + _check_init() + cfg = omegaconf.OmegaConf.create({"preprocessing": {"id": preprocessing}}) + if isinstance(tasks, str): + tasks = [tasks] + structs = [] + with default_file_manager(): + factory = TaskStructFactory(cfg=cfg) + for task in tasks: + structs.append(factory.create_task_struct(name=task, return_ref=True)) + return structs diff --git a/src/mml/interactive/planning.py b/src/mml/interactive/planning.py new file mode 100644 index 0000000..003d9e3 --- /dev/null +++ b/src/mml/interactive/planning.py @@ -0,0 +1,427 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import dataclasses +import logging +import math +import os +import subprocess +import sys +from pathlib import Path +from typing import Dict, List, Optional, Sequence, Set, Union + +import numpy as np +import pandas as pd +import scipy.stats +from omegaconf import OmegaConf + +from mml.cli import main +from mml.core.data_loading.task_attributes import Keyword, TaskType +from mml.core.data_preparation.registry import get_dset_for_task +from mml.core.scripts.utils import TAG_SEP +from mml.interactive import _check_init +from mml.interactive.loading import default_file_manager + +logger = logging.getLogger(__name__) + + +@dataclasses.dataclass +class AllTasksInfos: + """ + A class to store all standard meta information on a set of tasks. + """ + + num_classes: Dict[str, int] + num_samples: Dict[str, int] + imbalance_ratios: Dict[str, float] + datasets: Dict[str, str] + keywords: Dict[str, Set[Keyword]] + task_types: Dict[str, TaskType] + domains: Dict[str, Keyword] + dimensions: Dict[str, int] + max_resolution: Dict[str, int] + min_resolution: Dict[str, int] + small_tasks: List[str] + medium_tasks: List[str] + large_tasks: List[str] + + def __repr__(self): + return f"AllTasksInfos({len(self.num_classes)} tasks: {list(self.num_classes.keys())})" + + def __post_init__(self): + """ + Automatically called after instantiation of an instance. Performs consistency check. + :return: + """ + self.check_consistency() + + def check_consistency(self): + """ + Performs assertions that all information cover the same set of tasks. + :return: + """ + assert ( + self.num_classes.keys() + == self.num_samples.keys() + == self.keywords.keys() + == self.max_resolution.keys() + == self.min_resolution.keys() + ) + assert (self.dimensions.keys() == self.num_classes.keys()) or len(self.dimensions) == 0 + # assert set(self.small_tasks) != set(self.medium_tasks) != set(self.large_tasks) != set(self.small_tasks) + assert set(self.num_classes) == set(self.small_tasks + self.medium_tasks + self.large_tasks) + + def get_transformed(self, transforms: Sequence[str] = ("boxcox", "normalize")) -> "AllTasksInfos": + """ + Allows to receive a modified instance of the task information where a couple of attributes are transformed. + + transformed attributes are: 'num_classes', 'num_samples', 'imbalance_ratios', 'dimensions', 'max_resolution', + 'min_resolution' + + available single transforms are: 'boxcox', 'normalize', 'zscore' + + :param Sequence[str] transforms: a sequence of legal transforms + :return: a modified version of the task information, transforms have been applied on all attributes listed above + + """ + if len(transforms) == 0: + return self + transform, *remaining_transforms = transforms + to_replace = [ + "num_classes", + "num_samples", + "imbalance_ratios", + "dimensions", + "max_resolution", + "min_resolution", + ] + replace_dict = {} + for _att in to_replace: + _dict = getattr(self, _att) + _vals = np.asarray(list(_dict.values())) + if transform == "boxcox": + _transformed, lmbda = scipy.stats.boxcox(_vals) + logger.debug(f"boxcox lambda for {_att} is {lmbda}") + elif transform == "zscore": + _transformed = scipy.stats.zscore(_vals) + elif transform == "log": + _transformed = np.log(_vals) + elif transform == "normalize": + _transformed = _vals / _vals.max() + else: + raise ValueError(f"transform {transform} not available") + replace_dict[_att] = dict(zip(_dict.keys(), _transformed)) + return dataclasses.replace(self, **replace_dict).get_transformed(remaining_transforms) + + def store_csv(self, path: Path) -> None: + """ + Reformat meta information and write as a csv file. + + :param Path path: path to store csv file + :return: None + """ + all_tasks = sorted(self.num_samples.keys()) + task_infos = [] + for t in all_tasks: + info_dict = {"name": t} + for attr in [ + "task_types", + "num_classes", + "num_samples", + "domains", + "imbalance_ratios", + "datasets", + "keywords", + "dimensions", + "max_resolution", + "min_resolution", + ]: + attr_dict = getattr(self, attr) + try: + elem = attr_dict[t] + if attr == "keywords": # Set[Keyword] + elem = [str(_kw) for _kw in sorted(elem)] + elif attr == "task_types" or attr == "domains": # TaskType or Keyword + elem = str(elem) + info_dict[attr] = elem + except KeyError: + # some entries might be missing + pass + task_infos.append(info_dict) + df = pd.DataFrame(task_infos) + df.to_csv(path) + + @classmethod + def from_csv(cls, path: Path) -> "AllTasksInfos": + """ + Load stored AllTasksInfos from a csv file. + + :param path: path to load csv file + :return: AllTasksInfos + """ + df = pd.read_csv(path).set_index("name") + kwargs = {} + for attr in [ + "task_types", + "num_classes", + "num_samples", + "domains", + "imbalance_ratios", + "datasets", + "keywords", + "dimensions", + "max_resolution", + "min_resolution", + ]: + kwargs[attr] = df[attr].to_dict() if attr in df.columns else {} + if attr == "keywords": # Dict[str, Set[Keyword]] + for task in kwargs[attr]: + if kwargs[attr][task]: + kwargs[attr][task] = set( + [Keyword.from_str(_kw.strip(" \[\]'")) for _kw in kwargs[attr][task].split(",")] + ) + elif attr == "task_types": # Dict[str, TaskType] + kwargs[attr] = {task: TaskType(entry) for task, entry in kwargs[attr].items() if isinstance(entry, str)} + elif attr == "domains": # Dict[str, Keyword] + kwargs[attr] = {task: Keyword(entry) for task, entry in kwargs[attr].items() if isinstance(entry, str)} + + small_tasks = [t for t, size in kwargs["num_samples"].items() if size < 1000] + medium_tasks = [t for t, size in kwargs["num_samples"].items() if 1000 <= size < 10000] + large_tasks = [t for t, size in kwargs["num_samples"].items() if size >= 10000] + all_infos = cls(small_tasks=small_tasks, medium_tasks=medium_tasks, large_tasks=large_tasks, **kwargs) + return all_infos + + +def get_task_infos(task_list: List[str], dims: Optional[str] = None) -> AllTasksInfos: + """ + Most convenient way to receive a :class:AllTasksInfos instance. Provide a list of aliases and optional a project + name that computed dimensions before. + + :param List[str] task_list: list of task names, tasks must be available on the machine (run create before if + not) + :param Optional[str] dims: (optional) project name that computed dimensions with mml dim proj=THIS_ARG + :return: relevant meta information on all tasks combined in one object + :rtype: AllTasksInfos + """ + _check_init() + if dims: + r_conf = OmegaConf.create({"dimension": dims}) + try: + from mml_dimensionality.scripts.utils import load_dim + except ImportError: + raise ImportError("Install mml-dimensionality to use the dim functionality of get_task_infos.") + else: + load_dim = None + r_conf = OmegaConf.create({}) + # initialize empty dicts + num_classes = {} + num_samples = {} + imbalance_ratios = {} + keywords = {} + domains = {} + dimensions = {} + task_types = {} + max_resolution = {} + min_resolution = {} + domain_list = [ + Keyword.DERMATOSCOPY, + Keyword.LARYNGOSCOPY, + Keyword.GASTROSCOPY_COLONOSCOPY, + Keyword.LAPAROSCOPY, + Keyword.NATURAL_OBJECTS, + Keyword.HANDWRITINGS, + Keyword.CATARACT_SURGERY, + Keyword.FUNDUS_PHOTOGRAPHY, + Keyword.MRI_SCAN, + Keyword.X_RAY, + Keyword.CT_SCAN, + Keyword.CLE, + Keyword.CAPSULE_ENDOSCOPY, + Keyword.ULTRASOUND, + ] + overarching_dataset = {} + with default_file_manager(reuse_config=r_conf) as fm: + for task in task_list: + meta = fm.get_task_info(task, preprocess="none") + num_classes[task] = len(set(meta["idx_to_class"].values())) + task_desc = fm.load_task_description(fm.data_path / meta["relative_root"]) + num_samples[task] = task_desc.num_samples + try: + imbalance_ratios[task] = max(meta["class_occ"].values()) / min(meta["class_occ"].values()) + except ZeroDivisionError: + logger.error(f"Division by zero while computing imbalance ratio for task {task}.") + except ValueError: + logger.error(f"Unable to compute imbalance ratio for task {task}. Class occ = {meta['class_occ']}") + keywords[task] = set(meta["keywords"]) + task_types[task] = meta["task_type"] + sizes = meta["sizes"] + min_resolution[task] = sizes.min_height * sizes.min_width + max_resolution[task] = sizes.max_height * sizes.max_width + domain_candidates = [d for d in keywords[task] if d in domain_list] + if len(domain_candidates) != 1: + logger.error(f"Error while searching domain for task {task}, have candidates {domain_candidates}") + else: + domains[task] = domain_candidates[0].value + try: + plain_task = task.split(TAG_SEP)[0] + overarching_dataset[task] = get_dset_for_task(task_name=plain_task) + except KeyError: + logger.error(f"No registered dataset for task {task}.") + if dims: + dimensions[task] = load_dim(fm.reusables[task]["dimension"]) + small_tasks = [t for t, size in num_samples.items() if size < 1000] + medium_tasks = [t for t, size in num_samples.items() if 1000 <= size < 10000] + large_tasks = [t for t, size in num_samples.items() if size >= 10000] + all_infos = AllTasksInfos( + num_classes=num_classes, + num_samples=num_samples, + imbalance_ratios=imbalance_ratios, + keywords=keywords, + domains=domains, + dimensions=dimensions, + max_resolution=max_resolution, + min_resolution=min_resolution, + small_tasks=small_tasks, + medium_tasks=medium_tasks, + large_tasks=large_tasks, + datasets=overarching_dataset, + task_types=task_types, + ) + return all_infos + + +# Helper functions for rendering and running mml calls in different scenarios + + +class JobPrefixRequirements: + """The job prefix requirements to a job. Basically resolves how to invoke mml on the system.""" + + def get_prefix(self) -> str: ... + + +class DefaultRequirements(JobPrefixRequirements): + """The default how to call MML from e.g. a local machine (assuming it to be installed and the environment to + be loaded.""" + + def get_prefix(self) -> str: + return "mml" + + +@dataclasses.dataclass +class MMLJobDescription: + """ + Combined description of an MML call. Includes prefix requirements, config options and a multirun flag for hpo. + """ + + prefix_req: JobPrefixRequirements + mode: str + config_options: Dict[str, Union[str, float, List[Union[str, int, float]], int]] + multirun: bool = False + + def render(self) -> str: + """ + Actually renders the job description. + + :return: A string that might be pasted into a terminal to start the job described. + """ + parts = [self.prefix_req.get_prefix(), self.mode] + for key, option in self.config_options.items(): + if isinstance(option, str) and " " in option: + raise ValueError("Found whitespace in JobDescription!") + # no check for interrupting str in list + if isinstance(option, list): + option = str(option).replace(" ", "") + if key == "mode": + raise ValueError( + "Providing mode inside config_options is not supported anymore, provide mode " + "directly to MMLJobDescription." + ) + parts.append(f"{key}={option}") + if self.multirun: + parts.append("--multirun") + return " ".join(parts) + + def run(self, runner: "JobRunner") -> Optional[float]: + """ + Runs the job with the given runner. + + :param JobRunner runner: the runner to run the job. + :return: Potentially a float that represents the return value of the specified experiment (not guaranteed) + """ + return runner.run(job=self) + + +class JobRunner: + """The runner that invokes the rendered MML call.""" + + def run(self, job: MMLJobDescription): ... + + +class EmbeddedJobRunner(JobRunner): + """ + The embedded runner allows to start mml directly from within the same python interpreter, hence any previous + variables, imports, etc. are available during runtime. This also allows to receive the return value of MML. + """ + + def run(self, job: MMLJobDescription): + # override sys.argv + sys.argv = job.render().split(" ") + return main() + + +class SubprocessJobRunner(JobRunner): + """ + The subprocess runner only inherits the virtual environment but starts a new process including a new interpreter. + Any variables in the current interpreter will not be available during this run. It does not receive any return + values of an experiment. + """ + + def run(self, job: MMLJobDescription): + subprocess.run(job.render().split(" ")) + + +# convenience function for producing long outputs +def write_out_commands( + cmd_list: List[MMLJobDescription], + name: str = "output", + seperator: Optional[str] = "sleep 2\n", + max_cmds: Optional[int] = None, +) -> None: + """ + Writes a list of :class:MMLJobDescription into a file that may be called by a shell afterward. This is particularly + useful if the commands should be transferred to a different host via ssh, e.g. with:: + + ssh user@host 'bash -s' < /path/to/output.txt + + :param List[MMLJobDescription] cmd_list: list of commands + :param Optional[str] name: a file name to relate cmds to a common project or experiment, defaults to 'output' + :param Optional[str] seperator: (optional) a line seperator, useful if e.g. sleep X should delay cmd submission to + a cluster + :param Optional[int] max_cmds: (optional) max number of cmds per file, will split into consecutive files if more + cmds are present + :return: + """ + if seperator is None: + seperator = "" + else: + if len(seperator) > 0 and seperator[-1] != "\n": + raise ValueError( + "Seperator does not end line, this may cause interference with cmds and should be avoided!" + ) + if max_cmds is None: + max_cmds = len(cmd_list) + 1 + num_splits = math.ceil(len(cmd_list) / max_cmds) + for split_idx in range(num_splits): + file_name = name + if num_splits > 1: + file_name += f"_{split_idx}" + file_name += ".txt" + out = "" + for cmd in cmd_list[split_idx * max_cmds : (split_idx + 1) * max_cmds]: + out = out + cmd.render() + "\n" + seperator + with open(Path(os.path.abspath("")) / file_name, "w") as file: + file.write(out) + print(f"Stored {len(cmd_list[split_idx * max_cmds: (split_idx + 1) * max_cmds])} commands at {file_name}.") diff --git a/src/mml/template.env b/src/mml/template.env new file mode 100644 index 0000000..afd3df6 --- /dev/null +++ b/src/mml/template.env @@ -0,0 +1,62 @@ +# This is a template file for mml local variables setup. +# + +# ╔═════════════╗ +# ║ IMPORTANT ║ +# ╚═════════════╝ +# It is recommended to use the `mml-env-setup` command to create your personel mml.env file! After pip installing +# mml-core, navigate to your preferred config file storage location (e.g. ~/.config/mml) and start mml-env-setup. +# +# ALTERANTIVE MANUAL SETUP: +# Please duplicate the file and rename as "mml.env", afterwards set your variables - +# if you move to a different location, make sure to provide MML_ENV_PATH to your shell before starting mml + +# ╔═════════════════════════════╗ +# ║ Bare minimum - local system ║ +# ╚═════════════════════════════╝ +# Path variables, provides storage for data (input) and results (output) +export MML_DATA_PATH=/path/to/data +export MML_RESULTS_PATH=/path/to/results +export MML_LOCAL_WORKERS=available_local_CPU_cores + +# ╔════════════════════════════╗ +# ║ Config location management ║ +# ╚════════════════════════════╝ +# MML config location information (used when mofifications of configs files are needen, see docs for details) +# leave as is to use mml default configs files location +# make sure to be compatible across systems +export MML_CONFIGS_PATH=DEFAULT_CONF_PATH +export MML_CONFIG_NAME=config_mml + +# ╔══════════════════════════════════════╗ +# ║ Additional system - "cluster" system ║ +# ╚══════════════════════════════════════╝ +# mml supports an additional system (named cluster) out of the box, provide details here, similar to local system +export MML_CLUSTER_DATA_PATH=/gpu/data/... +export MML_CLUSTER_RESULTS_PATH=/gpu/checkpoints/... +export MML_CLUSTER_WORKERS=12 + +# ╔════════════╗ +# ║ Kaggle API ║ +# ╚════════════╝ +# OPTIONAL Kaggle API settings (see https://github.com/Kaggle/kaggle-api#api-credentials for details) +# only necessary when downloading kaggle datasets during "mml create ..." (example tasks see mml-data plugin) +export KAGGLE_USERNAME=your_kaggle_username +export KAGGLE_KEY=your_kaggle_api_key + +# ╔═══════════╗ +# ║ Notifiers ║ +# ╚═══════════╝ +# mml supports notification systems to message e.g. failed runs, see mml.core.scripts.notifier.py for more details +# notifications are optional and notifiers are independent +# Slack notifier +# URL for failure notification +export MML_SLACK_WEBHOOK_URL=dummy +# Email notifier +# details for failure notification +export MML_SMTP_SERVER=dummy +export MML_SMTP_SERVER_PORT=dummy +export MML_SENDER_EMAIL=dummy +export MML_RECEIVER_EMAIL=dummy +# set to NO_PASSWORD if there is no password necessary +export MML_MAIL_PASSWORD=NO_PASSWORD \ No newline at end of file diff --git a/src/mml/testing/__init__.py b/src/mml/testing/__init__.py new file mode 100644 index 0000000..2555c96 --- /dev/null +++ b/src/mml/testing/__init__.py @@ -0,0 +1,5 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# diff --git a/src/mml/testing/dummy_fake_model_storage.json b/src/mml/testing/dummy_fake_model_storage.json new file mode 100644 index 0000000..0a8dae5 --- /dev/null +++ b/src/mml/testing/dummy_fake_model_storage.json @@ -0,0 +1,14 @@ +{ + "pipeline": "dummy_project/PIPELINES/mml_fake_task+nested?0/pipeline_9999.yaml", + "parameters": "dummy_project/PARAMETERS/mml_fake_task+nested?0/model_9999.pth", + "performance": 3.1415, + "training_time": 1234.0, + "task": "mml_fake_task+nested?0", + "fold": 0, + "created": "2024-08-13T15:39:03", + "metrics": [], + "predictions": { + "mml_fake_task+nested?0": "dummy_project/PREDICTIONS/mml_fake_task+nested?0/preds-fold-0_9999.pt", + "mml_fake_task": "dummy_project/PREDICTIONS/mml_fake_task/preds-fold-0_9999.pt" + } +} \ No newline at end of file diff --git a/src/mml/testing/dummy_fake_pipeline.yaml b/src/mml/testing/dummy_fake_pipeline.yaml new file mode 100644 index 0000000..193b5a2 --- /dev/null +++ b/src/mml/testing/dummy_fake_pipeline.yaml @@ -0,0 +1,90 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +arch: + _target_: mml.core.models.timm.TimmGenericModel + pretrained: true + name: resnet34 + drop_rate: 0.0 +optimizer: + _target_: torch.optim.Adam + lr: 0.0005 + eps: 1.0e-08 + weight_decay: 0 + betas: + - 0.9 + - 0.999 + _convert_: partial +lr_scheduler: + _target_: null +loss: + cls: + _target_: torch.nn.CrossEntropyLoss + mlcls: + _target_: torch.nn.BCEWithLogitsLoss + seg: + _target_: segmentation_models_pytorch.losses.DiceLoss + mode: multiclass + ignore_index: 255 + reg: + _target_: torch.nn.HuberLoss + delta: 1.0 + auto_activate_weighing: true + class_weights: null +cbs: + stats: + _target_: lightning.pytorch.callbacks.DeviceStatsMonitor + lrm: + _target_: lightning.pytorch.callbacks.LearningRateMonitor +trainer: + _target_: lightning.Trainer + benchmark: true + precision: 16-mixed + min_epochs: 10 + max_epochs: 5 + enable_model_summary: true + num_sanity_val_steps: 0 + max_time: null + accelerator: auto + devices: 1 +preprocessing: + id: default + pipeline: + - name: SmallestMaxSize + max_size: 256 + - name: PadIfNeeded + min_height: 288 + min_width: 288 + - name: Resize + height: 256 + width: 256 +augmentations: + normalization: imagenet + cpu: + backend: albumentations + pipeline: + - name: RandomCrop + height: 224 + width: 224 + - name: ShiftScaleRotate + shift_limit: 0.05 + scale_limit: 0.05 + rotate_limit: 15 + p: 0.5 + - name: HorizontalFlip + p: 0.5 + - name: RandomBrightnessContrast + p: 0.5 + - name: CoarseDropout + p: 0.5 + gpu: {} +sampling: + sample_num: 0 + balanced: false + batch_size: 300 + drop_last: false + enable_caching: false + cache_max_size: 10000 \ No newline at end of file diff --git a/src/mml/testing/dummy_fake_preds.pt b/src/mml/testing/dummy_fake_preds.pt new file mode 100644 index 0000000000000000000000000000000000000000..3e01aa5bc92d712629327d8197726c9975743871 GIT binary patch literal 272440 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 literal 0 HcmV?d00001 diff --git a/src/mml/testing/dummy_meta_class.json b/src/mml/testing/dummy_meta_class.json new file mode 100644 index 0000000..58f2a97 --- /dev/null +++ b/src/mml/testing/dummy_meta_class.json @@ -0,0 +1,112 @@ +{ + "name": "dummy_task", + "description": "Used for testing of loading and writing task meta information.", + "creation_protocol": "Obsolete", + "reference": "Obsolete", + "url": "Obsolete", + "download": "Obsolete", + "license": "unknown", + "release": "Obsolete", + "task_type": "classification", + "keywords": [ + "dermatoscopy", + "medical", + "tissue_pathology" + ], + "means": [ + 0.7533503770828247, + 0.5765432715415955, + 0.488544762134552 + ], + "stds": [ + 0.2007199078798294, + 0.19744035601615906, + 0.20265881717205048 + ], + "sizes": [ + 553, + 577, + 761, + 769 + ], + "modalities": { + "image": ".bmp; ", + "class": "" + }, + "idx_to_class": { + "0": "test", + "1": "another", + "2": "random" + }, + "class_occ": { + "test": 3, + "another": 4, + "random": 3 + }, + "unlabeled_samples": {}, + "train_folds": [ + [ + "ID0", + "ID1" + ], + [ + "ID2", + "ID3" + ], + [ + "ID4", + "ID5" + ], + [ + "ID6", + "ID7" + ], + [ + "ID8", + "ID9" + ] + ], + "train_samples": { + "ID0": { + "image": "dummy0.bmp", + "class": 0 + }, + "ID1": { + "image": "dummy1.bmp", + "class": 1 + }, + "ID2": { + "image": "dummy2.bmp", + "class": 2 + }, + "ID3": { + "image": "dummy3.bmp", + "class": 1 + }, + "ID4": { + "image": "dummy4.bmp", + "class": 0 + }, + "ID5": { + "image": "dummy5.bmp", + "class": 2 + }, + "ID6": { + "image": "dummy6.bmp", + "class": 2 + }, + "ID7": { + "image": "dummy7.bmp", + "class": 1 + }, + "ID8": { + "image": "dummy8.bmp", + "class": 0 + }, + "ID9": { + "image": "dummy9.bmp", + "class": 1 + } + }, + "test_samples": {} +} \ No newline at end of file diff --git a/src/mml/testing/dummy_meta_seg.json b/src/mml/testing/dummy_meta_seg.json new file mode 100644 index 0000000..f435f8a --- /dev/null +++ b/src/mml/testing/dummy_meta_seg.json @@ -0,0 +1,112 @@ +{ + "name": "dummy_task", + "description": "Used for testing of loading and writing task meta information.", + "creation_protocol": "Obsolete", + "reference": "Obsolete", + "url": "Obsolete", + "download": "Obsolete", + "license": "unknown", + "release": "Obsolete", + "task_type": "semantic_segmentation", + "keywords": [ + "dermatoscopy", + "medical", + "tissue_pathology" + ], + "means": [ + 0.7533503770828247, + 0.5765432715415955, + 0.488544762134552 + ], + "stds": [ + 0.2007199078798294, + 0.19744035601615906, + 0.20265881717205048 + ], + "sizes": [ + 553, + 577, + 761, + 769 + ], + "modalities": { + "image": ".bmp; ", + "mask": "dummy" + }, + "idx_to_class": { + "0": "background", + "1": "another", + "2": "random" + }, + "class_occ": { + "background": 10, + "another": 8, + "random": 2 + }, + "unlabeled_samples": {}, + "train_folds": [ + [ + "ID0", + "ID1" + ], + [ + "ID2", + "ID3" + ], + [ + "ID4", + "ID5" + ], + [ + "ID6", + "ID7" + ], + [ + "ID8", + "ID9" + ] + ], + "train_samples": { + "ID0": { + "image": "dummy0.bmp", + "mask": "EMPTY_MASK_TOKEN" + }, + "ID1": { + "image": "dummy1.bmp", + "mask": "EMPTY_MASK_TOKEN" + }, + "ID2": { + "image": "dummy2.bmp", + "mask": "dummy_mask_2.png" + }, + "ID3": { + "image": "dummy3.bmp", + "mask": "dummy_mask_3.png" + }, + "ID4": { + "image": "dummy4.bmp", + "mask": "EMPTY_MASK_TOKEN" + }, + "ID5": { + "image": "dummy5.bmp", + "mask": "dummy_mask_5.png" + }, + "ID6": { + "image": "dummy6.bmp", + "mask": "EMPTY_MASK_TOKEN" + }, + "ID7": { + "image": "dummy7.bmp", + "mask": "dummy_mask_7.png" + }, + "ID8": { + "image": "dummy8.bmp", + "mask": "EMPTY_MASK_TOKEN" + }, + "ID9": { + "image": "dummy9.bmp", + "mask": "dummy_mask_9.png" + } + }, + "test_samples": {} +} \ No newline at end of file diff --git a/src/mml/testing/fixtures.py b/src/mml/testing/fixtures.py new file mode 100644 index 0000000..d9a3c4f --- /dev/null +++ b/src/mml/testing/fixtures.py @@ -0,0 +1,275 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +from pathlib import Path + +import numpy as np +import pytest +from hydra import compose, initialize_config_module +from pytorch_lightning import seed_everything + +import mml.core.scripts.utils +from mml.core.data_loading.file_manager import MMLFileManager +from mml.core.data_loading.task_attributes import Keyword, Modality, RGBInfo, Sizes, TaskType +from mml.core.data_loading.task_dataset import TaskDataset +from mml.core.data_loading.task_description import TaskDescription +from mml.core.data_loading.task_struct import TaskStruct, TaskStructFactory +from mml.core.data_preparation.fake_task import create_fake_dset, create_fake_task +from mml.core.scripts.utils import throttle_logging + + +@pytest.fixture(scope="function") +def fake_task(file_manager): + dset_path = create_fake_dset() + task_path = create_fake_task(dset_path) + file_manager.add_to_task_index(task_path) + yield + + +@pytest.fixture(autouse=True) +def no_plugins(monkeypatch, request): + # do not mock in case the test is marked (with "@pytest.mark.plugin") + if "plugin" in request.keywords: + yield + return + + # mock plugin loading (only effective in local test setups) + + def mock_load_plugins(*args, **kwargs): + pass + + # deactivate any plugin loading during the runs + monkeypatch.setattr(mml.core.scripts.utils, "load_mml_plugins", mock_load_plugins) + print("deactivated plugin loading") + yield + + +@pytest.fixture(autouse=True) +def env_variables(monkeypatch, tmp_path_factory, request): + # do not mock in case the test is marked (with "@pytest.mark.env") + if "env" in request.keywords: + yield + return + + # prevents resolving issues with the config + def mock_load_env(): + pass + + # first deactivate any env loading during the runs + monkeypatch.setattr(mml.core.scripts.utils, "load_env", mock_load_env) + # then set env variables accordingly + monkeypatch.setenv("MML_CONFIGS_PATH", "DEFAULT_CONF_PATH") + monkeypatch.setenv("MML_CONFIG_NAME", "config_mml") + monkeypatch.setenv("MML_DATA_PATH", str(tmp_path_factory.mktemp(basename="data"))) + monkeypatch.setenv("MML_RESULTS_PATH", str(tmp_path_factory.mktemp(basename="results"))) + monkeypatch.setenv("MML_LOCAL_WORKERS", "0") # test everything single threaded by default + monkeypatch.setenv("MML_MYSQL_USER", "test") + monkeypatch.setenv("MML_MYSQL_PW", "test") + monkeypatch.setenv("MML_HOSTNAME_OF_MYSQL_HOST", "test") + monkeypatch.setenv("MML_MYSQL_DATABASE", "test") + monkeypatch.setenv("MML_MYSQL_PORT", "test") + monkeypatch.setenv("MML_CLUSTER_WORKERS", "test") + monkeypatch.setenv("MML_CLUSTER_DATA_PATH", "test") + monkeypatch.setenv("MML_CLUSTER_RESULTS_PATH", "test") + monkeypatch.setenv("KAGGLE_USERNAME", "test") + monkeypatch.setenv("KAGGLE_KEY", "test") + print("monkeypatched environment variables") + yield + + +@pytest.fixture +def file_manager(tmp_path_factory, monkeypatch): + # store class attributes + assignments_backup = MMLFileManager._path_assignments.copy() + log_path = tmp_path_factory.mktemp(basename="logging") + results_root = tmp_path_factory.mktemp(basename="results") + proj_path = results_root / "test_project" + proj_path.mkdir() + monkeypatch.chdir(log_path) + manager = MMLFileManager( + data_path=tmp_path_factory.mktemp(basename="data"), + proj_path=proj_path, + log_path=log_path, + ) + yield manager + try: + MMLFileManager.clear_instance() + except KeyError: + # some routines might clear instance by themselves + pass + MMLFileManager._path_assignments = assignments_backup + + +@pytest.fixture +def dummy_meta_class_path(): + yield Path(__file__).parent / "dummy_meta_class.json" + + +@pytest.fixture +def dummy_meta_seg_path(): + yield Path(__file__).parent / "dummy_meta_seg.json" + + +@pytest.fixture +def dummy_fake_model_storage_path(): + yield Path(__file__).parent / "dummy_fake_model_storage.json" + + +@pytest.fixture +def dummy_fake_predictions_path(): + yield Path(__file__).parent / "dummy_fake_preds.pt" + + +@pytest.fixture +def dummy_fake_pipeline_path(): + yield Path(__file__).parent / "dummy_fake_pipeline.yaml" + + +@pytest.fixture +def image(): + return np.random.randint(low=0, high=256, size=(100, 100, 3), dtype=np.uint8) + + +@pytest.fixture +def mask(): + return np.random.randint(low=0, high=2, size=(100, 100), dtype=np.uint8) + + +@pytest.fixture +def mml_config(): + with initialize_config_module(config_module="mml.configs", version_base=None): + cfg = compose( + config_name="config_mml", + overrides=["mode.subroutines=[test]", "preprocessing=default", "augmentations=default"], + ) + cfg["num_workers"] = int(cfg["num_workers"]) + cfg.arch.name = "resnet18" + cfg.trainer.enable_model_summary = False + cfg.cbs = { + "stats": {"_target_": "lightning.pytorch.callbacks.DeviceStatsMonitor"}, + "lrm": {"_target_": "lightning.pytorch.callbacks.LearningRateMonitor"}, + } + cfg.trainer.min_epochs = 1 + cfg.trainer.max_epochs = 1 + cfg.sampling.sample_num = 20 + cfg.sampling.balanced = False + cfg.sampling.batch_size = 10 + cfg.sampling.enable_caching = False + cfg.sampling.cache_max_size = 0 + yield cfg + + +@pytest.fixture(scope="session", autouse=True) +def deactivate_lightning_logging(): + with throttle_logging(level=logging.WARN, package="pytorch_lightning"): + yield + + +@pytest.fixture(autouse=True) +def make_deterministic(): + seed_everything(42) + yield + + +@pytest.fixture +def test_task_monkeypatch(file_manager, monkeypatch, image, mask): + # the test struct that will be returned by the task factory + test_structs = { + f"test_task_{x}": TaskStruct( + name=f"test_task_{x}", + task_type=TaskType.CLASSIFICATION, + modalities={Modality.CLASS: "", Modality.IMAGE: "test"}, + means=RGBInfo(*[0.5, 0.5, 0.5]), + stds=RGBInfo(*[0.1, 0.1, 0.1]), + sizes=Sizes(*[100, 100, 100, 100]), + relative_root=f"root_{x}", + class_occ={"zero": 100, "one": 100, "two": 100}, + preprocessed="none", + keywords=[Keyword.ARTIFICIAL], + idx_to_class={0: "zero", 1: "one", 2: "two"}, + ) + for x in "abc" + } + test_structs["test_task_d"] = TaskStruct( + name="test_task_d", + task_type=TaskType.SEMANTIC_SEGMENTATION, + modalities={Modality.MASK: "", Modality.IMAGE: "test"}, + means=RGBInfo(*[0.5, 0.5, 0.5]), + stds=RGBInfo(*[0.1, 0.1, 0.1]), + sizes=Sizes(*[100, 100, 100, 100]), + relative_root="root_d", + class_occ={"zero": 100, "one": 100, "two": 100}, + preprocessed="none", + keywords=[Keyword.ARTIFICIAL], + idx_to_class={0: "zero", 1: "one", 2: "two"}, + ) + + def get_test_struct(self, name): + return test_structs[name] + + monkeypatch.setattr(target=TaskStructFactory, name="get_by_name", value=get_test_struct) + + # the meta information that will be returned by the file manager + task_description_class = TaskDescription.from_json( + { + "task_type": TaskType.CLASSIFICATION, + "modalities": {Modality.IMAGE: None, Modality.CLASS: None}, + "idx_to_class": {0: "zero", 1: "one", 2: "two"}, + "class_occ": {"zero": 100, "one": 100, "two": 100}, + "train_folds": [[str(x) for x in range(60 * y, 60 * (y + 1))] for y in range(5)], + "train_samples": { + str(x): {Modality.IMAGE: "some_path", Modality.CLASS: np.random.randint(low=0, high=3)} + for x in range(300) + }, + "test_samples": { + str(x): {Modality.IMAGE: "some_path", Modality.CLASS: np.random.randint(low=0, high=3)} + for x in range(50) + }, + "name": "test_task_class", + } + ) + task_description_seg = TaskDescription.from_json( + { + "task_type": TaskType.SEMANTIC_SEGMENTATION, + "modalities": {Modality.IMAGE: None, Modality.MASK: None}, + "idx_to_class": {0: "zero", 1: "one", 2: "two"}, + "class_occ": {"zero": 100, "one": 100, "two": 100}, + "train_folds": [[str(x) for x in range(60 * y, 60 * (y + 1))] for y in range(5)], + "train_samples": {str(x): {Modality.IMAGE: "some_path", Modality.MASK: "another_path"} for x in range(300)}, + "test_samples": {str(x): {Modality.IMAGE: "some_path", Modality.MASK: "another_path"} for x in range(50)}, + "name": "test_task_seg", + } + ) + + def get_test_descriptions(self, path=None): + # this trick covers both use cases as staticmethod and default class method + if path is None: + path = self + task_type = ( + TaskType.CLASSIFICATION if str(path.stem).split("_")[-1] in "abc" else TaskType.SEMANTIC_SEGMENTATION + ) + return {TaskType.CLASSIFICATION: task_description_class, TaskType.SEMANTIC_SEGMENTATION: task_description_seg}[ + task_type + ] + + monkeypatch.setattr(target=MMLFileManager, name="load_task_description", value=get_test_descriptions) + + # the data that will be returned when loading a sample + + def get_test_sample(self, index): + return { + Modality.IMAGE.value: np.random.randint(low=0, high=256, size=(100, 100, 3), dtype=np.uint8), + Modality.CLASS.value: np.random.randint(low=0, high=3), + Modality.MASK.value: np.random.randint(low=0, high=2, size=(100, 100), dtype=np.uint8), + } + + monkeypatch.setattr(target=TaskDataset, name="load_sample", value=get_test_sample) + + # set the task index of file manager + for task in test_structs: + monkeypatch.setitem(file_manager.task_index, name=task, value={"none": f"{task}.json"}) + yield test_structs diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..20a8acb --- /dev/null +++ b/tests/README.md @@ -0,0 +1,14 @@ +# Testing + +Testing is split into the following categories: + + * unit test of single functions + * integration tests of whole mml calls, specifically config compilation and full mode runs + * performance tests of time critical core functionality + * manual tests for special purposes, these are not run by default + + +Performance benchmarks are disabled by default. To do benchmarking, call +`pytest --benchmark-enable --benchmark-only --benchmark-autosave` for all commits you want to +benchmark. Afterwards you may call `pytest-benchmark compare` as described in +the [docs](https://pytest-benchmark.readthedocs.io/en/stable/usage.html#comparison-cli). diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..8778744 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,15 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# enables a special test to check if installed tasks are consistent with their current installation code +def pytest_addoption(parser): + parser.addoption( + "--check_tasks", + action="store_true", + dest="check_tasks", + default=False, + help="single test to check the instantiated task meta information", + ) diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py new file mode 100644 index 0000000..2555c96 --- /dev/null +++ b/tests/integration/conftest.py @@ -0,0 +1,5 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# diff --git a/tests/integration/core/test_clean_mode.py b/tests/integration/core/test_clean_mode.py new file mode 100644 index 0000000..a007eea --- /dev/null +++ b/tests/integration/core/test_clean_mode.py @@ -0,0 +1,24 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import shutil + +from mml.core.data_loading.file_manager import MMLFileManager + + +def test_clean_scheduler_console(script_runner, file_manager: MMLFileManager, fake_task, no_plugins): + # create download path + download_path = file_manager.get_download_path("mml_fake_dataset") + # create temp.json + json_path = file_manager.data_path / file_manager.task_index["mml_fake_task"]["none"] + dst_path = json_path.parent / "temp.json" + shutil.copy(src=json_path, dst=dst_path) + ret = script_runner.run(["mml", "clean", "task_list=[mml_fake_task]", "mode.force=True"], print_result=True) + assert ret.success + assert "MML run time was" in ret.stdout + assert not dst_path.exists() + assert json_path.exists() + assert not download_path.exists() diff --git a/tests/integration/core/test_create_mode.py b/tests/integration/core/test_create_mode.py new file mode 100644 index 0000000..5b2b5a0 --- /dev/null +++ b/tests/integration/core/test_create_mode.py @@ -0,0 +1,11 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + + +def test_create_scheduler_console(script_runner, file_manager): + ret = script_runner.run(["mml", "create", "task_list=[mml_fake_task]"], print_result=True) + assert ret.success + assert "MML run time was" in ret.stdout diff --git a/tests/integration/core/test_info_mode.py b/tests/integration/core/test_info_mode.py new file mode 100644 index 0000000..128510f --- /dev/null +++ b/tests/integration/core/test_info_mode.py @@ -0,0 +1,12 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + + +def test_info_scheduler_console(script_runner, no_plugins): + ret = script_runner.run(["mml", "info", "tasks=none"], print_result=False) + assert ret.success + assert "MML run time was" in ret.stdout + assert ret.stderr == "" diff --git a/tests/integration/core/test_post_mode.py b/tests/integration/core/test_post_mode.py new file mode 100644 index 0000000..0c28336 --- /dev/null +++ b/tests/integration/core/test_post_mode.py @@ -0,0 +1,58 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import shutil + +import pytest +import torch +from pytest_console_scripts import ScriptRunner + +from mml.core.data_loading.file_manager import MMLFileManager +from mml.core.scripts.model_storage import ModelStorage + + +@pytest.mark.gpu +def test_postprocess_console( + script_runner: ScriptRunner, + fake_task, + no_plugins, + file_manager: MMLFileManager, + monkeypatch, + dummy_fake_model_storage_path, + dummy_fake_predictions_path, +): + # need to monkeypatch prediction loading + orig_load = torch.load + + def mock_torch_load(path): + return orig_load(dummy_fake_predictions_path) + + monkeypatch.setattr(torch, "load", mock_torch_load) + + # schedule updates existing predictions - we avoid this update + def mock_torch_save(*args, **kwargs): + pass + + monkeypatch.setattr(torch, "save", mock_torch_save) + # create dummy model storage + destination_dummy_storage = file_manager.proj_path / "MODELS" / "mml_fake_task" / "dummy.json" + destination_dummy_storage.parent.mkdir(exist_ok=True, parents=True) + shutil.copy2(src=dummy_fake_model_storage_path, dst=destination_dummy_storage) + dummy_model_storage = ModelStorage.from_json(path=destination_dummy_storage) + # attach models to file_manager + file_manager.reusables["mml_fake_task"] = {} + file_manager.reusables["mml_fake_task"]["models"] = [dummy_model_storage] * 10 + # next try to postprocess + ret = script_runner.run( + [ + "mml", + "post", + "tasks=fake", + "reuse=current", + "mode.subroutines=[calibrate,ensemble]", + ], + print_result=True, + ) + assert ret.success diff --git a/tests/integration/core/test_preprocess_mode.py b/tests/integration/core/test_preprocess_mode.py new file mode 100644 index 0000000..0e64c8f --- /dev/null +++ b/tests/integration/core/test_preprocess_mode.py @@ -0,0 +1,11 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + + +def test_preprocess_scheduler_console(script_runner, fake_task, no_plugins): + ret = script_runner.run(["mml", "pp", "task_list=[mml_fake_task]", "num_workers=1"], print_result=True) + assert ret.success + assert "MML run time was" in ret.stdout diff --git a/tests/integration/core/test_train_mode.py b/tests/integration/core/test_train_mode.py new file mode 100644 index 0000000..e44e29b --- /dev/null +++ b/tests/integration/core/test_train_mode.py @@ -0,0 +1,43 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import pytest + + +@pytest.mark.gpu +def test_train_predict_console(script_runner, fake_task, no_plugins): + ret = script_runner.run( + [ + "mml", + "train", + "tasks=fake", + "mode.subroutines=[train,predict]", + "trainer.max_epochs=1", + "tune.lr=false", + "mode.cv=false", + "mode.nested=false", + ], + print_result=True, + ) + assert ret.success + assert "MML run time was" in ret.stdout + + +@pytest.mark.gpu +def test_train_test_console(script_runner, fake_task, no_plugins): + ret = script_runner.run( + [ + "mml", + "train", + "tasks=fake", + "mode.subroutines=[train,test]", + "trainer.max_epochs=1", + "tune.lr=false", + "mode.cv=false", + ], + print_result=True, + ) + assert ret.success + assert "MML run time was" in ret.stdout diff --git a/tests/manual/test_all_tags_correct.py b/tests/manual/test_all_tags_correct.py new file mode 100644 index 0000000..3051484 --- /dev/null +++ b/tests/manual/test_all_tags_correct.py @@ -0,0 +1,93 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import os +from pathlib import Path + +import pytest + +import mml.core.data_preparation.task_creator as task_creator_module +import mml.core.data_preparation.utils as prep_utils_module +from mml.core.data_loading.file_manager import MMLFileManager + + +@pytest.mark.skipif("not config.getoption('check_tasks')") +@pytest.mark.env # use real mml.env +@pytest.mark.plugin # load actual plugins +def test_installed_tasks(monkeypatch, tmp_path_factory): + """ + This is a manual test, call with >>pytest --check_tasks -k "installed"<<. + It checks whether the currently present tasks meta information match the currently coded meta information (imagine + updating coded task information without adapting installed one). + """ + # here we will store coded meta + coded_meta = {} + + # this dummy creator will be mocked and used instead of the actual task creator, it stores passed kwargs + class DummyTaskCreator: + def __init__(self, **kwargs): + nonlocal coded_meta + kwargs.pop("dset_path", None) + coded_meta[kwargs["name"]] = kwargs + raise RuntimeError("Intended interruption.") + + # this dummy iterator will be necessary in cases of dict-like task creators + def dummy_get_iterator(**kwargs): + return None, None + + # mock globally, this requires no previous import of the task creators + # more precisely: the mml.create_tasks.task_preparation module, otherwise the TaskCreator will already be linked! + # also see https://docs.python.org/dev/library/unittest.mock.html#where-to-patch + monkeypatch.setattr(target=task_creator_module, name="TaskCreator", value=DummyTaskCreator) + monkeypatch.setattr( + target=prep_utils_module, name="get_iterator_and_mapping_from_image_dataset", value=dummy_get_iterator + ) + + # import all the task creators + import mml.api + + mml.api.load_env() + mml.api.load_mml_plugins() + import mml.core.data_preparation.registry + + assert len(mml.core.data_preparation.registry._TASKCREATORS) > 0 + assert len(mml.core.data_preparation.registry._DATASET_CREATORS) > 0 + # iterate over registered coded task creators + for task_alias, task_creator in mml.core.data_preparation.registry._TASKCREATORS.items(): + if task_alias == "mml_fake_task": + continue + dummy_dset_path = Path("/dummy") + with pytest.raises(RuntimeError, match="Intended interruption."): + _ = task_creator(dset_path=dummy_dset_path) + + # now load installed tasks (this is why we mark with pytest.mark.env, to use the actual underlying data) + assignments_backup = MMLFileManager._path_assignments.copy() + log_path = tmp_path_factory.mktemp(basename="logging") + monkeypatch.chdir(log_path) + manager = MMLFileManager( + data_path=Path(os.getenv("MML_DATA_PATH")), + proj_path=tmp_path_factory.mktemp(basename="project"), + log_path=log_path, + ) + # iterate over installed tasks + for alias in manager.task_index: + if alias in coded_meta: + # load installed meta + written_meta = MMLFileManager.load_task_description_header( + manager.data_path / manager.task_index[alias]["none"] + ) + for attr in coded_meta[alias]: + kwarg_mapper = {"desc": "description", "ref": "reference", "instr": "download", "lic": "license"} + if attr in kwarg_mapper: + ref = kwarg_mapper[attr] + else: + ref = attr + assert ( + getattr(written_meta, ref) == coded_meta[alias][attr] + ), f"{alias=}, {attr=}, {ref=}, {getattr(written_meta, ref)=}, {coded_meta[alias][attr]=}" + # clearance + manager.clear_instance() + MMLFileManager._path_assignments = assignments_backup diff --git a/tests/performance/test_dataset_loading_speed.py b/tests/performance/test_dataset_loading_speed.py new file mode 100644 index 0000000..3e8165d --- /dev/null +++ b/tests/performance/test_dataset_loading_speed.py @@ -0,0 +1,32 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import pytest + +from mml.core.data_loading.task_dataset import TaskDataset + + +@pytest.mark.benchmark(group="fake_data_loading") +@pytest.mark.parametrize("caching", [True, False]) +def test_fake_dataset_loading_speed(benchmark, fake_task, file_manager, caching): + # create struct + root = file_manager.data_path / file_manager.task_index["mml_fake_task"]["none"] + if caching: + cache_limit = 10000 + else: + cache_limit = 0 + ds = TaskDataset(root=root, caching_limit=cache_limit) + if caching: + ds.fill_cache(num_workers=1) + + def loading_dummy(): + out = [] + for sample in ds: + out.append(sample["class"]) + return out + + result = benchmark(loading_dummy) + assert len(result) == len(ds) diff --git a/tests/performance/test_file_manager_init_speed.py b/tests/performance/test_file_manager_init_speed.py new file mode 100644 index 0000000..16ae8e6 --- /dev/null +++ b/tests/performance/test_file_manager_init_speed.py @@ -0,0 +1,30 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# TODO +import pytest + +from mml.core.data_loading.file_manager import MMLFileManager + + +@pytest.mark.benchmark(group="file_manager_init") +def test_file_manager_init_speed(tmp_path_factory, monkeypatch, benchmark): + # store class attributes + assignments_backup = MMLFileManager._path_assignments.copy() + log_path = tmp_path_factory.mktemp(basename="logging") + monkeypatch.chdir(log_path) + + def init_fm(): + _ = MMLFileManager( + data_path=tmp_path_factory.mktemp(basename="data"), + proj_path=tmp_path_factory.mktemp(basename="project"), + log_path=log_path, + ) + MMLFileManager.clear_instance() + + benchmark(init_fm) + # correct teardown + MMLFileManager._path_assignments = assignments_backup diff --git a/tests/performance/test_meta_reading_speed.py b/tests/performance/test_meta_reading_speed.py new file mode 100644 index 0000000..bdc3099 --- /dev/null +++ b/tests/performance/test_meta_reading_speed.py @@ -0,0 +1,22 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import pytest + +from mml.core.data_loading.file_manager import MMLFileManager +from mml.core.data_loading.task_description import ALL_HEADER_KEYS, ALL_TASK_DESCRIPTION_KEYS + + +@pytest.mark.benchmark(group="meta_header_loading") +def test_meta_header_loading_speed(benchmark, dummy_meta_class_path): + result = benchmark(MMLFileManager.load_task_description_header, dummy_meta_class_path) + assert all([k in result for k in ALL_HEADER_KEYS]) + + +@pytest.mark.benchmark(group="full_header_loading") +def test_full_meta_loading_speed(benchmark, dummy_meta_class_path): + result = benchmark(MMLFileManager.load_task_description, dummy_meta_class_path) + assert all([k in result for k in ALL_TASK_DESCRIPTION_KEYS]) diff --git a/tests/performance/test_scheduler_init_speed.py b/tests/performance/test_scheduler_init_speed.py new file mode 100644 index 0000000..28b9ba5 --- /dev/null +++ b/tests/performance/test_scheduler_init_speed.py @@ -0,0 +1,22 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import pytest + +from mml.core.scripts.schedulers.info_scheduler import InfoScheduler + + +@pytest.mark.benchmark(group="scheduler_init") +def test_scheduler_init(mml_config, benchmark, file_manager): + mml_config["mode"]["subroutines"] = ["tasks"] + + def clean_scheduler_reinit(): + scheduler = InfoScheduler(mml_config) + scheduler.lock_path.unlink() + scheduler.planned_schedule.unlink() + scheduler.status_log.unlink() + + benchmark(clean_scheduler_reinit) diff --git a/tests/performance/test_training_speed.py b/tests/performance/test_training_speed.py new file mode 100644 index 0000000..d57128a --- /dev/null +++ b/tests/performance/test_training_speed.py @@ -0,0 +1,23 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import pytest +from omegaconf import OmegaConf + +from mml.core.scripts.schedulers.train_scheduler import TrainingScheduler + + +@pytest.mark.benchmark(group="training_epoch") +def test_training_speed(mml_config, benchmark, file_manager, fake_task): + OmegaConf.set_struct(mml_config, False) + mml_config.mode.subroutines = ["train_fold"] + mml_config.pivot.name = ["mml_fake_task"] + mml_config.trainer.max_epochs = 1 + + scheduler = TrainingScheduler(mml_config) + scheduler.prepare_exp() + + benchmark(scheduler.train_fold, task_name="mml_fake_task", fold=0) diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py new file mode 100644 index 0000000..c299dec --- /dev/null +++ b/tests/unit/conftest.py @@ -0,0 +1,53 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import pytest +from lightning.pytorch.callbacks import ModelCheckpoint +from omegaconf import OmegaConf + +from mml.core.data_loading.task_attributes import Keyword, Modality, RGBInfo, Sizes, TaskType +from mml.core.data_loading.task_struct import TaskStruct +from mml.core.scripts.model_storage import ModelStorage + + +@pytest.fixture() +def dummy_task_struct(): + yield TaskStruct( + name="dummy", + task_type=TaskType.CLASSIFICATION, + means=RGBInfo(*[0.1, 0.2, 0.3]), + stds=RGBInfo(*[0.4, 0.5, 0.6]), + sizes=Sizes(*[1, 2, 3, 4]), + relative_root="dummy_root", + class_occ={"one": 1, "two": 2}, + preprocessed="none", + keywords=[Keyword.ARTIFICIAL], + idx_to_class={0: "one", 1: "two"}, + modalities={Modality.CLASS: "stuff"}, + ) + + +@pytest.fixture() +def dummy_model_storage(file_manager, dummy_task_struct): + par_path = file_manager.construct_saving_path(ModelCheckpoint(), key="parameters", task_name=dummy_task_struct.name) + pip_path = file_manager.construct_saving_path( + obj=OmegaConf.create({}), key="pipeline", task_name=dummy_task_struct.name + ) + pred_paths = [ + file_manager.construct_saving_path( + obj=dict(), key="predictions", task_name=dummy_task_struct.name, file_name="preds-test-fold-0.pt" + ) + for _ in range(3) + ] + s = ModelStorage( + pipeline=pip_path, + parameters=par_path, + performance=0.42, + training_time=13.37, + predictions={k: v for k, v in zip("abc", pred_paths)}, + metrics=[{"loss": 0.5, "acc": 0.1}, {"loss": 0.4, "acc": 0.2}], + ) + yield s diff --git a/tests/unit/core/data_loading/conftest.py b/tests/unit/core/data_loading/conftest.py new file mode 100644 index 0000000..d9b4f8d --- /dev/null +++ b/tests/unit/core/data_loading/conftest.py @@ -0,0 +1,22 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import omegaconf +import pytest + +from mml.core.data_loading.lightning_datamodule import MultiTaskDataModule +from mml.core.data_loading.task_struct import TaskStructFactory + + +@pytest.fixture() +def dummy_factory(file_manager): + dummy_cfg = omegaconf.OmegaConf.create({"preprocessing": {"id": "none"}}) + yield TaskStructFactory(cfg=dummy_cfg, load=False) + + +@pytest.fixture(scope="function", params=["a", "b", "c"]) +def datamodule(mml_config, test_task_monkeypatch, request): + yield MultiTaskDataModule(task_structs=[test_task_monkeypatch[f"test_task_{request.param}"]], cfg=mml_config) diff --git a/tests/unit/core/data_loading/test_albumentations.py b/tests/unit/core/data_loading/test_albumentations.py new file mode 100644 index 0000000..d1009b2 --- /dev/null +++ b/tests/unit/core/data_loading/test_albumentations.py @@ -0,0 +1,58 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import omegaconf +import pytest + +from mml.core.data_loading.augmentations.albumentations import AlbumentationsAugmentationModule +from mml.core.data_loading.task_attributes import Modality + + +def test_valid_transform_from_config(image): + conf_str = """ + pipeline: + - name: ShiftScaleRotate + shift_limit: 0.2 + scale_limit: 0.2 + rotate_limit: 30 + p: 0.5 + - name: RGBShift + r_shift_limit: 15 + g_shift_limit: 15 + b_shift_limit: 15 + p: 0.5 + - name: RandomBrightnessContrast + p: 0.5 + """ + conf = omegaconf.OmegaConf.create(conf_str) + transforms = AlbumentationsAugmentationModule( + cfg=conf["pipeline"], + device="cpu", + is_last=False, + is_first=False, + means=None, + stds=None, + floatify=False, + tensorize=False, + ) + assert len(transforms) == 3 + # apply transform + transforms(**{Modality.IMAGE.value: image}) + + +def test_invalid_transform_from_config(): + conf_str = """ + pipeline: + - name: MyImaginedTransform + p: 1.5 + - name: RandomBrightnessContrast + p: 0.5 + """ + conf = omegaconf.OmegaConf.create(conf_str) + with pytest.raises(KeyError, match="MyImaginedTransform"): + AlbumentationsAugmentationModule( + cfg=conf["pipeline"], device="cpu", is_last=False, is_first=False, means=None, stds=None + ) diff --git a/tests/unit/core/data_loading/test_file_manager.py b/tests/unit/core/data_loading/test_file_manager.py new file mode 100644 index 0000000..e3ff349 --- /dev/null +++ b/tests/unit/core/data_loading/test_file_manager.py @@ -0,0 +1,169 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# +import filecmp +from pathlib import Path + +import pytest +from omegaconf import DictConfig, open_dict + +from mml.core.data_loading.file_manager import DSET_PREFIX, MMLFileManager, RemoveConfig +from mml.core.data_loading.task_description import TaskDescription + + +# dummy class +@pytest.fixture +def foo(): + class Foo: + pass + + return Foo + + +# tests for path assignments +@pytest.mark.parametrize(argnames="numbering", argvalues=(True, False)) +def test_add_new_assignment(file_manager, foo, numbering): + file_manager.add_assignment_path(foo, key="test", path="TEMP_PATH/test.txt", enable_numbering=numbering) + constructed = file_manager.construct_saving_path(obj=foo(), key="test") + assert constructed.exists() == numbering + + +def test_assignment_numbering(file_manager): + p1 = file_manager.construct_saving_path(obj=None, key="temp", file_name="dummy.txt") + p2 = file_manager.construct_saving_path(obj=None, key="temp", file_name="dummy.txt") + assert p1.exists() + assert p2.exists() + assert p1 != p2 + + +def test_assignment_replace_file_name(file_manager): + p = file_manager.construct_saving_path(obj=None, key="temp", file_name="test123.txt") + assert p.name == "test123_0001.txt" + + +def test_assignment_replace_task_id(file_manager, foo): + file_manager.add_assignment_path(foo, key="test", path=Path("TEMP_PATH") / "TASK_NAME" / "test.txt") + task_name = "my_test_task" + constructed = file_manager.construct_saving_path(obj=foo(), key="test", task_name=task_name) + assert constructed.parent.name == task_name + + +def test_add_assignment_incorrect_path_beginning(file_manager, foo): + with pytest.raises(ValueError): + file_manager.add_assignment_path(foo, key="test", path=Path("/tmp/") / "test.txt") + + +def test_add_assignment_multiple_keys(file_manager, foo): + file_manager.add_assignment_path(foo, key="test", path=Path("TEMP_PATH") / "test.txt") + with pytest.raises(KeyError): + file_manager.add_assignment_path(foo, key="test", path=Path("TEMP_PATH") / "test.txt") + + +@pytest.mark.parametrize( + "path", + [ + Path("PROJ_PATH") / "TASK_NAME" / "file_name.sth", + Path("TEMP_PATH") / "TEST" / "TASK_NAME" / "file_name.sth", + Path("PROJ_PATH") / "TEST" / "ID" / "file_name.sth", + Path("PROJ_PATH") / "TEST" / "TEST_2" / "TASK_NAME" / "file_name.sth", + ], +) +def test_add_assignment_reuse_value_errors(file_manager, foo, path): + with pytest.raises(ValueError): + file_manager.add_assignment_path(foo, key="test", path=path, reusable=True) + + +# test other file manager paths +def test_download_path(file_manager): + d_path = file_manager.get_download_path(dset_name="myTestDataset") + assert isinstance(d_path, Path) + assert d_path.exists() + another_call = file_manager.get_download_path(dset_name="myTestDataset") + assert d_path == another_call + + +def test_get_dataset_path(file_manager): + new_path = file_manager.get_dataset_path(dset_name="myTestDataset") + assert new_path.exists() + assert new_path.is_dir() + assert len(list(new_path.iterdir())) == 0 + + +def test_get_dataset_preprocessing_path(file_manager): + raw_dset_path = file_manager.raw_data / f"{DSET_PREFIX}_myTestDataset" + pp_path = file_manager.get_dataset_path(raw_path=raw_dset_path, preprocessing="test_pp") + with pytest.warns(UserWarning, match="Dataset myTestDataset has already partly existing preprocessing"): + pp_path_again = file_manager.get_dataset_path(raw_path=raw_dset_path, preprocessing="test_pp") + assert pp_path == pp_path_again + assert file_manager.preprocessed_data in pp_path.parents + + +def test_remove_intermediates(file_manager, foo): + file_manager.add_assignment_path(foo, key="temp_test", path=Path("TEMP_PATH") / "TEST" / "test.txt") + file_manager.add_assignment_path(foo, key="proj_test", path=Path("PROJ_PATH") / "TEST" / "test.txt") + p_1 = file_manager.construct_saving_path(obj=foo(), key="temp_test") + assert p_1.exists() + p_2 = file_manager.construct_saving_path(obj=foo(), key="proj_test") + assert p_2.exists() + r_cfg = DictConfig(RemoveConfig()) + with open_dict(r_cfg): + r_cfg.proj_test = True + file_manager.remove_cfg = r_cfg + file_manager.remove_intermediates() + assert not p_1.exists() + assert not p_2.exists() + + +def test_load_meta(dummy_meta_class_path): + task_description = MMLFileManager.load_task_description(dummy_meta_class_path) + assert isinstance(task_description, TaskDescription) + + +def test_write_meta(tmp_path): + store_path = tmp_path / "dummy.json" + assert not store_path.exists() + dummy_description = TaskDescription(idx_to_class={0: "a", 1: "b"}) + MMLFileManager.write_task_description(path=store_path, task_description=dummy_description) + assert store_path.exists() + with pytest.warns(UserWarning, match="Overwriting"): + MMLFileManager.write_task_description(path=store_path, task_description=dummy_description) + + +def test_load_write_meta_consistency(tmp_path, dummy_meta_class_path): + # dummy_meta_path is formatted human friendly, not as written by FM + task_description = MMLFileManager.load_task_description(dummy_meta_class_path) + store_path_1 = tmp_path / "dummy_1.json" + MMLFileManager.write_task_description(path=store_path_1, task_description=task_description) + loaded_description = MMLFileManager.load_task_description(store_path_1) + store_path_2 = tmp_path / "dummy_2.json" + MMLFileManager.write_task_description(path=store_path_2, task_description=loaded_description) + assert filecmp.cmp(store_path_1, store_path_2, shallow=False) + + +@pytest.mark.parametrize("enable_numbering", [True, False]) +def test_find_global_reusables(file_manager: MMLFileManager, enable_numbering): + reuse_cfg = {} + property_name = "abc" + file_manager.add_assignment_path( + obj_cls=None, + key=property_name, + path=Path("PROJ_PATH") / property_name / "FILE_NAME", + enable_numbering=enable_numbering, + reusable=file_manager.GLOBAL_REUSABLE, + ) + p = file_manager.construct_saving_path(obj=None, key=property_name, file_name=f"some_{property_name}_file.file") + if not enable_numbering: + p.touch(exist_ok=False) + file_manager.construct_saving_path(obj=None, key=property_name, file_name=f"some_{property_name}_file.file") + reuse_cfg[property_name] = file_manager.proj_path.name + file_manager.reuse_cfg = DictConfig(reuse_cfg) + file_manager._find_reusables() + assert file_manager.GLOBAL_REUSABLE in file_manager.reusables + assert property_name in file_manager.global_reusables + assert isinstance(file_manager.global_reusables[property_name], Path) + assert file_manager.global_reusables[property_name].exists() + + +# TODO test_get_all_dset_names, test_reload_task_index, test_get_task_path, ... diff --git a/tests/unit/core/data_loading/test_lightning_datamodule.py b/tests/unit/core/data_loading/test_lightning_datamodule.py new file mode 100644 index 0000000..c32c2de --- /dev/null +++ b/tests/unit/core/data_loading/test_lightning_datamodule.py @@ -0,0 +1,118 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import pytest +import torch.utils.data +from omegaconf import OmegaConf + +from mml.core.data_loading.lightning_datamodule import MultiTaskDataModule +from mml.core.data_loading.task_attributes import Modality +from mml.core.data_loading.task_dataset import TaskDataset +from mml.core.scripts.utils import LearningPhase + + +def test_datamodule_setup(datamodule): + datamodule.setup(stage="fit") + tasks = list(datamodule.task_datasets.keys()) + assert len(tasks) == 1 # one task + assert len(datamodule.task_datasets[tasks[0]]) == 2 # train and val sets + assert all([isinstance(ds, TaskDataset) for ds in datamodule.task_datasets[tasks[0]].values()]) + assert all([len(ds) > 0 for ds in datamodule.task_datasets[tasks[0]].values()]) + + +@pytest.mark.parametrize("fold", [ix for ix in range(5)]) +def test_get_balancing_weights(fold, dummy_meta_class_path): + ds = TaskDataset(root=dummy_meta_class_path, fold=fold) + weights = MultiTaskDataModule.get_dataset_balancing_weights(ds) + assert weights.size() == torch.Size([len(ds)]) + # weights and class frequency must cancel out each other + all_mapped_classes = [ds.loaders[Modality.CLASS].load(entry=s[Modality.CLASS]) for s in ds.samples] + assert all( + [ + pytest.approx(1.0) == weights[i].item() * ds.class_occ[ds.classes[all_mapped_classes[i]]] + for i in range(len(ds)) + ] + ) + + +@pytest.mark.parametrize( + "cfg_overrides", + [ + { + "cpu": { + "backend": "albumentations", + "pipeline": [ + {"name": "RandomCrop", "height": 10, "width": 10}, + { + "name": "Affine", + "scale": 0.05, + "translate_percent": 0.05, + "rotate": 15, + "p": 0.5, + }, + ], + } + }, + { + "cpu": { + "backend": "torchvision", + "pipeline": [ + {"name": "RandomResizedCrop", "size": [10, 10], "antialias": True}, + {"name": "RandomHorizontalFlip", "p": 0.5}, + ], + } + }, + { + "gpu": { + "backend": "torchvision", + "pipeline": [ + {"name": "RandomResizedCrop", "size": [10, 10], "antialias": True}, + {"name": "RandomHorizontalFlip", "p": 0.5}, + ], + } + }, + { + "gpu": { + "backend": "kornia", + "pipeline": [ + {"name": "RandomCrop", "size": [10, 10]}, + {"name": "RandomAffine", "translate": [0.05, 0.05], "scale": [0.05, 0.05], "degrees": 15, "p": 0.5}, + ], + } + }, + ], +) +def test_get_common_train_transforms(datamodule, image, mask, dummy_task_struct, cfg_overrides): + OmegaConf.update(datamodule.cfg, key="augmentations", value=cfg_overrides, force_add=True) + if len(datamodule.cfg.augmentations.gpu) > 1: + datamodule.has_gpu_augs = True + datamodule.setup(stage="fit") + + # print(datamodule.gpu_train_augs.pipeline({'image': Image(torch.rand(size=(1, 3, 100, 100)))}).size()) + class DummyTrainer: + training: bool = False + + datamodule.trainer = DummyTrainer + + for phase in [LearningPhase.TRAIN, LearningPhase.VAL, LearningPhase.TEST]: + if len(datamodule.cfg.augmentations.gpu) > 1: + datamodule.trainer.training = phase == LearningPhase.TRAIN + cpu_transforms = datamodule.get_cpu_transforms(phase=phase, struct=dummy_task_struct) + cpu_transformed = cpu_transforms(image=image, mask=mask) + batch = torch.utils.data.default_collate([cpu_transformed]) + if phase == LearningPhase.TRAIN: + # combined loader treats val and test sequentially + batch = {"dummy_task": batch} + transformed = datamodule.on_after_batch_transfer(batch=batch, dataloader_idx=0) + if phase == LearningPhase.TRAIN: + transformed = transformed["dummy_task"] + assert isinstance(transformed["image"], torch.Tensor) and isinstance(transformed["mask"], torch.Tensor) + assert transformed["image"].size()[2:] == transformed["mask"].size()[1:] # omit batch and channel dims + if phase == LearningPhase.TRAIN: + assert transformed["mask"].size()[1:] == torch.Size([10, 10]) + else: + assert transformed["mask"].size()[1:] != torch.Size([10, 10]) + assert transformed["image"].dtype == torch.float32 diff --git a/tests/unit/core/data_loading/test_mixup_cutmix.py b/tests/unit/core/data_loading/test_mixup_cutmix.py new file mode 100644 index 0000000..058421f --- /dev/null +++ b/tests/unit/core/data_loading/test_mixup_cutmix.py @@ -0,0 +1,24 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from hydra.utils import instantiate + +from mml.core.data_loading.augmentations.mixup_cutmix import CutMixCallback, MixUpCallback +from mml.core.models.lightning_single_frame import SingleFrameLightningModule + + +def test_mixup_callback(mml_config, datamodule): + mixup = MixUpCallback() + trainer = instantiate(mml_config.trainer, callbacks=[mixup], fast_dev_run=True) + model = SingleFrameLightningModule(task_structs=datamodule.task_structs, cfg=mml_config) + trainer.fit(model, datamodule=datamodule) + + +def test_cutmix_callback(mml_config, datamodule): + cutmix = CutMixCallback() + trainer = instantiate(mml_config.trainer, callbacks=[cutmix], fast_dev_run=True) + model = SingleFrameLightningModule(task_structs=datamodule.task_structs, cfg=mml_config) + trainer.fit(model, datamodule=datamodule) diff --git a/tests/unit/core/data_loading/test_task_dataset.py b/tests/unit/core/data_loading/test_task_dataset.py new file mode 100644 index 0000000..45bfae4 --- /dev/null +++ b/tests/unit/core/data_loading/test_task_dataset.py @@ -0,0 +1,116 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import copy + +import cv2 +import numpy as np +import pytest +import torch +from omegaconf import ListConfig + +from mml.core.data_loading.augmentations.albumentations import AlbumentationsAugmentationModule +from mml.core.data_loading.task_attributes import EMPTY_MASK_TOKEN, IMAGENET_MEAN, IMAGENET_STD, DataSplit, Modality +from mml.core.data_loading.task_dataset import TaskDataset + + +@pytest.mark.parametrize("idx_dict", [{0: "background", 1: "interest"}, {3: "test", 4: "test", 5: "other"}]) +def test_get_classes_from_idx_dict_success(idx_dict): + classes = TaskDataset.get_classes_from_idx_dict(idx_to_class=idx_dict) + # each class shall be unique + assert len(classes) == len(set(classes)) + # classes shall be independent of dict order + reversed_dict = {k: v for k, v in reversed(idx_dict.items())} + assert classes == TaskDataset.get_classes_from_idx_dict(reversed_dict) + + +@pytest.fixture +def class_task_dataset_instance(dummy_meta_class_path): + yield TaskDataset(root=dummy_meta_class_path, split=DataSplit.TRAIN, fold=0, transform=None) + + +@pytest.fixture +def seg_task_dataset_instance(dummy_meta_seg_path): + yield TaskDataset(root=dummy_meta_seg_path, split=DataSplit.TRAIN, fold=0, transform=None) + + +def test_task_sample_selection(class_task_dataset_instance): + sample_backup = copy.deepcopy(class_task_dataset_instance.samples) + class_task_dataset_instance.select_samples(split=DataSplit.TRAIN, fold=1) + assert len(class_task_dataset_instance.samples) == len(sample_backup) + assert class_task_dataset_instance.samples != sample_backup + class_task_dataset_instance.select_samples(split=DataSplit.VAL, fold=0) + assert all([val_sample not in sample_backup for val_sample in class_task_dataset_instance.samples]) + assert len(class_task_dataset_instance.samples) + len(sample_backup) == len( + class_task_dataset_instance.task_description.train_samples + ) + class_task_dataset_instance.select_samples(split=DataSplit.TRAIN, fold=0) + assert class_task_dataset_instance.samples == sample_backup + + +def test_task_sample_loading(class_task_dataset_instance, seg_task_dataset_instance, monkeypatch, image): + def dummy_imread(*args): + return image.copy() + + monkeypatch.setattr(target=cv2, name="imread", value=dummy_imread) + for task_dataset_instance in [seg_task_dataset_instance, class_task_dataset_instance]: + sample = task_dataset_instance[0] + assert isinstance(sample, dict) + assert (Modality.CLASS.value in sample or Modality.MASK.value in sample) and Modality.IMAGE.value in sample + if Modality.CLASS.value in sample: + assert isinstance(sample[Modality.CLASS.value], torch.Tensor) + if Modality.MASK.value in sample: + assert isinstance(sample[Modality.MASK.value], np.ndarray) + sample_duplicate = task_dataset_instance[0] + assert np.array_equal(sample[Modality.IMAGE.value], sample_duplicate[Modality.IMAGE.value]) + assert sample is not sample_duplicate + task_dataset_instance.transform = AlbumentationsAugmentationModule( + device="cpu", cfg=ListConfig([]), is_first=True, is_last=True, means=IMAGENET_MEAN, stds=IMAGENET_STD + ) + sample_trans = task_dataset_instance[0] + assert isinstance(sample_trans[Modality.IMAGE.value], torch.Tensor) + assert not np.array_equal(sample[Modality.IMAGE.value], sample_trans[Modality.IMAGE.value].numpy()) + + +@pytest.mark.parametrize("size", [(100, 100), (150, 100)]) +def test_empty_mask_token_loading(seg_task_dataset_instance, monkeypatch, size): + all_empties = [ + ix + for ix, sample_dict in enumerate(seg_task_dataset_instance.samples) + if sample_dict[Modality.MASK.value] == EMPTY_MASK_TOKEN + ] + assert len(all_empties) > 0 + + def dummy_imread(*args): + return np.ones((*size, 3), dtype=np.uint8) + + monkeypatch.setattr(target=cv2, name="imread", value=dummy_imread) + loaded_sample = seg_task_dataset_instance[all_empties[0]] + + assert Modality.MASK.value in loaded_sample + assert np.unique(loaded_sample[Modality.MASK.value]).size == 1 + assert 0 in np.unique(loaded_sample[Modality.MASK.value]) + assert loaded_sample[Modality.MASK.value].shape[:2] == loaded_sample[Modality.IMAGE.value].shape[:2] + assert loaded_sample[Modality.MASK.value].ndim == 2 + + +def test_caching(dummy_meta_class_path, monkeypatch, image): + def dummy_imread(*args): + return image.copy() + + monkeypatch.setattr(target=cv2, name="imread", value=dummy_imread) + # create dataset and cache + ds = TaskDataset(root=dummy_meta_class_path, split=DataSplit.TRAIN, fold=0, transform=None, caching_limit=100) + ds.fill_cache(num_workers=2) + + # use cache and avoid reading images + + def imread_error(*args): + raise RuntimeError + + monkeypatch.setattr(target=cv2, name="imread", value=imread_error) + for _ in ds: + pass diff --git a/tests/unit/core/data_loading/test_task_description.py b/tests/unit/core/data_loading/test_task_description.py new file mode 100644 index 0000000..35e1e35 --- /dev/null +++ b/tests/unit/core/data_loading/test_task_description.py @@ -0,0 +1,14 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from mml.core.data_loading.task_description import STRUCT_REQ_HEADER_KEYS +from mml.core.data_loading.task_struct import TaskStruct + + +def test_required_header_keys(): + struct_init_keys = set(TaskStruct.__init__.__annotations__.keys()) + treated_sep = {"relative_root", "preprocessed", "name"} + assert set(STRUCT_REQ_HEADER_KEYS).union(treated_sep) == struct_init_keys diff --git a/tests/unit/core/data_loading/test_task_struct.py b/tests/unit/core/data_loading/test_task_struct.py new file mode 100644 index 0000000..b6659ee --- /dev/null +++ b/tests/unit/core/data_loading/test_task_struct.py @@ -0,0 +1,84 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +import pytest +from lightning.pytorch.callbacks import ModelCheckpoint +from omegaconf import OmegaConf + +from mml.core.data_loading.task_struct import TaskStruct, undup_names +from mml.core.scripts.exceptions import TaskNotFoundError +from mml.core.scripts.model_storage import ModelStorage +from mml.core.scripts.utils import ARG_SEP, TAG_SEP + + +def test_paths_representation(dummy_task_struct): + attr = TaskStruct.non_permanent_task_attributes() + test_path = Path("this/is/a/test") + dummy_task_struct.paths["test"] = test_path + path_representer, path_instantiator = attr["paths"] + representation = path_representer(dummy_task_struct.paths) + recreated = path_instantiator(representation) + assert dummy_task_struct.paths == recreated + + +def test_models_representation(dummy_task_struct, file_manager): + attr = TaskStruct.non_permanent_task_attributes() + par_path = file_manager.construct_saving_path(ModelCheckpoint(), key="parameters", task_name=dummy_task_struct.name) + pip_path = file_manager.construct_saving_path( + obj=OmegaConf.create({}), key="pipeline", task_name=dummy_task_struct.name + ) + test_model = ModelStorage(parameters=par_path, pipeline=pip_path, performance=0.3, metrics=[{"test": 0.3}]) + test_model.store(task_struct=dummy_task_struct) + dummy_task_struct.models.append(test_model) + model_representer, modelinstantiator = attr["models"] + representation = model_representer(dummy_task_struct.models) + recreated = modelinstantiator(representation) + assert dummy_task_struct.models == recreated + + +@pytest.mark.parametrize( + "task_name", ["test", f"test{TAG_SEP}duplicate{ARG_SEP}123", f"test{TAG_SEP}stuff{TAG_SEP}duplicate{ARG_SEP}0"] +) +def test_undup_names(task_name): + result = undup_names([task_name])[0] + assert f"{TAG_SEP}duplicate" not in result + assert undup_names([result])[0] == result + if f"{TAG_SEP}duplicate" not in task_name: + assert result == task_name + + +def test_get_by_name(dummy_factory, dummy_task_struct): + dummy_factory.container.append(dummy_task_struct) + response = dummy_factory.get_by_name("dummy") + assert response is dummy_task_struct + assert not dummy_factory.check_exists("another_dummy") + with pytest.raises(TaskNotFoundError): + dummy_factory.get_by_name("foo") + + +def test_create_task(dummy_meta_class_path, dummy_factory): + dummy_factory.fm.task_index["dummy_task"] = {} + dummy_factory.fm.task_index["dummy_task"]["none"] = dummy_meta_class_path + struct = dummy_factory.create_task_struct(name="dummy_task", return_ref=True) + assert struct in dummy_factory.container + assert dummy_factory.sizes.to_list() == struct.sizes.to_list() + + +def test_dumping_and_loading(dummy_meta_class_path, dummy_factory): + assert not dummy_factory.fm.task_dump_path.exists() + dummy_factory.fm.task_index["dummy_task"] = {} + dummy_factory.fm.task_index["dummy_task"]["none"] = dummy_meta_class_path + dummy_factory.create_task_struct(name="dummy_task", return_ref=False) + dummy_factory.dump(clear_container=True) + assert dummy_factory.fm.task_dump_path.exists() + assert len(dummy_factory.container) == 0 + assert dummy_factory.sizes.min_width == dummy_factory.sizes.min_height == 100000 + dummy_factory.loading_old_dump() + assert len(dummy_factory.container) == 1 + assert dummy_factory.sizes.min_height <= dummy_factory.sizes.max_height + assert dummy_factory.sizes.min_width <= dummy_factory.sizes.max_width diff --git a/tests/unit/core/data_preparation/test_archive_extractor.py b/tests/unit/core/data_preparation/test_archive_extractor.py new file mode 100644 index 0000000..417afe7 --- /dev/null +++ b/tests/unit/core/data_preparation/test_archive_extractor.py @@ -0,0 +1,26 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +import pytest + +from mml.core.data_preparation.archive_extractors import unpack_files +from mml.core.data_preparation.data_archive import DataArchive + + +def test_invalid_target_path(): + target_path = Path("~/invalid/path/to/store") + with pytest.raises(FileNotFoundError): + unpack_files(archives=[], target=target_path) + + +def test_invalid_file_path(tmp_path): + target_path = tmp_path / "DSET_001_name" + target_path.mkdir() + archive = DataArchive(path=Path("C:/Users/akrit/DKFZ/invalid.txt")) + with pytest.raises(FileNotFoundError): + unpack_files(archives=[archive], target=target_path) diff --git a/tests/unit/core/data_preparation/test_data_archive.py b/tests/unit/core/data_preparation/test_data_archive.py new file mode 100644 index 0000000..4839036 --- /dev/null +++ b/tests/unit/core/data_preparation/test_data_archive.py @@ -0,0 +1,28 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import pytest + +from mml.core.data_preparation.data_archive import DataArchive + + +def test_check_hash_success(tmp_path): + tmp_path /= "test.txt" + data = "some sample text to be stored and hashed" + with open(str(tmp_path), "w") as file: + file.write(data) + archive = DataArchive(path=tmp_path, md5sum="307f768a68e5ab1918ece2cb99d72d90") + archive.check_hash() + + +def test_check_hash_error(tmp_path): + tmp_path /= "test_fail.txt" + data = "some short random text" + with open(str(tmp_path), "w") as file: + file.write(data) + archive = DataArchive(path=tmp_path, md5sum="incorrecthashvalue") + with pytest.raises(RuntimeError): + archive.check_hash() diff --git a/tests/unit/core/data_preparation/test_dset_creator.py b/tests/unit/core/data_preparation/test_dset_creator.py new file mode 100644 index 0000000..e9637a9 --- /dev/null +++ b/tests/unit/core/data_preparation/test_dset_creator.py @@ -0,0 +1,20 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import pytest + +from mml.core.data_preparation.dset_creator import DSetCreator + + +def test_data_type(file_manager): + # dset creator uses file manager instance + url = "http://test/images.tar" + file_name = "images.tar" + data_kind = "invalid" + dset_name = "DSET001_name" + creator = DSetCreator(dset_name) + with pytest.raises(TypeError, match=r"unsupported operand"): + creator.download(url, file_name, data_kind) diff --git a/tests/unit/core/data_preparation/test_prep_utils.py b/tests/unit/core/data_preparation/test_prep_utils.py new file mode 100644 index 0000000..efc371c --- /dev/null +++ b/tests/unit/core/data_preparation/test_prep_utils.py @@ -0,0 +1,55 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from pathlib import Path + +import pytest +import requests + +from mml.core.data_preparation.utils import download_file + + +def test_invalid_path(): + non_existent_path = Path("/DOWNLOADS/DSET") + file_name_1 = "images.tar" + download_url = "http://test/images.tar" + with pytest.raises(ValueError, match=r"Invalid path"): + download_file(path_to_store=non_existent_path, download_url=download_url, file_name=file_name_1) + + +class MockResponse: + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + pass + + # prevents http error + @staticmethod + def raise_for_status(): + pass + + # necessary for progress bar + @property + def headers(self): + return {"content-length": 10000} + + # nonsense data that is returned + @staticmethod + def iter_content(chunk_size): + for _ in range(10000 // chunk_size): + yield bytes(chunk_size) + yield bytes(10000 % chunk_size) + + +def test_valid_download_path(tmp_path, monkeypatch): + # going to monkeypatch the http request, giving the mocked response above + def mock_get(*args, **kwargs): + return MockResponse() + + # apply the monkeypatch for requests.get to mock_get + monkeypatch.setattr(requests, "get", mock_get) + download_file(path_to_store=tmp_path, download_url="http://test/images.tar", file_name="images.tar") diff --git a/tests/unit/core/data_preparation/test_task_creator.py b/tests/unit/core/data_preparation/test_task_creator.py new file mode 100644 index 0000000..a25a1d4 --- /dev/null +++ b/tests/unit/core/data_preparation/test_task_creator.py @@ -0,0 +1,209 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import copy +import shutil +from collections import Counter + +import numpy as np +import pytest +from PIL import Image + +from mml.core.data_loading.task_attributes import DataSplit, Modality, TaskType +from mml.core.data_loading.task_dataset import TaskDataset +from mml.core.data_preparation.task_creator import TaskCreator, implements_action +from mml.core.data_preparation.utils import TaskCreatorActions, TaskCreatorState +from mml.core.scripts.exceptions import InvalidTransitionError +from mml.core.scripts.utils import ARG_SEP, TAG_SEP + + +@pytest.fixture() +def dummy_task_creator(tmp_path, file_manager): + yield TaskCreator(dset_path=tmp_path) + + +@pytest.fixture() +def patch_loading(image, monkeypatch): + def dummy_loading(self, index): + return {"image": image, "class": np.random.randint(low=0, high=3)} + + def dummy_pillow(*args, **kwargs): + return Image.fromarray(image) + + monkeypatch.setattr(target=TaskDataset, name="load_sample", value=dummy_loading) + monkeypatch.setattr(target=Image, name="open", value=dummy_pillow) + yield + + +def test_task_creator_protocol(dummy_task_creator): + old_protocol = copy.copy(dummy_task_creator.current_meta.creation_protocol) + dummy_task_creator.protocol("Random important message!") + assert dummy_task_creator.current_meta.creation_protocol.startswith(old_protocol) + assert len(dummy_task_creator.current_meta.creation_protocol) > len(old_protocol) + assert "Random important message!" in dummy_task_creator.current_meta.creation_protocol + + +def test_loading(dummy_meta_class_path, file_manager): + creator = TaskCreator(dset_path=dummy_meta_class_path.parent) + creator.load_existent(dummy_meta_class_path) + assert "Copied" in creator.current_meta.creation_protocol + + +@pytest.mark.parametrize( + argnames=["class_list", "n_folds", "balancing", "fraction", "expected_split"], + argvalues=[ + # simplest case + ([0, 1, 1, 1, 0, 1, 1, 1, 0, 0], 5, False, None, [[2, 6], [8, 1], [5, 4], [0, 9], [7, 3]]), + # turning on balancing changes output + ([0, 1, 0, 1, 0, 1, 1, 1, 0, 0], 5, True, None, [[4, 5], [7, 9], [6, 8], [0, 1], [3, 2]]), + # as long as ensure balancing is enabled, changing the class list also changes output + ([0, 0, 1, 0, 1, 1, 1, 0, 0, 1], 5, True, None, [[3, 5], [9, 8], [6, 7], [0, 2], [4, 1]]), + # if pool sizes are not multiples of n_folds, it may happen that fold_0 is the largest + ([0, 1, 1, 1, 0, 1, 1, 1, 1, 0], 2, True, None, [[5, 0, 2, 8, 9, 7], [1, 6, 3, 4]]), + # it may also happen that fold_1 is the largest + ([0, 1, 1, 1, 0, 1, 1, 1, 1, 0], 3, True, None, [[0, 8, 2], [7, 5, 6, 9], [1, 4, 3]]), + # if pool sizes are multiples of n_folds, folds should be of equal size + ([0, 1, 1, 1, 0, 1, 1, 0, 1], 3, True, None, [[0, 5, 1], [6, 3, 7], [2, 4, 8]]), + # increasing the fraction of fold 0 + ([0, 1, 1, 1, 0, 1, 1, 1, 0, 0], 5, False, 0.6, [[4, 2, 1, 8, 6, 5], [0], [9], [3], [7]]), + # decreasing the fraction of fold 0 + ([0, 1, 1, 1, 0, 1, 1, 1, 0, 0], 5, False, 0.1, [[2], [8, 1, 6], [5, 4], [0, 9], [7, 3]]), + # increasing the fraction of fold 0 in balanced mode + ([0, 1, 1, 1, 0, 1, 1, 1, 0, 0], 2, True, 0.6, [[3, 8, 1, 5, 9, 6], [2, 4, 7, 0]]), + ], +) +def test_fold_splitting_success(dummy_task_creator, class_list, n_folds, balancing, fraction, expected_split): + dummy_task_creator.data = { + DataSplit.FULL_TRAIN: {str(ix): {Modality.CLASS: cls_id} for ix, cls_id in enumerate(class_list)} + } + dummy_task_creator.current_meta.class_occ = Counter(class_list) + dummy_task_creator.current_meta.idx_to_class = {ix: str(ix) for ix in set(class_list)} + if balancing: + dummy_task_creator.current_meta.task_type = TaskType.CLASSIFICATION + dummy_task_creator.split_folds( + n_folds=n_folds, ensure_balancing=balancing, fold_0_fraction=fraction, ignore_state=True + ) + assert dummy_task_creator.current_meta.train_folds == [[str(s_id) for s_id in fold] for fold in expected_split] + + +@pytest.mark.parametrize( + argnames=["class_list", "n_folds", "balancing", "fraction"], + argvalues=[ + # too many folds + ([0, 1, 1, 1, 0, 1, 1, 1, 1, 0], 11, False, None), + # too few folds + ([0, 1, 1, 1, 0, 1, 1, 1, 1, 0], 1, False, None), + ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 5, True, None), + # balancing not possible with the number of folds + ([0, 1, 1, 1, 0, 1, 1, 1, 1, 0], 4, True, None), + ([0, 1, 1, 1, 0, 1, 1, 1, 1], 2, True, 2 / 3), + # first fold fraction too small + ([0, 1, 0, 1, 0, 0, 1, 0, 1], 5, True, 0.1), + ], +) +def test_fold_splitting_failure(dummy_task_creator, class_list, n_folds, balancing, fraction): + dummy_task_creator.data = { + DataSplit.FULL_TRAIN: {str(ix): {Modality.CLASS: cls_id} for ix, cls_id in enumerate(class_list)} + } + dummy_task_creator.current_meta.class_occ = Counter(class_list) + dummy_task_creator.current_meta.idx_to_class = {ix: str(ix) for ix in set(class_list)} + if balancing: + dummy_task_creator.current_meta.task_type = TaskType.CLASSIFICATION + with pytest.raises(ValueError): + dummy_task_creator.split_folds( + n_folds=n_folds, ensure_balancing=balancing, fold_0_fraction=fraction, ignore_state=True + ) + + +def test_invalid_traversal(dummy_meta_class_path, file_manager, monkeypatch): + @implements_action(TaskCreatorActions.SET_FOLDING) + def dummy_traversal(self: TaskCreator) -> None: + pass + + creator = TaskCreator(dset_path=dummy_meta_class_path.parent) + creator.load_existent(dummy_meta_class_path) + + dummy_traversal(creator) + + with pytest.raises(InvalidTransitionError): + creator.push_and_test() + + +def test_valid_traversals(dummy_meta_class_path, file_manager, patch_loading): + creator = TaskCreator(dset_path=dummy_meta_class_path.parent) + creator.load_existent(dummy_meta_class_path) + creator.identity() + creator.infer_stats() + + +def test_auto_complete_after_modify(dummy_meta_class_path, file_manager, patch_loading): + p = file_manager.raw_data / "dummy_dset" + p.mkdir() + shutil.copy(src=dummy_meta_class_path, dst=p) + creator = TaskCreator(dset_path=p) + creator.load_existent(p / dummy_meta_class_path.name) + creator.identity() + creator.data = { + DataSplit.FULL_TRAIN: { + f"ID_{ix}": {Modality.CLASS: ix % 3, Modality.IMAGE: f"dummy_{ix}.bmp"} for ix in range(100) + } + } + creator.current_meta.class_occ = Counter( + [ + creator.current_meta.idx_to_class[elem[Modality.CLASS]] + for elem in creator.data[DataSplit.FULL_TRAIN].values() + ] + ) + creator._state = TaskCreatorState.DATA_FOUND + creator.auto_complete() + + +def test_identity_tag(file_manager, dummy_meta_class_path, patch_loading): + p = file_manager.raw_data / "dummy_dset" + p.mkdir() + shutil.copy(src=dummy_meta_class_path, dst=p) + file_manager.add_to_task_index(path=p / dummy_meta_class_path.name) + new_path = TaskCreator.auto_create_tagged(full_alias=f"dummy_task{TAG_SEP}identity") + assert file_manager.load_task_description(new_path).name == f"dummy_task{TAG_SEP}identity" + + +@pytest.mark.parametrize( + argnames=["fold_str", "new_folds_str", "valid"], + argvalues=[ + # too few folds + ("3", "1", False), + # fold number invalid + ("7", "4", False), + ("-1", "3", False), + ("nine", "3", False), + ("", "3", False), + # valid cases, unfortunately higher new_folds leads to impossible balancing + ("4", "2", True), + ("0", "2", True), + ], +) +def test_nested_validation_tag(file_manager, dummy_meta_class_path, patch_loading, fold_str, new_folds_str, valid): + p = file_manager.raw_data / "dummy_dset" + p.mkdir() + shutil.copy(src=dummy_meta_class_path, dst=p) + file_manager.add_to_task_index(path=p / dummy_meta_class_path.name) + old_meta = file_manager.load_task_description(p / dummy_meta_class_path.name) + if not valid: + with pytest.raises(ValueError): + _ = TaskCreator.auto_create_tagged( + full_alias=f"dummy_task{TAG_SEP}nested{ARG_SEP}{fold_str}{ARG_SEP}{new_folds_str}" + ) + else: + new_path = TaskCreator.auto_create_tagged( + full_alias=f"dummy_task{TAG_SEP}nested{ARG_SEP}{fold_str}{ARG_SEP}{new_folds_str}" + ) + new_meta = file_manager.load_task_description(new_path) + # correct number of folds in new task + assert len(new_meta.train_folds) == int(new_folds_str) + # old validation moved to test samples + assert all([s_id in new_meta.test_samples for s_id in old_meta.train_folds[int(fold_str)]]) + # fold one is never moved to test samples + assert all([s_id not in new_meta.test_samples for s_id in old_meta.train_folds[1]]) diff --git a/tests/unit/core/models/test_timm.py b/tests/unit/core/models/test_timm.py new file mode 100644 index 0000000..8c2b0b0 --- /dev/null +++ b/tests/unit/core/models/test_timm.py @@ -0,0 +1,84 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import pytest +import torch + +from mml.core.data_loading.task_attributes import Modality, RGBInfo, Sizes, TaskType +from mml.core.data_loading.task_struct import TaskStruct +from mml.core.models.timm import TimmGenericModel + + +@pytest.mark.parametrize("model_name", ["resnet18", "vit_tiny_r_s16_p8_224"]) +def test_timm_freeze_unfreeze(model_name, dummy_task_struct): + model = TimmGenericModel(name=model_name, pretrained=True, drop_rate=0.5) + model.add_head(task_struct=dummy_task_struct) + model.freeze_backbone() + assert not next(model.backbone.parameters()).requires_grad + assert next(model.heads[dummy_task_struct.name].parameters()).requires_grad + model.unfreeze_backbone() + assert next(model.backbone.parameters()).requires_grad + + +def test_timm_multi_heads(): + model = TimmGenericModel(name="resnet18", pretrained=True, drop_rate=0.5) + struct_one = TaskStruct( + name="dummy", + task_type=TaskType.CLASSIFICATION, + means=RGBInfo(*[0.1, 0.2, 0.3]), + stds=RGBInfo(*[0.4, 0.5, 0.6]), + sizes=Sizes(*[1, 2, 3, 4]), + relative_root="dummy_root", + class_occ={"one": 1, "two": 2}, + preprocessed="none", + keywords=[], + idx_to_class={0: "one", 1: "two"}, + modalities={Modality.CLASS: "stuff"}, + ) + struct_two = TaskStruct( + name="dummy_two", + task_type=TaskType.MULTILABEL_CLASSIFICATION, + means=RGBInfo(*[0.1, 0.2, 0.3]), + stds=RGBInfo(*[0.4, 0.5, 0.6]), + sizes=Sizes(*[1, 2, 3, 4]), + relative_root="dummy_root", + class_occ={"one": 1, "two": 2, "three": 3}, + preprocessed="none", + keywords=[], + idx_to_class={0: "one", 1: "two", 3: "three"}, + modalities={Modality.SOFT_CLASSES: "stuff"}, + ) + struct_three = TaskStruct( + name="dummy_three", + task_type=TaskType.REGRESSION, + means=RGBInfo(*[0.1, 0.2, 0.3]), + stds=RGBInfo(*[0.4, 0.5, 0.6]), + sizes=Sizes(*[1, 2, 3, 4]), + relative_root="dummy_root", + class_occ={"one": 1, "two": 2}, + preprocessed="none", + keywords=[], + idx_to_class={0: "one", 1: "two"}, + modalities={Modality.VALUE: "stuff"}, + ) + model.add_head(struct_one) + model.add_head(struct_two) + model.add_head(struct_three) + result = model(torch.rand((7, 3, 224, 224))) + assert all(struct.name in result for struct in [struct_one, struct_two, struct_three]) + assert all(isinstance(result[struct.name], torch.Tensor) for struct in [struct_one, struct_two, struct_three]) + + +@pytest.mark.parametrize("model_name", ["resnet18", "vit_tiny_r_s16_p8_224"]) +def test_timm_count_parameters(model_name, dummy_task_struct): + model = TimmGenericModel(name=model_name, pretrained=True, drop_rate=0.5) + bb_pars = model.count_parameters()["backbone"] + model.add_head(task_struct=dummy_task_struct) + _ = model.count_parameters()[dummy_task_struct.name] + assert bb_pars == model.count_parameters()["backbone"] # backbone pars do not change with another head + model.freeze_backbone() + assert model.count_parameters()["backbone"] == 0 + assert model.count_parameters(only_trainable=False)["backbone"] > 0 diff --git a/tests/unit/core/scripts/test_base_scheduler.py b/tests/unit/core/scripts/test_base_scheduler.py new file mode 100644 index 0000000..9eee178 --- /dev/null +++ b/tests/unit/core/scripts/test_base_scheduler.py @@ -0,0 +1,60 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import os +import warnings +from pathlib import Path + +import pytest + +import mml.core.scripts.callbacks +import mml.core.scripts.schedulers.base_scheduler as base_scheduler_module +import mml.core.scripts.utils +from mml.core.scripts.schedulers.base_scheduler import AbstractBaseScheduler + + +@pytest.fixture +def base_scheduler(monkeypatch, mml_config, file_manager): + # enables testing of abstract method, also ensures that the file manager is set correctly before testing scheduler + monkeypatch.setattr(AbstractBaseScheduler, "__abstractmethods__", set()) + mml_config["allow_gpu"] = False + yield AbstractBaseScheduler(cfg=mml_config, available_subroutines=["test"]) + + +def test_routine(base_scheduler, file_manager): + with open(base_scheduler.planned_schedule, "r") as file: + lines = file.readlines() + assert lines == ["method: prepare_exp / []\n", "method: finish_exp / []\n"] + with open(base_scheduler.status_log, "r") as file: + lines = file.readlines() + assert lines[:2] == ["HEADER\n", "Timepoint of beginning\n"] + assert lines[3] == "START\n" + + +def test_lock_is_set(base_scheduler, file_manager): + lock_path = Path(os.getcwd()) / "lock.tmp" + assert lock_path.exists() + + +def test_lock_prevents_scheduler_race(base_scheduler, file_manager, mml_config): + with pytest.raises(RuntimeError, match="lock"): + AbstractBaseScheduler(cfg=mml_config, available_subroutines=["test"]) + + +def test_create_trainer_with_callbacks(base_scheduler, mml_config): + trainer = base_scheduler.create_trainer(monitor=None, metrics_callback=True) + assert base_scheduler.checkpoint_callback in trainer.callbacks + assert base_scheduler.metrics_callback in trainer.callbacks + assert any([isinstance(cb, mml.core.scripts.callbacks.StopAfterKeyboardInterrupt) for cb in trainer.callbacks]) + + +def test_after_init_hooks(base_scheduler, monkeypatch): + def dummy(scheduler): + warnings.warn("success!") + + monkeypatch.setattr(base_scheduler_module, "AFTER_SCHEDULER_INIT_HOOKS", [dummy]) + with pytest.warns(match="success"): + base_scheduler._run_after_init_hooks() diff --git a/tests/unit/core/scripts/test_model_storage.py b/tests/unit/core/scripts/test_model_storage.py new file mode 100644 index 0000000..3a2e943 --- /dev/null +++ b/tests/unit/core/scripts/test_model_storage.py @@ -0,0 +1,22 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +from mml.core.scripts.model_storage import ModelStorage + + +def test_restoring(dummy_model_storage, dummy_task_struct): + path = dummy_model_storage.store(task_struct=dummy_task_struct) + loaded = ModelStorage.from_json(path=path) + print(loaded) + print(dummy_model_storage) + assert dummy_model_storage == loaded + + +def test_updating(dummy_model_storage, dummy_task_struct): + path = dummy_model_storage.store(task_struct=dummy_task_struct) + dummy_model_storage.training_time += 1.0 + updated_path = dummy_model_storage.store(path=path) + assert updated_path == path diff --git a/tests/unit/core/scripts/test_notifier.py b/tests/unit/core/scripts/test_notifier.py new file mode 100644 index 0000000..be35487 --- /dev/null +++ b/tests/unit/core/scripts/test_notifier.py @@ -0,0 +1,25 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import pytest + +from mml.core.scripts.exceptions import MMLMisconfigurationException +from mml.core.scripts.notifier import BaseNotifier, DummyNotifier + + +def test_is_master(monkeypatch): + assert BaseNotifier.is_master() + monkeypatch.setenv(name="RANK", value="0") + assert BaseNotifier.is_master() + monkeypatch.setenv(name="RANK", value="42") + assert not BaseNotifier.is_master() + + +@pytest.mark.parametrize(argnames="exception", argvalues=[OSError(), MMLMisconfigurationException(), RuntimeError()]) +def test_create_failure_message(exception): + notifier = DummyNotifier(on_failure=True) + with pytest.warns(): + notifier.notify_on_failure(error=exception) diff --git a/tests/unit/core/scripts/test_train_scheduler.py b/tests/unit/core/scripts/test_train_scheduler.py new file mode 100644 index 0000000..d997bc8 --- /dev/null +++ b/tests/unit/core/scripts/test_train_scheduler.py @@ -0,0 +1,34 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import pytest +from omegaconf import OmegaConf + +from mml.core.scripts.pipeline_configuration import PIPELINE_CONFIG_PARTS +from mml.core.scripts.schedulers.train_scheduler import TrainingScheduler + + +@pytest.mark.gpu +@pytest.mark.parametrize("test_task_name", ["test_task_a"]) # TODO add 'test_task_d' +def test_train_probe_model(test_task_monkeypatch, mml_config, test_task_name) -> None: + OmegaConf.set_struct(mml_config, False) + mml_config.mode.subroutines = ["train"] + mml_config.pivot.name = test_task_name + mml_config.mode.cv = False + mml_config.mode.nested = False + mml_config.mode.multitask = False + mml_config.mode.store_parameters = False + mml_config.mode.use_blueprint = False + mml_config.mode.pipeline_keys = PIPELINE_CONFIG_PARTS + mml_config.mode.store_best = True + mml_config.mode.eval_on = None + mml_config.mode.task_weights = None + OmegaConf.set_struct(mml_config, True) + with pytest.warns(UserWarning, match="MMLFileManager was not created by BaseScheduler"): + scheduler = TrainingScheduler(cfg=mml_config) + scheduler.train_fold(task_name=test_task_name, fold=0) + # check if model storage has been created + assert len(scheduler.get_struct(test_task_name).models) == 1 diff --git a/tests/unit/core/scripts/test_utils.py b/tests/unit/core/scripts/test_utils.py new file mode 100644 index 0000000..5823d05 --- /dev/null +++ b/tests/unit/core/scripts/test_utils.py @@ -0,0 +1,93 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import logging +import time + +import pytest + +from mml.core.scripts.decorators import beta +from mml.core.scripts.utils import Singleton, StrEnum, catch_time, throttle_logging + + +def test_catch_time(): + with catch_time() as timer: + time.sleep(1.0) + assert timer.seconds > 0 + assert len(timer.pretty_time) > 0 + + +def test_throttle_logging(): + # dummy handler that raises an error if a message is emmitted + class DummyHandler(logging.Handler): + def emit(self, record: logging.LogRecord) -> None: + raise RuntimeError("Should not be emitted!") + + logger = logging.getLogger("mml.test.dummy") + logger.addHandler(hdlr=DummyHandler()) + logger.setLevel(level=logging.DEBUG) + # test 1: no message if logging is throttled above + with throttle_logging(logging.INFO): + logger.info("something") + # test 2: message if logging is throttled below + with pytest.raises(RuntimeError): + with throttle_logging(logging.DEBUG): + logger.info("something") + # test 3: message if logging is throttled on a different logger + with pytest.raises(RuntimeError): + with throttle_logging(logging.INFO, package="mml.test.other"): + logger.info("something") + # test 4: no message if logging is throttled on that exact logger + with throttle_logging(logging.INFO, package="mml.test.dummy"): + logger.info("something") + # test 5: reset of level + assert logger.level == logging.DEBUG + + +def test_singleton_class(): + class Dummy(Singleton): + def __init__(self, x): + self.x = x + + instance = Dummy(3) + assert Dummy.instance() is instance + assert Dummy.instance(5).x == 3 + assert Dummy.exists() + Dummy.clear_instance() + assert Dummy.instance(5).x == 5 + assert Dummy.instance() is not instance + + +def test_strenum(): + class Dummy(StrEnum): + A = "a" + B = "bb" + C = "ccc" + + assert Dummy.C is Dummy.from_str("c") + assert Dummy.B == "bb" + with pytest.raises(ValueError): + Dummy.from_str("aaa") + + +def test_beta_decorator(monkeypatch): + @beta("some message") + class DummyClass: + pass + + # raises first time + with pytest.warns(UserWarning, match="some message"): + DummyClass() + # no raise + DummyClass() + + @beta("some message") + def func(): + pass + + # raises again, since new caller + with pytest.warns(UserWarning, match="some message"): + func() diff --git a/tests/unit/interactive/test_planning.py b/tests/unit/interactive/test_planning.py new file mode 100644 index 0000000..cded16e --- /dev/null +++ b/tests/unit/interactive/test_planning.py @@ -0,0 +1,77 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import os.path + +import pandas as pd +import pytest + +from mml.core.data_loading.task_attributes import Keyword, TaskType +from mml.interactive import _check_init +from mml.interactive.planning import AllTasksInfos, DefaultRequirements, MMLJobDescription, write_out_commands + + +def test_valid_rendering(script_runner): + job = MMLJobDescription( + prefix_req=DefaultRequirements(), mode="info", config_options={"tasks": "none"}, multirun=False + ) + ret = script_runner.run(job.render().split(" "), print_result=False) + assert ret.success + assert "MML run time was" in ret.stdout + assert ret.stderr == "" + + +def test_write_out(monkeypatch, tmp_path): + def mocked_path(*args, **kwargs): + return tmp_path + + monkeypatch.setattr(target=os.path, name="abspath", value=mocked_path) + + cmds = [ + MMLJobDescription(prefix_req=DefaultRequirements(), mode="dummy", config_options={"optimizer.lr": 0.01}), + MMLJobDescription( + prefix_req=DefaultRequirements(), + mode="dummy", + config_options={"optimizer.lr": [0.01, 0.001]}, + multirun=True, + ), + ] + assert tmp_path.exists() + assert len(list(tmp_path.iterdir())) == 0 + write_out_commands(cmd_list=cmds, name="bazz", seperator="", max_cmds=1) + assert len(list(tmp_path.iterdir())) == 2 + assert all(["bazz" in p.stem for p in tmp_path.iterdir()]) + + +def test_task_info_write_read(tmp_path): + tasks = ["a", "b", "c"] + infos = AllTasksInfos( + num_classes={t: idx for idx, t in enumerate(tasks)}, + num_samples={t: idx * 100 for idx, t in enumerate(tasks)}, + imbalance_ratios={t: idx * 1.2345 for idx, t in enumerate(tasks)}, + datasets={t: "data_" + t for t in tasks}, + keywords={t: set(Keyword(_kw) for _kw in Keyword.list()[: (idx + 1) * 2]) for idx, t in enumerate(tasks)}, + task_types={t: TaskType(TaskType.list()[idx]) for idx, t in enumerate(tasks)}, + domains={t: Keyword(Keyword.list()[idx]) for idx, t in enumerate(tasks)}, + dimensions={t: idx * 13 for idx, t in enumerate(tasks)}, + max_resolution={t: idx * 1000000 for idx, t in enumerate(tasks)}, + min_resolution={t: idx * 1000 for idx, t in enumerate(tasks)}, + small_tasks=[tasks[0]], + medium_tasks=[tasks[1]], + large_tasks=[tasks[2]], + ) + infos.store_csv(tmp_path / "infos.csv") + df = pd.read_csv(tmp_path / "infos.csv") + infos2 = AllTasksInfos.from_csv(tmp_path / "infos.csv") + infos2.store_csv(tmp_path / "infos2.csv") + df2 = pd.read_csv(tmp_path / "infos2.csv") + pd.testing.assert_frame_equal(df.set_index("name"), df2.set_index("name")[df.set_index("name").columns]) + + +@pytest.mark.env +def test_init_check(): + with pytest.raises(RuntimeError): + _check_init() diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py new file mode 100644 index 0000000..798988a --- /dev/null +++ b/tests/unit/test_cli.py @@ -0,0 +1,14 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +import mml + + +def test_version_tag(script_runner): + ret = script_runner.run(["mml", "--version"]) + assert ret.success + assert f"mml-core {mml.__version__}" in ret.stdout + assert "Hydra" not in ret.stdout From 8ac0b03046d01dfcb1965a059d39625f793a23d4 Mon Sep 17 00:00:00 2001 From: Patrick Godau Date: Thu, 19 Dec 2024 05:44:38 +0100 Subject: [PATCH 2/4] add docs --- RELEASE.md | 54 - docs/Makefile | 20 + docs/README.md | 73 ++ docs/make.bat | 35 + docs/source/_static/mml_favicon.ico | Bin 0 -> 3262 bytes docs/source/_static/mml_logo.png | Bin 0 -> 161794 bytes docs/source/_static/mml_logo_old.png | Bin 0 -> 18418 bytes docs/source/_static/mml_logo_sqare.png | Bin 0 -> 157818 bytes docs/source/_static/mml_overview.png | Bin 0 -> 370205 bytes docs/source/_static/mml_overview.svg | 1161 +++++++++++++++++ docs/source/_static/old_mml_favicon.ico | Bin 0 -> 1581 bytes docs/source/_static/tensorboard_example.png | Bin 0 -> 154212 bytes docs/source/api/api.rst | 23 + docs/source/api/cli.rst | 9 + docs/source/api/components.rst | 87 ++ .../augmentations/albumentations.rst | 7 + .../augmentations/augmentation_module.rst | 7 + .../data_loading/augmentations/kornia.rst | 7 + .../augmentations/mixup_cutmix.rst | 7 + .../data_loading/augmentations/overview.rst | 48 + .../augmentations/torchvision.rst | 7 + .../api/core/data_loading/file_manager.rst | 7 + .../data_loading/lightning_datamodule.rst | 7 + .../core/data_loading/modality_loaders.rst | 7 + .../source/api/core/data_loading/overview.rst | 32 + .../api/core/data_loading/task_attributes.rst | 7 + .../api/core/data_loading/task_dataset.rst | 7 + .../core/data_loading/task_description.rst | 7 + .../api/core/data_loading/task_struct.rst | 7 + docs/source/api/core/data_loading/utils.rst | 7 + .../data_preparation/archive_extractors.rst | 7 + .../core/data_preparation/data_archive.rst | 7 + .../core/data_preparation/dset_creator.rst | 7 + .../api/core/data_preparation/fake_task.rst | 7 + .../api/core/data_preparation/overview.rst | 36 + .../api/core/data_preparation/registry.rst | 7 + .../core/data_preparation/task_creator.rst | 7 + .../api/core/data_preparation/utils.rst | 7 + .../core/models/lightning_single_frame.rst | 7 + docs/source/api/core/models/overview.rst | 22 + docs/source/api/core/models/smp.rst | 7 + docs/source/api/core/models/timm.rst | 7 + docs/source/api/core/models/torch_base.rst | 7 + docs/source/api/core/scripts/callbacks.rst | 7 + docs/source/api/core/scripts/decorators.rst | 7 + docs/source/api/core/scripts/exceptions.rst | 7 + .../source/api/core/scripts/model_storage.rst | 7 + docs/source/api/core/scripts/notifier.rst | 7 + docs/source/api/core/scripts/overview.rst | 43 + .../core/scripts/pipeline_configuration.rst | 7 + .../scripts/schedulers/base_scheduler.rst | 7 + .../scripts/schedulers/clean_scheduler.rst | 6 + .../scripts/schedulers/create_scheduler.rst | 6 + .../scripts/schedulers/info_scheduler.rst | 6 + .../schedulers/preprocess_scheduler.rst | 6 + .../scripts/schedulers/train_scheduler.rst | 6 + .../scripts/schedulers/transfer_scheduler.rst | 6 + .../scripts/schedulers/upgrade_scheduler.rst | 6 + docs/source/api/core/scripts/utils.rst | 7 + docs/source/api/core/visualization/cm.rst | 7 + docs/source/api/core/visualization/logo.rst | 8 + .../api/core/visualization/overview.rst | 21 + .../api/core/visualization/predictions.rst | 7 + docs/source/api/core/visualization/utils.rst | 7 + docs/source/api/interactive.rst | 7 + docs/source/api/overview.rst | 35 + docs/source/api/plugins/data.rst | 17 + docs/source/api/plugins/dimensionality.rst | 6 + docs/source/api/plugins/drive.rst | 8 + docs/source/api/plugins/lsf.rst | 8 + docs/source/api/plugins/overview.rst | 28 + docs/source/api/plugins/similarity.rst | 11 + docs/source/api/plugins/sql.rst | 75 ++ docs/source/api/plugins/suggest.rst | 16 + docs/source/api/plugins/tags.rst | 14 + docs/source/api/testing.rst | 12 + docs/source/cli/arch.rst | 20 + docs/source/cli/augmentations.rst | 21 + docs/source/cli/callbacks.rst | 57 + docs/source/cli/compile.rst | 9 + docs/source/cli/hpo.rst | 22 + docs/source/cli/loaders.rst | 52 + docs/source/cli/logging.rst | 53 + docs/source/cli/loss.rst | 68 + docs/source/cli/lr_scheduler.rst | 45 + docs/source/cli/metrics.rst | 29 + docs/source/cli/mode.rst | 72 + docs/source/cli/optimizer.rst | 17 + docs/source/cli/overview.rst | 138 ++ docs/source/cli/preprocessing.rst | 54 + docs/source/cli/remove.rst | 30 + docs/source/cli/reuse.rst | 18 + docs/source/cli/sampling.rst | 12 + docs/source/cli/search_space.rst | 12 + docs/source/cli/sys.rst | 19 + docs/source/cli/tasks.rst | 34 + docs/source/cli/trainer.rst | 10 + docs/source/cli/tta.rst | 16 + docs/source/cli/tune.rst | 15 + docs/source/conf.py | 105 ++ docs/source/extensions.rst | 110 ++ docs/source/guides.rst | 11 + docs/source/hpo.rst | 42 + docs/source/index.rst | 187 +++ docs/source/install.rst | 180 +++ docs/source/modes.rst | 11 + docs/source/notebooks/mml-modes/create.ipynb | 143 ++ docs/source/notebooks/mml-modes/info.ipynb | 167 +++ docs/source/notebooks/mml-modes/post.ipynb | 35 + docs/source/notebooks/mml-modes/pp.ipynb | 116 ++ docs/source/notebooks/mml-modes/train.ipynb | 536 ++++++++ docs/source/notebooks/mml-modes/upgrade.ipynb | 57 + .../baseline-checkpoint.ipynb | 387 ++++++ .../cluster_integration-checkpoint.ipynb | 58 + .../notebooks/tricks/adapt_dataset.ipynb | 301 +++++ docs/source/notebooks/tricks/baseline.ipynb | 387 ++++++ .../tricks/cluster_integration.ipynb | 58 + docs/source/notebooks/tricks/efficiency.ipynb | 46 + .../notebooks/tricks/jupyter_usage.ipynb | 231 ++++ docs/source/notebooks/tricks/tta.ipynb | 108 ++ docs/source/notebooks/tricks/tune.ipynb | 63 + docs/source/plugins.rst | 65 + docs/source/usage.rst | 310 +++++ 123 files changed, 6679 insertions(+), 54 deletions(-) delete mode 100644 RELEASE.md create mode 100644 docs/Makefile create mode 100644 docs/README.md create mode 100644 docs/make.bat create mode 100644 docs/source/_static/mml_favicon.ico create mode 100644 docs/source/_static/mml_logo.png create mode 100644 docs/source/_static/mml_logo_old.png create mode 100644 docs/source/_static/mml_logo_sqare.png create mode 100644 docs/source/_static/mml_overview.png create mode 100644 docs/source/_static/mml_overview.svg create mode 100644 docs/source/_static/old_mml_favicon.ico create mode 100644 docs/source/_static/tensorboard_example.png create mode 100644 docs/source/api/api.rst create mode 100644 docs/source/api/cli.rst create mode 100644 docs/source/api/components.rst create mode 100644 docs/source/api/core/data_loading/augmentations/albumentations.rst create mode 100644 docs/source/api/core/data_loading/augmentations/augmentation_module.rst create mode 100644 docs/source/api/core/data_loading/augmentations/kornia.rst create mode 100644 docs/source/api/core/data_loading/augmentations/mixup_cutmix.rst create mode 100644 docs/source/api/core/data_loading/augmentations/overview.rst create mode 100644 docs/source/api/core/data_loading/augmentations/torchvision.rst create mode 100644 docs/source/api/core/data_loading/file_manager.rst create mode 100644 docs/source/api/core/data_loading/lightning_datamodule.rst create mode 100644 docs/source/api/core/data_loading/modality_loaders.rst create mode 100644 docs/source/api/core/data_loading/overview.rst create mode 100644 docs/source/api/core/data_loading/task_attributes.rst create mode 100644 docs/source/api/core/data_loading/task_dataset.rst create mode 100644 docs/source/api/core/data_loading/task_description.rst create mode 100644 docs/source/api/core/data_loading/task_struct.rst create mode 100644 docs/source/api/core/data_loading/utils.rst create mode 100644 docs/source/api/core/data_preparation/archive_extractors.rst create mode 100644 docs/source/api/core/data_preparation/data_archive.rst create mode 100644 docs/source/api/core/data_preparation/dset_creator.rst create mode 100644 docs/source/api/core/data_preparation/fake_task.rst create mode 100644 docs/source/api/core/data_preparation/overview.rst create mode 100644 docs/source/api/core/data_preparation/registry.rst create mode 100644 docs/source/api/core/data_preparation/task_creator.rst create mode 100644 docs/source/api/core/data_preparation/utils.rst create mode 100644 docs/source/api/core/models/lightning_single_frame.rst create mode 100644 docs/source/api/core/models/overview.rst create mode 100644 docs/source/api/core/models/smp.rst create mode 100644 docs/source/api/core/models/timm.rst create mode 100644 docs/source/api/core/models/torch_base.rst create mode 100644 docs/source/api/core/scripts/callbacks.rst create mode 100644 docs/source/api/core/scripts/decorators.rst create mode 100644 docs/source/api/core/scripts/exceptions.rst create mode 100644 docs/source/api/core/scripts/model_storage.rst create mode 100644 docs/source/api/core/scripts/notifier.rst create mode 100644 docs/source/api/core/scripts/overview.rst create mode 100644 docs/source/api/core/scripts/pipeline_configuration.rst create mode 100644 docs/source/api/core/scripts/schedulers/base_scheduler.rst create mode 100644 docs/source/api/core/scripts/schedulers/clean_scheduler.rst create mode 100644 docs/source/api/core/scripts/schedulers/create_scheduler.rst create mode 100644 docs/source/api/core/scripts/schedulers/info_scheduler.rst create mode 100644 docs/source/api/core/scripts/schedulers/preprocess_scheduler.rst create mode 100644 docs/source/api/core/scripts/schedulers/train_scheduler.rst create mode 100644 docs/source/api/core/scripts/schedulers/transfer_scheduler.rst create mode 100644 docs/source/api/core/scripts/schedulers/upgrade_scheduler.rst create mode 100644 docs/source/api/core/scripts/utils.rst create mode 100644 docs/source/api/core/visualization/cm.rst create mode 100644 docs/source/api/core/visualization/logo.rst create mode 100644 docs/source/api/core/visualization/overview.rst create mode 100644 docs/source/api/core/visualization/predictions.rst create mode 100644 docs/source/api/core/visualization/utils.rst create mode 100644 docs/source/api/interactive.rst create mode 100644 docs/source/api/overview.rst create mode 100644 docs/source/api/plugins/data.rst create mode 100644 docs/source/api/plugins/dimensionality.rst create mode 100644 docs/source/api/plugins/drive.rst create mode 100644 docs/source/api/plugins/lsf.rst create mode 100644 docs/source/api/plugins/overview.rst create mode 100644 docs/source/api/plugins/similarity.rst create mode 100644 docs/source/api/plugins/sql.rst create mode 100644 docs/source/api/plugins/suggest.rst create mode 100644 docs/source/api/plugins/tags.rst create mode 100644 docs/source/api/testing.rst create mode 100644 docs/source/cli/arch.rst create mode 100644 docs/source/cli/augmentations.rst create mode 100644 docs/source/cli/callbacks.rst create mode 100644 docs/source/cli/compile.rst create mode 100644 docs/source/cli/hpo.rst create mode 100644 docs/source/cli/loaders.rst create mode 100644 docs/source/cli/logging.rst create mode 100644 docs/source/cli/loss.rst create mode 100644 docs/source/cli/lr_scheduler.rst create mode 100644 docs/source/cli/metrics.rst create mode 100644 docs/source/cli/mode.rst create mode 100644 docs/source/cli/optimizer.rst create mode 100644 docs/source/cli/overview.rst create mode 100644 docs/source/cli/preprocessing.rst create mode 100644 docs/source/cli/remove.rst create mode 100644 docs/source/cli/reuse.rst create mode 100644 docs/source/cli/sampling.rst create mode 100644 docs/source/cli/search_space.rst create mode 100644 docs/source/cli/sys.rst create mode 100644 docs/source/cli/tasks.rst create mode 100644 docs/source/cli/trainer.rst create mode 100644 docs/source/cli/tta.rst create mode 100644 docs/source/cli/tune.rst create mode 100644 docs/source/conf.py create mode 100644 docs/source/extensions.rst create mode 100644 docs/source/guides.rst create mode 100644 docs/source/hpo.rst create mode 100644 docs/source/index.rst create mode 100644 docs/source/install.rst create mode 100644 docs/source/modes.rst create mode 100644 docs/source/notebooks/mml-modes/create.ipynb create mode 100644 docs/source/notebooks/mml-modes/info.ipynb create mode 100644 docs/source/notebooks/mml-modes/post.ipynb create mode 100644 docs/source/notebooks/mml-modes/pp.ipynb create mode 100644 docs/source/notebooks/mml-modes/train.ipynb create mode 100644 docs/source/notebooks/mml-modes/upgrade.ipynb create mode 100644 docs/source/notebooks/tricks/.ipynb_checkpoints/baseline-checkpoint.ipynb create mode 100644 docs/source/notebooks/tricks/.ipynb_checkpoints/cluster_integration-checkpoint.ipynb create mode 100644 docs/source/notebooks/tricks/adapt_dataset.ipynb create mode 100644 docs/source/notebooks/tricks/baseline.ipynb create mode 100644 docs/source/notebooks/tricks/cluster_integration.ipynb create mode 100644 docs/source/notebooks/tricks/efficiency.ipynb create mode 100644 docs/source/notebooks/tricks/jupyter_usage.ipynb create mode 100644 docs/source/notebooks/tricks/tta.ipynb create mode 100644 docs/source/notebooks/tricks/tune.ipynb create mode 100644 docs/source/plugins.rst create mode 100644 docs/source/usage.rst diff --git a/RELEASE.md b/RELEASE.md deleted file mode 100644 index b05b6e4..0000000 --- a/RELEASE.md +++ /dev/null @@ -1,54 +0,0 @@ -### Steps to take before releasing a new version - -#### Prerequisites - -- Has the `CHANGELOG.md` been updated? -- Is the `README.md` up to date? -- Is the documentation up to date? - -#### Quality control - -Run the following in order. Treat upcoming issues. -This still happens on individual develop branches! - -- `ruff check` + `ruff format` -- `mypy src` (currently not necessary) -- `pylint src/mml --max-line-length 120` -- `isort .` -- `pytest` - -Commit changes! - -#### Check docs - -- `cd docs` -- `make clean` -- `make html` -- Open `docs/build/index.html` and check any changes -- Finally, create a merge request to `dev` - -#### Dev branch - -- Continue once all individual branches have been merged into the main `dev` branch -- Set release version in `CHANGELOG.md`, `CITATION.cff` and `src.mml.__init__.py` -- Optionally set version of plugins (and `mml-core` dependency) -- Commit (-m "bump version(s)") -- Next we need to update license headers, be careful to with any potential newly added config files as a fresh license -header may mess with hydra's `@package` header, directive! - -```commandline -find . -type f \( -iname \*.py -o -iname \*.ini -o -iname \*.toml -o -iname \*.yaml \) -not -path "./.tox/*" -exec add-license-header --license-file license_header.template --create-year 2024 --single-year-if-same {} \; -``` -- Commit (-m "update license header") -- Push and wait for pipeline to succeed - -#### Master branch - -- Create merge request from `dev` to `master` -- Wait for pipeline to succeed -- Trigger required manual release jobs: - - release documentation - - release plugins -- Checkout `master` -- Create tag (naming: major.minor.patch) -- Push tag \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d0c3cbf --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..f47a940 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,73 @@ +# MML Docs + +We are using Sphinx to build the documentation. The API is documented with the help of +[autodoc](https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html) and automatically pulls the docstrings +from all [listed modules](source/api/overview.rst). The CLI interaction is documented within the `.yaml` files of the +`mml.configs` folder through [autoyaml](https://github.com/Jakski/sphinxcontrib-autoyaml) and referenced in the +[cli subfolder](source/cli/overview.rst). The gallery of examples is created through +[MyST-NB](https://github.com/executablebooks/MyST-NB) and the jupyter notebooks in `source/notebooks`. + +See following example shows the documentation of a function: + +```python +from typing import Optional +from pathlib import Path + + +def do_something(arg1: Path, kwarg1: Optional[float] = None) -> Path: + """ + One sentence description. Additional information, e.g. to the kwarg1 behaviour. + + .. code-block: python + + # Usage example + arg1 = ... + output = do_something(arg1) + + :param arg1: description of arg1 + :param kwarg1: desciption of kwarg1 + + :raises FileExistsError: in case arg1 already exists + :raises ValueError: in case kwarg1 is not positive + + :return: description of return value + :rtype: ~pathlib.Path + """ + if kwarg1 and kwarg1 < 1: + raise ValueError('Kwarg1 must be a positive integer if provided.') + if arg1.exists(): + raise FileExistsError('Arg1 already exists.') + ... +``` + +For documentation of CLI options the following template can be used for documentation: + +```yaml +### +# default: False +# - provide desciption of parameter +# - reference to class/method in mml, e.g. :meth:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler.create_model` +# - reference external `links `_ +# - see Sphinx documentation for more syntax details +parameter: False +# inline comment on top-level key parameter, will not be shown in generated docs +key: + ### + # default: 0.5 + # - document as above + subparameter: 0.5 +``` + + +## Building Docs + +After any update to the docs, building them locally and visually inspecting the output is required. No errors should be +reported by `sphinx` during the build-process. Run these commands from within the `docs` directory: + +```bash +make clean +make html +``` + +and open `docs/build/html/index.html` in your browser. After the PR has been sent an automated pipeline will run tests +and build the docs. diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..dc1312a --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/source/_static/mml_favicon.ico b/docs/source/_static/mml_favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..9e5b52a8fc670f6f9e413ec52df65a54ad2f44bb GIT binary patch literal 3262 zcmeH|OHf)@7{}?p>rR)MPCL_OC!0<;olF;P+D&IVleAg1)0uYJtTLHoChatjHrl+5 zae|_vhzO`4pgcqo5eSb60`ionfCR26Dk#r;p?`7{Bxcf%&7xiOc)fo2JLmk)cmCgZ zjts^d_&ITcf%n@C;hPM`TMP!{ef+}3IECM)|5dH=VyoBdg+c*uxVN`+$>he)&JI1~ z;NXDvzc}M~U+HuP%)Pz6QmIT3o3J-Gv*mJmfByhBdS7!1kimJ?gB=|&+~=cfwc76P zE=5t>+uJR8B9V;86L_~gxm=T9tyW2rd_J{7l9l{k3ZIGfrQ*RBMb+wcs?|#y+3Xe| z8yhJa1#CDR2?j&-0~;Q?ix#bYBcoP1YE$K}r^TLAG>;60I5;>c7EkebV_vV1!{LCR$z%dc8vWn{ z{a_D^#Tp-isd0&qj^tvIxM`AYe zko01)n9C7X6W?hULa1283=bqqr_(KAF%g;r(q8AND>@O;Xsk7oP628L%DbIYSt496 z6_W84*r9+dow8#!I?J_M4XdY8PcSzYTc=SwJ4n#8hH9am=*1YEGK|Npom?~=oJK-@ zZV9mTgDk_doeeyn{p>H!Ddzf|dY{J$n!`Gu+DPo=a$&zU;P=9_qMeI{Ldirjva(#O zl*wv^2zn}|{U;mNc{Nk5WUAy3=TuDRiZDxf5Pyr0?L%jJsXCwHgasSs3}vOmba^%kAs4pPm2dyUUj^&a3-Sw=Fnr z(7{7e@I7{oMKhop`Eri`1I_oYT5-I@r<;63f4AcN8SU+>-VgzPAxkW8)WFwj1X;oh z+QI(j5jZ}fXQfg>PUQpdx^45S;nQA+PRah*=X!+rLw-kcBL#lUX`lK2RM2LVojW-; zy9T~{Ei>t(z+YWm%@ym#>QOd|2M0>0)5T&j^eG13GpQdahdzPMW_6Ecj@iy%5siv| zJU6pOE%dR*?{mQC>C;?ylh0K<$GxO{jcgv;wl*>{f>Sd*JS-B4aMjEE-;ob|fJ0X* zm7)O~Z1A^<1j-5VOTRg(5l(YgNxs4(KJy{?15*2tB?ta*A_x5Ixg+>Se}6xZ$D5d# zz~RM#Li_;ch$uq9$x;n}iqFDshN{=W2QU&zfx}%Xiq3w7&zl{+SGxJ&-xz-k|9pfB zY}O%EYX?jw6HBn!Y=J<4E81%jcr8M@w_L8QubJGYu~Kmlp2tF-uy<1IC&A$?@Alp3 zn)vnSQ4WtYE*tt#w~E3YErOm}(MS zwf?1K*SJopR3dTmnVCVs^tFK*j;(-RPllon!*BHT^mKJ~VHbbPr&knsNUpQWoDX+# zm3EtLW_nsGkq9KJPQH#~%Y$!CQtkRcnF|*#T)K3L%jN!c{1vkCC{FR*O$EB;?(1xY zNU^xQysS_vJBQ^RJnit)_|a>OAL;{f5IGto+TY)QS(bK>$VbWoP5xb(tCPQUwNKI` zGTh?pI(UoM*~$@Db<#%?h5Givp+F9Y1C=Qji!ByQ`+wDTY|AF82DHTzL$-qsfw5yu z_she{t1Q{?T+MxjAM2VDhmp5t9m_y?&m>X>|CoGyZAgvExjnVQG7{3KTWb&gSY&!| zsn*a$sNGWCohsj*cK2x_EQPaAp9yW%t7Idwd#KDmfVWSHdWdrC#*|F{390=QcL)%GWWHEehQ literal 0 HcmV?d00001 diff --git a/docs/source/_static/mml_logo.png b/docs/source/_static/mml_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..09802de2139f1ccaed9e0e78096a653a726d4220 GIT binary patch literal 161794 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 literal 0 HcmV?d00001 diff --git a/docs/source/_static/mml_overview.png b/docs/source/_static/mml_overview.png new file mode 100644 index 0000000000000000000000000000000000000000..888c6605b2e46ea9f698f6bba7bcccbce496455b GIT binary patch literal 370205 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

?RXmLq&SVBtUc~y z;zI-%IHWIG*t#H|G+1;D>Te0&AHaC)Gz$h~`DjWf%#t#hbAl1p*@x|tu8_|@rKO}A z7M-P;r*tv6srb{n?EAro=cVjt39v+cz`(R6p65#QmNfM&i@Js64W>Qb#gIw`(XrTF zzE+*@vt;BU7G$^*(Q~JDzOXZK^`7*Ms^Cc0Dzf6QmU0xFpGid8W2R$h*%X*Bqk`my zi|L&XJnl?PLQNY~l%AEG(a;xlF2IP`%^ktqe1%8)AnN$-t$4`p5719AK;enF$3@2e z4Br3?PaP!%JrN!?q$7+Gs$< z>r26gvhzLP((?QV*Dpp`8I6^ga1J_NaWzPW0`Kq+Qx0tB!mlu4H;4y7X*0N5V|B~z zBK;C*)x4?@d_0<@6~=R6q$3t|Z^8w<;rl%_gwoMr7uwRk3d3u2-M^#E;3H&A@oe?4 zxl6yDgm3Oje@uAWhWHAJB^_+ibc*m7RjH(fx!H;udRdat_xi4!^;d;vi&A=xDSHO&~~;Gei{W53V5J8%?vtI!5$IxONs@OWe?vJ9S$g!{Mv00Vi*$3GK*- zBWpoZZ3o1ryE+kL{g)tT_f$x|jnIr5kGI$*DfMZvqzdnyNjZ!8151Nq>MTcuJGHd?ld4dPDEDY8+7x!Cs&iOv13KjKdly|rK0D|SD!G* z-bs*iHQ-&Mfagc;G>;musbNtMgL+c&=X3S~!v{OB(vI5tEr#DO|42#XDACmR=1SG_ z2SL%j)lB33{fSG*?UWe|#m4T#p*&(*tUf{q%0!VO1u|MPTn-K?K*)$f@4?9Z5Xg-l zENW?0fir}*x3L-9+CGK_`f=8q&GgDjOxd9+f`@=N)EmEY#1SN@KNdw~a067z%H9xC z%k(O0s_PDKskh6f+|0;mM4aL@3|(4P0sN_`NFgZ`@(Ex@$oY#IUe#~OB^zI`DFka? zZpG#hY>U?@0FmY_C9n}QSz5{I9TjYsxh)5JJPmEJXI&ja@?xQ{&9vVgD|G=Lz*Vrg zA2C(<09Oh6e-|tKDpUg8jsLp<`xy#^(}i=HE(sWgKhtpxrPV1n+$Uo~Jj=?+1}uEk z00}*RDsz#~z{1NgCS@KDKa4=pyuv(TbtwT+att23GXKuf6G+SJ7G&^6ERh5pb@!lw zZ*0d3>(lsoXJ&uW5uxhB?v-Zt5hWMTExu%|*Nuo&29NAo$H(J${OMB9jQQH(Y*QYj z_l?G{qQEYb(X?M`6SOSP`~+5_WQL>#Bk;k!gT-dEyIXqmJ9k3qpU7#+;DQKZy0;Iv zErrASZmIxy8FOW~uV1Z+X6z8W{cO8zN;sC_jkk4vL?q&^7KLxO z_tswWb6Y2Kx!OG{s5Z>AS!rdr9|L}FhG2VIh!iWcoTsly4|7ChUuj&I;R zz z!`H|7TY;T>vmn;paB0K1VY}~_iye<*LIdDGPQmx;xV!jupMoKDasxMyfg44piTA>| zB5GSF?YC8pn^}`yM8Ap8QylEA{bYPjiySWCKk~m)LFf_wFS{rJv;n3-rLd^PBIOxF zdTT?Ay5F27Kir(s#)6K&G8n!EzikB&|9F&8W5t678Sn|M^fM%ieH2IPxpMFHZ1e^` zy6*Y)Ei*h9n#Rmbf(Yf?5qMLVb9bPHC)t`tZ#wl9Qd%A)_OCad(>gS|? zR(RzPL@)#W3#OuvxwdSTR*q0!oksf zUMHa1@RufoVvOaRqzV9*^sL$!67`(aczMbsxX%*yS$Hxp*eW#Y6WZr)6 z9?+CHy8o~3kz#M<+V2F~hZ^$!Z`vHxpr0uubl*n|oc)3^x+4P=Uv3ayV7ipP16_F$`@PB_v$WWrBOu7&-> zdc@_xsNJpb#+fYR->;7@eX!t4G((*ipS8B_`S$4>CpGqnsi@u<-!o6;QbbL`I$ zLFyU_$Rpvw{(vlrEmoyjc$u)zNAg$#NPu*+VJruyF3L`~@ zgYaFfi6Rs4`s%p9gGc(PxGFmW0RI{Iv|Vj@I3Mj_fbIdQ+Ri^CC1$$MdpL@74`_)+ zfLw1B6#;?|HPT54xi(2qZMlsfxhlvIN1!l3(01{N?Y{Y9Ak5ThaF=6~S6s}G0~UoN z$R)I%@fGmEV`Ev9U8q=L;o$LpL6q;Nin5a40iB1aL>3|kq;(?!JoHop+P(dw9Z7DO z7!)L$OLzf*rDcC?7Rpzk3a4ZIBV*(#3nj=g4E`X!@?ps;R05FUDQ{^78(wCYPg|y7Q~S=CsSnEnLOwVs0Q# zA_R;6 z&eW(y#FnoIPy<<%o5rr&L87n#vBdQ#7)>k=$tw@JRt8ZJfyzM#*em6WsZY$z*(I7K zoc@UuKk?5dM?lM{-R|JgYNSEavoU5ex=S$s*4dT0XnB7%{g0((rB6!Jv$5!Nve=jm zoKrd_I=ff6q-VbrzT3|uLI4Gt-?=C;mHYskrpRW1wVcys9d$;pRE4V@Oqa;-k&<_e z1+=d5y*QlbDsV4)rXW6AQdloe{h|@6e*eZ|VT;Si%WHm&&flvJcf_VDT*9zfewmszu1%-ImuHW-sR?LS=BwHa9$fM9JscG}DcL$__ zSw6}0_Wk3ZT7*)3r|r@ze*Y#2MIylzVcjQYw3sc|(pE#spMZaV(6#7CiCH$~Zrx&) z>me_cAnrhIhXs~XfW^WUM@~`n9xn|&4kb{u5Tg~k>h597^By={Kn(b+qv+{;pj;y? zx~gE$sjB4c0PaN6Lh~II^eJlhoOsS8rU)H}Y2{>SSzu&$ILxo=F5zC^z21ICAuB!Z zJ}DEqWNgHkse7)5x~fnmWBAD4_a?+eVssq9=#)sevp1E7rK9^jlG_4T{x%5Rof{vR zog!e8^+|22*X#gOV&Y41NI&kYh@Yx1CbCWmM8G52`C^>KQIuH`qbzeN8{0d`G=*nj zMn7(xF7MF)VX+ebyD!93YyJfp&h(XovbOS_n3C$JyADRdn(B}7NhQYh>|=8uaJekJ zPePf$YPi^ho+w1kAwf-k<{(%H(&;%T8W$9zaa6#}t(NsYy;QLv)-qr6sM;$w&b&g7 zZ04=JdW%e@4~A#JC6jLekEe`@+!Sn>+k(6@T~A_+f9b(68%qrSdfjwRYyUjVO{FLwldHc19GPzE9p4XZaIF&)c!1q3>#Yu>;uO6mmq|sp%~2f>n$&=%d1gn> z5?XQ-i*TQa;ZuZ)Ukv@_+7XJ;$sZLoXh;|_qQu$-k!zzX)B^8(dcD+- zy|RRegz1{sg20}MlAtKv@C`i1AH$A`;kZ7VUcWx@kSN=qm#}pvHCrZv1d4`ODDxwH zG+}#o&tF9bkt|&lF;ABW`1#Z_Fu1$FaK5tfUlYegw?|PkEU+K=c&DGZS@ zYCbwDByBm%a{67rseN}ji}(XUqj%g}uRGpf4FM2+Uw_Inb?=CmR-_6K00E3BcP%G8 z(C7tj{_54%&c5cSA|-U^O}}Waeboh`zIo@pGq#9v#OMYADxuc(glDQm0G5z9!BU0c z)4brpTw1t35V%z+KIbcKK34=E=?AYWRLQ*(>Xi0sid8AS)U(|@8O-bNgk22;&XNwL z(F2V=GJhvog#;rSL$@V)XiU-4{`Qp0Ha|bIbGVy$Xf8BZmJ|sGP7OeT^`h-*uKLuV zAiARM5)Ms!16;Nuvw=$YIPG`1!4=dQ5edox;Nq%qYVnI*+ zQYd6>T%$7{-)XC~HZ_A~B|cakG`DaI()BU}TV9gh0?3^48>Zy?VlIN8lAQ!cEnbZZ zsv0I-c_u?oXN>ZW1|F`DZI|LtODyay#QA}d%0m=5fx70!ZW2+dUw(~ZhYF{6&b}Ij z=d-~Et>Kvo4btm(MGW=6XFNDHN8;1QT&QU&2%`cYf7RJE7QOo;rG7leH3RNO9EUT5 zg@EDYXYeSh%IcV}qh>vNNfker&iitQ(%P?RFRq}0(wA1G?yPr>BnIBp-D6V#Nz)=Q z_FoK>3;{_t@@>*)&(37od}a!?%8nn4WO>EPD^ik}nu}(7AVJ-sc~{TNBtZ}<-n_*I zM8@xI0=p5qs1To^?U|;$4~Gl^ry!%5arDxIA@UI(Wuq6tU2{4Rg?x4;#2728^oQ<)SLAGA506#Lc33_A>Jf7a#~lfw%)5zqFjy-;}m|kyNcj?RC zKoDWg3D`nM+iGv9N|Wa_5+xsVtVQ|MPy%LlWxd`vX&~P7|5P!W0Y|y2Suq%~U+)XU zkNo^H%Yv4wqQcQDMG>IzdWY$K1M@MGH480V2wj0f0q+6*>(`X&JHfxU6mRv{kEmJQ6dpuIiBgJK zjFY*Z$p`$n&;}IZ6b6pN(j@L-xHzWHj`5FYQ1XgKXri{FbZ^HH6E8Y$b{;>~I#iF> zQZ=s@ZRXxn$ZHj~z8VgD)%=mi&aO36F1)Lz-=1t|fg@Bod^W*X_40r`GLQHAveX5fs2@Ei~2qQNg; zgf3ocDJcB_u&1=G(cUAsOHqkjRaMja6Zg$Z=5);pa4sD$E⁡LI^TdXmJV9-zg0| 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�FYu10 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

Rnnk1|~G?bo-5-muc?uzQr()rX~zXeZnLB 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 z%0DD;hqeU`BdPx(QP~XPo!3OT= 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 A2mk;8 literal 0 HcmV?d00001 diff --git a/docs/source/_static/mml_overview.svg b/docs/source/_static/mml_overview.svg new file mode 100644 index 0000000..79ed8ba --- /dev/null +++ b/docs/source/_static/mml_overview.svg @@ -0,0 +1,1161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MML initialization + MML runtime + + + + + + + + + + + + + __main__.wrapped_main + mml.core.scripts.base_scheduler. AbstractBaseScheduler + mml.core.data_loading.file_manager. MMLFileManager + mml.core.data_loading.task_struct. TaskStruct + __init__ + __init__ + run + __init__ + create_routine + + (optional) after_preparation_hook + + (optional) before_finishing_hook + concrete scheduler class + + + mml_main + @hydra.main + - (optional) continue logic- (optional) best params logic- intantiate scheduler- run scheduler- return value from run + - acquire run dir lock- create MMLFileManager- resolve task_list and pivot- create TaskStructFactory- create full schedule- write "scheduler_plan.txt"- if continue: update schedule- run generic checks + - loop over schedule: - always first: prepare_exp - always last: finish_exp - seed - run command - update status_log- return self.return_value + - should call super().__init__ first- additional custom definitions + custom logic to define each step of the schedule, extends both self.command and self.params with custom scheduler methodsbased on self.subroutines and potential other config options + + + prepare_exp + - if continue: load old tasks- else create task structs- after_preparation_hook() + + finish_exp + - before_finishing_hook()- remove intermediates- delete MMLFileManager- delete "schedule_plan.txt" + + custom processing step + defines a step as part of the processing of this scheduler, a step marks an "atomic" actionand is the finest granularity to use the continue functionality, except for model training, whichis restored on epoch granularity;may use the many convenience functions of the base scheduler to access or create common corecore objects + - create various run subdirs- scan for existing tasks data- import path assignments- find reusables + + remove_intermediates + based on path assignments and reuse.clean_up config removes stored files + + construct_saving_path + should be used to create ANY path for files + - loads and compiles config- set logging handlers- (optional) multirun loops + - load env variables- load mml plugins- set search path for configs + + + + + + + + + - lightweight representation of a task- attach persistent information either inside paths or models (these will be recovered in continue mode)- created and contained in scheduler's TaskStructFactory- access inside scheduler via self.get_struct(task_name) + + other processing step + some different processing step... + ... + + diff --git a/docs/source/_static/old_mml_favicon.ico b/docs/source/_static/old_mml_favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8ef220458ed4e7cbd93ab9599b462adc59521122 GIT binary patch literal 1581 zcmV+|2GaS7P)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H11-eN@ zK~z|U?U!FnROuOqpYP0>GXo5R1GqEFI=E!5aZ{?nSQ^}SielF7-L@BM!7bKdVg?_`vS*nq}c(pyXXe}Fdv5RFD@Z*M0Wjs9>G5wYbpG(9~n zLqkJSS63%WDap>x7NwM&K7Cp&%X%Fv5fOQ1fQg9-IePS{XqqN~1cO28>FE*2aiqJu zTLOWAl$V#w*|TS*udnaT0wj}3IdI^B?Ay0b9zJ|1Po6xH;o;$RF`b>AQdd_e2M-<; zm&+wBEiG>j;K73j;`MrEe0)6hT~}9^R99C^adEL!R8&Y?TU%=F%9Sf(7>2}Rv9thb zo3Nv!gEME&pp@d)ty_o)y}i90IdX(RAV5Py1G{(c=G3WET)uo6(=-_x8p1S9s;a8! z?d|>HP59{1BQXp^8XFts(xpq{_xq)(sYz_xmXVQ>b+H2j0}_cuq@|@r3JVM6#*G_N zS63&2KtP^9f4*S_HU(&CXpm#aj-~F~+SjMBhefpHESFbWTIY}%Qqo=2bojZ3j zHa3=evP2?*$KwIO<#JI}R75x&rlh2V`uchb3JNwR-K+;hL^?V;q^71uqS2`I_xDRU z92OCg%F0T)efzf9wk@GhNQQ@prM0zHYHDgWv-^(HzJ?brT;S%-o9x}Ym$I@lg2CXr zbxqUOU1w%y=U9kIu7d8=?4 z8p|pJL)xY9cU!lx@4cRMyc&Is(b7;BQh~uC#JYZS) zfA?!9CMF1lLIC)DzElFG6z%Qp^z`&_{``3=D=WEo@80)T#!B45UTH(Qwu1H!IB`U# z(LGh@T23bD8fXeM-DvMd@K8`l{trP#G=7qM83+S=L; zk49!K{)-vzk);( zB;&tDoOxVEDYp3tO)tWo+3*rT5~h~8`xz*OGZ)A6%M$eWx34oMJ{kLzEIk89Y*rl;UDN3p=}wy*zBPz8Qe<+O7x5&f9mnr=F%dUewS=*`1QhxK z=$nqPH6s^W94yObF}Z|CGgvU=_zmBt{%I=^^ck48L)^5<@x0{S;??=-4*yzAMjrF# zB6*%I%$bWAnw#RhAEizHN&pAm&1PG+!HygcC`j7EyEz6~#@f~ox9w+(;m2_4cr*iD z(+OqdZ{oV9S8Br96^lO(OcC_C8DB6tRT3oI<4UdDV)JBnkS}JwB;Omr@AmPt;NCX} f@W0es|8MvoeYW0~RhPRU00000NkvXXu0mjf30?g8 literal 0 HcmV?d00001 diff --git a/docs/source/_static/tensorboard_example.png b/docs/source/_static/tensorboard_example.png new file mode 100644 index 0000000000000000000000000000000000000000..4033758e7329ee2a690cfd94c755032416aa3300 GIT binary patch literal 154212 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 Xg0POJD{-TWGjVxYVZixgjQ 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 Am6)a> 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 z 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 vPZuHo^kmObTChO`_ + * `kornia `_ + * `torchvision `_ + +The basic idea is that ``mml`` deals with all underlying details of loading, precision, device movement etc. As a user +one may use any (or even multiple!) of the libraries above and describe the sequence of desired transformations as part +of the configuration file. + +The general flow is as follows: + + * image, mask, etc. are read by their respective :class:`~mml.core.data_loading.modality_loaders.ModalityLoader` + * if preprocessing is performed (aka a preprocessing pipeline is part of the config AND the data has not yet been preprocessed): + + * the respective composed preprocessing pipeline is performed on a per sample basis on the CPU + * WARNING: consider preprocessing the dataset for improved efficiency, see :doc:`/modes` + + * if the config contains CPU augmentations these are applied as well on a per sample basis + * afterwards samples are turned into float precision objects and moved to the device determined by config + * if the config contains GPU augmentations these are applied on a batch level + * the last augmentation performed will be the normalization (if requested by config) + +Certain limitations apply: + * preprocessing is only supported for the albumentations library + * albumentations is only supported on CPU + * kornia is only supported on GPU + +Multiple examples can be found in the ``src/mml/configs/augmentations`` folder (and ``src/mml/configs/preprocessing``). + +Furthermore :mod:`~mml.core.data_loading.augmentations.mixup_cutmix` offers some lightning callbacks to perform CutMix +and MixUp during batch collation. In contrast to the torchvision/kornia versions of these those callbacks support +multi-task. + +.. toctree:: + :hidden: + :maxdepth: 1 + + albumentations + augmentation_module + kornia + mixup_cutmix + torchvision \ No newline at end of file diff --git a/docs/source/api/core/data_loading/augmentations/torchvision.rst b/docs/source/api/core/data_loading/augmentations/torchvision.rst new file mode 100644 index 0000000..8c222fc --- /dev/null +++ b/docs/source/api/core/data_loading/augmentations/torchvision.rst @@ -0,0 +1,7 @@ +mml.core.data\_loading.augmentations.torchvision +========================================================= + +.. automodule:: mml.core.data_loading.augmentations.torchvision + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/source/api/core/data_loading/file_manager.rst b/docs/source/api/core/data_loading/file_manager.rst new file mode 100644 index 0000000..24b2937 --- /dev/null +++ b/docs/source/api/core/data_loading/file_manager.rst @@ -0,0 +1,7 @@ +mml.core.data\_loading.file\_manager +==================================== + +.. automodule:: mml.core.data_loading.file_manager + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/source/api/core/data_loading/lightning_datamodule.rst b/docs/source/api/core/data_loading/lightning_datamodule.rst new file mode 100644 index 0000000..726fb73 --- /dev/null +++ b/docs/source/api/core/data_loading/lightning_datamodule.rst @@ -0,0 +1,7 @@ +mml.core.data\_loading.lightning\_datamodule +============================================ + +.. automodule:: mml.core.data_loading.lightning_datamodule + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/data_loading/modality_loaders.rst b/docs/source/api/core/data_loading/modality_loaders.rst new file mode 100644 index 0000000..05e2b0f --- /dev/null +++ b/docs/source/api/core/data_loading/modality_loaders.rst @@ -0,0 +1,7 @@ +mml.core.data\_loading.modality\_loaders +======================================== + +.. automodule:: mml.core.data_loading.modality_loaders + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/data_loading/overview.rst b/docs/source/api/core/data_loading/overview.rst new file mode 100644 index 0000000..b9c0cde --- /dev/null +++ b/docs/source/api/core/data_loading/overview.rst @@ -0,0 +1,32 @@ +mml.core.data\_loading +====================== + +``mml.core.data_loading`` deals with all file and data operations except for the initial data integration part, +which is dealt with in :doc:`../data_preparation/overview`. + +Data loading from a task is layered in three: + * :class:`~mml.core.data_loading.task_struct.TaskStruct` holds only lightweight meta information of a task + * :class:`~mml.core.data_loading.task_dataset.TaskDataset` implements mechanics to use the task description file and load individual samples + * :class:`~mml.core.data_loading.lightning_datamodule.MultiTaskDataModule` holds different splits of (potentially) multiple task, deals with transforms and provides the dataloaders + +Furthermore :mod:`~mml.core.data_loading.file_manager` holds the central :class:`~mml.core.data_loading.file_manager.MMLFileManager`. +:mod:`~mml.core.data_loading.augmentations` deals with data augmentations. +:mod:`~mml.core.data_loading.task_attributes` declares task meta information +formats as they are needed by the central :mod:`~mml.core.data_loading.task_description`. +:mod:`~mml.core.data_loading.modality_loaders` implement the reading operations for different +:class:`~mml.core.data_loading.task_attributes.Modality`'s. Lastly +:mod:`~mml.core.data_loading.utils` holds a small number of utility functions for data transformations. + +.. toctree:: + :hidden: + :maxdepth: 1 + + augmentations/overview + file_manager + lightning_datamodule + modality_loaders + task_attributes + task_dataset + task_struct + task_description + utils diff --git a/docs/source/api/core/data_loading/task_attributes.rst b/docs/source/api/core/data_loading/task_attributes.rst new file mode 100644 index 0000000..e814ee6 --- /dev/null +++ b/docs/source/api/core/data_loading/task_attributes.rst @@ -0,0 +1,7 @@ +mml.core.data\_loading.task\_attributes +======================================= + +.. automodule:: mml.core.data_loading.task_attributes + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/data_loading/task_dataset.rst b/docs/source/api/core/data_loading/task_dataset.rst new file mode 100644 index 0000000..7366af1 --- /dev/null +++ b/docs/source/api/core/data_loading/task_dataset.rst @@ -0,0 +1,7 @@ +mml.core.data\_loading.task\_dataset +==================================== + +.. automodule:: mml.core.data_loading.task_dataset + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/data_loading/task_description.rst b/docs/source/api/core/data_loading/task_description.rst new file mode 100644 index 0000000..0f40152 --- /dev/null +++ b/docs/source/api/core/data_loading/task_description.rst @@ -0,0 +1,7 @@ +mml.core.data\_loading.task_description +======================================= + +.. automodule:: mml.core.data_loading.task_description + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/data_loading/task_struct.rst b/docs/source/api/core/data_loading/task_struct.rst new file mode 100644 index 0000000..eeb0624 --- /dev/null +++ b/docs/source/api/core/data_loading/task_struct.rst @@ -0,0 +1,7 @@ +mml.core.data\_loading.task\_struct +=================================== + +.. automodule:: mml.core.data_loading.task_struct + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/data_loading/utils.rst b/docs/source/api/core/data_loading/utils.rst new file mode 100644 index 0000000..f360e8d --- /dev/null +++ b/docs/source/api/core/data_loading/utils.rst @@ -0,0 +1,7 @@ +mml.core.data\_loading.utils +============================ + +.. automodule:: mml.core.data_loading.utils + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/source/api/core/data_preparation/archive_extractors.rst b/docs/source/api/core/data_preparation/archive_extractors.rst new file mode 100644 index 0000000..724241b --- /dev/null +++ b/docs/source/api/core/data_preparation/archive_extractors.rst @@ -0,0 +1,7 @@ +mml.core.data\_preparation.archive\_extractors +============================================== + +.. automodule:: mml.core.data_preparation.archive_extractors + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/source/api/core/data_preparation/data_archive.rst b/docs/source/api/core/data_preparation/data_archive.rst new file mode 100644 index 0000000..2ebc16d --- /dev/null +++ b/docs/source/api/core/data_preparation/data_archive.rst @@ -0,0 +1,7 @@ +mml.core.data\_preparation.data\_archive +======================================== + +.. automodule:: mml.core.data_preparation.data_archive + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/data_preparation/dset_creator.rst b/docs/source/api/core/data_preparation/dset_creator.rst new file mode 100644 index 0000000..ba70f9b --- /dev/null +++ b/docs/source/api/core/data_preparation/dset_creator.rst @@ -0,0 +1,7 @@ +mml.core.data\_preparation.dset\_creator +======================================== + +.. automodule:: mml.core.data_preparation.dset_creator + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/source/api/core/data_preparation/fake_task.rst b/docs/source/api/core/data_preparation/fake_task.rst new file mode 100644 index 0000000..d9c85a6 --- /dev/null +++ b/docs/source/api/core/data_preparation/fake_task.rst @@ -0,0 +1,7 @@ +mml.core.data\_preparation.fake\_task +===================================== + +.. automodule:: mml.core.data_preparation.fake_task + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/source/api/core/data_preparation/overview.rst b/docs/source/api/core/data_preparation/overview.rst new file mode 100644 index 0000000..b7f73f4 --- /dev/null +++ b/docs/source/api/core/data_preparation/overview.rst @@ -0,0 +1,36 @@ +mml.core.data\_preparation +========================== + +``mml.core.data_preparation`` deals with the initial data integration part, for more general runtime data loading see +which is dealt with in :doc:`../data_loading/overview`. + +The two core components of integrating a task into ``mml`` are + * :class:`~mml.core.data_preparation.dset_creator.DSetCreator` to virtually arrange data at the right place + * :class:`~mml.core.data_preparation.task_creator.TaskCreator` to aggregate full task description into a ``.json`` file + +The splitting of these two concepts has the following advantages: + * large files like images and masks are only stored once even if multiple tasks share the same files + * support of multiple kind of tasks on the same data + * capabilities to easily modify task descriptions without touching underlying data + +The modules :mod:`~mml.core.data_preparation.dset_creator` and :mod:`~mml.core.data_preparation.task_creator` hold +the respective classes. :mod:`~mml.core.data_preparation.fake_task` is a simple instantiation of those, +that can be used during testing. The :mod:`~mml.core.data_preparation.registry` is the central spot to administrate +all :class:`~mml.core.data_preparation.dset_creator.DSetCreator`s and :class:`~mml.core.data_preparation.task_creator.TaskCreator`s. +:mod:`~mml.core.data_preparation.data_archive` provides the capability to describe and arrange raw datasets, as e.g. +to be downloaded from the web. The :mod:`~mml.core.data_preparation.archive_extractors` add support for unpacking +archives as ``zip`` or ``rar``. +Finally :class:`~mml.core.data_preparation.task_creator.utils` holds a bunch of convenience functions to be used while +creating tasks. + +.. toctree:: + :hidden: + :maxdepth: 1 + + dset_creator + data_archive + archive_extractors + fake_task + registry + task_creator + utils diff --git a/docs/source/api/core/data_preparation/registry.rst b/docs/source/api/core/data_preparation/registry.rst new file mode 100644 index 0000000..036c926 --- /dev/null +++ b/docs/source/api/core/data_preparation/registry.rst @@ -0,0 +1,7 @@ +mml.core.data\_preparation.registry +=================================== + +.. automodule:: mml.core.data_preparation.registry + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/source/api/core/data_preparation/task_creator.rst b/docs/source/api/core/data_preparation/task_creator.rst new file mode 100644 index 0000000..04ee1ac --- /dev/null +++ b/docs/source/api/core/data_preparation/task_creator.rst @@ -0,0 +1,7 @@ +mml.core.data\_preparation.task\_creator +======================================== + +.. automodule:: mml.core.data_preparation.task_creator + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/source/api/core/data_preparation/utils.rst b/docs/source/api/core/data_preparation/utils.rst new file mode 100644 index 0000000..d06f96c --- /dev/null +++ b/docs/source/api/core/data_preparation/utils.rst @@ -0,0 +1,7 @@ +mml.core.data\_preparation.utils +================================ + +.. automodule:: mml.core.data_preparation.utils + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/source/api/core/models/lightning_single_frame.rst b/docs/source/api/core/models/lightning_single_frame.rst new file mode 100644 index 0000000..e2e8771 --- /dev/null +++ b/docs/source/api/core/models/lightning_single_frame.rst @@ -0,0 +1,7 @@ +mml.core.models.lightning\_single\_frame +======================================== + +.. automodule:: mml.core.models.lightning_single_frame + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/models/overview.rst b/docs/source/api/core/models/overview.rst new file mode 100644 index 0000000..432f7d2 --- /dev/null +++ b/docs/source/api/core/models/overview.rst @@ -0,0 +1,22 @@ +mml.core.models +=============== + +``MML`` abstracts it's models into underlying :mod:`torch` models and overlaying :mod:`lightning` models. The ``torch`` +model encapsulates the network description while the ``lightning`` wrapper controls loss computation, +optimizer, metrics and logging. + +This allows very simple extensions via adding new ``torch`` models and wrapping those with the same ``lightning`` +module. Two examples for very flexible ``torch`` models are the :mod:`~mml.core.models.timm` and +:mod:`~mml.core.models.smp` models that build upon the :mod:`timm` library and the :mod:`pytorch_segmentation_models` +library respectively. So far only ``single frame`` tasks are supported by the +:mod:`~mml.core.models.lightning_single_frame` ``lightning wrapper`` but video clip support is planned. + + +.. toctree:: + :hidden: + :maxdepth: 1 + + torch_base + timm + smp + lightning_single_frame diff --git a/docs/source/api/core/models/smp.rst b/docs/source/api/core/models/smp.rst new file mode 100644 index 0000000..1cf8001 --- /dev/null +++ b/docs/source/api/core/models/smp.rst @@ -0,0 +1,7 @@ +mml.core.models.smp +=================== + +.. automodule:: mml.core.models.smp + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/models/timm.rst b/docs/source/api/core/models/timm.rst new file mode 100644 index 0000000..82edf4d --- /dev/null +++ b/docs/source/api/core/models/timm.rst @@ -0,0 +1,7 @@ +mml.core.models.timm +==================== + +.. automodule:: mml.core.models.timm + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/models/torch_base.rst b/docs/source/api/core/models/torch_base.rst new file mode 100644 index 0000000..5c2ffc8 --- /dev/null +++ b/docs/source/api/core/models/torch_base.rst @@ -0,0 +1,7 @@ +mml.core.models.torch\_base +=========================== + +.. automodule:: mml.core.models.torch_base + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/scripts/callbacks.rst b/docs/source/api/core/scripts/callbacks.rst new file mode 100644 index 0000000..e721506 --- /dev/null +++ b/docs/source/api/core/scripts/callbacks.rst @@ -0,0 +1,7 @@ +mml.core.scripts.callbacks +========================== + +.. automodule:: mml.core.scripts.callbacks + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/scripts/decorators.rst b/docs/source/api/core/scripts/decorators.rst new file mode 100644 index 0000000..64ed9ee --- /dev/null +++ b/docs/source/api/core/scripts/decorators.rst @@ -0,0 +1,7 @@ +mml.core.scripts.decorators +=========================== + +.. automodule:: mml.core.scripts.decorators + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/scripts/exceptions.rst b/docs/source/api/core/scripts/exceptions.rst new file mode 100644 index 0000000..bb8ef74 --- /dev/null +++ b/docs/source/api/core/scripts/exceptions.rst @@ -0,0 +1,7 @@ +mml.core.scripts.exceptions +=========================== + +.. automodule:: mml.core.scripts.exceptions + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/scripts/model_storage.rst b/docs/source/api/core/scripts/model_storage.rst new file mode 100644 index 0000000..2805a18 --- /dev/null +++ b/docs/source/api/core/scripts/model_storage.rst @@ -0,0 +1,7 @@ +mml.core.scripts.model\_storage +=============================== + +.. automodule:: mml.core.scripts.model_storage + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/scripts/notifier.rst b/docs/source/api/core/scripts/notifier.rst new file mode 100644 index 0000000..74f43a0 --- /dev/null +++ b/docs/source/api/core/scripts/notifier.rst @@ -0,0 +1,7 @@ +mml.core.scripts.notifier +========================= + +.. automodule:: mml.core.scripts.notifier + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/scripts/overview.rst b/docs/source/api/core/scripts/overview.rst new file mode 100644 index 0000000..031deca --- /dev/null +++ b/docs/source/api/core/scripts/overview.rst @@ -0,0 +1,43 @@ +mml.core.scripts +================ + +The ``scripts`` sub-module of ``MML`` focuses on the data processing. It's core is the +:class:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler` that provides all internal routing, logging, +object holding as well as common methods to ease objects creation. Developers can inherit from it and quickly write +new schedulers for their use case. The following inherited schedulers are shipped with ``mml-core``: + + * :class:`~mml.core.scripts.schedulers.info_scheduler.InfoScheduler` - provides basic information on ``mml``, available tasks and hyperparameter searches + * :class:`~mml.core.scripts.schedulers.create_scheduler.CreateScheduler` - allows to automatically create (and integrate) data of new tasks + * :class:`~mml.core.scripts.schedulers.preprocess_scheduler.PreprocessScheduler` - preprocess tasks once to speed up training + * :class:`~mml.core.scripts.schedulers.train_scheduler.TrainingScheduler` - single task training, cross-fold validation, generate predictions + +Some ``MML`` plugins ship their own schedulers with them. In addition this sub-module holds: + + * :doc:`callbacks` - some useful ``lightning`` callback implementations + * :doc:`decorators` - some useful decorators + * :doc:`exceptions` - exceptions defined by ``mml`` + * :doc:`notifier` - a notification system for ``mml`` monitoring + * :doc:`model_storage` - a container to hold all relevant information of a trained model + * :doc:`pipeline_configuration` - a container to encapsulate a training pipeline + * :doc:`utils` - a bunch of useful stuff + + +.. toctree:: + :hidden: + :maxdepth: 1 + + schedulers/base_scheduler + schedulers/info_scheduler + schedulers/create_scheduler + schedulers/preprocess_scheduler + schedulers/train_scheduler + schedulers/transfer_scheduler + schedulers/clean_scheduler + schedulers/upgrade_scheduler + callbacks + decorators + exceptions + model_storage + notifier + pipeline_configuration + utils diff --git a/docs/source/api/core/scripts/pipeline_configuration.rst b/docs/source/api/core/scripts/pipeline_configuration.rst new file mode 100644 index 0000000..3b851d1 --- /dev/null +++ b/docs/source/api/core/scripts/pipeline_configuration.rst @@ -0,0 +1,7 @@ +mml.core.scripts.pipeline\_configuration +======================================== + +.. automodule:: mml.core.scripts.pipeline_configuration + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/scripts/schedulers/base_scheduler.rst b/docs/source/api/core/scripts/schedulers/base_scheduler.rst new file mode 100644 index 0000000..8223202 --- /dev/null +++ b/docs/source/api/core/scripts/schedulers/base_scheduler.rst @@ -0,0 +1,7 @@ +mml.core.scripts.schedulers.base\_scheduler +=========================================== + +.. automodule:: mml.core.scripts.schedulers.base_scheduler + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/scripts/schedulers/clean_scheduler.rst b/docs/source/api/core/scripts/schedulers/clean_scheduler.rst new file mode 100644 index 0000000..a13323a --- /dev/null +++ b/docs/source/api/core/scripts/schedulers/clean_scheduler.rst @@ -0,0 +1,6 @@ +mml.core.scripts.schedulers.clean\_scheduler +============================================ + +.. automodule:: mml.core.scripts.schedulers.clean_scheduler + :members: + :undoc-members: diff --git a/docs/source/api/core/scripts/schedulers/create_scheduler.rst b/docs/source/api/core/scripts/schedulers/create_scheduler.rst new file mode 100644 index 0000000..34b41ac --- /dev/null +++ b/docs/source/api/core/scripts/schedulers/create_scheduler.rst @@ -0,0 +1,6 @@ +mml.core.scripts.schedulers.create\_scheduler +============================================= + +.. automodule:: mml.core.scripts.schedulers.create_scheduler + :members: + :undoc-members: diff --git a/docs/source/api/core/scripts/schedulers/info_scheduler.rst b/docs/source/api/core/scripts/schedulers/info_scheduler.rst new file mode 100644 index 0000000..f68da7f --- /dev/null +++ b/docs/source/api/core/scripts/schedulers/info_scheduler.rst @@ -0,0 +1,6 @@ +mml.core.scripts.schedulers.info\_scheduler +=========================================== + +.. automodule:: mml.core.scripts.schedulers.info_scheduler + :members: + :undoc-members: diff --git a/docs/source/api/core/scripts/schedulers/preprocess_scheduler.rst b/docs/source/api/core/scripts/schedulers/preprocess_scheduler.rst new file mode 100644 index 0000000..3a7d429 --- /dev/null +++ b/docs/source/api/core/scripts/schedulers/preprocess_scheduler.rst @@ -0,0 +1,6 @@ +mml.core.scripts.schedulers.preprocess\_scheduler +================================================= + +.. automodule:: mml.core.scripts.schedulers.preprocess_scheduler + :members: + :undoc-members: diff --git a/docs/source/api/core/scripts/schedulers/train_scheduler.rst b/docs/source/api/core/scripts/schedulers/train_scheduler.rst new file mode 100644 index 0000000..028287a --- /dev/null +++ b/docs/source/api/core/scripts/schedulers/train_scheduler.rst @@ -0,0 +1,6 @@ +mml.core.scripts.schedulers.train\_scheduler +============================================ + +.. automodule:: mml.core.scripts.schedulers.train_scheduler + :members: + :undoc-members: diff --git a/docs/source/api/core/scripts/schedulers/transfer_scheduler.rst b/docs/source/api/core/scripts/schedulers/transfer_scheduler.rst new file mode 100644 index 0000000..b83e840 --- /dev/null +++ b/docs/source/api/core/scripts/schedulers/transfer_scheduler.rst @@ -0,0 +1,6 @@ +mml.core.scripts.schedulers.transfer\_scheduler +=============================================== + +.. automodule:: mml.core.scripts.schedulers.transfer_scheduler + :members: + :undoc-members: diff --git a/docs/source/api/core/scripts/schedulers/upgrade_scheduler.rst b/docs/source/api/core/scripts/schedulers/upgrade_scheduler.rst new file mode 100644 index 0000000..c4c3500 --- /dev/null +++ b/docs/source/api/core/scripts/schedulers/upgrade_scheduler.rst @@ -0,0 +1,6 @@ +mml.core.scripts.schedulers.upgrade\_scheduler +============================================== + +.. automodule:: mml.core.scripts.schedulers.upgrade_scheduler + :members: + :undoc-members: diff --git a/docs/source/api/core/scripts/utils.rst b/docs/source/api/core/scripts/utils.rst new file mode 100644 index 0000000..edbf3e4 --- /dev/null +++ b/docs/source/api/core/scripts/utils.rst @@ -0,0 +1,7 @@ +mml.core.scripts.utils +====================== + +.. automodule:: mml.core.scripts.utils + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/visualization/cm.rst b/docs/source/api/core/visualization/cm.rst new file mode 100644 index 0000000..77db0d0 --- /dev/null +++ b/docs/source/api/core/visualization/cm.rst @@ -0,0 +1,7 @@ +mml.core.visualization.cm +========================= + +.. automodule:: mml.core.visualization.cm + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/visualization/logo.rst b/docs/source/api/core/visualization/logo.rst new file mode 100644 index 0000000..52cc648 --- /dev/null +++ b/docs/source/api/core/visualization/logo.rst @@ -0,0 +1,8 @@ +mml.core.visualization.logo +=========================== + +.. automodule:: mml.core.visualization.logo + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/source/api/core/visualization/overview.rst b/docs/source/api/core/visualization/overview.rst new file mode 100644 index 0000000..50bd6ed --- /dev/null +++ b/docs/source/api/core/visualization/overview.rst @@ -0,0 +1,21 @@ +mml.core.visualization +====================== + +``MML`` gives some visualization options for tasks and image examples. Be aware that for the training visualization +(e.g. metrics) the corresponding ``exp_logger`` is responsible (default: ``tensorboard``). This sub-module is less +advanced and welcomes any contributions. + + + * :doc:`cm` - visualize a confusion matrix + * :doc:`predictions` - visualize samples images from a task + * :doc:`logo` - ``MML`` logo for the terminal + * :doc:`utils` - visualization utils + +.. toctree:: + :hidden: + :maxdepth: 1 + + cm + predictions + logo + utils diff --git a/docs/source/api/core/visualization/predictions.rst b/docs/source/api/core/visualization/predictions.rst new file mode 100644 index 0000000..cf45507 --- /dev/null +++ b/docs/source/api/core/visualization/predictions.rst @@ -0,0 +1,7 @@ +mml.core.visualization.predictions +================================== + +.. automodule:: mml.core.visualization.predictions + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/core/visualization/utils.rst b/docs/source/api/core/visualization/utils.rst new file mode 100644 index 0000000..03c7206 --- /dev/null +++ b/docs/source/api/core/visualization/utils.rst @@ -0,0 +1,7 @@ +mml.core.visualization.utils +============================ + +.. automodule:: mml.core.visualization.utils + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/interactive.rst b/docs/source/api/interactive.rst new file mode 100644 index 0000000..7a780d7 --- /dev/null +++ b/docs/source/api/interactive.rst @@ -0,0 +1,7 @@ +mml.interactive +=============== + +.. automodule:: mml.interactive + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/overview.rst b/docs/source/api/overview.rst new file mode 100644 index 0000000..fb55258 --- /dev/null +++ b/docs/source/api/overview.rst @@ -0,0 +1,35 @@ +mml-core API +============ + +The ``mml-core`` package makes up the core functionality of ``MML`` and implements the scaffold to operate it. + +``mml-core`` is split into 5 sub-packages: + + * :doc:`api` - which serves as fast external api access with some bonus convenience functions to use ``mml`` interactively + * :doc:`mml.configs <../cli/overview>` - which is the reference of config groups and provides the necessary ``.yaml`` files + * ``core`` - which is the actual core source code, it splits itself into 5 sub-packages + + * :doc:`core/data_loading/overview` - all code to load, transform, store and represent data internally + * :doc:`core/data_preparation/overview` - all code to integrate external data into the ``mml`` framework + * :doc:`core/models/overview` - all code with respect to deep neural networks functionality + * :doc:`core/scripts/overview` - basically the ``scheduler`` mechanics of ``mml`` + * :doc:`core/visualization/overview` - code to visualize results + + * :doc:`interactive` - which provides additional convenience classes to plan, process and visualize ``mml`` experiments + * :doc:`testing` - which supports testing ``mml-core`` and ``mml`` :doc:`../plugins` + +Furthermore there is the :doc:`cli` module to streamline command line interface access. + +.. toctree:: + :hidden: + :maxdepth: 1 + + api + cli + core/data_loading/overview + core/data_preparation/overview + core/models/overview + core/scripts/overview + core/visualization/overview + interactive + testing diff --git a/docs/source/api/plugins/data.rst b/docs/source/api/plugins/data.rst new file mode 100644 index 0000000..abd95e2 --- /dev/null +++ b/docs/source/api/plugins/data.rst @@ -0,0 +1,17 @@ +mml-data plugin +=============== + +The ``mml-data`` plugin enables the availability to use a set of pre-defined tasks. Install via + +.. code-block:: bash + + pip install mml-data --index-url https://__token__:@git.dkfz.de/api/v4/projects/89/packages/pypi/simple + +Afterwards you may call ``mml-data`` from the terminal to receive a report of available tasks and datasets. Run +``mml-data --help`` for more details. + +You may now use the defined task creators simply to create the corresponding tasks locally via: + +.. code-block:: bash + + mml create task_list=[...] \ No newline at end of file diff --git a/docs/source/api/plugins/dimensionality.rst b/docs/source/api/plugins/dimensionality.rst new file mode 100644 index 0000000..eaf6660 --- /dev/null +++ b/docs/source/api/plugins/dimensionality.rst @@ -0,0 +1,6 @@ +mml-dimensionality plugin +========================= + +Compute approximate dimension of task manifolds. Based on "The Intrinsic Dimensionaity of Images and Its Impact On +Learning" by Phillip Pope, Chen Zhu, Ahmed Abdelkader, Micah Goldblum, Tom Goldstein (ICLR 2021, spotlight). See their +code: https://github.com/ppope/dimensions \ No newline at end of file diff --git a/docs/source/api/plugins/drive.rst b/docs/source/api/plugins/drive.rst new file mode 100644 index 0000000..a6424f9 --- /dev/null +++ b/docs/source/api/plugins/drive.rst @@ -0,0 +1,8 @@ +mml-drive plugin +================ + +Features for DKFZ-LSF in combination with ``MML``. Currently supports: + +- derive number of workers by host (does not interfere with local host settings) +- plan :class:`~mml.interactive.planning.MMLJobDescription` accordingly with ``LSFSubmissionRequirements`` +- submit jobs from notebooks leveraging ``LSFJobRunner`` diff --git a/docs/source/api/plugins/lsf.rst b/docs/source/api/plugins/lsf.rst new file mode 100644 index 0000000..d9c4bd2 --- /dev/null +++ b/docs/source/api/plugins/lsf.rst @@ -0,0 +1,8 @@ +mml-lsf plugin +============== + +Features for (DKFZ-)LSF in combination with ``MML``. Currently supports: + +- derive number of workers by host (does not interfere with local host settings) +- plan :class:`~mml.interactive.planning.MMLJobDescription` accordingly with ``LSFSubmissionRequirements`` +- submit jobs from notebooks leveraging ``LSFJobRunner`` diff --git a/docs/source/api/plugins/overview.rst b/docs/source/api/plugins/overview.rst new file mode 100644 index 0000000..c5cef30 --- /dev/null +++ b/docs/source/api/plugins/overview.rst @@ -0,0 +1,28 @@ +plugins +======= + +The following is a comprehensive list of official ``mml`` plugins. + + * :doc:`data` - with quite a bunch of :class:`~mml.core.data_preparation.task_creator.TaskCreator` s + * :doc:`sql` - enable hyperparameter tuning through an sql database + * :doc:`dimensionality` - estimate complexity of a task + * :doc:`similarity` - estimate knowledge transfer between any two tasks + * :doc:`tags` - a collection of task tags, used to customize tasks + * :doc:`suggest` - compile learning pipelines from previous knowledge + * :doc:`lsf` - methods to interact with an LSF managed compute cluster + * :doc:`drive` - share downloaded files within a local network through a network drive + + +.. toctree:: + :hidden: + :maxdepth: 1 + :caption: Plugin References + + data + dimensionality + drive + lsf + similarity + sql + suggest + tags diff --git a/docs/source/api/plugins/similarity.rst b/docs/source/api/plugins/similarity.rst new file mode 100644 index 0000000..11450a7 --- /dev/null +++ b/docs/source/api/plugins/similarity.rst @@ -0,0 +1,11 @@ +mml-similarity plugin +===================== + +Compute task similarities. Has a bunch of supported similarity measures: + + * FED - Fisher Embedding Distance + * MMD - Maximum Mean Discrepancy + * KLD - Kullback Leibler Divergence + * EMD - Earth Mover's Distance + * FID - Frechet Inception Distance + * ENS - Ensemble Distance (combine any other distances to compute this) \ No newline at end of file diff --git a/docs/source/api/plugins/sql.rst b/docs/source/api/plugins/sql.rst new file mode 100644 index 0000000..0510218 --- /dev/null +++ b/docs/source/api/plugins/sql.rst @@ -0,0 +1,75 @@ +mml-sql plugin +============== + +Adds persistence and multi-node support to hyperparmeter optimization. After installation simply run your ``MML`` +experiment with ``mml hpo=sql ...``. + + +One big advantage of using Optuna together with the MySQL backend is the possibility of starting multiple jobs on +different nodes in parallel, while aggregating results automatically. To make sure to attach another run to the same +Optuna study the study name as unique identifier has to be passed. The study name is created from the first call +and if not specified from CLI (``hydra.sweeper.study_name=MY_HPO_STUDY``) follows the default pattern ``{proj}_${now:%Y-%m-%d_%H-%M-%S}`` ( +e.g. ``MY_HPO_PROJ_2021-06-29_09-58-42``). The study name is logged at the very beginning of a run. Attaching another run to the same study +works as follows: + +.. code-block:: bash + + mml MODE_WITH_RETURN_VALUE proj=MY_HPO_PROJ hpo=sql hydra.sweeper.study_name=MY_HPO_PROJ_2021-06-29_09-58-42 search_space=MY_SEARCH_SPACE --multirun + +Viewing the current status of the study, including top results can be done from info-mode as follows: + +.. code-block:: bash + + mml info proj=MY_HPO_PROJ hpo=sql mode.study_name=MY_HPO_PROJ_2021-06-29_09-58-42 tasks=none + +After the study has run, you may want to use the best results that the study offered. You may either manually create +a config file with the parameters identified via info mode, or use the ``use_best_params`` functionality: + +.. code-block:: bash + + mml PROBABLY_SAME_MODE proj=ANY_PROJ use_best_params=STUDY_NAME + +Note that these parameters are applied last after hydra config compilation and overwrite any other given config values. +So if a search space comprised ``example.parameter`` providing both ``example.parameter=42`` and ``use_best_params`` will +ignore the given value of 42. + +install +~~~~~~~ + +Install MySQL and enter interactive MySQL session: + +.. code-block:: bash + + sudo apt-get install mysql-server default-libmysqlclient-dev + sudo mysql -u root -p + +Create MySQL user and database (you can use different names for database, user and password): + +.. code-block:: bash + + mysql> CREATE DATABASE IF NOT EXISTS mml_hpo; + mysql> CREATE USER 'mml_user'@'%' IDENTIFIED WITH mysql_native_password BY 'password123'; + mysql> GRANT ALL PRVILEGES ON mml_hpo.* TO 'mml_user'@'%'; + mysql> FLUSH PRIVILEGES; + +Make sure to set the MySQL variables accordingly to your chosen values within ``mml.env`` (see :doc:`../../install`): + +.. code-block:: + + export MML_MYSQL_USER=mml_user + export MML_MYSQL_PW=password123 + export MML_MYSQL_PORT=3306 + export MML_HOSTNAME_OF_MYSQL_HOST=localhost + export MML_MYSQL_DATABASE=mml_hpo + +access +~~~~~~ + +This part is optional and only required if you want other machines to access your local database (e.g. from a remote cluster): + +.. code-block:: bash + + sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf + # change the line 'bind-adress = ...' to be a comment by adding a hashtag in front + # do not forget to save changes! + service mysql restart \ No newline at end of file diff --git a/docs/source/api/plugins/suggest.rst b/docs/source/api/plugins/suggest.rst new file mode 100644 index 0000000..badae6a --- /dev/null +++ b/docs/source/api/plugins/suggest.rst @@ -0,0 +1,16 @@ +mml-suggest plugin +==================== + +The infer mode compiles a strategy to transfer knowledge from other tasks to a specific target task. Hence it is +necessary to set `pivot.name` as one of the tasks provided in suggest mode. Furthermore it is +recommended to include a variety of closely related tasks to the task list - leave it empty to let the scheduler +determine related tasks. Prediction of task similarity must have been performed before and +previous model trainings on the related tasks are required. The following series of commands separates +each of the runs into a separate project, which is up to the user to decide. Alternatively all commands may run +upon the same project. + +The pipeline can be orchestrated as follows: + - **predicting** task similarity: `mml similarity distance=fed proj=my_distances` + - **crawling** information: `mml train proj=my_crawling` (it is recommended to run this often with a variety of setting on the pipeline, e.g. learning rate, model, ... you may also consider hyperparameter optimization on each of the tasks available or gridsearch multiple setups on all tasks to ease the command) + - **infering** a blueprint pipeline: `mml suggest proj=my_inference reuse.models=my_crawling +reuse.fed=my_distances` + - **optimizing** on the target task: `mml train proj=my_optimization mode.use_blueprint=true reuse.blueprint=my_inference` \ No newline at end of file diff --git a/docs/source/api/plugins/tags.rst b/docs/source/api/plugins/tags.rst new file mode 100644 index 0000000..1960f46 --- /dev/null +++ b/docs/source/api/plugins/tags.rst @@ -0,0 +1,14 @@ +mml-tags plugin +=============== + +The ``mml-tags`` plugin increases possibilities to modify base tasks. Install via + +.. code-block:: bash + + pip install mml-tags --index-url https://__token__:@git.dkfz.de/api/v4/projects/89/packages/pypi/simple + +Afterwards you may use the tags. For a list of (all) available tags, type ``mml-tags``. Using a task tag is demonstrated here: + +.. code-block:: bash + + mml task_list=[example_task+tag_one?parameter_one?parameter_two+tag_two+tag_three] \ No newline at end of file diff --git a/docs/source/api/testing.rst b/docs/source/api/testing.rst new file mode 100644 index 0000000..21179ab --- /dev/null +++ b/docs/source/api/testing.rst @@ -0,0 +1,12 @@ +mml.testing +=========== + +The testing sub-module provides utilities to test ``mml-core`` as well as plugins. The :mod:`~mml.testing.fixtures` +module is linked as a ``pytest`` entry point and thus loaded for every pytest session within a virtual environment +that has installed ``mml-core``. + +.. automodule:: mml.testing.fixtures + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/source/cli/arch.rst b/docs/source/cli/arch.rst new file mode 100644 index 0000000..a6e7711 --- /dev/null +++ b/docs/source/cli/arch.rst @@ -0,0 +1,20 @@ +arch +==== + +The arch config group determines the model architecture used by ``mml``. Currently there are two backbone libraries: +`timm `_ and +`segmentation-models-pytorch `_. The former supports +classification and regression tasks while the latter supports classification and segmentation tasks. + +Default config option is ``arch=timm``. Call ``arch=smp`` for segmentation models. + +timm +~~~~ + +.. autoyaml:: arch/timm.yaml + + +smp +~~~ + +.. autoyaml:: arch/smp.yaml \ No newline at end of file diff --git a/docs/source/cli/augmentations.rst b/docs/source/cli/augmentations.rst new file mode 100644 index 0000000..beb4aa8 --- /dev/null +++ b/docs/source/cli/augmentations.rst @@ -0,0 +1,21 @@ +augmentations +============= + +The augmentations config group determines the image augmentations applied by ``mml`` during the loading of train data +(on top of any preprocessing). Currently there are three backbone libraries: +`albumentations `_, `torchvision `_ and +`kornia `_. While albumentations works on CPU only, +kornia is implemented GPU only in ``mml``. Torchvision is flexible in being applied on both device types. Multiple +pipeline config files are shipped with ``mml`` as examples: + + * ``augmentations=base_rand`` - basic RandAugment + * ``augmentations=kornia`` - a default GPU transformation pipeline with kornia + * ``augmentations=load_imagenet_aa`` - a automatically learned augmentation pipeline (by autoalbument) + * ``augmentations=v2`` - an example with torchvision transforms + +Note that it is possible to combine CPU and GPU transforms. ``mml`` takes care of formatting, scaling, tensorizing, etc. +so the config pipelines may fully focus on the relevant image transformations. Complex pipelines are best created as +``.yaml`` files and called via file name. You may use the :ref:`config-copy` functionality to create your own +set of plain config files to modify. The relevant entries are documented below: + +.. autoyaml:: augmentations/default.yaml diff --git a/docs/source/cli/callbacks.rst b/docs/source/cli/callbacks.rst new file mode 100644 index 0000000..45b019b --- /dev/null +++ b/docs/source/cli/callbacks.rst @@ -0,0 +1,57 @@ +callbacks +========= + +The callbacks config group determines the lightning callbacks to be used by ``mml``, whenever lightning is invoked +(training, testing, predicting). Note that callbacks are mostly deactivated during tuning. Lightning provides comes +with some `builtin callbacks `_ +but special care has to taken since some callbacks are handled by ``mml`` itself internally. Callback creation is +handled within :meth:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler.create_trainer`, there + + * :class:`~mml.core.scripts.callbacks.StopAfterKeyboardInterrupt` will be added automatically and prevents lightning from catching keyboard interrupts + * :class:`~mml.core.scripts.callbacks.MetricsTrackerCallback` will also be added if ``metrics_callback=True`` and made accessible as :attr:`~src.mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler.metrics_callback` + * :class:`~mml.core.scripts.callbacks.MMLRichProgressBar` or :class:`~mml.core.scripts.callbacks.MMLTQDMProgressBar` are used as progress bar modifications (depending on ``logging.render`` settings) + * :class:`~mml.core.scripts.callbacks.MMLModelCheckpoint` is added multiple times as described in :meth:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler.create_trainer` + +All other callbacks are coordinated through the callbacks config. Noteworthy though the yaml config files are within the +``callbacks`` folder the underlying config structure is ``cbs:{id:{**kwargs}}``. This allows the following two features: + + * stacking callbacks: ``callbacks=[early,swa]`` - here adding both early stopping and stochastic weight averaging to the callbacks + * modify callback kwargs: ``cbs.early.patience=5`` - here setting the patience parameter of early stopping + +The following callbacks configuration files are currently available: + +default +~~~~~~~ + +.. autoyaml:: callbacks/default.yaml + + +early +~~~~~ + +.. autoyaml:: callbacks/early.yaml + +none +~~~~ + +.. autoyaml:: callbacks/none.yaml + +mixup +~~~~~ + +.. autoyaml:: callbacks/mixup.yaml + +cutmix +~~~~~~ + +.. autoyaml:: callbacks/cutmix.yaml + +swa +~~~ + +.. autoyaml:: callbacks/swa.yaml + +stats +~~~~~ + +.. autoyaml:: callbacks/stats.yaml \ No newline at end of file diff --git a/docs/source/cli/compile.rst b/docs/source/cli/compile.rst new file mode 100644 index 0000000..e64d60c --- /dev/null +++ b/docs/source/cli/compile.rst @@ -0,0 +1,9 @@ +compile +======= + +The compile config group determines whether to activate ``torch.compile`` upon the model. This may speed up model +training but has limitations (it requires an initial optimization routine when the model starts training) that leads to +overhead which may not be regained by (potentially lacking) training speed improvements. Furthermore there have been +issues with the :ref:`continue-option` functionality. Thus it is not enabled by default. + +.. autoyaml:: compile/default.yaml diff --git a/docs/source/cli/hpo.rst b/docs/source/cli/hpo.rst new file mode 100644 index 0000000..f356c73 --- /dev/null +++ b/docs/source/cli/hpo.rst @@ -0,0 +1,22 @@ +hpo +=== + +The hpo config group controls hyperparameter optimization searches. It is triggered by the ``--multirun`` flag when +invoking an mml experiment (see `hydra's documentation `_). +If using an:class:`~mml.interactive.planning.MMLJobDescription` there is the ``multirun`` boolean flag. + +``use_best_params`` + +:doc:`/hpo` + + +default +~~~~~~~ + +.. autoyaml:: hpo/default.yaml + + +grid +~~~~ + +.. autoyaml:: hpo/grid.yaml \ No newline at end of file diff --git a/docs/source/cli/loaders.rst b/docs/source/cli/loaders.rst new file mode 100644 index 0000000..d78f6fc --- /dev/null +++ b/docs/source/cli/loaders.rst @@ -0,0 +1,52 @@ +loaders +======= + +The loaders config group determines the way each :class:`~mml.core.data_loading.task_attributes.Modality` is +processed by some :class:`~mml.core.data_loading.modality_loaders.ModalityLoader` to bring sample entries to tensor +ready format in ``mml``. More details on available loaders can be found in the API entry of +:mod:`~mml.core.data_loading.modality_loaders`. The config requires an equally named entry to the +:class:`~mml.core.data_loading.task_attributes.Modality` that points to the respective +:class:`~mml.core.data_loading.modality_loaders.ModalityLoader` to be used for that +:class:`~mml.core.data_loading.task_attributes.Modality`. + +For most cases the ``default`` configuration should offer a sufficing solution, but specific file formats might +require a different :class:`~mml.core.data_loading.modality_loaders.ModalityLoader`. There is also some potential +for efficiency improvements through testing different :class:`~mml.core.data_loading.modality_loaders.ModalityLoader` s. + +The following callbacks configuration files are currently available: + +default +~~~~~~~ +The default configuration determines the general fallback option for all modalities. + +.. autoyaml:: loaders/default.yaml + +numpy +~~~~~ + +.. autoyaml:: loaders/numpy.yaml + +pillow +~~~~~~ + +.. autoyaml:: loaders/pillow.yaml + +pillow_acc +~~~~~~~~~~ + +.. autoyaml:: loaders/pillow_acc.yaml + +scikit +~~~~~~ + +.. autoyaml:: loaders/scikit.yaml + +torch +~~~~~ + +.. autoyaml:: loaders/torch.yaml + +uni +~~~ + +.. autoyaml:: loaders/uni.yaml diff --git a/docs/source/cli/logging.rst b/docs/source/cli/logging.rst new file mode 100644 index 0000000..7ca96df --- /dev/null +++ b/docs/source/cli/logging.rst @@ -0,0 +1,53 @@ +logging +======= + +The ``logging`` config group allows to modify the logging behaviour of mml. Next to sum options at the top level, there +are three sub-configurations: + + * ``exp_logger`` will determine the experiment logger used by ``lightning`` + * ``notifier`` will determine whether and how certain events will be messaged + * ``render`` will determine the rendering backend for logging + + +default +~~~~~~~ +The default top level configuration is stored in ``log.yaml``. + +.. autoyaml:: logging/log.yaml + + +exp_logger +---------- + +Currently ``mml`` only provides a config for `tensorboard `_. + +tensorboard +~~~~~~~~~~~ + +.. autoyaml:: logging/exp_logger/tensorboard.yaml + + +notifier +-------- + +``mml`` ships with two notifiers, but can easily be extended. There are three configuration files: ``none.yaml`` (the +default, which does not provide any notifier), ``slack.yaml`` which allows notification via Slack and ``email.yaml` for +email notification. Multiple notifiers can be combined via ``logging/notifier=[email,slack]``. For each notifier you +can independently determine the events to send notifications (e.g. ``logging.notifier.slack.on_start=true``). + +slack +~~~~~ + +.. autoyaml:: logging/notifier/slack.yaml + +email +~~~~~ + +.. autoyaml:: logging/notifier/email.yaml + +render +------ + +The backend for rendering the logs. Can be either `colorlog `_ +or `rich `_. The default is colorlog and support for ``rich`` might not be as +throughout as for ``colorlog``. Change the renderer via ``logging/render=rich``. \ No newline at end of file diff --git a/docs/source/cli/loss.rst b/docs/source/cli/loss.rst new file mode 100644 index 0000000..f50619a --- /dev/null +++ b/docs/source/cli/loss.rst @@ -0,0 +1,68 @@ +loss +==== + +The ``loss`` config group determines all loss functions that are used for ``mml`` models. It determines a single loss +function per task type. More precisely the :class:`~mml.core.data_loading.task_attributes.TaskType` is matched to +a short string via :attr:`~mml.core.models.lightning_single_frame.CONFIG_ROUTES`. For each model head (that matches +a task type) the respective `loss.SHORT_STRING` config is instantiated. The main file determines some additional +behaviour: + +default +~~~~~~~ +The default top level configuration. + +.. autoyaml:: loss/default.yaml + +The following task type matching subdirectories exist: + +cls +--- + +For classification tasks, currently shipped with a single option + +ce +~~ + +.. autoyaml:: loss/cls/ce.yaml + +mlcls +----- + +For multi-label classification tasks, currently shipped with two options + +bce +~~~ + +.. autoyaml:: loss/mlcls/bce.yaml + +ce +~~ + +.. autoyaml:: loss/mlcls/ce.yaml + + +reg +--- + +For regression tasks, currently shipped with a single option + +huber +~~~~~ + +.. autoyaml:: loss/reg/huber.yaml + + +seg +--- + +For segmentation tasks, currently shipped with two options + +ce +~~ + +.. autoyaml:: loss/seg/ce.yaml + +dice +~~~~ + +.. autoyaml:: loss/seg/dice.yaml diff --git a/docs/source/cli/lr_scheduler.rst b/docs/source/cli/lr_scheduler.rst new file mode 100644 index 0000000..39123a6 --- /dev/null +++ b/docs/source/cli/lr_scheduler.rst @@ -0,0 +1,45 @@ +lr_scheduler +============ + +Provides the possibility to choose a learning rate scheduler. Should be compatible with any `lr_scheduler``by +``torch`` (see `here `_ for a list). The +internal calls to the scheduler are dealt with by +`lightning `_. Most schedulers have a couple of +hyperparameters, which are not all mapped to the ``yaml`` config files. You may add those from CLI via prepending +a ``+`` (e.g. ``lr_scheduler=plateau +lr_scheduler.cooldown=3``). Below you can find the config files, but adding more +should be straightforward from the examples provided. By default no scheduler is used. + +none +~~~~ + +.. autoyaml:: lr_scheduler/none.yaml + +cosine +~~~~~~ + +.. autoyaml:: lr_scheduler/cosine.yaml + +cosine_restart +~~~~~~~~~~~~~~ + +.. autoyaml:: lr_scheduler/cosine_restart.yaml + +exponential +~~~~~~~~~~~ + +.. autoyaml:: lr_scheduler/exponential.yaml + +one_cycle +~~~~~~~~~ + +.. autoyaml:: lr_scheduler/one_cycle.yaml + +plateau +~~~~~~~ + +.. autoyaml:: lr_scheduler/plateau.yaml + +step +~~~~ + +.. autoyaml:: lr_scheduler/step.yaml \ No newline at end of file diff --git a/docs/source/cli/metrics.rst b/docs/source/cli/metrics.rst new file mode 100644 index 0000000..ada52a2 --- /dev/null +++ b/docs/source/cli/metrics.rst @@ -0,0 +1,29 @@ +metrics +======= + + +The ``metrics`` config group determines all metrics that are used to evaluate ``mml`` models. It determines a suite of +metrics per task type. More precisely the :class:`~mml.core.data_loading.task_attributes.TaskType` is matched to +a short string via :attr:`~mml.core.models.lightning_single_frame.CONFIG_ROUTES`. For each model head (that matches +a task type) the respective `metrics.SHORT_STRING` config is instantiated. + +The following task type matching subdirectories exist and contain a single ``default.yaml`` file each: + + * cls (for classification tasks) + * mlcls (for multi-label classification tasks) + * reg (for regression tasks) + * seg (for segmentation tasks) + +The currently used metrics can be seen via ``mml --cfg=job`` (add `` | grep torchmetrics`` for reduced output). All +metrics used by ``mml`` are from `torchmetrics `_. + +The main file determines some additional behaviour: + +default +~~~~~~~ +The default top level configuration. + +.. autoyaml:: metrics/default.yaml + + + diff --git a/docs/source/cli/mode.rst b/docs/source/cli/mode.rst new file mode 100644 index 0000000..eb7d7de --- /dev/null +++ b/docs/source/cli/mode.rst @@ -0,0 +1,72 @@ +mode +==== + +The ``mode`` config group has a special role in ``mml`` and is required to be passed as the first argument (and without +``mode=...``) e.g. as ``mml train ...`` or ``mml create ...``. Some examples can be found at :doc:`/modes`. Note that any +additional configurations must be prepended by the ``mode`` keyword as usual (e.g. ``mode.subroutines=[x,y,z]``). +A mode basically maps to a subclass of :class:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler` using +the ``mode.scheduler._target_`` config entry. This specific scheduler will be instantiated by ``mml`` and the +:meth:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler.run` method will be invoked to carry out any +computations. Sometimes different configs may point to the same scheduler with slightly different default parameters. +Such cases are marked below. + +clean +~~~~~ + +.. autoyaml:: mode/clean.yaml + +create +~~~~~~ + +.. autoyaml:: mode/create.yaml + +downgrade +~~~~~~~~~ + +The downgrade config is a convenience entry to call the upgrade scheduler with the downgrade subroutine. + +.. autoyaml:: mode/downgrade.yaml + +info +~~~~ + +.. autoyaml:: mode/info.yaml + +post +~~~~ + +.. autoyaml:: mode/post.yaml + +pp +~~ + +.. autoyaml:: mode/pp.yaml + +predict +~~~~~~~ + +The predict config is a convenience entry to call the train scheduler with the predict subroutine. + +.. autoyaml:: mode/predict.yaml + +test +~~~~ + +The test config is a convenience entry to call the train scheduler with the test subroutine. + +.. autoyaml:: mode/test.yaml + +tl +~~ + +.. autoyaml:: mode/tl.yaml + +train +~~~~~ + +.. autoyaml:: mode/train.yaml + +upgrade +~~~~~~~ + +.. autoyaml:: mode/upgrade.yaml \ No newline at end of file diff --git a/docs/source/cli/optimizer.rst b/docs/source/cli/optimizer.rst new file mode 100644 index 0000000..5869a64 --- /dev/null +++ b/docs/source/cli/optimizer.rst @@ -0,0 +1,17 @@ +optimizer +========= + +The ``optimizer`` config group determines the ``torch-optim`` optimizer used for backpropagation during model training. +For now only a single optimizer and single parameter group is supported. + + +adam +~~~~ +The default optimizer by ``mml``. + +.. autoyaml:: optimizer/adam.yaml + +sgd +~~~ + +.. autoyaml:: optimizer/sgd.yaml \ No newline at end of file diff --git a/docs/source/cli/overview.rst b/docs/source/cli/overview.rst new file mode 100644 index 0000000..2e7a999 --- /dev/null +++ b/docs/source/cli/overview.rst @@ -0,0 +1,138 @@ +CLI +=== + +This help provides a detailed overview on CLI of MML. The basic call pattern is + +.. code-block:: bash + + mml [mode] [overrides] [hydra.overrides] [hydra-flags] + +Besides there are also the following mml-core CLIs (without any arguments): + + * mml-env-setup - sets up an `mml.env` file at your current location + * mml-copy-conf - sets up mml configs outside the mml-core package + + +mode +---- + +Available modes include: + + * create - Installs datasets and tasks on the workstation. + * pp - Preprocesses tasks with the given "preprocessing". + * train - Trains, tests and/or predicts (single or multi-task). + * post - Postprocessing via calibration and ensembling. + * info - Provides information on tasks, trained models, etc.. + * clean - May be used the remove artefacts from mml. + * upgrade - Used to migrate mml results and data upwards. + * downgrade - Used to migrate mml results and data downwards. + +Note that mml plugins may add further modes. You can find more example usages for +modes at :doc:`/modes` and specific details on mode configuration at :doc:`mode`. + +overrides +--------- + +MML offers a flexible system to override experiment configuration from +the command line. It is powered by `Hydra `_ and more +details on the syntax can be found in the respective +`documentation `_. +In a nutshell +configuration options are grouped and one can either override a whole +group of options with existing config files (e.g. ``lr_scheduler=cosine``) +or set values inside a config group (e.g. ``lr_scheduler.verbose=false``). + +.. note:: + Hydra configuration is presented in a simplified manner above. There are + special cases of combining config files (e.g. ``callbacks=[early,mixup]``), + accessing nested config files (e.g. ``loss/mlcls=ce``) or adding new keys to + a configuration (e.g. ``+lr_scheduler.eta_min=0.01``). + +This following is a list of ``mml`` config groups. To see all available current options for a group call ``mml --help``. + + * :doc:`arch` - determines model architecture + * :doc:`augmentations` - sets the pipeline for image augmentations during training and general normalization strategy + * :doc:`callbacks` - determines ``lightning`` callbacks during training + * :doc:`compile` - BETA controls pytorch 2.0 ``torch.compile`` behaviour + * :doc:`hpo` - hyperparameter optimization methodology + * ``hydra`` - hydra internal configs, see ``hydra.overrides`` below + * :doc:`logging` - experiment logging and other notification settings + * :doc:`loss` - training loss + * :doc:`lr_scheduler` - learning rate schedulers + * :doc:`metrics` - metrics to measure model performance + * :doc:`mode` - central component defining the scheduler and other corresponding runtime settings + * :doc:`optimizer` - network training optimizer + * :doc:`preprocessing` - image preprocessing pipeline (applied while training and predicting) + * :doc:`reuse` - determines the reuse of previous results as well as clean up of intermediates + * :doc:`sampling` - sets sampling strategy + * :doc:`search_space` - defines the search space during hyperparameter optimization + * :doc:`sys` - system properties (manages to run on different hardware) + * :doc:`tasks` - pre-compiled task lists, pivot tasks and task tagging options + * :doc:`trainer` - ``lightning`` trainer options + * :doc:`tta` - BETA test time augmentation + * :doc:`tune` - tuning options with ``lightning`` tuner + +The configuration groups and overrides will be compiled to a final single +job configuration (or multiple in ``--multirun`` mode as described below). +The final configuration can be displayed with the help of hydra-flags +(see below) and is also stored in the run folder inside the ``.hydra`` subdir. + +.. toctree:: + :hidden: + :maxdepth: 1 + + arch + augmentations + callbacks + compile + hpo + loaders + logging + loss + lr_scheduler + metrics + mode + optimizer + preprocessing + remove + reuse + sampling + search_space + sys + tasks + trainer + tta + tune + +main config file +~~~~~~~~~~~~~~~~ + +Furthermore ``config_mml.yaml`` (the main config file) specifies the defaults for each of these groups as well as +some other default values. These few top-level options are listed here: + + +.. autoyaml:: config_mml.yaml + + +hydra.overrides +--------------- + +The same override style also let's you alter configurations that directly +influence the internal behaviour of hydra. The most common use case might +be for example ``hydra.verbose=true``, which enters verbose mode and print +all logged ``debug`` messages. You can find more config groups via ``mml --help`` +or follow the `hydra documentation `_. + + +hydra-flags +----------- + +``hydra`` offers some functionality that is inherited by ``mml``. All existing +options are displayed once more if you call ``mml --help``, but here are some +noteworthy ones: + + * ``--cfg=job`` - print the compiled config (without running ``mml``) + * ``--multirun`` - used for hyperparameter search, starts multiple jobs + * ``--info`` - information on the defaults tree, config search paths, etc + +More info in the `hydra docs `_. diff --git a/docs/source/cli/preprocessing.rst b/docs/source/cli/preprocessing.rst new file mode 100644 index 0000000..9ce6618 --- /dev/null +++ b/docs/source/cli/preprocessing.rst @@ -0,0 +1,54 @@ +preprocessing +============= + +Data preprocessing is the first transformation to data after loading from disk. It should comprise deterministic +one-one mappings that can e.g. be used to unify data (resizing operations to stack image tensors later on). The +preprocessing config determines the pipeline for this process. Note that preprocessing can be done on the fly - +which is ideal for exploration - but for number crunching a single call to the ``pp`` mode can drastically improve +efficiency (in exchange for disk space). Note that in contrast to :doc:`augmentations` only the +`albumentations `_ backend is supported! + +default +~~~~~~~ + +.. autoyaml:: preprocessing/default.yaml + +example +~~~~~~~ + +.. autoyaml:: preprocessing/example.yaml + +none +~~~~ + +.. autoyaml:: preprocessing/none.yaml + +size224 +~~~~~~~ + +.. autoyaml:: preprocessing/size224.yaml + +size256 +~~~~~~~ + +.. autoyaml:: preprocessing/size256.yaml + +size336 +~~~~~~~ + +.. autoyaml:: preprocessing/size336.yaml + +size384 +~~~~~~~ + +.. autoyaml:: preprocessing/size384.yaml + +size512 +~~~~~~~ + +.. autoyaml:: preprocessing/size512.yaml + +size528 +~~~~~~~ + +.. autoyaml:: preprocessing/size528.yaml \ No newline at end of file diff --git a/docs/source/cli/remove.rst b/docs/source/cli/remove.rst new file mode 100644 index 0000000..b9b74ad --- /dev/null +++ b/docs/source/cli/remove.rst @@ -0,0 +1,30 @@ +remove +====== + +The ``remove`` config group determines the :class:`~mml.core.data_loading.file_manager.MMLFileManager`'s behaviour at +the end of an experiment. During the :meth:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler.finish_exp` +routine of the experiment's scheduler the :meth:`~mml.core.data_loading.file_manager.MMLFileManager.remove_intermediates` +method of the :class:`~mml.core.data_loading.file_manager.MMLFileManager` is called and triggers the deletion of created +files according to the settings of this config +group. This is useful to get rid of intermediates or general results that are not used any more and may use up the disk +capacity. + +The path assignment system of the :class:`~mml.core.data_loading.file_manager.MMLFileManager` determines a ``key`` for +each kind of path assignment. This key is used within this config to trigger deletion of files. The default path +assignments (and according keys) are defined in :attr:`~mml.core.data_loading.file_manager.DEFAULT_ASSIGNMENTS`. Here +are some examples: + + * ``models``: the :class:`~mml.core.scripts.model_storage.ModelStorage` for each trained model + * ``parameters``: the :class:`~lightning.pytorch.callbacks.model_checkpoint.ModelCheckpoint` for a model + * ``pipeline``: the :class:`~mml.core.scripts.pipeline_configuration.PipelineCfg` for a training process + * ``predictions``: predictions of a model on a task, dictionary stored with ``torch.save`` + +By default (``remove=none``) no data is deleted (except for inherently temporary data, see +:meth:`~mml.core.data_loading.file_manager.MMLFileManager.remove_intermediates`). The alternative config file +``remove=all`` will take care of most of the default assignments. Any additional key can be added via prepedning a ``+`` +as in ``+remove.MY_KEY=true``, which might be necessary for plugin provided path assignments. + +all +~~~ + +.. autoyaml:: remove/all.yaml \ No newline at end of file diff --git a/docs/source/cli/reuse.rst b/docs/source/cli/reuse.rst new file mode 100644 index 0000000..8a3a8e8 --- /dev/null +++ b/docs/source/cli/reuse.rst @@ -0,0 +1,18 @@ +reuse +===== + +The ``reuse`` config group determines the :class:`~mml.core.data_loading.file_manager.MMLFileManager`'s behaviour at +the beginning of an experiment. Through the :meth:`~mml.core.data_loading.file_manager.MMLFileManager._find_reusables` +method the :class:`~mml.core.data_loading.file_manager.MMLFileManager` loads existing data as specified. When the +:class:`~mml.core.data_loading.task_struct.TaskStructFactory` creates a +:class:`~mml.core.data_loading.task_struct.TaskStruct` in +:meth:`~mml.core.data_loading.task_struct.TaskStructFactory.create_task_struct` it uses the +:meth:`~mml.core.data_loading.task_struct.TaskStructFactory.set_task_struct_defaults` method to attach the loaded paths +to the struct. As such they can be accessed during runtime of the scheduler and any of its subroutines. Note that for +``models`` the struct will hold a list of all loaded models, while every other key will only add a single path to the +struct. More details on the syntax can be found at :doc:`/usage`. By default no data is loaded (``reuse=none``). + +current +~~~~~~~ + +.. autoyaml:: reuse/current.yaml \ No newline at end of file diff --git a/docs/source/cli/sampling.rst b/docs/source/cli/sampling.rst new file mode 100644 index 0000000..f3bbcde --- /dev/null +++ b/docs/source/cli/sampling.rst @@ -0,0 +1,12 @@ +sampling +======== + +The ``sampling`` config group determines some behaviour of the dataloader within +:class:`~mml.core.data_loading.lightning_datamodule.MultiTaskDataModule` as well as the underlying +:class:`~mml.core.data_loading.task_dataset.TaskDataset`. + + +full +~~~~ + +.. autoyaml:: sampling/full.yaml \ No newline at end of file diff --git a/docs/source/cli/search_space.rst b/docs/source/cli/search_space.rst new file mode 100644 index 0000000..c808ff8 --- /dev/null +++ b/docs/source/cli/search_space.rst @@ -0,0 +1,12 @@ +search_space +============ + +The ``search_space`` config group determines the hyperparameter search space during a ``--multirun``. See :doc:`/hpo` +for a general introduction and :doc:`hpo` for more config options on how to use this. The syntax of defining the search +space is also documented by `hydra `_. +By default (``search_space=none``) no search space is defined. An example configuration is given below. + +example +~~~~~~~ + +.. autoyaml:: search_space/example.yaml diff --git a/docs/source/cli/sys.rst b/docs/source/cli/sys.rst new file mode 100644 index 0000000..d788470 --- /dev/null +++ b/docs/source/cli/sys.rst @@ -0,0 +1,19 @@ +sys +=== + +The ``sys`` config group deals with system specific settings and allows you to set ``mml`` configuration for multiple +compute hardware. By default ``mml`` ships with two systems in mind: a local setup and a remote compute cluster. For +each system the root paths need to be set somewhere - the ``mml.env`` file offers an easy solution to keep these +personal settings out of your repository but you may set those paths also directly in the ``sys`` config file. Below +you find the two configurations provided: + + +local +~~~~~ + +.. autoyaml:: sys/local.yaml + +cluster +~~~~~~~ + +.. autoyaml:: sys/cluster.yaml \ No newline at end of file diff --git a/docs/source/cli/tasks.rst b/docs/source/cli/tasks.rst new file mode 100644 index 0000000..506d778 --- /dev/null +++ b/docs/source/cli/tasks.rst @@ -0,0 +1,34 @@ +tasks +===== + +The ``tasks`` config group cares about the task selection available to the scheduler. For each task listed the scheduler +automatically holds a :class:`~mml.core.data_loading.task_struct.TaskStruct` that can be interacted with to load +the task as well as attach / retrieve other artifacts. + +Next to the base list of tasks +there are two important concepts: + + * the ``pivot`` task is a "highlighted" task, some schedulers behave differently depending whether a pivot is provided or specifically require one + * the ``tag`` mechanism allows task modifications (see also the ``mml-tags`` :doc:`/plugins`) - keep in mind that for the majority of cases tagged (and multi-tagged) tasks are treated completely independent + +Note that the ``tasks`` config entries +live "top level", which means although you select a config file via ``tasks=fake``, the modification of entries has no +``tasks`` prepended (aka. ´´pivot.name=MY_TASK``). Having a large pool of tasks is prone for typos during CLI +interaction which can be resolved either via creating a config file (you may use ``_template.yaml`` as a basis) or +using the :class:`~mml.interactive.planning.MMLJobDescription` jointly with a +:class:`~mml.interactive.planning.JobRunner`. + + +none +~~~~ + +By default no tasks are given. + +.. autoyaml:: tasks/none.yaml + +fake +~~~~ + +This config points to the :mod:`~mml.core.data_preparation.fake_task` and is intended for debugging and testing. + +.. autoyaml:: tasks/fake.yaml diff --git a/docs/source/cli/trainer.rst b/docs/source/cli/trainer.rst new file mode 100644 index 0000000..1f2446b --- /dev/null +++ b/docs/source/cli/trainer.rst @@ -0,0 +1,10 @@ +trainer +======= + +The ``trainer`` config group sets the flags for the ``lightning.Trainer`` used by ``mml`` The full documentation can be +found `here `_. + +default_trainer +~~~~~~~~~~~~~~~ + +.. autoyaml:: trainer/default_trainer.yaml diff --git a/docs/source/cli/tta.rst b/docs/source/cli/tta.rst new file mode 100644 index 0000000..c7dc56b --- /dev/null +++ b/docs/source/cli/tta.rst @@ -0,0 +1,16 @@ +tta +=== + +The ``tta`` config group manages ``test time augmentation`` during inference. Note that this feature is still in beta +phase. By default (``tta=none``) no tta is performed. If activated the model performs multiple predictions on the same +sample via using different augmentations - after the prediction any geometrical distortion is reversed and the produced +predictions are merged. The augmentations are loaded through the +:class:`~mml.core.data_loading.augmentations.kornia.KorniaAugmentationModule` that can deal with any (unnested) list of +`kornia `_ augmentations. +Note that tta is only active during testing and predicting with models - not during training nor validation. +The following example gives a good overview on the configuration options: + +rotate +~~~~~~ + +.. autoyaml:: tta/rotate.yaml \ No newline at end of file diff --git a/docs/source/cli/tune.rst b/docs/source/cli/tune.rst new file mode 100644 index 0000000..6e477f3 --- /dev/null +++ b/docs/source/cli/tune.rst @@ -0,0 +1,15 @@ +tune +==== + +The ``tune`` config group allows to make use of the +`lightning.Tuner `_. A scheduler +may call :meth:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler.lightning_tune` before starting a +``Trainer.fit`` run. This will (depending on the configuration) allow to modify two hyperparmeters: + + * the batch size (to maximize usage of VRAM) + * the learning rate (to stabilize learning) + +default +~~~~~~~ + +.. autoyaml:: tune/default.yaml \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..8f52e51 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,105 @@ +# LICENSE HEADER MANAGED BY add-license-header +# +# SPDX-FileCopyrightText: Copyright 2024 German Cancer Research Center (DKFZ) and contributors. +# SPDX-License-Identifier: MIT +# + +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html +import time +import warnings +from pathlib import Path + +import mml +import mml.configs + +# During docs building, show deprecation messages, they are also used for doc generation +warnings.simplefilter(action="default", category=DeprecationWarning) + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = "mml" +copyright = f'2021-{time.strftime("%Y")}, German Cancer Research Center (DKFZ), Heidelberg, Germany' +author = "Patrick Godau" +release = mml.__version__ +version = release + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + "sphinx.ext.autodoc", # generate documentation using doc strings + "sphinx.ext.autosummary", # used to generate overview tables + "sphinx.ext.intersphinx", # link between different python packages + "sphinx.ext.ifconfig", # allows conditional docs + "sphinx.ext.viewcode", # links to code snippets + "myst_nb", # allow jupyter notebooks to be included + "sphinxcontrib.autoyaml", # create documentation out of the config yaml files +] + +templates_path = ["_templates"] +exclude_patterns = [] + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "sphinx_rtd_theme" + +html_theme_options = { + "logo_only": False, + "prev_next_buttons_location": "bottom", + "style_external_links": False, + # Toc options + "collapse_navigation": True, + "sticky_navigation": True, + "navigation_depth": 4, + "includehidden": True, + "titles_only": False, +} + +# further configuration possibilities: +# https://sphinx-rtd-theme.readthedocs.io/en/stable/configuring.html + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +html_title = "MML" + +# A shorter title for the navigation bar. Default is the same as html_title. +html_short_title = "MML documentation" + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +html_logo = "_static/mml_logo.png" + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +html_favicon = "_static/mml_favicon.ico" + +html_static_path = ["_static"] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +html_last_updated_fmt = "%b %d, %Y" + +# remove the module prefix from module members documentation +add_module_names = False + +# other settings +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), + "torch": ("https://pytorch.org/docs/main/", None), + "numpy": ("https://numpy.org/doc/stable", None), +} + +autoclass_content = "class" +autodoc_class_signature = "separated" +autodoc_inherit_docstrings = False + +nb_execution_mode = "off" +# autoyaml options (https://github.com/Jakski/sphinxcontrib-autoyaml?tab=readme-ov-file#options) +autoyaml_root = str(Path(mml.configs.__file__).parent) +autoyaml_level = 3 diff --git a/docs/source/extensions.rst b/docs/source/extensions.rst new file mode 100644 index 0000000..b61c401 --- /dev/null +++ b/docs/source/extensions.rst @@ -0,0 +1,110 @@ +Extensions +========== + +``mml`` supports a lot of possible extensions. You can find some examples in the :doc:`plugins`. This site serves as +a reference to list and explain some possible entry points. + +Scheduler +--------- + +Writing a new scheduler allows you to completely design new processes inside ``mml`` while leveraging all of its +infrastructure and seamlessly integrate with existing procedures. New schedules are implemented by inheriting from the +:class:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler`. Several examples are provided in the +:mod:`~mml.core.scripts.schedulers` module, as well as scattered through some :doc:`plugins`. The first step would be to +consider the atomic steps of the scheduler. Usually they incorporate the interaction with a single or few tasks and +produce some sort of artifact as result of calculations (e.g. a trained model, extracted features, visualizations, ...). +Let's assume there are two atomic steps: ``step_a`` and ``step_b``, where the first one runs on every task of the task +list producing some artifact and the second runs a single time to aggregate all artifacts. Their methods might look like + +.. code-block:: python + + class BuzzScheduler(AbstractBaseScheduler): + def step_a(self, task_name): + struct = self.get_struct(task_name) + # do calculations + datamodule = self.create_datamodule(struct) + artifact = heavy_work(datamodule) + # store + path = self.fm.construct_saving_path(obj=artifact,key='foo',task_name=task_name) + artifact.store(path) + # attach path to struct (this will make it persistent across atomic steps) + struct.paths['foo'] = path + + def step_b(self): + # load artifacts + artifacts = {} + for task in self.cfg.task_list: + struct = self.get_struct(task_name) + artifacts[task] = load_my_artifact(path=struct.paths['foo']) + # do some work + end_result = heavy_work(artifacts) + # store + path = self.fm.construct_saving_path(obj=end_result,key='baz') + end_result.store(path) + +Now the only thing remaining is to tell the scheduler what subroutines are available and how they shall compose. + +.. code-block:: python + + class BuzzScheduler(AbstractBaseScheduler): + def __init__(self, cfg: DictConfig): + # initialize + super(BuzzScheduler, self).__init__(cfg=cfg, available_subroutines=["a", "b"]) + + def create_routine(self): + # -- add step_a commands + if "a" in self.subroutines: # subroutines may be called independently + for task in self.cfg.task_list: + self.commands.append(self.step_a) + self.params.append([task]) + # -- add step_b command + if "b" in self.subroutines: + # run only once, nor args + self.commands.append(self.step_b) + self.params.append([]) + +To make your scheduler accessible you need to provide a ``mode`` config. You may either place this config inside the +original ``mml`` config folder (e.g. if you cloned the repo), create a dedicated config folder where you like (using +``mml-copy-conf`` (see :doc:`install`) or provide them through a plugin (see :doc:`plugins`). It could look like this: + +.. code-block:: yaml + + # @package _global_ + + defaults: + - override /augmentations: no_norm + - override /sampling: extraction_default + + mode: + id: BUZZ + scheduler: + _target_: foo.bar.BuzzScheduler + subroutines: + - a + - b + var_one: 1337 + var_two: 42 + + sampling: + sample_num: 1000 + +Some more words on the interactions of such a config can be found in :doc:`usage`. + +Modalities and TaskTypes +------------------------ + +Adding a new :class:`~mml.core.data_loading.task_attributes.Modality` and/or a new +:class:`~mml.core.data_loading.task_attributes.TaskType` requires the following steps + + * add your modality and task type to the respective ``Enum`` classes at :mod:`~mml.core.data_loading.task_attributes` + * make sure to provide the correct entry in :meth:`~mml.core.data_loading.task_attributes.TaskType.requires` + * if a new modality is used: + * provide a :class:`~mml.core.data_loading.ModalityLoader` class and link it correctly in the configs (`config/loaders`) + * write a verifier (see :mod:`~mml.core.data_preparation.task_creator`) and add it to the :attr:`~mml.core.data_preparation.task_creator.MODALITY_VERIFIER_MAP` + * check compatibility with `kornia `_ and`albumentations `_, specifically ensure compatibility with :attr:`~mml.core.data_loading.task_attributes.KORNIA_VALID_MODALITIES` + * if a new task type is used: + * add the target modality to the :class:`~mml.core.data_loading.task_struct.TaskStruct` target property + * add heads that handle that task type to the model you intend to use + * add a config route entry to :attr:`~mml.core.models.lightning_single_frame.CONFIGS_ROUTES` + * create configs in `configs/metrics` as well as `configs/loss` representing suitable metrics and loss options + * link created configs in the respective `defaults.yaml` config file of those two folders \ No newline at end of file diff --git a/docs/source/guides.rst b/docs/source/guides.rst new file mode 100644 index 0000000..698ee86 --- /dev/null +++ b/docs/source/guides.rst @@ -0,0 +1,11 @@ +Guides +====== + +.. toctree:: + :caption: MML tricks + :name: mml-tricks + :glob: + :reversed: + :titlesonly: + + notebooks/tricks/* \ No newline at end of file diff --git a/docs/source/hpo.rst b/docs/source/hpo.rst new file mode 100644 index 0000000..b4f9b7d --- /dev/null +++ b/docs/source/hpo.rst @@ -0,0 +1,42 @@ +Hyperparameter optimization +=========================== + + +Attaching ``--multirun`` to your command will start the job in hpo mode. Note that multirun does not offer +the ``continue`` (see :doc:`usage`) functionality! + +Gridsearch +---------- + +This is a very easy way to start a bunch of jobs with slightly varying setting. Find the details at +`hydra multirun `_. Multiple values for a parameter are +simply given at once separated by a ``,``. You must specify ``hpo=grid`` for this variant. +An example usage to vary learning rate is given below: + +.. code-block:: bash + + mml MY_MODE proj=MY_HPO_PROJ hpo=grid optimizer.lr=1.e-4,1.e-5 --multirun + + +Optuna +------ + +This hpo method is more involved. Details can be found at the `hydra optuna plugin `_ +website as well as the website of the backend module `Optuna `_. + + +usage +~~~~~ + +Create a config file defining your search space for the hyperparameters at ``configs/search_space``. +And afterwards call the program as follows (make sure your mode has a return value to optimize using +:class:`~mml.core.scripts.schedulers.base_scheduler.AbstractBaseScheduler`'s ``return_value``). + +.. code-block:: bash + + mml MODE_WITH_RETURN_VALUE proj=MY_HPO_PROJ search_space=MY_SEARCH_SPACE --multirun + +plugin +~~~~~~ +The :doc:`api/plugins/sql` extends this setup with a database backend to coordinate hyperparameter optimization +trials across multiple nodes of a computing infrastructure. It further allows for results persistence in the storage. \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..834ddf8 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,187 @@ +Medical Meta Learner +==================== + +.. image:: _static/mml_logo.png + +|Python Badge| |Pipeline Badge| |Coverage Badge| |Release Badge| |Pylint Badge| |Docs Badge| |Style Badge| |License Badge| + +``mml`` is a research oriented Python package which aims to provide an easy and scalable +way of deep learning on multiple image tasks (see `Meta-Learning `_). + +It features: + + * a clear methodology to store, load, refer, modify and combine RGB image datasets across task types (classification, segmentation, ...) + * a highly configurable CLI for the full deep learning pipeline + * a dedicated file management system, capable of continuing aborted experiments, reuse previous results and parallelize runs + * an api for interactive pre- and post-experiment exploration + * smooth integration of latest deep learning libraries (`lightning `_, `hydra `_, `optuna `_, ...) + * easy expandability via using plugins or directly hooking into runtime objects via scripts or notebooks + * good documentation, broad testing and ambitious goals + + +.. note:: + MML is still considered in Beta stage, which means any feedback is highly appreciated! + + +Quickstart +---------- +Setup ``mml`` as described in :doc:`install` and write a short script to load your data into ``mml`` as follows: + +.. code-block:: python + + from mml.api import (DSetCreator, License, Keyword, TaskCreator, TaskType, register_dsetcreator, + register_taskcreator, get_iterator_and_mapping_from_image_dataset) + from mml.cli import main + # this example shows how to quickly include an existing pytorch image classification dataset + from my_code.data import MyExistingPyTorchDataSet + + dset_name = 'my_dataset' + task_name = 'my_task' + + @register_dsetcreator(dset_name=dset_name) + def create_dset(): + dset_creator = DSetCreator(dset_name=dset_name) + # DSetCreator has various help functions to create datasets (e.g. from kaggle, pytorch datasets, ...) + train_dset = MyExistingPyTorchDataSet(root=dset_creator.download_path, download=True, train=True) + test_dset = MyExistingPyTorchDataSet(root=dset_creator.download_path, download=True, train=False) + dset_path = dset_creator.extract_from_pytorch_datasets(datasets={'training': train_dset, + 'testing': test_dset}, + task_type=TaskType.CLASSIFICATION, + class_names=train_dset.classes) + return dset_path + + + @register_taskcreator(task_name=task_name, dset_name=dset_name) + def create_task(dset_path: Path): + task = TaskCreator(dset_path=dset_path, name=task_name, + task_type=TaskType.CLASSIFICATION, + desc="(optional) My task description.", + ref="(optional) My bibtex entry.", + url='(optional) My data website.', + instr='(optional) Any instructions to access data.', + lic=License.UNKNOWN, # the license of the task + release='(optional) Year of data release.', + keywords=[Keyword.NATURAL_OBJECTS]) # choose from a variety of keywords to describe data background + # if classes are split by folders (which is the case if using extract_from_pytorch_datasets), one may simply + train_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset( + root=dset_path / 'training_data', classes=None) + test_iterator, _ = get_iterator_and_mapping_from_image_dataset( + root=dset_path / 'testing_data', classes=None) + task.find_data(train_iterator=train_iterator, test_iterator=test_iterator, idx_to_class=idx_to_class) + task.auto_complete() + + # start the MML cli from this script + if __name__ == "__main__": + main() + +You can run your script with any ``mml`` CLI configurations and use the registered data along. +The following command installs the data, preprocesses it, trains a model and infers predictions on the test split. + +.. code-block:: bash + + python script_name.py create task_list=[my_task] + python script_name.py pp task_list=[my_task] + python script_name.py train pivot.name=my_task mode.subroutines=[train,predict] mode.cv=false + +See :doc:`usage` for more details on customizing the pipeline via CLI. Note that after the ``create`` call (where +the registered creators are needed) from now on you may omit the ``python script_name.py`` to start the ``mml`` +pipeline and instead type ``mml train ...`` instead. + +Similar libraries +----------------- + +Here is a small comparison to python packages that are close to ``mml``: + * `lightning-hydra-template `_ is a template for deep learning projects, similarly relying on hydra and pytorch lightning, offers much less functionality and configuration options as it is intended to be individually extended for each project, ``mml`` on the other hand tries to unify many tasks, datasets and models in one environment to ease cross project reusability + * `GaNDLF `_ the Generally Nuanced Deep Learning Framework for segmentation, regression and classification has a similar scope to ``mml``, no code requried to train robust models and few code to customize the framework, to name some differences it relies on click instead of hydra, implements training routines itself instead of leveraging pytorch lightning and focuses less on reusability of past experiments + * `MONAI `_ provides state-of-the-art, end-to-end training workflows for healthcare imaging; it implements a lot of metrics, network architectures and transforms specifically to the need of 3D medical image segmentation (but is not limited to this use case), preserving meta information on model training and applicability is also part of the concept, training routine is based on ignite (in contrast to pytorch lignting in ``mml``) + * `OpenMMLab `_ provides an ecosystem of dozens of interoperable toolboxes for computer vision models (e.g. `mmdetection `_ for detection models, `mmpose `_ for pose estimation or `mmpretrain `_ for model pre-training), while expandability and interoperability is a key feature it has minimal dependencies - implementing most features within the ecosystem + +Author and Contributors +------------------------- + +Feel free to leave **bug reports** or **feature requests**: + +Main author (>99%): + +- `Patrick Godau `_ + +Other contributors: + +- `Akriti Srivastava `_ +- `Leon Mayer `_ +- `Dominik Michael `_ +- `Piotr Kalinowski `_ +- `Amine Yamlahi `_ + +Licensing +--------- + +This library is licensed under the permissive `MIT license `_, +which is fully compatible with both **academic** and **commercial** applications. This project is/was supported by + + * the German Federal Ministry of Health under the reference number 2520DAT0P1 as part of the `pAItient `_ (Protected Artificial Intelligence Innovation Environment for Patient Oriented Digital Health Solutions for developing, testing and evidence based evaluation of clinical value) project, + * `HELMHOLTZ IMAGING `_, a platform of the Helmholtz Information & Data Science Incubator and + * the Helmholtz Association under the joint research school `“HIDSS4Health – Helmholtz Information and Data Science School for Health" `_ + +If you use this code in a research paper, **please cite**: + +:: + + @InProceedings{Godau2021TaskF, + author="Godau, Patrick and Maier-Hein, Lena", + editor="de Bruijne, Marleen and Cattin, Philippe C. and Cotin, St{\'e}phane and Padoy, Nicolas and Speidel, Stefanie and Zheng, Yefeng and Essert, Caroline", + title="Task Fingerprinting for Meta Learning inBiomedical Image Analysis", + booktitle="Medical Image Computing and Computer Assisted Intervention -- MICCAI 2021", + year="2021", + publisher="Springer International Publishing", + pages="436--446" + } + + +.. |Pipeline Badge| image:: https://git.dkfz.de/imsy/ise/mml/badges/master/pipeline.svg + :target: https://git.dkfz.de/imsy/ise/mml/-/commits/master +.. |Coverage Badge| image:: https://git.dkfz.de/imsy/ise/mml/badges/master/coverage.svg + :target: https://git.dkfz.de/imsy/ise/mml/-/commits/master +.. |Release Badge| image:: https://git.dkfz.de/imsy/ise/mml/-/badges/release.svg + :target: https://git.dkfz.de/imsy/ise/mml/-/releases +.. |Pylint Badge| image:: https://git.dkfz.de/imsy/ise/mml/-/jobs/artifacts/master/raw/pylint/pylint.svg?job=test-code-quality + :target: https://git.dkfz.de/imsy/ise/mml/-/jobs/artifacts/master/raw/pylint/pylint.log?job=pylint +.. |Python Badge| image:: https://img.shields.io/badge/python-3.8|3.9|3.10-informational + :target: https://www.python.org/doc/versions/ +.. |Docs Badge| image:: https://img.shields.io/badge/docs-sphinx-informational + :target: https://imsy.pages.dkfz.de/ise/mml +.. |Style Badge| image:: https://img.shields.io/badge/style-flake8-informational + :target: https://flake8.pycqa.org/en/latest/ +.. |License Badge| image:: https://img.shields.io/badge/license-MIT-blue + :target: https://opensource.org/license/mit/ + +.. toctree:: + :hidden: + :maxdepth: 1 + :caption: Contents + + install + usage + hpo + plugins + modes + guides + extensions + cli/overview + + +.. toctree:: + :hidden: + :maxdepth: 1 + :caption: API + + api/components + api/overview + api/plugins/overview + + +Indices +======= + + * :ref:`genindex` + * :ref:`modindex` diff --git a/docs/source/install.rst b/docs/source/install.rst new file mode 100644 index 0000000..0a02bf4 --- /dev/null +++ b/docs/source/install.rst @@ -0,0 +1,180 @@ +Installation +============ + +The setup start with the preparation of the `virtual environment `_, followed by +setting your personal system and users `local variables `_. After `testing `_ +your installation you may want to follow some of the optional parts, like +`config copy `_ within your project, `tab completion `_ to increase +CLI convenience or install any of the :doc:`plugins`. +For a quick start without manual installation you may also be interested in using the ``mml`` `docker image `_. + + +Virtual environment +------------------- + +We recommend `conda `_ +as virtual environment manager, but remain fully ``pip`` compatible + +.. code-block:: bash + + conda update -n base -c defaults conda # OPTIONAL: update conda + conda create --yes --name mml python=3.10 # create environment, choose python version + conda activate mml # activate environment, start runs later on with activated environment + +Now create a gitlab access token via `this link `_ +(click "Add Token" and "Create personal access token", no need to configure anything else), do not forget to copy the token once created. +Afterward, within your projects virtual environment you can call + +.. code-block:: bash + + pip install --index-url https://mmlToken:@git.dkfz.de/api/v4/projects/89/packages/pypi/simple mml-core + +and replace with your actual token. + +.. note:: + If you want to contribute to MML we suggest to install from source: clone the ``mml`` repository and install via + ``pip install -e .[dev,docs]`` in editable mode with the extras for documentation generation and linting tools. + +.. note:: + From version ``0.10.0`` the ``mml`` framework was split into the seperate installable packages ``mml-core`` and + diverse plugins. Please do **NOT** install as ``pip install ... mml`` anymore! + +Local variables +--------------- + +``mml`` relies on a ``mml.env`` file for relevant environment variables. There are multiple possibilities to locate this: + + - within the ``mml`` installation itself (e.g. for ``mml`` developers, called the ``default`` location) + - within your project folder (e.g. for separation of ``mml`` installations), + - within your home folder or similar (e.g. for shared ``mml`` configs across installations) + +The actual localization of the file is done as follows: + + - ``mml`` searches for a ``MML_ENV_PATH`` environment variable, if found follow this path + - else check the installation path of the currently running instance and search there for ``src/mml/mml.env`` (the ``default`` location), if found follow this path + - else raise an error + +default location +~~~~~~~~~~~~~~~~ + +If you want to use the ``default`` location, go to ``PROJECT_ROOT/src/mml`` for cloned projects or your interpreters +site-packages for pip installed packages (you can find that with ``pip show mml-core | grep Location``), do the following + + * copy and rename ``example.env`` to ``mml.env`` + +new non default location +~~~~~~~~~~~~~~~~~~~~~~~~ + +If else you want to go with any non-``default`` location you can use ``mml-env-setup`` from the command line at the location +you want to place your ``mml.env`` file: + +.. code-block:: bash + + mml-env-setup + +Afterward make sure to set ``MML_ENV_PATH``, if you use conda environments, there is a +`convenience setup `_ +for this: + +.. code-block:: bash + + conda env config vars set MML_ENV_PATH=/path/to/your/mml.env + # if your file is located at the current working directory, you may instead use + # pwd | conda env config vars set MML_ENV_PATH=$(`_ +for this: + +.. code-block:: bash + + conda env config vars set MML_ENV_PATH=/path/to/your/mml.env + # requires re-activation of environment + conda activate mml + +Test installation +----------------- + +To test the installation you may simply call + +.. code-block:: bash + + mml + +from the command line and check the output. + +.. _config-copy: + +Config copy +----------- + +Since version ``0.6`` ``mml`` supports using a separate configs folder than the one shipped within ``mml`` itself. +This comes in useful if you want to define new config files for your application and/or want to version control +a specific combination of configs that differ from the defaults. +If this is the case or you just want more fine-grained control on the config options, it is possible to create an own +``configs`` folder within your project to control ``mml`` behaviour from there (this is of course not necessary if +``mml`` has been cloned from the repository). +Conveniently this can be achieved by simply navigating to your desired configs root folder (likely your project root folder) +and type ``mml-copy-conf`` to navigate you through this process. Recall that your ``mml.env`` file (see +`above `_) **remains** at the specified location. + +.. note:: + Alternatively if you make your code installable, you can write :doc:`plugins` and just add custom config parts + to the standard config groups of ``mml``! + +Tab completion +-------------- + +The hydra config system allows for tab completion in multiple shells, see +`here `_ for details. +Roughly as example for ``bash`` you can install mml tab completion with ``eval "$(mml -sc install=bash)"``. + + +Docker +------ + + +prerequisites +~~~~~~~~~~~~~ + +For building docker images and running containers you will need docker installed on your system. As ``mml`` depends on using a GPU you will need the nvidia-container-toolkit as well - see `install guide `_ for installation instructions and further information. + + +building the mml image +~~~~~~~~~~~~~~~~~~~~~~ + +We recommend using prebuilt images from the ``mml`` container-registry. However, if you need a custom configuration or just want to build the image yourself you can do so. Adapt the ``Dockerfile`` in the base directory of ``mml`` to your requirements. This will most probably be the used python version, as well as the number of workers and other parameters in the ``mml.env`` file. +Build the image by running: + +.. code-block:: bash + + docker build . -t + + +running the container +~~~~~~~~~~~~~~~~~~~~~ + +If you have access to the ``mml`` container-registry or built the image yourself and installed all necessary prerequisites you're ready to go. +To start your container just run: + +.. code-block:: bash + + docker run -v :/data -v :/results --ipc=host --gpus=all -i -t + +Inside the container you can just start using ``mml`` like you would from your local bash. + +.. note:: + The paths you use for running the docker container are mounted from your host computer, so data that's already present can be used directly and all changes in data and results are accessible from your host and persist after closing the container. \ No newline at end of file diff --git a/docs/source/modes.rst b/docs/source/modes.rst new file mode 100644 index 0000000..faa8d1a --- /dev/null +++ b/docs/source/modes.rst @@ -0,0 +1,11 @@ +Modes +===== + +.. toctree:: + :maxdepth: 1 + :name: mode-examples + :glob: + :reversed: + :titlesonly: + + notebooks/mml-modes/* diff --git a/docs/source/notebooks/mml-modes/create.ipynb b/docs/source/notebooks/mml-modes/create.ipynb new file mode 100644 index 0000000..081923d --- /dev/null +++ b/docs/source/notebooks/mml-modes/create.ipynb @@ -0,0 +1,143 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Create mode\n", + "\n", + "This notebook depicts the `create` mode. It is used to generate the underlying data for a task. Task creation is the very first step that needs to be taken\n", + "in order to use it for processing. The `mml-data` plugin provides the creators to generate a variety of tasks. But we stick to the `mml_fake_task` implemented in\n", + "`mml-core` for simplicity.\n", + "\n" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 4, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[\u001B[36m2024-01-17 13:37:19,383\u001B[0m][\u001B[34mmml\u001B[0m][\u001B[32mINFO\u001B[0m] - Started MML 0.12.0 on Python 3.8.13 with mode CREATE.\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:19,383\u001B[0m][\u001B[34mmml\u001B[0m][\u001B[32mINFO\u001B[0m] - Plugins loaded: ['mml-data', 'mml-tags', 'mml-dimensionality', 'mml-inference', 'mml-sql', 'mml-similarity']\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:19,526\u001B[0m][\u001B[34mmml\u001B[0m][\u001B[32mINFO\u001B[0m] - MML init time was 0.0h 0.0m 0.14s.\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:19,527\u001B[0m][\u001B[34mmml.core.scripts.schedulers.create_scheduler\u001B[0m][\u001B[32mINFO\u001B[0m] - Starting task creation!\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:19,528\u001B[0m][\u001B[34mmml.core.scripts.schedulers.create_scheduler\u001B[0m][\u001B[32mINFO\u001B[0m] - Starting preparing dataset \u001B[33m\u001B[46m\u001B[1mmml_fake_dataset\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:19,530\u001B[0m][\u001B[34mmml.core.data_loading.file_manager\u001B[0m][\u001B[32mINFO\u001B[0m] - Found and reuse already existing download folder for dataset mml_fake_dataset @ /home/scholzpa/Pictures/datasets/mml_data/DOWNLOADS/mml_fake_dataset.\u001B[0m\r\n", + "Transfering training data: 100%|███████████| 1000/1000 [00:03<00:00, 277.82it/s]\r\n", + "Transfering testing data: 100%|██████████████| 500/500 [00:01<00:00, 280.32it/s]\r\n", + "[\u001B[36m2024-01-17 13:37:24,915\u001B[0m][\u001B[34mmml.core.scripts.schedulers.create_scheduler\u001B[0m][\u001B[32mINFO\u001B[0m] - Finished preparing dataset \u001B[33m\u001B[46m\u001B[1mmml_fake_dataset\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:24,916\u001B[0m][\u001B[34mmml.core.scripts.schedulers.create_scheduler\u001B[0m][\u001B[32mINFO\u001B[0m] - Starting preparing task \u001B[33m\u001B[46m\u001B[1mmml_fake_task\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:24,919\u001B[0m][\u001B[34mmml.core.data_preparation.task_creator\u001B[0m][\u001B[33mWARNING\u001B[0m] - Task name mml_fake_task already used with prepossessings dict_keys(['default', 'size512', 'size256']).\u001B[0m\r\n", + "Scanning train data: 100%|███████████████| 1000/1000 [00:00<00:00, 27284.29it/s]\r\n", + "[\u001B[36m2024-01-17 13:37:24,962\u001B[0m][\u001B[34mmml.core.data_preparation.task_creator\u001B[0m][\u001B[32mINFO\u001B[0m] - Found 1000 items in train.\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:24,968\u001B[0m][\u001B[34mmml.core.data_loading.file_manager\u001B[0m][\u001B[32mINFO\u001B[0m] - Writing task description at /home/scholzpa/Pictures/datasets/mml_data/RAW/DSET_mml_fake_dataset/temp.json.\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:24,977\u001B[0m][\u001B[34mmml.core.data_preparation.utils\u001B[0m][\u001B[32mINFO\u001B[0m] - Calculating mean, std and size. This may take a couple of minutes.\u001B[0m\r\n", + "Gathering sizes: 100%|███████████████████| 1000/1000 [00:00<00:00, 12743.30it/s]\r\n", + "Gathering mean and std: 100%|███████████████████| 10/10 [00:01<00:00, 8.88it/s]\r\n", + "[\u001B[36m2024-01-17 13:37:26,320\u001B[0m][\u001B[34mmml.core.data_loading.file_manager\u001B[0m][\u001B[32mINFO\u001B[0m] - Writing task description at /home/scholzpa/Pictures/datasets/mml_data/RAW/DSET_mml_fake_dataset/TASK_mml_fake_task.json.\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:26,322\u001B[0m][\u001B[34mmml.core.data_preparation.task_creator\u001B[0m][\u001B[32mINFO\u001B[0m] - Testing the loading of /home/scholzpa/Pictures/datasets/mml_data/RAW/DSET_mml_fake_dataset/TASK_mml_fake_task.json...\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:26,328\u001B[0m][\u001B[34mmml.core.data_preparation.task_creator\u001B[0m][\u001B[32mINFO\u001B[0m] - Testing of /home/scholzpa/Pictures/datasets/mml_data/RAW/DSET_mml_fake_dataset/TASK_mml_fake_task.json finished, dataset loading time was 0.01 seconds, sample loading time was 0.00 seconds.\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:26,329\u001B[0m][\u001B[34mmml.core.scripts.schedulers.create_scheduler\u001B[0m][\u001B[32mINFO\u001B[0m] - Finished preparing task \u001B[33m\u001B[46m\u001B[1mmml_fake_task\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:26,330\u001B[0m][\u001B[34mmml.core.data_loading.file_manager\u001B[0m][\u001B[32mINFO\u001B[0m] - A total of 0 paths have been created during this run.\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:26,330\u001B[0m][\u001B[34mmml.core.scripts.schedulers.base_scheduler\u001B[0m][\u001B[32mINFO\u001B[0m] - Successfully finished all experiments!\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:26,330\u001B[0m][\u001B[34mmml\u001B[0m][\u001B[32mINFO\u001B[0m] - MML run time was 0.0h 0.0m 6.80s.\u001B[0m\r\n" + ] + } + ], + "source": "!mml create task_list=[mml_fake_task]", + "metadata": { + "collapsed": false, + "ExecuteTime": { + "start_time": "2024-01-17T13:37:15.577387Z", + "end_time": "2024-01-17T13:37:27.007079Z" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "After creation we can see some information on the task with `info` mode." + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 5, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[\u001B[36m2024-01-17 13:37:49,066\u001B[0m][\u001B[34mmml\u001B[0m][\u001B[32mINFO\u001B[0m] - Started MML 0.12.0 on Python 3.8.13 with mode INFO.\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:49,067\u001B[0m][\u001B[34mmml\u001B[0m][\u001B[32mINFO\u001B[0m] - Plugins loaded: ['mml-data', 'mml-tags', 'mml-dimensionality', 'mml-inference', 'mml-sql', 'mml-similarity']\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:49,211\u001B[0m][\u001B[34mmml.core.scripts.schedulers.info_scheduler\u001B[0m][\u001B[32mINFO\u001B[0m] - Was given no study name to search for, so showing all studies with project prefix.\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:49,212\u001B[0m][\u001B[34mmml\u001B[0m][\u001B[32mINFO\u001B[0m] - MML init time was 0.0h 0.0m 0.15s.\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:49,213\u001B[0m][\u001B[34mmml.core.scripts.schedulers.base_scheduler\u001B[0m][\u001B[32mINFO\u001B[0m] - Preparing experiment ...\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:49,214\u001B[0m][\u001B[34mmml.core.scripts.schedulers.base_scheduler\u001B[0m][\u001B[32mINFO\u001B[0m] - Starting experiment!\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:49,214\u001B[0m][\u001B[34mmml.core.scripts.schedulers.info_scheduler\u001B[0m][\u001B[32mINFO\u001B[0m] - Starting info on task \u001B[33m\u001B[46m\u001B[1mmml_fake_task\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:49,214\u001B[0m][\u001B[34mmml.core.scripts.schedulers.info_scheduler\u001B[0m][\u001B[32mINFO\u001B[0m] - Task name: mml_fake_task\r\n", + "Task type: classification\r\n", + "Num classes: 10\r\n", + "Means: RGBInfo(r=0.49829596281051636, g=0.49836331605911255, b=0.498288631439209)\r\n", + "Stds: RGBInfo(r=0.1517328917980194, g=0.15169444680213928, b=0.1517714262008667)\r\n", + "Sizes: Sizes(min_height=256, max_height=256, min_width=256, max_width=256)\r\n", + "Class occ: {'J': 96, 'C': 103, 'I': 127, 'A': 93, 'B': 95, 'F': 93, 'E': 93, 'D': 121, 'H': 89, 'G': 90}\r\n", + "Preprocessed: default\r\n", + "Task keywords: ['artificial']\r\n", + "paths: {}\r\n", + "models: []\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:49,224\u001B[0m][\u001B[34mmml.core.scripts.schedulers.info_scheduler\u001B[0m][\u001B[32mINFO\u001B[0m] - Num samples (full train set): 1000\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:49,224\u001B[0m][\u001B[34mmml.core.scripts.schedulers.info_scheduler\u001B[0m][\u001B[32mINFO\u001B[0m] - Default validation class occurrences are: {2: 21, 7: 18, 9: 19, 0: 19, 3: 24, 8: 25, 4: 19, 1: 19, 5: 19, 6: 18}\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:49,224\u001B[0m][\u001B[34mmml.core.scripts.schedulers.info_scheduler\u001B[0m][\u001B[32mINFO\u001B[0m] - Finished info on task \u001B[33m\u001B[46m\u001B[1mmml_fake_task\u001B[0m\r\n", + "[\u001B[36m2024-01-17 13:37:49,225\u001B[0m][\u001B[34mmml.core.scripts.schedulers.info_scheduler\u001B[0m][\u001B[32mINFO\u001B[0m] - Starting plotting sample grid of all tasks.\u001B[0m\r\n", + "Loading samples: 0%| | 0/1 [00:00>> tensorboard --logdir path/to/MML_RESULTS/DEMO2\n", + ">>> Open browser -> http://localhost:6006\n" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + } + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/docs/source/notebooks/mml-modes/upgrade.ipynb b/docs/source/notebooks/mml-modes/upgrade.ipynb new file mode 100644 index 0000000..e0cf97b --- /dev/null +++ b/docs/source/notebooks/mml-modes/upgrade.ipynb @@ -0,0 +1,57 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Upgrade and Downgrade\n", + "\n", + "Whenever a breaking change happens `MML` tries to silently handle these internally (e.g. the switch from `.yaml` to `.json` format in storing `ModelStorage`, where\n", + "loading old `.yaml` files is still possible). Occasionally breaking changes require an upgrade of the underlying MML_EXPS and MML_DATA directories. This is where the\n", + "upgrade mode allows to switch versions with ease.\n", + "\n", + "For example `mml-core=0.12.0` changed the data backend, hence when coming from any version below an upgrade is necessary. This is performed via first upgrading `mml-core` to a version at least `0.12.0` and then calling.\n", + "\n", + "`mml upgrade mode.version=0.11.1`\n", + "\n", + "(if coming from version `0.11.1` before). The scheduler handles multiple upgrades internally so there is no need in upgrading step wise manually: simple upgrade `mml-core` to the most recent version and provide your previous version via `mode.version`.\n", + "\n", + "If you want to downgrade the necessary steps are almost identical, but the order is reversed: With the current `mml-core` version call\n", + "\n", + "`mml downgrade mode.version=0.11.1`\n", + "\n", + "(if you want to downgrade your files to a `0.11.1` compatible version). And afterward downgrade `mml-core` itself." + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "markdown", + "source": [], + "metadata": { + "collapsed": false + } + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/docs/source/notebooks/tricks/.ipynb_checkpoints/baseline-checkpoint.ipynb b/docs/source/notebooks/tricks/.ipynb_checkpoints/baseline-checkpoint.ipynb new file mode 100644 index 0000000..850e600 --- /dev/null +++ b/docs/source/notebooks/tricks/.ipynb_checkpoints/baseline-checkpoint.ipynb @@ -0,0 +1,387 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "899624e8ac3a5979", + "metadata": {}, + "source": [ + "# Baseline\n", + "\n", + "This guide is a good beginning to familiarize with basic `mml` usage. The goal is to run some baseline models for an existing task. We will use the widely known `MNIST` dataset for demonstration purposes.\n", + "\n", + "## Step 1: Prepare data\n", + "\n", + "`MNIST` is already available in `mml` through the `mml-data` plugin, which might be installed through `pip` easily.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "4896f0ce2d0385ea", + "metadata": { + "ExecuteTime": { + "end_time": "2024-11-22T14:14:38.123607Z", + "start_time": "2024-11-22T14:14:37.118505Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Name: mml-data\r\n", + "Version: 0.3.0\r\n", + "Summary: This is the MML data plugin, providing dataset and task implementation for a bunch of datasets.\r\n", + "Home-page: https://git.dkfz.de/imsy/ise/mml\r\n", + "Author: Patrick Godau\r\n", + "Author-email: patrick.scholz@dkfz-heidelberg.de\r\n", + "License: \r\n", + "Location: /home/scholzpa/Documents/development/gitlab/mml/plugins/data/src\r\n", + "Requires: mml-core\r\n", + "Required-by: \r\n" + ] + } + ], + "source": [ + "!pip show mml-data" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "eb0ef16dadb7b3f2", + "metadata": { + "ExecuteTime": { + "end_time": "2024-11-22T14:15:09.023643Z", + "start_time": "2024-11-22T14:15:01.134140Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/home/scholzpa/miniconda3/envs/mml/lib/python3.8/site-packages/kornia/feature/lightglue.py:44: FutureWarning: `torch.cuda.amp.custom_fwd(args...)` is deprecated. Please use `torch.amp.custom_fwd(args..., device_type='cuda')` instead.\r\n", + " @torch.cuda.amp.custom_fwd(cast_inputs=torch.float32)\r\n", + "\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m name \u001b[34m|\u001b[0m\u001b[96m dataset \u001b[34m|\u001b[0m\u001b[96m type \u001b[34m|\u001b[0m\u001b[96m installed \u001b[34m|\u001b[0m\u001b[96m license \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m idle_action_recognition \u001b[34m|\u001b[0m\u001b[96m idle_action \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m bean_plant_disease_classification \u001b[34m|\u001b[0m\u001b[96m ibean \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m MIT \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m caltech101_object_classification \u001b[34m|\u001b[0m\u001b[96m caltech101 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cifar10_object_classification \u001b[34m|\u001b[0m\u001b[96m cifar10 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cifar100_object_classification \u001b[34m|\u001b[0m\u001b[96m cifar100 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m sklin2_skin_lesions \u001b[34m|\u001b[0m\u001b[96m sklin2 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m barretts_esophagus_diagnosis \u001b[34m|\u001b[0m\u001b[96m barretts_esophagus \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mura_xr_wrist \u001b[34m|\u001b[0m\u001b[96m mura \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mura_xr_shoulder \u001b[34m|\u001b[0m\u001b[96m mura \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mura_xr_humerus \u001b[34m|\u001b[0m\u001b[96m mura \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mura_xr_hand \u001b[34m|\u001b[0m\u001b[96m mura \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mura_xr_forearm \u001b[34m|\u001b[0m\u001b[96m mura \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mura_xr_finger \u001b[34m|\u001b[0m\u001b[96m mura \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mura_xr_elbow \u001b[34m|\u001b[0m\u001b[96m mura \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m eye_condition_classification \u001b[34m|\u001b[0m\u001b[96m cataract \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m brain_tumor_classification \u001b[34m|\u001b[0m\u001b[96m brain_tumor \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m derm7pt_skin_lesions \u001b[34m|\u001b[0m\u001b[96m derm7pt \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m covid-19-chest-ct-image-augmentation_raw \u001b[34m|\u001b[0m\u001b[96m covid_chest_ct \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m DATABASE_CONTENTS_LICENSE_1_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m covid-19-chest-ct-image-augmentation_Aug \u001b[34m|\u001b[0m\u001b[96m covid_chest_ct \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m DATABASE_CONTENTS_LICENSE_1_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m covid-19-chest-ct-image-augmentation_CGAN \u001b[34m|\u001b[0m\u001b[96m covid_chest_ct \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m DATABASE_CONTENTS_LICENSE_1_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m covid-19-chest-ct-image-augmentation_Aug&CGAN \u001b[34m|\u001b[0m\u001b[96m covid_chest_ct \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m DATABASE_CONTENTS_LICENSE_1_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m deep_drid_quality \u001b[34m|\u001b[0m\u001b[96m deep_drid \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m deep_drid_dr_level \u001b[34m|\u001b[0m\u001b[96m deep_drid \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m deep_drid_clarity \u001b[34m|\u001b[0m\u001b[96m deep_drid \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m deep_drid_field \u001b[34m|\u001b[0m\u001b[96m deep_drid \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m deep_drid_artifact \u001b[34m|\u001b[0m\u001b[96m deep_drid \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m caltech256_object_classification \u001b[34m|\u001b[0m\u001b[96m caltech256 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m emnist_digit_classification \u001b[34m|\u001b[0m\u001b[96m emnist \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m kvasir_capsule_anatomy \u001b[34m|\u001b[0m\u001b[96m kvasir_capsule \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m kvasir_capsule_content \u001b[34m|\u001b[0m\u001b[96m kvasir_capsule \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m kvasir_capsule_pathologies \u001b[34m|\u001b[0m\u001b[96m kvasir_capsule \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m suncolondb-classification \u001b[34m|\u001b[0m\u001b[96m SUNdatabase \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m False \u001b[34m|\u001b[0m\u001b[96m CUSTOM \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m brain_tumor_type_classification \u001b[34m|\u001b[0m\u001b[96m brain_tumor_type \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m breast_cancer_classification_v2 \u001b[34m|\u001b[0m\u001b[96m breast_ultrasound \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_0_1_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m stanford_dogs_image_categorization \u001b[34m|\u001b[0m\u001b[96m stanford_dogs \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m hyperkvasir_anatomical-landmarks \u001b[34m|\u001b[0m\u001b[96m hyperkvasir \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m hyperkvasir_pathological-findings \u001b[34m|\u001b[0m\u001b[96m hyperkvasir \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m hyperkvasir_quality-of-mucosal-views \u001b[34m|\u001b[0m\u001b[96m hyperkvasir \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m hyperkvasir_therapeutic-interventions \u001b[34m|\u001b[0m\u001b[96m hyperkvasir \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m nerthus_bowel_cleansing_quality \u001b[34m|\u001b[0m\u001b[96m nerthus \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cervix_type_classification \u001b[34m|\u001b[0m\u001b[96m cervical_screening \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m False \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m laryngeal_tissues \u001b[34m|\u001b[0m\u001b[96m laryngeal \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m laryngeal_tissues_original_folds \u001b[34m|\u001b[0m\u001b[96m laryngeal \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m pneumonia_classification \u001b[34m|\u001b[0m\u001b[96m pneumonia \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m lapgyn4_anatomical_structures \u001b[34m|\u001b[0m\u001b[96m lapgyn4 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m lapgyn4_surgical_actions \u001b[34m|\u001b[0m\u001b[96m lapgyn4 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m lapgyn4_instrument_count \u001b[34m|\u001b[0m\u001b[96m lapgyn4 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m lapgyn4_anatomical_actions \u001b[34m|\u001b[0m\u001b[96m lapgyn4 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m shenzen_chest_xray_tuberculosis \u001b[34m|\u001b[0m\u001b[96m shenzhen_xray_tb \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholect45_triplet \u001b[34m|\u001b[0m\u001b[96m cholect45 \u001b[34m|\u001b[0m\u001b[96m multilabel_classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholect45_instrument \u001b[34m|\u001b[0m\u001b[96m cholect45 \u001b[34m|\u001b[0m\u001b[96m multilabel_classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholect45_verb \u001b[34m|\u001b[0m\u001b[96m cholect45 \u001b[34m|\u001b[0m\u001b[96m multilabel_classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholect45_target \u001b[34m|\u001b[0m\u001b[96m cholect45 \u001b[34m|\u001b[0m\u001b[96m multilabel_classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholect45_triplet_soft \u001b[34m|\u001b[0m\u001b[96m cholect45 \u001b[34m|\u001b[0m\u001b[96m multilabel_classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m svhn \u001b[34m|\u001b[0m\u001b[96m svhn \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholec80_grasper_presence \u001b[34m|\u001b[0m\u001b[96m cholec80 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholec80_bipolar_presence \u001b[34m|\u001b[0m\u001b[96m cholec80 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholec80_hook_presence \u001b[34m|\u001b[0m\u001b[96m cholec80 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholec80_scissors_presence \u001b[34m|\u001b[0m\u001b[96m cholec80 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholec80_clipper_presence \u001b[34m|\u001b[0m\u001b[96m cholec80 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholec80_irrigator_presence \u001b[34m|\u001b[0m\u001b[96m cholec80 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholec80_specimenbag_presence \u001b[34m|\u001b[0m\u001b[96m cholec80 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_enlarged_cardiomediastinum \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_cardiomegaly \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_lung_opacity \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_lung_lesion \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_edema \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_consolidation \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_pneumonia \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_atelectasis \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_pneumothorax \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_pleural_effusion \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_pleural_other \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_fracture \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_support_devices \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m identify_nbi_infframes \u001b[34m|\u001b[0m\u001b[96m nbi_infframes \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m identify_nbi_infframes_original_folds \u001b[34m|\u001b[0m\u001b[96m nbi_infframes \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m False \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m covid_xray_classification \u001b[34m|\u001b[0m\u001b[96m covid_xray \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_0_1_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m aptos19_blindness_detection \u001b[34m|\u001b[0m\u001b[96m aptos_blindness \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m isic20_melanoma_classification \u001b[34m|\u001b[0m\u001b[96m isic20 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mnist_digit_classification \u001b[34m|\u001b[0m\u001b[96m mnist \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m crawled_covid_ct_classification \u001b[34m|\u001b[0m\u001b[96m covid_ct_crawled \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mednode_melanoma_classification \u001b[34m|\u001b[0m\u001b[96m mednode \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m ph2-melanocytic-lesions-segmentation \u001b[34m|\u001b[0m\u001b[96m PH2 \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m ph2-melanocytic-lesions-classification \u001b[34m|\u001b[0m\u001b[96m PH2 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m pascal_voc_challenge_2012 \u001b[34m|\u001b[0m\u001b[96m VOC12 \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m endovissub18_robotic_instrument_seg \u001b[34m|\u001b[0m\u001b[96m endovis18_rob_instr \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m glenda_endometriosis_segmentation \u001b[34m|\u001b[0m\u001b[96m glenda \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m hyperkvasir_polyp_segmentation \u001b[34m|\u001b[0m\u001b[96m hyperkvasir_seg \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m motion-based-segmentation \u001b[34m|\u001b[0m\u001b[96m motion-based-rec \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m crowdsourced-endoscopic-instrument-segmentation-crowd-only \u001b[34m|\u001b[0m\u001b[96m crowdsourced-EIS \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m endometrial_implants \u001b[34m|\u001b[0m\u001b[96m enid \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m image2image-raw \u001b[34m|\u001b[0m\u001b[96m image2image \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m image2image-rand \u001b[34m|\u001b[0m\u001b[96m image2image \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m image2image-cholec80 \u001b[34m|\u001b[0m\u001b[96m image2image \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[0m\r\n", + "Overall 96 raw tasks available, from 48 datasets. Filter matches 95 raw tasks with additional 248 variants derived thereof.\r\n", + "\u001b[0m" + ] + } + ], + "source": [ + "# available datasets\n", + "!mml-data" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "f77519e1c16b242f", + "metadata": { + "ExecuteTime": { + "end_time": "2024-11-22T14:16:29.406429Z", + "start_time": "2024-11-22T14:16:22.942232Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/home/scholzpa/miniconda3/envs/mml/lib/python3.8/site-packages/kornia/feature/lightglue.py:44: FutureWarning: `torch.cuda.amp.custom_fwd(args...)` is deprecated. Please use `torch.amp.custom_fwd(args..., device_type='cuda')` instead.\r\n", + " @torch.cuda.amp.custom_fwd(cast_inputs=torch.float32)\r\n", + "[\u001b[36m2024-11-22 15:16:28,080\u001b[0m][\u001b[34mmml\u001b[0m][\u001b[32mINFO\u001b[0m] - Started MML 0.14.2 on Python 3.8.12 with mode CREATE.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:16:28,080\u001b[0m][\u001b[34mmml\u001b[0m][\u001b[32mINFO\u001b[0m] - Plugins loaded: ['mml-data', 'mml-dimensionality', 'mml-similarity', 'mml-tags', 'mml-sql', 'mml-drive', 'mml-lsf', 'mml-suggest', 'mml-prevalences', 'mml-tf']\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:16:28,305\u001b[0m][\u001b[34mmml.core.scripts.schedulers.create_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Skipping creation of task mnist_digit_classification because there already seems to be a RAW version of that.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:16:28,305\u001b[0m][\u001b[34mmml.core.scripts.schedulers.base_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Executing after init hook: check_lsf_workers\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:16:28,306\u001b[0m][\u001b[34mmml_lsf.workers\u001b[0m][\u001b[32mINFO\u001b[0m] - LSF cluster plugin detected local system, no changes made to the number of workers.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:16:28,306\u001b[0m][\u001b[34mmml\u001b[0m][\u001b[32mINFO\u001b[0m] - MML init time was 0.0h 0.0m 0.23s.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:16:28,360\u001b[0m][\u001b[34mmml.core.data_loading.file_manager\u001b[0m][\u001b[32mINFO\u001b[0m] - A total of 0 paths have been created during this run.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:16:28,361\u001b[0m][\u001b[34mmml.core.scripts.schedulers.base_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Successfully finished all experiments!\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:16:28,361\u001b[0m][\u001b[34mmml\u001b[0m][\u001b[32mINFO\u001b[0m] - MML run time was 0.0h 0.0m 0.05s.\u001b[0m\r\n" + ] + } + ], + "source": [ + "# install data for MNIST (data already installed here, might take a couple of minutes depending on hardware and ethernet connection)\n", + "!mml create task_list=[mnist_digit_classification]" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "bfece1f893e49e8f", + "metadata": { + "ExecuteTime": { + "end_time": "2024-11-22T14:21:05.831035Z", + "start_time": "2024-11-22T14:18:15.345112Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/home/scholzpa/miniconda3/envs/mml/lib/python3.8/site-packages/kornia/feature/lightglue.py:44: FutureWarning: `torch.cuda.amp.custom_fwd(args...)` is deprecated. Please use `torch.amp.custom_fwd(args..., device_type='cuda')` instead.\r\n", + " @torch.cuda.amp.custom_fwd(cast_inputs=torch.float32)\r\n", + "[\u001b[36m2024-11-22 15:18:20,420\u001b[0m][\u001b[34mmml\u001b[0m][\u001b[32mINFO\u001b[0m] - Started MML 0.14.2 on Python 3.8.12 with mode PP.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:20,420\u001b[0m][\u001b[34mmml\u001b[0m][\u001b[32mINFO\u001b[0m] - Plugins loaded: ['mml-data', 'mml-dimensionality', 'mml-similarity', 'mml-tags', 'mml-sql', 'mml-drive', 'mml-lsf', 'mml-suggest', 'mml-prevalences', 'mml-tf']\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:20,649\u001b[0m][\u001b[34mmml.core.scripts.schedulers.base_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Executing after init hook: check_lsf_workers\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:20,650\u001b[0m][\u001b[34mmml_lsf.workers\u001b[0m][\u001b[32mINFO\u001b[0m] - LSF cluster plugin detected local system, no changes made to the number of workers.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:20,657\u001b[0m][\u001b[34mmml\u001b[0m][\u001b[32mINFO\u001b[0m] - MML init time was 0.0h 0.0m 0.24s.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:20,659\u001b[0m][\u001b[34mmml.core.scripts.schedulers.base_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Preparing experiment ...\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:20,660\u001b[0m][\u001b[34mmml.core.scripts.schedulers.base_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Starting experiment!\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:20,660\u001b[0m][\u001b[34mmml.core.scripts.schedulers.preprocess_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Starting preprocessing data for task \u001b[33m\u001b[46m\u001b[1mmnist_digit_classification\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:20,660\u001b[0m][\u001b[34mpy.warnings\u001b[0m][\u001b[33mWARNING\u001b[0m] - /home/scholzpa/Documents/development/gitlab/mml/src/mml/core/scripts/schedulers/preprocess_scheduler.py:101: UserWarning: THIS BEHAVIOUR CHANGED: Test data is now also to be preprocessed!\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:21,009\u001b[0m][\u001b[34mmml.core.scripts.schedulers.preprocess_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Preprocessing split: full_train\u001b[0m\r\n", + "100%|███████████████████████████████████| 60000/60000 [00:23<00:00, 2564.80it/s]\r\n", + "[\u001b[36m2024-11-22 15:18:44,669\u001b[0m][\u001b[34mmml.core.scripts.schedulers.preprocess_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Existing full_train files found:\r\n", + "image 0\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:44,670\u001b[0m][\u001b[34mmml.core.scripts.schedulers.preprocess_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Preprocessing split: test\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:44,670\u001b[0m][\u001b[34mmml.core.scripts.schedulers.preprocess_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - No samples in split: test\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:44,670\u001b[0m][\u001b[34mmml.core.scripts.schedulers.preprocess_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Preprocessing split: unlabelled\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:44,670\u001b[0m][\u001b[34mmml.core.scripts.schedulers.preprocess_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - No samples in split: unlabelled\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:45,041\u001b[0m][\u001b[34mmml.core.data_loading.file_manager\u001b[0m][\u001b[32mINFO\u001b[0m] - Writing task description at /home/scholzpa/Pictures/datasets/mml_data/PREPROCESSED/size224/DSET_mnist/temp.json.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:45,122\u001b[0m][\u001b[34mmml.core.data_preparation.utils\u001b[0m][\u001b[32mINFO\u001b[0m] - Calculating mean, std and size. This may take a couple of minutes.\u001b[0m\r\n", + "Gathering sizes: 100%|█████████████████| 60000/60000 [00:05<00:00, 11661.43it/s]\r\n", + "Gathering mean and std: 100%|█████████████████| 600/600 [02:12<00:00, 4.53it/s]\r\n", + "[\u001b[36m2024-11-22 15:21:03,916\u001b[0m][\u001b[34mmml.core.data_loading.file_manager\u001b[0m][\u001b[32mINFO\u001b[0m] - Writing task description at /home/scholzpa/Pictures/datasets/mml_data/PREPROCESSED/size224/DSET_mnist/TASK_mnist_digit_classification.json.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:21:03,998\u001b[0m][\u001b[34mmml.core.data_preparation.task_creator\u001b[0m][\u001b[32mINFO\u001b[0m] - Testing the loading of /home/scholzpa/Pictures/datasets/mml_data/PREPROCESSED/size224/DSET_mnist/TASK_mnist_digit_classification.json...\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:21:04,601\u001b[0m][\u001b[34mmml.core.data_preparation.task_creator\u001b[0m][\u001b[32mINFO\u001b[0m] - Testing of /home/scholzpa/Pictures/datasets/mml_data/PREPROCESSED/size224/DSET_mnist/TASK_mnist_digit_classification.json finished, dataset loading time was 0.60 seconds, sample loading time was 0.00 seconds.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:21:04,615\u001b[0m][\u001b[34mmml.core.scripts.schedulers.preprocess_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Finished preprocessing the data for task \u001b[33m\u001b[46m\u001b[1mmnist_digit_classification\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:21:04,630\u001b[0m][\u001b[34mmml.core.data_loading.file_manager\u001b[0m][\u001b[32mINFO\u001b[0m] - A total of 0 paths have been created during this run.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:21:04,630\u001b[0m][\u001b[34mmml.core.scripts.schedulers.base_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Successfully finished all experiments!\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:21:04,630\u001b[0m][\u001b[34mmml\u001b[0m][\u001b[32mINFO\u001b[0m] - MML run time was 0.0h 2.0m 43.97s.\u001b[0m\r\n" + ] + } + ], + "source": [ + "# preprocess task\n", + "!mml pp task_list=[mnist_digit_classification] preprocessing=size224" + ] + }, + { + "cell_type": "markdown", + "id": "9fa178d147376fee", + "metadata": {}, + "source": [ + "## Step 2: Use defaults for training" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33891aeb2bbf72bf", + "metadata": {}, + "outputs": [], + "source": [ + "# to run a single training\n", + "!mml train pivot.name=mnist_digit_classification preprocessing=size224 proj=demo_baseline\n", + "# afterwards inspect the training via running tensorboard and inspecting through the browser\n", + "!tensorboard --logdir /path/to/mml/results/demo_baseline" + ] + }, + { + "cell_type": "markdown", + "id": "76000e8998ee5df5", + "metadata": {}, + "source": [ + "![image not found](../../../../docs/source/_static/tensorboard_example.png \"Tensorboard view\")" + ] + }, + { + "cell_type": "markdown", + "id": "49c76e16e67254d1", + "metadata": {}, + "source": [ + "## Step 3: Optimizing hyperparameters\n", + "\n", + "We will perform a simple grid search with a couple of architectures & augmentation strategies." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6556cc458ea30636", + "metadata": {}, + "outputs": [], + "source": [ + "# to run a hyperparameter search (here: grid search with 3 models x 3 augmentation strategies),\n", + "# to speed things up: no cross-validation, only 1 epoch, deactivated learning rate tuning\n", + "!mml train pivot.name=mnist_digit_classification preprocessing=size224 arch.name=resnet18,tiny_vit_21m_224.dist_in22k_ft_in1k,tf_efficientnet_b0.ns_jft_in1k augmentations=basic,randaugment,load_imagenet_aa proj=demo_grid trainer.max_epochs=1 tune.lr=false sampling.batch_size=100 mode.cv=false mode.nested=False +hpo/sampler=grid --multirun" + ] + }, + { + "cell_type": "markdown", + "id": "d1c658d74afcc506", + "metadata": {}, + "source": [ + "at the end it prints:\n", + "\n", + "> [HYDRA] Best parameters: {'arch.name': 'tiny_vit_21m_224.dist_in22k_ft_in1k', 'augmentations': 'randaugment'}\n", + "> [HYDRA] Best value: 0.0211497992277145" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c67617588ea39032", + "metadata": {}, + "outputs": [], + "source": [ + "# use the best hyperparameters in a full training run (the use_best_params is the name of our search, a folder inside the proj folder, inside \"hpo\", i.e. MML_RESULTS_PATH/demo_grid/hpo/2024-12-03_12-28-46_362374)\n", + "!mml train proj=demo_grid use_best_params=2024-12-03_12-28-46_362374 pivot.name=mnist_digit_classification" + ] + }, + { + "cell_type": "markdown", + "id": "2ff83f854dbba771", + "metadata": {}, + "source": [ + "[mml][INFO] - -------------------------------------------------------------------------------------\n", + "[mml][INFO] - Loaded hpo results from study 2024-12-03_12-28-46_362374 and merged 2 params into config.\n", + "[mml][INFO] - > arch.name=tiny_vit_21m_224.dist_in22k_ft_in1k\n", + "[mml][INFO] - > augmentations=randaugment\n", + "[mml][INFO] - -------------------------------------------------------------------------------------\n", + "[mml][INFO] - Started MML 0.14.2 on Python 3.10.9 with mode TRAIN.\n", + "..." + ] + }, + { + "cell_type": "markdown", + "id": "f3abca00-12e0-4993-9709-5cbb5d8b9d0f", + "metadata": {}, + "source": [ + "For more complex optimization setups (e.g. multi node optimization) one may use the `mml-sql` plugin. See the plugin documentation for installation and setup instructions. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62bf1503-ca31-4d8c-a86b-5c7bfa614d89", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/source/notebooks/tricks/.ipynb_checkpoints/cluster_integration-checkpoint.ipynb b/docs/source/notebooks/tricks/.ipynb_checkpoints/cluster_integration-checkpoint.ipynb new file mode 100644 index 0000000..d57eb29 --- /dev/null +++ b/docs/source/notebooks/tricks/.ipynb_checkpoints/cluster_integration-checkpoint.ipynb @@ -0,0 +1,58 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "605dfe269fb7d31", + "metadata": {}, + "source": [ + "# mml on a cluster\n", + "\n", + "Especially for large scale or hardware demanding experiments it is nice to outsource experiments to a cluster. It is straightforward to set up `mml` for compatible use throughout multiple systems. `mml` ships with a `cluster` configuration provided within `configs/sys`. It loads the environment variables `MML_CLUSTER_DATA_PATH`, `MML_CLUSTER_RESULTS_PATH` and `MML_CLUSTER_WORKERS` exported in the `mml.env` file instead of the local ones (adding even more system configurations can be achieved similarly via additional `sys` config files). Now the only difference in calling `mml` becomes:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "initial_id", + "metadata": { + "collapsed": true, + "jupyter": { + "outputs_hidden": true + } + }, + "outputs": [], + "source": [ + "!mml ... sys=cluster " + ] + }, + { + "cell_type": "markdown", + "id": "049d9791-f3f4-4082-91dd-9ab59772d687", + "metadata": {}, + "source": [ + "Of course the respective paths must be available on the other system and kept in sync (e.g. via `rsync`). It is possible to manage cluster jobs and data syncing via a `JobRunner` - see the `mml-lsf` plugin for an example on how to interact easily with an LSF cluster. " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/source/notebooks/tricks/adapt_dataset.ipynb b/docs/source/notebooks/tricks/adapt_dataset.ipynb new file mode 100644 index 0000000..ab8ef4d --- /dev/null +++ b/docs/source/notebooks/tricks/adapt_dataset.ipynb @@ -0,0 +1,301 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "# Adapt your dataset\n", + "\n", + "## NOTE:\n", + "`mml` handles preprocessing the data internally. No need to manually preprocess any data in advance. See `preprocess mode`.\n", + "\n", + "Assume having used your dataset as a plain pytorch Dataset previously. Migration to `mml` is as easy as follows:\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "## Step 1: Write your DsetCreator and TaskCreator\n", + "\n", + "`mml` distinguishes the concepts of \"Datasets\" and \"Tasks\". Whereby \"Datasets\" contains all data (plus maybe more meta information, additional tasks on the same data, additional test samples, etc.) and the \"Task\" is only a description which samples and labels of the \"Dataset\" belong to that specific task. There are a lot of convenience functions to simplify this process.\n", + "\n", + "### Example: Reusing your previous dataset definition\n", + "\n", + "In this example we use some `torchvision` dataset to be integrated into `mml`, but it may be fully replaced with your existing dataset class." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "ExecuteTime": { + "end_time": "2024-01-17T13:29:25.577217Z", + "start_time": "2024-01-17T13:29:22.909528Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "from mml.api import (\n", + " DSetCreator,\n", + " TaskCreator,\n", + " get_iterator_and_mapping_from_image_dataset,\n", + " TaskType,\n", + " Keyword,\n", + " License,\n", + " Modality,\n", + " DataKind,\n", + ")\n", + "from torchvision.datasets import STL10" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "ExecuteTime": { + "end_time": "2024-01-17T13:13:50.173543Z", + "start_time": "2024-01-17T13:09:39.782179Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "REFERENCE = \"\"\"\n", + "@inproceedings{Coates2011AnAO,\n", + " title={An Analysis of Single-Layer Networks in Unsupervised Feature Learning},\n", + " author={Adam Coates and A. Ng and Honglak Lee},\n", + " booktitle={AISTATS},\n", + " year={2011}\n", + "}\"\"\"\n", + "\n", + "dset_creator = DSetCreator(dset_name=\"STL_10_DEMO\")\n", + "train = STL10(root=dset_creator.download_path, split=\"train\", download=True)\n", + "test = STL10(root=dset_creator.download_path, split=\"test\", download=True)\n", + "dset_path = dset_creator.extract_from_pytorch_datasets(\n", + " datasets={\"training\": train, \"testing\": test}, task_type=TaskType.CLASSIFICATION, class_names=train.classes\n", + ")\n", + "task_creator = TaskCreator(\n", + " dset_path=dset_path,\n", + " task_type=TaskType.CLASSIFICATION,\n", + " name=\"STL_10_DEMO\",\n", + " desc=\"STL-10 image recognition task\",\n", + " ref=REFERENCE,\n", + " url=\"https://cs.stanford.edu/~acoates/stl10/\",\n", + " instr=\"downloaded via torchvision dataset (https://pytorch.org/vision/stable/generated/torchvision.datasets.STL10.html#torchvision.datasets.STL10)\",\n", + " lic=License.UNKNOWN,\n", + " release=\"2011\",\n", + " keywords=[Keyword.NATURAL_OBJECTS],\n", + ")\n", + "train_iterator, idx_to_class = get_iterator_and_mapping_from_image_dataset(\n", + " root=dset_path / \"training_data\", classes=train.classes\n", + ")\n", + "test_iterator, idx_to_class_2 = get_iterator_and_mapping_from_image_dataset(\n", + " root=dset_path / \"testing_data\", classes=test.classes\n", + ")\n", + "assert all([a == b for a, b in zip(idx_to_class, idx_to_class_2)])\n", + "task_creator.find_data(train_iterator=train_iterator, test_iterator=test_iterator, idx_to_class=idx_to_class)\n", + "task_creator.auto_complete()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "That's it already! For the future you may reference your task with `stl10` (the value provided to `alias=` in the `TaskCreator`).\n", + "\n", + "### Example: DSetCreator when using public data\n", + "\n", + "In this case we recommend to implement the `DSetCreator` from scratch including the download of the data. This allows for better reproducibility. There are the following convenience functions so far:\n", + "\n", + " - `DSetCreator.download()` to download given a URL\n", + " - `DSetCreator.kaggle_download()` to download given a kaggle dataset ID or competition ID\n", + " - `DSetCreator.verify_pre_download()` if parts of the data have to be downloaded manually (e.g. access only after registration)\n", + " - `DSetCreator.unpack_and_store()` simply call after any of the previous to extract the data from archive formats\n", + " - `DSetCreator.transform_masks()` if necessary transform masks (e.g. from segmentation masks) to fit the `mml` requirements\n", + "\n", + "### Example: TaskCreator, writing your own data iterator\n", + "\n", + "If `get_iterator_and_mapping_from_image_dataset` does not fit your data structure, you may simply write an iterator yourself, as done with this example:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "ExecuteTime": { + "end_time": "2024-01-17T13:33:14.574381Z", + "start_time": "2024-01-17T13:33:09.814012Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "dset_creator = DSetCreator(dset_name=\"laryngeal_DEMO\")\n", + "dset_creator.download(\n", + " url=\"https://zenodo.org/record/1003200/files/laryngeal%20dataset.tar?download=1\",\n", + " file_name=\"laryngeal dataset.tar\",\n", + " data_kind=DataKind.TRAINING_DATA,\n", + ")\n", + "dset_path = dset_creator.unpack_and_store()\n", + "laryngeal_tissue = TaskCreator(\n", + " dset_path=dset_path,\n", + " task_type=TaskType.CLASSIFICATION,\n", + " name=\"laryngeal_DEMO\",\n", + " desc=\"Laryngeal dataset for patches of healthy and early-stage cancerous laryngeal tissues\",\n", + " ref=\"...\",\n", + " url=\"https://nearlab.polimi.it/medical/dataset/\",\n", + " instr=\"download via zenodo.org/record/1003200/files/laryngeal%20dataset.tar?download=1\",\n", + " lic=License.CC_BY_NC_4_0,\n", + " release=\"2017\",\n", + " keywords=[Keyword.MEDICAL, Keyword.LARYNGOSCOPY, Keyword.TISSUE_PATHOLOGY, Keyword.ENDOSCOPY],\n", + ")\n", + "classes = [\"Hbv\", \"He\", \"IPCL\", \"Le\"]\n", + "folds = [\"FOLD 1\", \"FOLD 2\", \"FOLD 3\"]\n", + "data_iterator = []\n", + "for fold in folds:\n", + " root = dset_path / \"training_data\" / \"laryngeal dataset\" / f\"{fold}\"\n", + " folders = [p.name for p in root.iterdir() if p.is_dir()]\n", + " assert all([cl in folders for cl in classes]), \"some class folder is not existent\"\n", + " for class_folder in root.iterdir():\n", + " assert class_folder.is_dir()\n", + " if class_folder.name not in classes:\n", + " continue\n", + " for img_path in class_folder.iterdir():\n", + " data_iterator.append(\n", + " {\n", + " Modality.SAMPLE_ID: img_path.stem,\n", + " Modality.IMAGE: img_path,\n", + " Modality.CLASS: classes.index(class_folder.name),\n", + " }\n", + " )\n", + "idx_to_class = {classes.index(cl): cl for cl in classes}\n", + "laryngeal_tissue.find_data(train_iterator=data_iterator, idx_to_class=idx_to_class)\n", + "laryngeal_tissue.auto_complete()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Example: Multiple tasks per Dataset\n", + "\n", + "This example will be added later." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "## Step 2: BONUS - automize the task creation\n", + "\n", + "`mml` has a `create` mode to generate tasks automatically. If set up correctly the above datasets would be downloaded and prepared automatically when calling `mml create tasks=example` (assuming `example.yaml` is already provided). This is much more convenient if using `mml` from within and not as a library - nevertheless possible and allows any other `mml` user that installed your package to quickly start on your data and code.\n", + "\n", + " - make your code installable via a package - you need a `pyproject.toml` and `setup.cfg` file for this\n", + " - decorate the `DSetCreator` with `@register_dsetcreator` and your `TaskCreator` with `@register_taskcreator`\n", + " - add an `activate.py` script to the root of your package's source code\n", + " - import the module (file) that defines the creators within this file\n", + " - in your `setup.cfg` (or `setup.py` or `pyproject.toml`, see [here](https://setuptools.pypa.io/en/latest/userguide/entry_point.html?highlight=entry_points#entry-points-syntax)) provide the correct entry point for `mml`\n", + "\n", + "```cfg\n", + "[options.entry_points]\n", + "mml.plugins =\n", + " some_key = your_package:activate\n", + "```\n", + "\n", + " - (replace some_key with a descriptive id and your_package with your package and your_module the module you want to refer to).\n", + " - These tasks are now always linked when calling `mml task_list=[stl10,laryngeal_tissues]` 🎉\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "\n", + "## Step 3: BONUS - add your task(s) to a tasks config file\n", + "\n", + "In order to refer to your task(s) later on create a tasks config file in a configs folder that is linked to `mml`\n", + "\n", + " - if you cloned `mml` just navigate into `configs/tasks`\n", + " - if you are writing your own package, create a `configs` folder, best at your package root level, add a `tasks` folder inside\n", + " - create a new file `example.yaml` with the following content\n", + "\n", + "```yaml\n", + "# @package _global_\n", + "\n", + "tasks:\n", + " - 'stl10'\n", + " - 'laryngeal_tissues'\n", + "\n", + "pivot:\n", + " name: False\n", + " tags: ''\n", + "\n", + "tagging:\n", + " all: False\n", + " variants: []\n", + "```\n", + "\n", + " - add something like the following to your `activate.py` (see step before)\n", + "\n", + "```python\n", + "from hydra.core.config_search_path import ConfigSearchPath\n", + "from hydra.core.plugins import Plugins\n", + "from hydra.plugins.search_path_plugin import SearchPathPlugin\n", + "\n", + "\n", + "# register plugin configs\n", + "class MMLINSERTPLUGINNAMESearchPathPlugin(SearchPathPlugin):\n", + " def manipulate_search_path(self, search_path: ConfigSearchPath) -> None:\n", + " # Sets the search path for mml with copied config files\n", + " search_path.append(\n", + " provider=\"mml-???\", path=f\"pkg://mml_???.configs\"\n", + " )\n", + "\n", + "\n", + "Plugins.instance().register(MMLINSERTPLUGINNAMESearchPathPlugin)\n", + "```\n", + "\n", + " - ofcourse you have to replace `INSERTPLUGINNAME` and `mml-???` / `mml_???`\n", + "\n", + "These tasks are now always linked when calling `mml tasks=example` 🎉" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/docs/source/notebooks/tricks/baseline.ipynb b/docs/source/notebooks/tricks/baseline.ipynb new file mode 100644 index 0000000..850e600 --- /dev/null +++ b/docs/source/notebooks/tricks/baseline.ipynb @@ -0,0 +1,387 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "899624e8ac3a5979", + "metadata": {}, + "source": [ + "# Baseline\n", + "\n", + "This guide is a good beginning to familiarize with basic `mml` usage. The goal is to run some baseline models for an existing task. We will use the widely known `MNIST` dataset for demonstration purposes.\n", + "\n", + "## Step 1: Prepare data\n", + "\n", + "`MNIST` is already available in `mml` through the `mml-data` plugin, which might be installed through `pip` easily.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "4896f0ce2d0385ea", + "metadata": { + "ExecuteTime": { + "end_time": "2024-11-22T14:14:38.123607Z", + "start_time": "2024-11-22T14:14:37.118505Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Name: mml-data\r\n", + "Version: 0.3.0\r\n", + "Summary: This is the MML data plugin, providing dataset and task implementation for a bunch of datasets.\r\n", + "Home-page: https://git.dkfz.de/imsy/ise/mml\r\n", + "Author: Patrick Godau\r\n", + "Author-email: patrick.scholz@dkfz-heidelberg.de\r\n", + "License: \r\n", + "Location: /home/scholzpa/Documents/development/gitlab/mml/plugins/data/src\r\n", + "Requires: mml-core\r\n", + "Required-by: \r\n" + ] + } + ], + "source": [ + "!pip show mml-data" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "eb0ef16dadb7b3f2", + "metadata": { + "ExecuteTime": { + "end_time": "2024-11-22T14:15:09.023643Z", + "start_time": "2024-11-22T14:15:01.134140Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/home/scholzpa/miniconda3/envs/mml/lib/python3.8/site-packages/kornia/feature/lightglue.py:44: FutureWarning: `torch.cuda.amp.custom_fwd(args...)` is deprecated. Please use `torch.amp.custom_fwd(args..., device_type='cuda')` instead.\r\n", + " @torch.cuda.amp.custom_fwd(cast_inputs=torch.float32)\r\n", + "\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m name \u001b[34m|\u001b[0m\u001b[96m dataset \u001b[34m|\u001b[0m\u001b[96m type \u001b[34m|\u001b[0m\u001b[96m installed \u001b[34m|\u001b[0m\u001b[96m license \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m idle_action_recognition \u001b[34m|\u001b[0m\u001b[96m idle_action \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m bean_plant_disease_classification \u001b[34m|\u001b[0m\u001b[96m ibean \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m MIT \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m caltech101_object_classification \u001b[34m|\u001b[0m\u001b[96m caltech101 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cifar10_object_classification \u001b[34m|\u001b[0m\u001b[96m cifar10 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cifar100_object_classification \u001b[34m|\u001b[0m\u001b[96m cifar100 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m sklin2_skin_lesions \u001b[34m|\u001b[0m\u001b[96m sklin2 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m barretts_esophagus_diagnosis \u001b[34m|\u001b[0m\u001b[96m barretts_esophagus \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mura_xr_wrist \u001b[34m|\u001b[0m\u001b[96m mura \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mura_xr_shoulder \u001b[34m|\u001b[0m\u001b[96m mura \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mura_xr_humerus \u001b[34m|\u001b[0m\u001b[96m mura \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mura_xr_hand \u001b[34m|\u001b[0m\u001b[96m mura \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mura_xr_forearm \u001b[34m|\u001b[0m\u001b[96m mura \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mura_xr_finger \u001b[34m|\u001b[0m\u001b[96m mura \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mura_xr_elbow \u001b[34m|\u001b[0m\u001b[96m mura \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m eye_condition_classification \u001b[34m|\u001b[0m\u001b[96m cataract \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m brain_tumor_classification \u001b[34m|\u001b[0m\u001b[96m brain_tumor \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m derm7pt_skin_lesions \u001b[34m|\u001b[0m\u001b[96m derm7pt \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m covid-19-chest-ct-image-augmentation_raw \u001b[34m|\u001b[0m\u001b[96m covid_chest_ct \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m DATABASE_CONTENTS_LICENSE_1_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m covid-19-chest-ct-image-augmentation_Aug \u001b[34m|\u001b[0m\u001b[96m covid_chest_ct \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m DATABASE_CONTENTS_LICENSE_1_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m covid-19-chest-ct-image-augmentation_CGAN \u001b[34m|\u001b[0m\u001b[96m covid_chest_ct \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m DATABASE_CONTENTS_LICENSE_1_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m covid-19-chest-ct-image-augmentation_Aug&CGAN \u001b[34m|\u001b[0m\u001b[96m covid_chest_ct \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m DATABASE_CONTENTS_LICENSE_1_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m deep_drid_quality \u001b[34m|\u001b[0m\u001b[96m deep_drid \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m deep_drid_dr_level \u001b[34m|\u001b[0m\u001b[96m deep_drid \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m deep_drid_clarity \u001b[34m|\u001b[0m\u001b[96m deep_drid \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m deep_drid_field \u001b[34m|\u001b[0m\u001b[96m deep_drid \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m deep_drid_artifact \u001b[34m|\u001b[0m\u001b[96m deep_drid \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m caltech256_object_classification \u001b[34m|\u001b[0m\u001b[96m caltech256 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m emnist_digit_classification \u001b[34m|\u001b[0m\u001b[96m emnist \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m kvasir_capsule_anatomy \u001b[34m|\u001b[0m\u001b[96m kvasir_capsule \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m kvasir_capsule_content \u001b[34m|\u001b[0m\u001b[96m kvasir_capsule \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m kvasir_capsule_pathologies \u001b[34m|\u001b[0m\u001b[96m kvasir_capsule \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m suncolondb-classification \u001b[34m|\u001b[0m\u001b[96m SUNdatabase \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m False \u001b[34m|\u001b[0m\u001b[96m CUSTOM \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m brain_tumor_type_classification \u001b[34m|\u001b[0m\u001b[96m brain_tumor_type \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m breast_cancer_classification_v2 \u001b[34m|\u001b[0m\u001b[96m breast_ultrasound \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_0_1_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m stanford_dogs_image_categorization \u001b[34m|\u001b[0m\u001b[96m stanford_dogs \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m hyperkvasir_anatomical-landmarks \u001b[34m|\u001b[0m\u001b[96m hyperkvasir \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m hyperkvasir_pathological-findings \u001b[34m|\u001b[0m\u001b[96m hyperkvasir \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m hyperkvasir_quality-of-mucosal-views \u001b[34m|\u001b[0m\u001b[96m hyperkvasir \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m hyperkvasir_therapeutic-interventions \u001b[34m|\u001b[0m\u001b[96m hyperkvasir \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m nerthus_bowel_cleansing_quality \u001b[34m|\u001b[0m\u001b[96m nerthus \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cervix_type_classification \u001b[34m|\u001b[0m\u001b[96m cervical_screening \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m False \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m laryngeal_tissues \u001b[34m|\u001b[0m\u001b[96m laryngeal \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m laryngeal_tissues_original_folds \u001b[34m|\u001b[0m\u001b[96m laryngeal \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m pneumonia_classification \u001b[34m|\u001b[0m\u001b[96m pneumonia \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m lapgyn4_anatomical_structures \u001b[34m|\u001b[0m\u001b[96m lapgyn4 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m lapgyn4_surgical_actions \u001b[34m|\u001b[0m\u001b[96m lapgyn4 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m lapgyn4_instrument_count \u001b[34m|\u001b[0m\u001b[96m lapgyn4 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m lapgyn4_anatomical_actions \u001b[34m|\u001b[0m\u001b[96m lapgyn4 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m shenzen_chest_xray_tuberculosis \u001b[34m|\u001b[0m\u001b[96m shenzhen_xray_tb \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholect45_triplet \u001b[34m|\u001b[0m\u001b[96m cholect45 \u001b[34m|\u001b[0m\u001b[96m multilabel_classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholect45_instrument \u001b[34m|\u001b[0m\u001b[96m cholect45 \u001b[34m|\u001b[0m\u001b[96m multilabel_classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholect45_verb \u001b[34m|\u001b[0m\u001b[96m cholect45 \u001b[34m|\u001b[0m\u001b[96m multilabel_classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholect45_target \u001b[34m|\u001b[0m\u001b[96m cholect45 \u001b[34m|\u001b[0m\u001b[96m multilabel_classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholect45_triplet_soft \u001b[34m|\u001b[0m\u001b[96m cholect45 \u001b[34m|\u001b[0m\u001b[96m multilabel_classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m svhn \u001b[34m|\u001b[0m\u001b[96m svhn \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholec80_grasper_presence \u001b[34m|\u001b[0m\u001b[96m cholec80 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholec80_bipolar_presence \u001b[34m|\u001b[0m\u001b[96m cholec80 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholec80_hook_presence \u001b[34m|\u001b[0m\u001b[96m cholec80 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholec80_scissors_presence \u001b[34m|\u001b[0m\u001b[96m cholec80 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholec80_clipper_presence \u001b[34m|\u001b[0m\u001b[96m cholec80 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholec80_irrigator_presence \u001b[34m|\u001b[0m\u001b[96m cholec80 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m cholec80_specimenbag_presence \u001b[34m|\u001b[0m\u001b[96m cholec80 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_SA_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_enlarged_cardiomediastinum \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_cardiomegaly \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_lung_opacity \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_lung_lesion \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_edema \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_consolidation \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_pneumonia \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_atelectasis \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_pneumothorax \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_pleural_effusion \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_pleural_other \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_fracture \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m chexpert_support_devices \u001b[34m|\u001b[0m\u001b[96m chexpert \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m identify_nbi_infframes \u001b[34m|\u001b[0m\u001b[96m nbi_infframes \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m identify_nbi_infframes_original_folds \u001b[34m|\u001b[0m\u001b[96m nbi_infframes \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m False \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m covid_xray_classification \u001b[34m|\u001b[0m\u001b[96m covid_xray \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_0_1_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m aptos19_blindness_detection \u001b[34m|\u001b[0m\u001b[96m aptos_blindness \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m isic20_melanoma_classification \u001b[34m|\u001b[0m\u001b[96m isic20 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mnist_digit_classification \u001b[34m|\u001b[0m\u001b[96m mnist \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m crawled_covid_ct_classification \u001b[34m|\u001b[0m\u001b[96m covid_ct_crawled \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m mednode_melanoma_classification \u001b[34m|\u001b[0m\u001b[96m mednode \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m ph2-melanocytic-lesions-segmentation \u001b[34m|\u001b[0m\u001b[96m PH2 \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m ph2-melanocytic-lesions-classification \u001b[34m|\u001b[0m\u001b[96m PH2 \u001b[34m|\u001b[0m\u001b[96m classification \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m pascal_voc_challenge_2012 \u001b[34m|\u001b[0m\u001b[96m VOC12 \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m endovissub18_robotic_instrument_seg \u001b[34m|\u001b[0m\u001b[96m endovis18_rob_instr \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m glenda_endometriosis_segmentation \u001b[34m|\u001b[0m\u001b[96m glenda \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m hyperkvasir_polyp_segmentation \u001b[34m|\u001b[0m\u001b[96m hyperkvasir_seg \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m motion-based-segmentation \u001b[34m|\u001b[0m\u001b[96m motion-based-rec \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m crowdsourced-endoscopic-instrument-segmentation-crowd-only \u001b[34m|\u001b[0m\u001b[96m crowdsourced-EIS \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m endometrial_implants \u001b[34m|\u001b[0m\u001b[96m enid \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m CC_BY_NC_4_0 \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m image2image-raw \u001b[34m|\u001b[0m\u001b[96m image2image \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m image2image-rand \u001b[34m|\u001b[0m\u001b[96m image2image \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[34m|\u001b[0m\u001b[96m image2image-cholec80 \u001b[34m|\u001b[0m\u001b[96m image2image \u001b[34m|\u001b[0m\u001b[96m semantic_segmentation \u001b[34m|\u001b[0m\u001b[96m True \u001b[34m|\u001b[0m\u001b[96m UNKNOWN \u001b[34m|\u001b[0m\u001b[96m\r\n", + "\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[34m-\u001b[0m\u001b[96m\u001b[36m+\u001b[0m\u001b[96m\u001b[0m\r\n", + "Overall 96 raw tasks available, from 48 datasets. Filter matches 95 raw tasks with additional 248 variants derived thereof.\r\n", + "\u001b[0m" + ] + } + ], + "source": [ + "# available datasets\n", + "!mml-data" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "f77519e1c16b242f", + "metadata": { + "ExecuteTime": { + "end_time": "2024-11-22T14:16:29.406429Z", + "start_time": "2024-11-22T14:16:22.942232Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/home/scholzpa/miniconda3/envs/mml/lib/python3.8/site-packages/kornia/feature/lightglue.py:44: FutureWarning: `torch.cuda.amp.custom_fwd(args...)` is deprecated. Please use `torch.amp.custom_fwd(args..., device_type='cuda')` instead.\r\n", + " @torch.cuda.amp.custom_fwd(cast_inputs=torch.float32)\r\n", + "[\u001b[36m2024-11-22 15:16:28,080\u001b[0m][\u001b[34mmml\u001b[0m][\u001b[32mINFO\u001b[0m] - Started MML 0.14.2 on Python 3.8.12 with mode CREATE.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:16:28,080\u001b[0m][\u001b[34mmml\u001b[0m][\u001b[32mINFO\u001b[0m] - Plugins loaded: ['mml-data', 'mml-dimensionality', 'mml-similarity', 'mml-tags', 'mml-sql', 'mml-drive', 'mml-lsf', 'mml-suggest', 'mml-prevalences', 'mml-tf']\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:16:28,305\u001b[0m][\u001b[34mmml.core.scripts.schedulers.create_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Skipping creation of task mnist_digit_classification because there already seems to be a RAW version of that.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:16:28,305\u001b[0m][\u001b[34mmml.core.scripts.schedulers.base_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Executing after init hook: check_lsf_workers\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:16:28,306\u001b[0m][\u001b[34mmml_lsf.workers\u001b[0m][\u001b[32mINFO\u001b[0m] - LSF cluster plugin detected local system, no changes made to the number of workers.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:16:28,306\u001b[0m][\u001b[34mmml\u001b[0m][\u001b[32mINFO\u001b[0m] - MML init time was 0.0h 0.0m 0.23s.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:16:28,360\u001b[0m][\u001b[34mmml.core.data_loading.file_manager\u001b[0m][\u001b[32mINFO\u001b[0m] - A total of 0 paths have been created during this run.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:16:28,361\u001b[0m][\u001b[34mmml.core.scripts.schedulers.base_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Successfully finished all experiments!\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:16:28,361\u001b[0m][\u001b[34mmml\u001b[0m][\u001b[32mINFO\u001b[0m] - MML run time was 0.0h 0.0m 0.05s.\u001b[0m\r\n" + ] + } + ], + "source": [ + "# install data for MNIST (data already installed here, might take a couple of minutes depending on hardware and ethernet connection)\n", + "!mml create task_list=[mnist_digit_classification]" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "bfece1f893e49e8f", + "metadata": { + "ExecuteTime": { + "end_time": "2024-11-22T14:21:05.831035Z", + "start_time": "2024-11-22T14:18:15.345112Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/home/scholzpa/miniconda3/envs/mml/lib/python3.8/site-packages/kornia/feature/lightglue.py:44: FutureWarning: `torch.cuda.amp.custom_fwd(args...)` is deprecated. Please use `torch.amp.custom_fwd(args..., device_type='cuda')` instead.\r\n", + " @torch.cuda.amp.custom_fwd(cast_inputs=torch.float32)\r\n", + "[\u001b[36m2024-11-22 15:18:20,420\u001b[0m][\u001b[34mmml\u001b[0m][\u001b[32mINFO\u001b[0m] - Started MML 0.14.2 on Python 3.8.12 with mode PP.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:20,420\u001b[0m][\u001b[34mmml\u001b[0m][\u001b[32mINFO\u001b[0m] - Plugins loaded: ['mml-data', 'mml-dimensionality', 'mml-similarity', 'mml-tags', 'mml-sql', 'mml-drive', 'mml-lsf', 'mml-suggest', 'mml-prevalences', 'mml-tf']\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:20,649\u001b[0m][\u001b[34mmml.core.scripts.schedulers.base_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Executing after init hook: check_lsf_workers\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:20,650\u001b[0m][\u001b[34mmml_lsf.workers\u001b[0m][\u001b[32mINFO\u001b[0m] - LSF cluster plugin detected local system, no changes made to the number of workers.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:20,657\u001b[0m][\u001b[34mmml\u001b[0m][\u001b[32mINFO\u001b[0m] - MML init time was 0.0h 0.0m 0.24s.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:20,659\u001b[0m][\u001b[34mmml.core.scripts.schedulers.base_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Preparing experiment ...\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:20,660\u001b[0m][\u001b[34mmml.core.scripts.schedulers.base_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Starting experiment!\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:20,660\u001b[0m][\u001b[34mmml.core.scripts.schedulers.preprocess_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Starting preprocessing data for task \u001b[33m\u001b[46m\u001b[1mmnist_digit_classification\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:20,660\u001b[0m][\u001b[34mpy.warnings\u001b[0m][\u001b[33mWARNING\u001b[0m] - /home/scholzpa/Documents/development/gitlab/mml/src/mml/core/scripts/schedulers/preprocess_scheduler.py:101: UserWarning: THIS BEHAVIOUR CHANGED: Test data is now also to be preprocessed!\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:21,009\u001b[0m][\u001b[34mmml.core.scripts.schedulers.preprocess_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Preprocessing split: full_train\u001b[0m\r\n", + "100%|███████████████████████████████████| 60000/60000 [00:23<00:00, 2564.80it/s]\r\n", + "[\u001b[36m2024-11-22 15:18:44,669\u001b[0m][\u001b[34mmml.core.scripts.schedulers.preprocess_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Existing full_train files found:\r\n", + "image 0\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:44,670\u001b[0m][\u001b[34mmml.core.scripts.schedulers.preprocess_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Preprocessing split: test\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:44,670\u001b[0m][\u001b[34mmml.core.scripts.schedulers.preprocess_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - No samples in split: test\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:44,670\u001b[0m][\u001b[34mmml.core.scripts.schedulers.preprocess_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Preprocessing split: unlabelled\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:44,670\u001b[0m][\u001b[34mmml.core.scripts.schedulers.preprocess_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - No samples in split: unlabelled\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:45,041\u001b[0m][\u001b[34mmml.core.data_loading.file_manager\u001b[0m][\u001b[32mINFO\u001b[0m] - Writing task description at /home/scholzpa/Pictures/datasets/mml_data/PREPROCESSED/size224/DSET_mnist/temp.json.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:18:45,122\u001b[0m][\u001b[34mmml.core.data_preparation.utils\u001b[0m][\u001b[32mINFO\u001b[0m] - Calculating mean, std and size. This may take a couple of minutes.\u001b[0m\r\n", + "Gathering sizes: 100%|█████████████████| 60000/60000 [00:05<00:00, 11661.43it/s]\r\n", + "Gathering mean and std: 100%|█████████████████| 600/600 [02:12<00:00, 4.53it/s]\r\n", + "[\u001b[36m2024-11-22 15:21:03,916\u001b[0m][\u001b[34mmml.core.data_loading.file_manager\u001b[0m][\u001b[32mINFO\u001b[0m] - Writing task description at /home/scholzpa/Pictures/datasets/mml_data/PREPROCESSED/size224/DSET_mnist/TASK_mnist_digit_classification.json.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:21:03,998\u001b[0m][\u001b[34mmml.core.data_preparation.task_creator\u001b[0m][\u001b[32mINFO\u001b[0m] - Testing the loading of /home/scholzpa/Pictures/datasets/mml_data/PREPROCESSED/size224/DSET_mnist/TASK_mnist_digit_classification.json...\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:21:04,601\u001b[0m][\u001b[34mmml.core.data_preparation.task_creator\u001b[0m][\u001b[32mINFO\u001b[0m] - Testing of /home/scholzpa/Pictures/datasets/mml_data/PREPROCESSED/size224/DSET_mnist/TASK_mnist_digit_classification.json finished, dataset loading time was 0.60 seconds, sample loading time was 0.00 seconds.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:21:04,615\u001b[0m][\u001b[34mmml.core.scripts.schedulers.preprocess_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Finished preprocessing the data for task \u001b[33m\u001b[46m\u001b[1mmnist_digit_classification\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:21:04,630\u001b[0m][\u001b[34mmml.core.data_loading.file_manager\u001b[0m][\u001b[32mINFO\u001b[0m] - A total of 0 paths have been created during this run.\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:21:04,630\u001b[0m][\u001b[34mmml.core.scripts.schedulers.base_scheduler\u001b[0m][\u001b[32mINFO\u001b[0m] - Successfully finished all experiments!\u001b[0m\r\n", + "[\u001b[36m2024-11-22 15:21:04,630\u001b[0m][\u001b[34mmml\u001b[0m][\u001b[32mINFO\u001b[0m] - MML run time was 0.0h 2.0m 43.97s.\u001b[0m\r\n" + ] + } + ], + "source": [ + "# preprocess task\n", + "!mml pp task_list=[mnist_digit_classification] preprocessing=size224" + ] + }, + { + "cell_type": "markdown", + "id": "9fa178d147376fee", + "metadata": {}, + "source": [ + "## Step 2: Use defaults for training" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33891aeb2bbf72bf", + "metadata": {}, + "outputs": [], + "source": [ + "# to run a single training\n", + "!mml train pivot.name=mnist_digit_classification preprocessing=size224 proj=demo_baseline\n", + "# afterwards inspect the training via running tensorboard and inspecting through the browser\n", + "!tensorboard --logdir /path/to/mml/results/demo_baseline" + ] + }, + { + "cell_type": "markdown", + "id": "76000e8998ee5df5", + "metadata": {}, + "source": [ + "![image not found](../../../../docs/source/_static/tensorboard_example.png \"Tensorboard view\")" + ] + }, + { + "cell_type": "markdown", + "id": "49c76e16e67254d1", + "metadata": {}, + "source": [ + "## Step 3: Optimizing hyperparameters\n", + "\n", + "We will perform a simple grid search with a couple of architectures & augmentation strategies." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6556cc458ea30636", + "metadata": {}, + "outputs": [], + "source": [ + "# to run a hyperparameter search (here: grid search with 3 models x 3 augmentation strategies),\n", + "# to speed things up: no cross-validation, only 1 epoch, deactivated learning rate tuning\n", + "!mml train pivot.name=mnist_digit_classification preprocessing=size224 arch.name=resnet18,tiny_vit_21m_224.dist_in22k_ft_in1k,tf_efficientnet_b0.ns_jft_in1k augmentations=basic,randaugment,load_imagenet_aa proj=demo_grid trainer.max_epochs=1 tune.lr=false sampling.batch_size=100 mode.cv=false mode.nested=False +hpo/sampler=grid --multirun" + ] + }, + { + "cell_type": "markdown", + "id": "d1c658d74afcc506", + "metadata": {}, + "source": [ + "at the end it prints:\n", + "\n", + "> [HYDRA] Best parameters: {'arch.name': 'tiny_vit_21m_224.dist_in22k_ft_in1k', 'augmentations': 'randaugment'}\n", + "> [HYDRA] Best value: 0.0211497992277145" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c67617588ea39032", + "metadata": {}, + "outputs": [], + "source": [ + "# use the best hyperparameters in a full training run (the use_best_params is the name of our search, a folder inside the proj folder, inside \"hpo\", i.e. MML_RESULTS_PATH/demo_grid/hpo/2024-12-03_12-28-46_362374)\n", + "!mml train proj=demo_grid use_best_params=2024-12-03_12-28-46_362374 pivot.name=mnist_digit_classification" + ] + }, + { + "cell_type": "markdown", + "id": "2ff83f854dbba771", + "metadata": {}, + "source": [ + "[mml][INFO] - -------------------------------------------------------------------------------------\n", + "[mml][INFO] - Loaded hpo results from study 2024-12-03_12-28-46_362374 and merged 2 params into config.\n", + "[mml][INFO] - > arch.name=tiny_vit_21m_224.dist_in22k_ft_in1k\n", + "[mml][INFO] - > augmentations=randaugment\n", + "[mml][INFO] - -------------------------------------------------------------------------------------\n", + "[mml][INFO] - Started MML 0.14.2 on Python 3.10.9 with mode TRAIN.\n", + "..." + ] + }, + { + "cell_type": "markdown", + "id": "f3abca00-12e0-4993-9709-5cbb5d8b9d0f", + "metadata": {}, + "source": [ + "For more complex optimization setups (e.g. multi node optimization) one may use the `mml-sql` plugin. See the plugin documentation for installation and setup instructions. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62bf1503-ca31-4d8c-a86b-5c7bfa614d89", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/source/notebooks/tricks/cluster_integration.ipynb b/docs/source/notebooks/tricks/cluster_integration.ipynb new file mode 100644 index 0000000..d57eb29 --- /dev/null +++ b/docs/source/notebooks/tricks/cluster_integration.ipynb @@ -0,0 +1,58 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "605dfe269fb7d31", + "metadata": {}, + "source": [ + "# mml on a cluster\n", + "\n", + "Especially for large scale or hardware demanding experiments it is nice to outsource experiments to a cluster. It is straightforward to set up `mml` for compatible use throughout multiple systems. `mml` ships with a `cluster` configuration provided within `configs/sys`. It loads the environment variables `MML_CLUSTER_DATA_PATH`, `MML_CLUSTER_RESULTS_PATH` and `MML_CLUSTER_WORKERS` exported in the `mml.env` file instead of the local ones (adding even more system configurations can be achieved similarly via additional `sys` config files). Now the only difference in calling `mml` becomes:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "initial_id", + "metadata": { + "collapsed": true, + "jupyter": { + "outputs_hidden": true + } + }, + "outputs": [], + "source": [ + "!mml ... sys=cluster " + ] + }, + { + "cell_type": "markdown", + "id": "049d9791-f3f4-4082-91dd-9ab59772d687", + "metadata": {}, + "source": [ + "Of course the respective paths must be available on the other system and kept in sync (e.g. via `rsync`). It is possible to manage cluster jobs and data syncing via a `JobRunner` - see the `mml-lsf` plugin for an example on how to interact easily with an LSF cluster. " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/source/notebooks/tricks/efficiency.ipynb b/docs/source/notebooks/tricks/efficiency.ipynb new file mode 100644 index 0000000..75c0cd6 --- /dev/null +++ b/docs/source/notebooks/tricks/efficiency.ipynb @@ -0,0 +1,46 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Time efficiency\n", + "\n", + "- use preprocessing: `mml pp ...`\n", + "- optimise number of workers: `num_workers=12` - use neither to many nor too few\n", + "- use caching: `sampling.enable_caching=true`\n", + "- reduce validation checks: `trainer.check_vals_every_n_epochs=10` - but keep in mind this may prohibit early stopping or reduce learning rate on plateau\n", + "- early stopping: `callbacks=early`\n", + "- pruning (not supported yet see issue #19)\n", + "\n", + "# Memory efficiency\n", + "\n", + "- remove intermediates: `remove.parameters=true` - remove any NEW intermediate of the specified type AFTER an experiment is done\n", + "- store_parameters (only for train mode): `mml train mode.store_parameters=false` - does not store parameters at all" + ], + "metadata": { + "collapsed": false + } + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/docs/source/notebooks/tricks/jupyter_usage.ipynb b/docs/source/notebooks/tricks/jupyter_usage.ipynb new file mode 100644 index 0000000..a973170 --- /dev/null +++ b/docs/source/notebooks/tricks/jupyter_usage.ipynb @@ -0,0 +1,231 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "# How to use mml interactively\n", + "\n", + "`MML` provides the `mml.interactive` module with the `mml.interactive.planning` and `mml.interactive.loading` submodules to support direct usage within jupyter notebooks. This notebook itself demonstrates the usage." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-09T15:23:56.175656Z", + "start_time": "2023-05-09T15:23:56.084137Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "from pathlib import Path\n", + "\n", + "import mml.interactive\n", + "\n", + "# your mml.env location might differ\n", + "mml.interactive.init(env_path=Path(mml.__file__).parent / \"mml.env\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "## data exploration" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-09T15:27:02.765778Z", + "start_time": "2023-05-09T15:27:02.589385Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "# this example shows how to retrieve all installed tasks\n", + "with mml.interactive.default_file_manager() as fm:\n", + " print(sorted(list(fm.task_index.keys())))" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-09T15:29:05.620904Z", + "start_time": "2023-05-09T15:29:05.487248Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "# this example loads task information\n", + "tasks = [\"caltech256_object_classification\", \"cifar10_object_classification\", \"svhn\"]\n", + "mml.interactive.get_task_infos(tasks)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "## experiment planning" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-09T15:42:40.699820Z", + "start_time": "2023-05-09T15:42:40.695104Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "# this example creates some MML calls to run experiments\n", + "base_reqs = mml.interactive.DefaultRequirements()\n", + "all_cmds = list()\n", + "# create task data\n", + "all_cmds.append(\n", + " mml.interactive.MMLJobDescription(\n", + " prefix_req=base_reqs, mode=\"create\", config_options={\"task_list\": tasks, \"proj\": \"my_exp\"}\n", + " )\n", + ")\n", + "# preprocess tasks\n", + "all_cmds.append(\n", + " mml.interactive.MMLJobDescription(\n", + " prefix_req=base_reqs, mode=\"pp\", config_options={\"task_list\": tasks, \"proj\": \"my_exp\"}\n", + " )\n", + ")\n", + "# create tagged task variants\n", + "all_cmds.append(\n", + " mml.interactive.MMLJobDescription(\n", + " prefix_req=base_reqs,\n", + " mode=\"info\",\n", + " config_options={\"task_list\": tasks, \"proj\": \"my_exp\", \"tagging.all\": \"+subset?0_05+confuse?0_1\"},\n", + " )\n", + ")\n", + "# you may also loop over\n", + "for t in tasks:\n", + " all_cmds.append(\n", + " mml.interactive.MMLJobDescription(\n", + " prefix_req=base_reqs,\n", + " mode=\"train\",\n", + " config_options={\"pivot.name\": f\"{t}+subset?0_05+confuse?0_1\", \"proj\": \"my_exp\", \"sampling.batch_size\": 500},\n", + " )\n", + " )\n", + "# either render jobs directly\n", + "for cmd in all_cmds:\n", + " print(cmd.render())\n", + "# or put them into a file\n", + "mml.interactive.write_out_commands(cmd_list=all_cmds, name=\"my_exp\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": "## start planned jobs from within a notebook" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "runner = mml.interactive.EmbeddedJobRunner()\n", + "job = mml.interactive.MMLJobDescription(\n", + " prefix_req=base_reqs,\n", + " mode=\"info\",\n", + " config_options={\"task_list\": tasks, \"proj\": \"my_exp\", \"tagging.all\": \"+subset?0_05+confuse?0_1\"},\n", + ")\n", + "runner.run(job=job)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "## experiment evaluation" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-09T15:47:34.352483Z", + "start_time": "2023-05-09T15:47:34.232398Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "# load experiment models\n", + "models = mml.interactive.load_project_models(\"test\")" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-09T15:49:56.550298Z", + "start_time": "2023-05-09T15:49:56.547572Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "# inspect and evaluate\n", + "print(models[\"lapgyn4_instrument_count_miccai\"][0].training_time)\n", + "print(models[\"lapgyn4_instrument_count_miccai\"][0].performance)\n", + "print(models[\"lapgyn4_instrument_count_miccai\"][0].metrics[-2])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/docs/source/notebooks/tricks/tta.ipynb b/docs/source/notebooks/tricks/tta.ipynb new file mode 100644 index 0000000..754f533 --- /dev/null +++ b/docs/source/notebooks/tricks/tta.ipynb @@ -0,0 +1,108 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "1d923e4f84643d2b", + "metadata": {}, + "source": "# Test time augmentation" + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "620ed78a77d63983", + "metadata": { + "ExecuteTime": { + "end_time": "2024-08-27T10:59:02.570959Z", + "start_time": "2024-08-27T10:59:02.527272Z" + } + }, + "outputs": [], + "source": [ + "# inspecting a sample tta configuration\n", + "import mml.configs\n", + "from pathlib import Path\n", + "from omegaconf import OmegaConf" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "c905c0e1e7a6aaf4", + "metadata": { + "ExecuteTime": { + "end_time": "2024-08-27T11:00:53.129520Z", + "start_time": "2024-08-27T11:00:53.118971Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "mode: mean\n", + "variations:\n", + " identity:\n", + " - name: RandomHorizontalFlip\n", + " p: 0.0\n", + " rot90:\n", + " - name: RandomRotation\n", + " degrees:\n", + " - 90\n", + " - 90\n", + " p: 1.0\n", + " rot270:\n", + " - name: RandomRotation\n", + " degrees:\n", + " - 270\n", + " - 270\n", + " p: 1.0\n", + " hflip:\n", + " - name: RandomHorizontalFlip\n", + " p: 1.0\n", + "\n" + ] + } + ], + "source": [ + "path = Path(mml.configs.__file__).parent / \"tta\" / \"rotate.yaml\"\n", + "cfg = OmegaConf.load(path)\n", + "print(OmegaConf.to_yaml(cfg))" + ] + }, + { + "cell_type": "markdown", + "id": "ee3966b85422869f", + "metadata": {}, + "source": "`mode` determines the merging strategy, currently only `mean` is supported but other strategies might be implemented later (majority vote, etc.). `variations` lists all [kornia augmentations](https://kornia.readthedocs.io/en/latest/augmentation.module.html) that shall be performed - ideally they are deterministic. `mml` will apply each transform to each image and merge the predictions of the model according to the `mode`. Note that `tta` is only active during testing and predicting with models - not during training nor validation." + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1c0c31de9f762235", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/source/notebooks/tricks/tune.ipynb b/docs/source/notebooks/tricks/tune.ipynb new file mode 100644 index 0000000..ec2462a --- /dev/null +++ b/docs/source/notebooks/tricks/tune.ipynb @@ -0,0 +1,63 @@ +{ + "cells": [ + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "# Tuning\n", + "\n", + "Via [pytorch-lightning](https://lightning.ai/docs/pytorch/stable/api/lightning.pytorch.tuner.tuning.Tuner.html) `mml` offers automatic tuning of the initial learning rate as well as the batch size. To activate this behaviour simply refer `tune.lr=true` and `tune.bs=true` respectively. Note that learning rate tuning is activated by default!\n" + ], + "id": "dec35ad56dc0e6ac" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": "", + "id": "df4dd60695d15023" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "To provide more granular access to lightnings tuning options you may use the `tune.lr_kwargs` (or `tune.bs_kwargs`) e.g.", + "id": "e6dcdbd41697799a" + }, + { + "metadata": {}, + "cell_type": "code", + "source": "!mml train tasks=fake tune.lr=true +tune.lr_kwargs.mode=linear +tune.lr_kwargs.early_stop_threshold=2.0 trainer.max_epochs=1", + "id": "47bab51af00459b1", + "outputs": [], + "execution_count": null + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "", + "id": "182780dd55a1db34" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/source/plugins.rst b/docs/source/plugins.rst new file mode 100644 index 0000000..24c9515 --- /dev/null +++ b/docs/source/plugins.rst @@ -0,0 +1,65 @@ +Plugins +======= + +The concept of plugins is a general pillar of ``mml``'s architecture. Plugins provide e.g. additional schedulers, +tasks and config options. A list of available plugins can be found at :doc:`api/plugins/overview`. This section +is intended to describe the purpose and possibilities of plugins as well as their intended internal structure. It can +thus also be seen as a guide to write your own plugin. + +introduction +------------ + +Plugins are actual python packages (and need to be such), and many are already available from the same registry +as ``mml-core``. Of course ``mml-core`` is a necessary dependency, so installing that one first is necessary +(see :doc:`install`). In a similar fashion and within the same virtual environment one may install plugins. +To make your code installable you have to add +``pyproject.toml`` and ``setup.cfg`` files ar your projects root level. See ``mml``'s ``plugins/_template`` folder +to see template files for those. More broadly the following plugin structure is recommended: + +.. note:: + | root + | ├── src + | │ └── my_plugin + | │ ├── configs (optional) + | │ │ └── config_group (e.g. foo) + | │ │ └── bar.yaml (allows this config to be used with ``foo=bar``) + | │ ├── stuff (modules, assets, ...) + | │ ├── ... + | │ ├── __init__.py (should provide a __version__ string) + | │ └── activate.py (contains all imports, adds the config search path) + | ├── tests + | │ └── unit (put your tests in here) + | ├── README.md + | ├── MANIFEST.in (declare any assets to be shipped with your plugin) + | ├── pyproject.toml + | └── setup.cfg + +loading +------- + +Plugins are loaded during the initialization of ``mml`` during :func:`mml.cli.main`, but before compiling the +hydra configuration of the experiment with the :func:`~mml.core.scripts.utils.load_mml_plugins` function. This allows +plugins to extend the search path of hydra for config files and provide config options themselves (you can check on +these search path plugins and inspect the order by calling ``mml --info searchpath``). Each plugin needs to provide an +entry point as follows in their ``setup.cfg``: + +.. code-block:: + + [options.entry_points] + mml.plugins = + my-plugin = my_plugin.activate + +This assure that ``my_plugin.activate`` is sourced before running the ``mml`` core routines and modify any behaviour +before the experiment. The ``activate.py`` file may for example + + * add the plugin's config folder to the configs search path of ``mml`` to add new config options from cli + * add path assignments to the :class:`~mml.core.data_loading.file_manager.MMLFileManager` via :meth:`~mml.core.data_loading.file_manager.MMLFileManager.add_assignment_path` + * register :class:`~mml.core.data_preparation.dset_creator.DSetCreator`'s or :class:`~mml.core.data_preparation.task_creator.TaskCreator`'s via :func:`~mml.core.data_preparation.registry.register_dsetcreator` and :func:`~mml.core.data_preparation.registry.register_taskcreator` + * add or overwrite methods of existing classes like :class:`~mml.core.scripts.base_scheduler.AbstractBaseScheduler` + * or simply import modules (from ``stuff``) that do so themselves + +testing +------- +``mml-core`` provides a ``pytest`` plugin so that tests (ideally within the ``tests`` folder) may use fixtures defined in +:mod:`mml.testing.fixtures`. + diff --git a/docs/source/usage.rst b/docs/source/usage.rst new file mode 100644 index 0000000..8321859 --- /dev/null +++ b/docs/source/usage.rst @@ -0,0 +1,310 @@ +Getting started +=============== + +This section is intended to help with the learning curve of ``mml`` and let you master it as +smoothly as possible. It splits itself into the following chunks: + + * a quick overview on the **core** concepts of ``mml`` + * **basic** usage of the ``mml`` CLI, for full descriptions of all command line options see :doc:`cli/overview` + * variants of hooking into ``mml`` to define your own scheduler, datasets, path assignments and more + * interactive experiment pre- and post-processing + +After reading through you may want to continue reading the :doc:`modes` for a more detailed overview on ``mml`` modes +and :doc:`guides` for more specific use cases. + +Finally if you want to dive deeper into the ``mml`` internals, read through :doc:`api/overview` section. + +Concept +------- + +``mml`` is a full toolkit to be leveraged in interacting with RGB images for deep learning. It can be accessed through +the command line interface (CLI) or interactively via jupyter notebooks. An ``experiment`` (or ``run``) comprises a +single call to the ``mml`` CLI. Each experiment is assigned to a ``project``, that determines where the produced +artefacts (e.g. trained models) and experiment logs reside (see `proj`_). Experiments within a project may reuse +artefacts from a different project though (see `reuse`_). The imaging data (except for plotting and visual logs) is kept +separately from conducted experiments and stored at the location given by the ``MML_DATA_PATH`` variable. The +installation of data is performed via an explicit ``mml create`` call. ``mml pp`` allows for preprocessing data and +storing the results as well - if this step is omitted or the ``preprocessing`` configuration changes (i.e. no +preprocessed data is stored) then data will be preprocessed on the fly automatically. ``create`` and ``pp` are two +exemplary modes of ``mml`` (see `mode`_), basically top level instructions. More fine-grained configuration can be +achieved more pretty much all internal details, see :doc:`cli/overview`. Next to this configurability, the strengths +of ``mml`` lie in its extendability e.g. through adding more modes (see :doc:`extensions`) and ease of data integration +(see :doc:`guides`). ``mml`` also offers a plugin system, and ships with a selection of useful plugins to enrich the +experience (see :doc:`plugins`). + + +Basics +------ + +``mml`` has a very flexible configuration mechanism from the command line using the `hydra `_ framework. +To understand the usage better we tackle piece by piece of the configuration. + +mode +~~~~ + +``mml`` has a bunch of **modes** to choose from, which determine its behaviour. The results of these modes may interact with +each other, e.g. first training a model on one task with ``train`` and afterwards reusing this model on a different +task with transfer learning via ``tl`` (the details on the ``reuse`` functionality are explained below). +Each time you call ``mml`` you should therefore specify this mode. If no mode is given ``mml`` only shows basic information. +An overview of modes can be found at :doc:`modes`. Each mode usually has further configuration options, for example +a mode may split into several **subroutines** that can be composed individually. A typical call may be +``train mode.subroutines=[train,predict] mode.cv=false mode.nested=false`` that trains a model on fold 0 (no cross +validation) of the training data and uses the same model to predict the test samples of a task. + + +proj +~~~~ + +Each ``mml`` run is assigned to a **project**, which is represented by a top level directory at the ``MML_RESULTS_PATH``. +You can use any string to define such a project (``proj=fancy_new_feature``) and also reuse existing projects. By default +the ``proj=default`` project is used, any new project name will automatically create the folder. +Multiple runs can be assigned to the same project sequentially or even in parallel. Inside the project folder (precisely +inside its ``runs`` subdir) each run will individually create a run folder that contains e.g. the ``exp.log`` file as well as +other information. Note that the results of a run are not stored at experiment level, but at project level to enable +shared usage across runs (and even across projects). + +.. _continue-option: + +continue +~~~~~~~~ + +In case a run failed (e.g. CUDA OOM) or you had for some reason to +stop the run, you may **continue** this run later on via specifying the continue flag. This is advantageous in case you are +developing a new feature or have a long series of computations already done within the run you do not want to repeat. +You can either specify the exact ``runs`` +subdir (``continue=2023-03-23/11-51-42``) to continue or as a shortcut start from the latest run (``continue=latest``). +If you use ``continue`` any other argument besides ``proj`` is ignored. + + +tasks/task_list/pivot +~~~~~~~~~~~~~~~~~~~~~ + +To determine which task is used within a mode to be processed use either ``task_list=[task_a,task_b,task_c]`` or define +a `my_tasks.yaml`` config file in ``configs/tasks`` and simplify to ``tasks=my_tasks``. Many modes behave differently if +a designated **pivot task** is given via ``pivot.name=task_a``, note that providing ``pivot.name`` automatically adds +the task in the ``task_list`` (or ``tasks`` config file) if not already present. + +hydra.verbose +~~~~~~~~~~~~~ + +For debugging purposes you may activate verbose logging (note that ``mml`` logs both to the ``stdout`` as well as to +the ``exp.log`` file of the run) by setting general ``hydra.verbose=true`` or specifying the loggers/modules you want +to debug by e.g. ``hydra.verbose=[mml.core,hydra]`` (see `hydra docs `_). + +reuse +~~~~~ + +If you have produced some result and want to reuse them in another experiment (e.g. extracted +features for a task in another task similarity experiment) you can use the ``reuse`` config option +as shown in the examples below: + +.. code-block:: bash + + mml XXX proj=test reuse=none # won't load any reusables (default) + mml XXX proj=test reuse.models=other_proj # loads models from project 'other_proj' + mml XXX proj=test reuse.predictions=[other_proj,foo_proj, baz_proj] # loads predictions from multiple projects + mml XXX proj=test reuse.parameters=other_proj#3 # loads parameters with number 3 from project 'other_proj' + +By default the most recent results within any project are reused! Appending ``#`` and some integer refers to a specific +file number (e.g. the parameter file ``model_0003.pth`` in the example above). If multiple projects are specified the +last found entry is kept (e.g. if in the example above ``other_proj`` and `foo_proj`` hold predictions for a task, but not +``baz_proj``, then the last predictions from ``foo_proj`` are reused. A fundamental exception to this mechanism are models since here +ALL models are loaded - within a project and across a given list of projects (specifying ``#`` is not allowed). + +trainer +~~~~~~~ + +Under the hood ``mml`` uses `lightning `_ to run deep learning routines. This +allows a very flexible parametrization of training behaviour through the interface of the +`lightning trainer class `_. You can pass through any +arguments to the trainer via ``trainer.kwarg=value`` from the CLI. (Some values are set by default from ``mml`` others +are not, so you may sometimes need to add a ``+`` in front for those not used previously.) + +.. code-block:: bash + + mml train proj=test trainer.accelerator=tpu # use given TPU's for computations (default=auto) + mml train proj=test trainer.max_epochs=40 # will stop training after 40 epochs + mml train proj=test +trainer.profiler=advanced # use lightning advanced profiler during training + +others +~~~~~~ + +`Lightning `_ offers more features like callbacks and model tuning +which are mapped to ``callbacks`` and ``tune`` CLI within ``mml``. Furthermore there are plenty of other +possibilities to set behaviour from CLI. To give you examples: + +sampling, seed, gpus, arch, .... + +.. code-block:: bash + + mml train proj=test callbacks=[mixup,swa] cbs.swa.swa_lrs=0.005 # use MixUp and SWA callbacks, set swa lr + mml train proj=test augmentations=randaugment tune.lr=true # use RandAugment and auto LR finder + mml train proj=test sampling.sample_num=1000 sampling.batch_size=100 # set batch size and number of samples per epoch + mml train proj=test seed=42 arch.name=resnet50 # use random seed 42 and a resnet50 model + +Type ``mml --help`` to see all available provided config files (or look into the ``mml/configs`` folder +for more details). At all times you may add ``--cfg=job`` to your command to give you the fully compiled +config file (may interesting to detect new options and become aware of defaults). + +--multirun +~~~~~~~~~~ + +Attaching ``--multirun`` to your command will start the job in hpo mode. Note that multirun does not offer +the ``continue`` functionality! Read more about this in :doc:`hpo`. + + +Hook into MML +------------- + +Depending on your use case there might be necessity to hook into the ``mml`` runtime to provide your own +scheduler, datasets, path assignments and more. To make ``mml`` use a local config folder within your project +read the corresponding section in :doc:`install`. There you can already create newly available config +files or modify default configurations. But to define e.g. a new mode with a new scheduler you have to make this +scheduler available inside ``mml``. Here are multiple options: + + * call the ``mml`` CLI from inside your code + * make your package importable and use ``hydra.instantiate`` to refer to your class/function through the configs + * provide the ``mml`` entry point from inside your package, to load it as plugin during ``mml`` initialization + * clone the ``mml`` source code and make your adaptions directly within ``mml`` + +The options are ordered by increasing complexity which means more possibilities on the one hand but also requiring +deeper understanding of ``mml``. + +call mml CLI +~~~~~~~~~~~~ + +An example for the first option is given in the quickstart guide of :doc:`index`. It involves importing +the objects of ``mml`` you want to modify, e.g. register a data creator and finally call the ``mml.cli.main`` +function to pass any CLI parameters forward. Note that as a downside ``hydra`` cannot instantiate your defined objects +unless your package is installable and you also have no runtime access to e.g. the path assignments of the file manager. + +hydra.instantiate +~~~~~~~~~~~~~~~~~ + +The next option is to package your code. This basically requires a ``setup.cfg`` and/or ``pyproject.toml`` file in +your project. Please refer to the `packaging documentation `_ +for the details of this process. Assume your package is named ``foo`` and you have a module ``foo.bar`` defining a +class ``BuzzScheduler`` (inherited from :class:`~mml.core.scripts.base_scheduler.AbstractBaseScheduler`). Then you could +create a new config file ``buzz.yaml`` inside ``configs/mode`` as follows: + +.. code-block:: yaml + + # @package _global_ + + defaults: + - override /augmentations: no_norm + - override /sampling: extraction_default + + mode: + id: BUZZ + scheduler: + _target_: foo.bar.BuzzScheduler + subroutines: + - a + - b + var_one: 1337 + var_two: 42 + + sampling: + sample_num: 1000 + +This will behave as follows: after hydra compiles the config with a CLI command starting like ``mml buzz`` the ``buzz.yaml`` +file is included and overrides the default ``augmentation`` and ``sampling`` configs. Further it even more overwrites +``sampling.sample_num`` value and when ``MML`` starts it will use ``hydra.instantiate`` to load the ``foo.bar.BuzzScheduler`` +scheduler. It may implement one or multiple subroutines determining its behaviour and also take ``cfg.mode.var_one`` and +``cfg.mode.var_two`` values into consideration. See :doc:`extensions` for more details on writing your own scheduler. + +entry point +~~~~~~~~~~~ + +If you want to modify or extend ``MML``'s behaviour outside the scope of a a single class (like the scheduler above) +and provide e.g. additional options to some of the core functions, like a new method of +:class:`~mml.core.scripts.base_scheduler.AbstractBaseScheduler` or automatically register a +:class:`~mml.core.data_preparation.task_creator.TaskCreator` to be available in mode ``create``, you can make your +package a plugin of ``MML`` by adding the following section to your ``setup.cfg``: + +.. code-block:: none + + [options.entry_points] + mml.plugins = + your_plugin_name = foo.bar + +Each time ``MML`` starts all available plugins are loaded automatically, which means importing of ``foo.bar`` in the above case. +The ``__init__.py`` file of this module may then modify ``MML`` internals. You can find examples for this at :doc:`plugins`. + +edit source +~~~~~~~~~~~ + +Finally consider cloning the ``MML`` repository and modify it's behaviour directly at the source. Have a look at +:doc:`api/overview` as good starting point to navigate through the internals of ``MML``. + +Pre- and Post-processing +------------------------ + +experiment preparation +~~~~~~~~~~~~~~~~~~~~~~ + +Especially to planning ``MML`` experiments there is the :mod:`mml.interactive` module, offering the +:class:`~mml.interactive.planning.MMLJobDescription` class. The following snippet shows an example usage: + +.. code-block:: python + + from mml.interactive import DefaultRequirements, EmbeddedJobRunner, MMLJobDescription, write_out_commands + + reqs = DefaultRequirements() + project = 'my_project' + all_tasks = ['task_a', 'task_b', 'task_c'] + cmds = list() + # step one: task creation + cmds.append(MMLJobDescription(prefix_req=reqs, mode='create', config_options={'task_list': all_tasks, 'proj': project})) + # step two: make sure all tasks are preprocessed + cmds.append(MMLJobDescription(prefix_req=reqs, mode='pp', config_options={'task_list': all_tasks, 'proj': project})) + # (optional) step three: modify tasks (in this case create subsets) + cmds.append(MMLJobDescription(prefix_req=reqs, mode='info', config_options={'task_list': all_tasks, 'tagging.all': '+subset?0_1', 'proj': project})) + # now either put all commands into a bash file + write_out_commands(cmd_list=cmds, name='my_commands_file.txt') + # or run them directly + runner = EmbeddedJobRunner() + for job in cmds: + runner.run(job=job) + +experiment evaluation +~~~~~~~~~~~~~~~~~~~~~ + +The MML framework offers extensive log information, both to the console and to the ``exp.log`` file of +each run. In addition any NN training can be monitored by some experiment logger. By default +``logging.exp_logger=tensorboard`` is active. To show these information you need to install +`tensorboard `_. This can for example be done via + +.. code-block:: bash + + pip install tensorboard + +To start tensorboard call + +.. code-block:: bash + + tensorboard --logdir path/to/results + +and navigate to `localhost:6006` within your preferred browser. Loss curves and metrics are shown in the ``SCALARS`` tab. +Multirun experiments may be best inspected via the ``HPARAMS`` tab, comparing specific combinations of hyperparameters +with different views. Setting ``logging.samples=n`` also logs n sample images with model predictions per epoch in the +``IMAGES`` tab. There you can also find a confusion matrix for each epoch if ``logging.cm`` is set to ``true``. + +For large scale evaluation loading model storages and the corresponding pipelines works as easy as follows with the +``mml.interactive`` module: + +.. code-block:: python + + import mml.interactive + # some interactive sessions do not inherit MML_ENV_PATH env variable, you may provide this directly + mml.interactive.init(env_path=...) + all_models = mml.interactive.load_project_models(project='my_project') + # this will return a dictionary with all instantiated models storages in a list assigned as value to each task as key + model_storage = all_models['my_sample_task'][0] + model_storage.metrics # holds all train/val metrics across the training + model_storage.pipeline # holds the path to the yaml file specifying all relevant training configurations + model_storage.parameters # holds path to model weights after training + model_storage.predictions # holds paths to all predictions made with this model + ... + From 9950d332aa2f9571707e3236c29f7b68f0051d3f Mon Sep 17 00:00:00 2001 From: godaup <37296210+godaup@users.noreply.github.com> Date: Mon, 30 Dec 2024 04:45:13 +0100 Subject: [PATCH 3/4] Remove tox.ini for coverage Replaced via .coveragerc in main branch --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d89fbe0..e2784b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ requires = [ build-backend = "setuptools.build_meta" [tool.pytest.ini_options] -addopts = "-p pytest_cov --cov --cov-config=tox.ini --cov-append --strict-markers --junitxml=unit_test_report.xml --benchmark-skip" +addopts = "-p pytest_cov --cov --cov-append --strict-markers --junitxml=unit_test_report.xml --benchmark-skip" testpaths = [ "tests", ] @@ -58,4 +58,4 @@ warn_no_return = true [tool.ruff] # Set the maximum line length -line-length = 120 \ No newline at end of file +line-length = 120 From d9503df97cf8f24aaf5d0d27566d53c6a7d80dc3 Mon Sep 17 00:00:00 2001 From: godaup <37296210+godaup@users.noreply.github.com> Date: Mon, 30 Dec 2024 06:37:24 +0100 Subject: [PATCH 4/4] Remove tox.ini from Dockerfile --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index e751b7f..a3b531d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,7 +26,7 @@ WORKDIR /mml COPY plugins/ plugins/ COPY src/ src/ COPY tests/ tests/ -COPY MANIFEST.in pyproject.toml README.md setup.cfg tox.ini ./ +COPY MANIFEST.in pyproject.toml README.md setup.cfg ./ # Install mml (insert your extras like e.g. "[dev, docs]" here) ENV EXTRAS="" @@ -47,4 +47,4 @@ RUN mkdir /data \ && sed -i -e 's/\/path\/to\/data/\/data/;s/\/path\/to\/results/\/results/;s/available_local_CPU_cores/'$NUM_WORKERS'/' mml.env ENV MML_ENV_PATH=/mml/mml.env -CMD ["/bin/bash"] \ No newline at end of file +CMD ["/bin/bash"]

v1c&l-m}PA}^#8w%Z$nYdLRzWHV^&|AE(tHg}=zCW6IZ*5aR@`&Yf z;24faff(AD2s77gald(!%g(ITOmx2`aH&$pic4vJx3Hp_hi{l|fDdZby35qGwr*|y z=6kd9$stf#O1ad0t)INO1O!WMWL26>+dJC@Gby{elFL{+ttTJuw`MQA9rTYgp9IEeDA~1f}0{9SB#pOIy!sL^KNt4ZTM%yy%%M&^*2%z4hi> znAPcibCwSLrA=0mgC-{UjKuI0$%)up_;6&nG7Z+#m8VWsU z$Zm$sVx7)G3`amLFP8B$@WViXp@se#yPfg=yZUrthMlB;Qn zVU%4-Qo3d$Pv|bC+VFzad+T*IO}@WcKaz32V5sNUR;rm8G$ljyW*Q<~>WGG;1zTe5 z1PSX`5g`fE4k&TI#H=;EUy-*sJ^?a2cjv3OBEN8W`MsBHDYe%MWL7-|s$srl8^uK? zg}U$&>*jKpAMfu9nd6H{$51Kh$al$dU3}<5tx=WsO^n?V`jmbY$tfHA6Lr<@g5>=r zMbs;rE@Q_G^s4idUl_1>0flCb{I zili_x0`Gmz87s9Ze*S`Ty!s!F&iA)&IXZ~f7cUOVT*!YsMHS=~hO7K;m`M!ahzU0g zX^A0Pjyk(|2HiLQYl^6BA`fYSd`>$z0IdXzUZF{{6$SB-?gNBdyFS%d7(Cfo)&6@s)^8{Io?UUy|P!GtO%d&n&%}3Dug3 zA21Y%mP$?t0`tWcv-|{mTUL=EldGwt1CWJmQl&YWgQ=|vW4p~6ex8oi;3H)0ZIzF@ zwqnF4D%3bz*o)*VO<7l6@gqxb*9x&?(|Tb9wPGxdf)Xg2-yhWR?hxQULr;c@TbSBB(%;u#&nr?M+i>hQ1ceYg)bPRs;q9UorlaY|B_ z;v8+v!c?`G5Im5N-_ozUVHZS3RmIfQ>11=2isi35Fw!u!bp>`U%Q0%zoB47sYY6<7 zqXHrZTv*!N>s(&i+R_tg9@h&^Obj>eODKdj>p`u5Y$uU`Og<<3lJJ4iPyKn{QtY(Na9m@Sk>f1p8%TT9{_m6b%T~XC7O1 z@!f~g-ra>UWmIe!8Ain5&6sO1y+RbHo5fXdS&)m1yV!7^kPUs3@NUfB%tr{!+VuI- z(`)*@zMrzF=g(Es{5=+)C}inb$Q&7Kk(!Mm#%&?!#lLg_+TLvMzV9UVl1Oj%%#O*c zWX&#-;3GG|Vw}(8Y&KtAcBbwk}MB`xf(d7Fr+0j|)*~EK1Bw%9F5T`57Qym!)dwcD`gP-Vy1RcJ^ z0FD9{7@YrZa80J+latttFKX(2U7ejl39`5Xy*_M%)x;>t)`1h z8Sk=3_WMlm=CsS2G7mC_J&T{nsJko1Y>zsvC1r=Z%uzh+Ycj`Fd--sov}ZgM5TxJ# z2Gao|&4A=_{o6#EbO-p*>Ge%bB}Z_aWa5wpy!n}X&u-R6MH4oA&cSY;K|-*2GylN* zZM_`?zSadZChJkjOf#h61Y_%$Xb>Yv%z*4j=wc~(r*PcchLNEQ7YlNf#~{YxATHAA zYQ+Ic4JCJ6)#bJ)w=`Ui;H-|8ETo0?(DT9fwa(9fbvHIxg#SN`{QhO`jZG6Y#q$`u zUTZ9fDrEinBa0x;OFQ1L*9=`}5U7{m-n)qswp~5CWUu%B8nnpLhsHugL*P62mOA99 z_fNi89j^-e;u$%l?>{F3YVaDJNO>d!ZQcu(78ZHBrCMDgqLvm`1)b?S>HF@jxM=fN z=Lcu+nB^rHAErJh@Q%QnBl0cwU!MCPXmkxc0kefL7c{2nBf&^>N?K|y>Q==-ag2)t zlH8u~C+B5Uup{=g&uL1f8MU@gZyb-kn}eMZIm&JuO)zqt`Zt;_RIkE2l)%L=#*!@^ z6J>!MLwN?|px9esh>;S8*dIueBN$UG%w}`H?5)2?!s;xcq|b2D2XKQiF@KjIt4`ik}1$p!EC=gY2K zDUGiRm`{6`>qJ73(=ZvUNO3$XDzn{}BA(^w0QTCKI|thSS6glvehJxedWDa!$ zM$_$)swxQLfQ~>308n8-V%($nIPf{`l7?oSZ4Vbr>Z&hI1pJY7y!~_2(H}eBK#l-m zSL1_!$ot~|o;385v1Fq&+B2fN_+DlY)>meI(ngF4cNaIYQ|ku-RFpL1bUvqq+Bxz= zCC3;vx#JHY$ffWWT%W$i`;H;`=pb@3Y z*$nB)NJi!j%`>?z13wkieM@>VUPa znoEo)aU55GpMY{#P?i2rJm#l|nXG?n%~o7y_!w<)_w;d41mcyASde|&J@e34y1(sK z7Z&6nrHI-O^yNgZu;1@6GGgzE-hB~deX@=WSRF+F26_YkN;*Cn^`ezFTCS$htZK6! zdtMDRr8-e2ij1LK=y0Ie6Ic$4Il`G~sWV=)*U**sB`T`WIPd%}EWk7BmkLVtau4oQ z{Bv!W`qy!4`^tVkA~=D=J3mwkJHWz7Y=vsu_^`Pt$Zh!%tu1aGyWK~okXB&4X4pbzeuAve?LuL<)YdBqe=#o` z%A_M7WLKu~vVj)9e(U|p5>&pG7)z0%r1&aTc4kJeF$+FNoi}v0ZF-D=Ed)o@F{AKQ za>zdJD$ns4CqiHIC#{?aO^s5*^qX&2eHu!HwLg<$O_OOyB8?{;e=cJnALkc>P-O0K zDIdhkq}Gvs1kZ+`y^xS9#vT+X>5qpHyfXK_P8`w|C4=cJiUwvBW6)wa5F!qAba2R` zOcAivLGK6da-kw!S0G17_Nkb(J#?bWj-hR*$EX4!?RZ<|%&=FE&yZTO=JF6X1CHhLZ&rS_cOa4NqAoTbVZVgthX%+ z2Uo%;`m3v_n8sf*D#RnR&aYXhrYH=~v7tYKzEPvLLQpGKr%k#Z!M2mQ0dYMuO0E11 zE(<4ts0MSo?}%9!r)ODnPRn#{NwS<4((ApzibLMaR0TI9RahLASY;jhQZV8b=py(I z02LCrL#c`LWQjDyOg0DaXmdqs)UAB7(NtJ?;c;3Io)Zs5ZCf)g>ie)zf4^1GTuwKL z*4LYytRCzuB>8VHkH+oN^-#ymWRKlu97$ROv3|1~TT%>KtMS*5 z?B+kQaXhN-^H{A%rQ+`Upb%npwu|>U;jn@PqQYok5fxB9W&&4z0fPr<)%j$ZA!823;2>JJ#h z495y-)KWXunL=Gx@EDMo=e+eo^IU{9=6h_iNQ*F#ARe*19lIaC6Y@b~SlM?iPEe#U z#?0G$&XMHo@uyl3bY@NU{B_mR!Wk>^IZE7P{jyTSH~sL67bK1dO?=eNafH-jLPAwS zq^7K7al!MFe1+naO>;829KMu497%GH9Lc8OXX8;6I>!>**}qoss~qtvcC%w&eMB^e z=Yt(c2$CZMS47@r%bqbvwQ!{#Rexhx^(#~hg_b|NMVpnA&o{{(89xT?V#L7sHG~M!n)jS9kSvw4F!dt zm_|In)FUttwTR7MJXb%b$&7H)@CJGOFL#1SK(RD+P^x$@`Z)lRPj(?30bI4OXmPi$ zMnw_JrycBN7XReBdXniHWC8r!Qchkf!9VdjKfF1xTNM4`Cqg;{>65?9*NuBwgJot(8yzn9C}I zOmn;X1RVwbX%+vjUl%1h1nj|7D&5R@#ZM|J{EI+3K~zbi0qrn&gYb#|Q{i<46~ z*vw4}syN0lrV`zLc&CZGV_Yok4LWLce7fF6rU<2Z!a`{FPP+vKnx01mA!VR32~x7V zX(Rx8Er)5sLuid`4ZV!4@K2CxA`VXHBhO>I_XFYKI&lv9#Mf6R8B~MEUhkd9Rppvm z;4#Hk;#xB>n6bU*@m5{4dr$l=SD(j@C(&NiLWI@vozbd&{SQk6nw@1UI_#$ZzG6$p zfQj5WvPKL(qb6Qhk>diL>XE{CoIV3UL;{5t_S1UMEq6V(&uq357=Er1gJzj93 zZ~peQq-3M*kmzD{#i#O?u_#98W5K(dpw{<6)BrC&>~~_CHn_g{yG1Os=gc@-E;8#0 zE(uP&@wlc?qR$INXSvX1ZNX4cX^Ws+MsU~V(8i5m!&D(deNA&tnSR^uz*u3#?2I}* zxk}~wx-0i07B;WM{X@l5EHajmIZZiVb-3EmF z@#YVHDXcr5NuTacXq(p@!`+>aroxWfKeq@!7Ehm@n;ax^-Zc>vzx-uh7FyxQd{P`*CGr4zs`D8359 zx)Q)@m#@xFp=rUu z?(F!n*MK8kol#iCv5WITC3TDNEd-t4nSSVg7`pBTnQ+|mQP6eN_37pW`)Y@6Y%eP~yT4&?) zdhRDWk1kD|RawNkHYF_3xdS=Ey|aQoZ!-NE<~AMqsK7XUKK5Z?FUf?$y-z$Hwq2)n z^hUb)r$VIu9$!k|OyM;33;l&xP_)nQ1-K<6Zo4$KA~Y#49^GY~-1_nIT+v-`nv0+C(qwS7S+WqTq3= z(0|&5Q0?@buq&WNgsiJXx|P%h2KAnP*s_I^&Pmmq!pw+4a@xwYa>_|ZYR9v-Dc>Ct zuv}WE%5}*7+|zbz*Z3(!m3rroir5Y{#hBY_+v_0DYlo%!dn}P5#hS6Em@JsWNoQJ0 zLoy{&XPWb^{K;!_9ZxqCW~Ulg>qE8o&$C0?To!>@7U}u7Iqe@jjGM>SJy4YkA3$p) zYnWx)Le7onWXj1ZOd&^I&Q380Th2z@Y9;Ib+p_Ra%Rzr$S$ElE3#0^r%Of;|iU3sY z2S-+|q-xKE+Cmvl-nD<*Xfbf+ zt7q6Zl4bgkKvY5@F^I9gP+hs8z@e?+A$_leB$p*un0mG%wPTdjOnJJL->B%DXWt6M z6j1$C=}`;h75tJ_MSb63p8S1z(l_lsu-%UCj*n{C-?VmoE#b4$HKr%FHXDD~aC>{a zYjz)k+F!55jsbyOhpH*y52%!yVFI#`I)%Ruo)?asq`#*7(oOP4Uoz@fFQoo%dG&+R zCg-)`Fm?8Gspwx)l3CHedWKsfG;gNu%1E6(tX7s9#E*CXvQjm0jaR|%LEUkwYM|*I zKB}1WWU(@RJTnq&i9D?Y=pD#oq?{L43xg)=#$b(}H>J-Y!UqvV6p7!w+Vw1}ad3Y3 zEoOMwF6C?}hDya~*1zr@mYWb~^HhV9LKrcsCB<3Y`SZ3h9e4NZBoubH2$@i+g-)Qh`7t6Jbd*}OR&YZK) zK6~cSYhu57`?e!KPy?1yHv)d^bQ0^2x!3+J$wD#Xi7dbM!8U(P$|v2!M$V1d`4de^ zDwQ^2Xb9PVVAXTd-`Zi)PmPc})M!DT zx}Rg?;C@&ZTVx@`fXGc;?xZiC-)g_8+(RTQRCXnc3 zao&94;rW?`5?{Xa*x`>kes8n8>x-Kf`R}ns1;8^)l}RGhRz(H|+l@8NzdZF&@ZXO% z>N#H%zOYcz^^1!Iu+>eu5e$R{^oGkaC`z%@z(KO!z4%VzflO6h5bhbHsh2&pV}2^W z!8x~Af>{lMDcgodr%)uU)YyuuYu)8Qm6h6&U_^-MK(thA5L6hs zs+>+#;KT?TSEP@PslMFeklAA2NgnFOMFtC{CwYQCPaG)PJCW6_f)C~CkLaoANknZ! zbYtpY=gnj#EOlaAV5(QCZT@E-Mssg72NlzeL>UU2RWmW^pB*-#f_~MafEWNdL<|ak z9~<0=zs)Gh2yXW;#a=(8P;x|eJ*chXzPcWkajeW9B_Jsw;^VUJAE&c#=CKnAKoNPLxe2KV09Rm84e!e9r#>ABizb2}UoFI}cp5w)o$QFG>}dFhd*V;n+fp z((OPzR)8xhOYw3GuIj+if-q4~1Xqa>ouIzV-%IM{gnL`lj`$*gTqn_?KfV zY^7L>R!Uum@E`L{n(yvbp+im1PY}#E|J!Y)vuqH4s!Al^q-W>^CRI7yLM_6dX}hW% znD0;2SW?Z3nk-sTD<}UY4u~R5M>)d$XNTs00Ko$Zqfz{D`|z8Z&;Rbb-VYDOe-@U- zdMrThlAbN#IdZi0qgcb$_dL$wU0!klBWX}EMKRU;6iJ(1rOFh^;gP{QxwMWnra=3t z>%LL4d*Y;zf4!Tdjtoof2zSy0Ggv5;tQk~StE<|+a=uP2QQh=Jhm2Fa7|HluV^hI# z`*Q~|znj(4U`|Fx;!5Y`bZg*~L5ix&W+=wyYIi6HAD{Qiix%dr9?vi(-M~i{TsS#R zcqZOd=zDdv#Q5REhyABpO+$Zm&^52Ljv}y@^kAToM(--`gj;o3s53xdNKp{Ou>tYx zxsz!iFJ-v@uMcH14XR1NwkG$lKb4fdLZozkO;5d4{Am{?wfp}iwZtCJXhG72?v>rh}V2j&0<=R|muS;_Y7WwZ0`KC7X*a zuHca}c^qvj2UvkKb-US5*DQWb>)EpycA7PZ!bCz=uCACK6v4Tuo6H!e4VF`)Sa6KZ zQbioNFqVyPARArW8bVtI<9rKze&P!6tN_QOyl+!AHyJ)MSMd+@w&CvB^~}Rl%QS( z2&(&RYG||&bZen`3ORtAy3GF=E^vyEb z+`leuf_=_RTO6!BYdJN9%-&a92@NDl^wc(dk~d2eO(Q5u7uEtE)5}8cAD&LqiRKgT z=amMwN>|AK1}sKw^~6bb*{6OYfjS8`JV>@pf4-L)^x8;p9Gy+8`ob`x$_sU3B${0$ zOph0%TBT;j9+b)YC&*!_7Vaf%+8+!-iK1KRBt1ChmpwMmu<&f1RY}b)Zx3W%;_&=4 z-%ER1f$1^7N8F*3-P{~bo{#rjzi}>wUZsmh3|cFaEOv3{&)lDiuq1pB*LD2ZPHy;f zZ$-_(ZlNyU>ed`~#|T_Av9VvXb(d}^{G0t#Mm5L6e{mFQUu}O6nF4}dM!A9u$PP%; z-02Z0h_IAJ5|8KA^D@4x9?M{X%Bd5AbOb!MDkv%03M_AK7B!k~k=r2DV!;U(C5%tV zW;NFZdzu@LkZ99a2yzw({!V4{IetK<=fkke-<9lvecGL|POEtl2dL z5`X^(Pg60ymL^GVt8l-*WEA33{Py8B)@N(Z@1(4@RUV^mNI~uvc%U_%^RgR(t;>a7 z@BKk2)-R_hX39K?^?N?228WVH-U?i`YY)+w-_ULln4pFKzFFY@vQpt^fN5(i!re`U z_Gin#M4XJ3cMH<3gJkJ))K!C{IzOg>i5nFcS}rw{@6GZxIq+*^EYQkADpF${+R;xW zc#S`#o7TLoD`>)2h7gZ``VKt-{7w^q2SEtS&Ol%lq4~HX`H_IzaXBG2)=J0#2>g87 zDjRgbQ(T{&ifk9Xo@)=i%_U;Kok_LJ3AMwCVI`lo=FTjbMdXe~H!=%9op7k|2)}r? zyxyl>0r(|o;R)zpUqH5}-m4j0gp(DPm^bQJbyEF#A+w@D7o@nU9U_G78$)PHTPLZ= zq+$|9V-q_$YZA3ypBZT~7=noso%g$2I=vAMx3OIWRah-$Df@G_KJUuJ;H$ZoYbLh( zx7Ull4(hEEZ^9Dg_LW`uI|6I?R*c({#H+gd?as9hCC3sWGy>?#KRoO??Pf8Ra)r%{ z+tYG#D!-dD5ylbPG|V4pu;BDG^q8QDlgg~_Zw-0UIl7&ByuMv5K|Qf8;vo2hjgyp- z5>`}1RYXNg$xe@iK_=X{G$g~z$9GC%k}Bm3!Kv1YD*r|LEj3YD*}WP~C&T5jbR~Q?Vp83 zS@60G+-17Fvm1;l&Jbl5Ma)yL=-73oU;!1qn;+~XV+8MO;Qx3zb8>mfwWEcAfM9ob z$ipijP*0rdOcxz}gC2~T?7kNdCQ50A>u0mpJIa53W51A%dS1t+<;;wI4w{DG#9MvW zv9bz5BoE7A_VIZ!JhMO(!WHtie~t{#3cMER8`t9bnENwTy+yLg7yQ*yF}Sm!BWYWE zJ74q|FCCJC%xw>j87AHr4eNGarI-`m(y(K;*q*AN%CEs<)JHEqj=QKcjxs(b6(n=2=-i?tBvO z?C>`>H9a4g@$vClj|hSg3;4V``k6_@F6S_Wf&!KwGr363R?(s1aF{{$iQuabbzamh z4l*pKbN6id&~@h3EvI8Y!|N6DL^*}Bk{1KcV8mL1dRa!La=qYRv3hP5nlZ=95D4wt zv;3mD%`nptyl2jY6)q(urAot2(*FMb$mnQs3k#Y)Y$Qos+^_mSxOKi;1;e8eo{-Q~ zY`XB-OmW2RW0RNA@T$hHWoO@@Z-l>9DM?NI_leJrTy&^{DO~*3hi~InW83J-eBr8a zw(^8DobQm$)#V_Xak2y@VgFh8ZGnIQm=Uup+LF%-&^MAkQ`%CJH`JKOd0h3w@StzT z&aZr!6=QrUS!Z@NhS!o5t(R1r>O9F?LrLYUb`#IH&iBUTzt2*YeL>ZMQa~jC7gHjLBQ8VjdSDFym!=j$*&zy< z$Hm+)LaZE-VZ-_kyd1E2lTUvMnL{WQO{Wga1k`QUas53oT_x`!M7mQg?_beZjKk)Q zlxV4k2Y6h}*}KW1De_ZX?&$4`y72p|@CHk<9G{Bru+6KP*>(=+LQq}U+i&7P)z_y5u`_BR07SO&J zO&FM>GZN_cMcd~j&}HIQm@5~raYyp=yJ5sfUf)JO{~n#eG54Y=sGFR zldhueB|cI(1x@SC(rL$F{xweOP2L2WNe&&9ou0b&x5#E0-~sv|gmJjP*BL%Rs^#8t zC`3m8_po#S_hFHvQ+Y3WGn<~CQmrzX8d3=U~(S9ut z0TJ;|3SRpw+o{Q0$aYt58S{bxt-k;Sy8^NgRRvl zTsv5%=&Vgl_Gl^4sMzI4%@b8|$G&#tCjs)gN0yZCtLu>eSr_&x34}Zh(}7q?k8sQy5)c-R9=z zJcFgyubMTaU$`9OLD)IDxRAWuo4O4Uhy~ZnZh)R$UYIzc85#IgG*oXyM9APw*!xV_ zL3?;(b8|RfU*Er#Dll>S`fGc8(HhLU1+LrUUky70S`Lv79{zksuxBJnl?yN0G^3)X zp#YIdR#tXsY$!;LCRBkYRFXo>*_oY*nc3LU5ko*g;BTci&inW8t>(Yef8lXN_w@Ai z^76{luD9^(Bx$Ehl>?Xcz2WA@1>Yg_{=KxE95VRz2E0>}jIx>|*yjj=JpJ=3{q*im^sON#M5FDh-S;1P zk^pVUBcr0kz}(gw|8Iw-owM=t8OX!-gH&W-Q_;$ zCJj@i(;)t*M3EeO(zJ;_QLZ?$%@>cJp5E)>hMiQ%C+zQEwIOqkp-mSVs!w=0lX8L8 z4Ov;MdOx`L!0gK=(>S@hN{nh${i?M7u)G{0W7Vy@66VWMho6AGe#%KrP)3iDbVUcZ z{^0j&*ep@Lm@Z{Bf67Yv=Lqujl)duOIPUuf{ngEN=ci5cX|g~H#ck&o6goP(U?=5KhK7UnD8lt<{GAQ7)N7s| zvc7&ma3|#M`@t+Y`CZ+%ZGTsrUgIL2?v+;-W&&+gl-HL}v8BLZ0@LEeKcj}L(wku; z{bhK~BuN1V6MWX5@er%xcUP`((C4(9f2AlWIN8?=qhUUP%LFT~rGscp&-B>TAM@1>y~R%>d;6cB8DW?`gg)5RAXx7GO}2Yg z{68PcZ;J|$S`ttV- zGc)sPHv(CnZj-~#R6XtD;$ky$uDVg^P87fCZa}7Pc*!6W2(B1nD zJN<5Pjkk|a&%^{qKqx}*+}v$(4N^F?m4e&uZOi#~o#`NYXhMx{6HCBSZE$}iDlKk| z^W~npUWW^uX0=|hmfmT(RIzGQTbtnK*4El^GA$%XKAolgf>2Xa)9-AU_68)uC%MlL z2*7Z&`X(gR)Ly;M6^;Yl(!4EKh8J{grLI^Q2@yS{QnMqd=)XDj| z#Nm9y9C~&}RB}^)#%)y0(4kk zIf=E@>fZZ~%s(tg$R|&uN~f~VFin9*;`!;3(N7-<<=!`d--|7b2{ljY3nvogyLhw3 z@rAEbHenGF8#-F}4vWpfKRl23^sI{xCN8IZu^?YRl%n&y?}Z6>bex=?vhNwOS3&*- zi=MP;h`h_8qF(dZQD1Dqjc)#t#9y_{NY5e-A}ST!?U0@I6-YeZyZaVsl27Q>F%iwn2x_zw)J$_%NAGE`o77rVBGP2a!w z-5+-*EVuibf^dCua$+RlmMs|YfKMqM%XV`E{(b}ed*It^l^%3); zzW#zu=B<2YCZ^TBqu}dScZnupf0Y^)(`=I#EElZ6!{y=?B0AH(PsLV68G_u)+ zKxNIC?vrNQQkqV2h#m#lWMU2$G}y=O50^Gma(E2|-`XjL@e+|ye zP-)`Pzd}A(`hln0=pdz`fy-z=@bJUsrZhL8r@79Q-SwZs->)h#U7h!kOske9V9Aow z(u96(^i=nh4l4tI(89vThNec54budC1)^@FU3VI@E(l?v?4|=o)0Nszo;*)RlG>j? zf4(^me2(er5?$=@&rB8ud-KKA|CB2AuB?zrM4~qVGW@7V!)+(D` z?`eO5DmQ^hR^j5ori1auGe=92adGDDWWZJA<-LK0gX^B3C-lF&=>Dow_^VC=VfyZu z73UTWeM@3i)|i|C9KQl7hnk)qaXg7gJPz&qHw{^R_(Z^AoXi*ouGIj<`|}GIyGb9S zAG(pVc7yPwXT*bz{zL( zTu3T)lAqYk990c&y~bV7CXBBfJf{f{59bYd;JrFtNdQ6D`5SY*YMG>$7jI8*@9E?9 z%0^*=aL>V9{bVQT;Z%*t%)rni^88?Wa{4oqhZWpJzBxf_Xjxpc-gTVmbm_+SonIKI zY|4geP*Bum42F2Fj)b!0XV)qc4x`}vtlWf~ov+A-*EGl^BXQu67}B8Up`_kl{m^@Q zMgbwT?%;b&;${qc0r!C&ZP#CI_PQGL7V>lI%@p~NCgAwivIAG|Qb#Kjm{U?xR#k_j z^pIO3k8znq6G(+l`tc0ACMG7VOi}c*af(${RZqafn*uk%ANULqF}Tzl-0l~g%BV^4 z<_!b|mx+y6S{!jLb2knb2cZ3*!9{L`v_VQ1ukag0KICasINuCmJ)91bWucOG%35>G zg6QmOG4Zjcre^XkfT&6%=JEd8bi=XJnfs(%nXcA-fty&!162eTHV+VYn8@LI*}1dD zQ#Q_P>rw~v4Jb_xOB_0#V5(;@;eN94%0wuMh$6kYCq`3f-{IGEWw zQ-muxcnSf51-i#Hn#=?e0eCVpGQYQ;EILgN_9-0|A+@z^4~^D1;t~>Z^Ns-l!hrjT z74p3@`WH)(A?VFfYW~Pv2K)UKDGV|z+c8wEnuWR;MZ^! z5B*k?&5O@oO;Rx~hMANVUgqRPXJ==%&KuGXR|}3q!^7-yxy98Fy8R^}c+56CQ?|9W z#mYk)cL&b8PDFTO!ykugXO=$ z?-!BKb#uE?K$t)sDB`e)sX>9F^{D$zze>Y&B1dSp))=OsurLmHFdPNXX{`tDyTcM8 z7_c8O$8pmNMZl+%($z zZmrd3hQ!IAGD_L%3*gy+Qbv&VpArJDTirCd;-0nMh?n?nv^A2NRf+7aZel_)5Kj^V zoQ=u$cs3ZM!v?&B)j}h)xVX4iOfde+u)sjJjQhyY%~Pgh5Dscn(b57JwUI;{_eKy2fdTbc1`{eYO@Ec1fy)m;) z-D!ARdU|P@yS|#X5|{SiKb38pe`E32>EOXyv1M4?ISCq>+Vfi1qz)fMUTFY3>)du# z3uyyKTRjd5`8^IIFZXB8abZ4K!@=DM84)yA>2=fH>Xt{nyTyTt-3sVq9wWUXC>>r= z)ro`ezK1zo+DY;n`1AIAxF{k*g$?VcPHWYquaA~Ob92dju8;H` zWZgfMPFkI8r5l=n&=~uvv-m3o4td|=WHJokkWBh*(Bg&0*mME|i?<1?SUX(DK@ z`RzM1G7gwRT9|8-r;H>o)%UkIobhts$@pAgt8|+N&bCIA47&}g2Y^cpnX9)no&RoK znSRUt@z(X<>O&o6Wy4HZ>0=Vq>RmsI7P~1Sa;zZzn^ObMwD-gbi(?9fS11tfv$e)k@*uyLgCyvMTzB0LV~*LEfg{UQqR0s{l>Rywj9uINDW&+hrZczq_RaxVsYSBJ2!;BO*#eLj5%*`Xb{6>9S`j4r_bvnY^l-*mj#otQ7-y!)HFL&96p z&W`D2Gn||_bx5!iMPQIgC*%kzUbSYVriMG`29D3?44Wg-L)rPEc5FL)Ql1{pPDVES zg!c!{p7N4I$#-M~-8VUOTwH&~_Mn9?E-f`ZS?$K>FpC_nrh5P(gxzu+@DsmACq$lO z3w@u>s)Qm4xm2#RKUOxBCJ>S1)p;!Iy*gLJqU53`U@TFTW=CO^zEoLK4U3IMz1W$A z*`Ka@+fo;vl|_t7!v6~VX+z*ucBTFg+)QqJlPV!gOUve#mbz(D^01R&Kt=*mB)n*g zLbKZ+>5rBy)+e*n&M;%}iozsM`4xs$RdkdkTYdH$mC)4;Te(Vb2&NA=r(RdFxt}Uphek(xXPq~kwxV~bqZB~SjP#FH zD@eQE@?3{s15aC9JA=cWVIL>v>r3!}{pdf@JD$`1jo$D~<47CtQ-~i^E<2iM@3Y}0 zwJt-bT<`d19>8^O2eVj%31pVVLM&B)MHBEm+7v*|UhE7c1HQ<(;U^6#Ddq`V_olHQ zF*l1gEZ4-sEtQB@5D8;CQNu(j64K6mL&b3A9Wywe(hZPUt=$|4FolZk?LHHYg^R1J ze_L5^!Z5l2=T2PY;@}aITUP%3^ZH_)a=NZ6DG4h~!~vT?Ci3rPEp(gEgM)*!uADdi zDJp#CpDMayT?FApqgp2%K(G^%=sDmn`i4{rF>!EuJ?Z#mm6YBcFSnm=4&#I_fCJMR zoYvSSUuHpH9+_g*SP}tTKrTwdBb+qAxNgF2oT%R_`jsc*5K7$evh;miAA1 zg}1To?V3b<{*27HYl5`l!2<%FLA#H0D=qhe#m_I{MJ^*Inb-iIfc#A&-{{)4D(c7S zs0iMO*^Tv)-K!CWjeyO?{Lsh_hb(5eb&BKFnC?*CvRB>V#q#MU3yt=E5h~TcT|*9i zg;-fxH5MqtFol1;IOPo9e9@q<f>KkbV-Uo^!Gh`(Ns8_eI26F~ zR>hMFjSQzj`5inHHJ@slebLfB(XY^S4mh$9_6{Ml91kk$YGbGy%V38Advi-5cE-v5 z{jaCau*8v|7cXG44hxz8>(aGjah&%h`0Z1T`9E^~@#Ws8a2eR``3A!W@2?GglrZzx z9v+ej|EjHKYFP@s!o*|J!OSOw%Y-4}&{8lm#;9cZDVM3;SS$+;@n)z$9yYCf`DtUN z+5sqooBR8>IB zKwNJYbag5+#`yyOy(ai$LwR>cE8Hkn-Tw09{mTf;@^XX}T%gxBF7vto>ifC*`8_|f zG(+Ve08=s#g(ARKWhLTPyAdWKCU$d3)_@|)tu_};HYHu1319iV)v&EC&EHs~g9M?Y zV-T-ito4mM?zl&1)TlIi%UQ_pbMaL+Z4+d`lE4E28lYeH{@CaHYSGe}nV^3NLKCIa zzZ0>-%d(1;4E#mJmLctXjwpP_QYERUdb{zv)o9QH5Y#B%q<;IM)STZeO#2e#%20R8 z0KYpXiN+{@VWYK>XUe6+jP9fb?-Qu{MQjkwwPM1B>fnz}13sS%mF<1p896mIT*XW! za8RHEy&mELU_!Pg2SHp zZGWsd@!58EnQqB@moJDJz}c9Q#yaquSUq&a^lUy z10O`xCH|=*==xx;SDRx11c~`RPsAENzZ@z}Wk zOjTN%+t%o$E<%e1Mt^!T1+_f^3mG&aB|)kvys@mT~Ere6{^ty`!Z8EDDrA ztU^Eb2Fa3=@}JvfrHDyLCPC7DaWn-08hU?izQp7YO;)#qUr_P!A8W1xl0j8YyjZnv zxtb3PIXr{S7<$E+tz^xAhC zk1igO@T0e0Uto5(&P7iXf!i@er&wGk7$3Pff`z*uQmHqFn^o9rZ#gP{gwuZ?==`wwVp>=XK(gvVi)Ece0g%5+B81^@_KcB9h!)U2vF=G z5()xQ(FjIZy%ZB}eFwvXIv`1d3JWR0*>V-SbP0xJa#~shP(G`?Zty%dVAA=H7)Que ze$wy)P%E|TFXRY2USFaB+3T0=(hSkW3b@ zGxYHAaO^!A3W@}XJ9|?VgFQdq=-s*kCGM>9E(RJ02$ zhAlmNn`u6md&a;I@5~pY0B8*p!&BJ?+RjCSoN$X#^JF_m$SWgp;46g2=(A3Y#OC7q`7i=mFxRVJLt9TCg)oJiKOZu|vrQj(HU?6(W|!!8_4|gszhcMa5|bqx z2v+morigH`2;<;oF^)DIym()7XlUF3%@1THtLuh?ll%4LkrM$Q8`0cq=G6+N(d-tR zu>d<^NsMsf*Lea^{sw@t??%&@*N%?RX=!PBd3p168f+4W%`jv7W#r^~z@Bv4`%Ayr z=AG=^DJ3Pv>wm}j5she|=Leg=;^NXR`dU@FwsxUI;YX*hyRd+xr;A1=$B|D=&xWH% zxZkniA`Hvr3l+nm`8I7~;K6-WHRHJdrKzsIzIQt}Fh1b%E+1s(wG9pa8@3x88_u_9 z=61_%1e24KvG*+W^kSl-5Fp_iY-awjwYAmni3kXEWVx4;K0zIpc3!8gJ~3O~<~Q7~ zr#?=;0NeX>=5r=Hd#?5~a+K^9}Bd8;Ae?!SnFivi z(}sl9+U=?igbstGMC)eB^Q-R6iBLMY-LKJMu7@uE3}_qj4OcpDnteULJI)u&^*AKx@J`iNzKM`o0Ur>Dn%& z))H1gk;m0s`ZuiBoJ2Kq&x`j?-p$TtP={DAadZoKRx&N?(e7@j6~A*dX;dw92p!G1GwYtHE(=d)CvH1j0`@ zrV4t7Z2n&AdHi?~2+p`&sX~7;Y#7O7{TDBpa?n)s10wymrJRF)?|MsA= zeAmyeGvM*$c01P;a18L*D^Lc|&=kPU$mI zq#7=bc3P|F27d+8DhXpi5S2)-vjBL`r>Cb3k-(1eiOZv-BPUPKL4Y)zPFBUnzHr5y z*01JEMAZ6R+HhJK-EHuH%mXTeqHiz1hh==mQrss>fxrhz4DVLb1OfCBFY>puub@~t z(pXW^_jx5T5tCThFT+`Y%XYf&B?Db<_aSg=Q>N?73x-)c+zNl;sX$FN)D-mZopNb=|k}vXu60k`krd_|uKSPWNe!6F)dnkaYe6hO3Y(OtL+ZJGjSXtF`o@ zhQaG(6$+hHa7f1&jflGs@C59D#^kAvWi+?8M#8|r0QFO&p+s^SdHLQu!vNzp9mmzK z;EcDH@#8f$2JQTfc5@+sT;J!)aJ00H06duSKrDgPY;8VyzW5tVql4KxtC?yNVDBdf zb8kcEp@J5g96vzMqBc)AidTG`a(*s*n&K!z=3*I?nXKpXr4|l7jz*i;ot+syy@lq* zX>{FwFX(+1<}3iJus6V&O@az%Xna#cL;sASKU__t{o3=CCP-A@@}|wsYArT9!;lDg z_-)w2LPHU|(ZSeic5hd*92^|D?Nw9~a@llE$Iop-0R;z>K^y)`z5#Nz?GRYUr64R|0^s4$^k7^6hJL zz+q+xc(N?}9t*X{Gw%0di1hWx;H~ZN$AD-%xat8YYgFMhM^K1VZYejSri7ngyU9{)HuJV2!1u}>=C5vu}y zGkdxLPj+A4Xun|c$FY;3O-T!ItCPS9Fd5cC|L{08VXhu=xXuv*m6poyQ#FPnuuQt} zzP`P3f4QxGK}4P}Z~!M6cYD4q!H~M=-jt%p$q>}D|MJhmzUMX%Fy_b_e=CfTu^pax7$!O22a{d zxEo5iS6Y`B7k!hI?@&9cQ!hbbVWVj!pcmjQ0)5W}5|O8A*xIuC%7JmA6`&$^UhhN7 z#^%4ey1Mz7>Bt87NMzcKT^kStUg8LlQlL4!2r6za{wNU)ic{y^sw|V1aYVs(KXW~J z7Npp^dNQrF5OJf@%7Y7GBJ|nz2d5A-xZ!l*XL2gKY1igDgnsv9Zw{lZnN{3thy%{@ zg{KFSrJ_IkV7{Ws0w1sd&&tiYm=4PLFRZ}H)fKnbR)Cuur!A7GX>DD7Zy-FHG$=ym z9PcuEomW_yPbl!XqMftDoQW|JuhpP#Kz9SN)eZR@$cq0p38S;R2dEYDy6?SWw2uQJXMeid zoLcsG{X2|@7Rw1+YVnnUg$1IuwKaI^K>5d$UJNUh?q~#%24o5Q6N0+51@o=04PXi3 zYh+;ZuFDB~a-R;-426i!L;>09L1S+gliGZ){0ucIJwElTBNkUTkf|qV}E%kUj7>k`P7DH575bp(Vz8wZFmJtm*+1lsRHF29`kVE6D+Up z2?jdwfRZbyA?kcFPHl=k z+<1aHSy-WE4>;m+I=8!>mc)b1&d%q5NXW@(u;D6Ux$Wrrb~C`{GN7Pf(0tSIdmCDa zw#}}|3HouCFf*jS}YK;2=$WxuC3W>)*HrF<3-|3=lCQNo|!3bRAMHm?W4+W))F6mqA- zY~F{0E>J)Q24S_-%2g-~Ze6K0A5G&y_d&yFgMcPo-L$!WJzsNq0C)~9EiLUH6bX39 z=(j>l-{aLOc>M8^x*%GPv)RkAM~;}5vY##Q?(Ln=e$#eE9l(ji!Y&|0zLX$=qhgZ0 z;CTN0c64dMK(nl@4E|VqoChT-@^T^?@Kx=n`|@c_-GK62JvtiK$u(!Emq!U|FvA8? z2&Fl*6pcc$A;YobgwBj-<~_pZhQ5Ux|5Iw9cHq3Zu_V~_diCsAk=oWHE;u&TnFW%c z{gvi-UrS4A9hTdo_+0-vr3IPs6Yy}Qwh#Z&tF5i=N|BOZeeOm6Yjncb+Z0eJy;0BF z!E|j44MWp*LBK`mz^u!GhO(PL%I>hSNd8avI3=FB_9rOBbaZsY&hxtdLzSPbm7u~l z206@Zy(I=f%)OqxAWabPu>myi+s!{+1ef+zX#Ct_Oz+I%jkm}~`R_T2_@c4f6ZZcM z!Cj@5{D2WNHYSf}BbKbzuKyR)E!(Kkp2FpDpd~%H!r>%R0er{XJv^@`(ME?uopueM zy}is9*U4geyy=B1roT2^8!Pq@D}Zc41#e(4D4+~vRi+~;^o|cc?LL>7uU>@#+|)Hc zUu(Ns(dxbr9~k&N^Axb$=KWGxx8cC&oq|igdW{SxCwI|_juUXWZU4eh7F)%}#N6k3pZ{yuz+M31 z7BC83-^@pO^&2*Jc7}F@h6&QBn1M+9ywr|h2f@>UGR`<;2+$F3M{_a8YFqWy1|-5T z8Pstml$3@K*N+zpuXg#8YC){KxtuXHyuSzf6G~3bSIpWnzuV)$RgHxkbNrSq9OkFj zJC_9Y6L=jh-i>{;HI|*H`*+nqPaiA_$rTIz90ms&n(!Xjxmhou2+K8Zymp+cgJWT< zQpLu_9Z;n@c*z!Mlyb&^z8lkoBBaX_Rb%o<$*kjURn%pR=^1E+P@}@;HfNt9hKpC~)rBMt?-`ZX>%<5ou4nzv_n_TD zUldMka($~&D_0QxisdBOn zWMp#=Y5Nos-Bs~iVgFx=VsIf}ztZ6r8V{_j;dmigZuf^mg}tg5rAfL&jm41Aa7B7waTcCgWDz^ z>1$G~j&QTl5l}|>a<|uv612tA^gl*?7b(|b8u-Rd&}veb;X@Ox#U#xshSUR8JmX@e zF=b_K+doFf$I)4Fj@Y=VKv7(NUeL(oDKRBWL2v*7DY%JmjZIC1jI5o0#}nh@<1gsQ zdFK~72(J=}d_UaxKLT%UdULY&0(PdW^%;i*F>LJYsE#TW3yXM633HaH@c-l*?)s+c zBy13vWhSGS%mgbD&1u7a9xZXXyRa@emynQPxA{vaS7B|aWkoj$qbHo%#1yQY`3$xY_nX%J=o{yEJ5dC|1o$JA!Wc4*@)dvW@-fE ztXAg9ptO;U+Te<hl;Zgb<0xrX-vEhluydTnHwR*Mc;x_x=H7TM{hk zAM~(90M?0&iFtd?f&bB%3H^S$iw)JZnDqQyQp7Xh5f+8;i*rZTv*O)a5Axpzr)Lhq z(i)L0rib9yD^Jayidnp;`A@;(f)5}i<(<6s_V&(--`3@Bt)fq+rDRJykZ)$s34HSI z-maAfWx_tw42EV>9Gp;aOv_|FEQ;6jh#2fUW|`sLMjFL0VSsOJd%D{X8UHg4T;Js4 zm=I-hoqbUKi}U>b{a?sU$Ii!Tv+kAAbXJ_erh2t=11%_8JUmy{(An>|DE$8VROI)l zNY zJ7e}cq9?Dw$vv_Mc`4Ev4O)%sIip%L{RbD}b^z;zxXR3YCO!VL?z~y9UQ0(V?&SEMngztxDgSuNzCh&yh1`{|JXcJan%o z_2G|%b|SM5v+5ag{-0AiMq>(UYHFZ!N)S;XN+ptPh1Ub%aSD!h3bFmqX(jpjP+;-7 zOB6Gu7agJDHV1@TB=7~Q$$2ErJr8by{9M@Ix` z)TphSU};~%k?*+iA1t=u0N!+HWQ60|1(w}n-Yv7a13fSp#l_%i!pQGP4 z-`ggB7M|R{`|{bA={L8)KXi!5`Pf@0kiYE{zHI$e>)dsA)Lw9=^VCD4xk;dU#tDNW zg`3e?MZJPoBFo?St+DbFJZEY{jbAIm8-c=UE-=3h`26>0HX5 zxWwzYW~BeU%moN)Py@5RZrCel*tv8YEt;E~6DwTPL{AwF9qTEeFmV0;8jJM3AUs|u zJX%O*CJ`Yap#pzR@kl8qB%W;&Ch|&6Q@wk57zxBa3tbpZK0ZDfMMWu9RqXfK{NVr_ zxw1yBiI)CB;=U>(cW`q3lqWXq|5klIn?~(#+1j?TpV6U48Mfz$de$}}!8Dq%L)x=@ zl3Qp@dOF^Cu85K~S2kspm65fWj6@|pq!K73fsm)Dq+}gvLqP(ZGDl`b#L?&pIhcoa z?Z@qy{5?H%He4;_kdrf{K*?(C7`x~4Z4ZjMJYGb?AuY9cZkbeUxugnTMML8ws1A_R z(<6ZrNwe2!f$TO9o`A0}YP`?i#nHS1B`vK%*62P+I2ty#z)LcCr`Ru}i z#Lv2>YklPKkTaXu?bX#FKnY~n2Y@M;x4d210j@aXJu?zY-(AdH+X&y_cDnI-Gh*TB z5Z70(8^sYJ*Q$hyw*wb!`d74uMUR1w%Wc-bIR>dxvIU2{mFrU4+H_@P5Kr;-X6NSe zfvB_D?{k|-Ci4&_)0#bCITKfn@oB-IOJuhnJ zw3<|$vy}-03UP%n0d&0-S7FUk1a$qf-m|Cy$7O!EIge41nW-r;mhGqO+36Z2q#G{s z;NQ_<=JrrV^2~#D>7ziSKjk}f@MGq1U_jcHH4aCKcJ$%?5Seh_Mn%c%P*&LE)$m}v zs!md^4yvB-@8bT%NGZgNB110m3ecGTaA9a@NEAq=UzG4*69YUJai=%^hOSa1tI|rs z%+d!A&i&@gY;3Tu&PdGg-LuYAJ>1*nTp+{GBQh>?1e2*d@IU)y8Tv^;`Oxl^pLH)0 z$zYBWkgQ>(k?2evh`yOBUbdC<`ck3OAZvm>qNhjPm9^VUjTpL%(+B-(_fLcuYBhi| z+K`)086KXC-9Li|pY`~waEqyn5fAK_ZJ>dQMG_b)khmQQ#cux4&8bu1nwnBZ&KhPD z_?@f?F8o0+bwz=k?-Cst(e`ZgF7oAC+Wb4>v$W9@{_#_h3j6b;D~#3814Vgx3Gh8E z25mr#j;fIqOs=6Vp7ztx9yBaOC3P)RMvl@7%Q-U3B>}1^UZ8e((ZDfkR==U73{}6d zrks@&+E?rz?A++6=Nu8q)HRP9Ta;%baD@+2RHw-_#vjnBgRu3o#iD89&&PnrvSNm@ zw}WIj-fmMHrx`wJS7{WMmyaxt*2?_+`LoaT=Jr-a3yBBFDmZVm(#jjt4B=Pxg%Iz> zCkxaVlvPxWf3MI2s{s@=+Ue;julE_1*|+L*wo*nL8yj&&#rt-2YeJ!}*TN1SUu{+m z2A*|P-kNbSBc6D$t!u#{SD=bC2mbm$T>S-5mF@Qh3?Gn?P*OrEX$hs2E-6Vtx?4J> zq(iy{B&0(^8j((ErA10WN?J-v`rGIE{oncCd1sh$hB=;_`-*+-z4lt``X^pyUd&Eu zb^M5q0+ajYwT7A+4Rq|Wu&|Ktx4HT6X!d1FjLQ$Ax{{{1hHpl{_$==3SRe8WWZZ@> zmV~#rPz<$b3@qG563ZJGH`uPdYB=HKUYHf1D0s$(QQG{WMI-NiIbl0l?~lYDI6O*k z{g=#7`Ag-XXuZ0^;1Spf&c-82%9AP#3JRbSbWXfmXf}J}!wq5m{jk^-3j%db%``78 zMuyc9)o|(O)X>dc;;jGsq%%F~*+;d%J9m7N>*`kCIaXAZ1O>I+5NdhD{ygp7yEp8* zwa6DaI=VP3<(`nrSIa4V*Sr+K*+pw~#({V7c3`)fY0;V8Ad0h@V9Bv@JIN0N!N0gl zV$-=&Ju?gCq=Ry{Y?;P#d%%sUTDyC|-&ee7=;g?;GMdc1o&THENK5R|n}068yD4dD zkwC4#3%t_4u`ba)F9 zT_N-$osu)h!rfqPqR!H>GJAHx>3rv1wp4G+#X)t>gv!=&j0q8_n{e3x!^#Wqfv4{;f_Sb z+7*BAk z1P2>0b_DY|EurCDaRsWfG)~mWbnO33xX&uy`1vy80kQ=I0fEz~9RW?_ICMY$zm?gF z@98Nh1kR%HrzKA<%vC2FrBkX`g7{gYAz{!W`d?;7fFp6kBddvN(ouHI$KAH>g4;;X zfmL^@?>=|o`==O{{H??ST4KB6@?v>!>KLx{lM<6&d{t^=g(#2gaY6?qE-6XcPOs)B}d zoKNnb{zNRXdbVud_TG`46wXkR^CQ*Mq6(%Cp`W|krdEwQwNO+=j`r3T3E**&byA=h zz1oqirRPEYr^hX-kpJNW8cWAKTtgAvcDe140u+}2&QtRqPSvF)z~bGZycvw{kE~tZga!#0oUCeI6=>&4dHeSI;GN9I?QcG^WnY1- z4uNC=@$kVz2A^$av=@T}dK=aO0WpqWk9WfIMb>|8xd5r4xf)?(ZH?@VAUnd0gOW~; zj_tY*Ex|v3>ex45CA+j2q$qSEPd zS8f*e2LUf+E28+QZ+P+F|BTrd`sOr|WtQ3A?~>H{u8Q`s&+_1*G1c3!vbDt$oZ(U) zn-x2T7V2Q^0mEhw0{D6vC#Nc!2^GT6_zMgxxg1rl&;t}60HKDR2HSixAr z5?EY@7h73;pDgMStkzjgO@bPwS^?08|1;l4je>%*x3^$u6_g|pOvv=&Vx;s|boS5oNcQU0$VvTY!Wx#x zLX^900T1n8EP3;vP|lcodC+C29hr^0{ z_Bx+|nU%dJWqyk(#LHxC)Y)K-N}-~2p*^%>G*s~G?VW)?&$b?1<7z#ZHMI)9%-_N4RxiLU>Aq8q7^o-alr6GOh`mwregvaSW zD4lz+FYXokMw1#z`8m3}N|~9_Lv?%utlP7;^Yn-aS5k2MMA@M0D&e zcEW4Md;l?1C(;Do71NVgI#E-r3wNrl1Rm@I_z*38)( zbBNoOd~E*6r15z58x=NUx2dz`qB=+`$^to{h_G&x`lhD5*4E4uGT>{ZaGA>$_J02S zIr~#?;0eX57+q)aPh6BP?11VwrNPhWk(Cx?QRZl<_(IDOB+)w2CLf7W0s<&S@COD4 zxmI)Tp&gwTe{kA6~PeUAQmdK4Co%8iu-s|;E(o_Pe#;N$ZO8e;z1a5P4;+X z9RA-@6egDy7Jn{JmXLN(-xD`}oFp~(J#d@a@22pVp3Wv5sa{9jU+ve9z6u>9Mf zh2i9?Fg$;}NbPg`WJ8UMp|1q@cNS~@SnkIon7?9@8tyf5L)}yFdnvGcfP;;VOGPKC zEtzxbva2K%^0_FiL$024bw00TeXNPMoCwVyK9UVromseIiNj{s(uwkK_jj9j*lj+z zz2^G`?-KyGX%4O7pmLm}_3Y;ifwbUV9}HjOs)1ZnX4v8HJ4lwyM$HMjf2`i(i9r^T zxjr07*%q->A$VM3)*Zf|^ij6YDIlB16Zz-wK><4+$uHIVWEQS&_JTWUu+ZZ95+{pX zy~C#(3?|9?82Jgtmb03u8F0p#m*qX#|u4s z@0k79TJ`QHzGzJ*a-qWSeNsZ^}^ z#6PplKsXW8-jLvK6o=sGvrO){tJdbu{U&v!#>bV_=^Zq2f4 zA0D}Ojr>Z=(mtXwG&BTy7g4m+7RhyJ^*|@ZgZX77ZxN)2lBPm``{?RjHV92jO||!u zb2|EaNvYmUX6DZ7$(2;GwQbMK2=$z~&v(W)x$AoGY37eExJliKu~?%yRYJkJ`fD6C z-R6#thDns+@TVFbD#MTs-2W|`?EirMxwP|Mdl!+FEd4+99`P24pR;EtyU$&G!5t+v zE$tSSOkQF6gQMHOug_g3j|LR5Svd`$DR*QLFv0d_4+RZjW@e_W6}|yD7dS@DpJZMj z2gCFJjdrNgIE_2dzOT%Ujf{xdv8@_g*WCS{OIxH{ui4GPVCXI=MDnfTgQa;32C1`- zJZ|QYwOCNR*Xf#e+(gs+fX{8-1>vGuw(qrQbAH7hBpdqP7nlc?eA~re98cA$0XNbn zdu{|i{!^0lf#FtJD~2RG(R0QRuie9XQtq7#(OL|5f7#-7tWu7M7r5GfjX2xYEK|b# z*i1tDH`0-w^`3UVx#f$GxLJLl`!(QB`@e|Fs$micLu3Wq{|oj(Jtvzn?e-UeQEUAx z%y33(*wK}%zq;-aX6>Uc*Eo}U$i^16?hQo3ckhUUdbM>Cd>kBa>+7swi5+c7)D0?(?YwdRk5sf3LqaIH)wZBl`r`f@l^ zk*6of+NL3S+9C=rji+IcCrrM0lBnHznrtMJ{wvkh zho~xFJUzdX&Kq3-iVEFbQ_!Dwwb9|3Oxj@}JkgIB1g(GS$u+UP-Qbou4gE zi?(^}4uAS7@PUMQ(P&js@4>@>(poBZ9s9I&%VxvJ0+bQfIzg>ilMXaxMP&I$W&u_O zHP6e-US6Y$J@2r2^Zy+$Nd(E^R`-@(hC%E`=%al1jP!r$9T(zeDc!_qQw(^nF%6gR%f%L)Ub*9{dk9D2b<9O)(3E zulQQe&TM|A-Td}VPDNci7__&9Wmcfolw7L|MJIftVyGEwV#Vnqurpn`%C$^@HzogX zJU}GHATrLB9;^=cY^wO6iM_NJj>_l8v91nEut()uU5Wedpd_ zMIv548OS$5Y(0S6~WvaSPNYJFi!l!rWK2}63fkWdh93GGQ zXB;p6Su0-MVHeQrvkH7MczJz5q>&Dn56220lkJn)Rq)m-&@W9}HbxJ9%D2MwuP|&= za=8KlIyQg?&~*c+u(!#{GOh|e0=M!VxB1=E**fRG6R-Zp&k#KvwakmLQ7%@7k(3X9 zapB8~*=A<8G!?D;tT7>$^#!@Tx>|0wbj+tS3^TL%BNaO}Z8sdO5(eu*M6LN{$nD@X zrfK1c@)oZ+bq$m|vAZJ3Xn&*fKe%Vm^T#BSG1bKx*5Aiq0K=!XPs$IItMHyH*b)~M zj(`x~6N*`t_zntDTrxiVSF1zak2^y1DZ?WoXknUiB#L;y44uw-9cO?1D7*K%bP#xk zVZBHRRB$4h8`S7-@=EfY?e=?J1&n53(uR`Lcej26(IoFao)95#a2g=;G`3eQYfJTN;;N(Z`Pg zpNnqZjs7_+f1i+O=e7mrn2%H>_D+a_!GwOGiiw3x^A{wRzghx^x7ME-Y&KOE70qRh4PBv&HCqiNa2ym1gV$)b$V<(Yopqxf27H3> zZVxjaZAY0rjpa2vT^M_g*Xj(nZD+6(Uxa_ilc_v=fBH}Oij>84%T<7f$iCerzj;)t zWSn;G>~XOv7cOaR)cxzLql2W1(cDp*w%XfF2a#`848mX5a0D2&7{metHMgpY03O;7 z9u#{$_Z(bwE`uO+RN4OTuONvva8pM@9c&8mH;1Lb0$r7#S_DeyiZI(glAFaZqao->KPMjum~P z&6rq24!rktEcsZtjINoQw6_GUx(X!7!8~;CX`oCny$VFvI&ZtS;qZDcl~M)3p$tre z@4rRNP1Do_g9_f$bdW)Ge>eG|rkUn#f1ghzI~&HI8s3;VScL8qvrr)U zsr2t3dbUtGw4Sc|d>Je*W&uqJ29Ta0X$>%X)%1BxH=(5T_LI4r1PDf-h1rqz7N*+! zzZaNVc_ZRMF z;%%AuGhz=4MSRYXrDxaj#WMAEJJ=iu2=|0@AiQ^G`H|nV-I@f5W-!PSLDyGQR>qKu zX~}+%AIgd)r_IgHO1EttanvxG7zzTR&Z$%gWTvYF@4J@ul%Dq%Vm#s7a~0+$x(7-0 z7!o4}TsnpG6=SX4{I5l)5BDCju(E>jS6Gjw{KI5q*RAjg)h)vCH|yT2$p&DKAp;5B zJGsU?cmsoK4DT6C2wsYq%%K>;ih)uQnz8i_ap*(fX=|X{a(5inf$`t)^(A#o7T@TO zO}NFd$ypTn)Wx_a25b1=&)7m*gfA7Gzh^sJJ(&C6$fT4mCLOXD z&{*CvpXexf)T#5DkbKSay@9)R9TiuSlu_xHPG4|)T z7kpyvpBtN&G{@V^Zkl?XC{xB7*Z0dDzKm70hQ;&!3?u!)yQSPx z+#2H6ymSFqY>=xvoYegJW2=xMa0mJZl8TDA_VtiKYvX?>MYLCKmen_|N1VpBRU-zT z8w^XF;1{(zm=+2QGk1?Dx-UV4Af{V*etjT{L5;urs~S_))a0$>9?fpUPAb@S?30OY z-Poy{s3=TjPl=BY9QV6qt=YF#|MSUQtp|i8I7r-!#dOZ~U{$gC-%@0=7b^=f_UF$o z%{Z<1j91fi%AVAJ42p~uISZ51sM1la_|0kcdI|*A$~v-ZE&`Nt@^Z>521@C6X5oyt z-GV}Kv^jo}<(;_))v>;QuJx+%-hc}T7{;E9Dhe5ZOGr|858(;!ZeNlE(6FfeW;Zya zqoV=s>`XXVT@+Y}KPL=F11lYxyL7CqI2H-_si~=QWw!YmB~p5N z6#INU71I+#N^H{EO&cs!H*?aO1R00DB0SQ+=RR#d`6mBX6HB$5aq&E3>au$+gDTI` zx?^Zqq`Pq{zpv?a!T|+5Na@Xq4sXRsNyppF^r+H)s}MXMF`K~5k|?{hhTr^4oH}YO zwjQTaW`+%aM{LX$75Q|vq7J(Ai&XZ`sS;CC!hqs^?;`3aGy?$psGLNzV?`$E0{`1+ zJ?yt}{6}6l_{`~Xe4CeF&{nVj{vK$67^n&X(o0}^-UBp&pFVRSs-fjPiCq%*I$1g; zHQ;FEH2{_da<0KlBEIP2@A6oI%2v=BK=?-EHWexx>J*?-n_A1_eSMts_%4qne$R__ zbX>%4clY9Q^u3Q}ub3DZ?jN77sTde2@eD!2D(F2p7bG<11ggj`Q$+iFZVRNn3X3V& zV7ws5qkW=!i)n2*S9CC4;0MJgTL)ED_y_+K ze3U^D_i`vzswO%RoJnS`&q#m0UZcz#Zty%}c{%((2sD;i-z--2zkK=9W!ii+q5HP( ztA-0#Zi~N88JLy`R(hS-=dJDkrERLSwYTqi)Hbr=&oAD=Ks6HqyP6U^?<54LMW8M(fY2BA5UHE%ycay#LUU(KS?-+9RPOr0qR>!mesC44nQdP%^B!~CdbeJF(7ny>$FYi=!X zMyUv|qiqZPg+^syjDt0-DZi_OtdCLoYAjVqlnvzAAXt69?)q@$mIE|Q6aCJJz!oZ~ zM|wy2Q_SV@y@H;ug_+&fFF`2yBsXBZ z9TQ|U6m+5a@39z6T9oK6{Oo?y^+Uijau2{4yvkJO954SFSS-CuPRx;H+#>vvFs;&o zVL`bql|o`Xx01!+7JvSvJ{Uw}z<^Zic?c=|E710XRHJWrnCb2oSWu^&|4u;CGS^-~ zC~lo?2Cc);2a>l`e2z5xWPrG)v>Bm5zZfO^z>6HnGH>3X0gh)1{7J0_=loH;_vc4j zGR+h9^?XZSZ~p!BXg=R*>as!6(KSvNdL92wYvLgt-Hirva%RBC%1SiZS4F!iO0*9* z??tVL|K2u5WEbS3?zSFU*uK6Nen%2#wtNKiNO{MCN-~C9l%m|w3U60^E*yM^RUXw3b@xTPJjtUTJkblW=9nfV zW-k>pjByv!uUM(hZTNtem*+sBZDsJM@IZJ^fM1Iq+(P`@yA;3rQ2uAz|=wd z|K&kamaA-lO$!gAa5jvKEsk~N_cl>lkn+l-7s zub8AH5~QfG@Ojqi9X6osbSFF)3IFto>z9oONW#)MV8TN`Wq}vrTKv$5d}9diVet%+60cOr*j7lZ@qx_iGk6%o9A?E zt>r$4nHc2<%juA{ zfWs%t9f}U1#Zld`yu8R1F~!LASi%~}5G3sk0sVX|9%z4|JN`ByAqct{6ha<*tzI8j zS6?DAE+Fvn^7X#GFA+8gENR8Ao*olusWzXbJIpoSdDL=9IR1UGM57Gp&P0vv$eJj( z)Y=Qgzd-a=gQrcjz0tj*b@pp6Lmiq1-78((YEPK0YIG=O>PV4rAsyrMFL}#MM#^Ty z7dHg1Tk|J3lvC1z`ekML{QmM)a1G(budFTWY`&I^A~XK6A8`MEeUfK@(A^`Jd}m8#b-|!gH<`R{=`6y0>Brd+caH>oZxe z+jSV19C`JItVLX=3(1X88I##kCJw$$6*N2wkNI887P;Wh-<|8#`w3RJ!x8Sh#9-+L z;Lo#X&)VbYWWpv@baf+vd7x~S(~a!!1^w6GYeaVKJ%m>|D|(`sC=$bJV!aZp@IBPVj@!IY*V(gzg_OVbp=FUx2z!$H>@I^a>UQK2(H{+AiYVW0zxiczK~`L{7$QPl4~uQ#w8Sw_q-Zr)gD#g3!4^ z11J?t;eyLAz~iE@5x@e!Pf!2GgZmci^8F(2q;IEK9Yzu`H#y=lEZui4Yxz3*EK#O2PLvHx4r2x=xw1?=^hB+;~Mx2v7lDuo|Cd1H0V%{iMP<(rscX z^3f6mMFO*niwp0iPapM~kAK=oQ}P0F6vB(YM=SgqYT;WD`MZI_fTV(hI%wUXr|fBt z*z4E)FH}{X4%b!SR+DFM2Py1;6f5i^ym%&pjfYoQn+YuJWuRl>T?#=Pzz9)aTTAly zF8^m8<8sak6Qy^BG$;%9z~`VcnY&l_=Z^po!Y13U?)1h`1%IyBdfO2B;RW&g`n5UM zie^-IcY*7dNEJB{vCH)uo|+4Z_+DSSze`HW1qnJvYzC((M(e*NoF)F@bp9aNF!N1y z_c%?^;3ap=cgH6uB^VPHktdYrAu}9h(mvHMbg_eT=LTKCyESm|>rI={k`l+oE-baa zHx0+{`puY=zoL;h(LHB342Kl(#43hDkc74>#bY@M){3s^tbb>dZ`TK4l6ZI!pWUWF zB-@uGbmY}0zuG8+I|&5IXYxWpFRTbg(?f{Y)^hl+ug;4LLNE-*6;sNs%m#R(((eZ0 zFg?G?<=dhcbI&Rn`7kJ$dI6bK6kq}@sPliMBNu|mr#H~B5Rb5MK8O@BOnFM5vhDs0yf$gWQ(69vFa7w*0($Yw`xIm1O{0y`q;9Dx|>)(p@ z7bmshV(UYPuAZ{m_*2)}6kuIXX*(2zNYVyq&F-Jg>FMte*Uk3;u%uYevWQD9LecM0 zYq#Fl%#_7rgV4$wHG_WH4T3IV4N*4k24-YMqh7G zN8Z19<{>sLoevLVmOi=uUEs(_7Qq5cgD5D(zqj1_b1QD?DXP9!m&T)TGP9X^hU zfgZ59ginT)8s?}qPf=NUU|mI4Lvn{!_#KC`-spa-qU8R;7Ge|d0qYH=_O;wGhwX%OApoqoxs%O(44O4eUY3{4?$-8?RX1`RbrN=*$PEq_Y>Gg~*d z=mMreeZEGw2|-QELuM(5mWSP}ci6srs-xxT;divY!H@sSm0&h;j%jiyV8Co>fS>!| z@}e;PAd~40KliK5lh;)Cs&uq+_;v2q(e$!&Grsc*f&vU_>iVh+-eRO4dJ#RKLv+F`K~2L zK8i-!E7W!%ebn3z=x{vPBdFhsE8u;yp26N7lU1fg{^Ro4S)%uOn3yE#>$~?gR7ZU!Ye` zZgnI5H4pn#)Y3)qDw4zJSyj9=98%SL{PpaJ{1)HRlbgJKwYqw>)wTrgpRtaTaW&4} z*k%?MC9U?>)+_}@dg>I#pe0^{vrv(Wsh^AL_3t=lN#bTrgV*Rly?2wGc!}=#CymGJ zb_j9oq(D^VfcHhRn$CGp7#+4Y|SvNcE8UQ7~=(&uI^s_#Y^$;u3BSYGnp0BsT;i027(uXD7k-@gB7 zH}f6RD!QU&Dvt$}->a+Ae5ngjcOPSe%80iomO2))gW}e!4d!8w{JxYHZ*&-q3Rkj0 z=gH@5+4Es>gCd5UWRB;DW{{=Cq>*>aEBDn=O-m6$^s-vFXpzh@d_91BhSak zWq7bPAypcD1m%dbkiDMdgnbMgrtbzaN?ge}Ek@Yu7Qn|5{Fg%}a?s3ykWg>;^gtK) zp(O z{o9@HQTnf3Z)i&V9&wW4dYtAbbKH+Q4<_-2@_jju{}rugG?W8u2BmiBFDmV_6&Z;# zy>=RI$`I*M%xAgt+5O}huW*7EoyQcm=;{NE8&rlTg1C1}VsBY|NfkOTOyRryQaMTP zG_$?#IyT56Nt`Ke8ZjdLh#K)$)QCo>R=v$jedV8`ac@QrTH%(JF$U({}=d>Nv^s5VqYAA;uWety{yOP z$3kVkPp65f)*C-Q5ES{Y6WAZ7HMM)3nU+&hMPDtp4 z625El6~J^KNcs3pCy-_#hbf6hvGd`LZE$psGGsg3X=Bjtq2wOF)>q50K<9XDxc|c{ zeRVz&g~wExI;i_rLv`5 z{w&EHR$3%5>tt4NQgfL-b{f`r%Fu?OozwrQ<%6|gzcTCKl6dbQ+vX}KI>xBU`9A_B z;}I5_zIRVPzAGgYaA5|sw%l(zIp6yGo0jzUfjyT4G}2;&5`HWr*?6GOhJ>lhW*Ixv z(c6vTu4mlwjXWNG{h*jWzJ{isumejUA8jCu7Y~{uQlLs!kCayg19%VP%d;@eD+Bwl z@eE|@T4dukzJ{RrR;`iwK0LfuHcNsd@rB^>UuJSKsN`3|obY z1*gx6iH$CIeM52X+~M>6!v_PeqN$15HjmUiE{tm$s@Fucl$MriudS@Ent&fMK|@#>&0uTp4DFKa|;w_ZU_LHLiQB3zJ~+_3h#4EoNj{-@n41eFQlV-uCJYT5>o#^ z>+5BJ`0SW*6jq1viJA z&qbsaTje#k4VsSs1T$SPtIzVdXh}}&dh6o}wI0_!i(TqT`y8dfcC~%bxB2r(#*ZsHSi*LaIo#TfkXPGG*8JC>ER1~l2``$r1i~LL<9urvF;AA zzUi<~?YGDbg0*vN{aVx6`u{tNug+`+piI#yso6-Nl_Zu@$P^-{wx15v#kl>0E#~9N zeC(j#1sznUbiVA`N&5@XF8O!1RjhI4YxqhxrY9)i2If+R=p`1E9t7v-b`gUwC7=QK z#C|rcT+`!iVTi2gDVD)(C5jy#2kDM8fRDX6kDB-NUyLt1+iX>67` zdC~>OPC(Nx`1UwW6~+5&ws;VD6_A*jn|~ziXE0Z=e`BlAN*OX~gV$hv?1Y$gZT29lM6!IzznNFH|Srty|s3E%{?_5T}GeQrGcJ)h%! z?!hkdRl$-7nGif%dk}#nbT3X@WJUj5E0^c?gIV+%^kag)Nf)Hl>gRRDLq2JT{i!Cs z67oq)UnigB4lmqKWegnDU@f??eVEktk4vYAIh};EA@ue;8$yE+M&7$zbSTcRrgo%IglgqB|HMQ|f=AW!X zGJr(sQoF?^B^OPRn+RoYE?>WTxTcRVLa>-yhR*=$-UagSPC#BNO}ZnBM7q?8(ZM~o zD^$1E=%`rT60Se_QSS4&#p|Re>*_#sfA-aIj=YkRWVw^-e5;4e!Aqh2E+PUSE%uwJ zX4)}RXPy>Z@ApPZwg2@`lp!IDMxbpaZow^+NW<)@ziXn)kSEZJOg4abqQ`a13CF9| zfiShoI-AMcHd#I-C7NY{D|fkDXQQJX`HHW!_bFCykZLDMoMpTgqTd%`kiGL{!yXXp zI$ismd?D#p)Ps}B!)%D+;s`DV0dteBm(`;`KC137Cb7fO7_sgOJ8XZWFv|q^B$bb= zzgq!D4^G>UcIuaJC+0O-!o48>&gZXV0IWlIy#V7>q!&gdZ~OGN+h?1}i{XtAesh2S z?)R@vE>F9Qwy!ts2JlCmWd8o4rjUL`GtqiL#i)=`pyM7~@Y!-4yWhYAt2&uYN+;wj z4SSG;b?0n@g3WK^#FD7%q%vvyr}3%$Bh%S;UdA`8aTG$+AHt1v#%1D%KI9O67O(4Y z+h!VXsmf7Fyi8lSYvm=wtp^X0D(HQHAEiOHV!Nc|hs-XYTv^F??HHexBrr>`m^L>h zMCzDJ7}%VbYPxSpL!X7@pMxFlME~>S>$1(bBl&LSzsGk@&4z)bURWoIzl0W;}De4cD%<6;G~DR!~ddAu$1?AP$+=lTFjMJ*KfD z5$8KCq+tBjk(Tx(SU42kX{X-(8!>R~Lem$%4h{8y<=j5tXv-}pzd8*?uE=_0C~f`< zNvVu9xjW!e36a$)ruaiLumGz?RA6ZLq;nUqoqDfx_k?cY#L#sR60eK%&G8iHVPTKc zmE@|GPQ1l^kEds^TOY+4$}f^7WCdo-|9HGLt7UgxN=BQNz8;?tw9=n!3P~XdnFVY8 zV6YtK%RTSB1OgWZE}8#mp3L$Dg!7-CBE;b2)zvtEMRI-KN9VDUsJUmj+Zy@p+qcR| zcy)Gw1jC^FfCq;Fi=^ki$SL?GnSlM1$JOcD{!g2VoW{n+>8-DyqL40DAjE*Y74P%{ z0N~|=VbR_u_$o-emxJ&`+D{J@>p~S}WyOI6&gu3?Yxeb8M&*p@!I4~!)no(rOOYxx z)m4#*3X!>h3b%_phTH#GS=4^fn^#SbY!#$A9aJvXzh38HzB}gy6I;1Y#9{QKY-)cE zZ*M;BI?UnNmvSQ2>iv5%ry0p82wfX_@OtOk$jQogcD=9WSPa;hIyt>wD53Q0-hqbEVf%Hl zC#94MhvR}+)IHwY(5rm;Jvoed=q8Ftzw!HtlZOFcPUz(nYN#?$@>-fY3(*6m#X#u(lZ8<;ADK6eD?ky}R$c5CW zZ~NyR*xQ}iUxM;JPdPfX;_kQ z$5hZg`+5|K5L|JYL6Vw|L~4CL}5>ObNhs-_VdWTsMN;8o$?8HVVG;5*t*IX89bGUme%A8PAJe z1t6hcXtGT<52q7`d-ITI{6MoL(q#6&bp*LZ@WM(jG_9nktZ`cHR3qF%sum2yh$lzq`?dC z_boF2*~}I-yZpJS5&wkzP^X_HmX7+f^{HmH?PgUp)r$8%@BYvpn`rjDA4V&g zVQ&`UzG9)Y++MEF=X1zBL?IZVDkJB#*+)=cvH!E7>t%HgTs?zqDZtiM0kIam>#Jn~ z0u>76X&d&8PN|TnrlzK-q(s8bj(u}$>wZ5MY5?Lwg!;wUcOH2UX?bWBKm$NoR~M&n zEd0XE+K*@(`k8jzA6i;t$54Kv3JNZRFL1z|GFZwXpBuxH>=% z`oHYfRw|J!Jd7X|#sn;Ka&kx!g6#=Yk?&bl^l!&UR)u)V_6hue_w9=@@{#ZX>YGM> zQVcN~{Oy=8G)ec)7EbC3_Rdudcb^801$!pr+1geU8O=b%1n+0$p{D@Qxm~CC@BCJ4k7ujjQ3o7)=oO-rizfzfz$JN zb21m5s-!-cl-ysLSxe7dP3hb+*k#xSOVAh=jykA&rqF5Cu{!F$8ou;1mC{YSgI=a< zO^HE3VD*L@V23alX?(Pl!Iyknsk~cpv=W3;&*F*Ia71WntsmZJ)Ma1_Eckg&q%V(X zUzEeVZBXkr_E{J3WWhb9j$i3RgY&C}K)?X9S4|7`Tv7Mwm;VNfif5sYFCB z2a19uv3LY+b;$=MbwLW`YLb(SD1TX-aMd70^@oL3#@uI&n`NUn1&y%`EBEGTd+l&l zLH>B)J2Hn`&mr|gB64BRLW!jUa+&w`#AC~E1|qbRAUYt+f99Q=xi_^}HPwUmI$q2orMKo`frz%5GFN8eH8j~kOMqc99;@05 zARmCN&}nJs2&D*KR+B$Wmfuod=Za^38gKT`+ZJ6>lK7!G{*)YF5;|&8Nm+3J3X+#C zm_pCtN8^8aCy`HQMNDkVXeot87C&10-@Q4+b-@EvG}#c#g>&apIYqgrjbA??7u1Iv zvnGo0kLgPh$#M4XY(%LGEiHDM2}fm<8O7eYx1*XmvY}^bmK^m)b#5wbyZ8Cx&4e}; z2s!k51b+tQt%=MT{Y>?fd738f;}gUwRsJ`By;0J1^x7fA{c@@;1ddJy`DyI`!opG& z%8L4>kW@_FPCULjQ5R2Z<|#z*Zn&E0ey;`%72 zhKp||yT!qbdrVKKqumgm9v1e{nZD8_S_W>19j zK%nr`S#ns|Rrr5npJ9rsHIIvN19}o)$ZaJhb5wA#(~=nx$z$O#tr}^!o}}GE?Pcl; z{(sgU@0SgjLmJqHyZe@u*xh%<-OH%8I)lM0U2&mm@e|g<3IKqAkT`Wm52${&Oqy3lQ@! z%MK3@J#>%k~@k5*sX)buUMo;7@-$bRtyD+GjFn;^%CM|ss z3cfb$-RI@QwgF1V#ATf{w6q!j7YAnTd5epS7tD1RQ2}3h2{| z$^#ySP$jd*hjl1T1u6?|NjGIY_y3kV$W;#=H7wT5+Pbx1WI6+;uB2(A41IPLbX*!)(>(% ze-FqTf4tW%#(Fe+$n(3P@V}6}f&af)4;W1-hzy6eBAieV(YJ2d&L~Q{kOz(448N24 z15Gw5ER?0oEZ7R(q8 z_0GJp-Sr516OUdt<_m8rNlDH2|K7AmhzbumuEtvn^@|7R5CVT7Cw1ZK1>5l@ zy=)C>{7qx5-)X4liDS+m(2I9f#!$YcKe&tw3oDQMZyVqGF*(_}=-6ISP1*IKJfugu z_K-0bjj27w>_Mt$ST^_ID)6)+2yk#hw@nXAPBxoFfRTozU1RM)eag)mdor_|0 zGdGyth|&0mgh)G1+$CUO8M|Y$IIR1NB{~HaVxtEa2 zmZ94j#TKTM6BU|RFj7?tcX~S+m=zSne^YBnk3@Ocz!G<9pQQ~$4LNAV9_J@7lV?KdTl<52%ccVRSBH9%=dYGeVV`#c+ z9whb`Pi{HC4@^sGxr)0w{QZ8Ltdd#&g*hkDms6A99_3NJ{B6lj7OxZsS%1;&m%10p zoU^-@8xj53)RSs6(9QVgih>vm1&?BXR^WDJ2ia>j4=mLve0St9OGRz}fs^+vW^st8 z{5>ZK_EgI>5*7~}XsQ1Ev1%Htp}dh~ZdJ?{!%sKGX!_ej;X&I z(J3pC%Qq2}TV&8KIG>3fU-Mz7e=zv2$24NW#*9Ly=YVh7{b^FaxlfH#=eOQpThtqi zzVheEv$t#Y9&DAk3btV)#P*dDHxL{sR;k5v_FF~sbue(rA3jQJR$}8KY!8HDtF_|p zW$u=YS~`*(G1Op4T<-6y=FbXr*k~89#U%EGdlc`}$_T^Ul5tEuX5Cxd%90)}6kFBF0+iv{SI2I(mRXqx0h!onG zWft5UGo1c)Z&W^bwhVP*CGV}9>t3Il%)8Rei%ouL*sH2U}0G zt*If0S%&rVOlJ-Z<6*PA$Ex8NTe6FV={B}13Zmc^@?oSrRI%gMH9S<&wld-<(LJUN zPPT#=2)$G%ieO{r)pu_#R^+6PJoRH%HY#$@lBqM5{@}_h+#je^LNTSixS@zvB{jl%Lp&nQYQky<}4T;aVGUU&6MMCZ5}| zZLe6|hmW7=-=A_#)$iOY!fEakiqrQ&ti== z7Lo*bSQzqQ++n?@H9zg5LnLNYILx_ZJHIGT)dN(?xBfT7B zFwgJWNoM%=RA3O!Gj8*Z{fKqjZ`1|C54|Wi)b}H|PMq?}XZjUqI3L>L_j(?FDx((A zPZWCIc5T`3Mvo9fQGxZjN2Q(gab_EK??zDQUj*qp^Y<7*IWb#Ch`u(Oo4*^&x5?Ti zVcAIM-5)-%mHFD@l)8C!YH%8i&hLq8 z;=KK3D6>{je}^WycysKds+mFDx=lF*#iUpmSC^LG%4 zcxHbT1mEJqf*9spxyS1_?6UE2Z~Al$3c|rj|GBu>Y2@^RXXfTnBV4t%&D`+L?EQ{| zsD__VE#=C0pSQ_5Skx2fnjrEru)3IlDf4pM9!aRXf3Wbt?W= ziwRfO(w_g!pi18BQJvQ2&o$?~wTvu>iRF@#Ou{c25F8sBr>?Ue34Ty+7;>qd{?f6t z&zqxgh)Wa3_~2zz8EU85?Nget!iluUl;5Bk;JJNGsV?_}v|gt|p1@?lcMbrEek|1p zrjsAnIFKya!~*YZDAd%ly!EZ&h?EaEV}1nOW(gY zl~ESlv9HglpRNDEG5SLm-#I&$S@vMBd}>Q!b#(=uU-sz^(stg-cyQ22FPh;Dg48@w zNkfo}xx{JEr*jr#Y%ZTkvX*a{@X+WPXZ9BKR|$(SV9hM5a%J*Yjr-B92Mp9@X$k#T z_`8^M3Fr2H%aYn-PDZP4I^Hl%ImX@IJ=iL)V*r`yoJ^2TP!(7Csy;x$t*ye1UUr^A3+CAg@ z**z?xx@D5GI|MgIHf2*G}^J?{F2dt7J_^h=X^zp ze0{w8^R09uwktt{7s)#0i$47vN-s^>K8OYVZW+EIO`F66$-&{RZ~PSe2G~K zFafrIx5M*AnI%l@t|?eY{T>Y>d?qb_nktSP>v~eyAZ>k0;elC7b^P=a2i~0tLFj_? zZXvikEycGI)m3DwtE1{)vj)u*#uCmWdQES)4-Q#7&CORnNy=^4i?PGM;K^^(ahvb^ zlhJ}!t*ZU-uKupkYt3^=Z09p>vV_`#4w)jj9u|6PP}dugP3}x1H$YsUZc$RbK81Ha z@ib@_r6>qEVpU=zqiiPkt-sqn%XZAd2b%^6W#5}~ymszrVnH2Ykp+*-TYs?gH0HeJ zfCz%{9pH?oL~eykVN2`l3wM}>_yRn%eke!&(X}d4d3#Ttj7kt(9Xx?cHWtAub$#ye-x_U5)OdO8vgn*&BEo& z$39znGe|Z3H3WUW<5>oOt?QPXrOR)xO>>MvtBZ{}vF4c=VR@X(W5uHIzBr9=ZeOnJ z=2A0&KY;Sd2vrJ%Zfs#eGtoVMiFy4H-kIs?+pwRr9DyDpbRWUcq+o$++IB4^VBh_l zp~tI-yfNx)4)%sZ0U4tu!2zXZqMgHBfh9iP9o^kjoPdcV#uZm-5x%G!8Qc-k(YWj| z5xO+ZBe@;OcGGm>Q9(3UV7X^qAvt<$?g1OKsWhtV5%(o_#!BigkA+A7$oJjp_r2;N z#f*CYOQ>2%?9WdpK$z%4k5&XpfL%b|b5MM~aGIa~YGnb08G#8->?&qV2A9qr=X*#! zzH3q$U}UU2Vls2G2XL!4{;pwRo0?SbZ?T(ac2@s9ozk+Fp%d0tR!!Xp3<8!yDgc+FF;X7-e#`V*~m;Sf9gYwx$?Q}eO0Z7a6y7R#Z3QX#54 zzqF)ae0NE9$KCd-Lj1Uy&WLmo9V-&pO?KOK*(QaA-*!7}FC^>6`Dw2_pQ3rKnlukn z3Lwne7F7nDC~O5z#+OdL@pk~!YVE7?uj}CZQT-Y)b|s!c_X-tpl1%=y<76}Yd}1yE zO8w%@4&Veu{BSh}s#{P)s}v=Te6&|LICDpW*0S%MTk4N-&X-3U+}@B2_@mr~Cxwq< zTFjh@{6f(;t2}JATV1}mGnw*+MP3`8o%s%qQL(`3>@h@B-__N1>5Uzw{AUqmDA??u zgRi}totc#08kOBc<}E#6chC`0eqI(zSsbdIUP=BXMVSLPL$#f)ye6uu;2*RYGa#PT z$2l|fKq3Sspj*v*lz;m?(~fL<{>_WyUoYJktkITiQUB%n3Uk*kZYDFHXdiTPBl$3s zaf)K6UiD!n21>_=d9PY|%Pfugo)dp&2sKrxn&Ne@Ejn4%C3_SzECv0m^?Uoz21fxM zKxF>F?9>yz7sz(t%cv%iaZ0K)tJ^hbe<8}k9y^H>&S}?<4T^ON1-Pltv9&7Ou$3Hj zm)^wtIPTsfvEaOYUEIE&vqliz^$%1CpV)lu)Qa~6O3}=7oat=BVfv_WbmAI8Lt^1U z-zBiP4v}-SjvgMpH~#Trn=JS6-keQL@_kOTlql9&xaxidkKAyq(|=Ev|A`|{C=n); z+}KeZuWm@d$E?uK=9N4cHivUp2Br zB=F<&+WTk3G!@&na!LMIX(;G2yB&hDfpp%UF09g&n*5|sR{}iA{820w0SJmx&Kii; zAEz-I@Hqe0hLLih9hJtT`rBrniWrlg9Vy1ZL3M)UCY-u+_<)lr>vYL+-9joPCp6a= z3G8xe%hoCk#!@hKd0ah%*F5yiu+LCeo=PEB&mqrcP9Xz{&X z(K_!THFDd{U+o!Xq5Ji4ihok$A(sm?ICoUsTmqy}qp5gkCE3c%J_J0&e^Rn2H zpxGjQ!4*7Sqg4N?IwgYpBTQy)WT|er)kPqKDJ)$Idx;HIfl(gn-aOcsJ?KEHKFmf; zzU3x{dWxkO@!5R!oRgCaxQXDJ_utjc?TsYK!@FX2GHl2^g0x$)_GNUdHZkLc6#NSqpr1rxp~ zk|#5RHqQWZR~!^4dXjG~|8_YhO&!RrFPNbq>;KO_(G5B>h+_5`)zm!Q!yHt6iF_di z-$RC`9|+KoROPwq<$Je%qwW*T?PbC{PoUnN`d-f$*>kD3ygpYq@-enpWc*dOyk9d} z;u}S1dPLKE*8T42qCVjhw;NN6TaBwr8-KfN>-~}r=fEq^@}k$0T>XRYnuopJ2|Z=K zm&!LaG~M8!w`QoO+U1|0xwk!Kdm*N`!tW=k`{K$JX7--V1RsL@U}Xht?<(ob>3#47 zOA*yaD($ez;rlgvW1e>2?C2)%_uUMy?Mh;9PDVr|KQMV2B#ETNSp&$Qd)sMkEyaE=S^cUC1#Fw4484sy zeZJ&BhJrSOR9!l3onAtCMY;;i%hCrfqg<4z-<5Shzy(Zse}_!ss)mFK*NofB?3m*C zt1r~Ao?QIw>bJD~Mt)*87z?VApOQ*}ybE(Em-Y~&`nSJ#1D8Y!((+Pvz_bZ9qD?Ov z=Eu-8_#9Zs8r8mFbKE?%sc))5U5~5Y70op`S?ek(Or*+=YhqaQTMGnn zI{!7&BMS+nyCf&q>x4_(z-0=YXUb!o`;@PYT2`z~>Caz4cd(Xsxn z+#T&iqY#VpAG)v2yM6bb_Bo$aI9l@RqTl9>XKQwu-k{G8X{Y?&d9igcBdYUcBkY1q z6leGc{r7Pvza2RJ#pmpJqLo)cznvg;1K&m4#2OE=V~gHlmD10S*>*aVUsX|5>fBYb z&UW=K>F;36fBIe3B@GW;@9b{S#HV$}b=j9+PMQW(a};BH3w@aPx?-Td(HGf|V7y&G z8#PsLs(K~a%Ev#!QszaMuI4NfMwkn~TzlzWWt@mM;sg2M`D>(9Kh(Eh!hWmyVpkBb z^-GJam0U_y19lVPR#$yW?eZh!zPj$r5emhHHp08b=U0CItaC3}+1;Z+-ZSirJ4-ir za%m|tG+z->zCBYL)5f3NiaLWx_Y}F@B&iK97{pLK^OwlF_qG?Dr&S=OH ztt?M!_X$!4p)7U-jwQ56%C(JG4Q#KfTt2un-&s`0XG8TZ?mAcf zR@wHHa@M5z+xw8lczT+HL51~?*U00sG5hqLyv#?+YPE)H&kwI{O1x=ZsTQj5ax=lQ zy_%C?g`-k;N%OV{(h^1?jHDFD5HgZv{qr__Ii=|WqchSs>@xf93dV}rnd3Bln^6Yi zzY~sIpnp7eRi~*PvK>@}q4%EoHStW$+N-$MOvAhYW#m=A(cbQOp_tI*RM<*U`e}1*ZKc8WkpTN}?3EbU)X+T1a9s}8 zZ~qi}_?h{z+*It^%y79(zHK3gLz7APw`r4H{>iDmiF+SdX(RAc5ocQ}vo#`@7iApJ zpZjJ@q^b4eUzu$QH)4_aLt1Y69v#N*X04cyc4?|L8n)$6K?ijLx6kC?`5r!az3r^AHQw^|O1 z(N-U^<(8Xpci5Ja59!Gz!Z&HJU%0(D`4)V8xHQ0Vi6^x>Y#S+EL<=64L{_!Z*N(0p zE}`2@G3j>nrny0tluVB(TJM|Nc!G9Xf6pf`ulZjzEx7ATZC_-vHgZnXq#O!n3(>Vr zx?r2+e6vg7?f^?^GYVSRJB?Y{@?)TRR4VJhh>==j4*DJXq)zJm_|$z>@7&%B_pLQd zZ;f87&)|m1X;*3Vgs*g`RI;sTvW;lGtt|YAw~>v9e{Btm*L*+`fFatg zoU>+D+U(sem@B_a#=B$e5S$=xrB|G!Q15k}!xPp*YKcx#^c)Az+)KMIfh{!>OfC%0 z{1idFe{WD{pxl~)ohfw91a_LT4fw$q0!Y$pEk;&;mI&f5`+$I|_8A+9T+Zcuokd%O z4GmU$ZLLY0v)Kp{()9#XQLR>+h4sE^W=W2`-!2$3t;HJ=F`u*&Zp+TG1BU|Jipb#&Bt_2t_A`}gCbO@)_kG`~~ZVh$3B zA>1wx7`BtRvnKBr#@v#iZEnv`jU!PW4fJE0Y;2_3StAZV#xAjg+9M`pXh6=}#PGL@ zK8==qVf98jvF)gC_S_5{{5NrZ!;Mv#C1>P81+(f>oKV5jhQo0UCp<6(^SvFC<`bde zB3kLSJAO)?R=U2ts;MT0Sq-KsBogU%A-<3}y>wSP<;sTKRB~+9&X#2LV26l*WcjDN z@!Q-=dz{}3EvtqdCbbl{8E*`V^{RMyfAFV3JSqHTD3Jv@NZ@Gj9>2i+X;-t(rq2*l zWt<_TkGBr%92!ajgZLO?Zx(+c=UV(#&Vb;5Ym9sUt38c5bevvNhmG0dX2a z7_u3ReNvhCri?oIvqMEE2jLtf$S4qK$qm-!W6t?l+}^Bgmi)>2)kG*1t(rqvG& z^i~^7TtScp(J{~Q0|+io-?rB%U$EI$SUKEEySA~B`A9(h@%%W=Ode)?O#z7zCZ9qv zwP>E_2_#>kn6T&Em&T)bo`Xx9k!wUB=pO9XisWfX8b+n*=4Ld?c-+Y)J{qfF2v@eS z$bT?`=UizoU;5FF5$@_M56BQ@2n-D z-gRIC0|R1pi`S7RszZUr({s{aq}5COzS~Q`(wj|xV?ph#t&5z??P$6e<8 z`A4b>o;JQ+b@$LSVsVnR&Ce@c`u#xA#=Yd?`qTs7RqFCDEAqoiSwd-vMf{sPbua>7 zMXyR6o)1aYjO3A)mhKvmbc_?6)Dn=Ke0$k=ewX9SVzbBIjj+HWu}3EF+Cz*A`<6@1 z!aLh(o|w=dZreeS3K~kV+@aI$t`A#e^lhUp`yW+>JUpc-f|^(uF+CVf!G*tGzGZgC zMk0Q4>Op31{|So`$rqI@)AlU0VGJi$y>FDXPAf0TYUt=pf@>XJtSFVN$gnxreJz*e z)MWhVD|L^(I=jnjg*=sgHdT)^DrRuB6Hj6r-QEp{>OqwpQnQ*bTP^74H%IdT+_r@caCB-&VKMPipR`09WX zYJ6V+y>y^tgm_o1OzAEuUcsj9VJ)c{<)?dZQ|Z!gqhm;5#5DvGy&S~?-EPtu$2Ez} zCZVY>=7q+w(*guHFRyIUq#Hk;DyDV9+hd_RF*Ed(=b{+8L8)NY@*al|+sC^%M?zO2 z{bOlRmMJ5SwNTPZhdrkglag*+ST~7rG`%lgh99%bye!m{o-s(`>WY~|Kj*;3pJVW? zMKNs-?z&{jo~bJo@^~<2CgY%qAg0~NKzE#IZ1cOsde`4odu#_hE7G;8FT8h9W{vt$ z5NOT{OlQsDV$*-3BwQ&R-!6_m@KI9eI9 z)_K4pY~KyDM&RR;62*LQpOX_g?WGpGWQrZN7Di2^4ikU={P`zw{>On{9Pcw(y*=TaWf%R4fFs!D;KiZ> zL(T*Bs1I3Ndgcd~dGGe|O^~zL>KSH*reFVn%O=Y5uM7m z?zc8pR&*>ATUc?C>Ij&h4OqqtR`~}QFpPDq97b@r$pT)WNE+wITBxaO#0y%Mh5@AA z=yuEZp=bVgp}Y`14a-^WBM#?vbEE238$)BuDT>lJW_VG3=qu(Ik_vN8EYdxwj4wPi zcHOFUvNv$b@TqYg+xCHI)=E!xJH85SQ z)L;_tz9;CGMO9HeI_+G>kmD}RaeJh)*sS3#m*mSQgE>+Nt`mdjDO#WrZho3*p39#8Gg7(`ZtnC zi%E%WoA*R*?$O<-A9fscu(Zp|_WcfNh>`2BBQX$#2+dc(4u)4tNi0~Rs`xjd?UtDZPf&%Pn*1~eDvWWZ58 z8{2Ye(UxB1Ol!+?{LJgY10@?q@GVPA!=7&M9`DuMTk&3NTRX(Af}ZKg8MO|NhOU@# zMJ*i?=o6CqPMbqPi{17^NeSc6`G@0P=W?eKwJH(B?r9BQ&p_nDnsLGO11a{L99u72 zR-Z&m$mMGxgx?0aXnLB>Sq+8W;i#({*lst~VXenz=c@yltGf8BvL$H*2qb~pi$DD0 zcs5%}8niI9qhI8ZAP!aYdTCw1P=9LDJ1M71SBr`5l3^!FHrn#b6Eq}aJ}((9QV$CE z9vEKJA(n*0u(XPUvZPEazsW&2L{q5Pb&!?+`pN8WDB6x(?(1Sp6Vbi$&IF9!Uyb@^~j>KP7)V&N5Ct3zj}SsEYDA>?1ekRo8`0 zv^@M!v9Y*kcgUnW13}8}B!Inqm=u-3iYSAZb!N8(Dcgw}v^e`{eOQ#trZ_r=N=rWR z#y>J^)5)&9`w2j{`l+)^94b0Z_h4pBUq0J?H3Z3f zDWdE(gzdBeDAJFCvDJLK0OpUvJ*HA*YH=q+Mk~Y>=Ht!tb+njrR8Ai>Td#P;a&=9p z?4h`FJLyjS&Sci+R@H4sHI4@3iQVX`9*Q4H@z1$J7r>~jIw+tBs>iiS4~2W;Nuq`o%iHRxQU-kXLYyJhtn90E&vqfKA-e($Y>Fn;7{ni~N#u7;AliyUL;p z_mcl)?|K4ZTfuR%Bevsp^5?4-}H7Tn39N8lf~(L5Nrq5kbv_wr{B*8$ev(qe&u z&zqdw^f3RZ_f0zu^1iZ5?98@b$|+hg*6=9iCo?LKE1M0K?JaCsRFl*Fb_O)$I~C@7 zLgXALBN%;>l2)sW2nmcG2!gC#rGW_dD2)3@`lF$r36?nNO>Yrn8S-m2!rdqN6zv_| zXxQLbY#i%_;OKrUy{$-7P$2@`fpdhjSrd~ItmTvUCbrhL{Q9wOD-=gdX&>%M&ra`Q zHCDh2opl@*9Q&rgb#ki3KB{20IX#eYft7**LEsB<8*_dk)b;<7Y9-A}TXGlBd&Cwy*!*($Jc#k)CQ-c-u8omaz2u zHmUGcNLF9&-F*wES;?+@7L89Dd`FuEF{Dw!(7}j*m2=+#MDfv*fbC3?al5t-@mxqM zY2VCqrVX(KKRYCFj4wB2!9yvp^jyf56>A;^TK|Pr!TdZVW>)o|X|#f0W`KWH+Ke1p zVXZS`-|>^#_bFN%K{)wouRf_wYRl>_mHT6^H&o{SRSKI{RZv=8J>a<}j-=Fvm4f@J zo0l}cF%JGGC&$g-zhKcbj}Urz3Tw{pC&FcZHsx8ymIqf^LKAn7td3 z#Fva6WFKhSOABcn{fDycE1RwHr8AkcN-vjWhvTrr)%v!M_{(Sk8wFOx)JNY|M>krw z-L@(!|DUICLD?rK`5R;wUMf4MYq1Z?(C*s3@W>&1TQLN|`7wfqy+42*>*j0B%+pyOh2w&S&ZqB*5NBRB1kO#GC`R`BI2HAX@(@#S9e^2?@X)R~>St`9!UPB9HAIG5@}eR&qi2ir)6 z*a^XGn%d2(k|7B4SRFouAYu`auL(RuD84n` zoo#irCRaxNA4`MggHtq+x^v-Bfo-MKVkwbt$5iVJ1qgA1R7l^)`OmL^R|A@>(J1qw zzgp3;XHAMCh@uK+D-6O}YKZXVN4QJIw*Z{RywumXuGjM2Hqa5}U}2;|JS%GWz?-C8 zt-(IdWY!A{f}w-lMje=tpnD2y;Z+w0bZo1r^M4Lyr59L6dI(>ZzP7^tcGu|FE>vhzxF za&DLv65aTbKyfFzh-_A*!)$O8aoFR86!QDZzwbW1Q8FV#Q3yUjtk?Q}a6!7bXfrt( zKDo9pkSpb*dosmb{~!xj2M+~KLO_G$cK>a1l!&rH(#@($J~>u?weF|6-%Si+_=Q3; z3E%(}negXwZ~UQxFbJ7#riJ0Tz@x75g7BvxH1&F);S;lOZu~DGSH+I+Y}l>)L-Oi| z@uHYht)eS$mJsA_LutI+*uPHf8xTPhE#*azOG&oZZ+V|wSBr%KL+LQG$i+`>4+@x} zav(zuQx*uJp_v29ht+!dszA01YF1OO7;o(G%?*O*)-1_G_=hNz6$kv=-P%qYWIN~?#*Pjwn<_84bg#f*1lli1&?o%F~rke)h+O~?VGkD9(2uP`b6Tb3mGR<}CdA_0pBs^y;z z`OpK)$t8M_87tAc#YwSVJzC{0MGMVsB}*n==f-owMgq`B^PA#dc(SYocwu*YUXB+% zN43BuIPNMyh}|dsD zJhm?ZPTbq5ccoVQ+=v$;*ZaRrkbU8dDh5zTMq0@XS7R|6JA~W2V;g?^#=Zj890JXH z&yo>Ukf(TMP{I9}Dr1Y^)SN(0S2Dy@>`EcPU@Dlgb z^F5h)DytA>?pv?DBP;PFb%z`keWQ$eH_zT4u~*%ZutiV5`s1kD1sQvtv!$-oJ{Jxd zTq*P7IY!C3Do+PhrREc-dl(T<3_G{QtddQ$5(6|3v^X=_o2lE6C}A86L<;JWO5;40ZMJU>=y2 zz|bQ@fzkG4MjN4E=A@IeM7-Ju4-axZ)IXBii~8+uCspv}u1KfalW&F_+&u^`ANNF)+_nKgCP3pNw8vq)$H#wfv7a8W?Rv}jz(5t}#?d4zH@=J*4#n1;bi?D{9 zizYTZN!8TPIZ1u0k51$-X|FR?tz|DRn*jhcS z$9aT%h33)gFuX|8E$;Tcssxx2)ZDs)`OqdeAJuAgd~|W$asDEdG4U{O#fB2;aGvfx z=U#0*g_0FU3z$p9!wQgYGV!BMQrCPuVx?Hz?#5V>8zlQiHg0w2Z2XFJ*}&}4>&@jT z4PIvqCVHPU+ZTYT9X8O+>G*hBAp_|&;yfN!+3vdd4U}mSF?V!MV2sZ{`WY%fFxQU} z;S5h@59cNnpWTDiVKt;sCd zJ8NV<;)k-C;a|A(PU$PYitM_7u#FE80kcdzScWWAn_4I;i#1WK|d}SY=q8!LPGf< ze^xhHD7ScD^*~sGj4&R@A&U2n(P(_7&29Wh(73)=4*ef-uk5Zh+tx`Y$z+AQ!NVe6 zNiZKF8Dg}*FC~G>Or-DlbL9>PXmC8DQ66=!fu;Wjd*h(1In(cQTUfG;!fJ?HY0DP~ ze92Obd+fToIx`;CT<$)yt@otE$6Vg*v-n2|B`Y$KP-bsYVv>bzpfX6pn-_Vm?#T!c zP%)NGE-Y%@O^cpkRXM*rW#zZ*8v?ZGgP~nCk1j{jgVyCV{yTT8&7;M?K4Q|1b*HYJ z2qd{ZIs}U3Dlv_*D<9|)@ieW|Z?covGAk#R+4o@l(6sSK{-|uZwyd=iZsxo1>Xw~$ z>wYgV3I}cMo1fw}vW;OYYiq-&(f)^ow5t9i_DC!1INqr$Y*oSNJ?YoXx9Nkmjs$CA zmA_>ACjTO}swIG?imbO(C;NwV9yL021e&sU4LX!=EwJ~<$=;tYq^Xa(<@b0>arjDe zrrE^xysXgNX*dPTD0j{PV_znvUrPM-=MNZ5UDx#5D6Febd~*^YX=K*rIwR7-lGUxc zF(C5E>09=aBsb_8D9&0Xm`nHMvdX`{(w`>XLi$*;eIZ)q3*ip=DIAje?5C4wkH>8fxl5+CO}~(seR?7K(?KQ{gP1`Lr`>FuIF%<0vl|J* z|MD+;*Q!`L#_CB2M8IBrIyxK0SMf9M)nF){^FFzN6pGSA(UeG{rcQK;v5b`%r-~L+ zwuNtOgXzM%g=+YqS^OTvS*xENzg5p|5VPZ)9Ki1rn)=M7Fjl%Rw1q^r^E|!W9xcz5 zeGFWL1={;s=Gn*us(JSH?re+zLC}12Eqh5e;DdxT_pjAeiMY(l`h@!J^np!u%Z`H3 zj{jb(`d#&`?r-yJ&Z`x(Q5ME3#yVQ=c7F0821oqBcKQKiB5Ky%R>={6E2~>i;d1}< zN-A+$2{Nz+3X*DKcQc2{S)j6D8g}v;9H-yxnjYI}80q}r1lGUnQt;kpCH5j;h`wMf>?#K0>TwqQ z=p+@^>B&x31v+$?a+9fBuxiZ{2&RQK(1R!Bq|38U*~uv1k<;BGn^V?LY1ay9h*&spCv2!KFiHL zKL#T=2rMB*!NdA7i$ww!PN?=-4qbx*8#1CRDPK@ihb*gn!kN&KxWk>qx@ZJ0UO;YIct z$CqRy##~syk@QWM9xCJFYbU*K9f!BtQ(%)pH;K?$t5?!3xd4Cyg$3p#pW#JBunFdD z>^pk{Z8n2{s5|nMa{L%kO?!JD$2;dPpQofxqFEEYIC!Mm{<5l5+v$<2;qGw0`<9uM z;Ad|`g#-ejqP{+&ch+83US6GJvUNHbGOB=TPCS0Yc>nUytgNi;w1iSIf;sBxyJ_z! zm~4bBM7%aWh$N(^^8NCz40A4e)?@vP`Bl4>yTL~`G3;m$W1C*&wE>K?t83c&Ver8Q zU4S16A2MxH3#MVUe$k-aOsQ*g)IT#rXPzoLGU)nOzd zT!8TF*Dr3)?-IJ@<%LMoURrI#RT;;U%Cl{z{i2k4{ zGBWdZoK#U&hXscKjyEYODHH4F9+&ytR{}zeg^yKr5j+0#N!x7Db(X@uoLoN$$P>Pp z2{ql?$}bp4?RnXDB{H*fZKp>hQ11ngD*Y&`-hW#PYJEBG6*g*pVBef$ z$U^7?`U<8~ZQ}F`b&CdOp~|JIf>1HFEG$J$WX}KcMl>6e7Smf3RSth8khy!;b6s!{Nk9e$dBiZk(8WMAQN~HI>Wel(fHP1Q&Z=T z1Yd>I>DQOnr7-EQM2|G~Fa{p_?Zs)|-2}_=LB+s+LW%dwy0WhOi zsRDLoG3hou&*#vd<3O|-`{;1}t~4f!x%Y$pvY#UnGQr3^nI{W>GJq^8<$(qtMhC10aL=9QDioi~17^<7{1 zX?%hwYgZP2s8!i8pfvsNx#&E_Hyp*I`oWmln8>n54s?f8AiXqF&!oht zMuaN!p?ZYvYvy`zPR^!<1( zy2Li?BFgO1D@O2wCxHploBo8%*pH`n{f%nm#O^_C=KR*TdG|%Prmb9?fr+i5iu+{3 z4$|QeL@323?%nhz!GC0SRSBOBN52@v)P5rct=(tGufy)r8VdL2lkpYg;8W(xIe2Zv zhYz&A=Ebm#>p(Gi|Bg|wSR14U}JqP;>t@{QwUmU zzIzhE9VRTv3W5?h_V#vGk8GMf<59(K-U@ssWQ^Ne_lJ?RYC$;fj0py#5L0e)0}Ipn zLMluIEnxe#sF$r9b|=-k+5ct1p~nER2K?8C+e5j*hUn#Q!5e|9ERg73X!$?NyYX`e zH!942i3PVewJ8sM23a{dzZFNYFEe%kZM|FM-lK2$5n$gT9@T%q>n;7^&EZ15+T8M2 z4~zvvq90xF9mdoTTZGiZqfVmav5#APgyIS?q~Nk}vhS3Y^(76%+oO7Pq6l7hXSLzW z&d&vWJ76Z@4x#oo*|4%VAVmevdUmkE;i2X+#m=CVX5_|U@!dTx!*ZRf2io?x<3Ajd zN-BBWDi9R!^$pbLbr3`ZLe<8yYkqem9|AP&Egdxr9G$pQG-G&{D>s?3@q zD&*^D@7mpMg$3wqEc(_}pkpjQ#J67Srihq2ypZPo^?)x5NhN-E@;$V|wBM=B2c{wQ!1Olb?>K`U5 z?Ah~tN&x?1Im+p|AP_eQul}JRQr?jv5ZJ2Ll9Fm_Rt~NXE>;eXcjYA|?>ag=SXkSc zBM>j9(ljlRnmYy{t)M^_E-G(r6Ul zGGASbit>L=tj=;X9Q*tA<$KvtFLPdncb_hJ<=Bol9If_U)J%x1mF%T`7`Wbyc{4$d zOP$C6W}yVttsgHt+rKU>vxx;@(>fyXF+Z5yb2+C$K^*%E2|c*qe7y;Q@?zu$CZbt6 zwfW(l&`Z1xiR8y9{y`|su5bAjG5v`UVxCbF?-61$DE?_l^qPoFG=x!)smT&TjTK?U z;I}%0@J~BV_Ci4z#N8uC$$X2rOKAQ|3SlLPC>hWWmqzG5L=aghwhJJ>vmzeK>sZJk zD(Vo;{rESk5STX+57l1rMUSU-lSfanP^F!z$r>9<@FwC-u*C%7^V)o;Y+i{ zd6v^_BJ(_m3L6m=ueYoPPfV{JDl*{fx;8H!ArQNt9a=^iF|YYsy<8Y@zuXZ$m(8R@ z_*=-wI3W;ErD)lZ-5*3dF%bx<%mC&Jaf z?>HMVl>|yKhV)fXG8?gvicxYmt6PP{I^wdmYJJ2NcEtN@jG5lT*bsn)CjJeR(D>fe zD-@G(U79FN(&XUddo6Nk1QE1%yIv8g-&cIgBgdf;j=ZZSN4YEPj4BZNSmx7P!EXr8 zz_XABS&q1XDs|z}n>CX41$^W|GTAo<&0INBqDeAS2c4_Qg{gRu-U&$-9ORjwmJ1`xnbVnlykZ#7}MRS+9YfL3B zr>mr^@?Ear?j2h0TT@tkSl5EoTN&=h7ARKJf4X(jPG-W%5vnW4LNiVfO~{V#^-8jx zkCq@zl9QqS4XS))E^?S)SZ4T{2F*{F!c=ZKa+=t#DKp!u>jH5scOQHUUQSzXTjpA( zSiZMwfSqO{=9GJ^xyY!|ZKH5|1%HKm1;advQ(P-2MPs%g3wettT3@0xt5&02J+y$3 z+bu<)?{0O-fsnwBn`MT?;TeI<0Dv5(S!#zJ`*Av&T?YrN^2_b&j`O1>< zb}HF*GRxcUWaUXp?{AMp-0nm^(T1&=DcF@vgu4VQne%p;5uMkfkPr=NNEG&9o zG*@&(Yfq~O8D02P)2B>Ei%WB<5NkA{SgR;aZBvs%)3Q*oAhgJ`zyT?m>#KJjhN0J{ z)TSz#tDaeDxYY3V?hVu1A6~HBv&AV6aSPySr?2dr^nT9#Iq978bA)hFVU~a-mjaj0 z2aUZr3(@OKNlwS_Tvf2v81obNe8cC6c9<5KDBg1`)pM9Xwk=9XOwcWsD^@R--E8D7 z+saRS-zfcA?=%2cyiR zr8hnGPgiotpYv#3`+LWS{Tz92|2O|Y_NFezhnut*(>MFcggSVf9E2#@JE#AsOFn56 zlgu-YH%?p#dRspvlrtt1DTDXg`s?E*+9mt1_Fr@8G3f8nD=Kd&Z>MM|*S}|aFQ_D_ z)Y;eDm)$p>%#$k2F~PZ(x|TYTI$vj`|3aUowxIT-xqQ{K{(HUc+JEG~M8aG(YcYS>D zy78)UM4RtThTza(oe_HR!dJ+k^+_k;6E z3fTx)9wmq=y;9+i`z?;oTtM=gZkN!VE(+VDm9o|HKKl^w(5vr~kC~}dcIB9rJ!5{o zZQ${s?cmB|S*Z_VD16hPgrhW@`Y4?w<@sHEPT@z594}+uzHyQ$x~CjlYq?>$YVo|M z#5}m_qT^Xa9XnP0^)A~FZ%WYhSg~s*-mfF|87G*pS6Q0tSbXUV>lR2TPJht1)%&4) z`VHT^os7#Zf>wfsnA*G$MIBa3-POht8-XezCy#0DC1UgkA=(%vLLb9xneE3^i??(V z%X}N@J(X<(p0;!cw$z~5Zr;$sUJ3TuoSE2qqN>ZTH(z7?HzbWhgg7j`jA)uPk=XA$ z9-gf+o;ZFsv`yjFaLD~@Y}%mV=v<_$ zX<7?KOL@#<%=}dT^uv*8Sy<7}2EqQvyB}S5tEN{7bw28(ls_`G-*DX!x`-W7?fm@i zb4pqLW83;|&&C=ri=&?u>3sdO`;8udNG`|6(glQP8}~dNjyjGG=1FFKof*#idp=LP zGi;YOs5Thxi*1QdO3sFki5gtYeBYVzvuSqE+#8yaJ;DfnIdJjzAR12+JvuqMCj=*C zGo4>VKwweS`TXZuzT|+}0DU^?MfOEc87T?7@A25?ME_9IP*&n@V(b@t@4WMk=FQvX z(_dS^QZ;qG;Np0?uYJ1J;y&X}xsx-Gr@HKY*N^ei>ZI~Ob1?rj_I7OSCEB&5y)#oT z)@i_-cTMFqlo1F|It0T1B?57B3IG2@Alx1z5F17a#G@nxg47|#utNrc5T=xu5=Xw6 z`qk*JOQdu81z&|NLG$Rq1pn*KcB2A z5i1e}fe_1qK}G^V<_6e2$OvDohyb3c!wE8Qm>m6o9RBD0|2TYg{=a|yAD8>**Z*<3 z|2X{r^=?iOcu3l9$uFRwbQA=Cq`xG-I|#2ga;A~{vn zFRnj_yJ8ts(;mgArS%C*hDi_yMOuw;QE zl_Tb8W@&l)_wU?CC&^=JH&@r0FMgN#8NT74G4LZ%#ntrm>fLvq>gedyI2Op!dY z@60tuQwoN7UC&g%i^*&E{o(Up-{azlc$i(p#ajy0a}Iw^zMO`GnF`C!Corv+{qOW@ z0$zElBauV|1iNE8hJ~gJ0o^U*wEnmsEc*1n_%`Za25n8(+1lD({@pD9n2H!;RC}KD zVy?ksWBY2*Fb3<9_j(^J7Sd6*jdH1wI`UvA78VxIo;_1nS07``Fsanl(U}+=9BgiG zo|&2H?(S}G{vjD7{u0CbJAU7Q=%tXuoRFOncBXpstC*OWprD}ZcvS5j9l{>Fw5+VG z!ouh0r$;r11mPVfgoK1JkOvPQSX!>Bq&*V$I%HvCdEI#($x>Tc`L@dp=J?a6PtNrX z1qF-`9&Ez$AbH1&iS6yTXk?>~PfwTrfCCj!)<3>j?usoaC|F-#XHZQS^7)IjiVjFj zO#J-WtM1vXevQpowY8>;%U-l;TWf18ti0dlIUgGv8}HS22$vo0sc_pIXa90WpnAh! zrp52Y?sC^kPvX(`tQQ!};-X0w@xa&^4?jOYBjdNeK4lgXE~SIRt?7>+KmPvxJ4ZG; zAueu^`E^)W*TLq*lP6F9e1`z^ikX?Y>~Vb+T$zwTg@}X%yCO(jTpZ3m+}j%&8KLQ? z6%i3(VX^CsqO4XhH#OZ`AEJRN5t7JEKcpNq!oG1MCp+8oV539mqb4UTnyAa_&5jK3 z&GAyOT6_CPu_qxnZwKaMGGdUA>B7zK)6h)U*fM71OL?%lfwAt{hGD=%+ls>W7QLLzQbhvN2a0mmO=dBPh6VeLahmF_!pU@X68 z>RsR-f6OFu#Du>$cgw9i z(13wQC1m#P4GesNDOe^zOkPp(1}<)s_es^88$W;iaQw3ii;Bw1Th8WR+uPy0teQ0BB0-Pc z+(8BOO!dfYHLC6&+N=_l8puu5>f^WQ}Bv@vsy zUU;`T&02%7stO9RaBxXD=Wd&V`F2<$2K5^iJb3iUi8!4d+&F7aeBC= z8IeqekW|_bx3>P7DgKgi?g)bY*RNk8t7bo&DAA+obsuSK10P1^!<1C=#~m6P@;N=s zi-A1&L|0c=Obo&M{IuC0yEPiwWis;$zYez~cJhsnaXt%j6nzMK~ zczA?;&yFGc3JVL{;tWH|**`dd%m~}-*RMgS818=lb2yLJekwOFZ-Mt7IeHNI(AW9- zFI81Biu4ek{4P%NmFOjX#(NC?&fOp%RabM{+uJ8ASwP^9?P6hNg^Rknxve;RjO~|$ z3GeUk>y$sGV_@j)>=gAr{tW@K;cG6;G$%KAJ5HbsitVH4zg~bfE-pWM^vLw<>&XTW zE?&!}c$fr1_wC2^&MV`k1{@q5-oFHPJ4g-f=9?(Ba3WEkOG!z+CgTWH#5JgUcD~!g zt{&UH+?UG7pz`i}laH5#1nTUOZBGI#ERzh5WR5>mSXdZD_JO`Wx_vIDVhkTF|b4G#wO_wQe` zy03F{7vS&YTn3+QY}6rIKv>kf+LCoy#$g*8;sCtH$yrrVp_U_$>0B?w%xp7SpngZ^ zkNft_2~1+QP%gPxj?Gta*6TRrQqOI1sYQfd{5Ik_UjX~vftjKb_T2x`@^bW_4V=gv z67lM)HWG@caUsc{=f7ru^rXMJt0)0|68gpq~i4&SrKV|rR< z0(Mi?Sg{S{Mg*&eUYe&!RGs3B`sR!|5J3!4Na2BDL`%+Wl!vC+rK$mkNl;=v}v zyC>+7QoLa3)YPg84YJWx5EiwzJch(*TYYm{mp<<_(R_~Ing2q%yYtC$p|!%e4OvzJ zVCEd)7359S!i4Z}><|XrQ7HohK{`70@|!9c=wsH?wX7`^bl;cy0sTOP_lKn6HGV=U)gdkKDJt ze>9`i6zqL=-#OeEvjvN1Vq#)u`5I3A;M@4E_RdaHQqrZ_7JS0v%k{ZN!4_qf2M-A4 zP5}LbZRNk;2@DSI2qR=b>UzN{&@$FWM)vh2vj5r6RL7IL|CW)4hK7eH-kurq@4a`J z0ATi)qDB9noHTmu$tZ7L0&+w_L1CU5Hb4HofOgF(IXM|ZQrqTB8R5Hr)SidGn1W)C zAf@&^SR((TGY#n@PCEn8gKmut@#K_WrS7lwb$Zx2w_V#^brve z0~w;CR)cr-ADC0#xs$+ZaCrR3w85$y#UPe3_3Z2nqG)JnC<866+Q4J_*ghCVcN~*K zQY1AoF^^F*qNyCxdPzwMIggE*jg1XBcf10GduwZJUteFybwDMxwMlk_4fXYbAzWp+ zbQfvq4&a*LXGw8!?Xq2f;#T|9irG?qA+wQH`d#|M0ypgxzI-VO#L>x#qx_5cVtbg7 z#|O=Pm8(Q!Wn~4q3eq7F%Xn{3kD`JCWR34&fdJaf9UKM>OEoeyJi!Pc;cHq)F^cKv zxc9#k=(c+ghIG6LVEN+WqWkRn@YvV^M8dQ4Y#^M2kvZ3{T?0n&7g&m;HKk#rr`yHZ z$&=5|^UCr8rVZ;iroVe9LNTl|;iA`b(oF zdR)wOzlQUA0L89v@9OC3-6kdFb6S)Ff7a(=B8dRdP@lL32o)#>vj-Ul4tZQkO1KUI zxfWN|hYv3U1Ci4XBcI$hL-D9JF0C_s|1u?N+$JYiNqQI%9jFzd3ix5^2S8qWJZh2N zN+HN>np@k~Ra8{4u&`cmWU1FIob0VpK61sE!26h&M|V)x=(P0pEwPM&f!Fs6<7g^j zjj70Q-Q9nG=4U`k=GR^VKp58Z8!`&m@r?!JhYug}1K)b8YK6pkak5KSPD6#Z3rUEy zgZjnUu~VQ48XB6Ej0~(V^JNtHHSo{`Masj?iRfR$z_F~SstX;dFe-I{ZMin&4i-2T zmXzGY!&{>|{oMj4X2rz9$5#ha+skhM>{*j(CvLohObyW6Mcfg1*sverK(0R2)DZt@ z`whtw%hKVY713EJ1O-gXqXGRjg5ke;klKx^!sS^=ygWTcJa(n-@~uyPummECrX@Rg z>kr_c#hiq=Wjs{iv$IBoIVlVw_n_GQ*LU>^HcgmsFk<}G zK4y0I`3mD}d*l>c7B`C{Zvgy6^7KR!L#hV!(Aje%5*r;5E{}fmA!INO*7>-(x%v2Xe$?3kA5+q<0x6(MpIBR0*UH#9i%m7KsmWJK>E@iF74o3> zoq%SpHW@kj1z-@@2U*$K_aV$QJ|~;1wvJs4-yzBNmGwuEdY3cc zCi#krv~+M~rIWh)t)mivg4b`7J%q5KsyYAy%=+f0-|-cBhge+aFfZb=s$^zHTPo~% zu)nXNsR?5wKUQX8XTKs1!8b_LMSS!hKc2~zkA;at!@wYT{UJlh!x_RR6AS#OhIpHB)EV7eh40Q6kiGt=C^uD z^THSqj9{^EKkEg)aurnRl~dF_Fuq1pM@RZHRr#KKZu6P9zq)l(b}c+S9G6Pyd!?!D zHfem98TR1_>N>?r1h6qDyX(L*%A5W&)6l%!%A5bS_|r-KF}_;2-kC1Z zi^Fw&5QM18Mk{soq4F;mf1UP%Uqd`BUZzF2s$PgmOk7)7Xjv(Ab9Yx&Qd-ss0exdz zwhdS=Jmo@&#ywC$ez7H`q`(@*_T*)V_>dD2w3^3?X=;u@2Ah$xLVCcXhMLZZn=7b6 z`~`RCPpO8CZ#AWP50>iNw^#P(pFe$q=$Lpq_JEn0KctOlqFy{F)A!@MZUKwlq}^TT z@L;_rZ-GRNrrO%W8rum+)xzf5{9V8mUA?`zy8eTMYHWBAp822M=PtSlI)TJl(%<7_ zHA8AWb@fV%K5{nWS9y8no}Q1kS=@EgdWGz#xJ7C)!=j?-MQF#+(`SKL{V(5Z7sFBw0wNCnpbnj&u$T zL>qBuyoR&hD));*WS!nZqbR`1R7ZvTOXElC>*|6+5ps%V9Rl)7Yg-%5g9j0JOG`^x zXXzHiYHm^q9j_1N*l7aWwTJLf(C9fNL5wdpI1e^oV?9EjCxE0S0B61x{V+E-mqoV% z!KZJUB;xa^rI0sYHA7}hJg4DJe0)48GraLIJG<^QIM~?a942UbQ%jxEgl9^3l|)W| zePC}o4$Kt1fA1bj&GpFPHGn*5sRC}>GkSDuDW&=~;lDnCI`XZnt7U7P3^So%b!FvA zy)(KNoXa2}P@kI{WM2eoRzYqxE-o&ldo$~>Q#AjFe+~}JQWw=9sW1=F(A}s&Sk3qh5Qj`A9Lj#wY`w<>G_}H z_~ekw0Ac*DGODPmDtmQ7W3Qm9!otFuni`uP2o8jS(%E2O9b4nHkDol5ot@RAlUG)j z{^!;T3ML0WprYNoqkUy^wQpZdrS)JCnOa$Wdu}`R`t{9G3T}lA5K(If%CfSux+7R) zyL9a(t+=P2Sv*E$5f$)e^ZrjdS2-q$dVVxV7Vk<;7QuP>BS-`h zsS)x+&L9ksq#T;Y1?YublP`x`TTP~G?U~;_LA;Q-dzmengG25%A80i5(Fp)0sF~PJ zFq9V?qfFatf+#2&dU|0B{xV}b)O#S2=v#JcW&sTY?Wow+yr{0u9oT*&g*hq@ov0{v zycnfD5@jBQMA*p5$T0KesHmt&*`K}+4+mgA1G5ME0H~WnLPCLof!|eLp=_Y@ZU@Ss z2Si5V6nD7-Ie?8bSxL7KpOw|n&@gZ;K&;f`V1u}L=f*~cANK}NC?y`KXe3B}6hz!aN$VSAfWJO>XU7+x&yNT5Vg@%4m9)7P(@y~KVD8_%+iBClp z)#vPwt=I5^V|r3WUtb@jk1NC8w;nIK-ST?{q$|8T{Qgtdm=~ZZRPr2IAVD8{i<%ZU z5>Q~_3m;|`DInio5(cWpQ$^o#?5cZO>7zX6RF-eVv*uIh-?g+&E;u+}et*)pLqr6YP z67iNsHim8nW@&e&M?F9c>z%OIb68rYdUeI?@o61jOxAo}B0G-~P$NR`?2DAY=6kH+Tb zGkUY`zb%lCAOR9C#Uqi^z~yyl$7U<^Z1&R_%n%Ul9C{RK4Gj%o8?|$voG4i9rOF?Dr!V{2hYGDkzy z107ebPzGdOz}DV?<-e!he7FW&XLF*Q;rsJk?bY7o56&wJwU$njIfINk<7H1y&yVIu zx=Ud-Km~&Mtpt9fUYE%>_r>puih_gB*1LpirvsR0NG-sNl*l3ay|*Xm^Ow7if`;Te z8rlmluj}aO0{r}$A>za*CnumD%R-)VUB@rhBuf%<2ILHyg*csLPSFBf1Q>9W;{xiz zyU5qCK{n)k@%snpAJx_)7^S5lP~`wkc0v_$EhJq)LW!OipihCwjD?FUqa~Tc{2tQ( z%<1u_1atf&etvG-@tX%TgHUvM6%oFj%^MO`>gT$`i83 z3rXt$8R0KNeiuTtw99~c;Bxpgv$LSWY%ebd6+r<&7&MlsurR&4XO#5JDDgBT5uK3~ z?w1!n{Bh15_sO+zA%8-eo~|&K6ckdmq1w*WC6$juyx#-PQkQTXFkS6AEF+k*rl1iBy?Z6#5<3Cp#zsbi1?n_VQH03^hQJ3f z6v`#=p{}}GY6VmV9`B=BcM4uRqkY|19rxd24q)t*XXx4iAO2Sj4(es5rlt-K4sd?} z_3+oyvU6o!FO&NrN;ZnIv2n}q)Et>eeTW0#d3&(!?gHP0tmWeDEOIsv^)JY9Py_+q z4`Be{5$LWlF$Au^e1StxjE+`s_yH&fUAMHP1Sl^n3ky(xGe{crpx%QP2!t>x91W_a znIAtUE%1RBoc8V=S(zIXlwA3G?(8o<`wU3Bq#;Zi%f z8jvJBk3tC`B`v=-TZ!!x&>LWBJuA*(QrSSM-^vw96_%EsSMud){Jiev zD`fv|dioSXniAV6U=V-?LW)rR|5dK>tQ~|5(LA=6kn^CCmjf}(|Uk5E! zE&4p*)5}#1wLBMV^Nzu+5+U6OWY4c%H4bE|motIR*XVox=)r^H>S`n`0n}9c`&A4L zsd=tJLjuv;ckjSk7Qlt*X=#NZ9!XMYLV0WQpKW4-@8QG2xj8B~bU61y5=6a?v0_lF zwKiWT!=rXy$*yPooSe>(SpWrQ2)aLm@SyI1z`U~`$sG3T)hke}?7mk7bd|J$T|iYA zbdnPN8f?NT6n`0tM?n6rG(!#(DZu%~LF|T2@Aw?%fZ?VmCWhLeAtL``DCp@;g0=t} zlj^%RaCW#Y6e87=5qHV$Un!*vB}YgWgKLuuK4)PjL|9d~RD#8eUL3zv&<1C|3g<;c zu-mxOtcxJZ)zN{z$3FGN}hKT1v1q@)vo=ASlt0tL@G%v3)RyLKo1TrEi6 z*mwc>K`0JI!rQkkhapd)KnGbjX&)mJl@4mEfeQF{Apy;Oc4v3mO=LF&rq(&j@%4w3PEZ$MPQA|^F;8d6VhuhJ+3H?tKulM=n=X2wIaZ}>B^;!X># z!SN4tG`cpRf&#yhjt6-~25fVDTwD1DJ4wVusX-`B)~nB)+s%GD0KIms@;9a6bI4@uPK5O?kXs?xtTKo`I1Vj^}J(kh1F zSztEy$<6ll8DawpwV4E&>f$-2r9J>!0LVJ_c0%Q5d-iiu5G@+FU0o1hxy5ve9Er~E z?hUY3;7#oUA3uEpnN?d=6)zquQX}-QBON#PiBpJsd?1eEN?(PyqbQC-iU)b3xmlw?k z{Pi(^rlmoBMZ2!{IaEYo0{{Bg7t@r5O>LBf$>!_x467%s>(dV zqIwOBCU&U^1gdKP{ttCmnJ!uFKWXg{y#uO6Raw7~R70CpHSJJ~BVyK2;cqC}B) z=Hom1w$F&Th+Mh5>wbzXM;{Ye(Tbk$j{qQt5ZpmW2>AKqNB(#_&w;DsV?T|Tn^eG;SQ`!k#Brz^L^bj2OKfgDQPD5Zl>-mN_4xPUq-BP*tSrD@eSTb?>bE-Qoqq@pR&(Bo zXg3iyL zodI1;3wMPxG|uj;RUd}Pfv*NOx%s+U2Z7llPl!n=(?|-AcM=hTP7qm%mi!_zOV_r$ z+TvP9nS4F(MlwIri7>qfO#|I}la);W2*KEy6`uP0G5s56IRl3l#@cNG>$ogQVzM_1 za=JPqN=n$tsLgf%kM9c7@0ZC-=`;18Xirq&QRCQzpomH(EP*8xO>WkZ`!Z*K|YQCQVqqlK}+rExn- zR|Lk#*;rZ4ca`IRjR$-c*&B>5*&6U!6i%elcusCk99~tU(KxSD5uo{m899Tazoj{r zvJb-Z<>~yTN`?qTq{n+B0E$KcXALrj5JCvF@sOTxs&1Y)Z1 z@j@uHo~;%_E?N8eQ@~?)8LAE#r{swV2|#n5p-2Za#j;o!7--&;aIiH^YRuHB7Uv<@ z$X4$3-xs@QH>&B7&Q+HbC?xPqB)j!Q6%q#!eDBK(VZB`-EtVD*aD5#BH6L|8WoA0e zH$jE{t|ArW7O08C^jAB~Q~53ns+nJ)ci=dN*t^vBxoq!cU{V}l_s7#w&r3Y$ z1|08?GOEtqtFV01pI1{;;CwSRBLh_R%aRh7ZM`ihNkPc6OMVw1t1GeO-+E0 z-p5P>1<*af%9K_WHV7=;u~n9~wN(#9(hf1Usa4OB#TxAl*<9N^z-Yyeq9{C~C3t#O z;Rh&dwNh&{Rs>8G8$}I(zq)#h?bs}o;Xuf#c8-XQJm0FDHTJ%kMgO2#NjicB99=5JkN`#jAnxSb3785n;sWD% zGHr1k|G>F1&$=F(<5%AsrrIU$tv{qoCo|k!eZga}o_*QBWvL;t!j5QkS;Ku!ac>Dq z6+o%Im*1tOr6nY+E-nTtSg;WV;%Y92{i%5trSl<}?eETvFFjqZGb3S|Rh&medUF z(_w!b`eSA13mmimy*mh%vAl3Cr>%Otoa5bBw4m3(7ag%dByo~m$Bxo1SE_wx!XGIw zz-WEVX!UJoAYlT&v<(5M4lr4ksX$&EXS;emmHsi~Cc`_M(l`)r16Rl{EKOBt?axYw)S+}*jTks5YtTpT5XQwLC8 z1xk#wS7SX^G?pzLu|3x~oh5laa2fW3pDe8;SJ&7N=VCR`2PFtrl1$dlkFA=iu@z~_ zw>`$1upcXmhl&REgO4EctpE7Yd?e!5o|K#ncK7q=Pp7VB=wpN470iPwpNo?&7?D1Jj5ZBA0w%a?5+CX#ORq8fCgADUfU1_Pku5OZ;3JzkhU@GT~Y!WCb6#b!!L-)l) zUmuc-9&{O8YcPDEQ}*tmF)Bnubo6sjKHtB8|Kb>>lPoz+#&-57)(x|ng|&l6F>p)6 z(cK-&nN^{o*Twar@08l_i~~d%V>XOLg}g7&xCIJCR}3`NxIv4OBV(oQ$6gYXq=dy3 zx~9)WqfHKRJzY6tyaC!>E|Z{bLT@b)*KRY;)k5eof@0P=G~e_7PCf%QIXp7byarJS z&EBBCVcxhgGBy@WGRC%T8gI}@T2zb09Zf#=Yc{4x<+;X*1GG`ie6SoKVS9X47wu3U zLb--&z(7h&3|bLHjT);VsFmdafq?pR zL2=446x{#*h3>U4Q22mi;RRF(KU7sMJJ&;Ic=_@rw5wWX_>5PXDkFY*IwK3|V56g7FXZX0SQ1bLPG z?R1&}x?C;!JAE6Ngev5Dwo2iH1bj-^2!qNZFOH2VSp|>(c(25!NZpklb@0tl1Emb| zP9(O=eWLf4D4BPH1a2u<=Vi|n$iBixNFb$hY)TaA^CVtj`@i3akuN;PRF~&2x)aJg zIXd_N5$IeHqujSMPTP)3(3B*?(ibR+lF4>=q5RHy1$Tt0dc93`S=-7<#A$(Sp(7&# zd8hlK@AA(QkNEbiW%BbMl<270oAl|mju;5XKT)VCLpahNQ?1D)K@=-vaYSF&QLMh< zoP-EP#`Om=te*BhVD(2wFyj2{lNLQut$o?gLH*!wvWOddsCUIe$C;%>P;~>65^cG= z2eTd%$v+Gap2I+(t*Ehu(~@;)I6J)Lo&7}=`p(W^ACnhFjs0IAH->xHiiV;GG_%cx zLssctJz6kF6nMpU7xtiCee>AmtoeCVLmuAqv(xpZ2?9}m%c?YF(fKdOY-Wu`YWL;z!jMlLahVi%)Xy&`4E@(`py~P(z>qs zmc(M^OSZ`kdU!Wlto9QYIr?jdWR)$39@%kxNZ^PcgUKfNKAlc`ep$G$p*X5>@u*Sevr zpB02k*7J?o_KBM+bEu>bVB1Q59 zpE34~r!80MPIstS@-iOm6^qB!>c8pj=J3PCsleIdM@|4&E}s@sNod`+IP<-AlEq6V(z<%_^d?&38+2&=*U7^L=&hskXFfC3&eH*QeO-^y87KZf1GFl!DDH0>);&q zTHF=YOf(&JHGL~&l2r~i8ZK}aYyxc`Bx|X6uucu_;z=cTwvOB5St)na!oVOcYAwZ7 z{$DR@Xt%FlBbF+E$ds+#%to~0FoGWrbYZ;Ok~n;~&Kk2r@5pLOGDobvg1C1^mZ(pf zR|ok`*$chYXjLTJimj?X+iI%#mVN;$aY%OW^iMZym8RB+oLZZ{fESzza$#%RZ)*xC zYxfC5Dc1^0^+F0oat)&|VDd^t(-Gwm)Az zQLQKTmMKxa##bIMMji~7h0359GwM6MmajNk@07Q(DEppk!(kn#^*{EJ>1oIg@-dgF z#f`-&=?jW#^}JJ%&EH*nL$H&0c2B_XzxFV!zPV2>&8Yw7De>o$vM>cRQ_c3hSUpignU8Vf&5zOQQLK=AZe5Li z1}-*4()Voq+3M>&Y*iw&8Ku?<$k79%H1v|=>>j6=C62Kvn44=Izi`6~hZDQivY!b@?q`M*_L4PgoTE;yGeC`hVTrk~AJy z6~4_;>NWVUFJbER5G$HiR7#|4x7=}_O=w;LK$fY4LB>JHv7!#QF?egr>4_R?((h3* zoE}?>hL$K1AG=3Sr+-`-b|xxj16*S9tDv7e6dsVPQiv9mf4$V`Pj>sR4AlHtCme5w z8vlb!c!teOPkpO`jrGHA6EYRy#!fSxE6YPRsbVzSrm6o0HmH120rqlCrwo{jq{!vK{YHw0F9H!}tTAW0kwxvmOf-$CO>uK9&1p zuR)KyvZxpDN?9=_3$Hoha7$^;n~c^(#|=s#4_IZMoXY*zFyU>_s{#zP$KTXe-NkuC zh{8SPkH0F#sGO2c*Bhpml#U*W8dQL(4)dL{CoXhNqSnW*I*>82K#L^f@D=1>|*g>d3iW@4kHA2C0i~~on@c*E=*q* z|FYS1wk%hM{kN`K>1ZQDv7Er)^zoXBSiOq)ZbdnXq9VVe5)Q~x67OyVB@Pu_U;f`I zS@+ugL4BN#m3`As;*c&-eC!Lmvv_*mlPJbxR_8H?jL9cI$%Dj~mNPi9P}Albco z8H=(gNUb{Sc5TW|9DaCfMGD$#q>aQ?K1SVOlk9}caVyu9NWJD23HT>77reip(6dqy zjN$qvOq&m-%AaU1=<1cAzemVRt4Nhe7zO?>>3bTx literal 0 HcmV?d00001 diff --git a/docs/source/_static/mml_logo_sqare.png b/docs/source/_static/mml_logo_sqare.png new file mode 100644 index 0000000000000000000000000000000000000000..f834c2026b9dbfa012528bcc1d442d10e1dcfb14 GIT binary patch literal 157818 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