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.
- torch_molecule/__init__.py +70 -0
- torch_molecule/base/__init__.py +8 -0
- torch_molecule/base/base.py +396 -0
- torch_molecule/base/encoder.py +44 -0
- torch_molecule/base/generator.py +24 -0
- torch_molecule/base/old_encoder.py +322 -0
- torch_molecule/base/old_predictor.py +904 -0
- torch_molecule/base/old_predictor2.py +436 -0
- torch_molecule/base/predictor.py +112 -0
- torch_molecule/encoder/attrmask/__init__.py +3 -0
- torch_molecule/encoder/attrmask/model.py +113 -0
- torch_molecule/encoder/attrmask/modeling_attrmask.py +304 -0
- torch_molecule/encoder/constant.py +13 -0
- torch_molecule/encoder/contextpred/__init__.py +3 -0
- torch_molecule/encoder/contextpred/model.py +207 -0
- torch_molecule/encoder/contextpred/modeling_contextpred.py +299 -0
- torch_molecule/encoder/contextpred/utils.py +206 -0
- torch_molecule/encoder/edgepred/__init__.py +3 -0
- torch_molecule/encoder/edgepred/model.py +104 -0
- torch_molecule/encoder/edgepred/modeling_edgepred.py +285 -0
- torch_molecule/encoder/graphmae/__init__.py +3 -0
- torch_molecule/encoder/graphmae/dataloader.py +206 -0
- torch_molecule/encoder/graphmae/model.py +137 -0
- torch_molecule/encoder/graphmae/modeling_graphmae.py +323 -0
- torch_molecule/encoder/infograph/__init__.py +3 -0
- torch_molecule/encoder/infograph/loss_function.py +128 -0
- torch_molecule/encoder/infograph/model.py +92 -0
- torch_molecule/encoder/infograph/modeling_infograph.py +301 -0
- torch_molecule/encoder/infograph/module.py +31 -0
- torch_molecule/encoder/moama/__init__.py +3 -0
- torch_molecule/encoder/moama/model.py +131 -0
- torch_molecule/encoder/moama/modeling_moama.py +307 -0
- torch_molecule/encoder/moama/utils.py +143 -0
- torch_molecule/encoder/pretrained/__init__.py +3 -0
- torch_molecule/encoder/pretrained/modeling_pretrained.py +274 -0
- torch_molecule/encoder/supervised/__init__.py +3 -0
- torch_molecule/encoder/supervised/model.py +97 -0
- torch_molecule/encoder/supervised/modeling_supervised.py +354 -0
- torch_molecule/generator/digress/__init__.py +3 -0
- torch_molecule/generator/digress/diffusion.py +194 -0
- torch_molecule/generator/digress/modeling_digress.py +503 -0
- torch_molecule/generator/digress/transformer.py +360 -0
- torch_molecule/generator/digress/utils.py +196 -0
- torch_molecule/generator/gdss/__init__.py +3 -0
- torch_molecule/generator/gdss/layers.py +257 -0
- torch_molecule/generator/gdss/model.py +204 -0
- torch_molecule/generator/gdss/modeling_gdss.py +474 -0
- torch_molecule/generator/gdss/sde.py +334 -0
- torch_molecule/generator/gdss/solver.py +227 -0
- torch_molecule/generator/gdss/toremove/ScoreNetworkA.py +167 -0
- torch_molecule/generator/gdss/toremove/ScoreNetworkX.py +85 -0
- torch_molecule/generator/gdss/utils.py +240 -0
- torch_molecule/generator/graph_dit/__init__.py +3 -0
- torch_molecule/generator/graph_dit/diffusion.py +188 -0
- torch_molecule/generator/graph_dit/modeling_graph_dit.py +581 -0
- torch_molecule/generator/graph_dit/transformer.py +207 -0
- torch_molecule/generator/graph_dit/utils.py +220 -0
- torch_molecule/generator/graph_ga/__init__.py +3 -0
- torch_molecule/generator/graph_ga/crossover.py +182 -0
- torch_molecule/generator/graph_ga/modeling_graph_ga.py +310 -0
- torch_molecule/generator/graph_ga/mutate.py +136 -0
- torch_molecule/generator/graph_ga/oracle.py +95 -0
- torch_molecule/generator/jtvae/__init__.py +3 -0
- torch_molecule/generator/jtvae/jtnn/chemutils.py +450 -0
- torch_molecule/generator/jtvae/jtnn/datautils.py +127 -0
- torch_molecule/generator/jtvae/jtnn/jtmpn.py +140 -0
- torch_molecule/generator/jtvae/jtnn/jtnn_dec.py +350 -0
- torch_molecule/generator/jtvae/jtnn/jtnn_enc.py +131 -0
- torch_molecule/generator/jtvae/jtnn/mol_tree.py +111 -0
- torch_molecule/generator/jtvae/jtnn/mpn.py +129 -0
- torch_molecule/generator/jtvae/jtnn/nnutils.py +66 -0
- torch_molecule/generator/jtvae/jtnn/vocab.py +31 -0
- torch_molecule/generator/jtvae/jtnn_vae.py +246 -0
- torch_molecule/generator/jtvae/modeling_jtvae.py +247 -0
- torch_molecule/generator/lstm/__init__.py +3 -0
- torch_molecule/generator/lstm/action_sampler.py +91 -0
- torch_molecule/generator/lstm/lstm.py +59 -0
- torch_molecule/generator/lstm/modeling_lstm.py +263 -0
- torch_molecule/generator/lstm/smiles_char_dict.py +123 -0
- torch_molecule/generator/lstm/utils.py +62 -0
- torch_molecule/generator/molgpt/__init__.py +3 -0
- torch_molecule/generator/molgpt/dataset.py +87 -0
- torch_molecule/generator/molgpt/gpt.py +251 -0
- torch_molecule/generator/molgpt/modeling_molgpt.py +427 -0
- torch_molecule/generator/pretrained/modeling_pretrained.py +1 -0
- torch_molecule/nn/__init__.py +16 -0
- torch_molecule/nn/attention.py +63 -0
- torch_molecule/nn/embedder.py +183 -0
- torch_molecule/nn/gnn.py +631 -0
- torch_molecule/nn/mlp.py +34 -0
- torch_molecule/predictor/bfgnn/__init__.py +3 -0
- torch_molecule/predictor/bfgnn/model.py +116 -0
- torch_molecule/predictor/bfgnn/modeling_bfgnn.py +81 -0
- torch_molecule/predictor/dir/__init__.py +3 -0
- torch_molecule/predictor/dir/model.py +235 -0
- torch_molecule/predictor/dir/modeling_dir.py +161 -0
- torch_molecule/predictor/dir/utils.py +40 -0
- torch_molecule/predictor/gnn/__init__.py +3 -0
- torch_molecule/predictor/gnn/model.py +114 -0
- torch_molecule/predictor/gnn/modeling_gnn.py +706 -0
- torch_molecule/predictor/gnn/old_modeling_gnn.py +707 -0
- torch_molecule/predictor/grea/__init__.py +3 -0
- torch_molecule/predictor/grea/model.py +190 -0
- torch_molecule/predictor/grea/modeling_grea.py +107 -0
- torch_molecule/predictor/grea/old1_features.py +229 -0
- torch_molecule/predictor/grea/old1_modeling_grea.py +493 -0
- torch_molecule/predictor/grea/utils.py +97 -0
- torch_molecule/predictor/grin/__init__.py +3 -0
- torch_molecule/predictor/grin/model.py +116 -0
- torch_molecule/predictor/grin/modeling_grin.py +91 -0
- torch_molecule/predictor/irm/__init__.py +3 -0
- torch_molecule/predictor/irm/model.py +127 -0
- torch_molecule/predictor/irm/modeling_irm.py +179 -0
- torch_molecule/predictor/lstm/__init__.py +3 -0
- torch_molecule/predictor/lstm/model.py +145 -0
- torch_molecule/predictor/lstm/modeling_lstm.py +627 -0
- torch_molecule/predictor/lstm/token_from_smiles.py +85 -0
- torch_molecule/predictor/old_modeling_graph.py +650 -0
- torch_molecule/predictor/rpgnn/__init__.py +3 -0
- torch_molecule/predictor/rpgnn/model.py +185 -0
- torch_molecule/predictor/rpgnn/modeling_rpgnn.py +76 -0
- torch_molecule/predictor/sgir/__init__.py +3 -0
- torch_molecule/predictor/sgir/modeling_sgir.py +260 -0
- torch_molecule/predictor/sgir/strategy.py +266 -0
- torch_molecule/predictor/smiles_transformer/__init__.py +3 -0
- torch_molecule/predictor/smiles_transformer/model.py +424 -0
- torch_molecule/predictor/smiles_transformer/modeling_transformer.py +252 -0
- torch_molecule/predictor/ssr/__init__.py +3 -0
- torch_molecule/predictor/ssr/model.py +283 -0
- torch_molecule/predictor/ssr/modeling_ssr.py +267 -0
- torch_molecule/predictor/ssr/utils.py +185 -0
- torch_molecule/utils/__init__.py +31 -0
- torch_molecule/utils/checker.py +158 -0
- torch_molecule/utils/checkpoint.py +294 -0
- torch_molecule/utils/format.py +140 -0
- torch_molecule/utils/generic/metrics.py +530 -0
- torch_molecule/utils/generic/pseudo_tasks.py +11 -0
- torch_molecule/utils/generic/weights.py +30 -0
- torch_molecule/utils/graph/features.py +178 -0
- torch_molecule/utils/graph/graph_from_smiles.py +134 -0
- torch_molecule/utils/graph/graph_to_smiles.py +312 -0
- torch_molecule/utils/hf.py +232 -0
- torch_molecule/utils/search.py +64 -0
- torch_molecule-0.1.0.dev2.dist-info/METADATA +243 -0
- torch_molecule-0.1.0.dev2.dist-info/RECORD +148 -0
- torch_molecule-0.1.0.dev2.dist-info/WHEEL +5 -0
- torch_molecule-0.1.0.dev2.dist-info/licenses/LICENSE +21 -0
- torch_molecule-0.1.0.dev2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
from tqdm import tqdm
|
|
3
|
+
from typing import Optional, Union, Dict, Any, Tuple, List, Literal
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
|
|
6
|
+
import torch
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from ...base import BaseMolecularEncoder
|
|
10
|
+
|
|
11
|
+
known_repos = [
|
|
12
|
+
"entropy/gpt2_zinc_87m",
|
|
13
|
+
"entropy/roberta_zinc_480m",
|
|
14
|
+
"ncfrey/ChemGPT-1.2B",
|
|
15
|
+
"ncfrey/ChemGPT-19M",
|
|
16
|
+
"ncfrey/ChemGPT-4.7M",
|
|
17
|
+
"DeepChem/ChemBERTa-77M-MTR",
|
|
18
|
+
"DeepChem/ChemBERTa-77M-MLM",
|
|
19
|
+
"DeepChem/ChemBERTa-10M-MTR",
|
|
20
|
+
"DeepChem/ChemBERTa-10M-MLM",
|
|
21
|
+
"DeepChem/ChemBERTa-5M-MLM",
|
|
22
|
+
"DeepChem/ChemBERTa-5M-MTR",
|
|
23
|
+
"unikei/bert-base-smiles",
|
|
24
|
+
'seyonec/ChemBERTa-zinc-base-v1'
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
known_add_bos_eos_list = ["entropy/gpt2_zinc_87m"]
|
|
28
|
+
|
|
29
|
+
@dataclass(init=False)
|
|
30
|
+
class HFPretrainedMolecularEncoder(BaseMolecularEncoder):
|
|
31
|
+
"""Implements Hugging Face pretrained transformer models as molecular encoders.
|
|
32
|
+
|
|
33
|
+
This class provides an interface to use pretrained transformer models from Hugging Face
|
|
34
|
+
as molecular encoders. It handles tokenization and encoding of molecular representations.
|
|
35
|
+
|
|
36
|
+
Tested models include:
|
|
37
|
+
|
|
38
|
+
- ChemGPT series (1.2B/19M/4.7M): GPT-Neo based models pretrained on PubChem10M dataset with SELFIES strings.
|
|
39
|
+
Output dimension: 2048.
|
|
40
|
+
|
|
41
|
+
repo_id: "ncfrey/ChemGPT-1.2B" (https://huggingface.co/ncfrey/ChemGPT-1.2B)
|
|
42
|
+
|
|
43
|
+
repo_id: "ncfrey/ChemGPT-19M" (https://huggingface.co/ncfrey/ChemGPT-19M)
|
|
44
|
+
|
|
45
|
+
repo_id: "ncfrey/ChemGPT-4.7M" (https://huggingface.co/ncfrey/ChemGPT-4.7M)
|
|
46
|
+
|
|
47
|
+
- GPT2-ZINC-87M: GPT-2 based model (87M parameters) pretrained on ZINC dataset with ~480M SMILES strings.
|
|
48
|
+
Output dimension: 768.
|
|
49
|
+
|
|
50
|
+
repo_id: "entropy/gpt2_zinc_87m" (https://huggingface.co/entropy/gpt2_zinc_87m)
|
|
51
|
+
|
|
52
|
+
- RoBERTa-ZINC-480M: RoBERTa based model (102M parameters) pretrained on ZINC dataset with ~480M SMILES strings.
|
|
53
|
+
Output dimension: 768.
|
|
54
|
+
|
|
55
|
+
repo_id: "entropy/roberta_zinc_480m" (https://huggingface.co/entropy/roberta_zinc_480m)
|
|
56
|
+
|
|
57
|
+
- ChemBERTa series: Available in multiple sizes (77M/10M/5M) and training objectives (MTR/MLM).
|
|
58
|
+
Output dimension: 384.
|
|
59
|
+
|
|
60
|
+
repo_id: "DeepChem/ChemBERTa-77M-MTR" (https://huggingface.co/DeepChem/ChemBERTa-77M-MTR)
|
|
61
|
+
|
|
62
|
+
repo_id: "DeepChem/ChemBERTa-77M-MLM" (https://huggingface.co/DeepChem/ChemBERTa-77M-MLM)
|
|
63
|
+
|
|
64
|
+
repo_id: "DeepChem/ChemBERTa-10M-MTR" (https://huggingface.co/DeepChem/ChemBERTa-10M-MTR)
|
|
65
|
+
|
|
66
|
+
repo_id: "DeepChem/ChemBERTa-10M-MLM" (https://huggingface.co/DeepChem/ChemBERTa-10M-MLM)
|
|
67
|
+
|
|
68
|
+
repo_id: "DeepChem/ChemBERTa-5M-MLM" (https://huggingface.co/DeepChem/ChemBERTa-5M-MLM)
|
|
69
|
+
|
|
70
|
+
repo_id: "DeepChem/ChemBERTa-5M-MTR" (https://huggingface.co/DeepChem/ChemBERTa-5M-MTR)
|
|
71
|
+
|
|
72
|
+
- UniKi/bert-base-smiles: BERT model pretrained on SMILES strings.
|
|
73
|
+
Output dimension: 768.
|
|
74
|
+
|
|
75
|
+
repo_id: "unikei/bert-base-smiles" (https://huggingface.co/unikei/bert-base-smiles)
|
|
76
|
+
|
|
77
|
+
- ChemBERTa-zinc-base-v1: RoBERTa model pretrained on ZINC dataset with ~100k SMILES strings.
|
|
78
|
+
Output dimension: 384.
|
|
79
|
+
|
|
80
|
+
repo_id: "seyonec/ChemBERTa-zinc-base-v1" (https://huggingface.co/seyonec/ChemBERTa-zinc-base-v1)
|
|
81
|
+
|
|
82
|
+
Other models accessible through the transformers library have not been explicitly tested but may still be compatible with this interface.
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
repo_id : str
|
|
87
|
+
The Hugging Face repository ID of the pretrained model.
|
|
88
|
+
max_length : int, default=128
|
|
89
|
+
Maximum sequence length for tokenization. Longer sequences will be truncated.
|
|
90
|
+
batch_size : int, default=128
|
|
91
|
+
Batch size used when encoding multiple molecules.
|
|
92
|
+
add_bos_eos : Optional[bool], default=None
|
|
93
|
+
Whether to add beginning/end of sequence tokens. If None, models in known_add_bos_eos_list will be set to True.
|
|
94
|
+
The current known_add_bos_eos_list includes: ["entropy/gpt2_zinc_87m"].
|
|
95
|
+
model_name : str, default="PretrainedMolecularEncoder"
|
|
96
|
+
Name identifier for the model instance.
|
|
97
|
+
verbose : bool, default=False
|
|
98
|
+
Whether to display progress information during encoding.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
repo_id: str
|
|
102
|
+
|
|
103
|
+
# Default arguments
|
|
104
|
+
max_length: int = 128
|
|
105
|
+
batch_size: int = 128
|
|
106
|
+
add_bos_eos: Optional[bool] = None
|
|
107
|
+
model_name: str = "PretrainedMolecularEncoder"
|
|
108
|
+
verbose: bool = False
|
|
109
|
+
|
|
110
|
+
def __init__(self, repo_id: str, max_length: int = 128, batch_size: int = 128, add_bos_eos: Optional[bool] = None,
|
|
111
|
+
model_name: str = "PretrainedMolecularEncoder", verbose: bool = False, **kwargs):
|
|
112
|
+
self.repo_id = repo_id
|
|
113
|
+
self.max_length = max_length
|
|
114
|
+
self.batch_size = batch_size
|
|
115
|
+
self.add_bos_eos = add_bos_eos
|
|
116
|
+
self.model_name = model_name
|
|
117
|
+
self.verbose = verbose
|
|
118
|
+
super().__init__(**kwargs)
|
|
119
|
+
|
|
120
|
+
def __post_init__(self):
|
|
121
|
+
super().__post_init__()
|
|
122
|
+
self._require_transformers()
|
|
123
|
+
self.fitting_epoch = -1
|
|
124
|
+
self.fitting_loss = -1
|
|
125
|
+
|
|
126
|
+
if self.repo_id not in known_repos:
|
|
127
|
+
warnings.warn(f"Unknown repo_id: {self.repo_id}. The class will try to load the model from HuggingFace, but it might fail.")
|
|
128
|
+
|
|
129
|
+
@staticmethod
|
|
130
|
+
def _get_param_names() -> List[str]:
|
|
131
|
+
"""Get parameter names for the estimator.
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
List[str]
|
|
136
|
+
List of parameter names that can be used for model configuration.
|
|
137
|
+
"""
|
|
138
|
+
return ["repo_id", "max_length", "model_name", "add_bos_eos"]
|
|
139
|
+
|
|
140
|
+
def _get_model_params(self) -> Dict[str, Any]:
|
|
141
|
+
raise NotImplementedError("PretrainedMolecularEncoder does not support model parameters.")
|
|
142
|
+
|
|
143
|
+
def _setup_optimizers(self) -> None:
|
|
144
|
+
raise NotImplementedError("PretrainedMolecularEncoder does not support training.")
|
|
145
|
+
|
|
146
|
+
def _train_epoch(self) -> None:
|
|
147
|
+
raise NotImplementedError("PretrainedMolecularEncoder does not support training.")
|
|
148
|
+
|
|
149
|
+
def save_to_local(self) -> None:
|
|
150
|
+
raise NotImplementedError("PretrainedMolecularEncoder does not support saving to local.")
|
|
151
|
+
|
|
152
|
+
def load_from_local(self) -> None:
|
|
153
|
+
raise NotImplementedError("PretrainedMolecularEncoder does not support loading from local.")
|
|
154
|
+
|
|
155
|
+
def save_to_hf(self) -> None:
|
|
156
|
+
raise NotImplementedError("PretrainedMolecularEncoder does not support saving to huggingface.")
|
|
157
|
+
|
|
158
|
+
def load_from_hf(self) -> None:
|
|
159
|
+
"""The same as fit()"""
|
|
160
|
+
self.fit()
|
|
161
|
+
|
|
162
|
+
def load(self) -> None:
|
|
163
|
+
"""The same as fit()"""
|
|
164
|
+
self.fit()
|
|
165
|
+
|
|
166
|
+
def fit(self) -> "HFPretrainedMolecularEncoder":
|
|
167
|
+
"""Load the pretrained model from HuggingFace."""
|
|
168
|
+
assert self.repo_id is not None, "repo_id is not set"
|
|
169
|
+
self._require_transformers()
|
|
170
|
+
import transformers
|
|
171
|
+
|
|
172
|
+
self.tokenizer = transformers.AutoTokenizer.from_pretrained(self.repo_id, max_length=self.max_length)
|
|
173
|
+
self.model = transformers.AutoModel.from_pretrained(self.repo_id)
|
|
174
|
+
self.model.to(self.device)
|
|
175
|
+
|
|
176
|
+
model_config = self.model.config
|
|
177
|
+
model_type = model_config.model_type
|
|
178
|
+
|
|
179
|
+
if self.add_bos_eos is None:
|
|
180
|
+
self.add_bos_eos = self.repo_id in known_add_bos_eos_list
|
|
181
|
+
|
|
182
|
+
if self.tokenizer.pad_token is None:
|
|
183
|
+
if self.tokenizer.eos_token is not None:
|
|
184
|
+
self.tokenizer.pad_token = self.tokenizer.eos_token
|
|
185
|
+
else:
|
|
186
|
+
self.tokenizer.add_special_tokens({'pad_token': '[PAD]'})
|
|
187
|
+
self.model.resize_token_embeddings(len(self.tokenizer))
|
|
188
|
+
|
|
189
|
+
if self.add_bos_eos:
|
|
190
|
+
if self.tokenizer.bos_token is None:
|
|
191
|
+
self.tokenizer.add_special_tokens({'bos_token': '[BOS]'})
|
|
192
|
+
if self.tokenizer.eos_token is None:
|
|
193
|
+
self.tokenizer.add_special_tokens({'eos_token': '[EOS]'})
|
|
194
|
+
self.model.resize_token_embeddings(len(self.tokenizer))
|
|
195
|
+
|
|
196
|
+
warnings.warn("BOS and EOS tokens are not found in the tokenizer. They are added to the tokenizer since add_bos_eos is set to True.")
|
|
197
|
+
|
|
198
|
+
self.collator = transformers.DataCollatorWithPadding(self.tokenizer, padding=True, return_tensors='pt')
|
|
199
|
+
self.is_fitted_ = True
|
|
200
|
+
return self
|
|
201
|
+
|
|
202
|
+
def encode(self, X: List[str], return_type: Literal["np", "pt"] = "pt") -> Union[np.ndarray, torch.Tensor]:
|
|
203
|
+
"""Encode molecules into vector representations.
|
|
204
|
+
|
|
205
|
+
Parameters
|
|
206
|
+
----------
|
|
207
|
+
X : List[str]
|
|
208
|
+
List of SMILES strings
|
|
209
|
+
return_type : Literal["np", "pt"], default="pt"
|
|
210
|
+
Return type of the representations
|
|
211
|
+
|
|
212
|
+
Returns
|
|
213
|
+
-------
|
|
214
|
+
representations : ndarray or torch.Tensor
|
|
215
|
+
Molecular representations
|
|
216
|
+
"""
|
|
217
|
+
self._require_transformers()
|
|
218
|
+
self._check_is_fitted()
|
|
219
|
+
X, _ = self._validate_inputs(X, return_rdkit_mol=False)
|
|
220
|
+
|
|
221
|
+
# Process in batches
|
|
222
|
+
all_embeddings = []
|
|
223
|
+
iterator = tqdm(range(0, len(X), self.batch_size), desc="Encoding molecules", total=len(X) // self.batch_size, disable=not self.verbose)
|
|
224
|
+
for i in iterator:
|
|
225
|
+
batch_X = X[i:i + self.batch_size]
|
|
226
|
+
|
|
227
|
+
if self.add_bos_eos:
|
|
228
|
+
# For decoding models (e.g. GPT2), manually add BOS and EOS tokens
|
|
229
|
+
processed_batch = [self.tokenizer.bos_token + x + self.tokenizer.eos_token for x in batch_X]
|
|
230
|
+
inputs = self.collator(self.tokenizer(processed_batch))
|
|
231
|
+
else:
|
|
232
|
+
inputs = self.collator(self.tokenizer(batch_X))
|
|
233
|
+
|
|
234
|
+
# Move inputs to the same device as the model
|
|
235
|
+
inputs = {k: v.to(self.device) for k, v in inputs.items()}
|
|
236
|
+
|
|
237
|
+
# Get model outputs
|
|
238
|
+
with torch.no_grad():
|
|
239
|
+
outputs = self.model(**inputs, output_hidden_states=True)
|
|
240
|
+
|
|
241
|
+
# get all attributes of outputs
|
|
242
|
+
print('outputs', outputs.keys())
|
|
243
|
+
# Extract embeddings based on model type
|
|
244
|
+
if hasattr(outputs, 'hidden_states'):
|
|
245
|
+
# For models that return a named tuple
|
|
246
|
+
full_embeddings = outputs.hidden_states[-1]
|
|
247
|
+
elif isinstance(outputs, tuple) and len(outputs) > 1:
|
|
248
|
+
# For models that return a tuple with hidden states
|
|
249
|
+
full_embeddings = outputs[-1][-1]
|
|
250
|
+
else:
|
|
251
|
+
# For models that return last_hidden_state directly
|
|
252
|
+
full_embeddings = outputs.last_hidden_state
|
|
253
|
+
|
|
254
|
+
# Apply attention mask to get meaningful embeddings
|
|
255
|
+
mask = inputs['attention_mask']
|
|
256
|
+
batch_embeddings = ((full_embeddings * mask.unsqueeze(-1)).sum(1) /
|
|
257
|
+
mask.sum(-1).unsqueeze(-1))
|
|
258
|
+
|
|
259
|
+
all_embeddings.append(batch_embeddings)
|
|
260
|
+
|
|
261
|
+
# Concatenate all batch embeddings
|
|
262
|
+
embeddings = torch.cat(all_embeddings, dim=0)
|
|
263
|
+
|
|
264
|
+
return embeddings if return_type == "pt" else embeddings.cpu().numpy()
|
|
265
|
+
|
|
266
|
+
@staticmethod
|
|
267
|
+
def _require_transformers():
|
|
268
|
+
try:
|
|
269
|
+
import transformers # noqa: F401
|
|
270
|
+
except ImportError:
|
|
271
|
+
raise ImportError(
|
|
272
|
+
"The 'transformers' package is required for PretrainedMolecularEncoder. "
|
|
273
|
+
"Please install it using `pip install transformers`."
|
|
274
|
+
)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
import torch.nn as nn
|
|
3
|
+
from torch_geometric.nn import global_add_pool, global_mean_pool, global_max_pool
|
|
4
|
+
|
|
5
|
+
from ...nn import GNN_node, GNN_node_Virtualnode, MLP
|
|
6
|
+
from ...utils import init_weights
|
|
7
|
+
|
|
8
|
+
reg_criterion = torch.nn.L1Loss()
|
|
9
|
+
class_criterion = torch.nn.BCEWithLogitsLoss()
|
|
10
|
+
|
|
11
|
+
class GNN(nn.Module):
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
num_layer,
|
|
15
|
+
hidden_size,
|
|
16
|
+
num_task,
|
|
17
|
+
drop_ratio=0.5,
|
|
18
|
+
norm_layer="batch_norm",
|
|
19
|
+
encoder_type="gin-virtual",
|
|
20
|
+
readout="max",
|
|
21
|
+
):
|
|
22
|
+
super(GNN, self).__init__()
|
|
23
|
+
gnn_name = encoder_type.split("-")[0]
|
|
24
|
+
self.num_task = num_task
|
|
25
|
+
self.hidden_size = hidden_size
|
|
26
|
+
|
|
27
|
+
encoder_params = {
|
|
28
|
+
"num_layer": num_layer,
|
|
29
|
+
"hidden_size": hidden_size,
|
|
30
|
+
"JK": "last",
|
|
31
|
+
"drop_ratio": drop_ratio,
|
|
32
|
+
"residual": True,
|
|
33
|
+
"gnn_name": gnn_name,
|
|
34
|
+
"norm_layer": norm_layer
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Choose encoder type based on encoder
|
|
38
|
+
encoder_class = GNN_node_Virtualnode if "virtual" in encoder_type else GNN_node
|
|
39
|
+
self.graph_encoder = encoder_class(**encoder_params)
|
|
40
|
+
pooling_funcs = {
|
|
41
|
+
"sum": global_add_pool,
|
|
42
|
+
"mean": global_mean_pool,
|
|
43
|
+
"max": global_max_pool
|
|
44
|
+
}
|
|
45
|
+
self.readout = pooling_funcs.get(readout)
|
|
46
|
+
if self.readout is None:
|
|
47
|
+
raise ValueError(f"Invalid graph pooling type {readout}.")
|
|
48
|
+
|
|
49
|
+
self.predictor = MLP(hidden_size, hidden_features=2 * hidden_size, out_features=num_task)
|
|
50
|
+
|
|
51
|
+
def initialize_parameters(self, seed=None):
|
|
52
|
+
"""
|
|
53
|
+
Randomly initialize all model parameters using the init_weights function.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
seed (int, optional): Random seed for reproducibility. Defaults to None.
|
|
57
|
+
"""
|
|
58
|
+
if seed is not None:
|
|
59
|
+
torch.manual_seed(seed)
|
|
60
|
+
|
|
61
|
+
# Initialize the main components
|
|
62
|
+
init_weights(self.graph_encoder)
|
|
63
|
+
init_weights(self.predictor)
|
|
64
|
+
|
|
65
|
+
# Reset all parameters using PyTorch Geometric's reset function
|
|
66
|
+
def reset_parameters(module):
|
|
67
|
+
if hasattr(module, 'reset_parameters'):
|
|
68
|
+
module.reset_parameters()
|
|
69
|
+
elif hasattr(module, 'weight') and hasattr(module.weight, 'data'):
|
|
70
|
+
init_weights(module)
|
|
71
|
+
|
|
72
|
+
self.apply(reset_parameters)
|
|
73
|
+
|
|
74
|
+
def compute_loss(self, batched_data, is_class):
|
|
75
|
+
h_node, _ = self.graph_encoder(batched_data)
|
|
76
|
+
h_rep = self.readout(h_node, batched_data.batch)
|
|
77
|
+
prediction = self.predictor(h_rep)
|
|
78
|
+
|
|
79
|
+
target = batched_data.y.to(torch.float32)
|
|
80
|
+
is_labeled = ~torch.isnan(target)
|
|
81
|
+
is_labeled_class = is_labeled[:, is_class]
|
|
82
|
+
is_labeled_reg = is_labeled[:, ~is_class]
|
|
83
|
+
|
|
84
|
+
target_class = target[:, is_class]
|
|
85
|
+
target_reg = target[:, ~is_class]
|
|
86
|
+
prediction_class = prediction[:, is_class]
|
|
87
|
+
prediction_reg = prediction[:, ~is_class]
|
|
88
|
+
|
|
89
|
+
loss_class = class_criterion(prediction_class.to(torch.float32)[is_labeled_class], target_class[is_labeled_class])
|
|
90
|
+
loss_reg = reg_criterion(prediction_reg.to(torch.float32)[is_labeled_reg], target_reg[is_labeled_reg])
|
|
91
|
+
loss = loss_class + loss_reg
|
|
92
|
+
return loss
|
|
93
|
+
|
|
94
|
+
def forward(self, batched_data):
|
|
95
|
+
h_node, _ = self.graph_encoder(batched_data)
|
|
96
|
+
h_rep = self.readout(h_node, batched_data.batch)
|
|
97
|
+
return {"graph": h_rep, "node": h_node}
|