D4CMPP2 0.4.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.
Files changed (103) hide show
  1. D4CMPP2/_Data/AGENTS.md +24 -0
  2. D4CMPP2/_Data/Aqsoldb.csv +9291 -0
  3. D4CMPP2/_Data/BradleyMP.csv +3042 -0
  4. D4CMPP2/_Data/Lipophilicity.csv +1131 -0
  5. D4CMPP2/_Data/README.md +8 -0
  6. D4CMPP2/_Data/__init__.py +26 -0
  7. D4CMPP2/_Data/optical.csv +20237 -0
  8. D4CMPP2/_Data/test.csv +190 -0
  9. D4CMPP2/__init__.py +16 -0
  10. D4CMPP2/__main__.py +5 -0
  11. D4CMPP2/_main.py +500 -0
  12. D4CMPP2/cli.py +7 -0
  13. D4CMPP2/exceptions.py +53 -0
  14. D4CMPP2/grid_search.py +259 -0
  15. D4CMPP2/network_refer.yaml +160 -0
  16. D4CMPP2/networks/AFP_model.py +72 -0
  17. D4CMPP2/networks/AFPwithSolv_model.py +72 -0
  18. D4CMPP2/networks/DMPNN_model.py +90 -0
  19. D4CMPP2/networks/DMPNNwithSolv_model.py +89 -0
  20. D4CMPP2/networks/GAT_model.py +48 -0
  21. D4CMPP2/networks/GATwithSolv_model.py +63 -0
  22. D4CMPP2/networks/GCN_model.py +113 -0
  23. D4CMPP2/networks/GCNwithSolv_model.py +103 -0
  24. D4CMPP2/networks/GC_model.py +122 -0
  25. D4CMPP2/networks/ISATPM_model.py +14 -0
  26. D4CMPP2/networks/ISATPN_model.py +199 -0
  27. D4CMPP2/networks/ISAT_model.py +90 -0
  28. D4CMPP2/networks/MPNN_model.py +56 -0
  29. D4CMPP2/networks/MPNNwithSolv_model.py +72 -0
  30. D4CMPP2/networks/__init__.py +25 -0
  31. D4CMPP2/networks/base.py +250 -0
  32. D4CMPP2/networks/registry.py +187 -0
  33. D4CMPP2/networks/src/AFP.py +118 -0
  34. D4CMPP2/networks/src/BiDropout.py +29 -0
  35. D4CMPP2/networks/src/DMPNN.py +35 -0
  36. D4CMPP2/networks/src/GAT.py +69 -0
  37. D4CMPP2/networks/src/GC.py +85 -0
  38. D4CMPP2/networks/src/GCN.py +71 -0
  39. D4CMPP2/networks/src/ISAT.py +153 -0
  40. D4CMPP2/networks/src/Linear.py +49 -0
  41. D4CMPP2/networks/src/MPNN.py +56 -0
  42. D4CMPP2/networks/src/SolventLayer.py +62 -0
  43. D4CMPP2/networks/src/__init__.py +0 -0
  44. D4CMPP2/networks/src/distGCN.py +21 -0
  45. D4CMPP2/networks/src/pyg_hetero.py +24 -0
  46. D4CMPP2/optimize.py +472 -0
  47. D4CMPP2/src/Analyzer/ISAAnalyzer.py +458 -0
  48. D4CMPP2/src/Analyzer/ISAPNAnalyzer.py +366 -0
  49. D4CMPP2/src/Analyzer/ISAwSAnalyzer.py +117 -0
  50. D4CMPP2/src/Analyzer/MolAnalyzer.py +319 -0
  51. D4CMPP2/src/Analyzer/__init__.py +54 -0
  52. D4CMPP2/src/Analyzer/core.py +480 -0
  53. D4CMPP2/src/Analyzer/factory.py +166 -0
  54. D4CMPP2/src/Analyzer/interpretation.py +232 -0
  55. D4CMPP2/src/Analyzer/results.py +101 -0
  56. D4CMPP2/src/DataManager/Dataset/GraphDataset.py +314 -0
  57. D4CMPP2/src/DataManager/Dataset/ISAGraphDataset.py +384 -0
  58. D4CMPP2/src/DataManager/Dataset/__init__.py +0 -0
  59. D4CMPP2/src/DataManager/GraphGenerator/ISAGraphGenerator.py +223 -0
  60. D4CMPP2/src/DataManager/GraphGenerator/MolGraphGenerator.py +73 -0
  61. D4CMPP2/src/DataManager/GraphGenerator/__init__.py +14 -0
  62. D4CMPP2/src/DataManager/ISADataManager.py +67 -0
  63. D4CMPP2/src/DataManager/MolDataManager.py +735 -0
  64. D4CMPP2/src/DataManager/__init__.py +14 -0
  65. D4CMPP2/src/DataManager/contracts.py +179 -0
  66. D4CMPP2/src/NetworkManager/ISANetworkManager.py +12 -0
  67. D4CMPP2/src/NetworkManager/NetworkManager.py +520 -0
  68. D4CMPP2/src/NetworkManager/__init__.py +14 -0
  69. D4CMPP2/src/PostProcessor.py +160 -0
  70. D4CMPP2/src/TrainManager/ISATrainManager.py +26 -0
  71. D4CMPP2/src/TrainManager/TrainManager.py +254 -0
  72. D4CMPP2/src/TrainManager/__init__.py +14 -0
  73. D4CMPP2/src/TrainManager/callbacks.py +119 -0
  74. D4CMPP2/src/__init__.py +0 -0
  75. D4CMPP2/src/utils/PATH.py +246 -0
  76. D4CMPP2/src/utils/__init__.py +0 -0
  77. D4CMPP2/src/utils/argparser.py +56 -0
  78. D4CMPP2/src/utils/checkpointing.py +90 -0
  79. D4CMPP2/src/utils/config_resolution.py +123 -0
  80. D4CMPP2/src/utils/config_validation.py +370 -0
  81. D4CMPP2/src/utils/csv_validation.py +105 -0
  82. D4CMPP2/src/utils/data_quality.py +181 -0
  83. D4CMPP2/src/utils/featureizer.py +202 -0
  84. D4CMPP2/src/utils/functional_group.csv +169 -0
  85. D4CMPP2/src/utils/graph_cache.py +213 -0
  86. D4CMPP2/src/utils/leaderboard.py +212 -0
  87. D4CMPP2/src/utils/metrics.py +31 -0
  88. D4CMPP2/src/utils/module_loader.py +147 -0
  89. D4CMPP2/src/utils/output.py +80 -0
  90. D4CMPP2/src/utils/reproducibility.py +70 -0
  91. D4CMPP2/src/utils/run_manifest.py +175 -0
  92. D4CMPP2/src/utils/scaler.py +40 -0
  93. D4CMPP2/src/utils/sculptor.py +713 -0
  94. D4CMPP2/src/utils/splitting.py +250 -0
  95. D4CMPP2/src/utils/supportfile_saver.py +94 -0
  96. D4CMPP2/src/utils/tools.py +156 -0
  97. D4CMPP2/src/utils/transfer_learning.py +111 -0
  98. d4cmpp2-0.4.0.dist-info/METADATA +420 -0
  99. d4cmpp2-0.4.0.dist-info/RECORD +103 -0
  100. d4cmpp2-0.4.0.dist-info/WHEEL +5 -0
  101. d4cmpp2-0.4.0.dist-info/entry_points.txt +2 -0
  102. d4cmpp2-0.4.0.dist-info/licenses/LICENSE +21 -0
  103. d4cmpp2-0.4.0.dist-info/top_level.txt +1 -0
