diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index 3c4d6bf5..1cfd65ea 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -7,4 +7,6 @@ jobs: - uses: actions/checkout@v2 - uses: psf/black@stable with: + options: "--check --verbose" src: "deckard/" + jupyter: true diff --git a/.gitignore b/.gitignore index b6774923..680aabf0 100644 --- a/.gitignore +++ b/.gitignore @@ -126,3 +126,19 @@ deckard/deckard.egg-info/* *log.txt *.hydra + + +# envs +env/ + + +# random pdfs +*.pdf +# random pngs +*.png + +# screenlog +screenlog.* + +# tmp.py +tmp.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0b74b0b3..4de900c8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,36 +1,36 @@ repos: - - repo: https://github.com/asottile/add-trailing-comma - rev: v2.2.3 - hooks: - - id: add-trailing-comma - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 # Use the ref you want to point at - hooks: - - id: check-builtin-literals - - id: check-case-conflict - - id: check-symlinks - - id: check-toml - - id: detect-private-key - - id: end-of-file-fixer - - id: check-yaml - args : ['--unsafe'] - - repo: https://github.com/hadialqattan/pycln - rev: v2.1.1 # Possible releases: https://github.com/hadialqattan/pycln/releases - hooks: - - id: pycln - args: [deckard/] - - repo: https://github.com/pycqa/flake8 - rev: '5.0.4' # pick a git hash / tag to point to - hooks: - - id: flake8 - exclude: __init__.py - args: [--ignore=E501 W503] - - repo: https://github.com/psf/black - rev: 22.8.0 - hooks: - - id: black +- repo: https://github.com/asottile/add-trailing-comma + rev: v3.1.0 + hooks: + - id: add-trailing-comma +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 # Use the ref you want to point at + hooks: + - id: check-builtin-literals + - id: check-case-conflict + - id: check-symlinks + - id: check-toml + - id: detect-private-key + - id: end-of-file-fixer + - id: check-yaml + args: [--unsafe] +- repo: https://github.com/hadialqattan/pycln + rev: v2.4.0 # Possible releases: https://github.com/hadialqattan/pycln/releases + hooks: + - id: pycln + args: [deckard/] +- repo: https://github.com/psf/black + rev: 24.2.0 + hooks: + - id: black # It is recommended to specify the latest version of Python # supported by your project here, or alternatively use # pre-commit's default_language_version, see # https://pre-commit.com/#top_level-default_language_version - language_version: python3 + language_version: python3 +- repo: https://github.com/pycqa/flake8 + rev: 7.0.0 # pick a git hash / tag to point to + hooks: + - id: flake8 + exclude: __init__.py + args: [--ignore=E501 W503] diff --git a/Dockerfile b/Dockerfile index 38e07f93..80fd2bee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,8 +6,6 @@ RUN python3 -m pip install nvidia-pyindex nvidia-cuda-runtime-cu11 RUN git clone https://github.com/simplymathematics/deckard.git WORKDIR /deckard RUN python3 -m pip install --editable . -RUN python3 -m pip install pytest torch torchvision tensorflow RUN git clone https://github.com/Trusted-AI/adversarial-robustness-toolbox.git RUN cd adversarial-robustness-toolbox && python3 -m pip install . RUN apt install python-is-python3 -RUN pytest test diff --git a/deckard/__init__.py b/deckard/__init__.py index 960c1a33..9d6190ae 100644 --- a/deckard/__init__.py +++ b/deckard/__init__.py @@ -46,7 +46,7 @@ }, }, "loggers": { - "deckard": {"handlers": ["default"]}, + "deckard": {"handlers": ["default"], "level": "INFO", "propagate": True}, "tests": {"handlers": ["test"], "level": "DEBUG", "propagate": True}, }, } diff --git a/deckard/__main__.py b/deckard/__main__.py index ce7b27e4..cbd1505f 100644 --- a/deckard/__main__.py +++ b/deckard/__main__.py @@ -1,5 +1,4 @@ -""""Runs a submodule passed as an arg.""" - +#!/usr/bin/env python3 import argparse import subprocess import logging @@ -44,9 +43,11 @@ def parse_and_repro(args, default_config="default.yaml", config_dir="conf"): if len(args) == 0: assert ( save_params_file( - config_dir=Path(Path(), config_dir) - if not Path(config_dir).is_absolute() - else Path(config_dir), + config_dir=( + Path(Path(), config_dir) + if not Path(config_dir).is_absolute() + else Path(config_dir) + ), config_file=default_config, ) is None diff --git a/deckard/base/attack/attack.py b/deckard/base/attack/attack.py index d7014503..976fab63 100644 --- a/deckard/base/attack/attack.py +++ b/deckard/base/attack/attack.py @@ -8,6 +8,9 @@ from omegaconf import DictConfig, OmegaConf from hydra.utils import instantiate from art.utils import to_categorical, compute_success +from sklearn.utils.validation import check_is_fitted +from sklearn.base import BaseEstimator +from sklearn.exceptions import NotFittedError from random import randint from ..data import Data from ..model import Model @@ -117,7 +120,13 @@ class EvasionAttack: kwargs: Union[dict, None] = field(default_factory=dict) def __init__( - self, name: str, data: Data, model: Model, init: dict, attack_size=-1, **kwargs + self, + name: str, + data: Data, + model: Model, + init: dict, + attack_size=-1, + **kwargs, ): self.name = name self.data = data @@ -148,6 +157,10 @@ def __call__( if attack_file is not None and Path(attack_file).exists(): samples = self.data.load(attack_file) else: + print(f"Type of self.init: {type(self.init)}") + print(f"Type of self.init.model: {type(self.init.model)}") + print(f"Type of model: {type(model)}") + atk = self.init(model=model, attack_size=self.attack_size) if targeted is True: @@ -466,7 +479,13 @@ class InferenceAttack: kwargs: Union[dict, None] = field(default_factory=dict) def __init__( - self, name: str, data: Data, model: Model, init: dict, attack_size=-1, **kwargs + self, + name: str, + data: Data, + model: Model, + init: dict, + attack_size=-1, + **kwargs, ): self.name = name self.data = data @@ -577,7 +596,13 @@ class ExtractionAttack: kwargs: Union[dict, None] = field(default_factory=dict) def __init__( - self, name: str, data: Data, model: Model, init: dict, attack_size=-1, **kwargs + self, + name: str, + data: Data, + model: Model, + init: dict, + attack_size=-1, + **kwargs, ): self.name = name self.data = data @@ -798,12 +823,21 @@ def __call__( adv_predictions_file=None, adv_probabilities_file=None, adv_losses_file=None, + **kwargs, ): name = self.init.name kwargs = deepcopy(self.kwargs) kwargs.update({"init": self.init.kwargs}) data = self.data() data, model = self.model.initialize(data) + if isinstance(model, BaseEstimator): + try: + check_is_fitted(model), "Model must be fitted before calling attack." + except NotFittedError as e: + logger.warning( + f"Model not fitted. Fitting model before attack. Error: {e}", + ) + model, _ = self.model.fit(data=data, model=model) if "art" not in str(type(model)): model = self.model.art(model=model, data=data) if self.method == "evasion": diff --git a/deckard/base/data/data.py b/deckard/base/data/data.py index 690d27c0..7b1859ea 100644 --- a/deckard/base/data/data.py +++ b/deckard/base/data/data.py @@ -4,10 +4,10 @@ from dataclasses import dataclass, field from pathlib import Path from typing import Union - import numpy as np from pandas import DataFrame, read_csv, Series - +from omegaconf import OmegaConf +from validators import url from ..utils import my_hash from .generator import DataGenerator from .sampler import SklearnDataSampler @@ -28,6 +28,7 @@ class Data: ) target: Union[str, None] = None name: Union[str, None] = None + drop: list = field(default_factory=list) def __init__( self, @@ -36,6 +37,8 @@ def __init__( sample: SklearnDataSampler = None, sklearn_pipeline: SklearnDataPipeline = None, target: str = None, + drop: list = [], + **kwargs, ): """Initialize the data object. If the data is generated, then generate the data and sample it. If the data is loaded, then load the data and sample it. @@ -46,9 +49,6 @@ def __init__( sklearn_pipeline (SklearnDataPipeline, optional): The sklearn pipeline. Defaults to None. target (str, optional): The target column. Defaults to None. """ - logger.info( - f"Instantiating {self.__class__.__name__} with name={name} and generate={generate} and sample={sample} and sklearn_pipeline={sklearn_pipeline} and target={target}", - ) if generate is not None: self.generate = ( generate @@ -66,16 +66,19 @@ def __init__( else: self.sample = SklearnDataSampler() if sklearn_pipeline is not None: + sklearn_pipeline = OmegaConf.to_container( + OmegaConf.create(sklearn_pipeline), + ) self.sklearn_pipeline = ( sklearn_pipeline - if isinstance(sklearn_pipeline, (SklearnDataPipeline, type(None))) + if isinstance(sklearn_pipeline, (SklearnDataPipeline)) else SklearnDataPipeline(**sklearn_pipeline) ) else: self.sklearn_pipeline = None + self.drop = drop self.target = target self.name = name if name is not None else my_hash(self) - logger.debug(f"Instantiating Data with id: {self.get_name()}") def get_name(self): """Get the name of the data object.""" @@ -91,7 +94,6 @@ def initialize(self, filename=None): """ if filename is not None and Path(filename).exists(): result = self.load(filename) - assert len(result) == 4, f"Data is not generated: {self.name}" elif self.generate is not None: result = self.generate() else: @@ -100,14 +102,23 @@ def initialize(self, filename=None): assert self.target is not None, "Target is not specified" y = result[self.target] X = result.drop(self.target, axis=1) - X = np.array(X) - y = np.array(y) + if self.drop != []: + X = X.drop(self.drop, axis=1) + X = X.to_numpy() + y = y.to_numpy() result = [X, y] + else: + if self.drop != []: + raise ValueError( + f"Drop is not supported for non-DataFrame data. Data is type {type(result)}", + ) if len(result) == 2: result = self.sample(*result) assert ( len(result) == 4 ), f"Data is not generated: {self.name} {result}. Length: {len(result)}," + if self.sklearn_pipeline is not None: + result = self.sklearn_pipeline(*result) return result def load(self, filename) -> DataFrame: @@ -125,6 +136,8 @@ def load(self, filename) -> DataFrame: elif suffix in [".pkl", ".pickle"]: with open(filename, "rb") as f: data = pickle.load(f) + elif suffix in [".npz"]: + data = np.load(filename) else: # pragma: no cover raise ValueError(f"Unknown file type {suffix}") return data @@ -138,6 +151,10 @@ def save(self, data, filename): logger.info(f"Saving data to {filename}") suffix = Path(filename).suffix Path(filename).parent.mkdir(parents=True, exist_ok=True) + if isinstance(data, dict): + for k, v in data.items(): + v = str(v) + data[k] = v if suffix in [".json"]: if isinstance(data, (Series, DataFrame)): data = data.to_dict() @@ -155,16 +172,20 @@ def save(self, data, filename): else: # pragma: no cover raise ValueError(f"Unknown data type {type(data)} for {filename}.") with open(filename, "w") as f: - json.dump(data, f) + json.dump(data, f, indent=4, sort_keys=True) elif suffix in [".csv"]: assert isinstance( data, (Series, DataFrame, dict, np.ndarray), ), f"Data must be a Series, DataFrame, or dict, not {type(data)} to save to {filename}" - DataFrame(data).to_csv(filename, index=False) + if isinstance(data, (np.ndarray)): + data = DataFrame(data) + data.to_csv(filename, index=False) elif suffix in [".pkl", ".pickle"]: with open(filename, "wb") as f: pickle.dump(data, f) + elif suffix in [".npz"]: + np.savez(filename, data) else: # pragma: no cover raise ValueError(f"Unknown file type {type(suffix)} for {suffix}") assert Path(filename).exists() @@ -174,19 +195,19 @@ def __call__( data_file=None, train_labels_file=None, test_labels_file=None, + **kwargs, ) -> list: """Loads data from file if it exists, otherwise generates data and saves it to file. Returns X_train, X_test, y_train, y_test as a list of arrays, typed according to the framework. :param filename: str :return: list """ - result_dict = {} - if data_file is not None and Path(data_file).exists(): - data = self.load(data_file) - assert len(data) == 4, f"Some data is missing: {self.name}" + if Path(self.name).is_file() or url(self.name): + new_data_file = data_file + data_file = self.name else: - data = self.initialize(filename=data_file) - assert len(data) == 4, f"Some data is missing: {self.name}" - data_file = self.save(data, data_file) + new_data_file = data_file + result_dict = {} + data = self.initialize(data_file) result_dict["data"] = data if train_labels_file is not None: self.save(data[2], train_labels_file) @@ -198,4 +219,6 @@ def __call__( assert Path( test_labels_file, ).exists(), f"Error saving test labels to {test_labels_file}" + if new_data_file is not None: + self.save(data, new_data_file) return data diff --git a/deckard/base/data/generator.py b/deckard/base/data/generator.py index 4283ed22..b9494756 100644 --- a/deckard/base/data/generator.py +++ b/deckard/base/data/generator.py @@ -1,6 +1,6 @@ import logging -from typing import Literal +from typing import Literal, Callable, Union from dataclasses import dataclass, field from pathlib import Path import numpy as np @@ -11,16 +11,19 @@ make_moons, make_circles, ) +from torchvision.io import read_image, read_file from art.utils import load_mnist, load_cifar10, load_diabetes, to_categorical from ..utils import my_hash +logger = logging.getLogger(__name__) + + __all__ = [ "SklearnDataGenerator", "TorchDataGenerator", "KerasDataGenerator", "DataGenerator", ] -logger = logging.getLogger(__name__) SKLEARN_DATASETS = [ "classification", @@ -222,6 +225,8 @@ def __call__(self): return TorchDataGenerator(self.name, **self.kwargs)() elif self.name in KERAS_DATASETS: return KerasDataGenerator(self.name, **self.kwargs)() + elif isinstance(self.name, str) and Path(self.name).exists(): + return SklearnDataGenerator(self.name, **self.kwargs)() else: # pragma: no cover raise ValueError( f"Invalid name {self.name}. Please choose from {ALL_DATASETS}", @@ -229,3 +234,63 @@ def __call__(self): def __hash__(self): return int(my_hash(self), 16) + + +@dataclass +class TorchBaseLoader: + name: str = "data/" + labels: str = "labels.csv" + transform = Union[Callable, None] + target_transform = Union[Callable, None] + regex = "*" + + def __init__(self, name, labels, transform=None, target_transform=None, regex="*"): + self.name = name + self.labels = read_file(labels) + self.files = list(Path(self.name).glob(regex)) + self.transform = transform + self.target_transform = target_transform + self.regex = regex + assert len(self.files) > 0, f"No files found in {self.name} with regex {regex}" + assert len(self.files) == len( + self.labels, + ), f"Number of files {len(self.files)} does not match number of labels {len(self.labels)}" + + def __getitem__(self, idx): + raise NotImplementedError("This method is not implemented yet.") + + def __len__(self): + return len(self.files) + + def __call__(self): + for X, y in self: + yield X, y + + +@dataclass +class TorchImageLoader(TorchBaseLoader): + + def __getitem__(self, idx): + file_path = self.files[idx] + image = read_image(file_path) + label = self.labels[idx] + if self.transform: + image = self.transform(image) + if self.target_transform: + label = self.target_transform(label) + return image, label + + +@dataclass +class TorchTextLoader(TorchBaseLoader): + + def __getitem__(self, idx): + file_path = self.files[idx] + with file_path.open("r") as f: + text = f.read() + label = self.labels[idx] + if self.transform: + text = self.transform(text) + if self.target_transform: + label = self.target_transform(label) + return text, label diff --git a/deckard/base/data/sampler.py b/deckard/base/data/sampler.py index de1c33d0..9f95c6a1 100644 --- a/deckard/base/data/sampler.py +++ b/deckard/base/data/sampler.py @@ -3,11 +3,13 @@ from copy import deepcopy from typing import Union from sklearn.model_selection import train_test_split + from ..utils import my_hash -__all__ = ["SklearnDataSampler"] logger = logging.getLogger(__name__) +__all__ = ["SklearnDataSampler"] + @dataclass class SklearnDataSampler: @@ -27,9 +29,6 @@ def __init__( stratify=False, time_series=False, ): - logger.info( - f"Instantiating {self.__class__.__name__} with params {asdict(self)}", - ) self.test_size = test_size self.train_size = train_size self.random_state = random_state diff --git a/deckard/base/data/sklearn_pipeline.py b/deckard/base/data/sklearn_pipeline.py index 0c725896..ccb73745 100644 --- a/deckard/base/data/sklearn_pipeline.py +++ b/deckard/base/data/sklearn_pipeline.py @@ -16,9 +16,6 @@ class SklearnDataPipelineStage: kwargs: dict = field(default_factory=dict) def __init__(self, name, **kwargs): - logger.info( - f"Instantiating {self.__class__.__name__} with name={name} and kwargs={kwargs}", - ) self.name = name self.kwargs = kwargs @@ -43,7 +40,10 @@ def __init__(self, **kwargs): pipe = kwargs.pop("pipeline", {}) pipe.update(**kwargs) for stage in pipe: - pipe[stage] = OmegaConf.to_container(pipe[stage], resolve=True) + pipe[stage] = OmegaConf.to_container( + OmegaConf.create(pipe[stage]), + resolve=True, + ) name = pipe[stage].pop("name", pipe[stage].pop("_target_", stage)) pipe[stage] = SklearnDataPipelineStage(name, **pipe[stage]) self.pipeline = pipe diff --git a/deckard/base/experiment/experiment.py b/deckard/base/experiment/experiment.py index 79d40f00..0f1828ed 100644 --- a/deckard/base/experiment/experiment.py +++ b/deckard/base/experiment/experiment.py @@ -29,7 +29,7 @@ class Experiment: name: Union[str, None] = field(default_factory=str) stage: Union[str, None] = field(default_factory=str) optimizers: Union[list, None] = field(default_factory=list) - device_id: str = None + device_id: str = "cpu" kwargs: Union[dict, None] = field(default_factory=dict) def __init__( @@ -38,7 +38,7 @@ def __init__( model: Model, scorers: ScorerDict, files: list, - device_id: str = None, + device_id: str = "cpu", attack: Attack = None, name=None, stage=None, @@ -84,7 +84,7 @@ def __init__( self.files = FileConfig(**files) elif isinstance(files, DictConfig): file_dict = OmegaConf.to_container(files, resolve=True) - self.files = FileConfig(**file_dict) + self.files = FileConfig(**file_dict, files=files) elif isinstance(files, FileConfig): self.files = files else: # pragma: no cover @@ -107,7 +107,6 @@ def __init__( self.optimizers = optimizers self.kwargs = kwargs self.name = name if name is not None else self._set_name() - logger.info("Instantiating Experiment with id: {}".format(self.get_name())) def __hash__(self): name = str(self.name).encode("utf-8") @@ -120,8 +119,6 @@ def __call__(self): :return: The score for the specified scorer or the status of the experiment if scorer=None (default). """ logger.info("Running experiment with id: {}".format(self.get_name())) - old_name = self.get_name() - old_hash = my_hash(self) # Setup files, data, and model files = deepcopy(self.files).get_filenames() @@ -141,28 +138,12 @@ def __call__(self): ######################################################################### # Load or generate data ######################################################################### - data_files = { - "data_file": files.get("data_file", None), - "train_labels_file": files.get("train_labels_file", None), - "test_labels_file": files.get("test_labels_file", None), - # "time_dict_file": files.get("score_dict_file", None), - # TODO data_score_file - } - data = self.data(**data_files) + data = self.data(**files) ######################################################################### # Load or train model ######################################################################### if self.model is not None: - model_files = { - "model_file": files.get("model_file", None), - "predictions_file": files.get("predictions_file", None), - "probabilities_file": files.get("probabilities_file", None), - "time_dict_file": files.get("score_dict_file", None), - "losses_file": files.get("losses_file", None), - # TODO train_score_file - # TODO test_score_file - } - model_results = self.model(data, **model_files) + model_results = self.model(data, **files) score_dict.update(**model_results.pop("time_dict", {})) score_dict.update(**model_results.pop("score_dict", {})) model = model_results["model"] @@ -186,7 +167,7 @@ def __call__(self): if not hasattr(losses, "shape"): losses = np.array(losses) logger.debug(f"losses shape: {losses.shape}") - else: # For experiments without models + else: # For experiments without models, e.g Mutual Information experiments on datasets preds = data[2] ########################################################################## # Load or run attack @@ -195,10 +176,7 @@ def __call__(self): adv_results = self.attack( data, model, - attack_file=files.get("attack_file", None), - adv_predictions_file=files.get("adv_predictions_file", None), - adv_probabilities_file=files.get("adv_probabilities_file", None), - adv_losses_file=files.get("adv_losses_file", None), + **files, ) if "adv_predictions" in adv_results: adv_preds = adv_results["adv_predictions"] @@ -260,13 +238,6 @@ def __call__(self): raise ValueError("Scorer is None. Please specify a scorer.") logger.info(f"Score for id : {self.get_name()}: {score_dict}") logger.info("Finished running experiment with id: {}".format(self.get_name())) - new_name = self.get_name() - assert ( - old_name == new_name - ), f"Experiment hash() name changed from {old_name} to {new_name}." - logger.debug( - f"Experiment deckard hash changed from {old_hash} to {my_hash(self)}.", - ) return score_dict def _set_name(self): diff --git a/deckard/base/files/files.py b/deckard/base/files/files.py index ba871710..da55a7c5 100644 --- a/deckard/base/files/files.py +++ b/deckard/base/files/files.py @@ -1,9 +1,9 @@ import logging from dataclasses import dataclass, field from pathlib import Path -from typing import Dict +from typing import Dict, Union from copy import deepcopy - +from omegaconf import OmegaConf from ..utils import my_hash logger = logging.getLogger(__name__) @@ -13,12 +13,12 @@ @dataclass class FileConfig: - reports: str = "reports" - data_dir: str = "data" - model_dir: str = "models" - attack_dir = "attacks" - name: str = None - stage: str = None + reports: Union[str, None] = "reports" + data_dir: Union[str, None] = "data" + model_dir: Union[str, None] = "models" + attack_dir: Union[str, None] = "attacks" + name: Union[str, None] = None + stage: Union[str, None] = None files: dict = field(default_factory=dict) def __init__( @@ -50,7 +50,7 @@ def __init__( :return: A FileConfig object. """ self._target_ = "deckard.base.files.FileConfig" - files.update(kwargs) + files = OmegaConf.merge(files, kwargs) self.reports = str(Path(reports).as_posix()) if reports is not None else None self.data_dir = str(Path(data_dir).as_posix()) if data_dir is not None else None self.model_dir = ( @@ -71,10 +71,13 @@ def __init__( if directory else None ) - self.name = name if name else None self.stage = stage if stage else None self.files = files if files else {} logger.debug(f"FileConfig init: {self.files}") + if name is None: + self.name = my_hash(self) + else: + self.name = name def __call__(self): files = dict(self.get_filenames()) diff --git a/deckard/base/model/art_pipeline.py b/deckard/base/model/art_pipeline.py index 6ac7d8b5..e21c0204 100644 --- a/deckard/base/model/art_pipeline.py +++ b/deckard/base/model/art_pipeline.py @@ -7,6 +7,7 @@ from omegaconf import DictConfig, OmegaConf import numpy as np from random import randint +from art.utils import to_categorical from .keras_models import KerasInitializer, keras_dict # noqa F401 from .tensorflow_models import ( # noqa F401 TensorflowV1Initializer, @@ -113,8 +114,22 @@ def __call__(self): and not isinstance(model, tuple(sklearn_dict.values())) ): model = SklearnModelInitializer( - data=data, model=model, library=library, **kwargs + data=data, + model=model, + library=library, + **kwargs, )() + try: + model.fit(data[0], data[2]) + except np.AxisError: + # Turn column vector, data[2], into a 2D array + nb_classes = len(np.unique(data[2])) if len(data[2]) > 2 else 2 + data[2] = to_categorical(data[2], nb_classes=nb_classes) + data[3] = to_categorical(data[3], nb_classes=nb_classes) + model.fit(data[0], data[2]) + if library in sklearn_dict and "art." not in str(type(model)): + est = sklearn_dict[library] + model = est(model, **kwargs) elif library in [ "tf2", "tensorflowv2", @@ -123,7 +138,10 @@ def __call__(self): "tfv2", ] and not isinstance(model, tuple(tensorflow_dict.values())): model = TensorflowV2Initializer( - data=data, model=model, library=library, **kwargs + data=data, + model=model, + library=library, + **kwargs, )() elif library in ["tf1", "tensorflowv1", "tfv1"] and not isinstance( model, diff --git a/deckard/base/model/keras_models.py b/deckard/base/model/keras_models.py index b0c4b5ca..ae1ca7f5 100644 --- a/deckard/base/model/keras_models.py +++ b/deckard/base/model/keras_models.py @@ -34,7 +34,6 @@ def __init__(self, name, **kwargs): def __call__(self): import tensorflow as tf - logger.info(f"Initializing model {self.name} with kwargs {self.kwargs}") if len(self.kwargs) > 0: config = {"class_name": self.name, "config": self.kwargs} else: @@ -128,7 +127,6 @@ def __init__(self, name, **kwargs): def __call__(self): import tensorflow as tf - logger.info(f"Initializing model {self.name} with kwargs {self.kwargs}") if len(self.kwargs) > 0: config = {"class_name": self.name, "config": self.kwargs} else: diff --git a/deckard/base/model/model.py b/deckard/base/model/model.py index 71e3de37..13d810f5 100644 --- a/deckard/base/model/model.py +++ b/deckard/base/model/model.py @@ -4,7 +4,7 @@ from pathlib import Path from time import process_time_ns, time from typing import Union, Dict -from omegaconf import OmegaConf, DictConfig, ListConfig +from omegaconf import OmegaConf, DictConfig from copy import deepcopy import numpy as np from sklearn.exceptions import NotFittedError @@ -42,50 +42,10 @@ def __init__(self, name, pipeline={}, **kwargs): def __call__(self): params = self.kwargs - logger.info(f"Initializing model {self.name} with kwargs {self.kwargs}") - if "input_dim" in params: - if isinstance(params["input_dim"], list): - params["input_dim"] = tuple(params["input_dim"]) - elif isinstance(params["input_dim"], int): - params["input_dim"] = params["input_dim"] - elif isinstance(params["input_dim"], ListConfig): - input_dim_list = tuple( - OmegaConf.to_container(params["input_dim"], resolve=True), - ) - if len(input_dim_list) == 1: - params["input_dim"] = input_dim_list[0] - else: - params["input_dim"] = tuple(input_dim_list) - else: # pragma: no cover - raise ValueError( - f"input_dim must be a list or tuple. Got {type(params['input_dim'])}", - ) - if "output_dim" in params: - if isinstance(params["output_dim"], list): - params["output_dim"] = tuple(params["output_dim"]) - elif isinstance(params["output_dim"], int): - params["output_dim"] = params["output_dim"] - elif isinstance(params["output_dim"], ListConfig): - output_dim_list = OmegaConf.to_container( - params["output_dim"], - resolve=True, - ) - if len(output_dim_list) == 1: - params["output_dim"] = output_dim_list[0] - else: - params["output_dim"] = tuple(output_dim_list) - else: # pragma: no cover - raise ValueError( - f"output_dim must be a list or tuple. Got {type(params['output_dim'])}", - ) name = params.pop("name", self.name) if self.pipeline is not None: pipeline = deepcopy(self.pipeline) obj = factory(name, **params) - # if isinstance(pipeline, DictConfig): - # pipeline = OmegaConf.to_container(pipeline, resolve=True) - # elif isinstance(pipeline, dict): - # pipeline = pipeline if is_dataclass(pipeline): pipeline = asdict(pipeline) else: # pragma: no cover @@ -107,7 +67,6 @@ class ModelTrainer: kwargs: dict = field(default_factory=dict) def __init__(self, **kwargs): - logger.info(f"Initializing model trainer with kwargs {kwargs}") self.kwargs = kwargs def __call__(self, data: list, model: object, library=None): @@ -129,13 +88,20 @@ def __call__(self, data: list, model: object, library=None): try: start = process_time_ns() start_timestamp = time() + logger.info(f"Fitting type(model): {type(model)} with kwargs {trainer}") model.fit(data[0], data[2], **trainer) end = process_time_ns() end_timestamp = time() except np.AxisError: # pragma: no cover from art.utils import to_categorical - data[2] = to_categorical(data[2]) + nb_classes = len(np.unique(data[2])) + if nb_classes < 2: + nb_classes = 2 + data[2] = np.squeeze(data[2]) + data[3] = np.squeeze(data[3]) + data[2] = to_categorical(data[2], nb_classes=nb_classes) + data[3] = to_categorical(data[3], nb_classes=nb_classes) start = process_time_ns() start_timestamp = time() model.fit(data[0], data[2], **trainer) @@ -146,6 +112,18 @@ def __call__(self, data: list, model: object, library=None): from art.utils import to_categorical nb_classes = len(np.unique(data[2])) + if nb_classes < 2: + nb_classes = 2 + data[2] = to_categorical(data[2], nb_classes=nb_classes) + data[3] = to_categorical(data[3], nb_classes=nb_classes) + start = process_time_ns() + start_timestamp = time() + model.fit(data[0], data[2], **trainer) + end = process_time_ns() + end_timestamp = time() + if "must be greater than or equal to 2" in str(e): + from art.utils import to_categorical + data[2] = to_categorical(data[2], nb_classes=nb_classes) start = process_time_ns() start_timestamp = time() @@ -167,7 +145,7 @@ def __call__(self, data: list, model: object, library=None): except Exception as e: raise e except RuntimeError as e: # pragma: no cover - if "eager mode" in str(e): + if "eager mode" in str(e) and library in tensorflow_dict.keys(): import tensorflow as tf tf.config.run_functions_eagerly(True) @@ -176,7 +154,9 @@ def __call__(self, data: list, model: object, library=None): model.fit(data[0], data[2], **trainer) end = process_time_ns() end_timestamp = time() - elif "should be the same" in str(e).lower(): + elif ( + "should be the same" in str(e).lower() and library in torch_dict.keys() + ): import torch device = torch.device("cuda" if torch.cuda.is_available() else "cpu") @@ -293,9 +273,6 @@ def __init__( else: self.art = None self.name = my_hash(self) if name is None else str(name) - logger.info( - f"Initializing model with data {self.data}, init {self.init}, trainer {self.trainer}, art {self.art}", - ) def __hash__(self): return int(my_hash(self), 16) @@ -310,20 +287,9 @@ def __call__( probabilities_file=None, time_dict_file=None, losses_file=None, + **kwargs, ): result_dict = {} - if isinstance(data, Data): - data = data.initialize(data_file) - elif isinstance(data, type(None)): - data = self.data.initialize(data_file) - elif isinstance(data, (str, Path)): - data = self.load(data) - assert isinstance( - data, - (type(None), list, tuple), - ), f"Data {data} is not a list. It is of type {type(data)}." - assert len(data) == 4, f"Data {data} is not a tuple of length 4." - result_dict["data"] = data if isinstance(model, Model): data, model = model.initialize(data) elif isinstance(model, type(None)): @@ -331,13 +297,38 @@ def __call__( assert len(data) == 4, f"Data {data} is not a tuple of length 4." elif isinstance(model, (str, Path)): model = self.load(model) + if isinstance(data, Data): + data = data(data_file=data_file) + elif isinstance(data, type(None)): + data = self.data.initialize(data_file) + elif isinstance(data, (str, Path)): + data = self.data.load(data) + else: + assert len(data) == 4, f"Data {data} is not a tuple of length 4." + assert isinstance( + data, + (list, tuple), + ), f"Data {data} is not a list. It is of type {type(data)}." elif hasattr(model, ("fit", "fit_generator")): assert hasattr(model, "predict") or hasattr( model, "predict_proba", ), f"Model {model} does not have a predict or predict_proba method." + if isinstance(data, Data): + data = data.initialize(data_file) + elif isinstance(data, type(None)): + data = self.data.initialize(data_file) + elif isinstance(data, (str, Path)): + data = self.load(data) + assert isinstance( + data, + (type(None), list, tuple), + ), f"Data {data} is not a list. It is of type {type(data)}." else: # pragma: no cover raise ValueError(f"Model {model} is not a valid model.") + assert len(data) == 4, f"Data {data} is not a tuple of length 4." + assert hasattr(model, "fit"), f"Model {model} does not have a fit method." + result_dict["data"] = data result_dict["model"] = model if predictions_file is not None and Path(predictions_file).exists(): @@ -417,13 +408,7 @@ def __call__( result_dict["probabilities"] = probs result_dict["time_dict"].update(**prob_time_dict) else: - probs, prob_time_dict = self.predict_proba( - data=data, - model=model, - probabilities_file=probabilities_file, - ) - result_dict["probabilities"] = probs - result_dict["time_dict"].update(**prob_time_dict) + pass # Predicting loss if losses_file is not None: loss, loss_time_dict = self.predict_log_loss( @@ -438,14 +423,7 @@ def __call__( loss = self.data.load(losses_file) result_dict["losses"] = loss else: - loss, loss_time_dict = self.predict_log_loss( - data=data, - model=model, - losses_file=losses_file, - ) - time_dict.update(**loss_time_dict) - result_dict["losses"] = loss - result_dict["time_dict"].update(**loss_time_dict) + pass if time_dict_file is not None: if Path(time_dict_file).exists(): old_time_dict = self.data.load(time_dict_file) diff --git a/deckard/base/model/sklearn_pipeline.py b/deckard/base/model/sklearn_pipeline.py index 631b39ed..03318512 100644 --- a/deckard/base/model/sklearn_pipeline.py +++ b/deckard/base/model/sklearn_pipeline.py @@ -1,15 +1,11 @@ import logging -from sklearn.utils.validation import check_is_fitted from typing import Dict, Union from dataclasses import dataclass, asdict, field, is_dataclass from omegaconf import DictConfig, OmegaConf from hydra.utils import instantiate from copy import deepcopy -import numpy as np -from sklearn.exceptions import NotFittedError from sklearn.base import BaseEstimator from sklearn.pipeline import Pipeline - from art.estimators.classification.scikitlearn import ( ScikitlearnAdaBoostClassifier, ScikitlearnBaggingClassifier, @@ -25,7 +21,6 @@ ScikitlearnDecisionTreeRegressor, ScikitlearnRegressor, ) -from art.utils import to_categorical from ..utils import my_hash @@ -162,16 +157,16 @@ def __call__(self, model): for stage in pipeline: stage = pipeline[stage] if isinstance(stage, dict): - stage[ - "_target_" - ] = "deckard.base.model.sklearn_pipeline.SklearnModelPipelineStage" + stage["_target_"] = ( + "deckard.base.model.sklearn_pipeline.SklearnModelPipelineStage" + ) stage = instantiate(stage) model = stage(model=model) elif isinstance(stage, DictConfig): stage = OmegaConf.to_container(stage, resolve=True) - stage[ - "_target_" - ] = "deckard.base.model.sklearn_pipeline.SklearnModelPipelineStage" + stage["_target_"] = ( + "deckard.base.model.sklearn_pipeline.SklearnModelPipelineStage" + ) stage = instantiate(stage) model = stage(model=model) elif isinstance(stage, SklearnModelPipelineStage): @@ -222,10 +217,7 @@ def __init__(self, data, model=None, library="sklearn", pipeline={}, **kwargs): self.data = data self.model = model self.library = library - params = deepcopy(kwargs) - # while "kwargs" in params: - # params.update(**params.pop("kwargs")) - self.kwargs = params + self.kwargs = kwargs if len(pipeline) > 0: self.pipeline = SklearnModelPipeline(**pipeline) else: @@ -233,71 +225,43 @@ def __init__(self, data, model=None, library="sklearn", pipeline={}, **kwargs): def __call__(self): logger.debug(f"Initializing model {self.model} with kwargs {self.kwargs}") - data = self.data model = self.model - library = self.library - kwargs = {} - params = deepcopy(self.kwargs) - if "library" in kwargs: - library = kwargs.pop("library") - if "clip_values" in params: - clip_values = params.pop("clip_values") - kwargs["clip_values"] = tuple(clip_values) + if isinstance(model, BaseEstimator): + pass + elif isinstance(model, DictConfig): + model = OmegaConf.to_container(model, resolve=True) + elif isinstance(model, str): + model = {"name": model, **self.kwargs} + else: + assert "art." in str( + type(model), + ), f"model must be a string, dict, or sklearn estimator. Got {type(model)}" + if isinstance(model, dict): + if "name" in model: + name = model.pop("name") + else: + raise ValueError( + f"model must have a name attribute. Got {model}", + ) + model["_target_"] = name + model = instantiate(model) else: - X_train, _, _, _ = data - kwargs.update({"clip_values": (np.amin(X_train), np.amax(X_train))}) - if "preprocessing" not in params: - if len(data[0].shape) > 2: - mean = np.mean(data[0], axis=0) - std = np.std(data[0], axis=0) - pre_tup = (mean, std) + if hasattr(model, "model"): + assert isinstance( + model.model, + BaseEstimator, + ), f"model must be a sklearn estimator. Got {type(model.model)}" else: - pre_tup = (np.mean(data[0]), np.std(data[0])) - kwargs["preprocessing"] = pre_tup - if "preprocessing_defences" in params: - preprocessing_defences = params.pop("preprocessing_defences") - kwargs["preprocessing_defences"] = preprocessing_defences - if "postprocessing_defences" in params: - postprocessing_defences = params.pop("postprocessing_defences") - kwargs["postprocessing_defences"] = postprocessing_defences + assert isinstance( + model, + BaseEstimator, + ), f"model must be a sklearn estimator. Got {type(model)}" if self.pipeline is not None: - obj = self.pipeline(model) + model = self.pipeline(model) assert isinstance( - obj, + model, BaseEstimator, ), f"model must be a sklearn estimator. Got {type(model)}" - else: - obj = model - if library in sklearn_dict and "art." not in str(type(model)): - est = sklearn_dict[library] - try: - check_is_fitted(obj) - except NotFittedError: - try: - obj.fit(data[0], data[2]) - except np.AxisError as e: - logger.warning(e) - logger.warning( - "Error while fitting model. Attempting to reshape data", - ) - if len(np.squeeze(data[2]).shape) > 1: - nb_classes = np.squeeze(data[2]).shape[1] - else: - nb_classes = len(np.unique(data[2])) - y_train = to_categorical(data[2], nb_classes) - obj.fit(data[0], y_train) - except ValueError as e: - if "Found array with dim 3. Estimator expected <= 2." in str(e): - obj.fit(data[0].reshape(data[0].shape[0], -1), data[2]) - elif "y should be a 1d array, got an array of shape" in str(e): - obj.fit(data[0], np.argmax(data[2], axis=1)) - else: - raise e - model = est(obj, **kwargs) - elif "art." in str(type(model)): - model = obj - else: - raise ValueError(f"library must be one of {sklearn_models}. Got {library}") assert hasattr( model, "fit", diff --git a/deckard/base/model/torch_models.py b/deckard/base/model/torch_models.py index 9e532c96..748c6017 100644 --- a/deckard/base/model/torch_models.py +++ b/deckard/base/model/torch_models.py @@ -88,11 +88,11 @@ def __call__(self): kwargs.update(**kwargs.pop("kwargs", {})) data = self.data optimizer = TorchOptimizer( - **kwargs.pop("optimizer", {"name": "torch.optim.Adam"}) + **kwargs.pop("optimizer", {"name": "torch.optim.Adam"}), )(model) kwargs.update({"optimizer": optimizer}) criterion = TorchCriterion( - **kwargs.pop("criterion", {"name": "torch.nn.CrossEntropyLoss"}) + **kwargs.pop("criterion", {"name": "torch.nn.CrossEntropyLoss"}), )() kwargs.update({"loss": criterion}) if "input_shape" not in kwargs: diff --git a/deckard/base/scorer/scorer.py b/deckard/base/scorer/scorer.py index a4dcbfb9..52429e44 100644 --- a/deckard/base/scorer/scorer.py +++ b/deckard/base/scorer/scorer.py @@ -156,7 +156,11 @@ def load(self, filename): return scores def __call__( - self, *args, score_dict_file=None, labels_file=None, predictions_file=None + self, + *args, + score_dict_file=None, + labels_file=None, + predictions_file=None, ): new_scores = {} args = list(args) diff --git a/deckard/base/utils/factory.py b/deckard/base/utils/factory.py index e5fffd07..7116fded 100644 --- a/deckard/base/utils/factory.py +++ b/deckard/base/utils/factory.py @@ -8,7 +8,7 @@ def flatten_dict(dictionary: dict, separator: str = ".", prefix: str = ""): """ - Flattens a dictionary into a list of dictionarieswith keys separated by the separator. + Flattens a dictionary into a list of dictionarie swith keys separated by the separator. :param dictionary: The dictionary to flatten. :param separator: The separator to use when flattening the dictionary. :param prefix: The prefix to use when flattening the dictionary. diff --git a/deckard/layers/afr.py b/deckard/layers/afr.py index e7e22bcf..8312d67a 100644 --- a/deckard/layers/afr.py +++ b/deckard/layers/afr.py @@ -30,11 +30,40 @@ def plot_aft( xlabel=None, ylabel=None, replacement_dict={}, - filetype=".pdf", + filetype=".eps", folder=".", + legend={}, **kwargs, ): file = Path(folder, file).with_suffix(filetype) + aft = fit_aft(df, event_col, duration_col, mtype, kwargs) + columns = list(df.columns) + columns.remove(event_col) + columns.remove(duration_col) + ax = aft.plot(columns=columns) + labels = ax.get_yticklabels() + labels = [label.get_text() for label in labels] + for k, v in replacement_dict.items(): + labels = [label.replace(k, v) for label in labels] + values = ax.get_yticks().tolist() + # sort labels by values + labels = [x for _, x in sorted(zip(values, labels))] + values = [x for x, _ in sorted(zip(values, labels))] + ax.set_yticks(values) + ax.set_yticklabels(labels, fontsize=12) + ax.set_xlabel(xlabel) + ax.set_ylabel(ylabel) + ax.set_title(title) + ax.legend(**legend) + ax.get_figure().tight_layout() + ax.get_figure().savefig(file) + logger.info(f"Saved graph to {file}") + plt.show() + plt.gcf().clear() + return ax, aft + + +def fit_aft(df, event_col, duration_col, mtype, kwargs): if mtype == "weibull": aft = WeibullAFTFitter(**kwargs) elif mtype == "log_normal": @@ -51,22 +80,14 @@ def plot_aft( event_col in df.columns ), f"Column {event_col} not in dataframe with columns {df.columns}" plt.gcf().clear() - aft.fit(df, duration_col=duration_col, event_col=event_col) - ax = aft.plot() - labels = ax.get_yticklabels() - labels = [label.get_text() for label in labels] - for k, v in replacement_dict.items(): - labels = [label.replace(k, v) for label in labels] - ax.set_yticklabels(labels) - ax.set_xlabel(xlabel) - ax.set_ylabel(ylabel) - ax.set_title(title) - ax.get_figure().tight_layout() - ax.get_figure().savefig(file) - logger.info(f"Saved graph to {file}") - plt.show() - plt.gcf().clear() - return ax, aft + assert duration_col in df.columns, f"{duration_col} not in df.columns" + assert event_col in df.columns, f"{event_col} not in df.columns" + aft.fit( + df, + duration_col=duration_col, + event_col=event_col, + ) + return aft def plot_partial_effects( @@ -74,35 +95,40 @@ def plot_partial_effects( covariate_array, values_array, title=None, - file="partial_effects.pdf", + file="partial_effects.eps", xlabel="Covariate", ylabel="Failure rate", legend_kwargs={"loc": "upper left"}, replacement_dict={}, cmap="coolwarm", folder=".", - filetype=".pdf", + filetype=".eps", **kwargs, ): plt.gcf().clear() file = Path(folder, file).with_suffix(filetype) - pareto = aft.plot_partial_effects_on_outcome( - covariate_array, values_array, cmap=cmap, **kwargs + partial_effects = aft.plot_partial_effects_on_outcome( + covariate_array, + values_array, + cmap=cmap, + **kwargs, ) - labels = pareto.get_yticklabels() + labels = partial_effects.get_yticklabels() labels = [label.get_text() for label in labels] + values = partial_effects.get_yticks().tolist() for k, v in replacement_dict.items(): labels = [label.replace(k, v) for label in labels] - pareto.set_yticklabels(labels) - pareto.legend(**legend_kwargs) - pareto.set_ylabel(ylabel) - pareto.set_xlabel(xlabel) - pareto.set_title(title) - pareto.get_figure().tight_layout() - pareto.get_figure().savefig(file) + partial_effects.set_yticks(values) + partial_effects.set_yticklabels(labels) + partial_effects.legend(**legend_kwargs) + partial_effects.set_ylabel(ylabel) + partial_effects.set_xlabel(xlabel) + partial_effects.set_title(title) + partial_effects.get_figure().tight_layout() + partial_effects.get_figure().savefig(file) logger.info(f"Saved graph to {file}") plt.gcf().clear() - return pareto + return partial_effects def score_model(aft, train, test): @@ -113,15 +139,20 @@ def score_model(aft, train, test): return scores -def make_afr_table(score_list, aft_dict, dataset, X_train, folder="."): - pd.set_option("display.float_format", lambda x: "%.3f" % x) +def make_afr_table( + score_list, + aft_dict, + dataset, + X_train, + folder=".", + filename="aft_comparison", +): assert len(score_list) == len( aft_dict, ), "Length of score list and aft dict must be equal" folder = Path(folder) aft_data = pd.DataFrame() - aft_data.index.name = "Model" - aft_data.index = aft_dict.keys() + aft_data["AIC"] = [ x.AIC_ if not isinstance(x, CoxPHFitter) else np.nan for x in aft_dict.values() ] @@ -131,20 +162,31 @@ def make_afr_table(score_list, aft_dict, dataset, X_train, folder="."): ] # aft_data["Train LL"] = [x["train_score"] for x in score_list] # aft_data["Test LL"] = [x["test_score"] for x in score_list] - aft_data["Mean $S(t;\\theta)$"] = [ + aft_data[r"Mean $S(t;\theta)$"] = [ x.predict_expectation(X_train).mean() for x in aft_dict.values() ] - aft_data["Median $S(t;\\theta)$"] = [ + aft_data[r"Median $S(t;\theta)$"] = [ x.predict_median(X_train).median() for x in aft_dict.values() ] - aft_data.to_csv(folder / "aft_comparison.csv") + label = f"tab:{dataset}" + upper = dataset.upper() + aft_data.index.name = "Distribution" + aft_data.index = [str(k).replace("_", " ").capitalize() for k in aft_dict.keys()] + aft_data.to_csv(folder / "aft_comparison.csv", na_rep="--") logger.info(f"Saved AFT comparison to {folder / 'aft_comparison.csv'}") - aft_data.fillna("--", inplace=True) aft_data.to_latex( - folder / "aft_comparison.tex", + buf=folder / f"{filename}.tex", float_format="%.3g", - label=f"tab:{dataset}", - caption=f"Comparison of AFR Models on the {dataset.upper()} dataset.", + na_rep="--", + label=label, + index_names=True, + caption=f"Comparison of AFR Models on the {upper} dataset.", + escape=False, + ) + aft_data.to_csv( + Path(folder / f"{filename}.csv"), + index_label="Distribution", + na_rep="--", ) return aft_data @@ -153,7 +195,7 @@ def make_afr_table(score_list, aft_dict, dataset, X_train, folder="."): def clean_data_for_aft( data, covariate_list, - target="adv_failure_rate", + target="adv_accuracy", ): subset = data.copy() assert ( @@ -162,17 +204,22 @@ def clean_data_for_aft( logger.info(f"Shape of dirty data: {subset.shape}") cleaned = pd.DataFrame() covariate_list.append(target) + logger.info(f"Covariates : {covariate_list}") for kwarg in covariate_list: assert kwarg in subset.columns, f"{kwarg} not in data.columns" cleaned = pd.concat([cleaned, subset[kwarg]], axis=1) cols = cleaned.columns cleaned = pd.DataFrame(subset, columns=cols) + cleaned.index = subset.index + # remove rows with -1e10 or 1e10, which are placeholders for run-time errors depending on the direction of optimization for col in cols: cleaned = cleaned[cleaned[col] != -1e10] cleaned = cleaned[cleaned[col] != 1e10] - cleaned.dropna(inplace=True, how="any", axis=0) + # Convert categorical variables to C-1 dummy variables where C is the number of categories cleaned = pd.get_dummies(cleaned) + # de-duplicate index + cleaned = cleaned.loc[~cleaned.index.duplicated(keep="first")] assert ( target in cleaned ), f"Target {target} not in dataframe with columns {cleaned.columns}" @@ -204,6 +251,8 @@ def split_data_for_aft( ), f"Duration {duration_col} not in dataframe with columns {cleaned.columns}" X_train = X_train.dropna(axis=0, how="any") X_test = X_test.dropna(axis=0, how="any") + X_train = pd.DataFrame(X_train, columns=cleaned.columns) + X_test = pd.DataFrame(X_test, columns=cleaned.columns) return X_train, X_test @@ -226,7 +275,9 @@ def render_afr_plot(mtype, config, X_train, X_test, target, duration_col, folder score = score_model(aft, X_train, X_test) for partial_effect_dict in partial_effect_list: partial_effect_plot = plot_partial_effects( - aft=aft, **partial_effect_dict, folder=folder + aft=aft, + **partial_effect_dict, + folder=folder, ) plots.append(partial_effect_plot) return aft, plots, score @@ -239,6 +290,7 @@ def render_all_afr_plots( data, dataset, test_size=0.8, + filename="aft_comparison", folder=".", ): covariate_list = config.pop("covariates", []) @@ -266,7 +318,14 @@ def render_all_afr_plots( folder=folder, ) score_list = list(scores.values()) - aft_data = make_afr_table(score_list, models, dataset, X_train, folder=folder) + aft_data = make_afr_table( + score_list, + models, + dataset, + X_train, + folder=folder, + filename=filename, + ) print("*" * 80) print("*" * 34 + " RESULTS " + "*" * 34) print("*" * 80) @@ -274,6 +333,25 @@ def render_all_afr_plots( print("*" * 80) +def set_matplotlib_vars(matplotlib_dict=None): + if matplotlib_dict is None: + matplotlib_dict = { + "font": { + "family": "Times New Roman", + "weight": "bold", + "size": 22, + }, + } + matplotlib.rc(**matplotlib_dict) + + +def fillna(data, config): + fillna = config.pop("fillna", {}) + for k, v in fillna.items(): + assert k in data.columns, f"{k} not in data" + data[k] = data[k].fillna(v) + + if "__main__" == __name__: afr_parser = argparse.ArgumentParser() afr_parser.add_argument("--target", type=str, default="adv_failures") @@ -282,46 +360,62 @@ def render_all_afr_plots( afr_parser.add_argument("--data_file", type=str, default="data.csv") afr_parser.add_argument("--config_file", type=str, default="afr.yaml") afr_parser.add_argument("--plots_folder", type=str, default="plots") + afr_parser.add_argument("--summary_file", type=str, default="aft_comparison") args = afr_parser.parse_args() target = args.target duration_col = args.duration_col dataset = args.dataset logging.basicConfig(level=logging.INFO) - font = { - "family": "Times New Roman", - "weight": "bold", - "size": 22, - } - - matplotlib.rc("font", **font) + set_matplotlib_vars() + # Filesystem stuff csv_file = args.data_file FOLDER = args.plots_folder + filename = ( + Path(args.summary_file).as_posix() if args.summary_file is not None else None + ) + assert Path(args.config_file).exists(), f"{args.config_file} does not exist." Path(FOLDER).mkdir(exist_ok=True, parents=True) + assert Path(FOLDER).exists(), f"{FOLDER} does not exist." + assert Path(csv_file).exists(), f"{csv_file} does not exist." + + # Reading compiled csv file data = pd.read_csv(csv_file, index_col=0) logger.info(f"Shape of data: {data.shape}") data.columns = data.columns.str.strip() with Path(args.config_file).open("r") as f: config = yaml.safe_load(f) - fillna = config.pop("fillna", {}) - for k, v in fillna.items(): - assert k in data.columns, f"{k} not in data" - data[k] = data[k].fillna(v) + fillna(data, config) + + # Strip whitespace from strings data = data.applymap(lambda x: x.strip() if isinstance(x, str) else x) - assert Path(args.config_file).exists(), f"{args.config_file} does not exist." + + # Check if covariates are specified covariates = config.get("covariates", []) assert len(covariates) > 0, "No covariates specified in config file" + + # Cannot fit AFT models with missing values logger.info(f"Shape of data before data before dropping na: {data.shape}") data = drop_frames_without_results(data, covariates) logger.info(f"Shape of data before data before dropping na: {data.shape}") - data.loc[:, "adv_failures"] = (1 - data.loc[:, "adv_accuracy"]) * data.loc[ - :, - "attack.attack_size", - ] - data.loc[:, "ben_failures"] = (1 - data.loc[:, "accuracy"]) * data.loc[ - :, - "attack.attack_size", - ] + # Converting accuracy to unnormalized count, if needed + if "adv_failures" in covariates and "adv_failures" in data.columns: + logger.info("Adding adv_failures to data") + assert "adv_accuracy" in data.columns, "adv_accuracy not in data" + assert "attack.attack_size" in data.columns, "attack.attack_size not in data" + data.loc[:, "adv_failures"] = (1 - data.loc[:, "adv_accuracy"]) * data.loc[ + :, + "attack.attack_size", + ] + if "ben_failures" in covariates: + logger.info("Adding ben_failures to data") + assert "accuracy" in data.columns, "accuracy not in data" + assert "attack.attack_size" in data.columns, "attack.attack_size not in data" + data.loc[:, "ben_failures"] = (1 - data.loc[:, "accuracy"]) * data.loc[ + :, + "data.sample.test_size", + ] + # Plotting AFT models render_all_afr_plots( config, duration_col, @@ -330,4 +424,5 @@ def render_all_afr_plots( dataset, test_size=0.8, folder=FOLDER, + filename=filename, ) diff --git a/deckard/layers/attack.py b/deckard/layers/attack.py new file mode 100644 index 00000000..ebe34146 --- /dev/null +++ b/deckard/layers/attack.py @@ -0,0 +1,53 @@ +#! /usr/bin/env python + +import logging +from pathlib import Path +import argparse + + +from .utils import save_params_file, run_stages + +logger = logging.getLogger(__name__) + +attack_parser = argparse.ArgumentParser() +attack_parser.add_argument("stage", type=str, nargs="*", default=None) +attack_parser.add_argument("--verbosity", type=str, default="INFO") +attack_parser.add_argument("--params_file", type=str, default="params.yaml") +attack_parser.add_argument("--pipeline_file", type=str, default="dvc.yaml") +attack_parser.add_argument("--config_dir", type=str, default="conf") +attack_parser.add_argument("--config_file", type=str, default="default") +attack_parser.add_argument("--workdir", type=str, default=".") +attack_parser.add_argument("--overrides", nargs="*", default=[], type=str) + + +def attack_main(args): + config_dir = Path(args.workdir, args.config_dir).absolute().as_posix() + logging.basicConfig( + level=args.verbosity, + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", + ) + if args.overrides is not None and len(args.overrides) > 0: + save_params_file( + config_dir=config_dir, + config_file=args.config_file, + params_file=args.params_file, + overrides=args.overrides, + ) + logger.info( + f"Using existing params file {args.params_file} in directory {args.workdir}", + ) + results = run_stages( + stages=args.stage, + pipeline_file=args.pipeline_file, + params_file=args.params_file, + repo=args.workdir, + config_dir=config_dir, + config_file=args.config_file, + sub_dict="attack", + ) + return results + + +if __name__ == "__main__": + args = attack_parser.parse_args() + attack_main(args) diff --git a/deckard/layers/clean_data.py b/deckard/layers/clean_data.py index ab7aee73..609ce48c 100644 --- a/deckard/layers/clean_data.py +++ b/deckard/layers/clean_data.py @@ -5,7 +5,6 @@ import pandas as pd import seaborn as sns import yaml -from math import isnan import numpy as np from tqdm import tqdm @@ -63,34 +62,47 @@ def calculate_failure_rate(data): data = data[data.columns.drop(list(data.filter(regex=r"\.1$")))] data.columns.str.replace(" ", "") assert "accuracy" in data.columns, "accuracy not in data.columns" + data.loc[:, "accuracy"] = pd.to_numeric(data.loc[:, "accuracy"]) assert ( "attack.attack_size" in data.columns ), "attack.attack_size not in data.columns" + data.loc[:, "attack.attack_size"] = pd.to_numeric( + data.loc[:, "attack.attack_size"], + ) assert ( "predict_time" in data.columns or "predict_proba_time" in data.columns ), "predict_time or predict_proba_time not in data.columns" assert "adv_accuracy" in data.columns, "adv_accuracy not in data.columns" + data.loc[:, "adv_accuracy"] = pd.to_numeric(data.loc[:, "adv_accuracy"]) assert "adv_fit_time" in data.columns, "adv_fit_time not in data.columns" + data.loc[:, "adv_fit_time"] = pd.to_numeric(data.loc[:, "adv_fit_time"]) assert "train_time" in data.columns, "train_time not in data.columns" + data.loc[:, "train_time"] = pd.to_numeric(data.loc[:, "train_time"]) if "predict_time" in data.columns: + data.loc[:, "predict_time"] = pd.to_numeric(data.loc[:, "predict_time"]) failure_rate = ( - 1 - data.loc[:, "accuracy"] * data.loc[:, "attack.attack_size"] + (1 - data.loc[:, "accuracy"]) * data.loc[:, "attack.attack_size"] ) / data.loc[:, "predict_time"] elif "predict_proba_time" in data.columns: + data.loc[:, "predict_proba_time"] = pd.to_numeric( + data.loc[:, "predict_proba_time"], + ) failure_rate = ( - 1 - data.loc[:, "accuracy"] * data.loc[:, "attack.attack_size"] + (1 - data.loc[:, "accuracy"]) * data.loc[:, "attack.attack_size"] ) / data.loc[:, "predict_proba_time"] else: raise ValueError("predict_time or predict_proba_time not in data.columns") adv_failure_rate = ( - 1 - data.loc[:, "adv_accuracy"] * data.loc[:, "attack.attack_size"] - ) / data.loc[:, "predict_time"] + (1 - data.loc[:, "adv_accuracy"]) + * data.loc[:, "attack.attack_size"] + / data.loc[:, "predict_time"] + ) data = data.assign(adv_failure_rate=adv_failure_rate) data = data.assign(failure_rate=failure_rate) training_time_per_failure = data.loc[:, "train_time"] / data.loc[:, "failure_rate"] training_time_per_adv_failure = ( - data.loc[:, "train_time_per_sample"] * data.loc[:, "adv_failure_rate"] + data.loc[:, "train_time"] * data.loc[:, "adv_failure_rate"] ) data = data.assign(training_time_per_failure=training_time_per_failure) data = data.assign(training_time_per_adv_failure=training_time_per_adv_failure) @@ -172,17 +184,24 @@ def min_max_scaling(data, *args): # Min-max scaling of control parameters for def_ in defences: max_ = data[data.def_gen == def_].def_value.max() + max_ = pd.to_numeric(max_, errors="raise") min_ = data[data.def_gen == def_].def_value.min() + min_ = pd.to_numeric(min_, errors="raise") scaled_value = (data[data.def_gen == def_].def_value - min_) / (max_ - min_) data.loc[data.def_gen == def_, "def_value"] = scaled_value for atk in attacks: max_ = data[data.atk_gen == atk].atk_value.max() + max_ = pd.to_numeric(max_, errors="raise") min_ = data[data.atk_gen == atk].atk_value.min() + min_ = pd.to_numeric(min_, errors="raise") scaled_value = (data[data.atk_gen == atk].atk_value - min_) / (max_ - min_) data.loc[data.atk_gen == atk, "atk_value"] = scaled_value for k in args: max_ = data[k].max() + max_ = pd.to_numeric(max_, errors="raise") min_ = data[k].min() + min_ = pd.to_numeric(min_, errors="raise") + data[k] = pd.to_numeric(data[k], errors="raise") scaled_value = (data[k] - min_) / (max_ - min_) data[k] = scaled_value return data @@ -200,13 +219,6 @@ def merge_defences( "model.art.transformer.name", "model.art.trainer.name", ], - control_variable=["device_id"], - defaults={ - # "model.trainer.nb_epoch": 20, - # "model.trainer.kwargs.nb_epoch": 20, - # "model.trainer.batch_size" : 1024, - # "model.trainer.kwargs.batch_size" : 1024, - }, ): """ The function `merge_defences` merges different defence columns in a DataFrame and assigns a unique @@ -228,8 +240,6 @@ def merge_defences( """ defences = [] def_gens = [] - for control in control_variable: - assert control in results, f"{control} not in results.columns" for _, entry in tqdm(results.iterrows(), desc="Merging defences"): defence = [] i = 0 @@ -239,21 +249,6 @@ def merge_defences( else: pass i += 1 - for k, v in defaults.items(): - if ( - k in entry - and v != entry[k] - and not isnan(pd.to_numeric(entry[k])) - and len(defence) == 0 - ): - defence.append(k) - else: - pass - for col in control_variable: - if col in entry and entry[col] not in nones and len(defence) == 0: - defence.append(col) - else: - pass ############################################################################################################ if len(defence) > 1: def_gen = [str(x).split(".")[-1] for x in defence] @@ -271,6 +266,7 @@ def merge_defences( results["defence_name"] = defences results["def_gen"] = def_gens logger.info(f"Unique defences after merging: {set(results.def_gen)}") + logger.info(f"Unique set of full names after merge: {set(results.defence_name)}") assert hasattr(results, "def_gen"), "def_gen not in results.columns" return results @@ -297,8 +293,9 @@ def merge_attacks(results: pd.DataFrame): attack = None attacks.append(attack) if attacks != [None] * len(attacks): - results["attack_name"] = attacks - results["atk_gen"] = [str(x).split(".")[-1] for x in attacks] + results = results.assign(attack_name=attacks) + attacks = [str(x).split(".")[-1] for x in attacks] + results = results.assign(atk_gen=attacks) logger.info(f"Unique attacks: {set(results.atk_gen)}") else: logger.warning("No attacks found in data. Check your config file.") @@ -342,7 +339,7 @@ def format_control_parameter(data, control_dict, fillna): logger.info("Fillna: ") logger.info(yaml.dump(fillna)) for defence in defences: - if defence in control_dict and defence != "Epochs": + if defence in control_dict: # Get parameter name from control_dict param = control_dict[defence] # Shorten parameter name @@ -375,6 +372,7 @@ def format_control_parameter(data, control_dict, fillna): else value ) data.loc[data.def_gen == defence, "def_value"] = value + del fillna[defence] else: logger.warning(f"Defence {defence} not in control_dict. Deleting rows.") data = data[data.def_gen != defence] @@ -414,17 +412,38 @@ def format_control_parameter(data, control_dict, fillna): else value ) data.loc[data.atk_gen == attack, "def_value"] = value + del fillna[attack] else: logger.warning(f"Attack {attack} not in control_dict. Deleting rows.") data = data[data.atk_gen != attack] - defences = list(data.def_gen.unique()) - attacks = list(data.atk_gen.unique()) + defences = list(data.def_gen.unique()) if "def_gen" in data.columns else [] + attacks = list(data.atk_gen.unique()) if "atk_gen" in data.columns else [] logger.info(f"Unique defences: {defences}") logger.info(f"Unique attacks: {attacks}") - assert "def_param" in data.columns, "def_param not in data.columns" - assert "atk_param" in data.columns, "atk_param not in data.columns" - assert "def_value" in data.columns, "def_value not in data.columns" - assert "atk_value" in data.columns, "atk_value not in data.columns" + if len(defences) > 0: + assert "def_param" in data.columns, "def_param not in data.columns" + assert "def_value" in data.columns, "def_value not in data.columns" + if len(attacks) > 0: + assert "atk_param" in data.columns, "atk_param not in data.columns" + assert "atk_value" in data.columns, "atk_value not in data.columns" + return data, fillna + + +def replace_strings_in_data(data, replace_dict): + for k, v in replace_dict.items(): + logger.info(f"Replacing strings in {k}...") + assert isinstance( + v, + dict, + ), f"Value for key {k} in replace_dict is not a dictionary." + assert k in data.columns, f"Key {k} not in data.columns." + for k1, v1 in v.items(): + logger.info(f"Replacing {k1} with {v1} in {k}...") + k1 = str(k1) + v1 = str(v1) + data[k] = data[k].astype(str) + data.loc[:, k] = data.loc[:, k].str.replace(k1, v1) + logger.info(f"Unique values after replacement: {data[k].unique()}") return data @@ -434,6 +453,8 @@ def clean_data_for_plotting( atk_gen_dict, control_dict, fillna, + replace_dict, + pareto_dict, ): """ The function `clean_data_for_plotting` cleans and formats data for plotting by dropping empty rows, @@ -465,99 +486,115 @@ def clean_data_for_plotting( data = data.loc[:, ~data.columns.str.endswith(".1")] logger.info(f"Shape after dropping poorly merged columns: {data.shape}") logger.info("Shortening model names...") - # Removes the path and to the model object and leaves the name of the model - model_names = data["model.init.name"].str.split(".").str[-1] - data["model_name"] = model_names # If "Net" is in the model name, we assume the following string denotes the layers as in ResNet18 if hasattr(data, "model.init.name"): model_names = data["model.init.name"].str.split(".").str[-1] - data.loc[:, "model_name"] = model_names + data = data.assign(model_name=model_names) model_layers = [str(x).split("Net")[-1] for x in model_names] - data.loc[:, "model_layers"] = model_layers + data = data.assign(model_layers=model_layers) logger.info(f"Model Names: {data.model_name.unique()}") logger.info(f"Model Layers: {data.model_layers.unique()}") - data["nb_epoch"] = ( - data["model.trainer.kwargs.nb_epoch"] - if "model.trainer.kwargs.nb_epoch" in data.columns - else data["model.trainer.nb_epoch"] - ) + logger.info("Replacing data.sample.random_state with random_state...") data["data.sample.random_state"].rename("random_state", inplace=True) - data = merge_defences(data) + if len(def_gen_dict) > 0: + data = merge_defences(data) logger.info("Replacing attack and defence names with short names...") if hasattr(data, "def_gen"): def_gen = data.def_gen.map(def_gen_dict) data.def_gen = def_gen data.dropna(axis=0, subset=["def_gen"], inplace=True) - data = merge_attacks(data) + if "attack.init.name" in data: + data = merge_attacks(data) if hasattr(data, "atk_gen"): atk_gen = data.atk_gen.map(atk_gen_dict) data.atk_gen = atk_gen data.dropna(axis=0, subset=["atk_gen"], inplace=True) - data = format_control_parameter(data, control_dict, fillna) + data, fillna = format_control_parameter(data, control_dict, fillna) + for k, v in fillna.items(): + if k in data.columns: + data[k] = data[k].fillna(v) + else: + data[k] = str(v) + data = replace_strings_in_data(data, replace_dict) + if len(pareto_dict) > 0: + data = pareto_set(data, pareto_dict) return data -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument( - "-i", - "--input_file", - type=str, - help="Data file to read from", - required=True, - ) - parser.add_argument( - "-o", - "--output_file", - type=str, - help="Data file to read from", - required=True, - ) - parser.add_argument( - "-v", - "--verbosity", - default="INFO", - help="Increase output verbosity", - ) - parser.add_argument( - "-c", - "--config", - help="Path to the config file", - default="clean.yaml", - ) - parser.add_argument( - "-s", - "--subset", - help="Subset of data you would like to plot", - default=None, - nargs="?", - ) - parser.add_argument( - "-d", - "--drop_if_empty", - help="Drop row if this columns is empty", - nargs="+", - type=str, - default=[ - "accuracy", - "adv_accuracy", - "train_time", - "adv_fit_time", - "predict_proba_time", - ], - ) - parser.add_argument( - "--pareto_dict", - help="Path to (optional) pareto set dictionary.", - default=None, - ) - args = parser.parse_args() +def drop_values(data, drop_dict): + for k, v in drop_dict.items(): + data = data[data[k] != v] + return data + + +parser = argparse.ArgumentParser() +parser.add_argument( + "-i", + "--input_file", + type=str, + help="Data file to read from", + required=True, +) +parser.add_argument( + "-o", + "--output_file", + type=str, + help="Data file to read from", + required=True, +) +parser.add_argument( + "-v", + "--verbosity", + default="INFO", + help="Increase output verbosity", +) +parser.add_argument( + "-c", + "--config", + help="Path to the config file", + default="clean.yaml", +) +parser.add_argument( + "-s", + "--subset", + help="Subset of data you would like to plot", + default=None, + nargs="?", +) +parser.add_argument( + "-d", + "--drop_if_empty", + help="Drop row if this columns is empty", + nargs="+", + type=str, + default=[ + "accuracy", + "train_time", + "predict_time", + ], +) +parser.add_argument( + "--pareto_dict", + help="Path to (optional) pareto set dictionary.", + default=None, +) + + +def main(args): logging.basicConfig(level=args.verbosity) assert Path( args.input_file, ).exists(), f"File {args.input_file} does not exist. Please specify a valid file using the -i flag." data = pd.read_csv(args.input_file) + # Strip whitespace from column names + trim_strings = lambda x: x.strip() if isinstance(x, str) else x # noqa E731 + data.rename(columns=trim_strings, inplace=True) + # Strip whitespace from column values + data = data.applymap(lambda x: x.strip() if isinstance(x, str) else x) + + assert "model.init.name" in data.columns, "model.init.name not in data.columns" + if isinstance(args.drop_if_empty, str): args.drop_if_empty = args.drop_if_empty.split(",") else: @@ -565,22 +602,6 @@ def clean_data_for_plotting( for col in args.drop_if_empty: assert col in data.columns, f"Column {col} not in data.columns" data = drop_frames_without_results(data, subset=args.drop_if_empty) - if args.pareto_dict is None: - sense_dict = {} - else: - if Path(args.pareto_dict).exists(): - with open(args.pareto_dict, "r") as f: - sense_dict = yaml.safe_load(f) - elif ( - isinstance(args.pareto_dict.split(":")[:-2], str) - and Path(args.pareto_dict.split(":")[:-2]).exists() - ): - with open(Path(args.pareto_dict.split(":")[:-2]), "r") as f: - sense_dict = yaml.safe_load(f)[args.pareto_dict.split(":")[:-1]] - else: - raise ValueError( - f"Pareto_dictionary, {args.pareto_dict} does not exist as a file or file and dictionary using file:dictionary notation.", - ) # Reads Config file with open(Path(args.config), "r") as f: big_dict = yaml.load(f, Loader=yaml.FullLoader) @@ -588,16 +609,23 @@ def clean_data_for_plotting( atk_gen_dict = big_dict.get("attacks", {}) control_dict = big_dict.get("params", {}) fillna = big_dict.get("fillna", {}) - min_max = big_dict.get("min_max", ["nb_epoch"]) - + min_max = big_dict.get("min_max", []) + replace_dict = big_dict.get("replace", {}) + pareto_dict = big_dict.get("pareto", {}) + drop_dict = big_dict.pop("drop_values", {}) + data = drop_values(data, drop_dict) results = clean_data_for_plotting( data, def_gen_dict, atk_gen_dict, control_dict, fillna=fillna, + replace_dict=replace_dict, + pareto_dict=pareto_dict, ) - results = calculate_failure_rate(results) + + if "adv_accuracy" in results.columns: + results = calculate_failure_rate(results) results = min_max_scaling(results, *min_max) output_file = save_results( @@ -609,3 +637,8 @@ def clean_data_for_plotting( output_file, ).exists(), f"File {output_file} does not exist. Please specify a valid file using the -o flag." logger.info(f"Saved results to {output_file}") + + +if __name__ == "__main__": + args = parser.parse_args() + main(args) diff --git a/deckard/layers/compile.py b/deckard/layers/compile.py index da7c4f8b..b9059389 100644 --- a/deckard/layers/compile.py +++ b/deckard/layers/compile.py @@ -20,7 +20,7 @@ def flatten_results(df: pd.DataFrame) -> pd.DataFrame: df = df.applymap(lambda x: x.strip() if isinstance(x, str) else x) for col in tqdm(df.columns, desc="Flattening columns"): if isinstance(df[col][0], dict): - tmp = pd.json_normalize(df[col]) + tmp = pd.json_normalize(df[col].fillna({i: {} for i in df[col].index})) tmp.columns = [f"{col}.{subcol}" for subcol in tmp.columns] tmp.index = df.index df = pd.merge(df, tmp, left_index=True, how="outer", right_index=True) @@ -79,14 +79,31 @@ def read_file(file, results): if folder not in results: results[folder] = {} if suffix == ".json": - with open(file, "r") as f: - try: + try: + retries = locals().get("retries", 0) + with open(file, "r") as f: dict_ = json.load(f) - except json.decoder.JSONDecodeError as e: + except json.decoder.JSONDecodeError as e: + logger.error(f"Error reading {file}") + print(f"Error reading {file}. Please fix the file and press Enter.") + input( + "Press Enter to continue. The next failure on this file will raise an error.", + ) + if retries > 1: raise e + else: + with open(file, "r") as f: + dict_ = json.load(f) + retries += 1 elif suffix == ".yaml": with open(file, "r") as f: - dict_ = yaml.safe_load(f) + try: + dict_ = yaml.safe_load(f) + except Exception as e: + logger.error(f"Error reading {file}") + print(f"Error reading {file}") + input("Press Enter to raise the error.") + raise e else: raise ValueError(f"File type {suffix} not supported.") results[folder]["stage"] = stage @@ -106,16 +123,16 @@ def save_results(results, results_file, results_folder) -> str: """ results_file = Path(results_folder, results_file) logger.info(f"Saving data to {results_file}") - Path(results_folder).mkdir(exist_ok=True, parents=True) + Path(results_file).parent.mkdir(exist_ok=True, parents=True) suffix = results_file.suffix if suffix == ".csv": - results.to_csv(results_file) + results.to_csv(results_file, index=True) elif suffix == ".xlsx": - results.to_excel(results_file) + results.to_excel(results_file, index=True) elif suffix == ".html": - results.to_html(results_file) + results.to_html(results_file, index=True) elif suffix == ".json": - results.to_json(results_file) + results.to_json(results_file, index=True, orient="records") else: raise ValueError(f"File type {suffix} not supported.") assert Path( @@ -155,7 +172,6 @@ def load_results(results_file, results_folder) -> pd.DataFrame: parser.add_argument("--results_file", type=str, default="results.csv") parser.add_argument("--report_folder", type=str, default="reports", required=True) parser.add_argument("--results_folder", type=str, default=".") - parser.add_argument("--config", type=str, default="conf/compile.yaml") parser.add_argument("--exclude", type=list, default=None, nargs="*") parser.add_argument("--verbose", type=str, default="INFO") args = parser.parse_args() diff --git a/deckard/layers/data.py b/deckard/layers/data.py new file mode 100644 index 00000000..95768bbc --- /dev/null +++ b/deckard/layers/data.py @@ -0,0 +1,53 @@ +#! /usr/bin/env python + +import logging +from pathlib import Path +import argparse + + +from .utils import save_params_file, run_stages + +logger = logging.getLogger(__name__) + +data_parser = argparse.ArgumentParser() +data_parser.add_argument("stage", type=str, nargs="*", default=None) +data_parser.add_argument("--verbosity", type=str, default="INFO") +data_parser.add_argument("--params_file", type=str, default="params.yaml") +data_parser.add_argument("--pipeline_file", type=str, default="dvc.yaml") +data_parser.add_argument("--config_dir", type=str, default="conf") +data_parser.add_argument("--config_file", type=str, default="default") +data_parser.add_argument("--workdir", type=str, default=".") +data_parser.add_argument("--overrides", nargs="*", default=[], type=str) + + +def data_main(args): + config_dir = Path(args.workdir, args.config_dir).absolute().as_posix() + logging.basicConfig( + level=args.verbosity, + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", + ) + if args.overrides is not None and len(args.overrides) > 0: + save_params_file( + config_dir=config_dir, + config_file=args.config_file, + params_file=args.params_file, + overrides=args.overrides, + ) + logger.info( + f"Using existing params file {args.params_file} in directory {args.workdir}", + ) + results = run_stages( + stages=args.stage, + pipeline_file=args.pipeline_file, + params_file=args.params_file, + repo=args.workdir, + config_dir=config_dir, + config_file=args.config_file, + sub_dict="data", + ) + return results + + +if __name__ == "__main__": + args = data_parser.parse_args() + data_main(args) diff --git a/deckard/layers/experiment.py b/deckard/layers/experiment.py index 14d9ba43..b4336cb8 100644 --- a/deckard/layers/experiment.py +++ b/deckard/layers/experiment.py @@ -1,133 +1,52 @@ +#! /usr/bin/env python + import logging from pathlib import Path -import dvc.api -from hydra.utils import instantiate - -from dulwich.errors import NotGitRepository -import yaml import argparse -from copy import deepcopy -from ..base.utils import unflatten_dict - -logger = logging.getLogger(__name__) - -__all__ = [ - "get_dvc_stage_params", - "run_stage", - "get_stages", - "run_stages", -] - - -def get_dvc_stage_params( - stage, - params_file="params.yaml", - pipeline_file="dvc.yaml", - directory=".", - name=None, -): - logger.info( - f"Getting params for stage {stage} from {params_file} and {pipeline_file} in {directory}.", - ) - params = dvc.api.params_show(stages=stage) - params.update({"_target_": "deckard.base.experiment.Experiment"}) - files = dvc.api.params_show(pipeline_file, stages=stage, repo=directory) - unflattened_files = unflatten_dict(files) - params["files"] = dict(unflattened_files.get("files", unflattened_files)) - params["files"]["_target_"] = "deckard.base.files.FileConfig" - params["files"]["stage"] = stage - params["stage"] = stage - if name is not None: - params["files"]["name"] = name - return params -def run_stage( - params_file="params.yaml", - pipeline_file="dvc.yaml", - directory=".", - stage=None, -): - logger.info( - f"Running stage {stage} with params_file: {params_file} and pipeline_file: {pipeline_file} in directory {directory}", - ) - params = get_dvc_stage_params( - stage=stage, - params_file=params_file, - pipeline_file=pipeline_file, - directory=directory, - ) - exp = instantiate(params) - id_ = exp.name - files = deepcopy(exp.files()) - params_file = Path(files["score_dict_file"]).with_name("params.yaml").as_posix() - Path(params_file).parent.mkdir(exist_ok=True, parents=True) - with Path(params_file).open("w") as f: - yaml.dump(params, f) - score = exp() - return id_, score - +from .utils import save_params_file, run_stages -def get_stages(pipeline_file="dvc.yaml", stages=None, repo=None): - try: - def_stages = list( - dvc.api.params_show(pipeline_file, repo=repo)["stages"].keys(), - ) - except NotGitRepository: - raise ValueError( - f"Directory {repo} is not a git repository. Please run `dvc init` in {repo} and try again.", - ) - if stages is None or stages == []: - raise ValueError(f"Please specify one or more stage(s) from {def_stages}") - elif isinstance(stages, str): - stages = [stages] - else: - assert isinstance(stages, list), f"args.stage is of type {type(stages)}" - for stage in stages: - assert ( - stage in def_stages - ), f"Stage {stage} not found in {pipeline_file}. Available stages: {def_stages}" - return stages +logger = logging.getLogger(__name__) +experiment_parser = argparse.ArgumentParser() +experiment_parser.add_argument("stage", type=str, nargs="*", default=None) +experiment_parser.add_argument("--verbosity", type=str, default="INFO") +experiment_parser.add_argument("--params_file", type=str, default="params.yaml") +experiment_parser.add_argument("--pipeline_file", type=str, default="dvc.yaml") +experiment_parser.add_argument("--config_dir", type=str, default="conf") +experiment_parser.add_argument("--config_file", type=str, default="default") +experiment_parser.add_argument("--workdir", type=str, default=".") +experiment_parser.add_argument("--overrides", nargs="*", default=[], type=str) -def run_stages(stages, pipeline_file="dvc.yaml", params_file="params.yaml", repo=None): - results = {} - stages = get_stages(stages=stages, pipeline_file=pipeline_file, repo=repo) - for stage in stages: - id_, score = run_stage( - stage=stage, - pipeline_file=pipeline_file, - params_file=params_file, - directory=repo, - ) - results[id_] = score - return results - -if __name__ == "__main__": - logger = logging.getLogger(__name__) - dvc_parser = argparse.ArgumentParser() - dvc_parser.add_argument("stage", type=str, nargs="*", default=None) - dvc_parser.add_argument("--verbosity", type=str, default="INFO") - dvc_parser.add_argument("--params_file", type=str, default="params.yaml") - dvc_parser.add_argument("--pipeline_file", type=str, default="dvc.yaml") - dvc_parser.add_argument("--config_dir", type=str, default="conf") - dvc_parser.add_argument("--config_file", type=str, default="default") - dvc_parser.add_argument("--workdir", type=str, default=".") - args = dvc_parser.parse_args() - config_dir = Path(args.workdir, args.config_dir).resolve().as_posix() - # save_params_file( - # config_dir=config_dir, - # config_file=args.config_file, - # params_file=args.params_file, - # ) +def experiment_main(args): + config_dir = Path(args.workdir, args.config_dir).absolute().as_posix() logging.basicConfig( level=args.verbosity, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", ) + if args.overrides is not None and len(args.overrides) > 0: + save_params_file( + config_dir=config_dir, + config_file=args.config_file, + params_file=args.params_file, + overrides=args.overrides, + ) + logger.info( + f"Using existing params file {args.params_file} in directory {args.workdir}", + ) results = run_stages( stages=args.stage, pipeline_file=args.pipeline_file, params_file=args.params_file, repo=args.workdir, + config_dir=config_dir, + config_file=args.config_file, ) + return results + + +if __name__ == "__main__": + args = experiment_parser.parse_args() + experiment_main(args) diff --git a/deckard/layers/find_best.py b/deckard/layers/find_best.py index 0461f28e..eb582d51 100644 --- a/deckard/layers/find_best.py +++ b/deckard/layers/find_best.py @@ -3,6 +3,7 @@ from pathlib import Path from hydra import initialize_config_dir, compose from omegaconf import OmegaConf +import argparse import yaml from ..base.utils import flatten_dict @@ -19,7 +20,7 @@ def find_optuna_best( config_folder=Path(Path(), "conf"), default_config="default.yaml", config_subdir=None, - direction=None, + direction="maximize", ): logger.info(f"Study name: {study_name}") logger.info(f"Storage name: {storage_name}") @@ -31,59 +32,115 @@ def find_optuna_best( ) df = study.trials_dataframe(attrs=("number", "value", "params", "state")) if study_csv is not None: + Path(study_csv).parent.mkdir(parents=True, exist_ok=True) df.to_csv(study_csv) + # To dotlist best_params = flatten_dict(study.best_params) more_params = flatten_dict(study.best_trial.user_attrs) even_more_params = flatten_dict(study.best_trial.system_attrs) logger.debug(f"Best params: {best_params}") logger.debug(f"Best user params: {more_params}") logger.debug(f"Best system params: {even_more_params}") - best_params = {**more_params, **best_params} + # Merge all the params + best_params = OmegaConf.to_container( + OmegaConf.merge(best_params, more_params, even_more_params), + resolve=False, + ) + # to dotlist + best_params = flatten_dict(best_params) overrides = [] + # Changing the keys to hydra override format for key, value in best_params.items(): - logger.info(f"Overriding {key} with {value}") - overrides.append(f"{key}={value}") - with initialize_config_dir(config_dir=config_folder, version_base="1.3"): - cfg = compose(config_name=default_config, overrides=overrides) - cfg = OmegaConf.to_container(cfg, resolve=False) - if params_file is not None: - if params_file is True: - if config_subdir is not None: - params_file = Path( - config_folder, - f"{config_subdir}", - f"{default_config}.yaml", - ) - params = cfg.get(config_subdir) - else: - params_file = Path(config_folder, f"{default_config}.yaml") - params = cfg + if ( + key.startswith("++") or key.startswith("~~") or key.startswith("--") + ): # reserved meaning + pass + elif key.startswith("+"): # appends to config + key = "++" + key[1:] # force override else: - if config_subdir is not None: - params_file = Path( - config_folder, - f"{config_subdir}", - f"{params_file}.yaml", - ) - params = cfg.get(config_subdir) + key = "++" + key # force override + if config_subdir is None: + overrides.append(f"{key}={value}") + else: # if we are using a subdir, we need to remove the directory from the key + if ( + key.startswith(f"++{config_subdir}.") + or key.startswith(f"~~{config_subdir}.") + or key.startswith(f"--{config_subdir}.") + ): + key = key.replace(f"{config_subdir}.", "") + overrides.append(f"{key}={value}") + logger.info(f"Adding {key} to param list") else: - params = cfg - params_file = Path(config_folder, f"{params_file}.yaml") - params_file.parent.mkdir(parents=True, exist_ok=True) - with open(params_file.with_suffix(".yaml"), "w") as f: - yaml.dump(params, f) - assert ( - params_file.exists() - ), f"{params_file.resolve().as_posix()} does not exist." + logger.debug(f"Skipping {key} because it is not in {config_subdir}") + params = override_default_with_best( + config_folder, + default_config, + overrides, + config_subdir=config_subdir, + ) + if params_file is not None: + params_file = create_new_config_in_subdir( + params_file, + config_folder, + default_config, + config_subdir, + params, + ) return params -if __name__ == "__main__": - import argparse +def create_new_config_in_subdir( + params_file, + config_folder, + default_config, + config_subdir, + params, +): + if params_file is True: + if config_subdir is not None: + params_file = Path( + config_folder, + f"{config_subdir}", + f"{default_config}.yaml", + ) + else: + params_file = Path(config_folder, f"{default_config}.yaml") + else: + if config_subdir is not None: + params_file = Path( + config_folder, + f"{config_subdir}", + f"{params_file}.yaml", + ) + else: + params_file = Path(config_folder, f"{params_file}.yaml") + params_file.parent.mkdir(parents=True, exist_ok=True) + with open(params_file.with_suffix(".yaml"), "w") as f: + yaml.dump(params, f) + assert params_file.exists(), f"{params_file.resolve().as_posix()} does not exist." + + return params_file + +def override_default_with_best( + config_folder, + default_config, + overrides, + config_subdir=None, +): + if config_subdir is not None: + config_folder = Path(config_folder, config_subdir) + config_folder = config_folder.resolve().as_posix() + with initialize_config_dir(config_dir=config_folder, version_base="1.3"): + cfg = compose(config_name=default_config, overrides=overrides) + cfg = OmegaConf.to_container(cfg, resolve=False) + return cfg + + +if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--params_file", type=str, default=True) - parser.add_argument("--study_type", type=str, default="optuna") + parser.add_argument("--study_csv", type=str, default=None) parser.add_argument("--config_folder", type=str, default=Path(Path(), "conf")) parser.add_argument("--default_config", type=str, default="default") @@ -91,25 +148,22 @@ def find_optuna_best( parser.add_argument("--study_name", type=str, required=True) parser.add_argument("--config_name", type=str) parser.add_argument("--verbosity", type=str, default="INFO") + parser.add_argument("--storage_name", type=str, required=True) + parser.add_argument("--direction", type=str, default="maximize") + parser.add_argument("--study_type", type=str, default="optuna") args = parser.parse_args() args.config_folder = Path(args.config_folder).resolve().as_posix() - + logging if args.study_type == "optuna": - with open( - Path(args.config_folder, args.default_config).with_suffix(".yaml"), - "r", - ) as f: - default_params = yaml.load(f, Loader=yaml.FullLoader) - if "hydra" in default_params: - hydra_params = default_params.pop("hydra") - study_name = args.study_name - storage_name = hydra_params["sweeper"]["storage"] - direction = default_params.get("direction", "maximize") + storage_name = args.storage_name + direction = args.direction + if len(direction) == 1: + direction = direction[0] find_optuna_best( - study_name=study_name, - storage_name=storage_name, + study_name=args.study_name, + storage_name=args.storage_name, study_csv=args.study_csv, params_file=args.params_file, config_folder=args.config_folder, diff --git a/deckard/layers/model.py b/deckard/layers/model.py new file mode 100644 index 00000000..5b098570 --- /dev/null +++ b/deckard/layers/model.py @@ -0,0 +1,53 @@ +#! /usr/bin/env python + +import logging +from pathlib import Path +import argparse + + +from .utils import save_params_file, run_stages + +logger = logging.getLogger(__name__) + +model_parser = argparse.ArgumentParser() +model_parser.add_argument("stage", type=str, nargs="*", default=None) +model_parser.add_argument("--verbosity", type=str, default="INFO") +model_parser.add_argument("--params_file", type=str, default="params.yaml") +model_parser.add_argument("--pipeline_file", type=str, default="dvc.yaml") +model_parser.add_argument("--config_dir", type=str, default="conf") +model_parser.add_argument("--config_file", type=str, default="default") +model_parser.add_argument("--workdir", type=str, default=".") +model_parser.add_argument("--overrides", nargs="*", default=[], type=str) + + +def model_main(args): + config_dir = Path(args.workdir, args.config_dir).absolute().as_posix() + logging.basicConfig( + level=args.verbosity, + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", + ) + if args.overrides is not None and len(args.overrides) > 0: + save_params_file( + config_dir=config_dir, + config_file=args.config_file, + params_file=args.params_file, + overrides=args.overrides, + ) + logger.info( + f"Using existing params file {args.params_file} in directory {args.workdir}", + ) + results = run_stages( + stages=args.stage, + pipeline_file=args.pipeline_file, + params_file=args.params_file, + repo=args.workdir, + config_dir=config_dir, + config_file=args.config_file, + sub_dict="model", + ) + return results + + +if __name__ == "__main__": + args = model_parser.parse_args() + model_main(args) diff --git a/deckard/layers/optimise.py b/deckard/layers/optimise.py index 6b0280e7..71bf6893 100644 --- a/deckard/layers/optimise.py +++ b/deckard/layers/optimise.py @@ -32,7 +32,9 @@ def get_files( stage, ): """ - Gets the file names from + Gets the file names from cfg and calculates the hash of the attack, model and data, and files objects. + If "files.name == 'default'", the name is set to the hash of the cfg. + For attack, model and data, the file name is set to the hash of the respective object. """ if isinstance(cfg, dict): pass @@ -74,7 +76,9 @@ def get_files( cfg["files"]["_target_"] = "deckard.base.files.FileConfig" id_ = my_hash(cfg) cfg["name"] = id_ - cfg["files"]["name"] = id_ + cfg["files"]["name"] = ( + id_ if cfg["files"]["name"] == "default" else cfg["files"]["name"] + ) if stage is not None: cfg["files"]["stage"] = stage return cfg @@ -165,36 +169,6 @@ def parse_stage(stage: str = None, params: dict = None, path=None) -> dict: else: assert isinstance(stage, list), f"args.stage is of type {type(stage)}" stages = stage - # if params is None: - # with open(Path(path, "params.yaml"), "r") as f: - # default_params = yaml.load(f, Loader=yaml.FullLoader) - # key_list = [] - # for stage in stages: - # with open(Path(path, "dvc.yaml"), "r") as f: - # new_keys = yaml.load(f, Loader=yaml.FullLoader)["stages"][stage][ - # "params" - # ] - # key_list.extend(new_keys) - # params = read_subset_of_params(key_list, params) - # params = merge_params(default_params, params) - # elif isinstance(params, str) and Path(params).is_file() and Path(params).exists(): - # with open(Path(params), "r") as f: - # params = yaml.load(f, Loader=yaml.FullLoader) - # assert isinstance( - # params, - # dict, - # ), f"Params in file {params} must be a dict. It is a {type(params)}." - # key_list = [] - # for stage in stages: - # with open(Path(path, "dvc.yaml"), "r") as f: - # new_keys = yaml.load(f, Loader=yaml.FullLoader)["stages"][stage][ - # "params" - # ] - # key_list.extend(new_keys) - # with open(Path(path, "params.yaml"), "r") as f: - # all_params = yaml.load(f, Loader=yaml.FullLoader) - # default_params = read_subset_of_params(key_list, all_params) - # params = merge_params(default_params, params) if isinstance(params, dict): key_list = [] for stage in stages: @@ -228,11 +202,14 @@ def parse_stage(stage: str = None, params: dict = None, path=None) -> dict: files = params["files"] file_list = list(files.keys()) for key in file_list: - template_string = "${files." + key + "}" - if template_string in file_string: - pass - else: - params["files"].pop(key) + if key == "params.yaml": + continue + if key.endswith("_file") or key.endswith("_dir"): + template_string = "${files." + key + "}" + if template_string in file_string: + pass + else: + params["files"].pop(key) params = get_files(params, stage) return params @@ -265,11 +242,13 @@ def write_stage(params: dict, stage: str, path=None, working_dir=None) -> None: def optimise(cfg: DictConfig) -> None: cfg = OmegaConf.to_container(OmegaConf.create(cfg), resolve=True) - raise_exception = cfg.pop("raise_exception", False) + raise_exception = cfg.pop("raise_exception", True) working_dir = Path(config_path).parent direction = cfg.get("direction", "minimize") direction = [direction] if not isinstance(direction, list) else direction optimizers = cfg.get("optimizers", None) + optimizers = [optimizers] if not isinstance(optimizers, list) else optimizers + assert len(optimizers) == len(direction) stage = cfg.pop("stage", None) cfg = parse_stage(params=cfg, stage=stage, path=working_dir) exp = instantiate(cfg) @@ -288,36 +267,39 @@ def optimise(cfg: DictConfig) -> None: scores.append(score_dict[optimizer]) else: if direction[i] == "minimize": - scores.append(1e10) + scores.append(1.00000000000) elif direction[i] == "maximize": - scores.append(-1e10) + scores.append(0.00000000000) else: scores.append(None) i += 1 logger.info(f"Optimizers are : {optimizers}") logger.info(f"Score is : {scores}") except Exception as e: - logger.warning( - f"Exception {e} occured while running experiment {id_}. Setting score to default for specified direction (e.g. -/+ 1e10).", - ) with open(Path(folder, "exception.log"), "w") as f: f.write(str(e)) f.write(traceback.format_exc()) - fake_scores = [] - for direction in direction: - if direction == "minimize": - fake_scores.append(1e10) - elif direction == "maximize": - fake_scores.append(-1e10) - else: - fake_scores.append(None) - scores = fake_scores - logger.info(f"Optimizers: {optimizers}") - logger.info(f"Score: {scores}") - if raise_exception: + if not raise_exception: + logger.warning( + f"Exception {e} occured while running experiment {id_}. Setting score to default for specified direction (e.g. -/+ 1e10).", + ) + fake_scores = [] + for direction in direction: + if direction == "minimize": + fake_scores.append(1.00000000000) + elif direction == "maximize": + fake_scores.append(0.00000000000) + else: + fake_scores.append(None) + scores = fake_scores + logger.info(f"Optimizers: {optimizers}") + logger.info(f"Score: {scores}") + else: raise e if len(scores) == 1: - scores = scores[0] + scores = float(scores[0]) + else: + scores = [float(x) for x in scores] return scores diff --git a/deckard/layers/parse.py b/deckard/layers/parse.py index 3e879cd5..44a2200b 100644 --- a/deckard/layers/parse.py +++ b/deckard/layers/parse.py @@ -14,10 +14,8 @@ hydra_parser.add_argument("--config_file", type=str, default="default") hydra_parser.add_argument("--workdir", type=str, default=".") -if __name__ == "__main__": - logger = logging.getLogger(__name__) - args = hydra_parser.parse_args() +def parse_hydra_config(args) -> None: logging.basicConfig(level=args.verbosity) config_dir = Path(Path(), args.config_dir).resolve().as_posix() OmegaConf.register_new_resolver("eval", eval) @@ -32,3 +30,9 @@ ) os.environ["DECKARD_DEFAULT_CONFIG"] = args.config_file os.environ["DECKARD_CONFIG_PATH"] = args.config_dir + return None + + +if __name__ == "__main__": + args = hydra_parser.parse_args() + parse_hydra_config(args) diff --git a/deckard/layers/plots.py b/deckard/layers/plots.py index fcfa03a4..99f77e52 100644 --- a/deckard/layers/plots.py +++ b/deckard/layers/plots.py @@ -25,7 +25,7 @@ def cat_plot( hue_order=None, rotation=0, set={}, - filetype=".pdf", + filetype=".eps", **kwargs, ): """ @@ -66,27 +66,45 @@ def cat_plot( plot. You can pass any valid keyword arguments that are accepted by the `set()` method of the `seaborn.FacetGrid` object. These properties can be used to customize the appearance of the plot, filetype: The `filetype` parameter is used to specify the file extension for saving the graph. By - default, it is set to ".pdf", but you can change it to any other valid file extension such as - ".png", ".jpg", etc. Defaults to .pdf + default, it is set to ".eps", but you can change it to any other valid file extension such as + ".png", ".jpg", etc. Defaults to .eps """ plt.gcf().clear() - file = Path(file).with_suffix(filetype) + suffix = Path(file).suffix + if suffix is not None: + file = Path(file) + else: + file = Path(file).with_suffix(filetype) logger.info(f"Rendering graph {file}") - data = data.sort_values(by=[hue, x, y]) - logger.debug( - f"Data sorted by x:{x}, y:{y}, hue:{hue}, kind:{kind}, hue_order:{hue_order}, and kwargs:{kwargs}.", - ) - graph = sns.catplot( - data=data, x=x, y=y, hue=hue, kind=kind, hue_order=hue_order, **kwargs - ) + if hue is not None: + data = data.sort_values(by=[hue, x, y]) + logger.debug( + f"Data sorted by x:{x}, y:{y}, hue:{hue}, kind:{kind}, hue_order:{hue_order}, and kwargs:{kwargs}.", + ) + graph = sns.catplot( + data=data, + x=x, + y=y, + hue=hue, + kind=kind, + hue_order=hue_order, + **kwargs, + ) + else: + data = data.sort_values(by=[x, y]) + logger.debug(f"Data sorted by x:{x}, y:{y}, kind:{kind}, and kwargs:{kwargs}.") + graph = sns.catplot(data=data, x=x, y=y, kind=kind, **kwargs) graph.set_xlabels(xlabels) graph.set_ylabels(ylabels) graph.set_titles(titles) if legend_title is not None: graph.legend.set_title(title=legend_title) else: - graph.legend.remove() + if graph.legend is not None: + graph.legend.remove() + else: + pass graph.set_xticklabels(graph.axes.flat[-1].get_xticklabels(), rotation=rotation) graph.set(**set) graph.tight_layout() @@ -99,7 +117,6 @@ def line_plot( data, x, y, - hue, xlabel, ylabel, title, @@ -108,8 +125,7 @@ def line_plot( y_scale=None, x_scale=None, legend={}, - hue_order=None, - filetype=".pdf", + filetype=".eps", **kwargs, ): """ @@ -146,21 +162,35 @@ def line_plot( variable in the plot. It is a list that determines the order in which the different categories of the `hue` variable will be plotted. filetype: The `filetype` parameter specifies the file type of the saved graph. In the given code, - the default value is set to ".pdf", indicating that the graph will be saved as a PDF file. However, - you can change the value of `filetype` to save the graph in a different. Defaults to .pdf + the default value is set to ".eps", indicating that the graph will be saved as a PDF file. However, + you can change the value of `filetype` to save the graph in a different. Defaults to .eps Returns: the line plot graph object. """ plt.gcf().clear() - file = Path(file).with_suffix(filetype) + suffix = Path(file).suffix + if suffix is not None: + file = Path(file) + else: + file = Path(file).with_suffix(filetype) logger.info(f"Rendering graph {file}") - data = data.sort_values(by=[hue, x, y]) - graph = sns.lineplot(data=data, x=x, y=y, hue=hue, hue_order=hue_order, **kwargs) + if "hue" in kwargs and kwargs.get("hue") in data.columns: + hue = kwargs.get("hue") + data = data.sort_values(by=[hue, x, y]) + else: + data.sort_values(by=[x, y]) + xlim = kwargs.pop("xlim", None) + ylim = kwargs.pop("ylim", None) + graph = sns.lineplot(data=data, x=x, y=y, **kwargs) graph.legend(**legend) graph.set_xlabel(xlabel) graph.set_ylabel(ylabel) graph.set_title(title) + if xlim is not None: + graph.set_xlim(xlim) + if ylim is not None: + graph.set_ylim(ylim) if y_scale is not None: graph.set_yscale(y_scale) if x_scale is not None: @@ -186,7 +216,7 @@ def scatter_plot( x_scale=None, legend={}, hue_order=None, - filetype=".pdf", + filetype=".eps", **kwargs, ): """ @@ -221,15 +251,19 @@ def scatter_plot( variable in the scatter plot. By default, the levels of the `hue` variable are ordered based on the order in which they appear in the data. However, if you want to specify a specific filetype: The `filetype` parameter is a string that specifies the file type of the saved graph. It - is used to determine the file extension of the saved graph file. By default, it is set to ".pdf", - indicating that the graph will be saved as a PDF file. However, you can change. Defaults to .pdf + is used to determine the file extension of the saved graph file. By default, it is set to ".eps", + indicating that the graph will be saved as a PDF file. However, you can change. Defaults to .eps Returns: the scatter plot graph object. """ plt.gcf().clear() - file = Path(file).with_suffix(filetype) + suffix = Path(file).suffix + if suffix is not None: + file = Path(file) + else: + file = Path(file).with_suffix(filetype) logger.info(f"Rendering graph {file}") data = data.sort_values(by=[hue, x, y]) graph = sns.scatterplot( @@ -240,8 +274,10 @@ def scatter_plot( hue_order=hue_order, **kwargs, ) - graph.set_yscale(y_scale) - graph.set_xscale(x_scale) + if y_scale is not None: + graph.set_yscale(y_scale) + if x_scale is not None: + graph.set_xscale(x_scale) graph.set_xlabel(xlabel) graph.set_ylabel(ylabel) graph.legend(**legend) @@ -254,42 +290,43 @@ def scatter_plot( return graph -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument( - "-p", - "--path", - type=str, - help="Path to the plot folder", - required=True, - ) - parser.add_argument( - "-f", - "--file", - type=str, - help="Data file to read from", - required=True, - ) - parser.add_argument( - "-t", - "--plotfiletype", - type=str, - help="Filetype of the plots", - default=".pdf", - ) - parser.add_argument( - "-v", - "--verbosity", - default="INFO", - help="Increase output verbosity", - ) - parser.add_argument( - "-c", - "--config", - help="Path to the config file", - default="conf/plots.yaml", - ) - args = parser.parse_args() +parser = argparse.ArgumentParser() +parser.add_argument( + "-p", + "--path", + type=str, + help="Path to the plot folder", + required=True, +) +parser.add_argument( + "-f", + "--file", + type=str, + help="Data file to read from", + required=True, +) +parser.add_argument( + "-t", + "--plotfiletype", + type=str, + help="Filetype of the plots", + default=".eps", +) +parser.add_argument( + "-v", + "--verbosity", + default="INFO", + help="Increase output verbosity", +) +parser.add_argument( + "-c", + "--config", + help="Path to the config file", + default="conf/plots.yaml", +) + + +def main(args): logging.basicConfig(level=args.verbosity) assert Path( args.file, @@ -334,3 +371,8 @@ def scatter_plot( for dict_ in scatter_plot_list: i += 1 scatter_plot(data, **dict_, folder=FOLDER, filetype=IMAGE_FILETYPE) + + +if __name__ == "__main__": + args = parser.parse_args() + main(args) diff --git a/deckard/layers/prometheus.py b/deckard/layers/prometheus.py index 7e0171d4..68e20092 100644 --- a/deckard/layers/prometheus.py +++ b/deckard/layers/prometheus.py @@ -1,185 +1,188 @@ -import experiments.libs.functions -from prometheus_api_client import PrometheusConnect -from datetime import datetime -from dataclasses import dataclass -from pathlib import Path -import yaml +# import experiments.libs.functions +# from prometheus_api_client import PrometheusConnect +# from datetime import datetime +# from dataclasses import dataclass +# from pathlib import Path +# import yaml -@dataclass -class PromQuery: - prom_host = "labumu.se" - prom_port = "30090" - prom_address = "http://" + prom_host + ":" + prom_port + "/" - warmup = 9000 - warmdown = 3000 - step = 5 - query = "" - start = 0 - end = 0 - service = "" - namespace = "" - percentile = "" - reporter = "source" - response_code = "" +# @dataclass +# class PromQuery: +# prom_host = "labumu.se" +# prom_port = "30090" +# prom_address = "http://" + prom_host + ":" + prom_port + "/" +# warmup = 9000 +# warmdown = 3000 +# step = 5 +# query = "" +# start = 0 +# end = 0 +# service = "" +# namespace = "" +# percentile = "" +# reporter = "source" +# response_code = "" - def query_prometheus(self): - """ - This function collects data in prometheus for a given query, in a given time interval, with a given - warmup/warmdown time offset and a given step. - :return: - """ - prom = PrometheusConnect(url=self.prom_address, disable_ssl=True) - start = datetime.fromtimestamp((self.start + self.warmup) / 1000) - end = datetime.fromtimestamp((self.end - self.warmdown) / 1000) +# def query_prometheus(self): +# """ +# This function collects data in prometheus for a given query, in a given time interval, with a given +# warmup/warmdown time offset and a given step. +# :return: +# """ +# prom = PrometheusConnect(url=self.prom_address, disable_ssl=True) +# start = datetime.fromtimestamp((self.start + self.warmup) / 1000) +# end = datetime.fromtimestamp((self.end - self.warmdown) / 1000) - result = prom.custom_query_range( - query=self.query, start_time=start, end_time=end, step=self.step - ) - return result +# result = prom.custom_query_range( +# query=self.query, +# start_time=start, +# end_time=end, +# step=self.step, +# ) +# return result - def get_response_time(self, version=None): - """ - This function will get the response time for a given service in a given time interval and based on a given - percentile - :return: - """ - if version == None: - version = "latest" - if self.response_code == "": - self.query = ( - "(histogram_quantile(" - + str(self.percentile) - + ', sum(irate(istio_request_duration_milliseconds_bucket{reporter="' - + self.reporter - + '", destination_service=~"' - + self.service - + "." - + self.namespace - + '.svc.cluster.local", destination_canonical_revision="' - + version - + '"}[1m])) ' - "by (le)) / 1000)" - ) - elif self.response_code == "200": - self.query = ( - "(histogram_quantile(" - + str(self.percentile) - + ', sum(irate(istio_request_duration_milliseconds_bucket{reporter="' - + self.reporter - + '", destination_service=~"' - + self.service - + "." - + self.namespace - + '.svc.cluster.local",' - 'response_code="' - + self.response_code - + '", destination_canonical_revision="' - + version - + '"}[1m])) by (le)) / 1000)' - ) - else: - self.query = ( - "(histogram_quantile(" - + str(self.percentile) - + ', sum(irate(istio_request_duration_milliseconds_bucket{reporter="' - + self.reporter - + '", destination_service=~"' - + self.service - + "." - + self.namespace - + '.svc.cluster.local",' - 'response_code!="200", destination_canonical_revision="' - + version - + '"}[1m])) by (le)) / 1000)' - ) +# def get_response_time(self, version=None): +# """ +# This function will get the response time for a given service in a given time interval and based on a given +# percentile +# :return: +# """ +# if version == None: +# version = "latest" +# if self.response_code == "": +# self.query = ( +# "(histogram_quantile(" +# + str(self.percentile) +# + ', sum(irate(istio_request_duration_milliseconds_bucket{reporter="' +# + self.reporter +# + '", destination_service=~"' +# + self.service +# + "." +# + self.namespace +# + '.svc.cluster.local", destination_canonical_revision="' +# + version +# + '"}[1m])) ' +# "by (le)) / 1000)" +# ) +# elif self.response_code == "200": +# self.query = ( +# "(histogram_quantile(" +# + str(self.percentile) +# + ', sum(irate(istio_request_duration_milliseconds_bucket{reporter="' +# + self.reporter +# + '", destination_service=~"' +# + self.service +# + "." +# + self.namespace +# + '.svc.cluster.local",' +# 'response_code="' +# + self.response_code +# + '", destination_canonical_revision="' +# + version +# + '"}[1m])) by (le)) / 1000)' +# ) +# else: +# self.query = ( +# "(histogram_quantile(" +# + str(self.percentile) +# + ', sum(irate(istio_request_duration_milliseconds_bucket{reporter="' +# + self.reporter +# + '", destination_service=~"' +# + self.service +# + "." +# + self.namespace +# + '.svc.cluster.local",' +# 'response_code!="200", destination_canonical_revision="' +# + version +# + '"}[1m])) by (le)) / 1000)' +# ) - result = self.query_prometheus() - return result +# result = self.query_prometheus() +# return result - def get_status_codes(self, version=None): - """ - This function will get the request status codes for agiven service, in agiven time interval with a given - warmup/warmdown time offset and a given step +# def get_status_codes(self, version=None): +# """ +# This function will get the request status codes for agiven service, in agiven time interval with a given +# warmup/warmdown time offset and a given step - """ - if version == None: - version = "latest" - self.query = ( - 'round(sum(irate(istio_requests_total{destination_service=~"' - + self.service - + "" - "." - + self.namespace - + '.svc.cluster.local", reporter="source", destination_canonical_revision="' - + version - + '"}[1m])) by (response_code, response_flags), 0.001)' - ) - result = self.query_prometheus() - return result +# """ +# if version == None: +# version = "latest" +# self.query = ( +# 'round(sum(irate(istio_requests_total{destination_service=~"' +# + self.service +# + "" +# "." +# + self.namespace +# + '.svc.cluster.local", reporter="source", destination_canonical_revision="' +# + version +# + '"}[1m])) by (response_code, response_flags), 0.001)' +# ) +# result = self.query_prometheus() +# return result - def get_retried_requests(self, port, version=""): - """ - This function gets the number of retried requests for a given service, in given time interval with a given - warmup/warmdown time offset and a given step - """ - self.query = ( - 'round(sum(irate(envoy_cluster_upstream_rq_retry{cluster_name="outbound|' - + str(port) - + "|" - + version - + "|" - + self.service - + '.default.svc.cluster.local"}[1m])) by (), 0.001)' - ) - result = self.query_prometheus() - return result +# def get_retried_requests(self, port, version=""): +# """ +# This function gets the number of retried requests for a given service, in given time interval with a given +# warmup/warmdown time offset and a given step +# """ +# self.query = ( +# 'round(sum(irate(envoy_cluster_upstream_rq_retry{cluster_name="outbound|' +# + str(port) +# + "|" +# + version +# + "|" +# + self.service +# + '.default.svc.cluster.local"}[1m])) by (), 0.001)' +# ) +# result = self.query_prometheus() +# return result - def get_requests_in_queue(self): - """ - This function will get the request in the queue for a given service - """ - self.query = ( - 'round(sum(irate(envoy_http_inbound_0_0_0_0_5000_downstream_rq_active{app=~"' - + self.service - + '"}[1m])) by (service_istio_io_canonical_name), 0.001)' - ) - result = self.query_prometheus() - return result +# def get_requests_in_queue(self): +# """ +# This function will get the request in the queue for a given service +# """ +# self.query = ( +# 'round(sum(irate(envoy_http_inbound_0_0_0_0_5000_downstream_rq_active{app=~"' +# + self.service +# + '"}[1m])) by (service_istio_io_canonical_name), 0.001)' +# ) +# result = self.query_prometheus() +# return result - def get_current_queue_size(self, job="istio"): - """ - This function will get the current queue size which is pushed in pushgateway (HTTP2MaxRequests) - """ - self.query = 'destination_rule_http2_max_requests{exported_job="' + job + '"}' - result = self.query_prometheus() - return result +# def get_current_queue_size(self, job="istio"): +# """ +# This function will get the current queue size which is pushed in pushgateway (HTTP2MaxRequests) +# """ +# self.query = 'destination_rule_http2_max_requests{exported_job="' + job + '"}' +# result = self.query_prometheus() +# return result - def get_retry_attempt(self): - """ - This function get the retry attempt which is pushed in pushgateway (attempts) - """ - self.query = "retry_attempts_" + self.service - result = self.query_prometheus() - return result +# def get_retry_attempt(self): +# """ +# This function get the retry attempt which is pushed in pushgateway (attempts) +# """ +# self.query = "retry_attempts_" + self.service +# result = self.query_prometheus() +# return result - def __call__(self, config_file, output_file, output_folder) -> None: - """ - This function will call the prometheus query function and write the result in a given file - """ - # Available metrics: - # train_time, train_start_time, train_end_time, - # predict_proba_time, predict_proba_start_time, predict_proba_end_time, - # adv_train_time, adv_train_start_time, adv_train_end_time, - # adv_predict_proba_time, adv_predict_proba_start_time, adv_predict_proba_end_time, - # Find all output_file recursively inside output_folder - with open(config_file, "r") as f: - config = yaml.load(f, Loader=yaml.FullLoader) - files = Path(output_folder).rglob(output_file) - # Each file will have train_start_time train_end_time, predict_proba_start_time predict_predict_proba_end_time, adv_ - # Query Prometheus - # Do calulations - # Write to file - # Use a lambda function so that this will be parallelized across all the files in the files iterator and across each entry of the config - # Return None - None +# def __call__(self, config_file, output_file, output_folder) -> None: +# """ +# This function will call the prometheus query function and write the result in a given file +# """ +# # Available metrics: +# # train_time, train_start_time, train_end_time, +# # predict_proba_time, predict_proba_start_time, predict_proba_end_time, +# # adv_train_time, adv_train_start_time, adv_train_end_time, +# # adv_predict_proba_time, adv_predict_proba_start_time, adv_predict_proba_end_time, +# # Find all output_file recursively inside output_folder +# with open(config_file, "r") as f: +# config = yaml.load(f, Loader=yaml.FullLoader) +# files = Path(output_folder).rglob(output_file) +# # Each file will have train_start_time train_end_time, predict_proba_start_time predict_predict_proba_end_time, adv_ +# # Query Prometheus +# # Do calulations +# # Write to file +# # Use a lambda function so that this will be parallelized across all the files in the files iterator and across each entry of the config +# # Return None +# None diff --git a/deckard/layers/utils.py b/deckard/layers/utils.py index fc72e9a7..2217f785 100644 --- a/deckard/layers/utils.py +++ b/deckard/layers/utils.py @@ -1,15 +1,20 @@ import logging from pathlib import Path +import re from hydra.errors import OverrideParseException from omegaconf import OmegaConf +from omegaconf import SCMode from copy import deepcopy import yaml from hydra import initialize_config_dir, compose +import dvc.api +from hydra.utils import instantiate +from dulwich.errors import NotGitRepository from numpy import nan -from ..base.utils import my_hash +from ..base.utils import my_hash, flatten_dict, unflatten_dict logger = logging.getLogger(__name__) @@ -59,7 +64,7 @@ def find_conf_files( return files -def get_overrides(file: str, key: str = None, overrides=None): +def get_overrides(overrides=None): if overrides is None: overrides = {} else: @@ -137,14 +142,257 @@ def save_params_file( config_dir="conf", config_file="default", params_file="params.yaml", + working_directory=".", overrides=[], ): - config_dir = str(Path(Path(), config_dir).absolute().as_posix()) + config_dir = str(Path(working_directory, config_dir).absolute().as_posix()) + logger.info(f"Running save_params_file in config_dir: {config_dir}") with initialize_config_dir(config_dir=config_dir, version_base="1.3"): cfg = compose(config_name=config_file, overrides=overrides) - params = OmegaConf.to_container(cfg, resolve=True) - with open(params_file, "w") as f: - yaml.dump(params, f) - logger.info(f"Saved params file to {params_file}") + params = OmegaConf.to_container( + cfg, + resolve=True, + structured_config_mode=SCMode.DICT, + ) + with open(params_file, "w") as f: + yaml.dump(params, f) + logger.info(f"Saved params file to {params_file}") assert Path(params_file).exists(), f"Failed to save params file to {params_file}" return None + + +def get_dvc_stage_params( + stage, + params_file="params.yaml", + pipeline_file="dvc.yaml", + directory=".", + name=None, +): + logger.info( + f"Getting params for stage {stage} from {params_file} and {pipeline_file} in {directory}.", + ) + params = dvc.api.params_show(stages=stage, repo=directory) + params.update({"_target_": "deckard.base.experiment.Experiment"}) + params = OmegaConf.to_container(OmegaConf.create(params), resolve=True) + flat_params = flatten_dict(params) + pipe_params = dvc.api.params_show(pipeline_file, stages=stage, repo=directory)[ + "stages" + ][stage] + file_list = [] + for key in ["metrics", "deps", "outs", "plots"]: + param_string = str(pipe_params.get(key, {})) + # find all values within ${} and add them to file_list + file_list.extend(re.findall(r"\${(.*?)}", param_string)) + file_dict = {} + for k in file_list: + if k in flat_params: + file_dict[k] = flat_params[k] + else: + raise ValueError(f"File {k} not found in {pipe_params.keys()}") + file_dict = unflatten_dict(file_dict) + params["files"] = file_dict.pop("files", {}) + params["files"]["stage"] = stage + # Merge remaining params + params = OmegaConf.merge(params, file_dict) + params = OmegaConf.to_container(OmegaConf.create(params), resolve=True) + if name is not None: + params["files"]["name"] = name + return params + + +# def get_dvc_stage_params( +# stage, +# params_file="params.yaml", +# pipeline_file="dvc.yaml", +# directory=".", +# name=None, +# ): +# logger.info( +# f"Getting params for stage {stage} from {params_file} and {pipeline_file} in {directory}.", +# ) +# params = dvc.api.params_show(stages=stage) +# params.update({"_target_": "deckard.base.experiment.Experiment"}) +# pipe_params = dvc.api.params_show(pipeline_file, stages=stage, repo=directory) +# pipe_params = unflatten_dict(pipe_params) +# params["files"] = dict(pipe_params.pop("files", pipe_params)) +# params["files"]["_target_"] = "deckard.base.files.FileConfig" +# params["files"]["stage"] = stage +# params["stage"] = stage +# if name is not None: +# params["files"]["name"] = name +# # Merge remaining params +# params = OmegaConf.merge(params, pipe_params) +# return params + + +def prepare_files(params_file, stage, params, id_): + # Turns the dictionary into a FileConfig object. + # This creates a new directory at files.directory + # It also creates a new directory at files.directory/files.data_dir + # It also creates a new directory at files.directory/files.reports_dir + # If a stage is specified, it also creates a new directory at files.directory/files.reports/stage + params["files"]["_target_"] = "deckard.base.files.FileConfig" + params["files"]["stage"] = stage + params["files"]["name"] = ( + id_ if params["files"].get("name", None) is None else params["files"]["name"] + ) + params["files"]["params_file"] = Path(params_file).name + # This creates a the object + files = instantiate(params["files"]) + # Which will return the dictionary of the files + files = files.get_filenames() + # If the params_file is in the files, then the params_file is the params_file + if "params_file" in files: + params_file = files["params_file"] + # Otherwise we take the folder of the score_dict_file and change the name to whatever the params_file is + elif "score_dict_file" in files: + params_file = Path(files["score_dict_file"]).with_name(params_file) + else: + raise ValueError( + f"Neither params_file nor score_dict_file found in {list(files.keys())}.", + ) + + # Save the params to the params_file + Path(params_file).parent.mkdir(exist_ok=True, parents=True) + with Path(params_file).open("w") as f: + yaml.dump(params, f) + return files + + +def get_stages(pipeline_file="dvc.yaml", stages=None, repo=None): + try: + def_stages = list( + dvc.api.params_show(pipeline_file, repo=repo)["stages"].keys(), + ) + except NotGitRepository: + raise ValueError( + f"Directory {repo} is not a dvc repository. Please run `dvc init` in {repo} and try again.", + ) + if stages is None or stages == []: + logger.info("No stages specified. Running default from hydra configuration") + stages = [None] + elif isinstance(stages, str): + stages = [stages] + else: + assert isinstance(stages, list), f"args.stage is of type {type(stages)}" + for stage in stages: + assert ( + stage in def_stages + ), f"Stage {stage} not found in {pipeline_file}. Available stages: {def_stages}" + return stages + + +def get_params_from_disk( + params_file, + pipeline_file, + directory, + stage, + config_dir, + config_file, +): + if stage is not None: + params = get_dvc_stage_params( + stage=stage, + params_file=params_file, + pipeline_file=pipeline_file, + directory=directory, + ) + else: + # Use hydras compose to get the params + assert config_dir is not None, "config_dir must be specified if stage is None" + with initialize_config_dir( + config_dir=config_dir, + job_name=Path(config_file).stem, + version_base="1.3", + ): + cfg = compose(config_name=config_file) + params = OmegaConf.to_container(cfg, resolve=True) + params["files"] = dict(params.pop("files", params)) + params["files"]["_target_"] = "deckard.base.files.FileConfig" + params["files"]["stage"] = None + params["stage"] = None + return params + + +def run_stage( + params_file="params.yaml", + pipeline_file="dvc.yaml", + directory=".", + stage=None, + overrides=None, + config_dir=None, + config_file=None, + sub_dict=None, +): + logger.info( + f"Running stage {stage} with params_file: {params_file} and pipeline_file: {pipeline_file} in directory {directory}", + ) + params = get_params_from_disk( + params_file, + pipeline_file, + directory, + stage, + config_dir, + config_file, + ) + params = add_overrides(overrides, params) + if sub_dict is None: + params["_target_"] = "deckard.experiment.Experiment" + exp = instantiate(params) + id_ = exp.name + _ = prepare_files(params_file, stage, params, id_) + score = exp() + else: + possible_subdicts = ["data", "model", "attack", "scorers", "plots", "files"] + assert ( + sub_dict in possible_subdicts + ), f"sub_dict must be one of {possible_subdicts}" + target = f"deckard.{sub_dict}.{sub_dict.capitalize()}" + params["_target_"] = target + exp = instantiate(params[sub_dict]) + id_ = exp.name + files = params["files"] + params[sub_dict]["files"] = files + files = prepare_files(params_file, stage, params[sub_dict], id_) + score = exp(**files) + return id_, score + + +def add_overrides(overrides, params): + old_params = deepcopy(params) + if overrides is not None and len(overrides) > 0: + # convert from dot notation to nested dict + overrides = OmegaConf.from_dotlist(overrides) + params = OmegaConf.merge(params, overrides) + params = OmegaConf.to_container(params, resolve=True) + assert ( + params != old_params + ), f"Params are the same as before overrides: {overrides}" + params = OmegaConf.create(params) + params = OmegaConf.to_container(params, resolve=True) + return params + + +def run_stages( + stages, + pipeline_file="dvc.yaml", + params_file="params.yaml", + repo=None, + config_dir=None, + config_file=None, + sub_dict=None, +): + results = {} + stages = get_stages(stages=stages, pipeline_file=pipeline_file, repo=repo) + for stage in stages: + id_, score = run_stage( + stage=stage, + pipeline_file=pipeline_file, + params_file=params_file, + directory=repo, + config_dir=config_dir, + config_file=config_file, + sub_dict=sub_dict, + ) + results[id_] = score + return results diff --git a/examples/bit_depth/conf/compile.yaml b/examples/bit_depth/conf/compile.yaml index 1433e2cd..1d325efa 100644 --- a/examples/bit_depth/conf/compile.yaml +++ b/examples/bit_depth/conf/compile.yaml @@ -29,3 +29,35 @@ params: FSQ: model.art.pipeline.preprocessor.bit_depth Gauss-in: model.art.pipeline.preprocessor.sigma Control: model_layers + +attacks: + # CarliniL0Method: CW_0 + # CarliniL2Method: CW_2 + # CarliniLInfMethod: CW_inf + DeepFool: Deep + FastGradientMethod: FGM + HopSkipJump: HSJ + PixelAttack: Pixel + ProjectedGradientDescent: PGD + ThresholdAttack: Thresh +defences: + Control: Control + FeatureSqueezing: FSQ + GaussianAugmentation: Gauss-in + GaussianNoise: Gauss-out + HighConfidence: Conf +params: + # art.attacks.evasion.CarliniL0Method: attack.init.confidence + # art.attacks.evasion.CarliniL2Method: attack.init.confidence + # art.attacks.evasion.CarliniLInfMethod: attack.init.confidence + Deep: attack.init.nb_grads + FGM: attack.init.eps + HSJ: attack.init.max_iter + Pixel: attack.init.th + PGD: attack.init.eps + Thresh: attack.init.th + Gauss-out: model.art.pipeline.postprocessor.scale + Conf: model.art.pipeline.postprocessor.cutoff + FSQ: model.art.pipeline.preprocessor.bit_depth + Gauss-in: model.art.pipeline.preprocessor.sigma + Control: model_layers diff --git a/examples/gzip/.dvc/.gitignore b/examples/gzip/.dvc/.gitignore new file mode 100644 index 00000000..528f30c7 --- /dev/null +++ b/examples/gzip/.dvc/.gitignore @@ -0,0 +1,3 @@ +/config.local +/tmp +/cache diff --git a/examples/gzip/.dvcignore b/examples/gzip/.dvcignore new file mode 100644 index 00000000..51973055 --- /dev/null +++ b/examples/gzip/.dvcignore @@ -0,0 +1,3 @@ +# Add patterns of files dvc should ignore, which could improve +# the performance. Learn more at +# https://dvc.org/doc/user-guide/dvcignore diff --git a/examples/gzip/.gitignore b/examples/gzip/.gitignore new file mode 100644 index 00000000..8e6ca79d --- /dev/null +++ b/examples/gzip/.gitignore @@ -0,0 +1,11 @@ +output +*.db +kdd_nsl +truthseeker +ddos +sms_spam +/raw_data +.dvc/config +2-22/ +2-28/ +/params.yaml diff --git a/examples/gzip/README.md b/examples/gzip/README.md new file mode 100644 index 00000000..43af47f2 --- /dev/null +++ b/examples/gzip/README.md @@ -0,0 +1,70 @@ + + +# Installation +You should probably be using a virutal environment rather than installing things globally. Why? 1. Because you can just remove this folder after to delete all traces of this software. 2. Your system might have python3 rather than python even though python2 is long dead. The dvc.yaml file contains scripts that are executed in whatever environment you run the `dvc repro` (see below) command from, and changing the python interpreter of the dvc command won't change that. You're welcome to change the call to the binary in each cmd or do things the right way: + + +If you don't already have a preferred environment manager (ce.g. conda), I recommend venv. You might need to install the operating system dependencies and python package with: +``` +sudo apt-get install python3-venv +python3 -m pip install venv +``` +You create a virutal environment in the folder `env` with: +``` +python3 -m venv env +``` +Then activate it: +``` +source env/bin/activate +``` +run `deactivate` to exit the virtual environment + +You might need to install pip? +``` +sudo -H python -m ensurepip +``` +To run the gzip_classifier.py you need to install some python dependencies: + +``` +python -m pip install numpy scikit-learn pandas tqdm scikit-learn-extra imbalanced-learn plotext +``` + +To reproduce the entire experiment, install `deckard` from this folder as working directory with: + +``` +python -m pip install ../../ +``` +which will run the setup.py script in the root directory of this repository. + +Additionally, we are using some optuna features that are not necessarily available in whatever version of hydra you have installed. Instead, install it from source, much like you did for this repository: + +``` +git clone https://github.com/facebookresearch/hydra +cd hydra +python -m pip install . +``` +Additionally, you need to install the hydra-optuna-sweeper plugin by navigating to the `examples/gzip/hydra/plugins/hydra_optuna_sweeper` folder and installing it with: +``` +python -m pip install . +``` + +Now, we need to specify a default configuration to test before our grid search. Return to this folder and run the parser, which will read the config files, accept command line overrides, and allow you to specify a default `dvc` `params.yaml` file that will contain the git-trackable defaults for your experiments. Run the parser with: +``` +python -m deckard.layers.parse --config_name default --config_folder conf +``` +Both of the displayed options are the default choices anyway, but you can change them to another config folder and file as you wish. This will create a `params.yaml` file in the current working directory using hydra's compose API. + +From here, we will let dvc manage our tasks, execution order, caching, and reproducibility. You can run the entire experiment with: + +``` +dvc repro +``` +which will read the `dvc.yaml` file, parsing any parameters specified in the `params.yaml` or any other specified file. + +It will then execute a "stage", which is a single shell command as well as "params", "deps", "outs", "metrics" and/or plots, which track the the parameters, dependencies, outputs, metric files, and/or plot files using DVC. + + You can specify an order of operations by requiring the output of an earlier stage to be a dependency of a later stage. + +To exploit the dvc file-tracking features, you can use dictionary keywords ( e.g. files.X ) when specifying a stage, regardless of usage within said stage. If you run the optimise script, it will overwrite files.name with the hash of the experiment config if and only if the name is set to default. Other entries: files.data_file, files.model_file, files.attack_file, will likewise be overwritten with the hash of the respective sub dictionary. + + Additionally, deckard will allow us to use the parameter tracking features of dvc as well as the configuration, launching, and optimization features of hydra by specifying a "stage", which will allow us to isolate pipeline stages from one another if so desired. See the `dvc.yaml` file for examples of this. In this example, it's mostly used for testing the functionality of different features in isolation of each other, but could be used for any arbitrary division of an ML pipeline you so choose. For example, we could have separate stages for sampling, feature selection, training, and evaluation. This is just a matter of passing different subsets of the configuration dictionary to the the run-time. The `deckard.layers.experiment` script will parse the entire params.yaml file, load or generate data, split it into train and test sets, fit a model, attack it (if so desired), make predictions, and score it according to the specified configs. diff --git a/examples/gzip/batchMixin.py b/examples/gzip/batchMixin.py new file mode 100644 index 00000000..5cc762b7 --- /dev/null +++ b/examples/gzip/batchMixin.py @@ -0,0 +1,255 @@ +from tqdm import tqdm +import logging +import numpy as np + + +from sklearn.datasets import make_classification +import random + +# from gzip_classifier import GzipSVC, GzipKNN, GzipLogisticRegressor +from sklearn.svm import SVC +from sklearn.model_selection import train_test_split +import plotext + +logger = logging.getLogger(__name__) + +train_scores = [] +test_scores = [] + + +class BatchedMixin: + def __init__( + self, + batch_size: int = 10, + max_batches: int = 100, + nb_epoch=1, + **kwargs, + ): + self.batch_size = kwargs.pop("m", batch_size) + self.max_batches = kwargs.pop("max_batches", max_batches) + nb_epoch = kwargs.pop("nb_epoch", nb_epoch) + if not nb_epoch >= 1: + nb_epoch = 1 + self.nb_epoch = nb_epoch + if "m" in kwargs: + logger.warning( + f"Parameter 'm' is being overwritten with batch_size={self.batch_size}.", + ) + kwargs["m"] = self.batch_size + super().__init__(**kwargs) + self.predict = self.batched_predict(self.predict) + if hasattr(self, "_find_best_samples"): + self._find_best_samples = self.batched_find_best_samples( + self._find_best_samples, + ) + if hasattr(self, "score"): + self.score = self.batched_score(self.score) + self.fit = self.batched_fit(self.fit) + self.predict = self.batched_predict(self.predict) + if self.nb_epoch > 1: + self.fit = self.epoch_fit(self.fit) + # self.score = self.batched_score(self.score) + + def epoch_fit(self, fit_func): + def wrapper(*args, **kwargs): + X, y = args + for i in range(self.nb_epoch): + random.shuffle(X) + random.shuffle(y) + fit_func(X, y, **kwargs) + + return wrapper + + def batched_fit(self, fit_func): + def wrapper(*args, **kwargs): + X_train, y_train = args + n = len(X_train) + n_batches = n // self.batch_size + if n_batches > self.max_batches: + logger.warning( + f"Number of batches ({n_batches}) is greater than max_batches ({self.max_batches}). Using max_batches.", + ) + n_batches = self.max_batches + for i in tqdm( + range(n_batches), + desc="Fitting batches", + total=n_batches, + leave=False, + dynamic_ncols=True, + ): + start = i * self.batch_size + end = (i + 1) * self.batch_size + X_batch = X_train[start:end] + y_batch = y_train[start:end] + print( + f"Shape of X_batch is {X_batch.shape} and shape of y_batch is {y_batch.shape}", + ) + fit_func(X_batch, y_batch, **kwargs) + if self.nb_epoch > 1: + continue + train_score = self.score(X_batch, y_batch) + test_score = self.score(X_train, y_train) + print( + f"Batch {i+1} of {n_batches} - Train score: {np.mean(train_score)}; Test score: {np.mean(test_score)}", + ) + train_scores.append(train_score) + test_scores.append(test_score) + + return wrapper + + def batched_find_best_samples(self, func): + def wrapper(method, **kwargs): + if "X" in kwargs: + X = kwargs["X"] + assert "y" in kwargs, "y must be provided if X is provided" + y = kwargs["y"] + append = True + else: + X = self.X_ + y = self.y_ + append = False + n_jobs = kwargs.pop("n_jobs", -1) + n = len(X) + n_batches = n // self.batch_size + if n_batches > self.max_batches: + n_batches = self.max_batches + elif n_batches == 0: + n_batches = 1 + for i in range(n_batches): + if append is True: + new_X = X[i * self.batch_size : (i + 1) * self.batch_size] # noqa + new_y = y[i * self.batch_size : (i + 1) * self.batch_size] # noqa + indices = func(X=new_X, y=new_y, method=method, n_jobs=n_jobs) + # print("After finding best samples") + # print(f"Length of indices is {len(indices)}") + X = X[indices] + y = y[indices] + self.X_ = X + self.y_ = y + self.distance_matrix = self.distance_matrix + else: + indices = func(method=method, n_jobs=n_jobs) + return indices + + return wrapper + + def batched_predict(self, predict_func): + def wrapper(*args, **kwargs): + X_test = args[0] + n = len(X_test) + n_batches = n // self.batch_size + if n_batches > self.max_batches: + n_batches = self.max_batches + elif n_batches == 0: + n_batches = 1 + preds = [] + for i in tqdm( + range(n_batches), + desc="Predicting batches", + total=n_batches, + leave=False, + dynamic_ncols=True, + ): + start = i * self.batch_size + end = (i + 1) * self.batch_size + X_batch = X_test[start:end] + new_preds = predict_func(X_batch, **kwargs) + preds.append(new_preds) + return np.concatenate(preds) + + return wrapper + + def batched_score(self, score_func): + def wrapper(*args, **kwargs): + X_test, y_test = args + n = len(X_test) + n_batches = n // self.batch_size + if n_batches > self.max_batches: + n_batches = self.max_batches + elif n_batches == 0: + n_batches = 1 + scores = [] + for i in tqdm( + range(n_batches), + desc="Scoring batches", + total=n_batches, + leave=False, + dynamic_ncols=True, + ): + start = i * self.batch_size + end = (i + 1) * self.batch_size + X_batch = X_test[start:end] + y_batch = y_test[start:end] + score = score_func(X_batch, y_batch, **kwargs) + scores.append(score) + return scores + + return wrapper + + +def create_batched_class(cls, *args, **kwargs): + name = cls.__name__ + + class BatchedClass(cls, BatchedMixin): + def __init__(self, *args, **kwargs): + self.max_batches = kwargs.pop("max_batches", 100) + self.batch_size = kwargs.pop("batch_size", 10) + super().__init__(*args, **kwargs) + + batched_class = BatchedClass() + combined_name = f"Batched{name}" + batched_class.__name__ = combined_name + batched_class.__init__(*args, **kwargs) + return batched_class + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + big_X = [] + big_y = [] + for i in range(100): + X, y = make_classification( + n_samples=100, + n_features=20, + n_informative=19, + n_redundant=1, + n_classes=2, + random_state=42 + i, + ) + big_X.extend(X.tolist()) + big_y.extend(y.tolist()) + big_X = np.array(big_X) + big_y = np.array(big_y) + logger.info(f"Shape of big_X: {big_X.shape}") + i = 42 + X, y = make_classification( + n_samples=10000, + n_features=20, + n_informative=19, + n_redundant=1, + n_classes=2, + random_state=42 + i, + ) + X_train, X_test, y_train, y_test = train_test_split( + X, + y, + test_size=0.2, + random_state=42, + ) + + class BatchedSVC(BatchedMixin, SVC): + pass + + clf = BatchedSVC(max_batches=100, batch_size=100, kernel="rbf") + clf.fit(X_train, y_train) + score = clf.score(X_test, y_test) + print(score) + input("Press enter to continue") + score = round(np.mean(score), 2) + std = round(np.std(score), 3) + logger.info(f"Final Score: {score}") + logger.info(f"Standard Deviation: {std}") + # if plotext_available is True: + plotext.scatter(train_scores, label="Train scores") + plotext.scatter(test_scores, label="Test scores") + plotext.plot() diff --git a/examples/gzip/conf/attack/.gitignore b/examples/gzip/conf/attack/.gitignore new file mode 100644 index 00000000..41ee9b5a --- /dev/null +++ b/examples/gzip/conf/attack/.gitignore @@ -0,0 +1 @@ +/best.yaml diff --git a/examples/gzip/conf/attack/attack_grid.yaml b/examples/gzip/conf/attack/attack_grid.yaml new file mode 100644 index 00000000..d7dc3050 --- /dev/null +++ b/examples/gzip/conf/attack/attack_grid.yaml @@ -0,0 +1,49 @@ +- attack.init.name: [art.attacks.evasion.FastGradientMethod] + attack.init.eps : [.01, .03, .3, .1] + attack.init.norm : ['inf', 1, 2] + attack.init.eps_step : [.001, .003, .01] + attack.init.batch_size : [100] + +- attack.init.name: [art.attacks.evasion.ProjectedGradientDescent] + attack.init.eps : [.01, .03, .3, .1] + attack.init.norm : ['inf', 1, 2] + attack.init.eps_step : [.001, .003, .01] + attack.init.batch_size : [100] + attack.init.max_iter : [10] + +- attack.init.name: [art.attacks.evasion.CarliniL0Method] + attack.init.batch_size : [100] + attack.init.max_iter : [10] + attack.init.confidence : [.1, .9, .99] + +- attack.init.name: [art.attacks.evasion.CarliniL2Method] + attack.init.batch_size : [100] + attack.init.max_iter : [10] + attack.init.confidence : [.1, .9, .99] + +- attack.init.name: [art.attacks.evasion.CarliniLInfMethod] + attack.init.max_iter : [10] + attack.init.confidence: [.1, .9, .99] + +- attack.init.name: [art.attacks.evasion.DeepFool] + attack.init.max_iter : [10] + attack.init.batch_size : [100] + attack.init.nb_grads : [10, 100, 1000] + +- attack.init.name: [art.attacks.evasion.HopSkipJump] + attack.init.max_iter : [10] + attack.init.max_eval : [10] + attack.init.init_eval : [10] + attack.init.norm : ['inf', 2] + +- attack.init.name: [art.attacks.evasion.PixelAttack] + attack.init.th : [.5, .9, .99] + attack.init.max_iter : [10] + +- attack.init.name: [art.attacks.evasion.ThresholdAttack] + attack.init.th : [.5, .9, .99] + attack.init.max_iter : [10] + +- attack.init.name: [art.attacks.evasion.AdversarialPatch] + attack.init.max_iter : [10] + attack.init.learning_rate : [.5, 5.0, 50.0] diff --git a/examples/gzip/conf/attack/default.yaml b/examples/gzip/conf/attack/default.yaml new file mode 100644 index 00000000..e0967ff7 --- /dev/null +++ b/examples/gzip/conf/attack/default.yaml @@ -0,0 +1,2 @@ +defaults: + - hsj diff --git a/examples/gzip/conf/attack/hsj.yaml b/examples/gzip/conf/attack/hsj.yaml new file mode 100644 index 00000000..9f4c7e02 --- /dev/null +++ b/examples/gzip/conf/attack/hsj.yaml @@ -0,0 +1,15 @@ +data: ${data} +model: ${model} +_target_ : deckard.base.attack.Attack +init: + name: art.attacks.evasion.HopSkipJump + model: ${model} + batch_size : 1024 + norm : 2 + max_iter : 10 + max_eval : 10 + init_eval : 10 + init_size : 10 + verbose : true +attack_size : 10 +method : evasion diff --git a/examples/gzip/conf/clean.yaml b/examples/gzip/conf/clean.yaml new file mode 100644 index 00000000..c5bc3dd5 --- /dev/null +++ b/examples/gzip/conf/clean.yaml @@ -0,0 +1,35 @@ +# params: + # control: + # data.sample.train_size: 100 + # defaults: + # model.init.m : -1 +# fillna: +# model.init.compressor : "None" +# model.init.metric : "ncd" +# model.init.method : "random" +# model.init.m : ${data.sample.random_state} +# model.init.precompute : "False" +replace: + model.init.metric: + jaro: "Jaro" + _winkler: "-Winkler" + levenshtein: "Levenshtein" + ncd: "NCD" + ratio: "Ratio" + seqRatio: "SeqRatio" + hamming: "Hamming" + gzip: "Gzip" + pkl: "Pickle" + bz2: "BZ2" + zstd: "Zstd" + lzma : "Lzma" + model_name: + GzipSVC : "k-SVC" + GzipLogisticRegressor : "k-Logistic" + GzipKNN : "k-KNN" + model.init.symmetric: + True: "Symmetric" + False: "Asymmetric" +drop_values: + accuracy : 0.00000000000 + predict_time : 1.00000000000 diff --git a/examples/gzip/conf/condense.yaml b/examples/gzip/conf/condense.yaml new file mode 100644 index 00000000..a64263ea --- /dev/null +++ b/examples/gzip/conf/condense.yaml @@ -0,0 +1,69 @@ +defaults: + # - _target_ : deckard.base.experiment.Experiment + - _self_ + - data: ??? + - model: ??? + - files: default + - scorers: default + - override hydra/sweeper : optuna + - override hydra/sweeper/sampler : tpe + - override hydra/launcher : joblib +dataset : ??? +model_name : ??? +stage : train +direction : + - maximize + - minimize +optimizers: + - accuracy + - predict_time +device_id : ${oc.env:DECKARD_DEVICE_ID, "cpu"} +hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir : ${hydra.job.num} + callbacks: + study_dump: + _target_ : database.OptunaStudyDumpCallback + storage : ${hydra.sweeper.storage} + study_name : ${hydra.sweeper.study_name} + directions : ${direction} + metric_names : ${optimizers} + output_file : ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + # group: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials : 2 + direction: ${direction} + max_failure_rate: 1.0 + params: + ++data.sample.train_size : 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m : tag(log, interval(.01, .1)) + +model.init.sampling_method : medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer : processes + verbose: 1 + timeout: null + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r diff --git a/examples/gzip/conf/condense_knn.yaml b/examples/gzip/conf/condense_knn.yaml new file mode 100644 index 00000000..52bd92be --- /dev/null +++ b/examples/gzip/conf/condense_knn.yaml @@ -0,0 +1,72 @@ +defaults: + # - _target_ : deckard.base.experiment.Experiment + - _self_ + - data: ??? + - model: gzip_knn + - files: default + - scorers: default + - override hydra/sweeper : optuna + - override hydra/sweeper/sampler : tpe + - override hydra/launcher : joblib +dataset : ??? +model_name : gzip_knn +stage : train +direction : + - maximize +optimizers: + - accuracy +device_id : ${oc.env:DECKARD_DEVICE_ID, "cpu"} +hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir : ${hydra.job.num} + callbacks: + study_dump: + _target_ : database.OptunaStudyDumpCallback + storage : ${hydra.sweeper.storage} + study_name : ${hydra.sweeper.study_name} + directions : ${direction} + metric_names : ${optimizers} + output_file : ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k : 1,3,5,7,11 + +model.init.weights : uniform,distance + +model.init.algorithm : brute + model.init.symmetric : True,False + ++model.init.precompute : True + model.init.metric : gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name : ${model_name} + data.sample.random_state: 0,1,2,3,4,5,6,7,8,9 + model.init.m: tag(log, interval(.1, 1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer : processes + verbose: 1 + timeout: null + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r diff --git a/examples/gzip/conf/condense_logistic.yaml b/examples/gzip/conf/condense_logistic.yaml new file mode 100644 index 00000000..5a585b06 --- /dev/null +++ b/examples/gzip/conf/condense_logistic.yaml @@ -0,0 +1,75 @@ +defaults: + # - _target_ : deckard.base.experiment.Experiment + - _self_ + - data: ??? + - model: gzip_logistic + - files: default + - scorers: default + - override hydra/sweeper : optuna + - override hydra/sweeper/sampler : tpe + - override hydra/launcher : joblib +dataset : ??? +model_name : gzip_logistic +stage : train +direction : + - maximize +optimizers: + - accuracy +device_id : ${oc.env:DECKARD_DEVICE_ID, "cpu"} +hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir : ${hydra.job.id} + callbacks: + study_dump: + _target_ : database.OptunaStudyDumpCallback + storage : ${hydra.sweeper.storage} + study_name : ${hydra.sweeper.study_name} + directions : ${direction} + metric_names : ${optimizers} + output_file : ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials : 1 + params: + +model.init.solver: saga + +model.init.penalty : l2,l1,l2,none + +model.init.tol : 1e-4,1e-3,1e-2 + +model.init.C : 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept : True,False + +model.init.class_weight : balanced,None + model.init.symmetric : True,False + ++model.init.precompute : True + model.init.metric : gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name : ${model_name} + data.sample.random_state: 0,1,2,3,4,5,6,7,8,9 + model.init.m: tag(log, interval(.1, 1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer : processes + verbose: 1 + timeout: null + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r diff --git a/examples/gzip/conf/condense_svc.yaml b/examples/gzip/conf/condense_svc.yaml new file mode 100644 index 00000000..478c9c97 --- /dev/null +++ b/examples/gzip/conf/condense_svc.yaml @@ -0,0 +1,74 @@ +defaults: + # - _target_ : deckard.base.experiment.Experiment + - _self_ + - data: ??? + - model: gzip_svc + - files: default + - scorers: default + - override hydra/sweeper : optuna + - override hydra/sweeper/sampler : tpe + - override hydra/launcher : joblib +dataset : ??? +model_name : gzip_svc +stage : train +direction : + - maximize +optimizers: + - accuracy +device_id : ${oc.env:DECKARD_DEVICE_ID, "cpu"} +hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir : ${hydra.job.id} + callbacks: + study_dump: + _target_ : database.OptunaStudyDumpCallback + storage : ${hydra.sweeper.storage} + study_name : ${hydra.sweeper.study_name} + directions : + - maximize + metric_names : + - accuracy + output_file : ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ??? + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials : 2 + params: + +model.init.kernel : rbf,precomputed + +model.init.C : 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma : scale,auto + +model.init.class_weight : balanced,null + ++model.init.precompute : True + model.init.metric : gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name : ${model_name} + data.sample.random_state: 0,1,2,3,4,5,6,7,8,9 + model.init.m: tag(log, interval(.1, 1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer : processes + verbose: 1 + timeout: null + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r diff --git a/examples/gzip/conf/condensed_plots.yaml b/examples/gzip/conf/condensed_plots.yaml new file mode 100644 index 00000000..268802a3 --- /dev/null +++ b/examples/gzip/conf/condensed_plots.yaml @@ -0,0 +1,61 @@ +line_plot: + - file : sampling_method_vs_accuracy.pdf + hue: model.init.sampling_method + title: #"Accuracy vs Sampling Method" + x : model.init.m + xlabel: Percentage of Samples per Class + y : accuracy + ylabel: Accuracy + hue_order: + - random + - svc + - knn + - sum + - medoid + - nearmiss + - hardness + errorbar: se + err_style: bars + xlim : [0, 1] + y_scale : linear + legend: {"title": "Sampling Method", "bbox_to_anchor": [1.05, .5], "loc" : "center left", "prop" : {"size" : 14}} + - file: sampling_method_vs_train_time.pdf + hue: model.init.sampling_method + title: #"Training Time vs Sampling Method" + x : model.init.m + xlabel: Percentage of Samples per Class + y : train_time + ylabel: Training Time (s) + y_scale : linear + hue_order: + - random + - svc + - knn + - sum + - medoid + - nearmiss + - hardness + errorbar: se + err_style: bars + xlim : [0, 1] + legend: {"title": "Sampling Method", "bbox_to_anchor": [1.05, .5], "loc" : "center left", "prop" : {"size" : 14}} + - file : sampling_method_vs_predict_time.pdf + hue: model.init.sampling_method + title: #"Prediction Time vs Sampling Method" + x : model.init.m + xlabel: Percentage of Samples per Class + y : predict_time + ylabel: Prediction Time (s) + y_scale : log + hue_order: + - random + - svc + - knn + - sum + - medoid + - nearmiss + - hardness + errorbar: se + err_style: bars + xlim : [0, 1] + legend: {"title": "Sampling Method", "bbox_to_anchor": [1.05, .5], "loc" : "center left", "prop" : {"size" : 14}} diff --git a/examples/gzip/conf/data/ddos.yaml b/examples/gzip/conf/data/ddos.yaml new file mode 100644 index 00000000..ed201a5e --- /dev/null +++ b/examples/gzip/conf/data/ddos.yaml @@ -0,0 +1,12 @@ +_target_: deckard.base.data.Data +name: raw_data/ddos_undersampled_10000.csv +target: 'Label' +drop: + - 'Timestamp' # Drop the timestamp column + - 'Unnamed: 0' # Drop the index column +sample: + random_state : 0 + train_size : 100 + test_size : 100 + stratify: True + shuffle : True diff --git a/examples/gzip/conf/data/default.yaml b/examples/gzip/conf/data/default.yaml new file mode 100644 index 00000000..e4aa937b --- /dev/null +++ b/examples/gzip/conf/data/default.yaml @@ -0,0 +1,3 @@ +defaults: + - ddos + diff --git a/examples/gzip/conf/data/kdd_nsl.yaml b/examples/gzip/conf/data/kdd_nsl.yaml new file mode 100644 index 00000000..48bc817b --- /dev/null +++ b/examples/gzip/conf/data/kdd_nsl.yaml @@ -0,0 +1,11 @@ +_target_: deckard.base.data.Data +drop: + - id +sample: + _target_: deckard.base.data.SklearnDataSampler + random_state : 0 + stratify: True + train_size : 100 + test_size : 100 +name: raw_data/kdd_nsl_undersampled_5000.csv +target: label diff --git a/examples/gzip/conf/data/sms_spam.yaml b/examples/gzip/conf/data/sms_spam.yaml new file mode 100644 index 00000000..5741cfb0 --- /dev/null +++ b/examples/gzip/conf/data/sms_spam.yaml @@ -0,0 +1,9 @@ +_target_: deckard.base.data.Data +name: raw_data/sms-spam_undersampled_1450.csv +target: 'label' +sample: + random_state : 0 + train_size : 100 + test_size : 100 + stratify: True + shuffle : True diff --git a/examples/gzip/conf/data/truthseeker.yaml b/examples/gzip/conf/data/truthseeker.yaml new file mode 100644 index 00000000..baa78bb3 --- /dev/null +++ b/examples/gzip/conf/data/truthseeker.yaml @@ -0,0 +1,9 @@ +_target_: deckard.base.data.Data +name: raw_data/truthseeker_undersampled_8000.csv +target: 'BotScoreBinary' +sample: + random_state : 0 + train_size : 100 + test_size : 100 + stratify: True + shuffle : True diff --git a/examples/gzip/conf/default.yaml b/examples/gzip/conf/default.yaml new file mode 100644 index 00000000..a0a93718 --- /dev/null +++ b/examples/gzip/conf/default.yaml @@ -0,0 +1,53 @@ +defaults: + # - _target_ : deckard.base.experiment.Experiment + - _self_ + - data: kdd_nsl + - model: default + - files: default + - scorers: default + - override hydra/sweeper : optuna + - override hydra/sweeper/sampler : grid + - override hydra/launcher : joblib +dataset : kdd_nsl +model_name : gzip_knn +stage : train +direction : + - maximize +optimizers: + - accuracy +device_id : ${oc.env:DECKARD_DEVICE_ID, "cpu"} +hydra: + run: + dir: ${files.directory}/logs/${stage}/ + sweep: + dir: ${files.directory}/logs/ + subdir : ${hydra.sweeper.study_name}/${hydra.job.id} + callbacks: + study_dump: + _target_ : database.OptunaStudyDumpCallback + storage : ${hydra.sweeper.storage} + study_name : ${hydra.sweeper.study_name} + directions : ${direction} + metric_names : ${optimizers} + output_file : ${files.directory}/${hydra.sweep.dir}/${hydra.sweeper.study_name}.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${model_name}_${dataset} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials : 1 + params: + direction: ${direction} + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: -1 + prefer : processes + verbose: 1 + timeout: null + pre_dispatch: n_jobs*2 + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r diff --git a/examples/gzip/conf/files/default.yaml b/examples/gzip/conf/files/default.yaml new file mode 100644 index 00000000..5c28f314 --- /dev/null +++ b/examples/gzip/conf/files/default.yaml @@ -0,0 +1,11 @@ +_target_: deckard.base.files.FileConfig +reports: reports +data_dir: data +# data_file : ${data.sample.random_state}-${data.sample.train_size} +data_type: .csv +model_dir : model +directory: ${dataset} +score_dict_file: score_dict.json +params_file : params.yaml +predictions_file : predictions.json +name : default diff --git a/examples/gzip/conf/gzip_knn.yaml b/examples/gzip/conf/gzip_knn.yaml new file mode 100644 index 00000000..da8b7ca5 --- /dev/null +++ b/examples/gzip/conf/gzip_knn.yaml @@ -0,0 +1,70 @@ +defaults: + # - _target_ : deckard.base.experiment.Experiment + - _self_ + - data: ??? + - model: gzip_knn + - files: default + - scorers: default + - override hydra/sweeper : optuna + - override hydra/sweeper/sampler : tpe + - override hydra/launcher : joblib +dataset : ??? +model_name : gzip_knn +stage : train +direction : + - maximize +optimizers: + - accuracy +device_id : ${oc.env:DECKARD_DEVICE_ID, "cpu"} +hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir : ${hydra.job.num} + callbacks: + study_dump: + _target_ : database.OptunaStudyDumpCallback + storage : ${hydra.sweeper.storage} + study_name : ${hydra.sweeper.study_name} + directions : ${direction} + metric_names : ${optimizers} + output_file : ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k : 1,3,5,7,11 + +model.init.weights : uniform,distance + +model.init.algorithm : brute + model.init.symmetric : True,False + ++model.init.precompute : True + model.init.metric : gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name : ${model_name} + ++data.sample.random_state: int(interval(1, 10000)) + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer : processes + verbose: 1 + timeout: null + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r diff --git a/examples/gzip/conf/gzip_logistic.yaml b/examples/gzip/conf/gzip_logistic.yaml new file mode 100644 index 00000000..3636c201 --- /dev/null +++ b/examples/gzip/conf/gzip_logistic.yaml @@ -0,0 +1,73 @@ +defaults: + # - _target_ : deckard.base.experiment.Experiment + - _self_ + - data: ??? + - model: gzip_logistic + - files: default + - scorers: default + - override hydra/sweeper : optuna + - override hydra/sweeper/sampler : tpe + - override hydra/launcher : joblib +dataset : ??? +model_name : gzip_logistic +stage : train +direction : + - maximize +optimizers: + - accuracy +device_id : ${oc.env:DECKARD_DEVICE_ID, "cpu"} +hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir : ${hydra.job.id} + callbacks: + study_dump: + _target_ : database.OptunaStudyDumpCallback + storage : ${hydra.sweeper.storage} + study_name : ${hydra.sweeper.study_name} + directions : ${direction} + metric_names : ${optimizers} + output_file : ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials : 1 + params: + +model.init.solver: saga + +model.init.penalty : l2,l1,l2,none + +model.init.tol : 1e-4,1e-3,1e-2 + +model.init.C : 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept : True,False + +model.init.class_weight : balanced,None + model.init.symmetric : True,False + ++model.init.precompute : True + model.init.metric : gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name : ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer : processes + verbose: 1 + timeout: null + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r diff --git a/examples/gzip/conf/gzip_svc.yaml b/examples/gzip/conf/gzip_svc.yaml new file mode 100644 index 00000000..42212998 --- /dev/null +++ b/examples/gzip/conf/gzip_svc.yaml @@ -0,0 +1,73 @@ +defaults: + # - _target_ : deckard.base.experiment.Experiment + - _self_ + - data: ??? + - model: gzip_svc + - files: default + - scorers: default + - override hydra/sweeper : optuna + - override hydra/sweeper/sampler : tpe + - override hydra/launcher : joblib +dataset : ??? +model_name : gzip_svc +stage : train +direction : + - maximize +optimizers: + - accuracy +device_id : ${oc.env:DECKARD_DEVICE_ID, "cpu"} +hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir : ${hydra.job.id} + callbacks: + study_dump: + _target_ : database.OptunaStudyDumpCallback + storage : ${hydra.sweeper.storage} + study_name : ${hydra.sweeper.study_name} + directions : + - maximize + metric_names : + - accuracy + output_file : ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials : 2 + params: + +model.init.kernel : rbf,precomputed + +model.init.C : 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma : scale,auto + +model.init.class_weight : balanced,null + model.init.symmetric : True,False + ++model.init.precompute : True + model.init.metric : gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name : ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer : processes + verbose: 1 + timeout: null + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r diff --git a/examples/gzip/conf/model/.gitignore b/examples/gzip/conf/model/.gitignore new file mode 100644 index 00000000..3101d5ea --- /dev/null +++ b/examples/gzip/conf/model/.gitignore @@ -0,0 +1,12 @@ +/best_gzip_knn_kdd_nsl.yaml +/best_gzip_svc_kdd_nsl.yaml +/best_gzip_logistic_kdd_nsl.yaml +/best_gzip_knn_truthseeker.yaml +/best_gzip_svc_truthseeker.yaml +/best_gzip_logistic_truthseeker.yaml +/best_gzip_knn_ddos.yaml +/best_gzip_svc_ddos.yaml +/best_gzip_logistic_ddos.yaml +/best_gzip_knn_sms_spam.yaml +/best_gzip_svc_sms_spam.yaml +/best_gzip_logistic_sms_spam.yaml diff --git a/examples/gzip/conf/model/default.yaml b/examples/gzip/conf/model/default.yaml new file mode 100644 index 00000000..1aa36bb4 --- /dev/null +++ b/examples/gzip/conf/model/default.yaml @@ -0,0 +1,2 @@ +defaults: + - gzip_knn.yaml diff --git a/examples/gzip/conf/model/gzip_knn.yaml b/examples/gzip/conf/model/gzip_knn.yaml new file mode 100644 index 00000000..fc926aaf --- /dev/null +++ b/examples/gzip/conf/model/gzip_knn.yaml @@ -0,0 +1,11 @@ +data: ${data} +library : sklearn +init: + _target_: deckard.base.model.ModelInitializer + name : gzip_classifier.GzipKNN + k : 1 + m: -1 + metric : gzip + symmetric : false + distance_matrix : ${files.directory}/${files.model_dir}/${model.init.metric}/${data.sample.train_size}-${data.sample.test_size}/${data.sample.random_state}.npz +_target_: deckard.base.model.Model diff --git a/examples/gzip/conf/model/gzip_logistic.yaml b/examples/gzip/conf/model/gzip_logistic.yaml new file mode 100644 index 00000000..ea95121c --- /dev/null +++ b/examples/gzip/conf/model/gzip_logistic.yaml @@ -0,0 +1,10 @@ +data: ${data} +library : sklearn +init: + _target_: deckard.base.model.ModelInitializer + name : gzip_classifier.GzipLogisticRegressor + m: -1 + metric : gzip + symmetric : false + distance_matrix : ${files.directory}/${files.model_dir}/${model.init.metric}/${data.sample.train_size}-${data.sample.test_size}/${data.sample.random_state}.npz +_target_: deckard.base.model.Model diff --git a/examples/gzip/conf/model/gzip_svc.yaml b/examples/gzip/conf/model/gzip_svc.yaml new file mode 100644 index 00000000..58111a99 --- /dev/null +++ b/examples/gzip/conf/model/gzip_svc.yaml @@ -0,0 +1,10 @@ +data: ${data} +library : sklearn +init: + _target_: deckard.base.model.ModelInitializer + name : gzip_classifier.GzipSVC + m: -1 + distance_matrix : ${files.directory}/${files.model_dir}/${model.init.metric}/${data.sample.train_size}-${data.sample.test_size}/${data.sample.random_state}.npz + metric : gzip + symmetric : false +_target_: deckard.base.model.Model diff --git a/examples/gzip/conf/plots.yaml b/examples/gzip/conf/plots.yaml new file mode 100644 index 00000000..eac757c4 --- /dev/null +++ b/examples/gzip/conf/plots.yaml @@ -0,0 +1,169 @@ +line_plot: +- file: metric_vs_accuracy.pdf + hue: model.init.metric + title: #"Accuracy vs $m$-best samples" + x: data.sample.train_size + xlabel: Number of Training Samples + y: accuracy + ylabel: Accuracy + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: [10, 500] + legend: {"title": "Metrics", "bbox_to_anchor": [1.05, .5], "loc" : "center left", "prop" : {"size" : 14}} +- file: metric_vs_train_time.pdf + hue: model.init.metric + title: #"Training Time vs $m$-best samples" + x: data.sample.train_size + xlabel: Number of Training Samples + y: train_time + ylabel: Training Time (s) + y_scale: linear + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: [10, 500] + legend: {"title": "Metrics", "bbox_to_anchor": [1.05, .5], "loc" : "center left", "prop" : {"size" : 14}} +- file: metric_vs_predict_time.pdf + hue: model.init.metric + title: #"Prediction Time vs $m$-best samples" + x: data.sample.train_size + xlabel: Number of Training Samples + y: predict_time + ylabel: Prediction Time (s) + y_scale: linear + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: [10, 500] + legend: {"title": "Metrics", "bbox_to_anchor": [1.05, .5], "loc" : "center left", "prop" : {"size" : 14}} +cat_plot: + - file: symmetric_vs_metric.pdf + x : model.init.symmetric + y : accuracy + hue : model.init.metric + errorbar: se + kind : bar + titles : + xlabels : "" + ylabels : Accuracy + legend_title: "Metrics" + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: {"bbox_to_anchor": [1.05, .5], "loc" : "center left", "prop" : {"size" : 14}} + set: + yscale: linear + ylim: [0, 1] + - file: symmetric_vs_metric_train_time.pdf + x : model.init.symmetric + y : train_time + hue : model.init.metric + errorbar: se + kind : bar + titles : + xlabels : "" + ylabels : Training Time (s) + legend_title: "Metrics" + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: {"bbox_to_anchor": [1.05, .5], "loc" : "center left", "prop" : {"size" : 14}} + set: + yscale: log + - file: models_vs_accuracy.pdf + x : model_name + y : accuracy + hue : data.sample.train_size + errorbar: se + kind : boxen + titles : + xlabels : Model + ylabels : Accuracy + legend_title: "Samples" + + legend: {"bbox_to_anchor": [1.05, .5], "loc" : "center left", "prop" : {"size" : 14}} + set: + yscale: linear + ylim: [0, 1] + rotation: 90 + - file: models_vs_train_time.pdf + x : model_name + y : accuracy + hue : data.sample.train_size + errorbar: se + kind : bar + titles : + xlabels : Model + ylabels : Training Time (s) + legend_title: "Samples" + rotation: 90 + legend: {"bbox_to_anchor": [1.05, .5], "loc" : "center left", "prop" : {"size" : 14}} + set: + yscale: log + - file: models_vs_predict_time.pdf + x : model_name + y : accuracy + hue : data.sample.train_size + errorbar: se + kind : bar + titles : + xlabels : Model + ylabels : Prediction Time (s) + legend_title: "Samples" + + legend: {"bbox_to_anchor": [1.05, .5], "loc" : "center left", "prop" : {"size" : 14}} + set: + yscale: log + rotation: 90 diff --git a/examples/gzip/conf/scorers/default.yaml b/examples/gzip/conf/scorers/default.yaml new file mode 100644 index 00000000..108c1520 --- /dev/null +++ b/examples/gzip/conf/scorers/default.yaml @@ -0,0 +1,10 @@ +_target_: deckard.base.scorer.ScorerDict +accuracy: + _target_: deckard.base.scorer.ScorerConfig + name: sklearn.metrics.accuracy_score + direction: maximize + +log_loss: + _target_: deckard.base.scorer.ScorerConfig + name: sklearn.metrics.log_loss + direction: minimize diff --git a/examples/gzip/conf/scorers/regression.yaml b/examples/gzip/conf/scorers/regression.yaml new file mode 100644 index 00000000..0ff16a7c --- /dev/null +++ b/examples/gzip/conf/scorers/regression.yaml @@ -0,0 +1,13 @@ +_target_: deckard.base.scorer.ScorerDict +explained_variance: + _target_: deckard.base.scorer.ScorerConfig + name: sklearn.metrics.explained_variance_score + direction: maximize +r2: + _target_: deckard.base.scorer.ScorerConfig + name: sklearn.metrics.r2_score + direction: maximize +mse: + _target_: deckard.base.scorer.ScorerConfig + name: sklearn.metrics.mean_squared_error + direction: minimize diff --git a/examples/gzip/data_prep.py b/examples/gzip/data_prep.py new file mode 100644 index 00000000..9ab72bb8 --- /dev/null +++ b/examples/gzip/data_prep.py @@ -0,0 +1,145 @@ +import pandas as pd +from pathlib import Path +import logging +from imblearn.under_sampling import RandomUnderSampler + +try: + import plotext as plt + + plot = True +except ImportError: + plot = False + +logger = logging.getLogger(__name__) +if plot is False: + logger.warning("plotext not installed. Skipping plots.") + + +def undersample(df, target, n_samples=10000): + """ + Undersamples the dataframe to balance the target column + """ + y = df[target] + X = df.drop(target, axis=1) + n_classes = y.value_counts().shape[0] + keys = y.value_counts().keys() + values = [n_samples // n_classes] * len(keys) + sampling_strategy = dict(zip(keys, values)) + rus = RandomUnderSampler(random_state=0, sampling_strategy=sampling_strategy) + X_resampled, y_resampled = rus.fit_resample(X, y) + df_resampled = pd.concat([X_resampled, y_resampled], axis=1) + return df_resampled + + +def undersample_datasets(datasets: list, targets: list, n_samples: list): + """ + Undersamples the datasets to balance the target columns + """ + assert len(datasets) == len( + targets, + ), "The number of datasets and targets must be the same" + for i in range(len(datasets)): + path = Path(datasets[i]) + print(f"Undersampling {path.as_posix()}") + df = pd.read_csv(datasets[i]) + df = undersample(df, targets[i], n_samples[i]) + new_name = path.stem + f"_undersampled_{n_samples[i]}.csv" + new_name = path.parent / new_name + print(f"Renaming to {new_name}") + Path(new_name).parent.mkdir(parents=True, exist_ok=True) + df.to_csv(new_name, index=False) + print(f"Saved to {new_name}") + + +if __name__ == "__main__": + Path("raw_data").mkdir(parents=True, exist_ok=True) + df = pd.read_csv( + "https://gist.githubusercontent.com/simplymathematics/8c6c04bd151950d5ea9e62825db97fdd/raw/34e546e4813f154d11d4f13869b9e3481fc3e829/kdd_nsl.csv", + ) + del df["difficulty_level"] + X = df.drop("label", axis=1) + y = df["label"] + y = pd.DataFrame(y, columns=["label"]) + df = pd.concat([X, y], axis=1) + df.to_csv("raw_data/kdd_nsl.csv", index=False) + # Find the number of entries for each label + counts = pd.DataFrame(df["label"]).value_counts().values + labels = range(len(counts)) + # Plot the counts + if plot is True: + plt.simple_bar(labels, counts, title="KDD NSL Label Counts", width=50) + plt.show() + else: + logger.info("Label counts for KDD NSL: {}".format(counts)) + df = pd.read_csv( + "https://gist.githubusercontent.com/simplymathematics/8c6c04bd151950d5ea9e62825db97fdd/raw/34e546e4813f154d11d4f13869b9e3481fc3e829/truthseeker.csv", + ) + X = df["tweet"] + label = "BotScoreBinary" + y = df[label] + df = pd.concat([X, y], axis=1) + df.to_csv("raw_data/truthseeker.csv", index=False) + # Find the number of entries for each label + counts = pd.DataFrame(df[label]).value_counts().values + labels = range(len(counts)) + if plot is True: + # Plot the counts + plt.simple_bar(labels, counts, title="Truthseeker Label Counts", width=50) + plt.show() + else: + logger.info("Label counts for Truthseeker: {}".format(counts)) + df = pd.read_csv( + "https://gist.githubusercontent.com/simplymathematics/8c6c04bd151950d5ea9e62825db97fdd/raw/c91944733b8f2b9a6ac0b8c8fab01ddcdf0898eb/sms-spam.csv", + ) + X = df["message"] + y = df["label"] + y = y.str.replace("ham", "0").replace("spam", "1") + df = pd.concat([X, y], axis=1) + df.to_csv("raw_data/sms-spam.csv", index=False) + # Find the number of entries for each label + counts = pd.DataFrame(df["label"]).value_counts().values + labels = range(len(counts)) + # Plot the counts + if plot is True: + plt.simple_bar(labels, counts, title="SMS Spam Label Counts", width=50) + plt.show() + else: + logger.info("Label counts for SMS Spam: {}".format(counts)) + df = pd.read_csv( + "https://gist.githubusercontent.com/simplymathematics/8c6c04bd151950d5ea9e62825db97fdd/raw/712b528dcd212d5a6d1767332f50161fc1cfe55c/ddos.csv", + ) + # Find the number of entries for each label + X = df.drop("Label", axis=1) + y = df["Label"] + y = y.str.replace("Benign", "0").replace("ddos", "1") + df = pd.concat([X, y], axis=1) + df.to_csv("raw_data/ddos.csv", index=False) + counts = pd.DataFrame(y).value_counts().values + labels = range(len(counts)) + # Plot the counts + if plot is True: + plt.simple_bar(labels, counts, title="DDoS Label Counts", width=50) + plt.show() + else: + logger.info("Label counts for DDoS: {}".format(counts)) + + datasets = [ + "raw_data/kdd_nsl.csv", + "raw_data/truthseeker.csv", + "raw_data/sms-spam.csv", + "raw_data/ddos.csv", + ] + targets = [ + "label", # kdd_nsl + "BotScoreBinary", # truthseeker + "label", # sms_spam + "Label", # ddos + ] + n_samples = [ + 5000, # kdd_nsl + 8000, # truthseeker + 1450, # sms_spam + 10000, # ddos + ] + + paths = undersample_datasets(datasets, targets, n_samples) diff --git a/examples/gzip/database.py b/examples/gzip/database.py new file mode 100644 index 00000000..7670a911 --- /dev/null +++ b/examples/gzip/database.py @@ -0,0 +1,126 @@ +# Script to query the database + +from omegaconf import DictConfig, ListConfig, OmegaConf +from dataclasses import dataclass +import optuna +from pathlib import Path +from hydra.experimental.callback import Callback +import argparse + +storage = "sqlite:///optuna.db" +study_name = "gzip_knn_20-0" +metric_names = ["accuracy"] +directions = ["maximize"] +output_file = "optuna.csv" + + +@dataclass +class OptunaStudyDumpCallback(Callback): + def __init__( + self, + storage: str, + study_name: str, + metric_names: list, + directions: list, + output_file: str, + seed=42, + ): + self.storage = storage + self.study_name = study_name + if isinstance(metric_names, ListConfig): + self.metric_names = OmegaConf.to_container(metric_names, resolve=True) + elif isinstance(metric_names, list): + self.metric_names = metric_names + else: + self.metric_names = [metric_names] + if isinstance(directions, ListConfig): + self.metric_names = OmegaConf.to_container(directions, resolve=True) + elif isinstance(directions, list): + self.directions = directions + else: + self.directions = [directions] + self.output_file = output_file + super().__init__() + + def on_multirun_start(self, config: DictConfig, **kwargs) -> None: + studies = optuna.get_all_study_names(self.storage) + study_names = [study for study in studies] + # study_names = [study.study_name for study in studies] + assert ( + self.study_name in study_names + ), f"Study {self.study_name} not found in {study_names}" + study = optuna.load_study(self.study_name, storage=self.storage) + if hasattr(study, "set_metric_names"): + study.set_metric_names(self.metric_names) + else: + print("Cannot set metric names") + + def on_multirun_end(self, *args, **kwargs) -> None: + studies = optuna.get_all_study_names(self.storage) + study_names = [study for study in studies] + assert ( + self.study_name in study_names + ), f"Study {self.study_name} not found in {study_names}" + study = optuna.load_study(self.study_name, storage=self.storage) + df = study.trials_dataframe() + if len(self.metric_names) == 1: + metric_names = [f"value_{metric}" for metric in self.metric_names] + df = df.sort_values(metric_names[0], ascending=False) + else: + metric_names = [f"values_{metric}" for metric in self.metric_names] + df = df.sort_values(metric_names, ascending=False) + suffix = Path(self.output_file).suffix + if suffix in [".csv"]: + df.to_csv(self.output_file, index=False) + elif suffix in [".json"]: + df.to_json(self.output_file, orient="records") + else: + raise ValueError(f"Unknown file type {suffix}") + + assert Path(self.output_file).exists(), f"File {self.output_file} not found" + + +def multirun_call(args): + storage = args.storage + study_name = args.study_name + metric_names = ( + args.metric_names + if isinstance(args.metric_names, list) + else [args.metric_names] + ) + directions = ( + args.directions if isinstance(args.directions, list) else [args.directions] + ) + output_file = args.output_file + + callback = OptunaStudyDumpCallback( + storage, + study_name, + metric_names, + directions, + output_file, + ) + callback.on_multirun_start() + callback.on_multirun_end() + + +optuna_callback_parser = argparse.ArgumentParser() +optuna_callback_parser.add_argument("--storage", type=str, default=storage) +optuna_callback_parser.add_argument("--study_name", type=str, default=study_name) +optuna_callback_parser.add_argument( + "--metric_names", + type=str, + nargs="+", + default=metric_names, +) +optuna_callback_parser.add_argument( + "--directions", + type=str, + nargs="+", + default=directions, +) +optuna_callback_parser.add_argument("--output_file", type=str, default=output_file) + +if __name__ == "__main__": + args = optuna_callback_parser.parse_args() + multirun_call(args) diff --git a/examples/gzip/dvc.lock b/examples/gzip/dvc.lock new file mode 100644 index 00000000..a02a4b1d --- /dev/null +++ b/examples/gzip/dvc.lock @@ -0,0 +1,19910 @@ +schema: '2.0' +stages: + train: + cmd: python -m deckard.layers.experiment train + deps: + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + - path: raw_data/ + hash: md5 + md5: 33d46673e0631bef98be9e8991ed1ed1.dir + size: 50328647 + nfiles: 8 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/reports/train/default/predictions.json + hash: md5 + md5: 986d2f0abe9b96253b196a222a550609 + size: 702 + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + test_each_method@knn-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=knn model.init.m=10 files.name=knn + files.directory=kdd_nsl data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn hydra.run.dir=kdd_nsl/logs/method/knn + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: f8a4019adc566855c2a704a0311ff7c4 + size: 489 + - path: params.yaml + hash: md5 + md5: f6a5538a55c3c37d8a2d6d1d4eb95ec2 + size: 1467 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/method/knn + hash: md5 + md5: f902bdd8882aa06bba0d1fef19c4a313.dir + size: 11613 + nfiles: 4 + - path: kdd_nsl/reports/train/knn/score_dict.json + hash: md5 + md5: 4e7f0750779df5202e5dec6228f94f99 + size: 490 + test_each_method@knn-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=knn model.init.m=10 files.name=knn + files.directory=truthseeker data=truthseeker dataset=truthseeker model_name=gzip_knn + hydra.run.dir=truthseeker/logs/method/knn ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: f8a4019adc566855c2a704a0311ff7c4 + size: 489 + - path: params.yaml + hash: md5 + md5: f6a5538a55c3c37d8a2d6d1d4eb95ec2 + size: 1467 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/logs/method/knn + hash: md5 + md5: 5a52da2681ff444c53a1623722c2d431.dir + size: 11642 + nfiles: 4 + - path: truthseeker/reports/train/knn/score_dict.json + hash: md5 + md5: f09f746efa5c7a56f4dd1a3e20a7ab6b + size: 485 + test_each_method@svc-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=svc model.init.m=10 files.name=svc + files.directory=kdd_nsl data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn hydra.run.dir=kdd_nsl/logs/method/svc + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: f8a4019adc566855c2a704a0311ff7c4 + size: 489 + - path: params.yaml + hash: md5 + md5: f6a5538a55c3c37d8a2d6d1d4eb95ec2 + size: 1467 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/method/svc + hash: md5 + md5: 433b30d37ba64e71527ac2d837b44fa2.dir + size: 11612 + nfiles: 4 + - path: kdd_nsl/reports/train/svc/score_dict.json + hash: md5 + md5: f41538adb6ffa9182ea126c85c353abf + size: 489 + test_each_method@svc-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=svc model.init.m=10 files.name=svc + files.directory=truthseeker data=truthseeker dataset=truthseeker model_name=gzip_knn + hydra.run.dir=truthseeker/logs/method/svc ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: f8a4019adc566855c2a704a0311ff7c4 + size: 489 + - path: params.yaml + hash: md5 + md5: f6a5538a55c3c37d8a2d6d1d4eb95ec2 + size: 1467 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/logs/method/svc + hash: md5 + md5: bc37655235ef0d2919a62c85456d379c.dir + size: 11645 + nfiles: 4 + - path: truthseeker/reports/train/svc/score_dict.json + hash: md5 + md5: 97f1fed3ee2887773ca9a50eeeb5b1ed + size: 488 + test_each_method@medoid-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=medoid model.init.m=10 files.name=medoid + files.directory=kdd_nsl data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn hydra.run.dir=kdd_nsl/logs/method/medoid + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: f8a4019adc566855c2a704a0311ff7c4 + size: 489 + - path: params.yaml + hash: md5 + md5: f6a5538a55c3c37d8a2d6d1d4eb95ec2 + size: 1467 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/method/medoid + hash: md5 + md5: 5b972c1f6a8c4ebff94a088e2be12b28.dir + size: 11661 + nfiles: 4 + - path: kdd_nsl/reports/train/medoid/score_dict.json + hash: md5 + md5: 10a0913632dea0d6717263ba1854b1e2 + size: 484 + test_each_method@medoid-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=medoid model.init.m=10 files.name=medoid + files.directory=truthseeker data=truthseeker dataset=truthseeker model_name=medoid + hydra.run.dir=truthseeker/logs/method/medoid ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 064e5bb42979e36c917c538b2a7bc0cc + size: 489 + - path: params.yaml + hash: md5 + md5: 8e937140db56a135e97c05461c573520 + size: 1345 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/logs/method/medoid + hash: md5 + md5: 7b6fef8487e5b8dec0f76f4b4fc59ccb.dir + size: 10226 + nfiles: 4 + - path: truthseeker/reports/train/medoid/score_dict.json + hash: md5 + md5: 8cebb3ee0098d2ee2bb4130e346e8e0f + size: 282 + test_each_method@sum-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=sum model.init.m=10 files.name=sum + files.directory=kdd_nsl data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn hydra.run.dir=kdd_nsl/logs/method/sum + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: f8a4019adc566855c2a704a0311ff7c4 + size: 489 + - path: params.yaml + hash: md5 + md5: f6a5538a55c3c37d8a2d6d1d4eb95ec2 + size: 1467 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/method/sum + hash: md5 + md5: 41cd7632a1d85e7380d14b0e8eccc819.dir + size: 11607 + nfiles: 4 + - path: kdd_nsl/reports/train/sum/score_dict.json + hash: md5 + md5: 2a97e468ea2e9071e1f7d5bdb1e7495b + size: 484 + test_each_method@sum-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=sum model.init.m=10 files.name=sum + files.directory=truthseeker data=truthseeker dataset=truthseeker model_name=sum + hydra.run.dir=truthseeker/logs/method/sum ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 064e5bb42979e36c917c538b2a7bc0cc + size: 489 + - path: params.yaml + hash: md5 + md5: 8e937140db56a135e97c05461c573520 + size: 1345 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/logs/method/sum + hash: md5 + md5: e7f9741f777d98f3d3416264b9f3e6b2.dir + size: 10164 + nfiles: 4 + - path: truthseeker/reports/train/sum/score_dict.json + hash: md5 + md5: d49a3cbdeb348bbf9ad3b59e9e8e0e32 + size: 283 + test_each_method@random-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=random model.init.m=10 files.name=random + files.directory=kdd_nsl data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn hydra.run.dir=kdd_nsl/logs/method/random + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: f8a4019adc566855c2a704a0311ff7c4 + size: 489 + - path: params.yaml + hash: md5 + md5: f6a5538a55c3c37d8a2d6d1d4eb95ec2 + size: 1467 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/method/random + hash: md5 + md5: 723e8c93428a09edb21943a20fca5c3c.dir + size: 11639 + nfiles: 4 + - path: kdd_nsl/reports/train/random/score_dict.json + hash: md5 + md5: ed402e68904e8888b8ba6b0bebf6fa05 + size: 488 + test_each_method@random-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=random model.init.m=10 files.name=random + files.directory=truthseeker data=truthseeker dataset=truthseeker model_name=gzip_knn + hydra.run.dir=truthseeker/logs/method/random ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: f8a4019adc566855c2a704a0311ff7c4 + size: 489 + - path: params.yaml + hash: md5 + md5: f6a5538a55c3c37d8a2d6d1d4eb95ec2 + size: 1467 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/logs/method/random + hash: md5 + md5: f785fe50b4007a169c37e6e9cb856268.dir + size: 11670 + nfiles: 4 + - path: truthseeker/reports/train/random/score_dict.json + hash: md5 + md5: 8bfb4b2efa55e9944cec7331401762f9 + size: 485 + prepare_distance_matrices@0-10-kdd_nsl: + cmd: python -m deckard.layers.optimise files.name=0-10 stage=train data=kdd_nsl + dataset=kdd_nsl data.sample.random_state=0 data.sample.train_size=10 dataset=kdd_nsl + files.directory=kdd_nsl model_name=gzip_classifier model=gzip_classifier model.init.distance_matrix=kdd_nsl/model/gzip_classifier/gzip/0-10.npz + model.init.method=random model.init.m=100 ++raise_exception=True + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 3332d80113acf55f8e69e46aea82a1cc + size: 412 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: + https://gist.githubusercontent.com/simplymathematics/8c6c04bd151950d5ea9e62825db97fdd/raw/d6a22cdb42a1db624c89f0298cb4f654d3812703/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: + https://gist.githubusercontent.com/simplymathematics/8c6c04bd151950d5ea9e62825db97fdd/raw/d6a22cdb42a1db624c89f0298cb4f654d3812703/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: kdd_nsl/model/gzip_classifier/gzip/0-100.npz + k: 1 + m: -1 + method: + name: gzip_classifier.GzipClassifier + library: sklearn + model_name: gzip_classifier + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/model/gzip_classifier/gzip/0-10.npz + hash: md5 + md5: 1b745ff8dbc88f247f3245d9efd6de7e + size: 208 + - path: kdd_nsl/reports/train/0-10/score_dict.json + hash: md5 + md5: cae521db2dcda14d0d3ed880c26adf62 + size: 233 + prepare_distance_matrices@0-100-kdd_nsl: + cmd: python -m deckard.layers.optimise files.name=0-100 stage=train data=kdd_nsl + dataset=kdd_nsl data.sample.random_state=0 data.sample.train_size=100 dataset=kdd_nsl + files.directory=kdd_nsl model_name=gzip_classifier model=gzip_classifier model.init.distance_matrix=kdd_nsl/model/gzip_classifier/gzip/0-100.npz + model.init.method=random model.init.m=100 ++raise_exception=True + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 222b4b55b1b16639ce30218bf60c1f32 + size: 412 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: + https://gist.githubusercontent.com/simplymathematics/8c6c04bd151950d5ea9e62825db97fdd/raw/d6a22cdb42a1db624c89f0298cb4f654d3812703/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + data: + cmd: python data_prep.py + deps: + - path: data_prep.py + hash: md5 + md5: 18244c921ed2d7cbf25b8362b3ca33aa + size: 5146 + outs: + - path: raw_data/ + hash: md5 + md5: 33d46673e0631bef98be9e8991ed1ed1.dir + size: 50328647 + nfiles: 8 + test_symmetric_methods@true-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train model.init.method=random + model.init.m=10 files.name=symmetric_true files.directory=kdd_nsl data=kdd_nsl + dataset=kdd_nsl model_name=gzip_knn model.init.symmetric=true hydra.run.dir=kdd_nsl/logs/symmetric/true + model.init.distance_matrix=kdd_nsl/model/gzip_knn/None/symmetric_true.npz ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + - path: raw_data/ + hash: md5 + md5: d897229dd67895957a0a4330ce95b09a.dir + size: 42279674 + nfiles: 4 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/model/gzip_knn/None/symmetric_true.npz + hash: md5 + md5: 1b745ff8dbc88f247f3245d9efd6de7e + size: 208 + - path: kdd_nsl/reports/train/symmetric_true/score_dict.json + hash: md5 + md5: bb10a010ac3f8790cdbe4310288efc63 + size: 432 + test_symmetric_methods@true-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train model.init.method=random + model.init.m=10 files.name=symmetric_true files.directory=truthseeker data=truthseeker + dataset=truthseeker model_name=gzip_knn model.init.symmetric=true hydra.run.dir=truthseeker/logs/symmetric/true + model.init.distance_matrix=truthseeker/model/gzip_knn/None/symmetric_true.npz + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + - path: raw_data/ + hash: md5 + md5: d897229dd67895957a0a4330ce95b09a.dir + size: 42279674 + nfiles: 4 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/model/gzip_knn/None/symmetric_true.npz + hash: md5 + md5: f71a2727e708fdfb7867a6983f3aa8cf + size: 223 + - path: truthseeker/reports/train/symmetric_true/score_dict.json + hash: md5 + md5: 6d7a4eb01733e4e2fda1c40b5562646c + size: 434 + test_symmetric_methods@true-sms_spam: + cmd: 'python -m deckard.layers.optimise stage=train model.init.method=random + model.init.m=10 files.name=symmetric_true files.directory=sms_spam data=sms_spam + dataset=sms_spam model_name=gzip_knn model.init.symmetric=true hydra.run.dir=sms_spam/logs/symmetric/true + model.init.distance_matrix=sms_spam/model/gzip_knn/None/symmetric_true.npz ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + - path: raw_data/ + hash: md5 + md5: d897229dd67895957a0a4330ce95b09a.dir + size: 42279674 + nfiles: 4 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: sms_spam/model/gzip_knn/None/symmetric_true.npz + hash: md5 + md5: 1b745ff8dbc88f247f3245d9efd6de7e + size: 208 + - path: sms_spam/reports/train/symmetric_true/score_dict.json + hash: md5 + md5: 0b8d690ffca7173942d490a2f0cbeec4 + size: 432 + test_symmetric_methods@true-ddos: + cmd: 'python -m deckard.layers.optimise stage=train model.init.method=random + model.init.m=10 files.name=symmetric_true files.directory=ddos data=ddos dataset=ddos + model_name=gzip_knn model.init.symmetric=true hydra.run.dir=ddos/logs/symmetric/true + model.init.distance_matrix=ddos/model/gzip_knn/None/symmetric_true.npz ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + - path: raw_data/ + hash: md5 + md5: d897229dd67895957a0a4330ce95b09a.dir + size: 42279674 + nfiles: 4 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/model/gzip_knn/None/symmetric_true.npz + hash: md5 + md5: 1b745ff8dbc88f247f3245d9efd6de7e + size: 208 + - path: ddos/reports/train/symmetric_true/score_dict.json + hash: md5 + md5: 2c12176f8bf7355f284e059b2527cf44 + size: 418 + test_symmetric_methods@false-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train model.init.method=random + model.init.m=10 files.name=symmetric_false files.directory=kdd_nsl data=kdd_nsl + dataset=kdd_nsl model_name=gzip_knn model.init.symmetric=false hydra.run.dir=kdd_nsl/logs/symmetric/false + model.init.distance_matrix=kdd_nsl/model/gzip_knn/None/symmetric_false.npz ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + - path: raw_data/ + hash: md5 + md5: d897229dd67895957a0a4330ce95b09a.dir + size: 42279674 + nfiles: 4 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/model/gzip_knn/None/symmetric_false.npz + hash: md5 + md5: 9a9fcf9ba5dbc34eb2ca1f203088fc47 + size: 740 + - path: kdd_nsl/reports/train/symmetric_false/score_dict.json + hash: md5 + md5: 8ae56e642565330a37e731472a6c2d76 + size: 429 + test_symmetric_methods@false-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train model.init.method=random + model.init.m=10 files.name=symmetric_false files.directory=truthseeker data=truthseeker + dataset=truthseeker model_name=gzip_knn model.init.symmetric=false hydra.run.dir=truthseeker/logs/symmetric/false + model.init.distance_matrix=truthseeker/model/gzip_knn/None/symmetric_false.npz + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + - path: raw_data/ + hash: md5 + md5: d897229dd67895957a0a4330ce95b09a.dir + size: 42279674 + nfiles: 4 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/model/gzip_knn/None/symmetric_false.npz + hash: md5 + md5: b02cc76ddfb10d1e0e63e0f6e05cdaae + size: 1791 + - path: truthseeker/reports/train/symmetric_false/score_dict.json + hash: md5 + md5: 4ef36cb0b198d778dc8e0e6ff282d778 + size: 433 + test_symmetric_methods@false-sms_spam: + cmd: 'python -m deckard.layers.optimise stage=train model.init.method=random + model.init.m=10 files.name=symmetric_false files.directory=sms_spam data=sms_spam + dataset=sms_spam model_name=gzip_knn model.init.symmetric=false hydra.run.dir=sms_spam/logs/symmetric/false + model.init.distance_matrix=sms_spam/model/gzip_knn/None/symmetric_false.npz + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + - path: raw_data/ + hash: md5 + md5: d897229dd67895957a0a4330ce95b09a.dir + size: 42279674 + nfiles: 4 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: sms_spam/model/gzip_knn/None/symmetric_false.npz + hash: md5 + md5: ac71e5af3607731b783a490caf81c37f + size: 694 + - path: sms_spam/reports/train/symmetric_false/score_dict.json + hash: md5 + md5: 66d92f0ed630b08fbddb1a9c07f13981 + size: 432 + test_symmetric_methods@false-ddos: + cmd: 'python -m deckard.layers.optimise stage=train model.init.method=random + model.init.m=10 files.name=symmetric_false files.directory=ddos data=ddos dataset=ddos + model_name=gzip_knn model.init.symmetric=false hydra.run.dir=ddos/logs/symmetric/false + model.init.distance_matrix=ddos/model/gzip_knn/None/symmetric_false.npz ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + - path: raw_data/ + hash: md5 + md5: d897229dd67895957a0a4330ce95b09a.dir + size: 42279674 + nfiles: 4 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/model/gzip_knn/None/symmetric_false.npz + hash: md5 + md5: 0d3f08d9c6cb8ddc6d3e68f8208c9bc5 + size: 821 + - path: ddos/reports/train/symmetric_false/score_dict.json + hash: md5 + md5: ba81be29d56943d6d573597c93ba8081 + size: 412 + test_each_compressor@gzip-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train files.name=gzip files.directory=kdd_nsl + data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn model.init.method=random model.init.distance_matrix=kdd_nsl/model/gzip_knn/None/gzip.npz + model.init.compressor=gzip model.init.m=10 hydra.run.dir=kdd_nsl/logs/compressor/gzip + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/reports/train/gzip/score_dict.json + hash: md5 + md5: b3f76b5e7fe68821d9336c4968888b08 + size: 431 + test_each_compressor@gzip-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train files.name=gzip files.directory=truthseeker + data=truthseeker dataset=truthseeker model_name=gzip_knn model.init.method=random + model.init.distance_matrix=truthseeker/model/gzip_knn/None/gzip.npz model.init.compressor=gzip model.init.m=10 + hydra.run.dir=truthseeker/logs/compressor/gzip ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/reports/train/gzip/score_dict.json + hash: md5 + md5: df9b8a302dfb3b85b5c3c7623d86383e + size: 434 + test_each_compressor@gzip-sms_spam: + cmd: 'python -m deckard.layers.optimise stage=train files.name=gzip files.directory=sms_spam + data=sms_spam dataset=sms_spam model_name=gzip_knn model.init.method=random + model.init.distance_matrix=sms_spam/model/gzip_knn/None/gzip.npz model.init.compressor=gzip model.init.m=10 + hydra.run.dir=sms_spam/logs/compressor/gzip ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: sms_spam/reports/train/gzip/score_dict.json + hash: md5 + md5: 39a6710366ed557259ef981fc0b45a6a + size: 432 + test_each_compressor@gzip-ddos: + cmd: 'python -m deckard.layers.optimise stage=train files.name=gzip files.directory=ddos + data=ddos dataset=ddos model_name=gzip_knn model.init.method=random model.init.distance_matrix=ddos/model/gzip_knn/None/gzip.npz + model.init.compressor=gzip model.init.m=10 hydra.run.dir=ddos/logs/compressor/gzip + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/reports/train/gzip/score_dict.json + hash: md5 + md5: 1919cb29d6196b8dd14c01458e341a6b + size: 414 + test_each_compressor@zstd-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train files.name=zstd files.directory=kdd_nsl + data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn model.init.method=random model.init.distance_matrix=kdd_nsl/model/gzip_knn/None/zstd.npz + model.init.compressor=zstd model.init.m=10 hydra.run.dir=kdd_nsl/logs/compressor/zstd + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/reports/train/zstd/score_dict.json + hash: md5 + md5: 868509c201cbb0093818357427896da7 + size: 416 + test_each_compressor@zstd-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train files.name=zstd files.directory=truthseeker + data=truthseeker dataset=truthseeker model_name=gzip_knn model.init.method=random + model.init.distance_matrix=truthseeker/model/gzip_knn/None/zstd.npz model.init.compressor=zstd model.init.m=10 + hydra.run.dir=truthseeker/logs/compressor/zstd ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/reports/train/zstd/score_dict.json + hash: md5 + md5: 89546ca3a3510fd73671341863c69cb9 + size: 434 + test_each_compressor@zstd-sms_spam: + cmd: 'python -m deckard.layers.optimise stage=train files.name=zstd files.directory=sms_spam + data=sms_spam dataset=sms_spam model_name=gzip_knn model.init.method=random + model.init.distance_matrix=sms_spam/model/gzip_knn/None/zstd.npz model.init.compressor=zstd model.init.m=10 + hydra.run.dir=sms_spam/logs/compressor/zstd ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: sms_spam/reports/train/zstd/score_dict.json + hash: md5 + md5: e5a10b0013b032b22dd6cc596a7810bb + size: 429 + test_each_compressor@zstd-ddos: + cmd: 'python -m deckard.layers.optimise stage=train files.name=zstd files.directory=ddos + data=ddos dataset=ddos model_name=gzip_knn model.init.method=random model.init.distance_matrix=ddos/model/gzip_knn/None/zstd.npz + model.init.compressor=zstd model.init.m=10 hydra.run.dir=ddos/logs/compressor/zstd + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/reports/train/zstd/score_dict.json + hash: md5 + md5: 898feb287504053c9de9c1a809733c4b + size: 432 + test_each_compressor@pkl-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train files.name=pkl files.directory=kdd_nsl + data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn model.init.method=random model.init.distance_matrix=kdd_nsl/model/gzip_knn/None/pkl.npz + model.init.compressor=pkl model.init.m=10 hydra.run.dir=kdd_nsl/logs/compressor/pkl + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/reports/train/pkl/score_dict.json + hash: md5 + md5: 3e01c227095014ab9f4665ea98e7f3b5 + size: 430 + test_each_compressor@pkl-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train files.name=pkl files.directory=truthseeker + data=truthseeker dataset=truthseeker model_name=gzip_knn model.init.method=random + model.init.distance_matrix=truthseeker/model/gzip_knn/None/pkl.npz model.init.compressor=pkl model.init.m=10 + hydra.run.dir=truthseeker/logs/compressor/pkl ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/reports/train/pkl/score_dict.json + hash: md5 + md5: 85d4598fcbe6077a465a9edeadd3843a + size: 430 + test_each_compressor@pkl-sms_spam: + cmd: 'python -m deckard.layers.optimise stage=train files.name=pkl files.directory=sms_spam + data=sms_spam dataset=sms_spam model_name=gzip_knn model.init.method=random + model.init.distance_matrix=sms_spam/model/gzip_knn/None/pkl.npz model.init.compressor=pkl model.init.m=10 + hydra.run.dir=sms_spam/logs/compressor/pkl ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: sms_spam/reports/train/pkl/score_dict.json + hash: md5 + md5: a4667414e7721ee7ed489df1e412e0b0 + size: 431 + test_each_compressor@pkl-ddos: + cmd: 'python -m deckard.layers.optimise stage=train files.name=pkl files.directory=ddos + data=ddos dataset=ddos model_name=gzip_knn model.init.method=random model.init.distance_matrix=ddos/model/gzip_knn/None/pkl.npz + model.init.compressor=pkl model.init.m=10 hydra.run.dir=ddos/logs/compressor/pkl + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/reports/train/pkl/score_dict.json + hash: md5 + md5: 340261dd836239b846699c4c687b3042 + size: 432 + test_each_compressor@bz2-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train files.name=bz2 files.directory=kdd_nsl + data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn model.init.method=random model.init.distance_matrix=kdd_nsl/model/gzip_knn/None/bz2.npz + model.init.compressor=bz2 model.init.m=10 hydra.run.dir=kdd_nsl/logs/compressor/bz2 + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/reports/train/bz2/score_dict.json + hash: md5 + md5: 05fd4b45d252c648d4afb4ba3ffc05e4 + size: 430 + test_each_compressor@bz2-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train files.name=bz2 files.directory=truthseeker + data=truthseeker dataset=truthseeker model_name=gzip_knn model.init.method=random + model.init.distance_matrix=truthseeker/model/gzip_knn/None/bz2.npz model.init.compressor=bz2 model.init.m=10 + hydra.run.dir=truthseeker/logs/compressor/bz2 ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/reports/train/bz2/score_dict.json + hash: md5 + md5: 1b3094ea4075cb1b5b8cd3f74bf0c3dc + size: 432 + test_each_compressor@bz2-sms_spam: + cmd: 'python -m deckard.layers.optimise stage=train files.name=bz2 files.directory=sms_spam + data=sms_spam dataset=sms_spam model_name=gzip_knn model.init.method=random + model.init.distance_matrix=sms_spam/model/gzip_knn/None/bz2.npz model.init.compressor=bz2 model.init.m=10 + hydra.run.dir=sms_spam/logs/compressor/bz2 ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: sms_spam/reports/train/bz2/score_dict.json + hash: md5 + md5: 45303b7d052fb91e65c9f3ad97999b6a + size: 431 + test_each_compressor@bz2-ddos: + cmd: 'python -m deckard.layers.optimise stage=train files.name=bz2 files.directory=ddos + data=ddos dataset=ddos model_name=gzip_knn model.init.method=random model.init.distance_matrix=ddos/model/gzip_knn/None/bz2.npz + model.init.compressor=bz2 model.init.m=10 hydra.run.dir=ddos/logs/compressor/bz2 + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/reports/train/bz2/score_dict.json + hash: md5 + md5: fdfa470b2053f561dea2e047423b54cd + size: 431 + test_each_precompute@True-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train files.name=precompute_True + files.directory=kdd_nsl data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn model.init.method=random + model.init.distance_matrix=kdd_nsl/model/gzip_knn/None/True.npz +model.init.precompute=True model.init.m=10 hydra.run.dir=kdd_nsl/logs/precompute/True + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/reports/train/precompute_True/score_dict.json + hash: md5 + md5: f5c9a9ce41a0680f1e18874d6f21bd25 + size: 433 + test_each_precompute@True-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train files.name=precompute_True + files.directory=truthseeker data=truthseeker dataset=truthseeker model_name=gzip_knn + model.init.method=random model.init.distance_matrix=truthseeker/model/gzip_knn/None/True.npz + +model.init.precompute=True model.init.m=10 hydra.run.dir=truthseeker/logs/precompute/True + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/reports/train/precompute_True/score_dict.json + hash: md5 + md5: 76dcdbf7dc1fb63ce7b978c2f6bef8a2 + size: 435 + test_each_precompute@True-sms_spam: + cmd: 'python -m deckard.layers.optimise stage=train files.name=precompute_True + files.directory=sms_spam data=sms_spam dataset=sms_spam model_name=gzip_knn + model.init.method=random model.init.distance_matrix=sms_spam/model/gzip_knn/None/True.npz + +model.init.precompute=True model.init.m=10 hydra.run.dir=sms_spam/logs/precompute/True + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: sms_spam/reports/train/precompute_True/score_dict.json + hash: md5 + md5: fe9a23520513840fe4a90fb8413e62da + size: 432 + test_each_precompute@True-ddos: + cmd: 'python -m deckard.layers.optimise stage=train files.name=precompute_True + files.directory=ddos data=ddos dataset=ddos model_name=gzip_knn model.init.method=random + model.init.distance_matrix=ddos/model/gzip_knn/None/True.npz +model.init.precompute=True model.init.m=10 hydra.run.dir=ddos/logs/precompute/True + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/reports/train/precompute_True/score_dict.json + hash: md5 + md5: 0d72c99dc99df13629a383ca9745712e + size: 429 + test_each_precompute@False-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train files.name=precompute_False + files.directory=kdd_nsl data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn model.init.method=random + model.init.distance_matrix=kdd_nsl/model/gzip_knn/None/False.npz +model.init.precompute=False model.init.m=10 hydra.run.dir=kdd_nsl/logs/precompute/False + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/reports/train/precompute_False/score_dict.json + hash: md5 + md5: d225ea006c02f56f552431e223ef6576 + size: 429 + test_each_precompute@False-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train files.name=precompute_False + files.directory=truthseeker data=truthseeker dataset=truthseeker model_name=gzip_knn + model.init.method=random model.init.distance_matrix=truthseeker/model/gzip_knn/None/False.npz + +model.init.precompute=False model.init.m=10 hydra.run.dir=truthseeker/logs/precompute/False + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/reports/train/precompute_False/score_dict.json + hash: md5 + md5: e8094fb43b55432d298346a0a291ac71 + size: 431 + test_each_precompute@False-sms_spam: + cmd: 'python -m deckard.layers.optimise stage=train files.name=precompute_False + files.directory=sms_spam data=sms_spam dataset=sms_spam model_name=gzip_knn + model.init.method=random model.init.distance_matrix=sms_spam/model/gzip_knn/None/False.npz + +model.init.precompute=False model.init.m=10 hydra.run.dir=sms_spam/logs/precompute/False + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: sms_spam/reports/train/precompute_False/score_dict.json + hash: md5 + md5: 0f3b13aba3cc817f2327769f36b54939 + size: 432 + test_each_precompute@False-ddos: + cmd: 'python -m deckard.layers.optimise stage=train files.name=precompute_False + files.directory=ddos data=ddos dataset=ddos model_name=gzip_knn model.init.method=random + model.init.distance_matrix=ddos/model/gzip_knn/None/False.npz +model.init.precompute=False model.init.m=10 hydra.run.dir=ddos/logs/precompute/False + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/reports/train/precompute_False/score_dict.json + hash: md5 + md5: 9cc47f921a908ad81e486980d134f453 + size: 418 + test_each_metric@levenshtein-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=levenshtein files.name=levenshtein + files.directory=kdd_nsl data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn model.init.distance_matrix=kdd_nsl/model/gzip_knn/ncd/levenshtein.npz + hydra.sweeper.n_jobs=1 hydra.run.dir=kdd_nsl/logs/metric/levenshtein ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/reports/train/levenshtein/score_dict.json + hash: md5 + md5: 4f517489b794c13bbbbb477bd7b14ea8 + size: 248 + test_each_metric@levenshtein-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=levenshtein files.name=levenshtein + files.directory=truthseeker data=truthseeker dataset=truthseeker model_name=gzip_knn + model.init.distance_matrix=truthseeker/model/gzip_knn/ncd/levenshtein.npz hydra.sweeper.n_jobs=1 + hydra.run.dir=truthseeker/logs/metric/levenshtein ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/reports/train/levenshtein/score_dict.json + hash: md5 + md5: 2f0fa43167cde43c2d8c901ee6bc360d + size: 250 + test_each_metric@levenshtein-sms_spam: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=levenshtein files.name=levenshtein + files.directory=sms_spam data=sms_spam dataset=sms_spam model_name=gzip_knn + model.init.distance_matrix=sms_spam/model/gzip_knn/ncd/levenshtein.npz hydra.sweeper.n_jobs=1 + hydra.run.dir=sms_spam/logs/metric/levenshtein ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: sms_spam/reports/train/levenshtein/score_dict.json + hash: md5 + md5: bb8456e5a2457e841619d5750922bd0c + size: 246 + test_each_metric@levenshtein-ddos: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=levenshtein files.name=levenshtein + files.directory=ddos data=ddos dataset=ddos model_name=gzip_knn model.init.distance_matrix=ddos/model/gzip_knn/ncd/levenshtein.npz + hydra.sweeper.n_jobs=1 hydra.run.dir=ddos/logs/metric/levenshtein ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/reports/train/levenshtein/score_dict.json + hash: md5 + md5: 1956a0651292bf6919a103e46c0c5906 + size: 248 + test_each_metric@ratio-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=ratio files.name=ratio + files.directory=kdd_nsl data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn model.init.distance_matrix=kdd_nsl/model/gzip_knn/ncd/ratio.npz + hydra.sweeper.n_jobs=1 hydra.run.dir=kdd_nsl/logs/metric/ratio ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/reports/train/ratio/score_dict.json + hash: md5 + md5: 841058c500666af10a3a84fd7769e53d + size: 244 + test_each_metric@ratio-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=ratio files.name=ratio + files.directory=truthseeker data=truthseeker dataset=truthseeker model_name=gzip_knn + model.init.distance_matrix=truthseeker/model/gzip_knn/ncd/ratio.npz hydra.sweeper.n_jobs=8 + hydra.run.dir=truthseeker/logs/metric/ratio ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/reports/train/ratio/score_dict.json + hash: md5 + md5: 5cbc24c928a073a9459428d4e1984ba1 + size: 426 + test_each_metric@ratio-sms_spam: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=ratio files.name=ratio + files.directory=sms_spam data=sms_spam dataset=sms_spam model_name=gzip_knn + model.init.distance_matrix=sms_spam/model/gzip_knn/ncd/ratio.npz hydra.sweeper.n_jobs=8 + hydra.run.dir=sms_spam/logs/metric/ratio ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: sms_spam/reports/train/ratio/score_dict.json + hash: md5 + md5: b8ea7bf8de9af2250f1a2c84695be1f9 + size: 425 + test_each_metric@ratio-ddos: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=ratio files.name=ratio + files.directory=ddos data=ddos dataset=ddos model_name=gzip_knn model.init.distance_matrix=ddos/model/gzip_knn/ncd/ratio.npz + hydra.sweeper.n_jobs=8 hydra.run.dir=ddos/logs/metric/ratio ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/reports/train/ratio/score_dict.json + hash: md5 + md5: 5f9750a5729db8f4912f50a8610fc48c + size: 429 + test_each_metric@hamming-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=hamming files.name=hamming + files.directory=kdd_nsl data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn model.init.distance_matrix=kdd_nsl/model/gzip_knn/ncd/hamming.npz + hydra.sweeper.n_jobs=8 hydra.run.dir=kdd_nsl/logs/metric/hamming ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/reports/train/hamming/score_dict.json + hash: md5 + md5: ed699605a76c4116a461994f139da237 + size: 429 + test_each_metric@hamming-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=hamming files.name=hamming + files.directory=truthseeker data=truthseeker dataset=truthseeker model_name=gzip_knn + model.init.distance_matrix=truthseeker/model/gzip_knn/ncd/hamming.npz hydra.sweeper.n_jobs=8 + hydra.run.dir=truthseeker/logs/metric/hamming ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/reports/train/hamming/score_dict.json + hash: md5 + md5: 8a3f87734f208a61bc27114729fd4fd6 + size: 432 + test_each_metric@hamming-sms_spam: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=hamming files.name=hamming + files.directory=sms_spam data=sms_spam dataset=sms_spam model_name=gzip_knn + model.init.distance_matrix=sms_spam/model/gzip_knn/ncd/hamming.npz hydra.sweeper.n_jobs=8 + hydra.run.dir=sms_spam/logs/metric/hamming ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: sms_spam/reports/train/hamming/score_dict.json + hash: md5 + md5: 0c0988090568dc526d0137ff7e38ca6a + size: 428 + test_each_metric@hamming-ddos: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=hamming files.name=hamming + files.directory=ddos data=ddos dataset=ddos model_name=gzip_knn model.init.distance_matrix=ddos/model/gzip_knn/ncd/hamming.npz + hydra.sweeper.n_jobs=8 hydra.run.dir=ddos/logs/metric/hamming ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/reports/train/hamming/score_dict.json + hash: md5 + md5: 949f7ea27f2521fbbb2b05ec3a111346 + size: 428 + test_each_metric@jaro-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=jaro files.name=jaro + files.directory=kdd_nsl data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn model.init.distance_matrix=kdd_nsl/model/gzip_knn/ncd/jaro.npz + hydra.sweeper.n_jobs=8 hydra.run.dir=kdd_nsl/logs/metric/jaro ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/reports/train/jaro/score_dict.json + hash: md5 + md5: 3bd4e5c89097070d439c3f13359ff369 + size: 428 + test_each_metric@jaro-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=jaro files.name=jaro + files.directory=truthseeker data=truthseeker dataset=truthseeker model_name=gzip_knn + model.init.distance_matrix=truthseeker/model/gzip_knn/ncd/jaro.npz hydra.sweeper.n_jobs=8 + hydra.run.dir=truthseeker/logs/metric/jaro ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/reports/train/jaro/score_dict.json + hash: md5 + md5: b86d70f18ea7ee85132f4d8407058d60 + size: 429 + test_each_metric@jaro-sms_spam: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=jaro files.name=jaro + files.directory=sms_spam data=sms_spam dataset=sms_spam model_name=gzip_knn + model.init.distance_matrix=sms_spam/model/gzip_knn/ncd/jaro.npz hydra.sweeper.n_jobs=8 + hydra.run.dir=sms_spam/logs/metric/jaro ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: sms_spam/reports/train/jaro/score_dict.json + hash: md5 + md5: b7550248d10852d10a16610f707ea50f + size: 429 + test_each_metric@jaro-ddos: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=jaro files.name=jaro + files.directory=ddos data=ddos dataset=ddos model_name=gzip_knn model.init.distance_matrix=ddos/model/gzip_knn/ncd/jaro.npz + hydra.sweeper.n_jobs=8 hydra.run.dir=ddos/logs/metric/jaro ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/reports/train/jaro/score_dict.json + hash: md5 + md5: e7987cb2d248f7eaa20a842bbcacc442 + size: 430 + test_each_metric@jaro_winkler-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=jaro_winkler files.name=jaro_winkler + files.directory=kdd_nsl data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn model.init.distance_matrix=kdd_nsl/model/gzip_knn/ncd/jaro_winkler.npz + hydra.sweeper.n_jobs=8 hydra.run.dir=kdd_nsl/logs/metric/jaro_winkler ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/reports/train/jaro_winkler/score_dict.json + hash: md5 + md5: a44e09663d05f8330352712ccfd72f17 + size: 428 + test_each_metric@jaro_winkler-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=jaro_winkler files.name=jaro_winkler + files.directory=truthseeker data=truthseeker dataset=truthseeker model_name=gzip_knn + model.init.distance_matrix=truthseeker/model/gzip_knn/ncd/jaro_winkler.npz hydra.sweeper.n_jobs=8 + hydra.run.dir=truthseeker/logs/metric/jaro_winkler ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/reports/train/jaro_winkler/score_dict.json + hash: md5 + md5: 2a80298804f36bc7af477e11ff9f6679 + size: 428 + test_each_metric@jaro_winkler-sms_spam: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=jaro_winkler files.name=jaro_winkler + files.directory=sms_spam data=sms_spam dataset=sms_spam model_name=gzip_knn + model.init.distance_matrix=sms_spam/model/gzip_knn/ncd/jaro_winkler.npz hydra.sweeper.n_jobs=8 + hydra.run.dir=sms_spam/logs/metric/jaro_winkler ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: sms_spam/reports/train/jaro_winkler/score_dict.json + hash: md5 + md5: 8b7d0f92e14d74042fb8cd907e3a8274 + size: 430 + test_each_metric@jaro_winkler-ddos: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=jaro_winkler files.name=jaro_winkler + files.directory=ddos data=ddos dataset=ddos model_name=gzip_knn model.init.distance_matrix=ddos/model/gzip_knn/ncd/jaro_winkler.npz + hydra.sweeper.n_jobs=8 hydra.run.dir=ddos/logs/metric/jaro_winkler ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/reports/train/jaro_winkler/score_dict.json + hash: md5 + md5: aa4130c79130ddbaaebaa35a1cae7d91 + size: 426 + test_each_metric@seqratio-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=seqratio files.name=seqratio + files.directory=kdd_nsl data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn model.init.distance_matrix=kdd_nsl/model/gzip_knn/ncd/seqratio.npz + hydra.sweeper.n_jobs=8 hydra.run.dir=kdd_nsl/logs/metric/seqratio ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/reports/train/seqratio/score_dict.json + hash: md5 + md5: 9075115a02136aaa59bd87074589ce42 + size: 430 + test_each_metric@seqratio-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=seqratio files.name=seqratio + files.directory=truthseeker data=truthseeker dataset=truthseeker model_name=gzip_knn + model.init.distance_matrix=truthseeker/model/gzip_knn/ncd/seqratio.npz hydra.sweeper.n_jobs=8 + hydra.run.dir=truthseeker/logs/metric/seqratio ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/reports/train/seqratio/score_dict.json + hash: md5 + md5: ac2bdff9261ce4c9e511294dd69b19f8 + size: 434 + test_each_metric@seqratio-sms_spam: + cmd: 'python -m deckard.layers.optimise stage=train model.init.metric=seqratio files.name=seqratio + files.directory=sms_spam data=sms_spam dataset=sms_spam model_name=gzip_knn + model.init.distance_matrix=sms_spam/model/gzip_knn/ncd/seqratio.npz hydra.sweeper.n_jobs=8 + hydra.run.dir=sms_spam/logs/metric/seqratio ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 14173762472fe294a1d3228b4ee83d4b + size: 431 + - path: params.yaml + hash: md5 + md5: 4999b48c21cb63a45801003d03576594 + size: 2082 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + art: + _target_: deckard.base.model.art_pipeline.ArtPipeline + initialize: + nb_classes: 2 + library: sklearn + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 10 + train_size: 10 + sklearn_pipeline: + encoder: + handle_unknown: use_encoded_value + name: sklearn.preprocessing.OrdinalEncoder + unknown_value: -1 + preprocessor: + name: sklearn.preprocessing.StandardScaler + with_mean: true + with_std: true + target: label + init: + _target_: deckard.base.model.ModelInitializer + compressor: gzip + distance_matrix: + k: 1 + m: -1 + method: + metric: ncd + test_each_method@ddos-random: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=random model.init.m=3 + data.sample.train_size=100 files.name=random files.directory=ddos data=ddos + dataset=ddos model_name=random hydra.run.dir=ddos/logs/method/random ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/logs/method/random + hash: md5 + md5: 3bfcc27fd44bf9333be7081f3fceb94c.dir + size: 8340 + nfiles: 4 + - path: ddos/reports/train/random/score_dict.json + hash: md5 + md5: 218449c8e2b7425707008d01e751eee4 + size: 281 + test_each_method@ddos-medoid: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=medoid model.init.m=3 + data.sample.train_size=100 files.name=medoid files.directory=ddos data=ddos + dataset=ddos model_name=medoid hydra.run.dir=ddos/logs/method/medoid ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/logs/method/medoid + hash: md5 + md5: cab03f71d3883157c103a207662f0f01.dir + size: 8377 + nfiles: 4 + - path: ddos/reports/train/medoid/score_dict.json + hash: md5 + md5: eb281dc186936044bcf39edf3b5c2a97 + size: 283 + test_each_method@ddos-sum: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=sum model.init.m=3 + data.sample.train_size=100 files.name=sum files.directory=ddos data=ddos dataset=ddos + model_name=sum hydra.run.dir=ddos/logs/method/sum ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/logs/method/sum + hash: md5 + md5: 1acd35c26f1f01c1d97695be4df4be9f.dir + size: 8320 + nfiles: 4 + - path: ddos/reports/train/sum/score_dict.json + hash: md5 + md5: d8ee90602dcf3e5e3d1541fd051d8c25 + size: 283 + test_each_method@ddos-svc: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=svc model.init.m=3 + data.sample.train_size=100 files.name=svc files.directory=ddos data=ddos dataset=ddos + model_name=svc hydra.run.dir=ddos/logs/method/svc ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/logs/method/svc + hash: md5 + md5: ff1e2d4db8fbd074fae27c28e6d7efab.dir + size: 8317 + nfiles: 4 + - path: ddos/reports/train/svc/score_dict.json + hash: md5 + md5: 02086eaaafb2de9549a587e0cac8d44f + size: 280 + test_each_method@ddos-condensed: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=condensed model.init.m=1 + files.name=condensed files.directory=ddos data=ddos dataset=ddos model_name=condensed + hydra.run.dir=ddos/logs/method/condensed ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 064e5bb42979e36c917c538b2a7bc0cc + size: 489 + - path: params.yaml + hash: md5 + md5: 8e937140db56a135e97c05461c573520 + size: 1345 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/logs/method/condensed + hash: md5 + md5: 5dfc9ebfe1c6f3e496814c86a05a5329.dir + size: 10117 + nfiles: 4 + - path: ddos/reports/train/condensed/score_dict.json + hash: md5 + md5: 56bcddf54558d9cdd1a7587878aceffa + size: 284 + test_each_method@ddos-hardness: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=hardness model.init.m=3 + data.sample.train_size=100 files.name=hardness files.directory=ddos data=ddos + dataset=ddos model_name=hardness hydra.run.dir=ddos/logs/method/hardness ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/logs/method/hardness + hash: md5 + md5: 92679e897538c5e98e89f11ca456f483.dir + size: 8413 + nfiles: 4 + - path: ddos/reports/train/hardness/score_dict.json + hash: md5 + md5: 24a77200255cec8b4ec9f1877188fdda + size: 281 + test_each_method@ddos-nearmiss: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=nearmiss model.init.m=3 + data.sample.train_size=100 files.name=nearmiss files.directory=ddos data=ddos + dataset=ddos model_name=nearmiss hydra.run.dir=ddos/logs/method/nearmiss ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/logs/method/nearmiss + hash: md5 + md5: 84fc6455a5c576fa04c36919c33ae8fd.dir + size: 8416 + nfiles: 4 + - path: ddos/reports/train/nearmiss/score_dict.json + hash: md5 + md5: b4602181657a738a97631883018e221a + size: 284 + test_each_method@truthseeker-svc: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=svc model.init.m=3 + data.sample.train_size=100 files.name=svc files.directory=truthseeker data=truthseeker + dataset=truthseeker model_name=svc hydra.run.dir=truthseeker/logs/method/svc + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 064e5bb42979e36c917c538b2a7bc0cc + size: 489 + - path: params.yaml + hash: md5 + md5: 8e937140db56a135e97c05461c573520 + size: 1345 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/logs/method/svc + hash: md5 + md5: 7f9ad95f5b5a7d8ea8a41d09560bca7e.dir + size: 10252 + nfiles: 4 + - path: truthseeker/reports/train/svc/score_dict.json + hash: md5 + md5: dca27d752d8d9db2b52a61d9e0d9bebf + size: 283 + test_each_method@truthseeker-medoid: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=medoid model.init.m=3 + data.sample.train_size=100 files.name=medoid files.directory=truthseeker data=truthseeker + dataset=truthseeker model_name=medoid hydra.run.dir=truthseeker/logs/method/medoid + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 064e5bb42979e36c917c538b2a7bc0cc + size: 489 + - path: params.yaml + hash: md5 + md5: 8e937140db56a135e97c05461c573520 + size: 1345 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/logs/method/medoid + hash: md5 + md5: 57b1e2e154ae8653331898992d0d7f7c.dir + size: 10316 + nfiles: 4 + - path: truthseeker/reports/train/medoid/score_dict.json + hash: md5 + md5: a728020aeb632257e52cc9b13337870e + size: 284 + test_each_method@truthseeker-sum: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=sum model.init.m=3 + data.sample.train_size=100 files.name=sum files.directory=truthseeker data=truthseeker + dataset=truthseeker model_name=sum hydra.run.dir=truthseeker/logs/method/sum + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 064e5bb42979e36c917c538b2a7bc0cc + size: 489 + - path: params.yaml + hash: md5 + md5: 8e937140db56a135e97c05461c573520 + size: 1345 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/logs/method/sum + hash: md5 + md5: b8934f0660e9e6043e5a7117d2e3d462.dir + size: 10252 + nfiles: 4 + - path: truthseeker/reports/train/sum/score_dict.json + hash: md5 + md5: 0a4117f35aab6ec4b41ac526f8715aa2 + size: 283 + test_each_method@truthseeker-random: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=random model.init.m=3 + data.sample.train_size=100 files.name=random files.directory=truthseeker data=truthseeker + dataset=truthseeker model_name=random hydra.run.dir=truthseeker/logs/method/random + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 064e5bb42979e36c917c538b2a7bc0cc + size: 489 + - path: params.yaml + hash: md5 + md5: 8e937140db56a135e97c05461c573520 + size: 1345 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/logs/method/random + hash: md5 + md5: a77f4e67f85e529063b18617cda5525a.dir + size: 10289 + nfiles: 4 + - path: truthseeker/reports/train/random/score_dict.json + hash: md5 + md5: 08f3cc499d61caaa4ab912af1a2ff558 + size: 283 + test_each_method@truthseeker-nearmiss: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=nearmiss model.init.m=3 + data.sample.train_size=100 files.name=nearmiss files.directory=truthseeker data=truthseeker + dataset=truthseeker model_name=nearmiss hydra.run.dir=truthseeker/logs/method/nearmiss + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 064e5bb42979e36c917c538b2a7bc0cc + size: 489 + - path: params.yaml + hash: md5 + md5: 8e937140db56a135e97c05461c573520 + size: 1345 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/logs/method/nearmiss + hash: md5 + md5: 6ea3f0a574d7abd052e3ee5466356e13.dir + size: 10359 + nfiles: 4 + - path: truthseeker/reports/train/nearmiss/score_dict.json + hash: md5 + md5: f03918d65cac7f21e210a14be8ee1373 + size: 285 + test_each_method@truthseeker-hardness: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=hardness model.init.m=3 + data.sample.train_size=100 files.name=hardness files.directory=truthseeker data=truthseeker + dataset=truthseeker model_name=hardness hydra.run.dir=truthseeker/logs/method/hardness + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 064e5bb42979e36c917c538b2a7bc0cc + size: 489 + - path: params.yaml + hash: md5 + md5: 8e937140db56a135e97c05461c573520 + size: 1345 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/logs/method/hardness + hash: md5 + md5: c5ea09925ae34a0fee42f1ec06d88090.dir + size: 10355 + nfiles: 4 + - path: truthseeker/reports/train/hardness/score_dict.json + hash: md5 + md5: 87bdbb0cafd4462b87035af79efc81c5 + size: 281 + test_each_method@truthseeker-knn: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=knn model.init.m=3 + data.sample.train_size=100 files.name=knn files.directory=truthseeker data=truthseeker + dataset=truthseeker model_name=knn hydra.run.dir=truthseeker/logs/method/knn + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 064e5bb42979e36c917c538b2a7bc0cc + size: 489 + - path: params.yaml + hash: md5 + md5: 8e937140db56a135e97c05461c573520 + size: 1345 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/logs/method/knn + hash: md5 + md5: 5c5fe8f17151816b01d863f51db3d01a.dir + size: 10254 + nfiles: 4 + - path: truthseeker/reports/train/knn/score_dict.json + hash: md5 + md5: 4157a5deabda43d207a543b9f038b5af + size: 285 + test_each_method@ddos-knn: + cmd: 'python -m deckard.layers.optimise stage=train +model.init.sampling_method=knn model.init.m=3 + data.sample.train_size=100 files.name=knn files.directory=ddos data=ddos dataset=ddos + model_name=knn hydra.run.dir=ddos/logs/method/knn ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/logs/method/knn + hash: md5 + md5: 8d73125fea91a47efc49ba2b4a68e1fe.dir + size: 8319 + nfiles: 4 + - path: ddos/reports/train/knn/score_dict.json + hash: md5 + md5: fb77e1c8e53bac0e077d2140f1abc6d6 + size: 282 + condense@sms_spam-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.test_size=100 model_name=gzip_logistic model=gzip_logistic hydra.sweeper.study_name=condense_gzip_logistic_sms_spam + hydra.sweeper.n_trials=1 hydra.sweeper.n_jobs=32 hydra.sweep.dir=sms_spam/logs/condense/gzip_logistic/ + hydra.callbacks.study_dump.output_file=sms_spam/logs/gzip_logistic/study.csv + ++data.sample.train_size='int(interval(30, 1000))' ++data.sample.random_state='int(interval(10000, + 20000))' ++data.sample.stratify=True model.init.m='tag(log, interval(.1, 1))' + +model.init.sampling_method=medoid,sum,svc,random,hardness,nearmiss,knn files.directory=sms_spam + files.reports=reports/condense/gzip_logistic/ hydra.launcher.n_jobs=32 --config-name + gzip_logistic --multirun + deps: + - path: conf/model/best_gzip_logistic_sms_spam.yaml + hash: md5 + md5: 026fca7fe5d7bb75c4a3ae245f86a2c2 + size: 332 + - path: sms_spam/logs/method/ + hash: md5 + md5: e8e327bbd5859a6c1c362fd482435727.dir + size: 69377 + nfiles: 24 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: ??? + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 2 + direction: ${direction} + params: + ++data.sample.train_size: int(interval(20, 1000)) + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.1, 1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: sms_spam/logs/condense/gzip_logistic/ + hash: md5 + md5: 9496098bd1497b6c46124e40e665ee74.dir + size: 14280 + nfiles: 5 + - path: sms_spam/reports/condense/gzip_logistic/ + hash: md5 + md5: c7e2a43c1dc170c3d593825f57ad0e9b.dir + size: 2707 + nfiles: 3 + condense@truthseeker-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.test_size=100 model_name=gzip_svc model=gzip_svc hydra.sweeper.study_name=condense_gzip_svc_truthseeker + hydra.sweeper.n_trials=1 hydra.sweeper.n_jobs=32 hydra.sweep.dir=truthseeker/logs/condense/gzip_svc/ + hydra.callbacks.study_dump.output_file=truthseeker/logs/gzip_svc/study.csv ++data.sample.train_size='int(interval(30, + 1000))' ++data.sample.random_state='int(interval(10000, 20000))' ++data.sample.stratify=True + model.init.m='tag(log, interval(.1, 1))' +model.init.sampling_method=medoid,sum,svc,random,hardness,nearmiss,knn + files.directory=truthseeker files.reports=reports/condense/gzip_svc/ hydra.launcher.n_jobs=32 + --config-name gzip_svc --multirun + deps: + - path: conf/model/best_gzip_svc_truthseeker.yaml + hash: md5 + md5: 97d9d5857744b1cc077513ac5a659f62 + size: 302 + - path: truthseeker/logs/method/ + hash: md5 + md5: 6f6693db2bb9520dc7956f0d0c003e23.dir + size: 116543 + nfiles: 44 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: ??? + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 2 + direction: ${direction} + params: + ++data.sample.train_size: int(interval(20, 1000)) + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.1, 1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: truthseeker/logs/condense/gzip_svc/ + hash: md5 + md5: bd7cbae34fd6feecf60a49cb537b0f80.dir + size: 13751 + nfiles: 5 + - path: truthseeker/reports/condense/gzip_svc/ + hash: md5 + md5: a24584cdc3464b86b6ff88b90dc62e5e.dir + size: 2701 + nfiles: 3 + condense@sms_spam-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.test_size=100 model_name=gzip_svc model=best_gzip_svc_sms_spam hydra.sweeper.study_name=condense_gzip_svc_sms_spam + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=sms_spam/logs/condense/gzip_svc/ + hydra.callbacks.study_dump.output_file=sms_spam/logs/gzip_svc/study.csv model.init.m='tag(log, + interval(.01, .1))' +model.init.sampling_method=medoid,sum,svc,random,hardness,nearmiss,knn + files.directory=sms_spam files.reports=reports/condense/gzip_svc/ hydra.launcher.n_jobs=16 + --config-name condense --multirun + deps: + - path: conf/model/best_gzip_svc_sms_spam.yaml + hash: md5 + md5: 771cd8e3b1368f0fbb30e518002db80f + size: 317 + - path: sms_spam/logs/method/ + hash: md5 + md5: e8e327bbd5859a6c1c362fd482435727.dir + size: 69377 + nfiles: 24 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: ??? + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 2 + direction: ${direction} + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: sms_spam/logs/condense/gzip_svc/ + hash: md5 + md5: c6ef4ecf2bec03894b2f2018cffc0888.dir + size: 1597147 + nfiles: 513 + - path: sms_spam/reports/condense/gzip_svc/ + hash: md5 + md5: aff4ca5c41e7043fe0d36b4a669ad6a7.dir + size: 344414 + nfiles: 381 + condense@ddos-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.test_size=100 + model_name=gzip_svc model=best_gzip_svc_ddos hydra.sweeper.study_name=condense_gzip_svc_ddos + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=ddos/logs/condense/gzip_svc/ + hydra.callbacks.study_dump.output_file=ddos/logs/gzip_svc/study.csv model.init.m='tag(log, + interval(.01, .1))' +model.init.sampling_method=medoid,sum,svc,random,hardness,nearmiss,knn + files.directory=ddos files.reports=reports/condense/gzip_svc/ hydra.launcher.n_jobs=16 + ++raise_exception=True --config-name condense --multirun + deps: + - path: conf/model/best_gzip_svc_ddos.yaml + hash: md5 + md5: f2ec5b2ff8103b93ca61a5b86888a3e6 + size: 305 + - path: ddos/logs/method/ + hash: md5 + md5: 7128c67930147170f54fb89880528199.dir + size: 120518 + nfiles: 48 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: ??? + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 2 + direction: ${direction} + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: ddos/logs/condense/gzip_svc/ + hash: md5 + md5: 98f11cc76f9f370871bfb325ec4186e4.dir + size: 1589126 + nfiles: 513 + - path: ddos/reports/condense/gzip_svc/ + hash: md5 + md5: 87ca8778bbdb8363a1e237019c87ebf5.dir + size: 345583 + nfiles: 384 + condense@sms_spam-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.test_size=100 model_name=gzip_knn model=best_gzip_knn_sms_spam hydra.sweeper.study_name=condense_gzip_knn_sms_spam + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=sms_spam/logs/condense/gzip_knn/ + hydra.callbacks.study_dump.output_file=sms_spam/logs/gzip_knn/study.csv model.init.m='tag(log, + interval(.01, .1))' +model.init.sampling_method=medoid,sum,svc,random,hardness,nearmiss,knn + files.directory=sms_spam files.reports=reports/condense/gzip_knn/ hydra.launcher.n_jobs=16 + --config-name condense --multirun + deps: + - path: conf/model/best_gzip_knn_sms_spam.yaml + hash: md5 + md5: 430e2be20ddaa39808a6739627a98d77 + size: 259 + - path: sms_spam/logs/method/ + hash: md5 + md5: e8e327bbd5859a6c1c362fd482435727.dir + size: 69377 + nfiles: 24 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: ??? + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 2 + direction: ${direction} + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: sms_spam/logs/condense/gzip_knn/ + hash: md5 + md5: a45625dcc1d1cc1f1e20d19440e1cdf1.dir + size: 1559584 + nfiles: 513 + - path: sms_spam/reports/condense/gzip_knn/ + hash: md5 + md5: 0ac87faa8d16d77b4e7d5a96cfdde177.dir + size: 335094 + nfiles: 384 + compile@sms_spam-gzip_knn: + cmd: python -m deckard.layers.compile --report_folder sms_spam/reports/gzip_knn --results_file + sms_spam/reports/gzip_knn.csv + deps: + - path: sms_spam/reports/gzip_knn/ + hash: md5 + md5: 89e3b68400367dee648064784adb9796.dir + size: 1499301 + nfiles: 1337 + outs: + - path: sms_spam/reports/gzip_knn.csv + hash: md5 + md5: ee7ee47f5ee27acca9e58b9249ecb954 + size: 695526 + compile@truthseeker-gzip_knn: + cmd: python -m deckard.layers.compile --report_folder truthseeker/reports/gzip_knn --results_file + truthseeker/reports/gzip_knn.csv + deps: + - path: truthseeker/reports/gzip_knn/ + hash: md5 + md5: e5702237f62021b85240717035b53d81.dir + size: 1537318 + nfiles: 1325 + outs: + - path: truthseeker/reports/gzip_knn.csv + hash: md5 + md5: 183afe36078f60e3e478f3813b1b52a7 + size: 711959 + compile@kdd_nsl-gzip_knn: + cmd: python -m deckard.layers.compile --report_folder kdd_nsl/reports/gzip_knn --results_file + kdd_nsl/reports/gzip_knn.csv + deps: + - path: kdd_nsl/reports/gzip_knn/ + hash: md5 + md5: 4dfe630ff7f6f036220f2b9aa5b3c6b1.dir + size: 4225577 + nfiles: 3608 + outs: + - path: kdd_nsl/reports/gzip_knn.csv + hash: md5 + md5: 17f27e4404093a5b50a74ca0af24e4db + size: 1964725 + compile@truthseeker-gzip_svc: + cmd: python -m deckard.layers.compile --report_folder truthseeker/reports/gzip_svc --results_file + truthseeker/reports/gzip_svc.csv + deps: + - path: truthseeker/reports/gzip_svc/ + hash: md5 + md5: e6e273bb143c7a8949d5be4acca87eb9.dir + size: 1536370 + nfiles: 1725 + outs: + - path: truthseeker/reports/gzip_svc.csv + hash: md5 + md5: 746aae81f4af3c8ce4c8c7e3c3e866b1 + size: 870818 + compile@truthseeker-gzip_logistic: + cmd: python -m deckard.layers.compile --report_folder truthseeker/reports/gzip_logistic --results_file + truthseeker/reports/gzip_logistic.csv + deps: + - path: truthseeker/reports/gzip_logistic/ + hash: md5 + md5: 5074027dccab644424973514ae7c8922.dir + size: 2225784 + nfiles: 1473 + outs: + - path: truthseeker/reports/gzip_logistic.csv + hash: md5 + md5: ed858c429ea35f3dac4eca9c52e036ce + size: 786129 + compile@ddos-gzip_logistic: + cmd: python -m deckard.layers.compile --report_folder ddos/reports/gzip_logistic --results_file + ddos/reports/gzip_logistic.csv + deps: + - path: ddos/reports/gzip_logistic/ + hash: md5 + md5: 6ce8a2aa8cc08ccde4467403dec1a124.dir + size: 6278656 + nfiles: 4845 + outs: + - path: ddos/reports/gzip_logistic.csv + hash: md5 + md5: 7ff452295887d9c84250c7375b7ea58a + size: 2606734 + compile@ddos-gzip_knn: + cmd: python -m deckard.layers.compile --report_folder ddos/reports/gzip_knn --results_file + ddos/reports/gzip_knn.csv + deps: + - path: ddos/reports/gzip_knn/ + hash: md5 + md5: ce89d46c7a34959f9d39a3d1e6ad8911.dir + size: 5724814 + nfiles: 5690 + outs: + - path: ddos/reports/gzip_knn.csv + hash: md5 + md5: fe28ae14c5cc37ee8eb5e705c3610da8 + size: 2899113 + compile@kdd_nsl-gzip_logistic: + cmd: python -m deckard.layers.compile --report_folder kdd_nsl/reports/gzip_logistic --results_file + kdd_nsl/reports/gzip_logistic.csv + deps: + - path: kdd_nsl/reports/gzip_logistic/ + hash: md5 + md5: bca1b51ebae4e3ef166f9424a0f8c1ff.dir + size: 4923952 + nfiles: 3945 + outs: + - path: kdd_nsl/reports/gzip_logistic.csv + hash: md5 + md5: 07859f070e6b9246456e860d63ab4438 + size: 2149350 + compile@kdd_nsl-gzip_svc: + cmd: python -m deckard.layers.compile --report_folder kdd_nsl/reports/gzip_svc --results_file + kdd_nsl/reports/gzip_svc.csv + deps: + - path: kdd_nsl/reports/gzip_svc/ + hash: md5 + md5: 907ec439b02a0d2b3ba36d54e250ff89.dir + size: 4798455 + nfiles: 4393 + outs: + - path: kdd_nsl/reports/gzip_svc.csv + hash: md5 + md5: b25b5925936e935b62cdc6bd5b96d8d3 + size: 2257942 + compile@sms_spam-gzip_logistic: + cmd: python -m deckard.layers.compile --report_folder sms_spam/reports/gzip_logistic --results_file + sms_spam/reports/gzip_logistic.csv + deps: + - path: sms_spam/reports/gzip_logistic/ + hash: md5 + md5: c70a60ca7e7e433d1cbd21bfddd26320.dir + size: 2212768 + nfiles: 1438 + outs: + - path: sms_spam/reports/gzip_logistic.csv + hash: md5 + md5: 34643e6fbb37caef6b6f9054cb1b5203 + size: 754980 + compile@ddos-gzip_svc: + cmd: python -m deckard.layers.compile --report_folder ddos/reports/gzip_svc --results_file + ddos/reports/gzip_svc.csv + deps: + - path: ddos/reports/gzip_svc/ + hash: md5 + md5: 3b3fdb3e3d2321e8ee5dc36311626231.dir + size: 6101649 + nfiles: 5283 + outs: + - path: ddos/reports/gzip_svc.csv + hash: md5 + md5: 7bd491b47bf7d5f373cb825e9e3d0c4c + size: 2689051 + compile@sms_spam-gzip_svc: + cmd: python -m deckard.layers.compile --report_folder sms_spam/reports/gzip_svc --results_file + sms_spam/reports/gzip_svc.csv + deps: + - path: sms_spam/reports/gzip_svc/ + hash: md5 + md5: 52af2b025a2aafa3e4a78db0bf221f59.dir + size: 2173475 + nfiles: 1536 + outs: + - path: sms_spam/reports/gzip_svc.csv + hash: md5 + md5: 12c2eec80495a5fb326dbed7c4cfe382 + size: 758618 + clean@truthseeker-gzip_svc: + cmd: python -m deckard.layers.clean_data -i truthseeker/reports/gzip_svc.csv + -o truthseeker/plots/clean/gzip_svc.csv -c conf/clean.yaml + deps: + - path: truthseeker/reports/gzip_svc.csv + hash: md5 + md5: 746aae81f4af3c8ce4c8c7e3c3e866b1 + size: 870818 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: truthseeker/plots/clean/gzip_svc.csv + hash: md5 + md5: cdb96b7ba00dc0bf6b4c8db38311447b + size: 679004 + clean@kdd_nsl-gzip_svc: + cmd: python -m deckard.layers.clean_data -i kdd_nsl/reports/gzip_svc.csv -o kdd_nsl/plots/clean/gzip_svc.csv + -c conf/clean.yaml + deps: + - path: kdd_nsl/reports/gzip_svc.csv + hash: md5 + md5: b25b5925936e935b62cdc6bd5b96d8d3 + size: 2257942 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: kdd_nsl/plots/clean/gzip_svc.csv + hash: md5 + md5: a359fb46b83265dec352e0af17f19cb2 + size: 1771361 + clean@kdd_nsl-gzip_knn: + cmd: python -m deckard.layers.clean_data -i kdd_nsl/reports/gzip_knn.csv -o kdd_nsl/plots/clean/gzip_knn.csv + -c conf/clean.yaml + deps: + - path: kdd_nsl/reports/gzip_knn.csv + hash: md5 + md5: 17f27e4404093a5b50a74ca0af24e4db + size: 1964725 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: kdd_nsl/plots/clean/gzip_knn.csv + hash: md5 + md5: 686b0f04494630491244a6ead99949b7 + size: 996268 + clean@ddos-gzip_knn: + cmd: python -m deckard.layers.clean_data -i ddos/reports/gzip_knn.csv -o ddos/plots/clean/gzip_knn.csv + -c conf/clean.yaml + deps: + - path: ddos/reports/gzip_knn.csv + hash: md5 + md5: fe28ae14c5cc37ee8eb5e705c3610da8 + size: 2899113 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: ddos/plots/clean/gzip_knn.csv + hash: md5 + md5: ad6773d0af82535d3c525f8bf405bbfe + size: 1919757 + clean@ddos-gzip_svc: + cmd: python -m deckard.layers.clean_data -i ddos/reports/gzip_svc.csv -o ddos/plots/clean/gzip_svc.csv + -c conf/clean.yaml + deps: + - path: ddos/reports/gzip_svc.csv + hash: md5 + md5: 7bd491b47bf7d5f373cb825e9e3d0c4c + size: 2689051 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: ddos/plots/clean/gzip_svc.csv + hash: md5 + md5: 45515bad8f1a4167a7a64d0a3d62464e + size: 1842449 + clean@kdd_nsl-gzip_logistic: + cmd: python -m deckard.layers.clean_data -i kdd_nsl/reports/gzip_logistic.csv + -o kdd_nsl/plots/clean/gzip_logistic.csv -c conf/clean.yaml + deps: + - path: kdd_nsl/reports/gzip_logistic.csv + hash: md5 + md5: 07859f070e6b9246456e860d63ab4438 + size: 2149350 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: kdd_nsl/plots/clean/gzip_logistic.csv + hash: md5 + md5: 82d8bddbe4db8eb6835d00931af7fc12 + size: 1456814 + clean@truthseeker-gzip_knn: + cmd: python -m deckard.layers.clean_data -i truthseeker/reports/gzip_knn.csv + -o truthseeker/plots/clean/gzip_knn.csv -c conf/clean.yaml + deps: + - path: truthseeker/reports/gzip_knn.csv + hash: md5 + md5: 183afe36078f60e3e478f3813b1b52a7 + size: 711959 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: truthseeker/plots/clean/gzip_knn.csv + hash: md5 + md5: dbbbb4c6ab13f540b1b4d9ee23d4a91a + size: 354842 + clean@ddos-gzip_logistic: + cmd: python -m deckard.layers.clean_data -i ddos/reports/gzip_logistic.csv -o + ddos/plots/clean/gzip_logistic.csv -c conf/clean.yaml + deps: + - path: ddos/reports/gzip_logistic.csv + hash: md5 + md5: 7ff452295887d9c84250c7375b7ea58a + size: 2606734 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: ddos/plots/clean/gzip_logistic.csv + hash: md5 + md5: a7d5cf7362711724ae19bba3becf66d2 + size: 1523208 + clean@sms_spam-gzip_knn: + cmd: python -m deckard.layers.clean_data -i sms_spam/reports/gzip_knn.csv -o + sms_spam/plots/clean/gzip_knn.csv -c conf/clean.yaml + deps: + - path: sms_spam/reports/gzip_knn.csv + hash: md5 + md5: ee7ee47f5ee27acca9e58b9249ecb954 + size: 695526 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: sms_spam/plots/clean/gzip_knn.csv + hash: md5 + md5: 020bbec4f2594935bd33efdcdf90eba7 + size: 358497 + clean@sms_spam-gzip_logistic: + cmd: python -m deckard.layers.clean_data -i sms_spam/reports/gzip_logistic.csv + -o sms_spam/plots/clean/gzip_logistic.csv -c conf/clean.yaml + deps: + - path: sms_spam/reports/gzip_logistic.csv + hash: md5 + md5: 34643e6fbb37caef6b6f9054cb1b5203 + size: 754980 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: sms_spam/plots/clean/gzip_logistic.csv + hash: md5 + md5: d9a1be37cfb498a7d87c116db6f553e2 + size: 497702 + clean@sms_spam-gzip_svc: + cmd: python -m deckard.layers.clean_data -i sms_spam/reports/gzip_svc.csv -o + sms_spam/plots/clean/gzip_svc.csv -c conf/clean.yaml + deps: + - path: sms_spam/reports/gzip_svc.csv + hash: md5 + md5: 12c2eec80495a5fb326dbed7c4cfe382 + size: 758618 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: sms_spam/plots/clean/gzip_svc.csv + hash: md5 + md5: 4455964d2014f4705b4ea3191cef40b2 + size: 588874 + clean@truthseeker-gzip_logistic: + cmd: python -m deckard.layers.clean_data -i truthseeker/reports/gzip_logistic.csv + -o truthseeker/plots/clean/gzip_logistic.csv -c conf/clean.yaml + deps: + - path: truthseeker/reports/gzip_logistic.csv + hash: md5 + md5: 276fcd9d025d60418d6a92db6bee859e + size: 748894 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: truthseeker/plots/clean/gzip_logistic.csv + hash: md5 + md5: 82450f3b94f517f586b35ed85b494add + size: 417258 + copy@sms_spam: + cmd: 'rm -rf ~/Gzip-KNN/figs/sms_spam/ && mkdir -p ~/Gzip-KNN/figs/sms_spam/ && + cp -r sms_spam/plots/* ~/Gzip-KNN/figs/sms_spam/ ' + deps: + - path: sms_spam/plots/ + hash: md5 + md5: b4562b1ad06e680bf0247d4e8dab85c1.dir + size: 10160120 + nfiles: 19 + copy@truthseeker: + cmd: 'rm -rf ~/Gzip-KNN/figs/truthseeker/ && mkdir -p ~/Gzip-KNN/figs/truthseeker/ + && cp -r truthseeker/plots/* ~/Gzip-KNN/figs/truthseeker/ ' + deps: + - path: truthseeker/plots/ + hash: md5 + md5: 47a062972487c796e962fa241d4bf108.dir + size: 8761443 + nfiles: 18 + copy@kdd_nsl: + cmd: 'rm -rf ~/Gzip-KNN/figs/kdd_nsl/ && mkdir -p ~/Gzip-KNN/figs/kdd_nsl/ && + cp -r kdd_nsl/plots/* ~/Gzip-KNN/figs/kdd_nsl/ ' + deps: + - path: kdd_nsl/plots/ + hash: md5 + md5: 526bfd7a3ffd1b1cee332632d79a96f8.dir + size: 13281984 + nfiles: 18 + copy@ddos: + cmd: 'rm -rf ~/Gzip-KNN/figs/ddos/ && mkdir -p ~/Gzip-KNN/figs/ddos/ && cp -r + ddos/plots/* ~/Gzip-KNN/figs/ddos/ ' + deps: + - path: ddos/plots/ + hash: md5 + md5: 22ac4455d4f24b7a0624f5d670f81e24.dir + size: 15551940 + nfiles: 19 + condense@truthseeker-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.test_size=100 model_name=gzip_knn model=best_gzip_knn_truthseeker + hydra.sweeper.study_name=condense_gzip_knn_truthseeker hydra.sweeper.n_trials=128 + hydra.sweeper.n_jobs=8 hydra.sweep.dir=truthseeker/logs/condense/gzip_knn/ hydra.callbacks.study_dump.output_file=truthseeker/logs/gzip_knn/study.csv + model.init.m='tag(log, interval(.01, .1))' +model.init.sampling_method=medoid,sum,svc,random,hardness,nearmiss,knn + files.directory=truthseeker files.reports=reports/condense/gzip_knn/ hydra.launcher.n_jobs=16 + --config-name condense --multirun + deps: + - path: conf/model/best_gzip_knn_truthseeker.yaml + hash: md5 + md5: 79baf4709c4a5f2535059ef8d1b6a082 + size: 258 + - path: truthseeker/logs/method/ + hash: md5 + md5: 6f6693db2bb9520dc7956f0d0c003e23.dir + size: 116543 + nfiles: 44 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: ??? + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 2 + direction: ${direction} + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: truthseeker/logs/condense/gzip_knn/ + hash: md5 + md5: 029aa9a618d0edd127756b0b724a1742.dir + size: 1568426 + nfiles: 513 + - path: truthseeker/reports/condense/gzip_knn/ + hash: md5 + md5: ef4ee3a0a4c954cea9b4f557a216e421.dir + size: 353591 + nfiles: 374 + plot@ddos-gzip_knn: + cmd: python -m deckard.layers.plots --path ddos/plots/ --file ddos/plots/clean_gzip_knn.csv -c + conf/plots.yaml + deps: + - path: ddos/plots/clean_gzip_knn.csv + hash: md5 + md5: c730af75faf35ba958b15b2da82b25be + size: 451405 + params: + conf/plots.yaml: + cat_plot: + - file: symmetric_vs_metric.pdf + x: model.init.symmetric + y: accuracy + hue: model.init.metric + errorbar: se + kind: bar + titles: + xlabels: '' + ylabels: Accuracy + legend_title: Metrics + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: linear + ylim: + - 0 + - 1 + - file: symmetric_vs_metric_train_time.pdf + x: model.init.symmetric + y: train_time + hue: model.init.metric + errorbar: se + kind: bar + titles: + xlabels: '' + ylabels: Training Time (s) + legend_title: Metrics + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: log + - file: models_vs_accuracy.pdf + x: model_name + y: accuracy + hue: dataset + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Accuracy + legend_title: Samples + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: linear + ylim: + - 0 + - 1 + rotation: 90 + - file: models_vs_train_time.pdf + x: model_name + y: train_time + hue: dataset + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Training Time (s) + legend_title: Samples + rotation: 90 + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: log + - file: models_vs_predict_time.pdf + x: model_name + y: predict_time + hue: dataset + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Prediction Time (s) + legend_title: Samples + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: log + rotation: 90 + line_plot: + - file: metric_vs_accuracy.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: accuracy + ylabel: Accuracy + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + - file: metric_vs_train_time.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: train_time + ylabel: Training Time (s) + y_scale: log + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + - file: metric_vs_predict_time.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: predict_time + ylabel: Prediction Time (s) + y_scale: log + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + outs: + - path: ddos/plots/metric_vs_accuracy.pdf + hash: md5 + md5: b8279045dcf3a1fc574578e991427e73 + size: 23629 + - path: ddos/plots/metric_vs_predict_time.pdf + hash: md5 + md5: 1512c0c363753afc28a3c093cc8e252c + size: 22784 + - path: ddos/plots/metric_vs_train_time.pdf + hash: md5 + md5: dd17a922e53b59b2d9b2d91c1237bb54 + size: 22329 + - path: ddos/plots/models_vs_accuracy.pdf + hash: md5 + md5: bbbc08a7161735b6174984688003809f + size: 13970 + - path: ddos/plots/models_vs_predict_time.pdf + hash: md5 + md5: 9b6acd61045df87af51626be2bdff7ab + size: 15507 + - path: ddos/plots/models_vs_train_time.pdf + hash: md5 + md5: 6a2303b531dfc78f20d9bf3dc62d8d42 + size: 16118 + - path: ddos/plots/symmetric_vs_metric.pdf + hash: md5 + md5: 9cd54391a16400664710c9f0589a4d5f + size: 22044 + - path: ddos/plots/symmetric_vs_metric_train_time.pdf + hash: md5 + md5: 0397f39f681300638b6fcc7c2d4e3bda + size: 21616 + plot@kdd_nsl-gzip_knn: + cmd: python -m deckard.layers.plots --path kdd_nsl/plots/ --file kdd_nsl/plots/clean_gzip_knn.csv -c + conf/plots.yaml + deps: + - path: kdd_nsl/plots/clean_gzip_knn.csv + hash: md5 + md5: 1c001f5a7008b439ee4c7946998cbe25 + size: 1002255 + params: + conf/plots.yaml: + cat_plot: + - file: symmetric_vs_metric.pdf + x: model.init.symmetric + y: accuracy + hue: model.init.metric + errorbar: se + kind: bar + titles: + xlabels: '' + ylabels: Accuracy + legend_title: Metrics + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: linear + ylim: + - 0 + - 1 + - file: symmetric_vs_metric_train_time.pdf + x: model.init.symmetric + y: train_time + hue: model.init.metric + errorbar: se + kind: bar + titles: + xlabels: '' + ylabels: Training Time (s) + legend_title: Metrics + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: log + - file: models_vs_accuracy.pdf + x: model_name + y: accuracy + hue: dataset + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Accuracy + legend_title: Samples + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: linear + ylim: + - 0 + - 1 + rotation: 90 + - file: models_vs_train_time.pdf + x: model_name + y: train_time + hue: dataset + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Training Time (s) + legend_title: Samples + rotation: 90 + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: log + - file: models_vs_predict_time.pdf + x: model_name + y: predict_time + hue: dataset + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Prediction Time (s) + legend_title: Samples + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: log + rotation: 90 + line_plot: + - file: metric_vs_accuracy.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: accuracy + ylabel: Accuracy + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + - file: metric_vs_train_time.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: train_time + ylabel: Training Time (s) + y_scale: log + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + - file: metric_vs_predict_time.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: predict_time + ylabel: Prediction Time (s) + y_scale: log + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + outs: + - path: kdd_nsl/plots/metric_vs_accuracy.pdf + hash: md5 + md5: a146ab8c45d548ecd6c285a40c5d49e7 + size: 23228 + - path: kdd_nsl/plots/metric_vs_predict_time.pdf + hash: md5 + md5: 59f7befb701cf34c5bf62a78206d7867 + size: 22642 + - path: kdd_nsl/plots/metric_vs_train_time.pdf + hash: md5 + md5: 938036a897293cbf7dc0b4caa19a5596 + size: 22182 + - path: kdd_nsl/plots/models_vs_accuracy.pdf + hash: md5 + md5: 0dad2f21fc6049c3a24972a35514ee71 + size: 15035 + - path: kdd_nsl/plots/models_vs_predict_time.pdf + hash: md5 + md5: 4361ffb492bff25d3cde95fcdb941ced + size: 16578 + - path: kdd_nsl/plots/models_vs_train_time.pdf + hash: md5 + md5: 416681afbf2e0e87dcc7dfe97f0835fc + size: 16239 + - path: kdd_nsl/plots/symmetric_vs_metric.pdf + hash: md5 + md5: 05a28fb9adea7b847f396fdd96c37d02 + size: 22208 + - path: kdd_nsl/plots/symmetric_vs_metric_train_time.pdf + hash: md5 + md5: 0a0a9daf98ab6efe98cb31b69cba2c65 + size: 21578 + plot@truthseeker-gzip_knn: + cmd: python -m deckard.layers.plots --path truthseeker/plots/ --file truthseeker/plots/clean_gzip_knn.csv -c + conf/plots.yaml + deps: + - path: truthseeker/plots/clean_gzip_knn.csv + hash: md5 + md5: ff0162ac672b57d59126b965580901d9 + size: 620009 + params: + conf/plots.yaml: + cat_plot: + - file: symmetric_vs_metric.pdf + x: model.init.symmetric + y: accuracy + hue: model.init.metric + errorbar: se + kind: bar + titles: + xlabels: '' + ylabels: Accuracy + legend_title: Metrics + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: linear + ylim: + - 0 + - 1 + - file: symmetric_vs_metric_train_time.pdf + x: model.init.symmetric + y: train_time + hue: model.init.metric + errorbar: se + kind: bar + titles: + xlabels: '' + ylabels: Training Time (s) + legend_title: Metrics + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: log + - file: models_vs_accuracy.pdf + x: model_name + y: accuracy + hue: dataset + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Accuracy + legend_title: Samples + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: linear + ylim: + - 0 + - 1 + rotation: 90 + - file: models_vs_train_time.pdf + x: model_name + y: train_time + hue: dataset + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Training Time (s) + legend_title: Samples + rotation: 90 + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: log + - file: models_vs_predict_time.pdf + x: model_name + y: predict_time + hue: dataset + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Prediction Time (s) + legend_title: Samples + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: log + rotation: 90 + line_plot: + - file: metric_vs_accuracy.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: accuracy + ylabel: Accuracy + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + - file: metric_vs_train_time.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: train_time + ylabel: Training Time (s) + y_scale: log + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + - file: metric_vs_predict_time.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: predict_time + ylabel: Prediction Time (s) + y_scale: log + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + outs: + - path: truthseeker/plots/metric_vs_accuracy.pdf + hash: md5 + md5: 3cef9a04adf0d3378d4627c1a8b097a7 + size: 23348 + - path: truthseeker/plots/metric_vs_predict_time.pdf + hash: md5 + md5: a4a5f2426ffaf289e124fb09235e374b + size: 22838 + - path: truthseeker/plots/metric_vs_train_time.pdf + hash: md5 + md5: cda8914da9fabcfb40ea1eb0943e28d3 + size: 22333 + - path: truthseeker/plots/models_vs_accuracy.pdf + hash: md5 + md5: 7ef865e460d2652c873cfe333e7a308d + size: 15215 + - path: truthseeker/plots/models_vs_predict_time.pdf + hash: md5 + md5: eb57bd848d231a47615e311dbd1102b1 + size: 17930 + - path: truthseeker/plots/models_vs_train_time.pdf + hash: md5 + md5: e7bc6589ed86e8f5c3fbb5a747c652fe + size: 17739 + - path: truthseeker/plots/symmetric_vs_metric.pdf + hash: md5 + md5: 0e7c326bef4c0d835f810c67172b2698 + size: 22057 + - path: truthseeker/plots/symmetric_vs_metric_train_time.pdf + hash: md5 + md5: ce21956e382cc48f0a71ef7ccfd79751 + size: 21593 + plot@sms_spam-gzip_knn: + cmd: python -m deckard.layers.plots --path sms_spam/plots/ --file sms_spam/plots/clean_gzip_knn.csv -c + conf/plots.yaml + deps: + - path: sms_spam/plots/clean_gzip_knn.csv + hash: md5 + md5: 13a5803849f7dfdefe18ba16b0a5010f + size: 448070 + params: + conf/plots.yaml: + cat_plot: + - file: symmetric_vs_metric.pdf + x: model.init.symmetric + y: accuracy + hue: model.init.metric + errorbar: se + kind: bar + titles: + xlabels: '' + ylabels: Accuracy + legend_title: Metrics + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: linear + ylim: + - 0 + - 1 + - file: symmetric_vs_metric_train_time.pdf + x: model.init.symmetric + y: train_time + hue: model.init.metric + errorbar: se + kind: bar + titles: + xlabels: '' + ylabels: Training Time (s) + legend_title: Metrics + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: log + - file: models_vs_accuracy.pdf + x: model_name + y: accuracy + hue: dataset + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Accuracy + legend_title: Samples + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: linear + ylim: + - 0 + - 1 + rotation: 90 + - file: models_vs_train_time.pdf + x: model_name + y: train_time + hue: dataset + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Training Time (s) + legend_title: Samples + rotation: 90 + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: log + - file: models_vs_predict_time.pdf + x: model_name + y: predict_time + hue: dataset + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Prediction Time (s) + legend_title: Samples + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + set: + yscale: log + rotation: 90 + line_plot: + - file: metric_vs_accuracy.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: accuracy + ylabel: Accuracy + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + - file: metric_vs_train_time.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: train_time + ylabel: Training Time (s) + y_scale: log + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + - file: metric_vs_predict_time.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: predict_time + ylabel: Prediction Time (s) + y_scale: log + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + outs: + - path: sms_spam/plots/metric_vs_accuracy.pdf + hash: md5 + md5: 507715814c07145dbb140b2b6714973b + size: 23499 + - path: sms_spam/plots/metric_vs_predict_time.pdf + hash: md5 + md5: 97ec5498625837c79fc02850afba09f1 + size: 22606 + - path: sms_spam/plots/metric_vs_train_time.pdf + hash: md5 + md5: f4c9d0805ea5d0ac8e1a2210ee788d47 + size: 22104 + - path: sms_spam/plots/models_vs_accuracy.pdf + hash: md5 + md5: 2eb9ea23cba4e5b734565b7aacdcf43c + size: 14146 + - path: sms_spam/plots/models_vs_predict_time.pdf + hash: md5 + md5: b518bf6b070e7916ad71febd3d3face6 + size: 15523 + - path: sms_spam/plots/models_vs_train_time.pdf + hash: md5 + md5: 617f20892ba643f5c47077af63ae727f + size: 14895 + - path: sms_spam/plots/symmetric_vs_metric.pdf + hash: md5 + md5: 40aa8607331327c4f667fda367defb5f + size: 22033 + - path: sms_spam/plots/symmetric_vs_metric_train_time.pdf + hash: md5 + md5: 775c0bdfc7d9524f1e63b8879ddefccd + size: 21590 + merge@truthseeker: + cmd: python merge.py --big_dir truthseeker/plots/ --data_file clean/gzip_knn.csv + --little_dir_data_file clean/gzip_logistic.csv clean/gzip_svc.csv --output_folder + truthseeker/plots --output_file merged.csv + deps: + - path: truthseeker/plots/clean/gzip_knn.csv + hash: md5 + md5: 1f46e4b3afd875ee11939b23bd1c0852 + size: 560551 + - path: truthseeker/plots/clean/gzip_logistic.csv + hash: md5 + md5: 82450f3b94f517f586b35ed85b494add + size: 417258 + - path: truthseeker/plots/clean/gzip_svc.csv + hash: md5 + md5: cdb96b7ba00dc0bf6b4c8db38311447b + size: 679004 + outs: + - path: truthseeker/plots/merged.csv + hash: md5 + md5: a9b4f71f4d7eccde5a901730969b0bb1 + size: 1711555 + merge@sms_spam: + cmd: python merge.py --big_dir sms_spam/plots/ --data_file clean/gzip_knn.csv + --little_dir_data_file clean/gzip_logistic.csv clean/gzip_svc.csv --output_folder + sms_spam/plots --output_file merged.csv + deps: + - path: sms_spam/plots/clean/gzip_knn.csv + hash: md5 + md5: 020bbec4f2594935bd33efdcdf90eba7 + size: 358497 + - path: sms_spam/plots/clean/gzip_logistic.csv + hash: md5 + md5: d9a1be37cfb498a7d87c116db6f553e2 + size: 497702 + - path: sms_spam/plots/clean/gzip_svc.csv + hash: md5 + md5: 4455964d2014f4705b4ea3191cef40b2 + size: 588874 + outs: + - path: sms_spam/plots/merged.csv + hash: md5 + md5: 3e3e63943b3d62dddc79e554cb691405 + size: 1492939 + merge@ddos: + cmd: python merge.py --big_dir ddos/plots/ --data_file clean/gzip_knn.csv --little_dir_data_file + clean/gzip_logistic.csv clean/gzip_svc.csv --output_folder ddos/plots --output_file + merged.csv + deps: + - path: ddos/plots/clean/gzip_knn.csv + hash: md5 + md5: ad6773d0af82535d3c525f8bf405bbfe + size: 1919757 + - path: ddos/plots/clean/gzip_logistic.csv + hash: md5 + md5: a7d5cf7362711724ae19bba3becf66d2 + size: 1523208 + - path: ddos/plots/clean/gzip_svc.csv + hash: md5 + md5: 45515bad8f1a4167a7a64d0a3d62464e + size: 1842449 + outs: + - path: ddos/plots/merged.csv + hash: md5 + md5: 2fd123789b3c749a653aa9c142d23858 + size: 5465498 + merge@kdd_nsl: + cmd: python merge.py --big_dir kdd_nsl/plots/ --data_file clean/gzip_knn.csv --little_dir_data_file + clean/gzip_logistic.csv clean/gzip_svc.csv --output_folder kdd_nsl/plots --output_file + merged.csv + deps: + - path: kdd_nsl/plots/clean/gzip_knn.csv + hash: md5 + md5: 686b0f04494630491244a6ead99949b7 + size: 996268 + - path: kdd_nsl/plots/clean/gzip_logistic.csv + hash: md5 + md5: 82d8bddbe4db8eb6835d00931af7fc12 + size: 1456814 + - path: kdd_nsl/plots/clean/gzip_svc.csv + hash: md5 + md5: a359fb46b83265dec352e0af17f19cb2 + size: 1771361 + outs: + - path: kdd_nsl/plots/merged.csv + hash: md5 + md5: 7817c0dd6f149eb072f4a5c787fa9655 + size: 4361588 + plot@kdd_nsl: + cmd: python -m deckard.layers.plots --path kdd_nsl/plots/ --file kdd_nsl/plots/merged.csv -c + conf/plots.yaml + deps: + - path: kdd_nsl/plots/merged.csv + hash: md5 + md5: 7817c0dd6f149eb072f4a5c787fa9655 + size: 4361588 + params: + conf/plots.yaml: + cat_plot: + - file: symmetric_vs_metric.pdf + x: model.init.symmetric + y: accuracy + hue: model.init.metric + errorbar: se + kind: bar + titles: + xlabels: '' + ylabels: Accuracy + legend_title: Metrics + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: linear + ylim: + - 0 + - 1 + - file: symmetric_vs_metric_train_time.pdf + x: model.init.symmetric + y: train_time + hue: model.init.metric + errorbar: se + kind: bar + titles: + xlabels: '' + ylabels: Training Time (s) + legend_title: Metrics + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: log + - file: models_vs_accuracy.pdf + x: model_name + y: accuracy + hue: data.sample.train_size + errorbar: se + kind: boxen + titles: + xlabels: Model + ylabels: Accuracy + legend_title: Samples + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: linear + ylim: + - 0 + - 1 + rotation: 90 + - file: models_vs_train_time.pdf + x: model_name + y: accuracy + hue: data.sample.train_size + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Training Time (s) + legend_title: Samples + rotation: 90 + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: log + - file: models_vs_predict_time.pdf + x: model_name + y: accuracy + hue: data.sample.train_size + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Prediction Time (s) + legend_title: Samples + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: log + rotation: 90 + line_plot: + - file: metric_vs_accuracy.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: accuracy + ylabel: Accuracy + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + - file: metric_vs_train_time.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: train_time + ylabel: Training Time (s) + y_scale: linear + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + - file: metric_vs_predict_time.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: predict_time + ylabel: Prediction Time (s) + y_scale: linear + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + outs: + - path: kdd_nsl/plots/metric_vs_accuracy.pdf + hash: md5 + md5: 2abfc1441c3515f07d2e28459e730a4f + size: 24689 + - path: kdd_nsl/plots/metric_vs_predict_time.pdf + hash: md5 + md5: d91c94bf17617b79b2a417710efb9dfc + size: 23239 + - path: kdd_nsl/plots/metric_vs_train_time.pdf + hash: md5 + md5: d2c40b3e36886868c650917d02015be4 + size: 24227 + - path: kdd_nsl/plots/models_vs_accuracy.pdf + hash: md5 + md5: c6807ba0356e42159d683a2b3ab610a9 + size: 23546 + - path: kdd_nsl/plots/models_vs_predict_time.pdf + hash: md5 + md5: 2f6d79e1a5164884b87ef3f40bdafeeb + size: 19370 + - path: kdd_nsl/plots/models_vs_train_time.pdf + hash: md5 + md5: 30ed28915c3ff6de16fffbf8c6bdda45 + size: 18949 + - path: kdd_nsl/plots/symmetric_vs_metric.pdf + hash: md5 + md5: 1d0bb7d03823bb54b5b12b50dbc6615c + size: 22232 + - path: kdd_nsl/plots/symmetric_vs_metric_train_time.pdf + hash: md5 + md5: 802d5119895198601ba2ee24b3cc9528 + size: 21618 + plot@truthseeker: + cmd: python -m deckard.layers.plots --path truthseeker/plots/ --file truthseeker/plots/merged.csv -c + conf/plots.yaml + deps: + - path: truthseeker/plots/merged.csv + hash: md5 + md5: a9b4f71f4d7eccde5a901730969b0bb1 + size: 1711555 + params: + conf/plots.yaml: + cat_plot: + - file: symmetric_vs_metric.pdf + x: model.init.symmetric + y: accuracy + hue: model.init.metric + errorbar: se + kind: bar + titles: + xlabels: '' + ylabels: Accuracy + legend_title: Metrics + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: linear + ylim: + - 0 + - 1 + - file: symmetric_vs_metric_train_time.pdf + x: model.init.symmetric + y: train_time + hue: model.init.metric + errorbar: se + kind: bar + titles: + xlabels: '' + ylabels: Training Time (s) + legend_title: Metrics + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: log + - file: models_vs_accuracy.pdf + x: model_name + y: accuracy + hue: data.sample.train_size + errorbar: se + kind: boxen + titles: + xlabels: Model + ylabels: Accuracy + legend_title: Samples + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: linear + ylim: + - 0 + - 1 + rotation: 90 + - file: models_vs_train_time.pdf + x: model_name + y: accuracy + hue: data.sample.train_size + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Training Time (s) + legend_title: Samples + rotation: 90 + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: log + - file: models_vs_predict_time.pdf + x: model_name + y: accuracy + hue: data.sample.train_size + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Prediction Time (s) + legend_title: Samples + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: log + rotation: 90 + line_plot: + - file: metric_vs_accuracy.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: accuracy + ylabel: Accuracy + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + - file: metric_vs_train_time.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: train_time + ylabel: Training Time (s) + y_scale: linear + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + - file: metric_vs_predict_time.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: predict_time + ylabel: Prediction Time (s) + y_scale: linear + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + outs: + - path: truthseeker/plots/metric_vs_accuracy.pdf + hash: md5 + md5: 935a8c7365ac4b738a1ab222357db671 + size: 23824 + - path: truthseeker/plots/metric_vs_predict_time.pdf + hash: md5 + md5: d5095d1375ed12b1a9b9f8ce5bfee839 + size: 22984 + - path: truthseeker/plots/metric_vs_train_time.pdf + hash: md5 + md5: c6dec8707d3da6a57eb64874b8489aa1 + size: 23404 + - path: truthseeker/plots/models_vs_accuracy.pdf + hash: md5 + md5: c09acc549b30af58463a3a8af31b80d1 + size: 20437 + - path: truthseeker/plots/models_vs_predict_time.pdf + hash: md5 + md5: ff7ffac5905b059ec6670c9220caf124 + size: 18153 + - path: truthseeker/plots/models_vs_train_time.pdf + hash: md5 + md5: f48cdb573700e225810e4ed960768e57 + size: 17725 + - path: truthseeker/plots/symmetric_vs_metric.pdf + hash: md5 + md5: 4b92b154563b9c13bb5f177d0e106002 + size: 22192 + - path: truthseeker/plots/symmetric_vs_metric_train_time.pdf + hash: md5 + md5: 2013309b971cea5728652df1a18ece16 + size: 21586 + plot@sms_spam: + cmd: python -m deckard.layers.plots --path sms_spam/plots/ --file sms_spam/plots/merged.csv -c + conf/plots.yaml + deps: + - path: sms_spam/plots/merged.csv + hash: md5 + md5: 3e3e63943b3d62dddc79e554cb691405 + size: 1492939 + params: + conf/plots.yaml: + cat_plot: + - file: symmetric_vs_metric.pdf + x: model.init.symmetric + y: accuracy + hue: model.init.metric + errorbar: se + kind: bar + titles: + xlabels: '' + ylabels: Accuracy + legend_title: Metrics + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: linear + ylim: + - 0 + - 1 + - file: symmetric_vs_metric_train_time.pdf + x: model.init.symmetric + y: train_time + hue: model.init.metric + errorbar: se + kind: bar + titles: + xlabels: '' + ylabels: Training Time (s) + legend_title: Metrics + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: log + - file: models_vs_accuracy.pdf + x: model_name + y: accuracy + hue: data.sample.train_size + errorbar: se + kind: boxen + titles: + xlabels: Model + ylabels: Accuracy + legend_title: Samples + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: linear + ylim: + - 0 + - 1 + rotation: 90 + - file: models_vs_train_time.pdf + x: model_name + y: accuracy + hue: data.sample.train_size + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Training Time (s) + legend_title: Samples + rotation: 90 + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: log + - file: models_vs_predict_time.pdf + x: model_name + y: accuracy + hue: data.sample.train_size + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Prediction Time (s) + legend_title: Samples + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: log + rotation: 90 + line_plot: + - file: metric_vs_accuracy.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: accuracy + ylabel: Accuracy + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + - file: metric_vs_train_time.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: train_time + ylabel: Training Time (s) + y_scale: linear + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + - file: metric_vs_predict_time.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: predict_time + ylabel: Prediction Time (s) + y_scale: linear + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + outs: + - path: sms_spam/plots/metric_vs_accuracy.pdf + hash: md5 + md5: 695e96d374959cef893859230a15f1a7 + size: 24667 + - path: sms_spam/plots/metric_vs_predict_time.pdf + hash: md5 + md5: 857505ffce8416303759a76cb29b26a3 + size: 23552 + - path: sms_spam/plots/metric_vs_train_time.pdf + hash: md5 + md5: 98b34d861b84d36cb30f58c763445eb7 + size: 23637 + - path: sms_spam/plots/models_vs_accuracy.pdf + hash: md5 + md5: 3d9cda5e091398ec195ff1c763fb0b5a + size: 23033 + - path: sms_spam/plots/models_vs_predict_time.pdf + hash: md5 + md5: 06ae4883133a4f2bb4c19f531c693fdd + size: 19365 + - path: sms_spam/plots/models_vs_train_time.pdf + hash: md5 + md5: f8af33a8abf0caf4fc83a69b6af565a0 + size: 18945 + - path: sms_spam/plots/symmetric_vs_metric.pdf + hash: md5 + md5: 43b4f4865931fca59079491745c20f1c + size: 22231 + - path: sms_spam/plots/symmetric_vs_metric_train_time.pdf + hash: md5 + md5: 4f5b0a9ac3efe2e0daa225f79fe0e40c + size: 21606 + plot@ddos: + cmd: python -m deckard.layers.plots --path ddos/plots/ --file ddos/plots/merged.csv -c + conf/plots.yaml + deps: + - path: ddos/plots/merged.csv + hash: md5 + md5: 2fd123789b3c749a653aa9c142d23858 + size: 5465498 + params: + conf/plots.yaml: + cat_plot: + - file: symmetric_vs_metric.pdf + x: model.init.symmetric + y: accuracy + hue: model.init.metric + errorbar: se + kind: bar + titles: + xlabels: '' + ylabels: Accuracy + legend_title: Metrics + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: linear + ylim: + - 0 + - 1 + - file: symmetric_vs_metric_train_time.pdf + x: model.init.symmetric + y: train_time + hue: model.init.metric + errorbar: se + kind: bar + titles: + xlabels: '' + ylabels: Training Time (s) + legend_title: Metrics + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: log + - file: models_vs_accuracy.pdf + x: model_name + y: accuracy + hue: data.sample.train_size + errorbar: se + kind: boxen + titles: + xlabels: Model + ylabels: Accuracy + legend_title: Samples + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: linear + ylim: + - 0 + - 1 + rotation: 90 + - file: models_vs_train_time.pdf + x: model_name + y: accuracy + hue: data.sample.train_size + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Training Time (s) + legend_title: Samples + rotation: 90 + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: log + - file: models_vs_predict_time.pdf + x: model_name + y: accuracy + hue: data.sample.train_size + errorbar: se + kind: bar + titles: + xlabels: Model + ylabels: Prediction Time (s) + legend_title: Samples + legend: + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + set: + yscale: log + rotation: 90 + line_plot: + - file: metric_vs_accuracy.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: accuracy + ylabel: Accuracy + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + - file: metric_vs_train_time.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: train_time + ylabel: Training Time (s) + y_scale: linear + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + - file: metric_vs_predict_time.pdf + hue: model.init.metric + title: + x: data.sample.train_size + xlabel: Number of Training Samples + y: predict_time + ylabel: Prediction Time (s) + y_scale: linear + hue_order: + - Gzip + - Pickle + - BZ2 + - Zstd + - Lzma + - Levenshtein + - Ratio + - Hamming + - Jaro + - Jaro-Winkler + - SeqRatio + errorbar: se + err_style: bars + xlim: + - 10 + - 500 + legend: + title: Metrics + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + outs: + - path: ddos/plots/metric_vs_accuracy.pdf + hash: md5 + md5: 3b2f9c2885d331a0cadd339177318f3f + size: 24827 + - path: ddos/plots/metric_vs_predict_time.pdf + hash: md5 + md5: 56c78e45d5932c61b339753810a6fed1 + size: 24347 + - path: ddos/plots/metric_vs_train_time.pdf + hash: md5 + md5: 7ba195f1f39c450c7ebd9165eee97f32 + size: 22962 + - path: ddos/plots/models_vs_accuracy.pdf + hash: md5 + md5: 4e5e04199aa08c3098632cf8fad2c744 + size: 23780 + - path: ddos/plots/models_vs_predict_time.pdf + hash: md5 + md5: 41c0c84e0b3b737273692f10c366b275 + size: 19529 + - path: ddos/plots/models_vs_train_time.pdf + hash: md5 + md5: 38dd71a6ac8cd50294d5b81bffd8425b + size: 19106 + - path: ddos/plots/symmetric_vs_metric.pdf + hash: md5 + md5: 72331f97089e5465a2df8a071f6dcf10 + size: 22223 + - path: ddos/plots/symmetric_vs_metric_train_time.pdf + hash: md5 + md5: 3014b61ef7c5fe2e5276149ecd20625b + size: 22143 + condense@truthseeker-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.test_size=100 model_name=gzip_logistic model=best_gzip_logistic_truthseeker + hydra.sweeper.study_name=condense_gzip_logistic_truthseeker hydra.sweeper.n_trials=128 + hydra.sweeper.n_jobs=8 hydra.sweep.dir=truthseeker/logs/condense/gzip_logistic/ + hydra.callbacks.study_dump.output_file=truthseeker/logs/gzip_logistic/study.csv + model.init.m='tag(log, interval(.01, .1))' +model.init.sampling_method=medoid,sum,svc,random,hardness,nearmiss,knn + files.directory=truthseeker files.reports=reports/condense/gzip_logistic/ hydra.launcher.n_jobs=16 + --config-name condense --multirun + deps: + - path: conf/model/best_gzip_logistic_truthseeker.yaml + hash: md5 + md5: 448e12c542f48c074057e9374743d61e + size: 326 + - path: truthseeker/logs/method/ + hash: md5 + md5: 6f6693db2bb9520dc7956f0d0c003e23.dir + size: 116543 + nfiles: 44 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: ??? + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 2 + direction: ${direction} + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: truthseeker/logs/condense/gzip_logistic/ + hash: md5 + md5: 79d74a0dfe0486ada3f03b24c68973dc.dir + size: 1576129 + nfiles: 513 + - path: truthseeker/reports/condense/gzip_logistic/ + hash: md5 + md5: 3de3011b1d96e4990111f5b1601e3b9d.dir + size: 400559 + nfiles: 343 + condense@ddos-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.test_size=100 + model_name=gzip_knn model=best_gzip_knn_ddos hydra.sweeper.study_name=condense_gzip_knn_ddos + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=ddos/logs/condense/gzip_knn/ + hydra.callbacks.study_dump.output_file=ddos/logs/gzip_knn/study.csv model.init.m='tag(log, + interval(.01, .1))' +model.init.sampling_method=medoid,sum,svc,random,hardness,nearmiss,knn + files.directory=ddos files.reports=reports/condense/gzip_knn/ hydra.launcher.n_jobs=16 + --config-name condense --multirun + deps: + - path: conf/model/best_gzip_knn_ddos.yaml + hash: md5 + md5: 74721f3e7ab6096e246c486d6080e1ab + size: 259 + - path: ddos/logs/method/ + hash: md5 + md5: 7128c67930147170f54fb89880528199.dir + size: 120518 + nfiles: 48 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: ??? + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 2 + direction: ${direction} + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: ddos/logs/condense/gzip_knn/ + hash: md5 + md5: a2dc5aef876897f53c4076e4012b678a.dir + size: 1542474 + nfiles: 513 + - path: ddos/reports/condense/gzip_knn/ + hash: md5 + md5: 781709e87f2e740f6a0f4e914ee9754f.dir + size: 340848 + nfiles: 379 + condense@ddos-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.test_size=100 + model_name=gzip_logistic model=best_gzip_logistic_ddos hydra.sweeper.study_name=condense_gzip_logistic_ddos + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=ddos/logs/condense/gzip_logistic/ + hydra.callbacks.study_dump.output_file=ddos/logs/gzip_logistic/study.csv model.init.m='tag(log, + interval(.01, .1))' +model.init.sampling_method=medoid,sum,svc,random,hardness,nearmiss,knn + files.directory=ddos files.reports=reports/condense/gzip_logistic/ hydra.launcher.n_jobs=16 + --config-name condense --multirun + deps: + - path: conf/model/best_gzip_logistic_ddos.yaml + hash: md5 + md5: 9507b28fa5a18b501fe9d80ec33bed1c + size: 334 + - path: ddos/logs/method/ + hash: md5 + md5: 7128c67930147170f54fb89880528199.dir + size: 120518 + nfiles: 48 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: ??? + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 2 + direction: ${direction} + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: ddos/logs/condense/gzip_logistic/ + hash: md5 + md5: 4f8f846516837f0e7cd63c8911aff99a.dir + size: 1623568 + nfiles: 513 + - path: ddos/reports/condense/gzip_logistic/ + hash: md5 + md5: 051b71717b4a7986a1965ebadf448838.dir + size: 350870 + nfiles: 384 + condense@kdd_nsl-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=kdd_nsl dataset=kdd_nsl + data.sample.test_size=100 model_name=gzip_knn model=best_gzip_knn_kdd_nsl hydra.sweeper.study_name=condense_gzip_knn_kdd_nsl + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=kdd_nsl/logs/condense/gzip_knn/ + hydra.callbacks.study_dump.output_file=kdd_nsl/logs/gzip_knn/study.csv model.init.m='tag(log, + interval(.01, .1))' +model.init.sampling_method=medoid,sum,svc,random,hardness,nearmiss,knn + files.directory=kdd_nsl files.reports=reports/condense/gzip_knn/ hydra.launcher.n_jobs=16 + --config-name condense --multirun + deps: + - path: conf/model/best_gzip_knn_kdd_nsl.yaml + hash: md5 + md5: 2697918626643d0136286367b83ee6b9 + size: 258 + - path: kdd_nsl/logs/method/ + hash: md5 + md5: de8764bbb2daa13261f3f5d1dff27a30.dir + size: 79348 + nfiles: 28 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: ??? + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 2 + direction: ${direction} + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: kdd_nsl/logs/condense/gzip_knn/ + hash: md5 + md5: 7d53f3534ceb486e6601d344562cfb32.dir + size: 1564530 + nfiles: 513 + - path: kdd_nsl/reports/condense/gzip_knn/ + hash: md5 + md5: 7e5a283215281be3ee4189ebd5a6e3f1.dir + size: 342924 + nfiles: 384 + parse_params: + cmd: python -m deckard.layers.parse + deps: + - path: conf/data/default.yaml + hash: md5 + md5: 86639d6672cfd9529dda3e2ae4036c01 + size: 22 + - path: conf/default.yaml + hash: md5 + md5: a0a533f84a7ffce197e0db5439219faf + size: 1504 + - path: conf/files/default.yaml + hash: md5 + md5: 7a2df5f8b98699376c3fb4da05d70dea + size: 306 + - path: conf/model/default.yaml + hash: md5 + md5: 39dc7512b1d19fea54550b080d880153 + size: 27 + - path: conf/scorers/default.yaml + hash: md5 + md5: d8d00e7d284ea68b1244743dfef8f00c + size: 280 + outs: + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + test_each_metric@gzip-gzip_knn-kdd_nsl-20: + cmd: 'python -m deckard.layers.optimise stage=test_each_metric files.name=gzip_knn/gzip/20 + files.directory=kdd_nsl data=kdd_nsl data.sample.train_size=20 dataset=kdd_nsl + model=gzip_knn model_name=gzip_knn model.init.metric=gzip model.init.m=-1 hydra.run.dir=kdd_nsl/logs/test_each_metric/gzip_knn/gzip/20 + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/test_each_metric/gzip_knn/gzip/20 + hash: md5 + md5: 6091388fcd68296e6ccd16f0955cba96.dir + size: 7683 + nfiles: 4 + - path: kdd_nsl/reports/test_each_metric/gzip_knn/gzip/20/score_dict.json + hash: md5 + md5: 5d8bf090bc8e34df8ed01766adfca5eb + size: 26 + test_each_metric@zstd-gzip_knn-kdd_nsl-20: + cmd: 'python -m deckard.layers.optimise stage=test_each_metric files.name=gzip_knn/zstd/20 + files.directory=kdd_nsl data=kdd_nsl data.sample.train_size=20 dataset=kdd_nsl + model=gzip_knn model_name=gzip_knn model.init.metric=zstd model.init.m=-1 hydra.run.dir=kdd_nsl/logs/test_each_metric/gzip_knn/zstd/20 + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/test_each_metric/gzip_knn/zstd/20 + hash: md5 + md5: 704acd4e060b20b19dd8c6528ee42b02.dir + size: 7683 + nfiles: 4 + - path: kdd_nsl/reports/test_each_metric/gzip_knn/zstd/20/score_dict.json + hash: md5 + md5: 5d8bf090bc8e34df8ed01766adfca5eb + size: 26 + test_each_metric@pkl-gzip_knn-kdd_nsl-20: + cmd: 'python -m deckard.layers.optimise stage=test_each_metric files.name=gzip_knn/pkl/20 + files.directory=kdd_nsl data=kdd_nsl data.sample.train_size=20 dataset=kdd_nsl + model=gzip_knn model_name=gzip_knn model.init.metric=pkl model.init.m=-1 hydra.run.dir=kdd_nsl/logs/test_each_metric/gzip_knn/pkl/20 + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/test_each_metric/gzip_knn/pkl/20 + hash: md5 + md5: 539ec713f43133226c23d088f60a66bf.dir + size: 7668 + nfiles: 4 + - path: kdd_nsl/reports/test_each_metric/gzip_knn/pkl/20/score_dict.json + hash: md5 + md5: 5d8bf090bc8e34df8ed01766adfca5eb + size: 26 + test_each_metric@bz2-gzip_knn-kdd_nsl-20: + cmd: 'python -m deckard.layers.optimise stage=test_each_metric files.name=gzip_knn/bz2/20 + files.directory=kdd_nsl data=kdd_nsl data.sample.train_size=20 dataset=kdd_nsl + model=gzip_knn model_name=gzip_knn model.init.metric=bz2 model.init.m=-1 hydra.run.dir=kdd_nsl/logs/test_each_metric/gzip_knn/bz2/20 + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/test_each_metric/gzip_knn/bz2/20 + hash: md5 + md5: dc85f72896e274b978488f36ec121474.dir + size: 7668 + nfiles: 4 + - path: kdd_nsl/reports/test_each_metric/gzip_knn/bz2/20/score_dict.json + hash: md5 + md5: 5d8bf090bc8e34df8ed01766adfca5eb + size: 26 + test_each_metric@lzma-gzip_knn-kdd_nsl-20: + cmd: 'python -m deckard.layers.optimise stage=test_each_metric files.name=gzip_knn/lzma/20 + files.directory=kdd_nsl data=kdd_nsl data.sample.train_size=20 dataset=kdd_nsl + model=gzip_knn model_name=gzip_knn model.init.metric=lzma model.init.m=-1 hydra.run.dir=kdd_nsl/logs/test_each_metric/gzip_knn/lzma/20 + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/test_each_metric/gzip_knn/lzma/20 + hash: md5 + md5: 3e929ed47c2f62267a513fcc9ac7faec.dir + size: 7683 + nfiles: 4 + - path: kdd_nsl/reports/test_each_metric/gzip_knn/lzma/20/score_dict.json + hash: md5 + md5: 5d8bf090bc8e34df8ed01766adfca5eb + size: 26 + test_each_metric@levenshtein-gzip_knn-kdd_nsl-20: + cmd: 'python -m deckard.layers.optimise stage=test_each_metric files.name=gzip_knn/levenshtein/20 + files.directory=kdd_nsl data=kdd_nsl data.sample.train_size=20 dataset=kdd_nsl + model=gzip_knn model_name=gzip_knn model.init.metric=levenshtein model.init.m=-1 + hydra.run.dir=kdd_nsl/logs/test_each_metric/gzip_knn/levenshtein/20 ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/test_each_metric/gzip_knn/levenshtein/20 + hash: md5 + md5: 6e719f5801c71fe88793e4a42fe47b68.dir + size: 7767 + nfiles: 4 + - path: kdd_nsl/reports/test_each_metric/gzip_knn/levenshtein/20/score_dict.json + hash: md5 + md5: 5d8bf090bc8e34df8ed01766adfca5eb + size: 26 + test_each_metric@ratio-gzip_knn-kdd_nsl-20: + cmd: 'python -m deckard.layers.optimise stage=test_each_metric files.name=gzip_knn/ratio/20 + files.directory=kdd_nsl data=kdd_nsl data.sample.train_size=20 dataset=kdd_nsl + model=gzip_knn model_name=gzip_knn model.init.metric=ratio model.init.m=-1 + hydra.run.dir=kdd_nsl/logs/test_each_metric/gzip_knn/ratio/20 ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/test_each_metric/gzip_knn/ratio/20 + hash: md5 + md5: c7917445640a277d2a898413a74442e3.dir + size: 7677 + nfiles: 4 + - path: kdd_nsl/reports/test_each_metric/gzip_knn/ratio/20/score_dict.json + hash: md5 + md5: 5d8bf090bc8e34df8ed01766adfca5eb + size: 26 + test_each_metric@hamming-gzip_knn-kdd_nsl-20: + cmd: 'python -m deckard.layers.optimise stage=test_each_metric files.name=gzip_knn/hamming/20 + files.directory=kdd_nsl data=kdd_nsl data.sample.train_size=20 dataset=kdd_nsl + model=gzip_knn model_name=gzip_knn model.init.metric=hamming model.init.m=-1 + hydra.run.dir=kdd_nsl/logs/test_each_metric/gzip_knn/hamming/20 ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/test_each_metric/gzip_knn/hamming/20 + hash: md5 + md5: 384b5ae13749ca9006486a64dd50faf0.dir + size: 7707 + nfiles: 4 + - path: kdd_nsl/reports/test_each_metric/gzip_knn/hamming/20/score_dict.json + hash: md5 + md5: 5d8bf090bc8e34df8ed01766adfca5eb + size: 26 + test_each_dataset@gzip_knn-kdd_nsl: + cmd: 'python -m deckard.layers.optimise stage=test_each_dataset files.name=gzip_knn + data.sample.train_size=100 files.directory=kdd_nsl data=kdd_nsl dataset=kdd_nsl + model_name=gzip_knn model=gzip_knn hydra.run.dir=kdd_nsl/logs/test_each_dataset/gzip_knn + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 41e95614d524a857c0260b13ce77202b + size: 488 + - path: params.yaml + hash: md5 + md5: 9a178db02b5ad8f990c7a557790a36c7 + size: 1381 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/test_each_dataset/gzip_knn + hash: md5 + md5: 955370e62c64341f4410f3f46f6d84fd.dir + size: 7263 + nfiles: 4 + - path: kdd_nsl/reports/test_each_dataset/gzip_knn/score_dict.json + hash: md5 + md5: 5d8bf090bc8e34df8ed01766adfca5eb + size: 26 + test_each_dataset@gzip_knn-truthseeker: + cmd: 'python -m deckard.layers.optimise stage=test_each_dataset files.name=gzip_knn + data.sample.train_size=100 files.directory=truthseeker data=truthseeker dataset=truthseeker + model_name=gzip_knn model=gzip_knn hydra.run.dir=truthseeker/logs/test_each_dataset/gzip_knn + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 41e95614d524a857c0260b13ce77202b + size: 488 + - path: params.yaml + hash: md5 + md5: 9a178db02b5ad8f990c7a557790a36c7 + size: 1381 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/logs/test_each_dataset/gzip_knn + hash: md5 + md5: f8dd2e14f7e12daed6ebfd9a552d6c4e.dir + size: 7305 + nfiles: 4 + - path: truthseeker/reports/test_each_dataset/gzip_knn/score_dict.json + hash: md5 + md5: 5d8bf090bc8e34df8ed01766adfca5eb + size: 26 + test_each_dataset@ddos-gzip_knn: + cmd: 'python -m deckard.layers.optimise stage=train files.name=gzip_knn data.sample.train_size=100 + files.directory=ddos data=ddos dataset=ddos model_name=gzip_knn model=gzip_knn + hydra.run.dir=ddos/logs/train/gzip_knn ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/logs/train/gzip_knn + hash: md5 + md5: 86973d6369f6a61b442f6387478ccde6.dir + size: 8041 + nfiles: 4 + - path: ddos/reports/train/gzip_knn/score_dict.json + hash: md5 + md5: 1269132e68fc8dff521df51cb2fe321c + size: 284 + test_each_dataset@ddos-gzip_svc: + cmd: 'python -m deckard.layers.optimise stage=train files.name=gzip_svc data.sample.train_size=100 + files.directory=ddos data=ddos dataset=ddos model_name=gzip_svc model=gzip_svc + hydra.run.dir=ddos/logs/train/gzip_svc ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/logs/train/gzip_svc + hash: md5 + md5: 67d472318cba51a8f9e7989991cbf09e.dir + size: 8038 + nfiles: 4 + - path: ddos/reports/train/gzip_svc/score_dict.json + hash: md5 + md5: 5728b15f67d338a4bf8160b60715dce8 + size: 283 + test_each_dataset@ddos-gzip_logistic: + cmd: 'python -m deckard.layers.optimise stage=train files.name=gzip_logistic + data.sample.train_size=100 files.directory=ddos data=ddos dataset=ddos model_name=gzip_logistic + model=gzip_logistic hydra.run.dir=ddos/logs/train/gzip_logistic ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: ddos/logs/train/gzip_logistic + hash: md5 + md5: 24fe0f4f52e6989c5a1c65795ea0d936.dir + size: 8173 + nfiles: 4 + - path: ddos/reports/train/gzip_logistic/score_dict.json + hash: md5 + md5: 259b4ae57c0c1e8d08b72f7f888fbe45 + size: 281 + test_each_dataset@truthseeker-gzip_knn: + cmd: 'python -m deckard.layers.optimise stage=train files.name=gzip_knn data.sample.train_size=100 + files.directory=truthseeker data=truthseeker dataset=truthseeker model_name=gzip_knn + model=gzip_knn hydra.run.dir=truthseeker/logs/train/gzip_knn ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/logs/train/gzip_knn + hash: md5 + md5: ba3eb31317c073b3b07a9c9d1948e656.dir + size: 8158 + nfiles: 4 + - path: truthseeker/reports/train/gzip_knn/score_dict.json + hash: md5 + md5: 2088612d107192d0497e9fd2c569818f + size: 283 + test_each_dataset@truthseeker-gzip_svc: + cmd: 'python -m deckard.layers.optimise stage=train files.name=gzip_svc data.sample.train_size=100 + files.directory=truthseeker data=truthseeker dataset=truthseeker model_name=gzip_svc + model=gzip_svc hydra.run.dir=truthseeker/logs/train/gzip_svc ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/logs/train/gzip_svc + hash: md5 + md5: 4512bda479ab6cd5ae74e7f575928b9d.dir + size: 8154 + nfiles: 4 + - path: truthseeker/reports/train/gzip_svc/score_dict.json + hash: md5 + md5: 25d8ec2a07497188e4311c5d62f9ddb6 + size: 281 + test_each_dataset@truthseeker-gzip_logistic: + cmd: 'python -m deckard.layers.optimise stage=train files.name=gzip_logistic + data.sample.train_size=100 files.directory=truthseeker data=truthseeker dataset=truthseeker + model_name=gzip_logistic model=gzip_logistic hydra.run.dir=truthseeker/logs/train/gzip_logistic + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: truthseeker/logs/train/gzip_logistic + hash: md5 + md5: e1da0260d3c55bfbf4a44bb1b96206ba.dir + size: 8315 + nfiles: 4 + - path: truthseeker/reports/train/gzip_logistic/score_dict.json + hash: md5 + md5: 9ba0565e8f7dcb14a1e45b8e585d9ccb + size: 283 + test_each_dataset@sms_spam-gzip_knn: + cmd: 'python -m deckard.layers.optimise stage=train files.name=gzip_knn data.sample.train_size=100 + files.directory=sms_spam data=sms_spam dataset=sms_spam model_name=gzip_knn + model=gzip_knn hydra.run.dir=sms_spam/logs/train/gzip_knn ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: sms_spam/logs/train/gzip_knn + hash: md5 + md5: 2066e09b41a2f6ce0c835018278b0dc6.dir + size: 8093 + nfiles: 4 + - path: sms_spam/reports/train/gzip_knn/score_dict.json + hash: md5 + md5: 45ab656d14366622402a687082c5feeb + size: 284 + test_each_dataset@sms_spam-gzip_svc: + cmd: 'python -m deckard.layers.optimise stage=train files.name=gzip_svc data.sample.train_size=100 + files.directory=sms_spam data=sms_spam dataset=sms_spam model_name=gzip_svc + model=gzip_svc hydra.run.dir=sms_spam/logs/train/gzip_svc ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: sms_spam/logs/train/gzip_svc + hash: md5 + md5: 4f8d2f14bf8ed23f7443b91640fbb2c0.dir + size: 8090 + nfiles: 4 + - path: sms_spam/reports/train/gzip_svc/score_dict.json + hash: md5 + md5: 6cf7317e720631b93bcd699b22a9c4ec + size: 283 + test_each_dataset@sms_spam-gzip_logistic: + cmd: 'python -m deckard.layers.optimise stage=train files.name=gzip_logistic + data.sample.train_size=100 files.directory=sms_spam data=sms_spam dataset=sms_spam + model_name=gzip_logistic model=gzip_logistic hydra.run.dir=sms_spam/logs/train/gzip_logistic + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: sms_spam/logs/train/gzip_logistic + hash: md5 + md5: e9577cb3ce87a9e0a55da46017111e2a.dir + size: 8225 + nfiles: 4 + - path: sms_spam/reports/train/gzip_logistic/score_dict.json + hash: md5 + md5: 8c39b120c89ed2d1c51c88d99f202ab1 + size: 281 + test_each_dataset@kdd_nsl-gzip_knn: + cmd: 'python -m deckard.layers.optimise stage=train files.name=gzip_knn data.sample.train_size=100 + files.directory=kdd_nsl data=kdd_nsl dataset=kdd_nsl model_name=gzip_knn model=gzip_knn + hydra.run.dir=kdd_nsl/logs/train/gzip_knn ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/train/gzip_knn + hash: md5 + md5: d9f95ac89efb51e0b9474a50ed1ee34d.dir + size: 8108 + nfiles: 4 + - path: kdd_nsl/reports/train/gzip_knn/score_dict.json + hash: md5 + md5: 1bb23417615a5663b20ae3c9bb05ab41 + size: 284 + test_each_dataset@kdd_nsl-gzip_svc: + cmd: 'python -m deckard.layers.optimise stage=train files.name=gzip_svc data.sample.train_size=100 + files.directory=kdd_nsl data=kdd_nsl dataset=kdd_nsl model_name=gzip_svc model=gzip_svc + hydra.run.dir=kdd_nsl/logs/train/gzip_svc ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/train/gzip_svc + hash: md5 + md5: 8efe1af9a07fe35bf35a620aecc9984e.dir + size: 8105 + nfiles: 4 + - path: kdd_nsl/reports/train/gzip_svc/score_dict.json + hash: md5 + md5: 6e851ecef3c53745a566ce54bc9b64e3 + size: 283 + test_each_dataset@kdd_nsl-gzip_logistic: + cmd: 'python -m deckard.layers.optimise stage=train files.name=gzip_logistic + data.sample.train_size=100 files.directory=kdd_nsl data=kdd_nsl dataset=kdd_nsl + model_name=gzip_logistic model=gzip_logistic hydra.run.dir=kdd_nsl/logs/train/gzip_logistic + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/train/gzip_logistic + hash: md5 + md5: b3b1f1813a6bc3b51b1aca53b3730892.dir + size: 8240 + nfiles: 4 + - path: kdd_nsl/reports/train/gzip_logistic/score_dict.json + hash: md5 + md5: ce2f45436d570475e2cd62b1d5417305 + size: 281 + test_each_metric@jaro-gzip_knn-kdd_nsl-20: + cmd: 'python -m deckard.layers.optimise stage=test_each_metric files.name=gzip_knn/jaro/20 + files.directory=kdd_nsl data=kdd_nsl data.sample.train_size=20 dataset=kdd_nsl + model=gzip_knn model_name=gzip_knn model.init.metric=jaro model.init.m=-1 hydra.run.dir=kdd_nsl/logs/test_each_metric/gzip_knn/jaro/20 + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/test_each_metric/gzip_knn/jaro/20 + hash: md5 + md5: 8b71ff09c44e615322095f861b3f1dca.dir + size: 7662 + nfiles: 4 + - path: kdd_nsl/reports/test_each_metric/gzip_knn/jaro/20/score_dict.json + hash: md5 + md5: 5d8bf090bc8e34df8ed01766adfca5eb + size: 26 + test_each_metric@jaro_winkler-gzip_knn-kdd_nsl-20: + cmd: 'python -m deckard.layers.optimise stage=test_each_metric files.name=gzip_knn/jaro_winkler/20 + files.directory=kdd_nsl data=kdd_nsl data.sample.train_size=20 dataset=kdd_nsl + model=gzip_knn model_name=gzip_knn model.init.metric=jaro_winkler model.init.m=-1 + hydra.run.dir=kdd_nsl/logs/test_each_metric/gzip_knn/jaro_winkler/20 ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/test_each_metric/gzip_knn/jaro_winkler/20 + hash: md5 + md5: 2b831c44b315a8b61c3f762b365c8e5f.dir + size: 7782 + nfiles: 4 + - path: kdd_nsl/reports/test_each_metric/gzip_knn/jaro_winkler/20/score_dict.json + hash: md5 + md5: 5d8bf090bc8e34df8ed01766adfca5eb + size: 26 + test_each_metric@seqratio-gzip_knn-kdd_nsl-20: + cmd: 'python -m deckard.layers.optimise stage=test_each_metric files.name=gzip_knn/seqratio/20 + files.directory=kdd_nsl data=kdd_nsl data.sample.train_size=20 dataset=kdd_nsl + model=gzip_knn model_name=gzip_knn model.init.metric=seqratio model.init.m=-1 + hydra.run.dir=kdd_nsl/logs/test_each_metric/gzip_knn/seqratio/20 ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/test_each_metric/gzip_knn/seqratio/20 + hash: md5 + md5: ed632f40ed8ff016cb649ab00c408114.dir + size: 7722 + nfiles: 4 + - path: kdd_nsl/reports/test_each_metric/gzip_knn/seqratio/20/score_dict.json + hash: md5 + md5: 5d8bf090bc8e34df8ed01766adfca5eb + size: 26 + test_each_model@gzip-gzip_knn-kdd_nsl-20: + cmd: 'python -m deckard.layers.optimise stage=test_each_model files.name=gzip_knn/gzip/20 + files.directory=kdd_nsl data=kdd_nsl data.sample.train_size=20 dataset=kdd_nsl + model=gzip_knn model_name=gzip_knn model.init.metric=gzip model.init.m=-1 hydra.run.dir=kdd_nsl/logs/test_each_model/gzip_knn/gzip/20 + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/test_each_model/gzip_knn/gzip/20 + hash: md5 + md5: c8075fa1867cb00a11f6df654086bd97.dir + size: 7675 + nfiles: 4 + - path: kdd_nsl/reports/test_each_model/gzip_knn/gzip/20/score_dict.json + hash: md5 + md5: 5d8bf090bc8e34df8ed01766adfca5eb + size: 26 + test_each_model@gzip-gzip_svc-kdd_nsl-20: + cmd: 'python -m deckard.layers.optimise stage=test_each_model files.name=gzip_svc/gzip/20 + files.directory=kdd_nsl data=kdd_nsl data.sample.train_size=20 dataset=kdd_nsl + model=gzip_svc model_name=gzip_knn model.init.metric=gzip model.init.m=-1 hydra.run.dir=kdd_nsl/logs/test_each_model/gzip_svc/gzip/20 + ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/test_each_model/gzip_svc/gzip/20 + hash: md5 + md5: 6ec9663f42d781dc482f1da6df886312.dir + size: 7678 + nfiles: 4 + - path: kdd_nsl/reports/test_each_model/gzip_svc/gzip/20/score_dict.json + hash: md5 + md5: 5d8bf090bc8e34df8ed01766adfca5eb + size: 26 + test_each_model@gzip-gzip_logistic-kdd_nsl-20: + cmd: 'python -m deckard.layers.optimise stage=test_each_model files.name=gzip_logistic/gzip/20 + files.directory=kdd_nsl data=kdd_nsl data.sample.train_size=20 dataset=kdd_nsl + model=gzip_logistic model_name=gzip_knn model.init.metric=gzip model.init.m=-1 + hydra.run.dir=kdd_nsl/logs/test_each_model/gzip_logistic/gzip/20 ++raise_exception=True ' + deps: + - path: kdd_nsl/reports/train/default/score_dict.json + hash: md5 + md5: 81a03f1290fe4d5eaa739ba9807b5b20 + size: 488 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + params.yaml: + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + dataset: kdd_nsl + device_id: cpu + files: + _target_: deckard.base.files.FileConfig + data_dir: data + data_type: .csv + directory: kdd_nsl + model_dir: model + name: default + params_file: params.yaml + predictions_file: predictions.json + reports: reports + score_dict_file: score_dict.json + model: + _target_: deckard.base.model.Model + data: + _target_: deckard.base.data.Data + name: raw_data/kdd_nsl_undersampled_5000.csv + sample: + _target_: deckard.base.data.SklearnDataSampler + random_state: 0 + stratify: true + test_size: 100 + train_size: 100 + target: label + init: + _target_: deckard.base.model.ModelInitializer + distance_matrix: kdd_nsl/model/gzip/100-100/0.npz + k: 1 + m: -1 + metric: gzip + name: gzip_classifier.GzipKNN + symmetric: false + library: sklearn + model_name: gzip_knn + scorers: + _target_: deckard.base.scorer.ScorerDict + accuracy: + _target_: deckard.base.scorer.ScorerConfig + direction: maximize + name: sklearn.metrics.accuracy_score + log_loss: + _target_: deckard.base.scorer.ScorerConfig + direction: minimize + name: sklearn.metrics.log_loss + outs: + - path: kdd_nsl/logs/test_each_model/gzip_logistic/gzip/20 + hash: md5 + md5: 8ba9f7659cef2c4d610fece176de1548.dir + size: 7767 + nfiles: 4 + - path: kdd_nsl/reports/test_each_model/gzip_logistic/gzip/20/score_dict.json + hash: md5 + md5: 5d8bf090bc8e34df8ed01766adfca5eb + size: 26 + grid_search@20-kdd_nsl-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=kdd_nsl dataset=kdd_nsl + data.sample.train_size=20 data.sample.test_size=100 model_name=gzip_knn model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_knn_kdd_nsl hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=kdd_nsl/logs/gzip_knn/20 hydra.callbacks.study_dump.output_file=kdd_nsl/logs/gzip_knn/20/study.csv + files.directory=kdd_nsl files.reports=reports/gzip_knn/20 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_knn --multirun + deps: + - path: conf/gzip_knn.yaml + hash: md5 + md5: a58015cd6f327e171842b045a2524bfd + size: 2062 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_knn.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k: 1,3,5,7,11 + +model.init.weights: uniform,distance + +model.init.algorithm: brute + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + ++data.sample.random_state: int(interval(1, 10000)) + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_knn + outs: + - path: kdd_nsl/logs/gzip_knn/20 + hash: md5 + md5: 5c03e3e52e7a24e15acbd0b2aadfee35.dir + size: 1389089 + nfiles: 514 + - path: kdd_nsl/reports/gzip_knn/20/train/ + hash: md5 + md5: a7e0e97547bfac97d8518259bffdd4c1.dir + size: 1847622 + nfiles: 1661 + grid_search@20-kdd_nsl-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=kdd_nsl dataset=kdd_nsl + data.sample.train_size=20 data.sample.test_size=100 model_name=gzip_logistic + model.init.distance_matrix=null hydra.sweeper.study_name=gzip_logistic_kdd_nsl + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=kdd_nsl/logs/gzip_logistic/20 + hydra.callbacks.study_dump.output_file=kdd_nsl/logs/gzip_logistic/20/study.csv + files.directory=kdd_nsl files.reports=reports/gzip_logistic/20 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_logistic --multirun + deps: + - path: conf/gzip_logistic.yaml + hash: md5 + md5: 847d4d804fff0b6f2533f90820eebd04 + size: 2205 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_logistic.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 1 + params: + +model.init.solver: saga + +model.init.penalty: l2,l1,l2,none + +model.init.tol: 1e-4,1e-3,1e-2 + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept: True,False + +model.init.class_weight: balanced,None + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_logistic + outs: + - path: kdd_nsl/logs/gzip_logistic/20 + hash: md5 + md5: e7528ce71bad9f745a9f5e4fcf3a2df1.dir + size: 1571121 + nfiles: 514 + - path: kdd_nsl/reports/gzip_logistic/20/train/ + hash: md5 + md5: 127796b95b1817c4b0d9f1846537b0a6.dir + size: 2083086 + nfiles: 1772 + grid_search@20-kdd_nsl-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=kdd_nsl dataset=kdd_nsl + data.sample.train_size=20 data.sample.test_size=100 model_name=gzip_svc model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_svc_kdd_nsl hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=kdd_nsl/logs/gzip_svc/20 hydra.callbacks.study_dump.output_file=kdd_nsl/logs/gzip_svc/20/study.csv + files.directory=kdd_nsl files.reports=reports/gzip_svc/20 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_svc --multirun + deps: + - path: conf/gzip_svc.yaml + hash: md5 + md5: 957922cb6993eb99866232d944a4a106 + size: 2131 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_svc.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: + - maximize + metric_names: + - accuracy + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + params: + +model.init.kernel: rbf,precomputed + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma: scale,auto + +model.init.class_weight: balanced,null + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_svc + outs: + - path: kdd_nsl/logs/gzip_svc/20 + hash: md5 + md5: a1cb35a26808d09dac04aef8fc7106cb.dir + size: 1524012 + nfiles: 514 + - path: kdd_nsl/reports/gzip_svc/20/train/ + hash: md5 + md5: f475c4428240afaaf863bb021eb82890.dir + size: 2095726 + nfiles: 2092 + grid_search@20-truthseeker-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.train_size=20 data.sample.test_size=100 model_name=gzip_knn model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_knn_truthseeker hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=truthseeker/logs/gzip_knn/20 hydra.callbacks.study_dump.output_file=truthseeker/logs/gzip_knn/20/study.csv + files.directory=truthseeker files.reports=reports/gzip_knn/20 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_knn --multirun + deps: + - path: conf/gzip_knn.yaml + hash: md5 + md5: a58015cd6f327e171842b045a2524bfd + size: 2062 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_knn.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k: 1,3,5,7,11 + +model.init.weights: uniform,distance + +model.init.algorithm: brute + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + ++data.sample.random_state: int(interval(1, 10000)) + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_knn + outs: + - path: truthseeker/logs/gzip_knn/20 + hash: md5 + md5: 21da241789a9856418302895c146cd4d.dir + size: 1370161 + nfiles: 514 + - path: truthseeker/reports/gzip_knn/20/train/ + hash: md5 + md5: 394a7d8c033166c958996d646f822460.dir + size: 376291 + nfiles: 340 + grid_search@20-truthseeker-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.train_size=20 data.sample.test_size=100 model_name=gzip_logistic + model.init.distance_matrix=null hydra.sweeper.study_name=gzip_logistic_truthseeker + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=truthseeker/logs/gzip_logistic/20 + hydra.callbacks.study_dump.output_file=truthseeker/logs/gzip_logistic/20/study.csv + files.directory=truthseeker files.reports=reports/gzip_logistic/20 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_logistic --multirun + deps: + - path: conf/gzip_logistic.yaml + hash: md5 + md5: 847d4d804fff0b6f2533f90820eebd04 + size: 2205 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_logistic.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 1 + params: + +model.init.solver: saga + +model.init.penalty: l2,l1,l2,none + +model.init.tol: 1e-4,1e-3,1e-2 + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept: True,False + +model.init.class_weight: balanced,None + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_logistic + outs: + - path: truthseeker/logs/gzip_logistic/20 + hash: md5 + md5: 4eceda9fdfa787e48b4a2d397ad89332.dir + size: 1497002 + nfiles: 514 + - path: truthseeker/reports/gzip_logistic/20/train/ + hash: md5 + md5: 9b32f4ef152eda3a3f2e68d424d163d2.dir + size: 555897 + nfiles: 366 + grid_search@20-truthseeker-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.train_size=20 data.sample.test_size=100 model_name=gzip_svc model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_svc_truthseeker hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=truthseeker/logs/gzip_svc/20 hydra.callbacks.study_dump.output_file=truthseeker/logs/gzip_svc/20/study.csv + files.directory=truthseeker files.reports=reports/gzip_svc/20 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_svc --multirun + deps: + - path: conf/gzip_svc.yaml + hash: md5 + md5: 957922cb6993eb99866232d944a4a106 + size: 2131 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_svc.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: + - maximize + metric_names: + - accuracy + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + params: + +model.init.kernel: rbf,precomputed + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma: scale,auto + +model.init.class_weight: balanced,null + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_svc + outs: + - path: truthseeker/logs/gzip_svc/20 + hash: md5 + md5: 20a01b45b6f1901a8e929bf1cbccd349.dir + size: 1473672 + nfiles: 514 + - path: truthseeker/reports/gzip_svc/20/train/ + hash: md5 + md5: a2b059debfa307134c83ec03713e8a50.dir + size: 546743 + nfiles: 384 + grid_search@20-sms_spam-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.train_size=20 data.sample.test_size=100 model_name=gzip_knn model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_knn_sms_spam hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=sms_spam/logs/gzip_knn/20 hydra.callbacks.study_dump.output_file=sms_spam/logs/gzip_knn/20/study.csv + files.directory=sms_spam files.reports=reports/gzip_knn/20 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_knn --multirun + deps: + - path: conf/gzip_knn.yaml + hash: md5 + md5: a58015cd6f327e171842b045a2524bfd + size: 2062 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_knn.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k: 1,3,5,7,11 + +model.init.weights: uniform,distance + +model.init.algorithm: brute + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + ++data.sample.random_state: int(interval(1, 10000)) + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_knn + outs: + - path: sms_spam/logs/gzip_knn/20 + hash: md5 + md5: bcee56ea959096e8255fb482a8854457.dir + size: 1381168 + nfiles: 514 + - path: sms_spam/reports/gzip_knn/20/train/ + hash: md5 + md5: 12133daeda911e75210cff4d8a3fa5a7.dir + size: 379524 + nfiles: 326 + grid_search@20-sms_spam-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.train_size=20 data.sample.test_size=100 model_name=gzip_logistic + model.init.distance_matrix=null hydra.sweeper.study_name=gzip_logistic_sms_spam + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=sms_spam/logs/gzip_logistic/20 + hydra.callbacks.study_dump.output_file=sms_spam/logs/gzip_logistic/20/study.csv + files.directory=sms_spam files.reports=reports/gzip_logistic/20 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_logistic --multirun + deps: + - path: conf/gzip_logistic.yaml + hash: md5 + md5: 847d4d804fff0b6f2533f90820eebd04 + size: 2205 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_logistic.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 1 + params: + +model.init.solver: saga + +model.init.penalty: l2,l1,l2,none + +model.init.tol: 1e-4,1e-3,1e-2 + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept: True,False + +model.init.class_weight: balanced,None + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_logistic + outs: + - path: sms_spam/logs/gzip_logistic/20 + hash: md5 + md5: 5c7265a3ac4bf4774fbb1c440b9910c4.dir + size: 1520121 + nfiles: 514 + - path: sms_spam/reports/gzip_logistic/20/train/ + hash: md5 + md5: 9ae8109f623b19dcbabe51e4401a1f8c.dir + size: 552539 + nfiles: 357 + grid_search@20-sms_spam-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.train_size=20 data.sample.test_size=100 model_name=gzip_svc model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_svc_sms_spam hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=sms_spam/logs/gzip_svc/20 hydra.callbacks.study_dump.output_file=sms_spam/logs/gzip_svc/20/study.csv + files.directory=sms_spam files.reports=reports/gzip_svc/20 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_svc --multirun + deps: + - path: conf/gzip_svc.yaml + hash: md5 + md5: 957922cb6993eb99866232d944a4a106 + size: 2131 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_svc.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: + - maximize + metric_names: + - accuracy + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + params: + +model.init.kernel: rbf,precomputed + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma: scale,auto + +model.init.class_weight: balanced,null + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_svc + outs: + - path: sms_spam/logs/gzip_svc/20 + hash: md5 + md5: fe6324545be6dc97b88326e10a65e815.dir + size: 1451676 + nfiles: 514 + - path: sms_spam/reports/gzip_svc/20/train/ + hash: md5 + md5: 814632194dc03d626a24f0418fd703e1.dir + size: 542357 + nfiles: 384 + grid_search@20-ddos-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.train_size=20 + data.sample.test_size=100 model_name=gzip_knn model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_knn_ddos hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=ddos/logs/gzip_knn/20 hydra.callbacks.study_dump.output_file=ddos/logs/gzip_knn/20/study.csv + files.directory=ddos files.reports=reports/gzip_knn/20 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_knn --multirun + deps: + - path: conf/gzip_knn.yaml + hash: md5 + md5: a58015cd6f327e171842b045a2524bfd + size: 2062 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_knn.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k: 1,3,5,7,11 + +model.init.weights: uniform,distance + +model.init.algorithm: brute + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + ++data.sample.random_state: int(interval(1, 10000)) + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_knn + outs: + - path: ddos/logs/gzip_knn/20 + hash: md5 + md5: 057fc9613b2210a0dd1e03ef46f3d6bc.dir + size: 1616211 + nfiles: 514 + - path: ddos/reports/gzip_knn/20/train/ + hash: md5 + md5: b0ae22713c6a319a24acb69525a9f01a.dir + size: 1375974 + nfiles: 1536 + grid_search@20-ddos-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.train_size=20 + data.sample.test_size=100 model_name=gzip_logistic model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_logistic_ddos hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=ddos/logs/gzip_logistic/20 hydra.callbacks.study_dump.output_file=ddos/logs/gzip_logistic/20/study.csv + files.directory=ddos files.reports=reports/gzip_logistic/20 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_logistic --multirun + deps: + - path: conf/gzip_logistic.yaml + hash: md5 + md5: 847d4d804fff0b6f2533f90820eebd04 + size: 2205 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_logistic.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 1 + params: + +model.init.solver: saga + +model.init.penalty: l2,l1,l2,none + +model.init.tol: 1e-4,1e-3,1e-2 + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept: True,False + +model.init.class_weight: balanced,None + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_logistic + outs: + - path: ddos/logs/gzip_logistic/20 + hash: md5 + md5: f2c036dc149976bc0de5187f8661669d.dir + size: 1705246 + nfiles: 514 + - path: ddos/reports/gzip_logistic/20/train/ + hash: md5 + md5: 36eee9b3fb432eafed577ca45b477dab.dir + size: 1608552 + nfiles: 1349 + grid_search@20-ddos-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.train_size=20 + data.sample.test_size=100 model_name=gzip_svc model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_svc_ddos hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=ddos/logs/gzip_svc/20 hydra.callbacks.study_dump.output_file=ddos/logs/gzip_svc/20/study.csv + files.directory=ddos files.reports=reports/gzip_svc/20 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_svc --multirun + deps: + - path: conf/gzip_svc.yaml + hash: md5 + md5: 957922cb6993eb99866232d944a4a106 + size: 2131 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_svc.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: + - maximize + metric_names: + - accuracy + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + params: + +model.init.kernel: rbf,precomputed + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma: scale,auto + +model.init.class_weight: balanced,null + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_svc + outs: + - path: ddos/logs/gzip_svc/20 + hash: md5 + md5: 5934a7b63c96844a0eaa9ecea06a79c2.dir + size: 1639820 + nfiles: 514 + - path: ddos/reports/gzip_svc/20/train/ + hash: md5 + md5: 0e902831c38cc7b2f2b03d7bb7f4f5cf.dir + size: 1580188 + nfiles: 1536 + grid_search@100-kdd_nsl-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=kdd_nsl dataset=kdd_nsl + data.sample.train_size=100 data.sample.test_size=100 model_name=gzip_knn model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_knn_kdd_nsl hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=kdd_nsl/logs/gzip_knn/100 hydra.callbacks.study_dump.output_file=kdd_nsl/logs/gzip_knn/100/study.csv + files.directory=kdd_nsl files.reports=reports/gzip_knn/100 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_knn --multirun + deps: + - path: conf/gzip_knn.yaml + hash: md5 + md5: a58015cd6f327e171842b045a2524bfd + size: 2062 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_knn.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k: 1,3,5,7,11 + +model.init.weights: uniform,distance + +model.init.algorithm: brute + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + ++data.sample.random_state: int(interval(1, 10000)) + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_knn + outs: + - path: kdd_nsl/logs/gzip_knn/100 + hash: md5 + md5: aa2209bce9b2f829ca22f244b53ed58f.dir + size: 1416182 + nfiles: 514 + - path: kdd_nsl/reports/gzip_knn/100/train/ + hash: md5 + md5: 1547fa66fbaac37a7badef9b300577a7.dir + size: 1163933 + nfiles: 1000 + grid_search@100-kdd_nsl-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=kdd_nsl dataset=kdd_nsl + data.sample.train_size=100 data.sample.test_size=100 model_name=gzip_logistic + model.init.distance_matrix=null hydra.sweeper.study_name=gzip_logistic_kdd_nsl + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=kdd_nsl/logs/gzip_logistic/100 + hydra.callbacks.study_dump.output_file=kdd_nsl/logs/gzip_logistic/100/study.csv + files.directory=kdd_nsl files.reports=reports/gzip_logistic/100 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_logistic --multirun + deps: + - path: conf/gzip_logistic.yaml + hash: md5 + md5: 847d4d804fff0b6f2533f90820eebd04 + size: 2205 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_logistic.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 1 + params: + +model.init.solver: saga + +model.init.penalty: l2,l1,l2,none + +model.init.tol: 1e-4,1e-3,1e-2 + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept: True,False + +model.init.class_weight: balanced,None + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_logistic + outs: + - path: kdd_nsl/logs/gzip_logistic/100 + hash: md5 + md5: b6e7cf1d3984f8029177576f9668944b.dir + size: 1609157 + nfiles: 514 + - path: kdd_nsl/reports/gzip_logistic/100/train/ + hash: md5 + md5: d40db4814c403a903c7d0cd2a8a5bb7b.dir + size: 1329546 + nfiles: 1093 + grid_search@100-kdd_nsl-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=kdd_nsl dataset=kdd_nsl + data.sample.train_size=100 data.sample.test_size=100 model_name=gzip_svc model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_svc_kdd_nsl hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=kdd_nsl/logs/gzip_svc/100 hydra.callbacks.study_dump.output_file=kdd_nsl/logs/gzip_svc/100/study.csv + files.directory=kdd_nsl files.reports=reports/gzip_svc/100 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_svc --multirun + deps: + - path: conf/gzip_svc.yaml + hash: md5 + md5: 957922cb6993eb99866232d944a4a106 + size: 2131 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_svc.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: + - maximize + metric_names: + - accuracy + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + params: + +model.init.kernel: rbf,precomputed + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma: scale,auto + +model.init.class_weight: balanced,null + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_svc + outs: + - path: kdd_nsl/logs/gzip_svc/100 + hash: md5 + md5: 4b96e2a3bb0e0d230ebd96591a16e441.dir + size: 1553624 + nfiles: 514 + - path: kdd_nsl/reports/gzip_svc/100/train/ + hash: md5 + md5: 3cf8a86de1026ead8fcd1b6cda47e910.dir + size: 1247698 + nfiles: 1152 + grid_search@100-truthseeker-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.train_size=100 data.sample.test_size=100 model_name=gzip_knn model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_knn_truthseeker hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=truthseeker/logs/gzip_knn/100 hydra.callbacks.study_dump.output_file=truthseeker/logs/gzip_knn/100/study.csv + files.directory=truthseeker files.reports=reports/gzip_knn/100 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_knn --multirun + deps: + - path: conf/gzip_knn.yaml + hash: md5 + md5: a58015cd6f327e171842b045a2524bfd + size: 2062 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_knn.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k: 1,3,5,7,11 + +model.init.weights: uniform,distance + +model.init.algorithm: brute + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + ++data.sample.random_state: int(interval(1, 10000)) + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_knn + outs: + - path: truthseeker/logs/gzip_knn/100 + hash: md5 + md5: 818cba0a8349442987e5d6be1f0672d4.dir + size: 1374869 + nfiles: 514 + - path: truthseeker/reports/gzip_knn/100/train/ + hash: md5 + md5: 261a37d5d497bd477d872aa72a94a13f.dir + size: 394446 + nfiles: 320 + grid_search@100-truthseeker-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.train_size=100 data.sample.test_size=100 model_name=gzip_logistic + model.init.distance_matrix=null hydra.sweeper.study_name=gzip_logistic_truthseeker + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=truthseeker/logs/gzip_logistic/100 + hydra.callbacks.study_dump.output_file=truthseeker/logs/gzip_logistic/100/study.csv + files.directory=truthseeker files.reports=reports/gzip_logistic/100 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_logistic --multirun + deps: + - path: conf/gzip_logistic.yaml + hash: md5 + md5: 847d4d804fff0b6f2533f90820eebd04 + size: 2205 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_logistic.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 1 + params: + +model.init.solver: saga + +model.init.penalty: l2,l1,l2,none + +model.init.tol: 1e-4,1e-3,1e-2 + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept: True,False + +model.init.class_weight: balanced,None + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_logistic + outs: + - path: truthseeker/logs/gzip_logistic/100 + hash: md5 + md5: dd822b92438871be421644a82afa8e2f.dir + size: 1528739 + nfiles: 514 + - path: truthseeker/reports/gzip_logistic/100/train/ + hash: md5 + md5: d1b22149466a949b86aba9390d7cf992.dir + size: 556386 + nfiles: 365 + grid_search@100-truthseeker-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.train_size=100 data.sample.test_size=100 model_name=gzip_svc model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_svc_truthseeker hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=truthseeker/logs/gzip_svc/100 hydra.callbacks.study_dump.output_file=truthseeker/logs/gzip_svc/100/study.csv + files.directory=truthseeker files.reports=reports/gzip_svc/100 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_svc --multirun + deps: + - path: conf/gzip_svc.yaml + hash: md5 + md5: 957922cb6993eb99866232d944a4a106 + size: 2131 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_svc.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: + - maximize + metric_names: + - accuracy + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + params: + +model.init.kernel: rbf,precomputed + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma: scale,auto + +model.init.class_weight: balanced,null + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_svc + outs: + - path: truthseeker/logs/gzip_svc/100 + hash: md5 + md5: c9493ae71545ccec0ea01adc6d664bce.dir + size: 1505603 + nfiles: 514 + - path: truthseeker/reports/gzip_svc/100/train/ + hash: md5 + md5: c9a4bae4aed04fcdb578f44fba94af87.dir + size: 547282 + nfiles: 384 + grid_search@100-sms_spam-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.train_size=100 data.sample.test_size=100 model_name=gzip_knn model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_knn_sms_spam hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=sms_spam/logs/gzip_knn/100 hydra.callbacks.study_dump.output_file=sms_spam/logs/gzip_knn/100/study.csv + files.directory=sms_spam files.reports=reports/gzip_knn/100 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_knn --multirun + deps: + - path: conf/gzip_knn.yaml + hash: md5 + md5: a58015cd6f327e171842b045a2524bfd + size: 2062 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_knn.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k: 1,3,5,7,11 + +model.init.weights: uniform,distance + +model.init.algorithm: brute + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + ++data.sample.random_state: int(interval(1, 10000)) + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_knn + outs: + - path: sms_spam/logs/gzip_knn/100 + hash: md5 + md5: ad8714bbbce96d2c1ff75deda0add5ec.dir + size: 1415136 + nfiles: 514 + - path: sms_spam/reports/gzip_knn/100/train/ + hash: md5 + md5: 6bcf048da228e84a757916c797891044.dir + size: 376546 + nfiles: 331 + find_best_model@ddos-gzip_knn: + cmd: python -m deckard.layers.find_best --storage sqlite:///optuna.db --study_name + gzip_knn_ddos --config_subdir model --params_file best_gzip_knn_ddos --default_config + gzip_knn + deps: + - path: ddos/logs/gzip_knn/ + hash: md5 + md5: d2c6441e85e3509b8968240a48196d07.dir + size: 4193267 + nfiles: 1542 + outs: + - path: conf/model/best_gzip_knn_ddos.yaml + hash: md5 + md5: bdea475d3a2bc59106f27dccd0fc27fc + size: 419 + find_best_model@ddos-gzip_svc: + cmd: python -m deckard.layers.find_best --storage sqlite:///optuna.db --study_name + gzip_svc_ddos --config_subdir model --params_file best_gzip_svc_ddos --default_config + gzip_svc + deps: + - path: ddos/logs/gzip_svc/ + hash: md5 + md5: 78cd23f301a93a7c9842abb061e3cc7b.dir + size: 7447727 + nfiles: 2570 + outs: + - path: conf/model/best_gzip_svc_ddos.yaml + hash: md5 + md5: 3a7f27dd470ec9e55c10403814f550f2 + size: 442 + find_best_model@ddos-gzip_logistic: + cmd: python -m deckard.layers.find_best --storage sqlite:///optuna.db --study_name + gzip_logistic_ddos --config_subdir model --params_file best_gzip_logistic_ddos + --default_config gzip_logistic + deps: + - path: ddos/logs/gzip_logistic/ + hash: md5 + md5: b28cadbd10b9bbe40802e39b1beaee18.dir + size: 6561328 + nfiles: 2056 + outs: + - path: conf/model/best_gzip_logistic_ddos.yaml + hash: md5 + md5: d5e603d6386dd6cf1167088eaecbdde5 + size: 498 + condense@ddos-knn: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.train_size=100 + data.sample.test_size=100 model_name=condensed_knn model=gzip_knn files.directory=ddos + files.reports=reports/condense/knn/ hydra.sweeper.study_name=condense_knn_ddos + hydra.sweeper.n_trials=1024 hydra.sweeper.n_jobs=8 hydra.sweep.dir=ddos/logs/condense/knn/ + hydra.callbacks.study_dump.output_file=ddos/logs/knn/study.csv hydra.launcher.n_jobs=-1 + --config-name condense_knn --multirun + deps: + - path: conf/condense_knn.yaml + hash: md5 + md5: abd25d17a742e467d39dda34b448ba88 + size: 2181 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + direction: ${direction} + max_failure_rate: 1.0 + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: ddos/logs/condense/knn/ + hash: md5 + md5: 34f8b7196af71d106965513050a254fb.dir + size: 10910937 + nfiles: 4097 + - path: ddos/reports/condense/knn/ + hash: md5 + md5: 9b6918814be3bea732abc71b8684fd8d.dir + size: 8458502 + nfiles: 9157 + condense@ddos-svc: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.train_size=100 + data.sample.test_size=100 model_name=condensed_svc model=gzip_svc files.directory=ddos + files.reports=reports/condense/svc/ hydra.sweeper.study_name=condense_svc_ddos + hydra.sweeper.n_trials=1024 hydra.sweeper.n_jobs=8 hydra.sweep.dir=ddos/logs/condense/svc/ + hydra.callbacks.study_dump.output_file=ddos/logs/svc/study.csv hydra.launcher.n_jobs=-1 + --config-name condense_svc --multirun + deps: + - path: conf/model/best_gzip_svc_ddos.yaml + hash: md5 + md5: 3a7f27dd470ec9e55c10403814f550f2 + size: 442 + - path: ddos/logs/method/ + hash: md5 + md5: a09dd0467b0e8a142d6f32a38f205159.dir + size: 59399 + nfiles: 28 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + direction: ${direction} + max_failure_rate: 1.0 + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: ddos/logs/condense/svc/ + hash: md5 + md5: 6a15cfc205c7382b8d7d6d67d35ddfb0.dir + size: 11072739 + nfiles: 4097 + - path: ddos/reports/condense/svc/ + hash: md5 + md5: daaf428c939e9bfcc233bf88ee39f9fb.dir + size: 2819182 + nfiles: 3072 + condense@ddos-logistic: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.train_size=100 + data.sample.test_size=100 model_name=condensed_logistic model=gzip_logistic + files.directory=ddos files.reports=reports/condense/logistic/ hydra.sweeper.study_name=condense_logistic_ddos + hydra.sweeper.n_trials=1024 hydra.sweeper.n_jobs=8 hydra.sweep.dir=ddos/logs/condense/logistic/ + hydra.callbacks.study_dump.output_file=ddos/logs/logistic/study.csv hydra.launcher.n_jobs=-1 + --config-name condense_logistic --multirun + deps: + - path: conf/model/best_gzip_logistic_ddos.yaml + hash: md5 + md5: d5e603d6386dd6cf1167088eaecbdde5 + size: 498 + - path: ddos/logs/method/ + hash: md5 + md5: a09dd0467b0e8a142d6f32a38f205159.dir + size: 59399 + nfiles: 28 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + direction: ${direction} + max_failure_rate: 1.0 + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: ddos/logs/condense/logistic/ + hash: md5 + md5: 064e5768d0155635c9bc6287914ac9f7.dir + size: 11690343 + nfiles: 4097 + - path: ddos/reports/condense/logistic/ + hash: md5 + md5: 7ce841278929a90690417685b7c7f143.dir + size: 5929815 + nfiles: 5888 + grid_search@100-ddos-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.train_size=100 + data.sample.test_size=100 model_name=gzip_knn model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_knn_ddos hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=ddos/logs/gzip_knn/100 hydra.callbacks.study_dump.output_file=ddos/logs/gzip_knn/100/study.csv + files.directory=ddos files.reports=reports/gzip_knn/100 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_knn --multirun + deps: + - path: conf/gzip_knn.yaml + hash: md5 + md5: a58015cd6f327e171842b045a2524bfd + size: 2062 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_knn.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k: 1,3,5,7,11 + +model.init.weights: uniform,distance + +model.init.algorithm: brute + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + ++data.sample.random_state: int(interval(1, 10000)) + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_knn + outs: + - path: ddos/logs/gzip_knn/100 + hash: md5 + md5: 41af522bae6f35684d51a90652c37082.dir + size: 1645388 + nfiles: 514 + - path: ddos/reports/gzip_knn/100/train/ + hash: md5 + md5: b9374a5acb2480c2ed6a35803a344f69.dir + size: 1341749 + nfiles: 1499 + grid_search@100-ddos-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.train_size=100 + data.sample.test_size=100 model_name=gzip_logistic model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_logistic_ddos hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=ddos/logs/gzip_logistic/100 hydra.callbacks.study_dump.output_file=ddos/logs/gzip_logistic/100/study.csv + files.directory=ddos files.reports=reports/gzip_logistic/100 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_logistic --multirun + deps: + - path: conf/gzip_logistic.yaml + hash: md5 + md5: 847d4d804fff0b6f2533f90820eebd04 + size: 2205 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_logistic.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 1 + params: + +model.init.solver: saga + +model.init.penalty: l2,l1,l2,none + +model.init.tol: 1e-4,1e-3,1e-2 + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept: True,False + +model.init.class_weight: balanced,None + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_logistic + outs: + - path: ddos/logs/gzip_logistic/100 + hash: md5 + md5: 3f1d14c70e73f668316f86a8d7d0e22b.dir + size: 1733688 + nfiles: 514 + - path: ddos/reports/gzip_logistic/100/train/ + hash: md5 + md5: c839c1faf70de47c057714c3a8bdc52d.dir + size: 1562420 + nfiles: 1315 + grid_search@100-ddos-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.train_size=100 + data.sample.test_size=100 model_name=gzip_svc model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_svc_ddos hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=ddos/logs/gzip_svc/100 hydra.callbacks.study_dump.output_file=ddos/logs/gzip_svc/100/study.csv + files.directory=ddos files.reports=reports/gzip_svc/100 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_svc --multirun + deps: + - path: conf/gzip_svc.yaml + hash: md5 + md5: 957922cb6993eb99866232d944a4a106 + size: 2131 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_svc.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: + - maximize + metric_names: + - accuracy + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + params: + +model.init.kernel: rbf,precomputed + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma: scale,auto + +model.init.class_weight: balanced,null + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_svc + outs: + - path: ddos/logs/gzip_svc/100 + hash: md5 + md5: 4adc8c896e06e2d7e8450f2b863b95bf.dir + size: 1681042 + nfiles: 514 + - path: ddos/reports/gzip_svc/100/train/ + hash: md5 + md5: 8ad9bbb8a118699458753528a263f5ba.dir + size: 1790102 + nfiles: 1678 + find_best_model@kdd_nsl-gzip_knn: + cmd: python -m deckard.layers.find_best --storage sqlite:///optuna.db --study_name + gzip_knn_kdd_nsl --config_subdir model --params_file best_gzip_knn_kdd_nsl --default_config + gzip_knn + deps: + - path: kdd_nsl/logs/gzip_knn/ + hash: md5 + md5: 6418750af32f15be9c6f35e0975b3276.dir + size: 4024441 + nfiles: 1542 + outs: + - path: conf/model/best_gzip_knn_kdd_nsl.yaml + hash: md5 + md5: f9ad25a19931041146b4b1eab45fda68 + size: 420 + find_best_model@kdd_nsl-gzip_svc: + cmd: python -m deckard.layers.find_best --storage sqlite:///optuna.db --study_name + gzip_svc_kdd_nsl --config_subdir model --params_file best_gzip_svc_kdd_nsl --default_config + gzip_svc + deps: + - path: kdd_nsl/logs/gzip_svc/ + hash: md5 + md5: 381879c377b6eeccbb9d1aa42f78fec2.dir + size: 4366326 + nfiles: 1542 + outs: + - path: conf/model/best_gzip_svc_kdd_nsl.yaml + hash: md5 + md5: 0542c20ce7b5a74a20d4ab1c38fdf213 + size: 434 + find_best_model@kdd_nsl-gzip_logistic: + cmd: python -m deckard.layers.find_best --storage sqlite:///optuna.db --study_name + gzip_logistic_kdd_nsl --config_subdir model --params_file best_gzip_logistic_kdd_nsl + --default_config gzip_logistic + deps: + - path: kdd_nsl/logs/gzip_logistic/ + hash: md5 + md5: 34325e24d16a4af0ec3286ec4b034e14.dir + size: 4504884 + nfiles: 1542 + outs: + - path: conf/model/best_gzip_logistic_kdd_nsl.yaml + hash: md5 + md5: e21d828b4b1ad122d7755e986de5b93d + size: 353 + find_best_model@sms_spam-gzip_knn: + cmd: python -m deckard.layers.find_best --storage sqlite:///optuna.db --study_name + gzip_knn_sms_spam --config_subdir model --params_file best_gzip_knn_sms_spam + --default_config gzip_knn + deps: + - path: sms_spam/logs/gzip_knn/ + hash: md5 + md5: 689c69db8c621101649ddef5bd0c1bb5.dir + size: 2713750 + nfiles: 1028 + outs: + - path: conf/model/best_gzip_knn_sms_spam.yaml + hash: md5 + md5: 41fad710bcb8b8b8dd548d669b2ed748 + size: 419 + find_best_model@sms_spam-gzip_svc: + cmd: python -m deckard.layers.find_best --storage sqlite:///optuna.db --study_name + gzip_svc_sms_spam --config_subdir model --params_file best_gzip_svc_sms_spam + --default_config gzip_svc + deps: + - path: sms_spam/logs/gzip_svc/ + hash: md5 + md5: b91e15f0eb5ee57aed8aeb5a5d6feeab.dir + size: 2777710 + nfiles: 1028 + outs: + - path: conf/model/best_gzip_svc_sms_spam.yaml + hash: md5 + md5: bb3008613c3311a696d32fb683732c00 + size: 442 + find_best_model@sms_spam-gzip_logistic: + cmd: python -m deckard.layers.find_best --storage sqlite:///optuna.db --study_name + gzip_logistic_sms_spam --config_subdir model --params_file best_gzip_logistic_sms_spam + --default_config gzip_logistic + deps: + - path: sms_spam/logs/gzip_logistic/ + hash: md5 + md5: 89191dbe147b40192129776ef2652900.dir + size: 1649284 + nfiles: 578 + outs: + - path: conf/model/best_gzip_logistic_sms_spam.yaml + hash: md5 + md5: fd1d0481be57844d935aea28e995a369 + size: 485 + condense@kdd_nsl-knn: + cmd: python -m deckard.layers.optimise stage=train data=kdd_nsl dataset=kdd_nsl + data.sample.train_size=100 data.sample.test_size=100 model_name=condensed_knn + model=gzip_knn files.directory=kdd_nsl files.reports=reports/condense/knn/ hydra.sweeper.study_name=condense_knn_kdd_nsl + hydra.sweeper.n_trials=1024 hydra.sweeper.n_jobs=8 hydra.sweep.dir=kdd_nsl/logs/condense/knn/ + hydra.callbacks.study_dump.output_file=kdd_nsl/logs/knn/study.csv hydra.launcher.n_jobs=-1 + --config-name condense_knn --multirun + deps: + - path: conf/model/best_gzip_knn_kdd_nsl.yaml + hash: md5 + md5: f9ad25a19931041146b4b1eab45fda68 + size: 420 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + direction: ${direction} + max_failure_rate: 1.0 + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: kdd_nsl/logs/condense/knn/ + hash: md5 + md5: 81f50250e51650881283dcf68d43234c.dir + size: 10952920 + nfiles: 4097 + - path: kdd_nsl/reports/condense/knn/ + hash: md5 + md5: 3f8eb680f1f8960490e4581bfa16cfd2.dir + size: 2869636 + nfiles: 3011 + condense@kdd_nsl-svc: + cmd: python -m deckard.layers.optimise stage=train data=kdd_nsl dataset=kdd_nsl + data.sample.train_size=100 data.sample.test_size=100 model_name=condensed_svc + model=gzip_svc files.directory=kdd_nsl files.reports=reports/condense/svc/ hydra.sweeper.study_name=condense_svc_kdd_nsl + hydra.sweeper.n_trials=1024 hydra.sweeper.n_jobs=8 hydra.sweep.dir=kdd_nsl/logs/condense/svc/ + hydra.callbacks.study_dump.output_file=kdd_nsl/logs/svc/study.csv hydra.launcher.n_jobs=-1 + --config-name condense_svc --multirun + deps: + - path: conf/model/best_gzip_svc_kdd_nsl.yaml + hash: md5 + md5: 0542c20ce7b5a74a20d4ab1c38fdf213 + size: 434 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + direction: ${direction} + max_failure_rate: 1.0 + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: kdd_nsl/logs/condense/svc/ + hash: md5 + md5: cdf319e0c94e4c6eda84ec9b2e9ea1a9.dir + size: 10708020 + nfiles: 4097 + - path: kdd_nsl/reports/condense/svc/ + hash: md5 + md5: ad27897c6454024915fdcef827219bd3.dir + size: 8340639 + nfiles: 5462 + condense@kdd_nsl-logistic: + cmd: python -m deckard.layers.optimise stage=train data=kdd_nsl dataset=kdd_nsl + data.sample.train_size=100 data.sample.test_size=100 model_name=condensed_logistic + model=gzip_logistic files.directory=kdd_nsl files.reports=reports/condense/logistic/ + hydra.sweeper.study_name=condense_logistic_kdd_nsl hydra.sweeper.n_trials=1024 + hydra.sweeper.n_jobs=8 hydra.sweep.dir=kdd_nsl/logs/condense/logistic/ hydra.callbacks.study_dump.output_file=kdd_nsl/logs/logistic/study.csv + hydra.launcher.n_jobs=-1 --config-name condense_logistic --multirun + deps: + - path: conf/model/best_gzip_logistic_kdd_nsl.yaml + hash: md5 + md5: e21d828b4b1ad122d7755e986de5b93d + size: 353 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + direction: ${direction} + max_failure_rate: 1.0 + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: kdd_nsl/logs/condense/logistic/ + hash: md5 + md5: 0ce56c12dc58fe66c1fa6fec867b2cf5.dir + size: 11710344 + nfiles: 4097 + - path: kdd_nsl/reports/condense/logistic/ + hash: md5 + md5: ae358823518ca6759ddfa8d1c738e367.dir + size: 3101125 + nfiles: 2948 + condense@truthseeker-knn: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.train_size=100 data.sample.test_size=100 model_name=condensed_knn + model=gzip_knn files.directory=truthseeker files.reports=reports/condense/knn/ + hydra.sweeper.study_name=condense_knn_truthseeker hydra.sweeper.n_trials=1024 + hydra.sweeper.n_jobs=8 hydra.sweep.dir=truthseeker/logs/condense/knn/ hydra.callbacks.study_dump.output_file=truthseeker/logs/knn/study.csv + hydra.launcher.n_jobs=-1 --config-name condense_knn --multirun + deps: + - path: conf/model/best_gzip_knn_truthseeker.yaml + hash: md5 + md5: 79baf4709c4a5f2535059ef8d1b6a082 + size: 258 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + direction: ${direction} + max_failure_rate: 1.0 + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: truthseeker/logs/condense/knn/ + hash: md5 + md5: 3e8b9011ee1c591904115e67db9a1a50.dir + size: 11038890 + nfiles: 4097 + - path: truthseeker/reports/condense/knn/ + hash: md5 + md5: 1565eb2348976cc6ac9108396141080b.dir + size: 2831604 + nfiles: 3016 + condense@truthseeker-svc: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.train_size=100 data.sample.test_size=100 model_name=condensed_svc + model=gzip_svc files.directory=truthseeker files.reports=reports/condense/svc/ + hydra.sweeper.study_name=condense_svc_truthseeker hydra.sweeper.n_trials=1024 + hydra.sweeper.n_jobs=8 hydra.sweep.dir=truthseeker/logs/condense/svc/ hydra.callbacks.study_dump.output_file=truthseeker/logs/svc/study.csv + hydra.launcher.n_jobs=-1 --config-name condense_svc --multirun + deps: + - path: conf/model/best_gzip_svc_truthseeker.yaml + hash: md5 + md5: 97d9d5857744b1cc077513ac5a659f62 + size: 302 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + direction: ${direction} + max_failure_rate: 1.0 + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: truthseeker/logs/condense/svc/ + hash: md5 + md5: 845724e35dc3a54bea549410a35d6afd.dir + size: 11192018 + nfiles: 4097 + - path: truthseeker/reports/condense/svc/ + hash: md5 + md5: 6cbdc47d51df656dcf7e8ae6221795b3.dir + size: 2825163 + nfiles: 3064 + condense@truthseeker-logistic: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.train_size=100 data.sample.test_size=100 model_name=condensed_logistic + model=gzip_logistic files.directory=truthseeker files.reports=reports/condense/logistic/ + hydra.sweeper.study_name=condense_logistic_truthseeker hydra.sweeper.n_trials=1024 + hydra.sweeper.n_jobs=8 hydra.sweep.dir=truthseeker/logs/condense/logistic/ hydra.callbacks.study_dump.output_file=truthseeker/logs/logistic/study.csv + hydra.launcher.n_jobs=-1 --config-name condense_logistic --multirun + deps: + - path: conf/model/best_gzip_logistic_truthseeker.yaml + hash: md5 + md5: 448e12c542f48c074057e9374743d61e + size: 326 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + direction: ${direction} + max_failure_rate: 1.0 + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: truthseeker/logs/condense/logistic/ + hash: md5 + md5: f7e754346e500d1b007b519d86f4c608.dir + size: 11847643 + nfiles: 4097 + - path: truthseeker/reports/condense/logistic/ + hash: md5 + md5: 8bd6876fc856ea5bd1e95b54093aedb8.dir + size: 2976098 + nfiles: 3011 + condense@sms_spam-knn: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.train_size=100 data.sample.test_size=100 model_name=condensed_knn + model=gzip_knn files.directory=sms_spam files.reports=reports/condense/knn/ + hydra.sweeper.study_name=condense_knn_sms_spam hydra.sweeper.n_trials=1024 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=sms_spam/logs/condense/knn/ hydra.callbacks.study_dump.output_file=sms_spam/logs/knn/study.csv + hydra.launcher.n_jobs=-1 --config-name condense_knn --multirun + deps: + - path: conf/condense_knn.yaml + hash: md5 + md5: abd25d17a742e467d39dda34b448ba88 + size: 2181 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + direction: ${direction} + max_failure_rate: 1.0 + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: sms_spam/logs/condense/knn/ + hash: md5 + md5: ee1eda16b8989f2a23a7dfeba27b4437.dir + size: 10519093 + nfiles: 4097 + - path: sms_spam/reports/condense/knn/ + hash: md5 + md5: 84b8fcb1e78a8685141409736c6d6afa.dir + size: 4713599 + nfiles: 4258 + condense@sms_spam-svc: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.train_size=100 data.sample.test_size=100 model_name=condensed_svc + model=gzip_svc files.directory=sms_spam files.reports=reports/condense/svc/ + hydra.sweeper.study_name=condense_svc_sms_spam hydra.sweeper.n_trials=1024 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=sms_spam/logs/condense/svc/ hydra.callbacks.study_dump.output_file=sms_spam/logs/svc/study.csv + hydra.launcher.n_jobs=-1 --config-name condense_svc --multirun + deps: + - path: conf/condense_svc.yaml + hash: md5 + md5: 7a311db45e697a23a2bed8180fd45e64 + size: 2182 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + direction: ${direction} + max_failure_rate: 1.0 + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: sms_spam/logs/condense/svc/ + hash: md5 + md5: 9d28ee3f4494d207369bd35c2f5d2164.dir + size: 11082621 + nfiles: 4097 + - path: sms_spam/reports/condense/svc/ + hash: md5 + md5: 200cad31398ec4545e7a490011218c47.dir + size: 4416840 + nfiles: 3068 + condense@sms_spam-logistic: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.train_size=100 data.sample.test_size=100 model_name=condensed_logistic + model=gzip_logistic files.directory=sms_spam files.reports=reports/condense/logistic/ + hydra.sweeper.study_name=condense_logistic_sms_spam hydra.sweeper.n_trials=1024 + hydra.sweeper.n_jobs=8 hydra.sweep.dir=sms_spam/logs/condense/logistic/ hydra.callbacks.study_dump.output_file=sms_spam/logs/logistic/study.csv + hydra.launcher.n_jobs=-1 --config-name condense_logistic --multirun + deps: + - path: conf/condense_logistic.yaml + hash: md5 + md5: 85b6d1d835afd7e95b5b9f804fbd7119 + size: 2326 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/condense.yaml: + hydra: + run: + dir: ${dataset}/logs/condense/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + direction: ${direction} + max_failure_rate: 1.0 + params: + ++data.sample.train_size: 1000 + ++data.sample.random_state: int(interval(10000, 20000)) + model.init.m: tag(log, interval(.01, .1)) + +model.init.sampling_method: medoid,sum,svc,random,hardness,nearmiss,knn + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + outs: + - path: sms_spam/logs/condense/logistic/ + hash: md5 + md5: 3846050e3a2341b246c2c3366debe0dc.dir + size: 11620551 + nfiles: 4097 + - path: sms_spam/reports/condense/logistic/ + hash: md5 + md5: 05562ae582796b70d35ae7062a5030d7.dir + size: 9597627 + nfiles: 6388 + compile@sms_spam-condense/logistic: + cmd: python -m deckard.layers.compile --report_folder sms_spam/reports/condense/logistic --results_file + sms_spam/reports/condense/logistic.csv + deps: + - path: sms_spam/reports/condense/logistic/ + hash: md5 + md5: 05562ae582796b70d35ae7062a5030d7.dir + size: 9597627 + nfiles: 6388 + outs: + - path: sms_spam/reports/condense/logistic.csv + hash: md5 + md5: 7094b26a582820cc1f88512573ce8c25 + size: 3430438 + compile@kdd_nsl-condense/svc: + cmd: python -m deckard.layers.compile --report_folder kdd_nsl/reports/condense/svc --results_file + kdd_nsl/reports/condense/svc.csv + deps: + - path: kdd_nsl/reports/condense/svc/ + hash: md5 + md5: ad27897c6454024915fdcef827219bd3.dir + size: 8340639 + nfiles: 5462 + outs: + - path: kdd_nsl/reports/condense/svc.csv + hash: md5 + md5: 643a67cb6d5974a787efa6339e3af058 + size: 3003804 + compile@kdd_nsl-condense/logistic: + cmd: python -m deckard.layers.compile --report_folder kdd_nsl/reports/condense/logistic --results_file + kdd_nsl/reports/condense/logistic.csv + deps: + - path: kdd_nsl/reports/condense/logistic/ + hash: md5 + md5: df73404e3f7d00371dd55b40e76fa9e0.dir + size: 3112185 + nfiles: 2954 + outs: + - path: kdd_nsl/reports/condense/logistic.csv + hash: md5 + md5: 4193461c63aca8b61956fc443f5bcd3d + size: 1649004 + compile@ddos-condense/svc: + cmd: python -m deckard.layers.compile --report_folder ddos/reports/condense/svc --results_file + ddos/reports/condense/svc.csv + deps: + - path: ddos/reports/condense/svc/ + hash: md5 + md5: b40b878f7eca11a9eae0c19e054bee47.dir + size: 8854939 + nfiles: 7199 + outs: + - path: ddos/reports/condense/svc.csv + hash: md5 + md5: 76b35c3e1dfa2d0476a737f9a41c25c4 + size: 3771755 + compile@truthseeker-condense/knn: + cmd: python -m deckard.layers.compile --report_folder truthseeker/reports/condense/knn --results_file + truthseeker/reports/condense/knn.csv + deps: + - path: truthseeker/reports/condense/knn/ + hash: md5 + md5: 1565eb2348976cc6ac9108396141080b.dir + size: 2831604 + nfiles: 3016 + outs: + - path: truthseeker/reports/condense/knn.csv + hash: md5 + md5: b4ec50d98f613984be6261a059120255 + size: 1595839 + compile@truthseeker-condense/svc: + cmd: python -m deckard.layers.compile --report_folder truthseeker/reports/condense/svc --results_file + truthseeker/reports/condense/svc.csv + deps: + - path: truthseeker/reports/condense/svc/ + hash: md5 + md5: 6cbdc47d51df656dcf7e8ae6221795b3.dir + size: 2825163 + nfiles: 3064 + outs: + - path: truthseeker/reports/condense/svc.csv + hash: md5 + md5: 4cdede4407c88bcda2afc8bbeae91ace + size: 1617655 + compile@ddos-condense/knn: + cmd: python -m deckard.layers.compile --report_folder ddos/reports/condense/knn --results_file + ddos/reports/condense/knn.csv + deps: + - path: ddos/reports/condense/knn/ + hash: md5 + md5: 9b6918814be3bea732abc71b8684fd8d.dir + size: 8458502 + nfiles: 9157 + outs: + - path: ddos/reports/condense/knn.csv + hash: md5 + md5: 0cd0ff58f94fb06093779ff81d37d2bf + size: 4723182 + compile@sms_spam-condense/svc: + cmd: python -m deckard.layers.compile --report_folder sms_spam/reports/condense/svc --results_file + sms_spam/reports/condense/svc.csv + deps: + - path: sms_spam/reports/condense/svc/ + hash: md5 + md5: 200cad31398ec4545e7a490011218c47.dir + size: 4416840 + nfiles: 3068 + outs: + - path: sms_spam/reports/condense/svc.csv + hash: md5 + md5: 32f06cbea623f845dcfa7400d707abad + size: 1573621 + compile@kdd_nsl-condense/knn: + cmd: python -m deckard.layers.compile --report_folder kdd_nsl/reports/condense/knn --results_file + kdd_nsl/reports/condense/knn.csv + deps: + - path: kdd_nsl/reports/condense/knn/ + hash: md5 + md5: 3f8eb680f1f8960490e4581bfa16cfd2.dir + size: 2869636 + nfiles: 3011 + outs: + - path: kdd_nsl/reports/condense/knn.csv + hash: md5 + md5: 29211ec6d9b2b1a5e9193eaabfff3488 + size: 1608857 + compile@truthseeker-condense/logistic: + cmd: python -m deckard.layers.compile --report_folder truthseeker/reports/condense/logistic --results_file + truthseeker/reports/condense/logistic.csv + deps: + - path: truthseeker/reports/condense/logistic/ + hash: md5 + md5: 8bd6876fc856ea5bd1e95b54093aedb8.dir + size: 2976098 + nfiles: 3011 + outs: + - path: truthseeker/reports/condense/logistic.csv + hash: md5 + md5: 5c01852f352ac96150fb36c2df9bcbbf + size: 1648856 + compile@sms_spam-condense/knn: + cmd: python -m deckard.layers.compile --report_folder sms_spam/reports/condense/knn --results_file + sms_spam/reports/condense/knn.csv + deps: + - path: sms_spam/reports/condense/knn/ + hash: md5 + md5: 84b8fcb1e78a8685141409736c6d6afa.dir + size: 4713599 + nfiles: 4258 + outs: + - path: sms_spam/reports/condense/knn.csv + hash: md5 + md5: c8d4f7036e0c3e1cf8fa5a0b922c6ecc + size: 2287605 + compile@ddos-condense/logistic: + cmd: python -m deckard.layers.compile --report_folder ddos/reports/condense/logistic --results_file + ddos/reports/condense/logistic.csv + deps: + - path: ddos/reports/condense/logistic/ + hash: md5 + md5: 7ce841278929a90690417685b7c7f143.dir + size: 5929815 + nfiles: 5888 + outs: + - path: ddos/reports/condense/logistic.csv + hash: md5 + md5: b24764aed957fdf6d2ccb541ef490d37 + size: 3150984 + clean@sms_spam-condense/svc: + cmd: python -m deckard.layers.clean_data -i sms_spam/reports/condense/svc.csv + -o sms_spam/plots/clean/condense/svc.csv -c conf/clean.yaml + deps: + - path: sms_spam/reports/condense/svc.csv + hash: md5 + md5: 32f06cbea623f845dcfa7400d707abad + size: 1573621 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: sms_spam/plots/clean/condense/svc.csv + hash: md5 + md5: 92b8648f6759e0a56c65aeec4a15aa92 + size: 1223675 + clean@ddos-condense/knn: + cmd: python -m deckard.layers.clean_data -i ddos/reports/condense/knn.csv -o + ddos/plots/clean/condense/knn.csv -c conf/clean.yaml + deps: + - path: ddos/reports/condense/knn.csv + hash: md5 + md5: 0cd0ff58f94fb06093779ff81d37d2bf + size: 4723182 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: ddos/plots/clean/condense/knn.csv + hash: md5 + md5: d214914ecfbba6afbd4ff9a61cb96bb1 + size: 3652514 + clean@truthseeker-condense/svc: + cmd: python -m deckard.layers.clean_data -i truthseeker/reports/condense/svc.csv + -o truthseeker/plots/clean/condense/svc.csv -c conf/clean.yaml + deps: + - path: truthseeker/reports/condense/svc.csv + hash: md5 + md5: 4cdede4407c88bcda2afc8bbeae91ace + size: 1617655 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: truthseeker/plots/clean/condense/svc.csv + hash: md5 + md5: a17c0cdb6a3fbfae5bd4fcfca1938a96 + size: 1257671 + clean@kdd_nsl-condense/knn: + cmd: python -m deckard.layers.clean_data -i kdd_nsl/reports/condense/knn.csv + -o kdd_nsl/plots/clean/condense/knn.csv -c conf/clean.yaml + deps: + - path: kdd_nsl/reports/condense/knn.csv + hash: md5 + md5: 29211ec6d9b2b1a5e9193eaabfff3488 + size: 1608857 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: kdd_nsl/plots/clean/condense/knn.csv + hash: md5 + md5: 23789b08b0fd1616555611d0e7971db9 + size: 1204868 + clean@kdd_nsl-condense/svc: + cmd: python -m deckard.layers.clean_data -i kdd_nsl/reports/condense/svc.csv + -o kdd_nsl/plots/clean/condense/svc.csv -c conf/clean.yaml + deps: + - path: kdd_nsl/reports/condense/svc.csv + hash: md5 + md5: 643a67cb6d5974a787efa6339e3af058 + size: 3003804 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: kdd_nsl/plots/clean/condense/svc.csv + hash: md5 + md5: c9b2ff8546f531fa439c664c63fc06fd + size: 2021393 + clean@kdd_nsl-condense/logistic: + cmd: python -m deckard.layers.clean_data -i kdd_nsl/reports/condense/logistic.csv + -o kdd_nsl/plots/clean/condense/logistic.csv -c conf/clean.yaml + deps: + - path: kdd_nsl/reports/condense/logistic.csv + hash: md5 + md5: 4193461c63aca8b61956fc443f5bcd3d + size: 1649004 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: kdd_nsl/plots/clean/condense/logistic.csv + hash: md5 + md5: 55a0ac50149a3e3d93b69c63ccd0d7a3 + size: 1174964 + clean@sms_spam-condense/knn: + cmd: python -m deckard.layers.clean_data -i sms_spam/reports/condense/knn.csv + -o sms_spam/plots/clean/condense/knn.csv -c conf/clean.yaml + deps: + - path: sms_spam/reports/condense/knn.csv + hash: md5 + md5: c8d4f7036e0c3e1cf8fa5a0b922c6ecc + size: 2287605 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: sms_spam/plots/clean/condense/knn.csv + hash: md5 + md5: 7dda620e8ae59aab14ac83c0071a8b96 + size: 1268504 + clean@sms_spam-condense/logistic: + cmd: python -m deckard.layers.clean_data -i sms_spam/reports/condense/logistic.csv + -o sms_spam/plots/clean/condense/logistic.csv -c conf/clean.yaml + deps: + - path: sms_spam/reports/condense/logistic.csv + hash: md5 + md5: 7094b26a582820cc1f88512573ce8c25 + size: 3430438 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: sms_spam/plots/clean/condense/logistic.csv + hash: md5 + md5: 1f89cfa87c87f195079e49eb5d6e7ce5 + size: 2461824 + clean@truthseeker-condense/logistic: + cmd: python -m deckard.layers.clean_data -i truthseeker/reports/condense/logistic.csv + -o truthseeker/plots/clean/condense/logistic.csv -c conf/clean.yaml + deps: + - path: truthseeker/reports/condense/logistic.csv + hash: md5 + md5: 5c01852f352ac96150fb36c2df9bcbbf + size: 1648856 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: truthseeker/plots/clean/condense/logistic.csv + hash: md5 + md5: 9710addb440069a5ea884d90ed4c394a + size: 1237939 + clean@truthseeker-condense/knn: + cmd: python -m deckard.layers.clean_data -i truthseeker/reports/condense/knn.csv + -o truthseeker/plots/clean/condense/knn.csv -c conf/clean.yaml + deps: + - path: truthseeker/reports/condense/knn.csv + hash: md5 + md5: b4ec50d98f613984be6261a059120255 + size: 1595839 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: truthseeker/plots/clean/condense/knn.csv + hash: md5 + md5: a0c8deb8fe7617477ec43fae2a851b4d + size: 1191230 + clean@ddos-condense/svc: + cmd: python -m deckard.layers.clean_data -i ddos/reports/condense/svc.csv -o + ddos/plots/clean/condense/svc.csv -c conf/clean.yaml + deps: + - path: ddos/reports/condense/svc.csv + hash: md5 + md5: 76b35c3e1dfa2d0476a737f9a41c25c4 + size: 3771755 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: ddos/plots/clean/condense/svc.csv + hash: md5 + md5: 102b712883464d547a4d2119f6c5df60 + size: 2968961 + clean@ddos-condense/logistic: + cmd: python -m deckard.layers.clean_data -i ddos/reports/condense/logistic.csv + -o ddos/plots/clean/condense/logistic.csv -c conf/clean.yaml + deps: + - path: ddos/reports/condense/logistic.csv + hash: md5 + md5: b24764aed957fdf6d2ccb541ef490d37 + size: 3150984 + params: + conf/clean.yaml: + replace: + model.init.metric: + jaro: Jaro + _winkler: -Winkler + levenshtein: Levenshtein + ncd: NCD + ratio: Ratio + seqRatio: SeqRatio + hamming: Hamming + gzip: Gzip + pkl: Pickle + bz2: BZ2 + zstd: Zstd + lzma: Lzma + model_name: + GzipSVC: k-SVC + GzipLogisticRegressor: k-Logistic + GzipKNN: k-KNN + model.init.symmetric: + true: Symmetric + false: Asymmetric + outs: + - path: ddos/plots/clean/condense/logistic.csv + hash: md5 + md5: bfca6e865bca11a25fa1e42dfbdea0ad + size: 2331762 + merge_condense@ddos: + cmd: python merge.py --big_dir ddos/plots/ --data_file clean/condense/knn.csv + --little_dir_data_file clean/condense/logistic.csv clean/condense/svc.csv --output_folder + ddos/plots/ --output_file condensed_merged.csv + deps: + - path: ddos/plots/clean/condense/knn.csv + hash: md5 + md5: d214914ecfbba6afbd4ff9a61cb96bb1 + size: 3652514 + - path: ddos/plots/clean/condense/logistic.csv + hash: md5 + md5: bfca6e865bca11a25fa1e42dfbdea0ad + size: 2331762 + - path: ddos/plots/clean/condense/svc.csv + hash: md5 + md5: 102b712883464d547a4d2119f6c5df60 + size: 2968961 + outs: + - path: ddos/plots/condensed_merged.csv + hash: md5 + md5: dc147a2e9c585b39c5e212a46ade70ac + size: 9306964 + merge_condense@kdd_nsl: + cmd: python merge.py --big_dir kdd_nsl/plots/ --data_file clean/condense/knn.csv + --little_dir_data_file clean/condense/logistic.csv clean/condense/svc.csv --output_folder + kdd_nsl/plots/ --output_file condensed_merged.csv + deps: + - path: kdd_nsl/plots/clean/condense/knn.csv + hash: md5 + md5: 23789b08b0fd1616555611d0e7971db9 + size: 1204868 + - path: kdd_nsl/plots/clean/condense/logistic.csv + hash: md5 + md5: 55a0ac50149a3e3d93b69c63ccd0d7a3 + size: 1174964 + - path: kdd_nsl/plots/clean/condense/svc.csv + hash: md5 + md5: c9b2ff8546f531fa439c664c63fc06fd + size: 2021393 + outs: + - path: kdd_nsl/plots/condensed_merged.csv + hash: md5 + md5: 1ddcee7de7db0c1a7d4898de4a03d7b7 + size: 4543759 + merge_condense@sms_spam: + cmd: python merge.py --big_dir sms_spam/plots/ --data_file clean/condense/knn.csv + --little_dir_data_file clean/condense/logistic.csv clean/condense/svc.csv --output_folder + sms_spam/plots/ --output_file condensed_merged.csv + deps: + - path: sms_spam/plots/clean/condense/knn.csv + hash: md5 + md5: 7dda620e8ae59aab14ac83c0071a8b96 + size: 1268504 + - path: sms_spam/plots/clean/condense/logistic.csv + hash: md5 + md5: 1f89cfa87c87f195079e49eb5d6e7ce5 + size: 2461824 + - path: sms_spam/plots/clean/condense/svc.csv + hash: md5 + md5: 92b8648f6759e0a56c65aeec4a15aa92 + size: 1223675 + outs: + - path: sms_spam/plots/condensed_merged.csv + hash: md5 + md5: 8f549743001ca622a6c7c8cbb2b3d17d + size: 5114716 + merge_condense@truthseeker: + cmd: python merge.py --big_dir truthseeker/plots/ --data_file clean/condense/knn.csv + --little_dir_data_file clean/condense/logistic.csv clean/condense/svc.csv --output_folder + truthseeker/plots/ --output_file condensed_merged.csv + deps: + - path: truthseeker/plots/clean/condense/knn.csv + hash: md5 + md5: a0c8deb8fe7617477ec43fae2a851b4d + size: 1191230 + - path: truthseeker/plots/clean/condense/logistic.csv + hash: md5 + md5: 9710addb440069a5ea884d90ed4c394a + size: 1237939 + - path: truthseeker/plots/clean/condense/svc.csv + hash: md5 + md5: a17c0cdb6a3fbfae5bd4fcfca1938a96 + size: 1257671 + outs: + - path: truthseeker/plots/condensed_merged.csv + hash: md5 + md5: 738dc93bfff1b9c167949e722ee79665 + size: 3805499 + grid_search@300-ddos-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.train_size=300 + data.sample.test_size=100 model_name=gzip_knn model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_knn_ddos hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=ddos/logs/gzip_knn/300 hydra.callbacks.study_dump.output_file=ddos/logs/gzip_knn/300/study.csv + files.directory=ddos files.reports=reports/gzip_knn/300 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_knn --multirun + deps: + - path: conf/gzip_knn.yaml + hash: md5 + md5: a58015cd6f327e171842b045a2524bfd + size: 2062 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_knn.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k: 1,3,5,7,11 + +model.init.weights: uniform,distance + +model.init.algorithm: brute + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + ++data.sample.random_state: int(interval(1, 10000)) + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_knn + outs: + - path: ddos/logs/gzip_knn/300 + hash: md5 + md5: 1e533c118406ca2ffae2b0a3e11a5035.dir + size: 1671182 + nfiles: 514 + - path: ddos/reports/gzip_knn/300/train/ + hash: md5 + md5: 000376454dd461f25065cdb093e78e7c.dir + size: 1461265 + nfiles: 1403 + plot_condense@sms_spam: + cmd: python -m deckard.layers.plots --path sms_spam/plots/ --file sms_spam/plots/condensed_merged.csv -c + conf/condensed_plots.yaml + deps: + - path: sms_spam/plots/condensed_merged.csv + hash: md5 + md5: 8f549743001ca622a6c7c8cbb2b3d17d + size: 5114716 + params: + conf/condensed_plots.yaml: + line_plot: + - file: sampling_method_vs_accuracy.pdf + hue: model.init.sampling_method + title: + x: model.init.m + xlabel: Percentage of Samples per Class + y: accuracy + ylabel: Accuracy + hue_order: + - random + - svc + - knn + - sum + - medoid + - nearmiss + - hardness + errorbar: se + err_style: bars + xlim: + - 0 + - 1 + y_scale: linear + legend: + title: Sampling Method + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + - file: sampling_method_vs_train_time.pdf + hue: model.init.sampling_method + title: + x: model.init.m + xlabel: Percentage of Samples per Class + y: train_time + ylabel: Training Time (s) + y_scale: linear + hue_order: + - random + - svc + - knn + - sum + - medoid + - nearmiss + - hardness + errorbar: se + err_style: bars + xlim: + - 0 + - 1 + legend: + title: Sampling Method + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + - file: sampling_method_vs_predict_time.pdf + hue: model.init.sampling_method + title: + x: model.init.m + xlabel: Percentage of Samples per Class + y: predict_time + ylabel: Prediction Time (s) + y_scale: log + hue_order: + - random + - svc + - knn + - sum + - medoid + - nearmiss + - hardness + errorbar: se + err_style: bars + xlim: + - 0 + - 1 + legend: + title: Sampling Method + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + outs: + - path: sms_spam/plots/sampling_method_vs_accuracy.pdf + hash: md5 + md5: 8d3c7b03379f2f16bdb6de450083608b + size: 40643 + - path: sms_spam/plots/sampling_method_vs_predict_time.pdf + hash: md5 + md5: 095622e64533aedee66d72079f141c0d + size: 53902 + - path: sms_spam/plots/sampling_method_vs_train_time.pdf + hash: md5 + md5: da26bd3fc967c9925975f6c8ad189a88 + size: 50367 + plot_condense@ddos: + cmd: python -m deckard.layers.plots --path ddos/plots/ --file ddos/plots/condensed_merged.csv -c + conf/condensed_plots.yaml + deps: + - path: ddos/plots/condensed_merged.csv + hash: md5 + md5: dc147a2e9c585b39c5e212a46ade70ac + size: 9306964 + params: + conf/condensed_plots.yaml: + line_plot: + - file: sampling_method_vs_accuracy.pdf + hue: model.init.sampling_method + title: + x: model.init.m + xlabel: Percentage of Samples per Class + y: accuracy + ylabel: Accuracy + hue_order: + - random + - svc + - knn + - sum + - medoid + - nearmiss + - hardness + errorbar: se + err_style: bars + xlim: + - 0 + - 1 + y_scale: linear + legend: + title: Sampling Method + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + - file: sampling_method_vs_train_time.pdf + hue: model.init.sampling_method + title: + x: model.init.m + xlabel: Percentage of Samples per Class + y: train_time + ylabel: Training Time (s) + y_scale: linear + hue_order: + - random + - svc + - knn + - sum + - medoid + - nearmiss + - hardness + errorbar: se + err_style: bars + xlim: + - 0 + - 1 + legend: + title: Sampling Method + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + - file: sampling_method_vs_predict_time.pdf + hue: model.init.sampling_method + title: + x: model.init.m + xlabel: Percentage of Samples per Class + y: predict_time + ylabel: Prediction Time (s) + y_scale: log + hue_order: + - random + - svc + - knn + - sum + - medoid + - nearmiss + - hardness + errorbar: se + err_style: bars + xlim: + - 0 + - 1 + legend: + title: Sampling Method + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + outs: + - path: ddos/plots/sampling_method_vs_accuracy.pdf + hash: md5 + md5: 09737e6b272979bf7fc879ece10d25e5 + size: 57907 + - path: ddos/plots/sampling_method_vs_predict_time.pdf + hash: md5 + md5: 78e2e0111219f86d189dfb952d81cdba + size: 78230 + - path: ddos/plots/sampling_method_vs_train_time.pdf + hash: md5 + md5: ab34ce0b71b6c0153525b0194178ecaf + size: 64512 + plot_condense@kdd_nsl: + cmd: python -m deckard.layers.plots --path kdd_nsl/plots/ --file kdd_nsl/plots/condensed_merged.csv -c + conf/condensed_plots.yaml + deps: + - path: kdd_nsl/plots/condensed_merged.csv + hash: md5 + md5: 1ddcee7de7db0c1a7d4898de4a03d7b7 + size: 4543759 + params: + conf/condensed_plots.yaml: + line_plot: + - file: sampling_method_vs_accuracy.pdf + hue: model.init.sampling_method + title: + x: model.init.m + xlabel: Percentage of Samples per Class + y: accuracy + ylabel: Accuracy + hue_order: + - random + - svc + - knn + - sum + - medoid + - nearmiss + - hardness + errorbar: se + err_style: bars + xlim: + - 0 + - 1 + y_scale: linear + legend: + title: Sampling Method + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + - file: sampling_method_vs_train_time.pdf + hue: model.init.sampling_method + title: + x: model.init.m + xlabel: Percentage of Samples per Class + y: train_time + ylabel: Training Time (s) + y_scale: linear + hue_order: + - random + - svc + - knn + - sum + - medoid + - nearmiss + - hardness + errorbar: se + err_style: bars + xlim: + - 0 + - 1 + legend: + title: Sampling Method + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + - file: sampling_method_vs_predict_time.pdf + hue: model.init.sampling_method + title: + x: model.init.m + xlabel: Percentage of Samples per Class + y: predict_time + ylabel: Prediction Time (s) + y_scale: log + hue_order: + - random + - svc + - knn + - sum + - medoid + - nearmiss + - hardness + errorbar: se + err_style: bars + xlim: + - 0 + - 1 + legend: + title: Sampling Method + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + outs: + - path: kdd_nsl/plots/sampling_method_vs_accuracy.pdf + hash: md5 + md5: 1c673220cd32e3f9bd2aa92516d0b20e + size: 38546 + - path: kdd_nsl/plots/sampling_method_vs_predict_time.pdf + hash: md5 + md5: 4bcb086fcd47e05d2b79e30a12d15869 + size: 50187 + - path: kdd_nsl/plots/sampling_method_vs_train_time.pdf + hash: md5 + md5: 2b3e91d9b656ba35d06f8e97d1e8359d + size: 45992 + grid_search@300-ddos-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.train_size=300 + data.sample.test_size=100 model_name=gzip_logistic model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_logistic_ddos hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=ddos/logs/gzip_logistic/300 hydra.callbacks.study_dump.output_file=ddos/logs/gzip_logistic/300/study.csv + files.directory=ddos files.reports=reports/gzip_logistic/300 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_logistic --multirun + deps: + - path: conf/gzip_logistic.yaml + hash: md5 + md5: 847d4d804fff0b6f2533f90820eebd04 + size: 2205 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_logistic.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 1 + params: + +model.init.solver: saga + +model.init.penalty: l2,l1,l2,none + +model.init.tol: 1e-4,1e-3,1e-2 + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept: True,False + +model.init.class_weight: balanced,None + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_logistic + outs: + - path: ddos/logs/gzip_logistic/300 + hash: md5 + md5: ace39d7825de3ce5c0d678839c812ab6.dir + size: 1765030 + nfiles: 514 + - path: ddos/reports/gzip_logistic/300/train/ + hash: md5 + md5: 9f23532033970310bd5915d4018de935.dir + size: 1436932 + nfiles: 963 + grid_search@300-ddos-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.train_size=300 + data.sample.test_size=100 model_name=gzip_svc model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_svc_ddos hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=ddos/logs/gzip_svc/300 hydra.callbacks.study_dump.output_file=ddos/logs/gzip_svc/300/study.csv + files.directory=ddos files.reports=reports/gzip_svc/300 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_svc --multirun + deps: + - path: conf/gzip_svc.yaml + hash: md5 + md5: 957922cb6993eb99866232d944a4a106 + size: 2131 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_svc.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: + - maximize + metric_names: + - accuracy + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + params: + +model.init.kernel: rbf,precomputed + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma: scale,auto + +model.init.class_weight: balanced,null + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_svc + outs: + - path: ddos/logs/gzip_svc/300 + hash: md5 + md5: 7681421b662e0a0690e9a1a6a4cf4b79.dir + size: 1710386 + nfiles: 514 + - path: ddos/reports/gzip_svc/300/train/ + hash: md5 + md5: c872a806e708289c65e6856bc2a057bf.dir + size: 1393355 + nfiles: 1045 + plot_condense@truthseeker: + cmd: python -m deckard.layers.plots --path truthseeker/plots/ --file truthseeker/plots/condensed_merged.csv -c + conf/condensed_plots.yaml + deps: + - path: truthseeker/plots/condensed_merged.csv + hash: md5 + md5: 738dc93bfff1b9c167949e722ee79665 + size: 3805499 + params: + conf/condensed_plots.yaml: + line_plot: + - file: sampling_method_vs_accuracy.pdf + hue: model.init.sampling_method + title: + x: model.init.m + xlabel: Percentage of Samples per Class + y: accuracy + ylabel: Accuracy + hue_order: + - random + - svc + - knn + - sum + - medoid + - nearmiss + - hardness + errorbar: se + err_style: bars + xlim: + - 0 + - 1 + y_scale: linear + legend: + title: Sampling Method + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + - file: sampling_method_vs_train_time.pdf + hue: model.init.sampling_method + title: + x: model.init.m + xlabel: Percentage of Samples per Class + y: train_time + ylabel: Training Time (s) + y_scale: linear + hue_order: + - random + - svc + - knn + - sum + - medoid + - nearmiss + - hardness + errorbar: se + err_style: bars + xlim: + - 0 + - 1 + legend: + title: Sampling Method + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + - file: sampling_method_vs_predict_time.pdf + hue: model.init.sampling_method + title: + x: model.init.m + xlabel: Percentage of Samples per Class + y: predict_time + ylabel: Prediction Time (s) + y_scale: log + hue_order: + - random + - svc + - knn + - sum + - medoid + - nearmiss + - hardness + errorbar: se + err_style: bars + xlim: + - 0 + - 1 + legend: + title: Sampling Method + bbox_to_anchor: + - 1.05 + - 0.5 + loc: center left + prop: + size: 14 + outs: + - path: truthseeker/plots/sampling_method_vs_accuracy.pdf + hash: md5 + md5: 0d293f64173585cb19c88218a7327f83 + size: 18158 + - path: truthseeker/plots/sampling_method_vs_predict_time.pdf + hash: md5 + md5: bb494d7b950451096bb639f3a9f1b4cb + size: 45092 + - path: truthseeker/plots/sampling_method_vs_train_time.pdf + hash: md5 + md5: 85a9eeb8f5aecc63f5634b12483941cf + size: 39796 + grid_search@500-ddos-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.train_size=500 + data.sample.test_size=100 model_name=gzip_logistic model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_logistic_ddos hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=ddos/logs/gzip_logistic/500 hydra.callbacks.study_dump.output_file=ddos/logs/gzip_logistic/500/study.csv + files.directory=ddos files.reports=reports/gzip_logistic/500 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_logistic --multirun + deps: + - path: conf/gzip_logistic.yaml + hash: md5 + md5: 847d4d804fff0b6f2533f90820eebd04 + size: 2205 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_logistic.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 1 + params: + +model.init.solver: saga + +model.init.penalty: l2,l1,l2,none + +model.init.tol: 1e-4,1e-3,1e-2 + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept: True,False + +model.init.class_weight: balanced,None + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_logistic + outs: + - path: ddos/logs/gzip_logistic/500 + hash: md5 + md5: afb6463625f139e82a88976c24b93f16.dir + size: 1791134 + nfiles: 514 + - path: ddos/reports/gzip_logistic/500/train/ + hash: md5 + md5: dbed10dfbc2747c79e14dcedcbce0661.dir + size: 968208 + nfiles: 702 + grid_search@500-ddos-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.train_size=500 + data.sample.test_size=100 model_name=gzip_svc model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_svc_ddos hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=ddos/logs/gzip_svc/500 hydra.callbacks.study_dump.output_file=ddos/logs/gzip_svc/500/study.csv + files.directory=ddos files.reports=reports/gzip_svc/500 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_svc --multirun + deps: + - path: conf/gzip_svc.yaml + hash: md5 + md5: 957922cb6993eb99866232d944a4a106 + size: 2131 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_svc.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: + - maximize + metric_names: + - accuracy + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + params: + +model.init.kernel: rbf,precomputed + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma: scale,auto + +model.init.class_weight: balanced,null + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_svc + outs: + - path: ddos/logs/gzip_svc/500 + hash: md5 + md5: 319357234ff9123f09bb6603fe74866f.dir + size: 1737584 + nfiles: 514 + - path: ddos/reports/gzip_svc/500/train/ + hash: md5 + md5: 63ecb36bf4e16027b60bcd2892330829.dir + size: 897567 + nfiles: 768 + grid_search@100-sms_spam-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.train_size=100 data.sample.test_size=100 model_name=gzip_logistic + model.init.distance_matrix=null hydra.sweeper.study_name=gzip_logistic_sms_spam + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=sms_spam/logs/gzip_logistic/100 + hydra.callbacks.study_dump.output_file=sms_spam/logs/gzip_logistic/100/study.csv + files.directory=sms_spam files.reports=reports/gzip_logistic/100 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_logistic --multirun + deps: + - path: conf/gzip_logistic.yaml + hash: md5 + md5: 847d4d804fff0b6f2533f90820eebd04 + size: 2205 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_logistic.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 1 + params: + +model.init.solver: saga + +model.init.penalty: l2,l1,l2,none + +model.init.tol: 1e-4,1e-3,1e-2 + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept: True,False + +model.init.class_weight: balanced,None + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_logistic + outs: + - path: sms_spam/logs/gzip_logistic/100 + hash: md5 + md5: d1120618c5a674fe50c5717e2d71d640.dir + size: 1554813 + nfiles: 514 + - path: sms_spam/reports/gzip_logistic/100/train/ + hash: md5 + md5: 89f61791ac36513c4957057485a2e8e3.dir + size: 553318 + nfiles: 357 + grid_search@100-sms_spam-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.train_size=100 data.sample.test_size=100 model_name=gzip_svc model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_svc_sms_spam hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=sms_spam/logs/gzip_svc/100 hydra.callbacks.study_dump.output_file=sms_spam/logs/gzip_svc/100/study.csv + files.directory=sms_spam files.reports=reports/gzip_svc/100 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_svc --multirun + deps: + - path: conf/gzip_svc.yaml + hash: md5 + md5: 957922cb6993eb99866232d944a4a106 + size: 2131 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_svc.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: + - maximize + metric_names: + - accuracy + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + params: + +model.init.kernel: rbf,precomputed + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma: scale,auto + +model.init.class_weight: balanced,null + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_svc + outs: + - path: sms_spam/logs/gzip_svc/100 + hash: md5 + md5: cb8e4936d6ee03af99fa775d8b4b956b.dir + size: 1483653 + nfiles: 514 + - path: sms_spam/reports/gzip_svc/100/train/ + hash: md5 + md5: ae31535b48c489e3040a2836c43215a5.dir + size: 543085 + nfiles: 384 + grid_search@300-kdd_nsl-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=kdd_nsl dataset=kdd_nsl + data.sample.train_size=300 data.sample.test_size=100 model_name=gzip_knn model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_knn_kdd_nsl hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=kdd_nsl/logs/gzip_knn/300 hydra.callbacks.study_dump.output_file=kdd_nsl/logs/gzip_knn/300/study.csv + files.directory=kdd_nsl files.reports=reports/gzip_knn/300 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_knn --multirun + deps: + - path: conf/gzip_knn.yaml + hash: md5 + md5: a58015cd6f327e171842b045a2524bfd + size: 2062 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_knn.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k: 1,3,5,7,11 + +model.init.weights: uniform,distance + +model.init.algorithm: brute + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + ++data.sample.random_state: int(interval(1, 10000)) + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_knn + outs: + - path: kdd_nsl/logs/gzip_knn/300 + hash: md5 + md5: d3f58cbd5181a4f86ac660aba7173dfb.dir + size: 1437824 + nfiles: 514 + - path: kdd_nsl/reports/gzip_knn/300/train/ + hash: md5 + md5: d5317915e16e54a5fb4c82963cc0b058.dir + size: 825336 + nfiles: 612 + grid_search@300-kdd_nsl-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=kdd_nsl dataset=kdd_nsl + data.sample.train_size=300 data.sample.test_size=100 model_name=gzip_logistic + model.init.distance_matrix=null hydra.sweeper.study_name=gzip_logistic_kdd_nsl + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=kdd_nsl/logs/gzip_logistic/300 + hydra.callbacks.study_dump.output_file=kdd_nsl/logs/gzip_logistic/300/study.csv + files.directory=kdd_nsl files.reports=reports/gzip_logistic/300 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_logistic --multirun + deps: + - path: conf/gzip_logistic.yaml + hash: md5 + md5: 847d4d804fff0b6f2533f90820eebd04 + size: 2205 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_logistic.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 1 + params: + +model.init.solver: saga + +model.init.penalty: l2,l1,l2,none + +model.init.tol: 1e-4,1e-3,1e-2 + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept: True,False + +model.init.class_weight: balanced,None + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_logistic + outs: + - path: kdd_nsl/logs/gzip_logistic/300 + hash: md5 + md5: 6793362a9053b6f28647bb49875ebcf3.dir + size: 1634660 + nfiles: 514 + - path: kdd_nsl/reports/gzip_logistic/300/train/ + hash: md5 + md5: f2a46e55c8597a4d4082202f69186083.dir + size: 945424 + nfiles: 723 + grid_search@300-kdd_nsl-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=kdd_nsl dataset=kdd_nsl + data.sample.train_size=300 data.sample.test_size=100 model_name=gzip_svc model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_svc_kdd_nsl hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=kdd_nsl/logs/gzip_svc/300 hydra.callbacks.study_dump.output_file=kdd_nsl/logs/gzip_svc/300/study.csv + files.directory=kdd_nsl files.reports=reports/gzip_svc/300 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_svc --multirun + deps: + - path: conf/gzip_svc.yaml + hash: md5 + md5: 957922cb6993eb99866232d944a4a106 + size: 2131 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_svc.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: + - maximize + metric_names: + - accuracy + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + params: + +model.init.kernel: rbf,precomputed + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma: scale,auto + +model.init.class_weight: balanced,null + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_svc + outs: + - path: kdd_nsl/logs/gzip_svc/300 + hash: md5 + md5: 1bd3b191acf0f78e361e1bc3cb6df928.dir + size: 1584389 + nfiles: 514 + - path: kdd_nsl/reports/gzip_svc/300/train/ + hash: md5 + md5: b6e64c8b751bf3a140aa9871f341a173.dir + size: 899234 + nfiles: 765 + grid_search@300-sms_spam-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.train_size=300 data.sample.test_size=100 model_name=gzip_knn model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_knn_sms_spam hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=sms_spam/logs/gzip_knn/300 hydra.callbacks.study_dump.output_file=sms_spam/logs/gzip_knn/300/study.csv + files.directory=sms_spam files.reports=reports/gzip_knn/300 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_knn --multirun + deps: + - path: conf/gzip_knn.yaml + hash: md5 + md5: a58015cd6f327e171842b045a2524bfd + size: 2062 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_knn.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k: 1,3,5,7,11 + +model.init.weights: uniform,distance + +model.init.algorithm: brute + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + ++data.sample.random_state: int(interval(1, 10000)) + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_knn + outs: + - path: sms_spam/logs/gzip_knn/300 + hash: md5 + md5: 09019492218a189aabe0601cb4c3f3a3.dir + size: 1460894 + nfiles: 514 + - path: sms_spam/reports/gzip_knn/300/train/ + hash: md5 + md5: 3aa09498a167a50051ee2fdf3e46d62d.dir + size: 364240 + nfiles: 349 + grid_search@300-sms_spam-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.train_size=300 data.sample.test_size=100 model_name=gzip_logistic + model.init.distance_matrix=null hydra.sweeper.study_name=gzip_logistic_sms_spam + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=sms_spam/logs/gzip_logistic/300 + hydra.callbacks.study_dump.output_file=sms_spam/logs/gzip_logistic/300/study.csv + files.directory=sms_spam files.reports=reports/gzip_logistic/300 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_logistic --multirun + deps: + - path: conf/gzip_logistic.yaml + hash: md5 + md5: 847d4d804fff0b6f2533f90820eebd04 + size: 2205 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_logistic.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 1 + params: + +model.init.solver: saga + +model.init.penalty: l2,l1,l2,none + +model.init.tol: 1e-4,1e-3,1e-2 + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept: True,False + +model.init.class_weight: balanced,None + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_logistic + outs: + - path: sms_spam/logs/gzip_logistic/300 + hash: md5 + md5: 627574a996abf0037be2b9d798c0a1f6.dir + size: 1593011 + nfiles: 514 + - path: sms_spam/reports/gzip_logistic/300/train/ + hash: md5 + md5: 886edc50f38dc580603074bf8dc46835.dir + size: 553839 + nfiles: 363 + grid_search@300-sms_spam-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.train_size=300 data.sample.test_size=100 model_name=gzip_svc model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_svc_sms_spam hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=sms_spam/logs/gzip_svc/300 hydra.callbacks.study_dump.output_file=sms_spam/logs/gzip_svc/300/study.csv + files.directory=sms_spam files.reports=reports/gzip_svc/300 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_svc --multirun + deps: + - path: conf/gzip_svc.yaml + hash: md5 + md5: 957922cb6993eb99866232d944a4a106 + size: 2131 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_svc.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: + - maximize + metric_names: + - accuracy + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + params: + +model.init.kernel: rbf,precomputed + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma: scale,auto + +model.init.class_weight: balanced,null + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_svc + outs: + - path: sms_spam/logs/gzip_svc/300 + hash: md5 + md5: 7d9d939af4228ad75b78ee5c347a984a.dir + size: 1513139 + nfiles: 514 + - path: sms_spam/reports/gzip_svc/300/train/ + hash: md5 + md5: cb8713e4f13494c3c1ab3c93c238d2d7.dir + size: 544369 + nfiles: 384 + grid_search@300-truthseeker-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.train_size=300 data.sample.test_size=100 model_name=gzip_knn model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_knn_truthseeker hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=truthseeker/logs/gzip_knn/300 hydra.callbacks.study_dump.output_file=truthseeker/logs/gzip_knn/300/study.csv + files.directory=truthseeker files.reports=reports/gzip_knn/300 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_knn --multirun + deps: + - path: conf/gzip_knn.yaml + hash: md5 + md5: a58015cd6f327e171842b045a2524bfd + size: 2062 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_knn.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k: 1,3,5,7,11 + +model.init.weights: uniform,distance + +model.init.algorithm: brute + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + ++data.sample.random_state: int(interval(1, 10000)) + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_knn + outs: + - path: truthseeker/logs/gzip_knn/300 + hash: md5 + md5: 7fc2fb64903d90052db980e395a73a1b.dir + size: 1418937 + nfiles: 514 + - path: truthseeker/reports/gzip_knn/300/train/ + hash: md5 + md5: 1b7d0b73ddb24fa30f48675625cad64c.dir + size: 384561 + nfiles: 332 + grid_search@300-truthseeker-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.train_size=300 data.sample.test_size=100 model_name=gzip_logistic + model.init.distance_matrix=null hydra.sweeper.study_name=gzip_logistic_truthseeker + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=truthseeker/logs/gzip_logistic/300 + hydra.callbacks.study_dump.output_file=truthseeker/logs/gzip_logistic/300/study.csv + files.directory=truthseeker files.reports=reports/gzip_logistic/300 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_logistic --multirun + deps: + - path: conf/gzip_logistic.yaml + hash: md5 + md5: 847d4d804fff0b6f2533f90820eebd04 + size: 2205 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_logistic.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 1 + params: + +model.init.solver: saga + +model.init.penalty: l2,l1,l2,none + +model.init.tol: 1e-4,1e-3,1e-2 + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept: True,False + +model.init.class_weight: balanced,None + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_logistic + outs: + - path: truthseeker/logs/gzip_logistic/300 + hash: md5 + md5: 121b624ea70d27aba89bd5448c35580f.dir + size: 1564349 + nfiles: 514 + - path: truthseeker/reports/gzip_logistic/300/train/ + hash: md5 + md5: 7dfeff37b85b221b60c7bad442f21658.dir + size: 557318 + nfiles: 367 + grid_search@300-truthseeker-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.train_size=300 data.sample.test_size=100 model_name=gzip_svc model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_svc_truthseeker hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=truthseeker/logs/gzip_svc/300 hydra.callbacks.study_dump.output_file=truthseeker/logs/gzip_svc/300/study.csv + files.directory=truthseeker files.reports=reports/gzip_svc/300 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_svc --multirun + deps: + - path: conf/gzip_svc.yaml + hash: md5 + md5: 957922cb6993eb99866232d944a4a106 + size: 2131 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_svc.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: + - maximize + metric_names: + - accuracy + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + params: + +model.init.kernel: rbf,precomputed + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma: scale,auto + +model.init.class_weight: balanced,null + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_svc + outs: + - path: truthseeker/logs/gzip_svc/300 + hash: md5 + md5: c1b03e3fa37ca812864d04d3a38216db.dir + size: 1536045 + nfiles: 514 + - path: truthseeker/reports/gzip_svc/300/train/ + hash: md5 + md5: 2cf3648372291b72f9b16020c5c3ad4e.dir + size: 548358 + nfiles: 384 + grid_search@500-ddos-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=ddos dataset=ddos data.sample.train_size=500 + data.sample.test_size=100 model_name=gzip_knn model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_knn_ddos hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=ddos/logs/gzip_knn/500 hydra.callbacks.study_dump.output_file=ddos/logs/gzip_knn/500/study.csv + files.directory=ddos files.reports=reports/gzip_knn/500 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_knn --multirun + deps: + - path: conf/gzip_knn.yaml + hash: md5 + md5: a58015cd6f327e171842b045a2524bfd + size: 2062 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_knn.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k: 1,3,5,7,11 + +model.init.weights: uniform,distance + +model.init.algorithm: brute + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + ++data.sample.random_state: int(interval(1, 10000)) + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_knn + outs: + - path: ddos/logs/gzip_knn/500 + hash: md5 + md5: ebb76a3ffe046f5763072644ec826dd9.dir + size: 1693130 + nfiles: 514 + - path: ddos/reports/gzip_knn/500/train/ + hash: md5 + md5: 00682fbb7c897d179ed788f09be3b1e9.dir + size: 732559 + nfiles: 763 + grid_search@500-kdd_nsl-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=kdd_nsl dataset=kdd_nsl + data.sample.train_size=500 data.sample.test_size=100 model_name=gzip_knn model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_knn_kdd_nsl hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=kdd_nsl/logs/gzip_knn/500 hydra.callbacks.study_dump.output_file=kdd_nsl/logs/gzip_knn/500/study.csv + files.directory=kdd_nsl files.reports=reports/gzip_knn/500 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_knn --multirun + deps: + - path: conf/gzip_knn.yaml + hash: md5 + md5: a58015cd6f327e171842b045a2524bfd + size: 2062 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_knn.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k: 1,3,5,7,11 + +model.init.weights: uniform,distance + +model.init.algorithm: brute + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + ++data.sample.random_state: int(interval(1, 10000)) + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_knn + outs: + - path: kdd_nsl/logs/gzip_knn/500 + hash: md5 + md5: f1d5a2b6b59bc61a8c8d9c52d3a2ad11.dir + size: 1496906 + nfiles: 514 + - path: kdd_nsl/reports/gzip_knn/500/train/ + hash: md5 + md5: bffa17c78573257f1d85dccf5d93fade.dir + size: 388686 + nfiles: 335 + grid_search@500-kdd_nsl-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=kdd_nsl dataset=kdd_nsl + data.sample.train_size=500 data.sample.test_size=100 model_name=gzip_logistic + model.init.distance_matrix=null hydra.sweeper.study_name=gzip_logistic_kdd_nsl + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=kdd_nsl/logs/gzip_logistic/500 + hydra.callbacks.study_dump.output_file=kdd_nsl/logs/gzip_logistic/500/study.csv + files.directory=kdd_nsl files.reports=reports/gzip_logistic/500 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_logistic --multirun + deps: + - path: conf/gzip_logistic.yaml + hash: md5 + md5: 847d4d804fff0b6f2533f90820eebd04 + size: 2205 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_logistic.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 1 + params: + +model.init.solver: saga + +model.init.penalty: l2,l1,l2,none + +model.init.tol: 1e-4,1e-3,1e-2 + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept: True,False + +model.init.class_weight: balanced,None + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_logistic + outs: + - path: kdd_nsl/logs/gzip_logistic/500 + hash: md5 + md5: 44795a3a64e10088623faf15b87a4548.dir + size: 1666384 + nfiles: 514 + - path: kdd_nsl/reports/gzip_logistic/500/train/ + hash: md5 + md5: 607cd0515dec2502b0bd11b6480b5d7b.dir + size: 565896 + nfiles: 357 + grid_search@500-kdd_nsl-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=kdd_nsl dataset=kdd_nsl + data.sample.train_size=500 data.sample.test_size=100 model_name=gzip_svc model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_svc_kdd_nsl hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=kdd_nsl/logs/gzip_svc/500 hydra.callbacks.study_dump.output_file=kdd_nsl/logs/gzip_svc/500/study.csv + files.directory=kdd_nsl files.reports=reports/gzip_svc/500 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_svc --multirun + deps: + - path: conf/gzip_svc.yaml + hash: md5 + md5: 957922cb6993eb99866232d944a4a106 + size: 2131 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_svc.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: + - maximize + metric_names: + - accuracy + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + params: + +model.init.kernel: rbf,precomputed + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma: scale,auto + +model.init.class_weight: balanced,null + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_svc + outs: + - path: kdd_nsl/logs/gzip_svc/500 + hash: md5 + md5: 1ed2e3d83e888471981684eaaa3f3b8e.dir + size: 1613038 + nfiles: 514 + - path: kdd_nsl/reports/gzip_svc/500/train/ + hash: md5 + md5: c53dae7497a8f55965cc708c28280f4e.dir + size: 555797 + nfiles: 384 + grid_search@500-sms_spam-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.train_size=500 data.sample.test_size=100 model_name=gzip_knn model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_knn_sms_spam hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=sms_spam/logs/gzip_knn/500 hydra.callbacks.study_dump.output_file=sms_spam/logs/gzip_knn/500/study.csv + files.directory=sms_spam files.reports=reports/gzip_knn/500 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_knn --multirun + deps: + - path: conf/gzip_knn.yaml + hash: md5 + md5: a58015cd6f327e171842b045a2524bfd + size: 2062 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_knn.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k: 1,3,5,7,11 + +model.init.weights: uniform,distance + +model.init.algorithm: brute + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + ++data.sample.random_state: int(interval(1, 10000)) + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_knn + outs: + - path: sms_spam/logs/gzip_knn/500 + hash: md5 + md5: 0e5c9c1b5970ef63e76b3adcbb1d9bde.dir + size: 1465483 + nfiles: 514 + - path: sms_spam/reports/gzip_knn/500/train/ + hash: md5 + md5: dd14847ddf87817f4410aea70b8fdce3.dir + size: 378991 + nfiles: 331 + grid_search@500-sms_spam-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.train_size=500 data.sample.test_size=100 model_name=gzip_logistic + model.init.distance_matrix=null hydra.sweeper.study_name=gzip_logistic_sms_spam + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=sms_spam/logs/gzip_logistic/500 + hydra.callbacks.study_dump.output_file=sms_spam/logs/gzip_logistic/500/study.csv + files.directory=sms_spam files.reports=reports/gzip_logistic/500 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_logistic --multirun + deps: + - path: conf/gzip_logistic.yaml + hash: md5 + md5: 847d4d804fff0b6f2533f90820eebd04 + size: 2205 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_logistic.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 1 + params: + +model.init.solver: saga + +model.init.penalty: l2,l1,l2,none + +model.init.tol: 1e-4,1e-3,1e-2 + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept: True,False + +model.init.class_weight: balanced,None + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_logistic + outs: + - path: sms_spam/logs/gzip_logistic/500 + hash: md5 + md5: 6e6d0761de2d778fbdbebd1d547f04a1.dir + size: 1619183 + nfiles: 514 + - path: sms_spam/reports/gzip_logistic/500/train/ + hash: md5 + md5: fb78d7f4f526194a09b6561a121f734e.dir + size: 553072 + nfiles: 361 + grid_search@500-sms_spam-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=sms_spam dataset=sms_spam + data.sample.train_size=500 data.sample.test_size=100 model_name=gzip_svc model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_svc_sms_spam hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=sms_spam/logs/gzip_svc/500 hydra.callbacks.study_dump.output_file=sms_spam/logs/gzip_svc/500/study.csv + files.directory=sms_spam files.reports=reports/gzip_svc/500 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_svc --multirun + deps: + - path: conf/gzip_svc.yaml + hash: md5 + md5: 957922cb6993eb99866232d944a4a106 + size: 2131 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_svc.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: + - maximize + metric_names: + - accuracy + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + params: + +model.init.kernel: rbf,precomputed + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma: scale,auto + +model.init.class_weight: balanced,null + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_svc + outs: + - path: sms_spam/logs/gzip_svc/500 + hash: md5 + md5: 4b37a4947b8a27e8b050b76a2252f6d2.dir + size: 1542505 + nfiles: 514 + - path: sms_spam/reports/gzip_svc/500/train/ + hash: md5 + md5: adfaa61acf833b9b2d823fd944876030.dir + size: 543664 + nfiles: 384 + grid_search@500-truthseeker-gzip_knn: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.train_size=500 data.sample.test_size=100 model_name=gzip_knn model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_knn_truthseeker hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=truthseeker/logs/gzip_knn/500 hydra.callbacks.study_dump.output_file=truthseeker/logs/gzip_knn/500/study.csv + files.directory=truthseeker files.reports=reports/gzip_knn/500 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_knn --multirun + deps: + - path: conf/gzip_knn.yaml + hash: md5 + md5: a58015cd6f327e171842b045a2524bfd + size: 2062 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_knn.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.num} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + direction: ${direction} + storage: sqlite:///optuna.db + study_name: ${dataset}_${model_name}_${stage} + n_trials: 2 + n_jobs: 2 + max_failure_rate: 1.0 + params: + model.init.k: 1,3,5,7,11 + +model.init.weights: uniform,distance + +model.init.algorithm: brute + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + ++data.sample.random_state: int(interval(1, 10000)) + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_knn + outs: + - path: truthseeker/logs/gzip_knn/500 + hash: md5 + md5: 8f89bb6eee2faa7d319f0e667a455558.dir + size: 1449788 + nfiles: 514 + - path: truthseeker/reports/gzip_knn/500/train/ + hash: md5 + md5: 22ad9cc6a9f1fc454ff08e23e1194b6a.dir + size: 382020 + nfiles: 333 + grid_search@500-truthseeker-gzip_logistic: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.train_size=500 data.sample.test_size=100 model_name=gzip_logistic + model.init.distance_matrix=null hydra.sweeper.study_name=gzip_logistic_truthseeker + hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 hydra.sweep.dir=truthseeker/logs/gzip_logistic/500 + hydra.callbacks.study_dump.output_file=truthseeker/logs/gzip_logistic/500/study.csv + files.directory=truthseeker files.reports=reports/gzip_logistic/500 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_logistic --multirun + deps: + - path: conf/gzip_logistic.yaml + hash: md5 + md5: 847d4d804fff0b6f2533f90820eebd04 + size: 2205 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_logistic.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: ${direction} + metric_names: ${optimizers} + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 1 + n_trials: 1 + params: + +model.init.solver: saga + +model.init.penalty: l2,l1,l2,none + +model.init.tol: 1e-4,1e-3,1e-2 + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.fit_intercept: True,False + +model.init.class_weight: balanced,None + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_logistic + outs: + - path: truthseeker/logs/gzip_logistic/500 + hash: md5 + md5: 536a09eb3f82d03737e3cec6aafdbac8.dir + size: 1605851 + nfiles: 514 + - path: truthseeker/reports/gzip_logistic/500/train/ + hash: md5 + md5: 4560cd0abd0609eebe34c6f578d77f2d.dir + size: 556183 + nfiles: 375 + grid_search@500-truthseeker-gzip_svc: + cmd: python -m deckard.layers.optimise stage=train data=truthseeker dataset=truthseeker + data.sample.train_size=500 data.sample.test_size=100 model_name=gzip_svc model.init.distance_matrix=null + hydra.sweeper.study_name=gzip_svc_truthseeker hydra.sweeper.n_trials=128 hydra.sweeper.n_jobs=8 + hydra.sweep.dir=truthseeker/logs/gzip_svc/500 hydra.callbacks.study_dump.output_file=truthseeker/logs/gzip_svc/500/study.csv + files.directory=truthseeker files.reports=reports/gzip_svc/500 hydra.launcher.n_jobs=-1 + ++raise_exception=True --config-name gzip_svc --multirun + deps: + - path: conf/gzip_svc.yaml + hash: md5 + md5: 957922cb6993eb99866232d944a4a106 + size: 2131 + - path: params.yaml + hash: md5 + md5: 8be0cf0b5f453ffb12b19a1bf1af6468 + size: 1435 + params: + conf/gzip_svc.yaml: + hydra: + run: + dir: ${dataset}/logs/${stage}/ + sweep: + dir: ??? + subdir: ${hydra.job.id} + callbacks: + study_dump: + _target_: database.OptunaStudyDumpCallback + storage: ${hydra.sweeper.storage} + study_name: ${hydra.sweeper.study_name} + directions: + - maximize + metric_names: + - accuracy + output_file: ${dataset}/logs/${model_name}/${data.sample.train_size}/study.csv + sweeper: + sampler: + _target_: optuna.samplers.TPESampler + seed: 123 + consider_prior: true + prior_weight: 1.0 + consider_magic_clip: true + consider_endpoints: false + n_startup_trials: 10 + n_ei_candidates: 24 + multivariate: true + _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper + study_name: ${dataset}_${model_name}_${stage} + storage: sqlite:///optuna.db + n_jobs: 2 + n_trials: 2 + params: + +model.init.kernel: rbf,precomputed + +model.init.C: 1e-2,1e-1,1e0,1e1,1e2 + +model.init.gamma: scale,auto + +model.init.class_weight: balanced,null + model.init.symmetric: True,False + ++model.init.precompute: true + model.init.metric: gzip,lzma,bz2,pkl,zstd,levenshtein,ratio,hamming,jaro,jaro_winkler,seqratio + model_name: ${model_name} + data.sample.random_state: int(interval(1, 10000)) + direction: ${direction} + max_failure_rate: 1.0 + launcher: + _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher + n_jobs: 8 + prefer: processes + verbose: 1 + timeout: + pre_dispatch: ${hydra.sweeper.n_jobs} + batch_size: auto + temp_folder: /tmp/deckard + max_nbytes: 100000 + mmap_mode: r + model_name: gzip_svc + outs: + - path: truthseeker/logs/gzip_svc/500 + hash: md5 + md5: 10808502e0c1c7d780ea6178ae53c19c.dir + size: 1568093 + nfiles: 514 + - path: truthseeker/reports/gzip_svc/500/train/ + hash: md5 + md5: 1fb9105254065d6d93e9647e12d650b2.dir + size: 547905 + nfiles: 384 diff --git a/examples/gzip/dvc.yaml b/examples/gzip/dvc.yaml new file mode 100644 index 00000000..b7d4c8d6 --- /dev/null +++ b/examples/gzip/dvc.yaml @@ -0,0 +1,439 @@ +vars: + - conf/default.yaml:hydra + - conf/plots.yaml:line_plot + - conf/plots.yaml:cat_plot + # - conf/condensed_plots.yaml:line_plot + # - conf/clean.yaml:params + # - conf/clean.yaml:fillna + - conf/clean.yaml:replace +stages: + ############################################################################## + # These stages use the dvc API to run a single experiment at a time using a + # deckard.Experiment object. This parses this file, saves the default hydra configuration + # to params.yaml, and then runs the experiment with the given parameters. + # This can be used to define a stage that runs a single experiment, or a stage for the + # optimisation using the optimise.py script and the hydrasweeper API. This API is primarily used for + # development and testing, as it is easier to run a single experiment at a time and debug it using + # DVC's git-like features to track changes and minimise run time. + + # This stage will parse the conf/default.yaml file and save it to params.yaml + # In addition, it will define a schema stage that will will + # 1. Determine the file paths for the data and model files (if specified) + # 2. Run the experiment with the given parameters + # 3. Save the results to the given file paths (will always save a score_dict_file, and a params_file to files.directory/files.reports/stage/) + # 4. Save a 'params.yaml' file with the scores (Always) + # 5. Save the predictions to the given file paths (if specified) + # 6. Save the probabilities to the given file paths (if specified) + # 7. Save the (final) losses to the given file paths (if specified) + # 8. Save the train/test labels to the given file paths (if specified) + + # You can arbitrarily define parameters in the 'conf' folder. + # To parse the parameters, you can use the 'hydra' API to define a schema for the parameters + # Or run `deckard.layers.parse` to parse the parameters and save them to a file. + ############################################################################## + data: + desc: "This stage will parse the conf/default.yaml file and save it to params.yaml" + cmd: python data_prep.py + outs: + - raw_data/ + deps: + - data_prep.py + parse_params: + cmd: python -m deckard.layers.parse + deps: + - conf/default.yaml + - conf/data/default.yaml + - conf/model/default.yaml + - conf/files/default.yaml + - conf/scorers/default.yaml + outs: + - params.yaml: + cache: true + desc : "Parsed parameters for the experiment" + persist: true + push : true + + train: + cmd: python -m deckard.layers.experiment train + metrics: + - ${files.directory}/${files.reports}/train/${files.name}/${files.score_dict_file} + outs: + - ${files.directory}/${files.reports}/train/${files.name}/${files.predictions_file} + params: + - data + - model + - scorers + - files + - dataset + - model_name + - device_id + deps: + - params.yaml + - raw_data/ # Raw data + ############################################################################## + test_each_dataset: + matrix: + dataset : [ddos, truthseeker, sms_spam, kdd_nsl] + model_name : [gzip_knn, gzip_svc, gzip_logistic] + cmd : >- + python -m deckard.layers.optimise + stage=train + files.name=${item.model_name} + data.sample.train_size=100 + files.directory=${item.dataset} + data=${item.dataset} + dataset=${item.dataset} + model_name=${item.model_name} + model=${item.model_name} + hydra.run.dir=${item.dataset}/logs/train/${item.model_name} + ++raise_exception=True + deps: + - params.yaml + - ${files.directory}/${files.reports}/train/default/${files.score_dict_file} + outs: + - ${item.dataset}/${files.reports}/train/${item.model_name}/${files.score_dict_file} + - ${item.dataset}/logs/train/${item.model_name} + params: + - data + - model + - scorers + - files + - dataset + - model_name + - device_id + ############################################################################## + test_each_metric: + matrix: + metric: [gzip, zstd, pkl, bz2, lzma,levenshtein, ratio, hamming, jaro, jaro_winkler, seqratio] + model : [gzip_knn,] # gzip_svc, gzip_logistic + dataset : [kdd_nsl] #truthseeker, sms_spam, ddos + train_size: [20] #100, 1000, 10000 + cmd : >- + python -m deckard.layers.optimise + stage=test_each_metric + files.name=${item.model}/${item.metric}/${item.train_size} + files.directory=${item.dataset} + data=${item.dataset} + data.sample.train_size=${item.train_size} + dataset=${item.dataset} + model=${item.model} + model_name=${model_name} + model.init.metric=${item.metric} + model.init.m=-1 + hydra.run.dir=${item.dataset}/logs/test_each_metric/${item.model}/${item.metric}/${item.train_size} + ++raise_exception=True + deps: + - params.yaml + - ${files.directory}/${files.reports}/train/default/${files.score_dict_file} + outs: + - ${item.dataset}/${files.reports}/test_each_metric/${item.model}/${item.metric}/${item.train_size}/${files.score_dict_file} + - ${item.dataset}/logs/test_each_metric/${item.model}/${item.metric}/${item.train_size} + params: + - data + - model + - scorers + - files + - dataset + - model_name + - device_id + # ############################################################################## + test_each_model: + matrix: + metric: [gzip] #, zstd, pkl, bz2, lzma,levenshtein, ratio, hamming, jaro, jaro_winkler, seqratio + model : [gzip_knn, gzip_svc, gzip_logistic] + dataset : [kdd_nsl] #truthseeker, sms_spam, ddos + train_size: [20] #100, 1000, 10000 + cmd : >- + python -m deckard.layers.optimise + stage=test_each_model + files.name=${item.model}/${item.metric}/${item.train_size} + files.directory=${item.dataset} + data=${item.dataset} + data.sample.train_size=${item.train_size} + dataset=${item.dataset} + model=${item.model} + model_name=${model_name} + model.init.metric=${item.metric} + model.init.m=-1 + hydra.run.dir=${item.dataset}/logs/test_each_model/${item.model}/${item.metric}/${item.train_size} + ++raise_exception=True + deps: + - params.yaml + - ${files.directory}/${files.reports}/train/default/${files.score_dict_file} + outs: + - ${item.dataset}/${files.reports}/test_each_model/${item.model}/${item.metric}/${item.train_size}/${files.score_dict_file} + - ${item.dataset}/logs/test_each_model/${item.model}/${item.metric}/${item.train_size} + params: + - data + - model + - scorers + - files + - dataset + - model_name + - device_id + ############################################################################## + grid_search: + matrix: + train_size: [20, 100, 300, 500] # + dataset : [ddos, kdd_nsl, sms_spam, truthseeker] # + configs: [gzip_knn, gzip_logistic, gzip_svc] + cmd: >- + python -m deckard.layers.optimise + stage=train + data=${item.dataset} + dataset=${item.dataset} + data.sample.train_size=${item.train_size} + data.sample.test_size=100 + model_name=${item.configs} + model.init.distance_matrix=null + hydra.sweeper.study_name=${item.configs}_${item.dataset} + hydra.sweeper.n_trials=128 + hydra.sweeper.n_jobs=8 + hydra.sweep.dir=${item.dataset}/logs/${item.configs}/${item.train_size} + hydra.callbacks.study_dump.output_file=${item.dataset}/logs/${item.configs}/${item.train_size}/study.csv + files.directory=${item.dataset} + files.reports=${files.reports}/${item.configs}/${item.train_size} + hydra.launcher.n_jobs=-1 + ++raise_exception=True + --config-name ${item.configs} + --multirun + deps: + - params.yaml + - conf/${item.configs}.yaml + outs: + - ${item.dataset}/logs/${item.configs}/${item.train_size} + - ${item.dataset}/${files.reports}/${item.configs}/${item.train_size}/train/: + cache: true + persist: true + push: true + params: + - conf/${item.configs}.yaml: + - hydra + - model_name + ############################################################################## + # find_best_model: # This isn't actually used in later steps, but it's handy to have these configs ready for a line search instead of a massive grid search + # matrix: + # dataset : [ddos, kdd_nsl, sms_spam,] # + # model : [gzip_knn, gzip_svc, gzip_logistic] + # deps: + # - ${item.dataset}/logs/${item.model}/ + # cmd: >- + # python -m deckard.layers.find_best --storage sqlite:///optuna.db --study_name ${item.model}_${item.dataset} --config_subdir model --params_file best_${item.model}_${item.dataset} --default_config ${item.model} + # outs: + # - conf/model/best_${item.model}_${item.dataset}.yaml + ############################################################################# + test_each_method: + matrix: + dataset : [ddos] # kdd_nsl, truthseeker, sms_spam, + method: [medoid, sum, svc, hardness, nearmiss,random,knn] + cmd : >- + python -m deckard.layers.optimise + stage=train + +model.init.sampling_method=${item.method} + model.init.m=3 + data.sample.train_size=100 + files.name=${item.method} + files.directory=${item.dataset} + data=${item.dataset} + dataset=${item.dataset} + model_name=${item.method} + hydra.run.dir=${item.dataset}/logs/method/${item.method} + ++raise_exception=True + deps: + - params.yaml + - ${files.directory}/${files.reports}/train/default/${files.score_dict_file} + outs: + - ${item.dataset}/${files.reports}/train/${item.method}/${files.score_dict_file} + - ${item.dataset}/logs/method/${item.method} + params: + - data + - model + - scorers + - files + - dataset + - model_name + - device_id + ############################################################################## + condense: + matrix: + dataset : [ddos, kdd_nsl, truthseeker, sms_spam,] # kdd_nsl, truthseeker, sms_spam, + model_name : [knn, svc, logistic] + deps: + - params.yaml + - conf/condense_${item.model_name}.yaml + cmd: >- + python -m deckard.layers.optimise + stage=train + data=${item.dataset} + dataset=${item.dataset} + data.sample.train_size=100 + data.sample.test_size=100 + model_name=condensed_${item.model_name} + model=gzip_${item.model_name} + files.directory=${item.dataset} + files.reports=${files.reports}/condense/${item.model_name}/ + hydra.sweeper.study_name=condense_${item.model_name}_${item.dataset} + hydra.sweeper.n_trials=1024 + hydra.sweeper.n_jobs=8 + hydra.sweep.dir=${item.dataset}/logs/condense/${item.model_name}/ + hydra.callbacks.study_dump.output_file=${item.dataset}/logs/${item.model_name}/study.csv + hydra.launcher.n_jobs=-1 + --config-name condense_${item.model_name} + --multirun + outs: + - ${item.dataset}/logs/condense/${item.model_name}/ + - ${item.dataset}/${files.reports}/condense/${item.model_name}/: + cache: true + persist: true + push: true + params: + - conf/condense.yaml: + - hydra + compile: + matrix: + dataset : [kdd_nsl, sms_spam, ddos] + stage : [gzip_knn, gzip_svc, gzip_logistic, condense/knn, condense/svc, condense/logistic] + deps: + - ${item.dataset}/${files.reports}/${item.stage}/ + outs: + - ${item.dataset}/${files.reports}/${item.stage}.csv + cmd: >- + python -m deckard.layers.compile + --report_folder ${item.dataset}/${files.reports}/${item.stage} + --results_file ${item.dataset}/${files.reports}/${item.stage}.csv + ############################################################################## + clean: + matrix: + dataset : [kdd_nsl, sms_spam, ddos] + stage : [gzip_knn, gzip_svc, gzip_logistic, condense/knn, condense/svc, condense/logistic] + deps: + - ${item.dataset}/${files.reports}/${item.stage}.csv + cmd: >- + python -m deckard.layers.clean_data + -i ${item.dataset}/${files.reports}/${item.stage}.csv + -o ${item.dataset}/plots/clean/${item.stage}.csv + -c conf/clean.yaml + outs: + - ${item.dataset}/plots/clean/${item.stage}.csv + params: + - conf/clean.yaml: + - replace + ############################################################################## + merge: + matrix: + dataset : [kdd_nsl, sms_spam, ddos] + deps: + - ${item.dataset}/plots/clean/gzip_knn.csv + - ${item.dataset}/plots/clean/gzip_logistic.csv + - ${item.dataset}/plots/clean/gzip_svc.csv + cmd: >- + python merge.py + --big_dir ${item.dataset}/plots/ + --data_file clean/gzip_knn.csv + --little_dir_data_file clean/gzip_logistic.csv clean/gzip_svc.csv + --output_folder ${item.dataset}/plots + --output_file merged.csv + outs: + - ${item.dataset}/plots/merged.csv + ############################################################################## + merge_condense: + matrix: + dataset : [kdd_nsl, sms_spam, ddos] + deps: + - ${item.dataset}/plots/clean/condense/knn.csv + - ${item.dataset}/plots/clean/condense/logistic.csv + - ${item.dataset}/plots/clean/condense/svc.csv + cmd: >- + python merge.py + --big_dir ${item.dataset}/plots/ + --data_file clean/condense/knn.csv + --little_dir_data_file clean/condense/logistic.csv clean/condense/svc.csv + --output_folder ${item.dataset}/plots/ + --output_file condensed_merged.csv + outs: + - ${item.dataset}/plots/condensed_merged.csv + ############################################################################## + plot: + matrix: + dataset : [kdd_nsl, sms_spam, ddos] + cmd: >- + python -m deckard.layers.plots + --path ${item.dataset}/plots/ + --file ${item.dataset}/plots/merged.csv + -c conf/plots.yaml + deps: + - ${item.dataset}/plots/merged.csv + plots: + - ${item.dataset}/plots/${line_plot[0].file} + - ${item.dataset}/plots/${line_plot[1].file} + - ${item.dataset}/plots/${line_plot[2].file} + - ${item.dataset}/plots/${cat_plot[0].file} + - ${item.dataset}/plots/${cat_plot[1].file} + - ${item.dataset}/plots/${cat_plot[2].file} + - ${item.dataset}/plots/${cat_plot[3].file} + - ${item.dataset}/plots/${cat_plot[4].file} + params: + - conf/plots.yaml: + - line_plot + - cat_plot + ############################################################################## + plot_condense: + matrix: + dataset : [kdd_nsl, sms_spam, ddos] + cmd: >- + python -m deckard.layers.plots + --path ${item.dataset}/plots/ + --file ${item.dataset}/plots/condensed_merged.csv + -c conf/condensed_plots.yaml + deps: + - ${item.dataset}/plots/condensed_merged.csv + plots: + - ${item.dataset}/plots/sampling_method_vs_accuracy.pdf + - ${item.dataset}/plots/sampling_method_vs_train_time.pdf + - ${item.dataset}/plots/sampling_method_vs_predict_time.pdf + params: + - conf/condensed_plots.yaml: + - line_plot + # copy: + # matrix: + # dataset : [kdd_nsl, truthseeker, sms_spam, ddos] + # cmd: >- + # rm -rf ~/Gzip-KNN/figs/${item.dataset}/ && + # mkdir -p ~/Gzip-KNN/figs/${item.dataset}/ && + # cp -r ${item.dataset}/plots/* ~/Gzip-KNN/figs/${item.dataset}/ + # deps: + # - ${item.dataset}/plots/ + # ############################################################################## + # # attack: + # # cmd: python -m deckard.layers.experiment attack + # # deps: + # # - ${files.directory}/${files.data_dir}/${files.data_file}${files.data_type} + # # - ${files.directory}/${files.model_dir}/${files.model_file}${files.model_type} + # # metrics: + # # - ${files.directory}/${files.reports}/attack/${files.name}/${files.score_dict_file} + # # outs: + # # - ${files.directory}/${files.reports}/attack/${files.name}/${files.adv_probabilities_file} + # # params: + # # - data + # # - model + # # - attack + # # - scorers + # # - files + # ############################################################################## + # # attack_optimise: + # # cmd: python -m deckard.layers.optimise +stage=attack +optimizers=adv_accuracy model=best --multirun --config-name attack + # # deps: + # # - ${files.directory}/${files.data_dir}/${files.data_file}${files.data_type} + # # - ${files.directory}/${files.model_dir}/${files.model_file}${files.model_type} + # # - conf/model/best.yaml + # # outs: + # # - attack.db + # # params: + # # - conf/attack.yaml: + # # - hydra + # # find_best_attack: + # # cmd: python -m deckard.layers.find_best attack.yaml + # # deps: + # # - attack.db + # # outs: + # # - conf/attack/best.yaml diff --git a/examples/gzip/gzip_classifier.py b/examples/gzip/gzip_classifier.py new file mode 100644 index 00000000..49d4e159 --- /dev/null +++ b/examples/gzip/gzip_classifier.py @@ -0,0 +1,1051 @@ +#!/usr/bin/env python3 +""" +This is a module that implments a gzip classifier. You can test it by running the following command: +python -m gzip_classifier --compressor gzip --k 3 --m 100 --method random --distance_matrix None --dataset 20newsgroups +""" +# These lines will be used to setup a virtual environment inside the current working directory in a folder called env +# You might need to install venv with: +# sudo apt-get install python3-venv +# python3 -m pip install venv +# python3 -m venv env +# source env/bin/activate +# run `deactivate` to exit the virtual environment +# These lines will be used to install the dependencies needed for this file +# You might need to install pip with: +# sudo apt-get install python3-pip +# python -m pip install numpy scikit-learn tqdm scikit-learn-extra pandas imbalanced-learn + +import numpy as np +import gzip +from tqdm import tqdm +from pathlib import Path +import logging +import time +import argparse +from sklearn.utils.validation import check_is_fitted +from sklearn.utils.multiclass import unique_labels +from sklearn.metrics import accuracy_score +from sklearn.model_selection import train_test_split +from sklearn.datasets import fetch_20newsgroups, make_classification +from sklearn.preprocessing import LabelBinarizer, LabelEncoder +from sklearn.base import BaseEstimator, ClassifierMixin +from sklearn.neighbors import KNeighborsClassifier +from sklearn.svm import SVC +from sklearn.linear_model import LogisticRegression +from sklearn_extra.cluster import KMedoids +from imblearn.under_sampling import ( + CondensedNearestNeighbour, + NearMiss, + InstanceHardnessThreshold, +) +from Levenshtein import distance, ratio, hamming, jaro, jaro_winkler, seqratio +import pandas as pd + +from joblib import Parallel, delayed +from typing import Literal + +from batchMixin import BatchedMixin + +logger = logging.getLogger(__name__) + + +def _gzip_compressor(x): + return len(gzip.compress(str(x).encode())) + + +def _lzma_compressor(x): + import lzma + + return len(lzma.compress(str(x).encode())) + + +def _bz2_compressor(x): + import bz2 + + return len(bz2.compress(str(x).encode())) + + +def _zstd_compressor(x): + import zstd + + return len(zstd.compress(str(x).encode())) + + +def _pickle_compressor(x): + import pickle + + return len(pickle.dumps(x)) + + +compressors = { + "gzip": _gzip_compressor, + "lzma": _lzma_compressor, + "bz2": _bz2_compressor, + "zstd": _zstd_compressor, + "pkl": _pickle_compressor, +} + + +def ncd( + x1, + x2, + cx1=None, + cx2=None, + method: Literal["gzip", "lzma", "bz2", "zstd", "pkl", None] = "gzip", +) -> float: + """ + Calculate the normalized compression distance between two objects treated as strings. + Args: + x1 (str): The first object + x2 (str): The second object + Returns: + float: The normalized compression distance between x1 and x2 + """ + + compressor = ( + compressors[method] if method in compressors.keys() else compressors["gzip"] + ) + x1 = str(x1) + x2 = str(x2) + Cx1 = compressor(x1) if cx1 is None else cx1 + Cx2 = compressor(x2) if cx2 is None else cx2 + x1x2 = " ".join([x1, x2]) + Cx1x2 = compressor(x1x2) + min_ = min(Cx1, Cx2) + max_ = max(Cx1, Cx2) + ncd = (Cx1x2 - min_) / max_ + return ncd + + +string_metrics = { + "levenshtein": distance, + "ratio": ratio, + "hamming": hamming, + "jaro": jaro, + "jaro_winkler": jaro_winkler, + "seqratio": seqratio, +} + +all_metrics = { + **compressors, + **string_metrics, +} + + +def _calculate_string_distance(x1, x2, method): + x1 = str(x1) + x2 = str(x2) + if method in string_metrics.keys(): + dist = string_metrics[method] + else: + raise NotImplementedError( + f"Method {method} not supported. Supported methods are: {string_metrics.keys()}", + ) + return dist(x1, x2) + + +class GzipClassifier(ClassifierMixin, BaseEstimator): + """An example classifier which implements a 1-NN algorithm. + + For more information regarding how to build your own classifier, read more + in the :ref:`User Guide `. + + Parameters + ---------- + k : int, default=3 + The number of neighbors to use. + m: int, default=-1 + The number of best samples to use. If -1, all samples will be used. + compressor: str, default="gzip" + The name of the compressor to use. Choices are + method: str, default="random" + The method used to select the best training samples. Choices are "sum", "mean", "medoid", "random", "knn", "svc". + metric: str, default="ncd" + The metric used to calculate the distance between samples. Choices are "gzip", "lzma", "bz2", "zstd", "pkl", "pickle", "levenshtein", "ratio", "seqratio", "hamming", "jaro", "jaro". + distance_matrix: str or np.ndarray, default=None + The path to a numpy file or a numpy array representing the distance matrix. If a path is provided, the file will be loaded. If an array is provided, it will be used directly. Default is None. + Attributes + ---------- + X_ : ndarray, shape (n_samples, n_features) + The input passed during :meth:`fit`. + y_ : ndarray, shape (n_samples,) + The labels passed during :meth:`fit`. + classes_ : ndarray, shape (n_classes,) + The classes seen at :meth:`fit`. + distance_matrix_ : ndarray, shape (n_samples, n_samples) + """ + + def __init__( + self, + m=0, + sampling_method="random", + distance_matrix=None, + metric="gzip", + symmetric=False, + precompute=True, + **kwargs, + ): + """ + Initialize the GzipClassifier object. + + Args: + k (int): The value of k for k-nearest neighbors. Default is 3. + m (int): The value of m for m-best samples. Default is -1, which indicates using all training samples. + sampling_method (str): The method used for classification. Default is "random". + metric (str): The metric used to calculate the distance between samples. Default is "ncd". + distance_matrix (str or np.ndarray): The path to a numpy file or a numpy array representing the distance matrix. + If a path is provided, the file will be loaded. If an array is provided, it will be used directly. + Default is None. + symmetric (bool): If True, the distance matrix will be treated as symmetric. Default is False. + precompute (bool): If True, the distance matrix will be precomputed and stored in self.distance_matrix during the fit method and a sklearn KNeighborsClassifier object will be created and stored in self.clf_. + + Raises: + ValueError: If distance_matrix is not a path to a numpy file or a numpy array. + NotImplementedError: If the metric is not supported. + """ + kwarg_string = str([f"{key}={value}" for key, value in kwargs.items()]) + logger.info( + f"Initializing GzipClassifier with m={m}, method={sampling_method}, distance_matrix={distance_matrix}, metric={metric}, symmetric={symmetric}, precompute={precompute}, {kwarg_string}", + ) + self.m = m + self.sampling_method = sampling_method + if metric in compressors.keys(): + logger.info(f"Using NCD metric with {metric} compressor.") + self._distance = ncd + self.metric = metric + elif metric in string_metrics.keys(): + logger.info(f"Using {metric} metric") + self._distance = _calculate_string_distance + self.metric = metric + else: + raise NotImplementedError( + f"Metric {metric} not supported. Supported metrics are: ncd, {string_metrics.keys()} and {compressors.keys()}", + ) + + self.symmetric = symmetric + if self.symmetric is True: + self._calculate_distance_matrix = ( + self._calculate_lower_triangular_distance_matrix + ) + else: + self._calculate_distance_matrix = ( + self._calculate_rectangular_distance_matrix + ) + self.precompute = precompute # If True, the distance matrix will be precomputed and stored in self.distance_matrix during the fit method and a sklearn KNeighborsClassifier object will be created and stored in self.clf_. + self.distance_matrix = distance_matrix + for key, value in kwargs.items(): + setattr(self, key, value) + + def _calculate_rectangular_distance_matrix( + self, + x1, + x2, + Cx1=None, + Cx2=None, + n_jobs=-1, + ): + """ + Calculate the distance matrix between two sets of objects, treating them as strings, assuming d(a,b) != d(b,a) + Args: + x1 (np.ndarray): The first set of objects + x2 (np.ndarray): The second set of objects + Returns: + np.ndarray: The distance matrix of size (len(x1), len(x2)) + """ + matrix_ = np.zeros((len(x1), len(x2))) + pbar = tqdm( + total=len(x1), + desc="Calculating asymmetric distance matrix.", + leave=False, + dynamic_ncols=True, + ) + Cx1 = Cx1 if Cx1 is not None else [None] * len(x1) + Cx2 = Cx2 if Cx2 is not None else [None] * len(x2) + for i in range(len(x1)): + # Parallelize the calculation of the distance matrix + if self.metric in compressors.keys(): + matrix_[i, :] = Parallel(n_jobs=n_jobs)( + delayed(self._distance)( + x1[i], + x2[j], + cx1=Cx1[i], + cx2=Cx2[j], + method=self.metric, + ) + for j in range(len(x2)) + ) + else: + matrix_[i, :] = Parallel(n_jobs=n_jobs)( + delayed(self._distance)(x1[i], x2[j], method=self.metric) + for j in range(len(x2)) + ) + pbar.update(1) + pbar.close() + assert matrix_.shape == ( + len(x1), + len(x2), + ), f"Expected {matrix_.shape} == ({len(x1)}, {len(x2)})" + return matrix_ + + def _calculate_lower_triangular_distance_matrix( + self, + x1, + x2, + Cx1=None, + Cx2=None, + n_jobs=-1, + ): + """ + Calculate the distance matrix between two sets of objects, treating them as strings. Assuming the d(a,b) = d(b,a) + Args: + x1 (np.ndarray): The first set of objects + x2 (np.ndarray): The second set of objects + Returns: + np.ndarray: The distance matrix of size (len(x1), len(x2)) + """ + + matrix_ = np.zeros((len(x1), len(x2))) + pbar = tqdm( + total=len(x1), + desc="Calculating symmetric distance metrix.", + leave=False, + dynamic_ncols=True, + ) + Cx1 = Cx1 if Cx1 is not None else [None] * len(x1) + Cx2 = Cx2 if Cx2 is not None else [None] * len(x2) + for i in range(len(x1)): + # Parallelize the calculation of the distance matrix + if self.metric in compressors.keys(): + matrix_[i, :i] = Parallel(n_jobs=n_jobs)( + delayed(self._distance)( + x1[i], + x2[j], + cx1=Cx1[i], + cx2=Cx2[j], + method=self.metric, + ) + for j in range(i) + ) + else: + matrix_[i, :i] = Parallel(n_jobs=n_jobs)( + delayed(self._distance)(x1[i], x2[j], method=self.metric) + for j in range(i) + ) + # Copy the lower triangular part to the upper triangular part + matrix_[i, :i] = matrix_[:i, i] + pbar.update(1) + pbar.close() + assert matrix_.shape == ( + len(x1), + len(x2), + ), f"Expected {matrix_.shape} == ({len(x1)}, {len(x2)})" + return matrix_ + + def calculate_upper_triangular_distance_matrix( + self, + x1, + x2, + Cx1=None, + Cx2=None, + n_jobs=-1, + ): + matrix_ = np.zeros((len(x1), len(x2))) + pbar = tqdm( + total=len(x1), + desc="Calculating symmetric distance metrix.", + leave=False, + dynamic_ncols=True, + ) + Cx1 = Cx1 if Cx1 is not None else [None] * len(x1) + Cx2 = Cx2 if Cx2 is not None else [None] * len(x2) + for i in range(len(x1)): + if self.metric in compressors.keys(): + matrix_[i, i:] = Parallel(n_jobs=n_jobs)( + delayed(self._distance)( + x1[i], + x2[j], + cx1=Cx1[i], + cx2=Cx2[j], + method=self.metric, + ) + for j in range(i, len(x2)) + ) + else: + matrix_[i, i:] = Parallel(n_jobs=n_jobs)( + delayed(self._distance)(x1[i], x2[j], method=self.metric) + for j in range(i, len(x2)) + ) + # copy the upper triangular part to the lower triangular part + matrix_[i, i:] = matrix_[i:, i] + pbar.update(1) + pbar.close() + assert matrix_.shape == ( + len(x1), + len(x2), + ), f"Expected {matrix_.shape} == ({len(x1)}, {len(x2)})" + return matrix_ + + def _load_distance_matrix(self, path): + if Path(path).exists(): + return np.load(path, allow_pickle=True)["X"] + else: + raise FileNotFoundError(f"Distance matrix file {path} not found") + + def _save_distance_matrix(self, path, matrix): + Path(path).parent.mkdir(parents=True, exist_ok=True) + np.savez_compressed(path, X=matrix) + + def _prepare_training_matrix(self, n_jobs=-1): + """ + Prepare the distance matrix for classification. + If self.distance_matrix is a path to a numpy file, it will be loaded. + If it is a numpy array, it will be used directly. + If it is None, the distance matrix will be calculated using self.X_ and self.X_. + """ + + if ( + isinstance(self.distance_matrix, str) + and Path(self.distance_matrix).exists() + ): + distance_matrix = self._load_distance_matrix(self.distance_matrix) + elif ( + isinstance(self.distance_matrix, str) + and not Path(self.distance_matrix).exists() + ): + distance_matrix = self._calculate_distance_matrix( + self.X_, + self.X_, + Cx1=self.Cx_, + Cx2=self.Cx_, + n_jobs=n_jobs, + ) + self._save_distance_matrix(self.distance_matrix, distance_matrix) + elif isinstance(self.distance_matrix, np.ndarray): + distance_matrix = self.distance_matrix + elif isinstance(self.distance_matrix, type(None)): + distance_matrix = self._calculate_distance_matrix( + self.X_, + self.X_, + Cx1=self.Cx_, + Cx2=self.Cx_, + n_jobs=n_jobs, + ) + else: + raise ValueError( + f"distance_matrix must be a path to a numpy file or a numpy array, got {type(self.distance_matrix)}", + ) + return distance_matrix + + def _find_best_samples(self, method="medoid", n_jobs=-1): + """ + Args: + method (str): The method used to select the best training samples. Default is "medoid". Choices are "sum", "mean", "medoid", "random", "knn", "svc". + Returns: + list: The indices of the best training samples. + """ + self.distance_matrix = self._prepare_training_matrix(n_jobs=n_jobs) + assert isinstance( + self.distance_matrix, + np.ndarray, + ), f"Expected {type(self.distance_matrix)} to be np.ndarray" + distance_matrix = self.distance_matrix + indices = [] + if isinstance(self.m, float): + m = int(self.m * len(self.X_) / self.n_classes_) + if m == 0: + m = 1 + else: + m = self.m + y = self.y_ + n_classes = len(unique_labels(y)) + if method in ["sum", "medoid", "svc", "random"]: + if method == "sum": + for label in np.unique(y): + label_idx = np.where(y == label)[0] + label_distance_matrix = distance_matrix[label_idx, :] + summed_matrix = np.sum(label_distance_matrix, axis=0) + sorted_idx = np.argsort(summed_matrix) + indices.extend(sorted_idx[:m]) + elif method == "medoid": + for label in np.unique(y): + label_idx = np.where(y == label)[0] + min_ = min(m, len(label_idx)) + label_distance_matrix = distance_matrix[label_idx, :][:, label_idx] + kmedoids = KMedoids(n_clusters=min_, metric="precomputed").fit( + label_distance_matrix, + ) + indices.extend(kmedoids.medoid_indices_[:m]) + elif method == "svc": + svc = SVC(kernel="precomputed").fit(distance_matrix, y) + support_idx = svc.support_ + summed_matrix = np.sum(distance_matrix, axis=0) + sorted_idx = np.argsort(summed_matrix[support_idx])[ + ::-1 + ] # Sort in descending order + indices.extend(sorted_idx[: m * n_classes]) + elif method == "random": + keys = np.unique(y) + values = [m] * len(keys) + dict_ = dict(zip(keys, values)) + for label in np.unique(y): + label_idx = np.where(y == label)[0] + if len(label_idx) < m: + random_idx = np.random.choice(label_idx, m, replace=True) + else: + random_idx = np.random.choice(label_idx, m, replace=False) + indices.extend(random_idx) + else: + raise NotImplementedError(f"Method {method} not supported") + elif method in ["hardness", "nearmiss", "knn"]: + if method == "hardness": + keys = np.unique(y) + values = [m] * len(keys) + dict_ = dict(zip(keys, values)) + model = InstanceHardnessThreshold(sampling_strategy=dict_) + elif method == "nearmiss": + keys = np.unique(y) + values = [m] * len(keys) + dict_ = dict(zip(keys, values)) + model = NearMiss(sampling_strategy=dict_) + elif method == "knn": + distance_matrix = pd.DataFrame( + distance_matrix, + columns=range(len(distance_matrix)), + ) + y = pd.DataFrame(y, columns=["y"]) + y.index = list(range(len(y))) + model = CondensedNearestNeighbour(sampling_strategy="not majority") + else: + raise NotImplementedError(f"Method {method} not supported") + distance_matrix = pd.DataFrame( + distance_matrix, + columns=list(range(len(distance_matrix))), + ) + y = pd.DataFrame(y, columns=["y"]) + y.index = list(range(len(y))) + distance_matrix, y = model.fit_resample(distance_matrix, y) + indices = y.index[: m * n_classes] + else: + raise NotImplementedError(f"Method {method} not supported") + return indices + + def fit(self, X: np.ndarray, y: np.ndarray, n_jobs=-1): + """Fit the model using X as training data and y as target values. If self.m is not -1, the best m samples will be selected using the method specified in self.sampling_method. + + Args: + X (np.ndarray): The input data + y (np.ndarray): The target labels + + Returns: + GzipClassifier: The fitted model + """ + assert len(X) == len(y), f"Expected {len(X)} == {len(y)}" + logger.info(f"Fitting with X of shape {X.shape} and y of shape {y.shape}") + self.X_ = np.array(X) if not isinstance(X, np.ndarray) else X + y = np.array(y) if not isinstance(y, np.ndarray) else y + if len(np.squeeze(y).shape) == 1: + encoder = LabelBinarizer() + self.y_ = encoder.fit_transform(y) + self.n_classes_ = len(unique_labels(y)) + flat_y = np.squeeze(y).astype(int) + else: + self.y_ = y + self.n_classes_ = y.shape[1] + flat_y = np.argmax(y, axis=1) + counts = np.bincount(flat_y) + self.counts_ = counts + logger.info(f"Num Classes: {self.n_classes_}, counts: {counts}") + self.n_features_ = X.shape[1] if len(X.shape) > 1 else 1 + self.classes_ = range(len(unique_labels(y))) + + if self.metric in compressors.keys(): + compressor = compressors[self.metric] + Cx_ = Parallel(n_jobs=n_jobs)(delayed(compressor)(x) for x in self.X_) + self.Cx_ = np.array(Cx_) if not isinstance(Cx_, np.ndarray) else Cx_ + else: + self.Cx_ = None + self.X_ = self.X_.astype(str) + if self.m > 0: + assert isinstance( + self.m, + (int, float), + ), f"Expected {self.m} to be an integer" + assert isinstance( + self.sampling_method, + (str, type(None)), + ), f"Expected {self.sampling_method} to be a string or None" + indices = self._find_best_samples(self.sampling_method) + self._set_best_indices(indices) + elif self.m == -1: + distance_matrix = self._prepare_training_matrix(n_jobs=n_jobs) + self.distance_matrix = distance_matrix + elif self.m is None or self.m == 0: + pass + else: + raise ValueError( + f"Expected {self.m} to be -1, 0, a positive integer or a float between 0 and 1. Got type {type(self.m)}", + ) + if self.precompute is True: + self.distance_matrix = self._prepare_training_matrix(n_jobs=n_jobs) + self.clf_ = self.clf_.fit(self.distance_matrix, self.y_) + else: + raise NotImplementedError( + f"Precompute {self.precompute} not supported for type(self.clf_) {type(self.clf_)}", + ) + return self + + def _set_best_indices(self, indices): + self.X_ = self.X_[indices] + self.y_ = self.y_[indices] + if self.Cx_ is not None: + self.Cx_ = self.Cx_[indices] + # This is a hack that allows us to deal with n-dimensional arrays using the normal matrix[:, indices][indices, :] breaks if n>2 + distance_matrix = self.distance_matrix[ + indices + ].T # select the rows at the indices and transpose the matrix + distance_matrix = distance_matrix[ + indices + ] # select the transposed columns at the indices + self.distance_matrix = distance_matrix.T # transpose the matrix again + logger.info( + f"Selected {len(self.X_)} samples using method {self.sampling_method}.", + ) + counts = np.bincount(np.argmax(self.y_, axis=1)) + logger.info(f"Num Classes: {self.n_classes_}, counts: {counts}") + assert len(self.X_) == len( + self.y_, + ), f"Expected {len(self.X_)} == {len(self.y_)}" + assert distance_matrix.shape == ( + len(self.X_), + len(self.X_), + ), f"Expected {distance_matrix.shape} == ({len(self.X_)}, {len(self.X_)})" + + def predict(self, X: np.ndarray): + """Predict the class labels for the provided data. + + Args: + X (np.ndarray): The input data + + Returns: + np.ndarray: The predicted class labels + """ + check_is_fitted(self) + logger.info(f"Predicting with X of shape {X.shape}") + if self.metric in compressors.keys(): + compressor = compressors[self.metric] + Cx2 = Parallel(n_jobs=-1)( + delayed(compressor)(x) + for x in tqdm( + X, + desc="Compressing samples", + leave=False, + dynamic_ncols=True, + ) + ) + assert len(Cx2) == len(X), f"Expected {len(Cx2)} == {len(X)}" + assert len(self.X_) == len( + self.Cx_, + ), f"Expected {len(self.X_)} == {len(self.Cx_)}" + distance_matrix = self._calculate_rectangular_distance_matrix( + x1=X, + Cx1=Cx2, + x2=self.X_, + Cx2=self.Cx_, + n_jobs=-1, + ) + else: + distance_matrix = self._calculate_rectangular_distance_matrix( + x2=self.X_, + x1=X, + n_jobs=-1, + ) + assert distance_matrix.shape == ( + len(X), + len(self.X_), + ), f"Expected {distance_matrix.shape} == ({len(X)}, {len(self.X_)})" + y_pred = self.clf_.predict(distance_matrix) + + if len(np.squeeze(y_pred).shape) == 1: + encoder = LabelBinarizer() + y_pred = encoder.fit(self.y_).transform(y_pred) + else: + encoder = LabelEncoder() + y_pred = encoder.fit(self.y_).transform(y_pred) + return y_pred + + def score(self, X: np.ndarray, y: np.ndarray): + """Score the model using the provided data. + + Args: + X (np.ndarray): The input data + y (np.ndarray): The target labels + + Returns: + float: The accuracy of the model + """ + y_pred = self.predict(X) + return accuracy_score(y, y_pred) + + +class BatchedGzipClassifier(GzipClassifier, BatchedMixin): + pass + + +class GzipKNN(GzipClassifier): + def __init__( + self, + k: int = 2, + m=0, + sampling_method="random", + distance_matrix=None, + metric="gzip", + symmetric=False, + precompute=True, + **kwargs, + ): + super().__init__( + sampling_method=sampling_method, + m=m, + distance_matrix=distance_matrix, + metric=metric, + symmetric=symmetric, + precompute=precompute, + **kwargs, + ) + self.clf_ = KNeighborsClassifier(n_neighbors=k, metric="precomputed", **kwargs) + self.k = k + + def predict(self, X: np.ndarray, n_jobs=-1): + """Predict the class labels for the provided data. + + Args: + X (np.ndarray): The input data + + Returns: + np.ndarray: The predicted class labels + """ + check_is_fitted(self) + + logger.info(f"Predicting with X of shape {X.shape}") + # Pre-compress samples not working + if self.metric in compressors.keys(): + compressor = compressors[self.metric] + Cx2 = Parallel(n_jobs=n_jobs)( + delayed(compressor)(x) + for x in tqdm( + X, + desc="Compressing samples", + leave=False, + dynamic_ncols=True, + ) + ) + assert len(Cx2) == len(X), f"Expected {len(Cx2)} == {len(X)}" + assert len(self.X_) == len( + self.Cx_, + ), f"Expected {len(self.X_)} == {len(self.Cx_)}" + distance_matrix = self._calculate_rectangular_distance_matrix( + x1=X, + Cx1=Cx2, + x2=self.X_, + Cx2=self.Cx_, + n_jobs=n_jobs, + ) + else: + distance_matrix = self._calculate_rectangular_distance_matrix( + X, + self.X_, + n_jobs=n_jobs, + ) + assert distance_matrix.shape == ( + len(X), + len(self.X_), + ), f"Expected {distance_matrix.shape} == ({len(X)}, {len(self.X_)})" + y_pred = [] + if self.precompute is True: + y_pred = self.clf_.predict(distance_matrix) + else: + for i in tqdm( + range(len(X)), + desc="Predicting", + leave=False, + total=len(X), + dynamic_ncols=True, + ): + # Sort the distances and get the nearest k samples + sorted_idx = np.argsort(distance_matrix[i]) + # Get the first k samples + nearest_k = sorted_idx[: self.k] + # Get the labels of the nearest samples + nearest_labels = list(self.y_[nearest_k]) + # predict class + unique, counts = np.unique(nearest_labels, return_counts=True) + # Get the most frequent label + y_pred.append(unique[np.argmax(counts)]) + return y_pred + + +class BatchedGzipKNN(GzipKNN, BatchedMixin): + pass + + +class GzipLogisticRegressor(GzipClassifier): + def __init__( + self, + m=0, + sampling_method="random", + distance_matrix=None, + metric="gzip", + symmetric=False, + precompute=True, + **kwargs, + ): + self.precompute = precompute + clf = LogisticRegression(**kwargs) + super().__init__( + clf_=clf, + precompute=precompute, + sampling_method=sampling_method, + m=m, + distance_matrix=distance_matrix, + metric=metric, + symmetric=symmetric, + **kwargs, + ) + + +class BatchedGzipLogisticRegressor(GzipLogisticRegressor, BatchedMixin): + pass + + +class GzipSVC(GzipClassifier): + def __init__( + self, + kernel="rbf", + m=0, + sampling_method="random", + distance_matrix=None, + metric="gzip", + symmetric=False, + precompute=True, + **kwargs, + ): + self.precompute = precompute + clf = SVC(kernel=kernel, **kwargs) + super().__init__( + clf_=clf, + precompute=precompute, + sampling_method=sampling_method, + m=m, + distance_matrix=distance_matrix, + metric=metric, + symmetric=symmetric, + **kwargs, + ) + self.kernel = kernel + + +class BatchedGzipSVC(GzipSVC, BatchedMixin): + pass + + +supported_models = { + "knn": GzipKNN, + "logistic": GzipLogisticRegressor, + "svc": GzipSVC, +} + +batched_models = { + "knn": BatchedGzipKNN, + "logistic": BatchedGzipLogisticRegressor, + "svc": BatchedGzipSVC, +} + +model_scorers = { + "knn": "accuracy", + "logistic": "accuracy", + "svc": "accuracy", +} + +scorers = { + "accuracy": accuracy_score, +} + + +def test_model( + X_train, + X_test, + y_train, + y_test, + model_type, + optimizer=None, + batched=False, + **kwargs, +) -> dict: + """ + Args: + X (np.ndarray): The input data + y (np.ndarray): The target labels + train_size (int): The number of samples to use for training. Default is 100. + test_size (int): The number of samples to use for testing. Default is 100. + **kwargs: Additional keyword arguments to pass to the GzipClassifier + Returns: + dict: A dictionary containing the accuracy, train_time, and pred_time + """ + if batched is True: + model = batched_models[model_type](**kwargs) + else: + model = supported_models[model_type](**kwargs) + alias = model_scorers[model_type] + scorer = scorers[alias] + start = time.time() + model.fit(X_train, y_train) + check_is_fitted(model) + end = time.time() + train_time = end - start + start = time.time() + predictions = model.predict(X_test) + end = time.time() + pred_time = end - start + score = round(scorer(y_test, predictions), 3) + print(f"Training time: {train_time}") + print(f"Prediction time: {pred_time}") + print(f"{alias} is: {score}") + score_dict = { + f"{alias.lower()}": score, + "train_time": train_time, + "pred_time": pred_time, + } + if optimizer is not None: + score = score_dict[optimizer] + return score + else: + return score_dict + + +def load_data(dataset, precompressed): + if dataset == "20newsgroups": + X, y = fetch_20newsgroups( + subset="train", + categories=["alt.atheism", "talk.religion.misc"], + shuffle=True, + random_state=42, + return_X_y=True, + ) + y = ( + LabelEncoder().fit(y).transform(y) + ) # Turns the labels "alt.atheism" and "talk.religion.misc" into 0 and 1 + elif dataset == "kdd_nsl": + df = pd.read_csv("raw_data/kdd_nsl.csv") + y = df["label"] + X = df.drop("label", axis=1) + elif dataset == "kdd_nsl": + df = pd.read_csv("raw_data/kdd_nsl.csv") + y = df["label"] + X = df.drop("label", axis=1) + X = np.array(X) + elif dataset == "make_classification": + X, y = make_classification( + n_samples=1000, + n_features=20, + n_classes=2, + random_state=42, + ) + y = LabelEncoder().fit(y).transform(y) + elif dataset == "truthseeker": + df = pd.read_csv("raw_data/truthseeker.csv") + y = df["BotScoreBinary"] + X = df.drop("BotScoreBinary", axis=1) + elif dataset == "sms-spam": + df = pd.read_csv("raw_data/sms-spam_undersampled_1450.csv") + y = df["label"] + X = df.drop("label", axis=1) + elif dataset == "ddos": + df = pd.read_csv("raw_data/ddos.csv") + y = df["Label"] + X = df.drop("Label", axis=1) + else: + raise ValueError( + f"Dataset {dataset} not found. Options are: 20newsgroups, kdd_nsl, make_classification, truthseeker, sms-spam, ddos.", + ) + if precompressed is True: + X = pd.DataFrame(X).applymap(lambda x: len(gzip.compress(str(x).encode()))) + X = np.array(X) + return X, y + + +def prepare_data( + dataset="truthseeker", + precompressed=False, + train_size=100, + test_size=100, + random_state=42, +): + X, y = load_data(dataset, precompressed=precompressed) + X = np.array(X) + y = np.array(y) + X_train, X_test, y_train, y_test = train_test_split( + X, + y, + train_size=train_size, + test_size=test_size, + random_state=random_state, + stratify=y, + ) + return X_train, X_test, y_train, y_test + + +def main(args: argparse.Namespace): + """ + This is the main function that runs the GzipClassifier with the provided arguments. + It will fetch the dataset, split it into training and testing sets. + Then, it will train the model using the fit method and test it using the predict method. + Args: + args (argparse.Namespace): The command line arguments + Usage: + python gzip_classifier.py --compressor gzip --k 3 --m 100 --method random --distance_matrix distance_matrix --dataset kdd_nsl + """ + + X, y = load_data(dataset=args.dataset, precompressed=args.precompressed) + params = vars(args) + dataset = params.pop("dataset") + precompressed = params.pop("precompressed") + train_size = params.pop("train_size") + test_size = params.pop("test_size") + random_state = params.pop("random_state") + X_train, X_test, y_train, y_test = prepare_data( + dataset=dataset, + precompressed=precompressed, + train_size=train_size, + test_size=test_size, + random_state=random_state, + ) + kwarg_args = params.pop("kwargs") + # conver list of key-value pairs to dictionary + kwarg_args = dict([arg.split("=") for arg in kwarg_args]) + params.update(**kwarg_args) + params["precompute"] = True + X = np.array(X) if not isinstance(X, np.ndarray) else X + y = np.array(y) if not isinstance(y, np.ndarray) else y + test_model(X_train, X_test, y_train, y_test, **params) + + +parser = argparse.ArgumentParser() +parser.add_argument("--model_type", type=str, default="knn") +parser.add_argument("--precompute", action="store_true") +parser.add_argument("--symmetric", action="store_true") +parser.add_argument("--metric", type=str, default="gzip", choices=all_metrics) +parser.add_argument("--m", type=int, default=-1) +parser.add_argument("--sampling_method", type=str, default="random") +parser.add_argument("--distance_matrix", type=str, default=None) +parser.add_argument("--dataset", type=str, default="kdd_nsl") +parser.add_argument("--train_size", type=int, default=100) +parser.add_argument("--test_size", type=int, default=100) +parser.add_argument("--optimizer", type=str, default="accuracy") +parser.add_argument("--precompressed", action="store_true") +parser.add_argument("--random_state", type=int, default=42) +parser.add_argument("kwargs", nargs=argparse.REMAINDER) + +if __name__ == "__main__": + args = parser.parse_args() + logging.basicConfig(level=logging.INFO) + main(args) diff --git a/examples/gzip/merge.py b/examples/gzip/merge.py new file mode 100644 index 00000000..afbd4d09 --- /dev/null +++ b/examples/gzip/merge.py @@ -0,0 +1,161 @@ +import pandas as pd +from pathlib import Path +import logging +import yaml +import argparse +from deckard.layers.compile import save_results + +logger = logging.getLogger(__name__) + + +__all__ = ["merge_csv", "merge_main", "merge_parser"] + + +def merge_csv( + big_dir, + little_dir, + output_file="merged", + data_file="raw.csv", + little_dir_data_file=None, + fillna={}, + how="outer", + **kwargs, +): + """ + The function `merge_csv` merges two CSV files, one from a big directory and one from a little + directory, and saves the merged file. + + Args: + big_dir: The `big_dir` parameter is the directory path where the dataset to be merged into is located. This + dataset is assumed to have a file named "raw.csv" which will be read. + little_dir: The `little_dir` parameter is the directory path where the smaller dataset is located. + data_file: The `data_file` parameter is the name of the CSV file that will be used for both the + `big` and `small` dataframes. If `little_dir_data_file` is not provided, then the `data_file` from + the `big` directory will be used for both dataframes. Defaults to raw.csv + little_dir_data_file: The parameter `little_dir_data_file` is an optional argument that specifies + the name of the data file in the `little_dir` directory. If this argument is provided, the function + will read the data from the specified file in the `little_dir` directory. If this argument is not + provided, the + + Returns: + None. + """ + if Path(Path(big_dir) / data_file).exists() is False: + big = pd.DataFrame() + else: + big = pd.read_csv(Path(big_dir) / data_file, index_col=0) + assert "name" in big + if little_dir is None: + little_dir = big_dir + if little_dir_data_file is not None: + small = pd.read_csv(Path(little_dir) / little_dir_data_file, index_col=0) + assert "name" in small + else: + small = pd.read_csv(Path(little_dir) / data_file) + logger.info(f"Shape of big: {big.shape}") + logger.info(f"Shape of small: {small.shape}") + merged = pd.merge(big, small, how=how, **kwargs) + for k, v in fillna.items(): + if k in merged.columns: + merged[k] = merged[k].fillna(v) + else: + merged[k] = v + logger.info(f"Shape of merged: {merged.shape}") + logger.info(f"Saving merged to {data_file}.") + results_folder = Path(output_file).parent + results_file = Path(output_file).name + results_folder.mkdir(parents=True, exist_ok=True) + merged["id"] = merged["name"] + saved_path = save_results( + merged, + results_file=results_file, + results_folder=results_folder, + ) + assert Path(saved_path).exists(), f"Saved path {saved_path} does not exist." + return None + + +def merge_main(args): + if args.config is not None: + with open(args.config, "r") as stream: + fillna = yaml.safe_load(stream).get("fillna", {}) + else: + fillna = {} + if args.output_folder is None: + args.output_folder = Path().cwd() + output_file = Path(args.output_folder) / args.output_file + if isinstance(args.little_dir_data_file, list): + for little in args.little_dir_data_file: + merge_csv( + args.big_dir, + args.little_dir, + data_file=args.data_file, + little_dir_data_file=little, + fillna=fillna, + output_file=output_file, + ) + args.big_dir = Path(args.output_folder) + args.data_file = Path(args.output_file).name + print(f"Big dir: {args.big_dir}") + print(f"Data file: {args.data_file}") + print(f"Output file: {args.output_file}") + else: + merge_csv( + args.big_dir, + args.little_dir, + data_file=args.data_file, + little_dir_data_file=args.little_dir_data_file, + fillna=fillna, + output_file=output_file, + how="outer", + ) + + +merge_parser = argparse.ArgumentParser() +merge_parser.add_argument( + "--big_dir", + type=str, + help="Directory of the big run", + required=True, +) +merge_parser.add_argument( + "--little_dir", + type=str, + help="Directory of the small run", + required=False, +) +merge_parser.add_argument( + "--data_file", + type=str, + help="Name of the data file", + required=True, +) +merge_parser.add_argument( + "--output_file", + type=str, + help="Name of the output file", + default="merged.csv", +) +merge_parser.add_argument( + "--output_folder", + type=str, + help="Name of the output folder", + required=False, +) +merge_parser.add_argument( + "--little_dir_data_file", + type=str, + help="Name(s) of the files to merge into the big file.", + required=False, + nargs="*", +) +merge_parser.add_argument( + "--config", + type=str, + help="Name of file containing a 'fillna' config dictionary.", + required=False, +) + +if __name__ == "__main__": + args = merge_parser.parse_args() + merge_main(args) diff --git a/examples/gzip/privacy_metric.py b/examples/gzip/privacy_metric.py new file mode 100644 index 00000000..e6856491 --- /dev/null +++ b/examples/gzip/privacy_metric.py @@ -0,0 +1,101 @@ +from gzip_classifier import GzipSVC +import art +import numpy as np +from gzip_classifier import prepare_data + + +# Create a GzipKNN classifier +def calculate_privacy_risk(X_train, X_test, y_train, y_test, metric): + clf = GzipSVC(metric=metric) + clf.fit(X_train, y_train) + est = art.estimators.classification.SklearnClassifier(model=clf, preprocessing=None) + privacy_risk = art.metrics.SHAPr( + target_estimator=est, + x_train=X_train, + x_test=X_test, + y_train=y_train, + y_test=y_test, + ) + accuracies = clf.score(X_test, y_test) + return privacy_risk, accuracies + + +def line_search_metrics(X_train, X_test, y_train, y_test, metrics): + metric_dict = {} + acc_list = [] + shapr_list = [] + for metric in metrics: + scores, privacy_risks = calculate_privacy_risk( + X_train, + X_test, + y_train, + y_test, + metric, + ) + metric_dict[metric] = {} + nb_classes = len(np.unique(y_test)) + shaprs = [] + accuracies = [] + for i in range(nb_classes): + idxs = np.where(y_test == i) + privacy_risk = np.mean(privacy_risks[idxs]) + privacy_risk = 0.01 if privacy_risk == 0 else privacy_risk + shaprs.append(privacy_risk) + accuracy = round(np.mean(scores[idxs]), 2) + accuracies.append(accuracy) + print( + f"{metric.capitalize()} SHAPr for class {i}: {privacy_risk}; Accuracy: {accuracy}", + ) + assert len(shaprs) == nb_classes + assert len(accuracies) == nb_classes + acc_list.append(accuracies) + shapr_list.append(shaprs) + print(f"{metric.capitalize()} SHAPr: {shaprs}; Accuracy: {accuracies}") + import plotext as plt + + label_prefixes = ["Accuracy", "SHAPr"] + labels = [ + f"{label_prefixes[i]}_{j}" + for i in range(nb_classes) + for j in range(len(label_prefixes)) + ] + values = [] + # Turn acc_list into separate lists for each class + for i in range(nb_classes): + sub_values = [acc_list[j][i] for j in range(len(acc_list))] + values.append(sub_values) + for i in range(nb_classes): + sub_values = [shapr_list[j][i] for j in range(len(shapr_list))] + values.append(sub_values) + plt.simple_multiple_bar( + metrics, + values, + title="Accuracy and SHAPr for different metrics", + labels=labels, + ) + plt.show() + return metric_dict + + +if __name__ == "__main__": + metrics = [ + "gzip", + "lzma", + "bz2", + "zstd", + "pkl", + "levenshtein", + "ratio", + "hamming", + "jaro", + "jaro_winkler", + "seqratio", + ] + datasets = ["kdd_nsl", "truthseeker", "sms-spam", "ddos"] + + for dataset in datasets: + X_train, X_test, y_train, y_test = prepare_data(dataset=dataset) + line_search_metrics(X_train, X_test, y_train, y_test, metrics) + + +# Decorator to make to turn a fit function into the batch'd version diff --git a/examples/pytorch/.dvc/.gitignore b/examples/pytorch/.dvc/.gitignore new file mode 100644 index 00000000..528f30c7 --- /dev/null +++ b/examples/pytorch/.dvc/.gitignore @@ -0,0 +1,3 @@ +/config.local +/tmp +/cache diff --git a/examples/pytorch/.dvc/tmp/lock b/examples/pytorch/.dvc/tmp/lock index b7b7a089..d6eb4e1b 100644 --- a/examples/pytorch/.dvc/tmp/lock +++ b/examples/pytorch/.dvc/tmp/lock @@ -1 +1 @@ - 21824 + 1966819 diff --git a/examples/pytorch/.dvc/tmp/rwlock b/examples/pytorch/.dvc/tmp/rwlock index 9e26dfee..0967ef42 100644 --- a/examples/pytorch/.dvc/tmp/rwlock +++ b/examples/pytorch/.dvc/tmp/rwlock @@ -1 +1 @@ -{} \ No newline at end of file +{} diff --git a/examples/pytorch/cifar10/.dvc/config b/examples/pytorch/cifar10/.dvc/config index e69de29b..4cf322d9 100644 --- a/examples/pytorch/cifar10/.dvc/config +++ b/examples/pytorch/cifar10/.dvc/config @@ -0,0 +1,2 @@ +[core] + autostage = true diff --git a/examples/pytorch/cifar10/conf/afr.yaml b/examples/pytorch/cifar10/conf/afr.yaml index ae09b33b..7413432c 100644 --- a/examples/pytorch/cifar10/conf/afr.yaml +++ b/examples/pytorch/cifar10/conf/afr.yaml @@ -1,19 +1,20 @@ covariates: + - "adv_fit_time" - "accuracy" - "train_time" - - "predict_time" - "atk_value" - "def_value" - "data.sample.random_state" - - "adv_failure_rate" - "model_layers" - - "adv_fit_time" - model.trainer.nb_epoch +# - atk_gen +# - def_gen + - predict_time fillna: model.trainer.nb_epoch: 20 weibull: plot: - file : weibull_aft.pdf + file : weibull_aft.eps title : Weibull AFR Model labels: "Intercept: rho_": "$\\rho$" @@ -25,13 +26,16 @@ weibull: "adv_accuracy: lambda_": "Adv. Accuracy" "accuracy: lambda_": "Ben. Accuracy" "adv_fit_time: lambda_": "$t_{attack}$" - "adv_failure_rate: lambda_": "$h_{adv.}(t;\\theta)$" - "failure_rate: lambda_": "$h_{ben.}(t;\\theta)$" + "adv_failure_rate: lambda_": "$f_{adv.}(t;\\theta)$" + "failure_rate: lambda_": "$f_{ben.}(t;\\theta)$" "model.trainer.nb_epoch: lambda_": "No. of Epochs" "model.trainer.batch_size: lambda_": "Batch Size" "def_gen": "Defence" + "model_layers: lambda_" : "Layers" + "def_value: lambda_" : "Defence Strength" + "predict_time: lambda_" : "$t_{predict}$" partial_effect: - - "file": "weibull_epochs_partial_effect.pdf" + - "file": "weibull_epochs_partial_effect.eps" "covariate_array": "model.trainer.nb_epoch" "values_array": [1,10,25,50] "title": "$S(t)$ for Weibull AFR" @@ -41,19 +45,19 @@ weibull: "title": "Epochs", "labels": ["1", "10", "25", "50"] } - - "file": "weibull_layers_partial_effect.pdf" + - "file": "weibull_layers_partial_effect.eps" "covariate_array": "model_layers" "values_array": [18, 34, 50, 101, 152] - "title": "$S(t)$ for Cox AFR" + "title": "$S(t)$ for Weibull AFR" "ylabel": "Expectation of $S(t)$" "xlabel": "Time $T$ (seconds)" "legend_kwargs": { - "title": "ResNet Layers", + "title": "Layers", "labels": ["18", "34", "50", "101", "152"] } # cox: # plot: -# file : cox_aft.pdf +# file : cox_aft.eps # title : Cox AFR Model # labels: # "Intercept: rho_": "$\\rho$" @@ -65,13 +69,13 @@ weibull: # "adv_accuracy: lambda_": "Adv. Accuracy" # "accuracy: lambda_": "Ben. Accuracy" # "adv_fit_time: lambda_": "$t_{attack}$" -# "adv_failure_rate: lambda_": "$h_{adv.}(t;\\theta)$" -# "failure_rate: lambda_": "$h_{ben.}(t;\\theta)$" +# "adv_failure_rate: lambda_": "$f_{adv.}(t;\\theta)$" +# "failure_rate: lambda_": "$f_{ben.}(t;\\theta)$" # "model.trainer.nb_epoch: lambda_": "No. of Epochs" # "model.trainer.batch_size: lambda_": "Batch Size" # "def_gen": "Defence" # partial_effect: -# - "file": "cox_epochs_partial_effect.pdf" +# - "file": "cox_epochs_partial_effect.eps" # "covariate_array": "model.trainer.nb_epoch" # "values_array": [1,10,25,50] # "title": "$S(t)$ for Cox AFR" @@ -81,37 +85,40 @@ weibull: # "title": "Epochs", # "labels": ["1", "10", "25", "50"] # } -# - "file": "cox_layers_partial_effect.pdf" +# - "file": "cox_layers_partial_effect.eps" # "covariate_array": "model_layers" # "values_array": [18, 34, 50, 101, 152] # "title": "$S(t)$ for Cox AFR" # "ylabel": "Expectation of $S(t)$" # "xlabel": "Time $T$ (seconds)" # "legend_kwargs": { -# "title": "ResNet Layers", +# "title": "Layers", # "labels": ["18", "34", "50", "101", "152"] # } log_logistic: plot: - file : log_logistic_aft.pdf + file : log_logistic_aft.eps title : Log logistic AFR Model labels: - "Intercept: rho_": "$\\rho$" - "Intercept: lambda_": "$\\lambda$" - "data.sample.random_state: lambda_": "Random State" - "atk_value: lambda_": "Attack Strength" - "train_time: lambda_": "$t_{train}$" - "predict_proba_time: lambda_": "$t_{predict}$" - "adv_accuracy: lambda_": "Adv. Accuracy" - "accuracy: lambda_": "Ben. Accuracy" - "adv_fit_time: lambda_": "$t_{attack}$" - "adv_failure_rate: lambda_": "$h_{adv.}(t;\\theta)$" - "failure_rate: lambda_": "$h_{ben.}(t;\\theta)$" - "model.trainer.nb_epoch: lambda_": "No. of Epochs" - "model.trainer.batch_size: lambda_": "Batch Size" + "Intercept: beta_": "$\\beta$" + "Intercept: alpha_": "$\\alpha$" + "data.sample.random_state: alpha_": "Random State" + "atk_value: alpha_": "Attack Strength" + "train_time: alpha_": "$t_{train}$" + "predict_proba_time: alpha_": "$t_{predict}$" + "adv_accuracy: alpha_": "Adv. Accuracy" + "accuracy: alpha_": "Ben. Accuracy" + "adv_fit_time: alpha_": "$t_{attack}$" + "adv_failure_rate: alpha_": "$f_{adv.}(t;\\theta)$" + "failure_rate: alpha_": "$f_{ben.}(t;\\theta)$" + "model.trainer.nb_epoch: alpha_": "No. of Epochs" + "model.trainer.batch_size: alpha_": "Batch Size" "def_gen": "Defence" + "model_layers: alpha_" : "Layers" + "def_value: alpha_" : "Defence Strength" + "predict_time: alpha_" : "$t_{predict}$" partial_effect: - - "file": "log_logistic_epochs_partial_effect.pdf" + - "file": "log_logistic_epochs_partial_effect.eps" "covariate_array": "model.trainer.nb_epoch" "values_array": [1,10,25,50] "title": "$S(t)$ for Log-Logistic AFR" @@ -121,37 +128,40 @@ log_logistic: "title": "Epochs", "labels": ["1", "10", "25", "50"] } - - "file": "log_logistic_layers_partial_effect.pdf" + - "file": "log_logistic_layers_partial_effect.eps" "covariate_array": "model_layers" "values_array": [18, 34, 50, 101, 152] - "title": "$S(t)$ for Cox AFR" + "title": "$S(t)$ for Log Logistic AFR" "ylabel": "Expectation of $S(t)$" "xlabel": "Time $T$ (seconds)" "legend_kwargs": { - "title": "ResNet Layers", + "title": "Layers", "labels": ["18", "34", "50", "101", "152"] } log_normal: plot: - file : log_normal_aft.pdf + file : log_normal_aft.eps title : Log Normal AFR Model labels: - "Intercept: rho_": "$\\rho$" - "Intercept: lambda_": "$\\lambda$" - "data.sample.random_state: lambda_": "Random State" - "atk_value: lambda_": "Attack Strength" - "train_time: lambda_": "$t_{train}$" - "predict_proba_time: lambda_": "$t_{predict}$" - "adv_accuracy: lambda_": "Adv. Accuracy" - "accuracy: lambda_": "Ben. Accuracy" - "adv_fit_time: lambda_": "$t_{attack}$" - "adv_failure_rate: lambda_": "$h_{adv.}(t;\\theta)$" - "failure_rate: lambda_": "$h_{ben.}(t;\\theta)$" - "model.trainer.nb_epoch: lambda_": "No. of Epochs" - "model.trainer.batch_size: lambda_": "Batch Size" + "Intercept: sigma_": "$\\rho$" + "Intercept: mu_": "$\\mu$" + "data.sample.random_state: mu_": "Random State" + "atk_value: mu_": "Attack Strength" + "train_time: mu_": "$t_{train}$" + "predict_proba_time: mu_": "$t_{predict}$" + "adv_accuracy: mu_": "Adv. Accuracy" + "accuracy: mu_": "Ben. Accuracy" + "adv_fit_time: mu_": "$t_{attack}$" + "adv_failure_rate: mu_": "$f_{adv.}(t;\\theta)$" + "failure_rate: mu_": "$f_{ben.}(t;\\theta)$" + "model.trainer.nb_epoch: mu_": "No. of Epochs" + "model.trainer.batch_size: mu_": "Batch Size" "def_gen": "Defence" + "model_layers: mu_" : "Layers" + "def_value: mu_" : "Defence Strength" + "predict_time: mu_" : "$t_{predict}$" partial_effect: - - "file": "log_normal_epochs_partial_effect.pdf" + - "file": "log_normal_epochs_partial_effect.eps" "covariate_array": "model.trainer.nb_epoch" "values_array": [1,10,25,50] "title": "$S(t)$ for Log-Normal AFR" @@ -161,13 +171,13 @@ log_normal: "title": "Epochs", "labels": ["1", "10", "25", "50"] } - - "file": "log_normal_layers_partial_effect.pdf" + - "file": "log_normal_layers_partial_effect.eps" "covariate_array": "model_layers" "values_array": [18, 34, 50, 101, 152] - "title": "$S(t)$ for Cox AFR" + "title": "$S(t)$ for Log Normal AFR" "ylabel": "Expectation of $S(t)$" "xlabel": "Time $T$ (seconds)" "legend_kwargs": { - "title": "ResNet Layers", + "title": "Layers", "labels": ["18", "34", "50", "101", "152"] } diff --git a/examples/pytorch/cifar10/conf/cifar10.yaml b/examples/pytorch/cifar10/conf/cifar10.yaml index 474fdfc6..5f701a6a 100644 --- a/examples/pytorch/cifar10/conf/cifar10.yaml +++ b/examples/pytorch/cifar10/conf/cifar10.yaml @@ -29,7 +29,6 @@ hydra: params: ++data.sample.random_state: choice(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) ++model.art.initialize.optimizer.lr: choice(10, 1, 0.1, 0.01, 0.001, .0001, .00001, 0.000001) - ++model.trainer.nb_epoch: choice(1, 10, 30, 50, 100) _target_: hydra_plugins.hydra_optuna_sweeper.optuna_sweeper.OptunaSweeper launcher: _target_: hydra_plugins.hydra_joblib_launcher.joblib_launcher.JoblibLauncher diff --git a/examples/pytorch/cifar10/conf/clean.yaml b/examples/pytorch/cifar10/conf/clean.yaml index 7843aba8..e9c215ab 100644 --- a/examples/pytorch/cifar10/conf/clean.yaml +++ b/examples/pytorch/cifar10/conf/clean.yaml @@ -11,7 +11,7 @@ defences: GaussianAugmentation: Gauss-in GaussianNoise: Gauss-out HighConfidence: Conf - nb_epoch: Epochs + nb_epoch : Epochs model_layers: Control params: Deep: attack.init.kwargs.nb_grads @@ -26,5 +26,9 @@ params: Gauss-in: model.art.pipeline.preprocessor.kwargs.sigma Control: model_layers Epochs: model.trainer.nb_epoch + control: + model_layers: 18 + defaults: + model.trainer.nb_epoch: 20 fillna: - Epochs: 20 + model.trainer.nb_epoch : 20 diff --git a/examples/pytorch/cifar10/conf/compile.yaml b/examples/pytorch/cifar10/conf/compile.yaml deleted file mode 100644 index 1314aceb..00000000 --- a/examples/pytorch/cifar10/conf/compile.yaml +++ /dev/null @@ -1,33 +0,0 @@ -attacks: - # CarliniL0Method: CW_0 - # CarliniL2Method: CW_2 - # CarliniLInfMethod: CW_inf - DeepFool: Deep - FastGradientMethod: FGM - HopSkipJump: HSJ - PixelAttack: Pixel - ProjectedGradientDescent: PGD - ThresholdAttack: Thresh -defences: - Control: Control - FeatureSqueezing: FSQ - GaussianAugmentation: Gauss-in - GaussianNoise: Gauss-out - HighConfidence: Conf - Epochs: Epochs -params: - # art.attacks.evasion.CarliniL0Method: attack.init.confidence - # art.attacks.evasion.CarliniL2Method: attack.init.confidence - # art.attacks.evasion.CarliniLInfMethod: attack.init.confidence - Deep: attack.init.nb_grads - FGM: attack.init.eps - HSJ: attack.init.max_iter - Pixel: attack.init.th - PGD: attack.init.eps - Thresh: attack.init.th - Gauss-out: model.art.pipeline.postprocessor.scale - Conf: model.art.pipeline.postprocessor.cutoff - FSQ: model.art.pipeline.preprocessor.bit_depth - Gauss-in: model.art.pipeline.preprocessor.sigma - Control: model_layers - Epochs: model.trainer.nb_epoch diff --git a/examples/pytorch/cifar10/conf/plots.yaml b/examples/pytorch/cifar10/conf/plots.yaml index 464f53b3..57c016f7 100644 --- a/examples/pytorch/cifar10/conf/plots.yaml +++ b/examples/pytorch/cifar10/conf/plots.yaml @@ -1,5 +1,5 @@ cat_plot: -- file: adv_accuracy_vs_defence_type.pdf +- file: adv_accuracy_vs_defence_type.eps hue: model_name kind: boxen set: @@ -16,7 +16,7 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: ben_accuracy_vs_defence_type.pdf +- file: ben_accuracy_vs_defence_type.eps hue: model_name kind: boxen titles: Ben. Accuracy vs Defence Type @@ -31,7 +31,7 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: ben_failures_per_train_time_vs_defence_type.pdf +- file: ben_failures_per_train_time_vs_defence_type.eps hue: model_name kind: boxen set: @@ -48,11 +48,11 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: adv_failures_per_train_time_vs_defence_type.pdf +- file: adv_failures_per_train_time_vs_defence_type.eps hue: model_name kind: boxen - set: - yscale: log + # set: + # yscale: log titles: $\bar{C}_{adv.}$ vs Defence Type x: def_gen xlabels: Defence Type @@ -65,12 +65,12 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: adv_failures_per_train_time_vs_attack_type.pdf +- file: adv_failures_per_train_time_vs_attack_type.eps hue: model_name kind: boxen legend_title: Model Name - set: - yscale: log + # set: + # yscale: log titles: $\bar{C}_{adv.}$ vs Attack Type x: atk_gen xlabels: Attack Type @@ -83,15 +83,15 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: adv_failures_per_test_time_vs_defence_type.pdf +- file: adv_failures_per_test_time_vs_defence_type.eps hue: model_name kind: boxen legend_title: Model Name - titles: $h_{adv}$ vs Defence Type + titles: $f_{adv}$ vs Defence Type x: def_gen xlabels: Defence Type y: adv_failure_rate - ylabels: $h_{adv.}$ + ylabels: $f_{adv.}$ rotation : 90 hue_order: - ResNet18 @@ -99,23 +99,7 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: adv_accuracy_vs_defence_type.pdf - hue: model_name - kind: boxen - legend_title: Model Name - titles: Adv. Accuracy vs Defence Type - x: def_gen - xlabels: Defence Type - y: adv_accuracy - ylabels: Adv. Ben. Accuracy - rotation : 90 - hue_order: - - ResNet18 - - ResNet34 - - ResNet50 - - ResNet101 - - ResNet152 -- file: adv_accuracy_vs_attack_type.pdf +- file: adv_accuracy_vs_attack_type.eps hue: model_name kind: boxen legend_title: Model Name @@ -131,17 +115,17 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: ben_failure_rate_vs_defence_type.pdf +- file: ben_failure_rate_vs_defence_type.eps hue: model_name kind: boxen legend_title: Model Name set: yscale: log - titles: $h_{ben}(t; \theta)$ vs Defence Type + titles: $f_{ben}(t; \theta)$ vs Defence Type x: def_gen xlabels: Defence Type y: failure_rate - ylabels: $h_{ben}(t; \theta)$ + ylabels: $f_{ben}(t; \theta)$ rotation : 90 hue_order: - ResNet18 @@ -150,7 +134,7 @@ cat_plot: - ResNet101 - ResNet152 line_plot: -- file: def_param_vs_accuracy.pdf +- file: def_param_vs_accuracy.eps hue: def_gen legend: {"bbox_to_anchor": [1.05, 1], "title": "Defence"} title: Ben. Accuracy vs Defence Strength @@ -160,15 +144,17 @@ line_plot: y: accuracy y_scale: ylabel: Ben. Accuracy - # hue_order: - # - Control - # - Conf - # - Epochs - # - Gauss-in - # - Gauss-out - # - Conf - # - FSQ -- file: def_param_vs_adv_accuracy.pdf + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars +- file: def_param_vs_adv_accuracy.eps hue: def_gen legend: {"bbox_to_anchor": [1.05, 1], "title": "Defence"} title: Adv. Accuracy vs Defence Strength @@ -178,33 +164,37 @@ line_plot: y: adv_accuracy y_scale: ylabel: Adv. Accuracy - # hue_order: - # - Control - # - Conf - # - Epochs - # - Gauss-in - # - Gauss-out - # - Conf - # - FSQ -- file: def_param_vs_adv_failure_rate.pdf + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars +- file: def_param_vs_adv_failure_rate.eps hue: def_gen legend: {"bbox_to_anchor": [1.05, 1], "title": "Defence"} - title: $h_{adv}$ vs Defence Strength + title: $f_{adv}$ vs Defence Strength x: def_value - x_scale: linear + x_scale: log xlabel: Defence Control Parameter y: adv_failure_rate y_scale: log - ylabel: $h_{adv.}$ - # hue_order: - # - Control - # - Conf - # - Epochs - # - Gauss-in - # - Gauss-out - # - Conf - # - FSQ -- file: atk_param_vs_accuracy.pdf + ylabel: $f_{adv.}$ + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars +- file: atk_param_vs_accuracy.eps hue: atk_gen legend: {bbox_to_anchor: [1.05, 1]} title: Adv. Accuracy vs Attack Strength @@ -221,16 +211,17 @@ line_plot: - HSJ - Pixel - Thresh - + errorbar: se + err_style: bars scatter_plot: - x: train_time_per_sample y: adv_failure_rate hue: model_name xlabel: $t_{train}$ - ylabel: $h_{adv}$ - title: $h_{adv}$ vs $t_{train}$ - file: adv_failure_rate_vs_train_time.pdf - y_scale: log + ylabel: $f_{adv}$ + title: $f_{adv}$ vs $t_{train}$ + file: adv_failure_rate_vs_train_time.eps + y_scale: linear x_scale: log legend: title: Model Name diff --git a/examples/pytorch/cifar10/dvc.lock b/examples/pytorch/cifar10/dvc.lock index f353aeed..e371d08c 100644 --- a/examples/pytorch/cifar10/dvc.lock +++ b/examples/pytorch/cifar10/dvc.lock @@ -1,501 +1,296 @@ schema: '2.0' stages: - train: - cmd: python -m deckard.layers.experiment train --config_file cifar10.yaml + clean@attack: + cmd: python -m deckard.layers.clean_data -i cifar/reports/attack.csv -o cifar/reports/clean_attack.csv + -c conf/clean.yaml + deps: + - path: cifar/reports/attack.csv + md5: f782978aea22d56dbd68fa9f04e4dfcf + size: 26091607 params: params.yaml: - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar10 - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - files: - _target_: deckard.base.files.FileConfig - adv_predictions_file: adv_predictions.json - attack_dir: attacks - attack_file: attack - attack_type: .pkl - data_dir: data - data_file: data - data_type: .pkl - directory: cifar - model_dir: models - model_file: model - model_type: .pt - name: default - params_file: params.yaml - predictions_file: predictions.json - reports: reports - score_dict_file: score_dict.json - model: - _target_: deckard.base.model.Model - art: - _target_: deckard.base.model.art_pipeline.ArtPipeline - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar10 - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - initialize: - clip_values: - - 0.0 - - 255.0 - criterion: - name: torch.nn.CrossEntropyLoss - optimizer: - lr: 0.01 - momentum: 0.9 - name: torch.optim.SGD - library: pytorch - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar10 - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - init: - _target_: deckard.base.model.ModelInitializer - name: torch_example.ResNet18 - num_channels: 3 - num_classes: 10 - library: pytorch - trainer: - batch_size: 1024 - nb_epoch: 100 - scorers: - _target_: deckard.base.scorer.ScorerDict - accuracy: - _target_: deckard.base.scorer.ScorerConfig - direction: maximize - name: sklearn.metrics.accuracy_score - log_loss: - _target_: deckard.base.scorer.ScorerConfig - direction: minimize - name: sklearn.metrics.log_loss + files.directory: cifar + files.reports: reports + conf/clean.yaml: + attacks: + DeepFool: Deep + FastGradientMethod: FGM + HopSkipJump: HSJ + PixelAttack: Pixel + ProjectedGradientDescent: PGD + ThresholdAttack: Thresh + defences: + Control: Control + FeatureSqueezing: FSQ + GaussianAugmentation: Gauss-in + GaussianNoise: Gauss-out + HighConfidence: Conf + nb_epoch: Epochs + model_layers: Control + fillna: + model.trainer.nb_epoch: 20 + params: + Deep: attack.init.kwargs.nb_grads + FGM: attack.init.kwargs.eps + HSJ: attack.init.kwargs.max_iter + Pixel: attack.init.kwargs.th + PGD: attack.init.kwargs.eps + Thresh: attack.init.kwargs.th + Gauss-out: model.art.pipeline.postprocessor.kwargs.scale + Conf: model.art.pipeline.postprocessor.kwargs.cutoff + FSQ: model.art.pipeline.preprocessor.kwargs.bit_depth + Gauss-in: model.art.pipeline.preprocessor.kwargs.sigma + Control: model_layers + Epochs: model.trainer.nb_epoch + control: + model_layers: 18 + defaults: + model.trainer.nb_epoch: 20 outs: - - path: cifar/data/data.pkl - md5: 6503fed5d4e6cc1163898c0ab6a863dd - size: 739680311 - - path: cifar/models/model.optimizer.pt - hash: md5 - md5: d46598fb7feec074c02bd0ed081184da - size: 44805933 - - path: cifar/models/model.pt - hash: md5 - md5: f5d11f93160ad27b8468efc0d71eb695 - size: 44811029 - - path: cifar/reports/train/default/predictions.json - hash: md5 - md5: 37f581850d9f6d491cb0d9025e620bf9 - size: 2439094 - - path: cifar/reports/train/default/score_dict.json - hash: md5 - md5: 055f95d856bc09b533eccb57314db0c4 - size: 397 - attack: - cmd: python -m deckard.layers.experiment attack --config_file cifar10.yaml + - path: cifar/reports/clean_attack.csv + md5: 81b63f1d5864d65bdaf71aed4ae4c2b0 + size: 14727230 + afr: + cmd: python -m deckard.layers.afr --dataset cifar --data_file cifar/reports/clean_attack.csv --target + adv_accuracy --duration_col predict_time --dataset cifar --config_file conf/afr.yaml + --plots_folder cifar/plots/ deps: - - path: cifar/data/data.pkl - hash: md5 - md5: 6503fed5d4e6cc1163898c0ab6a863dd - size: 739680311 - - path: cifar/models/model.pt - hash: md5 - md5: f5d11f93160ad27b8468efc0d71eb695 - size: 44811029 + - path: cifar/reports/clean_attack.csv + md5: 81b63f1d5864d65bdaf71aed4ae4c2b0 + size: 14727230 params: params.yaml: - attack: - _target_: deckard.base.attack.Attack - attack_size: 10 - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar10 - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - init: - _target_: deckard.base.attack.AttackInitializer - model: - _target_: deckard.base.model.Model - art: - _target_: deckard.base.model.art_pipeline.ArtPipeline - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar10 - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - initialize: - clip_values: - - 0.0 - - 255.0 - criterion: - name: torch.nn.CrossEntropyLoss - optimizer: - lr: 0.01 - momentum: 0.9 - name: torch.optim.SGD - library: pytorch - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar10 - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - init: - _target_: deckard.base.model.ModelInitializer - name: torch_example.ResNet18 - num_channels: 3 - num_classes: 10 - library: pytorch - trainer: - batch_size: 1024 - nb_epoch: 100 - name: art.attacks.evasion.HopSkipJump - method: evasion - model: - _target_: deckard.base.model.Model - art: - _target_: deckard.base.model.art_pipeline.ArtPipeline - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar10 - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - initialize: - clip_values: - - 0.0 - - 255.0 - criterion: - name: torch.nn.CrossEntropyLoss - optimizer: - lr: 0.01 - momentum: 0.9 - name: torch.optim.SGD - library: pytorch - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar10 - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - init: - _target_: deckard.base.model.ModelInitializer - name: torch_example.ResNet18 - num_channels: 3 - num_classes: 10 - library: pytorch - trainer: - batch_size: 1024 - nb_epoch: 100 - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar10 - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - files: - _target_: deckard.base.files.FileConfig - adv_predictions_file: adv_predictions.json - attack_dir: attacks - attack_file: attack - attack_type: .pkl - data_dir: data - data_file: data - data_type: .pkl - directory: cifar - model_dir: models - model_file: model - model_type: .pt - name: default - params_file: params.yaml - predictions_file: predictions.json - reports: reports - score_dict_file: score_dict.json - model: - _target_: deckard.base.model.Model - art: - _target_: deckard.base.model.art_pipeline.ArtPipeline - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar10 - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - initialize: - clip_values: - - 0.0 - - 255.0 - criterion: - name: torch.nn.CrossEntropyLoss - optimizer: - lr: 0.01 - momentum: 0.9 - name: torch.optim.SGD - library: pytorch - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar10 - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - init: - _target_: deckard.base.model.ModelInitializer - name: torch_example.ResNet18 - num_channels: 3 - num_classes: 10 - library: pytorch - trainer: - batch_size: 1024 - nb_epoch: 100 - scorers: - _target_: deckard.base.scorer.ScorerDict - accuracy: - _target_: deckard.base.scorer.ScorerConfig - direction: maximize - name: sklearn.metrics.accuracy_score - log_loss: - _target_: deckard.base.scorer.ScorerConfig - direction: minimize - name: sklearn.metrics.log_loss - outs: - - path: cifar/attacks/attack.pkl - hash: md5 - md5: 4c6d7b56c319a2a3a8f4288873141a44 - size: 123046 - - path: cifar/reports/attack/default/adv_predictions.json - hash: md5 - md5: 0e905b6a95defafe1472cd1d329ed124 - size: 2136 - - path: cifar/reports/attack/default/score_dict.json - hash: md5 - md5: f40b5d8125bf8b6370a94fe65d43cffa - size: 458 - attacks@ResNet101: - cmd: bash attacks.sh ++attack.attack_size=100 ++model.init.name=torch_example.ResNet101 - stage=attack ++hydra.sweeper.storage=sqlite:///cifar/reports/attack/ResNet101.db - --config-name cifar10.yaml - deps: - - path: attacks.sh - hash: md5 - md5: 963c858a322d7a4990a92a25d5684c57 - size: 2907 - - path: cifar/reports/attack/default/score_dict.json - hash: md5 - md5: f40b5d8125bf8b6370a94fe65d43cffa - size: 458 - - path: models.sh - hash: md5 - md5: 02a4961b4afe7ba84c41e9ad49c30c83 - size: 2760 - outs: - - path: cifar/reports/attack/ResNet101.db - hash: md5 - md5: 268500e55100c8e2c0de628e8b66b612 - size: 819200 - attacks@ResNet152: - cmd: bash attacks.sh ++attack.attack_size=100 ++model.init.name=torch_example.ResNet152 - stage=attack ++hydra.sweeper.storage=sqlite:///cifar/reports/attack/ResNet152.db - --config-name cifar10.yaml - deps: - - path: attacks.sh - hash: md5 - md5: 963c858a322d7a4990a92a25d5684c57 - size: 2907 - - path: cifar/reports/attack/default/score_dict.json - hash: md5 - md5: f40b5d8125bf8b6370a94fe65d43cffa - size: 458 - - path: models.sh - hash: md5 - md5: 02a4961b4afe7ba84c41e9ad49c30c83 - size: 2760 - outs: - - path: cifar/reports/attack/ResNet152.db - hash: md5 - md5: 47684cf7d10b05f6343f58579fd05af3 - size: 249856 - attacks@ResNet18: - cmd: bash attacks.sh ++attack.attack_size=100 ++model.init.name=torch_example.ResNet18 - stage=attack ++hydra.sweeper.storage=sqlite:///cifar/reports/attack/ResNet18.db - --config-name cifar10.yaml - deps: - - path: attacks.sh - hash: md5 - md5: 963c858a322d7a4990a92a25d5684c57 - size: 2907 - - path: cifar/reports/attack/default/score_dict.json - hash: md5 - md5: f40b5d8125bf8b6370a94fe65d43cffa - size: 458 - - path: models.sh - hash: md5 - md5: 02a4961b4afe7ba84c41e9ad49c30c83 - size: 2760 - outs: - - path: cifar/reports/attack/ResNet18.db - hash: md5 - md5: bf2b93a31c49e96b219c23095504a7f1 - size: 819200 - attacks@ResNet34: - cmd: bash attacks.sh ++attack.attack_size=100 ++model.init.name=torch_example.ResNet34 - stage=attack ++hydra.sweeper.storage=sqlite:///cifar/reports/attack/ResNet34.db - --config-name cifar10.yaml - deps: - - path: attacks.sh - hash: md5 - md5: 963c858a322d7a4990a92a25d5684c57 - size: 2907 - - path: cifar/reports/attack/default/score_dict.json - hash: md5 - md5: f40b5d8125bf8b6370a94fe65d43cffa - size: 458 - - path: models.sh - hash: md5 - md5: 02a4961b4afe7ba84c41e9ad49c30c83 - size: 2760 - outs: - - path: cifar/reports/attack/ResNet34.db - hash: md5 - md5: 8de8f4dfcda52bb40f206cf3c4977dd5 - size: 819200 - attacks@ResNet50: - cmd: bash attacks.sh ++attack.attack_size=100 ++model.init.name=torch_example.ResNet50 - stage=attack ++hydra.sweeper.storage=sqlite:///cifar/reports/attack/ResNet50.db - --config-name cifar10.yaml - deps: - - path: attacks.sh - hash: md5 - md5: 963c858a322d7a4990a92a25d5684c57 - size: 2907 - - path: cifar/reports/attack/default/score_dict.json - hash: md5 - md5: f40b5d8125bf8b6370a94fe65d43cffa - size: 458 - - path: models.sh - hash: md5 - md5: 02a4961b4afe7ba84c41e9ad49c30c83 - size: 2760 - outs: - - path: cifar/reports/attack/ResNet50.db - hash: md5 - md5: 8adabcf8a15b13fc20ea31f58ae7388b - size: 1069056 - compile@attack: - cmd: python -m deckard.layers.compile --report_folder cifar/reports/attack --results_file - cifar/reports/attack.csv - deps: - - path: cifar/reports/attack/ - hash: md5 - md5: 8c7a44700932e363fa7482224eac15bb.dir - size: 9973372888 - nfiles: 34873 - - path: cifar/reports/attack/ResNet101.db - hash: md5 - md5: 268500e55100c8e2c0de628e8b66b612 - size: 819200 - - path: cifar/reports/attack/ResNet18.db - hash: md5 - md5: bf2b93a31c49e96b219c23095504a7f1 - size: 819200 - - path: cifar/reports/attack/ResNet34.db - hash: md5 - md5: 8de8f4dfcda52bb40f206cf3c4977dd5 - size: 819200 - - path: cifar/reports/attack/ResNet50.db - hash: md5 - md5: 8adabcf8a15b13fc20ea31f58ae7388b - size: 1069056 + files.directory: cifar + conf/afr.yaml: + covariates: + - adv_fit_time + - accuracy + - train_time + - atk_value + - def_value + - data.sample.random_state + - model_layers + - model.trainer.nb_epoch + - predict_time + log_logistic: + plot: + file: log_logistic_aft.eps + title: Log logistic AFR Model + labels: + 'Intercept: beta_': $\beta$ + 'Intercept: alpha_': $\alpha$ + 'data.sample.random_state: alpha_': Random State + 'atk_value: alpha_': Attack Strength + 'train_time: alpha_': $t_{train}$ + 'predict_proba_time: alpha_': $t_{predict}$ + 'adv_accuracy: alpha_': Adv. Accuracy + 'accuracy: alpha_': Ben. Accuracy + 'adv_fit_time: alpha_': $t_{attack}$ + 'adv_failure_rate: alpha_': $f_{adv.}(t;\theta)$ + 'failure_rate: alpha_': $f_{ben.}(t;\theta)$ + 'model.trainer.nb_epoch: alpha_': No. of Epochs + 'model.trainer.batch_size: alpha_': Batch Size + def_gen: Defence + 'model_layers: alpha_': Layers + 'def_value: alpha_': Defence Strength + 'predict_time: alpha_': $t_{predict}$ + partial_effect: + - file: log_logistic_epochs_partial_effect.eps + covariate_array: model.trainer.nb_epoch + values_array: + - 1 + - 10 + - 25 + - 50 + title: $S(t)$ for Log-Logistic AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Epochs + labels: + - '1' + - '10' + - '25' + - '50' + - file: log_logistic_layers_partial_effect.eps + covariate_array: model_layers + values_array: + - 18 + - 34 + - 50 + - 101 + - 152 + title: $S(t)$ for Log Logistic AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Layers + labels: + - '18' + - '34' + - '50' + - '101' + - '152' + log_normal: + plot: + file: log_normal_aft.eps + title: Log Normal AFR Model + labels: + 'Intercept: sigma_': $\rho$ + 'Intercept: mu_': $\mu$ + 'data.sample.random_state: mu_': Random State + 'atk_value: mu_': Attack Strength + 'train_time: mu_': $t_{train}$ + 'predict_proba_time: mu_': $t_{predict}$ + 'adv_accuracy: mu_': Adv. Accuracy + 'accuracy: mu_': Ben. Accuracy + 'adv_fit_time: mu_': $t_{attack}$ + 'adv_failure_rate: mu_': $f_{adv.}(t;\theta)$ + 'failure_rate: mu_': $f_{ben.}(t;\theta)$ + 'model.trainer.nb_epoch: mu_': No. of Epochs + 'model.trainer.batch_size: mu_': Batch Size + def_gen: Defence + 'model_layers: mu_': Layers + 'def_value: mu_': Defence Strength + 'predict_time: mu_': $t_{predict}$ + partial_effect: + - file: log_normal_epochs_partial_effect.eps + covariate_array: model.trainer.nb_epoch + values_array: + - 1 + - 10 + - 25 + - 50 + title: $S(t)$ for Log-Normal AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Epochs + labels: + - '1' + - '10' + - '25' + - '50' + - file: log_normal_layers_partial_effect.eps + covariate_array: model_layers + values_array: + - 18 + - 34 + - 50 + - 101 + - 152 + title: $S(t)$ for Log Normal AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Layers + labels: + - '18' + - '34' + - '50' + - '101' + - '152' + weibull: + plot: + file: weibull_aft.eps + title: Weibull AFR Model + labels: + 'Intercept: rho_': $\rho$ + 'Intercept: lambda_': $\lambda$ + 'data.sample.random_state: lambda_': Random State + 'atk_value: lambda_': Attack Strength + 'train_time: lambda_': $t_{train}$ + 'predict_proba_time: lambda_': $t_{predict}$ + 'adv_accuracy: lambda_': Adv. Accuracy + 'accuracy: lambda_': Ben. Accuracy + 'adv_fit_time: lambda_': $t_{attack}$ + 'adv_failure_rate: lambda_': $f_{adv.}(t;\theta)$ + 'failure_rate: lambda_': $f_{ben.}(t;\theta)$ + 'model.trainer.nb_epoch: lambda_': No. of Epochs + 'model.trainer.batch_size: lambda_': Batch Size + def_gen: Defence + 'model_layers: lambda_': Layers + 'def_value: lambda_': Defence Strength + 'predict_time: lambda_': $t_{predict}$ + partial_effect: + - file: weibull_epochs_partial_effect.eps + covariate_array: model.trainer.nb_epoch + values_array: + - 1 + - 10 + - 25 + - 50 + title: $S(t)$ for Weibull AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Epochs + labels: + - '1' + - '10' + - '25' + - '50' + - file: weibull_layers_partial_effect.eps + covariate_array: model_layers + values_array: + - 18 + - 34 + - 50 + - 101 + - 152 + title: $S(t)$ for Weibull AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Layers + labels: + - '18' + - '34' + - '50' + - '101' + - '152' outs: - - path: cifar/reports/attack.csv - hash: md5 - md5: 51d3b7360885430ef15c78e66a85393a - size: 26068128 + - path: cifar/plots/log_logistic_aft.eps + md5: 25c507a344b0589027e50473873485f4 + size: 44483 + - path: cifar/plots/log_logistic_epochs_partial_effect.eps + md5: 58ad2cc4455c7a2e14dd8baf5e0bebbc + size: 43547 + - path: cifar/plots/log_logistic_layers_partial_effect.eps + md5: c1ec42636bdbf6ba5a3279da4ff03226 + size: 46098 + - path: cifar/plots/log_normal_aft.eps + md5: c10aef0b38507ea46d0bcab12edd43d7 + size: 43898 + - path: cifar/plots/log_normal_epochs_partial_effect.eps + md5: c7e71cb7f8673260b6ba330e228f9897 + size: 44094 + - path: cifar/plots/log_normal_layers_partial_effect.eps + md5: c516900f508281933e52f08fc6e4cec3 + size: 46510 + - path: cifar/plots/weibull_aft.eps + md5: 42a59a94ef52a0bd0260cc1fe2113bc3 + size: 41411 + - path: cifar/plots/weibull_epochs_partial_effect.eps + md5: e5397975c6e5b322a41b7c5918e278cf + size: 43063 + - path: cifar/plots/weibull_layers_partial_effect.eps + md5: 00b0191fdd4ac6f407a33374dbb7a06b + size: 45397 plot: cmd: python -m deckard.layers.plots --path cifar/plots/ --file cifar/reports/clean_attack.csv -c conf/plots.yaml deps: - path: cifar/reports/clean_attack.csv - hash: md5 - md5: 726a596355273abf4a5172268bf69c62 - size: 14801171 + md5: 81b63f1d5864d65bdaf71aed4ae4c2b0 + size: 14727230 params: params.yaml: files.directory: cifar files.reports: reports conf/plots.yaml: cat_plot: - - file: adv_accuracy_vs_defence_type.pdf + - file: adv_accuracy_vs_defence_type.eps hue: model_name kind: boxen set: @@ -512,7 +307,7 @@ stages: - ResNet50 - ResNet101 - ResNet152 - - file: ben_accuracy_vs_defence_type.pdf + - file: ben_accuracy_vs_defence_type.eps hue: model_name kind: boxen titles: Ben. Accuracy vs Defence Type @@ -527,7 +322,7 @@ stages: - ResNet50 - ResNet101 - ResNet152 - - file: ben_failures_per_train_time_vs_defence_type.pdf + - file: ben_failures_per_train_time_vs_defence_type.eps hue: model_name kind: boxen set: @@ -544,11 +339,9 @@ stages: - ResNet50 - ResNet101 - ResNet152 - - file: adv_failures_per_train_time_vs_defence_type.pdf + - file: adv_failures_per_train_time_vs_defence_type.eps hue: model_name kind: boxen - set: - yscale: log titles: $\bar{C}_{adv.}$ vs Defence Type x: def_gen xlabels: Defence Type @@ -561,12 +354,10 @@ stages: - ResNet50 - ResNet101 - ResNet152 - - file: adv_failures_per_train_time_vs_attack_type.pdf + - file: adv_failures_per_train_time_vs_attack_type.eps hue: model_name kind: boxen legend_title: Model Name - set: - yscale: log titles: $\bar{C}_{adv.}$ vs Attack Type x: atk_gen xlabels: Attack Type @@ -579,31 +370,15 @@ stages: - ResNet50 - ResNet101 - ResNet152 - - file: adv_failures_per_test_time_vs_defence_type.pdf + - file: adv_failures_per_test_time_vs_defence_type.eps hue: model_name kind: boxen legend_title: Model Name - titles: $h_{adv}$ vs Defence Type + titles: $f_{adv}$ vs Defence Type x: def_gen xlabels: Defence Type y: adv_failure_rate - ylabels: $h_{adv.}$ - rotation: 90 - hue_order: - - ResNet18 - - ResNet34 - - ResNet50 - - ResNet101 - - ResNet152 - - file: adv_accuracy_vs_defence_type.pdf - hue: model_name - kind: boxen - legend_title: Model Name - titles: Adv. Accuracy vs Defence Type - x: def_gen - xlabels: Defence Type - y: adv_accuracy - ylabels: Adv. Ben. Accuracy + ylabels: $f_{adv.}$ rotation: 90 hue_order: - ResNet18 @@ -611,7 +386,7 @@ stages: - ResNet50 - ResNet101 - ResNet152 - - file: adv_accuracy_vs_attack_type.pdf + - file: adv_accuracy_vs_attack_type.eps hue: model_name kind: boxen legend_title: Model Name @@ -627,17 +402,17 @@ stages: - ResNet50 - ResNet101 - ResNet152 - - file: ben_failure_rate_vs_defence_type.pdf + - file: ben_failure_rate_vs_defence_type.eps hue: model_name kind: boxen legend_title: Model Name set: yscale: log - titles: $h_{ben}(t; \theta)$ vs Defence Type + titles: $f_{ben}(t; \theta)$ vs Defence Type x: def_gen xlabels: Defence Type y: failure_rate - ylabels: $h_{ben}(t; \theta)$ + ylabels: $f_{ben}(t; \theta)$ rotation: 90 hue_order: - ResNet18 @@ -646,7 +421,7 @@ stages: - ResNet101 - ResNet152 line_plot: - - file: def_param_vs_accuracy.pdf + - file: def_param_vs_accuracy.eps hue: def_gen legend: bbox_to_anchor: @@ -660,7 +435,17 @@ stages: y: accuracy y_scale: ylabel: Ben. Accuracy - - file: def_param_vs_adv_accuracy.pdf + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars + - file: def_param_vs_adv_accuracy.eps hue: def_gen legend: bbox_to_anchor: @@ -674,21 +459,41 @@ stages: y: adv_accuracy y_scale: ylabel: Adv. Accuracy - - file: def_param_vs_adv_failure_rate.pdf + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars + - file: def_param_vs_adv_failure_rate.eps hue: def_gen legend: bbox_to_anchor: - 1.05 - 1 title: Defence - title: $h_{adv}$ vs Defence Strength + title: $f_{adv}$ vs Defence Strength x: def_value - x_scale: linear + x_scale: log xlabel: Defence Control Parameter y: adv_failure_rate y_scale: log - ylabel: $h_{adv.}$ - - file: atk_param_vs_accuracy.pdf + ylabel: $f_{adv.}$ + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars + - file: atk_param_vs_accuracy.eps hue: atk_gen legend: bbox_to_anchor: @@ -708,15 +513,17 @@ stages: - HSJ - Pixel - Thresh + errorbar: se + err_style: bars scatter_plot: - x: train_time_per_sample y: adv_failure_rate hue: model_name xlabel: $t_{train}$ - ylabel: $h_{adv}$ - title: $h_{adv}$ vs $t_{train}$ - file: adv_failure_rate_vs_train_time.pdf - y_scale: log + ylabel: $f_{adv}$ + title: $f_{adv}$ vs $t_{train}$ + file: adv_failure_rate_vs_train_time.eps + y_scale: linear x_scale: log legend: title: Model Name @@ -730,343 +537,49 @@ stages: - ResNet101 - ResNet152 outs: - - path: cifar/plots/adv_accuracy_vs_attack_type.pdf - hash: md5 - md5: 2ad8aa1137712e792fc9339cd9409d54 - size: 32194 - - path: cifar/plots/adv_accuracy_vs_defence_type.pdf - hash: md5 - md5: 5c408e76ac388859dbb9cad4e2ddf968 - size: 32506 - - path: cifar/plots/adv_failure_rate_vs_train_time.pdf - hash: md5 - md5: 351d7f3bf8b5933c8ee3031447f48658 - size: 80138 - - path: cifar/plots/adv_failures_per_test_time_vs_defence_type.pdf - hash: md5 - md5: 4c1bd0364c0e2d3f372714202c05f911 - size: 39583 - - path: cifar/plots/adv_failures_per_train_time_vs_attack_type.pdf - hash: md5 - md5: 57ff7639a8f432aea0b4195e33d5ba96 - size: 40766 - - path: cifar/plots/adv_failures_per_train_time_vs_defence_type.pdf - hash: md5 - md5: ba23e1a31c95519b640bd2ab7edfea4b - size: 36881 - - path: cifar/plots/atk_param_vs_accuracy.pdf - hash: md5 - md5: 3bf276eed7ed8172d48896efd29991ac - size: 20181 - - path: cifar/plots/ben_accuracy_vs_defence_type.pdf - hash: md5 - md5: d182987f8164dc47305649c193506f10 - size: 29771 - - path: cifar/plots/ben_failure_rate_vs_defence_type.pdf - hash: md5 - md5: a4bdbad3210e9da50098d068792673cc - size: 41749 - - path: cifar/plots/ben_failures_per_train_time_vs_defence_type.pdf - hash: md5 - md5: 900f4362e3e0ffa76a6d0f7f99d52051 - size: 36648 - - path: cifar/plots/def_param_vs_accuracy.pdf - hash: md5 - md5: f7426fca89038c2f19da4afc9c41eab4 - size: 19712 - - path: cifar/plots/def_param_vs_adv_accuracy.pdf - hash: md5 - md5: bda0d408b829c40e17e04f768852fd44 - size: 19958 - - path: cifar/plots/def_param_vs_adv_failure_rate.pdf - hash: md5 - md5: 8b2e7a00615d225bdd9cfa0fdd3c7f36 - size: 23544 - afr: - cmd: python -m deckard.layers.afr --dataset cifar --data_file cifar/reports/clean_attack.csv --duration_col - adv_fit_time --dataset mnist --config_file conf/afr.yaml --plots_folder cifar/plots/ - deps: - - path: cifar/plots/adv_accuracy_vs_defence_type.pdf - hash: md5 - md5: 5c408e76ac388859dbb9cad4e2ddf968 - size: 32506 - - path: cifar/reports/clean_attack.csv - hash: md5 - md5: 726a596355273abf4a5172268bf69c62 - size: 14801171 - params: - params.yaml: - files.directory: cifar - conf/afr.yaml: - covariates: - - accuracy - - train_time - - predict_time - - atk_value - - def_value - - data.sample.random_state - - adv_failure_rate - - model_layers - - adv_fit_time - - model.trainer.nb_epoch - log_logistic: - plot: - file: log_logistic_aft.pdf - title: Log logistic AFR Model - labels: - 'Intercept: rho_': $\rho$ - 'Intercept: lambda_': $\lambda$ - 'data.sample.random_state: lambda_': Random State - 'atk_value: lambda_': Attack Strength - 'train_time: lambda_': $t_{train}$ - 'predict_proba_time: lambda_': $t_{predict}$ - 'adv_accuracy: lambda_': Adv. Accuracy - 'accuracy: lambda_': Ben. Accuracy - 'adv_fit_time: lambda_': $t_{attack}$ - 'adv_failure_rate: lambda_': $h_{adv.}(t;\theta)$ - 'failure_rate: lambda_': $h_{ben.}(t;\theta)$ - 'model.trainer.nb_epoch: lambda_': No. of Epochs - 'model.trainer.batch_size: lambda_': Batch Size - def_gen: Defence - partial_effect: - - file: log_logistic_epochs_partial_effect.pdf - covariate_array: model.trainer.nb_epoch - values_array: - - 1 - - 10 - - 25 - - 50 - title: $S(t)$ for Log-Logistic AFR - ylabel: Expectation of $S(t)$ - xlabel: Time $T$ (seconds) - legend_kwargs: - title: Epochs - labels: - - '1' - - '10' - - '25' - - '50' - - file: log_logistic_layers_partial_effect.pdf - covariate_array: model_layers - values_array: - - 18 - - 34 - - 50 - - 101 - - 152 - title: $S(t)$ for Cox AFR - ylabel: Expectation of $S(t)$ - xlabel: Time $T$ (seconds) - legend_kwargs: - title: ResNet Layers - labels: - - '18' - - '34' - - '50' - - '101' - - '152' - log_normal: - plot: - file: log_normal_aft.pdf - title: Log Normal AFR Model - labels: - 'Intercept: rho_': $\rho$ - 'Intercept: lambda_': $\lambda$ - 'data.sample.random_state: lambda_': Random State - 'atk_value: lambda_': Attack Strength - 'train_time: lambda_': $t_{train}$ - 'predict_proba_time: lambda_': $t_{predict}$ - 'adv_accuracy: lambda_': Adv. Accuracy - 'accuracy: lambda_': Ben. Accuracy - 'adv_fit_time: lambda_': $t_{attack}$ - 'adv_failure_rate: lambda_': $h_{adv.}(t;\theta)$ - 'failure_rate: lambda_': $h_{ben.}(t;\theta)$ - 'model.trainer.nb_epoch: lambda_': No. of Epochs - 'model.trainer.batch_size: lambda_': Batch Size - def_gen: Defence - partial_effect: - - file: log_normal_epochs_partial_effect.pdf - covariate_array: model.trainer.nb_epoch - values_array: - - 1 - - 10 - - 25 - - 50 - title: $S(t)$ for Log-Normal AFR - ylabel: Expectation of $S(t)$ - xlabel: Time $T$ (seconds) - legend_kwargs: - title: Epochs - labels: - - '1' - - '10' - - '25' - - '50' - - file: log_normal_layers_partial_effect.pdf - covariate_array: model_layers - values_array: - - 18 - - 34 - - 50 - - 101 - - 152 - title: $S(t)$ for Cox AFR - ylabel: Expectation of $S(t)$ - xlabel: Time $T$ (seconds) - legend_kwargs: - title: ResNet Layers - labels: - - '18' - - '34' - - '50' - - '101' - - '152' - weibull: - plot: - file: weibull_aft.pdf - title: Weibull AFR Model - labels: - 'Intercept: rho_': $\rho$ - 'Intercept: lambda_': $\lambda$ - 'data.sample.random_state: lambda_': Random State - 'atk_value: lambda_': Attack Strength - 'train_time: lambda_': $t_{train}$ - 'predict_proba_time: lambda_': $t_{predict}$ - 'adv_accuracy: lambda_': Adv. Accuracy - 'accuracy: lambda_': Ben. Accuracy - 'adv_fit_time: lambda_': $t_{attack}$ - 'adv_failure_rate: lambda_': $h_{adv.}(t;\theta)$ - 'failure_rate: lambda_': $h_{ben.}(t;\theta)$ - 'model.trainer.nb_epoch: lambda_': No. of Epochs - 'model.trainer.batch_size: lambda_': Batch Size - def_gen: Defence - partial_effect: - - file: weibull_epochs_partial_effect.pdf - covariate_array: model.trainer.nb_epoch - values_array: - - 1 - - 10 - - 25 - - 50 - title: $S(t)$ for Weibull AFR - ylabel: Expectation of $S(t)$ - xlabel: Time $T$ (seconds) - legend_kwargs: - title: Epochs - labels: - - '1' - - '10' - - '25' - - '50' - - file: weibull_layers_partial_effect.pdf - covariate_array: model_layers - values_array: - - 18 - - 34 - - 50 - - 101 - - 152 - title: $S(t)$ for Cox AFR - ylabel: Expectation of $S(t)$ - xlabel: Time $T$ (seconds) - legend_kwargs: - title: ResNet Layers - labels: - - '18' - - '34' - - '50' - - '101' - - '152' - outs: - - path: cifar/plots/log_logistic_aft.pdf - hash: md5 - md5: 2b28871d23665f9745e4d8cb1fef3a7c - size: 23397 - - path: cifar/plots/log_logistic_epochs_partial_effect.pdf - hash: md5 - md5: 820bec8e7d11f46984c7642e797c00d1 - size: 27103 - - path: cifar/plots/log_logistic_layers_partial_effect.pdf - hash: md5 - md5: 38c30a96926e95f5cbb810e1922d1ce3 - size: 28955 - - path: cifar/plots/log_normal_aft.pdf - hash: md5 - md5: df4c2cc42d194386fafea2ef78411bf7 - size: 23817 - - path: cifar/plots/log_normal_epochs_partial_effect.pdf - hash: md5 - md5: c3ffc8e94ccd522d1a8737a4e3c1436f - size: 28672 - - path: cifar/plots/log_normal_layers_partial_effect.pdf - hash: md5 - md5: 247006b93ddadc97a3849cfce5d2ea00 - size: 28982 - - path: cifar/plots/weibull_aft.pdf - hash: md5 - md5: a4759653f442f4acb739f80f4e763600 - size: 33056 - - path: cifar/plots/weibull_epochs_partial_effect.pdf - hash: md5 - md5: 0ddb5d5038243152cd0d68d6dffeb88a - size: 28141 - - path: cifar/plots/weibull_layers_partial_effect.pdf - hash: md5 - md5: e80a372b96f8845791f00a8a7b2f571b - size: 28960 + - path: cifar/plots/adv_accuracy_vs_attack_type.eps + md5: 5138387d43aa6b80861beda375a668a4 + size: 108266 + - path: cifar/plots/adv_accuracy_vs_defence_type.eps + md5: 413761c7484aed43f3d3f6f75da81e82 + size: 101582 + - path: cifar/plots/adv_failure_rate_vs_train_time.eps + md5: 2cdddda5ce788d5813ca55880fdb7a91 + size: 631508 + - path: cifar/plots/adv_failures_per_test_time_vs_defence_type.eps + md5: 23aff41fad24c912f0301f2e986ae96d + size: 121711 + - path: cifar/plots/adv_failures_per_train_time_vs_attack_type.eps + md5: 85efb2307112f220946f0c4b623df366 + size: 120765 + - path: cifar/plots/adv_failures_per_train_time_vs_defence_type.eps + md5: f914efca4568b2f5163b7e8723f0df5c + size: 113874 + - path: cifar/plots/atk_param_vs_accuracy.eps + md5: 35ee04493de38424453b9514c45d66f1 + size: 39212 + - path: cifar/plots/ben_accuracy_vs_defence_type.eps + md5: 61569c543a2891c9fcdc95314924ceb4 + size: 96824 + - path: cifar/plots/ben_failure_rate_vs_defence_type.eps + md5: 792603cf59c01c922408c18d1dfeda3e + size: 122740 + - path: cifar/plots/ben_failures_per_train_time_vs_defence_type.eps + md5: 25f8992268b8eefa2eaa60b73e1f6370 + size: 112749 + - path: cifar/plots/def_param_vs_accuracy.eps + md5: 21b2ace7923bdeb9c5bb950caf2307f1 + size: 38940 + - path: cifar/plots/def_param_vs_adv_accuracy.eps + md5: 43d5d57465019a4067af163be4178fa8 + size: 38631 + - path: cifar/plots/def_param_vs_adv_failure_rate.eps + md5: 2a6cfab767a224847deb07eb1d451b4a + size: 39304 copy_results: - cmd: cp -r cifar/plots/* ~/ml_afr/cifar/ + cmd: mkdir -p ~/ml_afr/cifar/ && cp -r cifar/plots/* ~/ml_afr/cifar/ deps: - path: cifar/plots/ - hash: md5 - md5: 7531488748e5e0453ac9eb36d844097e.dir - size: 15075359 + md5: c22ad5afc78d35f682d247d6bd61643f.dir + size: 16455580 nfiles: 25 - clean@attack: - cmd: python -m deckard.layers.clean_data -i cifar/reports/attack.csv -o cifar/reports/clean_attack.csv - -c conf/clean.yaml - deps: - - path: cifar/reports/attack.csv - hash: md5 - md5: 51d3b7360885430ef15c78e66a85393a - size: 26068128 - params: - params.yaml: - files.directory: cifar - files.reports: reports - conf/clean.yaml: - attacks: - DeepFool: Deep - FastGradientMethod: FGM - HopSkipJump: HSJ - PixelAttack: Pixel - ProjectedGradientDescent: PGD - ThresholdAttack: Thresh - defences: - Control: Control - FeatureSqueezing: FSQ - GaussianAugmentation: Gauss-in - GaussianNoise: Gauss-out - HighConfidence: Conf - nb_epoch: Epochs - model_layers: Control - fillna: - Epochs: 20 - params: - Deep: attack.init.kwargs.nb_grads - FGM: attack.init.kwargs.eps - HSJ: attack.init.kwargs.max_iter - Pixel: attack.init.kwargs.th - PGD: attack.init.kwargs.eps - Thresh: attack.init.kwargs.th - Gauss-out: model.art.pipeline.postprocessor.kwargs.scale - Conf: model.art.pipeline.postprocessor.kwargs.cutoff - FSQ: model.art.pipeline.preprocessor.kwargs.bit_depth - Gauss-in: model.art.pipeline.preprocessor.kwargs.sigma - Control: model_layers - Epochs: model.trainer.nb_epoch - outs: - - path: cifar/reports/clean_attack.csv - hash: md5 - md5: 726a596355273abf4a5172268bf69c62 - size: 14801171 diff --git a/examples/pytorch/cifar10/dvc.yaml b/examples/pytorch/cifar10/dvc.yaml index 7f6b417d..6b445d4c 100644 --- a/examples/pytorch/cifar10/dvc.yaml +++ b/examples/pytorch/cifar10/dvc.yaml @@ -12,7 +12,7 @@ vars: - conf/clean.yaml:fillna stages: train: - cmd: python -m deckard.layers.experiment train --config_file cifar10.yaml + cmd: python -m deckard.layers.experiment train --config_file cifar.yaml params: - data - model @@ -29,7 +29,7 @@ stages: metrics: - ${files.directory}/${files.reports}/train/${files.name}/${files.score_dict_file} attack: - cmd: python -m deckard.layers.experiment attack --config_file cifar10.yaml + cmd: python -m deckard.layers.experiment attack --config_file cifar.yaml params: - data - model @@ -55,7 +55,7 @@ stages: # # - ResNet101 # # - ResNet152 # do: # This script configures eazch defence - # cmd: bash models.sh ++model.init.name=torch_example.${item} stage=train ++hydra.sweeper.storage=sqlite:///${files.directory}/${files.reports}/train/${item}.db --config-name cifar10.yaml + # cmd: bash models.sh ++model.init.name=torch_example.${item} stage=train ++hydra.sweeper.storage=sqlite:///${files.directory}/${files.reports}/train/${item}.db --config-name cifar.yaml # deps: # - models.sh # - ${files.directory}/${files.model_dir}/${files.model_file}${files.model_type} @@ -72,7 +72,7 @@ stages: - ResNet101 - ResNet152 do: - cmd: bash attacks.sh ++attack.attack_size=100 ++model.init.name=torch_example.${item} stage=attack ++hydra.sweeper.storage=sqlite:///${files.directory}/${files.reports}/attack/${item}.db --config-name cifar10.yaml + cmd: bash attacks.sh ++attack.attack_size=100 ++model.init.name=torch_example.${item} stage=attack ++hydra.sweeper.storage=sqlite:///${files.directory}/${files.reports}/attack/${item}.db --config-name cifar.yaml deps: - models.sh # This script configures each defence - attacks.sh # This script configures each attack @@ -94,7 +94,7 @@ stages: - ${files.directory}/${files.reports}/${item}/ResNet34.db - ${files.directory}/${files.reports}/${item}/ResNet50.db - ${files.directory}/${files.reports}/${item}/ResNet101.db - # - ${files.directory}/${files.reports}/${item}/ResNet152.db + - ${files.directory}/${files.reports}/${item}/ResNet152.db outs: - ${files.directory}/${files.reports}/${item}.csv clean: @@ -128,7 +128,6 @@ stages: - ${files.directory}/plots/${cat_plot[5].file} - ${files.directory}/plots/${cat_plot[6].file} - ${files.directory}/plots/${cat_plot[7].file} - - ${files.directory}/plots/${cat_plot[8].file} - ${files.directory}/plots/${line_plot[0].file} - ${files.directory}/plots/${line_plot[1].file} - ${files.directory}/plots/${line_plot[2].file} @@ -142,20 +141,19 @@ stages: - scatter_plot - cat_plot afr: - cmd: python -m deckard.layers.afr --dataset ${files.directory} --data_file ${files.directory}/${files.reports}/clean_attack.csv --duration_col adv_fit_time --dataset mnist --config_file conf/afr.yaml --plots_folder ${files.directory}/plots/ + cmd: python -m deckard.layers.afr --dataset ${files.directory} --data_file ${files.directory}/${files.reports}/clean_attack.csv --target adv_accuracy --duration_col predict_time --dataset cifar --config_file conf/afr.yaml --plots_folder ${files.directory}/plots/ deps: - ${files.directory}/${files.reports}/clean_attack.csv - - ${files.directory}/plots/${cat_plot[0].file} plots: - - ${files.directory}/plots/weibull_aft.pdf - - ${files.directory}/plots/weibull_epochs_partial_effect.pdf - - ${files.directory}/plots/weibull_layers_partial_effect.pdf - - ${files.directory}/plots/log_logistic_aft.pdf - - ${files.directory}/plots/log_logistic_epochs_partial_effect.pdf - - ${files.directory}/plots/log_logistic_layers_partial_effect.pdf - - ${files.directory}/plots/log_normal_aft.pdf - - ${files.directory}/plots/log_normal_epochs_partial_effect.pdf - - ${files.directory}/plots/log_normal_layers_partial_effect.pdf + - ${files.directory}/plots/weibull_aft.eps + - ${files.directory}/plots/weibull_epochs_partial_effect.eps + - ${files.directory}/plots/weibull_layers_partial_effect.eps + - ${files.directory}/plots/log_logistic_aft.eps + - ${files.directory}/plots/log_logistic_epochs_partial_effect.eps + - ${files.directory}/plots/log_logistic_layers_partial_effect.eps + - ${files.directory}/plots/log_normal_aft.eps + - ${files.directory}/plots/log_normal_epochs_partial_effect.eps + - ${files.directory}/plots/log_normal_layers_partial_effect.eps params: - files.directory - conf/afr.yaml: @@ -164,6 +162,7 @@ stages: - log_logistic - log_normal copy_results: - cmd: cp -r ${files.directory}/plots/* ~/ml_afr/cifar/ + cmd: mkdir -p ~/ml_afr/cifar/ && cp -r ${files.directory}/plots/* ~/ml_afr/cifar/ deps: - ${files.directory}/plots/ + diff --git a/examples/pytorch/cifar10/models.sh b/examples/pytorch/cifar10/models.sh index 8d64d588..e8e0944f 100644 --- a/examples/pytorch/cifar10/models.sh +++ b/examples/pytorch/cifar10/models.sh @@ -3,36 +3,32 @@ # This script is used to generate the models for the sklearn example. # # Default model -echo "python -m deckard.layers.optimise " $@ "--multirun" -python -m deckard.layers.optimise $@ --multirun +echo "python -m deckard.layers.optimise ++model.trainer.nb_epoch=1,10,30,50,100" $@ "--multirun" +python -m deckard.layers.optimise ++model.trainer.nb_epoch=1,10,30,50,100 $@ --multirun # # This line generates the model and adds the FeatureSqueezing preprocessing defence. -# python -m deckard.layers.optimise ++model.art.preprocessor.name=art.defences.preprocessor.FeatureSqueezing +model.art.preprocessor.params.bit_depth=4,8,16,32,64 +model.art.preprocessor.params.clip_values=[0,255] ++hydra.sweeper.study_name=FSQ $@ --multirun - -# # # Gaussian Augmentation (Input) -# python -m deckard.layers.optimise ++model.art.preprocessor.name=art.defences.preprocessor.GaussianAugmentation +model.art.preprocessor.params.sigma=.01,.1,.3,.5,1 +model.art.preprocessor.params.ratio=.5 +model.art.preprocessor.params.augmentation=False ++hydra.sweeper.study_name=gauss-in $@ --multirun - -# # # # Gaussian Noise (Output) -# python -m deckard.layers.optimise ++model.art.postprocessor.name=art.defences.postprocessor.GaussianNoise ++model.art.postprocessor.params.scale=.01,.1,.3,.5,1 ++hydra.sweeper.study_name=gauss-out $@ --multirun - -# # # # High Confidence -# python -m deckard.layers.optimise +model.art.postprocessor.name=art.defences.postprocessor.HighConfidence +model.art.postprocessor.params.cutoff=.1,.3,.5,.9,.99 ++hydra.sweeper.study_name=conf $@ --multirun -#!/bin/bash - -# This script is used to generate the models for the sklearn example. - -# # Default model -echo "python -m deckard.layers.optimise " $@ "--multirun" -python -m deckard.layers.optimise $@ --multirun - -# # This line generates the model and adds the FeatureSqueezing preprocessing defence. -# python -m deckard.layers.optimise ++model.art.preprocessor.name=art.defences.preprocessor.FeatureSqueezing +model.art.preprocessor.params.bit_depth=4,8,16,32,64 +model.art.preprocessor.params.clip_values=[0,255] ++hydra.sweeper.study_name=FSQ $@ --multirun - -# # # Gaussian Augmentation (Input) -# python -m deckard.layers.optimise ++model.art.preprocessor.name=art.defences.preprocessor.GaussianAugmentation +model.art.preprocessor.params.sigma=.01,.1,.3,.5,1 +model.art.preprocessor.params.ratio=.5 +model.art.preprocessor.params.augmentation=False ++hydra.sweeper.study_name=gauss-in $@ --multirun - -# # # # Gaussian Noise (Output) -# python -m deckard.layers.optimise ++model.art.postprocessor.name=art.defences.postprocessor.GaussianNoise ++model.art.postprocessor.params.scale=.01,.1,.3,.5,1 ++hydra.sweeper.study_name=gauss-out $@ --multirun - -# # # # High Confidence -# python -m deckard.layers.optimise +model.art.postprocessor.name=art.defences.postprocessor.HighConfidence +model.art.postprocessor.params.cutoff=.1,.3,.5,.9,.99 ++hydra.sweeper.study_name=conf $@ --multirun +# python -m deckard.layers.optimise \ +# ++model.art.preprocessor.name=art.defences.preprocessor.FeatureSqueezing \ +# +model.art.preprocessor.params.bit_depth=4,8,16,32,64 \ +# +model.art.preprocessor.params.clip_values=[0,255] \ +# ++hydra.sweeper.study_name=FSQ $@ --multirun + +# # # # Gaussian Augmentation (Input) +# python -m deckard.layers.optimise \ +# ++model.art.preprocessor.name=art.defences.preprocessor.GaussianAugmentation \ +# +model.art.preprocessor.params.sigma=.01,.1,.3,.5,1 \ +# +model.art.preprocessor.params.ratio=.5 \ +# +model.art.preprocessor.params.augmentation=False \ +# ++hydra.sweeper.study_name=gauss-in $@ --multirun + +# # # # # Gaussian Noise (Output) +# python -m deckard.layers.optimise \ +# ++model.art.postprocessor.name=art.defences.postprocessor.GaussianNoise \ +# ++model.art.postprocessor.params.scale=.01,.1,.3,.5,1 \ +# ++hydra.sweeper.study_name=gauss-out $@ --multirun + +# # # # # High Confidence +# python -m deckard.layers.optimise \ +# +model.art.postprocessor.name=art.defences.postprocessor.HighConfidence \ +# +model.art.postprocessor.params.cutoff=.1,.3,.5,.9,.99 \ +# ++hydra.sweeper.study_name=conf $@ --multirun diff --git a/examples/pytorch/cifar100/.dvc/config b/examples/pytorch/cifar100/.dvc/config index e69de29b..4cf322d9 100644 --- a/examples/pytorch/cifar100/.dvc/config +++ b/examples/pytorch/cifar100/.dvc/config @@ -0,0 +1,2 @@ +[core] + autostage = true diff --git a/examples/pytorch/cifar100/conf/afr.yaml b/examples/pytorch/cifar100/conf/afr.yaml index af0b6cbc..a2f65dc9 100644 --- a/examples/pytorch/cifar100/conf/afr.yaml +++ b/examples/pytorch/cifar100/conf/afr.yaml @@ -1,17 +1,20 @@ covariates: + - "adv_fit_time" - "accuracy" - "train_time" - - "predict_time" - "atk_value" - "def_value" - "data.sample.random_state" - - "adv_failure_rate" - "model_layers" - - "adv_fit_time" - - "model.trainer.kwargs.nb_epoch" + - model.trainer.nb_epoch + - predict_time +# - atk_gen +# - def_gen +fillna: + model.trainer.nb_epoch: 20 weibull: plot: - file : weibull_aft.pdf + file : weibull_aft.eps title : Weibull AFR Model labels: "Intercept: rho_": "$\\rho$" @@ -28,78 +31,94 @@ weibull: "model.trainer.nb_epoch: lambda_": "No. of Epochs" "model.trainer.batch_size: lambda_": "Batch Size" "def_gen": "Defence" + "model_layers: lambda_" : "Layers" + "def_value: lambda_" : "Defence Strength" + "predict_time: lambda_" : "$t_{predict}$" partial_effect: - - "file": "weibull_epochs_partial_effect.pdf" - "covariate_array": "model.trainer.kwargs.nb_epoch" - "values_array": [1,10,25,50] - "title": "$S(t)$ for Weibull AFR" - "ylabel": "Expectation of $S(t)$" - "xlabel": "Time $T$ (seconds)" - "legend_kwargs": { - "title": "Epochs", - "labels": ["1", "10", "25", "50"] - } -cox: - plot: - file : cox_aft.pdf - title : Cox AFR Model - labels: - "Intercept: rho_": "$\\rho$" - "Intercept: lambda_": "$\\lambda$" - "data.sample.random_state: lambda_": "Random State" - "atk_value: lambda_": "Attack Strength" - "train_time: lambda_": "$t_{train}$" - "predict_proba_time: lambda_": "$t_{predict}$" - "adv_accuracy: lambda_": "Adv. Accuracy" - "accuracy: lambda_": "Ben. Accuracy" - "adv_fit_time: lambda_": "$t_{attack}$" - "adv_failure_rate: lambda_": "$h_{adv.}(t;\\theta)$" - "failure_rate: lambda_": "$h_{ben.}(t;\\theta)$" - "model.trainer.nb_epoch: lambda_": "No. of Epochs" - "model.trainer.batch_size: lambda_": "Batch Size" - "def_gen": "Defence" - partial_effect: - - "file": "cox_epochs_partial_effect.pdf" + - "file": "weibull_epochs_partial_effect.eps" "covariate_array": "model.trainer.nb_epoch" "values_array": [1,10,25,50] - "title": "$S(t)$ for Cox AFR" + "title": "$S(t)$ for Weibull AFR" "ylabel": "Expectation of $S(t)$" "xlabel": "Time $T$ (seconds)" "legend_kwargs": { "title": "Epochs", "labels": ["1", "10", "25", "50"] } - - "file": "cox_layers_partial_effect.pdf" - "covariate_array": "model.trainer.nb_epoch" + - "file": "weibull_layers_partial_effect.eps" + "covariate_array": "model_layers" "values_array": [18, 34, 50, 101, 152] - "title": "$S(t)$ for Cox AFR" + "title": "$S(t)$ for Weibull AFR" "ylabel": "Expectation of $S(t)$" "xlabel": "Time $T$ (seconds)" "legend_kwargs": { - "title": "ResNet Layers", + "title": "Layers", "labels": ["18", "34", "50", "101", "152"] } +# cox: +# plot: +# file : cox_aft.eps +# title : Cox AFR Model +# labels: +# "Intercept: rho_": "$\\rho$" +# "Intercept: lambda_": "$\\lambda$" +# "data.sample.random_state: lambda_": "Random State" +# "atk_value: lambda_": "Attack Strength" +# "train_time: lambda_": "$t_{train}$" +# "predict_proba_time: lambda_": "$t_{predict}$" +# "adv_accuracy: lambda_": "Adv. Accuracy" +# "accuracy: lambda_": "Ben. Accuracy" +# "adv_fit_time: lambda_": "$t_{attack}$" +# "adv_failure_rate: lambda_": "$h_{adv.}(t;\\theta)$" +# "failure_rate: lambda_": "$h_{ben.}(t;\\theta)$" +# "model.trainer.nb_epoch: lambda_": "No. of Epochs" +# "model.trainer.batch_size: lambda_": "Batch Size" +# "def_gen": "Defence" +# partial_effect: +# - "file": "cox_epochs_partial_effect.eps" +# "covariate_array": "model.trainer.nb_epoch" +# "values_array": [1,10,25,50] +# "title": "$S(t)$ for Cox AFR" +# "ylabel": "Expectation of $S(t)$" +# "xlabel": "Time $T$ (seconds)" +# "legend_kwargs": { +# "title": "Epochs", +# "labels": ["1", "10", "25", "50"] +# } +# - "file": "cox_layers_partial_effect.eps" +# "covariate_array": "model_layers" +# "values_array": [18, 34, 50, 101, 152] +# "title": "$S(t)$ for Cox AFR" +# "ylabel": "Expectation of $S(t)$" +# "xlabel": "Time $T$ (seconds)" +# "legend_kwargs": { +# "title": "Layers", +# "labels": ["18", "34", "50", "101", "152"] +# } log_logistic: plot: - file : log_logistic_aft.pdf + file : log_logistic_aft.eps title : Log logistic AFR Model labels: - "Intercept: rho_": "$\\rho$" - "Intercept: lambda_": "$\\lambda$" - "data.sample.random_state: lambda_": "Random State" - "atk_value: lambda_": "Attack Strength" - "train_time: lambda_": "$t_{train}$" - "predict_proba_time: lambda_": "$t_{predict}$" - "adv_accuracy: lambda_": "Adv. Accuracy" - "accuracy: lambda_": "Ben. Accuracy" - "adv_fit_time: lambda_": "$t_{attack}$" - "adv_failure_rate: lambda_": "$h_{adv.}(t;\\theta)$" - "failure_rate: lambda_": "$h_{ben.}(t;\\theta)$" - "model.trainer.nb_epoch: lambda_": "No. of Epochs" - "model.trainer.batch_size: lambda_": "Batch Size" + "Intercept: beta_": "$\\beta$" + "Intercept: alpha_": "$\\alpha$" + "data.sample.random_state: alpha_": "Random State" + "atk_value: alpha_": "Attack Strength" + "train_time: alpha_": "$t_{train}$" + "predict_proba_time: alpha_": "$t_{predict}$" + "adv_accuracy: alpha_": "Adv. Accuracy" + "accuracy: alpha_": "Ben. Accuracy" + "adv_fit_time: alpha_": "$t_{attack}$" + "adv_failure_rate: alpha_": "$h_{adv.}(t;\\theta)$" + "failure_rate: alpha_": "$h_{ben.}(t;\\theta)$" + "model.trainer.nb_epoch: alpha_": "No. of Epochs" + "model.trainer.batch_size: alpha_": "Batch Size" "def_gen": "Defence" + "model_layers: alpha_" : "Layers" + "def_value: alpha_" : "Defence Strength" + "predict_time: alpha_" : "$t_{predict}$" partial_effect: - - "file": "log_logistic_epochs_partial_effect.pdf" + - "file": "log_logistic_epochs_partial_effect.eps" "covariate_array": "model.trainer.nb_epoch" "values_array": [1,10,25,50] "title": "$S(t)$ for Log-Logistic AFR" @@ -109,27 +128,40 @@ log_logistic: "title": "Epochs", "labels": ["1", "10", "25", "50"] } + - "file": "log_logistic_layers_partial_effect.eps" + "covariate_array": "model_layers" + "values_array": [18, 34, 50, 101, 152] + "title": "$S(t)$ for Log Logistic AFR" + "ylabel": "Expectation of $S(t)$" + "xlabel": "Time $T$ (seconds)" + "legend_kwargs": { + "title": "Layers", + "labels": ["18", "34", "50", "101", "152"] + } log_normal: plot: - file : log_normal_aft.pdf + file : log_normal_aft.eps title : Log Normal AFR Model labels: - "Intercept: rho_": "$\\rho$" - "Intercept: lambda_": "$\\lambda$" - "data.sample.random_state: lambda_": "Random State" - "atk_value: lambda_": "Attack Strength" - "train_time: lambda_": "$t_{train}$" - "predict_proba_time: lambda_": "$t_{predict}$" - "adv_accuracy: lambda_": "Adv. Accuracy" - "accuracy: lambda_": "Ben. Accuracy" - "adv_fit_time: lambda_": "$t_{attack}$" - "adv_failure_rate: lambda_": "$h_{adv.}(t;\\theta)$" - "failure_rate: lambda_": "$h_{ben.}(t;\\theta)$" - "model.trainer.nb_epoch: lambda_": "No. of Epochs" - "model.trainer.batch_size: lambda_": "Batch Size" + "Intercept: sigma_": "$\\rho$" + "Intercept: mu_": "$\\mu$" + "data.sample.random_state: mu_": "Random State" + "atk_value: mu_": "Attack Strength" + "train_time: mu_": "$t_{train}$" + "predict_proba_time: mu_": "$t_{predict}$" + "adv_accuracy: mu_": "Adv. Accuracy" + "accuracy: mu_": "Ben. Accuracy" + "adv_fit_time: mu_": "$t_{attack}$" + "adv_failure_rate: mu_": "$h_{adv.}(t;\\theta)$" + "failure_rate: mu_": "$h_{ben.}(t;\\theta)$" + "model.trainer.nb_epoch: mu_": "No. of Epochs" + "model.trainer.batch_size: mu_": "Batch Size" "def_gen": "Defence" + "model_layers: mu_" : "Layers" + "def_value: mu_" : "Defence Strength" + "predict_time: mu_" : "$t_{predict}$" partial_effect: - - "file": "log_normal_epochs_partial_effect.pdf" + - "file": "log_normal_epochs_partial_effect.eps" "covariate_array": "model.trainer.nb_epoch" "values_array": [1,10,25,50] "title": "$S(t)$ for Log-Normal AFR" @@ -139,3 +171,14 @@ log_normal: "title": "Epochs", "labels": ["1", "10", "25", "50"] } + - "file": "log_normal_layers_partial_effect.eps" + "covariate_array": "model_layers" + "values_array": [18, 34, 50, 101, 152] + "title": "$S(t)$ for Log Normal AFR" + "ylabel": "Expectation of $S(t)$" + "xlabel": "Time $T$ (seconds)" + "legend_kwargs": { + "title": "Layers", + "labels": ["18", "34", "50", "101", "152"], + "bbox_to_anchor": [1.05, 1], + } diff --git a/examples/pytorch/cifar100/conf/cifar100.yaml b/examples/pytorch/cifar100/conf/cifar100.yaml index 7a7c9b41..4f9da157 100644 --- a/examples/pytorch/cifar100/conf/cifar100.yaml +++ b/examples/pytorch/cifar100/conf/cifar100.yaml @@ -25,7 +25,7 @@ hydra: study_name: control storage: sqlite:///model.db n_jobs: 4 - n_trials : 32 + n_trials : 10 params: ++data.sample.random_state: choice(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) ++model.art.initialize.optimizer.lr: choice(10, 1, 0.1, 0.01, 0.001, .0001, .00001, 0.000001) diff --git a/examples/pytorch/cifar100/conf/clean.yaml b/examples/pytorch/cifar100/conf/clean.yaml index f33ce91f..52f6c912 100644 --- a/examples/pytorch/cifar100/conf/clean.yaml +++ b/examples/pytorch/cifar100/conf/clean.yaml @@ -7,11 +7,11 @@ attacks: ThresholdAttack: Thresh defences: Control: Control - # FeatureSqueezing: FSQ - # GaussianAugmentation: Gauss-in - # GaussianNoise: Gauss-out - # HighConfidence: Conf - nb_epoch: Epochs + FeatureSqueezing: FSQ + GaussianAugmentation: Gauss-in + GaussianNoise: Gauss-out + HighConfidence: Conf + nb_epoch : Epochs model_layers: Control params: Deep: attack.init.nb_grads @@ -20,11 +20,15 @@ params: Pixel: attack.init.th PGD: attack.init.eps Thresh: attack.init.th - Gauss-out: model.art.pipeline.postprocessor.scale - Conf: model.art.pipeline.postprocessor.cutoff - FSQ: model.art.pipeline.preprocessor.bit_depth - Gauss-in: model.art.pipeline.preprocessor.sigma + Gauss-out: model.art.postprocessor.params.scale + Conf: model.art.postprocessor.params.cutoff + FSQ: model.art.preprocessor.params.bit_depth + Gauss-in: model.art.preprocessor.params.sigma Control: model_layers Epochs: model.trainer.nb_epoch + control: + model_layers: 18 + defaults: + Epochs: 10 fillna: - Epochs: 20 + Epochs: 10 diff --git a/examples/pytorch/cifar100/conf/compile.yaml b/examples/pytorch/cifar100/conf/compile.yaml deleted file mode 100644 index 1314aceb..00000000 --- a/examples/pytorch/cifar100/conf/compile.yaml +++ /dev/null @@ -1,33 +0,0 @@ -attacks: - # CarliniL0Method: CW_0 - # CarliniL2Method: CW_2 - # CarliniLInfMethod: CW_inf - DeepFool: Deep - FastGradientMethod: FGM - HopSkipJump: HSJ - PixelAttack: Pixel - ProjectedGradientDescent: PGD - ThresholdAttack: Thresh -defences: - Control: Control - FeatureSqueezing: FSQ - GaussianAugmentation: Gauss-in - GaussianNoise: Gauss-out - HighConfidence: Conf - Epochs: Epochs -params: - # art.attacks.evasion.CarliniL0Method: attack.init.confidence - # art.attacks.evasion.CarliniL2Method: attack.init.confidence - # art.attacks.evasion.CarliniLInfMethod: attack.init.confidence - Deep: attack.init.nb_grads - FGM: attack.init.eps - HSJ: attack.init.max_iter - Pixel: attack.init.th - PGD: attack.init.eps - Thresh: attack.init.th - Gauss-out: model.art.pipeline.postprocessor.scale - Conf: model.art.pipeline.postprocessor.cutoff - FSQ: model.art.pipeline.preprocessor.bit_depth - Gauss-in: model.art.pipeline.preprocessor.sigma - Control: model_layers - Epochs: model.trainer.nb_epoch diff --git a/examples/pytorch/cifar100/conf/plots.yaml b/examples/pytorch/cifar100/conf/plots.yaml index 464f53b3..f68955fc 100644 --- a/examples/pytorch/cifar100/conf/plots.yaml +++ b/examples/pytorch/cifar100/conf/plots.yaml @@ -1,5 +1,5 @@ cat_plot: -- file: adv_accuracy_vs_defence_type.pdf +- file: adv_accuracy_vs_defence_type.eps hue: model_name kind: boxen set: @@ -16,7 +16,7 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: ben_accuracy_vs_defence_type.pdf +- file: ben_accuracy_vs_defence_type.eps hue: model_name kind: boxen titles: Ben. Accuracy vs Defence Type @@ -31,7 +31,7 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: ben_failures_per_train_time_vs_defence_type.pdf +- file: ben_failures_per_train_time_vs_defence_type.eps hue: model_name kind: boxen set: @@ -48,7 +48,7 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: adv_failures_per_train_time_vs_defence_type.pdf +- file: adv_failures_per_train_time_vs_defence_type.eps hue: model_name kind: boxen set: @@ -65,7 +65,7 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: adv_failures_per_train_time_vs_attack_type.pdf +- file: adv_failures_per_train_time_vs_attack_type.eps hue: model_name kind: boxen legend_title: Model Name @@ -83,15 +83,15 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: adv_failures_per_test_time_vs_defence_type.pdf +- file: adv_failures_per_test_time_vs_defence_type.eps hue: model_name kind: boxen legend_title: Model Name - titles: $h_{adv}$ vs Defence Type + titles: $f_{adv}$ vs Defence Type x: def_gen xlabels: Defence Type y: adv_failure_rate - ylabels: $h_{adv.}$ + ylabels: $f_{adv.}$ rotation : 90 hue_order: - ResNet18 @@ -99,23 +99,7 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: adv_accuracy_vs_defence_type.pdf - hue: model_name - kind: boxen - legend_title: Model Name - titles: Adv. Accuracy vs Defence Type - x: def_gen - xlabels: Defence Type - y: adv_accuracy - ylabels: Adv. Ben. Accuracy - rotation : 90 - hue_order: - - ResNet18 - - ResNet34 - - ResNet50 - - ResNet101 - - ResNet152 -- file: adv_accuracy_vs_attack_type.pdf +- file: adv_accuracy_vs_attack_type.eps hue: model_name kind: boxen legend_title: Model Name @@ -131,17 +115,17 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: ben_failure_rate_vs_defence_type.pdf +- file: ben_failure_rate_vs_defence_type.eps hue: model_name kind: boxen legend_title: Model Name set: yscale: log - titles: $h_{ben}(t; \theta)$ vs Defence Type + titles: $f_{ben}(t; \theta)$ vs Defence Type x: def_gen xlabels: Defence Type y: failure_rate - ylabels: $h_{ben}(t; \theta)$ + ylabels: $f_{ben}(t; \theta)$ rotation : 90 hue_order: - ResNet18 @@ -150,7 +134,7 @@ cat_plot: - ResNet101 - ResNet152 line_plot: -- file: def_param_vs_accuracy.pdf +- file: def_param_vs_accuracy.eps hue: def_gen legend: {"bbox_to_anchor": [1.05, 1], "title": "Defence"} title: Ben. Accuracy vs Defence Strength @@ -160,15 +144,17 @@ line_plot: y: accuracy y_scale: ylabel: Ben. Accuracy - # hue_order: - # - Control - # - Conf - # - Epochs - # - Gauss-in - # - Gauss-out - # - Conf - # - FSQ -- file: def_param_vs_adv_accuracy.pdf + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars +- file: def_param_vs_adv_accuracy.eps hue: def_gen legend: {"bbox_to_anchor": [1.05, 1], "title": "Defence"} title: Adv. Accuracy vs Defence Strength @@ -178,33 +164,37 @@ line_plot: y: adv_accuracy y_scale: ylabel: Adv. Accuracy - # hue_order: - # - Control - # - Conf - # - Epochs - # - Gauss-in - # - Gauss-out - # - Conf - # - FSQ -- file: def_param_vs_adv_failure_rate.pdf + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars +- file: def_param_vs_adv_failure_rate.eps hue: def_gen legend: {"bbox_to_anchor": [1.05, 1], "title": "Defence"} - title: $h_{adv}$ vs Defence Strength + title: $f_{adv}$ vs Defence Strength x: def_value - x_scale: linear + x_scale: log xlabel: Defence Control Parameter y: adv_failure_rate y_scale: log - ylabel: $h_{adv.}$ - # hue_order: - # - Control - # - Conf - # - Epochs - # - Gauss-in - # - Gauss-out - # - Conf - # - FSQ -- file: atk_param_vs_accuracy.pdf + ylabel: $f_{adv.}$ + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars +- file: atk_param_vs_accuracy.eps hue: atk_gen legend: {bbox_to_anchor: [1.05, 1]} title: Adv. Accuracy vs Attack Strength @@ -221,16 +211,17 @@ line_plot: - HSJ - Pixel - Thresh - + errorbar: se + err_style: bars scatter_plot: - x: train_time_per_sample y: adv_failure_rate hue: model_name xlabel: $t_{train}$ - ylabel: $h_{adv}$ - title: $h_{adv}$ vs $t_{train}$ - file: adv_failure_rate_vs_train_time.pdf - y_scale: log + ylabel: $f_{adv}$ + title: $f_{adv}$ vs $t_{train}$ + file: adv_failure_rate_vs_train_time.eps + y_scale: linear x_scale: log legend: title: Model Name diff --git a/examples/pytorch/cifar100/dvc.lock b/examples/pytorch/cifar100/dvc.lock index 22f99534..70bd1857 100644 --- a/examples/pytorch/cifar100/dvc.lock +++ b/examples/pytorch/cifar100/dvc.lock @@ -1,387 +1,598 @@ schema: '2.0' stages: - train: - cmd: python -m deckard.layers.experiment train --config_file cifar100.yaml + clean@attack: + cmd: python -m deckard.layers.clean_data -i cifar100/reports/attack.csv -o cifar100/reports/clean_attack.csv + -c conf/clean.yaml + deps: + - path: cifar100/reports/attack.csv + md5: e1e1b67a591afdb5c9ea8f35003e5394 + size: 36167864 params: params.yaml: - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar100 - path: original_data - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - files: - _target_: deckard.base.files.FileConfig - adv_predictions_file: adv_predictions.json - attack_dir: attacks - attack_file: attack - attack_type: .pkl - data_dir: data - data_file: data - data_type: .pkl - directory: cifar100 - model_dir: models - model_file: model - model_type: .pt - name: default - params_file: params.yaml - predictions_file: predictions.json - reports: reports - score_dict_file: score_dict.json - model: - _target_: deckard.base.model.Model - art: - _target_: deckard.base.model.art_pipeline.ArtPipeline - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar100 - path: original_data - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - initialize: - clip_values: - - 0 - - 255 - criterion: - name: torch.nn.CrossEntropyLoss - optimizer: - lr: 0.01 - momentum: 0.9 - name: torch.optim.SGD - library: pytorch - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar100 - path: original_data - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - init: - _target_: deckard.base.model.ModelInitializer - name: torch_example.ResNet18 - num_channels: 3 - num_classes: 100 - library: pytorch - trainer: - batch_size: 1024 - nb_epoch: 10 - scorers: - _target_: deckard.base.scorer.ScorerDict - accuracy: - _target_: deckard.base.scorer.ScorerConfig - direction: maximize - name: sklearn.metrics.accuracy_score - log_loss: - _target_: deckard.base.scorer.ScorerConfig - direction: minimize - name: sklearn.metrics.log_loss + files.directory: cifar100 + files.reports: reports + conf/clean.yaml: + attacks: + DeepFool: Deep + FastGradientMethod: FGM + HopSkipJump: HSJ + PixelAttack: Pixel + ProjectedGradientDescent: PGD + ThresholdAttack: Thresh + defences: + Control: Control + FeatureSqueezing: FSQ + GaussianAugmentation: Gauss-in + GaussianNoise: Gauss-out + HighConfidence: Conf + nb_epoch: Epochs + model_layers: Control + fillna: + Epochs: 10 + params: + Deep: attack.init.nb_grads + FGM: attack.init.eps + HSJ: attack.init.max_iter + Pixel: attack.init.th + PGD: attack.init.eps + Thresh: attack.init.th + Gauss-out: model.art.postprocessor.params.scale + Conf: model.art.postprocessor.params.cutoff + FSQ: model.art.preprocessor.params.bit_depth + Gauss-in: model.art.preprocessor.params.sigma + Control: model_layers + Epochs: model.trainer.nb_epoch + control: + model_layers: 18 + defaults: + Epochs: 10 outs: - - path: cifar100/reports/train/default/predictions.json - md5: aeaec96d96a661f5185062898e19fd0d - size: 24404547 - - path: cifar100/reports/train/default/score_dict.json - md5: f3070a3adef622cd7899e813660957a8 - size: 898 - attack: - cmd: python -m deckard.layers.experiment attack --config_file cifar100.yaml + - path: cifar100/reports/clean_attack.csv + md5: 1e74314d258faf3aa6cd57f4f0aee4d4 + size: 30258589 + afr: + cmd: python -m deckard.layers.afr --dataset cifar100 --data_file cifar100/reports/clean_attack.csv --target + adv_accuracy --duration_col predict_time --dataset cifar100 --config_file conf/afr.yaml + --plots_folder cifar100/plots/ deps: - - path: cifar100/reports/train/default/predictions.json - md5: aeaec96d96a661f5185062898e19fd0d - size: 24404547 + - path: cifar100/reports/clean_attack.csv + md5: 1e74314d258faf3aa6cd57f4f0aee4d4 + size: 30258589 params: params.yaml: - attack: - _target_: deckard.base.attack.Attack - attack_size: 10 - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar100 - path: original_data - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - init: - _target_: deckard.base.attack.AttackInitializer - model: - _target_: deckard.base.model.Model - art: - _target_: deckard.base.model.art_pipeline.ArtPipeline - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar100 - path: original_data - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - initialize: - clip_values: - - 0 - - 255 - criterion: - name: torch.nn.CrossEntropyLoss - optimizer: - lr: 0.01 - momentum: 0.9 - name: torch.optim.SGD - library: pytorch - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar100 - path: original_data - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - init: - _target_: deckard.base.model.ModelInitializer - name: torch_example.ResNet18 - num_channels: 3 - num_classes: 100 - library: pytorch - trainer: - batch_size: 1024 - nb_epoch: 10 - name: art.attacks.evasion.HopSkipJump - method: evasion - model: - _target_: deckard.base.model.Model - art: - _target_: deckard.base.model.art_pipeline.ArtPipeline - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar100 - path: original_data - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - initialize: - clip_values: - - 0 - - 255 - criterion: - name: torch.nn.CrossEntropyLoss - optimizer: - lr: 0.01 - momentum: 0.9 - name: torch.optim.SGD - library: pytorch - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar100 - path: original_data - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - init: - _target_: deckard.base.model.ModelInitializer - name: torch_example.ResNet18 - num_channels: 3 - num_classes: 100 - library: pytorch - trainer: - batch_size: 1024 - nb_epoch: 10 - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar100 - path: original_data - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - files: - _target_: deckard.base.files.FileConfig - adv_predictions_file: adv_predictions.json - attack_dir: attacks - attack_file: attack - attack_type: .pkl - data_dir: data - data_file: data - data_type: .pkl - directory: cifar100 - model_dir: models - model_file: model - model_type: .pt - name: default - params_file: params.yaml - predictions_file: predictions.json - reports: reports - score_dict_file: score_dict.json - model: - _target_: deckard.base.model.Model - art: - _target_: deckard.base.model.art_pipeline.ArtPipeline - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar100 - path: original_data - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - initialize: - clip_values: - - 0 - - 255 - criterion: - name: torch.nn.CrossEntropyLoss - optimizer: - lr: 0.01 - momentum: 0.9 - name: torch.optim.SGD - library: pytorch - data: - _target_: deckard.base.data.Data - generate: - name: torch_cifar100 - path: original_data - sample: - random_state: 0 - stratify: true - sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - init: - _target_: deckard.base.model.ModelInitializer - name: torch_example.ResNet18 - num_channels: 3 - num_classes: 100 - library: pytorch - trainer: - batch_size: 1024 - nb_epoch: 10 - scorers: - _target_: deckard.base.scorer.ScorerDict - accuracy: - _target_: deckard.base.scorer.ScorerConfig - direction: maximize - name: sklearn.metrics.accuracy_score - log_loss: - _target_: deckard.base.scorer.ScorerConfig - direction: minimize - name: sklearn.metrics.log_loss - outs: - - path: cifar100/attacks/attack.pkl - md5: 5317760d3c6f266ece07523e98517d46 - size: 123046 - - path: cifar100/reports/attack/default/adv_predictions.json - md5: 18a846aed49541df9c48131c8f8ebc91 - size: 21453 - - path: cifar100/reports/attack/default/score_dict.json - md5: e7b9599098942b56f82f1f66c1c53280 - size: 1166 - attacks@ResNet18: - cmd: bash attacks.sh ++attack.attack_size=100 ++model.init.name=torch_example.ResNet18 - stage=attack ++hydra.sweeper.storage=sqlite:///cifar100/reports/attack/ResNet18.db - --config-name cifar100.yaml - deps: - - path: attacks.sh - md5: d78e6d6b697480fbccfb58bd791af506 - size: 2897 - - path: cifar100/reports/attack/default/score_dict.json - md5: 5d129878ac159ae1b3dbd9b135511973 - size: 1172 - - path: models.sh - md5: d477bb16f5082498a19285ded1a782e5 - size: 1522 + files.directory: cifar100 + conf/afr.yaml: + covariates: + - adv_fit_time + - accuracy + - train_time + - atk_value + - def_value + - data.sample.random_state + - model_layers + - model.trainer.nb_epoch + - predict_time + log_logistic: + plot: + file: log_logistic_aft.eps + title: Log logistic AFR Model + labels: + 'Intercept: beta_': $\beta$ + 'Intercept: alpha_': $\alpha$ + 'data.sample.random_state: alpha_': Random State + 'atk_value: alpha_': Attack Strength + 'train_time: alpha_': $t_{train}$ + 'predict_proba_time: alpha_': $t_{predict}$ + 'adv_accuracy: alpha_': Adv. Accuracy + 'accuracy: alpha_': Ben. Accuracy + 'adv_fit_time: alpha_': $t_{attack}$ + 'adv_failure_rate: alpha_': $h_{adv.}(t;\theta)$ + 'failure_rate: alpha_': $h_{ben.}(t;\theta)$ + 'model.trainer.nb_epoch: alpha_': No. of Epochs + 'model.trainer.batch_size: alpha_': Batch Size + def_gen: Defence + 'model_layers: alpha_': Layers + 'def_value: alpha_': Defence Strength + 'predict_time: alpha_': $t_{predict}$ + partial_effect: + - file: log_logistic_epochs_partial_effect.eps + covariate_array: model.trainer.nb_epoch + values_array: + - 1 + - 10 + - 25 + - 50 + title: $S(t)$ for Log-Logistic AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Epochs + labels: + - '1' + - '10' + - '25' + - '50' + - file: log_logistic_layers_partial_effect.eps + covariate_array: model_layers + values_array: + - 18 + - 34 + - 50 + - 101 + - 152 + title: $S(t)$ for Log Logistic AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Layers + labels: + - '18' + - '34' + - '50' + - '101' + - '152' + log_normal: + plot: + file: log_normal_aft.eps + title: Log Normal AFR Model + labels: + 'Intercept: sigma_': $\rho$ + 'Intercept: mu_': $\mu$ + 'data.sample.random_state: mu_': Random State + 'atk_value: mu_': Attack Strength + 'train_time: mu_': $t_{train}$ + 'predict_proba_time: mu_': $t_{predict}$ + 'adv_accuracy: mu_': Adv. Accuracy + 'accuracy: mu_': Ben. Accuracy + 'adv_fit_time: mu_': $t_{attack}$ + 'adv_failure_rate: mu_': $h_{adv.}(t;\theta)$ + 'failure_rate: mu_': $h_{ben.}(t;\theta)$ + 'model.trainer.nb_epoch: mu_': No. of Epochs + 'model.trainer.batch_size: mu_': Batch Size + def_gen: Defence + 'model_layers: mu_': Layers + 'def_value: mu_': Defence Strength + 'predict_time: mu_': $t_{predict}$ + partial_effect: + - file: log_normal_epochs_partial_effect.eps + covariate_array: model.trainer.nb_epoch + values_array: + - 1 + - 10 + - 25 + - 50 + title: $S(t)$ for Log-Normal AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Epochs + labels: + - '1' + - '10' + - '25' + - '50' + - file: log_normal_layers_partial_effect.eps + covariate_array: model_layers + values_array: + - 18 + - 34 + - 50 + - 101 + - 152 + title: $S(t)$ for Log Normal AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Layers + labels: + - '18' + - '34' + - '50' + - '101' + - '152' + bbox_to_anchor: + - 1.05 + - 1 + weibull: + plot: + file: weibull_aft.eps + title: Weibull AFR Model + labels: + 'Intercept: rho_': $\rho$ + 'Intercept: lambda_': $\lambda$ + 'data.sample.random_state: lambda_': Random State + 'atk_value: lambda_': Attack Strength + 'train_time: lambda_': $t_{train}$ + 'predict_proba_time: lambda_': $t_{predict}$ + 'adv_accuracy: lambda_': Adv. Accuracy + 'accuracy: lambda_': Ben. Accuracy + 'adv_fit_time: lambda_': $t_{attack}$ + 'adv_failure_rate: lambda_': $h_{adv.}(t;\theta)$ + 'failure_rate: lambda_': $h_{ben.}(t;\theta)$ + 'model.trainer.nb_epoch: lambda_': No. of Epochs + 'model.trainer.batch_size: lambda_': Batch Size + def_gen: Defence + 'model_layers: lambda_': Layers + 'def_value: lambda_': Defence Strength + 'predict_time: lambda_': $t_{predict}$ + partial_effect: + - file: weibull_epochs_partial_effect.eps + covariate_array: model.trainer.nb_epoch + values_array: + - 1 + - 10 + - 25 + - 50 + title: $S(t)$ for Weibull AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Epochs + labels: + - '1' + - '10' + - '25' + - '50' + - file: weibull_layers_partial_effect.eps + covariate_array: model_layers + values_array: + - 18 + - 34 + - 50 + - 101 + - 152 + title: $S(t)$ for Weibull AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Layers + labels: + - '18' + - '34' + - '50' + - '101' + - '152' outs: - - path: cifar100/reports/attack/ResNet18.db - md5: 2ba685aa1d1cd9ec621eb3a1b767a090 - size: 4087808 - attacks@ResNet34: - cmd: bash attacks.sh ++attack.attack_size=100 ++model.init.name=torch_example.ResNet34 - stage=attack ++hydra.sweeper.storage=sqlite:///cifar100/reports/attack/ResNet34.db - --config-name cifar100.yaml + - path: cifar100/plots/aft_comparison.csv + md5: 9c486aa8ca1b035f2d501971353760b0 + size: 381 + - path: cifar100/plots/aft_comparison.tex + md5: b8d8117defa391250aeaace7a9d0f31d + size: 420 + - path: cifar100/plots/log_logistic_aft.eps + md5: 25570be7c47838516dc2ce6737ea23cf + size: 43150 + - path: cifar100/plots/log_logistic_epochs_partial_effect.eps + md5: dce601a023295267b4219a3d344c6390 + size: 42195 + - path: cifar100/plots/log_logistic_layers_partial_effect.eps + md5: 422b035d3bffc50166597ad26e175400 + size: 43155 + - path: cifar100/plots/log_normal_aft.eps + md5: 2cf3e5852ca6cd9bee9aa66974db1ad7 + size: 44116 + - path: cifar100/plots/log_normal_epochs_partial_effect.eps + md5: 0cb86ef85c693118c8b6abc83a503ac3 + size: 42931 + - path: cifar100/plots/log_normal_layers_partial_effect.eps + md5: 4386a26119906fa28709501875c95660 + size: 43230 + - path: cifar100/plots/weibull_aft.eps + md5: 9509c6ffd09f15d01d411d76074695d3 + size: 41413 + - path: cifar100/plots/weibull_epochs_partial_effect.eps + md5: 65e05f0fee7247d061ce52014821d3dd + size: 41438 + - path: cifar100/plots/weibull_layers_partial_effect.eps + md5: 8903ae7d7c4fd97247d80abde3febaed + size: 42657 + plot: + cmd: python -m deckard.layers.plots --path cifar100/plots/ --file cifar100/reports/clean_attack.csv + -c conf/plots.yaml deps: - - path: attacks.sh - md5: d78e6d6b697480fbccfb58bd791af506 - size: 2897 - - path: cifar100/reports/attack/default/score_dict.json - md5: 5d129878ac159ae1b3dbd9b135511973 - size: 1172 - - path: models.sh - md5: d477bb16f5082498a19285ded1a782e5 - size: 1522 + - path: cifar100/reports/clean_attack.csv + md5: 1e74314d258faf3aa6cd57f4f0aee4d4 + size: 30258589 + params: + params.yaml: + files.directory: cifar100 + files.reports: reports + conf/plots.yaml: + cat_plot: + - file: adv_accuracy_vs_defence_type.eps + hue: model_name + kind: boxen + set: + yscale: linear + titles: Adv. Accuracy vs Defence Type + x: def_gen + xlabels: Defence Type + y: adv_accuracy + ylabels: Adv. Accuracy + rotation: 90 + hue_order: + - ResNet18 + - ResNet34 + - ResNet50 + - ResNet101 + - ResNet152 + - file: ben_accuracy_vs_defence_type.eps + hue: model_name + kind: boxen + titles: Ben. Accuracy vs Defence Type + x: def_gen + xlabels: Defence Type + y: accuracy + ylabels: Ben. Accuracy + rotation: 90 + hue_order: + - ResNet18 + - ResNet34 + - ResNet50 + - ResNet101 + - ResNet152 + - file: ben_failures_per_train_time_vs_defence_type.eps + hue: model_name + kind: boxen + set: + yscale: log + titles: $\bar{C}_{ben.}$ vs Defence Type + x: def_gen + xlabels: Defence Type + y: training_time_per_failure + ylabels: $\bar{C}_{ben.}$ + rotation: 90 + hue_order: + - ResNet18 + - ResNet34 + - ResNet50 + - ResNet101 + - ResNet152 + - file: adv_failures_per_train_time_vs_defence_type.eps + hue: model_name + kind: boxen + set: + yscale: log + titles: $\bar{C}_{adv.}$ vs Defence Type + x: def_gen + xlabels: Defence Type + y: training_time_per_adv_failure + ylabels: $\bar{C}_{adv.}$ + rotation: 90 + hue_order: + - ResNet18 + - ResNet34 + - ResNet50 + - ResNet101 + - ResNet152 + - file: adv_failures_per_train_time_vs_attack_type.eps + hue: model_name + kind: boxen + legend_title: Model Name + set: + yscale: log + titles: $\bar{C}_{adv.}$ vs Attack Type + x: atk_gen + xlabels: Attack Type + y: training_time_per_adv_failure + ylabels: $\bar{C}_{adv.}$ + rotation: 90 + hue_order: + - ResNet18 + - ResNet34 + - ResNet50 + - ResNet101 + - ResNet152 + - file: adv_failures_per_test_time_vs_defence_type.eps + hue: model_name + kind: boxen + legend_title: Model Name + titles: $f_{adv}$ vs Defence Type + x: def_gen + xlabels: Defence Type + y: adv_failure_rate + ylabels: $f_{adv.}$ + rotation: 90 + hue_order: + - ResNet18 + - ResNet34 + - ResNet50 + - ResNet101 + - ResNet152 + - file: adv_accuracy_vs_attack_type.eps + hue: model_name + kind: boxen + legend_title: Model Name + titles: Adv. Accuracy vs Attack Type + x: atk_gen + xlabels: Attack Type + y: adv_accuracy + ylabels: Adv. Accuracy + rotation: 90 + hue_order: + - ResNet18 + - ResNet34 + - ResNet50 + - ResNet101 + - ResNet152 + - file: ben_failure_rate_vs_defence_type.eps + hue: model_name + kind: boxen + legend_title: Model Name + set: + yscale: log + titles: $f_{ben}(t; \theta)$ vs Defence Type + x: def_gen + xlabels: Defence Type + y: failure_rate + ylabels: $f_{ben}(t; \theta)$ + rotation: 90 + hue_order: + - ResNet18 + - ResNet34 + - ResNet50 + - ResNet101 + - ResNet152 + line_plot: + - file: def_param_vs_accuracy.eps + hue: def_gen + legend: + bbox_to_anchor: + - 1.05 + - 1 + title: Defence + title: Ben. Accuracy vs Defence Strength + x: def_value + x_scale: linear + xlabel: Defence Control Parameter + y: accuracy + y_scale: + ylabel: Ben. Accuracy + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars + - file: def_param_vs_adv_accuracy.eps + hue: def_gen + legend: + bbox_to_anchor: + - 1.05 + - 1 + title: Defence + title: Adv. Accuracy vs Defence Strength + x: def_value + x_scale: linear + xlabel: Defence Control Parameter + y: adv_accuracy + y_scale: + ylabel: Adv. Accuracy + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars + - file: def_param_vs_adv_failure_rate.eps + hue: def_gen + legend: + bbox_to_anchor: + - 1.05 + - 1 + title: Defence + title: $f_{adv}$ vs Defence Strength + x: def_value + x_scale: log + xlabel: Defence Control Parameter + y: adv_failure_rate + y_scale: log + ylabel: $f_{adv.}$ + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars + - file: atk_param_vs_accuracy.eps + hue: atk_gen + legend: + bbox_to_anchor: + - 1.05 + - 1 + title: Adv. Accuracy vs Attack Strength + x: atk_value + x_scale: linear + xlabel: Attack Control Parameter + y: adv_accuracy + y_scale: + ylabel: Adv. Accuracy + hue_order: + - FGM + - PGD + - Deep + - HSJ + - Pixel + - Thresh + errorbar: se + err_style: bars + scatter_plot: + - x: train_time_per_sample + y: adv_failure_rate + hue: model_name + xlabel: $t_{train}$ + ylabel: $f_{adv}$ + title: $f_{adv}$ vs $t_{train}$ + file: adv_failure_rate_vs_train_time.eps + y_scale: linear + x_scale: log + legend: + title: Model Name + bbox_to_anchor: + - 1.05 + - 1 + hue_order: + - ResNet18 + - ResNet34 + - ResNet50 + - ResNet101 + - ResNet152 outs: - - path: cifar100/reports/attack/ResNet34.db - md5: ed1216c4d9bbfa4f0b6e343783970074 - size: 3174400 - attacks@ResNet50: - cmd: bash attacks.sh ++attack.attack_size=100 ++model.init.name=torch_example.ResNet50 - stage=attack ++hydra.sweeper.storage=sqlite:///cifar100/reports/attack/ResNet50.db - --config-name cifar100.yaml + - path: cifar100/plots/adv_accuracy_vs_attack_type.eps + md5: c8da4b76e14a314a366460692dc783c5 + size: 110928 + - path: cifar100/plots/adv_accuracy_vs_defence_type.eps + md5: 28fc6c3ec076122c0817ff72bf445724 + size: 89728 + - path: cifar100/plots/adv_failure_rate_vs_train_time.eps + md5: 6b120de323dda22b1d1f7c865a3fee40 + size: 1197829 + - path: cifar100/plots/adv_failures_per_test_time_vs_defence_type.eps + md5: 992a14b470a5297898effaacef21da58 + size: 117343 + - path: cifar100/plots/adv_failures_per_train_time_vs_attack_type.eps + md5: da342b3a5f817de813e3831fb704a137 + size: 135357 + - path: cifar100/plots/adv_failures_per_train_time_vs_defence_type.eps + md5: 02573bd82b9a8e91f222b223265d4c88 + size: 110305 + - path: cifar100/plots/atk_param_vs_accuracy.eps + md5: 3a9ee8b1f8d7632d5e5346ee98fd7302 + size: 38228 + - path: cifar100/plots/ben_accuracy_vs_defence_type.eps + md5: a87ff0bfe4abeb62c8a11b14625094c6 + size: 100131 + - path: cifar100/plots/ben_failure_rate_vs_defence_type.eps + md5: 353409db77a5e01b3e1cace395724747 + size: 118669 + - path: cifar100/plots/ben_failures_per_train_time_vs_defence_type.eps + md5: c5b1247944a237ece405e2cc6d8d5f17 + size: 109170 + - path: cifar100/plots/def_param_vs_accuracy.eps + md5: a1d1bca25b228523ca3518e85407d9f9 + size: 38880 + - path: cifar100/plots/def_param_vs_adv_accuracy.eps + md5: 361afc1a730165a3c05d80ad16fe4c66 + size: 37677 + - path: cifar100/plots/def_param_vs_adv_failure_rate.eps + md5: cd8cc762d8541f690335ea6118eff227 + size: 41408 + copy_results: + cmd: mkdir -p ~/ml_afr/cifar100 && cp -r cifar100/plots/* ~/ml_afr/cifar100 deps: - - path: attacks.sh - md5: d78e6d6b697480fbccfb58bd791af506 - size: 2897 - - path: cifar100/reports/attack/default/score_dict.json - md5: 5d129878ac159ae1b3dbd9b135511973 - size: 1172 - - path: models.sh - md5: d477bb16f5082498a19285ded1a782e5 - size: 1522 - outs: - - path: cifar100/reports/attack/ResNet50.db - md5: 4915a611bc8eed14feb13e4e5fcf7bc1 - size: 2863104 + - path: cifar100/plots/ + md5: 5862826c5918c815b4814de0b1d5e53b.dir + size: 2876717 + nfiles: 27 diff --git a/examples/pytorch/cifar100/dvc.yaml b/examples/pytorch/cifar100/dvc.yaml index 140eff79..60c91cf5 100644 --- a/examples/pytorch/cifar100/dvc.yaml +++ b/examples/pytorch/cifar100/dvc.yaml @@ -4,7 +4,6 @@ vars: - conf/plots.yaml:cat_plot - conf/afr.yaml:covariates - conf/afr.yaml:weibull - - conf/afr.yaml:cox - conf/afr.yaml:log_logistic - conf/afr.yaml:log_normal - conf/clean.yaml:attacks @@ -20,7 +19,13 @@ stages: - scorers - files outs: + - ${files.directory}/${files.data_dir}/${files.data_file}${files.data_type} + - ${files.directory}/${files.model_dir}/${files.model_file}${files.model_type} + - ${files.directory}/${files.model_dir}/${files.model_file}.optimizer${files.model_type} + # - ${files.directory}/${files.reports}/train/${files.name}/${files.params_file} + # - ${files.directory}/${files.reports}/train/${files.name}/${files.test_labels_file} # Omit to save space - ${files.directory}/${files.reports}/train/${files.name}/${files.predictions_file} # logit outputs for our model + # - ${files.directory}/${files.reports}/train/${files.name}/${files.probabilities_file} # Omit to save space metrics: - ${files.directory}/${files.reports}/train/${files.name}/${files.score_dict_file} attack: @@ -34,25 +39,27 @@ stages: outs: - ${files.directory}/${files.attack_dir}/${files.attack_file}${files.attack_type} - ${files.directory}/${files.reports}/attack/${files.name}/${files.adv_predictions_file} + # - ${files.directory}/${files.reports}/attack/${files.name}/${files.params_file} deps: - - ${files.directory}/${files.reports}/train/${files.name}/${files.predictions_file} + - ${files.directory}/${files.data_dir}/${files.data_file}${files.data_type} + - ${files.directory}/${files.model_dir}/${files.model_file}${files.model_type} metrics: - ${files.directory}/${files.reports}/attack/${files.name}/${files.score_dict_file} ############################################################################## - # models: - # foreach: # This is a loop over the ResNet models + # models: # This is a loop over the ResNet models + # foreach: # - ResNet18 - # - ResNet34 - # - ResNet50 - # - ResNet101 - # - ResNet152 - # do: - # cmd: bash models.sh ++attack.attack_size=100 ++model.init.name=torch_example.${item} stage=train ++hydra.sweeper.storage=sqlite:///${files.directory}/${files.reports}/train/${item}.db --config-name cifar100.yaml + # # - ResNet34 + # # - ResNet50 + # # - ResNet101 + # # - ResNet152 + # do: # This script configures eazch defence + # cmd: bash models.sh ++model.init.name=torch_example.${item} stage=train ++hydra.sweeper.storage=sqlite:///${files.directory}/${files.reports}/train/${item}.db --config-name cifar100.yaml # deps: - # - models.sh # This script configures each defence - # - attacks.sh # This script configures each attack - # - ${files.directory}/${files.reports}/train/${files.name}/${files.score_dict_file} # This is here just to ensure it runs after the attack stage + # - models.sh + # - ${files.directory}/${files.model_dir}/${files.model_file}${files.model_type} + # - ${files.directory}/${files.model_dir}/${files.model_file}.optimizer${files.model_type} # outs: # - ${files.directory}/${files.reports}/train/${item}.db: # This outputs a database file for each model # cache: True @@ -121,7 +128,6 @@ stages: - ${files.directory}/plots/${cat_plot[5].file} - ${files.directory}/plots/${cat_plot[6].file} - ${files.directory}/plots/${cat_plot[7].file} - - ${files.directory}/plots/${cat_plot[8].file} - ${files.directory}/plots/${line_plot[0].file} - ${files.directory}/plots/${line_plot[1].file} - ${files.directory}/plots/${line_plot[2].file} @@ -135,18 +141,19 @@ stages: - scatter_plot - cat_plot afr: - cmd: python -m deckard.layers.afr --dataset ${files.directory} --data_file ${files.directory}/plots/clean_attack.csv --target adv_accuracy --duration_col adv_fit_time --dataset cifar100 --config_file conf/afr.yaml + cmd: python -m deckard.layers.afr --dataset ${files.directory} --data_file ${files.directory}/${files.reports}/clean_attack.csv --target adv_accuracy --duration_col predict_time --dataset cifar100 --config_file conf/afr.yaml --plots_folder ${files.directory}/plots/ deps: - - ${files.directory}/plots/clean_attack.csv + - ${files.directory}/${files.reports}/clean_attack.csv plots: - - ${files.directory}/plots/weibull_aft.pdf - - ${files.directory}/plots/weibull_partial_effects.pdf - - ${files.directory}/plots/cox_partial_effects.pdf - - ${files.directory}/plots/cox_aft.pdf - - ${files.directory}/plots/log_logistic_aft.pdf - - ${files.directory}/plots/log_logistic_partial_effects.pdf - - ${files.directory}/plots/log_normal_aft.pdf - - ${files.directory}/plots/log_normal_partial_effects.pdf + - ${files.directory}/plots/weibull_aft.eps + - ${files.directory}/plots/weibull_epochs_partial_effect.eps + - ${files.directory}/plots/weibull_layers_partial_effect.eps + - ${files.directory}/plots/log_logistic_aft.eps + - ${files.directory}/plots/log_logistic_epochs_partial_effect.eps + - ${files.directory}/plots/log_logistic_layers_partial_effect.eps + - ${files.directory}/plots/log_normal_aft.eps + - ${files.directory}/plots/log_normal_epochs_partial_effect.eps + - ${files.directory}/plots/log_normal_layers_partial_effect.eps metrics: - ${files.directory}/plots/aft_comparison.csv outs: @@ -156,10 +163,9 @@ stages: - conf/afr.yaml: - covariates - weibull - - cox - log_logistic - log_normal copy_results: - cmd: cp -r ${files.directory}/plots/* ~/ml_afr/cifar100 + cmd: mkdir -p ~/ml_afr/cifar100 && cp -r ${files.directory}/plots/* ~/ml_afr/cifar100 deps: - ${files.directory}/plots/ diff --git a/examples/pytorch/cifar100/models.sh b/examples/pytorch/cifar100/models.sh index da6eaee5..da7204d3 100644 --- a/examples/pytorch/cifar100/models.sh +++ b/examples/pytorch/cifar100/models.sh @@ -3,10 +3,10 @@ # This script is used to generate the models for the sklearn example. # # Default model -# echo "python -m deckard.layers.optimise ++model.trainer.nb_epoch:1,10,30,50,100" $@ "--multirun" -# python -m deckard.layers.optimise ++model.trainer.nb_epoch:1,10,30,50,100 $@ --multirun +echo "python -m deckard.layers.optimise ++model.trainer.nb_epoch=1,10,30,50,100" $@ "--multirun" +python -m deckard.layers.optimise ++model.trainer.nb_epoch=1,10,30,50,100 $@ --multirun -# # This line generates the model and adds the FeatureSqueezing preprocessing defence. +# This line generates the model and adds the FeatureSqueezing preprocessing defence. python -m deckard.layers.optimise \ ++model.art.preprocessor.name=art.defences.preprocessor.FeatureSqueezing \ +model.art.preprocessor.params.bit_depth=4,8,16,32,64 \ @@ -24,7 +24,7 @@ python -m deckard.layers.optimise \ # # # # Gaussian Noise (Output) python -m deckard.layers.optimise \ ++model.art.postprocessor.name=art.defences.postprocessor.GaussianNoise \ - ++model.art.postprocessor.params.scale=.01,.1,.3,.5,1 \W + ++model.art.postprocessor.params.scale=.01,.1,.3,.5,1 \ ++hydra.sweeper.study_name=gauss-out $@ --multirun # # # # High Confidence diff --git a/examples/pytorch/cifar100/wait.sh b/examples/pytorch/cifar100/wait.sh new file mode 100644 index 00000000..7acc5e65 --- /dev/null +++ b/examples/pytorch/cifar100/wait.sh @@ -0,0 +1,13 @@ +#!/bin/bash +rm -rf waiting.log || true +echo "Trying to allocate gpu" +start=$(date +%s) +until gpu-allocate-cli allocate --duration 72h --wait && echo "Elapsed time: $(( $( date +%s ) - $start )) seconds" >| waiting.log && dvc repro +do + echo "Waiting 30 mins" + sleep 1800 + echo "Trying to allocate gpu" + echo "Elapsed time: $(( $( date +%s ) - $start )) seconds" + echo "Elapsed time in hours: $(( ($(date +%s) - $start) / 3600 )) hours" + echo "Elapsed time in days: $(( ($(date +%s) - $start) / 86400 )) days" +done diff --git a/examples/pytorch/main.sh b/examples/pytorch/main.sh new file mode 100644 index 00000000..34e724ac --- /dev/null +++ b/examples/pytorch/main.sh @@ -0,0 +1,17 @@ +#!/bin/bash +paper_dir=~/ml_afr/ +# set downstream to 2 or nothing +for d in */ ; do + cd $d + # run command and write to log file + dvc repro --downstream clean -f >| dvc_repro.log + # dvc push + cd - +done +# change to paper directory +cd $paper_dir +# run dvc repro and dvc push +dvc repro +dvc push +# change back to original directory +cd - diff --git a/examples/pytorch/mnist/.dvc/config b/examples/pytorch/mnist/.dvc/config index e69de29b..4cf322d9 100644 --- a/examples/pytorch/mnist/.dvc/config +++ b/examples/pytorch/mnist/.dvc/config @@ -0,0 +1,2 @@ +[core] + autostage = true diff --git a/examples/pytorch/mnist/conf/afr.yaml b/examples/pytorch/mnist/conf/afr.yaml index ae09b33b..3585a28e 100644 --- a/examples/pytorch/mnist/conf/afr.yaml +++ b/examples/pytorch/mnist/conf/afr.yaml @@ -1,19 +1,20 @@ covariates: + - "adv_fit_time" - "accuracy" - "train_time" - - "predict_time" - "atk_value" - "def_value" - "data.sample.random_state" - - "adv_failure_rate" - - "model_layers" - - "adv_fit_time" - model.trainer.nb_epoch + - "model_layers" +# - atk_gen +# - def_gen + - predict_time fillna: model.trainer.nb_epoch: 20 weibull: plot: - file : weibull_aft.pdf + file : weibull_aft.eps title : Weibull AFR Model labels: "Intercept: rho_": "$\\rho$" @@ -25,13 +26,16 @@ weibull: "adv_accuracy: lambda_": "Adv. Accuracy" "accuracy: lambda_": "Ben. Accuracy" "adv_fit_time: lambda_": "$t_{attack}$" - "adv_failure_rate: lambda_": "$h_{adv.}(t;\\theta)$" - "failure_rate: lambda_": "$h_{ben.}(t;\\theta)$" + "adv_failure_rate: lambda_": "$f_{adv.}(t;\\theta)$" + "failure_rate: lambda_": "$f_{ben.}(t;\\theta)$" "model.trainer.nb_epoch: lambda_": "No. of Epochs" "model.trainer.batch_size: lambda_": "Batch Size" "def_gen": "Defence" + "model_layers: lambda_" : "Layers" + "def_value: lambda_" : "Defence Strength" + "predict_time: lambda_" : "$t_{predict}$" partial_effect: - - "file": "weibull_epochs_partial_effect.pdf" + - "file": "weibull_epochs_partial_effect.eps" "covariate_array": "model.trainer.nb_epoch" "values_array": [1,10,25,50] "title": "$S(t)$ for Weibull AFR" @@ -41,19 +45,19 @@ weibull: "title": "Epochs", "labels": ["1", "10", "25", "50"] } - - "file": "weibull_layers_partial_effect.pdf" + - "file": "weibull_layers_partial_effect.eps" "covariate_array": "model_layers" "values_array": [18, 34, 50, 101, 152] - "title": "$S(t)$ for Cox AFR" + "title": "$S(t)$ for Weibull AFR" "ylabel": "Expectation of $S(t)$" "xlabel": "Time $T$ (seconds)" "legend_kwargs": { - "title": "ResNet Layers", + "title": "Layers", "labels": ["18", "34", "50", "101", "152"] } # cox: # plot: -# file : cox_aft.pdf +# file : cox_aft.eps # title : Cox AFR Model # labels: # "Intercept: rho_": "$\\rho$" @@ -65,13 +69,13 @@ weibull: # "adv_accuracy: lambda_": "Adv. Accuracy" # "accuracy: lambda_": "Ben. Accuracy" # "adv_fit_time: lambda_": "$t_{attack}$" -# "adv_failure_rate: lambda_": "$h_{adv.}(t;\\theta)$" -# "failure_rate: lambda_": "$h_{ben.}(t;\\theta)$" +# "adv_failure_rate: lambda_": "$f_{adv.}(t;\\theta)$" +# "failure_rate: lambda_": "$f_{ben.}(t;\\theta)$" # "model.trainer.nb_epoch: lambda_": "No. of Epochs" # "model.trainer.batch_size: lambda_": "Batch Size" # "def_gen": "Defence" # partial_effect: -# - "file": "cox_epochs_partial_effect.pdf" +# - "file": "cox_epochs_partial_effect.eps" # "covariate_array": "model.trainer.nb_epoch" # "values_array": [1,10,25,50] # "title": "$S(t)$ for Cox AFR" @@ -81,37 +85,40 @@ weibull: # "title": "Epochs", # "labels": ["1", "10", "25", "50"] # } -# - "file": "cox_layers_partial_effect.pdf" +# - "file": "cox_layers_partial_effect.eps" # "covariate_array": "model_layers" # "values_array": [18, 34, 50, 101, 152] # "title": "$S(t)$ for Cox AFR" # "ylabel": "Expectation of $S(t)$" # "xlabel": "Time $T$ (seconds)" # "legend_kwargs": { -# "title": "ResNet Layers", +# "title": "Layers", # "labels": ["18", "34", "50", "101", "152"] # } log_logistic: plot: - file : log_logistic_aft.pdf + file : log_logistic_aft.eps title : Log logistic AFR Model labels: - "Intercept: rho_": "$\\rho$" - "Intercept: lambda_": "$\\lambda$" - "data.sample.random_state: lambda_": "Random State" - "atk_value: lambda_": "Attack Strength" - "train_time: lambda_": "$t_{train}$" - "predict_proba_time: lambda_": "$t_{predict}$" - "adv_accuracy: lambda_": "Adv. Accuracy" - "accuracy: lambda_": "Ben. Accuracy" - "adv_fit_time: lambda_": "$t_{attack}$" - "adv_failure_rate: lambda_": "$h_{adv.}(t;\\theta)$" - "failure_rate: lambda_": "$h_{ben.}(t;\\theta)$" - "model.trainer.nb_epoch: lambda_": "No. of Epochs" - "model.trainer.batch_size: lambda_": "Batch Size" + "Intercept: beta_": "$\\beta$" + "Intercept: alpha_": "$\\alpha$" + "data.sample.random_state: alpha_": "Random State" + "atk_value: alpha_": "Attack Strength" + "train_time: alpha_": "$t_{train}$" + "predict_proba_time: alpha_": "$t_{predict}$" + "adv_accuracy: alpha_": "Adv. Accuracy" + "accuracy: alpha_": "Ben. Accuracy" + "adv_fit_time: alpha_": "$t_{attack}$" + "adv_failure_rate: alpha_": "$f_{adv.}(t;\\theta)$" + "failure_rate: alpha_": "$f_{ben.}(t;\\theta)$" + "model.trainer.nb_epoch: alpha_": "No. of Epochs" + "model.trainer.batch_size: alpha_": "Batch Size" "def_gen": "Defence" + "model_layers: alpha_" : "Layers" + "def_value: alpha_" : "Defence Strength" + "predict_time: alpha_" : "$t_{predict}$" partial_effect: - - "file": "log_logistic_epochs_partial_effect.pdf" + - "file": "log_logistic_epochs_partial_effect.eps" "covariate_array": "model.trainer.nb_epoch" "values_array": [1,10,25,50] "title": "$S(t)$ for Log-Logistic AFR" @@ -121,37 +128,40 @@ log_logistic: "title": "Epochs", "labels": ["1", "10", "25", "50"] } - - "file": "log_logistic_layers_partial_effect.pdf" + - "file": "log_logistic_layers_partial_effect.eps" "covariate_array": "model_layers" "values_array": [18, 34, 50, 101, 152] - "title": "$S(t)$ for Cox AFR" + "title": "$S(t)$ for Log Logistic AFR" "ylabel": "Expectation of $S(t)$" "xlabel": "Time $T$ (seconds)" "legend_kwargs": { - "title": "ResNet Layers", + "title": "Layers", "labels": ["18", "34", "50", "101", "152"] } log_normal: plot: - file : log_normal_aft.pdf + file : log_normal_aft.eps title : Log Normal AFR Model labels: - "Intercept: rho_": "$\\rho$" - "Intercept: lambda_": "$\\lambda$" - "data.sample.random_state: lambda_": "Random State" - "atk_value: lambda_": "Attack Strength" - "train_time: lambda_": "$t_{train}$" - "predict_proba_time: lambda_": "$t_{predict}$" - "adv_accuracy: lambda_": "Adv. Accuracy" - "accuracy: lambda_": "Ben. Accuracy" - "adv_fit_time: lambda_": "$t_{attack}$" - "adv_failure_rate: lambda_": "$h_{adv.}(t;\\theta)$" - "failure_rate: lambda_": "$h_{ben.}(t;\\theta)$" - "model.trainer.nb_epoch: lambda_": "No. of Epochs" - "model.trainer.batch_size: lambda_": "Batch Size" + "Intercept: sigma_": "$\\rho$" + "Intercept: mu_": "$\\mu$" + "data.sample.random_state: mu_": "Random State" + "atk_value: mu_": "Attack Strength" + "train_time: mu_": "$t_{train}$" + "predict_proba_time: mu_": "$t_{predict}$" + "adv_accuracy: mu_": "Adv. Accuracy" + "accuracy: mu_": "Ben. Accuracy" + "adv_fit_time: mu_": "$t_{attack}$" + "adv_failure_rate: mu_": "$f_{adv.}(t;\\theta)$" + "failure_rate: mu_": "$f_{ben.}(t;\\theta)$" + "model.trainer.nb_epoch: mu_": "No. of Epochs" + "model.trainer.batch_size: mu_": "Batch Size" "def_gen": "Defence" + "model_layers: mu_" : "Layers" + "def_value: mu_" : "Defence Strength" + "predict_time: mu_" : "$t_{predict}$" partial_effect: - - "file": "log_normal_epochs_partial_effect.pdf" + - "file": "log_normal_epochs_partial_effect.eps" "covariate_array": "model.trainer.nb_epoch" "values_array": [1,10,25,50] "title": "$S(t)$ for Log-Normal AFR" @@ -161,13 +171,13 @@ log_normal: "title": "Epochs", "labels": ["1", "10", "25", "50"] } - - "file": "log_normal_layers_partial_effect.pdf" + - "file": "log_normal_layers_partial_effect.eps" "covariate_array": "model_layers" "values_array": [18, 34, 50, 101, 152] - "title": "$S(t)$ for Cox AFR" + "title": "$S(t)$ for Log Normal AFR" "ylabel": "Expectation of $S(t)$" "xlabel": "Time $T$ (seconds)" "legend_kwargs": { - "title": "ResNet Layers", + "title": "Layers", "labels": ["18", "34", "50", "101", "152"] } diff --git a/examples/pytorch/mnist/conf/clean.yaml b/examples/pytorch/mnist/conf/clean.yaml index 7843aba8..e9c215ab 100644 --- a/examples/pytorch/mnist/conf/clean.yaml +++ b/examples/pytorch/mnist/conf/clean.yaml @@ -11,7 +11,7 @@ defences: GaussianAugmentation: Gauss-in GaussianNoise: Gauss-out HighConfidence: Conf - nb_epoch: Epochs + nb_epoch : Epochs model_layers: Control params: Deep: attack.init.kwargs.nb_grads @@ -26,5 +26,9 @@ params: Gauss-in: model.art.pipeline.preprocessor.kwargs.sigma Control: model_layers Epochs: model.trainer.nb_epoch + control: + model_layers: 18 + defaults: + model.trainer.nb_epoch: 20 fillna: - Epochs: 20 + model.trainer.nb_epoch : 20 diff --git a/examples/pytorch/mnist/conf/plots.yaml b/examples/pytorch/mnist/conf/plots.yaml index 464f53b3..b684aec3 100644 --- a/examples/pytorch/mnist/conf/plots.yaml +++ b/examples/pytorch/mnist/conf/plots.yaml @@ -1,5 +1,5 @@ cat_plot: -- file: adv_accuracy_vs_defence_type.pdf +- file: adv_accuracy_vs_defence_type.eps hue: model_name kind: boxen set: @@ -16,7 +16,7 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: ben_accuracy_vs_defence_type.pdf +- file: ben_accuracy_vs_defence_type.eps hue: model_name kind: boxen titles: Ben. Accuracy vs Defence Type @@ -31,7 +31,7 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: ben_failures_per_train_time_vs_defence_type.pdf +- file: ben_failures_per_train_time_vs_defence_type.eps hue: model_name kind: boxen set: @@ -48,7 +48,7 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: adv_failures_per_train_time_vs_defence_type.pdf +- file: adv_failures_per_train_time_vs_defence_type.eps hue: model_name kind: boxen set: @@ -65,7 +65,7 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: adv_failures_per_train_time_vs_attack_type.pdf +- file: adv_failures_per_train_time_vs_attack_type.eps hue: model_name kind: boxen legend_title: Model Name @@ -83,15 +83,15 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: adv_failures_per_test_time_vs_defence_type.pdf +- file: adv_failures_per_test_time_vs_defence_type.eps hue: model_name kind: boxen legend_title: Model Name - titles: $h_{adv}$ vs Defence Type + titles: $f_{adv}$ vs Defence Type x: def_gen xlabels: Defence Type y: adv_failure_rate - ylabels: $h_{adv.}$ + ylabels: $f_{adv.}$ rotation : 90 hue_order: - ResNet18 @@ -99,23 +99,8 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: adv_accuracy_vs_defence_type.pdf - hue: model_name - kind: boxen - legend_title: Model Name - titles: Adv. Accuracy vs Defence Type - x: def_gen - xlabels: Defence Type - y: adv_accuracy - ylabels: Adv. Ben. Accuracy - rotation : 90 - hue_order: - - ResNet18 - - ResNet34 - - ResNet50 - - ResNet101 - - ResNet152 -- file: adv_accuracy_vs_attack_type.pdf + +- file: adv_accuracy_vs_attack_type.eps hue: model_name kind: boxen legend_title: Model Name @@ -131,17 +116,17 @@ cat_plot: - ResNet50 - ResNet101 - ResNet152 -- file: ben_failure_rate_vs_defence_type.pdf +- file: ben_failure_rate_vs_defence_type.eps hue: model_name kind: boxen legend_title: Model Name set: yscale: log - titles: $h_{ben}(t; \theta)$ vs Defence Type + titles: $f_{ben}(t; \theta)$ vs Defence Type x: def_gen xlabels: Defence Type y: failure_rate - ylabels: $h_{ben}(t; \theta)$ + ylabels: $f_{ben}(t; \theta)$ rotation : 90 hue_order: - ResNet18 @@ -150,7 +135,7 @@ cat_plot: - ResNet101 - ResNet152 line_plot: -- file: def_param_vs_accuracy.pdf +- file: def_param_vs_accuracy.eps hue: def_gen legend: {"bbox_to_anchor": [1.05, 1], "title": "Defence"} title: Ben. Accuracy vs Defence Strength @@ -160,15 +145,17 @@ line_plot: y: accuracy y_scale: ylabel: Ben. Accuracy - # hue_order: - # - Control - # - Conf - # - Epochs - # - Gauss-in - # - Gauss-out - # - Conf - # - FSQ -- file: def_param_vs_adv_accuracy.pdf + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars +- file: def_param_vs_adv_accuracy.eps hue: def_gen legend: {"bbox_to_anchor": [1.05, 1], "title": "Defence"} title: Adv. Accuracy vs Defence Strength @@ -178,33 +165,37 @@ line_plot: y: adv_accuracy y_scale: ylabel: Adv. Accuracy - # hue_order: - # - Control - # - Conf - # - Epochs - # - Gauss-in - # - Gauss-out - # - Conf - # - FSQ -- file: def_param_vs_adv_failure_rate.pdf + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars +- file: def_param_vs_adv_failure_rate.eps hue: def_gen legend: {"bbox_to_anchor": [1.05, 1], "title": "Defence"} - title: $h_{adv}$ vs Defence Strength + title: $f_{adv}$ vs Defence Strength x: def_value - x_scale: linear + x_scale: linear xlabel: Defence Control Parameter y: adv_failure_rate - y_scale: log - ylabel: $h_{adv.}$ - # hue_order: - # - Control - # - Conf - # - Epochs - # - Gauss-in - # - Gauss-out - # - Conf - # - FSQ -- file: atk_param_vs_accuracy.pdf + y_scale: linear + ylabel: $f_{adv.}$ + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars +- file: atk_param_vs_accuracy.eps hue: atk_gen legend: {bbox_to_anchor: [1.05, 1]} title: Adv. Accuracy vs Attack Strength @@ -221,16 +212,17 @@ line_plot: - HSJ - Pixel - Thresh - + errorbar: se + err_style: bars scatter_plot: - x: train_time_per_sample y: adv_failure_rate hue: model_name xlabel: $t_{train}$ - ylabel: $h_{adv}$ - title: $h_{adv}$ vs $t_{train}$ - file: adv_failure_rate_vs_train_time.pdf - y_scale: log + ylabel: $f_{adv}$ + title: $f_{adv}$ vs $t_{train}$ + file: adv_failure_rate_vs_train_time.eps + # y_scale: log x_scale: log legend: title: Model Name diff --git a/examples/pytorch/mnist/dvc.lock b/examples/pytorch/mnist/dvc.lock index a1fb908f..db59a303 100644 --- a/examples/pytorch/mnist/dvc.lock +++ b/examples/pytorch/mnist/dvc.lock @@ -1,46 +1,299 @@ schema: '2.0' stages: - compile@attack: - cmd: python -m deckard.layers.compile --report_folder mnist/reports/attack --results_file - mnist/reports/attack.csv + clean@attack: + cmd: python -m deckard.layers.clean_data -i mnist/reports/attack.csv -o mnist/reports/clean_attack.csv + -c conf/clean.yaml deps: - - path: mnist/reports/attack/ - hash: md5 - md5: a2694f8e9ea5c5ff400d11fa1d98001d.dir - size: 21895572255 - nfiles: 53006 - - path: mnist/reports/attack/ResNet101.db - md5: 600452804d96c8b8483c3f8da01130c4 - size: 462848 - - path: mnist/reports/attack/ResNet18.db - md5: 920b0ed178ec504c0d7990777862283f - size: 1363968 - - path: mnist/reports/attack/ResNet34.db - md5: 3f56dd2ea0783a56a2a9e3eaaad88c21 - size: 1945600 - - path: mnist/reports/attack/ResNet50.db - md5: d9ee221b942b56d9bb720e022e05bf4b - size: 462848 - outs: - path: mnist/reports/attack.csv - hash: md5 - md5: aa61d0f5118327d164cfc37a466e5162 - size: 47376297 + md5: 51d779c26865540247a82408cd6a46d0 + size: 189645846 + params: + params.yaml: + files.directory: mnist + files.reports: reports + conf/clean.yaml: + attacks: + DeepFool: Deep + FastGradientMethod: FGM + HopSkipJump: HSJ + PixelAttack: Pixel + ProjectedGradientDescent: PGD + ThresholdAttack: Thresh + defences: + Control: Control + FeatureSqueezing: FSQ + GaussianAugmentation: Gauss-in + GaussianNoise: Gauss-out + HighConfidence: Conf + nb_epoch: Epochs + model_layers: Control + fillna: + model.trainer.nb_epoch: 20 + params: + Deep: attack.init.kwargs.nb_grads + FGM: attack.init.kwargs.eps + HSJ: attack.init.kwargs.max_iter + Pixel: attack.init.kwargs.th + PGD: attack.init.kwargs.eps + Thresh: attack.init.kwargs.th + Gauss-out: model.art.pipeline.postprocessor.kwargs.scale + Conf: model.art.pipeline.postprocessor.kwargs.cutoff + FSQ: model.art.pipeline.preprocessor.kwargs.bit_depth + Gauss-in: model.art.pipeline.preprocessor.kwargs.sigma + Control: model_layers + Epochs: model.trainer.nb_epoch + control: + model_layers: 18 + defaults: + model.trainer.nb_epoch: 20 + outs: + - path: mnist/reports/clean_attack.csv + md5: 2c19e993bd04189f0f47a38eda17f3b9 + size: 43039659 + afr: + cmd: python -m deckard.layers.afr --dataset mnist --data_file mnist/reports/clean_attack.csv --target + adv_accuracy --duration_col predict_time --dataset mnist --config_file conf/afr.yaml + --plots_folder mnist/plots/ + deps: + - path: mnist/reports/clean_attack.csv + md5: 2c19e993bd04189f0f47a38eda17f3b9 + size: 43039659 + params: + params.yaml: + files.directory: mnist + conf/afr.yaml: + covariates: + - adv_fit_time + - accuracy + - train_time + - atk_value + - def_value + - data.sample.random_state + - model.trainer.nb_epoch + - model_layers + - predict_time + log_logistic: + plot: + file: log_logistic_aft.eps + title: Log logistic AFR Model + labels: + 'Intercept: beta_': $\beta$ + 'Intercept: alpha_': $\alpha$ + 'data.sample.random_state: alpha_': Random State + 'atk_value: alpha_': Attack Strength + 'train_time: alpha_': $t_{train}$ + 'predict_proba_time: alpha_': $t_{predict}$ + 'adv_accuracy: alpha_': Adv. Accuracy + 'accuracy: alpha_': Ben. Accuracy + 'adv_fit_time: alpha_': $t_{attack}$ + 'adv_failure_rate: alpha_': $f_{adv.}(t;\theta)$ + 'failure_rate: alpha_': $f_{ben.}(t;\theta)$ + 'model.trainer.nb_epoch: alpha_': No. of Epochs + 'model.trainer.batch_size: alpha_': Batch Size + def_gen: Defence + 'model_layers: alpha_': Layers + 'def_value: alpha_': Defence Strength + 'predict_time: alpha_': $t_{predict}$ + partial_effect: + - file: log_logistic_epochs_partial_effect.eps + covariate_array: model.trainer.nb_epoch + values_array: + - 1 + - 10 + - 25 + - 50 + title: $S(t)$ for Log-Logistic AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Epochs + labels: + - '1' + - '10' + - '25' + - '50' + - file: log_logistic_layers_partial_effect.eps + covariate_array: model_layers + values_array: + - 18 + - 34 + - 50 + - 101 + - 152 + title: $S(t)$ for Log Logistic AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Layers + labels: + - '18' + - '34' + - '50' + - '101' + - '152' + log_normal: + plot: + file: log_normal_aft.eps + title: Log Normal AFR Model + labels: + 'Intercept: sigma_': $\rho$ + 'Intercept: mu_': $\mu$ + 'data.sample.random_state: mu_': Random State + 'atk_value: mu_': Attack Strength + 'train_time: mu_': $t_{train}$ + 'predict_proba_time: mu_': $t_{predict}$ + 'adv_accuracy: mu_': Adv. Accuracy + 'accuracy: mu_': Ben. Accuracy + 'adv_fit_time: mu_': $t_{attack}$ + 'adv_failure_rate: mu_': $f_{adv.}(t;\theta)$ + 'failure_rate: mu_': $f_{ben.}(t;\theta)$ + 'model.trainer.nb_epoch: mu_': No. of Epochs + 'model.trainer.batch_size: mu_': Batch Size + def_gen: Defence + 'model_layers: mu_': Layers + 'def_value: mu_': Defence Strength + 'predict_time: mu_': $t_{predict}$ + partial_effect: + - file: log_normal_epochs_partial_effect.eps + covariate_array: model.trainer.nb_epoch + values_array: + - 1 + - 10 + - 25 + - 50 + title: $S(t)$ for Log-Normal AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Epochs + labels: + - '1' + - '10' + - '25' + - '50' + - file: log_normal_layers_partial_effect.eps + covariate_array: model_layers + values_array: + - 18 + - 34 + - 50 + - 101 + - 152 + title: $S(t)$ for Log Normal AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Layers + labels: + - '18' + - '34' + - '50' + - '101' + - '152' + weibull: + plot: + file: weibull_aft.eps + title: Weibull AFR Model + labels: + 'Intercept: rho_': $\rho$ + 'Intercept: lambda_': $\lambda$ + 'data.sample.random_state: lambda_': Random State + 'atk_value: lambda_': Attack Strength + 'train_time: lambda_': $t_{train}$ + 'predict_proba_time: lambda_': $t_{predict}$ + 'adv_accuracy: lambda_': Adv. Accuracy + 'accuracy: lambda_': Ben. Accuracy + 'adv_fit_time: lambda_': $t_{attack}$ + 'adv_failure_rate: lambda_': $f_{adv.}(t;\theta)$ + 'failure_rate: lambda_': $f_{ben.}(t;\theta)$ + 'model.trainer.nb_epoch: lambda_': No. of Epochs + 'model.trainer.batch_size: lambda_': Batch Size + def_gen: Defence + 'model_layers: lambda_': Layers + 'def_value: lambda_': Defence Strength + 'predict_time: lambda_': $t_{predict}$ + partial_effect: + - file: weibull_epochs_partial_effect.eps + covariate_array: model.trainer.nb_epoch + values_array: + - 1 + - 10 + - 25 + - 50 + title: $S(t)$ for Weibull AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Epochs + labels: + - '1' + - '10' + - '25' + - '50' + - file: weibull_layers_partial_effect.eps + covariate_array: model_layers + values_array: + - 18 + - 34 + - 50 + - 101 + - 152 + title: $S(t)$ for Weibull AFR + ylabel: Expectation of $S(t)$ + xlabel: Time $T$ (seconds) + legend_kwargs: + title: Layers + labels: + - '18' + - '34' + - '50' + - '101' + - '152' + outs: + - path: mnist/plots/aft_comparison.csv + md5: f59decd89bd1e9a684ea77c280dd4977 + size: 375 + - path: mnist/plots/aft_comparison.tex + md5: 9ba120db593233d5811417ba894d3551 + size: 566 + - path: mnist/plots/log_logistic_aft.eps + md5: b7b0671479b42062562f0c03d8c0975f + size: 43143 + - path: mnist/plots/log_logistic_epochs_partial_effect.eps + md5: 6d4454d35005dfd34dc25de5691b05b3 + size: 45110 + - path: mnist/plots/log_logistic_layers_partial_effect.eps + md5: 04f63bb1af4c6cc182f031b0a6f2f570 + size: 46247 + - path: mnist/plots/log_normal_aft.eps + md5: 3c5895eed8d86f1bb68e50a9e8d705fb + size: 44109 + - path: mnist/plots/log_normal_epochs_partial_effect.eps + md5: e273ac270f3c7a04257edf27250f0451 + size: 45828 + - path: mnist/plots/log_normal_layers_partial_effect.eps + md5: 0bd9b1734275002d5fba203829d9ace6 + size: 46723 + - path: mnist/plots/weibull_aft.eps + md5: 7671058fb0db407eef4a01464e324a5c + size: 41411 + - path: mnist/plots/weibull_epochs_partial_effect.eps + md5: b77d411ad6499a3a77a38486ef67e600 + size: 44468 + - path: mnist/plots/weibull_layers_partial_effect.eps + md5: 90c8f92165a288641f249f866d8c25d0 + size: 45557 plot: cmd: python -m deckard.layers.plots --path mnist/plots/ --file mnist/reports/clean_attack.csv -c conf/plots.yaml deps: - path: mnist/reports/clean_attack.csv - hash: md5 - md5: ada4d505a6c72408e50b929b2869ffee - size: 19747128 + md5: 2c19e993bd04189f0f47a38eda17f3b9 + size: 43039659 params: - params.yaml: - files.directory: mnist - files.reports: reports conf/plots.yaml: cat_plot: - - file: adv_accuracy_vs_defence_type.pdf + - file: adv_accuracy_vs_defence_type.eps hue: model_name kind: boxen set: @@ -57,7 +310,7 @@ stages: - ResNet50 - ResNet101 - ResNet152 - - file: ben_accuracy_vs_defence_type.pdf + - file: ben_accuracy_vs_defence_type.eps hue: model_name kind: boxen titles: Ben. Accuracy vs Defence Type @@ -72,7 +325,7 @@ stages: - ResNet50 - ResNet101 - ResNet152 - - file: ben_failures_per_train_time_vs_defence_type.pdf + - file: ben_failures_per_train_time_vs_defence_type.eps hue: model_name kind: boxen set: @@ -89,7 +342,7 @@ stages: - ResNet50 - ResNet101 - ResNet152 - - file: adv_failures_per_train_time_vs_defence_type.pdf + - file: adv_failures_per_train_time_vs_defence_type.eps hue: model_name kind: boxen set: @@ -106,7 +359,7 @@ stages: - ResNet50 - ResNet101 - ResNet152 - - file: adv_failures_per_train_time_vs_attack_type.pdf + - file: adv_failures_per_train_time_vs_attack_type.eps hue: model_name kind: boxen legend_title: Model Name @@ -124,31 +377,15 @@ stages: - ResNet50 - ResNet101 - ResNet152 - - file: adv_failures_per_test_time_vs_defence_type.pdf + - file: adv_failures_per_test_time_vs_defence_type.eps hue: model_name kind: boxen legend_title: Model Name - titles: $h_{adv}$ vs Defence Type + titles: $f_{adv}$ vs Defence Type x: def_gen xlabels: Defence Type y: adv_failure_rate - ylabels: $h_{adv.}$ - rotation: 90 - hue_order: - - ResNet18 - - ResNet34 - - ResNet50 - - ResNet101 - - ResNet152 - - file: adv_accuracy_vs_defence_type.pdf - hue: model_name - kind: boxen - legend_title: Model Name - titles: Adv. Accuracy vs Defence Type - x: def_gen - xlabels: Defence Type - y: adv_accuracy - ylabels: Adv. Ben. Accuracy + ylabels: $f_{adv.}$ rotation: 90 hue_order: - ResNet18 @@ -156,7 +393,7 @@ stages: - ResNet50 - ResNet101 - ResNet152 - - file: adv_accuracy_vs_attack_type.pdf + - file: adv_accuracy_vs_attack_type.eps hue: model_name kind: boxen legend_title: Model Name @@ -172,17 +409,17 @@ stages: - ResNet50 - ResNet101 - ResNet152 - - file: ben_failure_rate_vs_defence_type.pdf + - file: ben_failure_rate_vs_defence_type.eps hue: model_name kind: boxen legend_title: Model Name set: yscale: log - titles: $h_{ben}(t; \theta)$ vs Defence Type + titles: $f_{ben}(t; \theta)$ vs Defence Type x: def_gen xlabels: Defence Type y: failure_rate - ylabels: $h_{ben}(t; \theta)$ + ylabels: $f_{ben}(t; \theta)$ rotation: 90 hue_order: - ResNet18 @@ -191,7 +428,7 @@ stages: - ResNet101 - ResNet152 line_plot: - - file: def_param_vs_accuracy.pdf + - file: def_param_vs_accuracy.eps hue: def_gen legend: bbox_to_anchor: @@ -205,7 +442,17 @@ stages: y: accuracy y_scale: ylabel: Ben. Accuracy - - file: def_param_vs_adv_accuracy.pdf + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars + - file: def_param_vs_adv_accuracy.eps hue: def_gen legend: bbox_to_anchor: @@ -219,21 +466,41 @@ stages: y: adv_accuracy y_scale: ylabel: Adv. Accuracy - - file: def_param_vs_adv_failure_rate.pdf + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars + - file: def_param_vs_adv_failure_rate.eps hue: def_gen legend: bbox_to_anchor: - 1.05 - 1 title: Defence - title: $h_{adv}$ vs Defence Strength + title: $f_{adv}$ vs Defence Strength x: def_value x_scale: linear xlabel: Defence Control Parameter y: adv_failure_rate - y_scale: log - ylabel: $h_{adv.}$ - - file: atk_param_vs_accuracy.pdf + y_scale: linear + ylabel: $f_{adv.}$ + hue_order: + - Control + - Conf + - Epochs + - Gauss-in + - Gauss-out + - Conf + - FSQ + errorbar: se + err_style: bars + - file: atk_param_vs_accuracy.eps hue: atk_gen legend: bbox_to_anchor: @@ -253,15 +520,16 @@ stages: - HSJ - Pixel - Thresh + errorbar: se + err_style: bars scatter_plot: - x: train_time_per_sample y: adv_failure_rate hue: model_name xlabel: $t_{train}$ - ylabel: $h_{adv}$ - title: $h_{adv}$ vs $t_{train}$ - file: adv_failure_rate_vs_train_time.pdf - y_scale: log + ylabel: $f_{adv}$ + title: $f_{adv}$ vs $t_{train}$ + file: adv_failure_rate_vs_train_time.eps x_scale: log legend: title: Model Name @@ -275,106 +543,102 @@ stages: - ResNet101 - ResNet152 outs: - - path: mnist/plots/adv_accuracy_vs_attack_type.pdf - hash: md5 - md5: 175188b326b4c519d51274f461fe4b56 - size: 32685 - - path: mnist/plots/adv_accuracy_vs_defence_type.pdf - hash: md5 - md5: 65201d5844ae16efa9e675d3622c6c6d - size: 33020 - - path: mnist/plots/adv_failure_rate_vs_train_time.pdf - hash: md5 - md5: ee56e84db4091efa7b1526ec51fdfdd5 - size: 96055 - - path: mnist/plots/adv_failures_per_test_time_vs_defence_type.pdf - hash: md5 - md5: bdd64c58fc2cfdc344ec81a0642be597 - size: 40000 - - path: mnist/plots/adv_failures_per_train_time_vs_attack_type.pdf - hash: md5 - md5: 1216c3aa5898e874f430c7734b26ea56 - size: 41252 - - path: mnist/plots/adv_failures_per_train_time_vs_defence_type.pdf - hash: md5 - md5: 8f04fa98643a1210910ef8657df1c2fa - size: 37353 - - path: mnist/plots/atk_param_vs_accuracy.pdf - hash: md5 - md5: 66c481c894939696b9f217570790fcec - size: 20223 - - path: mnist/plots/ben_accuracy_vs_defence_type.pdf - hash: md5 - md5: ff6f4bb8bde362750bf5878eea7e13ff - size: 30124 - - path: mnist/plots/ben_failure_rate_vs_defence_type.pdf - hash: md5 - md5: 983850e56fcd0ad50d85e630d61c82a5 - size: 42600 - - path: mnist/plots/ben_failures_per_train_time_vs_defence_type.pdf - hash: md5 - md5: e62b68ef46db339eb9def2f4959be2b3 - size: 37589 - - path: mnist/plots/def_param_vs_accuracy.pdf - hash: md5 - md5: e1b0f111bc5d7797256be82187586023 - size: 20548 - - path: mnist/plots/def_param_vs_adv_accuracy.pdf - hash: md5 - md5: 310f01fdaa47a92500f03d728cd6b117 - size: 19862 - - path: mnist/plots/def_param_vs_adv_failure_rate.pdf - hash: md5 - md5: d376c93f824251f3508b0a7e3c365020 - size: 23632 - afr: - cmd: python -m deckard.layers.afr --dataset mnist --data_file mnist/reports/clean_attack.csv --duration_col - adv_fit_time --dataset mnist --config_file conf/afr.yaml --plots_folder mnist/plots/ + - path: mnist/plots/adv_accuracy_vs_attack_type.eps + md5: d51200cf3e8cefd7517a97c507c32a92 + size: 123974 + - path: mnist/plots/adv_accuracy_vs_defence_type.eps + md5: 1142a65c254df12224d88187d580c756 + size: 118866 + - path: mnist/plots/adv_failure_rate_vs_train_time.eps + md5: 584a893a5e386ce8af1b49dd4333f27a + size: 987785 + - path: mnist/plots/adv_failures_per_test_time_vs_defence_type.eps + md5: ae31c6898b60fc8c4b2d5ed523e8648b + size: 138229 + - path: mnist/plots/adv_failures_per_train_time_vs_attack_type.eps + md5: 32d8a97ee6fa8bfb385cd10cef9985a0 + size: 128046 + - path: mnist/plots/adv_failures_per_train_time_vs_defence_type.eps + md5: 191c566d64c2f94b5832578951a1ca3a + size: 122522 + - path: mnist/plots/atk_param_vs_accuracy.eps + md5: 2d20b9e7214b8b04c8d6ba60e59be5a0 + size: 39701 + - path: mnist/plots/ben_accuracy_vs_defence_type.eps + md5: c94bb2af2ed7a26bf6d1f232d010671a + size: 112716 + - path: mnist/plots/ben_failure_rate_vs_defence_type.eps + md5: ab115d786b80015aba9efe0b03df9ada + size: 140041 + - path: mnist/plots/ben_failures_per_train_time_vs_defence_type.eps + md5: e2e8499a4b6fc81d50e18d6b4bdf29f7 + size: 123124 + - path: mnist/plots/def_param_vs_accuracy.eps + md5: a37bec164c0ba420ef4c20cab952cd9a + size: 39660 + - path: mnist/plots/def_param_vs_adv_accuracy.eps + md5: 09af779c5fd3c9b132bd5270516a6e53 + size: 39631 + - path: mnist/plots/def_param_vs_adv_failure_rate.eps + md5: 706238ba734e5a65642f12e105365aa9 + size: 39067 + copy_results: + cmd: mkdir -p ~/ml_afr/mnist/ && cp -r mnist/plots/* ~/ml_afr/mnist/ + deps: + - path: mnist/plots/ + md5: 37a3df39d57394928f1d659d522f9544.dir + size: 3021764 + nfiles: 35 + - path: mnist/plots/ + md5: 37a3df39d57394928f1d659d522f9544.dir + size: 3021764 + nfiles: 35 + afr_with_dummies: + cmd: python -m deckard.layers.afr --dataset mnist --data_file mnist/reports/clean_attack.csv --target + adv_accuracy --duration_col predict_time --dataset mnist --config_file conf/afr_dummy.yaml + --plots_folder mnist/plots/ --summary_file aft_comparison_with_dummy deps: - - path: mnist/plots/adv_accuracy_vs_defence_type.pdf - hash: md5 - md5: 65201d5844ae16efa9e675d3622c6c6d - size: 33020 - path: mnist/reports/clean_attack.csv - hash: md5 - md5: ada4d505a6c72408e50b929b2869ffee - size: 19747128 + md5: 2c19e993bd04189f0f47a38eda17f3b9 + size: 43039659 params: params.yaml: files.directory: mnist conf/afr.yaml: covariates: + - adv_fit_time - accuracy - train_time - - predict_time - atk_value - def_value - data.sample.random_state - - adv_failure_rate - - model_layers - - adv_fit_time - model.trainer.nb_epoch + - model_layers + - predict_time log_logistic: plot: - file: log_logistic_aft.pdf + file: log_logistic_aft.eps title: Log logistic AFR Model labels: - 'Intercept: rho_': $\rho$ - 'Intercept: lambda_': $\lambda$ - 'data.sample.random_state: lambda_': Random State - 'atk_value: lambda_': Attack Strength - 'train_time: lambda_': $t_{train}$ - 'predict_proba_time: lambda_': $t_{predict}$ - 'adv_accuracy: lambda_': Adv. Accuracy - 'accuracy: lambda_': Ben. Accuracy - 'adv_fit_time: lambda_': $t_{attack}$ - 'adv_failure_rate: lambda_': $h_{adv.}(t;\theta)$ - 'failure_rate: lambda_': $h_{ben.}(t;\theta)$ - 'model.trainer.nb_epoch: lambda_': No. of Epochs - 'model.trainer.batch_size: lambda_': Batch Size + 'Intercept: beta_': $\beta$ + 'Intercept: alpha_': $\alpha$ + 'data.sample.random_state: alpha_': Random State + 'atk_value: alpha_': Attack Strength + 'train_time: alpha_': $t_{train}$ + 'predict_proba_time: alpha_': $t_{predict}$ + 'adv_accuracy: alpha_': Adv. Accuracy + 'accuracy: alpha_': Ben. Accuracy + 'adv_fit_time: alpha_': $t_{attack}$ + 'adv_failure_rate: alpha_': $f_{adv.}(t;\theta)$ + 'failure_rate: alpha_': $f_{ben.}(t;\theta)$ + 'model.trainer.nb_epoch: alpha_': No. of Epochs + 'model.trainer.batch_size: alpha_': Batch Size def_gen: Defence + 'model_layers: alpha_': ResNet Layers + 'def_value: alpha_': Defence Strength + 'predict_time: alpha_': $t_{predict}$ partial_effect: - - file: log_logistic_epochs_partial_effect.pdf + - file: log_logistic_epochs_partial_effect.eps covariate_array: model.trainer.nb_epoch values_array: - 1 @@ -391,7 +655,7 @@ stages: - '10' - '25' - '50' - - file: log_logistic_layers_partial_effect.pdf + - file: log_logistic_layers_partial_effect.eps covariate_array: model_layers values_array: - 18 @@ -399,7 +663,7 @@ stages: - 50 - 101 - 152 - title: $S(t)$ for Cox AFR + title: $S(t)$ for Log Logistic AFR ylabel: Expectation of $S(t)$ xlabel: Time $T$ (seconds) legend_kwargs: @@ -412,25 +676,28 @@ stages: - '152' log_normal: plot: - file: log_normal_aft.pdf + file: log_normal_aft.eps title: Log Normal AFR Model labels: - 'Intercept: rho_': $\rho$ - 'Intercept: lambda_': $\lambda$ - 'data.sample.random_state: lambda_': Random State - 'atk_value: lambda_': Attack Strength - 'train_time: lambda_': $t_{train}$ - 'predict_proba_time: lambda_': $t_{predict}$ - 'adv_accuracy: lambda_': Adv. Accuracy - 'accuracy: lambda_': Ben. Accuracy - 'adv_fit_time: lambda_': $t_{attack}$ - 'adv_failure_rate: lambda_': $h_{adv.}(t;\theta)$ - 'failure_rate: lambda_': $h_{ben.}(t;\theta)$ - 'model.trainer.nb_epoch: lambda_': No. of Epochs - 'model.trainer.batch_size: lambda_': Batch Size + 'Intercept: sigma_': $\rho$ + 'Intercept: mu_': $\mu$ + 'data.sample.random_state: mu_': Random State + 'atk_value: mu_': Attack Strength + 'train_time: mu_': $t_{train}$ + 'predict_proba_time: mu_': $t_{predict}$ + 'adv_accuracy: mu_': Adv. Accuracy + 'accuracy: mu_': Ben. Accuracy + 'adv_fit_time: mu_': $t_{attack}$ + 'adv_failure_rate: mu_': $f_{adv.}(t;\theta)$ + 'failure_rate: mu_': $f_{ben.}(t;\theta)$ + 'model.trainer.nb_epoch: mu_': No. of Epochs + 'model.trainer.batch_size: mu_': Batch Size def_gen: Defence + 'model_layers: mu_': ResNet Layers + 'def_value: mu_': Defence Strength + 'predict_time: mu_': $t_{predict}$ partial_effect: - - file: log_normal_epochs_partial_effect.pdf + - file: log_normal_epochs_partial_effect.eps covariate_array: model.trainer.nb_epoch values_array: - 1 @@ -447,7 +714,7 @@ stages: - '10' - '25' - '50' - - file: log_normal_layers_partial_effect.pdf + - file: log_normal_layers_partial_effect.eps covariate_array: model_layers values_array: - 18 @@ -455,7 +722,7 @@ stages: - 50 - 101 - 152 - title: $S(t)$ for Cox AFR + title: $S(t)$ for Log Normal AFR ylabel: Expectation of $S(t)$ xlabel: Time $T$ (seconds) legend_kwargs: @@ -468,7 +735,7 @@ stages: - '152' weibull: plot: - file: weibull_aft.pdf + file: weibull_aft.eps title: Weibull AFR Model labels: 'Intercept: rho_': $\rho$ @@ -480,13 +747,16 @@ stages: 'adv_accuracy: lambda_': Adv. Accuracy 'accuracy: lambda_': Ben. Accuracy 'adv_fit_time: lambda_': $t_{attack}$ - 'adv_failure_rate: lambda_': $h_{adv.}(t;\theta)$ - 'failure_rate: lambda_': $h_{ben.}(t;\theta)$ + 'adv_failure_rate: lambda_': $f_{adv.}(t;\theta)$ + 'failure_rate: lambda_': $f_{ben.}(t;\theta)$ 'model.trainer.nb_epoch: lambda_': No. of Epochs 'model.trainer.batch_size: lambda_': Batch Size def_gen: Defence + 'model_layers: lambda_': ResNet Layers + 'def_value: lambda_': Defence Strength + 'predict_time: lambda_': $t_{predict}$ partial_effect: - - file: weibull_epochs_partial_effect.pdf + - file: weibull_epochs_partial_effect.eps covariate_array: model.trainer.nb_epoch values_array: - 1 @@ -503,7 +773,7 @@ stages: - '10' - '25' - '50' - - file: weibull_layers_partial_effect.pdf + - file: weibull_layers_partial_effect.eps covariate_array: model_layers values_array: - 18 @@ -511,7 +781,7 @@ stages: - 50 - 101 - 152 - title: $S(t)$ for Cox AFR + title: $S(t)$ for Weibull AFR ylabel: Expectation of $S(t)$ xlabel: Time $T$ (seconds) legend_kwargs: @@ -523,224 +793,36 @@ stages: - '101' - '152' outs: - - path: mnist/plots/aft_comparison.csv - hash: md5 - md5: a35241fbedbd3900b42424e4036f1cdb - size: 183 - - path: mnist/plots/aft_comparison.tex - hash: md5 - md5: c0d2c64f3b2696750aa5de1539312379 - size: 407 - - path: mnist/plots/log_logistic_aft.pdf - hash: md5 - md5: 03f05b16a9504eea7e81652b31de0d00 - size: 23401 - - path: mnist/plots/log_logistic_epochs_partial_effect.pdf - hash: md5 - md5: 535a9ea4255b7577cb300efbd1d256df - size: 27394 - - path: mnist/plots/log_logistic_layers_partial_effect.pdf - hash: md5 - md5: 2a4ab1809b665e226617185e475fb76b - size: 28988 - - path: mnist/plots/log_normal_aft.pdf - hash: md5 - md5: 007fd6530b124cb76995f2d11ccea52f - size: 24471 - - path: mnist/plots/log_normal_epochs_partial_effect.pdf - hash: md5 - md5: 29293af9fa83d8c9a6ca3680183c53c5 - size: 28043 - - path: mnist/plots/log_normal_layers_partial_effect.pdf - hash: md5 - md5: 1848f13abd7b100cb455de45f4fd13fd - size: 29095 - - path: mnist/plots/weibull_aft.pdf - hash: md5 - md5: 0e5d3b23fa0607678359c96c978c0952 - size: 33691 - - path: mnist/plots/weibull_epochs_partial_effect.pdf - hash: md5 - md5: c48ae038ac53ec5844f72eda45812146 - size: 27547 - - path: mnist/plots/weibull_layers_partial_effect.pdf - hash: md5 - md5: e7c2e1ec85fdb54e59bfbe55a9065c5a - size: 29116 - copy_results: - cmd: cp -r mnist/plots/* ~/ml_afr/mnist/ - deps: - - path: mnist/plots/ - hash: md5 - md5: 7baeb7db4aacc8c9e9676f7d04713294.dir - size: 727279 - nfiles: 24 - clean@attack: - cmd: python -m deckard.layers.clean_data -i mnist/reports/attack.csv -o mnist/reports/clean_attack.csv - -c conf/clean.yaml - deps: - - path: mnist/reports/attack.csv - hash: md5 - md5: aa61d0f5118327d164cfc37a466e5162 - size: 47376297 - params: - params.yaml: - files.directory: mnist - files.reports: reports - conf/clean.yaml: - attacks: - DeepFool: Deep - FastGradientMethod: FGM - HopSkipJump: HSJ - PixelAttack: Pixel - ProjectedGradientDescent: PGD - ThresholdAttack: Thresh - defences: - Control: Control - FeatureSqueezing: FSQ - GaussianAugmentation: Gauss-in - GaussianNoise: Gauss-out - HighConfidence: Conf - nb_epoch: Epochs - model_layers: Control - fillna: - Epochs: 20 - params: - Deep: attack.init.kwargs.nb_grads - FGM: attack.init.kwargs.eps - HSJ: attack.init.kwargs.max_iter - Pixel: attack.init.kwargs.th - PGD: attack.init.kwargs.eps - Thresh: attack.init.kwargs.th - Gauss-out: model.art.pipeline.postprocessor.kwargs.scale - Conf: model.art.pipeline.postprocessor.kwargs.cutoff - FSQ: model.art.pipeline.preprocessor.kwargs.bit_depth - Gauss-in: model.art.pipeline.preprocessor.kwargs.sigma - Control: model_layers - Epochs: model.trainer.nb_epoch - outs: - - path: mnist/reports/clean_attack.csv - hash: md5 - md5: ada4d505a6c72408e50b929b2869ffee - size: 19747128 - train: - cmd: python -m deckard.layers.experiment train --config_file mnist.yaml - params: - params.yaml: - data: - _target_: deckard.base.data.Data - generate: - _target_: deckard.base.data.generator.DataGenerator - name: torch_mnist - sample: - _target_: deckard.base.data.sampler.SklearnDataSampler - random_state: 0 - stratify: true - sklearn_pipeline: - _target_: deckard.base.data.sklearn_pipeline.SklearnDataPipeline - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - files: - _target_: deckard.base.files.FileConfig - adv_predictions_file: adv_predictions.json - attack_dir: attacks - attack_file: attack - attack_type: .pkl - data_dir: data - data_file: data - data_type: .pkl - directory: mnist - model_dir: models - model_file: model - model_type: .pt - name: default - params_file: params.yaml - predictions_file: predictions.json - reports: reports - score_dict_file: score_dict.json - model: - _target_: deckard.base.model.Model - art: - _target_: deckard.base.model.art_pipeline.ArtPipeline - data: - _target_: deckard.base.data.Data - generate: - _target_: deckard.base.data.generator.DataGenerator - name: torch_mnist - sample: - _target_: deckard.base.data.sampler.SklearnDataSampler - random_state: 0 - stratify: true - sklearn_pipeline: - _target_: deckard.base.data.sklearn_pipeline.SklearnDataPipeline - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - initialize: - clip_values: - - 0 - - 255 - criterion: - name: torch.nn.CrossEntropyLoss - optimizer: - lr: 0.01 - momentum: 0.9 - name: torch.optim.SGD - library: pytorch - data: - _target_: deckard.base.data.Data - generate: - _target_: deckard.base.data.generator.DataGenerator - name: torch_mnist - sample: - _target_: deckard.base.data.sampler.SklearnDataSampler - random_state: 0 - stratify: true - sklearn_pipeline: - _target_: deckard.base.data.sklearn_pipeline.SklearnDataPipeline - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: true - with_std: true - init: - _target_: deckard.base.model.ModelInitializer - name: torch_example.ResNet18 - num_channels: 1 - library: pytorch - trainer: - batch_size: 1024 - nb_epoch: 100 - scorers: - _target_: deckard.base.scorer.ScorerDict - accuracy: - _target_: deckard.base.scorer.ScorerConfig - direction: maximize - name: sklearn.metrics.accuracy_score - log_loss: - _target_: deckard.base.scorer.ScorerConfig - direction: minimize - name: sklearn.metrics.log_loss - outs: - - path: mnist/data/data.pkl - hash: md5 - md5: de934a5f5157970e5f30b8f3f1856a68 - size: 222320311 - - path: mnist/models/model.optimizer.pt - hash: md5 - md5: 1e527d70896a4a05a2d6ac103382cd50 - size: 44780845 - - path: mnist/models/model.pt - hash: md5 - md5: f01e051c7b7dfa20eca3fe1caab0b25e - size: 44785941 - - path: mnist/reports/train/default/predictions.json - hash: md5 - md5: 1e2cf0100bb5f0a42182021e12b00dd9 - size: 2882749 - - path: mnist/reports/train/default/score_dict.json - hash: md5 - md5: ebe552d99842320709ca466da6d3092c - size: 410 + - path: mnist/plots/aft_comparison_with_dummy.csv + md5: 00cfc38147e5ffed62c71eef81d76604 + size: 382 + - path: mnist/plots/aft_comparison_with_dummy.tex + md5: a7b04f60efcb56609a0374f4a614b322 + size: 566 + - path: mnist/plots/log_logistic_aft_dummy.eps + md5: 6c3c08024c4464c7069cc1ba0b0b2a29 + size: 62987 + - path: mnist/plots/log_logistic_epochs_partial_effect_dummy.eps + md5: 8c83fe60085369058bce8c4860a82e96 + size: 43270 + - path: mnist/plots/log_logistic_layers_partial_effect_dummy.eps + md5: df5b4c525afc9799f66348f89e4c0f11 + size: 48378 + - path: mnist/plots/log_normal_aft_dummy.eps + md5: 9792419c39453877f3a37361b5605ca0 + size: 61512 + - path: mnist/plots/log_normal_epochs_partial_effect_dummy.eps + md5: e55b95768eeaf862ba16d23e3ca17c53 + size: 45738 + - path: mnist/plots/log_normal_layers_partial_effect_dummy.eps + md5: 91d32fe10a4c39014c2b310388a34e1f + size: 48808 + - path: mnist/plots/weibull_aft_dummy.eps + md5: 75ca056699d7c578d7492d6dcacf9e57 + size: 60898 + - path: mnist/plots/weibull_epochs_partial_effect_dummy.eps + md5: d93f5cd06f362504b56215a89783990f + size: 44530 + - path: mnist/plots/weibull_layers_partial_effect_dummy.eps + md5: 0434dbd9406305ab7551e9ad8ce6bdc6 + size: 47796 diff --git a/examples/pytorch/mnist/dvc.yaml b/examples/pytorch/mnist/dvc.yaml index 851dc5fc..2baf8db6 100644 --- a/examples/pytorch/mnist/dvc.yaml +++ b/examples/pytorch/mnist/dvc.yaml @@ -128,34 +128,30 @@ stages: - ${files.directory}/plots/${cat_plot[5].file} - ${files.directory}/plots/${cat_plot[6].file} - ${files.directory}/plots/${cat_plot[7].file} - - ${files.directory}/plots/${cat_plot[8].file} - ${files.directory}/plots/${line_plot[0].file} - ${files.directory}/plots/${line_plot[1].file} - ${files.directory}/plots/${line_plot[2].file} - ${files.directory}/plots/${line_plot[3].file} - ${files.directory}/plots/${scatter_plot[0].file} params: - - files.directory - - files.reports - conf/plots.yaml: - line_plot - scatter_plot - cat_plot afr: - cmd: python -m deckard.layers.afr --dataset ${files.directory} --data_file ${files.directory}/${files.reports}/clean_attack.csv --duration_col adv_fit_time --dataset mnist --config_file conf/afr.yaml --plots_folder ${files.directory}/plots/ + cmd: python -m deckard.layers.afr --dataset ${files.directory} --data_file ${files.directory}/${files.reports}/clean_attack.csv --target adv_accuracy --duration_col predict_time --dataset mnist --config_file conf/afr.yaml --plots_folder ${files.directory}/plots/ deps: - ${files.directory}/${files.reports}/clean_attack.csv - - ${files.directory}/plots/${cat_plot[0].file} plots: - - ${files.directory}/plots/weibull_aft.pdf - - ${files.directory}/plots/weibull_epochs_partial_effect.pdf - - ${files.directory}/plots/weibull_layers_partial_effect.pdf - - ${files.directory}/plots/log_logistic_aft.pdf - - ${files.directory}/plots/log_logistic_epochs_partial_effect.pdf - - ${files.directory}/plots/log_logistic_layers_partial_effect.pdf - - ${files.directory}/plots/log_normal_aft.pdf - - ${files.directory}/plots/log_normal_epochs_partial_effect.pdf - - ${files.directory}/plots/log_normal_layers_partial_effect.pdf + - ${files.directory}/plots/weibull_aft.eps + - ${files.directory}/plots/weibull_epochs_partial_effect.eps + - ${files.directory}/plots/weibull_layers_partial_effect.eps + - ${files.directory}/plots/log_logistic_aft.eps + - ${files.directory}/plots/log_logistic_epochs_partial_effect.eps + - ${files.directory}/plots/log_logistic_layers_partial_effect.eps + - ${files.directory}/plots/log_normal_aft.eps + - ${files.directory}/plots/log_normal_epochs_partial_effect.eps + - ${files.directory}/plots/log_normal_layers_partial_effect.eps metrics: - ${files.directory}/plots/aft_comparison.csv outs: @@ -168,6 +164,7 @@ stages: - log_logistic - log_normal copy_results: - cmd: cp -r ${files.directory}/plots/* ~/ml_afr/mnist/ + cmd: mkdir -p ~/ml_afr/mnist/ && cp -r ${files.directory}/plots/* ~/ml_afr/mnist/ deps: - ${files.directory}/plots/ + - ${files.directory}/plots/ diff --git a/examples/pytorch/tuned.ipynb b/examples/pytorch/tuned.ipynb new file mode 100644 index 00000000..9ed15d18 --- /dev/null +++ b/examples/pytorch/tuned.ipynb @@ -0,0 +1,126 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "\n", + "df = pd.read_csv(\"cifar100/cifar100/reports/clean_attack.csv\", index_col=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "# ! cd ../../ && python -m pip install -e ." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(718, 233)" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from deckard.layers.clean_data import pareto_set\n", + "\n", + "sense_dict = {\n", + " \"accuracy\": \"max\",\n", + " \"adv_accuracy\": \"max\",\n", + " # \"atk_gen\": \"diff\",\n", + " \"def_value\": \"diff\",\n", + " \"def_gen\": \"diff\",\n", + " \"data.sample.random_state\": \"diff\",\n", + " # \"train_time\" : \"min\",\n", + " # \"predict_time\" : \"min\",\n", + " # \"model_layers\" : \"diff\",\n", + "}\n", + "pareto = pareto_set(df, sense_dict)\n", + "pareto.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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l5mZSVFREQBRUVGenrVjUSqVDB48mL1792Kz2fjzzz859dRTu/agBK/xSiBWWVnJpZde2uy2hQsX8sknn7QIxK699lpmzZrFtGnTmDBhwnFdNz09nRdffJE//vgDcH+6uOOOOwgPDz+u85aWlvLOO++wYcMGvv322w4ds2rVqmZj/w0kSeLrr79utqpG6B1Ol8yuw10ra9QR4afPJv/rFViLSyj89ntiFi7w+jUEwZtkWebulzeyP6uit5vSbYYnBPPULVN7LRirqanh2WefxWaztbgvKiqK999/nxtvvNEzNLlmzRo2bNjAggULWLJkSau5v/Lz8z3bbU3Qb0tERAR79+4FIC8vr1PHCt3DK3PE9Hp9iz/yadOmsWvXLnJycprdHhoail6vZ+nSpcd1zV9//ZUFCxYQFBTEzz//zI8//khdXR3z5s0jIyOjS+csKiriscceY/bs2bzzzjuYTKYOH/vWW2+1evusWbNEENZHpOdWUme246tTMTQm0OvnV6jVxF12CQB5X36No5W6q4IgnNi+/fZbJkyY4PmaNGkSn376aZv7Dx8+nG+++YYFCxZ43kcdDgefffYZZ511Fl988UWLY5omj9XrO5eCp+n+nUlCK3Qfr/SIpaSk8Nxzz/Hggw96xpslSWLRokX84x//4P333/fcvm7dOmpqatizZ0+Xr5eZmcntt99OUlISDz30EAqFO558+umnmTVrFosXL2blypVotdpOnXfjxo3MnTuXvXv3sn379g4ft379evR6Pd9//32L+8QQbN/RMD8sdWgoSmX3ZG4JnT6N/C+/xpSTS/5XKwi9cH63XEcQvEGSJJ66ZWrnhiYtVnQ6LUqFsptb5x09PTQ5d+5cnnzySc/PdrudFStWeOZ0tSYwMJAnnniCiy++mMcff5y0tDTA3Zt23333sWfPnmZpLJoORVoslk61z9kkxU5n3yOF7uGVQGzBggXce++9fPXVV6hUKm666SZuvvlmLr74Yj744APmzp3L6aefTnl5OatWrUKSpOMqtfDkk09isVhYtGiRJwgDd6R/wQUX8P777/Pmm29y6623duq8CxcuBODMM8/sVCD25ptvcv3114ulwH3cjvpA7Hiy6R+LpFQSd8XlHHj8KQpWfkfg7Fnddi1B8AZJktBpO/ZW4HRK4HKg06hQKvtHINbb1Go1CxcubHWO2NHGjRvHZ599xtdff81zzz1Haan7NWvZsmWMGDHCk71/0KDGFd+1nex5b7p/WJh358oKXeOVboH58+czd+5cZFnGbrezZcsWwP0H+Mwzz1BaWsp7773HypUrsdvtyLLMJZdc0qVr5ebmsm7dOgCmTJnS4v6GiYfLly/H3sU0Ah2d+Aiwfft2cnJyGDt2bJeuJfQMk8XOgfp5MONSuvfFJ3jSRAzJQ3FZrRR91fanYEEQBo577723Q/tJksT555/Pl19+2Sy7QNNak4mJiajV7lXf+fn5rc4/a0vDJH+gw6sthe7ltfGZZ599ltdee4277rqrWQmF1NRU3n33XUaMGIFGoyEhIYG7776b6667rkvXaQjCDAZDq6tKhg8fDkBZWRnbtm3r0jU680nvjTfeoLi4mMmTJzN//nzef/99T640oe/Yk1GO0yUTEaInIqTjgXZXSJJE/JWLACj/5VdcYh6GIAitaC848/X15dlnn/XkEMvJyfHM6TIYDJx88smAez7Zvn37OnQ9i8VCZmYm4E5lERMTcxytF7zFqxNlZs2axXXXXdfil3vSSSfxxRdfsGvXLn744QeuueaaLo/Zb9y4EXCv/GhNaGio55NCwzh7dzlw4ABr164F3KuP9u3bx+OPP84555zD77//3q3XFjrHm2WNOiIwdTQBqaORnU4c6zb0yDUFQehf9u3bh9FobPN+hULBFVdc0eznBk1HlVatWtWh6/366684HA7AncFA6Bu8Mkfsf//7H08//TSnn356txcUbVhu21aKCkmS8Pf3p7y8nCNHjnRrWyRJ4rHHHqOkpITdu3ezadMmrFYrBQUFXHfddTz//POcccYZx3UNWZY7tXqzoxp67QZK7932A+6l4cPj/bvl+WxN+EUXUp22G1faHqrSMyBJzCHsLgPt7/lYrFYrLpcLp9PZbHL28ZJl2fPdm+ft75qW9Gt43jvC4XDw6aeftij31/R5btgeMmQIvr6+nnOfdtppTJ06lY0bN/LVV19xww03EBgY2Oa1ZFnmww8/BGDy5MmcddZZA/p3KNOYB8/lcuGk9efC6XTicrkwm82tlm5s8/yy3OEOJ68EYs8++yxGo5Effvih2wOxigr3PJ/25nE1FGCtrq7u1rakpKSQkpLi+bm4uJgnnniCVatWYbfbufvuu0lJSSE+Pr7L17Db7ezfv98bzW1VVlZWt527r6iqc1BQZkKSQO0oY//+nsuZpEhJxnXwENkff0LhxRf22HUHqoHw99xRKpUKq9XaLefurvP2V03TQNTU1HR4JaMsy7z00kuMGDGCMWPGtLjfYrHw+eefA3DDDTe0OO+DDz7I9ddfT3Z2Nv/617/497//3ea1li9fzvbt24mOjubxxx/v9GrLE03TQMxmsyHRetBktVpxOByeId3O6GgxeK8EYoGBgdTU1HD99dd743Ttagiu2ivL0BC1dmYCozeEh4fzwgsvkJKSwgsvvIDJZOLVV1/lqaee6vI51Wo1SUlJXmylm9lsJisri4SEBHx8fLx+/r7k1z/zgSKSYgI4aczIHr121RWXc+SBh3EdOEicRovvkMQevf5AMZD+njuioWdeq9V6tYSNLMtYrVa0Wm2vZ6vvK2w2G8uWLfP8vGPHDg4ePNhqYHU0SZKwWCxcf/31XH755cyfP9+z+v7AgQO88cYbbN26ldtvv53zzjuvxfExMTG899573HzzzaxatQofHx/uvffeZh0Vdrudt99+m5deeomRI0fyyiuviNWS1Adi9Z8nNBpNu+lYVCoVcXFxnUr3kZ6e3uF9vRKI/eMf/+C2227r8ErI2tpaJk6c2KWeHrVajcPh8HTXtqZhDLy3CosvXryY7OxsvvrqK3755RdcLlezsf3OkCSp0wn7OsPHx6dbz98X7MtyB+/jh0X0/GNNGoIidRSutD2UfP4lIx95sGevP8AMhL/njlAoFCgUCpRKpVfTTDQMZUmSJNJXAI899hjLli1rNsRXVVXFZZddho+PD++99167K+qTkpJ44403yMrK4rfffuOf//wn+fn5WK1WDAYDEyZM4JNPPmn3HFFRUXz++ed8/PHH/Pe//2XmzJlMmTKFQYMGUVlZyZYtW9DpdNxzzz1cccUVqFReedvv91xy4zBjw/9Ka5RKJQqFAh8fn059qOnMBxWv/EbmzJnDiy++yH333ccjjzxyzBJDv/76a5evFRgYiNlsbre3qyFPSlBQUJevc7zuuOMOvv32W4xGI1VVVQQHB/daWwYyl0v2JHId2435w9qjmjEd+979VO3cRVXabgJTR/dKOwRB8K5//vOf/POf/+zy8Q0VZmJiYpg6darndqfT6SnI3ZGAV6lUctVVV3HppZfyn//8h3feecdzn4+PD999991x5e4UupdXArH7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mPItWA1z/EynFRoaashCvnv37gKzCvhJpm7n5ORkFi1axJYtW7h79y5FixalSZMmDB061LCKsCAydTsHBgayaNEijh49Snx8PA4ODtStW5c333yTli1b5sE7yn9WrlzJtGnTjPJ8gW7/3gkTJtC7d2/Dsfz2OSiBmBBCCCGEhcgcMSGEEEIIC5FATAghhBDCQiQQE0IIIYSwEAnEhBBCCCEsRAIxIYQQQggLkUBMCCGEEMJCJBATQgghhLAQCcSEEEIIISxEAjEhhBBCCAuRQEwIIYQQwkIkEBNCWB2tVsu+ffsYNmxYtvaWzI2oqChmzZqFr68v9erVo127dkycOJGIiAizPM9cQkJCmD59Ok2aNOHo0aOWro4Q4gkSiAkhrMqmTZvo0qUL7777Lv/88w9ardbkz7hw4QI9evSgWrVqrF+/nu+//57Y2FjWrFlDt27duHv3rsmfaWphYWGMHDkSX19fli5dSmxsrKWrJITIgARiQgir8sorr7BlyxZefPFFs5QfFxfH+++/T5UqVfD19aVQoUK0a9eOGTNmoFKpiIqK4tKlS2Z5til5enry448/8u2331q6KkKILNhZugJCCJETTk5OANSuXZtjx46ZvPxNmzYRFhZGu3btjI536NCBlStXcuPGDVq3bm3y55qara0tANWqVbNwTYQQWZFATAhhlRwdHc1S7oEDBwAoVKhQunONGzemcePGZnmuuTg4OFi6CkKILMjQpBDCKul7fEwtPDzcrOXnNRsb+WdeiPxMfkOFECKNuLg4AFQqlYVrIoQoCGRoUgiRr127do2lS5dy6NAh7t27R8mSJenatSsajeap9wYEBLB27VrOnTtHXFwcpUqVok2bNgwdOpRSpUoZrpszZw5z5841unfu3LlGxwIDA3P9HjZv3szYsWPTHXdxceH06dOG7w8dOsSgQYOMrtm9ezdlypQBIDQ0lEWLFnHo0CHu3LmDo6Mj3t7etGvXjiFDhuDq6pqt+qSmplKrVi2jY926dWPatGmG7xs1asTDhw8zPa+n1WrZvHkzf/zxB4GBgSQmJlK6dGk6derEO++8Q+HChbNVJyEKKukRE0LkW1u3bqVbt27cuXOHn376iSNHjvDFF1+wadMmli1blul9KSkpfPLJJyxdupRhw4YREBDAr7/+ire3N6tXr6Zr165cvnzZcP3IkSO5cOEC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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "sns.lineplot(\n", + " data=pareto,\n", + " x=\"def_value\",\n", + " y=\"accuracy\",\n", + " hue=\"def_gen\",\n", + " errorbar=\"se\",\n", + " err_style=\"bars\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "survey", + "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.10.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/pytorch/weibull.ipynb b/examples/pytorch/weibull.ipynb deleted file mode 100644 index def6e2d1..00000000 --- a/examples/pytorch/weibull.ipynb +++ /dev/null @@ -1,2062 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import numpy as np\n", - "from pathlib import Path\n", - "import seaborn as sns\n", - "\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from sklearn.preprocessing import StandardScaler\n", - "from sklearn.model_selection import train_test_split\n", - "\n", - "\n", - "from paretoset import paretoset\n", - "from lifelines import (\n", - " WeibullAFTFitter,\n", - " LogNormalAFTFitter,\n", - " LogLogisticAFTFitter,\n", - " CoxPHFitter,\n", - ")\n", - "from plots import calculate_failure_rate, drop_frames_without_results, min_max_scaling\n", - "import matplotlib\n", - "import argparse\n", - "from pathlib import Path\n", - "import logging\n", - "\n", - "logger = logging.getLogger(__name__)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "font = {\"family\": \"Times New Roman\", \"weight\": \"bold\", \"size\": 22}\n", - "\n", - "matplotlib.rc(\"font\", **font)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Adversarial Accuracy: \n", - " ResNet152: 0.08431102362204726 \n", - " Resnet101: 0.08595785440613028 \n", - " Resnet50: 0.09093333333333335 \n", - " Resnet34: 0.08867549668874172 \n", - " Resnet18: 0.07971698113207548 \n", - "\n" - ] - } - ], - "source": [ - "FOLDER = Path(\"output/plots/\")\n", - "csv_file = FOLDER / \"data.csv\"\n", - "data = pd.read_csv(csv_file, index_col=0)\n", - "data.columns = data.columns.str.strip()\n", - "data = data.applymap(lambda x: x.strip() if isinstance(x, str) else x)\n", - "data.def_value.replace(\"\", 0, inplace=True)\n", - "data.atk_value.replace(\"\", 0, inplace=True)\n", - "data = drop_frames_without_results(data)\n", - "data = calculate_failure_rate(data)\n", - "data = min_max_scaling(data)\n", - "data.dropna(axis=0, subset=[\"atk_value\", \"atk_param\"], inplace=True)\n", - "data.dropna(axis=0, subset=[\"def_value\", \"def_param\"], inplace=True)\n", - "# data=data[data['def_gen'] == 'Gauss-in']\n", - "# data=data[data['atk_gen'] == 'HSJ']\n", - "\n", - "print(\n", - " \"Adversarial Accuracy:\",\n", - " \"\\n\",\n", - " \"ResNet152:\",\n", - " data[data[\"model_layers\"] == 152].adv_accuracy.mean(skipna=True),\n", - " \"\\n\",\n", - " \"Resnet101:\",\n", - " data[data[\"model_layers\"] == 101].adv_accuracy.mean(skipna=True),\n", - " \"\\n\",\n", - " \"Resnet50:\",\n", - " data[data[\"model_layers\"] == 50].adv_accuracy.mean(skipna=True),\n", - " \"\\n\",\n", - " \"Resnet34:\",\n", - " data[data[\"model_layers\"] == 34].adv_accuracy.mean(skipna=True),\n", - " \"\\n\",\n", - " \"Resnet18:\",\n", - " data[data[\"model_layers\"] == 18].adv_accuracy.mean(skipna=True),\n", - " \"\\n\",\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "def plot_aft(\n", - " df,\n", - " file,\n", - " event_col,\n", - " duration_col,\n", - " title,\n", - " mtype,\n", - " xlabel=None,\n", - " ylabel=None,\n", - " replacement_dict={},\n", - " **kwargs,\n", - "):\n", - " if mtype == \"weibull\":\n", - " aft = WeibullAFTFitter(**kwargs)\n", - " elif mtype == \"log_normal\":\n", - " aft = LogNormalAFTFitter(**kwargs)\n", - " elif mtype == \"log_logistic\":\n", - " aft = LogLogisticAFTFitter(**kwargs)\n", - " elif mtype == \"cox\":\n", - " aft = CoxPHFitter(**kwargs)\n", - " assert (\n", - " duration_col in df.columns\n", - " ), f\"Column {duration_col} not in dataframe with columns {df.columns}\"\n", - " if event_col is not None:\n", - " assert (\n", - " event_col in df.columns\n", - " ), f\"Column {event_col} not in dataframe with columns {df.columns}\"\n", - " aft.fit(df, duration_col=duration_col, event_col=event_col)\n", - " ax = aft.plot()\n", - " labels = ax.get_yticklabels()\n", - " labels = [label.get_text() for label in labels]\n", - " for k, v in replacement_dict.items():\n", - " labels = [label.replace(k, v) for label in labels]\n", - " ax.set_yticklabels(labels)\n", - " ax.set_xlabel(xlabel)\n", - " ax.set_ylabel(ylabel)\n", - " ax.set_title(title)\n", - " ax.get_figure().tight_layout()\n", - " ax.get_figure().savefig(FOLDER / file)\n", - " logger.info(f\"Saved graph to {FOLDER / file}\")\n", - " plt.show()\n", - " return ax, aft\n", - "\n", - "\n", - "def plot_partial_effects(\n", - " file,\n", - " aft,\n", - " covariate_array,\n", - " values_array,\n", - " title,\n", - " xlabel=\"Covariate\",\n", - " ylabel=\"Failure rate\",\n", - " legend_kwargs={\"loc\": \"upper left\"},\n", - " replacement_dict={},\n", - " cmap=\"coolwarm\",\n", - " **kwargs,\n", - "):\n", - " plt.gcf().clear()\n", - " # kwargs.pop(\"replacement_dict\")\n", - " pareto = aft.plot_partial_effects_on_outcome(\n", - " covariate_array, values_array, cmap=cmap, **kwargs\n", - " )\n", - " labels = pareto.get_yticklabels()\n", - " labels = [label.get_text() for label in labels]\n", - " for k, v in replacement_dict.items():\n", - " labels = [label.replace(k, v) for label in labels]\n", - " pareto.set_yticklabels(labels)\n", - " pareto.legend(**legend_kwargs)\n", - " pareto.set_ylabel(ylabel)\n", - " pareto.set_xlabel(xlabel)\n", - " pareto.set_title(title)\n", - " pareto.get_figure().tight_layout()\n", - " pareto.get_figure().savefig(FOLDER / file)\n", - " logger.info(f\"Saved graph to {FOLDER / file}\")\n", - " return pareto\n", - "\n", - "\n", - "def score_model(aft, train, test):\n", - " train_score = aft.score(train)\n", - " test_score = aft.score(test)\n", - " scores = {\"train_score\": train_score, \"test_score\": test_score}\n", - " plt.show()\n", - " return scores\n", - "\n", - "\n", - "def clean_data_for_aft(data, kwarg_list, target=\"adv_failure_rate\"):\n", - " subset = data.copy()\n", - " assert (\n", - " target in subset\n", - " ), f\"Target {target} not in dataframe with columns {subset.columns}\"\n", - "\n", - " cleaned = pd.DataFrame()\n", - " kwarg_list.append(target)\n", - " for kwarg in kwarg_list:\n", - " cleaned = pd.concat([cleaned, subset[kwarg]], axis=1)\n", - " cols = cleaned.columns\n", - " cleaned = pd.DataFrame(subset, columns=cols)\n", - "\n", - " # if \"accuracy\" in cleaned.columns:\n", - " # cleaned = cleaned[~cleaned[cleaned['accuracy'] != 1e10]]\n", - " # cleaned = cleaned[~cleaned[cleaned['accuracy'] != -1e10]]\n", - " # if \"adv_accuracy\" in cleaned.columns:\n", - " # cleaned = cleaned[cleaned[cleaned['adv_accuracy'] != 1e10]]\n", - " # cleaned = cleaned[cleaned[cleaned['adv_accuracy'] != -1e10]]\n", - " cleaned.dropna(inplace=True, how=\"any\", axis=0)\n", - " y = cleaned[target]\n", - " assert (\n", - " target in cleaned\n", - " ), f\"Target {target} not in dataframe with columns {cleaned.columns}\"\n", - " return cleaned, y, data" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "kwarg_list = [\n", - " # \"accuracy\",\n", - " \"train_time\",\n", - " \"predict_time\",\n", - " \"atk_value\",\n", - " \"def_value\",\n", - " \"data.sample.random_state\",\n", - " \"adv_failure_rate\",\n", - " # \"failure_rate\",\n", - " \"model_layers\",\n", - " \"adv_fit_time\",\n", - " # \"atk_param\",\n", - " # \"def_param\",\n", - " \"model.art.pipeline.initialize.kwargs.optimizer.lr\",\n", - " # \"def_gen\",\n", - " # \"atk_gen\",\n", - " # \"adv_log_loss\",\n", - " # \"adv_accuracy\",\n", - " # \"adv_accuracy\",\n", - "]\n", - "\n", - "\n", - "# cleaned['accuracy'] = y" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "data.loc[:, \"adv_failures\"] = 1 - data.loc[:, \"adv_accuracy\"]\n", - "data.loc[:, \"ben_failures\"] = 1 - data.loc[:, \"accuracy\"]\n", - "target = \"adv_failures\"\n", - "duration_col = \"adv_fit_time\"\n", - "cleaned, y, data = clean_data_for_aft(data, kwarg_list, target=target)\n", - "X_train, X_test, y_train, y_test = train_test_split(\n", - " cleaned, y, test_size=0.2, random_state=42\n", - ")\n", - "assert (\n", - " target in cleaned\n", - "), f\"Target {target} not in dataframe with columns {cleaned.columns}\"" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# from sklearn.preprocessing import PowerTransformer\n", - "# pt = PowerTransformer(method='yeo-johnson', standardize=False)\n", - "# del X_train[target]\n", - "# del X_test[target]\n", - "# X_train_cols = X_train.columns\n", - "# X_train = pt.fit(X_train).transform(X_train)\n", - "# X_test = pt.transform(X_test)\n", - "# X_train = pd.DataFrame(X_train, columns=X_train_cols)\n", - "# X_test = pd.DataFrame(X_test, columns=X_train_cols)\n", - "# X_train[target] = y_train\n", - "# y_train = X_train[target]" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# sense_dict ={\n", - "# \"accuracy\" : \"max\",\n", - "# \"train_time\" : \"min\",\n", - "# \"predict_time\" : \"min\",\n", - "# # \"atk_value\" : \"diff\",\n", - "# # \"def_value\" : \"diff\",\n", - "# \"data.sample.random_state\" : \"diff\",\n", - "# \"adv_accuracy\" : \"min\",\n", - "# \"model_layers\" : \"diff\",\n", - "# # \"adv_fit_time\" : \"min\",\n", - "# # \"atk_param\" : \"diff\",\n", - "# # \"def_param\" : \"diff\",\n", - "# \"model.art.pipeline.initialize.kwargs.optimizer.lr\" : \"diff\",\n", - "# # \"adv_failure_rate\" : \"maximize\",\n", - "# }\n", - "# subset = X_train.loc[:, sense_dict.keys()]\n", - "# senses = sense_dict.values()\n", - "# these = paretoset(subset)\n", - "# X_train = X_train.iloc[these, :]" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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iIiIiLTEQIqIiIhISwykiIiIiLTEQIqIiIhISwykiIiIiLTElxYTkUE6fvw49uzZg8zMTBgbG6N///7w9fXF22+/re+i0UsuPz8f4eHhSExMxP3799G6dWsMGDAAPj4+cHJy0nfxqJHxpcVEZHBCQkIQHh6O3r17Y+/evXjw4AE8PDwgk8mwdetWjBgxQt9FpJfUlStX4OPjA6lUqnLM1NQUGzduxOjRo/VQMtIXdu0RkUGJjY1FeHg4AMDLywvNmjVD165dMXToUMhkMixcuBCZmZl6LiW9jB4/fozZs2erDaIAQCaTYfny5cjNzW3kkpE+MZAiIoNRXl6O0NBQId2lSxdhu2vXrgAgtEoR1dXevXvRqVMnREVFIT09HfHx8RgzZowoz7Nnz7B//349lZD0gWOkiMhgpKSk4N69e0K6RYsWwraZmZmw/csvv+DJkyewsrJq1PLRyy0/Px8RERHC75KDgwNCQkLw8OFDpKamCvkePXqkpxKSPrBFiogMxtmzZ0VpU1NTtfnkcrlKXqKaBAYGigLyKh999JEo3a1bt0YqETUFDKSIyGD8/vvvorSJieZG9/T09AYuDb0q2rVrJ2ybmJjAxcVFj6WhxsZAiogMRl5enihtZKT5K66goKChi0OviJycHGHb3d0dHTp00GNpqLExkCIig1FYWChKSyQSjXk1zbwiqqvk5GQAgI2NDZYuXarn0lBjYyBFRAZDJpPVOi+X0CNdyMvLQ2JiIpo3b47Q0FC0adNG30WiRsZAiogMRsuWLWudlw880oWtW7eisrISW7Zswbvvvqvv4pAeMJAiIoOhPDalulan9u3bN3RxyMCdOnUKcXFx2LJlC4YPH67v4pCeMJAiIoOh3CIgl8s15u3du3dDF4cM2IMHD7Bq1Sps27YNrq6uomM5OTlcXuMVwkCKiAzG4MGDRemysjK1+YyMjNC3b9/GKBIZoPLycixbtgxBQUGipQ7kcjmys7OxZMkSjsF7hXBlcyIyGO+99x7atm0rLG1QVFQkHFNsnXJ2dkbr1q0bu3hkIFavXo3k5GRhtp463bt3b8QSkT6xRYqIDIaZmRkWLlwopLOzs4XtBw8eAHix2vmCBQsauWRkKHbt2oUDBw5Um6d9+/awtrZupBKRvjGQIiKDMmHCBEybNg0AsH//fpSWluLBgwf4+eefYWpqik2bNuGtt97SbyHppXT8+HEEBwfXmI+tUa8Wdu0RkcFZvnw5evXqhcjISDg7O8PY2BgDBw7EnDlzGESRVrKysuDn51ersU+Ojo6NUCJqKiSVHBFHREREpBV27RERERFpiYEUERERkZYYSBERERFpiYEUERERkZYYSBERERFpiYEUERERkZYYSBERERFpiYEUERERkZYYSBERERFpiYEUERERkZYYSBERERFpiYEUERERkZYYSBERERFpiYEUERERkZYYSBERERFp6f8BjOQKODxRgekAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
modellifelines.WeibullAFTFitter
duration col'adv_fit_time'
event col'adv_failures'
number of observations1500
number of events observed1500
log-likelihood-5531.26
time fit was run2023-09-29 11:13:25 UTC
\n", - "
\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
coefexp(coef)se(coef)coef lower 95%coef upper 95%exp(coef) lower 95%exp(coef) upper 95%cmp tozp-log2(p)
lambda_adv_failure_rate-0.001.000.00-0.00-0.001.001.000.00-39.62<0.005inf
atk_value0.151.160.16-0.160.460.851.580.000.950.341.56
data.sample.random_state0.031.030.02-0.010.070.991.070.001.310.192.39
def_value-0.210.810.16-0.530.100.591.110.00-1.310.192.41
model.art.pipeline.initialize.kwargs.optimizer.lr-0.001.000.00-0.000.001.001.000.00-0.530.600.74
model_layers0.011.010.000.010.011.011.010.007.04<0.00538.88
predict_time-0.150.860.01-0.17-0.120.840.880.00-12.17<0.005110.86
train_time0.001.000.000.000.001.001.000.0010.81<0.00588.14
Intercept3.0020.180.182.653.3614.1428.790.0016.56<0.005202.20
rho_Intercept-0.840.430.02-0.88-0.800.410.450.00-43.75<0.005inf

\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Concordance0.84
AIC11082.52
log-likelihood ratio test800.84 on 8 df
-log2(p) of ll-ratio test554.32
\n", - "
" - ], - "text/latex": [ - "\\begin{tabular}{llrrrrrrrrrrr}\n", - " & & coef & exp(coef) & se(coef) & coef lower 95% & coef upper 95% & exp(coef) lower 95% & exp(coef) upper 95% & cmp to & z & p & -log2(p) \\\\\n", - "param & covariate & & & & & & & & & & & \\\\\n", - "\\multirow[c]{9}{*}{lambda_} & adv_failure_rate & -0.00 & 1.00 & 0.00 & -0.00 & -0.00 & 1.00 & 1.00 & 0.00 & -39.62 & 0.00 & inf \\\\\n", - " & atk_value & 0.15 & 1.16 & 0.16 & -0.16 & 0.46 & 0.85 & 1.58 & 0.00 & 0.95 & 0.34 & 1.56 \\\\\n", - " & data.sample.random_state & 0.03 & 1.03 & 0.02 & -0.01 & 0.07 & 0.99 & 1.07 & 0.00 & 1.31 & 0.19 & 2.39 \\\\\n", - " & def_value & -0.21 & 0.81 & 0.16 & -0.53 & 0.10 & 0.59 & 1.11 & 0.00 & -1.31 & 0.19 & 2.41 \\\\\n", - " & model.art.pipeline.initialize.kwargs.optimizer.lr & -0.00 & 1.00 & 0.00 & -0.00 & 0.00 & 1.00 & 1.00 & 0.00 & -0.53 & 0.60 & 0.74 \\\\\n", - " & model_layers & 0.01 & 1.01 & 0.00 & 0.01 & 0.01 & 1.01 & 1.01 & 0.00 & 7.04 & 0.00 & 38.88 \\\\\n", - " & predict_time & -0.15 & 0.86 & 0.01 & -0.17 & -0.12 & 0.84 & 0.88 & 0.00 & -12.17 & 0.00 & 110.86 \\\\\n", - " & train_time & 0.00 & 1.00 & 0.00 & 0.00 & 0.00 & 1.00 & 1.00 & 0.00 & 10.81 & 0.00 & 88.14 \\\\\n", - " & Intercept & 3.00 & 20.18 & 0.18 & 2.65 & 3.36 & 14.14 & 28.79 & 0.00 & 16.56 & 0.00 & 202.20 \\\\\n", - "rho_ & Intercept & -0.84 & 0.43 & 0.02 & -0.88 & -0.80 & 0.41 & 0.45 & 0.00 & -43.75 & 0.00 & inf \\\\\n", - "\\end{tabular}\n" - ], - "text/plain": [ - "\n", - " duration col = 'adv_fit_time'\n", - " event col = 'adv_failures'\n", - " number of observations = 1500\n", - "number of events observed = 1500\n", - " log-likelihood = -5531.26\n", - " time fit was run = 2023-09-29 11:13:25 UTC\n", - "\n", - "---\n", - " coef exp(coef) se(coef) coef lower 95% coef upper 95% exp(coef) lower 95% exp(coef) upper 95%\n", - "param covariate \n", - "lambda_ adv_failure_rate -0.00 1.00 0.00 -0.00 -0.00 1.00 1.00\n", - " atk_value 0.15 1.16 0.16 -0.16 0.46 0.85 1.58\n", - " data.sample.random_state 0.03 1.03 0.02 -0.01 0.07 0.99 1.07\n", - " def_value -0.21 0.81 0.16 -0.53 0.10 0.59 1.11\n", - " model.art.pipeline.initialize.kwargs.optimizer.lr -0.00 1.00 0.00 -0.00 0.00 1.00 1.00\n", - " model_layers 0.01 1.01 0.00 0.01 0.01 1.01 1.01\n", - " predict_time -0.15 0.86 0.01 -0.17 -0.12 0.84 0.88\n", - " train_time 0.00 1.00 0.00 0.00 0.00 1.00 1.00\n", - " Intercept 3.00 20.18 0.18 2.65 3.36 14.14 28.79\n", - "rho_ Intercept -0.84 0.43 0.02 -0.88 -0.80 0.41 0.45\n", - "\n", - " cmp to z p -log2(p)\n", - "param covariate \n", - "lambda_ adv_failure_rate 0.00 -39.62 <0.005 inf\n", - " atk_value 0.00 0.95 0.34 1.56\n", - " data.sample.random_state 0.00 1.31 0.19 2.39\n", - " def_value 0.00 -1.31 0.19 2.41\n", - " model.art.pipeline.initialize.kwargs.optimizer.lr 0.00 -0.53 0.60 0.74\n", - " model_layers 0.00 7.04 <0.005 38.88\n", - " predict_time 0.00 -12.17 <0.005 110.86\n", - " train_time 0.00 10.81 <0.005 88.14\n", - " Intercept 0.00 16.56 <0.005 202.20\n", - "rho_ Intercept 0.00 -43.75 <0.005 inf\n", - "---\n", - "Concordance = 0.84\n", - "AIC = 11082.52\n", - "log-likelihood ratio test = 800.84 on 8 df\n", - "-log2(p) of ll-ratio test = 554.32" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "weibull_dict = {\n", - " \"Intercept: rho_\": \"$\\\\rho$\",\n", - " \"Intercept: lambda_\": \"$\\lambda$\",\n", - " \"data.sample.random_state: lambda_\": \"Random State\",\n", - " \"def_value: lambda_\": \"Defence Strength\",\n", - " \"atk_value: lambda_\": \"Attack Strength\",\n", - " \"train_time: lambda_\": \"Training Time\",\n", - " \"predict_time: lambda_\": \"Inference Time\",\n", - " \"adv_accuracy: lambda_\": \"Adv. Accuracy\",\n", - " \"accuracy: lambda_\": \"Ben. Accuracy\",\n", - " \"adv_fit_time: lambda_\": \"Adv. Fit Time\",\n", - " \"adv_log_loss: lambda_\": \"Adv. Log Loss\",\n", - " \"adv_failure_rate: lambda_\": \"Adv. Failure Rate\",\n", - " \"failure_rate: lambda_\": \"Ben. Failure Rate\",\n", - " \"model_layers: lambda_\": \"No. of Layers\",\n", - " \"model.art.pipeline.initialize.kwargs.optimizer.lr: lambda_\": \"Learning Rate\",\n", - " \"def_gen\": \"Defence\",\n", - "}\n", - "\n", - "weibull_afr, wft = plot_aft(\n", - " X_train,\n", - " file=\"weibull_aft.pdf\",\n", - " event_col=target,\n", - " duration_col=duration_col,\n", - " title=\"Weibull AFR Model\",\n", - " mtype=\"weibull\",\n", - " replacement_dict=weibull_dict,\n", - ")\n", - "wft.print_summary()\n", - "wft_scores = score_model(wft, X_train, X_test)" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/tmp/ipykernel_773113/12050270.py:64: UserWarning: FixedFormatter should only be used together with FixedLocator\n", - " pareto.set_yticklabels(labels)\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxwAAAGyCAYAAABujsK/AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAD/bElEQVR4nOzdZ1QTeRcG8GcSEjpSRLBixd5777r2rq+KvSv2Vdfuqmt37WXtioqKotixN8SCXbFioygoSA2kzvshm1lCAgRICOX+zvHIZCYzN5NMufNvDMuyLAghhBBCCCHEAHjGDoAQQgghhBCSd1HCQQghhBBCCDEYSjgIIYQQQgghBkMJByGEEEIIIcRgKOEghBBCCCGEGAwlHIQQQgghhBCDoYSDEEIIIYQQYjCUcBBCCCGEEEIMhhIOQgghhBBCiMHky4TjypUrqFevHoYOHQqJRKKXdYpEIhw7dgw9e/bEH3/8oZd16kNISAiWLl2Kdu3aoXr16mjfvj3WrFmDmJgYbhmWZXHmzBkMGjQI9evXR7169TBkyBD4+fkZMfLcgfad/t28eROjRo1C48aNUatWLfzvf//D+fPnwbKssUMjRM2hQ4dQq1Yt/P7771rnBwYGYsGCBahZsyZCQkKyOTpiaLpcX4mmL1++oF27dmjbti2+fPmiNs+Y91Lh4eHYvHkzmjdvDm9vb435OfU+L7cw0XXBHTt2YO3atanOFwgEsLS0RNGiRVGjRg30798f5cqV00uQ+ubl5YWYmBj4+/vj3bt3qFKlSpbW9/fff+PkyZOIiIgAALi6uur8Xn9/f5w/fx4BAQH4+PFjhrZrbW2NgICAVOffvn0b8+bNw/LlyzF16lRcvHgRCxYswM6dO3H58mX4+PiAYRhMmzYNZmZmWL9+PUQiEf744w/cu3cP9+7dw9KlS9GnT58MxZVfiMXiDO27oKAgdOzYUWM9/fr1w+LFi9Pc1u7du7Fq1Sqt82bPno2hQ4dm6bPkBCzLYtGiRfjy5QuWLVsGPp+Pv/76C76+vnjy5AnevXuHKVOmaLyvUqVKkMvlaa7b398f9vb2BoqcGENgYCCOHTuGR48e4d27dxl6r7u7OyZOnJjlGDw9PZGQkIAzZ85g7ty5sLOz42Jbs2ZNnnvwcPjwYTx58gTXr19HXFycxnyBQAALCwsULFgQZcuWxW+//YbffvsNPF7ee7apy/XVzMwsW2O6desWRo0aler8hw8fwsbGBm3btsXXr1+1LlO0aFFcu3ZN7bV169Zh+/btGsvOnz8fbm5uGY7zypUrXKJx9epVDB8+HACwfPlynD59GlFRUQAydi+VFXFxcVi0aBGuXLmCpKQkrctk5T4vPR4eHoiIiMD06dN1Wt7f3x8XLlzA3bt3ERwcnKFtLV++HD179jTOsczqSKFQsHFxcez58+fZqlWrsq6urqyrqyvbrFkzduTIkezo0aPZ5s2bc69XqFCBXb58OatQKHTdhF7duXMn1XmXL19m69atyw4ZMoQVi8VZ3pZYLGZFIhFbt25d1tXVlZ01a1aG1yGRSNh27dpx++/8+fPst2/fNP59+vSJvXbtGtu1a1e2du3aqa4vNDSUrVWrFrto0SK11w8cOMBt4/379+xff/3Furq6sj9//uSWiY6OZtu2bcu6urqykyZNyvBnyYpnz56xMTEx2brNzMrMvouLi2Nv377N/u9//+O+B1dXV/bAgQNpbkt1/F24cIGtWrUqW6VKFdbHx4eNiYkx2jGmb/v27WNdXV3ZZ8+eca+JxWK2X79+rKurK9urVy+t75NIJOynT5/Y4cOHq+3ThQsXsu/fv2fj4uKy6yMQI5DL5eyAAQO4733v3r0a582goCD25s2b7JgxY1hXV1d248aNetn2wYMH2Zo1a7K///672usSiYRVKBTsP//8w8UVHBysl23mBB8+fOA+V8OGDdkLFy6wr169Yt+9e8devHiRdXNz4+b36tWLjYyMNFgsaV3rDUXX62t2k8vlbGhoKDtr1iy1c+GmTZvY+Ph4brnExET27NmzbI0aNbhlateuzb548YKVSCQa65VKpWxYWBg7evRo1tXVle3WrRv79u1bViqVZirOz58/s23atGFbt27Nfv78mXs9Pj6ejY2NZWvXrp3pe6nMEovF7JMnT7j9ceLECY35Wb3P00Yul7Nt2rRh69WrxyYmJmbovUlJSWybNm1SvW8MCwtjP3z4wF66dIm7jqb8XNl5LOuccCSX/MJ+79497nW5XM56eXmxVapU4eYvWbIk08FlVnx8PNu1a9ds326vXr2y9EOcOHGi1v2qTUREBNuoUaNU569YsYK7+KZ09epV9sKFC2x0dDRbuXJltlatWhrLhIeHs/v372e/f/+e4c+RFYMHD84VF+as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yvrtt9+w2+04HA4yMzM5evQov/76K//5z38YMGAAH3zwQaX+jhav8b/qqqtqIstCCKRJVY3q168fTz31FO+++y6vvvrqWY9PSUnhlVde4dZbb630tS677DLCw8M9zaqysrI8+4rXdgwaNMgrOHjxxRfZu3cvANOnT6dPnz7079/fsz8vL4+JEydy6NChEhP+FWnTpk297IzWrVMwS5YnkJuRC2FBOFQjOsVKfl4eQcHBXscqikJ+TB8e/nASW07M4e91/Yho2vys12h0w9W02XOIw69OZ9cDL2Js3JCIIZfU1FsSQtQSVVXZMGgcGRu2n/3geir04h70Xz23TjXHWbx4cZn7LBYL06dPZ+PGjXz11Vf4+/ufNb2iYd71ej0TJkzwVTaFEGeQgKOazjYzeIcOHdi2bRsffvih14P8mfLz8/npp5+qnA+DwcDkyZN54YUXAPdIFX379gUgKSkJcP9Cfeyxx7zO27dvX4n1ony6XC6eeOIJDh06VO6127VrV+V8n0sXdXIHFccOpdClXxBJuf40CbSSV0rAARDaqSfpNicWu4N1c/+P656eVqHrxEx9mLyDR0mYv4ytN0yi3+/fENKn69lPFELUbXXoQfxCcPLkyRKT3JZm27ZtTJs2jTfffLPc4w4fPuxpDvzII4941eALIXxLAo5qmjRpUpntRs/06aeflru/uuNkjx07lsOHDzNz5kwWLFjAyJEjycnJYeXKlej1et566y3at2/vdU779u29foF37NjRs/z666/z559/nvW69TXgiGpoIqqhkYST6XTp15qDSX40CUynoKAAp9NZokOiRqPhrddeg/WLaR2i4spIRhPa8KzXUTQaLpr5NvaMbFJXrWfTqHvp/+dcAju0rqm3JoSoYYqi0H/1XJz558d8MU6nE6vFitFk9Pzu0/qZ61TtRnR0NAcPHqSgoIDs7GwOHz7Mli1bWLp0aYnhYBctWsSkSZPKHeCkaJSrq6++mnvvvbcmsy7EBU8Cjmq69tprmTlz5rnOhsezzz7LRRddxKxZsxg0aBBarZZ+/frx0EMPlQg2AF555RWeeuop4uLiuO222zy1G4sWLWLWrFkVumZ9DTgALuoUwvI/k1BcDrItBlSNAcVlIy83t9Rajq6XD8ViS8YZux/bxt8wXX1Hha6jNRroOf9j/hk6gczNu9g0/C4uXjMPc7PG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BQCMHz+ecePGVf8m1GMVLT+n0+mpbTx58iT33XcfTz/9NMePH0dVVXbt2sWiRYuYMWMGAQEBXulJ+fnWihUreOedd8563Jm/Gx955BGGDRsGwHfffYfdbufgwYNs27YNf39/Pv74YyIjI73OURSFDz/8kFatWuFwODxl9sMPP2C322nVqpXXlz5FGjRowMcff0xAQAC7du1i586duFwuvv/+ewCGDRvGo48+WuV7IISiyoDK4jyydOlSZs2axZEjR9BqtfTu3ZuHHnpIgo1akJaWxmeffcZff/1FfHw8qqoSERFBx44dGTJkCFdffbXn288z2Ww2ZsyYweLFi0lOTiYgIIArr7ySiRMner7xK01KSgoff/wxf/75J3l5eURFRXH99ddz++23e7UnF249evQgPz+/zCY4Wq2WG2+8kZdfftlre22Xz+7du5k+fTrbt2/H5XLRpk0b7rrrrhLfyl5oKlt++/fv58svv2Tbtm2kpKRgMBiIjIykd+/eXHXVVZ6+VGWR8qu+I0eOcP3115fbL6LIXXfd5TUBILiby82bN48ffviBuLg4jEYjAwYMYNKkSZ6O/qXJzc3l008/ZdmyZWRkZBAWFsY111zDfffdV+5AGrGxsXz88cds2LABq9VKs2bNuOWWW7j++uvLnVRXiLORgEMIIYQQQghRY6RJlRBCCCGEEKLGSMAhhBBCCCGEqDEScAghhBBCCCFqjAQcQgghhBBCiBojAYcQQgghhBCixkjAIYQQQgghhKgxEnAIIYQQQgghaowEHEIIIYQQQogaIwGHEEIIIYQQosZIwCGEEEIIIYSoMRJwCCGEEEIIIWqMBBxCCCGEEEKIGiMBhxBCCCGEEKLG6M51BoQQQlTMNddcw7///uuz9D744AOuuuqqKp3rcrnQaOQ7q3NF7r8Qoj6R31ZCiPPaU089RY8ePZgzZ865zkq15OTkcPjwYZ+m2a1bt0qfExcXx3PPPceBAwd8mpcLicvlYs2aNTzwwAMMGTKkSmls27aNV155hczMTN9mTgghaoDUcAgh6pR27dpV6/xnn32WCRMmAJCens7PP/8MwHfffcett95a3eydMzt37kRVVZ+lFxkZSVRUVKXO+fPPP/nss8947bXXaN26tc/yciFZtGgRX375pSd4bNKkSZXS6dWrFxqNhltuuYVXX32V7t27+zKbQgjh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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "pareto_dict = {\n", - " \"model_layers=18\": \"18\",\n", - " \"model_layers=34\": \"34\",\n", - " \"model_layers=50\": \"50\",\n", - " \"model_layers=101\": \"101\",\n", - " \"model_layers=152\": \"152\",\n", - "}\n", - "pareto_weibull = plot_partial_effects(\n", - " file=\"weibull_partial_effects.pdf\",\n", - " aft=wft,\n", - " covariate_array=\"model_layers\",\n", - " values_array=[18, 34, 50, 101, 152],\n", - " title=\"Partial Effects of No. of Layers on Failure Rate for Weibull AFR\",\n", - " replacement_dict=pareto_dict,\n", - " ylabel=\"% Chance of Survival\",\n", - " xlabel=\"Time $T$ (seconds)\",\n", - " legend_kwargs={\n", - " \"title\": \"No. of Layers\",\n", - " \"labels\": [\"18\", \"34\", \"50\", \"101\", \"152\"],\n", - " },\n", - ")\n", - "\n", - "# weibull_accuracy = plot_partial_effects(\n", - "# file = \"weibull_partial_effect_accuracy.pdf\",\n", - "# aft = wft,\n", - "# covariate_array = \"accuracy\",\n", - "# values_array = [.9, .99, .999, .9999],\n", - "# replacement_dict=weibull_dict,\n", - "# title=\"Partial Effects of Benign Accuracy on Failure Rate\",\n", - "# ylabel=\"% Chance of Survival\",\n", - "# xlabel=\"Time $T$ (seconds)\",\n", - "# legend = {\"title\" : \"Benign Accuracy\"},\n", - "# )" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/cmeyers/deckard/env/lib/python3.8/site-packages/lifelines/fitters/coxph_fitter.py:1614: ConvergenceWarning: Newton-Raphson failed to converge sufficiently. Please see the following tips in the lifelines documentation: https://lifelines.readthedocs.io/en/latest/Examples.html#problems-with-convergence-in-the-cox-proportional-hazard-model\n", - " warnings.warn(\n" - ] - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
modellifelines.CoxPHFitter
duration col'adv_fit_time'
event col'adv_failures'
baseline estimationbreslow
number of observations1500
number of events observed1500
partial log-likelihood-7421.70
time fit was run2023-09-29 11:13:28 UTC
\n", - "
\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
coefexp(coef)se(coef)coef lower 95%coef upper 95%exp(coef) lower 95%exp(coef) upper 95%cmp tozp-log2(p)
train_time-0.001.000.00-0.00-0.001.001.000.00-4.25<0.00515.52
predict_time0.031.030.010.020.041.021.040.004.21<0.00515.26
atk_value-0.090.910.07-0.230.050.801.050.00-1.310.192.40
def_value0.041.050.07-0.090.180.911.200.000.630.530.92
data.sample.random_state-0.010.990.01-0.030.000.971.000.00-1.570.123.10
adv_failure_rate0.011.010.000.010.011.011.010.0028.70<0.005599.53
model_layers-0.001.000.00-0.00-0.001.001.000.00-5.20<0.00522.23
model.art.pipeline.initialize.kwargs.optimizer.lr-0.001.000.00-0.000.001.001.000.00-0.130.900.15

\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Concordance0.92
Partial AIC14859.40
log-likelihood ratio test4105.41 on 8 df
-log2(p) of ll-ratio testinf
\n", - "
" - ], - "text/latex": [ - "\\begin{tabular}{lrrrrrrrrrrr}\n", - " & coef & exp(coef) & se(coef) & coef lower 95% & coef upper 95% & exp(coef) lower 95% & exp(coef) upper 95% & cmp to & z & p & -log2(p) \\\\\n", - "covariate & & & & & & & & & & & \\\\\n", - "train_time & -0.00 & 1.00 & 0.00 & -0.00 & -0.00 & 1.00 & 1.00 & 0.00 & -4.25 & 0.00 & 15.52 \\\\\n", - "predict_time & 0.03 & 1.03 & 0.01 & 0.02 & 0.04 & 1.02 & 1.04 & 0.00 & 4.21 & 0.00 & 15.26 \\\\\n", - "atk_value & -0.09 & 0.91 & 0.07 & -0.23 & 0.05 & 0.80 & 1.05 & 0.00 & -1.31 & 0.19 & 2.40 \\\\\n", - "def_value & 0.04 & 1.05 & 0.07 & -0.09 & 0.18 & 0.91 & 1.20 & 0.00 & 0.63 & 0.53 & 0.92 \\\\\n", - "data.sample.random_state & -0.01 & 0.99 & 0.01 & -0.03 & 0.00 & 0.97 & 1.00 & 0.00 & -1.57 & 0.12 & 3.10 \\\\\n", - "adv_failure_rate & 0.01 & 1.01 & 0.00 & 0.01 & 0.01 & 1.01 & 1.01 & 0.00 & 28.70 & 0.00 & 599.53 \\\\\n", - "model_layers & -0.00 & 1.00 & 0.00 & -0.00 & -0.00 & 1.00 & 1.00 & 0.00 & -5.20 & 0.00 & 22.23 \\\\\n", - "model.art.pipeline.initialize.kwargs.optimizer.lr & -0.00 & 1.00 & 0.00 & -0.00 & 0.00 & 1.00 & 1.00 & 0.00 & -0.13 & 0.90 & 0.15 \\\\\n", - "\\end{tabular}\n" - ], - "text/plain": [ - "\n", - " duration col = 'adv_fit_time'\n", - " event col = 'adv_failures'\n", - " baseline estimation = breslow\n", - " number of observations = 1500\n", - "number of events observed = 1500\n", - " partial log-likelihood = -7421.70\n", - " time fit was run = 2023-09-29 11:13:28 UTC\n", - "\n", - "---\n", - " coef exp(coef) se(coef) coef lower 95% coef upper 95% exp(coef) lower 95% exp(coef) upper 95%\n", - "covariate \n", - "train_time -0.00 1.00 0.00 -0.00 -0.00 1.00 1.00\n", - "predict_time 0.03 1.03 0.01 0.02 0.04 1.02 1.04\n", - "atk_value -0.09 0.91 0.07 -0.23 0.05 0.80 1.05\n", - "def_value 0.04 1.05 0.07 -0.09 0.18 0.91 1.20\n", - "data.sample.random_state -0.01 0.99 0.01 -0.03 0.00 0.97 1.00\n", - "adv_failure_rate 0.01 1.01 0.00 0.01 0.01 1.01 1.01\n", - "model_layers -0.00 1.00 0.00 -0.00 -0.00 1.00 1.00\n", - "model.art.pipeline.initialize.kwargs.optimizer.lr -0.00 1.00 0.00 -0.00 0.00 1.00 1.00\n", - "\n", - " cmp to z p -log2(p)\n", - "covariate \n", - "train_time 0.00 -4.25 <0.005 15.52\n", - "predict_time 0.00 4.21 <0.005 15.26\n", - "atk_value 0.00 -1.31 0.19 2.40\n", - "def_value 0.00 0.63 0.53 0.92\n", - "data.sample.random_state 0.00 -1.57 0.12 3.10\n", - "adv_failure_rate 0.00 28.70 <0.005 599.53\n", - "model_layers 0.00 -5.20 <0.005 22.23\n", - "model.art.pipeline.initialize.kwargs.optimizer.lr 0.00 -0.13 0.90 0.15\n", - "---\n", - "Concordance = 0.92\n", - "Partial AIC = 14859.40\n", - "log-likelihood ratio test = 4105.41 on 8 df\n", - "-log2(p) of ll-ratio test = inf" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/tmp/ipykernel_773113/12050270.py:64: UserWarning: FixedFormatter should only be used together with FixedLocator\n", - " pareto.set_yticklabels(labels)\n" - ] - }, - { - "data": { - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "cox_dict = {\n", - " \"adv_failure_rate\": \"Adv. Failure Rate\",\n", - " \"def_value\": \"Defence Strength\",\n", - " \"data.sample.random_state\": \"Random State\",\n", - " \"train_time\": \"Training Time\",\n", - " \"model_layers\": \"No. of Layers\",\n", - " \"model.art.pipeline.initialize.kwargs.optimizer.lr\": \"Learning Rate\",\n", - " \"adv_accuracy\": \"Adv. Accuracy\",\n", - " \"adv_fit_time\": \"Adv. Fit Time\",\n", - " \"adv_log_loss\": \"Adv. Log Loss\",\n", - " \"predict_time\": \"Inference Time\",\n", - " \"accuracy\": \"Ben. Accuracy\",\n", - " \"failure_rate\": \"Ben. Failure Rate\",\n", - " \"atk_value\": \"Attack Strength\",\n", - "}\n", - "\n", - "cox_afr, cft = plot_aft(\n", - " X_train,\n", - " file=\"cox_aft.pdf\",\n", - " event_col=target,\n", - " duration_col=duration_col,\n", - " title=\"Cox AFR Model\",\n", - " mtype=\"cox\",\n", - " replacement_dict=cox_dict,\n", - ")\n", - "cox_scores = score_model(cft, X_train, X_test)\n", - "cft.print_summary()\n", - "cox_partial = plot_partial_effects(\n", - " file=\"cox_partial_effects.pdf\",\n", - " aft=cft,\n", - " covariate_array=\"model_layers\",\n", - " values_array=[18, 34, 50, 101, 152],\n", - " replacement_dict=cox_dict,\n", - " title=\"Survival Time for Cox AFR\",\n", - " ylabel=\"% Chance of Survival\",\n", - " xlabel=\"Time $T$ (seconds)\",\n", - " legend_kwargs={\n", - " \"title\": \"No. of Layers\",\n", - " \"labels\": [\"18\", \"34\", \"50\", \"101\", \"152\"],\n", - " },\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
modellifelines.LogNormalAFTFitter
duration col'adv_fit_time'
event col'adv_failures'
number of observations1500
number of events observed1500
log-likelihood-5374.54
time fit was run2023-09-29 11:13:31 UTC
\n", - "
\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
coefexp(coef)se(coef)coef lower 95%coef upper 95%exp(coef) lower 95%exp(coef) upper 95%cmp tozp-log2(p)
mu_adv_failure_rate-0.001.000.00-0.00-0.001.001.000.00-31.84<0.005736.80
atk_value0.081.090.16-0.220.390.801.480.000.520.600.74
data.sample.random_state0.021.020.02-0.020.060.981.060.000.830.411.30
def_value-0.160.850.16-0.480.160.621.170.00-0.980.321.62
model.art.pipeline.initialize.kwargs.optimizer.lr-0.001.000.00-0.000.001.001.000.00-0.060.950.07
model_layers0.011.010.000.010.011.011.010.007.13<0.00539.81
predict_time-0.210.810.02-0.26-0.160.770.850.00-8.37<0.00553.94
train_time0.001.000.000.000.001.001.000.007.13<0.00539.89
Intercept2.027.540.171.682.365.3710.610.0011.63<0.005101.36
sigma_Intercept0.842.310.020.800.872.232.390.0045.86<0.005inf

\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Concordance0.84
AIC10769.08
log-likelihood ratio test925.72 on 8 df
-log2(p) of ll-ratio test643.78
\n", - "
" - ], - "text/latex": [ - "\\begin{tabular}{llrrrrrrrrrrr}\n", - " & & coef & exp(coef) & se(coef) & coef lower 95% & coef upper 95% & exp(coef) lower 95% & exp(coef) upper 95% & cmp to & z & p & -log2(p) \\\\\n", - "param & covariate & & & & & & & & & & & \\\\\n", - "\\multirow[c]{9}{*}{mu_} & adv_failure_rate & -0.00 & 1.00 & 0.00 & -0.00 & -0.00 & 1.00 & 1.00 & 0.00 & -31.84 & 0.00 & 736.80 \\\\\n", - " & atk_value & 0.08 & 1.09 & 0.16 & -0.22 & 0.39 & 0.80 & 1.48 & 0.00 & 0.52 & 0.60 & 0.74 \\\\\n", - " & data.sample.random_state & 0.02 & 1.02 & 0.02 & -0.02 & 0.06 & 0.98 & 1.06 & 0.00 & 0.83 & 0.41 & 1.30 \\\\\n", - " & def_value & -0.16 & 0.85 & 0.16 & -0.48 & 0.16 & 0.62 & 1.17 & 0.00 & -0.98 & 0.32 & 1.62 \\\\\n", - " & model.art.pipeline.initialize.kwargs.optimizer.lr & -0.00 & 1.00 & 0.00 & -0.00 & 0.00 & 1.00 & 1.00 & 0.00 & -0.06 & 0.95 & 0.07 \\\\\n", - " & model_layers & 0.01 & 1.01 & 0.00 & 0.01 & 0.01 & 1.01 & 1.01 & 0.00 & 7.13 & 0.00 & 39.81 \\\\\n", - " & predict_time & -0.21 & 0.81 & 0.02 & -0.26 & -0.16 & 0.77 & 0.85 & 0.00 & -8.37 & 0.00 & 53.94 \\\\\n", - " & train_time & 0.00 & 1.00 & 0.00 & 0.00 & 0.00 & 1.00 & 1.00 & 0.00 & 7.13 & 0.00 & 39.89 \\\\\n", - " & Intercept & 2.02 & 7.54 & 0.17 & 1.68 & 2.36 & 5.37 & 10.61 & 0.00 & 11.63 & 0.00 & 101.36 \\\\\n", - "sigma_ & Intercept & 0.84 & 2.31 & 0.02 & 0.80 & 0.87 & 2.23 & 2.39 & 0.00 & 45.86 & 0.00 & inf \\\\\n", - "\\end{tabular}\n" - ], - "text/plain": [ - "\n", - " duration col = 'adv_fit_time'\n", - " event col = 'adv_failures'\n", - " number of observations = 1500\n", - "number of events observed = 1500\n", - " log-likelihood = -5374.54\n", - " time fit was run = 2023-09-29 11:13:31 UTC\n", - "\n", - "---\n", - " coef exp(coef) se(coef) coef lower 95% coef upper 95% exp(coef) lower 95% exp(coef) upper 95%\n", - "param covariate \n", - "mu_ adv_failure_rate -0.00 1.00 0.00 -0.00 -0.00 1.00 1.00\n", - " atk_value 0.08 1.09 0.16 -0.22 0.39 0.80 1.48\n", - " data.sample.random_state 0.02 1.02 0.02 -0.02 0.06 0.98 1.06\n", - " def_value -0.16 0.85 0.16 -0.48 0.16 0.62 1.17\n", - " model.art.pipeline.initialize.kwargs.optimizer.lr -0.00 1.00 0.00 -0.00 0.00 1.00 1.00\n", - " model_layers 0.01 1.01 0.00 0.01 0.01 1.01 1.01\n", - " predict_time -0.21 0.81 0.02 -0.26 -0.16 0.77 0.85\n", - " train_time 0.00 1.00 0.00 0.00 0.00 1.00 1.00\n", - " Intercept 2.02 7.54 0.17 1.68 2.36 5.37 10.61\n", - "sigma_ Intercept 0.84 2.31 0.02 0.80 0.87 2.23 2.39\n", - "\n", - " cmp to z p -log2(p)\n", - "param covariate \n", - "mu_ adv_failure_rate 0.00 -31.84 <0.005 736.80\n", - " atk_value 0.00 0.52 0.60 0.74\n", - " data.sample.random_state 0.00 0.83 0.41 1.30\n", - " def_value 0.00 -0.98 0.32 1.62\n", - " model.art.pipeline.initialize.kwargs.optimizer.lr 0.00 -0.06 0.95 0.07\n", - " model_layers 0.00 7.13 <0.005 39.81\n", - " predict_time 0.00 -8.37 <0.005 53.94\n", - " train_time 0.00 7.13 <0.005 39.89\n", - " Intercept 0.00 11.63 <0.005 101.36\n", - "sigma_ Intercept 0.00 45.86 <0.005 inf\n", - "---\n", - "Concordance = 0.84\n", - "AIC = 10769.08\n", - "log-likelihood ratio test = 925.72 on 8 df\n", - "-log2(p) of ll-ratio test = 643.78" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/tmp/ipykernel_773113/12050270.py:64: UserWarning: FixedFormatter should only be used together with FixedLocator\n", - " pareto.set_yticklabels(labels)\n" - ] - }, - { - "data": { - "image/png": "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UlJStJdffjmojAEDBmiHDh2q8DxpaWnawIEDtZSUFG3FihWaqqra888/r6WkpGi33nqrVlZWVi/X2xBRVVVbvXq1NnnyZK1du3ZaSkqK1qtXr0rT17eNVq1apXXq1Enr3bu3dvToUa20tFQbM2aMlpKSor3yyiunfwMaMDW1naZp2vTp06t8Jq+55hpNVdWgPMJ2dcuOHTu0iy++uNLvxO+++65cHrfbrT366KNaSkqK9sADD2hOp1PbvHmz1q5dO61Hjx7a5s2bKzxXfn6+du2112opKSna3LlzNU3TtA8//FBLSUnRhg0bpuXm5laYb+vWrVrPnj21jh07atu2bdMcDod29913aykpKdrDDz+suVyuGl+36NprQCxevJhZs2YBcOONN2IymWjevDkDBw7E6XQybdo09u7de5ZreWGwZMmSKo8PGzaMpKQk//706dPZsGEDABMmTADgmmuuITo6muzsbCZPnozdbg8qw+FwMHnyZLKysmjcuDFDhw5FkiTGjx8PwMaNG3n22Wfr8rLOC+x2O5988gkjRoxgypQp/Prrr2iadsp89WmjgwcP8uCDD+J0OhkyZAhNmjQhNDSU6667DoDZs2ezcOHC07oPDZHa2s7hcPDDDz9UmWbSpElBrQ3CdnVLcXEx9957L/n5+RUedzqdPP3002RkZATF/+c//+Hbb78F4JZbbkGn09GjRw86duxIWVkZd955J7m5ueXKe+CBB9i3bx8Gg4Fx48YBMH78eCRJ4sCBA9x3333l8uTn53PXXXdRWlpKz5496dKlC3q9nptuugmAZcuW8fbbb9f42oWQaiA4HA7ee+89/36zZs384ebNmwOeP9Ta/BEIakZeXh4bN25k06ZN7N27t8LPa6+95k9/4MAB/xeFTqejSZMmAEiS5Lddeno68+fPDzrPF198wZEjR4Bge7do0cIfXrZsGdu3bz8j19lQkSSJPn368O2331b7eahvG7377rs4HI5y+Xzn8qWxWq3Vqv/5Qm1sB7BmzRqaN29e6fO4d+9err/++qA8wnZ1y9y5c2ncuDHz589ny5YtfP/991x77bVBaex2O1988YV/Pz8/n7lz5/r3A++hzw6lpaW8//77QeX88ssv/PHHHwAkJSVhNBoBCAsLIy4uDoAtW7awfPnyoHyzZ8+msLAQqNx2H3/8MVlZWTW5dCGkGgrr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DzwQdHzjxo3MmzePPXv2sGLFCjRNY+HChSxYsIC0tDSaN2/Ovffey7BhwwDPwPb58+fz+eefc+TIEZKSkpg0aVKVrWgrV67ks88+Y/v27ZSWlpKYmMjgwYO5++67SUxMPO1rPHjwIE6ns1x8hw4dTrvs//3vf7hcLvr06UNYWFil6RwOB++//z7ffPMNWVlZJCUlMWDAANq2bcvOnTt5+eWXK8xXm3uzfv165s+fz+bNmykqKiI2NpYBAwYwdepUkpOTK63jjh07+OSTT/jjjz/Izs4mMjKSHj16cPPNN9O/f/9y6d1uN6tWrWL+/Pm43W7mzZuH3W7nv//9L1999RW5ubl07tyZZ599tsp7ffDgQWbPns3atWvJyckhISGBUaNG4Xa76/R+hoWFkZKSws6dO5k7dy6PPPJIpeULBPWFaJESCBooLpeLp556iiuuuIJXX32Vw4cPBx1fuXIlo0aNYsKECfz444+43W4cDgf3338/r732GoWFhdjtdvbt28cjjzzCTz/9hM1mY8qUKbz++uuUlJTgcDg4cuQIzz//PEuWLClXB6fTyeOPP87s2bO55557WLlyJQsWLKBRo0bMnz+fUaNG1Ykvpoq69eD0hZTb7eb777+vVln3338/y5Yt49VXX2X9+vW88847HDt2jBkzZlQ4AaA298btdjNjxgymTp3KkCFD+OGHH/jpp5/o0aMHixcvZvTo0ezdu7fC+s2aNYubbrqJpKQkFixYwK+//spDDz3EunXruOOOO3jhhReCXEssXLiQ66+/nqlTp7Ju3ToAsrKyGDduHLNnz6asrAyr1eqfSVpUVFTheb/99luuu+46MjMzef/991m/fj3PPfccX3/9dbkZpqdzP334WnOXLFlSp64yBIJaowkEgnOG9evXaykpKVpKSor25JNPnjK93W7X0tPTtXbt2mkpKSnav//9b/+xzMxMLTc3V7vhhhu0lJQUbcCAAdrjjz+uzZ8/X7PZbJqmadqmTZu0nj17aikpKdr111+v3XfffdoHH3yglZSUaJqmaRkZGdrVV1+tpaSkaMOHDy93/hdffFG79tprNavVGhRvsVi0QYMGaSkpKdpVV12luVyu07kt2ksvveS/L4GfvLy80yp38+bN/rLmz59fabrffvtNS0lJ0ZYvXx4U73K5tBtuuEF79NFHy+Wpzb15+eWXtZSU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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "log_normal_dict = {\n", - " \"Intercept: sigma_\": \"$\\sigma$\",\n", - " \"Intercept: mu_\": \"$\\mu$\",\n", - " \"def_value: mu_\": \"Defence Strength\",\n", - " \"atk_value: mu_\": \"Attack Strength\",\n", - " \"train_time: mu_\": \"Training Time\",\n", - " \"predict_time: mu_\": \"Inference Time\",\n", - " \"adv_fit_time: mu_\": \"Adv. Fit Time\",\n", - " \"model_layers: mu_\": \"No. of Layers\",\n", - " \"model.art.pipeline.initialize.kwargs.optimizer.lr: mu_\": \"Learning Rate\",\n", - " \"data.sample.random_state: mu_\": \"Random State\",\n", - " \"adv_log_loss: mu_\": \"Adv. Log Loss\",\n", - " \"adv_accuracy: mu_\": \"Adv. Accuracy\",\n", - " \"accuracy: mu_\": \"Ben. Accuracy\",\n", - " \"adv_failure_rate: mu_\": \"Adv. Failure Rate\",\n", - " \"def_gen\": \"Defence\",\n", - " \"learning_rate: mu_\": \"Learning Rate\",\n", - "}\n", - "\n", - "log_normal_graph, lnt = plot_aft(\n", - " X_train,\n", - " \"log_normal_aft.pdf\",\n", - " target,\n", - " duration_col,\n", - " \"Log Normal AFR Model\",\n", - " \"log_normal\",\n", - " replacement_dict=log_normal_dict,\n", - ")\n", - "lnt_scores = score_model(lnt, X_train, X_test)\n", - "lnt.print_summary()\n", - "lnt_partial = plot_partial_effects(\n", - " file=\"log_normal_partial_effects.pdf\",\n", - " aft=lnt,\n", - " covariate_array=\"model_layers\",\n", - " values_array=[18, 34, 50, 101, 152],\n", - " replacement_dict=log_normal_dict,\n", - " title=\"Survival Time for Log-Normal AFR\",\n", - " ylabel=\"% Chance of Survival\",\n", - " xlabel=\"Time $T$ (seconds)\",\n", - " legend_kwargs={\n", - " \"title\": \"No. of Layers\",\n", - " \"labels\": [\"18\", \"34\", \"50\", \"101\", \"152\"],\n", - " },\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
modellifelines.LogLogisticAFTFitter
duration col'adv_fit_time'
event col'adv_failures'
number of observations1500
number of events observed1500
log-likelihood-5426.84
time fit was run2023-09-29 11:13:33 UTC
\n", - "
\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
coefexp(coef)se(coef)coef lower 95%coef upper 95%exp(coef) lower 95%exp(coef) upper 95%cmp tozp-log2(p)
alpha_adv_failure_rate-0.001.000.00-0.00-0.001.001.000.00-26.62<0.005516.20
atk_value0.071.070.17-0.260.400.771.490.000.420.670.58
data.sample.random_state0.021.020.02-0.020.060.981.070.000.910.361.47
def_value-0.190.820.18-0.540.150.581.160.00-1.110.271.90
model.art.pipeline.initialize.kwargs.optimizer.lr0.001.000.00-0.000.001.001.000.000.030.970.04
model_layers0.011.010.000.010.021.011.020.007.88<0.00548.13
predict_time-0.310.740.04-0.38-0.240.690.790.00-8.73<0.00558.49
train_time0.001.000.000.000.001.001.000.006.12<0.00530.02
Intercept1.886.540.191.512.254.529.460.009.97<0.00575.31
beta_Intercept-0.320.720.02-0.36-0.280.690.750.00-15.46<0.005176.59

\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Concordance0.82
AIC10873.68
log-likelihood ratio test961.93 on 8 df
-log2(p) of ll-ratio test669.73
\n", - "
" - ], - "text/latex": [ - "\\begin{tabular}{llrrrrrrrrrrr}\n", - " & & coef & exp(coef) & se(coef) & coef lower 95% & coef upper 95% & exp(coef) lower 95% & exp(coef) upper 95% & cmp to & z & p & -log2(p) \\\\\n", - "param & covariate & & & & & & & & & & & \\\\\n", - "\\multirow[c]{9}{*}{alpha_} & adv_failure_rate & -0.00 & 1.00 & 0.00 & -0.00 & -0.00 & 1.00 & 1.00 & 0.00 & -26.62 & 0.00 & 516.20 \\\\\n", - " & atk_value & 0.07 & 1.07 & 0.17 & -0.26 & 0.40 & 0.77 & 1.49 & 0.00 & 0.42 & 0.67 & 0.58 \\\\\n", - " & data.sample.random_state & 0.02 & 1.02 & 0.02 & -0.02 & 0.06 & 0.98 & 1.07 & 0.00 & 0.91 & 0.36 & 1.47 \\\\\n", - " & def_value & -0.19 & 0.82 & 0.18 & -0.54 & 0.15 & 0.58 & 1.16 & 0.00 & -1.11 & 0.27 & 1.90 \\\\\n", - " & model.art.pipeline.initialize.kwargs.optimizer.lr & 0.00 & 1.00 & 0.00 & -0.00 & 0.00 & 1.00 & 1.00 & 0.00 & 0.03 & 0.97 & 0.04 \\\\\n", - " & model_layers & 0.01 & 1.01 & 0.00 & 0.01 & 0.02 & 1.01 & 1.02 & 0.00 & 7.88 & 0.00 & 48.13 \\\\\n", - " & predict_time & -0.31 & 0.74 & 0.04 & -0.38 & -0.24 & 0.69 & 0.79 & 0.00 & -8.73 & 0.00 & 58.49 \\\\\n", - " & train_time & 0.00 & 1.00 & 0.00 & 0.00 & 0.00 & 1.00 & 1.00 & 0.00 & 6.12 & 0.00 & 30.02 \\\\\n", - " & Intercept & 1.88 & 6.54 & 0.19 & 1.51 & 2.25 & 4.52 & 9.46 & 0.00 & 9.97 & 0.00 & 75.31 \\\\\n", - "beta_ & Intercept & -0.32 & 0.72 & 0.02 & -0.36 & -0.28 & 0.69 & 0.75 & 0.00 & -15.46 & 0.00 & 176.59 \\\\\n", - "\\end{tabular}\n" - ], - "text/plain": [ - "\n", - " duration col = 'adv_fit_time'\n", - " event col = 'adv_failures'\n", - " number of observations = 1500\n", - "number of events observed = 1500\n", - " log-likelihood = -5426.84\n", - " time fit was run = 2023-09-29 11:13:33 UTC\n", - "\n", - "---\n", - " coef exp(coef) se(coef) coef lower 95% coef upper 95% exp(coef) lower 95% exp(coef) upper 95%\n", - "param covariate \n", - "alpha_ adv_failure_rate -0.00 1.00 0.00 -0.00 -0.00 1.00 1.00\n", - " atk_value 0.07 1.07 0.17 -0.26 0.40 0.77 1.49\n", - " data.sample.random_state 0.02 1.02 0.02 -0.02 0.06 0.98 1.07\n", - " def_value -0.19 0.82 0.18 -0.54 0.15 0.58 1.16\n", - " model.art.pipeline.initialize.kwargs.optimizer.lr 0.00 1.00 0.00 -0.00 0.00 1.00 1.00\n", - " model_layers 0.01 1.01 0.00 0.01 0.02 1.01 1.02\n", - " predict_time -0.31 0.74 0.04 -0.38 -0.24 0.69 0.79\n", - " train_time 0.00 1.00 0.00 0.00 0.00 1.00 1.00\n", - " Intercept 1.88 6.54 0.19 1.51 2.25 4.52 9.46\n", - "beta_ Intercept -0.32 0.72 0.02 -0.36 -0.28 0.69 0.75\n", - "\n", - " cmp to z p -log2(p)\n", - "param covariate \n", - "alpha_ adv_failure_rate 0.00 -26.62 <0.005 516.20\n", - " atk_value 0.00 0.42 0.67 0.58\n", - " data.sample.random_state 0.00 0.91 0.36 1.47\n", - " def_value 0.00 -1.11 0.27 1.90\n", - " model.art.pipeline.initialize.kwargs.optimizer.lr 0.00 0.03 0.97 0.04\n", - " model_layers 0.00 7.88 <0.005 48.13\n", - " predict_time 0.00 -8.73 <0.005 58.49\n", - " train_time 0.00 6.12 <0.005 30.02\n", - " Intercept 0.00 9.97 <0.005 75.31\n", - "beta_ Intercept 0.00 -15.46 <0.005 176.59\n", - "---\n", - "Concordance = 0.82\n", - "AIC = 10873.68\n", - "log-likelihood ratio test = 961.93 on 8 df\n", - "-log2(p) of ll-ratio test = 669.73" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'train_score': -3.617893432558881, 'test_score': -3.971188942813805}\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/tmp/ipykernel_773113/12050270.py:64: UserWarning: FixedFormatter should only be used together with FixedLocator\n", - " pareto.set_yticklabels(labels)\n" - ] - }, - { - "data": { - "image/png": "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zbXXXlulvKqqIsvi9+a5Qjx/QW1A/IUKBBcAjz32GF26dGHOnDnnuipnRGFhIQcOHKjWMjt16lTpPMeOHePpp59mz5491VqXiwlVVVm5ciX33HMP/fv3r1IZmzZt4sUXXyQvL696KycQVCPCIyUQnANatWp1RvmfeuopJk6cCEBOTg4//PADAF999RXjxo070+qdM7Zu3YqmadVWXkJCAomJiZXK8/vvv/Phhx/y0ksv0bx582qry8XEokWL+Pjjj/2iuH79+lUqp2vXrsiyzM0338x///tfOnfuXJ3VFAiqBSGkBIJzRIcOHXjyySdp1aoVFosFgA0bNvgF0siRI/nvf/8LgKIoHD9+nG+++YZPP/00qJyYmBiGDx/OihUruOmmm2r0HqqbjIwM2rVrV2pcYWEhR44cKRHeqFEjwsPDS83TvXv3Sl3/hx9+YPr06Xz99ddV/vIXwLXXXsuwYcOYOHEi69evP6OyunTpwiuvvMJdd93FSy+9RL9+/aqplgJB9SCElEBwDoiMjOT//u//iIyMDAoP7A8iSRJ6vfcV1ev1NG3alCeeeAKXy1WivNdee+3sVriGuP7667n++utLjfv888/9wjKQN954g44dO57xtVevXs1TTz3FjBkzhIg6Q8xmMwDt27c/YyEF0LFjRx588EEeffRRvvnmG1q2bHnGZQoE1YXoIyUQnAMGDhxYQkRVlDFjxlRzbWoHu3fvLhGm0+lISko647Lz8/N54okn6NChA3369Dnj8gReTCZTtZU1duxYGjVqxJQpUygqKqq2cgWCM0UIKYHgHHAmTXDNmzfn8ssvr8ba1A5KE1JNmzb1ez/OhNdff52MjAwmTJhwxmUJTqLT6aqtLEmSuO2220hJSWHmzJnVVq5AcKYIISUQnAPat29f5bx6vZ7WrVtXY23Of9xud6mj+arjORw9epSFCxei1+vp1avXGZcnOHv0798fg8HAF198QU5OzrmujkAAiD5SAkGtJycnh0WLFvHNN98wZMgQ7r///qD49evX88UXX7Bnzx6WL1+OpmnMmzePuXPncuTIERo3bsy9997L4MGDAW/H9jlz5vDtt99y+PBhEhMTuf3228v1oq1YsYKvv/6a7du3U1RUREJCAn369OHuu+8mISHhjO8xOTkZt9tdIrxNmzZnXPZnn32Gx+OhW7duhIWFlZnO5XLx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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "log_logistic_dict = {\n", - " \"Intercept: beta_\": \"$\\\\beta$\",\n", - " \"Intercept: alpha_\": \"$\\\\alpha$\",\n", - " \"data.sample.random_state: alpha_\": \"Random State\",\n", - " \"def_value: alpha_\": \"Defence Strength\",\n", - " \"atk_value: alpha_\": \"Attack Strength\",\n", - " \"train_time: alpha_\": \"Training Time\",\n", - " \"predict_time: alpha_\": \"Inference Time\",\n", - " \"adv_accuracy: alpha_\": \"Adv. Accuracy\",\n", - " \"accuracy: alpha_\": \"Ben. Accuracy\",\n", - " \"adv_fit_time: alpha_\": \"Adv. Fit Time\",\n", - " \"model_layers: alpha_\": \"No. of Layers\",\n", - " \"model.art.pipeline.initialize.kwargs.optimizer.lr\": \"Learning Rate\",\n", - " \"adv_failure_rate: alpha_\": \"Adv. Failure Rate\",\n", - " \"alpha_\": \"\",\n", - "}\n", - "\n", - "log_logistic_graph, llt = plot_aft(\n", - " X_train,\n", - " \"log_logistic_aft.pdf\",\n", - " target,\n", - " duration_col,\n", - " \"Log Logistic AFR Model\",\n", - " \"log_logistic\",\n", - " replacement_dict=log_logistic_dict,\n", - ")\n", - "llt.print_summary()\n", - "llt_scores = score_model(llt, X_train, X_test)\n", - "print(llt_scores)\n", - "llt_partial = plot_partial_effects(\n", - " file=\"log_logistic_partial_effects.pdf\",\n", - " aft=llt,\n", - " covariate_array=\"model_layers\",\n", - " values_array=[18, 34, 50, 101, 152],\n", - " replacement_dict=log_logistic_dict,\n", - " title=\"Survival Time for Log-Logistic AFR\",\n", - " ylabel=\"% Chance of Survival\",\n", - " xlabel=\"Time $T$ (seconds)\",\n", - " legend_kwargs={\n", - " \"title\": \"No. of Layers\",\n", - " \"labels\": [\"18\", \"34\", \"50\", \"101\", \"152\"],\n", - " },\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "8.62393284274078" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.mean(llt.predict_median(X_train))" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
AICConcordanceBICTrain LLTest LLMean STMedian ST
Weibull11082.520.8411082.52-3.69-4.0071.5310.23
LogNormal10769.080.8410769.08-3.58-3.92122.817.79
LogLogistic10873.680.8210873.68-3.62-3.97NaN6.62
\n", - "
" - ], - "text/plain": [ - " AIC Concordance BIC Train LL Test LL Mean ST \\\n", - "Weibull 11082.52 0.84 11082.52 -3.69 -4.00 71.53 \n", - "LogNormal 10769.08 0.84 10769.08 -3.58 -3.92 122.81 \n", - "LogLogistic 10873.68 0.82 10873.68 -3.62 -3.97 NaN \n", - "\n", - " Median ST \n", - "Weibull 10.23 \n", - "LogNormal 7.79 \n", - "LogLogistic 6.62 " - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "aft_dict = {\n", - " \"Weibull\": wft,\n", - " \"LogNormal\": lnt,\n", - " \"LogLogistic\": llt,\n", - " # \"Cox\": cft,\n", - "}\n", - "\n", - "score_list = [\n", - " wft_scores,\n", - " lnt_scores,\n", - " llt_scores,\n", - " # cft_scores,\n", - "]\n", - "aft_data = pd.DataFrame()\n", - "aft_data.index.name = \"Model\"\n", - "aft_data.index = aft_dict.keys()\n", - "aft_data[\"AIC\"] = [\n", - " x.AIC_ if not isinstance(x, CoxPHFitter) else np.nan for x in aft_dict.values()\n", - "]\n", - "aft_data[\"Concordance\"] = [x.concordance_index_ for x in aft_dict.values()]\n", - "aft_data[\"BIC\"] = [\n", - " x.AIC_ if not isinstance(x, CoxPHFitter) else np.nan for x in aft_dict.values()\n", - "]\n", - "aft_data[\"Train LL\"] = [x[\"train_score\"] for x in score_list]\n", - "aft_data[\"Test LL\"] = [x[\"test_score\"] for x in score_list]\n", - "aft_data[\"Mean ST\"] = [x.predict_expectation(X_train).mean() for x in aft_dict.values()]\n", - "aft_data[\"Median ST\"] = [x.predict_median(X_train).median() for x in aft_dict.values()]\n", - "aft_data = aft_data.round(2)\n", - "aft_data.to_csv(FOLDER / \"aft_comparison.csv\")\n", - "logger.info(f\"Saved AFT comparison to {FOLDER / 'aft_comparison.csv'}\")\n", - "aft_data = aft_data.round(\n", - " 2,\n", - ")\n", - "aft_data.to_latex(\n", - " FOLDER / \"aft_comparison.tex\",\n", - " float_format=\"%.2f\",\n", - " label=\"tab:mnist\",\n", - " caption=\"Comparison of AFR Models on the MNIST dataset.\",\n", - ")\n", - "aft_data" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "env", - "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.8" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/security/classification/plots/.gitignore b/examples/security/classification/plots/.gitignore deleted file mode 100644 index 4c882c2e..00000000 --- a/examples/security/classification/plots/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -/accuracy_vs_attack_parameters.eps -/accuracy_vs_features.eps -/accuracy_vs_samples.eps -/confidence_vs_attack_parameters.eps -/train_time_vs_attack_parameters.eps -/train_time_vs_features.eps -/train_time_vs_samples.eps -/retrain_accuracy.eps -/retrain_confidence_vs_attack_parameters.eps -/retrain_time.eps diff --git a/examples/security/truthseeker/conf/data/truthseeker.yaml b/examples/security/truthseeker/conf/data/truthseeker.yaml index 7fdb84a9..18a3d226 100644 --- a/examples/security/truthseeker/conf/data/truthseeker.yaml +++ b/examples/security/truthseeker/conf/data/truthseeker.yaml @@ -1,15 +1,15 @@ _target_: deckard.base.data.Data generate: # _target_: deckard.base.data.generator.DataGenerator - name: https://gist.githubusercontent.com/simplymathematics/8c6c04bd151950d5ea9e62825db97fdd/raw/379b679bdea30724e9fa188931f0109ff422cce0/kdd_nsl.csv - target : -2 + name: https://gist.githubusercontent.com/simplymathematics/8c6c04bd151950d5ea9e62825db97fdd/raw/34e546e4813f154d11d4f13869b9e3481fc3e829/truthseeker.csv + target : BotScoreBinary sample: # _target_: deckard.base.data.sampler.SklearnDataSampler random_state : 0 stratify: True train_size : 10000 test_size : 1000 -ssklearn_pipeline: +sklearn_pipeline: encoder: name : sklearn.preprocessing.OrdinalEncoder handle_unknown : use_encoded_value diff --git a/examples/sklearn/.gitignore b/examples/sklearn/.gitignore index 900aa55a..c9066ade 100644 --- a/examples/sklearn/.gitignore +++ b/examples/sklearn/.gitignore @@ -3,3 +3,4 @@ /model_grid.db /attack_grid.db /output +/multirun diff --git a/setup.py b/setup.py index 65317ddb..c75633e1 100644 --- a/setup.py +++ b/setup.py @@ -11,26 +11,23 @@ "numpy", "scipy", "scikit-learn", - "six", - "setuptools", "tqdm", "numba", "pillow", - "wheel", "pandas", "pre-commit", "PyYAML", "pytest", "validators", - "yellowbrick", "hydra-core", "hydra-optuna-sweeper", "hydra-joblib-launcher", - "hydra-rq-launcher", "sqlalchemy<=1.4.46", "dvc", "paretoset", "lifelines", + "seaborn", + "jinja2", ] test_requires = [ "pytest", @@ -184,6 +181,8 @@ def get_version(rel_path): "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3 :: Only", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Scientific/Engineering :: Artificial Intelligence", diff --git a/test/base/test_attack/test_attack.py b/test/base/test_attack/test_attack.py index cd486389..d5c26f13 100644 --- a/test/base/test_attack/test_attack.py +++ b/test/base/test_attack/test_attack.py @@ -46,10 +46,10 @@ def tearDown(self) -> None: rmtree(self.dir) -class testPoisoningAttackInitializer(testAttackInitializer): - config_dir = Path(this_dir, "../../conf/attack").resolve().as_posix() - config_file = "poisoning.yaml" - file = "attack.pkl" +# class testPoisoningAttackInitializer(testAttackInitializer): +# config_dir = Path(this_dir, "../../conf/attack").resolve().as_posix() +# config_file = "poisoning.yaml" +# file = "attack.pkl" # class testInferenceAttackInitializer(testAttackInitializer): diff --git a/test/base/test_attack/torch_example.py b/test/base/test_attack/torch_example.py index 59554442..9cfc5912 100644 --- a/test/base/test_attack/torch_example.py +++ b/test/base/test_attack/torch_example.py @@ -343,5 +343,11 @@ def resnet18(pretrained=False, progress=True, device="cpu", **kwargs): progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet( - "resnet18", BasicBlock, [2, 2, 2, 2], pretrained, progress, device, **kwargs + "resnet18", + BasicBlock, + [2, 2, 2, 2], + pretrained, + progress, + device, + **kwargs, ) diff --git a/test/base/test_data/test_data.py b/test/base/test_data/test_data.py index 5f41cf1d..9c82279d 100644 --- a/test/base/test_data/test_data.py +++ b/test/base/test_data/test_data.py @@ -3,7 +3,7 @@ from tempfile import mkdtemp from shutil import rmtree import os -import numpy as np +from numpy import ndarray from hydra import initialize_config_dir, compose from hydra.utils import instantiate from pandas import DataFrame, Series @@ -35,10 +35,10 @@ def test_init(self): def test_call(self): filename = Path(self.directory, self.data_file + self.data_type).as_posix() X_train, X_test, y_train, y_test = self.data(data_file=filename) - self.assertIsInstance(X_train, np.ndarray) - self.assertIsInstance(X_test, np.ndarray) - self.assertIsInstance(y_train, np.ndarray) - self.assertIsInstance(y_test, np.ndarray) + self.assertIsInstance(X_train, ndarray) + self.assertIsInstance(X_test, ndarray) + self.assertIsInstance(y_train, ndarray) + self.assertIsInstance(y_test, ndarray) self.assertEqual(X_train.shape[0], y_train.shape[0]) self.assertEqual(X_test.shape[0], y_test.shape[0]) self.assertTrue(Path(filename).exists()) diff --git a/test/base/test_experiment/torch_example.py b/test/base/test_experiment/torch_example.py index e7479cb8..2ece33fe 100644 --- a/test/base/test_experiment/torch_example.py +++ b/test/base/test_experiment/torch_example.py @@ -343,5 +343,11 @@ def resnet18(pretrained=False, progress=True, device="cpu", **kwargs): progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet( - "resnet18", BasicBlock, [2, 2, 2, 2], pretrained, progress, device, **kwargs + "resnet18", + BasicBlock, + [2, 2, 2, 2], + pretrained, + progress, + device, + **kwargs, ) diff --git a/test/base/test_model/torch_example.py b/test/base/test_model/torch_example.py index e7479cb8..2ece33fe 100644 --- a/test/base/test_model/torch_example.py +++ b/test/base/test_model/torch_example.py @@ -343,5 +343,11 @@ def resnet18(pretrained=False, progress=True, device="cpu", **kwargs): progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet( - "resnet18", BasicBlock, [2, 2, 2, 2], pretrained, progress, device, **kwargs + "resnet18", + BasicBlock, + [2, 2, 2, 2], + pretrained, + progress, + device, + **kwargs, ) diff --git a/test/conf/attack/poisoning.yaml b/test/conf/attack/poisoning.yaml index b05834e4..3d86793a 100644 --- a/test/conf/attack/poisoning.yaml +++ b/test/conf/attack/poisoning.yaml @@ -10,28 +10,24 @@ data: n_redundant: 0 n_repeated: 0 sample: - _target_: deckard.base.data.sampler.SklearnDataSampler - random_state : 0 - stratify: True - train_size : .8 - test_size : .2 + random_state : 0 + stratify: True + train_size : .8 + test_size : .2 model: data : ${data} init: - _target_: deckard.base.model.ModelInitializer name: torch_example.LogisticRegression input_dim : - ${data.generate.n_features} output_dim : - ${data.generate.n_classes} - _target_: deckard.base.model.Model trainer: nb_epoch: 1 batch_size: 1024 library : torch art: library : torch - _target_ : deckard.base.model.art_pipeline.ArtPipeline initialize: criterion: name : "torch.nn.CrossEntropyLoss" @@ -40,7 +36,6 @@ model: lr : 0.01 momentum : 0.9 nb_classes : ${data.generate.n_classes} -_target_ : deckard.base.attack.Attack init: name: art.attacks.poisoning.GradientMatchingAttack model: ${model} diff --git a/test/conf/data/titanic.yaml b/test/conf/data/titanic.yaml index 40bf66b5..58111e6d 100644 --- a/test/conf/data/titanic.yaml +++ b/test/conf/data/titanic.yaml @@ -1,8 +1,3 @@ _target_: deckard.base.data.Data name: https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv target : Survived -sklearn_pipeline: - preprocessor: - name: sklearn.preprocessing.StandardScaler - with_mean: True - with_std: True