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
@@ -0,0 +1,89 @@
1
+
2
+ import torch.nn as nn
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.GCN import graph_sum_pool
10
+
11
+ from D4CMPP2.networks.src.SolventLayer import SolventLayer
12
+ from D4CMPP2.networks.src.DMPNN import DMPNNLayer
13
+
14
+
15
+ class SolventDMPNN(MolecularNetwork):
16
+ """Directed-edge compound encoder coupled to a solvent graph branch."""
17
+
18
+ model_name = "dmpnn_solvent"
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
+ "solvent_graphs",
26
+ "solvent_node_feature",
27
+ )
28
+ )
29
+ hyperparameters = STANDARD_SOLVENT_HYPERPARAMETERS
30
+ default_optimization_space = STANDARD_SOLVENT_OPTIMIZATION_SPACE
31
+
32
+ def __init__(self, config):
33
+ super().__init__(config)
34
+ hidden_dim = self.config["hidden_dim"]
35
+ conv_layers = self.config["conv_layers"]
36
+ dropout = self.config["dropout"]
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.SolvLayer = SolventLayer(self.config)
51
+
52
+
53
+ def forward(self, **kwargs):
54
+ graph = kwargs.get('compound_graphs', kwargs.get('graph'))
55
+ node_feats = kwargs.get('compound_node_feature', kwargs.get('node_feats'))
56
+ edge_feats = kwargs.get('compound_edge_feature', kwargs.get('edge_feats'))
57
+ solv_graph = kwargs.get('solvent_graphs', kwargs.get('solv_graph'))
58
+ solv_node_feats = kwargs.get('solvent_node_feature', kwargs.get('solv_node_feats'))
59
+ missing = [
60
+ name
61
+ for name, value in {
62
+ "compound_graphs": graph,
63
+ "compound_node_feature": node_feats,
64
+ "compound_edge_feature": edge_feats,
65
+ "solvent_graphs": solv_graph,
66
+ "solvent_node_feature": solv_node_feats,
67
+ }.items()
68
+ if value is None
69
+ ]
70
+ if missing:
71
+ raise ValueError(
72
+ f"SolventDMPNN input is missing required fields {missing!r}."
73
+ )
74
+
75
+ node = self.embedding_node_lin(node_feats)
76
+ edge = self.embedding_edge_lin(edge_feats)
77
+
78
+ direct_feats = None
79
+ backward_feats = None
80
+ for layer in self.DMPNNLayer:
81
+ hidden_feats, direct_feats, backward_feats = layer(graph, node, edge, direct_feats, backward_feats)
82
+
83
+ graph_feats = graph_sum_pool(graph, hidden_feats)
84
+ output = self.SolvLayer(graph_feats, solv_graph, solv_node_feats)
85
+ return output
86
+
87
+ network = SolventDMPNN
88
+
89
+
@@ -0,0 +1,48 @@
1
+ import torch.nn as nn
2
+ from D4CMPP2.networks.base import (
3
+ InputContract,
4
+ MolecularNetwork,
5
+ STANDARD_GRAPH_HYPERPARAMETERS,
6
+ STANDARD_GRAPH_OPTIMIZATION_SPACE,
7
+ )
8
+ from D4CMPP2.networks.src.GAT import GATs
9
+ from D4CMPP2.networks.src.GCN import graph_sum_pool
10
+ from D4CMPP2.networks.src.Linear import Linears
11
+
12
+ class GAT(MolecularNetwork):
13
+ """Graph-attention network with graph-sum readout."""
14
+
15
+ model_name = "gat"
16
+ input_contract = InputContract(
17
+ required=("compound_graphs", "compound_node_feature")
18
+ )
19
+ hyperparameters = STANDARD_GRAPH_HYPERPARAMETERS
20
+ default_optimization_space = STANDARD_GRAPH_OPTIMIZATION_SPACE
21
+
22
+ def __init__(self, config):
23
+ super().__init__(config)
24
+
25
+ hidden_dim = self.config["hidden_dim"]
26
+ gcn_layers = self.config["conv_layers"]
27
+ dropout = self.config["dropout"]
28
+ linear_layers = self.config["linear_layers"]
29
+ target_dim = self.config["target_dim"]
30
+
31
+
32
+ self.node_embedding = nn.Linear(self.config["node_dim"], hidden_dim)
33
+
34
+ self.GATs = GATs(hidden_dim, hidden_dim, hidden_dim, nn.ReLU(), gcn_layers, dropout, False, True) # in_feats, hidden_feats, out_feats, activation, n_layers, dropout=0.2, batch_norm=False, residual_sum = False):
35
+ self.Linears = Linears(hidden_dim,target_dim, nn.ReLU(), linear_layers, dropout, False, False, True) # in_feats, out_feats, activation, n_layers, dropout=0.2, batch_norm=False, residual_sum = False):
36
+
37
+ def forward(self, **kwargs):
38
+ self.validate_input(kwargs)
39
+ graph = kwargs["compound_graphs"]
40
+ node_feats = kwargs["compound_node_feature"]
41
+
42
+ h = self.node_embedding(node_feats)
43
+ h = self.GATs(graph, h)
44
+ h = graph_sum_pool(graph, h)
45
+ h = self.Linears(h)
46
+ return h
47
+
48
+ network = GAT
@@ -0,0 +1,63 @@
1
+ import torch.nn as nn
2
+ from D4CMPP2.networks.base import (
3
+ InputContract,
4
+ MolecularNetwork,
5
+ STANDARD_SOLVENT_HYPERPARAMETERS,
6
+ STANDARD_SOLVENT_OPTIMIZATION_SPACE,
7
+ )
8
+ from D4CMPP2.networks.src.GAT import GATs
9
+ from D4CMPP2.networks.src.GCN import graph_sum_pool
10
+ from D4CMPP2.networks.src.SolventLayer import SolventLayer
11
+
12
+ class SolventGAT(MolecularNetwork):
13
+ """Graph-attention compound encoder coupled to a solvent branch."""
14
+
15
+ model_name = "gat_solvent"
16
+ input_contract = InputContract(
17
+ required=(
18
+ "compound_graphs",
19
+ "compound_node_feature",
20
+ "solvent_graphs",
21
+ "solvent_node_feature",
22
+ )
23
+ )
24
+ hyperparameters = STANDARD_SOLVENT_HYPERPARAMETERS
25
+ default_optimization_space = STANDARD_SOLVENT_OPTIMIZATION_SPACE
26
+
27
+ def __init__(self, config):
28
+ super().__init__(config)
29
+
30
+ hidden_dim = self.config["hidden_dim"]
31
+ gcn_layers = self.config["conv_layers"]
32
+ dropout = self.config["dropout"]
33
+
34
+
35
+ self.node_embedding = nn.Linear(self.config["node_dim"], hidden_dim)
36
+
37
+ self.GATs = GATs(hidden_dim, hidden_dim, hidden_dim, nn.ReLU(), gcn_layers, dropout, False, True)
38
+ self.SolventLayer = SolventLayer(self.config)
39
+
40
+ def forward(self, **kwargs):
41
+ graph = kwargs.get('compound_graphs', kwargs.get('graph'))
42
+ node_feats = kwargs.get('compound_node_feature', kwargs.get('node_feats'))
43
+ solv_graph = kwargs.get('solvent_graphs', kwargs.get('solv_graph'))
44
+ solv_node_feats = kwargs.get('solvent_node_feature', kwargs.get('solv_node_feats'))
45
+ values = {
46
+ "compound_graphs": graph,
47
+ "compound_node_feature": node_feats,
48
+ "solvent_graphs": solv_graph,
49
+ "solvent_node_feature": solv_node_feats,
50
+ }
51
+ missing = [name for name, value in values.items() if value is None]
52
+ if missing:
53
+ raise ValueError(
54
+ f"SolventGAT input is missing required fields {missing!r}."
55
+ )
56
+
57
+ h = self.node_embedding(node_feats)
58
+ h = self.GATs(graph, h)
59
+ h = graph_sum_pool(graph, h)
60
+ h = self.SolventLayer(h,solv_graph,solv_node_feats)
61
+ return h
62
+
63
+ network = SolventGAT
@@ -0,0 +1,113 @@
1
+ import torch.nn as nn
2
+
3
+ from D4CMPP2.networks.base import (
4
+ Hyperparameter,
5
+ InputContract,
6
+ MolecularNetwork,
7
+ )
8
+ from D4CMPP2.networks.src.GCN import GCNs, graph_sum_pool
9
+ from D4CMPP2.networks.src.Linear import Linears
10
+
11
+
12
+ class GCN(MolecularNetwork):
13
+ """Graph convolution using transformed self-plus-neighbor sums."""
14
+
15
+ model_name = "gcn"
16
+ input_contract = InputContract(
17
+ required=("compound_graphs", "compound_node_feature"),
18
+ )
19
+ hyperparameters = {
20
+ "hidden_dim": Hyperparameter(
21
+ "int",
22
+ default=64,
23
+ low=1,
24
+ search_low=16,
25
+ search_high=256,
26
+ step=16,
27
+ grid=(32, 64, 128, 256),
28
+ description="Hidden node and graph representation width.",
29
+ ),
30
+ "conv_layers": Hyperparameter(
31
+ "int",
32
+ default=4,
33
+ low=1,
34
+ search_low=1,
35
+ search_high=8,
36
+ step=1,
37
+ grid=(2, 4, 6, 8),
38
+ description="Number of graph convolution layers.",
39
+ ),
40
+ "linear_layers": Hyperparameter(
41
+ "int",
42
+ default=2,
43
+ low=1,
44
+ search_low=1,
45
+ search_high=5,
46
+ step=1,
47
+ grid=(1, 2, 3, 4),
48
+ description="Number of prediction-head linear layers.",
49
+ ),
50
+ "dropout": Hyperparameter(
51
+ "float",
52
+ default=0.2,
53
+ low=0.0,
54
+ high=0.5,
55
+ search_low=0.0,
56
+ search_high=0.5,
57
+ grid=(0.0, 0.1, 0.2, 0.3, 0.5),
58
+ description="Dropout probability.",
59
+ ),
60
+ }
61
+ default_optimization_space = (
62
+ "hidden_dim",
63
+ "conv_layers",
64
+ "linear_layers",
65
+ "dropout",
66
+ )
67
+
68
+ def __init__(self, config):
69
+ super().__init__(config)
70
+ hidden_dim = self.config["hidden_dim"]
71
+ self.node_embedding = nn.Linear(self.config["node_dim"], hidden_dim)
72
+ # Keep the established module registration names so saved state dictionaries
73
+ # remain readable while the public class/config contract is redesigned.
74
+ self.GCNs = GCNs(
75
+ hidden_dim,
76
+ hidden_dim,
77
+ hidden_dim,
78
+ nn.ReLU(),
79
+ self.config["conv_layers"],
80
+ self.config["dropout"],
81
+ False,
82
+ True,
83
+ )
84
+ self.Linears = Linears(
85
+ hidden_dim,
86
+ self.config["target_dim"],
87
+ nn.ReLU(),
88
+ self.config["linear_layers"],
89
+ self.config["dropout"],
90
+ False,
91
+ False,
92
+ True,
93
+ )
94
+
95
+ @property
96
+ def convolutions(self):
97
+ return self.GCNs
98
+
99
+ @property
100
+ def prediction_head(self):
101
+ return self.Linears
102
+
103
+ def forward(self, **batch):
104
+ self.validate_input(batch)
105
+ graph = batch["compound_graphs"]
106
+ node = self.node_embedding(batch["compound_node_feature"])
107
+ node = self.GCNs(graph, node)
108
+ graph_feature = graph_sum_pool(graph, node)
109
+ return self.Linears(graph_feature)
110
+
111
+
112
+ # Staged bridge for code paths not yet migrated to the typed registry.
113
+ network = GCN
@@ -0,0 +1,103 @@
1
+ import torch.nn as nn
2
+ import torch
3
+ from D4CMPP2.networks.base import (
4
+ Hyperparameter,
5
+ InputContract,
6
+ MolecularNetwork,
7
+ STANDARD_SOLVENT_HYPERPARAMETERS,
8
+ STANDARD_SOLVENT_OPTIMIZATION_SPACE,
9
+ )
10
+ from D4CMPP2.networks.src.GCN import GCNs, graph_sum_pool
11
+ from D4CMPP2.networks.src.Linear import Linears
12
+
13
+ class SolventGCN(MolecularNetwork):
14
+ """Two-branch GCN for compound-solvent property prediction."""
15
+
16
+ model_name = "gcn_solvent"
17
+ input_contract = InputContract(
18
+ required=(
19
+ "compound_graphs",
20
+ "compound_node_feature",
21
+ "solvent_graphs",
22
+ "solvent_node_feature",
23
+ )
24
+ )
25
+ hyperparameters = {
26
+ **STANDARD_SOLVENT_HYPERPARAMETERS,
27
+ "fusion_dim": Hyperparameter(
28
+ "int", default=16, low=1, search_low=8, search_high=128,
29
+ step=8, grid=(16, 32, 64),
30
+ description="Width of the fused compound-solvent representation.",
31
+ ),
32
+ }
33
+ default_optimization_space = (
34
+ *STANDARD_SOLVENT_OPTIMIZATION_SPACE,
35
+ "fusion_dim",
36
+ )
37
+
38
+ def __init__(self, config):
39
+ super().__init__(config)
40
+
41
+ hidden_dim = self.config["hidden_dim"]
42
+ conv_layers = self.config["conv_layers"]
43
+ linear_layers = self.config["linear_layers"]
44
+ dropout = self.config["dropout"]
45
+ solvent_hidden_dim = self.config["solvent_hidden_dim"]
46
+ solvent_conv_layers = self.config["solvent_conv_layers"]
47
+ solvent_linear_layers = self.config["solvent_linear_layers"]
48
+ solvent_dropout = self.config["solvent_dropout"]
49
+ fusion_dim = self.config["fusion_dim"]
50
+ self.node_embedding = nn.Linear(self.config["node_dim"], hidden_dim)
51
+ self.node_embedding_solv = nn.Linear(
52
+ self.config["node_dim"], solvent_hidden_dim
53
+ )
54
+
55
+ self.GCNs = GCNs(hidden_dim, hidden_dim, hidden_dim, nn.ReLU(), conv_layers, dropout, False, True)
56
+ self.GCNs_solv = GCNs(solvent_hidden_dim, solvent_hidden_dim, solvent_hidden_dim, nn.ReLU(), solvent_conv_layers, solvent_dropout, False, True)
57
+ self.Linears1 = Linears(hidden_dim,hidden_dim, nn.ReLU(), 2, dropout, False, False)
58
+ self.Linears2 = Linears(solvent_hidden_dim,solvent_hidden_dim, nn.ReLU(), solvent_linear_layers, solvent_dropout, False, False)
59
+ self.Linears3 = Linears(hidden_dim+solvent_hidden_dim,fusion_dim, nn.ReLU(), linear_layers, dropout, False, False)
60
+
61
+ self.output = nn.Linear(fusion_dim, self.config["target_dim"])
62
+
63
+ def forward(self, **kwargs):
64
+ batch = {
65
+ "compound_graphs": kwargs.get(
66
+ "compound_graphs", kwargs.get("graph")
67
+ ),
68
+ "compound_node_feature": kwargs.get(
69
+ "compound_node_feature", kwargs.get("node_feats")
70
+ ),
71
+ "solvent_graphs": kwargs.get(
72
+ "solvent_graphs", kwargs.get("solv_graph")
73
+ ),
74
+ "solvent_node_feature": kwargs.get(
75
+ "solvent_node_feature", kwargs.get("solv_node_feats")
76
+ ),
77
+ }
78
+ missing = [name for name, value in batch.items() if value is None]
79
+ if missing:
80
+ raise ValueError(
81
+ f"SolventGCN input is missing required fields {missing!r}."
82
+ )
83
+ graph = batch["compound_graphs"]
84
+ node_feats = batch["compound_node_feature"]
85
+ solv_graph = batch["solvent_graphs"]
86
+ solv_node_feats = batch["solvent_node_feature"]
87
+
88
+ h = self.node_embedding(node_feats)
89
+ h = self.GCNs(graph, h)
90
+ h = graph_sum_pool(graph, h)
91
+
92
+ h_solv = self.node_embedding_solv(solv_node_feats)
93
+ h_solv = self.GCNs_solv(solv_graph, h_solv)
94
+ h_solv = graph_sum_pool(solv_graph, h_solv)
95
+
96
+ h = self.Linears1(h)
97
+ h_solv = self.Linears2(h_solv)
98
+ h = torch.cat([h,h_solv],axis=1)
99
+ h = self.Linears3(h)
100
+ h = self.output(h)
101
+ return h
102
+
103
+ network = SolventGCN
@@ -0,0 +1,122 @@
1
+ import torch.nn as nn
2
+
3
+ from D4CMPP2.networks.base import (
4
+ Hyperparameter,
5
+ InputContract,
6
+ MolecularNetwork,
7
+ STANDARD_GRAPH_HYPERPARAMETERS,
8
+ STANDARD_GRAPH_OPTIMIZATION_SPACE,
9
+ )
10
+ from D4CMPP2.networks.src.GC import GCconvolution
11
+ from D4CMPP2.networks.src.GCN import graph_sum_pool
12
+ from D4CMPP2.networks.src.pyg_hetero import relation_graph
13
+
14
+ class GroupContributionNetwork(MolecularNetwork):
15
+ """Group-contribution network over the ISA heterogeneous graph."""
16
+
17
+ model_name = "group_contribution"
18
+ required_config = ("node_dim", "edge_dim", "target_dim")
19
+ input_contract = InputContract(
20
+ required=(
21
+ "compound_graphs",
22
+ "compound_r_node",
23
+ "compound_i_node",
24
+ "compound_r2r_edge",
25
+ "compound_d2d_edge",
26
+ ),
27
+ optional=("get_score",),
28
+ )
29
+ hyperparameters = {
30
+ **{
31
+ name: field
32
+ for name, field in STANDARD_GRAPH_HYPERPARAMETERS.items()
33
+ if name != "linear_layers"
34
+ },
35
+ "activation": Hyperparameter(
36
+ "categorical",
37
+ default="Tanh",
38
+ values=("Tanh", "Sigmoid", "ReLU", "Identity"),
39
+ grid=("Tanh", "Sigmoid", "ReLU"),
40
+ description="Activation applied to the normalized contribution sum.",
41
+ ),
42
+ }
43
+ default_optimization_space = (
44
+ *(
45
+ name
46
+ for name in STANDARD_GRAPH_OPTIMIZATION_SPACE
47
+ if name != "linear_layers"
48
+ ),
49
+ "activation",
50
+ )
51
+
52
+ def __init__(self, config):
53
+ if "activation" not in config and "func_f" in config:
54
+ config = {**config, "activation": config["func_f"]}
55
+ super().__init__(config)
56
+ if self.config["target_dim"] != 1:
57
+ raise ValueError(
58
+ "GroupContributionNetwork requires target_dim=1 because its "
59
+ "contribution head produces one scalar per molecule."
60
+ )
61
+
62
+ hidden_dim = self.config["hidden_dim"]
63
+ gcn_layers = self.config["conv_layers"]
64
+ dropout = self.config["dropout"]
65
+
66
+ self.embedding_rnode_lin = nn.Sequential(
67
+ nn.Linear(self.config["node_dim"], hidden_dim, bias=False)
68
+ )
69
+ self.embedding_inode_lin = nn.Sequential(
70
+ nn.Linear(1, hidden_dim, bias=False)
71
+ )
72
+ self.embedding_edge_lin = nn.Sequential(
73
+ nn.Linear(self.config["edge_dim"], hidden_dim, bias=False)
74
+ )
75
+
76
+ self.GCconv = GCconvolution(hidden_dim, hidden_dim, hidden_dim, nn.LeakyReLU(), gcn_layers, dropout, False, True, 0.1)
77
+
78
+ self.linear = nn.Linear(1,1)
79
+ self.normalize = nn.LayerNorm(1)
80
+ self.func_f = getattr(nn, self.config["activation"])()
81
+
82
+ def forward(self, **kargs):
83
+ graph = kargs.get('compound_graphs', kargs.get('graph'))
84
+ r_node = kargs.get('compound_r_node', kargs.get('r_node'))
85
+ i_node = kargs.get('compound_i_node', kargs.get('i_node'))
86
+ r_edge = kargs.get('compound_r2r_edge', kargs.get('r_edge'))
87
+ d_edge = kargs.get('compound_d2d_edge', kargs.get('d_edge'))
88
+ missing = [
89
+ name
90
+ for name, value in {
91
+ "compound_graphs": graph,
92
+ "compound_r_node": r_node,
93
+ "compound_i_node": i_node,
94
+ "compound_r2r_edge": r_edge,
95
+ "compound_d2d_edge": d_edge,
96
+ }.items()
97
+ if value is None
98
+ ]
99
+ if missing:
100
+ raise ValueError(
101
+ f"GroupContributionNetwork input is missing required fields {missing!r}."
102
+ )
103
+
104
+ r_node = r_node.float()
105
+ r_node = self.embedding_rnode_lin(r_node)
106
+ i_node = i_node.float()
107
+ i_node = self.embedding_inode_lin(i_node)
108
+ r_edge = r_edge.float()
109
+ r_edge = self.embedding_edge_lin(r_edge)
110
+
111
+ score = self.GCconv(graph, r_node, r_edge, i_node, d_edge)
112
+ h = graph_sum_pool(relation_graph(graph, 'd_nd', 'd2d'), score)
113
+ h = self.normalize(h)
114
+ h = self.func_f(h)
115
+ h = self.linear(h)
116
+
117
+ if kargs.get('get_score',False):
118
+ return {'prediction':h, 'positive':score}
119
+
120
+ return h
121
+
122
+ network = GroupContributionNetwork
@@ -0,0 +1,14 @@
1
+ """Deprecated compatibility wrapper for the former ISATPM module name."""
2
+
3
+ import warnings
4
+
5
+ warnings.warn(
6
+ "D4CMPP2.networks.ISATPM_model is deprecated; use "
7
+ "D4CMPP2.networks.ISATPN_model instead.",
8
+ FutureWarning,
9
+ stacklevel=2,
10
+ )
11
+
12
+ from D4CMPP2.networks.ISATPN_model import ISATPN, network
13
+
14
+ __all__ = ["ISATPN", "network"]