Skip to content

Commit

Permalink
industrial adaptation for multriclassification and multiregression ts…
Browse files Browse the repository at this point in the history
… through Fedot API
  • Loading branch information
v1docq committed Dec 5, 2023
1 parent 488454c commit 113b3f7
Show file tree
Hide file tree
Showing 18 changed files with 380 additions and 86 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import os
from pathlib import Path

from fedot.core.pipelines.pipeline_builder import PipelineBuilder
from examples.example_utils import evaluate_metric
from examples.example_utils import init_input_data
from fedot_ind.api.utils.path_lib import PROJECT_PATH
from fedot_ind.tools.loader import DataLoader
from fedot_ind.core.repository.initializer_industrial_models import IndustrialModels

metric_dict = {}

# group = os.listdir(Path(PROJECT_PATH, 'data'))

model_dict = {
'eigen_basis_basic': PipelineBuilder().add_node(
'eigen_basis',
Expand Down Expand Up @@ -54,16 +49,16 @@
# ]

if __name__ == "__main__":
OperationTypesRepository = IndustrialModels().setup_repository()
for dataset_name in datasets_bad_f1:
train_data, test_data = DataLoader(dataset_name=dataset_name).load_data()
input_data = init_input_data(train_data[0], train_data[1])
val_data = init_input_data(test_data[0], test_data[1])
with IndustrialModels():
for model in model_dict.keys():
pipeline = model_dict[model].build()
pipeline.fit(input_data)
features = pipeline.predict(val_data, 'labels').predict
metric = evaluate_metric(target=test_data[1], prediction=features)
metric_dict.update({f'{dataset_name}_{model}': metric})
print(f'{dataset_name}_{model} - {metric}')
for model in model_dict.keys():
pipeline = model_dict[model].build()
pipeline.fit(input_data)
features = pipeline.predict(val_data, 'labels').predict
metric = evaluate_metric(target=test_data[1], prediction=features)
metric_dict.update({f'{dataset_name}_{model}': metric})
print(f'{dataset_name}_{model} - {metric}')
print(metric_dict)
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import matplotlib
from fedot import Fedot
from fedot.core.pipelines.pipeline_builder import PipelineBuilder
from fedot.core.pipelines.verification import common_rules

from examples.example_utils import evaluate_metric
from examples.example_utils import init_input_data
from fedot_ind.tools.loader import DataLoader
from fedot_ind.core.repository.initializer_industrial_models import IndustrialModels

matplotlib.use('TkAgg')
model_dict = {'basic_quantile': PipelineBuilder().add_node('quantile_extractor',
params={'window_size': 10,
'stride': 5}).add_node('rf'),
Expand All @@ -27,16 +32,75 @@
'rf')
}
metric_dict = {}
train_data, test_data = DataLoader(dataset_name='Ham').load_data()

dataset = 'Lightning7'
dataset_multi_dim = 'LSST'
train_data, test_data = DataLoader(dataset_name = dataset_multi_dim).load_data()
ts_clf_operations = [
'eigen_basis',
'dimension_reduction',
'inception_model',
'rf',
'minirocket_extractor',
'normalization',
'omniscale_model',
'pca',
'mlp',
'quantile_extractor',
'recurrence_extractor',
'resample',
'scaling',
'signal_extractor',
'topological_features'
]
# ts_clf_operations = [
# 'eigen_basis',
# 'dimension_reduction',
# 'inception_model',
# 'rf',
# 'minirocket_extractor',
# 'normalization',
# 'omniscale_model',
# 'pca',
# 'mlp',
# 'quantile_extractor',
# 'recurrence_extractor',
# 'resample',
# 'scaling',
# 'signal_extractor',
# 'topological_features'
# ]
if __name__ == "__main__":
with IndustrialModels():
for model in model_dict.keys():
pipeline = model_dict[model].build()
input_data = init_input_data(train_data[0], train_data[1])
val_data = init_input_data(test_data[0], test_data[1])
pipeline.fit(input_data)
features = pipeline.predict(val_data).predict
metric = evaluate_metric(target=test_data[1], prediction=features)
metric_dict.update({model: metric})
OperationTypesRepository = IndustrialModels().setup_repository()
#error_pipeline = PipelineBuilder().add_node('scaling').add_node('signal_extractor').add_node('quantile_extractor').add_node('inception_model').build()
error_pipeline = PipelineBuilder().add_node('scaling').add_node('inception_model').build()
# error_pipeline = PipelineBuilder().add_node('scaling').add_node('signal_extractor').add_node(
# 'quantile_extractor').add_node('normalization',branch_idx=1).add_node('signal_extractor',branch_idx=1).add_node(
# 'quantile_extractor',branch_idx=1).join_branches('logit').build()
# # error_pipeline = PipelineBuilder().add_node('signal_extractor').add_node(
# # 'quantile_extractor').add_node('logit').build()
# # add_node('inception_model').add_node(
# # 'scaling',
# # branch_idx=1).join_branches(
# # 'logit').build()
for model in model_dict.keys():
pipeline = model_dict[model].build()
input_data = init_input_data(train_data[0], train_data[1])
val_data = init_input_data(test_data[0], test_data[1])
model = Fedot(problem='classification',
logging_level=20,
n_jobs=1,
metric='f1',
available_operations=ts_clf_operations,
timeout=20
)
model.fit(input_data)
model.current_pipeline.show()
features = model.predict(val_data)
metric = evaluate_metric(target=val_data.target, prediction=features)
metric_dict.update({model: metric})
model.history.save(f"{dataset}classification_history.json")
model.history.show.fitness_box(best_fraction=0.5, dpi=100)
model.history.show.operations_kde(dpi=100)
model.history.show.operations_animated_bar(save_path=f'./{dataset}_history_animated_bars.gif',
show_fitness=True, dpi=100)
print(metric_dict)
20 changes: 13 additions & 7 deletions fedot_ind/core/architecture/preprocessing/data_convertor.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
# else:
# if return_names: return split_xy(X, y, splits), data_cols
# return split_xy(X, y, splits)
from fedot_ind.core.architecture.settings.computational import default_device
from fedot_ind.core.architecture.settings.constanst_repository import MULTI_ARRAY, MATRIX


Expand All @@ -117,21 +118,26 @@ def __len__(self):

class CustomDatasetCLF:
def __init__(self, ts):
self.x = torch.from_numpy(ts.features).float()
self.x = torch.from_numpy(ts.features).to(default_device()).float()
label_1 = max(ts.class_labels)
label_0 = min(ts.class_labels)
classes = ts.num_classes
if classes == 2 and label_1 != 1:
self.classes = ts.num_classes
if self.classes == 2 and label_1 != 1:
ts.target[ts.target == label_0] = 0
ts.target[ts.target == label_1] = 1
elif classes == 2 and label_0 != 0:
elif self.classes == 2 and label_0 != 0:
ts.target[ts.target == label_0] = 0
ts.target[ts.target == label_1] = 1
elif classes > 2 and label_0 == 1:
elif self.classes > 2 and label_0 == 1:
ts.target = ts.target - 1

self.y = torch.nn.functional.one_hot(torch.from_numpy(ts.target).long(),
num_classes=classes).squeeze(1)
try:
self.y = torch.nn.functional.one_hot(torch.from_numpy(ts.target).long(),
num_classes=self.classes).to(default_device()).squeeze(1)
except Exception:
self.y = torch.nn.functional.one_hot(torch.from_numpy(ts.target).long()).to(default_device()).squeeze(1)
self.classes = self.y.shape[1]

self.n_samples = ts.features.shape[0]
self.supplementary_data = ts.supplementary_data

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import torch
from fedot.core.repository.dataset_types import DataTypesEnum
from torch import nn, Tensor

import torch.nn.functional as F
from fedot_ind.core.models.nn.network_modules.losses import *
from fedot_ind.core.models.quantile.stat_features import *
from fedot_ind.core.models.topological.topofeatures import *
Expand Down
27 changes: 14 additions & 13 deletions fedot_ind/core/models/nn/network_impl/base_nn_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ class BaseNeuralModel:
"""

def __init__(self, params: Optional[OperationParameters] = {}):
self.num_classes = params.get('num_classes', 1)
self.num_classes = params.get('num_classes', None)
self.epochs = params.get('epochs', 10)
self.batch_size = params.get('batch_size', 20)
self.output_mode = params.get('output_mode', 'labels')

@convert_inputdata_to_torch_dataset
def _create_dataset(self, ts: InputData):
Expand All @@ -50,9 +51,16 @@ def _init_model(self, ts):
self.model = None
return

def _evalute_num_of_epochs(self, ts):
min_num_epochs = min(100, round(ts.features.shape[0] * 1.5))
if self.epochs is None:
self.epochs = min_num_epochs
else:
self.epochs = max(min_num_epochs, self.epochs)

def _convert_predict(self, pred):
pred = F.softmax(pred, dim=1)
if self.num_classes == 2:
if self.output_mode == 'labels':
pred = torch.argmax(pred, dim=1)
y_pred = pred.cpu().detach().numpy()
predict = OutputData(
Expand All @@ -70,6 +78,7 @@ def _prepare_data(self, ts, split_data: bool = True):
val_dataset = self._create_dataset(val_data)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=self.batch_size, shuffle=True)
val_loader = torch.utils.data.DataLoader(val_dataset, batch_size=self.batch_size, shuffle=True)
self.num_classes = train_dataset.classes
return train_loader, val_loader

def _train_loop(self, train_loader, val_loader, loss_fn, optimizer):
Expand All @@ -88,24 +97,16 @@ def _train_loop(self, train_loader, val_loader, loss_fn, optimizer):
training_loss /= len(train_loader.dataset)

self.model.eval()
num_correct = 0
num_examples = 0
for batch in val_loader:
inputs, targets = batch
output = self.model(inputs)
loss = loss_fn(output, targets.float())
valid_loss += loss.data.item() * inputs.size(0)
correct = torch.eq(torch.max(F.softmax(output, dim=1), dim=1)[1],
torch.max(targets, dim=1)[1])

num_correct += torch.sum(correct).item()
num_examples += correct.shape[0]
valid_loss /= len(val_loader.dataset)

print('Epoch: {}, Training Loss: {:.2f}, Validation Loss: {:.2f}, accuracy = {:.2f}'.format(epoch,
training_loss,
valid_loss,
num_correct / num_examples))
print('Epoch: {}, Training Loss: {:.2f}, Validation Loss: {:.2f}'.format(epoch,
training_loss,
valid_loss))

@convert_to_3d_torch_array
def _fit_model(self, ts: InputData, split_data: bool = True):
Expand Down
8 changes: 5 additions & 3 deletions fedot_ind/core/models/nn/network_impl/inception.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,18 @@ class InceptionTimeModel(BaseNeuralModel):
"""

def __init__(self, params: Optional[OperationParameters] = {}):
super().__init__(params)
self.num_classes = params.get('num_classes', 1)
self.epochs = params.get('epochs', 100)
self.epochs = params.get('epochs', None)
self.batch_size = params.get('batch_size', 32)

def _init_model(self, ts):
self.model = InceptionTime(input_dim=ts.features.shape[1],
output_dim=self.num_classes).to(default_device())
self._evalute_num_of_epochs(ts)
optimizer = optim.Adam(self.model.parameters(), lr=0.001)
if ts.num_classes == 2:
loss_fn = CROSS_ENTROPY
loss_fn = CROSS_ENTROPY()
else:
loss_fn = MULTI_CLASS_CROSS_ENTROPY
loss_fn = MULTI_CLASS_CROSS_ENTROPY()
return loss_fn, optimizer
8 changes: 5 additions & 3 deletions fedot_ind/core/models/nn/network_impl/omni_scale.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,17 +121,19 @@ class OmniScaleModel(BaseNeuralModel):
"""

def __init__(self, params: Optional[OperationParameters] = {}):
super().__init__(params)
self.num_classes = params.get('num_classes', 1)
self.epochs = params.get('epochs', 100)
self.epochs = params.get('epochs', 50)
self.batch_size = params.get('batch_size', 32)

def _init_model(self, ts):
self.model = OmniScaleCNN(input_dim=ts.features.shape[1],
output_dim=self.num_classes,
seq_len=ts.features.shape[2]).to(default_device())
self._evalute_num_of_epochs(ts)
optimizer = optim.Adam(self.model.parameters(), lr=0.001)
if ts.num_classes == 2:
loss_fn = CROSS_ENTROPY
loss_fn = CROSS_ENTROPY()
else:
loss_fn = MULTI_CLASS_CROSS_ENTROPY
loss_fn = MULTI_CLASS_CROSS_ENTROPY()
return loss_fn, optimizer
2 changes: 1 addition & 1 deletion fedot_ind/core/models/nn/network_impl/resnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class ResNetModel(BaseNeuralModel):

def __init__(self, params: Optional[OperationParameters] = {}):
self.num_classes = params.get('num_classes', 1)
self.epochs = params.get('epochs', 100)
self.epochs = params.get('epochs', 10)
self.batch_size = params.get('batch_size', 32)
self.model_name = params.get('model_name', 'ResNet18')

Expand Down
6 changes: 3 additions & 3 deletions fedot_ind/core/operation/filtration/feature_filtration.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ def _transform(self, operation):
operation_name = operation.task.task_params
else:
operation_name = operation.task.task_params.feature_filter
if operation_name in self.method_dict.keys():
if operation_name is None:
return operation.features
elif operation_name in self.method_dict.keys():
method = self.method_dict[operation_name]
return method(operation)
else:
return operation.features

def filter_dimension_num(self, data):
if len(data.features.shape) < 3:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def _convert_to_operation(self, operation_type: str):

def __init__(self, operation_type: str, params: Optional[OperationParameters] = None):
self.operation_impl = self._convert_to_operation(operation_type)
self.output_mode = params.get('output_mode', 'labels')
super().__init__(operation_type, params)

def fit(self, train_data: InputData):
Expand Down Expand Up @@ -60,4 +61,4 @@ def _convert_to_operation(self, operation_type: str):

def __init__(self, operation_type: str, params: Optional[OperationParameters] = None):
self.operation_impl = self._convert_to_operation(operation_type)
super().__init__(operation_type, params)
super().__init__(operation_type, params)
Loading

0 comments on commit 113b3f7

Please sign in to comment.