sdg-core-lib 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sdg-core-lib might be problematic. Click here for more details.

Files changed (76) hide show
  1. sdg_core_lib-0.1.0/PKG-INFO +9 -0
  2. sdg_core_lib-0.1.0/README.md +0 -0
  3. sdg_core_lib-0.1.0/pyproject.toml +35 -0
  4. sdg_core_lib-0.1.0/src/sdg_core_lib/NumericDataset.py +150 -0
  5. sdg_core_lib-0.1.0/src/sdg_core_lib/__init__.py +0 -0
  6. sdg_core_lib-0.1.0/src/sdg_core_lib/browser.py +73 -0
  7. sdg_core_lib-0.1.0/src/sdg_core_lib/data_generator/__init__.py +0 -0
  8. sdg_core_lib-0.1.0/src/sdg_core_lib/data_generator/model_factory.py +72 -0
  9. sdg_core_lib-0.1.0/src/sdg_core_lib/data_generator/models/ModelInfo.py +42 -0
  10. sdg_core_lib-0.1.0/src/sdg_core_lib/data_generator/models/TrainingInfo.py +40 -0
  11. sdg_core_lib-0.1.0/src/sdg_core_lib/data_generator/models/UnspecializedModel.py +106 -0
  12. sdg_core_lib-0.1.0/src/sdg_core_lib/data_generator/models/__init__.py +0 -0
  13. sdg_core_lib-0.1.0/src/sdg_core_lib/data_generator/models/keras/KerasBaseVAE.py +172 -0
  14. sdg_core_lib-0.1.0/src/sdg_core_lib/data_generator/models/keras/VAE.py +61 -0
  15. sdg_core_lib-0.1.0/src/sdg_core_lib/data_generator/models/keras/__init__.py +0 -0
  16. sdg_core_lib-0.1.0/src/sdg_core_lib/data_generator/models/keras/implementation/TabularVAE.py +96 -0
  17. sdg_core_lib-0.1.0/src/sdg_core_lib/data_generator/models/keras/implementation/TimeSeriesVAE.py +156 -0
  18. sdg_core_lib-0.1.0/src/sdg_core_lib/data_generator/models/keras/implementation/__init__.py +0 -0
  19. sdg_core_lib-0.1.0/src/sdg_core_lib/evaluate/Metrics.py +48 -0
  20. sdg_core_lib-0.1.0/src/sdg_core_lib/evaluate/TabularComparison.py +276 -0
  21. sdg_core_lib-0.1.0/src/sdg_core_lib/evaluate/__init__.py +0 -0
  22. sdg_core_lib-0.1.0/src/sdg_core_lib/job.py +56 -0
  23. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/FunctionApplier.py +14 -0
  24. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/__init__.py +0 -0
  25. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/function_factory.py +41 -0
  26. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/functions/FunctionInfo.py +25 -0
  27. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/functions/FunctionResult.py +15 -0
  28. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/functions/Parameter.py +33 -0
  29. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/functions/UnspecializedFunction.py +42 -0
  30. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/functions/__init__.py +0 -0
  31. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/functions/distribution_evaluator/__init__.py +0 -0
  32. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/functions/distribution_evaluator/implementation/NormalTester.py +65 -0
  33. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/functions/distribution_evaluator/implementation/__init__.py +0 -0
  34. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/functions/filter/IntervalThreshold.py +32 -0
  35. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/functions/filter/MonoThreshold.py +28 -0
  36. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/functions/filter/__init__.py +0 -0
  37. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/functions/filter/implementation/InnerThreshold.py +43 -0
  38. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/functions/filter/implementation/LowerThreshold.py +32 -0
  39. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/functions/filter/implementation/OuterThreshold.py +42 -0
  40. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/functions/filter/implementation/UpperThreshold.py +32 -0
  41. sdg_core_lib-0.1.0/src/sdg_core_lib/post_process/functions/filter/implementation/__init__.py +0 -0
  42. sdg_core_lib-0.1.0/src/sdg_core_lib/preprocess/__init__.py +0 -0
  43. sdg_core_lib-0.1.0/src/sdg_core_lib/preprocess/scale.py +51 -0
  44. sdg_core_lib-0.1.0/src/sdg_core_lib/test/__init__.py +0 -0
  45. sdg_core_lib-0.1.0/src/sdg_core_lib/test/data_generator/__init__.py +0 -0
  46. sdg_core_lib-0.1.0/src/sdg_core_lib/test/data_generator/models/__init__.py +0 -0
  47. sdg_core_lib-0.1.0/src/sdg_core_lib/test/data_generator/models/keras/__init__.py +0 -0
  48. sdg_core_lib-0.1.0/src/sdg_core_lib/test/data_generator/models/keras/implementation/__init__.py +0 -0
  49. sdg_core_lib-0.1.0/src/sdg_core_lib/test/data_generator/models/keras/implementation/test_TabularVAE.py +120 -0
  50. sdg_core_lib-0.1.0/src/sdg_core_lib/test/data_generator/models/keras/implementation/test_TimeSeriesVAE.py +110 -0
  51. sdg_core_lib-0.1.0/src/sdg_core_lib/test/data_generator/models/keras/test_KerasBaseVAE.py +74 -0
  52. sdg_core_lib-0.1.0/src/sdg_core_lib/test/data_generator/models/test_ModelInfo.py +27 -0
  53. sdg_core_lib-0.1.0/src/sdg_core_lib/test/data_generator/models/test_TrainingInfo.py +30 -0
  54. sdg_core_lib-0.1.0/src/sdg_core_lib/test/data_generator/models/test_UnspecializedModel.py +32 -0
  55. sdg_core_lib-0.1.0/src/sdg_core_lib/test/data_generator/test_model_factory.py +52 -0
  56. sdg_core_lib-0.1.0/src/sdg_core_lib/test/evaluate/__init__.py +0 -0
  57. sdg_core_lib-0.1.0/src/sdg_core_lib/test/evaluate/test_Metrics.py +62 -0
  58. sdg_core_lib-0.1.0/src/sdg_core_lib/test/evaluate/test_TabularComparisonEvaluator.py +75 -0
  59. sdg_core_lib-0.1.0/src/sdg_core_lib/test/infer_test.json +168 -0
  60. sdg_core_lib-0.1.0/src/sdg_core_lib/test/infer_test_nodata.json +77 -0
  61. sdg_core_lib-0.1.0/src/sdg_core_lib/test/infer_test_nodata_wrong.json +11 -0
  62. sdg_core_lib-0.1.0/src/sdg_core_lib/test/post_process/__init__.py +0 -0
  63. sdg_core_lib-0.1.0/src/sdg_core_lib/test/post_process/functions/__init__.py +0 -0
  64. sdg_core_lib-0.1.0/src/sdg_core_lib/test/post_process/functions/distribution_evaluator/__init__.py +0 -0
  65. sdg_core_lib-0.1.0/src/sdg_core_lib/test/post_process/functions/distribution_evaluator/implementation/__init__.py +0 -0
  66. sdg_core_lib-0.1.0/src/sdg_core_lib/test/post_process/functions/distribution_evaluator/implementation/test_NormalTester.py +55 -0
  67. sdg_core_lib-0.1.0/src/sdg_core_lib/test/post_process/functions/filters/__init__.py +0 -0
  68. sdg_core_lib-0.1.0/src/sdg_core_lib/test/post_process/functions/filters/implementation/__init__.py +0 -0
  69. sdg_core_lib-0.1.0/src/sdg_core_lib/test/post_process/functions/filters/implementation/test_InnerThreshold.py +30 -0
  70. sdg_core_lib-0.1.0/src/sdg_core_lib/test/pre_process/__init__.py +0 -0
  71. sdg_core_lib-0.1.0/src/sdg_core_lib/test/pre_process/test_scaling.py +55 -0
  72. sdg_core_lib-0.1.0/src/sdg_core_lib/test/test_browser.py +11 -0
  73. sdg_core_lib-0.1.0/src/sdg_core_lib/test/test_dataset.py +149 -0
  74. sdg_core_lib-0.1.0/src/sdg_core_lib/test/test_job.py +128 -0
  75. sdg_core_lib-0.1.0/src/sdg_core_lib/test/train_test.json +166 -0
  76. sdg_core_lib-0.1.0/src/sdg_core_lib/test/train_test_2.json +9 -0