D4CMPP2/grid_search.py ADDED
@@ -0,0 +1,259 @@
1
+ """Compatibility-preserving exhaustive grid search."""
2
+
3
+ import copy
4
+ import csv
5
+ import itertools
6
+ import json
7
+ import os
8
+ import traceback
9
+ import uuid
10
+ from datetime import datetime, timezone
11
+ from pathlib import Path
12
+
13
+ from D4CMPP2._main import check_args, run, set_config
14
+ from D4CMPP2.src.utils import supportfile_saver
15
+ from D4CMPP2.src.utils.output import get_output
16
+
17
+
18
+ GRID_SUMMARY_SCHEMA_VERSION = 1
19
+
20
+
21
+ def grid_generator(param_grid):
22
+ if not isinstance(param_grid, dict) or not param_grid:
23
+ raise ValueError(
24
+ "hyperparameters must be a non-empty mapping of parameter names to "
25
+ "non-empty value sequences."
26
+ )
27
+ invalid = {
28
+ key: values
29
+ for key, values in param_grid.items()
30
+ if (
31
+ not isinstance(key, str)
32
+ or not key.strip()
33
+ or isinstance(values, (str, bytes))
34
+ or not isinstance(values, (list, tuple))
35
+ or not values
36
+ )
37
+ }
38
+ if invalid:
39
+ raise ValueError(
40
+ "Each hyperparameter key must be a non-empty string and each value "
41
+ f"must be a non-empty list or tuple; invalid entries: {invalid!r}."
42
+ )
43
+ keys, values = zip(*param_grid.items())
44
+ for combination in itertools.product(*values):
45
+ yield dict(zip(keys, combination))
46
+
47
+
48
+ config0 = {
49
+ "data": None,
50
+ "target": [],
51
+ "network": None,
52
+ "scaler": "standard",
53
+ "optimizer": "Adam",
54
+ "max_epoch": 2000,
55
+ "batch_size": 256,
56
+ "learning_rate": 0.001,
57
+ "weight_decay": 0.0005,
58
+ "lr_patience": 40,
59
+ "early_stopping_patience": 100,
60
+ "device": "cuda:0",
61
+ "pin_memory": False,
62
+ }
63
+
64
+
65
+ def _grid_suffix(parameters):
66
+ return "".join(f"_{key},{value}" for key, value in parameters.items())
67
+
68
+
69
+ def _unique_trial_path(base_path, parameters, trial_number, used_paths):
70
+ candidate = f"{base_path}{_grid_suffix(parameters)}"
71
+ normalized = os.path.normcase(os.path.abspath(candidate))
72
+ if normalized not in used_paths and not os.path.exists(candidate):
73
+ used_paths.add(normalized)
74
+ return candidate
75
+
76
+ candidate = f"{candidate}__trial_{trial_number:04d}"
77
+ normalized = os.path.normcase(os.path.abspath(candidate))
78
+ suffix = 1
79
+ while normalized in used_paths or os.path.exists(candidate):
80
+ candidate = (
81
+ f"{base_path}{_grid_suffix(parameters)}"
82
+ f"__trial_{trial_number:04d}_{suffix}"
83
+ )
84
+ normalized = os.path.normcase(os.path.abspath(candidate))
85
+ suffix += 1
86
+ used_paths.add(normalized)
87
+ return candidate
88
+
89
+
90
+ def _atomic_json(path, value):
91
+ staging = path.with_name(f".{path.name}.{uuid.uuid4().hex}.tmp")
92
+ try:
93
+ staging.write_text(
94
+ json.dumps(value, indent=2, sort_keys=True, default=repr),
95
+ encoding="utf-8",
96
+ )
97
+ os.replace(staging, path)
98
+ finally:
99
+ if staging.exists():
100
+ staging.unlink()
101
+
102
+
103
+ def _write_summary(summary, base_path):
104
+ base = Path(base_path)
105
+ json_path = base.parent / f"{base.name}_grid_search.json"
106
+ csv_path = base.parent / f"{base.name}_grid_search.csv"
107
+ json_path.parent.mkdir(parents=True, exist_ok=True)
108
+ summary["summary_json"] = str(json_path)
109
+ summary["summary_csv"] = str(csv_path)
110
+ _atomic_json(json_path, summary)
111
+
112
+ fieldnames = [
113
+ "trial",
114
+ "status",
115
+ "model_path",
116
+ "parameters",
117
+ "started_at",
118
+ "ended_at",
119
+ "duration_seconds",
120
+ "error_type",
121
+ "error_message",
122
+ ]
123
+ staging = csv_path.with_name(f".{csv_path.name}.{uuid.uuid4().hex}.tmp")
124
+ try:
125
+ with open(staging, "w", encoding="utf-8", newline="") as stream:
126
+ writer = csv.DictWriter(stream, fieldnames=fieldnames)
127
+ writer.writeheader()
128
+ for trial in summary["trials"]:
129
+ row = {key: trial.get(key) for key in fieldnames}
130
+ row["parameters"] = json.dumps(
131
+ trial["parameters"], sort_keys=True, default=repr
132
+ )
133
+ writer.writerow(row)
134
+ os.replace(staging, csv_path)
135
+ finally:
136
+ if staging.exists():
137
+ staging.unlink()
138
+ return str(json_path), str(csv_path)
139
+
140
+
141
+ def grid_search(hyperparameters, **kwargs):
142
+ """Run every parameter combination and write a JSON/CSV status summary.
143
+
144
+ The historical return value remains ``None``. Hyperparameter values override
145
+ both base arguments and registry defaults for each isolated trial.
146
+ """
147
+ combinations = list(grid_generator(copy.deepcopy(hyperparameters)))
148
+ base_kwargs = copy.deepcopy(config0)
149
+ base_kwargs.update(copy.deepcopy(kwargs))
150
+ base_config = set_config(**check_args(**base_kwargs))
151
+ output = get_output(base_config)
152
+ base_model_path = base_config["MODEL_PATH"]
153
+ started = datetime.now(timezone.utc)
154
+ summary = {
155
+ "grid_summary_schema_version": GRID_SUMMARY_SCHEMA_VERSION,
156
+ "status": "running",
157
+ "started_at": started.isoformat(),
158
+ "base_model_path": base_model_path,
159
+ "hyperparameters": copy.deepcopy(hyperparameters),
160
+ "trial_count": len(combinations),
161
+ "completed_count": 0,
162
+ "failed_count": 0,
163
+ "interrupted_count": 0,
164
+ "trials": [],
165
+ }
166
+ used_paths = set()
167
+ interrupted_at = None
168
+
169
+ for trial_number, parameters in enumerate(combinations, start=1):
170
+ trial_started = datetime.now(timezone.utc)
171
+ trial_config = copy.deepcopy(base_config)
172
+ trial_config.update(copy.deepcopy(parameters))
173
+ trial_path = _unique_trial_path(
174
+ base_model_path, parameters, trial_number, used_paths
175
+ )
176
+ trial_config["MODEL_PATH"] = trial_path
177
+ trial = {
178
+ "trial": trial_number,
179
+ "status": "running",
180
+ "parameters": copy.deepcopy(parameters),
181
+ "model_path": trial_path,
182
+ "started_at": trial_started.isoformat(),
183
+ }
184
+ summary["trials"].append(trial)
185
+ _write_summary(summary, base_model_path)
186
+ try:
187
+ Path(trial_path).mkdir(parents=True, exist_ok=False)
188
+ supportfile_saver.save_additional_files(trial_config)
189
+ result_path = run(trial_config)
190
+ trial["status"] = "completed"
191
+ trial["result_path"] = result_path
192
+ summary["completed_count"] += 1
193
+ except KeyboardInterrupt:
194
+ trial["status"] = "interrupted"
195
+ summary["interrupted_count"] += 1
196
+ interrupted_at = trial_number
197
+ output.error(
198
+ f"[Grid Search] Interrupted during trial {trial_number}."
199
+ )
200
+ break
201
+ except Exception as exc:
202
+ trial["status"] = "failed"
203
+ trial["error_type"] = type(exc).__name__
204
+ trial["error_message"] = str(exc)[:2000]
205
+ trial["traceback"] = traceback.format_exc()[-8000:]
206
+ summary["failed_count"] += 1
207
+ output.error(
208
+ f"[Grid Search] Trial {trial_number} failed:\n"
209
+ f"{trial['traceback']}"
210
+ )
211
+ finally:
212
+ ended = datetime.now(timezone.utc)
213
+ trial["ended_at"] = ended.isoformat()
214
+ trial["duration_seconds"] = (
215
+ ended - trial_started
216
+ ).total_seconds()
217
+ _write_summary(summary, base_model_path)
218
+
219
+ if interrupted_at is not None:
220
+ for trial_number, parameters in enumerate(
221
+ combinations[interrupted_at:], start=interrupted_at + 1
222
+ ):
223
+ summary["trials"].append(
224
+ {
225
+ "trial": trial_number,
226
+ "status": "not_started",
227
+ "parameters": copy.deepcopy(parameters),
228
+ "model_path": None,
229
+ "error_type": None,
230
+ "error_message": "Grid search was interrupted before this trial started.",
231
+ }
232
+ )
233
+
234
+ ended = datetime.now(timezone.utc)
235
+ if summary["interrupted_count"]:
236
+ summary["status"] = "interrupted"
237
+ elif summary["failed_count"]:
238
+ summary["status"] = (
239
+ "failed" if summary["completed_count"] == 0 else "completed_with_failures"
240
+ )
241
+ else:
242
+ summary["status"] = "completed"
243
+ summary["ended_at"] = ended.isoformat()
244
+ summary["duration_seconds"] = (ended - started).total_seconds()
245
+ json_path, csv_path = _write_summary(summary, base_model_path)
246
+ output.always(
247
+ "[Grid Search] Run complete: "
248
+ f"completed={summary['completed_count']}, "
249
+ f"failed={summary['failed_count']}, "
250
+ f"interrupted={summary['interrupted_count']}. "
251
+ f"JSON: {json_path!r}; CSV: {csv_path!r}."
252
+ )
253
+ return None
254
+
255
+
256
+ if __name__ == "__main__":
257
+ raise SystemExit(
258
+ "Call grid_search(hyperparameters, **training_kwargs) from Python or D4CMPP2."
259
+ )
@@ -0,0 +1,160 @@
1
+
2
+ GCN:
3
+ name: "GCN1"
4
+ network: GCN_model
5
+ data_manager_module: MolDataManager
6
+ data_manager_class: MolDataManager
7
+ network_manager_module: NetworkManager
8
+ network_manager_class: NetworkManager
9
+ train_manager_module: TrainManager
10
+ train_manager_class: Trainer
11
+ description: "GCN"
12
+ version: "2.0"
13
+
14
+ GCNwS:
15
+ name: "GCN1withSolvent"
16
+ network: GCNwithSolv_model
17
+ data_manager_module: MolDataManager
18
+ data_manager_class: MolDataManager_withSolv
19
+ network_manager_module: NetworkManager
20
+ network_manager_class: NetworkManager
21
+ train_manager_module: TrainManager
22
+ train_manager_class: Trainer
23
+ description: "GCN"
24
+ version: "2.0"
25
+
26
+ MPNN:
27
+ name: "MPNN1"
28
+ network: MPNN_model
29
+ data_manager_module: MolDataManager
30
+ data_manager_class: MolDataManager
31
+ network_manager_module: NetworkManager
32
+ network_manager_class: NetworkManager
33
+ train_manager_module: TrainManager
34
+ train_manager_class: Trainer
35
+ description: "MPNN"
36
+ version: "2.0"
37
+
38
+ MPNNwS:
39
+ name: "MPNN1withSolvent"
40
+ network: MPNNwithSolv_model
41
+ data_manager_module: MolDataManager
42
+ data_manager_class: MolDataManager_withSolv
43
+ network_manager_module: NetworkManager
44
+ network_manager_class: NetworkManager
45
+ train_manager_module: TrainManager
46
+ train_manager_class: Trainer
47
+ description: "MPNN"
48
+ version: "2.0"
49
+
50
+ DMPNN:
51
+ name: "DMPNN1"
52
+ network: DMPNN_model
53
+ data_manager_module: MolDataManager
54
+ data_manager_class: MolDataManager
55
+ network_manager_module: NetworkManager
56
+ network_manager_class: NetworkManager
57
+ train_manager_module: TrainManager
58
+ train_manager_class: Trainer
59
+ description: "DMPNN"
60
+ version: "2.0"
61
+
62
+ DMPNNwS:
63
+ name: "DMPNN1withSolvent"
64
+ network: DMPNNwithSolv_model
65
+ data_manager_module: MolDataManager
66
+ data_manager_class: MolDataManager_withSolv
67
+ network_manager_module: NetworkManager
68
+ network_manager_class: NetworkManager
69
+ train_manager_module: TrainManager
70
+ train_manager_class: Trainer
71
+ description: "DMPNN"
72
+ version: "2.0"
73
+
74
+
75
+
76
+ AFP:
77
+ name: "AFP1"
78
+ network: AFP_model
79
+ data_manager_module: MolDataManager
80
+ data_manager_class: MolDataManager
81
+ network_manager_module: NetworkManager
82
+ network_manager_class: NetworkManager
83
+ train_manager_module: TrainManager
84
+ train_manager_class: Trainer
85
+ description: "AFP"
86
+ version: "2.0"
87
+
88
+ AFPwS:
89
+ name: "AFP1"
90
+ network: AFPwithSolv_model
91
+ data_manager_module: MolDataManager
92
+ data_manager_class: MolDataManager_withSolv
93
+ network_manager_module: NetworkManager
94
+ network_manager_class: NetworkManager
95
+ train_manager_module: TrainManager
96
+ train_manager_class: Trainer
97
+ description: "AFP"
98
+ version: "2.0"
99
+
100
+ GAT:
101
+ name: "GAT1"
102
+ network: GAT_model
103
+ data_manager_module: MolDataManager
104
+ data_manager_class: MolDataManager
105
+ network_manager_module: NetworkManager
106
+ network_manager_class: NetworkManager
107
+ train_manager_module: TrainManager
108
+ train_manager_class: Trainer
109
+ description: "GAT"
110
+ version: "2.0"
111
+
112
+ GATwS:
113
+ name: "GAT1withSolvent"
114
+ network: GATwithSolv_model
115
+ data_manager_module: MolDataManager
116
+ data_manager_class: MolDataManager_withSolv
117
+ network_manager_module: NetworkManager
118
+ network_manager_class: NetworkManager
119
+ train_manager_module: TrainManager
120
+ train_manager_class: Trainer
121
+ description: "GAT"
122
+ version: "2.0"
123
+
124
+
125
+ ISAT:
126
+ name: "ISAT1"
127
+ network: ISAT_model
128
+ data_manager_module: ISADataManager
129
+ data_manager_class: ISADataManager
130
+ network_manager_module: ISANetworkManager
131
+ network_manager_class: ISANetworkManager
132
+ train_manager_module: ISATrainManager
133
+ train_manager_class: ISATrainer
134
+ description: "IGS"
135
+ version: "2.0"
136
+
137
+
138
+ ISATPN:
139
+ name: "ISATPN"
140
+ network: ISATPN_model
141
+ data_manager_module: ISADataManager
142
+ data_manager_class: ISADataManager
143
+ network_manager_module: ISANetworkManager
144
+ network_manager_class: ISANetworkManager
145
+ train_manager_module: ISATrainManager
146
+ train_manager_class: ISATrainer
147
+ description: "ISATPN"
148
+ version: "2.0"
149
+
150
+ GC:
151
+ name: "GC1"
152
+ network: GC_model
153
+ data_manager_module: ISADataManager
154
+ data_manager_class: ISADataManager
155
+ network_manager_module: NetworkManager
156
+ network_manager_class: NetworkManager
157
+ train_manager_module: ISATrainManager
158
+ train_manager_class: ISATrainer
159
+ description: "GC"
160
+ version: "2.0"
@@ -0,0 +1,72 @@
1
+ import torch.nn as nn
2
+
3
+ from D4CMPP2.networks.base import (
4
+ InputContract,
5
+ MolecularNetwork,
6
+ STANDARD_GRAPH_HYPERPARAMETERS,
7
+ STANDARD_GRAPH_OPTIMIZATION_SPACE,
8
+ )
9
+ from D4CMPP2.networks.src.AFP import AttentiveFP
10
+ from D4CMPP2.networks.src.Linear import Linears
11
+
12
+
13
+ class AFP(MolecularNetwork):
14
+ """Attentive fingerprint network with optional atom-attention output."""
15
+
16
+ model_name = "afp"
17
+ required_config = ("node_dim", "edge_dim", "target_dim")
18
+ input_contract = InputContract(
19
+ required=(
20
+ "compound_graphs",
21
+ "compound_node_feature",
22
+ "compound_edge_feature",
23
+ ),
24
+ optional=("get_score",),
25
+ )
26
+ hyperparameters = STANDARD_GRAPH_HYPERPARAMETERS
27
+ default_optimization_space = STANDARD_GRAPH_OPTIMIZATION_SPACE
28
+
29
+ def __init__(self, config):
30
+ super().__init__(config)
31
+
32
+ linear_layers = self.config["linear_layers"]
33
+ dropout = self.config["dropout"]
34
+ hidden_dim = self.config["hidden_dim"]
35
+
36
+ self.embedding_node_lin = nn.Linear(self.config["node_dim"], hidden_dim, bias=True)
37
+ self.embedding_edge_lin = nn.Linear(self.config["edge_dim"], hidden_dim, bias=True)
38
+
39
+ self.AttentiveFP = AttentiveFP(self.config)
40
+ self.Linears = Linears(hidden_dim,self.config["target_dim"], nn.ReLU(), linear_layers, dropout, False, False, True)
41
+
42
+
43
+ def forward(self, **kwargs):
44
+ graph = kwargs.get('compound_graphs', kwargs.get('graph'))
45
+ node_feats = kwargs.get('compound_node_feature', kwargs.get('node_feats'))
46
+ edge_feats = kwargs.get('compound_edge_feature', kwargs.get('edge_feats'))
47
+ missing = [
48
+ name
49
+ for name, value in {
50
+ "compound_graphs": graph,
51
+ "compound_node_feature": node_feats,
52
+ "compound_edge_feature": edge_feats,
53
+ }.items()
54
+ if value is None
55
+ ]
56
+ if missing:
57
+ raise ValueError(f"AFP input is missing required fields {missing!r}.")
58
+
59
+ node = self.embedding_node_lin(node_feats)
60
+ edge = self.embedding_edge_lin(edge_feats)
61
+
62
+ super_node, att_w = self.AttentiveFP(graph, node, edge)
63
+
64
+ output = self.Linears(super_node)
65
+
66
+ if kwargs.get('get_score',False):
67
+ return {'prediction':output, 'positive':att_w}
68
+
69
+ return output
70
+
71
+
72
+ network = AFP
@@ -0,0 +1,72 @@
1
+ import torch.nn as nn
2
+
3
+ from D4CMPP2.networks.base import (
4
+ InputContract,
5
+ MolecularNetwork,
6
+ STANDARD_SOLVENT_HYPERPARAMETERS,
7
+ STANDARD_SOLVENT_OPTIMIZATION_SPACE,
8
+ )
9
+ from D4CMPP2.networks.src.AFP import AttentiveFP
10
+ from D4CMPP2.networks.src.SolventLayer import SolventLayer
11
+
12
+ class SolventAFP(MolecularNetwork):
13
+ """Attentive fingerprint compound encoder with a solvent branch."""
14
+
15
+ model_name = "afp_solvent"
16
+ required_config = ("node_dim", "edge_dim", "target_dim")
17
+ input_contract = InputContract(
18
+ required=(
19
+ "compound_graphs",
20
+ "compound_node_feature",
21
+ "compound_edge_feature",
22
+ "solvent_graphs",
23
+ "solvent_node_feature",
24
+ )
25
+ )
26
+ hyperparameters = STANDARD_SOLVENT_HYPERPARAMETERS
27
+ default_optimization_space = STANDARD_SOLVENT_OPTIMIZATION_SPACE
28
+
29
+ def __init__(self, config):
30
+ super().__init__(config)
31
+
32
+ hidden_dim = self.config["hidden_dim"]
33
+
34
+ self.embedding_node_lin = nn.Linear(self.config["node_dim"], hidden_dim, bias=True)
35
+ self.embedding_edge_lin = nn.Linear(self.config["edge_dim"], hidden_dim, bias=True)
36
+
37
+ self.AttentiveFP = AttentiveFP(self.config)
38
+ self.Linears = SolventLayer(self.config)
39
+
40
+
41
+ def forward(self, **kwargs):
42
+ graph = kwargs.get('compound_graphs', kwargs.get('graph'))
43
+ node_feats = kwargs.get('compound_node_feature', kwargs.get('node_feats'))
44
+ edge_feats = kwargs.get('compound_edge_feature', kwargs.get('edge_feats'))
45
+ solv_graph = kwargs.get('solvent_graphs', kwargs.get('solv_graph'))
46
+ solv_node_feats = kwargs.get('solvent_node_feature', kwargs.get('solv_node_feats'))
47
+ missing = [
48
+ name
49
+ for name, value in {
50
+ "compound_graphs": graph,
51
+ "compound_node_feature": node_feats,
52
+ "compound_edge_feature": edge_feats,
53
+ "solvent_graphs": solv_graph,
54
+ "solvent_node_feature": solv_node_feats,
55
+ }.items()
56
+ if value is None
57
+ ]
58
+ if missing:
59
+ raise ValueError(
60
+ f"SolventAFP input is missing required fields {missing!r}."
61
+ )
62
+
63
+ node = self.embedding_node_lin(node_feats)
64
+ edge = self.embedding_edge_lin(edge_feats)
65
+
66
+ super_node, att_w = self.AttentiveFP(graph, node, edge)
67
+
68
+ output = self.Linears(super_node, solv_graph, solv_node_feats)
69
+ return output
70
+
71
+
72
+ network = SolventAFP
@@ -0,0 +1,90 @@
1
+ import torch
2
+ import torch.nn as nn
3
+
4
+ from D4CMPP2.networks.base import (
5
+ InputContract,
6
+ MolecularNetwork,
7
+ STANDARD_GRAPH_HYPERPARAMETERS,
8
+ STANDARD_GRAPH_OPTIMIZATION_SPACE,
9
+ )
10
+ from D4CMPP2.networks.src.Linear import Linears
11
+ from D4CMPP2.networks.src.DMPNN import DMPNNLayer
12
+ from D4CMPP2.networks.src.GCN import graph_sum_pool
13
+
14
+
15
+ class DMPNN(MolecularNetwork):
16
+ """Directed-edge message-passing network."""
17
+
18
+ model_name = "dmpnn"
19
+ required_config = ("node_dim", "edge_dim", "target_dim")
20
+ input_contract = InputContract(
21
+ required=(
22
+ "compound_graphs",
23
+ "compound_node_feature",
24
+ "compound_edge_feature",
25
+ )
26
+ )
27
+ hyperparameters = STANDARD_GRAPH_HYPERPARAMETERS
28
+ default_optimization_space = STANDARD_GRAPH_OPTIMIZATION_SPACE
29
+
30
+ def __init__(self, config):
31
+ super().__init__(config)
32
+ hidden_dim = self.config["hidden_dim"]
33
+ conv_layers = self.config["conv_layers"]
34
+ dropout = self.config["dropout"]
35
+ linear_layers = self.config["linear_layers"]
36
+ target_dim = self.config["target_dim"]
37
+
38
+ self.embedding_node_lin = nn.Linear(self.config["node_dim"], hidden_dim, bias=True)
39
+ self.embedding_edge_lin = nn.Linear(self.config["edge_dim"], hidden_dim, bias=True)
40
+ self.init_h_func = nn.Sequential(
41
+ nn.Linear(2 * hidden_dim, hidden_dim, bias=True),
42
+ nn.LeakyReLU()
43
+ )
44
+ self.W_a = nn.Sequential(
45
+ nn.Linear(2 * hidden_dim, hidden_dim, bias=True),
46
+ nn.LeakyReLU()
47
+ )
48
+ self.dropout_layer = nn.Dropout(dropout)
49
+ self.DMPNNLayer = nn.ModuleList([DMPNNLayer(hidden_dim,hidden_dim,hidden_dim,nn.LeakyReLU(),dropout) for _ in range(conv_layers)])
50
+ self.Linears = Linears(hidden_dim, target_dim, nn.LeakyReLU(), linear_layers, dropout, last = True)
51
+
52
+ def send_income_edge(self, edges):
53
+ return {'mail': edges.data['feat']}
54
+
55
+ def sum_income_edge(self, nodes):
56
+ hidden_feats = self.W_a(torch.cat([nodes.data['feat'], torch.sum(nodes.mailbox['mail'], 1)], dim=-1))
57
+ hidden_feats = self.dropout_layer(hidden_feats)
58
+ return {'hidden_feats': hidden_feats}
59
+
60
+ def forward(self, **kwargs):
61
+ graph = kwargs.get('compound_graphs', kwargs.get('graph'))
62
+ node_feats = kwargs.get('compound_node_feature', kwargs.get('node_feats'))
63
+ edge_feats = kwargs.get('compound_edge_feature', kwargs.get('edge_feats'))
64
+ missing = [
65
+ name
66
+ for name, value in {
67
+ "compound_graphs": graph,
68
+ "compound_node_feature": node_feats,
69
+ "compound_edge_feature": edge_feats,
70
+ }.items()
71
+ if value is None
72
+ ]
73
+ if missing:
74
+ raise ValueError(f"DMPNN input is missing required fields {missing!r}.")
75
+
76
+ node = self.embedding_node_lin(node_feats)
77
+ edge = self.embedding_edge_lin(edge_feats)
78
+
79
+ direct_feats = None
80
+ backward_feats = None
81
+ for layer in self.DMPNNLayer:
82
+ hidden_feats, direct_feats, backward_feats = layer(graph, node, edge, direct_feats, backward_feats)
83
+
84
+ graph_feats = graph_sum_pool(graph, hidden_feats)
85
+ output = self.Linears(graph_feats)
86
+ return output
87
+
88
+ network = DMPNN
89
+
90
+