Skip to content

Commit

Permalink
Add version to metadata (#339)
Browse files Browse the repository at this point in the history
* Add version to metadata

* Add __version__ to metadata tests

* Fix flake8 indentation
  • Loading branch information
jklaise authored Sep 22, 2021
1 parent 63298b7 commit ba5da6a
Show file tree
Hide file tree
Showing 14 changed files with 45 additions and 15 deletions.
4 changes: 3 additions & 1 deletion alibi_detect/ad/tests/test_adae.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from tensorflow.keras.layers import Dense, InputLayer
from tensorflow.keras.utils import to_categorical
from alibi_detect.ad import AdversarialAE
from alibi_detect.version import __version__

threshold = [None, 5.]
w_model = [1., .5]
Expand Down Expand Up @@ -68,7 +69,8 @@ def test_adv_vae(adv_ae_params):
)

assert advae.threshold == threshold
assert advae.meta == {'name': 'AdversarialAE', 'detector_type': 'offline', 'data_type': None}
assert advae.meta == {'name': 'AdversarialAE', 'detector_type': 'offline', 'data_type': None,
'version': __version__}
for layer in advae.model.layers:
assert not layer.trainable

Expand Down
4 changes: 3 additions & 1 deletion alibi_detect/ad/tests/test_admd.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import tensorflow as tf
from tensorflow.keras.utils import to_categorical
from alibi_detect.ad import ModelDistillation
from alibi_detect.version import __version__

threshold = [None, 5.]
loss_type = ['kld', 'xent']
Expand Down Expand Up @@ -54,7 +55,8 @@ def test_adv_md(adv_md_params):
)

assert admd.threshold == threshold
assert admd.meta == {'name': 'ModelDistillation', 'detector_type': 'offline', 'data_type': None}
assert admd.meta == {'name': 'ModelDistillation', 'detector_type': 'offline', 'data_type': None,
'version': __version__}
for layer in admd.model.layers:
assert not layer.trainable

Expand Down
6 changes: 5 additions & 1 deletion alibi_detect/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
import numpy as np
from typing import Dict

from alibi_detect.version import __version__

DEFAULT_META = {
"name": None,
"detector_type": None, # online or offline
"data_type": None # tabular, image or time-series
"data_type": None, # tabular, image or time-series
"version": None,
} # type: Dict


Expand Down Expand Up @@ -55,6 +58,7 @@ class BaseDetector(ABC):
def __init__(self):
self.meta = copy.deepcopy(DEFAULT_META)
self.meta['name'] = self.__class__.__name__
self.meta['version'] = __version__

def __repr__(self):
return self.__class__.__name__
Expand Down
3 changes: 2 additions & 1 deletion alibi_detect/od/tests/test_ae.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import tensorflow as tf
from tensorflow.keras.layers import Dense, InputLayer
from alibi_detect.od import OutlierAE
from alibi_detect.version import __version__

threshold = [None, 5.]
threshold_perc = [90.]
Expand Down Expand Up @@ -60,7 +61,7 @@ def test_ae(ae_params):
)

assert ae.threshold == threshold
assert ae.meta == {'name': 'OutlierAE', 'detector_type': 'offline', 'data_type': None}
assert ae.meta == {'name': 'OutlierAE', 'detector_type': 'offline', 'data_type': None, 'version': __version__}

# fit OutlierAE, infer threshold and compute scores
ae.fit(X, epochs=5, verbose=False)
Expand Down
3 changes: 2 additions & 1 deletion alibi_detect/od/tests/test_aegmm.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import tensorflow as tf
from tensorflow.keras.layers import Dense, InputLayer
from alibi_detect.od import OutlierAEGMM
from alibi_detect.version import __version__

threshold = [None, 5.]
n_gmm = [1, 2]
Expand Down Expand Up @@ -69,7 +70,7 @@ def test_aegmm(aegmm_params):
)

assert aegmm.threshold == threshold
assert aegmm.meta == {'name': 'OutlierAEGMM', 'detector_type': 'offline', 'data_type': None}
assert aegmm.meta == {'name': 'OutlierAEGMM', 'detector_type': 'offline', 'data_type': None, 'version': __version__}

# fit OutlierAEGMM, infer threshold and compute scores
aegmm.fit(X, w_energy=w_energy, epochs=5, batch_size=1000, verbose=False)
Expand Down
4 changes: 3 additions & 1 deletion alibi_detect/od/tests/test_iforest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import pytest
from sklearn.datasets import load_iris
from alibi_detect.od import IForest
from alibi_detect.version import __version__

