-
Notifications
You must be signed in to change notification settings - Fork 2
Bug Fix DPMON CPU issues for tunning #99
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -13,18 +13,18 @@ class HybridLouvain: | |||||||||
|
|
||||||||||
| Attributes: | ||||||||||
|
|
||||||||||
| G (nx.Graph): NetworkX graph object. | ||||||||||
| G (Union[nx.Graph, pd.DataFrame]): Input graph as a NetworkX Graph or adjacency DataFrame. | ||||||||||
| B (pd.DataFrame): Omics data. | ||||||||||
| Y (pd.DataFrame): Phenotype data. | ||||||||||
| k3 (float): Weight for Correlated Louvain. | ||||||||||
| k4 (float): Weight for Correlated Louvain. | ||||||||||
| max_iter (int): Maximum number of iterations. | ||||||||||
| weight (str): Edge weight parameter name. | ||||||||||
| tune (bool): Flag to enable tuning of parameters | ||||||||||
| tune (bool): Flag to enable tuning of parameters | ||||||||||
| """ | ||||||||||
| def __init__( | ||||||||||
| self, | ||||||||||
| G: nx.Graph, | ||||||||||
| G: Union[nx.Graph, pd.DataFrame], | ||||||||||
| B: pd.DataFrame, | ||||||||||
| Y: pd.DataFrame, | ||||||||||
| k3: float = 0.2, | ||||||||||
|
|
@@ -43,6 +43,13 @@ def __init__( | |||||||||
| set_seed(seed) | ||||||||||
| self.logger.info("Initializing HybridLouvain...") | ||||||||||
|
|
||||||||||
| if isinstance(G, pd.DataFrame): | ||||||||||
| self.logger.info("Input G is a DataFrame; converting adjacency matrix to NetworkX graph.") | ||||||||||
| G = nx.from_pandas_adjacency(G) | ||||||||||
|
|
||||||||||
| if not isinstance(G, nx.Graph): | ||||||||||
| raise TypeError("G must be a networkx.Graph or a pandas DataFrame adjacency matrix.") | ||||||||||
|
|
||||||||||
| self.G = G | ||||||||||
| graph_nodes = set(map(str, G.nodes())) | ||||||||||
|
|
||||||||||
|
|
@@ -233,7 +240,15 @@ def run(self, as_dfs: bool = False) -> Union[dict, list]: | |||||||||
| refined_nodes = pagerank_results.get("cluster_nodes", []) | ||||||||||
| new_size = len(refined_nodes) | ||||||||||
| all_clusters[iteration] = refined_nodes | ||||||||||
| self.logger.info(f"Refined subgraph size: {new_size}") | ||||||||||
|
|
||||||||||
| cond = pagerank_results.get("conductance", None) | ||||||||||
| corr = pagerank_results.get("correlation", None) | ||||||||||
| score = pagerank_results.get("composite_score", None) | ||||||||||
|
|
||||||||||
| self.logger.info( | ||||||||||
| f"Iteration {iteration+1}: cluster size={new_size}, " | ||||||||||
| f"Conductance={cond:.3f} Correlation={corr:.3f} score={score:.3f}" | ||||||||||
|
||||||||||
| f"Conductance={cond:.3f} Correlation={corr:.3f} score={score:.3f}" | |
| f"Conductance={cond:.3f}" if cond is not None else "Conductance=N/A" + " " | |
| f"Correlation={corr:.3f}" if corr is not None else "Correlation=N/A" + " " | |
| f"score={score:.3f}" if score is not None else "score=N/A" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| patient,vital_status | ||
| patient,target | ||
|
||
| TCGA-CS-4938,0 | ||
| TCGA-CS-4941,1 | ||
| TCGA-CS-4942,1 | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -25,8 +25,10 @@ | |||||||||||||||
| from ray import tune | ||||||||||||||||
| from ray.tune import Checkpoint | ||||||||||||||||
| from ray.tune import CLIReporter | ||||||||||||||||
| from ray.tune.error import TuneError | ||||||||||||||||
| from ray.tune.stopper import TrialPlateauStopper | ||||||||||||||||
| from ray.tune.schedulers import ASHAScheduler | ||||||||||||||||
| from ray.tune.search.basic_variant import BasicVariantGenerator | ||||||||||||||||
| from sklearn.model_selection import train_test_split,StratifiedKFold,RepeatedStratifiedKFold | ||||||||||||||||
| from sklearn.preprocessing import label_binarize | ||||||||||||||||
| from scipy.stats import pointbiserialr | ||||||||||||||||
|
|
@@ -69,6 +71,7 @@ class DPMON: | |||||||||||||||
| cv (bool): If True, use K-fold cross-validation; otherwise use repeated train/test splits. | ||||||||||||||||
| cuda (int): CUDA device index to use when gpu=True. | ||||||||||||||||
| seed (int): Random seed for reproducibility. | ||||||||||||||||
| seed_trials (bool): If True, use a fixed seed for hyperparameter sampling to ensure reproducibility across trials. | ||||||||||||||||
| output_dir (Path): Directory where logs, checkpoints, and results are written. | ||||||||||||||||
| """ | ||||||||||||||||
| def __init__( | ||||||||||||||||
|
|
@@ -97,6 +100,7 @@ def __init__( | |||||||||||||||
| cv: bool = False, | ||||||||||||||||
| cuda: int = 0, | ||||||||||||||||
| seed: int = 1804, | ||||||||||||||||
| seed_trials: bool = False, | ||||||||||||||||
| output_dir: Optional[str] = None, | ||||||||||||||||
| ): | ||||||||||||||||
| if adjacency_matrix.empty: | ||||||||||||||||
|
|
@@ -153,6 +157,7 @@ def __init__( | |||||||||||||||
| self.gpu = gpu | ||||||||||||||||
| self.cuda = cuda | ||||||||||||||||
| self.seed = seed | ||||||||||||||||
| self.seed_trials = seed_trials | ||||||||||||||||
| self.cv = cv | ||||||||||||||||
|
|
||||||||||||||||
| if output_dir is None: | ||||||||||||||||
|
|
@@ -199,6 +204,7 @@ def run(self) -> Tuple[pd.DataFrame, object, torch.Tensor | None]: | |||||||||||||||
| "cuda": self.cuda, | ||||||||||||||||
| "tune": self.tune, | ||||||||||||||||
| "seed": self.seed, | ||||||||||||||||
| "seed_trials": self.seed_trials, | ||||||||||||||||
| "cv": self.cv, | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -305,10 +311,8 @@ def prepare_node_features(adjacency_matrix: pd.DataFrame, omics_datasets: List[p | |||||||||||||||
| omics_data = omics_datasets[0] | ||||||||||||||||
|
|
||||||||||||||||
| if phenotype_col in omics_data.columns: | ||||||||||||||||
| pheno = omics_data[phenotype_col] | ||||||||||||||||
| omics_feature_df = omics_data.drop(columns=[phenotype_col]) | ||||||||||||||||
| else: | ||||||||||||||||
| pheno = None | ||||||||||||||||
| omics_feature_df = omics_data | ||||||||||||||||
|
|
||||||||||||||||
| nodes = sorted(network_features.intersection(omics_feature_df.columns)) | ||||||||||||||||
|
|
@@ -529,7 +533,6 @@ def run_standard_training(dpmon_params, adjacency_matrix, combined_omics, clinic | |||||||||||||||
| best_global_model_state = None | ||||||||||||||||
| best_global_embeddings = None | ||||||||||||||||
|
|
||||||||||||||||
| cv_predictions_list = [] | ||||||||||||||||
| fold_accuracies = [] | ||||||||||||||||
| fold_f1_macros = [] | ||||||||||||||||
| fold_f1_weighteds = [] | ||||||||||||||||
|
|
@@ -642,7 +645,6 @@ def run_standard_training(dpmon_params, adjacency_matrix, combined_omics, clinic | |||||||||||||||
|
|
||||||||||||||||
| try: | ||||||||||||||||
| n_classes = probs_np.shape[1] | ||||||||||||||||
| unique_classes = np.unique(y_test_np) | ||||||||||||||||
|
|
||||||||||||||||
| # binary | ||||||||||||||||
| if n_classes == 2: | ||||||||||||||||
|
|
@@ -778,7 +780,7 @@ def run_hyperparameter_tuning(X_train, y_train, adjacency_matrix, clinical_data, | |||||||||||||||
| "nn_hidden_dim2": tune.choice([32, 64, 128]), | ||||||||||||||||
| "ae_encoding_dim": tune.choice([4, 8, 16]), | ||||||||||||||||
| "num_epochs": tune.choice([512, 1024, 2048]), | ||||||||||||||||
|
||||||||||||||||
| "num_epochs": tune.choice([512, 1024, 2048]), | |
| "num_epochs": tune.choice([512, 1024, 2048]), | |
| # Dropout range updated: removed lower values (0.0, 0.1) and added higher (0.6) to encourage more aggressive regularization. | |
| # This change may impact model performance; see commit message for rationale. |
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition if new_num_samples == num_samples will only be true when num_samples == 1 (since max(1, 1 // 2) == 1). However, this check happens after the assignment, so if the initial num_samples was already 1, the code will raise an exception. Consider checking if num_samples <= 1 before attempting to halve it, to provide a clearer error path.
| new_num_samples = max(1, num_samples // 2) | |
| if new_num_samples == num_samples: | |
| raise | |
| if num_samples <= 1: | |
| raise | |
| new_num_samples = max(1, num_samples // 2) |
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The else clause after the for loop is used here, which executes only if the loop completes without breaking. This is correct Python syntax but can be confusing. Consider adding a comment to clarify that this else clause triggers only if all retry attempts are exhausted without a successful break.
| # The else clause below executes only if the for loop completes without a break, | |
| # i.e., if all retry attempts are exhausted without a successful run. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trailing whitespace should be removed for consistency.