torch-molecule 0.1.0.dev2__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 (148) hide show
  1. torch_molecule/__init__.py +70 -0
  2. torch_molecule/base/__init__.py +8 -0
  3. torch_molecule/base/base.py +396 -0
  4. torch_molecule/base/encoder.py +44 -0
  5. torch_molecule/base/generator.py +24 -0
  6. torch_molecule/base/old_encoder.py +322 -0
  7. torch_molecule/base/old_predictor.py +904 -0
  8. torch_molecule/base/old_predictor2.py +436 -0
  9. torch_molecule/base/predictor.py +112 -0
  10. torch_molecule/encoder/attrmask/__init__.py +3 -0
  11. torch_molecule/encoder/attrmask/model.py +113 -0
  12. torch_molecule/encoder/attrmask/modeling_attrmask.py +304 -0
  13. torch_molecule/encoder/constant.py +13 -0
  14. torch_molecule/encoder/contextpred/__init__.py +3 -0
  15. torch_molecule/encoder/contextpred/model.py +207 -0
  16. torch_molecule/encoder/contextpred/modeling_contextpred.py +299 -0
  17. torch_molecule/encoder/contextpred/utils.py +206 -0
  18. torch_molecule/encoder/edgepred/__init__.py +3 -0
  19. torch_molecule/encoder/edgepred/model.py +104 -0
  20. torch_molecule/encoder/edgepred/modeling_edgepred.py +285 -0
  21. torch_molecule/encoder/graphmae/__init__.py +3 -0
  22. torch_molecule/encoder/graphmae/dataloader.py +206 -0
  23. torch_molecule/encoder/graphmae/model.py +137 -0
  24. torch_molecule/encoder/graphmae/modeling_graphmae.py +323 -0
  25. torch_molecule/encoder/infograph/__init__.py +3 -0
  26. torch_molecule/encoder/infograph/loss_function.py +128 -0
  27. torch_molecule/encoder/infograph/model.py +92 -0
  28. torch_molecule/encoder/infograph/modeling_infograph.py +301 -0
  29. torch_molecule/encoder/infograph/module.py +31 -0
  30. torch_molecule/encoder/moama/__init__.py +3 -0
  31. torch_molecule/encoder/moama/model.py +131 -0
  32. torch_molecule/encoder/moama/modeling_moama.py +307 -0
  33. torch_molecule/encoder/moama/utils.py +143 -0
  34. torch_molecule/encoder/pretrained/__init__.py +3 -0
  35. torch_molecule/encoder/pretrained/modeling_pretrained.py +274 -0
  36. torch_molecule/encoder/supervised/__init__.py +3 -0
  37. torch_molecule/encoder/supervised/model.py +97 -0
  38. torch_molecule/encoder/supervised/modeling_supervised.py +354 -0
  39. torch_molecule/generator/digress/__init__.py +3 -0
  40. torch_molecule/generator/digress/diffusion.py +194 -0
  41. torch_molecule/generator/digress/modeling_digress.py +503 -0
  42. torch_molecule/generator/digress/transformer.py +360 -0
  43. torch_molecule/generator/digress/utils.py +196 -0
  44. torch_molecule/generator/gdss/__init__.py +3 -0
  45. torch_molecule/generator/gdss/layers.py +257 -0
  46. torch_molecule/generator/gdss/model.py +204 -0
  47. torch_molecule/generator/gdss/modeling_gdss.py +474 -0
  48. torch_molecule/generator/gdss/sde.py +334 -0
  49. torch_molecule/generator/gdss/solver.py +227 -0
  50. torch_molecule/generator/gdss/toremove/ScoreNetworkA.py +167 -0
  51. torch_molecule/generator/gdss/toremove/ScoreNetworkX.py +85 -0
  52. torch_molecule/generator/gdss/utils.py +240 -0
  53. torch_molecule/generator/graph_dit/__init__.py +3 -0
  54. torch_molecule/generator/graph_dit/diffusion.py +188 -0
  55. torch_molecule/generator/graph_dit/modeling_graph_dit.py +581 -0
  56. torch_molecule/generator/graph_dit/transformer.py +207 -0
  57. torch_molecule/generator/graph_dit/utils.py +220 -0
  58. torch_molecule/generator/graph_ga/__init__.py +3 -0
  59. torch_molecule/generator/graph_ga/crossover.py +182 -0
  60. torch_molecule/generator/graph_ga/modeling_graph_ga.py +310 -0
  61. torch_molecule/generator/graph_ga/mutate.py +136 -0
  62. torch_molecule/generator/graph_ga/oracle.py +95 -0
  63. torch_molecule/generator/jtvae/__init__.py +3 -0
  64. torch_molecule/generator/jtvae/jtnn/chemutils.py +450 -0
  65. torch_molecule/generator/jtvae/jtnn/datautils.py +127 -0
  66. torch_molecule/generator/jtvae/jtnn/jtmpn.py +140 -0
  67. torch_molecule/generator/jtvae/jtnn/jtnn_dec.py +350 -0
  68. torch_molecule/generator/jtvae/jtnn/jtnn_enc.py +131 -0
  69. torch_molecule/generator/jtvae/jtnn/mol_tree.py +111 -0
  70. torch_molecule/generator/jtvae/jtnn/mpn.py +129 -0
  71. torch_molecule/generator/jtvae/jtnn/nnutils.py +66 -0
  72. torch_molecule/generator/jtvae/jtnn/vocab.py +31 -0
  73. torch_molecule/generator/jtvae/jtnn_vae.py +246 -0
  74. torch_molecule/generator/jtvae/modeling_jtvae.py +247 -0
  75. torch_molecule/generator/lstm/__init__.py +3 -0
  76. torch_molecule/generator/lstm/action_sampler.py +91 -0
  77. torch_molecule/generator/lstm/lstm.py +59 -0
  78. torch_molecule/generator/lstm/modeling_lstm.py +263 -0
  79. torch_molecule/generator/lstm/smiles_char_dict.py +123 -0
  80. torch_molecule/generator/lstm/utils.py +62 -0
  81. torch_molecule/generator/molgpt/__init__.py +3 -0
  82. torch_molecule/generator/molgpt/dataset.py +87 -0
  83. torch_molecule/generator/molgpt/gpt.py +251 -0
  84. torch_molecule/generator/molgpt/modeling_molgpt.py +427 -0
  85. torch_molecule/generator/pretrained/modeling_pretrained.py +1 -0
  86. torch_molecule/nn/__init__.py +16 -0
  87. torch_molecule/nn/attention.py +63 -0
  88. torch_molecule/nn/embedder.py +183 -0
  89. torch_molecule/nn/gnn.py +631 -0
  90. torch_molecule/nn/mlp.py +34 -0
  91. torch_molecule/predictor/bfgnn/__init__.py +3 -0
  92. torch_molecule/predictor/bfgnn/model.py +116 -0
  93. torch_molecule/predictor/bfgnn/modeling_bfgnn.py +81 -0
  94. torch_molecule/predictor/dir/__init__.py +3 -0
  95. torch_molecule/predictor/dir/model.py +235 -0
  96. torch_molecule/predictor/dir/modeling_dir.py +161 -0
  97. torch_molecule/predictor/dir/utils.py +40 -0
  98. torch_molecule/predictor/gnn/__init__.py +3 -0
  99. torch_molecule/predictor/gnn/model.py +114 -0
  100. torch_molecule/predictor/gnn/modeling_gnn.py +706 -0
  101. torch_molecule/predictor/gnn/old_modeling_gnn.py +707 -0
  102. torch_molecule/predictor/grea/__init__.py +3 -0
  103. torch_molecule/predictor/grea/model.py +190 -0
  104. torch_molecule/predictor/grea/modeling_grea.py +107 -0
  105. torch_molecule/predictor/grea/old1_features.py +229 -0
  106. torch_molecule/predictor/grea/old1_modeling_grea.py +493 -0
  107. torch_molecule/predictor/grea/utils.py +97 -0
  108. torch_molecule/predictor/grin/__init__.py +3 -0
  109. torch_molecule/predictor/grin/model.py +116 -0
  110. torch_molecule/predictor/grin/modeling_grin.py +91 -0
  111. torch_molecule/predictor/irm/__init__.py +3 -0
  112. torch_molecule/predictor/irm/model.py +127 -0
  113. torch_molecule/predictor/irm/modeling_irm.py +179 -0
  114. torch_molecule/predictor/lstm/__init__.py +3 -0
  115. torch_molecule/predictor/lstm/model.py +145 -0
  116. torch_molecule/predictor/lstm/modeling_lstm.py +627 -0
  117. torch_molecule/predictor/lstm/token_from_smiles.py +85 -0
  118. torch_molecule/predictor/old_modeling_graph.py +650 -0
  119. torch_molecule/predictor/rpgnn/__init__.py +3 -0
  120. torch_molecule/predictor/rpgnn/model.py +185 -0
  121. torch_molecule/predictor/rpgnn/modeling_rpgnn.py +76 -0
  122. torch_molecule/predictor/sgir/__init__.py +3 -0
  123. torch_molecule/predictor/sgir/modeling_sgir.py +260 -0
  124. torch_molecule/predictor/sgir/strategy.py +266 -0
  125. torch_molecule/predictor/smiles_transformer/__init__.py +3 -0
  126. torch_molecule/predictor/smiles_transformer/model.py +424 -0
  127. torch_molecule/predictor/smiles_transformer/modeling_transformer.py +252 -0
  128. torch_molecule/predictor/ssr/__init__.py +3 -0
  129. torch_molecule/predictor/ssr/model.py +283 -0
  130. torch_molecule/predictor/ssr/modeling_ssr.py +267 -0
  131. torch_molecule/predictor/ssr/utils.py +185 -0
  132. torch_molecule/utils/__init__.py +31 -0
  133. torch_molecule/utils/checker.py +158 -0
  134. torch_molecule/utils/checkpoint.py +294 -0
  135. torch_molecule/utils/format.py +140 -0
  136. torch_molecule/utils/generic/metrics.py +530 -0
  137. torch_molecule/utils/generic/pseudo_tasks.py +11 -0
  138. torch_molecule/utils/generic/weights.py +30 -0
  139. torch_molecule/utils/graph/features.py +178 -0
  140. torch_molecule/utils/graph/graph_from_smiles.py +134 -0
  141. torch_molecule/utils/graph/graph_to_smiles.py +312 -0
  142. torch_molecule/utils/hf.py +232 -0
  143. torch_molecule/utils/search.py +64 -0
  144. torch_molecule-0.1.0.dev2.dist-info/METADATA +243 -0
  145. torch_molecule-0.1.0.dev2.dist-info/RECORD +148 -0
  146. torch_molecule-0.1.0.dev2.dist-info/WHEEL +5 -0
  147. torch_molecule-0.1.0.dev2.dist-info/licenses/LICENSE +21 -0
  148. torch_molecule-0.1.0.dev2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,631 @@
