Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unit and integration test improvement + explainer module #108

Merged
merged 50 commits into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
f1e4aee
simplified path_lib, added unit-tests
technocreep Nov 1, 2023
2b95862
added unit-tests, systematizes directories
technocreep Nov 2, 2023
aac0952
pep8 fix
technocreep Nov 2, 2023
dc52933
few more units
technocreep Nov 2, 2023
4f73c77
unit-test for nn_experimenter
technocreep Nov 10, 2023
3284380
added units for splitter
technocreep Nov 13, 2023
291bcff
fixed splitter unit test
technocreep Nov 13, 2023
3fc8740
bunch of unit-tests
technocreep Nov 14, 2023
352043a
units for detection datasets
technocreep Nov 14, 2023
5214d56
minor fixes
technocreep Nov 14, 2023
42d7c9b
MORE UNIT TESTS
technocreep Nov 15, 2023
2f6e2ff
update requirements
technocreep Nov 15, 2023
48bb4b0
loader tests
technocreep Nov 15, 2023
7dde717
added data for tests
technocreep Nov 15, 2023
0742766
added new tests, enhanced old ones
technocreep Nov 16, 2023
76dff3d
added test data
technocreep Nov 16, 2023
97a9eaa
added test data
technocreep Nov 16, 2023
3351c3b
Readme link fix (#109)
technocreep Nov 17, 2023
b526f65
simplified path_lib, added unit-tests
technocreep Nov 1, 2023
8d4fc1d
added unit-tests, systematizes directories
technocreep Nov 2, 2023
9c3eee6
pep8 fix
technocreep Nov 2, 2023
0c5ff73
few more units
technocreep Nov 2, 2023
57e4167
unit-test for nn_experimenter
technocreep Nov 10, 2023
a1e1c8c
added units for splitter
technocreep Nov 13, 2023
1af94b0
fixed splitter unit test
technocreep Nov 13, 2023
7f30208
bunch of unit-tests
technocreep Nov 14, 2023
32ea434
units for detection datasets
technocreep Nov 14, 2023
2751950
minor fixes
technocreep Nov 14, 2023
12c01af
MORE UNIT TESTS
technocreep Nov 15, 2023
5019ad9
update requirements
technocreep Nov 15, 2023
68a4484
loader tests
technocreep Nov 15, 2023
bfe7068
added data for tests
technocreep Nov 15, 2023
3617764
added new tests, enhanced old ones
technocreep Nov 16, 2023
9ce74d7
added test data
technocreep Nov 16, 2023
21943e3
added test data
technocreep Nov 16, 2023
e0ed177
Merge remote-tracking branch 'origin/unittest_cov_improvement' into u…
technocreep Nov 17, 2023
ffacd2f
MORE UNIT TESTS
technocreep Nov 17, 2023
ad5bb9d
MORE UNIT TESTS
technocreep Nov 17, 2023
731ac75
MORE UNIT TESTS
technocreep Nov 17, 2023
32b1e22
added point/interval explainer with distance methods
technocreep Dec 8, 2023
34c8d01
additional init file for models
technocreep Oct 26, 2023
3bdd5a7
included feature names in transform output
technocreep Oct 30, 2023
0885dd0
Revert "included feature names in transform output"
technocreep Dec 20, 2023
878cf7c
Revert "additional init file for models"
technocreep Dec 20, 2023
1b58779
Revert "added point/interval explainer with distance methods"
technocreep Dec 20, 2023
86666f6
added explain module and updated tests
technocreep Dec 20, 2023
23ad9fb
added explain module tests and example
technocreep Dec 20, 2023
12d6363
fixed imports
technocreep Dec 20, 2023
4b539d8
cleaned up some unnecessary junk
technocreep Dec 21, 2023
d160a86
bug fix
technocreep Dec 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 3 additions & 11 deletions fedot_ind/api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from fedot.core.pipelines.pipeline import Pipeline

from fedot_ind.api.utils.configurator import Configurator
from fedot_ind.api.utils.path_lib import default_path_to_save_results
from fedot_ind.api.utils.path_lib import DEFAULT_PATH_RESULTS
from fedot_ind.core.architecture.experiment.computer_vision import CV_TASKS
from fedot_ind.core.architecture.settings.task_factory import TaskEnum
from fedot_ind.core.operation.transformation.splitter import TSTransformer
Expand Down Expand Up @@ -52,8 +52,8 @@ class FedotIndustrial(Fedot):
"""

def __init__(self, **kwargs):
kwargs.setdefault('output_folder', default_path_to_save_results())
Path(kwargs.get('output_folder', default_path_to_save_results())).mkdir(parents=True, exist_ok=True)
kwargs.setdefault('output_folder', DEFAULT_PATH_RESULTS)
Path(kwargs.get('output_folder', DEFAULT_PATH_RESULTS)).mkdir(parents=True, exist_ok=True)
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s %(levelname)s: %(name)s - %(message)s',
Expand All @@ -63,20 +63,15 @@ def __init__(self, **kwargs):
]
)
super(Fedot, self).__init__()

self.logger = logging.getLogger('FedotIndustrialAPI')

# self.reporter = ReporterTSC()
self.configurator = Configurator()

self.config_dict = None

self.__init_experiment_setup(**kwargs)
self.solver = self.__init_solver()

def __init_experiment_setup(self, **kwargs):
self.logger.info('Initialising experiment setup')
# self.reporter.path_to_save = kwargs.get('output_folder')
if 'task' in kwargs.keys() and kwargs['task'] in CV_TASKS.keys():
self.config_dict = kwargs
else:
Expand All @@ -88,9 +83,6 @@ def __init_solver(self):
if self.config_dict['task'] == 'ts_classification':
if self.config_dict['strategy'] == 'fedot_preset':
solver = TaskEnum[self.config_dict['task']].value['fedot_preset']
# elif self.config_dict['strategy'] is None:
# self.config_dict['strategy'] = 'InceptionTime'
# solver = TaskEnum[self.config_dict['task']].value['nn']
else:
solver = TaskEnum[self.config_dict['task']].value['default']
elif self.config_dict['task'] == 'ts_forecasting':
Expand Down
8 changes: 2 additions & 6 deletions fedot_ind/api/utils/path_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@
PATH_TO_DEFAULT_PARAMS = os.path.join(PROJECT_PATH, 'fedot_ind/core/repository/data/default_operation_params.json')

# For results collection
DS_INFO_PATH = os.path.join(PROJECT_PATH, 'core', 'architecture', 'postprocessing', 'ucr_datasets.json')
DS_INFO_PATH = os.path.join(PROJECT_PATH, 'fedot_ind', 'core', 'architecture', 'postprocessing', 'ucr_datasets.json')


def default_path_to_save_results() -> str:
path = PROJECT_PATH
save_path = os.path.join(path, 'results_of_experiments')
return save_path
DEFAULT_PATH_RESULTS = os.path.join(PROJECT_PATH, 'results_of_experiments')
37 changes: 0 additions & 37 deletions fedot_ind/api/utils/reporter.py

This file was deleted.

11 changes: 5 additions & 6 deletions fedot_ind/api/utils/saver_collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import pandas as pd

from fedot_ind.api.utils.path_lib import default_path_to_save_results
from fedot_ind.api.utils.path_lib import DEFAULT_PATH_RESULTS


class ResultSaver:
Expand All @@ -15,12 +15,11 @@ def __init__(self, dataset_name: str, generator_name: str, output_dir: str = Non
self.save_method_dict = {'labels': self.save_labels,
'probs': self.save_probs,
'metrics': self.save_metrics,
'baseline_metrics': self.save_baseline_metrics
}
'baseline_metrics': self.save_baseline_metrics}

def __init_save_path(self, dataset_name, generator_name, output_dir):
if output_dir is None:
self.output_dir = default_path_to_save_results()
self.output_dir = DEFAULT_PATH_RESULTS
else:
self.output_dir = os.path.abspath(output_dir)
path = os.path.join(self.output_dir, generator_name, dataset_name)
Expand All @@ -37,12 +36,12 @@ def save(self, predicted_data, prediction_type: str):

def save_labels(self, label_data):
df = pd.DataFrame(label_data, dtype=int)
df.to_csv(os.path.join(self.path, 'predicted_labels.csv'))
df.to_csv(os.path.join(self.path, 'labels.csv'))

def save_probs(self, prob_data):
df_preds = pd.DataFrame(prob_data.round(3), dtype=float)
df_preds.columns = [f'Class_{x + 1}' for x in df_preds.columns]
df_preds.to_csv(os.path.join(self.path, 'predicted_probs.csv'))
df_preds.to_csv(os.path.join(self.path, 'probs.csv'))

def save_metrics(self, metrics: dict):
df = pd.DataFrame(metrics, index=[0])
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging
from pathlib import Path
from typing import List, Union, Dict
from typing import Dict, List, Union
from typing import Optional

import matplotlib.patches as mpatches
Expand All @@ -18,7 +18,7 @@
from golem.core.tuning.simultaneous import SimultaneousTuner
from matplotlib import pyplot as plt

from fedot_ind.api.utils.path_lib import default_path_to_save_results
from fedot_ind.api.utils.path_lib import DEFAULT_PATH_RESULTS
from fedot_ind.api.utils.saver_collections import ResultSaver
from fedot_ind.core.metrics.evaluation import PerformanceAnalyzer
from fedot_ind.core.operation.transformation.splitter import TSTransformer
Expand Down Expand Up @@ -53,7 +53,7 @@ def __init__(self, params: Optional[OperationParameters] = None):
self.dataset_name = params.get('dataset')
self.tuning_iterations = params.get('tuning_iterations', 30)
self.tuning_timeout = params.get('tuning_timeout', 15.0)
self.output_folder = params.get('output_folder', default_path_to_save_results())
self.output_folder = params.get('output_folder', DEFAULT_PATH_RESULTS)

self.saver = ResultSaver(dataset_name=self.dataset_name,
generator_name='fedot_preset',
Expand Down Expand Up @@ -186,12 +186,10 @@ def fit(self, features,

with IndustrialModels():
self.train_data = self._init_input_data(features, anomaly_dict)
self.pre_pipeline = self._tune_pipeline(self.predictor,
self.train_data)

self.pre_pipeline.fit(self.train_data)
# train_data_preprocessed = self.generator.root_node.predict(self.train_data)
train_data_preprocessed = self.pre_pipeline.root_node.predict(self.train_data)
self.preprocessing_pipeline = self._tune_pipeline(self.predictor,
self.train_data)
self.preprocessing_pipeline.fit(self.train_data)
train_data_preprocessed = self.preprocessing_pipeline.root_node.predict(self.train_data)
train_data_preprocessed.predict = np.squeeze(train_data_preprocessed.predict)

train_data_preprocessed = InputData(idx=train_data_preprocessed.idx,
Expand All @@ -202,18 +200,12 @@ def fit(self, features,

metric = 'roc_auc' if train_data_preprocessed.num_classes == 2 else 'f1'
self.model_params.update({'metric': metric})
self.auto_model = Fedot(available_operations=['scaling',
'normalization',
'fast_ica',
'xgboost',
'rfr',
'rf',
'logit',
'mlp',
'knn',
'lgbm',
'pca'],
**self.model_params)
if self.model_params.get('available_operations') is None:
self.auto_model = Fedot(available_operations=['scaling', 'normalization', 'fast_ica', 'xgboost',
'rfr', 'rf', 'logit', 'mlp', 'knn', 'lgbm', 'pca'],
**self.model_params)
else:
self.auto_model = Fedot(**self.model_params)

self.auto_model.fit(train_data_preprocessed)
self.predictor = self.auto_model.current_pipeline
Expand All @@ -229,7 +221,7 @@ def predict(self, features: pd.DataFrame) -> np.array:
"""

test_data = self._init_input_data(features, is_fit_stage=False)
test_data_preprocessed = self.pre_pipeline.root_node.predict(test_data)
test_data_preprocessed = self.preprocessing_pipeline.root_node.predict(test_data)

if test_data.features.shape[0] == 1:
test_data_preprocessed.predict = np.squeeze(test_data_preprocessed.predict).reshape(1, -1)
Expand All @@ -247,7 +239,7 @@ def predict(self, features: pd.DataFrame) -> np.array:

def predict_proba(self, features) -> np.array:
test_data = self._init_input_data(features, is_fit_stage=False)
test_data_preprocessed = self.pre_pipeline.predict(test_data)
test_data_preprocessed = self.preprocessing_pipeline.predict(test_data)
test_data_preprocessed.predict = np.squeeze(test_data_preprocessed.predict)
test_data_preprocessed = InputData(idx=test_data_preprocessed.idx,
features=test_data_preprocessed.predict,
Expand Down
14 changes: 7 additions & 7 deletions fedot_ind/core/architecture/experiment/TimeSeriesClassifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ def __init__(self, params: Optional[OperationParameters] = None):

self.logger.info('TimeSeriesClassifier initialised')

def fit(self, features: Union[np.ndarray, pd.DataFrame],
def fit(self, features: pd.DataFrame,
target: np.ndarray,
**kwargs) -> object:
**kwargs) -> Fedot:

baseline_type = kwargs.get('baseline_type', None)
self.logger.info('Fitting model')
Expand Down Expand Up @@ -122,16 +122,16 @@ def _fit_baseline_model(self, features: pd.DataFrame, target: np.ndarray, baseli
return baseline_pipeline

def predict(self, features: np.ndarray, **kwargs) -> np.ndarray:
self.prediction_label = self.__predict_abstraction(test_features=features, mode='labels', **kwargs)
self.prediction_label = self._predict_abstraction(test_features=features, mode='labels', **kwargs)
return self.prediction_label

def predict_proba(self, features: np.ndarray, **kwargs) -> np.ndarray:
self.prediction_proba = self.__predict_abstraction(test_features=features, mode='probs', **kwargs)
self.prediction_proba = self._predict_abstraction(test_features=features, mode='probs', **kwargs)
return self.prediction_proba

def __predict_abstraction(self,
test_features: Union[np.ndarray, pd.DataFrame],
mode: str = 'labels', **kwargs):
def _predict_abstraction(self,
test_features: Union[np.ndarray, pd.DataFrame],
mode: str = 'labels', **kwargs):
self.logger.info(f'Predicting with {self.strategy} generator')

if self.test_features is None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import torch
from fedot.core.operations.operation_parameters import OperationParameters

from fedot_ind.api.utils.path_lib import DEFAULT_PATH_RESULTS
from fedot_ind.core.architecture.experiment.TimeSeriesClassifier import TimeSeriesClassifier
from fedot_ind.api.utils.path_lib import default_path_to_save_results
from fedot_ind.core.models.nn.inception import InceptionTimeNetwork

TSCCLF_MODEL = {
Expand All @@ -22,13 +22,13 @@ def __init__(self, params: Optional[OperationParameters] = None):
self.num_epochs = params.get('num_epochs', 10)

def _init_model_param(self, target: np.ndarray) -> Tuple[int, np.ndarray]:
self.model_hyperparams['models_saving_path'] = os.path.join(default_path_to_save_results(), 'TSCNN',
self.model_hyperparams['models_saving_path'] = os.path.join(DEFAULT_PATH_RESULTS, 'TSCNN',
'../../models')
self.model_hyperparams['summary_path'] = os.path.join(default_path_to_save_results(), 'TSCNN',
self.model_hyperparams['summary_path'] = os.path.join(DEFAULT_PATH_RESULTS, 'TSCNN',
'runs')
self.model_hyperparams['num_classes'] = np.unique(target).shape[0]

if target.min() != 0:
target = target - 1

return self.num_epochs, target
return self.num_epochs, target
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from golem.core.tuning.sequential import SequentialTuner

from fedot_ind.api.utils.input_data import init_input_data
from fedot_ind.api.utils.path_lib import default_path_to_save_results
from fedot_ind.api.utils.path_lib import DEFAULT_PATH_RESULTS
from fedot_ind.api.utils.saver_collections import ResultSaver
from fedot_ind.core.metrics.evaluation import PerformanceAnalyzer
from fedot_ind.core.repository.initializer_industrial_models import IndustrialModels
Expand Down Expand Up @@ -48,7 +48,7 @@ def __init__(self, params: Optional[OperationParameters] = None):
self.dataset_name = params.get('dataset')
self.tuning_iterations = params.get('tuning_iterations', 30)
self.tuning_timeout = params.get('tuning_timeout', 15.0)
self.output_folder = params.get('output_folder', default_path_to_save_results())
self.output_folder = params.get('output_folder', DEFAULT_PATH_RESULTS)

self.saver = ResultSaver(dataset_name=self.dataset_name,
generator_name='fedot_preset',
Expand Down Expand Up @@ -137,11 +137,9 @@ def fit(self, features,

with IndustrialModels():
self.train_data = self._init_input_data(features, target)

self.preprocessing_pipeline = self._tune_pipeline(self.preprocessing_pipeline,
self.train_data)
self.preprocessing_pipeline.fit(self.train_data)

self.baseline_model = self.preprocessing_pipeline.nodes[0]
self.preprocessing_pipeline.update_node(self.baseline_model, PipelineNode('cat_features'))
self.baseline_model.nodes_from = []
Expand Down
3 changes: 2 additions & 1 deletion fedot_ind/core/architecture/pipelines/anomaly_detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from pymonad.list import ListMonad
from pymonad.either import Right
from fedot_ind.core.architecture.pipelines.abstract_pipeline import AbstractPipelines
from fedot_ind.core.operation.transformation.basis.eigen_basis import EigenBasisImplementation


class AnomalyDetectionPipelines(AbstractPipelines):
Expand Down Expand Up @@ -66,7 +67,7 @@ def __multi_functional_pca(self):
def __functional_pca_pipeline(self, decomposition: str = 'svd', **kwargs):
feature_extractor, detector, lambda_func_dict = self._init_pipeline_nodes(model_type='functional_pca',
**kwargs)
data_basis = DataDrivenBasis()
data_basis = EigenBasisImplementation()
if kwargs['component'] is None:
kwargs['component'] = [0 for i in range(self.train_features.shape[1])]
if decomposition == 'tensor':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ def __init__(self, path: str = None, launch_type: Union[str, int] = 'max'):
self.launch_type = launch_type
self.logger = logging.getLogger(self.__class__.__name__)


def __get_results_path(self, path):
if path:
return path
Expand Down
4 changes: 2 additions & 2 deletions fedot_ind/core/ensemble/rank_ensembler.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def _deep_search_in_dict(self, obj, key):
if item is not None:
return item

def _create_models_rank_dict(self, prediction_proba_dict, metric_dict):
def _create_models_rank_dict(self, prediction_proba_dict, metric_dict) -> dict:
"""
Method that returns a dictionary with the best metric values of base models

Expand All @@ -96,7 +96,7 @@ def _create_models_rank_dict(self, prediction_proba_dict, metric_dict):
model_rank.update({model: current_metrics[self.metric]})
return model_rank

def _sort_models(self, model_rank):
def _sort_models(self, model_rank) -> dict:
"""
Method that returns sorted dictionary with models results ``

Expand Down
4 changes: 2 additions & 2 deletions fedot_ind/core/models/nn/inception.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ def __init__(self, in_channels,
padding=kernel_sizes[2] // 2,
bias=False
)
self.max_pool = nn.MaxPool1d(kernel_size=3, stride=1, padding=1, return_indices=return_indices)
self.max_pool = nn.MaxPool1d(
kernel_size=3, stride=1, padding=1, return_indices=return_indices)
self.conv_from_maxpool = nn.Conv1d(
in_channels=in_channels,
out_channels=n_filters,
Expand Down Expand Up @@ -316,4 +317,3 @@ def network_architecture(self):
nn.Linear(in_features=4 * 32 * 1, out_features=4)
)
return network

Loading