bella-companion 0.1.1__tar.gz → 0.1.20__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.
- {bella_companion-0.1.1 → bella_companion-0.1.20}/PKG-INFO +7 -5
- {bella_companion-0.1.1 → bella_companion-0.1.20}/pyproject.toml +17 -12
- bella_companion-0.1.20/src/bella_companion/backend/__init__.py +94 -0
- bella_companion-0.1.20/src/bella_companion/backend/activation_functions.py +72 -0
- bella_companion-0.1.20/src/bella_companion/backend/mlp.py +284 -0
- bella_companion-0.1.20/src/bella_companion/backend/plots.py +167 -0
- bella_companion-0.1.20/src/bella_companion/backend/type_hints.py +8 -0
- bella_companion-0.1.20/src/bella_companion/backend/utils/__init__.py +42 -0
- bella_companion-0.1.20/src/bella_companion/backend/utils/beast.py +304 -0
- bella_companion-0.1.20/src/bella_companion/backend/utils/metrics.py +135 -0
- bella_companion-0.1.20/src/bella_companion/backend/utils/misc.py +25 -0
- {bella_companion-0.1.1/src/bella_companion → bella_companion-0.1.20/src/bella_companion/backend}/utils/slurm.py +42 -6
- bella_companion-0.1.20/src/bella_companion/backend/xAI/__init__.py +27 -0
- bella_companion-0.1.20/src/bella_companion/backend/xAI/pdp.py +221 -0
- bella_companion-0.1.20/src/bella_companion/backend/xAI/shapley.py +164 -0
- bella_companion-0.1.20/src/bella_companion/cli.py +195 -0
- bella_companion-0.1.20/src/bella_companion/eucovid/__init__.py +15 -0
- bella_companion-0.1.1/src/bella_companion/eucovid/beast_configs/MLP.xml → bella_companion-0.1.20/src/bella_companion/eucovid/beast_configs/BELLA.xml +22 -8
- {bella_companion-0.1.1 → bella_companion-0.1.20}/src/bella_companion/eucovid/beast_configs/GLM.xml +24 -21
- bella_companion-0.1.20/src/bella_companion/eucovid/data/flights_and_populations/changetimes.csv +6 -0
- bella_companion-0.1.20/src/bella_companion/eucovid/data/flights_and_populations/flights.csv +35 -0
- bella_companion-0.1.20/src/bella_companion/eucovid/data/flights_and_populations/populations.csv +35 -0
- bella_companion-0.1.20/src/bella_companion/eucovid/data/msa.fasta +470 -0
- bella_companion-0.1.20/src/bella_companion/eucovid/plot.py +111 -0
- bella_companion-0.1.20/src/bella_companion/eucovid/run.py +46 -0
- bella_companion-0.1.20/src/bella_companion/eucovid/settings.py +4 -0
- bella_companion-0.1.20/src/bella_companion/eucovid/summarize.py +50 -0
- bella_companion-0.1.20/src/bella_companion/platyrrhine/__init__.py +17 -0
- {bella_companion-0.1.1 → bella_companion-0.1.20}/src/bella_companion/platyrrhine/beast_config.xml +3 -5
- bella_companion-0.1.20/src/bella_companion/platyrrhine/plot.py +218 -0
- bella_companion-0.1.20/src/bella_companion/platyrrhine/run.py +61 -0
- bella_companion-0.1.20/src/bella_companion/platyrrhine/settings.py +13 -0
- bella_companion-0.1.20/src/bella_companion/platyrrhine/summarize.py +54 -0
- bella_companion-0.1.20/src/bella_companion/simulations/__init__.py +25 -0
- bella_companion-0.1.1/src/bella_companion/simulations/beast_configs/epi-multitype/MLP.xml → bella_companion-0.1.20/src/bella_companion/simulations/beast_configs/epi-multitype/BELLA.xml +0 -1
- {bella_companion-0.1.1 → bella_companion-0.1.20}/src/bella_companion/simulations/beast_configs/epi-multitype/GLM.xml +0 -1
- bella_companion-0.1.1/src/bella_companion/simulations/beast_configs/epi-multitype/Nonparametric.xml → bella_companion-0.1.20/src/bella_companion/simulations/beast_configs/epi-multitype/PA.xml +0 -1
- bella_companion-0.1.1/src/bella_companion/simulations/beast_configs/fbd-2traits/MLP.xml → bella_companion-0.1.20/src/bella_companion/simulations/beast_configs/fbd-2traits/BELLA.xml +1 -3
- {bella_companion-0.1.1 → bella_companion-0.1.20}/src/bella_companion/simulations/beast_configs/fbd-2traits/GLM.xml +1 -3
- bella_companion-0.1.1/src/bella_companion/simulations/beast_configs/fbd-2traits/Nonparametric.xml → bella_companion-0.1.20/src/bella_companion/simulations/beast_configs/fbd-2traits/PA.xml +1 -3
- bella_companion-0.1.1/src/bella_companion/simulations/beast_configs/fbd-no-traits/MLP.xml → bella_companion-0.1.20/src/bella_companion/simulations/beast_configs/fbd-no-traits/BELLA.xml +1 -3
- {bella_companion-0.1.1 → bella_companion-0.1.20}/src/bella_companion/simulations/beast_configs/fbd-no-traits/GLM.xml +1 -3
- bella_companion-0.1.1/src/bella_companion/simulations/beast_configs/fbd-no-traits/Nonparametric.xml → bella_companion-0.1.20/src/bella_companion/simulations/beast_configs/fbd-no-traits/PA.xml +1 -3
- bella_companion-0.1.1/src/bella_companion/simulations/generate_data.py → bella_companion-0.1.20/src/bella_companion/simulations/generate.py +11 -5
- bella_companion-0.1.20/src/bella_companion/simulations/metrics/__init__.py +3 -0
- bella_companion-0.1.20/src/bella_companion/simulations/metrics/run.py +144 -0
- bella_companion-0.1.20/src/bella_companion/simulations/metrics/template.tex +42 -0
- bella_companion-0.1.20/src/bella_companion/simulations/plot/__init__.py +23 -0
- bella_companion-0.1.20/src/bella_companion/simulations/plot/epi_multitype.py +70 -0
- bella_companion-0.1.20/src/bella_companion/simulations/plot/epi_skyline.py +88 -0
- bella_companion-0.1.20/src/bella_companion/simulations/plot/fbd_2traits.py +151 -0
- bella_companion-0.1.20/src/bella_companion/simulations/plot/fbd_no_traits.py +100 -0
- bella_companion-0.1.20/src/bella_companion/simulations/plot/globals.py +3 -0
- {bella_companion-0.1.1/src/bella_companion/simulations/figures → bella_companion-0.1.20/src/bella_companion/simulations/plot}/scenarios.py +35 -27
- bella_companion-0.1.20/src/bella_companion/simulations/run.py +69 -0
- {bella_companion-0.1.1 → bella_companion-0.1.20}/src/bella_companion/simulations/scenarios/__init__.py +4 -4
- {bella_companion-0.1.1 → bella_companion-0.1.20}/src/bella_companion/simulations/scenarios/epi_multitype.py +7 -12
- {bella_companion-0.1.1 → bella_companion-0.1.20}/src/bella_companion/simulations/scenarios/epi_skyline.py +5 -12
- {bella_companion-0.1.1 → bella_companion-0.1.20}/src/bella_companion/simulations/scenarios/fbd_2traits.py +5 -13
- {bella_companion-0.1.1 → bella_companion-0.1.20}/src/bella_companion/simulations/scenarios/fbd_no_traits.py +5 -13
- bella_companion-0.1.20/src/bella_companion/simulations/scenarios/globals.py +7 -0
- {bella_companion-0.1.1 → bella_companion-0.1.20}/src/bella_companion/simulations/scenarios/scenario.py +0 -3
- bella_companion-0.1.1/src/bella_companion/simulations/scenarios/common.py → bella_companion-0.1.20/src/bella_companion/simulations/scenarios/utils.py +0 -8
- {bella_companion-0.1.1 → bella_companion-0.1.20}/src/bella_companion/simulations/summarize.py +7 -6
- bella_companion-0.1.1/src/bella_companion/.DS_Store +0 -0
- bella_companion-0.1.1/src/bella_companion/BELLA.jar +0 -0
- bella_companion-0.1.1/src/bella_companion/cli.py +0 -82
- bella_companion-0.1.1/src/bella_companion/eucovid/__init__.py +0 -3
- bella_companion-0.1.1/src/bella_companion/eucovid/data/msa.fasta +0 -79500
- bella_companion-0.1.1/src/bella_companion/eucovid/run_beast.py +0 -36
- bella_companion-0.1.1/src/bella_companion/features.py +0 -13
- bella_companion-0.1.1/src/bella_companion/platyrrhine/__init__.py +0 -5
- bella_companion-0.1.1/src/bella_companion/platyrrhine/results.py +0 -191
- bella_companion-0.1.1/src/bella_companion/platyrrhine/run_beast.py +0 -70
- bella_companion-0.1.1/src/bella_companion/platyrrhine/summarize.py +0 -41
- bella_companion-0.1.1/src/bella_companion/simulations/__init__.py +0 -13
- bella_companion-0.1.1/src/bella_companion/simulations/figures/__init__.py +0 -13
- bella_companion-0.1.1/src/bella_companion/simulations/figures/epi_multitype.py +0 -81
- bella_companion-0.1.1/src/bella_companion/simulations/figures/epi_skyline.py +0 -45
- bella_companion-0.1.1/src/bella_companion/simulations/figures/fbd_2traits.py +0 -83
- bella_companion-0.1.1/src/bella_companion/simulations/figures/fbd_no_traits.py +0 -56
- bella_companion-0.1.1/src/bella_companion/simulations/figures/utils.py +0 -98
- bella_companion-0.1.1/src/bella_companion/simulations/generate_figures.py +0 -15
- bella_companion-0.1.1/src/bella_companion/simulations/metrics.py +0 -59
- bella_companion-0.1.1/src/bella_companion/simulations/run_beast.py +0 -84
- bella_companion-0.1.1/src/bella_companion/utils/__init__.py +0 -19
- bella_companion-0.1.1/src/bella_companion/utils/beast.py +0 -69
- bella_companion-0.1.1/src/bella_companion/utils/explain/__init__.py +0 -7
- bella_companion-0.1.1/src/bella_companion/utils/explain/pdp.py +0 -138
- bella_companion-0.1.1/src/bella_companion/utils/explain/shap.py +0 -104
- bella_companion-0.1.1/src/bella_companion/utils/explain/typeguards.py +0 -20
- bella_companion-0.1.1/src/bella_companion/version.xml +0 -13
- {bella_companion-0.1.1 → bella_companion-0.1.20}/README.md +0 -0
- {bella_companion-0.1.1 → bella_companion-0.1.20}/src/bella_companion/__init__.py +0 -0
- {bella_companion-0.1.1/src/bella_companion/eucovid/data → bella_companion-0.1.20/src/bella_companion/eucovid/data/flights_over_populations}/changetimes.csv +0 -0
- /bella_companion-0.1.1/src/bella_companion/eucovid/data/flights.csv → /bella_companion-0.1.20/src/bella_companion/eucovid/data/flights_over_populations/flights_over_populations.csv +0 -0
- {bella_companion-0.1.1 → bella_companion-0.1.20}/src/bella_companion/platyrrhine/data/change_times.csv +0 -0
- {bella_companion-0.1.1 → bella_companion-0.1.20}/src/bella_companion/platyrrhine/data/traits.csv +0 -0
- {bella_companion-0.1.1 → bella_companion-0.1.20}/src/bella_companion/platyrrhine/data/trees.nwk +0 -0
- /bella_companion-0.1.1/src/bella_companion/simulations/beast_configs/epi-skyline/MLP.xml → /bella_companion-0.1.20/src/bella_companion/simulations/beast_configs/epi-skyline/BELLA.xml +0 -0
- {bella_companion-0.1.1 → bella_companion-0.1.20}/src/bella_companion/simulations/beast_configs/epi-skyline/GLM.xml +0 -0
- /bella_companion-0.1.1/src/bella_companion/simulations/beast_configs/epi-skyline/Nonparametric.xml → /bella_companion-0.1.20/src/bella_companion/simulations/beast_configs/epi-skyline/PA.xml +0 -0
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: bella-companion
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.20
|
|
4
4
|
Summary: Bayesian Evolutionary Layered Learning Architectures (BELLA) companion
|
|
5
5
|
Author: gabriele-marino
|
|
6
6
|
Author-email: gabriele-marino <gabmarino.8601@gmail.com>
|
|
7
|
-
Requires-Dist: arviz
|
|
8
|
-
Requires-Dist:
|
|
7
|
+
Requires-Dist: arviz==0.22.0
|
|
8
|
+
Requires-Dist: autoregistry>=1.2.0
|
|
9
9
|
Requires-Dist: dotenv>=0.9.9
|
|
10
|
-
Requires-Dist: phylogenie>=3.1.
|
|
11
|
-
Requires-Dist:
|
|
10
|
+
Requires-Dist: phylogenie>=3.1.14
|
|
11
|
+
Requires-Dist: plotly>=6.5.0
|
|
12
|
+
Requires-Dist: scipy>=1.15.3
|
|
12
13
|
Requires-Dist: seaborn>=0.13.2
|
|
14
|
+
Requires-Dist: shap>=0.49.1
|
|
13
15
|
Requires-Python: >=3.10
|
|
14
16
|
Description-Content-Type: text/markdown
|
|
15
17
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "bella-companion"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.20"
|
|
4
4
|
description = "Bayesian Evolutionary Layered Learning Architectures (BELLA) companion"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -8,27 +8,32 @@ authors = [
|
|
|
8
8
|
]
|
|
9
9
|
requires-python = ">=3.10"
|
|
10
10
|
dependencies = [
|
|
11
|
-
"arviz
|
|
12
|
-
"
|
|
11
|
+
"arviz==0.22.0",
|
|
12
|
+
"autoregistry>=1.2.0",
|
|
13
13
|
"dotenv>=0.9.9",
|
|
14
|
-
"phylogenie>=3.1.
|
|
15
|
-
"
|
|
14
|
+
"phylogenie>=3.1.14",
|
|
15
|
+
"plotly>=6.5.0",
|
|
16
|
+
"scipy>=1.15.3",
|
|
16
17
|
"seaborn>=0.13.2",
|
|
18
|
+
"shap>=0.49.1",
|
|
17
19
|
]
|
|
18
20
|
|
|
19
|
-
[project.scripts]
|
|
20
|
-
bella = "bella_companion.cli:main"
|
|
21
|
-
|
|
22
|
-
[build-system]
|
|
23
|
-
requires = ["uv_build>=0.9.5,<0.10.0"]
|
|
24
|
-
build-backend = "uv_build"
|
|
25
|
-
|
|
26
21
|
[dependency-groups]
|
|
27
22
|
dev = [
|
|
28
23
|
"joblib-stubs>=1.5.2.0.20250831",
|
|
24
|
+
"pandas-stubs>=2.3.2.250926",
|
|
25
|
+
"plotly-stubs>=0.0.6",
|
|
29
26
|
"pyright>=1.1.407",
|
|
27
|
+
"requests>=2.32.5",
|
|
28
|
+
"scipy-stubs>=1.15.3.0",
|
|
30
29
|
]
|
|
31
30
|
|
|
32
31
|
[tool.pyright]
|
|
33
32
|
typeCheckingMode = "strict"
|
|
34
33
|
|
|
34
|
+
[project.scripts]
|
|
35
|
+
bella = "bella_companion.cli:main"
|
|
36
|
+
|
|
37
|
+
[build-system]
|
|
38
|
+
requires = ["uv_build>=0.9.5,<0.10.0"]
|
|
39
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from bella_companion.backend.activation_functions import (
|
|
2
|
+
ActivationFunction,
|
|
3
|
+
ActivationFunctionLike,
|
|
4
|
+
Identity,
|
|
5
|
+
RegisteredActivationFunction,
|
|
6
|
+
ReLU,
|
|
7
|
+
Sigmoid,
|
|
8
|
+
Softplus,
|
|
9
|
+
Tanh,
|
|
10
|
+
as_activation_function,
|
|
11
|
+
)
|
|
12
|
+
from bella_companion.backend.mlp import MLP, MLPEnsemble, mlp_ensembles_from_logs_dir
|
|
13
|
+
from bella_companion.backend.plots import ribbon_plot, skyline_plot
|
|
14
|
+
from bella_companion.backend.type_hints import Array, Model, Weights
|
|
15
|
+
from bella_companion.backend.utils import (
|
|
16
|
+
ESS_POSTFIX,
|
|
17
|
+
LOWER_POSTFIX,
|
|
18
|
+
MEDIAN_POSTFIX,
|
|
19
|
+
UPPER_POSTFIX,
|
|
20
|
+
avg_ci_width_from_summaries,
|
|
21
|
+
coverage_from_summaries,
|
|
22
|
+
get_job_metadata,
|
|
23
|
+
mae_distribution_from_summaries,
|
|
24
|
+
mae_from_summaries,
|
|
25
|
+
mean_ess_per_hour_from_summaries,
|
|
26
|
+
normalize,
|
|
27
|
+
read_log_file,
|
|
28
|
+
read_weights,
|
|
29
|
+
read_weights_dir,
|
|
30
|
+
submit_beast_job,
|
|
31
|
+
submit_job,
|
|
32
|
+
summarize_log,
|
|
33
|
+
summarize_logs_dir,
|
|
34
|
+
)
|
|
35
|
+
from bella_companion.backend.xAI import (
|
|
36
|
+
get_median_partial_dependence_plot,
|
|
37
|
+
get_median_partial_dependence_plot_distribution,
|
|
38
|
+
get_median_shap_feature_importance_distribution,
|
|
39
|
+
get_partial_dependence_plot,
|
|
40
|
+
get_partial_dependence_plot_distribution,
|
|
41
|
+
get_partial_dependence_plots,
|
|
42
|
+
get_partial_dependence_plots_distribution,
|
|
43
|
+
get_shap_feature_importance_distribution,
|
|
44
|
+
get_shap_features_importance,
|
|
45
|
+
get_shap_values,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
__all__ = [
|
|
49
|
+
"ActivationFunction",
|
|
50
|
+
"ActivationFunctionLike",
|
|
51
|
+
"Identity",
|
|
52
|
+
"RegisteredActivationFunction",
|
|
53
|
+
"ReLU",
|
|
54
|
+
"Sigmoid",
|
|
55
|
+
"Softplus",
|
|
56
|
+
"Tanh",
|
|
57
|
+
"as_activation_function",
|
|
58
|
+
"MLP",
|
|
59
|
+
"MLPEnsemble",
|
|
60
|
+
"mlp_ensembles_from_logs_dir",
|
|
61
|
+
"ribbon_plot",
|
|
62
|
+
"skyline_plot",
|
|
63
|
+
"Array",
|
|
64
|
+
"Model",
|
|
65
|
+
"Weights",
|
|
66
|
+
"ESS_POSTFIX",
|
|
67
|
+
"LOWER_POSTFIX",
|
|
68
|
+
"MEDIAN_POSTFIX",
|
|
69
|
+
"UPPER_POSTFIX",
|
|
70
|
+
"avg_ci_width_from_summaries",
|
|
71
|
+
"coverage_from_summaries",
|
|
72
|
+
"get_job_metadata",
|
|
73
|
+
"mae_distribution_from_summaries",
|
|
74
|
+
"mae_from_summaries",
|
|
75
|
+
"mean_ess_per_hour_from_summaries",
|
|
76
|
+
"normalize",
|
|
77
|
+
"read_log_file",
|
|
78
|
+
"read_weights",
|
|
79
|
+
"read_weights_dir",
|
|
80
|
+
"submit_beast_job",
|
|
81
|
+
"submit_job",
|
|
82
|
+
"summarize_log",
|
|
83
|
+
"summarize_logs_dir",
|
|
84
|
+
"get_median_partial_dependence_plot",
|
|
85
|
+
"get_median_partial_dependence_plot_distribution",
|
|
86
|
+
"get_median_shap_feature_importance_distribution",
|
|
87
|
+
"get_partial_dependence_plot",
|
|
88
|
+
"get_partial_dependence_plot_distribution",
|
|
89
|
+
"get_partial_dependence_plots",
|
|
90
|
+
"get_partial_dependence_plots_distribution",
|
|
91
|
+
"get_shap_feature_importance_distribution",
|
|
92
|
+
"get_shap_features_importance",
|
|
93
|
+
"get_shap_values",
|
|
94
|
+
]
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from typing import Callable
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
from autoregistry import Registry
|
|
6
|
+
from numpy.typing import ArrayLike
|
|
7
|
+
|
|
8
|
+
from bella_companion.backend.type_hints import Array
|
|
9
|
+
|
|
10
|
+
ActivationFunction = Callable[[ArrayLike], Array]
|
|
11
|
+
ActivationFunctionLike = str | ActivationFunction
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class RegisteredActivationFunction(Registry):
|
|
15
|
+
@abstractmethod
|
|
16
|
+
def __call__(self, x: ArrayLike) -> Array: ...
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Identity(RegisteredActivationFunction):
|
|
20
|
+
def __call__(self, x: ArrayLike) -> Array:
|
|
21
|
+
return np.asarray(x, dtype=np.float64)
|
|
22
|
+
|
|
23
|
+
def __repr__(self) -> str:
|
|
24
|
+
return "Identity()"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Sigmoid(RegisteredActivationFunction):
|
|
28
|
+
def __init__(self, lower: float = 0.0, upper: float = 1.0, shape: float = 1.0):
|
|
29
|
+
self._lower = lower
|
|
30
|
+
self._upper = upper
|
|
31
|
+
self._shape = shape
|
|
32
|
+
|
|
33
|
+
def __call__(self, x: ArrayLike) -> Array:
|
|
34
|
+
x = np.asarray(x, dtype=np.float64)
|
|
35
|
+
return self._lower + (self._upper - self._lower) / (
|
|
36
|
+
1 + np.exp(-self._shape * x)
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def __repr__(self) -> str:
|
|
40
|
+
return f"Sigmoid(lower={self._lower}, upper={self._upper}, shape={self._shape})"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ReLU(RegisteredActivationFunction):
|
|
44
|
+
def __call__(self, x: ArrayLike) -> Array:
|
|
45
|
+
return np.maximum(0, x)
|
|
46
|
+
|
|
47
|
+
def __repr__(self) -> str:
|
|
48
|
+
return "ReLU()"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class Softplus(RegisteredActivationFunction):
|
|
52
|
+
def __call__(self, x: ArrayLike) -> Array:
|
|
53
|
+
return np.log1p(np.exp(x))
|
|
54
|
+
|
|
55
|
+
def __repr__(self) -> str:
|
|
56
|
+
return "Softplus()"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class Tanh(RegisteredActivationFunction):
|
|
60
|
+
def __call__(self, x: ArrayLike) -> Array:
|
|
61
|
+
return np.tanh(x)
|
|
62
|
+
|
|
63
|
+
def __repr__(self) -> str:
|
|
64
|
+
return "Tanh()"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def as_activation_function(
|
|
68
|
+
activation: ActivationFunctionLike,
|
|
69
|
+
) -> ActivationFunction:
|
|
70
|
+
if isinstance(activation, str):
|
|
71
|
+
return RegisteredActivationFunction[activation]()
|
|
72
|
+
return activation
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
from collections.abc import Iterator
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
from joblib import Parallel, delayed
|
|
6
|
+
from numpy.typing import ArrayLike
|
|
7
|
+
from tqdm import tqdm
|
|
8
|
+
|
|
9
|
+
from bella_companion.backend.activation_functions import (
|
|
10
|
+
ActivationFunctionLike,
|
|
11
|
+
as_activation_function,
|
|
12
|
+
)
|
|
13
|
+
from bella_companion.backend.type_hints import Array, Weights
|
|
14
|
+
from bella_companion.backend.utils import read_weights
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MLP:
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
weights: Weights,
|
|
21
|
+
hidden_activation: ActivationFunctionLike = "relu",
|
|
22
|
+
output_activation: ActivationFunctionLike = "sigmoid",
|
|
23
|
+
):
|
|
24
|
+
"""
|
|
25
|
+
Initialize the MLP with given weights and activation functions.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
weights : Weights
|
|
30
|
+
A list of weight matrices for each layer in the MLP.
|
|
31
|
+
The length of the list determines the number of layers.
|
|
32
|
+
The shape of each weight matrix should be (n_inputs + 1, n_outputs),
|
|
33
|
+
where n_inputs is the number of inputs to the layer (excluding bias)
|
|
34
|
+
and n_outputs is the number of outputs from the layer.
|
|
35
|
+
hidden_activation : ActivationFunctionLike, optional
|
|
36
|
+
Activation function to use for hidden layers, by default "relu".
|
|
37
|
+
output_activation : ActivationFunctionLike, optional
|
|
38
|
+
Activation function to use for the output layer, by default "sigmoid".
|
|
39
|
+
|
|
40
|
+
Raises
|
|
41
|
+
------
|
|
42
|
+
ValueError
|
|
43
|
+
If the output layer does not have a single output neuron.
|
|
44
|
+
"""
|
|
45
|
+
if weights[-1].shape[1] != 1:
|
|
46
|
+
raise ValueError("Output layer must have a single output neuron.")
|
|
47
|
+
|
|
48
|
+
self._weights = weights
|
|
49
|
+
self._hidden_activation = as_activation_function(activation=hidden_activation)
|
|
50
|
+
self._output_activation = as_activation_function(activation=output_activation)
|
|
51
|
+
self._activations = [self._hidden_activation] * (self.n_layers - 1) + [
|
|
52
|
+
self._output_activation
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def n_layers(self) -> int:
|
|
57
|
+
return len(self._weights)
|
|
58
|
+
|
|
59
|
+
def forward(self, inputs: ArrayLike) -> Array:
|
|
60
|
+
"""
|
|
61
|
+
Perform a forward pass through the MLP.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
inputs : ArrayLike
|
|
66
|
+
Input data of shape (n_samples, n_features).
|
|
67
|
+
|
|
68
|
+
Returns
|
|
69
|
+
-------
|
|
70
|
+
Array
|
|
71
|
+
The output of the MLP after the forward pass, of shape (n_samples,).
|
|
72
|
+
"""
|
|
73
|
+
x = np.asarray(inputs, dtype=np.float64)
|
|
74
|
+
n_samples, _ = x.shape
|
|
75
|
+
for layer_weights, activation in zip(self._weights, self._activations):
|
|
76
|
+
bias = np.ones((n_samples, 1))
|
|
77
|
+
x = np.hstack((bias, x))
|
|
78
|
+
x = np.dot(x, layer_weights)
|
|
79
|
+
x = activation(x)
|
|
80
|
+
return x.flatten()
|
|
81
|
+
|
|
82
|
+
def __call__(self, inputs: ArrayLike) -> Array:
|
|
83
|
+
return self.forward(inputs)
|
|
84
|
+
|
|
85
|
+
def __repr__(self) -> str:
|
|
86
|
+
return (
|
|
87
|
+
f"MLP(n_layers={self.n_layers}, "
|
|
88
|
+
f"hidden_activation={self._hidden_activation}, "
|
|
89
|
+
f"output_activation={self._output_activation})"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class MLPEnsemble:
|
|
94
|
+
def __init__(
|
|
95
|
+
self,
|
|
96
|
+
weights_list: list[Weights],
|
|
97
|
+
hidden_activation: ActivationFunctionLike = "relu",
|
|
98
|
+
output_activation: ActivationFunctionLike = "sigmoid",
|
|
99
|
+
):
|
|
100
|
+
"""
|
|
101
|
+
Initialize the MLP ensemble with given weights and activation functions.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
weights_list : list[Weights]
|
|
106
|
+
A list of weight sets, where each set corresponds to an MLP in the ensemble.
|
|
107
|
+
hidden_activation : ActivationFunctionLike, optional
|
|
108
|
+
Activation function to use for hidden layers, by default "relu".
|
|
109
|
+
output_activation : ActivationFunctionLike, optional
|
|
110
|
+
Activation function to use for the output layer, by default "sigmoid".
|
|
111
|
+
"""
|
|
112
|
+
self._mlps = [
|
|
113
|
+
MLP(
|
|
114
|
+
weights=weights,
|
|
115
|
+
hidden_activation=hidden_activation,
|
|
116
|
+
output_activation=output_activation,
|
|
117
|
+
)
|
|
118
|
+
for weights in weights_list
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def n_models(self) -> int:
|
|
123
|
+
return len(self._mlps)
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def mlps(self) -> tuple[MLP, ...]:
|
|
127
|
+
return tuple(self._mlps)
|
|
128
|
+
|
|
129
|
+
def forward(
|
|
130
|
+
self,
|
|
131
|
+
inputs: ArrayLike, # (n_samples, n_features)
|
|
132
|
+
) -> Array: # (n_models, n_samples)
|
|
133
|
+
"""
|
|
134
|
+
Perform a forward pass through the MLP ensemble.
|
|
135
|
+
|
|
136
|
+
Parameters
|
|
137
|
+
----------
|
|
138
|
+
inputs : ArrayLike
|
|
139
|
+
Input data of shape (n_samples, n_features).
|
|
140
|
+
|
|
141
|
+
Returns
|
|
142
|
+
-------
|
|
143
|
+
Array
|
|
144
|
+
The outputs of the MLP ensemble after the forward pass,
|
|
145
|
+
of shape (n_models, n_samples).
|
|
146
|
+
"""
|
|
147
|
+
return np.array([mlp(inputs) for mlp in self._mlps])
|
|
148
|
+
|
|
149
|
+
def forward_median(
|
|
150
|
+
self,
|
|
151
|
+
inputs: ArrayLike, # (n_samples, n_features)
|
|
152
|
+
) -> Array: # (n_samples,)
|
|
153
|
+
"""
|
|
154
|
+
Perform a forward pass through the MLP ensemble and compute the median output.
|
|
155
|
+
|
|
156
|
+
Parameters
|
|
157
|
+
----------
|
|
158
|
+
inputs : ArrayLike
|
|
159
|
+
Input data of shape (n_samples, n_features).
|
|
160
|
+
|
|
161
|
+
Returns
|
|
162
|
+
-------
|
|
163
|
+
Array
|
|
164
|
+
The median output of the MLP ensemble after the forward pass,
|
|
165
|
+
of shape (n_samples,).
|
|
166
|
+
"""
|
|
167
|
+
outputs = self.forward(inputs) # (n_models, n_samples)
|
|
168
|
+
return np.median(outputs, axis=0) # (n_samples,)
|
|
169
|
+
|
|
170
|
+
@classmethod
|
|
171
|
+
def from_log_file(
|
|
172
|
+
cls,
|
|
173
|
+
log_file: str | Path,
|
|
174
|
+
target_name: str,
|
|
175
|
+
burn_in: int | float = 0.1,
|
|
176
|
+
n_samples: int | None = 100,
|
|
177
|
+
random_seed: int | None = 42,
|
|
178
|
+
hidden_activation: ActivationFunctionLike = "relu",
|
|
179
|
+
output_activation: ActivationFunctionLike = "sigmoid",
|
|
180
|
+
) -> "MLPEnsemble":
|
|
181
|
+
"""
|
|
182
|
+
Create an MLPEnsemble instance from a BEAST log file.
|
|
183
|
+
|
|
184
|
+
Parameters
|
|
185
|
+
----------
|
|
186
|
+
log_file : str | Path
|
|
187
|
+
Path to the BEAST log file.
|
|
188
|
+
target_name : str
|
|
189
|
+
The target variable name for which to extract weights.
|
|
190
|
+
burn_in : int | float, optional
|
|
191
|
+
If int, number of initial samples to discard.
|
|
192
|
+
If float, fraction of samples to discard, by default 0.1.
|
|
193
|
+
n_samples : int | None, optional
|
|
194
|
+
Number of weight samples to return, by default 100.
|
|
195
|
+
If None, returns all available samples after burn-in.
|
|
196
|
+
random_seed : int | None, optional
|
|
197
|
+
Random seed for sampling weights when n_samples is specified, by default 42.
|
|
198
|
+
hidden_activation : ActivationFunctionLike, optional
|
|
199
|
+
Activation function to use for hidden layers, by default "relu".
|
|
200
|
+
output_activation : ActivationFunctionLike, optional
|
|
201
|
+
Activation function to use for the output layer, by default "sigmoid".
|
|
202
|
+
|
|
203
|
+
Returns
|
|
204
|
+
-------
|
|
205
|
+
MLPEnsemble
|
|
206
|
+
An instance of MLPEnsemble initialized with weights from the log file.
|
|
207
|
+
"""
|
|
208
|
+
weights_list = read_weights(
|
|
209
|
+
log_file=log_file,
|
|
210
|
+
burn_in=burn_in,
|
|
211
|
+
n_samples=n_samples,
|
|
212
|
+
random_seed=random_seed,
|
|
213
|
+
)
|
|
214
|
+
return cls(
|
|
215
|
+
weights_list=weights_list[target_name],
|
|
216
|
+
hidden_activation=hidden_activation,
|
|
217
|
+
output_activation=output_activation,
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
def __call__(self, inputs: ArrayLike) -> Array:
|
|
221
|
+
return self.forward(inputs)
|
|
222
|
+
|
|
223
|
+
def __len__(self) -> int:
|
|
224
|
+
return self.n_models
|
|
225
|
+
|
|
226
|
+
def __iter__(self) -> Iterator[MLP]:
|
|
227
|
+
return iter(self._mlps)
|
|
228
|
+
|
|
229
|
+
def __repr__(self) -> str:
|
|
230
|
+
return f"MLPEnsemble(n_models={self.n_models})"
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def mlp_ensembles_from_logs_dir(
|
|
234
|
+
logs_dir: str | Path,
|
|
235
|
+
target_name: str,
|
|
236
|
+
burn_in: int | float = 0.1,
|
|
237
|
+
n_samples: int | None = 100,
|
|
238
|
+
random_seed: int | None = 42,
|
|
239
|
+
hidden_activation: ActivationFunctionLike = "relu",
|
|
240
|
+
output_activation: ActivationFunctionLike = "sigmoid",
|
|
241
|
+
n_jobs: int = -1,
|
|
242
|
+
) -> list[MLPEnsemble]:
|
|
243
|
+
"""
|
|
244
|
+
Create a list of MLPEnsemble instances from all BEAST log files in a directory.
|
|
245
|
+
|
|
246
|
+
Parameters
|
|
247
|
+
----------
|
|
248
|
+
logs_dir : str | Path
|
|
249
|
+
Path to the directory containing BEAST log files.
|
|
250
|
+
target_name : str
|
|
251
|
+
The target variable name for which to extract weights.
|
|
252
|
+
burn_in : int | float, optional
|
|
253
|
+
If int, number of initial samples to discard.
|
|
254
|
+
If float, fraction of samples to discard, by default 0.1.
|
|
255
|
+
n_samples : int | None, optional
|
|
256
|
+
Number of weight samples to return, by default 100.
|
|
257
|
+
If None, returns all available samples after burn-in.
|
|
258
|
+
random_seed : int | None, optional
|
|
259
|
+
Random seed for sampling weights when n_samples is specified, by default 42.
|
|
260
|
+
hidden_activation : ActivationFunctionLike, optional
|
|
261
|
+
Activation function to use for hidden layers, by default "relu".
|
|
262
|
+
output_activation : ActivationFunctionLike, optional
|
|
263
|
+
Activation function to use for the output layer, by default "sigmoid".
|
|
264
|
+
n_jobs : int, optional
|
|
265
|
+
Number of parallel jobs to use, by default -1 (use all available cores).
|
|
266
|
+
|
|
267
|
+
Returns
|
|
268
|
+
-------
|
|
269
|
+
list[MLPEnsemble]
|
|
270
|
+
A list of MLPEnsemble instances initialized with weights from the log files.
|
|
271
|
+
"""
|
|
272
|
+
log_files = list(Path(logs_dir).glob("*.log"))
|
|
273
|
+
return Parallel(n_jobs=n_jobs)(
|
|
274
|
+
delayed(MLPEnsemble.from_log_file)(
|
|
275
|
+
log_file=log_file,
|
|
276
|
+
target_name=target_name,
|
|
277
|
+
burn_in=burn_in,
|
|
278
|
+
n_samples=n_samples,
|
|
279
|
+
random_seed=random_seed,
|
|
280
|
+
hidden_activation=hidden_activation,
|
|
281
|
+
output_activation=output_activation,
|
|
282
|
+
)
|
|
283
|
+
for log_file in tqdm(log_files, desc="Loading MLP ensembles from logs")
|
|
284
|
+
)
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import matplotlib.pyplot as plt
|
|
4
|
+
import numpy as np
|
|
5
|
+
from matplotlib.axes import Axes
|
|
6
|
+
from numpy.typing import ArrayLike
|
|
7
|
+
|
|
8
|
+
Color = (
|
|
9
|
+
str
|
|
10
|
+
| np.typing.NDArray[np.floating]
|
|
11
|
+
| tuple[float, float, float]
|
|
12
|
+
| tuple[float, float, float, float]
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def skyline_plot(
|
|
17
|
+
data: ArrayLike,
|
|
18
|
+
x: ArrayLike | None = None,
|
|
19
|
+
ax: Axes | None = None,
|
|
20
|
+
step_kwargs: dict[str, Any] | None = None,
|
|
21
|
+
) -> Axes:
|
|
22
|
+
"""
|
|
23
|
+
Plot a skyline (step) plot.
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
data : ArrayLike
|
|
28
|
+
The y values for the skyline plot, of shape (n_points,).
|
|
29
|
+
x : ArrayLike | None, optional
|
|
30
|
+
The x values, of shape (n_points + 1,), by default None (uses indices).
|
|
31
|
+
The first x value corresponds to the start of the first step, the
|
|
32
|
+
last x value corresponds to the end of the last step.
|
|
33
|
+
ax : Axes | None, optional
|
|
34
|
+
The matplotlib Axes to plot on, by default None (uses current Axes).
|
|
35
|
+
step_kwargs : dict[str, Any] | None, optional
|
|
36
|
+
Additional keyword arguments for the step plot, by default None.
|
|
37
|
+
|
|
38
|
+
Returns
|
|
39
|
+
-------
|
|
40
|
+
Axes
|
|
41
|
+
The matplotlib Axes with the plot.
|
|
42
|
+
"""
|
|
43
|
+
data = np.asarray(data, dtype=np.float64)
|
|
44
|
+
data = [data[0], *data]
|
|
45
|
+
|
|
46
|
+
if ax is None:
|
|
47
|
+
ax = plt.gca()
|
|
48
|
+
if x is None:
|
|
49
|
+
x = list(range(len(data)))
|
|
50
|
+
if step_kwargs is None:
|
|
51
|
+
step_kwargs = {}
|
|
52
|
+
|
|
53
|
+
ax.step(x, data, **(step_kwargs or {})) # pyright: ignore
|
|
54
|
+
return ax
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def ribbon_plot(
|
|
58
|
+
y: ArrayLike,
|
|
59
|
+
x: ArrayLike | None = None,
|
|
60
|
+
color: Color | None = None,
|
|
61
|
+
label: str | None = None,
|
|
62
|
+
ax: Axes | None = None,
|
|
63
|
+
skyline: bool = False,
|
|
64
|
+
lower_percentile: float = 2.5,
|
|
65
|
+
upper_percentile: float = 97.5,
|
|
66
|
+
show_fill: bool = True,
|
|
67
|
+
fill_kwargs: dict[str, Any] | None = None,
|
|
68
|
+
show_samples: bool = True,
|
|
69
|
+
samples_kwargs: dict[str, Any] | None = None,
|
|
70
|
+
show_median: bool = True,
|
|
71
|
+
median_kwargs: dict[str, Any] | None = None,
|
|
72
|
+
) -> Axes:
|
|
73
|
+
"""
|
|
74
|
+
Plot a ribbon plot with uncertainty intervals.
|
|
75
|
+
|
|
76
|
+
Parameters
|
|
77
|
+
----------
|
|
78
|
+
y : ArrayLike
|
|
79
|
+
The y values, of shape (n_samples, n_points).
|
|
80
|
+
x : ArrayLike | None, optional
|
|
81
|
+
The x values, by default None (uses indices).
|
|
82
|
+
If skyline is True, x should have shape (n_points + 1,),
|
|
83
|
+
where the first x value corresponds to the start of the first step,
|
|
84
|
+
the last x value corresponds to the end of the last step.
|
|
85
|
+
If skyline is False, x should have shape (n_points,).
|
|
86
|
+
color : str | None, optional
|
|
87
|
+
The color for the plot, by default None.
|
|
88
|
+
label : str | None, optional
|
|
89
|
+
The label for the median line, by default None.
|
|
90
|
+
ax : Axes | None, optional
|
|
91
|
+
The matplotlib Axes to plot on, by default None (uses current Axes).
|
|
92
|
+
skyline : bool, optional
|
|
93
|
+
Whether to use a skyline (step) plot, by default False.
|
|
94
|
+
lower_percentile : float, optional
|
|
95
|
+
The lower percentile for the percentile interval, by default 2.5.
|
|
96
|
+
upper_percentile : float, optional
|
|
97
|
+
The upper percentile for the percentile interval, by default 97.5.
|
|
98
|
+
show_fill : bool, optional
|
|
99
|
+
Whether to show the percentile interval fill, by default True.
|
|
100
|
+
fill_kwargs : dict[str, Any] | None, optional
|
|
101
|
+
Additional keyword arguments for the fill_between call, by default None.
|
|
102
|
+
show_samples : bool, optional
|
|
103
|
+
Whether to show individual sample lines, by default True.
|
|
104
|
+
samples_kwargs : dict[str, Any] | None, optional
|
|
105
|
+
Additional keyword arguments for the sample lines, by default None.
|
|
106
|
+
show_median : bool, optional
|
|
107
|
+
Whether to show the median line, by default True.
|
|
108
|
+
median_kwargs : dict[str, Any] | None, optional
|
|
109
|
+
Additional keyword arguments for the median line, by default None.
|
|
110
|
+
|
|
111
|
+
Returns
|
|
112
|
+
-------
|
|
113
|
+
Axes
|
|
114
|
+
The matplotlib Axes with the plot.
|
|
115
|
+
"""
|
|
116
|
+
if ax is None:
|
|
117
|
+
ax = plt.gca()
|
|
118
|
+
|
|
119
|
+
y = np.asarray(y, dtype=np.float64)
|
|
120
|
+
if x is None:
|
|
121
|
+
_, n_points = y.shape
|
|
122
|
+
if skyline:
|
|
123
|
+
n_points += 1
|
|
124
|
+
x = list(range(n_points))
|
|
125
|
+
|
|
126
|
+
if show_fill:
|
|
127
|
+
lower = np.percentile(y, lower_percentile, axis=0)
|
|
128
|
+
high = np.percentile(y, upper_percentile, axis=0)
|
|
129
|
+
if fill_kwargs is None:
|
|
130
|
+
fill_kwargs = {}
|
|
131
|
+
if "alpha" not in fill_kwargs:
|
|
132
|
+
fill_kwargs["alpha"] = 0.25
|
|
133
|
+
if "color" not in fill_kwargs:
|
|
134
|
+
fill_kwargs["color"] = color
|
|
135
|
+
if skyline:
|
|
136
|
+
fill_kwargs["step"] = "pre"
|
|
137
|
+
lower = [lower[0], *lower]
|
|
138
|
+
high = [high[0], *high]
|
|
139
|
+
ax.fill_between(x, lower, high, **fill_kwargs) # pyright: ignore
|
|
140
|
+
|
|
141
|
+
if show_samples:
|
|
142
|
+
if samples_kwargs is None:
|
|
143
|
+
samples_kwargs = {}
|
|
144
|
+
if "alpha" not in samples_kwargs:
|
|
145
|
+
samples_kwargs["alpha"] = 0.25
|
|
146
|
+
if "color" not in samples_kwargs:
|
|
147
|
+
samples_kwargs["color"] = color
|
|
148
|
+
for sample_y in y:
|
|
149
|
+
if skyline:
|
|
150
|
+
skyline_plot(data=sample_y, x=x, ax=ax, step_kwargs=samples_kwargs)
|
|
151
|
+
else:
|
|
152
|
+
ax.plot(x, sample_y, **samples_kwargs) # pyright: ignore
|
|
153
|
+
|
|
154
|
+
if show_median:
|
|
155
|
+
median = np.median(y, axis=0)
|
|
156
|
+
if median_kwargs is None:
|
|
157
|
+
median_kwargs = {}
|
|
158
|
+
if "color" not in median_kwargs:
|
|
159
|
+
median_kwargs["color"] = color
|
|
160
|
+
if "label" not in median_kwargs:
|
|
161
|
+
median_kwargs["label"] = label
|
|
162
|
+
if skyline:
|
|
163
|
+
skyline_plot(data=median, x=x, ax=ax, step_kwargs=median_kwargs)
|
|
164
|
+
else:
|
|
165
|
+
ax.plot(x, median, **median_kwargs) # pyright: ignore
|
|
166
|
+
|
|
167
|
+
return ax
|