fioriclass commited on
Commit
47d1597
·
1 Parent(s): bed4774

propre et fonctionnel

Browse files
Files changed (1) hide show
  1. 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
- from config import Config
 
 
 
 
 
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
- # Création de l'instance de l'optimizer
77
- optimizer_class = optimizer_map[optimizer_type]
78
- return optimizer_class()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- # Création du trainer approprié
102
- trainer = get_trainer(config)
103
 
104
- # Construction des composants (vectorizer, classifier, etc.)
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
- logger.info("Pipeline complet (optimisation, entraînement, évaluation, logging) terminé.")
 
 
 
122
 
123
- # Initialiser le décorateur MLflow
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