Spaces:
Sleeping
Sleeping
Commit
·
47d1597
1
Parent(s):
bed4774
propre et fonctionnel
Browse files- src/main.py +71 -36
src/main.py
CHANGED
@@ -6,7 +6,10 @@
|
|
6 |
import os
|
7 |
import logging
|
8 |
import hydra
|
|
|
|
|
9 |
from omegaconf import DictConfig, OmegaConf
|
|
|
10 |
from trainers.cuml.svm_trainer import SvmTrainer
|
11 |
from trainers.cuml.random_forest_trainer import RandomForestTrainer
|
12 |
from trainers.cuml.logistic_regression_trainer import LogisticRegressionTrainer
|
@@ -15,19 +18,18 @@ from trainers.huggingface.huggingface_transformer_trainer import HuggingFaceTran
|
|
15 |
from optimizers.optuna_optimizer import OptunaOptimizer
|
16 |
from optimizers.ray_tune_optimizer import RayTuneOptimizer
|
17 |
from mlflow_integration.mlflow_decorator import MLflowDecorator
|
18 |
-
|
|
|
|
|
|
|
|
|
|
|
19 |
logger = logging.getLogger(__name__)
|
20 |
|
21 |
|
22 |
def get_trainer(config: Config):
|
23 |
"""
|
24 |
Crée et retourne l'instance du trainer approprié en fonction de la configuration.
|
25 |
-
|
26 |
-
Args:
|
27 |
-
config: Objet de configuration
|
28 |
-
|
29 |
-
Returns:
|
30 |
-
Une instance concrète de BaseTrainer
|
31 |
"""
|
32 |
model_type = config.model.type.lower()
|
33 |
|
@@ -43,7 +45,6 @@ def get_trainer(config: Config):
|
|
43 |
if model_type not in trainer_map:
|
44 |
raise ValueError(f"Type de modèle non supporté: {model_type}")
|
45 |
|
46 |
-
# Création de l'instance du trainer avec la configuration
|
47 |
trainer_class = trainer_map[model_type]
|
48 |
return trainer_class(
|
49 |
config=config,
|
@@ -55,16 +56,8 @@ def get_trainer(config: Config):
|
|
55 |
def get_optimizer(config: Config):
|
56 |
"""
|
57 |
Crée et retourne l'instance d'optimizer appropriée en fonction de la configuration.
|
58 |
-
|
59 |
-
Args:
|
60 |
-
config: Objet de configuration
|
61 |
-
|
62 |
-
Returns:
|
63 |
-
Une instance concrète de HyperparameterOptimizer
|
64 |
"""
|
65 |
optimizer_type = config.hyperparameters.optimizer.lower()
|
66 |
-
|
67 |
-
# Mapping des types d'optimizers
|
68 |
optimizer_map = {
|
69 |
"optuna": OptunaOptimizer,
|
70 |
"raytune": RayTuneOptimizer,
|
@@ -73,23 +66,56 @@ def get_optimizer(config: Config):
|
|
73 |
if optimizer_type not in optimizer_map:
|
74 |
raise ValueError(f"Type d'optimizer non supporté: {optimizer_type}")
|
75 |
|
76 |
-
|
77 |
-
|
78 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
|
80 |
|
81 |
@hydra.main(config_path="conf", config_name="config", version_base=None)
|
82 |
def main(cfg: DictConfig) -> None:
|
83 |
"""
|
84 |
Point d'entrée principal de l'application.
|
85 |
-
|
86 |
-
Args:
|
87 |
-
cfg: Configuration Hydra sous forme de DictConfig
|
88 |
"""
|
89 |
-
# La configuration Hydra 'cfg' est maintenant correctement structurée grâce aux defaults dans config.yaml.
|
90 |
-
# Conversion directe en configuration Pydantic.
|
91 |
try:
|
92 |
-
# Convertit directement cfg en dict et l'utilise pour instancier Config
|
93 |
config = Config(**OmegaConf.to_container(cfg, resolve=True))
|
94 |
except Exception as e:
|
95 |
logger.error(f"Erreur lors de la validation Pydantic de la configuration: {e}")
|
@@ -98,14 +124,20 @@ def main(cfg: DictConfig) -> None:
|
|
98 |
|
99 |
logger.info(f"Configuration Pydantic finale chargée: {config}")
|
100 |
|
101 |
-
#
|
102 |
-
|
103 |
|
104 |
-
|
105 |
trainer.build_components()
|
106 |
|
107 |
-
# Définir la séquence d'opérations à exécuter dans un seul run MLflow
|
108 |
def run_pipeline(trainer_instance):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
109 |
logger.info("Vérification et lancement de l'optimisation des hyperparamètres si nécessaire...")
|
110 |
trainer_instance.optimize_if_needed()
|
111 |
|
@@ -113,26 +145,29 @@ def main(cfg: DictConfig) -> None:
|
|
113 |
trainer_instance.train()
|
114 |
|
115 |
logger.info("Lancement de l'évaluation...")
|
116 |
-
trainer_instance.evaluate()
|
|
|
|
|
|
|
|
|
117 |
|
118 |
logger.info("Logging des paramètres...")
|
119 |
trainer_instance.log_parameters_to_mlflow()
|
120 |
|
121 |
-
|
|
|
|
|
|
|
122 |
|
123 |
-
#
|
124 |
mlflow_decorator = MLflowDecorator(
|
125 |
experiment_name=config.mlflow.experiment_name,
|
126 |
tracking_uri=config.mlflow.tracking_uri
|
127 |
)
|
128 |
|
129 |
-
# Appliquer le décorateur à la fonction pipeline complète
|
130 |
run_pipeline_with_mlflow = mlflow_decorator(run_pipeline)
|
131 |
-
|
132 |
-
# Exécuter le pipeline complet sous un seul run MLflow
|
133 |
logger.info("Lancement du pipeline complet avec MLflow...")
|
134 |
run_pipeline_with_mlflow(trainer)
|
135 |
-
|
136 |
logger.info("Pipeline MLflow terminé avec succès.")
|
137 |
|
138 |
|
|
|
6 |
import os
|
7 |
import logging
|
8 |
import hydra
|
9 |
+
import mlflow
|
10 |
+
|
11 |
from omegaconf import DictConfig, OmegaConf
|
12 |
+
from config import Config
|
13 |
from trainers.cuml.svm_trainer import SvmTrainer
|
14 |
from trainers.cuml.random_forest_trainer import RandomForestTrainer
|
15 |
from trainers.cuml.logistic_regression_trainer import LogisticRegressionTrainer
|
|
|
18 |
from optimizers.optuna_optimizer import OptunaOptimizer
|
19 |
from optimizers.ray_tune_optimizer import RayTuneOptimizer
|
20 |
from mlflow_integration.mlflow_decorator import MLflowDecorator
|
21 |
+
|
22 |
+
import tempfile
|
23 |
+
import pickle
|
24 |
+
import pandas as pd
|
25 |
+
from utilities.cuml_pyfunc_wrapper import CuMLPyFuncWrapper
|
26 |
+
|
27 |
logger = logging.getLogger(__name__)
|
28 |
|
29 |
|
30 |
def get_trainer(config: Config):
|
31 |
"""
|
32 |
Crée et retourne l'instance du trainer approprié en fonction de la configuration.
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
"""
|
34 |
model_type = config.model.type.lower()
|
35 |
|
|
|
45 |
if model_type not in trainer_map:
|
46 |
raise ValueError(f"Type de modèle non supporté: {model_type}")
|
47 |
|
|
|
48 |
trainer_class = trainer_map[model_type]
|
49 |
return trainer_class(
|
50 |
config=config,
|
|
|
56 |
def get_optimizer(config: Config):
|
57 |
"""
|
58 |
Crée et retourne l'instance d'optimizer appropriée en fonction de la configuration.
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
"""
|
60 |
optimizer_type = config.hyperparameters.optimizer.lower()
|
|
|
|
|
61 |
optimizer_map = {
|
62 |
"optuna": OptunaOptimizer,
|
63 |
"raytune": RayTuneOptimizer,
|
|
|
66 |
if optimizer_type not in optimizer_map:
|
67 |
raise ValueError(f"Type d'optimizer non supporté: {optimizer_type}")
|
68 |
|
69 |
+
return optimizer_map[optimizer_type]()
|
70 |
+
|
71 |
+
|
72 |
+
def log_cuml_model_to_mlflow(trainer_instance, run_id=None):
|
73 |
+
"""
|
74 |
+
Sérialise le vectorizer et le classifier dans un répertoire temporaire
|
75 |
+
puis log le tout dans MLflow en tant que modèle PyFunc.
|
76 |
+
|
77 |
+
Les artifacts sont ainsi stockés dans mlruns, liés au run en cours.
|
78 |
+
"""
|
79 |
+
logger.info("Logging du modèle CuML via mlflow.pyfunc.log_model...")
|
80 |
+
input_example = pd.DataFrame({"example_text": ["exemple"]})
|
81 |
+
|
82 |
+
# On va utiliser mlflow.pyfunc.log_model pour stocker le wrapper PyFunc + nos artifacts
|
83 |
+
with tempfile.TemporaryDirectory() as tmpdir:
|
84 |
+
vectorizer_path = os.path.join(tmpdir, "vectorizer.pkl")
|
85 |
+
classifier_path = os.path.join(tmpdir, "classifier.pkl")
|
86 |
+
|
87 |
+
# Sauvegarde sur disque
|
88 |
+
with open(vectorizer_path, "wb") as vf:
|
89 |
+
pickle.dump(trainer_instance.vectorizer, vf)
|
90 |
+
with open(classifier_path, "wb") as cf:
|
91 |
+
pickle.dump(trainer_instance.classifier, cf)
|
92 |
+
|
93 |
+
# PyFunc wrapper (placeholder, héberge la logique de load_model)
|
94 |
+
pyfunc_wrapper = CuMLPyFuncWrapper(
|
95 |
+
vectorizer=None,
|
96 |
+
classifier=None
|
97 |
+
)
|
98 |
+
|
99 |
+
# Log en PyFunc; "cuml_model" est le chemin (artifact_path) où sera stocké le modèle dans MLflow
|
100 |
+
mlflow.pyfunc.log_model(
|
101 |
+
artifact_path="cuml_model",
|
102 |
+
python_model=pyfunc_wrapper,
|
103 |
+
artifacts={
|
104 |
+
"vectorizer": vectorizer_path,
|
105 |
+
"classifier": classifier_path
|
106 |
+
},
|
107 |
+
input_example=input_example
|
108 |
+
)
|
109 |
+
|
110 |
+
logger.info("Le modèle et ses artifacts ont été enregistrés dans MLflow.")
|
111 |
|
112 |
|
113 |
@hydra.main(config_path="conf", config_name="config", version_base=None)
|
114 |
def main(cfg: DictConfig) -> None:
|
115 |
"""
|
116 |
Point d'entrée principal de l'application.
|
|
|
|
|
|
|
117 |
"""
|
|
|
|
|
118 |
try:
|
|
|
119 |
config = Config(**OmegaConf.to_container(cfg, resolve=True))
|
120 |
except Exception as e:
|
121 |
logger.error(f"Erreur lors de la validation Pydantic de la configuration: {e}")
|
|
|
124 |
|
125 |
logger.info(f"Configuration Pydantic finale chargée: {config}")
|
126 |
|
127 |
+
# Sélection du tracker MLflow
|
128 |
+
mlflow.set_tracking_uri(config.mlflow.tracking_uri)
|
129 |
|
130 |
+
trainer = get_trainer(config)
|
131 |
trainer.build_components()
|
132 |
|
|
|
133 |
def run_pipeline(trainer_instance):
|
134 |
+
"""
|
135 |
+
Exécute la séquence complète :
|
136 |
+
- Optimisation hyperparamètres (si besoin)
|
137 |
+
- Entraînement
|
138 |
+
- Évaluation
|
139 |
+
- Logging MLflow (paramètres, métriques, et modèles)
|
140 |
+
"""
|
141 |
logger.info("Vérification et lancement de l'optimisation des hyperparamètres si nécessaire...")
|
142 |
trainer_instance.optimize_if_needed()
|
143 |
|
|
|
145 |
trainer_instance.train()
|
146 |
|
147 |
logger.info("Lancement de l'évaluation...")
|
148 |
+
metrics = trainer_instance.evaluate()
|
149 |
+
logger.info(f"Metrics calculés: {metrics}")
|
150 |
+
|
151 |
+
# Log des métriques
|
152 |
+
mlflow.log_metrics(metrics)
|
153 |
|
154 |
logger.info("Logging des paramètres...")
|
155 |
trainer_instance.log_parameters_to_mlflow()
|
156 |
|
157 |
+
# Log du modèle final (vectorizer+classifier) sous forme PyFunc
|
158 |
+
log_cuml_model_to_mlflow(trainer_instance)
|
159 |
+
|
160 |
+
logger.info("Pipeline MLflow complet terminé.")
|
161 |
|
162 |
+
# On utilise un décorateur défini pour centraliser le démarrage/arrêt du run
|
163 |
mlflow_decorator = MLflowDecorator(
|
164 |
experiment_name=config.mlflow.experiment_name,
|
165 |
tracking_uri=config.mlflow.tracking_uri
|
166 |
)
|
167 |
|
|
|
168 |
run_pipeline_with_mlflow = mlflow_decorator(run_pipeline)
|
|
|
|
|
169 |
logger.info("Lancement du pipeline complet avec MLflow...")
|
170 |
run_pipeline_with_mlflow(trainer)
|
|
|
171 |
logger.info("Pipeline MLflow terminé avec succès.")
|
172 |
|
173 |
|