dragon-ml-toolbox 19.14.0__py3-none-any.whl → 20.0.0__py3-none-any.whl
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.
- {dragon_ml_toolbox-19.14.0.dist-info → dragon_ml_toolbox-20.0.0.dist-info}/METADATA +29 -46
- dragon_ml_toolbox-20.0.0.dist-info/RECORD +178 -0
- ml_tools/{ETL_cleaning.py → ETL_cleaning/__init__.py} +13 -5
- ml_tools/ETL_cleaning/_basic_clean.py +351 -0
- ml_tools/ETL_cleaning/_clean_tools.py +128 -0
- ml_tools/ETL_cleaning/_dragon_cleaner.py +245 -0
- ml_tools/ETL_cleaning/_imprimir.py +13 -0
- ml_tools/{ETL_engineering.py → ETL_engineering/__init__.py} +8 -4
- ml_tools/ETL_engineering/_dragon_engineering.py +261 -0
- ml_tools/ETL_engineering/_imprimir.py +24 -0
- ml_tools/{_core/_ETL_engineering.py → ETL_engineering/_transforms.py} +14 -267
- ml_tools/{_core → GUI_tools}/_GUI_tools.py +37 -40
- ml_tools/{GUI_tools.py → GUI_tools/__init__.py} +7 -5
- ml_tools/GUI_tools/_imprimir.py +12 -0
- ml_tools/IO_tools/_IO_loggers.py +235 -0
- ml_tools/IO_tools/_IO_save_load.py +151 -0
- ml_tools/IO_tools/_IO_utils.py +140 -0
- ml_tools/{IO_tools.py → IO_tools/__init__.py} +13 -5
- ml_tools/IO_tools/_imprimir.py +14 -0
- ml_tools/MICE/_MICE_imputation.py +132 -0
- ml_tools/{MICE_imputation.py → MICE/__init__.py} +6 -7
- ml_tools/{_core/_MICE_imputation.py → MICE/_dragon_mice.py} +243 -322
- ml_tools/MICE/_imprimir.py +11 -0
- ml_tools/{ML_callbacks.py → ML_callbacks/__init__.py} +12 -4
- ml_tools/ML_callbacks/_base.py +101 -0
- ml_tools/ML_callbacks/_checkpoint.py +232 -0
- ml_tools/ML_callbacks/_early_stop.py +208 -0
- ml_tools/ML_callbacks/_imprimir.py +12 -0
- ml_tools/ML_callbacks/_scheduler.py +197 -0
- ml_tools/{ML_chaining_utilities.py → ML_chain/__init__.py} +8 -3
- ml_tools/{_core/_ML_chaining_utilities.py → ML_chain/_chaining_tools.py} +5 -129
- ml_tools/ML_chain/_dragon_chain.py +140 -0
- ml_tools/ML_chain/_imprimir.py +11 -0
- ml_tools/ML_configuration/__init__.py +90 -0
- ml_tools/ML_configuration/_base_model_config.py +69 -0
- ml_tools/ML_configuration/_finalize.py +366 -0
- ml_tools/ML_configuration/_imprimir.py +47 -0
- ml_tools/ML_configuration/_metrics.py +593 -0
- ml_tools/ML_configuration/_models.py +206 -0
- ml_tools/ML_configuration/_training.py +124 -0
- ml_tools/ML_datasetmaster/__init__.py +28 -0
- ml_tools/ML_datasetmaster/_base_datasetmaster.py +337 -0
- ml_tools/{_core/_ML_datasetmaster.py → ML_datasetmaster/_datasetmaster.py} +9 -329
- ml_tools/ML_datasetmaster/_imprimir.py +15 -0
- ml_tools/{_core/_ML_sequence_datasetmaster.py → ML_datasetmaster/_sequence_datasetmaster.py} +13 -15
- ml_tools/{_core/_ML_vision_datasetmaster.py → ML_datasetmaster/_vision_datasetmaster.py} +63 -65
- ml_tools/ML_evaluation/__init__.py +53 -0
- ml_tools/ML_evaluation/_classification.py +629 -0
- ml_tools/ML_evaluation/_feature_importance.py +409 -0
- ml_tools/ML_evaluation/_imprimir.py +25 -0
- ml_tools/ML_evaluation/_loss.py +92 -0
- ml_tools/ML_evaluation/_regression.py +273 -0
- ml_tools/{_core/_ML_sequence_evaluation.py → ML_evaluation/_sequence.py} +8 -11
- ml_tools/{_core/_ML_vision_evaluation.py → ML_evaluation/_vision.py} +12 -17
- ml_tools/{_core → ML_evaluation_captum}/_ML_evaluation_captum.py +11 -38
- ml_tools/{ML_evaluation_captum.py → ML_evaluation_captum/__init__.py} +6 -4
- ml_tools/ML_evaluation_captum/_imprimir.py +10 -0
- ml_tools/{_core → ML_finalize_handler}/_ML_finalize_handler.py +3 -7
- ml_tools/ML_finalize_handler/__init__.py +10 -0
- ml_tools/ML_finalize_handler/_imprimir.py +8 -0
- ml_tools/ML_inference/__init__.py +22 -0
- ml_tools/ML_inference/_base_inference.py +166 -0
- ml_tools/{_core/_ML_chaining_inference.py → ML_inference/_chain_inference.py} +14 -17
- ml_tools/ML_inference/_dragon_inference.py +332 -0
- ml_tools/ML_inference/_imprimir.py +11 -0
- ml_tools/ML_inference/_multi_inference.py +180 -0
- ml_tools/ML_inference_sequence/__init__.py +10 -0
- ml_tools/ML_inference_sequence/_imprimir.py +8 -0
- ml_tools/{_core/_ML_sequence_inference.py → ML_inference_sequence/_sequence_inference.py} +11 -15
- ml_tools/ML_inference_vision/__init__.py +10 -0
- ml_tools/ML_inference_vision/_imprimir.py +8 -0
- ml_tools/{_core/_ML_vision_inference.py → ML_inference_vision/_vision_inference.py} +15 -19
- ml_tools/ML_models/__init__.py +32 -0
- ml_tools/{_core/_ML_models_advanced.py → ML_models/_advanced_models.py} +22 -18
- ml_tools/ML_models/_base_mlp_attention.py +198 -0
- ml_tools/{_core/_models_advanced_base.py → ML_models/_base_save_load.py} +73 -49
- ml_tools/ML_models/_dragon_tabular.py +248 -0
- ml_tools/ML_models/_imprimir.py +18 -0
- ml_tools/ML_models/_mlp_attention.py +134 -0
- ml_tools/{_core → ML_models}/_models_advanced_helpers.py +13 -13
- ml_tools/ML_models_sequence/__init__.py +10 -0
- ml_tools/ML_models_sequence/_imprimir.py +8 -0
- ml_tools/{_core/_ML_sequence_models.py → ML_models_sequence/_sequence_models.py} +5 -8
- ml_tools/ML_models_vision/__init__.py +29 -0
- ml_tools/ML_models_vision/_base_wrapper.py +254 -0
- ml_tools/ML_models_vision/_image_classification.py +182 -0
- ml_tools/ML_models_vision/_image_segmentation.py +108 -0
- ml_tools/ML_models_vision/_imprimir.py +16 -0
- ml_tools/ML_models_vision/_object_detection.py +135 -0
- ml_tools/ML_optimization/__init__.py +21 -0
- ml_tools/ML_optimization/_imprimir.py +13 -0
- ml_tools/{_core/_ML_optimization_pareto.py → ML_optimization/_multi_dragon.py} +18 -24
- ml_tools/ML_optimization/_single_dragon.py +203 -0
- ml_tools/{_core/_ML_optimization.py → ML_optimization/_single_manual.py} +75 -213
- ml_tools/{_core → ML_scaler}/_ML_scaler.py +8 -11
- ml_tools/ML_scaler/__init__.py +10 -0
- ml_tools/ML_scaler/_imprimir.py +8 -0
- ml_tools/ML_trainer/__init__.py +20 -0
- ml_tools/ML_trainer/_base_trainer.py +297 -0
- ml_tools/ML_trainer/_dragon_detection_trainer.py +402 -0
- ml_tools/ML_trainer/_dragon_sequence_trainer.py +540 -0
- ml_tools/ML_trainer/_dragon_trainer.py +1160 -0
- ml_tools/ML_trainer/_imprimir.py +10 -0
- ml_tools/{ML_utilities.py → ML_utilities/__init__.py} +14 -6
- ml_tools/ML_utilities/_artifact_finder.py +382 -0
- ml_tools/ML_utilities/_imprimir.py +16 -0
- ml_tools/ML_utilities/_inspection.py +325 -0
- ml_tools/ML_utilities/_train_tools.py +205 -0
- ml_tools/{ML_vision_transformers.py → ML_vision_transformers/__init__.py} +9 -6
- ml_tools/{_core/_ML_vision_transformers.py → ML_vision_transformers/_core_transforms.py} +11 -155
- ml_tools/ML_vision_transformers/_imprimir.py +14 -0
- ml_tools/ML_vision_transformers/_offline_augmentation.py +159 -0
- ml_tools/{_core/_PSO_optimization.py → PSO_optimization/_PSO.py} +58 -15
- ml_tools/{PSO_optimization.py → PSO_optimization/__init__.py} +5 -3
- ml_tools/PSO_optimization/_imprimir.py +10 -0
- ml_tools/SQL/__init__.py +7 -0
- ml_tools/{_core/_SQL.py → SQL/_dragon_SQL.py} +7 -11
- ml_tools/SQL/_imprimir.py +8 -0
- ml_tools/{_core → VIF}/_VIF_factor.py +5 -8
- ml_tools/{VIF_factor.py → VIF/__init__.py} +4 -2
- ml_tools/VIF/_imprimir.py +10 -0
- ml_tools/_core/__init__.py +7 -1
- ml_tools/_core/_logger.py +8 -18
- ml_tools/_core/_schema_load_ops.py +43 -0
- ml_tools/_core/_script_info.py +2 -2
- ml_tools/{data_exploration.py → data_exploration/__init__.py} +32 -16
- ml_tools/data_exploration/_analysis.py +214 -0
- ml_tools/data_exploration/_cleaning.py +566 -0
- ml_tools/data_exploration/_features.py +583 -0
- ml_tools/data_exploration/_imprimir.py +32 -0
- ml_tools/data_exploration/_plotting.py +487 -0
- ml_tools/data_exploration/_schema_ops.py +176 -0
- ml_tools/{ensemble_evaluation.py → ensemble_evaluation/__init__.py} +6 -4
- ml_tools/{_core → ensemble_evaluation}/_ensemble_evaluation.py +3 -7
- ml_tools/ensemble_evaluation/_imprimir.py +14 -0
- ml_tools/{ensemble_inference.py → ensemble_inference/__init__.py} +5 -3
- ml_tools/{_core → ensemble_inference}/_ensemble_inference.py +15 -18
- ml_tools/ensemble_inference/_imprimir.py +9 -0
- ml_tools/{ensemble_learning.py → ensemble_learning/__init__.py} +4 -6
- ml_tools/{_core → ensemble_learning}/_ensemble_learning.py +7 -10
- ml_tools/ensemble_learning/_imprimir.py +10 -0
- ml_tools/{excel_handler.py → excel_handler/__init__.py} +5 -3
- ml_tools/{_core → excel_handler}/_excel_handler.py +6 -10
- ml_tools/excel_handler/_imprimir.py +13 -0
- ml_tools/{keys.py → keys/__init__.py} +4 -1
- ml_tools/keys/_imprimir.py +11 -0
- ml_tools/{_core → keys}/_keys.py +2 -0
- ml_tools/{math_utilities.py → math_utilities/__init__.py} +5 -2
- ml_tools/math_utilities/_imprimir.py +11 -0
- ml_tools/{_core → math_utilities}/_math_utilities.py +1 -5
- ml_tools/{optimization_tools.py → optimization_tools/__init__.py} +9 -4
- ml_tools/optimization_tools/_imprimir.py +13 -0
- ml_tools/optimization_tools/_optimization_bounds.py +236 -0
- ml_tools/optimization_tools/_optimization_plots.py +218 -0
- ml_tools/{path_manager.py → path_manager/__init__.py} +6 -3
- ml_tools/{_core/_path_manager.py → path_manager/_dragonmanager.py} +11 -347
- ml_tools/path_manager/_imprimir.py +15 -0
- ml_tools/path_manager/_path_tools.py +346 -0
- ml_tools/plot_fonts/__init__.py +8 -0
- ml_tools/plot_fonts/_imprimir.py +8 -0
- ml_tools/{_core → plot_fonts}/_plot_fonts.py +2 -5
- ml_tools/schema/__init__.py +15 -0
- ml_tools/schema/_feature_schema.py +223 -0
- ml_tools/schema/_gui_schema.py +191 -0
- ml_tools/schema/_imprimir.py +10 -0
- ml_tools/{serde.py → serde/__init__.py} +4 -2
- ml_tools/serde/_imprimir.py +10 -0
- ml_tools/{_core → serde}/_serde.py +3 -8
- ml_tools/{utilities.py → utilities/__init__.py} +11 -6
- ml_tools/utilities/_imprimir.py +18 -0
- ml_tools/{_core/_utilities.py → utilities/_utility_save_load.py} +13 -190
- ml_tools/utilities/_utility_tools.py +192 -0
- dragon_ml_toolbox-19.14.0.dist-info/RECORD +0 -111
- ml_tools/ML_chaining_inference.py +0 -8
- ml_tools/ML_configuration.py +0 -86
- ml_tools/ML_configuration_pytab.py +0 -14
- ml_tools/ML_datasetmaster.py +0 -10
- ml_tools/ML_evaluation.py +0 -16
- ml_tools/ML_evaluation_multi.py +0 -12
- ml_tools/ML_finalize_handler.py +0 -8
- ml_tools/ML_inference.py +0 -12
- ml_tools/ML_models.py +0 -14
- ml_tools/ML_models_advanced.py +0 -14
- ml_tools/ML_models_pytab.py +0 -14
- ml_tools/ML_optimization.py +0 -14
- ml_tools/ML_optimization_pareto.py +0 -8
- ml_tools/ML_scaler.py +0 -8
- ml_tools/ML_sequence_datasetmaster.py +0 -8
- ml_tools/ML_sequence_evaluation.py +0 -10
- ml_tools/ML_sequence_inference.py +0 -8
- ml_tools/ML_sequence_models.py +0 -8
- ml_tools/ML_trainer.py +0 -12
- ml_tools/ML_vision_datasetmaster.py +0 -12
- ml_tools/ML_vision_evaluation.py +0 -10
- ml_tools/ML_vision_inference.py +0 -8
- ml_tools/ML_vision_models.py +0 -18
- ml_tools/SQL.py +0 -8
- ml_tools/_core/_ETL_cleaning.py +0 -694
- ml_tools/_core/_IO_tools.py +0 -498
- ml_tools/_core/_ML_callbacks.py +0 -702
- ml_tools/_core/_ML_configuration.py +0 -1332
- ml_tools/_core/_ML_configuration_pytab.py +0 -102
- ml_tools/_core/_ML_evaluation.py +0 -867
- ml_tools/_core/_ML_evaluation_multi.py +0 -544
- ml_tools/_core/_ML_inference.py +0 -646
- ml_tools/_core/_ML_models.py +0 -668
- ml_tools/_core/_ML_models_pytab.py +0 -693
- ml_tools/_core/_ML_trainer.py +0 -2323
- ml_tools/_core/_ML_utilities.py +0 -886
- ml_tools/_core/_ML_vision_models.py +0 -644
- ml_tools/_core/_data_exploration.py +0 -1909
- ml_tools/_core/_optimization_tools.py +0 -493
- ml_tools/_core/_schema.py +0 -359
- ml_tools/plot_fonts.py +0 -8
- ml_tools/schema.py +0 -12
- {dragon_ml_toolbox-19.14.0.dist-info → dragon_ml_toolbox-20.0.0.dist-info}/WHEEL +0 -0
- {dragon_ml_toolbox-19.14.0.dist-info → dragon_ml_toolbox-20.0.0.dist-info}/licenses/LICENSE +0 -0
- {dragon_ml_toolbox-19.14.0.dist-info → dragon_ml_toolbox-20.0.0.dist-info}/licenses/LICENSE-THIRD-PARTY.md +0 -0
- {dragon_ml_toolbox-19.14.0.dist-info → dragon_ml_toolbox-20.0.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
from torch import nn
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from ._base_mlp_attention import _BaseMLP, _BaseAttention, _AttentionLayer, _MultiHeadAttentionLayer
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"DragonMLP",
|
|
10
|
+
"DragonAttentionMLP",
|
|
11
|
+
"DragonMultiHeadAttentionNet",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DragonMLP(_BaseMLP):
|
|
16
|
+
"""
|
|
17
|
+
Creates a versatile Multilayer Perceptron (MLP) for regression or classification tasks.
|
|
18
|
+
"""
|
|
19
|
+
def __init__(self, in_features: int, out_targets: int,
|
|
20
|
+
hidden_layers: list[int] = [256, 128], drop_out: float = 0.2) -> None:
|
|
21
|
+
"""
|
|
22
|
+
Args:
|
|
23
|
+
in_features (int): The number of input features (e.g., columns in your data).
|
|
24
|
+
out_targets (int): The number of output targets. For regression, this is
|
|
25
|
+
typically 1. For classification, it's the number of classes.
|
|
26
|
+
hidden_layers (list[int]): A list where each integer represents the
|
|
27
|
+
number of neurons in a hidden layer.
|
|
28
|
+
drop_out (float): The dropout probability for neurons in each hidden
|
|
29
|
+
layer. Must be between 0.0 and 1.0.
|
|
30
|
+
|
|
31
|
+
### Rules of thumb:
|
|
32
|
+
- Choose a number of hidden neurons between the size of the input layer and the size of the output layer.
|
|
33
|
+
- The number of hidden neurons should be 2/3 the size of the input layer, plus the size of the output layer.
|
|
34
|
+
- The number of hidden neurons should be less than twice the size of the input layer.
|
|
35
|
+
"""
|
|
36
|
+
super().__init__(in_features, out_targets, hidden_layers, drop_out)
|
|
37
|
+
|
|
38
|
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
|
39
|
+
"""Defines the forward pass of the model."""
|
|
40
|
+
x = self.mlp(x)
|
|
41
|
+
logits = self.output_layer(x)
|
|
42
|
+
return logits
|
|
43
|
+
|
|
44
|
+
def __repr__(self) -> str:
|
|
45
|
+
"""Returns the developer-friendly string representation of the model."""
|
|
46
|
+
# Extracts the number of neurons from each nn.Linear layer
|
|
47
|
+
layer_sizes = [str(layer.in_features) for layer in self.mlp if isinstance(layer, nn.Linear)]
|
|
48
|
+
|
|
49
|
+
return self._repr_helper(name="DragonMLP", mlp_layers=layer_sizes)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class DragonAttentionMLP(_BaseAttention):
|
|
53
|
+
"""
|
|
54
|
+
A Multilayer Perceptron (MLP) that incorporates an Attention layer to dynamically weigh input features.
|
|
55
|
+
|
|
56
|
+
In inference mode use `forward_attention()` to get a tuple with `(output, attention_weights)`
|
|
57
|
+
"""
|
|
58
|
+
def __init__(self, in_features: int, out_targets: int,
|
|
59
|
+
hidden_layers: list[int] = [256, 128], drop_out: float = 0.2) -> None:
|
|
60
|
+
"""
|
|
61
|
+
Args:
|
|
62
|
+
in_features (int): The number of input features (e.g., columns in your data).
|
|
63
|
+
out_targets (int): The number of output targets. For regression, this is
|
|
64
|
+
typically 1. For classification, it's the number of classes.
|
|
65
|
+
hidden_layers (list[int]): A list where each integer represents the
|
|
66
|
+
number of neurons in a hidden layer.
|
|
67
|
+
drop_out (float): The dropout probability for neurons in each hidden
|
|
68
|
+
layer. Must be between 0.0 and 1.0.
|
|
69
|
+
"""
|
|
70
|
+
super().__init__(in_features, out_targets, hidden_layers, drop_out)
|
|
71
|
+
# Attention
|
|
72
|
+
self.attention = _AttentionLayer(in_features)
|
|
73
|
+
self.has_interpretable_attention = True
|
|
74
|
+
|
|
75
|
+
def __repr__(self) -> str:
|
|
76
|
+
"""Returns the developer-friendly string representation of the model."""
|
|
77
|
+
# Start with the input features and the attention marker
|
|
78
|
+
arch = [str(self.in_features), "[Attention]"]
|
|
79
|
+
|
|
80
|
+
# Find all other linear layers in the MLP
|
|
81
|
+
for layer in self.mlp[1:]: # type: ignore
|
|
82
|
+
if isinstance(layer, nn.Linear):
|
|
83
|
+
arch.append(str(layer.in_features))
|
|
84
|
+
|
|
85
|
+
return self._repr_helper(name="DragonAttentionMLP", mlp_layers=arch)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class DragonMultiHeadAttentionNet(_BaseAttention):
|
|
89
|
+
"""
|
|
90
|
+
An MLP that incorporates a standard `nn.MultiheadAttention` layer to process
|
|
91
|
+
the input features.
|
|
92
|
+
|
|
93
|
+
In inference mode use `forward_attention()` to get a tuple with `(output, attention_weights)`.
|
|
94
|
+
"""
|
|
95
|
+
def __init__(self, in_features: int, out_targets: int,
|
|
96
|
+
hidden_layers: list[int] = [256, 128], drop_out: float = 0.2,
|
|
97
|
+
num_heads: int = 4, attention_dropout: float = 0.1) -> None:
|
|
98
|
+
"""
|
|
99
|
+
Args:
|
|
100
|
+
in_features (int): The number of input features.
|
|
101
|
+
out_targets (int): The number of output targets.
|
|
102
|
+
hidden_layers (list[int]): A list of neuron counts for each hidden layer.
|
|
103
|
+
drop_out (float): The dropout probability for the MLP layers.
|
|
104
|
+
num_heads (int): The number of attention heads.
|
|
105
|
+
attention_dropout (float): Dropout probability in the attention layer.
|
|
106
|
+
"""
|
|
107
|
+
super().__init__(in_features, out_targets, hidden_layers, drop_out)
|
|
108
|
+
self.num_heads = num_heads
|
|
109
|
+
self.attention_dropout = attention_dropout
|
|
110
|
+
|
|
111
|
+
self.attention = _MultiHeadAttentionLayer(
|
|
112
|
+
num_features=in_features,
|
|
113
|
+
num_heads=num_heads,
|
|
114
|
+
dropout=attention_dropout
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def get_architecture_config(self) -> dict[str, Any]:
|
|
118
|
+
"""Returns the full configuration of the model."""
|
|
119
|
+
config = super().get_architecture_config()
|
|
120
|
+
config['num_heads'] = self.num_heads
|
|
121
|
+
config['attention_dropout'] = self.attention_dropout
|
|
122
|
+
return config
|
|
123
|
+
|
|
124
|
+
def __repr__(self) -> str:
|
|
125
|
+
"""Returns the developer-friendly string representation of the model."""
|
|
126
|
+
mlp_part = " -> ".join(
|
|
127
|
+
[str(self.in_features)] +
|
|
128
|
+
[str(h) for h in self.hidden_layers] +
|
|
129
|
+
[str(self.out_targets)]
|
|
130
|
+
)
|
|
131
|
+
arch_str = f"{self.in_features} -> [MultiHead(h={self.num_heads})] -> {mlp_part}"
|
|
132
|
+
|
|
133
|
+
return f"DragonMultiHeadAttentionNet(arch: {arch_str})"
|
|
134
|
+
|
|
@@ -5,7 +5,7 @@ from torch.autograd import Function
|
|
|
5
5
|
import math
|
|
6
6
|
import random
|
|
7
7
|
import numpy as np
|
|
8
|
-
from typing import Optional,
|
|
8
|
+
from typing import Optional, Callable
|
|
9
9
|
|
|
10
10
|
# HELPER module for ML_models_advanced
|
|
11
11
|
# SOURCE CODE: Adapted and modified from:
|
|
@@ -183,7 +183,7 @@ def entmoid15(input):
|
|
|
183
183
|
def sparsemoid(input):
|
|
184
184
|
return (0.5 * input + 0.5).clamp_(0, 1)
|
|
185
185
|
|
|
186
|
-
def t_softmax(input: torch.Tensor, t: torch.Tensor = None, dim: int = -1) -> torch.Tensor:
|
|
186
|
+
def t_softmax(input: torch.Tensor, t: torch.Tensor = None, dim: int = -1) -> torch.Tensor: # type: ignore
|
|
187
187
|
if t is None:
|
|
188
188
|
t = torch.tensor(0.5, device=input.device)
|
|
189
189
|
maxes = torch.max(input, dim=dim, keepdim=True).values
|
|
@@ -250,7 +250,7 @@ class Embedding1dLayer(nn.Module):
|
|
|
250
250
|
def __init__(
|
|
251
251
|
self,
|
|
252
252
|
continuous_dim: int,
|
|
253
|
-
categorical_embedding_dims:
|
|
253
|
+
categorical_embedding_dims: list[tuple[int, int]],
|
|
254
254
|
embedding_dropout: float = 0.0,
|
|
255
255
|
batch_norm_continuous_input: bool = False,
|
|
256
256
|
virtual_batch_size: Optional[int] = None,
|
|
@@ -297,7 +297,7 @@ class Embedding1dLayer(nn.Module):
|
|
|
297
297
|
|
|
298
298
|
if self.embd_dropout is not None:
|
|
299
299
|
embed = self.embd_dropout(embed)
|
|
300
|
-
return embed
|
|
300
|
+
return embed # type: ignore
|
|
301
301
|
|
|
302
302
|
class GatedFeatureLearningUnit(nn.Module):
|
|
303
303
|
def __init__(
|
|
@@ -408,14 +408,14 @@ class NeuralDecisionStump(nn.Module):
|
|
|
408
408
|
feature_mask = self.feature_mask_function(self.feature_mask)
|
|
409
409
|
|
|
410
410
|
# Repeat W for each batch size using broadcasting
|
|
411
|
-
W = torch.ones(x.size(0), 1, 1, device=x.device) * self.W
|
|
411
|
+
W = torch.ones(x.size(0), 1, 1, device=x.device) * self.W # type: ignore
|
|
412
412
|
# Binning features
|
|
413
413
|
# x: (B, Features) -> (B, Features, 1) -> bmm -> (B, Features, Cutpoints+1)
|
|
414
414
|
x_out = torch.bmm(x.unsqueeze(-1), W) - self.cut_points.unsqueeze(0)
|
|
415
415
|
x_out = self.binning_activation(x_out)
|
|
416
416
|
x_out = x_out * self.leaf_responses.unsqueeze(0)
|
|
417
417
|
x_out = (x_out * feature_mask.reshape(1, -1, 1)).sum(dim=1)
|
|
418
|
-
return x_out, feature_mask
|
|
418
|
+
return x_out, feature_mask # type: ignore
|
|
419
419
|
|
|
420
420
|
class NeuralDecisionTree(nn.Module):
|
|
421
421
|
def __init__(
|
|
@@ -455,14 +455,14 @@ class NeuralDecisionTree(nn.Module):
|
|
|
455
455
|
layer_nodes_list = []
|
|
456
456
|
layer_feature_masks = []
|
|
457
457
|
for n in range(max(2 ** (d), 1)):
|
|
458
|
-
leaf_nodes, feature_mask = self._modules[f"decision_stump_{d}_{n}"](tree_input)
|
|
458
|
+
leaf_nodes, feature_mask = self._modules[f"decision_stump_{d}_{n}"](tree_input) # type: ignore
|
|
459
459
|
layer_nodes_list.append(leaf_nodes)
|
|
460
460
|
layer_feature_masks.append(feature_mask)
|
|
461
461
|
layer_nodes = torch.cat(layer_nodes_list, dim=1)
|
|
462
462
|
tree_input = torch.cat([x, layer_nodes], dim=1)
|
|
463
463
|
feature_masks.append(layer_feature_masks)
|
|
464
464
|
|
|
465
|
-
return self.dropout(layer_nodes), feature_masks
|
|
465
|
+
return self.dropout(layer_nodes), feature_masks # type: ignore
|
|
466
466
|
|
|
467
467
|
class ODST(nn.Module):
|
|
468
468
|
def __init__(
|
|
@@ -569,7 +569,7 @@ class SimpleLinearHead(nn.Module):
|
|
|
569
569
|
super().__init__()
|
|
570
570
|
layers = [nn.Linear(in_units, output_dim)]
|
|
571
571
|
if dropout > 0:
|
|
572
|
-
layers.append(nn.Dropout(dropout))
|
|
572
|
+
layers.append(nn.Dropout(dropout)) # type: ignore
|
|
573
573
|
self.main = nn.Sequential(*layers)
|
|
574
574
|
|
|
575
575
|
def forward(self, x):
|
|
@@ -649,7 +649,7 @@ class DenseODSTBlock(nn.Sequential):
|
|
|
649
649
|
|
|
650
650
|
# Initialize the specific ODST layer
|
|
651
651
|
if hasattr(layer, 'initialize'):
|
|
652
|
-
layer.initialize(layer_inp)
|
|
652
|
+
layer.initialize(layer_inp) # type: ignore
|
|
653
653
|
|
|
654
654
|
# Compute output to feed the next layer in the dense block
|
|
655
655
|
h = layer(layer_inp)
|
|
@@ -696,7 +696,7 @@ class Embedding2dLayer(nn.Module):
|
|
|
696
696
|
def __init__(
|
|
697
697
|
self,
|
|
698
698
|
continuous_dim: int,
|
|
699
|
-
categorical_cardinality:
|
|
699
|
+
categorical_cardinality: list[int],
|
|
700
700
|
embedding_dim: int,
|
|
701
701
|
shared_embedding_strategy: Optional[str] = None,
|
|
702
702
|
frac_shared_embed: float = 0.25,
|
|
@@ -813,7 +813,7 @@ class Embedding2dLayer(nn.Module):
|
|
|
813
813
|
if self.embd_dropout is not None:
|
|
814
814
|
embed = self.embd_dropout(embed)
|
|
815
815
|
|
|
816
|
-
return embed
|
|
816
|
+
return embed # type: ignore
|
|
817
817
|
|
|
818
818
|
|
|
819
819
|
|
|
@@ -1007,7 +1007,7 @@ class _GateHead(nn.Module):
|
|
|
1007
1007
|
else:
|
|
1008
1008
|
# Apply separate linear layers
|
|
1009
1009
|
y_hat = torch.cat(
|
|
1010
|
-
[h(backbone_features[:, :, i]).unsqueeze(1) for i, h in enumerate(self.head)],
|
|
1010
|
+
[h(backbone_features[:, :, i]).unsqueeze(1) for i, h in enumerate(self.head)], # type: ignore
|
|
1011
1011
|
dim=1,
|
|
1012
1012
|
)
|
|
1013
1013
|
|
|
@@ -2,13 +2,13 @@ import torch
|
|
|
2
2
|
from torch import nn
|
|
3
3
|
from typing import Literal
|
|
4
4
|
|
|
5
|
-
from
|
|
6
|
-
from .
|
|
7
|
-
from ._keys import MLTaskKeys
|
|
8
|
-
from ._ML_models import _ArchitectureHandlerMixin
|
|
5
|
+
from .._core import get_logger
|
|
6
|
+
from ..keys._keys import MLTaskKeys
|
|
9
7
|
|
|
8
|
+
from ..ML_models._base_save_load import _ArchitectureHandlerMixin
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
|
|
11
|
+
_LOGGER = get_logger("DragonSequenceLSTM")
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
__all__ = [
|
|
@@ -137,6 +137,3 @@ class DragonSequenceLSTM(nn.Module, _ArchitectureHandlerMixin):
|
|
|
137
137
|
f"recurrent_layers={self.lstm.num_layers}), "
|
|
138
138
|
f"mode='{self.prediction_mode}')")
|
|
139
139
|
|
|
140
|
-
|
|
141
|
-
def info():
|
|
142
|
-
_script_info(__all__)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from ._image_classification import (
|
|
2
|
+
DragonResNet,
|
|
3
|
+
DragonEfficientNet,
|
|
4
|
+
DragonVGG,
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
from ._image_segmentation import (
|
|
8
|
+
DragonFCN,
|
|
9
|
+
DragonDeepLabv3
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
from ._object_detection import (
|
|
13
|
+
DragonFastRCNN,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from ._imprimir import info
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
# Image Classification
|
|
21
|
+
"DragonResNet",
|
|
22
|
+
"DragonEfficientNet",
|
|
23
|
+
"DragonVGG",
|
|
24
|
+
# Image Segmentation
|
|
25
|
+
"DragonFCN",
|
|
26
|
+
"DragonDeepLabv3",
|
|
27
|
+
# Object Detection
|
|
28
|
+
"DragonFastRCNN",
|
|
29
|
+
]
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
from torch import nn
|
|
3
|
+
import torchvision.models as vision_models
|
|
4
|
+
from typing import Any, Optional
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
|
|
7
|
+
from ..ML_models._base_save_load import _ArchitectureHandlerMixin
|
|
8
|
+
|
|
9
|
+
from .._core import get_logger
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
_LOGGER = get_logger("DragonVisionModel")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"_BaseVisionWrapper",
|
|
17
|
+
"_BaseSegmentationWrapper",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class _BaseVisionWrapper(nn.Module, _ArchitectureHandlerMixin, ABC):
|
|
22
|
+
"""
|
|
23
|
+
Abstract base class for torchvision model wrappers.
|
|
24
|
+
|
|
25
|
+
Handles common logic for:
|
|
26
|
+
- Model instantiation (with/without pretrained weights)
|
|
27
|
+
- Input layer modification (for custom in_channels)
|
|
28
|
+
- Output layer modification (for custom num_classes)
|
|
29
|
+
- Architecture saving/loading and representation
|
|
30
|
+
"""
|
|
31
|
+
def __init__(self,
|
|
32
|
+
num_classes: int,
|
|
33
|
+
in_channels: int,
|
|
34
|
+
model_name: str,
|
|
35
|
+
init_with_pretrained: bool,
|
|
36
|
+
weights_enum_name: Optional[str] = None):
|
|
37
|
+
super().__init__()
|
|
38
|
+
|
|
39
|
+
# --- 1. Validation and Configuration ---
|
|
40
|
+
if not hasattr(vision_models, model_name):
|
|
41
|
+
_LOGGER.error(f"'{model_name}' is not a valid model name in torchvision.models.")
|
|
42
|
+
raise ValueError()
|
|
43
|
+
|
|
44
|
+
self.num_classes = num_classes
|
|
45
|
+
self.in_channels = in_channels
|
|
46
|
+
self.model_name = model_name
|
|
47
|
+
self._pretrained_default_transforms = None
|
|
48
|
+
|
|
49
|
+
# --- 2. Instantiate the base model ---
|
|
50
|
+
if init_with_pretrained:
|
|
51
|
+
weights_enum = getattr(vision_models, weights_enum_name, None) if weights_enum_name else None
|
|
52
|
+
weights = weights_enum.IMAGENET1K_V1 if weights_enum else None
|
|
53
|
+
|
|
54
|
+
# Save transformations for pretrained models
|
|
55
|
+
if weights:
|
|
56
|
+
self._pretrained_default_transforms = weights.transforms()
|
|
57
|
+
|
|
58
|
+
if weights is None and init_with_pretrained:
|
|
59
|
+
_LOGGER.warning(f"Could not find modern weights for {model_name}. Using 'pretrained=True' legacy fallback.")
|
|
60
|
+
self.model = getattr(vision_models, model_name)(pretrained=True)
|
|
61
|
+
else:
|
|
62
|
+
self.model = getattr(vision_models, model_name)(weights=weights)
|
|
63
|
+
else:
|
|
64
|
+
self.model = getattr(vision_models, model_name)(weights=None)
|
|
65
|
+
|
|
66
|
+
# --- 3. Modify the input layer (using abstract method) ---
|
|
67
|
+
if in_channels != 3:
|
|
68
|
+
original_conv1 = self._get_input_layer()
|
|
69
|
+
|
|
70
|
+
new_conv1 = nn.Conv2d(
|
|
71
|
+
in_channels,
|
|
72
|
+
original_conv1.out_channels,
|
|
73
|
+
kernel_size=original_conv1.kernel_size, # type: ignore
|
|
74
|
+
stride=original_conv1.stride, # type: ignore
|
|
75
|
+
padding=original_conv1.padding, # type: ignore
|
|
76
|
+
bias=(original_conv1.bias is not None)
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# (Optional) Average original weights if starting from pretrained
|
|
80
|
+
if init_with_pretrained and original_conv1.in_channels == 3:
|
|
81
|
+
with torch.no_grad():
|
|
82
|
+
avg_weights = torch.mean(original_conv1.weight, dim=1, keepdim=True)
|
|
83
|
+
new_conv1.weight[:] = avg_weights.repeat(1, in_channels, 1, 1)
|
|
84
|
+
|
|
85
|
+
self._set_input_layer(new_conv1)
|
|
86
|
+
|
|
87
|
+
# --- 4. Modify the output layer (using abstract method) ---
|
|
88
|
+
original_fc = self._get_output_layer()
|
|
89
|
+
if original_fc is None: # Handle case where layer isn't found
|
|
90
|
+
_LOGGER.error(f"Model '{model_name}' has an unexpected classifier structure. Cannot replace final layer.")
|
|
91
|
+
raise AttributeError("Could not find final classifier layer.")
|
|
92
|
+
|
|
93
|
+
num_filters = original_fc.in_features
|
|
94
|
+
self._set_output_layer(nn.Linear(num_filters, num_classes))
|
|
95
|
+
|
|
96
|
+
@abstractmethod
|
|
97
|
+
def _get_input_layer(self) -> nn.Conv2d:
|
|
98
|
+
"""Returns the first convolutional layer of the model."""
|
|
99
|
+
raise NotImplementedError
|
|
100
|
+
|
|
101
|
+
@abstractmethod
|
|
102
|
+
def _set_input_layer(self, layer: nn.Conv2d):
|
|
103
|
+
"""Sets the first convolutional layer of the model."""
|
|
104
|
+
raise NotImplementedError
|
|
105
|
+
|
|
106
|
+
@abstractmethod
|
|
107
|
+
def _get_output_layer(self) -> Optional[nn.Linear]:
|
|
108
|
+
"""Returns the final fully-connected layer of the model."""
|
|
109
|
+
raise NotImplementedError
|
|
110
|
+
|
|
111
|
+
@abstractmethod
|
|
112
|
+
def _set_output_layer(self, layer: nn.Linear):
|
|
113
|
+
"""Sets the final fully-connected layer of the model."""
|
|
114
|
+
raise NotImplementedError
|
|
115
|
+
|
|
116
|
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
|
117
|
+
"""Defines the forward pass of the model."""
|
|
118
|
+
return self.model(x)
|
|
119
|
+
|
|
120
|
+
def get_architecture_config(self) -> dict[str, Any]:
|
|
121
|
+
"""
|
|
122
|
+
Returns the structural configuration of the model.
|
|
123
|
+
The 'init_with_pretrained' flag is intentionally omitted,
|
|
124
|
+
as .load() should restore the architecture, not the weights.
|
|
125
|
+
"""
|
|
126
|
+
return {
|
|
127
|
+
'num_classes': self.num_classes,
|
|
128
|
+
'in_channels': self.in_channels,
|
|
129
|
+
'model_name': self.model_name
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
def __repr__(self) -> str:
|
|
133
|
+
"""Returns the developer-friendly string representation of the model."""
|
|
134
|
+
return (
|
|
135
|
+
f"{self.__class__.__name__}(model='{self.model_name}', "
|
|
136
|
+
f"in_channels={self.in_channels}, "
|
|
137
|
+
f"num_classes={self.num_classes})"
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# Image segmentation
|
|
142
|
+
class _BaseSegmentationWrapper(nn.Module, _ArchitectureHandlerMixin, ABC):
|
|
143
|
+
"""
|
|
144
|
+
Abstract base class for torchvision segmentation model wrappers.
|
|
145
|
+
|
|
146
|
+
Handles common logic for:
|
|
147
|
+
- Model instantiation (with/without pretrained weights and custom num_classes)
|
|
148
|
+
- Input layer modification (for custom in_channels)
|
|
149
|
+
- Forward pass dictionary unpacking (returns 'out' tensor)
|
|
150
|
+
- Architecture saving/loading and representation
|
|
151
|
+
"""
|
|
152
|
+
def __init__(self,
|
|
153
|
+
num_classes: int,
|
|
154
|
+
in_channels: int,
|
|
155
|
+
model_name: str,
|
|
156
|
+
init_with_pretrained: bool,
|
|
157
|
+
weights_enum_name: Optional[str] = None):
|
|
158
|
+
super().__init__()
|
|
159
|
+
|
|
160
|
+
# --- 1. Validation and Configuration ---
|
|
161
|
+
if not hasattr(vision_models.segmentation, model_name):
|
|
162
|
+
_LOGGER.error(f"'{model_name}' is not a valid model name in torchvision.models.segmentation.")
|
|
163
|
+
raise ValueError()
|
|
164
|
+
|
|
165
|
+
self.num_classes = num_classes
|
|
166
|
+
self.in_channels = in_channels
|
|
167
|
+
self.model_name = model_name
|
|
168
|
+
self._pretrained_default_transforms = None
|
|
169
|
+
|
|
170
|
+
# --- 2. Instantiate the base model ---
|
|
171
|
+
model_kwargs = {
|
|
172
|
+
'num_classes': num_classes,
|
|
173
|
+
'weights': None
|
|
174
|
+
}
|
|
175
|
+
model_constructor = getattr(vision_models.segmentation, model_name)
|
|
176
|
+
|
|
177
|
+
if init_with_pretrained:
|
|
178
|
+
weights_enum = getattr(vision_models.segmentation, weights_enum_name, None) if weights_enum_name else None
|
|
179
|
+
weights = weights_enum.DEFAULT if weights_enum else None
|
|
180
|
+
|
|
181
|
+
# save pretrained model transformations
|
|
182
|
+
if weights:
|
|
183
|
+
self._pretrained_default_transforms = weights.transforms()
|
|
184
|
+
|
|
185
|
+
if weights is None:
|
|
186
|
+
_LOGGER.warning(f"Could not find modern weights for {model_name}. Using 'pretrained=True' legacy fallback.")
|
|
187
|
+
# Legacy models used 'pretrained=True' and num_classes was separate
|
|
188
|
+
self.model = model_constructor(pretrained=True, **model_kwargs)
|
|
189
|
+
else:
|
|
190
|
+
# Modern way: weights object implies pretraining
|
|
191
|
+
model_kwargs['weights'] = weights
|
|
192
|
+
self.model = model_constructor(**model_kwargs)
|
|
193
|
+
else:
|
|
194
|
+
self.model = model_constructor(**model_kwargs)
|
|
195
|
+
|
|
196
|
+
# --- 3. Modify the input layer (using abstract method) ---
|
|
197
|
+
if in_channels != 3:
|
|
198
|
+
original_conv1 = self._get_input_layer()
|
|
199
|
+
|
|
200
|
+
new_conv1 = nn.Conv2d(
|
|
201
|
+
in_channels,
|
|
202
|
+
original_conv1.out_channels,
|
|
203
|
+
kernel_size=original_conv1.kernel_size, # type: ignore
|
|
204
|
+
stride=original_conv1.stride, # type: ignore
|
|
205
|
+
padding=original_conv1.padding, # type: ignore
|
|
206
|
+
bias=(original_conv1.bias is not None)
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
# (Optional) Average original weights if starting from pretrained
|
|
210
|
+
if init_with_pretrained and original_conv1.in_channels == 3:
|
|
211
|
+
with torch.no_grad():
|
|
212
|
+
avg_weights = torch.mean(original_conv1.weight, dim=1, keepdim=True)
|
|
213
|
+
new_conv1.weight[:] = avg_weights.repeat(1, in_channels, 1, 1)
|
|
214
|
+
|
|
215
|
+
self._set_input_layer(new_conv1)
|
|
216
|
+
|
|
217
|
+
@abstractmethod
|
|
218
|
+
def _get_input_layer(self) -> nn.Conv2d:
|
|
219
|
+
"""Returns the first convolutional layer of the model (in the backbone)."""
|
|
220
|
+
raise NotImplementedError
|
|
221
|
+
|
|
222
|
+
@abstractmethod
|
|
223
|
+
def _set_input_layer(self, layer: nn.Conv2d):
|
|
224
|
+
"""Sets the first convolutional layer of the model (in the backbone)."""
|
|
225
|
+
raise NotImplementedError
|
|
226
|
+
|
|
227
|
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
|
228
|
+
"""
|
|
229
|
+
Defines the forward pass.
|
|
230
|
+
Returns the 'out' tensor from the segmentation model's output dict.
|
|
231
|
+
"""
|
|
232
|
+
output_dict = self.model(x)
|
|
233
|
+
return output_dict['out'] # Key for standard torchvision seg models
|
|
234
|
+
|
|
235
|
+
def get_architecture_config(self) -> dict[str, Any]:
|
|
236
|
+
"""
|
|
237
|
+
Returns the structural configuration of the model.
|
|
238
|
+
The 'init_with_pretrained' flag is intentionally omitted,
|
|
239
|
+
as .load() should restore the architecture, not the weights.
|
|
240
|
+
"""
|
|
241
|
+
return {
|
|
242
|
+
'num_classes': self.num_classes,
|
|
243
|
+
'in_channels': self.in_channels,
|
|
244
|
+
'model_name': self.model_name
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
def __repr__(self) -> str:
|
|
248
|
+
"""Returns the developer-friendly string representation of the model."""
|
|
249
|
+
return (
|
|
250
|
+
f"{self.__class__.__name__}(model='{self.model_name}', "
|
|
251
|
+
f"in_channels={self.in_channels}, "
|
|
252
|
+
f"num_classes={self.num_classes})"
|
|
253
|
+
)
|
|
254
|
+
|