@@ -0,0 +1,9 @@
1
+ Metadata-Version: 2.3
2
+ Name: sdg-core-lib
3
+ Version: 0.1.0
4
+ Summary: Add your description here
5
+ Author: emiliocimino
6
+ Author-email: emiliocimino <emilio.cimino@outlook.it>
7
+ Requires-Python: >=3.12
8
+ Description-Content-Type: text/markdown
9
+
File without changes
@@ -0,0 +1,35 @@
1
+ [project]
2
+ name = "sdg-core-lib"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "emiliocimino", email = "emilio.cimino@outlook.it" }
8
+ ]
9
+
10
+ requires-python = ">=3.12"
11
+
12
+ [dependency-groups]
13
+ dev = [
14
+ "numpy==2.0.2",
15
+ "pandas==2.2.3",
16
+ "seaborn==0.13.2",
17
+ "scikit-learn==1.5.2",
18
+ "keras==3.6.0",
19
+ "tensorflow==2.18.0",
20
+ "loguru",
21
+ "skops",
22
+ "statsmodels"
23
+ ]
24
+
25
+ test = [
26
+ {include-group = "dev"},
27
+ "pytest"
28
+ ]
29
+
30
+ [project.scripts]
31
+ sdg-core-lib = "sdg_core_lib:main"
32
+
33
+ [build-system]
34
+ requires = ["uv_build>=0.8.22,<0.9.0"]
35
+ build-backend = "uv_build"
@@ -0,0 +1,150 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+
4
+ NUMERICAL = "continuous"
5
+ CATEGORICAL = "categorical"
6
+ OTHER = "none"
7
+
8
+
9
+ class NumericDataset:
10
+ """
11
+ Class to handle numeric datasets.
12
+ The class loads a dataset from a list of dictionaries into a pandas DataFrame.
13
+ It also identifies which columns are numerical and which are categorical.
14
+ """
15
+
16
+ def __init__(self, dataset: list[dict]):
17
+ self.dataset: list[dict] = dataset
18
+ self.dataframe: pd.DataFrame = pd.DataFrame()
19
+ self.columns: list[str] = []
20
+ self.continuous_columns = []
21
+ self.categorical_columns = []
22
+ self.unrecognized_columns = []
23
+ self.continuous_data: pd.DataFrame = pd.DataFrame()
24
+ self.categorical_data: pd.DataFrame = pd.DataFrame()
25
+ self.input_shape: str = ""
26
+ self._configure()
27
+
28
+ def _configure(self):
29
+ """
30
+ Convert data from requests into an easy-to-process dataframe
31
+ dataset: [{
32
+ column_data: [ ... ],
33
+ column_name: str,
34
+ column_type: str [continuous/categorical],
35
+ column_datatype: str
36
+ }]
37
+ :return: a pandas Dataframe where each column is structured as expected
38
+ :raises: ValueError if dataset is empty
39
+ """
40
+ data = self.dataset
41
+ if len(self.dataset) == 0:
42
+ raise ValueError("Dataset is empty")
43
+ column_names = []
44
+ categorical_columns = []
45
+ numerical_columns = []
46
+ unrecognized_columns = []
47
+ data_structure = []
48
+ for col in data:
49
+ content = col.get("column_data", [])
50
+ content_type = col.get("column_datatype", "object")
51
+ column_name = col.get("column_name", "")
52
+ column_type = col.get("column_type", "")
53
+ data_structure.append(np.array(content, dtype=content_type))
54
+ column_names.append(column_name)
55
+ if column_type == NUMERICAL:
56
+ numerical_columns.append(column_name)
57
+ elif column_type == CATEGORICAL:
58
+ categorical_columns.append(column_name)
59
+ else:
60
+ unrecognized_columns.append(column_name)
61
+
62
+ input_data = {
63
+ col["column_name"]: np.array(col.get("column_data", [])).tolist()
64
+ for col in data
65
+ }
66
+ data_frame = pd.DataFrame(input_data)
67
+ data_structure = np.array(data_frame.to_numpy().tolist())
68
+
69
+ self.dataframe = data_frame
70
+ self.columns = column_names
71
+ self.categorical_columns = categorical_columns
72
+ self.continuous_columns = numerical_columns
73
+ self.unrecognized_columns = unrecognized_columns
74
+ self.continuous_data = data_frame[numerical_columns]
75
+ self.categorical_data = data_frame[categorical_columns]
76
+ self.input_shape = str(data_structure.shape[1:])
77
+
78
+ def _categorize_column(self, col):
79
+ if col in self.continuous_columns:
80
+ return NUMERICAL
81
+ if col in self.categorical_columns:
82
+ return CATEGORICAL
83
+ return OTHER
84
+
85
+ def parse_tabular_data_json(self) -> list[dict]:
86
+ """
87
+ Converts data from a dataframe into a list of dictionaries
88
+ :return: a dictionary in form of:
89
+ dataset: [{
90
+ column_data: [ ... ],
91
+ column_name: str,
92
+ column_type: str [numerical/categorical],
93
+ column_datatype: str
94
+ }]
95
+ """
96
+ return [
97
+ {
98
+ "column_data": self.dataframe[col].to_numpy().tolist(),
99
+ "column_name": col,
100
+ "column_type": self._categorize_column(col),
101
+ "column_datatype": str(self.dataframe[col].to_numpy().dtype),
102
+ }
103
+ for col in self.dataframe.columns
104
+ ]
105
+
106
+ def parse_data_to_registry(self) -> list[dict]:
107
+ """
108
+ Translates data structure from input coherence to a structured feature list
109
+ :return:
110
+ """
111
+ feature_list = []
112
+ for idx, col in enumerate(self.dataset):
113
+ feat = {
114
+ "feature_name": col.get("column_name", ""),
115
+ "feature_position": idx,
116
+ "is_categorical": (
117
+ True if col.get("column_type", "") == CATEGORICAL else False
118
+ ),
119
+ "type": col.get("column_datatype", ""),
120
+ }
121
+ feature_list.append(feat)
122
+ return feature_list
123
+
124
+ def get_data(self) -> tuple[pd.DataFrame, list[str], list[str], list[str]]:
125
+ """
126
+ Returns the data in the dataset as a tuple of 4 elements:
127
+
128
+ 1. The pandas DataFrame containing the data
129
+ 2. A list of column names
130
+ 3. A list of continuous column names
131
+ 4. A list of categorical column names
132
+
133
+ :return: (dataframe, columns, continuous_columns, categorical_columns)
134
+ :rtype: tuple[pandas.DataFrame, list[str], list[str], list[str]]
135
+ """
136
+ return (
137
+ self.dataframe,
138
+ self.columns,
139
+ self.continuous_columns,
140
+ self.categorical_columns,
141
+ )
142
+
143
+ @staticmethod
144
+ def get_numpy_data(dataframe: pd.DataFrame) -> np.ndarray:
145
+ """
146
+ Correctly Returns numpy array with complex structures, like columns with type list
147
+ :param dataframe: numpy dataframe
148
+ :return: correctly structured numpy array
149
+ """
150
+ return np.array(dataframe.to_numpy().tolist())
File without changes
@@ -0,0 +1,73 @@
1
+ import os
2
+ from pathlib import Path
3
+ import importlib
4
+ from typing import Generator
5
+
6
+
7
+ def find_implementations(
8
+ root_path: str, implementation_folder: str = "implementation"
9
+ ) -> list[str]:
10
+ """
11
+ Takes a root path and a name of a folder. Returns all modules existing in each of the so-named folders
12
+ :param implementation_folder: folder name where implemented modules exist
13
+ :param root_path: root path in which to explore
14
+ :return: list of stringed modules represented in py-like dot-notation
15
+ """
16
+
17
+ root_dir = Path(root_path).resolve() # Ensure absolute path
18
+ implementation_dirs = root_dir.rglob(
19
+ implementation_folder
20
+ ) # Find all 'implementation' folders
21
+ module_paths = []
22
+
23
+ for impl_dir in implementation_dirs:
24
+ py_files = [
25
+ file for file in impl_dir.glob("*.py") if file.name != "__init__.py"
26
+ ]
27
+
28
+ for file in py_files:
29
+ rel_path = file.relative_to(root_dir).with_suffix("") # Remove extension
30
+ module_path = ".".join(rel_path.parts) # Convert to module notation
31
+ module_paths.append(module_path)
32
+
33
+ return module_paths
34
+
35
+
36
+ def browse(path: str, package: str) -> Generator[dict | None, None, None]:
37
+ """
38
+ Generator function to iterate.
39
+ It exploits the find_implementations function to gather all module names, then extract from each module
40
+ the main class. Each main class so extracted provides a dictionary description.
41
+
42
+ :return: dictionary description of each implementation existing in sdg_core_lib
43
+ """
44
+
45
+ modules = find_implementations(path)
46
+ list_module_names = [f"{package}{module}" for module in modules]
47
+
48
+ for module_name in list_module_names:
49
+ class_name = module_name.split(".")[-1]
50
+ try:
51
+ module = importlib.import_module(module_name)
52
+ except ImportError:
53
+ yield None
54
+ continue
55
+ Class = getattr(module, class_name)
56
+
57
+ yield Class.self_describe()
58
+
59
+
60
+ def browse_functions():
61
+ base_function_package = "sdg_core_lib.post_process.functions."
62
+ base_function_path = os.path.join(
63
+ os.path.dirname(os.path.abspath(__file__)), "post_process/functions/"
64
+ )
65
+ return browse(base_function_path, base_function_package)
66
+
67
+
68
+ def browse_algorithms():
69
+ base_model_package = "sdg_core_lib.data_generator.models."
70
+ base_model_path = os.path.join(
71
+ os.path.dirname(os.path.abspath(__file__)), "data_generator/models/"
72
+ )
73
+ return browse(base_model_path, base_model_package)
@@ -0,0 +1,72 @@
1
+ import importlib
2
+
3
+ from sdg_core_lib.data_generator.models.UnspecializedModel import UnspecializedModel
4
+
5
+
6
+ def dynamic_import(class_name: str):
7
+ """
8
+ Dynamically imports a class given its name.
9
+
10
+ :param class_name: a string with the full name of the class to import
11
+ :return: the class itself
12
+ """
13
+ module_name, class_name = class_name.rsplit(".", 1)
14
+ module = importlib.import_module(module_name)
15
+ return getattr(module, class_name)
16
+
17
+
18
+ def model_factory(model_dict: dict, input_shape: str = None) -> UnspecializedModel:
19
+ """
20
+ This function is a generic model factory. Takes a dictionary containing useful model information and plugs
21
+ them in the model itself.
22
+ Input shape may be passed as an argument (i.e) from the request data itself, or [alternatively] may be present in
23
+ model dictionary. If not explicitly passed, it will use the model dictionary
24
+
25
+ :param model_dict: A dictionary containing model information, structured as follows:
26
+ {
27
+ "image" -> contains the possible path where to find the model image. If not none, model will be loaded from there
28
+ "metadata" -> a dictionary itself, containing miscellaneous information
29
+ "algorithm_name" -> includes the model class module to _load
30
+ "model_name" -> the model name, used to identify the model itself
31
+ "input_shape" [optional] -> contains a stringed tuple that identifies the input layer shape
32
+ }
33
+ :param input_shape:
34
+ :return: An instance of a BaseModel class or any subclass
35
+ """
36
+ model_file, metadata, model_type, model_name, input_shape_model = parse_model_info(
37
+ model_dict
38
+ )
39
+ if input_shape is None:
40
+ input_shape = input_shape_model
41
+
42
+ ModelClass = dynamic_import(model_type)
43
+ model = ModelClass(
44
+ metadata=metadata,
45
+ model_name=model_name,
46
+ input_shape=input_shape,
47
+ load_path=model_file,
48
+ )
49
+ return model
50
+
51
+
52
+ def parse_model_info(model_dict: dict):
53
+ """
54
+ Extracts the necessary information from the model dictionary and returns them as separate arguments.
55
+
56
+ :param model_dict: A dictionary containing model information, structured as follows:
57
+ {
58
+ "image" -> contains the possible path where to find the model image. If not none, model will be loaded from there
59
+ "metadata" -> a dictionary itself, containing miscellaneous information
60
+ "algorithm_name" -> includes the model class module to _load
61
+ "model_name" -> the model name, used to identify the model itself
62
+ "input_shape" [optional] -> contains a stringed tuple that identifies the input layer shape
63
+ }
64
+ :return: model_file, metadata, model_type, model_name, input_shape
65
+ """
66
+ model_file = model_dict.get("image", None)
67
+ metadata = model_dict.get("metadata", {})
68
+ model_type = model_dict.get("algorithm_name")
69
+ model_name = model_dict.get("model_name")
70
+ input_shape = model_dict.get("input_shape", "")
71
+
72
+ return model_file, metadata, model_type, model_name, input_shape
@@ -0,0 +1,42 @@
1
+ class AllowedData:
2
+ def __init__(self, dtype: str, is_categorical: bool):
3
+ self.dtype = dtype
4
+ self.is_categorical = is_categorical
5
+
6
+ def to_json(self):
7
+ return {"type": self.dtype, "is_categorical": self.is_categorical}
8
+
9
+
10
+ class ModelInfo:
11
+ def __init__(
12
+ self,
13
+ name: str,
14
+ default_loss_function: str,
15
+ description: str,
16
+ allowed_data: list[AllowedData],
17
+ ):
18
+ self.name = name
19
+ self.default_loss_function = default_loss_function
20
+ self.description = description
21
+ self.allowed_data = allowed_data
22
+
23
+ def get_model_info(self):
24
+ """
25
+ Returns a dictionary containing the model information.
26
+
27
+ The dictionary includes the model's name, default loss function, description,
28
+ and a list of allowed data types with their categorical status.
29
+
30
+ :return: dict containing the model's information
31
+ """
32
+ allowed_data = [ad.to_json() for ad in self.allowed_data]
33
+ system_model_info = {
34
+ "algorithm": {
35
+ "name": self.name,
36
+ "default_loss_function": self.default_loss_function,
37
+ "description": self.description,
38
+ },
39
+ "datatypes": allowed_data,
40
+ }
41
+
42
+ return system_model_info
@@ -0,0 +1,40 @@
1
+ import json
2
+
3
+
4
+ class TrainingInfo:
5
+ def __init__(
6
+ self,
7
+ loss_fn: str,
8
+ train_samples: int,
9
+ train_loss: float,
10
+ validation_samples: int = None,
11
+ validation_loss: float = None,
12
+ ):
13
+ self._loss_fn = loss_fn
14
+ self._train_samples = train_samples
15
+ self._train_loss = train_loss
16
+ self._validation_samples = validation_samples
17
+ self._validation_loss = validation_loss
18
+
19
+ def to_dict(self) -> dict:
20
+ """
21
+ Convert the TrainingInfo to a dictionary
22
+
23
+ :return: dict: A dictionary with the training info
24
+ """
25
+ return {
26
+ "loss_function": self._loss_fn,
27
+ "train_samples": self._train_samples,
28
+ "train_loss": self._train_loss,
29
+ "val_samples": self._validation_samples,
30
+ "val_loss": self._validation_loss,
31
+ }
32
+
33
+ def to_json(self) -> str:
34
+ """
35
+ Convert the TrainingInfo to a JSON string
36
+
37
+ :return: str: A JSON string with the training info
38
+ """
39
+
40
+ return json.dumps(self.to_dict())
@@ -0,0 +1,106 @@
1
+ import numpy as np
2
+ from abc import ABC, abstractmethod
3
+
4
+ from sdg_core_lib import NumericDataset
5
+
6
+
7
+ class UnspecializedModel(ABC):
8
+ """
9
+ Abstract class for all models. Implements common functionalities and defines abstract methods that must be implemented
10
+ by all subclasses.
11
+
12
+ Attributes:
13
+ _metadata (dict): A dictionary containing miscellaneous information about the model.
14
+ model_name (str): The model name, used to identify the model itself.
15
+ input_shape (tuple): A tuple containing the input shape of the model.
16
+ _load_path (str): A string containing the path where to load the model from.
17
+ _model (keras.Model): The model instance.
18
+ _scaler (Scaler): The scaler instance.
19
+ training_info (TrainingInfo): The training info instance.
20
+ """
21
+
22
+ def __init__(
23
+ self,
24
+ metadata: dict,
25
+ model_name: str,
26
+ input_shape: str = None,
27
+ load_path: str = None,
28
+ ):
29
+ self._metadata = metadata
30
+ self.model_name = model_name
31
+ self.input_shape = self._parse_stringed_input_shape(input_shape)
32
+ self._load_path = load_path
33
+ self._model = None # Placeholder for the model instance
34
+ self._scaler = None # Placeholder for model scaler
35
+ self.training_info = None # Placeholder for training info
36
+ self._model_misc = None # Placeholder for model miscellaneous info
37
+
38
+ @abstractmethod
39
+ def _build(self, input_shape: str):
40
+ raise NotImplementedError
41
+
42
+ @abstractmethod
43
+ def _load(self, model_filepath: str):
44
+ """Load trained_models weights."""
45
+ raise NotImplementedError
46
+
47
+ @abstractmethod
48
+ def _instantiate(self):
49
+ raise NotImplementedError
50
+
51
+ @abstractmethod
52
+ def _scale(self, data: np.array):
53
+ """Scale inputs with its logic"""
54
+ raise NotImplementedError
55
+
56
+ @abstractmethod
57
+ def _inverse_scale(self, data: np.array):
58
+ """Inverse scale inputs with its logic"""
59
+ raise NotImplementedError
60
+
61
+ @abstractmethod
62
+ def _pre_process(self, data: NumericDataset, **kwargs):
63
+ """Pre-process data"""
64
+ raise NotImplementedError
65
+
66
+ @abstractmethod
67
+ def train(self, data):
68
+ """Train the model."""
69
+ raise NotImplementedError
70
+
71
+ @abstractmethod
72
+ def fine_tune(self, data: np.array, **kwargs):
73
+ """Fine-tune the model."""
74
+ raise NotImplementedError
75
+
76
+ @abstractmethod
77
+ def infer(self, n_rows: int, **kwargs):
78
+ """Run inference."""
79
+ raise NotImplementedError
80
+
81
+ @abstractmethod
82
+ def save(self, folder_path):
83
+ """Save Model."""
84
+ raise NotImplementedError
85
+
86
+ @abstractmethod
87
+ def set_hyperparameters(self, **kwargs):
88
+ """Set Hyperparameters"""
89
+ raise NotImplementedError
90
+
91
+ @classmethod
92
+ def self_describe(cls):
93
+ raise NotImplementedError
94
+
95
+ @staticmethod
96
+ def _parse_stringed_input_shape(stringed_shape: str) -> tuple[int, ...]:
97
+ """
98
+ Parses a stringed list of numbers into a tuple
99
+
100
+ :param stringed_shape: a stringed list of number in format "[x,y,z]"
101
+ :return: a tuple of numbers, in format (x, y, z)
102
+ """
103
+ brackets = ["(", ")", "[", "]", "{", "}"]
104
+ for b in brackets:
105
+ stringed_shape = stringed_shape.replace(b, "")
106
+ return tuple([int(n) for n in stringed_shape.split(",") if n != ""])