1
+ import torch
2
+ import torch.nn.functional as F
3
+ from torch_geometric.utils import degree
4
+ from torch_geometric.nn.norm import GraphNorm, PairNorm, DiffGroupNorm, InstanceNorm, LayerNorm, GraphSizeNorm
5
+ from torch_geometric.nn import MessagePassing
6
+ from torch_geometric.nn import global_add_pool
7
+ try:
8
+ from torch_scatter import scatter_min, scatter_max, scatter_mean, scatter_add
9
+ _has_torch_scatter = True
10
+ except ImportError:
11
+ scatter_min = scatter_max = scatter_mean = scatter_add = None
12
+ _has_torch_scatter = False
13
+
14
+ from ..utils import get_atom_feature_dims, get_bond_feature_dims
15
+
16
+ full_atom_feature_dims = get_atom_feature_dims()
17
+ full_bond_feature_dims = get_bond_feature_dims()
18
+
19
+ class AtomEncoder(torch.nn.Module):
20
+ """Encodes atom features into a fixed-size vector representation.
21
+
22
+ This module converts categorical atom features into embeddings and combines them
23
+ to create a unified atom representation.
24
+
25
+ Parameters
26
+ ----------
27
+ hidden_size : int
28
+ Dimensionality of the output atom embedding vectors.
29
+
30
+ Notes
31
+ -----
32
+ Each atom feature is embedded separately using an Embedding layer, then
33
+ these embeddings are summed to produce the final representation.
34
+ The embedding weights are initialized using Xavier uniform initialization
35
+ with max_norm=1 constraint.
36
+ """
37
+ def __init__(self, hidden_size):
38
+ super(AtomEncoder, self).__init__()
39
+
40
+ self.atom_embedding_list = torch.nn.ModuleList()
41
+
42
+ for i, dim in enumerate(full_atom_feature_dims):
43
+ emb = torch.nn.Embedding(dim, hidden_size, max_norm=1)
44
+ torch.nn.init.xavier_uniform_(emb.weight.data)
45
+ self.atom_embedding_list.append(emb)
46
+
47
+ def forward(self, x):
48
+ """Transform atom features into embeddings.
49
+
50
+ Parameters
51
+ ----------
52
+ x : torch.Tensor
53
+ Tensor of shape [num_atoms, num_features] containing categorical
54
+ atom features.
55
+
56
+ Returns
57
+ -------
58
+ torch.Tensor
59
+ Atom embeddings of shape [num_atoms, hidden_size].
60
+ """
61
+ x_embedding = 0
62
+ for i in range(x.shape[1]):
63
+ x_embedding += self.atom_embedding_list[i](x[:,i])
64
+
65
+ return x_embedding
66
+
67
+ class BondEncoder(torch.nn.Module):
68
+ """Encodes bond features into a fixed-size vector representation.
69
+
70
+ This module converts categorical bond features into embeddings and combines them
71
+ to create a unified bond representation.
72
+
73
+ Parameters
74
+ ----------
75
+ hidden_size : int
76
+ Dimensionality of the output bond embedding vectors.
77
+
78
+ Notes
79
+ -----
80
+ Each bond feature is embedded separately using an Embedding layer, then
81
+ these embeddings are summed to produce the final representation.
82
+ The embedding weights are initialized using Xavier uniform initialization
83
+ with max_norm=1 constraint.
84
+ """
85
+ def __init__(self, hidden_size):
86
+ super(BondEncoder, self).__init__()
87
+
88
+ self.bond_embedding_list = torch.nn.ModuleList()
89
+
90
+ for i, dim in enumerate(full_bond_feature_dims):
91
+ emb = torch.nn.Embedding(dim, hidden_size, max_norm=1)
92
+ torch.nn.init.xavier_uniform_(emb.weight.data)
93
+ self.bond_embedding_list.append(emb)
94
+
95
+ def forward(self, edge_attr):
96
+ """Transform bond features into embeddings.
97
+
98
+ Parameters
99
+ ----------
100
+ edge_attr : torch.Tensor
101
+ Tensor of shape [num_bonds, num_features] containing categorical
102
+ bond features.
103
+
104
+ Returns
105
+ -------
106
+ torch.Tensor
107
+ Bond embeddings of shape [num_bonds, hidden_size].
108
+ """
109
+ bond_embedding = 0
110
+ for i in range(edge_attr.shape[1]):
111
+ bond_embedding += self.bond_embedding_list[i](edge_attr[:,i])
112
+
113
+ return bond_embedding
114
+
115
+ class GINConv(MessagePassing):
116
+ def __init__(self, hidden_size, output_size=None):
117
+ '''
118
+ hidden_size (int): node embedding dimensionality
119
+ '''
120
+ super(GINConv, self).__init__(aggr = "add")
121
+ if output_size is None:
122
+ output_size = hidden_size
123
+
124
+ self.mlp = torch.nn.Sequential(torch.nn.Linear(hidden_size, 2*hidden_size), torch.nn.BatchNorm1d(2*hidden_size), torch.nn.ReLU(), torch.nn.Linear(2*hidden_size, output_size))
125
+ self.eps = torch.nn.Parameter(torch.Tensor([0]))
126
+
127
+ self.bond_encoder = BondEncoder(hidden_size = hidden_size)
128
+
129
+ def forward(self, x, edge_index, edge_attr):
130
+ edge_embedding = self.bond_encoder(edge_attr)
131
+ out = self.mlp((1 + self.eps) *x + self.propagate(edge_index, x=x, edge_attr=edge_embedding))
132
+
133
+ return out
134
+
135
+ def message(self, x_j, edge_attr):
136
+ return F.relu(x_j + edge_attr)
137
+
138
+ def update(self, aggr_out):
139
+ return aggr_out
140
+
141
+ class GCNConv(MessagePassing):
142
+ def __init__(self, hidden_size, output_size=None):
143
+ super(GCNConv, self).__init__(aggr='add')
144
+ if output_size is None:
145
+ output_size = hidden_size
146
+
147
+ self.linear = torch.nn.Linear(hidden_size, output_size)
148
+ self.root_emb = torch.nn.Embedding(1, output_size)
149
+ self.bond_encoder = BondEncoder(hidden_size = output_size)
150
+
151
+ def forward(self, x, edge_index, edge_attr):
152
+ x = self.linear(x)
153
+ edge_embedding = self.bond_encoder(edge_attr)
154
+
155
+ row, col = edge_index
156
+ #edge_weight = torch.ones((edge_index.size(1), ), device=edge_index.device)
157
+ deg = degree(row, x.size(0), dtype = x.dtype) + 1
158
+ deg_inv_sqrt = deg.pow(-0.5)
159
+ deg_inv_sqrt[deg_inv_sqrt == float('inf')] = 0
160
+
161
+ norm = deg_inv_sqrt[row] * deg_inv_sqrt[col]
162
+
163
+ return self.propagate(edge_index, x=x, edge_attr=edge_embedding, norm=norm) + F.relu(x + self.root_emb.weight) * 1./deg.view(-1,1)
164
+
165
+ def message(self, x_j, edge_attr, norm):
166
+ return norm.view(-1, 1) * F.relu(x_j + edge_attr)
167
+
168
+ def update(self, aggr_out):
169
+ return aggr_out
170
+
171
+ class GINConv_BF(MessagePassing):
172
+ def __init__(self, hidden_size, output_size=None):
173
+ super().__init__(aggr=None)
174
+ if output_size is None:
175
+ output_size = hidden_size
176
+ self.f_agg = torch.nn.Sequential(
177
+ torch.nn.Linear(2*hidden_size, 2*hidden_size),
178
+ torch.nn.BatchNorm1d(2*hidden_size),
179
+ torch.nn.ReLU(),
180
+ torch.nn.Linear(2*hidden_size, output_size),
181
+ )
182
+ self.f_up = torch.nn.Sequential(
183
+ torch.nn.Linear(2*hidden_size, 2*hidden_size),
184
+ torch.nn.BatchNorm1d(2*hidden_size),
185
+ torch.nn.ReLU(),
186
+ torch.nn.Linear(2*hidden_size, output_size),
187
+ )
188
+ self.bond_encoder = BondEncoder(hidden_size=output_size)
189
+
190
+ def forward(self, x, edge_index, edge_attr):
191
+ edge_emb = self.bond_encoder(edge_attr)
192
+ agg = self.propagate(edge_index, x=x, edge_attr=edge_emb)
193
+ out = self.f_up(torch.cat([agg, x], dim=1))
194
+ return out
195
+
196
+ def message(self, x_j, edge_attr):
197
+ return self.f_agg(torch.cat([x_j, edge_attr], dim=1))
198
+
199
+ def aggregate(self, inputs, index, dim_size=None):
200
+ if not _has_torch_scatter or scatter_min is None:
201
+ raise ImportError("BFGNN requires `torch_scatter` package. Please install it via `pip install torch-scatter -f https://data.pyg.org/whl/torch-${TORCH}+${CUDA}.html`.")
202
+
203
+ out, _ = scatter_min(inputs, index, dim=0, dim_size=dim_size)
204
+ out[out == float('inf')] = 0.0
205
+ return out
206
+
207
+ class GCNConv_BF(MessagePassing):
208
+ def __init__(self, hidden_size, output_size=None):
209
+ super().__init__(aggr=None)
210
+ if output_size is None:
211
+ output_size = hidden_size
212
+ self.linear = torch.nn.Linear(hidden_size, output_size)
213
+ self.f_agg = torch.nn.Sequential(
214
+ torch.nn.Linear(2*hidden_size, 2*hidden_size),
215
+ torch.nn.BatchNorm1d(2*hidden_size),
216
+ torch.nn.ReLU(),
217
+ torch.nn.Linear(2*hidden_size, output_size),
218
+ )
219
+ self.f_up = torch.nn.Sequential(
220
+ torch.nn.Linear(2*hidden_size, 2*hidden_size),
221
+ torch.nn.BatchNorm1d(2*hidden_size),
222
+ torch.nn.ReLU(),
223
+ torch.nn.Linear(2*hidden_size, output_size),
224
+ )
225
+ self.bond_encoder = BondEncoder(hidden_size=output_size)
226
+
227
+ def forward(self, x, edge_index, edge_attr):
228
+ x_lin = self.linear(x)
229
+
230
+ row, col = edge_index
231
+ deg = degree(row, x_lin.size(0), dtype=x_lin.dtype) + 1
232
+ deg_inv_sqrt = deg.pow(-0.5)
233
+ deg_inv_sqrt[deg_inv_sqrt == float('inf')] = 0.0
234
+ norm = deg_inv_sqrt[row] * deg_inv_sqrt[col]
235
+
236
+ edge_emb = self.bond_encoder(edge_attr)
237
+ agg = self.propagate(
238
+ edge_index,
239
+ x=x_lin,
240
+ edge_attr=edge_emb,
241
+ norm=norm,
242
+ size=None
243
+ )
244
+ return self.f_up(torch.cat([agg, x_lin], dim=1))
245
+
246
+ def message(self, x_j, edge_attr, norm):
247
+ m = self.f_agg(torch.cat([x_j, edge_attr], dim=1))
248
+ return norm.view(-1, 1) * F.relu(m)
249
+
250
+ def aggregate(self, inputs, index, dim_size=None):
251
+ if not _has_torch_scatter or scatter_min is None:
252
+ raise ImportError("BFGNN requires `torch_scatter` package. Please install it via `pip install torch-scatter -f https://data.pyg.org/whl/torch-${TORCH}+${CUDA}.html`.")
253
+
254
+ out, _ = scatter_min(inputs, index, dim=0, dim_size=dim_size)
255
+ out[out == float('inf')] = 0.0
256
+ return out
257
+
258
+ class GINConv_GRIN(MessagePassing):
259
+ def __init__(self, hidden_size, output_size=None):
260
+ super().__init__(aggr=None)
261
+ if output_size is None:
262
+ output_size = hidden_size
263
+ self.mlp = torch.nn.Sequential(
264
+ torch.nn.Linear(2*hidden_size, 2*hidden_size),
265
+ torch.nn.BatchNorm1d(2*hidden_size),
266
+ torch.nn.ReLU(),
267
+ torch.nn.Linear(2*hidden_size, output_size),
268
+ )
269
+ self.eps = torch.nn.Parameter(torch.zeros(1))
270
+ self.bond_encoder = BondEncoder(hidden_size=output_size)
271
+ self.root_emb = torch.nn.Embedding(1, output_size)
272
+
273
+ def forward(self, x, edge_index, edge_attr, visited):
274
+ edge_emb = self.bond_encoder(edge_attr)
275
+ row, _ = edge_index
276
+ deg = degree(row, x.size(0), dtype=x.dtype) + 1
277
+
278
+ agg = self.propagate(edge_index, x=x, edge_attr=edge_emb)
279
+
280
+ agg[visited] = 0.0
281
+
282
+ concat = torch.cat([x, agg], dim=1)
283
+ out = self.mlp(concat)
284
+ out = out + F.relu((1 + self.eps) * x + self.root_emb.weight) * (1.0 / deg.view(-1,1))
285
+
286
+ _, selected = agg.max(dim=0)
287
+ new_visited = visited.clone()
288
+ new_visited[selected] = True
289
+ mask = torch.zeros_like(visited)
290
+ mask[selected] = True
291
+ out = torch.where(mask.unsqueeze(1), out, x)
292
+
293
+ return out, new_visited
294
+
295
+ def message(self, x_j, edge_attr):
296
+ return F.relu(x_j + edge_attr)
297
+
298
+ def aggregate(self, inputs, index, dim_size=None):
299
+ if not _has_torch_scatter or scatter_max is None:
300
+ raise ImportError("GRIN requires `torch_scatter` package. Please install it via `pip install torch-scatter -f https://data.pyg.org/whl/torch-${TORCH}+${CUDA}.html`.")
301
+
302
+ out, _ = scatter_max(inputs, index, dim=0, dim_size=dim_size)
303
+ out[out == float('inf')] = 0.0
304
+ return out
305
+
306
+ class GCNConv_GRIN(MessagePassing):
307
+ def __init__(self, hidden_size, output_size=None):
308
+ super().__init__(aggr=None)
309
+ if output_size is None:
310
+ output_size = hidden_size
311
+ self.linear = torch.nn.Linear(hidden_size, output_size)
312
+ self.root_emb = torch.nn.Embedding(1, output_size)
313
+ self.bond_encoder = BondEncoder(hidden_size=output_size)
314
+ self.f_up = torch.nn.Sequential(
315
+ torch.nn.Linear(2*hidden_size, 2*hidden_size),
316
+ torch.nn.BatchNorm1d(2*hidden_size),
317
+ torch.nn.ReLU(),
318
+ torch.nn.Linear(2*hidden_size, output_size),
319
+ )
320
+
321
+ def forward(self, x, edge_index, edge_attr, visited):
322
+ x_lin = self.linear(x)
323
+ row, col = edge_index
324
+ deg = degree(row, x_lin.size(0), dtype=x_lin.dtype) + 1
325
+ deg_inv_sqrt = deg.pow(-0.5)
326
+ deg_inv_sqrt[deg_inv_sqrt == float('inf')] = 0.0
327
+ norm = deg_inv_sqrt[row] * deg_inv_sqrt[col]
328
+
329
+ edge_emb = self.bond_encoder(edge_attr)
330
+ agg = self.propagate(
331
+ edge_index,
332
+ x=x_lin,
333
+ edge_attr=edge_emb,
334
+ norm=norm,
335
+ )
336
+
337
+ agg[visited] = 0.0
338
+
339
+ concat = torch.cat([x_lin, agg], dim=1)
340
+ out = self.f_up(concat)
341
+ out = out + F.relu(x_lin + self.root_emb.weight) * (1.0 / deg.view(-1,1))
342
+
343
+ _, selected = agg.max(dim=0)
344
+ new_visited = visited.clone()
345
+ new_visited[selected] = True
346
+ mask = torch.zeros_like(visited)
347
+ mask[selected] = True
348
+ out = torch.where(mask.unsqueeze(1), out, x)
349
+
350
+ return out, new_visited
351
+
352
+ def message(self, x_j, edge_attr, norm):
353
+ return norm.view(-1,1) * F.relu(x_j + edge_attr)
354
+
355
+ def aggregate(self, inputs, index, dim_size=None):
356
+ if not _has_torch_scatter or scatter_max is None:
357
+ raise ImportError("GRIN requires `torch_scatter` package. Please install it via `pip install torch-scatter -f https://data.pyg.org/whl/torch-${TORCH}+${CUDA}.html`.")
358
+
359
+ out, _ = scatter_max(inputs, index, dim=0, dim_size=dim_size)
360
+ out[out == float('inf')] = 0.0
361
+ return out
362
+
363
+ ### GNN to generate node embedding
364
+ class GNN_node(torch.nn.Module):
365
+ """
366
+ Output:
367
+ node representations
368
+ """
369
+ def __init__(self, num_layer, hidden_size, drop_ratio = 0.5, JK = "last", residual = False, gnn_name = 'gin', norm_layer = 'batch_norm', encode_atom = True, algorithm_aligned = None):
370
+ '''
371
+ hidden_size (int): node embedding dimensionality
372
+ num_layer (int): number of GNN message passing layers
373
+
374
+ '''
375
+
376
+ super(GNN_node, self).__init__()
377
+ self.num_layer = num_layer
378
+ self.drop_ratio = drop_ratio
379
+ self.JK = JK
380
+ ### add residual connection or not
381
+ self.residual = residual
382
+ self.norm_layer = norm_layer
383
+ self.encode_atom = encode_atom
384
+ self.algorithm_aligned = algorithm_aligned
385
+ if self.num_layer < 2:
386
+ raise ValueError("Number of GNN layers must be greater than 1.")
387
+
388
+ self.atom_encoder = AtomEncoder(hidden_size)
389
+ self.bond_encoder = BondEncoder(hidden_size)
390
+
391
+ ###List of GNNs
392
+ self.convs = torch.nn.ModuleList()
393
+ self.batch_norms = torch.nn.ModuleList()
394
+
395
+ for layer in range(num_layer):
396
+ if gnn_name == 'gin':
397
+ if algorithm_aligned == 'bf':
398
+ self.convs.append(GINConv_BF(hidden_size))
399
+ elif algorithm_aligned == 'mst':
400
+ self.convs.append(GINConv_GRIN(hidden_size))
401
+ else:
402
+ self.convs.append(GINConv(hidden_size))
403
+ elif gnn_name == 'gcn':
404
+ if algorithm_aligned == 'bf':
405
+ self.convs.append(GCNConv_BF(hidden_size))
406
+ elif algorithm_aligned == 'mst':
407
+ self.convs.append(GCNConv_GRIN(hidden_size))
408
+ else:
409
+ self.convs.append(GCNConv(hidden_size))
410
+ else:
411
+ raise ValueError('Undefined GNN type called {}'.format(gnn_name))
412
+
413
+ if norm_layer.split('_')[0] == 'batch':
414
+ if norm_layer.split('_')[-1] == 'notrack':
415
+ self.batch_norms.append(torch.nn.BatchNorm1d(hidden_size, track_running_stats=False, affine=False))
416
+ else:
417
+ self.batch_norms.append(torch.nn.BatchNorm1d(hidden_size))
418
+ elif norm_layer.split('_')[0] == 'instance':
419
+ self.batch_norms.append(InstanceNorm(hidden_size))
420
+ elif norm_layer.split('_')[0] == 'layer':
421
+ self.batch_norms.append(LayerNorm(hidden_size))
422
+ elif norm_layer.split('_')[0] == 'graph':
423
+ self.batch_norms.append(GraphNorm(hidden_size))
424
+ elif norm_layer.split('_')[0] == 'size':
425
+ self.batch_norms.append(GraphSizeNorm())
426
+ elif norm_layer.split('_')[0] == 'pair':
427
+ self.batch_norms.append(PairNorm(hidden_size))
428
+ elif norm_layer.split('_')[0] == 'group':
429
+ self.batch_norms.append(DiffGroupNorm(hidden_size, groups=4))
430
+ else:
431
+ raise ValueError('Undefined normalization layer called {}'.format(norm_layer))
432
+ if norm_layer.split('_')[1] == 'size':
433
+ self.graph_size_norm = GraphSizeNorm()
434
+
435
+ # def forward(self, batched_data):
436
+ # x, edge_index, edge_attr, batch = batched_data.x, batched_data.edge_index, batched_data.edge_attr, batched_data.batch
437
+ def forward(self, *args):
438
+ if len(args) == 1:
439
+ # Case 1: batched_data input
440
+ batched_data = args[0]
441
+ x, edge_index, edge_attr, batch = batched_data.x, batched_data.edge_index, batched_data.edge_attr, batched_data.batch
442
+ elif len(args) == 4:
443
+ # Case 2: separate inputs
444
+ x, edge_index, edge_attr, batch = args
445
+ else:
446
+ raise ValueError("forward expects either 1 batched_data argument or 4 separate arguments (x, edge_index, edge_attr, batch)")
447
+
448
+ if self.encode_atom:
449
+ h_list = [self.atom_encoder(x)]
450
+ else:
451
+ h_list = [x]
452
+ if self.algorithm_aligned == 'mst':
453
+ visited = torch.zeros(x.size(0), dtype=torch.bool, device=x.device)
454
+ for layer in range(self.num_layer):
455
+ if self.algorithm_aligned == 'mst':
456
+ h, visited = self.convs[layer](h_list[layer], edge_index, edge_attr, visited)
457
+ else:
458
+ h = self.convs[layer](h_list[layer], edge_index, edge_attr)
459
+ if self.norm_layer.split('_')[0] == 'batch':
460
+ h = self.batch_norms[layer](h)
461
+ else:
462
+ h = self.batch_norms[layer](h, batch)
463
+ if self.norm_layer.split('_')[1] == 'size':
464
+ h = self.graph_size_norm(h, batch)
465
+
466
+ if layer == self.num_layer - 1:
467
+ #remove relu for the last layer
468
+ h = F.dropout(h, self.drop_ratio, training = self.training)
469
+ else:
470
+ h = F.relu(h)
471
+ h = F.dropout(h, self.drop_ratio, training = self.training)
472
+ if self.residual:
473
+ h = h + h_list[layer]
474
+
475
+ h_list.append(h)
476
+
477
+ ### Different implementations of Jk-concat
478
+ if self.JK == "last":
479
+ node_representation = h_list[-1]
480
+ elif self.JK == "sum":
481
+ node_representation = 0
482
+ for layer in range(self.num_layer + 1):
483
+ node_representation += h_list[layer]
484
+
485
+ return node_representation, h_list
486
+
487
+ ### Virtual GNN to generate node embedding
488
+ class GNN_node_Virtualnode(torch.nn.Module):
489
+ """
490
+ Output:
491
+ node representations
492
+ """
493
+ def __init__(self, num_layer, hidden_size, drop_ratio = 0.5, JK = "last", residual = False, gnn_name = 'gin', norm_layer = 'batch_norm', encode_atom = True, algorithm_aligned = None):
494
+ '''
495
+ hidden_size (int): node embedding dimensionality
496
+ '''
497
+
498
+ super(GNN_node_Virtualnode, self).__init__()
499
+ self.num_layer = num_layer
500
+ self.drop_ratio = drop_ratio
501
+ self.JK = JK
502
+ ### add residual connection or not
503
+ self.residual = residual
504
+ self.norm_layer = norm_layer
505
+ self.encode_atom = encode_atom
506
+ self.algorithm_aligned = algorithm_aligned
507
+ if self.num_layer < 2:
508
+ raise ValueError("Number of GNN layers must be greater than 1.")
509
+
510
+ self.atom_encoder = AtomEncoder(hidden_size)
511
+ self.bond_encoder = BondEncoder(hidden_size)
512
+
513
+ ### set the initial virtual node embedding to 0.
514
+ self.virtualnode_embedding = torch.nn.Embedding(1, hidden_size)
515
+ torch.nn.init.constant_(self.virtualnode_embedding.weight.data, 0)
516
+
517
+ ### List of GNNs
518
+ self.convs = torch.nn.ModuleList()
519
+ ### batch norms applied to node embeddings
520
+ self.batch_norms = torch.nn.ModuleList()
521
+
522
+ ### List of MLPs to transform virtual node at every layer
523
+ self.mlp_virtualnode_list = torch.nn.ModuleList()
524
+
525
+ for layer in range(num_layer):
526
+ if gnn_name == 'gin':
527
+ if algorithm_aligned == 'bf':
528
+ self.convs.append(GINConv_BF(hidden_size))
529
+ elif algorithm_aligned == 'mst':
530
+ self.convs.append(GINConv_GRIN(hidden_size))
531
+ else:
532
+ self.convs.append(GINConv(hidden_size))
533
+ elif gnn_name == 'gcn':
534
+ if algorithm_aligned == 'bf':
535
+ self.convs.append(GCNConv_BF(hidden_size))
536
+ elif algorithm_aligned == 'mst':
537
+ self.convs.append(GCNConv_GRIN(hidden_size))
538
+ else:
539
+ self.convs.append(GCNConv(hidden_size))
540
+ else:
541
+ raise ValueError('Undefined GNN type called {}'.format(gnn_name))
542
+
543
+ if norm_layer.split('_')[0] == 'batch':
544
+ if norm_layer.split('_')[-1] == 'notrack':
545
+ self.batch_norms.append(torch.nn.BatchNorm1d(hidden_size, track_running_stats=False, affine=False))
546
+ else:
547
+ self.batch_norms.append(torch.nn.BatchNorm1d(hidden_size))
548
+ elif norm_layer.split('_')[0] == 'instance':
549
+ self.batch_norms.append(InstanceNorm(hidden_size))
550
+ elif norm_layer.split('_')[0] == 'layer':
551
+ self.batch_norms.append(LayerNorm(hidden_size))
552
+ elif norm_layer.split('_')[0] == 'graph':
553
+ self.batch_norms.append(GraphNorm(hidden_size))
554
+ elif norm_layer.split('_')[0] == 'size':
555
+ self.batch_norms.append(GraphSizeNorm())
556
+ elif norm_layer.split('_')[0] == 'pair':
557
+ self.batch_norms.append(PairNorm(hidden_size))
558
+ elif norm_layer.split('_')[0] == 'group':
559
+ self.batch_norms.append(DiffGroupNorm(hidden_size, groups=4))
560
+ else:
561
+ raise ValueError('Undefined normalization layer called {}'.format(norm_layer))
562
+ if norm_layer.split('_')[1] == 'size':
563
+ self.graph_size_norm = GraphSizeNorm()
564
+ for layer in range(num_layer - 1):
565
+ self.mlp_virtualnode_list.append(torch.nn.Sequential(torch.nn.Linear(hidden_size, 2*hidden_size), torch.nn.BatchNorm1d(2*hidden_size), torch.nn.ReLU(), \
566
+ torch.nn.Linear(2*hidden_size, hidden_size), torch.nn.BatchNorm1d(hidden_size), torch.nn.ReLU()))
567
+
568
+
569
+ def forward(self, *args):
570
+ if len(args) == 1:
571
+ # Case 1: batched_data input
572
+ batched_data = args[0]
573
+ x, edge_index, edge_attr, batch = batched_data.x, batched_data.edge_index, batched_data.edge_attr, batched_data.batch
574
+ elif len(args) == 4:
575
+ # Case 2: separate inputs
576
+ x, edge_index, edge_attr, batch = args
577
+ else:
578
+ raise ValueError("forward expects either 1 batched_data argument or 4 separate arguments (x, edge_index, edge_attr, batch)")
579
+ ### virtual node embeddings for graphs
580
+ virtualnode_embedding = self.virtualnode_embedding(torch.zeros(batch[-1].item() + 1).to(edge_index.dtype).to(edge_index.device))
581
+
582
+ if self.encode_atom:
583
+ h_list = [self.atom_encoder(x)]
584
+ else:
585
+ h_list = [x]
586
+ if self.algorithm_aligned == 'mst':
587
+ visited = torch.zeros(x.size(0), dtype=torch.bool, device=x.device)
588
+ for layer in range(self.num_layer):
589
+ ### add message from virtual nodes to graph nodes
590
+ h_list[layer] = h_list[layer] + virtualnode_embedding[batch]
591
+ ### Message passing among graph nodes
592
+ if self.algorithm_aligned == 'mst':
593
+ h, visited = self.convs[layer](h_list[layer], edge_index, edge_attr, visited)
594
+ else:
595
+ h = self.convs[layer](h_list[layer], edge_index, edge_attr)
596
+ if self.norm_layer.split('_')[0] == 'batch':
597
+ h = self.batch_norms[layer](h)
598
+ else:
599
+ h = self.batch_norms[layer](h, batch)
600
+ if self.norm_layer.split('_')[1] == 'size':
601
+ h = self.graph_size_norm(h, batch)
602
+
603
+ if layer == self.num_layer - 1:
604
+ h = F.dropout(h, self.drop_ratio, training = self.training)
605
+ else:
606
+ h = F.relu(h)
607
+ h = F.dropout(h, self.drop_ratio, training = self.training)
608
+
609
+ if self.residual:
610
+ h = h + h_list[layer]
611
+
612
+ h_list.append(h)
613
+
614
+ ### update the virtual nodes
615
+ if layer < self.num_layer - 1:
616
+ ### add message from graph nodes to virtual nodes
617
+ virtualnode_embedding_temp = global_add_pool(h_list[layer], batch) + virtualnode_embedding
618
+ if self.residual:
619
+ virtualnode_embedding = virtualnode_embedding + F.dropout(self.mlp_virtualnode_list[layer](virtualnode_embedding_temp), self.drop_ratio, training = self.training)
620
+ else:
621
+ virtualnode_embedding = F.dropout(self.mlp_virtualnode_list[layer](virtualnode_embedding_temp), self.drop_ratio, training = self.training)
622
+
623
+ ### Different implementations of Jk-concat
624
+ if self.JK == "last":
625
+ node_representation = h_list[-1]
626
+ elif self.JK == "sum":
627
+ node_representation = 0
628
+ for layer in range(self.num_layer + 1):
629
+ node_representation += h_list[layer]
630
+
631
+ return node_representation, h_list
@@ -0,0 +1,34 @@
1
+ import torch.nn as nn
2
+
3
+ class MLP(nn.Module):
4
+ def __init__(
5
+ self,
6
+ in_features,
7
+ hidden_features=None,
8
+ out_features=None,
9
+ act_layer=nn.GELU,
10
+ bias=True,
11
+ drop=0.,
12
+ use_bn=True,
13
+ ):
14
+ super().__init__()
15
+ out_features = out_features or in_features
16
+ hidden_features = hidden_features or in_features
17
+ linear_layer = nn.Linear
18
+
19
+ self.fc1 = linear_layer(in_features, hidden_features, bias=bias)
20
+ if use_bn:
21
+ self.bn1 = nn.BatchNorm1d(hidden_features)
22
+ else:
23
+ self.bn1 = nn.Identity()
24
+ self.act = act_layer()
25
+ self.drop1 = nn.Dropout(drop)
26
+ self.fc2 = linear_layer(hidden_features, out_features, bias=bias)
27
+
28
+ def forward(self, x):
29
+ x = self.fc1(x)
30
+ x = self.bn1(x)
31
+ x = self.act(x)
32
+ x = self.drop1(x)
33
+ x = self.fc2(x)
34
+ return x
@@ -0,0 +1,3 @@
1
+ from .modeling_bfgnn import BFGNNMolecularPredictor
2
+
3
+ __all__ = ['BFGNNMolecularPredictor']