threshold = [None, 0.]
threshold_perc = [75., 95.]
Expand All @@ -23,7 +24,8 @@ def test_isolation_forest(iforest_params):
X, y = load_iris(return_X_y=True)
iforest = IForest(threshold)
assert iforest.threshold == threshold
assert iforest.meta == {'name': 'IForest', 'detector_type': 'offline', 'data_type': 'tabular'}
assert iforest.meta == {'name': 'IForest', 'detector_type': 'offline', 'data_type': 'tabular',
'version': __version__}
iforest.fit(X)
iforest.infer_threshold(X, threshold_perc=threshold_perc)
iscore = iforest.score(X)
Expand Down
3 changes: 2 additions & 1 deletion alibi_detect/od/tests/test_llr.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import tensorflow as tf
from tensorflow.keras.layers import Dense, Input, LSTM
from alibi_detect.od import LLR
from alibi_detect.version import __version__

input_dim = 5
hidden_dim = 20
Expand Down Expand Up @@ -55,7 +56,7 @@ def test_llr(llr_params):
od = LLR(threshold=threshold, sequential=True, model=model, log_prob=likelihood_fn)

assert od.threshold == threshold
assert od.meta == {'name': 'LLR', 'detector_type': 'offline', 'data_type': None}
assert od.meta == {'name': 'LLR', 'detector_type': 'offline', 'data_type': None, 'version': __version__}

od.fit(
X_train,
Expand Down
3 changes: 2 additions & 1 deletion alibi_detect/od/tests/test_mahalanobis.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pytest
from sklearn.datasets import load_iris
from alibi_detect.od import Mahalanobis
from alibi_detect.version import __version__

threshold = [None, 5.]
n_components = [2, 3]
Expand Down Expand Up @@ -31,7 +32,7 @@ def test_mahalanobis(mahalanobis_params):
start_clip=start_clip, max_n=max_n)
assert mh.threshold == threshold
assert mh.n == 0
assert mh.meta == {'name': 'Mahalanobis', 'detector_type': 'online', 'data_type': 'tabular'}
assert mh.meta == {'name': 'Mahalanobis', 'detector_type': 'online', 'data_type': 'tabular', 'version': __version__}
mh.infer_threshold(X, threshold_perc=threshold_perc)
assert mh.n == X.shape[0]
iscore = mh.score(X) # noqa
Expand Down
4 changes: 3 additions & 1 deletion alibi_detect/od/tests/test_prophet.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import pandas as pd
import pytest
from alibi_detect.od import OutlierProphet
from alibi_detect.version import __version__

growth = ['linear', 'logistic']
return_instance_score = [True, False]
Expand Down Expand Up @@ -36,7 +37,8 @@ def test_prophet(prophet_params):
growth, return_instance_score, return_forecast = prophet_params
od = OutlierProphet(growth=growth)
assert isinstance(od.model, fbprophet.forecaster.Prophet)
assert od.meta == {'name': 'OutlierProphet', 'detector_type': 'offline', 'data_type': 'time-series'}
assert od.meta == {'name': 'OutlierProphet', 'detector_type': 'offline', 'data_type': 'time-series',
'version': __version__}
if growth == 'logistic':
df_fit['cap'] = 10.
df_test['cap'] = 10.
Expand Down
8 changes: 5 additions & 3 deletions alibi_detect/od/tests/test_seq2seq.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pytest
from alibi_detect.od import OutlierSeq2Seq
from alibi_detect.utils.perturbation import inject_outlier_ts
from alibi_detect.version import __version__

n_features = [1, 2]
seq_len = [20, 50]
Expand Down Expand Up @@ -35,8 +36,8 @@ def test_seq2seq(seq2seq_params):
X = np.sin(np.linspace(-50, 50, 10000)).astype(np.float32).reshape((-1, n_features))

# create outliers for threshold and detection
X_threshold = inject_outlier_ts(X, perc_outlier=100-threshold_perc, perc_window=10, n_std=10., min_std=9.).data
X_outlier = inject_outlier_ts(X, perc_outlier=100-threshold_perc, perc_window=10, n_std=10., min_std=9.).data
X_threshold = inject_outlier_ts(X, perc_outlier=100 - threshold_perc, perc_window=10, n_std=10., min_std=9.).data
X_outlier = inject_outlier_ts(X, perc_outlier=100 - threshold_perc, perc_window=10, n_std=10., min_std=9.).data

