MEDfl 2.0.10.dev7__tar.gz → 2.0.10.dev9__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.
Files changed (69) hide show
  1. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/xgboost/server.py +1 -1
  2. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/rw/client.py +46 -0
  3. medfl-2.0.10.dev9/MEDfl/rw/holdout.py +864 -0
  4. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/rw/server.py +37 -0
  5. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/rw/strategy.py +39 -6
  6. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/rw/xgboost/client.py +62 -1
  7. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/rw/xgboost/strategy.py +46 -9
  8. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/PKG-INFO +1 -1
  9. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/medfl.egg-info/PKG-INFO +1 -1
  10. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/medfl.egg-info/SOURCES.txt +3 -1
  11. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/setup.py +1 -1
  12. medfl-2.0.10.dev9/tests/test_rw_holdout.py +171 -0
  13. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/LICENSE +0 -0
  14. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/__init__.py +0 -0
  15. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/client.py +0 -0
  16. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/dynamicModal.py +0 -0
  17. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/federated_dataset.py +0 -0
  18. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/flpipeline.py +0 -0
  19. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/model.py +0 -0
  20. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/params.yaml +0 -0
  21. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/params_optimiser.py +0 -0
  22. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/plot.py +0 -0
  23. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/server.py +0 -0
  24. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/shap/__init__.py +0 -0
  25. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/shap/aggregation.py +0 -0
  26. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/shap/config.py +0 -0
  27. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/shap/explainer.py +0 -0
  28. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/shap/xgboost_explainer.py +0 -0
  29. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/strategy.py +0 -0
  30. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/utils.py +0 -0
  31. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/xgboost/__init__.py +0 -0
  32. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/xgboost/client.py +0 -0
  33. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/xgboost/config.py +0 -0
  34. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/xgboost/data.py +0 -0
  35. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/xgboost/metrics.py +0 -0
  36. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/xgboost/serialization.py +0 -0
  37. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/LearningManager/xgboost/strategy.py +0 -0
  38. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/NetManager/__init__.py +0 -0
  39. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/NetManager/database_connector.py +0 -0
  40. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/NetManager/dataset.py +0 -0
  41. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/NetManager/flsetup.py +0 -0
  42. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/NetManager/net_helper.py +0 -0
  43. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/NetManager/net_manager_queries.py +0 -0
  44. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/NetManager/network.py +0 -0
  45. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/NetManager/node.py +0 -0
  46. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/__init__.py +0 -0
  47. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/rw/__init__.py +0 -0
  48. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/rw/model.py +0 -0
  49. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/rw/xgboost/__init__.py +0 -0
  50. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/rw/xgboost/config.py +0 -0
  51. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/rw/xgboost/data.py +0 -0
  52. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/rw/xgboost/metrics.py +0 -0
  53. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/rw/xgboost/serialization.py +0 -0
  54. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/scripts/__init__.py +0 -0
  55. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/scripts/base.py +0 -0
  56. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/MEDfl/scripts/create_db.py +0 -0
  57. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/README.md +0 -0
  58. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/alembic/__init__.py +0 -0
  59. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/alembic/env.py +0 -0
  60. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/medfl.egg-info/dependency_links.txt +0 -0
  61. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/medfl.egg-info/requires.txt +0 -0
  62. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/medfl.egg-info/top_level.txt +0 -0
  63. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/setup.cfg +0 -0
  64. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/tests/test_dataset.py +0 -0
  65. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/tests/test_federated_dataset.py +0 -0
  66. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/tests/test_flpipeline.py +0 -0
  67. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/tests/test_flsetup.py +0 -0
  68. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/tests/test_network.py +0 -0
  69. {medfl-2.0.10.dev7 → medfl-2.0.10.dev9}/tests/test_node.py +0 -0
@@ -743,4 +743,4 @@ class XGBoostSimulationServer:
743
743
  flush=True,
744
744
  )
745
745
 
