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,322 @@
1
+ import os
2
+ import json
3
+ import datetime
4
+ import tempfile
5
+ import warnings
6
+ import torch
7
+ import numpy as np
8
+ from rdkit import Chem
9
+ from ..utils.checker import MolecularInputChecker
10
+ from ..utils.checkpoint import LocalCheckpointManager, HuggingFaceCheckpointManager
11
+ from dataclasses import dataclass, field
12
+ from abc import ABC, abstractmethod
13
+ from typing import Optional, ClassVar, Union, List, Dict, Any, Tuple, Callable, Type, Literal
14
+
15
+ @dataclass
16
+ class BaseMolecularEncoder(ABC):
17
+ """Base class for molecular representation learning.
18
+
19
+ This class provides a skeleton for implementing custom molecular representation
20
+ learning models. It includes basic functionality for parameter management,
21
+ fitting, and encoding molecular representations.
22
+
23
+ Attributes
24
+ ----------
25
+ model_name : str
26
+ Name of the model
27
+ device : Optional[torch.device]
28
+ Device to run the model on
29
+ model : Optional[torch.nn.Module]
30
+ Model instance
31
+ """
32
+
33
+ model_name: str = field(default="BaseMolecularEncoder")
34
+ device: Optional[torch.device] = field(default=None)
35
+ model: Optional[torch.nn.Module] = field(default=None, init=False)
36
+
37
+ # Instance variables with default values
38
+ is_fitted_: bool = field(default=False, init=False)
39
+ model_class: Optional[Type[torch.nn.Module]] = field(default=None, init=False)
40
+
41
+ def __post_init__(self):
42
+ """Set device if not provided."""
43
+ # Set device if not provided
44
+ if self.device is None:
45
+ self.device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
46
+ elif isinstance(self.device, str):
47
+ self.device = torch.device(self.device)
48
+
49
+ def get_params(self, deep: bool = True) -> Dict[str, Any]:
50
+ """Get parameters for this estimator.
51
+
52
+ Parameters
53
+ ----------
54
+ deep : bool, default=True
55
+ If True, will return the parameters for this estimator and
56
+ contained subobjects.
57
+
58
+ Returns
59
+ -------
60
+ params : dict
61
+ Parameter names mapped to their values.
62
+ """
63
+ out = dict()
64
+ for key in self._get_param_names():
65
+ value = getattr(self, key)
66
+ if deep and hasattr(value, "get_params"):
67
+ deep_items = value.get_params().items()
68
+ out.update((key + "__" + k, val) for k, val in deep_items)
69
+ out[key] = value
70
+ return out
71
+
72
+ def set_params(self, **params) -> "BaseMolecularEncoder":
73
+ """Set the parameters of this representer.
74
+
75
+ Parameters
76
+ ----------
77
+ **params : dict
78
+ Representer parameters.
79
+
80
+ Returns
81
+ -------
82
+ self : object
83
+ Representer instance.
84
+ """
85
+ if not params:
86
+ return self
87
+
88
+ valid_params = self.get_params(deep=True)
89
+ for key, value in params.items():
90
+ if key not in valid_params:
91
+ raise ValueError(f"Invalid parameter {key} for representer {self}")
92
+ setattr(self, key, value)
93
+ return self
94
+
95
+ def _setup_optimizers(self) -> Tuple[torch.optim.Optimizer, Optional[Any]]:
96
+ raise NotImplementedError("optimizers and schedulers must be implemented by child class")
97
+
98
+ @abstractmethod
99
+ def fit(self, X: List[str], y: Optional[np.ndarray] = None) -> "BaseMolecularEncoder":
100
+ pass
101
+
102
+ @abstractmethod
103
+ def encode(self, X: List[str], return_type: Literal["np", "pt"] = "pt") -> Union[np.ndarray, torch.Tensor]:
104
+ pass
105
+
106
+ def _train_epoch(self, train_loader, optimizer):
107
+ raise NotImplementedError("Training epoch logic must be implemented by child class")
108
+
109
+ def _evaluation_epoch(self, evaluate_loader):
110
+ raise NotImplementedError("Evaluation epoch logic must be implemented by child class")
111
+
112
+ def _check_is_fitted(self) -> None:
113
+ if not self.is_fitted_:
114
+ raise AttributeError(
115
+ "This MolecularBaseRepresenter instance is not fitted yet. "
116
+ "Call 'fit' before using this representer."
117
+ )
118
+
119
+ def __repr__(self, N_CHAR_MAX=700):
120
+ """Get string representation of the representer.
121
+
122
+ Parameters
123
+ ----------
124
+ N_CHAR_MAX : int, default=700
125
+ Maximum number of non-blank characters to show
126
+
127
+ Returns
128
+ -------
129
+ str
130
+ String representation of the representer
131
+ """
132
+ # Get all relevant attributes (excluding private ones and callables)
133
+ attributes = {
134
+ name: value
135
+ for name, value in sorted(self.__dict__.items())
136
+ if not name.startswith("_") and not callable(value)
137
+ }
138
+
139
+ def format_value(v):
140
+ """Format a value for representation."""
141
+ if isinstance(v, (float, np.float32, np.float64)):
142
+ return f"{v:.3g}"
143
+ elif isinstance(v, (list, tuple, np.ndarray)) and len(v) > 6:
144
+ return f"{str(v[:3])[:-1]}, ..., {str(v[-3:])[1:]}"
145
+ elif isinstance(v, str) and len(v) > 50:
146
+ return f"'{v[:25]}...{v[-22:]}'"
147
+ elif isinstance(v, dict) and len(v) > 6:
148
+ items = list(v.items())
149
+ return f"{dict(items[:3])}...{dict(items[-3:])}"
150
+ elif isinstance(v, torch.nn.Module):
151
+ return f"{v.__class__.__name__}(...)"
152
+ elif v is None:
153
+ return "None"
154
+ else:
155
+ return repr(v)
156
+
157
+ # Build the representation string
158
+ class_name = self.__class__.__name__
159
+ attributes_str = []
160
+
161
+ # First add important attributes that should appear first
162
+ important_attrs = ["model_name", "is_fitted_"]
163
+ for attr in important_attrs:
164
+ if attr in attributes:
165
+ value = attributes.pop(attr)
166
+ attributes_str.append(f"{attr}={format_value(value)}")
167
+
168
+ # Then add the rest
169
+ sorted_attrs = sorted(attributes.items())
170
+ attributes_str.extend(f"{name}={format_value(value)}" for name, value in sorted_attrs)
171
+
172
+ # Join all parts
173
+ content = ",\n ".join(attributes_str)
174
+ repr_ = f"{class_name}(\n {content}\n)"
175
+
176
+ # Handle length limit
177
+ if len(repr_) > N_CHAR_MAX:
178
+ lines = repr_.split("\n")
179
+
180
+ # Keep header
181
+ result = [lines[0]]
182
+ current_length = len(lines[0])
183
+
184
+ # Process middle lines
185
+ for line in lines[1:-1]:
186
+ if current_length + len(line) + 5 > N_CHAR_MAX: # 5 for "...\n"
187
+ result.append(" ...")
188
+ break
189
+ result.append(line)
190
+ current_length += len(line) + 1 # +1 for newline
191
+
192
+ # Add closing parenthesis
193
+ result.append(lines[-1])
194
+ repr_ = "\n".join(result)
195
+
196
+ return repr_
197
+
198
+ @abstractmethod
199
+ def _get_model_params(self, checkpoint: Optional[Dict] = None) -> Dict[str, Any]:
200
+ raise NotImplementedError(
201
+ "Method _get_model_params must be implemented by child class. "
202
+ "This method should return a dictionary of model parameters either "
203
+ "from a checkpoint or current instance values."
204
+ )
205
+
206
+ def _initialize_model(
207
+ self, model_class: Type[torch.nn.Module], device, checkpoint: Optional[Dict] = None
208
+ ) -> None:
209
+ """Initialize the model with given parameters or checkpoint.
210
+ """
211
+ try:
212
+ model_params = self._get_model_params(checkpoint)
213
+
214
+ # Initialize model with parameters
215
+ self.model = model_class(**model_params)
216
+
217
+ # Move model to device
218
+ try:
219
+ self.model = self.model.to(device)
220
+ except Exception as e:
221
+ raise RuntimeError(f"Failed to move model to device {device}: {str(e)}")
222
+
223
+ # Load state dict if provided in checkpoint
224
+ if checkpoint is not None:
225
+ try:
226
+ self.model.load_state_dict(checkpoint["model_state_dict"])
227
+ except Exception as e:
228
+ raise ValueError(f"Failed to load model state dictionary: {str(e)}")
229
+
230
+ except Exception as e:
231
+ raise RuntimeError(f"Model initialization failed: {str(e)}")
232
+
233
+ @staticmethod
234
+ def _get_param_names() -> List[str]:
235
+ return ["model_name", "is_fitted_"]
236
+
237
+ def _validate_inputs(
238
+ self, X: List[str], y: Optional[Union[List, np.ndarray]] = None, return_rdkit_mol: bool = True, num_task: int = 0, predefined_num_task: int = 0
239
+ ) -> Tuple[Union[List[str], List["Mol"]], Optional[np.ndarray]]:
240
+ return MolecularInputChecker.validate_inputs(X, y, num_task, predefined_num_task, return_rdkit_mol)
241
+
242
+ def _inspect_task_types(self, y: Union[np.ndarray, torch.Tensor], return_type: Literal["pt", "np"] = "pt") -> Union[np.ndarray, torch.Tensor]:
243
+ """Inspect the task types of the target values.
244
+
245
+ Parameters
246
+ ----------
247
+ y : Union[np.ndarray, torch.Tensor]
248
+ Target values: 2D array for multiple tasks
249
+ return_type : Literal["pt", "np"], default="pt"
250
+ Return type of the result
251
+
252
+ Returns
253
+ -------
254
+ result : Union[np.ndarray, torch.Tensor]
255
+ Result of the task types inspection
256
+ """
257
+ if isinstance(y, np.ndarray):
258
+ y = torch.from_numpy(y)
259
+ # 0/1/nan -> binary classification (True), otherwise -> regression (False)
260
+ result = torch.tensor([torch.all(torch.isnan(y[:, i]) | (y[:, i] == 0) | (y[:, i] == 1)) for i in range(y.shape[1])], dtype=torch.bool)
261
+ if return_type == "np":
262
+ return result.numpy()
263
+ return result
264
+
265
+ def save_to_local(self, path: str) -> None:
266
+ """Save to local disk using LocalCheckpointManager."""
267
+ LocalCheckpointManager.save_model_to_local(self, path)
268
+
269
+ def load_from_local(self, path: str) -> None:
270
+ """Load from local disk using LocalCheckpointManager."""
271
+ LocalCheckpointManager.load_model_from_local(self, path)
272
+
273
+ def save_to_hf(
274
+ self,
275
+ repo_id: str,
276
+ task_id: str = "default",
277
+ metadata_dict: Optional[Dict[str, Any]] = None,
278
+ metrics: Optional[Dict[str, float]] = None,
279
+ commit_message: str = "Update model",
280
+ token: Optional[str] = None,
281
+ private: bool = False,
282
+ ) -> None:
283
+ HuggingFaceCheckpointManager.push_to_huggingface(
284
+ model_instance=self,
285
+ repo_id=repo_id,
286
+ task_id=task_id,
287
+ metadata_dict=metadata_dict,
288
+ metrics=metrics,
289
+ commit_message=commit_message,
290
+ token=token,
291
+ private=private,
292
+ )
293
+
294
+ def load_from_hf(self, repo_id: str, path: str) -> None:
295
+ """Download and load model from Hugging Face Hub."""
296
+ HuggingFaceCheckpointManager.load_model_from_hf(self, repo_id, path)
297
+
298
+ def save(self, path: Optional[str] = None, repo_id: Optional[str] = None, **kwargs) -> None:
299
+ """
300
+ Automatic save. If `repo_id` is given, push to Hugging Face Hub.
301
+ Otherwise, save to local path.
302
+ """
303
+ if repo_id is not None:
304
+ self.save_to_hf(repo_id=repo_id, **kwargs)
305
+ else:
306
+ if path is None:
307
+ raise ValueError("path must be provided if repo_id is not given.")
308
+ self.save_to_local(path)
309
+
310
+ def load(self, path: str, repo_id: Optional[str] = None) -> None:
311
+ """
312
+ Automatic load. If local `path` exists, load from there.
313
+ Otherwise, try loading from Hugging Face Hub if `repo_id` is given.
314
+ """
315
+ if os.path.exists(path):
316
+ self.load_from_local(path)
317
+ else:
318
+ if repo_id is None:
319
+ raise FileNotFoundError(
320
+ f"No local file found at '{path}' and no repo_id provided."
321
+ )
322
+ self.load_from_hf(repo_id, path)