# define architecture
od = OutlierSeq2Seq(n_features, seq_len, threshold=threshold, latent_dim=latent_dim)
Expand All @@ -45,7 +46,8 @@ def test_seq2seq(seq2seq_params):
assert od.threshold == 0.
else:
assert od.threshold == threshold
assert od.meta == {'name': 'OutlierSeq2Seq', 'detector_type': 'offline', 'data_type': 'time-series'}
assert od.meta == {'name': 'OutlierSeq2Seq', 'detector_type': 'offline', 'data_type': 'time-series',
'version': __version__}

# fit OutlierSeq2Seq
od.fit(X, epochs=2, verbose=False)
Expand Down
4 changes: 3 additions & 1 deletion alibi_detect/od/tests/test_sr.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import numpy as np
import pytest
from alibi_detect.od import SpectralResidual
from alibi_detect.version import __version__

# create normal time series and one with perturbations
t = np.linspace(0, 0.5, 1000)
Expand Down Expand Up @@ -35,7 +36,8 @@ def test_sr(sr_params):
assert od.threshold == threshold
assert od.meta == {'name': 'SpectralResidual',
'detector_type': 'online',
'data_type': 'time-series'}
'data_type': 'time-series',
'version': __version__}
preds_in = od.predict(X, t, return_instance_score=return_instance_score)
assert preds_in['data']['is_outlier'].sum() <= 2.
if return_instance_score:
Expand Down
3 changes: 2 additions & 1 deletion alibi_detect/od/tests/test_vae.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from tensorflow.keras.layers import Dense, InputLayer
from alibi_detect.od import OutlierVAE
from alibi_detect.models.tensorflow.losses import elbo
from alibi_detect.version import __version__

threshold = [None, 5.]
score_type = ['mse']
Expand Down Expand Up @@ -68,7 +69,7 @@ def test_vae(vae_params):
)

assert vae.threshold == threshold
assert vae.meta == {'name': 'OutlierVAE', 'detector_type': 'offline', 'data_type': None}
assert vae.meta == {'name': 'OutlierVAE', 'detector_type': 'offline', 'data_type': None, 'version': __version__}

# fit OutlierVAE, infer threshold and compute scores
vae.fit(X, loss_fn=loss_fn, epochs=5, verbose=False)
Expand Down
4 changes: 3 additions & 1 deletion alibi_detect/od/tests/test_vaegmm.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import tensorflow as tf
from tensorflow.keras.layers import Dense, InputLayer
from alibi_detect.od import OutlierVAEGMM
from alibi_detect.version import __version__

threshold = [None, 5.]
n_gmm = [1, 2]
Expand Down Expand Up @@ -73,7 +74,8 @@ def test_vaegmm(vaegmm_params):
)

assert vaegmm.threshold == threshold
assert vaegmm.meta == {'name': 'OutlierVAEGMM', 'detector_type': 'offline', 'data_type': None}
assert vaegmm.meta == {'name': 'OutlierVAEGMM', 'detector_type': 'offline', 'data_type': None,
'version': __version__}

# fit OutlierAEGMM, infer threshold and compute scores
vaegmm.fit(X, w_recon=w_recon, w_energy=w_energy, epochs=5, batch_size=1000, verbose=False)
Expand Down
7 changes: 7 additions & 0 deletions alibi_detect/utils/saving.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import logging
import os
from pathlib import Path
import warnings
import tensorflow as tf
from tensorflow.keras.layers import Input, InputLayer
from tensorflow_probability.python.distributions.distribution import Distribution
Expand All @@ -24,6 +25,7 @@
OutlierSeq2Seq, OutlierVAE, OutlierVAEGMM, SpectralResidual)
from alibi_detect.od.llr import build_model
from alibi_detect.utils.tensorflow.kernels import GaussianRBF
from alibi_detect.version import __version__

# do not extend pickle dispatch table so as not to change pickle behaviour
dill.extend(use_dill=False)
Expand Down Expand Up @@ -980,6 +982,11 @@ def load_detector(filepath: Union[str, os.PathLike], **kwargs) -> Data:
# load metadata
meta_dict = dill.load(open(filepath.joinpath('meta' + suffix), 'rb'))

# check version
if meta_dict['version'] != __version__:
warnings.warn(f'Trying to load detector from version {meta_dict["version"]} when using version {__version__}. '
f'This may lead to breaking code or invalid results.')

if 'backend' in list(meta_dict.keys()) and meta_dict['backend'] == 'pytorch':
raise NotImplementedError('Detectors with PyTorch backend are not yet supported.')

Expand Down

0 comments on commit ba5da6a

Please sign in to comment.