746
- return self.history
746
+ return self.history
@@ -12,6 +12,7 @@ from sklearn.metrics import accuracy_score, roc_auc_score
12
12
  from sklearn.model_selection import train_test_split
13
13
  from MEDfl.rw.model import Net # votre définition de modèle
14
14
  from MEDfl.LearningManager.shap import LocalPyTorchSHAPExplainer
15
+ from MEDfl.rw.holdout import run_local_holdout
15
16
  import socket
16
17
  import platform
17
18
  import psutil
@@ -77,6 +78,10 @@ class FlowerClient(fl.client.NumPyClient):
77
78
  Comma-separated list of IDs (or line numbers) to use as test set.
78
79
  seed : int, optional
79
80
  Random seed used for splits. Default is ``42``.
81
+ holdout_path : str, optional
82
+ Path to a local holdout CSV, never used for training. When the server
83
+ enables the federated holdout test, the final global model is tested
84
+ on it after the last round. Default is ``None`` (no holdout).
80
85
  """
81
86
  def __init__(
82
87
  self,
@@ -89,6 +94,7 @@ class FlowerClient(fl.client.NumPyClient):
89
94
  id_col=None,
90
95
  test_ids=None,
91
96
  seed=42,
97
+ holdout_path=None,
92
98
  ):
93
99
  self.server_address = server_address
94
100
  self.dp_config = dp_config
@@ -97,6 +103,8 @@ class FlowerClient(fl.client.NumPyClient):
97
103
  self.id_col = id_col
98
104
  self.test_ids = test_ids
99
105
  self.seed = seed
106
+ # read only when the server asks for the holdout test (features/target come from the server)
107
+ self.holdout_path = holdout_path
100
108
 
101
109
  # Load the CSV once; actual column selection happens on first fit using server config
102
110
  self._df = pd.read_csv(data_path)
@@ -585,10 +593,48 @@ class FlowerClient(fl.client.NumPyClient):
585
593
  flush=True,
586
594
  )
587
595
 
596
+ # ---------------------------------------------------------------
597
+ # Final-round federated holdout test
598
+ #
599
+ # Same final global parameters as SHAP above, tested on the local
600
+ # holdout file. Rows with missing feature values are dropped since
601
+ # the network cannot predict them.
602
+ # ---------------------------------------------------------------
603
+ if bool(config.get("holdout_enabled", False)):
604
+ metrics.update(
605
+ run_local_holdout(
606
+ config=config,
607
+ holdout_path=self.holdout_path,
608
+ features=self.effective_features,
609
+ target=self.effective_target,
610
+ predict=self._predict_probabilities,
611
+ client_id=socket.gethostname(),
612
+ drop_missing_features=True,
613
+ validation=self._validation_predictions,
614
+ )
615
+ )
616
+
588
617
  print(f"Evaluation metrics: {metrics}")
589
618
 
590
619
  return float(avg_loss), len(self.test_loader.dataset), metrics
591
620
 
621
+ def _predict_probabilities(self, X):
622
+ """Positive-class probabilities of the current model for a feature array."""
623
+ self.model.eval()
624
+ with torch.no_grad():
625
+ logits = self.model(torch.tensor(X, dtype=torch.float32))
626
+ return torch.sigmoid(logits.reshape(-1)).cpu().numpy()
627
+
628
+ def _validation_predictions(self):
629
+ """(y_true, y_prob) of the validation split, for the optimized holdout threshold."""
630
+ if self.val_loader is None:
631
+ return np.empty((0,)), np.empty((0,))
632
+ y_parts, prob_parts = [], []
633
+ for X_batch, y_batch in self.val_loader:
634
+ y_parts.append(y_batch.cpu().numpy().reshape(-1))
635
+ prob_parts.append(self._predict_probabilities(X_batch.cpu().numpy()))
636
+ return np.concatenate(y_parts), np.concatenate(prob_parts)
637
+
592
638
  def get_properties(self, config):
593
639
  hostname = socket.gethostname()
594
640
  os_type = platform.system()