Safetensors
yinuozhang commited on
Commit
aa45001
·
verified ·
1 Parent(s): fdef61b

Add computational release from Zenodo 22960654

Browse files
Files changed (49) hide show
  1. .gitattributes +3 -0
  2. Computational/README.md +111 -0
  3. Computational/package/APACHE-2.0.txt +201 -0
  4. Computational/package/THIRD_PARTY_NOTICES.md +10 -0
  5. Computational/package/assets/esm2_t33_650M_UR50D/LICENSE +21 -0
  6. Computational/package/assets/esm2_t33_650M_UR50D/config.json +29 -0
  7. Computational/package/assets/esm2_t33_650M_UR50D/model.safetensors +3 -0
  8. Computational/package/assets/esm2_t33_650M_UR50D/special_tokens_map.json +7 -0
  9. Computational/package/assets/esm2_t33_650M_UR50D/tokenizer_config.json +4 -0
  10. Computational/package/assets/esm2_t33_650M_UR50D/vocab.txt +33 -0
  11. Computational/package/checkpoints/metalatte_predictor.ckpt +3 -0
  12. Computational/package/checkpoints/metalorian_diffusion.pt +3 -0
  13. Computational/package/data/MbPA/mbpa_source_export.csv +3 -0
  14. Computational/package/data/MbPA/mbpa_training_sequences.csv +3 -0
  15. Computational/package/data/metalatte/train/data-00000-of-00004.arrow +3 -0
  16. Computational/package/data/metalatte/train/data-00001-of-00004.arrow +3 -0
  17. Computational/package/data/metalatte/train/data-00002-of-00004.arrow +3 -0
  18. Computational/package/data/metalatte/train/data-00003-of-00004.arrow +3 -0
  19. Computational/package/data/metalatte/train/dataset_info.json +128 -0
  20. Computational/package/data/metalatte/train/state.json +22 -0
  21. Computational/package/data/metalatte/validation/data-00000-of-00001.arrow +3 -0
  22. Computational/package/data/metalatte/validation/dataset_info.json +128 -0
  23. Computational/package/data/metalatte/validation/state.json +13 -0
  24. Computational/package/data/metalorian/test/data-00000-of-00001.arrow +3 -0
  25. Computational/package/data/metalorian/test/dataset_info.json +29 -0
  26. Computational/package/data/metalorian/test/state.json +13 -0
  27. Computational/package/data/metalorian/train/data-00000-of-00001.arrow +3 -0
  28. Computational/package/data/metalorian/train/dataset_info.json +29 -0
  29. Computational/package/data/metalorian/train/state.json +13 -0
  30. Computational/package/metalorian/__init__.py +1 -0
  31. Computational/package/metalorian/cli.py +83 -0
  32. Computational/package/metalorian/continuous.py +202 -0
  33. Computational/package/metalorian/data.py +35 -0
  34. Computational/package/metalorian/discrete.py +276 -0
  35. Computational/package/metalorian/layers.py +164 -0
  36. Computational/package/metalorian/objectives.py +76 -0
  37. Computational/package/metalorian/paths.py +35 -0
  38. Computational/package/metalorian/predictor.py +585 -0
  39. Computational/package/metalorian/sampling.py +173 -0
  40. Computational/package/metalorian/unet.py +93 -0
  41. Computational/package/requirements.txt +14 -0
  42. Computational/package/sample_direct.py +174 -0
  43. Computational/package/sample_prototype.py +129 -0
  44. Computational/package/train.py +219 -0
  45. Computational/validation/figures/amino_acid_composition_difference_full_reference_predictor_gated_n500.csv +81 -0
  46. Computational/validation/figures/amino_acid_composition_difference_overall_full_reference_predictor_gated_n500.csv +21 -0
  47. Computational/validation/figures/physicochemical_properties_full_reference.csv +3 -0
  48. Computational/validation/figures/physicochemical_summary_predictor_gated_n500.csv +49 -0
  49. Computational/validation/sampling_smoke.slurm +18 -0
.gitattributes CHANGED
@@ -37,3 +37,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
37
  *.png filter=lfs diff=lfs merge=lfs -text
38
  figures/*.png filter=lfs diff=lfs merge=lfs -text
39
  figures/*.jpg filter=lfs diff=lfs merge=lfs -text
 
 
 
 
37
  *.png filter=lfs diff=lfs merge=lfs -text
38
  figures/*.png filter=lfs diff=lfs merge=lfs -text
39
  figures/*.jpg filter=lfs diff=lfs merge=lfs -text
40
+ Computational/package/data/MbPA/mbpa_source_export.csv filter=lfs diff=lfs merge=lfs -text
41
+ Computational/package/data/MbPA/mbpa_training_sequences.csv filter=lfs diff=lfs merge=lfs -text
42
+ Computational/validation/figures/physicochemical_properties_full_reference.csv filter=lfs diff=lfs merge=lfs -text
Computational/README.md ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Metalorian / MetaLATTE
3
+
4
+ ---
5
+
6
+ # Repo structure
7
+
8
+ ```text
9
+ train.py Train either stage with --stage
10
+ sample_direct.py Direct sampling
11
+ sample_prototype.py Prototype-seeded sampling
12
+ metalorian/ Models and support functions
13
+ data/metalatte/ Training and validation split
14
+ data/metalorian/ Diffusion sequence-label training and test split
15
+ data/MbPA/ Original MbPA CSV exports
16
+ checkpoints/ Predictor and diffusion checkpoints
17
+ assets/ Local ESM-2 backbone and tokenizer
18
+ requirements.txt
19
+ ```
20
+
21
+ ## Install
22
+
23
+ Use Python 3.10. Run from this directory:
24
+
25
+ ```bash
26
+ python3.10 -m venv .venv
27
+ source .venv/bin/activate
28
+ python -m pip install -r requirements.txt
29
+ ```
30
+
31
+ Weights and tokenizer files are included for offline use after installation.
32
+ Use a CUDA-capable PyTorch installation. For CPU checks, pass `--device cpu`.
33
+
34
+ ## Data
35
+
36
+ | Split | Records |
37
+ | --- | ---: |
38
+ | `data/metalatte/train` | 50,694 groups |
39
+ | `data/metalatte/validation` | 12,729 groups |
40
+ | `data/metalorian/train` | 38,123 sequence-label records |
41
+ | `data/metalorian/test` | 9,531 sequence-label records |
42
+
43
+ MetaLATTE groups are stored in 1,852 training pre-batches and 460 validation
44
+ pre-batches.
45
+ Metalorian uses the separate sequence-label splits listed above.
46
+
47
+ `data/MbPA/` contains eight original CSV exports, aggregated from 14 different metal labels. File names, row counts and
48
+ hashes are listed in `provenance/mbpa_inventory.csv`.
49
+
50
+ ## Train either stage
51
+
52
+ MetaLATTE, initialized from pretrained ESM-2:
53
+
54
+ ```bash
55
+ python train.py --stage metalatte --epochs 30 --device cuda:0 \
56
+ --output runs/metalatte
57
+ ```
58
+
59
+ To start from the supplied predictor, add
60
+ `--init-checkpoint checkpoints/metalatte_predictor.ckpt`.
61
+ To resume training and optimizer state, use `--resume PATH`.
62
+
63
+ Metalorian, initialized from the supplied MetaLATTE predictor:
64
+
65
+ ```bash
66
+ python train.py --stage metalorian --epochs 1 --batch-size 2 --device cuda:0 \
67
+ --output runs/metalorian
68
+ ```
69
+
70
+ Use `--init-checkpoint PATH` for another MetaLATTE checkpoint, or
71
+ `--resume checkpoints/metalorian_diffusion.pt` to resume diffusion training.
72
+ Here, `--epochs` counts additional passes through the training set.
73
+ Outputs are `metalorian_latest.pt` in the output directory.
74
+
75
+ Short forward/backward checks for both stages:
76
+
77
+ ```bash
78
+ python train.py --stage metalatte --smoke-test --device cpu \
79
+ --init-checkpoint checkpoints/metalatte_predictor.ckpt --output runs/check_metalatte
80
+ python train.py --stage metalorian --smoke-test --batch-size 2 --device cpu \
81
+ --output runs/check_metalorian
82
+ ```
83
+
84
+ `--smoke-test` uses at most two records and 64 tokens for one update and writes
85
+ no model checkpoint. Training uses one device; see `VALIDATION.md` for checks.
86
+
87
+ ## Direct sampling
88
+
89
+ ```bash
90
+ python sample_direct.py --target_idx 3 --seq_len 30 --batch 1 \
91
+ --desired 1 --max_rounds 20 --output outputs/Cu_L30.csv
92
+ ```
93
+
94
+ ## Prototype-seeded sampling
95
+
96
+ ```bash
97
+ python sample_prototype.py --target_idx 1 --seq_len 30 --batch 1 \
98
+ --proto MDPETCPCPSGGSCTCADSCKCEGCKCTSCKKSCCSCCPAECEKCAKDCVCKGGEAAEAEAEKCSCCQ \
99
+ --t_start 15 --desired 1 --max_rounds 20 --output outputs/Cd_L30.csv
100
+ ```
101
+
102
+ ```text
103
+ Metal indices: 0 Ag, 1 Cd, 2 Co, 3 Cu, 4 Fe, 5 Hg, 6 Mn, 7 Mo,
104
+ 8 Ni, 9 Pb, 10 Pt, 11 V, 12 W, 13 Zn, 14 NA
105
+ ```
106
+
107
+ Both scripts load `checkpoints/metalatte_predictor.ckpt` and
108
+ `checkpoints/metalorian_diffusion.pt`. Use `--help` for sampling options.
109
+
110
+ The CSV contains unique accepted sequences; the adjacent JSON records settings
111
+ and counts. A run may return fewer than `--desired` at `--max_rounds`.
Computational/package/APACHE-2.0.txt ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
Computational/package/THIRD_PARTY_NOTICES.md ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # Third-party materials
2
+
3
+ The ESM-2 backbone and tokenizer are from
4
+ https://huggingface.co/facebook/esm2_t33_650M_UR50D.
5
+ The ESM project license is included at `assets/esm2_t33_650M_UR50D/LICENSE`.
6
+
7
+ The layer and tabular network modules retain the original Google Research
8
+ copyright and Apache License 2.0 headers; the license text is in `APACHE-2.0.txt`.
9
+
10
+ A project-wide license for the research code and data has not been assigned.
Computational/package/assets/esm2_t33_650M_UR50D/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) Meta Platforms, Inc. and affiliates.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
Computational/package/assets/esm2_t33_650M_UR50D/config.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "EsmForMaskedLM"
4
+ ],
5
+ "attention_probs_dropout_prob": 0.0,
6
+ "classifier_dropout": null,
7
+ "emb_layer_norm_before": false,
8
+ "esmfold_config": null,
9
+ "hidden_act": "gelu",
10
+ "hidden_dropout_prob": 0.0,
11
+ "hidden_size": 1280,
12
+ "initializer_range": 0.02,
13
+ "intermediate_size": 5120,
14
+ "is_folding_model": false,
15
+ "layer_norm_eps": 1e-05,
16
+ "mask_token_id": 32,
17
+ "max_position_embeddings": 1026,
18
+ "model_type": "esm",
19
+ "num_attention_heads": 20,
20
+ "num_hidden_layers": 33,
21
+ "pad_token_id": 1,
22
+ "position_embedding_type": "rotary",
23
+ "token_dropout": true,
24
+ "torch_dtype": "float32",
25
+ "transformers_version": "4.25.0.dev0",
26
+ "use_cache": true,
27
+ "vocab_list": null,
28
+ "vocab_size": 33
29
+ }
Computational/package/assets/esm2_t33_650M_UR50D/model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a08adabb949fa67ad3c14b509d04fd60368b35007b0095e3358f81200c4f4db0
3
+ size 2609506392
Computational/package/assets/esm2_t33_650M_UR50D/special_tokens_map.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "cls_token": "<cls>",
3
+ "eos_token": "<eos>",
4
+ "mask_token": "<mask>",
5
+ "pad_token": "<pad>",
6
+ "unk_token": "<unk>"
7
+ }
Computational/package/assets/esm2_t33_650M_UR50D/tokenizer_config.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "model_max_length": 1000000000000000019884624838656,
3
+ "tokenizer_class": "EsmTokenizer"
4
+ }
Computational/package/assets/esm2_t33_650M_UR50D/vocab.txt ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <cls>
2
+ <pad>
3
+ <eos>
4
+ <unk>
5
+ L
6
+ A
7
+ G
8
+ V
9
+ S
10
+ E
11
+ R
12
+ T
13
+ I
14
+ D
15
+ P
16
+ K
17
+ Q
18
+ N
19
+ F
20
+ Y
21
+ M
22
+ H
23
+ W
24
+ C
25
+ X
26
+ B
27
+ U
28
+ Z
29
+ O
30
+ .
31
+ -
32
+ <null_1>
33
+ <mask>
Computational/package/checkpoints/metalatte_predictor.ckpt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4a4b1eda0e66924a059f0bd2b6210142d24d37049bef6908ada05fb9195a83da
3
+ size 5676931901
Computational/package/checkpoints/metalorian_diffusion.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:04573e26f68a073e28306358eb75b2590970ddf443834bf5456cda06939063ad
3
+ size 4312375727
Computational/package/data/MbPA/mbpa_source_export.csv ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f10ed8374cd6a6831b223f75571f0e3102a49a28eec08b93deadb2c0b5ee8009
3
+ size 32964432
Computational/package/data/MbPA/mbpa_training_sequences.csv ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ee5cf56d9bec7fde2ead9d5186c2fc15f8786d3868fbe70ccbf9a6ab35f8aec4
3
+ size 22077531
Computational/package/data/metalatte/train/data-00000-of-00004.arrow ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f4a75af46db2fa53ddbde45446837bd7c858a7468210ef154ebbf76992471c98
3
+ size 541629744
Computational/package/data/metalatte/train/data-00001-of-00004.arrow ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fec5eebb35722dc2e962220712cf93b15b798f8042acfe78704a2dc43b0d431b
3
+ size 481637120
Computational/package/data/metalatte/train/data-00002-of-00004.arrow ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:94ef28a901f2df61bb92e983387219e6bfba6e5f3cdce04d60e126ff0419d3ea
3
+ size 450713552
Computational/package/data/metalatte/train/data-00003-of-00004.arrow ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fe69145deb459cad11d12569ede3930f6add4be0052b4d42c5931e4af46392d4
3
+ size 407762112
Computational/package/data/metalatte/train/dataset_info.json ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "citation": "",
3
+ "description": "",
4
+ "features": {
5
+ "anchor_input_ids": {
6
+ "feature": {
7
+ "feature": {
8
+ "dtype": "int64",
9
+ "_type": "Value"
10
+ },
11
+ "_type": "List"
12
+ },
13
+ "_type": "List"
14
+ },
15
+ "anchor_attention_mask": {
16
+ "feature": {
17
+ "feature": {
18
+ "dtype": "int64",
19
+ "_type": "Value"
20
+ },
21
+ "_type": "List"
22
+ },
23
+ "_type": "List"
24
+ },
25
+ "positive_input_ids": {
26
+ "feature": {
27
+ "feature": {
28
+ "dtype": "int64",
29
+ "_type": "Value"
30
+ },
31
+ "_type": "List"
32
+ },
33
+ "_type": "List"
34
+ },
35
+ "positive_attention_mask": {
36
+ "feature": {
37
+ "feature": {
38
+ "dtype": "int64",
39
+ "_type": "Value"
40
+ },
41
+ "_type": "List"
42
+ },
43
+ "_type": "List"
44
+ },
45
+ "negative_input_ids": {
46
+ "feature": {
47
+ "feature": {
48
+ "dtype": "int64",
49
+ "_type": "Value"
50
+ },
51
+ "_type": "List"
52
+ },
53
+ "_type": "List"
54
+ },
55
+ "negative_attention_mask": {
56
+ "feature": {
57
+ "feature": {
58
+ "dtype": "int64",
59
+ "_type": "Value"
60
+ },
61
+ "_type": "List"
62
+ },
63
+ "_type": "List"
64
+ },
65
+ "hard_negative_input_ids": {
66
+ "feature": {
67
+ "feature": {
68
+ "dtype": "int64",
69
+ "_type": "Value"
70
+ },
71
+ "_type": "List"
72
+ },
73
+ "_type": "List"
74
+ },
75
+ "hard_negative_attention_mask": {
76
+ "feature": {
77
+ "feature": {
78
+ "dtype": "int64",
79
+ "_type": "Value"
80
+ },
81
+ "_type": "List"
82
+ },
83
+ "_type": "List"
84
+ },
85
+ "anchor_labels": {
86
+ "feature": {
87
+ "feature": {
88
+ "dtype": "float32",
89
+ "_type": "Value"
90
+ },
91
+ "_type": "List"
92
+ },
93
+ "_type": "List"
94
+ },
95
+ "positive_labels": {
96
+ "feature": {
97
+ "feature": {
98
+ "dtype": "float32",
99
+ "_type": "Value"
100
+ },
101
+ "_type": "List"
102
+ },
103
+ "_type": "List"
104
+ },
105
+ "negative_labels": {
106
+ "feature": {
107
+ "feature": {
108
+ "dtype": "float32",
109
+ "_type": "Value"
110
+ },
111
+ "_type": "List"
112
+ },
113
+ "_type": "List"
114
+ },
115
+ "hard_negative_labels": {
116
+ "feature": {
117
+ "feature": {
118
+ "dtype": "float32",
119
+ "_type": "Value"
120
+ },
121
+ "_type": "List"
122
+ },
123
+ "_type": "List"
124
+ }
125
+ },
126
+ "homepage": "",
127
+ "license": ""
128
+ }
Computational/package/data/metalatte/train/state.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_data_files": [
3
+ {
4
+ "filename": "data-00000-of-00004.arrow"
5
+ },
6
+ {
7
+ "filename": "data-00001-of-00004.arrow"
8
+ },
9
+ {
10
+ "filename": "data-00002-of-00004.arrow"
11
+ },
12
+ {
13
+ "filename": "data-00003-of-00004.arrow"
14
+ }
15
+ ],
16
+ "_fingerprint": "3566914580fe3dd1",
17
+ "_format_columns": null,
18
+ "_format_kwargs": {},
19
+ "_format_type": null,
20
+ "_output_all_columns": false,
21
+ "_split": null
22
+ }
Computational/package/data/metalatte/validation/data-00000-of-00001.arrow ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:442bd690d79e20e06418584eaf88f168714b5fd455a4ca51146c4910fa2b65d7
3
+ size 469003504
Computational/package/data/metalatte/validation/dataset_info.json ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "citation": "",
3
+ "description": "",
4
+ "features": {
5
+ "anchor_input_ids": {
6
+ "feature": {
7
+ "feature": {
8
+ "dtype": "int64",
9
+ "_type": "Value"
10
+ },
11
+ "_type": "List"
12
+ },
13
+ "_type": "List"
14
+ },
15
+ "anchor_attention_mask": {
16
+ "feature": {
17
+ "feature": {
18
+ "dtype": "int64",
19
+ "_type": "Value"
20
+ },
21
+ "_type": "List"
22
+ },
23
+ "_type": "List"
24
+ },
25
+ "positive_input_ids": {
26
+ "feature": {
27
+ "feature": {
28
+ "dtype": "int64",
29
+ "_type": "Value"
30
+ },
31
+ "_type": "List"
32
+ },
33
+ "_type": "List"
34
+ },
35
+ "positive_attention_mask": {
36
+ "feature": {
37
+ "feature": {
38
+ "dtype": "int64",
39
+ "_type": "Value"
40
+ },
41
+ "_type": "List"
42
+ },
43
+ "_type": "List"
44
+ },
45
+ "negative_input_ids": {
46
+ "feature": {
47
+ "feature": {
48
+ "dtype": "int64",
49
+ "_type": "Value"
50
+ },
51
+ "_type": "List"
52
+ },
53
+ "_type": "List"
54
+ },
55
+ "negative_attention_mask": {
56
+ "feature": {
57
+ "feature": {
58
+ "dtype": "int64",
59
+ "_type": "Value"
60
+ },
61
+ "_type": "List"
62
+ },
63
+ "_type": "List"
64
+ },
65
+ "hard_negative_input_ids": {
66
+ "feature": {
67
+ "feature": {
68
+ "dtype": "int64",
69
+ "_type": "Value"
70
+ },
71
+ "_type": "List"
72
+ },
73
+ "_type": "List"
74
+ },
75
+ "hard_negative_attention_mask": {
76
+ "feature": {
77
+ "feature": {
78
+ "dtype": "int64",
79
+ "_type": "Value"
80
+ },
81
+ "_type": "List"
82
+ },
83
+ "_type": "List"
84
+ },
85
+ "anchor_labels": {
86
+ "feature": {
87
+ "feature": {
88
+ "dtype": "float32",
89
+ "_type": "Value"
90
+ },
91
+ "_type": "List"
92
+ },
93
+ "_type": "List"
94
+ },
95
+ "positive_labels": {
96
+ "feature": {
97
+ "feature": {
98
+ "dtype": "float32",
99
+ "_type": "Value"
100
+ },
101
+ "_type": "List"
102
+ },
103
+ "_type": "List"
104
+ },
105
+ "negative_labels": {
106
+ "feature": {
107
+ "feature": {
108
+ "dtype": "float32",
109
+ "_type": "Value"
110
+ },
111
+ "_type": "List"
112
+ },
113
+ "_type": "List"
114
+ },
115
+ "hard_negative_labels": {
116
+ "feature": {
117
+ "feature": {
118
+ "dtype": "float32",
119
+ "_type": "Value"
120
+ },
121
+ "_type": "List"
122
+ },
123
+ "_type": "List"
124
+ }
125
+ },
126
+ "homepage": "",
127
+ "license": ""
128
+ }
Computational/package/data/metalatte/validation/state.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_data_files": [
3
+ {
4
+ "filename": "data-00000-of-00001.arrow"
5
+ }
6
+ ],
7
+ "_fingerprint": "f4740a503b2e7630",
8
+ "_format_columns": null,
9
+ "_format_kwargs": {},
10
+ "_format_type": null,
11
+ "_output_all_columns": false,
12
+ "_split": null
13
+ }
Computational/package/data/metalorian/test/data-00000-of-00001.arrow ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:144f64b82f98ea84182c0b614db220258428bffd40400728d9ff7abae1cd58b0
3
+ size 50061616
Computational/package/data/metalorian/test/dataset_info.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "citation": "",
3
+ "description": "",
4
+ "features": {
5
+ "input_ids": {
6
+ "feature": {
7
+ "dtype": "int32",
8
+ "_type": "Value"
9
+ },
10
+ "_type": "Sequence"
11
+ },
12
+ "attention_mask": {
13
+ "feature": {
14
+ "dtype": "int8",
15
+ "_type": "Value"
16
+ },
17
+ "_type": "Sequence"
18
+ },
19
+ "labels": {
20
+ "feature": {
21
+ "dtype": "int64",
22
+ "_type": "Value"
23
+ },
24
+ "_type": "Sequence"
25
+ }
26
+ },
27
+ "homepage": "",
28
+ "license": ""
29
+ }
Computational/package/data/metalorian/test/state.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_data_files": [
3
+ {
4
+ "filename": "data-00000-of-00001.arrow"
5
+ }
6
+ ],
7
+ "_fingerprint": "4513d78e9e12f6ec",
8
+ "_format_columns": null,
9
+ "_format_kwargs": {},
10
+ "_format_type": null,
11
+ "_output_all_columns": false,
12
+ "_split": null
13
+ }
Computational/package/data/metalorian/train/data-00000-of-00001.arrow ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5c3a8a87ff95607803de5f3099313ab9b0d20127709d79fae0a1fcd9a4159987
3
+ size 200238632
Computational/package/data/metalorian/train/dataset_info.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "citation": "",
3
+ "description": "",
4
+ "features": {
5
+ "input_ids": {
6
+ "feature": {
7
+ "dtype": "int32",
8
+ "_type": "Value"
9
+ },
10
+ "_type": "Sequence"
11
+ },
12
+ "attention_mask": {
13
+ "feature": {
14
+ "dtype": "int8",
15
+ "_type": "Value"
16
+ },
17
+ "_type": "Sequence"
18
+ },
19
+ "labels": {
20
+ "feature": {
21
+ "dtype": "int64",
22
+ "_type": "Value"
23
+ },
24
+ "_type": "Sequence"
25
+ }
26
+ },
27
+ "homepage": "",
28
+ "license": ""
29
+ }
Computational/package/data/metalorian/train/state.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_data_files": [
3
+ {
4
+ "filename": "data-00000-of-00001.arrow"
5
+ }
6
+ ],
7
+ "_fingerprint": "23bf04a78c6463c4",
8
+ "_format_columns": null,
9
+ "_format_kwargs": {},
10
+ "_format_type": null,
11
+ "_output_all_columns": false,
12
+ "_split": null
13
+ }
Computational/package/metalorian/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+
Computational/package/metalorian/cli.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import csv
3
+ import json
4
+ from pathlib import Path
5
+
6
+
7
+ def parser(mode):
8
+ p = argparse.ArgumentParser(description=f'Metalorian {mode} sampling')
9
+ p.add_argument('--target_idx', type=int, required=True, help='Metal index; Cu=3, Cd=1, Zn=13, Ni=8')
10
+ p.add_argument('--seq_len', type=int, default=30)
11
+ p.add_argument('--batch', type=int, default=1)
12
+ p.add_argument('--desired', type=int, default=1)
13
+ p.add_argument('--max_rounds', type=int, default=150)
14
+ p.add_argument('--grad_steps', type=int, default=4)
15
+ p.add_argument('--guidance_scale', type=float, default=6.0)
16
+ p.add_argument('--penalty', type=float, default=0.1)
17
+ p.add_argument('--tau', type=float, default=1.0)
18
+ p.add_argument('--label_clamp', type=float, default=0.8)
19
+ p.add_argument('--best_decode', type=int, default=16, help='Candidate decodes; 0 uses argmax')
20
+ p.add_argument('--decode_temp', type=float, default=1.0)
21
+ p.add_argument('--device', default='cuda:0')
22
+ p.add_argument('--seed', type=int, default=42)
23
+ p.add_argument('--output', type=Path, required=True)
24
+ if mode == 'prototype':
25
+ p.add_argument('--proto', required=True)
26
+ p.add_argument('--t_start', type=int, default=15)
27
+ p.set_defaults(guide_on='x0', no_accum=False, track_best=False, accept_all=False,
28
+ amp=False, out_prefix=None, cys_logit_bias=0.0, cys_target=0.0,
29
+ cys_weight=0.0, min_cys=0, max_aa_frac=1.0, relax_after=10**9,
30
+ init_noise=0.3)
31
+ return p
32
+
33
+
34
+ def collect(args, sampler_class, mode):
35
+ from .sampling import FLAGS, METAL_LABELS
36
+ if not 0 <= args.target_idx < 15 or not 1 <= args.seq_len <= 1022:
37
+ raise ValueError('target_idx must be 0–14; seq_len must be 1–1022')
38
+ if min(args.batch, args.desired, args.max_rounds) < 1:
39
+ raise ValueError('batch, desired and max_rounds must be positive')
40
+ if mode == 'prototype':
41
+ if not 0 < args.t_start < 50:
42
+ raise ValueError('t_start must be 1–49')
43
+ if not args.proto or set(args.proto)-set('ACDEFGHIKLMNPQRSTVWY'):
44
+ raise ValueError('proto must contain standard uppercase amino acids')
45
+ import random
46
+ import numpy as np
47
+ import torch
48
+ random.seed(args.seed)
49
+ np.random.seed(args.seed)
50
+ torch.manual_seed(args.seed)
51
+ if torch.cuda.is_available():
52
+ torch.cuda.manual_seed_all(args.seed)
53
+ torch.backends.cuda.matmul.allow_tf32 = True
54
+ torch.backends.cudnn.allow_tf32 = True
55
+ sampler = sampler_class(args, device=args.device)
56
+ rows, seen, candidates = [], set(), 0
57
+ for round_index in range(1, args.max_rounds+1):
58
+ sequences, _ = sampler.run_round()
59
+ sequences = [s for s in sequences if s]
60
+ candidates += len(sequences)
61
+ hits, _ = sampler.accept(sequences, None) if sequences else ([], None)
62
+ for hit in hits:
63
+ if hit['sequence'] in seen:
64
+ continue
65
+ seen.add(hit['sequence'])
66
+ rows.append(dict(metal=METAL_LABELS[args.target_idx], **hit))
67
+ if len(rows) == args.desired:
68
+ break
69
+ print(f'round={round_index} candidates={candidates} unique_accepted={len(rows)}/{args.desired}', flush=True)
70
+ if len(rows) >= args.desired:
71
+ break
72
+ args.output.parent.mkdir(parents=True, exist_ok=True)
73
+ with args.output.open('w', newline='') as f:
74
+ writer = csv.DictWriter(f, fieldnames=['metal','sequence','score','n_cys','n_his'])
75
+ writer.writeheader()
76
+ writer.writerows(rows)
77
+ metadata = dict(mode=mode, arguments={k:str(v) if isinstance(v,Path) else v for k,v in vars(args).items()},
78
+ candidates=candidates, unique_accepted=len(rows), rounds=round_index,
79
+ target_threshold=sampler.threshold, diffusion_steps=int(FLAGS.T),
80
+ beta_start=float(FLAGS.beta_1), beta_end=float(FLAGS.beta_T),
81
+ predictor='checkpoints/metalatte_predictor.ckpt', diffusion='checkpoints/metalorian_diffusion.pt')
82
+ args.output.with_suffix('.metadata.json').write_text(json.dumps(metadata, indent=2)+'\n')
83
+ print(f'Wrote {len(rows)} sequences to {args.output}; requested {args.desired}.')
Computational/package/metalorian/continuous.py ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+ import numpy as np
5
+ import math
6
+ from .layers import get_timestep_embedding
7
+
8
+ def extract(v, t, x_shape):
9
+ out = torch.gather(v, index=t, dim=0).float()
10
+ return out.view([t.shape[0]] + [1] * (len(x_shape) - 1))
11
+
12
+
13
+ class GaussianDiffusionTrainer(nn.Module):
14
+ def __init__(self, model, beta_1, beta_T, T):
15
+ super().__init__()
16
+
17
+ self.model = model
18
+ self.T = T
19
+ betas = torch.linspace(beta_1, beta_T, T, dtype=torch.float64).double()
20
+ alphas = 1. - betas
21
+ self.register_buffer('betas', betas)
22
+ alphas_bar = torch.cumprod(alphas, dim=0)
23
+
24
+ self.register_buffer(
25
+ 'sqrt_alphas_bar', torch.sqrt(alphas_bar))
26
+ self.register_buffer(
27
+ 'sqrt_one_minus_alphas_bar', torch.sqrt(1. - alphas_bar))
28
+ self.register_buffer(
29
+ 'sqrt_recip_alphas_bar', torch.sqrt(1. / alphas_bar))
30
+ self.register_buffer(
31
+ 'sqrt_recipm1_alphas_bar', torch.sqrt(1. / alphas_bar - 1))
32
+
33
+ def make_x_t(self, x_0_con, t, noise):
34
+ x_t_con = (
35
+ extract(self.sqrt_alphas_bar, t, x_0_con.shape) * x_0_con +
36
+ extract(self.sqrt_one_minus_alphas_bar, t, x_0_con.shape) * noise)
37
+ return x_t_con
38
+
39
+ def predict_xstart_from_eps(self, x_t, t, eps):
40
+ assert x_t.shape == eps.shape
41
+ return (
42
+ extract(self.sqrt_recip_alphas_bar, t, x_t.shape) * x_t -
43
+ extract(self.sqrt_recipm1_alphas_bar, t, x_t.shape) * eps
44
+ )
45
+
46
+
47
+ class GaussianDiffusionSampler(nn.Module):
48
+ def __init__(self, model, beta_1, beta_T, T,
49
+ mean_type='eps', var_type='fixedlarge'):
50
+ assert mean_type in ['xprev' 'xstart', 'epsilon']
51
+ assert var_type in ['fixedlarge', 'fixedsmall']
52
+ super().__init__()
53
+
54
+ self.model = model
55
+ self.T = T
56
+ self.mean_type = mean_type
57
+ self.var_type = var_type
58
+
59
+ betas = torch.linspace(beta_1, beta_T, T, dtype=torch.float64).double()
60
+
61
+ alphas = 1. - betas
62
+ self.register_buffer(
63
+ 'betas', betas)
64
+ alphas_bar = torch.cumprod(alphas, dim=0)
65
+ alphas_bar_prev = F.pad(alphas_bar, [1, 0], value=1)[:T]
66
+
67
+ self.register_buffer(
68
+ 'sqrt_alphas_bar', torch.sqrt(alphas_bar))
69
+ self.register_buffer(
70
+ 'sqrt_one_minus_alphas_bar', torch.sqrt(1. - alphas_bar))
71
+
72
+ self.register_buffer(
73
+ 'sqrt_recip_alphas_bar', torch.sqrt(1. / alphas_bar))
74
+ self.register_buffer(
75
+ 'sqrt_recipm1_alphas_bar', torch.sqrt(1. / alphas_bar - 1))
76
+
77
+ self.register_buffer(
78
+ 'posterior_var',
79
+ self.betas * (1. - alphas_bar_prev) / (1. - alphas_bar))
80
+ # Avoid log(0) at the first diffusion step.
81
+ self.register_buffer(
82
+ 'posterior_log_var_clipped',
83
+ torch.log(
84
+ torch.cat([self.posterior_var[1:2], self.posterior_var[1:]])))
85
+ self.register_buffer(
86
+ 'posterior_mean_coef1',
87
+ torch.sqrt(alphas_bar_prev) * self.betas / (1. - alphas_bar))
88
+ self.register_buffer(
89
+ 'posterior_mean_coef2',
90
+ torch.sqrt(alphas) * (1. - alphas_bar_prev) / (1. - alphas_bar))
91
+
92
+ def q_mean_variance(self, x_0, x_t, t):
93
+ """Mean and log variance of q(x_{t-1} | x_t, x_0)."""
94
+ assert x_0.shape == x_t.shape
95
+ posterior_mean = (
96
+ extract(self.posterior_mean_coef1, t, x_t.shape) * x_0 +
97
+ extract(self.posterior_mean_coef2, t, x_t.shape) * x_t
98
+ )
99
+ posterior_log_var_clipped = extract(
100
+ self.posterior_log_var_clipped, t, x_t.shape)
101
+ return posterior_mean, posterior_log_var_clipped
102
+
103
+ def predict_xstart_from_eps(self, x_t, t, eps):
104
+ assert x_t.shape == eps.shape
105
+ return (
106
+ extract(self.sqrt_recip_alphas_bar, t, x_t.shape) * x_t -
107
+ extract(self.sqrt_recipm1_alphas_bar, t, x_t.shape) * eps
108
+ )
109
+
110
+
111
+ def p_mean_variance(self, x_t, t, cond, trans):
112
+ model_log_var = {
113
+ 'fixedlarge': torch.log(torch.cat([self.posterior_var[1:2],
114
+ self.betas[1:]])),
115
+ 'fixedsmall': self.posterior_log_var_clipped,
116
+ }[self.var_type]
117
+ model_log_var = extract(model_log_var, t, x_t.shape)
118
+
119
+ if self.mean_type == 'epsilon':
120
+ eps = self.model(x_t, t, cond)
121
+ x_0 = self.predict_xstart_from_eps(x_t, t, eps=eps)
122
+ model_mean, _ = self.q_mean_variance(x_0, x_t, t)
123
+ else:
124
+ raise NotImplementedError(self.mean_type)
125
+
126
+ return model_mean, model_log_var
127
+
128
+
129
+ class DiffusionProteinModel(nn.Module):
130
+ def __init__(self, base_model, FLAGS):
131
+ super().__init__()
132
+ self.base_model = base_model
133
+ self._freeze_base_model_layers()
134
+ self.embed_dim = FLAGS.nf
135
+
136
+ self.time_embed = nn.Sequential(
137
+ nn.Linear(self.embed_dim, self.embed_dim * 4),
138
+ nn.SiLU(),
139
+ nn.Linear(self.embed_dim * 4, 1280)
140
+ )
141
+
142
+ self.cond_proj = nn.Linear(FLAGS.cond_size, 1280)
143
+
144
+ self.output_proj = nn.Sequential(
145
+ nn.Linear(1280, FLAGS.output_size * 2),
146
+ nn.SiLU(),
147
+ nn.Linear(FLAGS.output_size * 2, FLAGS.output_size)
148
+ )
149
+ def _freeze_base_model_layers(self):
150
+ for param in self.base_model.parameters():
151
+ param.requires_grad = False
152
+
153
+ for i in range(23, 33):
154
+ for param in self.base_model.esm_model.encoder.layer[i].parameters():
155
+ param.requires_grad = True
156
+
157
+ for component in [self.base_model.lm_head, self.base_model.attn_head,
158
+ self.base_model.attn_ln, self.base_model.attn_skip,
159
+ self.base_model.linear_layers, self.base_model.reduction_layers,
160
+ self.base_model.clf_ln]:
161
+ for param in component.parameters():
162
+ param.requires_grad = True
163
+
164
+ for param in self.base_model.esm_model.embeddings.parameters():
165
+ param.requires_grad = False
166
+ def decode_embeddings(self, embeddings):
167
+ mlm_logits = self.base_model.lm_head(embeddings)
168
+ return mlm_logits
169
+
170
+ def get_embeddings(self, x, detach=False):
171
+ _, _, x_combined, _ = self.base_model(
172
+ input_ids=x['input_ids'],
173
+ attention_masks=x['attention_mask']
174
+ )
175
+ if detach:
176
+ return x_combined.detach()
177
+ return x_combined
178
+
179
+ def forward(self, x, time_cond, cond):
180
+ if isinstance(x, dict):
181
+ _, _, x_combined, _ = self.base_model(
182
+ input_ids=x['input_ids'],
183
+ attention_masks=x['attention_mask']
184
+ )
185
+ x = x_combined
186
+ seq_length = x.size(1)
187
+
188
+ temb = get_timestep_embedding(time_cond, self.embed_dim)
189
+ temb = self.time_embed(temb)
190
+ temb = temb.unsqueeze(1).expand(-1, seq_length, -1)
191
+
192
+ if len(cond.shape) == 3:
193
+ cond = self.cond_proj(cond)
194
+ else:
195
+ cond = self.cond_proj(cond)
196
+ cond = cond.unsqueeze(1).expand(-1, seq_length, -1)
197
+
198
+ x = x + temb + cond
199
+ return x
200
+
201
+ def get_token_embeddings(self):
202
+ return self.base_model.esm_model.embeddings.word_embeddings.weight
Computational/package/metalorian/data.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+
3
+ def collate_fn_hard(batch):
4
+ # Each stored row is a pre-batch.
5
+ item = batch[0]
6
+ return {
7
+ 'anchor_input_ids': torch.tensor(item['anchor_input_ids']),
8
+ 'anchor_attention_mask': torch.tensor(item['anchor_attention_mask']),
9
+ 'positive_input_ids': torch.tensor(item['positive_input_ids']),
10
+ 'positive_attention_mask': torch.tensor(item['positive_attention_mask']),
11
+ 'negative_input_ids': torch.tensor(item['negative_input_ids']),
12
+ 'negative_attention_mask': torch.tensor(item['negative_attention_mask']),
13
+ 'anchor_labels': torch.tensor(item['anchor_labels']),
14
+ 'positive_labels': torch.tensor(item['positive_labels']),
15
+ 'negative_labels': torch.tensor(item['negative_labels']),
16
+ 'hard_negative_input_ids': torch.tensor(item['hard_negative_input_ids']),
17
+ 'hard_negative_attention_mask': torch.tensor(item['hard_negative_attention_mask']),
18
+ 'hard_negative_labels': torch.tensor(item['hard_negative_labels'])
19
+ }
20
+
21
+
22
+ def collate_fn(batch):
23
+ # Each stored row is a pre-batch.
24
+ item = batch[0]
25
+ return {
26
+ 'anchor_input_ids': torch.tensor(item['anchor_input_ids']),
27
+ 'anchor_attention_mask': torch.tensor(item['anchor_attention_mask']),
28
+ 'positive_input_ids': torch.tensor(item['positive_input_ids']),
29
+ 'positive_attention_mask': torch.tensor(item['positive_attention_mask']),
30
+ 'negative_input_ids': torch.tensor(item['negative_input_ids']),
31
+ 'negative_attention_mask': torch.tensor(item['negative_attention_mask']),
32
+ 'anchor_labels': torch.tensor(item['anchor_labels']),
33
+ 'positive_labels': torch.tensor(item['positive_labels']),
34
+ 'negative_labels': torch.tensor(item['negative_labels']),
35
+ }
Computational/package/metalorian/discrete.py ADDED
@@ -0,0 +1,276 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn.functional as F
3
+ import numpy as np
4
+ from inspect import isfunction
5
+
6
+
7
+ """
8
+ Based in part on: https://github.com/lucidrains/denoising-diffusion-pytorch/blob/5989f4c77eafcdc6be0fb4739f0f277a6dd7f7d8/denoising_diffusion_pytorch/denoising_diffusion_pytorch.py#L281
9
+ """
10
+ eps = 1e-8
11
+
12
+ def log_1_min_a(a):
13
+ return torch.log(1 - a.exp() + 1e-40)
14
+
15
+ def log_add_exp(a, b):
16
+ maximum = torch.max(a, b)
17
+ return maximum + torch.log(torch.exp(a - maximum) + torch.exp(b - maximum))
18
+
19
+
20
+ def extract(a, t, x_shape):
21
+ b, *_ = t.shape
22
+ out = a.gather(-1, t)
23
+ return out.reshape(b, *((1,) * (len(x_shape) - 1)))
24
+
25
+ def index_to_log_onehot(x, num_classes):
26
+ log_x = torch.log(x.float().clamp(min=1e-30))
27
+
28
+ return log_x
29
+
30
+
31
+ class MultinomialDiffusion(torch.nn.Module):
32
+ def __init__(self, num_classes, shape, denoise_fn, FLAGS, timesteps=1000,
33
+ loss_type='vb_stochastic', parametrization='x0'):
34
+ super(MultinomialDiffusion, self).__init__()
35
+ assert loss_type in ('vb_stochastic', 'vb_all')
36
+ assert parametrization in ('x0', 'direct')
37
+
38
+ if loss_type == 'vb_all':
39
+ print('Computing the loss using the bound on _all_ timesteps.'
40
+ ' This is expensive both in terms of memory and computation.')
41
+ self.num_classes = num_classes
42
+ self._denoise_fn = denoise_fn
43
+ self.loss_type = loss_type
44
+ self.shape = shape
45
+ self.num_timesteps = timesteps
46
+ self.parametrization = parametrization
47
+
48
+ betas = torch.linspace(FLAGS.beta_1, FLAGS.beta_T, FLAGS.T, dtype=torch.float64).double()
49
+ alphas = 1. - betas
50
+
51
+ alphas = np.sqrt(alphas)
52
+ betas = 1. - alphas
53
+
54
+ log_alpha = np.log(alphas)
55
+ log_cumprod_alpha = np.cumsum(log_alpha)
56
+ log_1_min_alpha = log_1_min_a(log_alpha)
57
+ log_1_min_cumprod_alpha = log_1_min_a(log_cumprod_alpha)
58
+ self.num_classes_column = np.concatenate([self.num_classes[i].repeat(self.num_classes[i]) for i in range(len(self.num_classes))])
59
+ assert log_add_exp(log_alpha, log_1_min_alpha).abs().sum().item() < 1.e-5
60
+ assert log_add_exp(log_cumprod_alpha, log_1_min_cumprod_alpha).abs().sum().item() < 1e-5
61
+ assert (np.cumsum(log_alpha) - log_cumprod_alpha).abs().sum().item() < 1.e-5
62
+
63
+ self.register_buffer('log_alpha', log_alpha.float())
64
+ self.register_buffer('log_1_min_alpha', log_1_min_alpha.float())
65
+ self.register_buffer('log_cumprod_alpha', log_cumprod_alpha.float())
66
+ self.register_buffer('log_1_min_cumprod_alpha', log_1_min_cumprod_alpha.float())
67
+
68
+ self.register_buffer('Lt_history', torch.zeros(timesteps))
69
+ self.register_buffer('Lt_count', torch.zeros(timesteps))
70
+
71
+ def multinomial_kl(self, log_prob1, log_prob2):
72
+ kl = (log_prob1.exp() * (log_prob1 - log_prob2))
73
+ k=0
74
+ kl_list = []
75
+ for i in self.num_classes:
76
+ sub = kl[:, k:i+k].mean(dim=1)
77
+ kl_list.append(sub)
78
+ k+=i
79
+ kl = torch.stack(kl_list, 1)
80
+ return kl
81
+
82
+ def log_categorical(self, log_x_start, log_prob):
83
+ kl = (log_x_start.exp() * log_prob)
84
+ k=0
85
+ kl_list = []
86
+ for i in self.num_classes:
87
+ sub = kl[:, k:i+k].mean(dim=1)
88
+ kl_list.append(sub)
89
+ k+=i
90
+ kl = torch.stack(kl_list, 1)
91
+
92
+ return kl
93
+
94
+ def q_pred_one_timestep(self, log_x_t, t):
95
+ log_alpha_t = extract(self.log_alpha, t, log_x_t.shape)
96
+ log_1_min_alpha_t = extract(self.log_1_min_alpha, t, log_x_t.shape)
97
+
98
+ log_probs = log_add_exp(
99
+ log_x_t + log_alpha_t,
100
+ log_1_min_alpha_t -torch.tensor(np.log(self.num_classes_column)).to(log_1_min_alpha_t.device)
101
+ )
102
+
103
+ return log_probs
104
+
105
+ def q_pred(self, log_x_start, t):
106
+
107
+ log_cumprod_alpha_t = extract(self.log_cumprod_alpha, t, log_x_start.shape)
108
+ log_1_min_cumprod_alpha = extract(self.log_1_min_cumprod_alpha, t, log_x_start.shape)
109
+ log_probs = log_add_exp(
110
+ log_x_start + log_cumprod_alpha_t,
111
+ log_1_min_cumprod_alpha - torch.tensor(np.log(self.num_classes_column)).to(log_1_min_cumprod_alpha.device)
112
+ )
113
+
114
+ return log_probs
115
+
116
+ def predict_start(self, log_x_t, t, cond_con):
117
+ x_t = log_x_t
118
+ out = self._denoise_fn(x_t, t, cond_con)
119
+ assert out.size(0) == x_t.size(0)
120
+
121
+ k=0
122
+ log_pred = torch.empty_like(out)
123
+ full_sample=[]
124
+ for i in range(len(self.num_classes)):
125
+ out_column = out[:, k:self.num_classes[i]+k]
126
+ log_pred[:, k:self.num_classes[i]+k] = F.log_softmax(out_column, dim=1)
127
+ k+=self.num_classes[i]
128
+
129
+ return log_pred
130
+
131
+
132
+ def q_posterior(self, log_x_start, log_x_t, t):
133
+
134
+ t_minus_1 = t - 1
135
+ t_minus_1 = torch.where(t_minus_1 < 0, torch.zeros_like(t_minus_1), t_minus_1)
136
+
137
+ log_EV_qxtmin_x0 = self.q_pred(log_x_start, t_minus_1)
138
+
139
+ num_axes = (1,) * (len(log_x_start.size()) - 1)
140
+ t_broadcast = t.view(-1, *num_axes) * torch.ones_like(log_x_start)
141
+ log_EV_qxtmin_x0 = torch.where(t_broadcast == 0,
142
+ log_x_start.to(torch.float64),
143
+ log_EV_qxtmin_x0)
144
+
145
+
146
+ unnormed_logprobs = log_EV_qxtmin_x0 + self.q_pred_one_timestep(log_x_t, t)
147
+ k=0
148
+ unnormed_logprobs_column_list=[]
149
+ for i in range(len(self.num_classes)):
150
+ unnormed_logprobs_column = unnormed_logprobs[:,k:self.num_classes[i]+k]
151
+ k+=self.num_classes[i]
152
+ for j in range(self.num_classes[i]):
153
+ unnormed_logprobs_column_list.append(torch.logsumexp(unnormed_logprobs_column, dim=1, keepdim=True))
154
+ unnormed_logprobs_column_ = torch.stack(unnormed_logprobs_column_list,1).squeeze()
155
+
156
+ log_EV_xtmin_given_xt_given_xstart = \
157
+ unnormed_logprobs - unnormed_logprobs_column_
158
+
159
+ return log_EV_xtmin_given_xt_given_xstart
160
+
161
+ def p_pred(self, log_x, t, cond_con):
162
+ if self.parametrization == 'x0':
163
+ log_x_recon = self.predict_start(log_x, t=t, cond_con = cond_con)
164
+ log_model_pred = self.q_posterior(
165
+ log_x_start=log_x_recon, log_x_t=log_x, t=t)
166
+ elif self.parametrization == 'direct':
167
+ log_model_pred = self.predict_start(log_x, t=t, cond_con = cond_con)
168
+ else:
169
+ raise ValueError
170
+ return log_model_pred, log_x_recon
171
+
172
+ @torch.no_grad()
173
+ def p_sample(self, log_x, t, cond_con):
174
+ model_log_prob, log_x_recon = self.p_pred(log_x=log_x, t=t, cond_con=cond_con)
175
+ out = self.log_sample_categorical(model_log_prob).to(log_x.device)
176
+ return out
177
+ def log_sample_categorical_with_temp(self, logits, temperature=1.0):
178
+ full_sample = []
179
+ k = 0
180
+ for i in range(len(self.num_classes)):
181
+ logits_column = logits[:, k:self.num_classes[i]+k] / temperature
182
+ k += self.num_classes[i]
183
+
184
+ uniform = torch.rand_like(logits_column)
185
+ gumbel_noise = -torch.log(-torch.log(uniform + 1e-30) + 1e-30)
186
+
187
+ sample = (gumbel_noise + logits_column).argmax(dim=1)
188
+
189
+ col_t = torch.zeros_like(logits_column)
190
+ col_t.scatter_(1, sample.unsqueeze(1), 1)
191
+ full_sample.append(col_t)
192
+
193
+ full_sample = torch.cat(full_sample, dim=1)
194
+ log_sample = index_to_log_onehot(full_sample, self.num_classes)
195
+ return log_sample
196
+
197
+ def p_sample_with_temp(self, log_x, t, cond_con, temperature=1.0):
198
+ model_log_prob, log_x_recon = self.p_pred(log_x=log_x, t=t, cond_con=cond_con)
199
+ out = self.log_sample_categorical_with_temp(model_log_prob, temperature).to(log_x.device)
200
+ return out
201
+
202
+ def log_sample_categorical(self, logits):
203
+ full_sample = []
204
+ k=0
205
+ for i in range(len(self.num_classes)):
206
+ logits_column = logits[:,k:self.num_classes[i]+k]
207
+ k+=self.num_classes[i]
208
+ uniform = torch.rand_like(logits_column)
209
+ gumbel_noise = -torch.log(-torch.log(uniform+1e-30)+1e-30)
210
+ sample = (gumbel_noise + logits_column).argmax(dim=1)
211
+ col_t =np.zeros(logits_column.shape)
212
+ col_t[np.arange(logits_column.shape[0]), sample.detach().cpu()] = 1
213
+ full_sample.append(col_t)
214
+ full_sample = torch.tensor(np.concatenate(full_sample, axis=1))
215
+ log_sample = index_to_log_onehot(full_sample, self.num_classes)
216
+ return log_sample
217
+
218
+
219
+ def q_sample(self, log_x_start, t):
220
+ log_EV_qxt_x0 = self.q_pred(log_x_start, t)
221
+ log_sample = self.log_sample_categorical(log_EV_qxt_x0).to(log_EV_qxt_x0.device)
222
+ return log_sample
223
+
224
+
225
+ def kl_prior(self, log_x_start):
226
+ b = log_x_start.size(0)
227
+ device = log_x_start.device
228
+ ones = torch.ones(b, device=device).long()
229
+
230
+ log_qxT_prob = self.q_pred(log_x_start, t=(self.num_timesteps - 1) * ones)
231
+ log_half_prob = -torch.log(torch.tensor(self.num_classes_column, device=device) * torch.ones_like(log_qxT_prob))
232
+
233
+ kl_prior = self.multinomial_kl(log_qxT_prob, log_half_prob).mean(dim=1)
234
+ return kl_prior
235
+
236
+ def compute_Lt(self, log_x_start, log_x_t, t, cond_con, detach_mean=False):
237
+ log_true_prob = self.q_posterior(
238
+ log_x_start=log_x_start, log_x_t=log_x_t, t=t)
239
+ log_model_prob, log_x_recon = self.p_pred(log_x=log_x_t, t=t, cond_con=cond_con)
240
+
241
+ if detach_mean:
242
+ log_model_prob = log_model_prob.detach()
243
+ kl = self.multinomial_kl(log_true_prob, log_model_prob).mean(dim=1)
244
+
245
+ decoder_nll = -self.log_categorical(log_x_start, log_model_prob).mean(dim=1)
246
+
247
+ mask = (t == torch.zeros_like(t)).float()
248
+ loss = mask * decoder_nll + (1. - mask) * kl
249
+
250
+ return loss, log_x_recon
251
+
252
+ def compute_Lt_esm(self, log_x_start, log_x_t, t, cond_con, detach_mean=False):
253
+ if len(cond_con.shape) == 3:
254
+ x_t_con_pooled = cond_con.mean(dim=1)
255
+ else:
256
+ x_t_con_pooled = cond_con
257
+ log_true_prob = self.q_posterior(
258
+ log_x_start=log_x_start, log_x_t=log_x_t, t=t)
259
+ log_model_prob, log_x_recon = self.p_pred(log_x=log_x_t, t=t, cond_con=x_t_con_pooled)
260
+
261
+ if detach_mean:
262
+ log_model_prob = log_model_prob.detach()
263
+ kl = self.multinomial_kl(log_true_prob, log_model_prob).mean(dim=1)
264
+
265
+ decoder_nll = -self.log_categorical(log_x_start, log_model_prob).mean(dim=1)
266
+
267
+ direct_cls_loss = F.binary_cross_entropy_with_logits(
268
+ log_x_recon,
269
+ log_x_start.exp(),
270
+ reduction='none'
271
+ ).mean(dim=1)
272
+
273
+ mask = (t == torch.zeros_like(t)).float()
274
+ loss = mask * decoder_nll + (1. - mask) * kl + 0.1 * direct_cls_loss
275
+
276
+ return loss, log_x_recon
Computational/package/metalorian/layers.py ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2020 The Google Research Authors.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ # pylint: skip-file
17
+ import math
18
+ import torch.nn as nn
19
+ import torch
20
+ import torch.nn.functional as F
21
+ import numpy as np
22
+
23
+ def get_act(FLAGS):
24
+ if FLAGS.activation.lower() == 'elu':
25
+ return nn.ELU()
26
+ elif FLAGS.activation.lower() == 'relu':
27
+ return nn.ReLU()
28
+ elif FLAGS.activation.lower() == 'lrelu':
29
+ return nn.LeakyReLU(negative_slope=0.2)
30
+ elif FLAGS.activation.lower() == 'swish':
31
+ return nn.SiLU()
32
+ elif FLAGS.activation.lower() == 'tanh':
33
+ return nn.Tanh()
34
+ elif FLAGS.activation.lower() == 'softplus':
35
+ return nn.Softplus()
36
+ else:
37
+ raise NotImplementedError('activation function does not exist!')
38
+
39
+ def variance_scaling(scale, mode, distribution,
40
+ in_axis=1, out_axis=0,
41
+ dtype=torch.float32,
42
+ device='cpu'):
43
+ def _compute_fans(shape, in_axis=1, out_axis=0):
44
+ receptive_field_size = np.prod(shape) / shape[in_axis] / shape[out_axis]
45
+ fan_in = shape[in_axis] * receptive_field_size
46
+ fan_out = shape[out_axis] * receptive_field_size
47
+ return fan_in, fan_out
48
+
49
+ def init(shape, dtype=dtype, device=device):
50
+ fan_in, fan_out = _compute_fans(shape, in_axis, out_axis)
51
+ if mode == "fan_in":
52
+ denominator = fan_in
53
+ elif mode == "fan_out":
54
+ denominator = fan_out
55
+ elif mode == "fan_avg":
56
+ denominator = (fan_in + fan_out) / 2
57
+ else:
58
+ raise ValueError(
59
+ "invalid mode for variance scaling initializer: {}".format(mode))
60
+ variance = scale / denominator
61
+ if distribution == "normal":
62
+ return torch.randn(*shape, dtype=dtype, device=device) * np.sqrt(variance)
63
+ elif distribution == "uniform":
64
+ return (torch.rand(*shape, dtype=dtype, device=device) * 2. - 1.) * np.sqrt(3 * variance)
65
+ else:
66
+ raise ValueError("invalid distribution for variance scaling initializer")
67
+
68
+ return init
69
+
70
+ def default_init(scale=1.):
71
+ """DDPM initialization."""
72
+ scale = 1e-10 if scale == 0 else scale
73
+ return variance_scaling(scale, 'fan_avg', 'uniform')
74
+
75
+ def get_timestep_embedding(timesteps, embedding_dim, max_positions=10000):
76
+ assert len(timesteps.shape) == 1
77
+ half_dim = embedding_dim // 2
78
+ emb = math.log(max_positions) / (half_dim - 1)
79
+ emb = torch.exp(torch.arange(half_dim, dtype=torch.float32, device=timesteps.device) * -emb)
80
+ emb = timesteps.float()[:, None] * emb[None, :]
81
+ emb = torch.cat([torch.sin(emb), torch.cos(emb)], dim=1)
82
+ if embedding_dim % 2 == 1:
83
+ emb = F.pad(emb, (0, 1), mode='constant')
84
+ assert emb.shape == (timesteps.shape[0], embedding_dim)
85
+ return emb
86
+
87
+ class Encoder(nn.Module):
88
+ def __init__(self, encoder_dim, tdim, FLAGS):
89
+ super(Encoder, self).__init__()
90
+ self.encoding_blocks = nn.ModuleList()
91
+ for i in range(len(encoder_dim)):
92
+ if (i+1)==len(encoder_dim): break
93
+ encoding_block = EncodingBlock(encoder_dim[i], encoder_dim[i+1], tdim, FLAGS)
94
+ self.encoding_blocks.append(encoding_block)
95
+
96
+ def forward(self, x, t):
97
+ skip_connections = []
98
+ for encoding_block in self.encoding_blocks:
99
+ x, skip_connection = encoding_block(x, t)
100
+ skip_connections.append(skip_connection)
101
+ return skip_connections, x
102
+
103
+ class EncodingBlock(nn.Module):
104
+ def __init__(self, dim_in, dim_out, tdim, FLAGS):
105
+ super(EncodingBlock, self).__init__()
106
+ self.layer1 = nn.Sequential(
107
+ nn.Linear(dim_in, dim_out),
108
+ get_act(FLAGS)
109
+ )
110
+ self.temb_proj = nn.Sequential(
111
+ nn.Linear(tdim, dim_out),
112
+ get_act(FLAGS)
113
+ )
114
+ self.layer2 = nn.Sequential(
115
+ nn.Linear(dim_out, dim_out),
116
+ get_act(FLAGS)
117
+ )
118
+
119
+ def forward(self, x, t):
120
+ x = self.layer1(x).clone()
121
+ x += self.temb_proj(t)
122
+ x = self.layer2(x)
123
+ skip_connection = x
124
+ return x, skip_connection
125
+
126
+ class Decoder(nn.Module):
127
+ def __init__(self, decoder_dim, tdim, FLAGS):
128
+ super(Decoder, self).__init__()
129
+ self.decoding_blocks = nn.ModuleList()
130
+ for i in range(len(decoder_dim)):
131
+ if (i+1)==len(decoder_dim): break
132
+ decoding_block = DecodingBlock(decoder_dim[i], decoder_dim[i+1], tdim, FLAGS)
133
+ self.decoding_blocks.append(decoding_block)
134
+
135
+ def forward(self, skip_connections, x, t):
136
+ zipped = zip(reversed(skip_connections), self.decoding_blocks)
137
+ for skip_connection, decoding_block in zipped:
138
+ x = decoding_block(skip_connection, x, t)
139
+ return x
140
+
141
+ class DecodingBlock(nn.Module):
142
+ def __init__(self, dim_in, dim_out, tdim, FLAGS):
143
+ super(DecodingBlock, self).__init__()
144
+ self.layer1 = nn.Sequential(
145
+ nn.Linear(dim_in*2, dim_in),
146
+ get_act(FLAGS)
147
+ )
148
+ self.temb_proj = nn.Sequential(
149
+ nn.Linear(tdim, dim_in),
150
+ get_act(FLAGS)
151
+ )
152
+ self.layer2 = nn.Sequential(
153
+ nn.Linear(dim_in, dim_out),
154
+ get_act(FLAGS)
155
+ )
156
+
157
+ def forward(self, skip_connection, x, t):
158
+
159
+ x = torch.cat((skip_connection, x), dim=1)
160
+ x = self.layer1(x).clone()
161
+ x += self.temb_proj(t)
162
+ x = self.layer2(x)
163
+
164
+ return x
Computational/package/metalorian/objectives.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn.functional as F
3
+
4
+ def warmup_lr(step):
5
+ return min(step, 5000) / 5000
6
+
7
+
8
+ def training_with_esm(x_0_con, x_0_dis, trainer, trainer_dis, ns_con, ns_dis, trans, FLAGS, cls_head, class_weights):
9
+
10
+ t = torch.randint(FLAGS.T, size=(x_0_con['input_ids'].shape[0], ), device=x_0_con['input_ids'].device)
11
+ pt = torch.ones_like(t).float() / FLAGS.T
12
+
13
+ embeddings = trainer.model.get_embeddings(x_0_con)
14
+
15
+ noise = torch.randn_like(embeddings)
16
+ x_t_con = trainer.make_x_t(embeddings, t, noise)
17
+ torch.cuda.empty_cache()
18
+ log_x_start = torch.log(x_0_dis.float().clamp(min=1e-30))
19
+ x_t_dis = trainer_dis.q_sample(log_x_start=log_x_start, t=t)
20
+
21
+ eps = trainer.model(x_t_con, t, x_t_dis.to(x_t_con.device))
22
+ ps_0_con = trainer.predict_xstart_from_eps(x_t_con, t, eps=eps)
23
+ con_loss = F.mse_loss(eps, noise, reduction='none')
24
+ con_loss = con_loss.mean()
25
+ kl, ps_0_dis = trainer_dis.compute_Lt_esm(log_x_start, x_t_dis, t, x_t_con)
26
+ ps_0_dis = torch.exp(ps_0_dis)
27
+ kl_prior = trainer_dis.kl_prior(log_x_start)
28
+ dis_loss = (kl / pt + kl_prior).mean()
29
+ torch.cuda.empty_cache()
30
+ noise_ns = torch.randn_like(ns_con)
31
+ ns_t_con = trainer.make_x_t(ns_con, t, noise_ns)
32
+ log_ns_start = torch.log(ns_dis.float().clamp(min=1e-30))
33
+ ns_t_dis = trainer_dis.q_sample(log_x_start=log_ns_start, t=t)
34
+ torch.cuda.empty_cache()
35
+ eps_ns = trainer.model(x_t_con, t, ns_t_dis.to(ns_t_dis.device))
36
+ ns_0_con = trainer.predict_xstart_from_eps(x_t_con, t, eps=eps_ns)
37
+ _, ns_0_dis = trainer_dis.compute_Lt_esm(log_x_start, x_t_dis, t, ns_t_con)
38
+ ns_0_dis = torch.exp(ns_0_dis)
39
+
40
+
41
+ torch.cuda.empty_cache()
42
+ triplet_loss = torch.nn.TripletMarginLoss(margin=0.5, p=2)
43
+ triplet_con = triplet_loss(embeddings, ps_0_con, ns_0_con)
44
+ total_loss = con_loss
45
+ st=0
46
+ triplet_dis = []
47
+ for item in trans.output_info:
48
+ ed = st + item[0]
49
+ ps_dis = F.cross_entropy(ps_0_dis[:, st:ed], torch.argmax(x_0_dis[:, st:ed], dim=-1).long(), reduction='none')
50
+ ns_dis = F.cross_entropy(ns_0_dis[:, st:ed], torch.argmax(x_0_dis[:, st:ed], dim=-1).long(), reduction='none')
51
+
52
+ triplet_dis.append(max((ps_dis-ns_dis).mean()+1,0))
53
+ st = ed
54
+ triplet_dis = sum(triplet_dis)/len(triplet_dis)
55
+
56
+
57
+ return total_loss, triplet_con, dis_loss, triplet_dis
58
+
59
+
60
+ def make_negative_condition_esm(x_0_con, x_0_dis, base_model):
61
+ device = x_0_dis.device
62
+
63
+ with torch.no_grad():
64
+ _, _, embeddings, _ = base_model(
65
+ input_ids=x_0_con['input_ids'],
66
+ attention_masks=x_0_con['attention_mask']
67
+ )
68
+
69
+ B = embeddings.shape[0]
70
+
71
+ indices = torch.randperm(B)
72
+
73
+ ns_con = embeddings[indices].clone()
74
+ ns_dis = x_0_dis[indices].clone()
75
+
76
+ return ns_con, ns_dis
Computational/package/metalorian/paths.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+ import os
3
+ import sys
4
+
5
+ ROOT = Path(__file__).resolve().parents[1]
6
+ BACKBONE = ROOT/'assets/esm2_t33_650M_UR50D'
7
+ PREDICTOR = ROOT/'checkpoints/metalatte_predictor.ckpt'
8
+ DIFFUSION = ROOT/'checkpoints/metalorian_diffusion.pt'
9
+ TRAIN = ROOT/'data/metalatte/train'
10
+ VALIDATION = ROOT/'data/metalatte/validation'
11
+ os.environ['USE_TF'] = '0'
12
+ os.environ.setdefault('HF_HUB_OFFLINE', '1')
13
+ os.environ.setdefault('WANDB_MODE', 'disabled')
14
+ os.environ.setdefault('MPLCONFIGDIR', str(ROOT/'.cache/matplotlib'))
15
+ sys.dont_write_bytecode = True
16
+ _configured = False
17
+
18
+
19
+ def configure():
20
+ global _configured
21
+ if _configured:
22
+ return
23
+ import torch
24
+ original = torch.load
25
+
26
+ def load(file, *args, **kwargs):
27
+ candidate = file if isinstance(file, (str, Path)) else getattr(file, 'name', getattr(file, 'path', None))
28
+ if isinstance(candidate, (str, Path)) and Path(candidate).resolve() in {PREDICTOR.resolve(), DIFFUSION.resolve()}:
29
+ file = str(Path(candidate).resolve())
30
+ kwargs.setdefault('weights_only', False)
31
+ kwargs.setdefault('mmap', True)
32
+ return original(file, *args, **kwargs)
33
+
34
+ torch.load = load
35
+ _configured = True
Computational/package/metalorian/predictor.py ADDED
@@ -0,0 +1,585 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .paths import BACKBONE
2
+ import torch
3
+ import torch.nn as nn
4
+ import torch.nn.functional as F
5
+ import math
6
+ from transformers import AutoTokenizer
7
+ from torch.optim import AdamW
8
+ import numpy as np
9
+ from sklearn.metrics import f1_score
10
+ from typing import Tuple
11
+ import lightning.pytorch as pl
12
+ import gc
13
+ from torch.optim.lr_scheduler import _LRScheduler
14
+ from sklearn.metrics import f1_score, roc_auc_score, accuracy_score, matthews_corrcoef, precision_score, recall_score
15
+
16
+
17
+ class GELU(nn.Module):
18
+ def forward(self, x):
19
+ return 0.5 * x * (1.0 + torch.erf(x / math.sqrt(2.0)))
20
+
21
+
22
+ class FocalLoss(nn.Module):
23
+ """Focal loss.
24
+
25
+ Sources:
26
+ https://github.com/fcakyon/balanced-loss/blob/main/balanced_loss/losses.py
27
+ https://github.com/vandit15/Class-balanced-loss-pytorch/blob/master/class_balanced_loss.py
28
+ """
29
+ def __init__(self, gamma=2):
30
+ super(FocalLoss, self).__init__()
31
+ self.gamma = gamma
32
+
33
+ def forward(self, inputs, targets, sample_weights):
34
+ BCLoss = F.binary_cross_entropy_with_logits(input = inputs, target = targets,reduction = "none")
35
+
36
+ if self.gamma == 0.0:
37
+ modulator = 1.0
38
+ else:
39
+ modulator = torch.exp(-self.gamma * targets * inputs - self.gamma * torch.log(1 +
40
+ torch.exp(-1.0 * inputs)))
41
+
42
+ loss = modulator * BCLoss
43
+
44
+ weighted_loss = sample_weights * loss
45
+ focal_loss = torch.sum(weighted_loss)
46
+
47
+ focal_loss /= torch.sum(targets)
48
+ return focal_loss
49
+
50
+
51
+ class F1Loss(nn.Module):
52
+ def __init__(self, epsilon=1e-7):
53
+ super().__init__()
54
+ self.epsilon = epsilon
55
+
56
+ def forward(self, y_pred, y_true):
57
+ assert y_pred.ndim == 2
58
+ assert y_true.ndim == 2
59
+ y_true = y_true.float()
60
+ y_pred = torch.sigmoid(y_pred)
61
+
62
+ tp = (y_true * y_pred).sum(dim=0)
63
+ fp = ((1 - y_true) * y_pred).sum(dim=0)
64
+ fn = (y_true * (1 - y_pred)).sum(dim=0)
65
+
66
+ precision = tp / (tp + fp + self.epsilon)
67
+ recall = tp / (tp + fn + self.epsilon)
68
+
69
+ f1 = 2 * (precision * recall) / (precision + recall + self.epsilon)
70
+ f1 = f1.clamp(min=self.epsilon, max=1-self.epsilon)
71
+ return 1 - f1.mean()
72
+
73
+
74
+ def rotate_half(x):
75
+ x1, x2 = x.chunk(2, dim=-1)
76
+ return torch.cat((-x2, x1), dim=-1)
77
+
78
+
79
+ def apply_rotary_pos_emb(x, cos, sin):
80
+ # x: (B, L, H, D); cos and sin: (1, L, D).
81
+ cos = cos.unsqueeze(2)
82
+ sin = sin.unsqueeze(2)
83
+ return (x * cos) + (rotate_half(x) * sin)
84
+
85
+
86
+ class RotaryEmbedding(torch.nn.Module):
87
+ """Rotary position embeddings (Su et al.), inspired by GPT-NeoX.
88
+
89
+ https://arxiv.org/abs/2104.09864
90
+ https://github.com/ZhuiyiTechnology/roformer
91
+ https://github.com/EleutherAI/gpt-neox
92
+ """
93
+
94
+ def __init__(self, dim: int, *_, **__):
95
+ super().__init__()
96
+ inv_freq = 1.0 / (10000 ** (torch.arange(0, dim, 2).float() / dim))
97
+ self.register_buffer("inv_freq", inv_freq)
98
+
99
+ self._seq_len_cached = None
100
+ self._cos_cached = None
101
+ self._sin_cached = None
102
+
103
+ def _update_cos_sin_tables(self, x, seq_dimension=1):
104
+ seq_len = x.shape[seq_dimension]
105
+
106
+ if seq_len != self._seq_len_cached or self._cos_cached.device != x.device:
107
+ self._seq_len_cached = seq_len
108
+ t = torch.arange(x.shape[seq_dimension], device=x.device).type_as(self.inv_freq)
109
+ freqs = torch.einsum("i,j->ij", t, self.inv_freq)
110
+ emb = torch.cat((freqs, freqs), dim=-1).to(x.device)
111
+
112
+ self._cos_cached = emb.cos()[None, :, :]
113
+ self._sin_cached = emb.sin()[None, :, :]
114
+
115
+ return self._cos_cached, self._sin_cached
116
+
117
+ def forward(self, q: torch.Tensor, k: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
118
+ self._cos_cached, self._sin_cached = self._update_cos_sin_tables(k)
119
+
120
+ return (
121
+ apply_rotary_pos_emb(q, self._cos_cached, self._sin_cached),
122
+ apply_rotary_pos_emb(k, self._cos_cached, self._sin_cached),
123
+ )
124
+
125
+
126
+ def macro_f1(y_true, y_pred, thresholds):
127
+ y_pred_binary = (y_pred >= thresholds).float()
128
+ tp = (y_true * y_pred_binary).sum(dim=0)
129
+ fp = ((1 - y_true) * y_pred_binary).sum(dim=0)
130
+ fn = (y_true * (1 - y_pred_binary)).sum(dim=0)
131
+ precision = tp / (tp + fp + 1e-7)
132
+ recall = tp / (tp + fn + 1e-7)
133
+ f1 = 2 * precision * recall / (precision + recall + 1e-7)
134
+ macro_f1 = f1.mean()
135
+ return macro_f1
136
+
137
+
138
+ def safeguard_softmax(logits, dim=-1):
139
+ max_logits, _ = logits.max(dim=dim, keepdim=True)
140
+ exp_logits = torch.exp(logits - max_logits)
141
+ exp_sum = exp_logits.sum(dim=dim, keepdim=True)
142
+ probs = exp_logits / (exp_sum + 1e-7)
143
+ return probs
144
+
145
+
146
+ class PositionalAttentionHead(nn.Module):
147
+ def __init__(self, hidden_dim, n_heads):
148
+ super(PositionalAttentionHead, self).__init__()
149
+ self.n_heads = n_heads
150
+ self.hidden_dim = hidden_dim
151
+ self.head_dim = hidden_dim // n_heads
152
+ self.preattn_ln = nn.LayerNorm(self.head_dim)
153
+ self.Q = nn.Linear(self.head_dim, self.head_dim, bias=False)
154
+ self.K = nn.Linear(self.head_dim, self.head_dim, bias=False)
155
+ self.V = nn.Linear(self.head_dim, self.head_dim, bias=False)
156
+ self.rot_emb = RotaryEmbedding(self.head_dim)
157
+
158
+ def forward(self, x, attention_mask):
159
+ batch_size, seq_len, _ = x.size()
160
+ x = x.view(batch_size, seq_len, self.n_heads, self.head_dim)
161
+ x = self.preattn_ln(x)
162
+
163
+ q = self.Q(x)
164
+ k = self.K(x)
165
+ v = self.V(x)
166
+
167
+ q, k = self.rot_emb(q, k)
168
+ gc.collect()
169
+ torch.cuda.empty_cache()
170
+
171
+ attn_scores = torch.einsum('bqhd,bkhd->bhqk', q, k) / math.sqrt(self.head_dim)
172
+ attn_scores = attn_scores.masked_fill(torch.logical_not(attention_mask.unsqueeze(1).unsqueeze(1)), float("-inf"))
173
+
174
+ attn_probs = safeguard_softmax(attn_scores, dim=-1)
175
+
176
+ x = torch.einsum('bhqk,bkhd->bqhd', attn_probs, v)
177
+ x = x.reshape(batch_size, seq_len, self.hidden_dim)
178
+ gc.collect()
179
+ torch.cuda.empty_cache()
180
+ return x, attn_probs
181
+
182
+
183
+ class CosineAnnealingWithWarmup(_LRScheduler):
184
+ def __init__(self, optimizer, warmup_steps, total_steps, eta_ratio=0.1, last_epoch=-1):
185
+ self.warmup_steps = warmup_steps
186
+ self.total_steps = total_steps
187
+ self.eta_ratio = eta_ratio
188
+ super(CosineAnnealingWithWarmup, self).__init__(optimizer, last_epoch)
189
+
190
+ def get_lr(self):
191
+ if self.last_epoch < self.warmup_steps:
192
+ return [base_lr * self.last_epoch / self.warmup_steps for base_lr in self.base_lrs]
193
+
194
+ progress = (self.last_epoch - self.warmup_steps) / (self.total_steps - self.warmup_steps)
195
+ cosine_decay = 0.5 * (1 + np.cos(np.pi * progress))
196
+ decayed_lr = (1 - self.eta_ratio) * cosine_decay + self.eta_ratio
197
+
198
+ return [decayed_lr * base_lr for base_lr in self.base_lrs]
199
+
200
+
201
+ class AdaptiveMarginTripletLoss(nn.Module):
202
+ def __init__(self, initial_margin=0.05, scale_factor=0.1, min_margin=0.05, max_margin=2.0):
203
+ super(AdaptiveMarginTripletLoss, self).__init__()
204
+ self.initial_margin = initial_margin
205
+ self.scale_factor = scale_factor
206
+ self.min_margin = min_margin
207
+ self.max_margin = max_margin
208
+
209
+ def forward(self, anchor, positive, negative):
210
+ pos_dist = F.pairwise_distance(anchor, positive, p=2)
211
+ neg_dist = F.pairwise_distance(anchor, negative, p=2)
212
+
213
+ adaptive_margins = self.initial_margin + self.scale_factor * (neg_dist - pos_dist)
214
+
215
+ adaptive_margins = torch.clamp(adaptive_margins, min=self.min_margin, max=self.max_margin)
216
+
217
+ losses = F.relu(pos_dist - neg_dist + adaptive_margins)
218
+
219
+ return losses.mean()
220
+
221
+
222
+ class RobertaLMHead(nn.Module):
223
+ def __init__(self, embed_dim, output_dim, weight):
224
+ super().__init__()
225
+ self.dense = nn.Linear(embed_dim, embed_dim)
226
+ self.layer_norm = nn.LayerNorm(embed_dim)
227
+ self.weight = weight
228
+ self.gelu = GELU()
229
+ self.bias = nn.Parameter(torch.zeros(output_dim))
230
+ def forward(self, features):
231
+ x = self.dense(features)
232
+ x = self.gelu(x)
233
+ x = self.layer_norm(x)
234
+ x = F.linear(x, self.weight) + self.bias
235
+ return x
236
+
237
+
238
+ def pad_to_max_length(tensor, max_length, pad_value=1):
239
+ return F.pad(tensor, (0, max_length - tensor.shape[1]), value=pad_value)
240
+
241
+
242
+ def compute_ece(probs, labels, n_bins=10):
243
+ """Per-class calibration error for probabilities and labels of shape (B, C)."""
244
+ bin_boundaries = torch.linspace(0, 1, n_bins + 1)
245
+ bin_lowers = bin_boundaries[:-1]
246
+ bin_uppers = bin_boundaries[1:]
247
+
248
+ n_classes = probs.size(1)
249
+ ece_per_class = torch.zeros(n_classes, device=probs.device)
250
+
251
+ for class_idx in range(n_classes):
252
+ class_probs = probs[:, class_idx]
253
+ class_labels = labels[:, class_idx]
254
+
255
+ ece = torch.zeros(1, device=probs.device)
256
+ for bin_lower, bin_upper in zip(bin_lowers, bin_uppers):
257
+ in_bin = (class_probs.gt(bin_lower.item()) * class_probs.le(bin_upper.item())).float()
258
+ prop_in_bin = in_bin.mean()
259
+
260
+ if prop_in_bin > 0:
261
+ accuracy_in_bin = (class_labels * in_bin).sum() / in_bin.sum()
262
+ avg_confidence_in_bin = (class_probs * in_bin).sum() / in_bin.sum()
263
+ ece += torch.abs(avg_confidence_in_bin - accuracy_in_bin) * prop_in_bin
264
+
265
+ ece_per_class[class_idx] = ece.item()
266
+
267
+ return ece_per_class
268
+
269
+
270
+ class MultitaskProteinModel(pl.LightningModule):
271
+ def __init__(self, hparams, esm_model, num_layers_to_finetune, input_dim=1280, output_dim=12, class_weights=None, hidden_dim=512, n_heads=10):
272
+ super(MultitaskProteinModel, self).__init__()
273
+ self.save_hyperparameters(hparams)
274
+ self.esm_model = esm_model
275
+ for param in self.esm_model.parameters():
276
+ param.requires_grad = False
277
+ for i in range(num_layers_to_finetune):
278
+ for param in self.esm_model.encoder.layer[-i-1].parameters():
279
+ param.requires_grad = True
280
+
281
+ self.lm_head = RobertaLMHead(embed_dim = 1280, output_dim=33, weight=self.esm_model.embeddings.word_embeddings.weight)
282
+ self.attn_head = PositionalAttentionHead(input_dim, n_heads)
283
+ self.attn_ln = nn.LayerNorm(input_dim)
284
+ self.attn_skip = nn.Linear(input_dim, input_dim)
285
+ self.linear_layers = nn.ModuleList()
286
+ for _ in range(self.hparams.num_linear_layers):
287
+ self.linear_layers.append(nn.Linear(input_dim, input_dim))
288
+ self.reduction_layers = nn.Sequential(
289
+ nn.Linear(input_dim, hidden_dim),
290
+ GELU(),
291
+ nn.Linear(hidden_dim, output_dim)
292
+ )
293
+ self.clf_ln = nn.LayerNorm(input_dim)
294
+ self.class_weights = class_weights
295
+ self.classification_thresholds = nn.Parameter(torch.tensor([0.5]*output_dim))
296
+ self.historical_memory = 0.9
297
+ self.training_step_outputs = []
298
+ self.training_step_true_labels = []
299
+ self.testing_step_predictions = []
300
+ self.testing_step_labels = []
301
+ self.test_dataloader = None
302
+ self.tokenizer = AutoTokenizer.from_pretrained(str(BACKBONE), local_files_only=True)
303
+ self.corruption_epoch_threshold = 5
304
+
305
+ def setup(self, stage=None):
306
+ self.__build_loss()
307
+
308
+ def __build_loss(self):
309
+ self.contrastive_loss = AdaptiveMarginTripletLoss()
310
+ focal_gamma = torch.tensor(self.hparams.focal_gamma).to(self.device)
311
+ self.class_weights = self.class_weights.to(self.device)
312
+ self.focal_loss = FocalLoss(gamma=focal_gamma)
313
+ self.f1_loss = F1Loss()
314
+ self.reconstruction_loss = nn.CrossEntropyLoss(ignore_index=self.tokenizer.pad_token_id)
315
+
316
+ def forward(self, input_ids, attention_masks=None):
317
+ outputs = self.esm_model(input_ids=input_ids, attention_mask=attention_masks, output_hidden_states=True)
318
+ embeddings = outputs.last_hidden_state
319
+ attention_masks = attention_masks
320
+
321
+ x_pool, x_attns = self.attn_head(embeddings, attention_masks)
322
+ x_pool = self.attn_ln(x_pool + self.attn_skip(x_pool))
323
+
324
+ for linear_layer in self.linear_layers:
325
+ residue = x_pool
326
+ x_pool = linear_layer(x_pool)
327
+ x_pool = F.silu(x_pool)
328
+ x_pool = x_pool + residue
329
+
330
+ x_weighted = torch.einsum('bhlk,bld->bhld', x_attns, x_pool)
331
+ x_combined = x_weighted.mean(dim=1)
332
+ x_combined = self.clf_ln(x_combined)
333
+ mlm_logits = self.lm_head(x_combined)
334
+ attention_masks = attention_masks.unsqueeze(-1).float()
335
+ attention_sum = attention_masks.sum(dim=1, keepdim=True)
336
+ x_combined_masked = (x_combined * attention_masks).sum(dim=1) / attention_sum.squeeze(1)
337
+
338
+ x_pred = self.reduction_layers(x_combined_masked)
339
+ gc.collect()
340
+ torch.cuda.empty_cache()
341
+ return x_pred, x_attns, x_combined_masked, mlm_logits
342
+ def forward_from_embeds(self, inputs_embeds, attention_masks=None):
343
+ esm = self.esm_model
344
+ # Disable token dropout for embedding input.
345
+ if getattr(esm.embeddings, "token_dropout", False):
346
+ esm.embeddings.token_dropout = False
347
+
348
+ outs = esm(
349
+ inputs_embeds=inputs_embeds,
350
+ attention_mask=attention_masks.to(torch.long),
351
+ output_hidden_states=True,
352
+ )
353
+ embeddings = outs.last_hidden_state
354
+
355
+ x_pool, x_attns = self.attn_head(embeddings, attention_masks)
356
+ x_pool = self.attn_ln(x_pool + self.attn_skip(x_pool))
357
+ for linear_layer in self.linear_layers:
358
+ residue = x_pool
359
+ x_pool = F.silu(linear_layer(x_pool))
360
+ x_pool = x_pool + residue
361
+
362
+ x_weighted = torch.einsum('bhlk,bld->bhld', x_attns, x_pool).mean(dim=1)
363
+ x_weighted = self.clf_ln(x_weighted)
364
+
365
+ mask_f = attention_masks.unsqueeze(-1).float()
366
+ x_combined_masked = (x_weighted * mask_f).sum(dim=1) / mask_f.sum(dim=1).clamp_min(1e-6)
367
+
368
+ x_pred = self.reduction_layers(x_combined_masked)
369
+ return x_pred, x_attns, x_combined_masked, None
370
+ def predict(self, input_ids, attention_masks=None):
371
+ x_pred, _, _, _ = self.forward(input_ids, attention_masks)
372
+ classification_output = torch.sigmoid(x_pred)
373
+ predictions = (classification_output >= self.classification_thresholds).float()
374
+
375
+ for i, pred in enumerate(predictions):
376
+ if pred.sum() == 0:
377
+ weighted_probs = classification_output[i]
378
+ max_class = torch.argmax(weighted_probs)
379
+ predictions[i, max_class] = 1.0
380
+
381
+ confidence_scores = torch.abs(classification_output - self.classification_thresholds) / self.classification_thresholds
382
+ max_confidence_scores = confidence_scores.max(dim=1).values
383
+
384
+ return classification_output, predictions, max_confidence_scores
385
+
386
+ def training_step(self, batch, batch_idx):
387
+ anchor_input_ids, anchor_attention_masks = batch['anchor_input_ids'], batch['anchor_attention_mask']
388
+ positive_input_ids, positive_attention_masks = batch['positive_input_ids'], batch['positive_attention_mask']
389
+ negative_input_ids, negative_attention_masks = batch['negative_input_ids'], batch['negative_attention_mask']
390
+ anchor_labels = batch['anchor_labels']
391
+ positive_labels = batch['positive_labels']
392
+ negative_labels = batch['negative_labels']
393
+
394
+ anchor_x_pred, _, anchor_x_combined, mlm_logits = self.forward(anchor_input_ids, anchor_attention_masks)
395
+ positive_x_pred, _, positive_x_combined, _ = self.forward(positive_input_ids, positive_attention_masks)
396
+ negative_x_pred, _, negative_x_combined, _ = self.forward(negative_input_ids, negative_attention_masks)
397
+
398
+ reconstruction_loss = self.reconstruction_loss(mlm_logits.view(-1, mlm_logits.size(-1)), anchor_input_ids.view(-1))
399
+
400
+ anchor_focal_loss = self.focal_loss(anchor_x_pred, anchor_labels, self.class_weights)
401
+ positive_focal_loss = self.focal_loss(positive_x_pred, positive_labels, self.class_weights)
402
+
403
+ semi_hard_negative_ce_loss = F.binary_cross_entropy_with_logits(input=negative_x_pred, target=negative_labels)
404
+
405
+ focal_loss = (anchor_focal_loss + positive_focal_loss) / 2
406
+
407
+ anchor_f1_loss = self.f1_loss(anchor_x_pred, anchor_labels)
408
+ positive_f1_loss = self.f1_loss(positive_x_pred, positive_labels)
409
+ semi_hard_f1_loss = self.f1_loss(negative_x_pred, negative_labels)
410
+
411
+ semi_hard_triplet_loss = self.contrastive_loss(anchor_x_combined, positive_x_combined, negative_x_combined)
412
+
413
+ if self.current_epoch > self.corruption_epoch_threshold:
414
+ hard_negative_input_ids, hard_negative_attention_masks = batch['hard_negative_input_ids'], batch['hard_negative_attention_mask']
415
+ hard_negative_labels = batch['hard_negative_labels']
416
+ if self.current_epoch < 15:
417
+ epoch_ratio = min(1.0, (self.current_epoch - self.corruption_epoch_threshold) / (self.hparams.epochs - self.corruption_epoch_threshold))
418
+ hard_weight = epoch_ratio
419
+ semi_hard_weight = 1 - hard_weight
420
+ else:
421
+ semi_hard_weight = 0.0
422
+ hard_weight = 1.0
423
+ hard_negative_x_pred, _, hard_negative_x_combined, _ = self.forward(hard_negative_input_ids, hard_negative_attention_masks)
424
+ hard_negative_ce_loss = F.binary_cross_entropy_with_logits(input=hard_negative_x_pred, target=hard_negative_labels)
425
+ hard_triplet_loss = self.contrastive_loss(anchor_x_combined, positive_x_combined, hard_negative_x_combined)
426
+ hard_f1_loss = self.f1_loss(hard_negative_x_pred, hard_negative_labels)
427
+ negative_ce_loss = semi_hard_weight * semi_hard_negative_ce_loss + hard_weight * hard_negative_ce_loss
428
+ triplet_loss = semi_hard_weight * semi_hard_triplet_loss + hard_weight * hard_triplet_loss
429
+ f1_loss = anchor_f1_loss + positive_f1_loss + semi_hard_weight * semi_hard_triplet_loss + hard_weight * hard_f1_loss
430
+ else:
431
+ negative_ce_loss = semi_hard_negative_ce_loss
432
+ triplet_loss = semi_hard_triplet_loss
433
+ f1_loss = anchor_f1_loss + positive_f1_loss + semi_hard_f1_loss
434
+
435
+ loss = focal_loss * 2 + negative_ce_loss + f1_loss + triplet_loss * 2 + reconstruction_loss
436
+
437
+ self.training_step_outputs.append(anchor_x_pred)
438
+ self.training_step_outputs.append(positive_x_pred)
439
+ self.training_step_outputs.append(negative_x_pred)
440
+ self.training_step_true_labels.append(anchor_labels)
441
+ self.training_step_true_labels.append(positive_labels)
442
+ self.training_step_true_labels.append(negative_labels)
443
+ macro_f1_val = macro_f1(anchor_labels, torch.sigmoid(anchor_x_pred), self.classification_thresholds)
444
+ self.log('train_macro_f1', macro_f1_val, on_step=True, on_epoch=True, prog_bar=True, logger=True, sync_dist=True)
445
+ gc.collect()
446
+ torch.cuda.empty_cache()
447
+ gc.collect()
448
+ torch.cuda.empty_cache()
449
+ self.log('train_loss', loss, on_step=True, on_epoch=True, prog_bar=True, logger=True, sync_dist=True)
450
+ return loss
451
+
452
+ def on_train_epoch_end(self):
453
+ epoch_outputs = torch.cat(self.training_step_outputs, dim=0)
454
+ epoch_true_labels = torch.cat(self.training_step_true_labels, dim=0)
455
+ epoch_outputs = torch.sigmoid(epoch_outputs)
456
+ self.update_class_thresholds(epoch_outputs, epoch_true_labels)
457
+ threshold_dict = {f"threshold_{i}": self.classification_thresholds[i].item() for i in range(15)}
458
+ self.log_dict(threshold_dict, on_epoch=True)
459
+ self.training_step_outputs.clear()
460
+ self.training_step_true_labels.clear()
461
+ gc.collect()
462
+ torch.cuda.empty_cache()
463
+
464
+ def validation_step(self, batch, batch_idx):
465
+ anchor_input_ids, anchor_attention_masks = batch['anchor_input_ids'], batch['anchor_attention_mask']
466
+ positive_input_ids, positive_attention_masks = batch['positive_input_ids'], batch['positive_attention_mask']
467
+ negative_input_ids, negative_attention_masks = batch['negative_input_ids'], batch['negative_attention_mask']
468
+ anchor_labels = batch['anchor_labels']
469
+ positive_labels = batch['positive_labels']
470
+ negative_labels = batch['negative_labels']
471
+
472
+ anchor_x_pred, _, anchor_x_combined, mlm_logits = self.forward(anchor_input_ids, anchor_attention_masks)
473
+ positive_x_pred, _, positive_x_combined, _ = self.forward(positive_input_ids, positive_attention_masks)
474
+ negative_x_pred, _, negative_x_combined, _ = self.forward(negative_input_ids, negative_attention_masks)
475
+
476
+ reconstruction_loss = self.reconstruction_loss(mlm_logits.view(-1, mlm_logits.size(-1)), anchor_input_ids.view(-1))
477
+ anchor_focal_loss = self.focal_loss(anchor_x_pred, anchor_labels , self.class_weights)
478
+ positive_focal_loss = self.focal_loss(positive_x_pred, positive_labels, self.class_weights)
479
+
480
+ negative_ce_loss = F.binary_cross_entropy_with_logits(input=negative_x_pred, target=negative_labels)
481
+
482
+ focal_loss = (anchor_focal_loss + positive_focal_loss) / 2
483
+
484
+ f1_loss = self.f1_loss(anchor_x_pred, anchor_labels)
485
+
486
+ triplet_loss = self.contrastive_loss(anchor_x_combined, positive_x_combined, negative_x_combined)
487
+
488
+ loss = focal_loss * 2 + negative_ce_loss + f1_loss + triplet_loss * 2 + reconstruction_loss
489
+
490
+ macro_f1_val = macro_f1(anchor_labels, torch.sigmoid(anchor_x_pred), self.classification_thresholds)
491
+ self.log('val_macro_f1', macro_f1_val, on_step=True, on_epoch=True, prog_bar=True, logger=True, sync_dist=True)
492
+ gc.collect()
493
+ torch.cuda.empty_cache()
494
+ self.log('val_loss', loss, on_step=True, on_epoch=True, prog_bar=True, logger=True, sync_dist=True)
495
+
496
+
497
+ def test_step(self, batch, batch_idx):
498
+ input_ids, labels, attention_masks = batch['input_ids'], batch['labels'], batch['attention_masks']
499
+ x_pred, _, _ = self.forward_test(input_ids, attention_masks)
500
+ predictions = torch.sigmoid(x_pred)
501
+ self.testing_step_predictions.append(predictions)
502
+ self.testing_step_labels.append(labels)
503
+
504
+ def on_test_epoch_end(self,):
505
+ predictions = torch.cat(self.testing_step_predictions, dim=0)
506
+ labels = torch.cat(self.testing_step_labels, dim=0)
507
+
508
+ predictions_binary = (predictions >= self.classification_thresholds).float().cpu().numpy()
509
+ labels_binary = labels.cpu().numpy()
510
+
511
+ f1 = f1_score(labels_binary, predictions_binary, average='macro')
512
+ roc_auc = roc_auc_score(labels_binary, predictions.cpu().to(torch.float32).numpy(), average='micro')
513
+ accuracy = accuracy_score(labels_binary.flatten(), predictions_binary.flatten())
514
+ mcc = matthews_corrcoef(labels_binary.flatten(), predictions_binary.flatten())
515
+ precision = precision_score(labels_binary, predictions_binary, average='macro')
516
+ recall = recall_score(labels_binary, predictions_binary, average='macro')
517
+
518
+ results = {
519
+ 'test_F1_macro': f1,
520
+ 'test_AUCROC': roc_auc,
521
+ 'test_Accuracy': accuracy,
522
+ 'test_MCC': mcc,
523
+ 'test_Precision': precision,
524
+ 'test_Recall': recall,
525
+ }
526
+ self.log_dict(results)
527
+ self.testing_step_predictions.clear()
528
+ self.testing_step_labels.clear()
529
+ gc.collect()
530
+ torch.cuda.empty_cache()
531
+
532
+
533
+ def configure_optimizers(self):
534
+ optimizer = AdamW(self.parameters(), lr=self.hparams.lr, betas=(0.9, 0.95), weight_decay=1e-5)
535
+ schedulers = CosineAnnealingWithWarmup(optimizer, warmup_steps=100, eta_ratio=0.1, total_steps=9000)
536
+ lr_schedulers = {
537
+ "scheduler": schedulers,
538
+ "name": 'learning_rate_logs',
539
+ "interval": 'step',
540
+ 'frequency': 1
541
+ }
542
+ return [optimizer], [lr_schedulers]
543
+
544
+
545
+ def update_class_thresholds(self, inputs, targets):
546
+ with torch.no_grad():
547
+ min_threshold_value = 0.001
548
+ thresholds = torch.linspace(0.0, 1.0, steps=1000, device=inputs.device)
549
+ num_classes = targets.size(1)
550
+
551
+ best_f1_scores = torch.zeros(num_classes, device=inputs.device)
552
+ best_thresholds = torch.full((num_classes,), min_threshold_value, device=inputs.device)
553
+
554
+ for threshold in thresholds:
555
+ binary_predictions = (inputs >= threshold).float()
556
+
557
+ tp = (binary_predictions * targets).sum(dim=0)
558
+ fp = (binary_predictions * (1 - targets)).sum(dim=0)
559
+ fn = ((1 - binary_predictions) * targets).sum(dim=0)
560
+
561
+ precision = tp / (tp + fp + 1e-7)
562
+ recall = tp / (tp + fn + 1e-7)
563
+ f1_scores = 2 * precision * recall / (precision + recall + 1e-7)
564
+
565
+ is_better = f1_scores > best_f1_scores
566
+ best_f1_scores = torch.where(is_better, f1_scores, best_f1_scores)
567
+ best_thresholds = torch.where(is_better, threshold.expand_as(best_f1_scores), best_thresholds)
568
+
569
+ updated_thresholds = self.historical_memory * self.classification_thresholds.data + (1 - self.historical_memory) * best_thresholds
570
+
571
+ self.classification_thresholds = nn.Parameter(torch.clamp(updated_thresholds, min=min_threshold_value))
572
+ gc.collect()
573
+ torch.cuda.empty_cache()
574
+
575
+
576
+ class ResidueEncoder(MultitaskProteinModel):
577
+ """Return per-residue clf_ln outputs for diffusion training."""
578
+ def forward(self, input_ids, attention_masks=None):
579
+ captured = []
580
+ hook = self.clf_ln.register_forward_hook(lambda module, inputs, output: captured.append(output))
581
+ try:
582
+ logits, attention, pooled, mlm_logits = super().forward(input_ids, attention_masks)
583
+ finally:
584
+ hook.remove()
585
+ return logits, attention, captured[0], mlm_logits
Computational/package/metalorian/sampling.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .paths import ROOT, BACKBONE, PREDICTOR, DIFFUSION, TRAIN, configure
2
+ configure()
3
+ import argparse
4
+ import numpy as np
5
+ import torch
6
+ from absl import flags
7
+ from transformers import AutoTokenizer, EsmModel
8
+ from datasets import load_from_disk
9
+ from .continuous import GaussianDiffusionSampler, DiffusionProteinModel
10
+ from .discrete import MultinomialDiffusion
11
+ from .unet import tabularUnet
12
+ from .predictor import MultitaskProteinModel
13
+ FLAGS = flags.FLAGS
14
+ METAL_LABELS = ['Ag','Cd','Co','Cu','Fe','Hg','Mn','Mo','Ni','Pb','Pt','V','W','Zn','NA']
15
+ TOKEN_DROPOUT_SCALE = 0.88
16
+ CODI_CKPT, PRED_CKPT, TRAIN_DS, ESM_NAME = map(str, (DIFFUSION,PREDICTOR,TRAIN,BACKBONE))
17
+
18
+ def build_hparams():
19
+ ns = argparse.Namespace()
20
+ ns.date = 'test'
21
+ ns.attempts = '1'
22
+ ns.output_model_path = str(ROOT/'runs')
23
+ ns.num_workers = 8
24
+ ns.num_linear_layers = 3
25
+ ns.batch_size = 5
26
+ ns.devices = 1
27
+ ns.special_prefix = None
28
+ ns.focal_gamma = 1
29
+ ns.lr = 1e-3
30
+ ns.eps = 0.4
31
+ ns.n_splits = 2
32
+ ns.epochs = 100
33
+ ns.save_top_k = 3
34
+ return ns
35
+
36
+
37
+ def define_flags():
38
+ if not FLAGS.is_parsed():
39
+ FLAGS([""])
40
+ d = {
41
+ 'encoder_dim_con': ('string', "64,128,256"), 'encoder_dim_dis': ('string', "64,128,256"),
42
+ 'nf_con': ('int', 16), 'nf_dis': ('int', 64),
43
+ 'input_size': ('int', None), 'cond_size': ('int', None), 'output_size': ('int', None),
44
+ 'activation': ('string', 'relu'), 'nf': ('int', None),
45
+ 'hidden_size': ('int', 768), 'num_layers': ('int', 12), 'num_heads': ('int', 12),
46
+ 'intermediate_size': ('int', 4 * 768), 'max_seq_length': ('int', 1280),
47
+ 'T': ('int', 50), 'beta_1': ('float', 0.00001), 'beta_T': ('float', 0.02),
48
+ }
49
+ for name, (kind, default) in d.items():
50
+ if not hasattr(FLAGS, name):
51
+ {'string': flags.DEFINE_string, 'int': flags.DEFINE_integer,
52
+ 'float': flags.DEFINE_float}[kind](name, default, help=name)
53
+ if not hasattr(FLAGS, 'encoder_dim'):
54
+ flags.DEFINE_multi_integer('encoder_dim', None, help='encoder_dim')
55
+ if not hasattr(FLAGS, 'mean_type'):
56
+ flags.DEFINE_enum('mean_type', 'epsilon', ['xprev', 'xstart', 'epsilon'], help='mean type')
57
+ if not hasattr(FLAGS, 'var_type'):
58
+ flags.DEFINE_enum('var_type', 'fixedsmall', ['fixedlarge', 'fixedsmall'], help='var type')
59
+
60
+
61
+ def load_diffusion_models(checkpoint_path, base_model, device):
62
+ ckpt = torch.load(checkpoint_path, map_location=device)
63
+
64
+ model_con_state = ckpt['model_con']
65
+ base_keys = [k for k in model_con_state if 'base_model' in k]
66
+ if base_keys:
67
+ base_state = {k.replace('base_model.', ''): model_con_state[k] for k in base_keys}
68
+ base_model.load_state_dict(base_state, strict=False)
69
+ print("Loaded base model weights from CoDi checkpoint")
70
+
71
+ def strip(sd):
72
+ return {k.replace('module.', ''): v for k, v in sd.items()}
73
+ if 'module.' in next(iter(ckpt['model_con'])):
74
+ ckpt['model_con'] = strip(ckpt['model_con'])
75
+ if 'module.' in next(iter(ckpt['model_dis'])):
76
+ ckpt['model_dis'] = strip(ckpt['model_dis'])
77
+
78
+ FLAGS.input_size, FLAGS.cond_size, FLAGS.output_size = 1280, 15, 1280
79
+ FLAGS.encoder_dim = [int(x) for x in FLAGS.encoder_dim_con.split(',')]
80
+ FLAGS.nf = FLAGS.nf_con
81
+ FLAGS.hidden_size, FLAGS.num_layers, FLAGS.num_heads = 768, 12, 12
82
+ FLAGS.intermediate_size, FLAGS.max_seq_length = 4 * 768, 1280
83
+
84
+ model_con = DiffusionProteinModel(base_model, FLAGS).to(device)
85
+ filtered = {}
86
+ for k, v in ckpt['model_con'].items():
87
+ if not k.startswith('base_model.'):
88
+ filtered[k] = v
89
+ else:
90
+ bk = k.replace('base_model.', '')
91
+ if bk in base_model.state_dict() and v.shape == base_model.state_dict()[bk].shape:
92
+ filtered[k] = v
93
+ model_con.load_state_dict(filtered, strict=False)
94
+
95
+ FLAGS.input_size, FLAGS.cond_size, FLAGS.output_size = 15, 1280, 15
96
+ FLAGS.encoder_dim = [int(x) for x in FLAGS.encoder_dim_dis.split(',')]
97
+ FLAGS.nf = FLAGS.nf_dis
98
+ model_dis = tabularUnet(FLAGS).to(device)
99
+ model_dis.load_state_dict(ckpt['model_dis'])
100
+
101
+ trainer_dis = MultinomialDiffusion(
102
+ num_classes=np.array([15]), shape=torch.Size([10, 15]), denoise_fn=model_dis,
103
+ FLAGS=FLAGS, timesteps=FLAGS.T, loss_type='vb_stochastic').to(device)
104
+ net_sampler = GaussianDiffusionSampler(
105
+ model_con, FLAGS.beta_1, FLAGS.beta_T, FLAGS.T,
106
+ mean_type=FLAGS.mean_type, var_type=FLAGS.var_type).to(device)
107
+ return model_con, model_dis, trainer_dis, net_sampler
108
+
109
+
110
+ class Sampler:
111
+ def __init__(self, cfg, device='cuda:0'):
112
+ self.cfg = cfg
113
+ self.device = torch.device(device)
114
+ define_flags()
115
+
116
+ self.tokenizer = AutoTokenizer.from_pretrained(ESM_NAME)
117
+ self.cys_id = self.tokenizer.convert_tokens_to_ids('C')
118
+ self.cls_id = self.tokenizer.cls_token_id
119
+ self.eos_id = self.tokenizer.eos_token_id
120
+
121
+ ds = load_from_disk(TRAIN_DS)
122
+ labels = np.stack([l for b in ds['anchor_labels'] for l in b])
123
+ cw = 1.0 / (labels.sum(axis=0) + 1e-6)
124
+ cw = torch.tensor(cw / cw.sum() * labels.shape[1], dtype=torch.float32).to(self.device)
125
+
126
+ hp = build_hparams()
127
+ esm = EsmModel.from_pretrained(ESM_NAME).cpu()
128
+ base_model = MultitaskProteinModel.load_from_checkpoint(
129
+ PRED_CKPT, hparams=hp, esm_model=esm, num_layers_to_finetune=2,
130
+ input_dim=1280, output_dim=15, class_weights=cw).cpu()
131
+
132
+ esm2 = EsmModel.from_pretrained(ESM_NAME).cpu()
133
+ self.predictor = MultitaskProteinModel.load_from_checkpoint(
134
+ PRED_CKPT, hparams=hp, esm_model=esm2, num_layers_to_finetune=2,
135
+ input_dim=1280, output_dim=15, class_weights=cw).to(self.device).eval()
136
+
137
+ self.model_con, self.model_dis, self.trainer_dis, self.net_sampler = \
138
+ load_diffusion_models(CODI_CKPT, base_model, self.device)
139
+ self.model_con.eval()
140
+ self.model_dis.eval()
141
+
142
+ # Gradients are needed only with respect to the latent.
143
+ for m in (self.predictor, self.model_con, self.model_dis):
144
+ for p in m.parameters():
145
+ p.requires_grad_(False)
146
+
147
+ self.W = self.predictor.esm_model.embeddings.word_embeddings.weight
148
+ self.threshold = self.predictor.classification_thresholds[cfg.target_idx].item()
149
+
150
+ self.vocab_mask = torch.full((33,), float('-inf'), device=self.device)
151
+ self.vocab_mask[4:24] = 0.0
152
+ self.aa_bias = torch.zeros(33, device=self.device)
153
+ self.aa_bias[self.cys_id] = cfg.cys_logit_bias
154
+
155
+ self.others = [i for i in range(15) if i != cfg.target_idx]
156
+ print(f"target={METAL_LABELS[cfg.target_idx]} idx={cfg.target_idx} "
157
+ f"threshold={self.threshold:.4f} cys_token={self.cys_id}")
158
+
159
+ @torch.no_grad()
160
+ def hard_decode(self, x, attn_len):
161
+ logits = self.model_con.decode_embeddings(x[:, :attn_len])
162
+ biased = logits + self.vocab_mask[None, None, :] + self.aa_bias[None, None, :]
163
+ toks = torch.argmax(biased, dim=-1)
164
+ return [self.tokenizer.decode(t, skip_special_tokens=True).replace(' ', '')
165
+ for t in toks]
166
+
167
+ @torch.no_grad()
168
+ def score(self, seqs):
169
+ enc = self.tokenizer(seqs, return_tensors='pt', padding=True)
170
+ enc = {k: v.to(self.device) for k, v in enc.items()}
171
+ probs, fires, _ = self.predictor.predict(input_ids=enc['input_ids'],
172
+ attention_masks=enc['attention_mask'])
173
+ return probs, fires
Computational/package/metalorian/unet.py ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2020 The Google Research Authors.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ # pylint: skip-file
17
+
18
+
19
+ from . import layers
20
+ import torch
21
+ import torch.nn as nn
22
+
23
+ get_act = layers.get_act
24
+ default_initializer = layers.default_init
25
+
26
+ class tabularUnet(nn.Module):
27
+ def __init__(self, FLAGS):
28
+ super().__init__()
29
+
30
+ self.embed_dim = FLAGS.nf
31
+ tdim = self.embed_dim*4
32
+ self.act = get_act(FLAGS)
33
+
34
+ modules = []
35
+ modules.append(nn.Linear(self.embed_dim, tdim))
36
+ modules[-1].weight.data = default_initializer()(modules[-1].weight.shape)
37
+ nn.init.zeros_(modules[-1].bias)
38
+ modules.append(nn.Linear(tdim, tdim))
39
+ modules[-1].weight.data = default_initializer()(modules[-1].weight.shape)
40
+ nn.init.zeros_(modules[-1].bias)
41
+
42
+ cond = FLAGS.cond_size
43
+ cond_out = FLAGS.input_size
44
+ if cond_out < 2:
45
+ cond_out = FLAGS.input_size
46
+ modules.append(nn.Linear(cond, cond_out))
47
+ modules[-1].weight.data = default_initializer()(modules[-1].weight.shape)
48
+ nn.init.zeros_(modules[-1].bias)
49
+
50
+ self.all_modules = nn.ModuleList(modules)
51
+
52
+ dim_in = FLAGS.input_size + cond_out
53
+ dim_out = list(FLAGS.encoder_dim)[0]
54
+ self.inputs = nn.Linear(dim_in, dim_out)
55
+
56
+ self.encoder = layers.Encoder(list(FLAGS.encoder_dim), tdim, FLAGS)
57
+
58
+ dim_in = list(FLAGS.encoder_dim)[-1]
59
+ dim_out = list(FLAGS.encoder_dim)[-1]
60
+ self.bottom_block = nn.Linear(dim_in, dim_out)
61
+
62
+ self.decoder = layers.Decoder(list(reversed(FLAGS.encoder_dim)), tdim, FLAGS)
63
+
64
+ dim_in = list(FLAGS.encoder_dim)[0]
65
+ dim_out = FLAGS.output_size
66
+ self.outputs = nn.Linear(dim_in, dim_out)
67
+
68
+
69
+ def forward(self, x, time_cond, cond):
70
+ if len(x.shape) == 3:
71
+ x = x.mean(dim=1)
72
+ if len(cond.shape) == 3:
73
+ cond = cond.mean(dim=1)
74
+ modules = self.all_modules
75
+ m_idx = 0
76
+
77
+ temb = layers.get_timestep_embedding(time_cond, self.embed_dim)
78
+ temb = modules[m_idx](temb)
79
+ m_idx += 1
80
+ temb= self.act(temb)
81
+ temb = modules[m_idx](temb)
82
+ m_idx += 1
83
+ cond = modules[m_idx](cond)
84
+ m_idx += 1
85
+ x = torch.cat([x, cond], dim=1).float()
86
+ inputs = self.inputs(x)
87
+ skip_connections, encoding = self.encoder(inputs, temb)
88
+ encoding = self.bottom_block(encoding)
89
+ encoding = self.act(encoding)
90
+ x = self.decoder(skip_connections, encoding, temb)
91
+ outputs = self.outputs(x)
92
+
93
+ return outputs
Computational/package/requirements.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python 3.10
2
+ torch==2.8.0
3
+ transformers==4.46.0
4
+ lightning==2.5.5
5
+ pytorch-lightning==2.5.5
6
+ datasets==4.0.0
7
+ pyarrow==21.0.0
8
+ numpy==1.24.4
9
+ pandas==2.0.3
10
+ scipy==1.13.0
11
+ scikit-learn==1.7.1
12
+ absl-py==2.3.1
13
+ safetensors==0.6.2
14
+ tqdm==4.67.1
Computational/package/sample_direct.py ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Direct Metalorian sampling."""
2
+ from metalorian.sampling import Sampler, FLAGS, METAL_LABELS, TOKEN_DROPOUT_SCALE
3
+ from metalorian.cli import parser, collect
4
+ import torch
5
+ import torch.nn.functional as F
6
+ CANVAS = 1024
7
+
8
+ class FixedGradSampler(Sampler):
9
+
10
+ def __init__(self, cfg, device='cuda:0'):
11
+ super().__init__(cfg, device)
12
+ assert float(self.aa_bias.abs().max()) == 0.0, "aa_bias must be zero (no chemistry)"
13
+ print(f"guide_on={cfg.guide_on} accumulate={not cfg.no_accum} "
14
+ f"grad_steps={cfg.grad_steps} scale={cfg.guidance_scale}")
15
+
16
+ def x0_hat(self, x_t, t, cond):
17
+ eps = self.net_sampler.model(x_t, t, cond)
18
+ return self.net_sampler.predict_xstart_from_eps(x_t, t, eps=eps)
19
+
20
+ def target_logit(self, lat, attn_len):
21
+ cfg = self.cfg
22
+ logits = self.model_con.decode_embeddings(lat[:, :attn_len])
23
+ seg = logits + self.vocab_mask[None, None, :]
24
+ soft = F.softmax(seg / cfg.tau, dim=-1)
25
+
26
+ emb = soft @ self.W
27
+ B = emb.shape[0]
28
+ cls_e = self.W[self.cls_id].view(1, 1, -1).expand(B, 1, -1)
29
+ eos_e = self.W[self.eos_id].view(1, 1, -1).expand(B, 1, -1)
30
+ inp = torch.cat([cls_e, emb, eos_e], dim=1) * TOKEN_DROPOUT_SCALE
31
+ am = torch.ones(B, attn_len + 2, device=self.device)
32
+
33
+ x_pred, _, _, _ = self.predictor.forward_from_embeds(inp, am)
34
+ tgt = x_pred[:, cfg.target_idx]
35
+ oth = x_pred[:, self.others].max(dim=1).values
36
+ return tgt - cfg.penalty * oth, soft
37
+
38
+ def init_latent(self, B, lmask):
39
+ return torch.randn(B, CANVAS, 1280, device=self.device) * lmask
40
+
41
+ @torch.no_grad()
42
+ def _encode_perpos(self, seqs):
43
+ """Encode sequences as residue latents of shape (N, S, 1280)."""
44
+ S = self.cfg.seq_len
45
+ m = self.model_con.base_model
46
+ enc = self.tokenizer(seqs, return_tensors='pt', padding='max_length',
47
+ max_length=S + 2, truncation=True)
48
+ ids = enc['input_ids'].to(self.device); am = enc['attention_mask'].to(self.device)
49
+ emb = m.esm_model(input_ids=ids, attention_mask=am).last_hidden_state
50
+ x_pool, x_attns = m.attn_head(emb, am)
51
+ x_pool = m.attn_ln(x_pool + m.attn_skip(x_pool))
52
+ for lin in m.linear_layers:
53
+ r = x_pool; x_pool = F.silu(lin(x_pool)); x_pool = x_pool + r
54
+ x_w = torch.einsum('bhlk,bld->bhld', x_attns, x_pool).mean(dim=1)
55
+ return m.clf_ln(x_w)[:, 1:1 + S, :]
56
+
57
+ @torch.no_grad()
58
+ def _best_decode_one(self, lat_S, K, temp):
59
+ """Select among K decodes by mean positional cosine similarity."""
60
+ S = self.cfg.seq_len
61
+ lg = self.model_con.decode_embeddings(lat_S.unsqueeze(0))[0] + self.vocab_mask[None, :]
62
+ probs = F.softmax(lg / temp, dim=-1)
63
+ toks = torch.multinomial(probs, K, replacement=True).T
64
+ cand = [self.tokenizer.decode(t, skip_special_tokens=True).replace(' ', '') for t in toks]
65
+ cand = [c for c in cand if len(c) == S]
66
+ if not cand:
67
+ return self.tokenizer.decode(lg.argmax(-1), skip_special_tokens=True).replace(' ', '')
68
+ xc = F.normalize(self._encode_perpos(cand), dim=-1)
69
+ Ln = F.normalize(lat_S, dim=-1)
70
+ cos = (xc * Ln[None]).sum(-1).mean(-1)
71
+ return cand[int(cos.argmax())]
72
+
73
+ def decode(self, x, attn_len):
74
+ if getattr(self.cfg, 'best_decode', 0) and self.cfg.best_decode > 0:
75
+ return [self._best_decode_one(x[i, :attn_len], self.cfg.best_decode,
76
+ self.cfg.decode_temp) for i in range(x.shape[0])]
77
+ return self.hard_decode(x, attn_len)
78
+
79
+ def run_round(self):
80
+ cfg, dev = self.cfg, self.device
81
+ B, S = cfg.batch, cfg.seq_len
82
+
83
+ lens = torch.full((B,), S, device=dev, dtype=torch.long)
84
+ attn = torch.arange(CANVAS, device=dev)[None, :] < lens[:, None]
85
+ lmask = attn.unsqueeze(-1).float()
86
+
87
+ x = self.init_latent(B, lmask)
88
+
89
+ tgt1h = torch.zeros(B, 15, device=dev)
90
+ tgt1h[:, cfg.target_idx] = 1.0
91
+ log_dis = torch.log(tgt1h + 1e-10)
92
+
93
+ best_score = [-1.0] * B
94
+ best_seq = [None] * B
95
+
96
+ cys_trace = []
97
+ for step in reversed(range(FLAGS.T)):
98
+ t = torch.full((B,), step, device=dev, dtype=torch.long)
99
+
100
+ for k in range(cfg.grad_steps):
101
+ x = x.detach().requires_grad_(True)
102
+ if cfg.guide_on == 'x0':
103
+ lat = self.x0_hat(x, t, log_dis)
104
+ else:
105
+ lat = x
106
+ obj, soft = self.target_logit(lat, S)
107
+ g, = torch.autograd.grad(obj.sum(), x)
108
+ with torch.no_grad():
109
+ gn = g.flatten(1).norm(dim=1).clamp_min(1e-8).view(-1, 1, 1)
110
+ stepv = cfg.guidance_scale * (g / gn) * lmask
111
+ if cfg.no_accum:
112
+ mean, _ = self.net_sampler.p_mean_variance(
113
+ x_t=x.detach(), t=t, cond=log_dis, trans=None)
114
+ x = (mean * lmask + stepv).clamp(-1, 1)
115
+ else:
116
+ x = (x.detach() + stepv).clamp(-1, 1)
117
+ x = x * lmask
118
+
119
+ with torch.no_grad():
120
+ mean, log_var = self.net_sampler.p_mean_variance(
121
+ x_t=x, t=t, cond=log_dis, trans=None)
122
+ mean = (mean * lmask).float()
123
+ noise = torch.randn_like(x) if step > 0 else torch.zeros_like(x)
124
+ x = (mean + torch.exp(0.5 * log_var.float()) * noise * lmask).clamp(-1, 1)
125
+ x = x * lmask
126
+
127
+ log_dis = self.trainer_dis.p_sample(log_dis, t, x)
128
+ if step % 2 == 0:
129
+ c = cfg.label_clamp
130
+ log_dis = (1 - c) * log_dis + c * torch.log(tgt1h + 1e-10)
131
+
132
+ if cfg.track_best:
133
+ with torch.no_grad():
134
+ cur = self.hard_decode(x, S)
135
+ ok = [i for i, q in enumerate(cur) if len(q) == S]
136
+ if ok:
137
+ pr, _ = self.score([cur[i] for i in ok])
138
+ sc = pr[:, cfg.target_idx]
139
+ for j, i in enumerate(ok):
140
+ if sc[j].item() > best_score[i]:
141
+ best_score[i] = sc[j].item()
142
+ best_seq[i] = cur[i]
143
+
144
+ if step % 10 == 0:
145
+ with torch.no_grad():
146
+ seqs = self.hard_decode(x, S)
147
+ cys_trace.append(sum(q.count('C') for q in seqs) / max(len(seqs), 1))
148
+
149
+ if cfg.track_best:
150
+ final = self.decode(x, S)
151
+ out = [best_seq[i] if best_seq[i] is not None else final[i] for i in range(B)]
152
+ return out, cys_trace
153
+ return self.decode(x, S), cys_trace
154
+
155
+ def accept(self, seqs, _unused):
156
+ cfg = self.cfg
157
+ probs, fires = self.score(seqs)
158
+ out = []
159
+ for i, s in enumerate(seqs):
160
+ if len(s) != cfg.seq_len:
161
+ continue
162
+ sc = probs[i, cfg.target_idx].item()
163
+ if cfg.accept_all:
164
+ out.append({'sequence': s, 'score': sc, 'n_cys': s.count('C'),
165
+ 'n_his': s.count('H')})
166
+ continue
167
+ if sc >= self.threshold and fires[i, cfg.target_idx].item() >= 0.5:
168
+ out.append({'sequence': s, 'score': sc, 'n_cys': s.count('C'),
169
+ 'n_his': s.count('H')})
170
+ return out, probs
171
+
172
+
173
+ if __name__ == '__main__':
174
+ collect(parser('direct').parse_args(), FixedGradSampler, 'direct')
Computational/package/sample_prototype.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Prototype-seeded Metalorian sampling."""
2
+ from sample_direct import FixedGradSampler, CANVAS
3
+ from metalorian.sampling import FLAGS
4
+ from metalorian.cli import parser, collect
5
+ import torch
6
+
7
+ class ProtoSampler(FixedGradSampler):
8
+
9
+ def __init__(self, cfg, device='cuda:0'):
10
+ super().__init__(cfg, device)
11
+ self.proto_lat = self._encode_prototype(cfg.proto)
12
+
13
+ @torch.no_grad()
14
+ def _encode_prototype(self, seq):
15
+ """Encode the prototype using the diffusion model's residue representation."""
16
+ import torch.nn.functional as F
17
+ S = self.cfg.seq_len
18
+ seq = (seq * ((S // max(len(seq), 1)) + 1))[:S] if len(seq) < S else seq[:S]
19
+ enc = self.tokenizer(seq, return_tensors='pt')
20
+ ids = enc['input_ids'].to(self.device)
21
+ am = enc['attention_mask'].to(self.device)
22
+
23
+ m = self.model_con.base_model
24
+ emb = m.esm_model(input_ids=ids, attention_mask=am).last_hidden_state
25
+ x_pool, x_attns = m.attn_head(emb, am)
26
+ x_pool = m.attn_ln(x_pool + m.attn_skip(x_pool))
27
+ for lin in m.linear_layers:
28
+ res = x_pool
29
+ x_pool = F.silu(lin(x_pool))
30
+ x_pool = x_pool + res
31
+ x_comb = torch.einsum('bhlk,bld->bhld', x_attns, x_pool).mean(dim=1)
32
+ x_comb = m.clf_ln(x_comb)
33
+ h = x_comb[:, 1:-1, :] # Remove CLS/EOS.
34
+
35
+ lat = torch.zeros(1, CANVAS, 1280, device=self.device)
36
+ lat[:, :h.shape[1], :] = h
37
+ lat = lat.clamp(-1, 1)
38
+
39
+ rt = self.hard_decode(lat, S)[0]
40
+ ident = sum(a == b for a, b in zip(rt, seq))
41
+ print(f"prototype '{seq}'")
42
+ print(f"round-trip '{rt}' identity={ident}/{S} Cys={rt.count('C')}")
43
+ if rt.count('C') == 0:
44
+ print("Warning: the decoded seed contains no cysteine.")
45
+ return lat
46
+
47
+ def init_latent(self, B, lmask):
48
+ cfg = self.cfg
49
+ seed = self.proto_lat.expand(B, -1, -1).clone()
50
+ noise = torch.randn(B, CANVAS, 1280, device=self.device)
51
+ x = seed + cfg.init_noise * noise
52
+ return (x * lmask).clamp(-1, 1)
53
+
54
+ def _alphas_bar(self):
55
+ betas = torch.linspace(FLAGS.beta_1, FLAGS.beta_T, FLAGS.T, device=self.device)
56
+ return torch.cumprod(1.0 - betas, dim=0)
57
+
58
+ def run_round(self):
59
+ cfg, dev = self.cfg, self.device
60
+ if cfg.t_start <= 0 or cfg.t_start >= FLAGS.T:
61
+ return super().run_round()
62
+
63
+ import torch.nn.functional as F
64
+ B, S = cfg.batch, cfg.seq_len
65
+ lens = torch.full((B,), S, device=dev, dtype=torch.long)
66
+ attn = torch.arange(CANVAS, device=dev)[None, :] < lens[:, None]
67
+ lmask = attn.unsqueeze(-1).float()
68
+
69
+ ab = self._alphas_bar()
70
+ t0 = int(cfg.t_start)
71
+ seed = self.proto_lat.expand(B, -1, -1).clone() * lmask
72
+ noise = torch.randn(B, CANVAS, 1280, device=dev)
73
+ x = (ab[t0].sqrt() * seed + (1 - ab[t0]).sqrt() * noise) * lmask
74
+ x = x.clamp(-1, 1)
75
+
76
+ tgt1h = torch.zeros(B, 15, device=dev)
77
+ tgt1h[:, cfg.target_idx] = 1.0
78
+ log_dis = torch.log(tgt1h + 1e-10)
79
+
80
+ best_score = [-1.0] * B
81
+ best_seq = [None] * B
82
+
83
+ cys_trace = []
84
+ for step in reversed(range(t0 + 1)):
85
+ t = torch.full((B,), step, device=dev, dtype=torch.long)
86
+ for _ in range(cfg.grad_steps):
87
+ x = x.detach().requires_grad_(True)
88
+ lat = self.x0_hat(x, t, log_dis) if cfg.guide_on == 'x0' else x
89
+ obj, _ = self.target_logit(lat, S)
90
+ g, = torch.autograd.grad(obj.sum(), x)
91
+ with torch.no_grad():
92
+ gn = g.flatten(1).norm(dim=1).clamp_min(1e-8).view(-1, 1, 1)
93
+ x = (x.detach() + cfg.guidance_scale * (g / gn) * lmask).clamp(-1, 1) * lmask
94
+ with torch.no_grad():
95
+ mean, log_var = self.net_sampler.p_mean_variance(
96
+ x_t=x, t=t, cond=log_dis, trans=None)
97
+ mean = (mean * lmask).float()
98
+ nz = torch.randn_like(x) if step > 0 else torch.zeros_like(x)
99
+ x = (mean + torch.exp(0.5 * log_var.float()) * nz * lmask).clamp(-1, 1) * lmask
100
+ log_dis = self.trainer_dis.p_sample(log_dis, t, x)
101
+ if step % 2 == 0:
102
+ c = cfg.label_clamp
103
+ log_dis = (1 - c) * log_dis + c * torch.log(tgt1h + 1e-10)
104
+ if cfg.track_best:
105
+ with torch.no_grad():
106
+ cur = self.hard_decode(x, S)
107
+ ok = [i for i, q in enumerate(cur) if len(q) == S]
108
+ if ok:
109
+ pr, _ = self.score([cur[i] for i in ok])
110
+ sc = pr[:, cfg.target_idx]
111
+ for j, i in enumerate(ok):
112
+ if sc[j].item() > best_score[i]:
113
+ best_score[i] = sc[j].item()
114
+ best_seq[i] = cur[i]
115
+
116
+ if step % 5 == 0:
117
+ with torch.no_grad():
118
+ sq = self.hard_decode(x, S)
119
+ cys_trace.append(sum(q.count('C') for q in sq) / max(len(sq), 1))
120
+
121
+ if cfg.track_best:
122
+ final = self.decode(x, S)
123
+ return [best_seq[i] if best_seq[i] is not None else final[i]
124
+ for i in range(B)], cys_trace
125
+ return self.decode(x, S), cys_trace
126
+
127
+
128
+ if __name__ == '__main__':
129
+ collect(parser('prototype').parse_args(), ProtoSampler, 'prototype')
Computational/package/train.py ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Train MetaLATTE or Metalorian."""
2
+ import argparse
3
+ import csv
4
+ import json
5
+ from pathlib import Path
6
+
7
+
8
+ def arguments():
9
+ p = argparse.ArgumentParser(description=__doc__)
10
+ p.add_argument('--stage', choices=['metalatte', 'metalorian'], required=True)
11
+ p.add_argument('--output', type=Path, required=True)
12
+ p.add_argument('--device', default='cuda:0')
13
+ p.add_argument('--epochs', type=int, default=30)
14
+ p.add_argument('--batch-size', type=int, default=2,
15
+ help='Sequence batch size for Metalorian; MetaLATTE uses its saved pre-batches')
16
+ p.add_argument('--workers', type=int, default=0)
17
+ p.add_argument('--threads', type=int, default=4)
18
+ p.add_argument('--seed', type=int, default=42)
19
+ p.add_argument('--lr', type=float, default=2e-4)
20
+ p.add_argument('--init-checkpoint', type=Path,
21
+ help='MetaLATTE weights to initialize from; defaults to the supplied predictor for Metalorian')
22
+ p.add_argument('--resume', type=Path, help='Resume a checkpoint for the selected stage')
23
+ p.add_argument('--smoke-test', action='store_true', help='One update using at most two records and 64 tokens; saves no model')
24
+ a = p.parse_args()
25
+ if min(a.epochs, a.batch_size, a.threads) < 1 or a.workers < 0:
26
+ p.error('epochs, batch-size and threads must be positive; workers cannot be negative')
27
+ if a.smoke_test and a.resume:
28
+ p.error('smoke-test starts a short test run; omit resume')
29
+ return a
30
+
31
+
32
+ def class_weights():
33
+ import numpy as np
34
+ import torch
35
+ from datasets import load_from_disk
36
+ from metalorian.paths import TRAIN
37
+ ds = load_from_disk(str(TRAIN))
38
+ counts = np.zeros(15, dtype=np.float64)
39
+ for row in ds.select_columns(['anchor_labels']):
40
+ counts += np.asarray(row['anchor_labels']).sum(axis=0)
41
+ weights = 1.0/(counts+1e-6)
42
+ return torch.tensor(weights/weights.sum()*15, dtype=torch.float32)
43
+
44
+
45
+ def predictor(args, checkpoint=None, residue_encoder=False):
46
+ import torch
47
+ from transformers import EsmModel, EsmConfig
48
+ from metalorian.paths import BACKBONE, PREDICTOR
49
+ from metalorian.predictor import MultitaskProteinModel, ResidueEncoder
50
+ metadata = torch.load(PREDICTOR, map_location='cpu', weights_only=False, mmap=True)
51
+ hp = argparse.Namespace(**metadata['hyper_parameters'])
52
+ hp.lr, hp.epochs = args.lr, args.epochs
53
+ hp.output_model_path = str(args.output.resolve())
54
+ del metadata
55
+ esm = (EsmModel(EsmConfig.from_pretrained(str(BACKBONE), local_files_only=True))
56
+ if checkpoint else EsmModel.from_pretrained(str(BACKBONE), local_files_only=True))
57
+ cls = ResidueEncoder if residue_encoder else MultitaskProteinModel
58
+ model = cls(hparams=hp, esm_model=esm, num_layers_to_finetune=2,
59
+ input_dim=1280, output_dim=15, class_weights=class_weights())
60
+ if checkpoint:
61
+ state = torch.load(checkpoint, map_location='cpu', weights_only=False, mmap=True)
62
+ model.load_state_dict(state['state_dict'], strict=True)
63
+ return model
64
+
65
+
66
+ def smoke_group(row):
67
+ result = {}
68
+ for key, values in row.items():
69
+ result[key] = values[:2] if key.endswith('labels') else [x[:64] for x in values[:2]]
70
+ return result
71
+
72
+
73
+ def train_metalatte(args):
74
+ import torch
75
+ from datasets import load_from_disk
76
+ from torch.utils.data import DataLoader
77
+ from lightning.pytorch import Trainer
78
+ from lightning.pytorch.callbacks import ModelCheckpoint, StochasticWeightAveraging
79
+ from lightning.pytorch.loggers import CSVLogger
80
+ from metalorian.paths import TRAIN, VALIDATION
81
+ from metalorian.data import collate_fn_hard, collate_fn
82
+ train, valid = load_from_disk(str(TRAIN)), load_from_disk(str(VALIDATION))
83
+ if args.smoke_test:
84
+ train, valid = [smoke_group(train[0])], [smoke_group(valid[0])]
85
+ model = predictor(args, args.init_checkpoint or args.resume)
86
+ train_loader = DataLoader(train, batch_size=1, shuffle=False, collate_fn=collate_fn_hard, num_workers=args.workers)
87
+ valid_loader = DataLoader(valid, batch_size=1, shuffle=False, collate_fn=collate_fn, num_workers=args.workers)
88
+ gpu = args.device.startswith('cuda')
89
+ device_index = int(args.device.split(':')[1]) if ':' in args.device else 0
90
+ callbacks = [] if args.smoke_test else [
91
+ ModelCheckpoint(dirpath=args.output/'checkpoints', save_last=True, save_top_k=1,
92
+ monitor='val_macro_f1', mode='max', filename='metalatte-{epoch:02d}'),
93
+ StochasticWeightAveraging(swa_lrs=1e-2)]
94
+ trainer = Trainer(max_epochs=args.epochs, accelerator='gpu' if gpu else 'cpu',
95
+ devices=[device_index] if gpu else 1, precision='bf16-mixed' if gpu else '32-true',
96
+ logger=CSVLogger(str(args.output), name='metrics'), callbacks=callbacks,
97
+ gradient_clip_val=0.5, enable_checkpointing=not args.smoke_test,
98
+ enable_model_summary=False, fast_dev_run=args.smoke_test,
99
+ default_root_dir=str(args.output))
100
+ trainer.fit(model, train_dataloaders=train_loader, val_dataloaders=valid_loader,
101
+ ckpt_path=str(args.resume) if args.resume else None)
102
+ return {'stage': 'metalatte', 'status': 'completed', 'steps': int(trainer.global_step),
103
+ 'smoke_test': args.smoke_test}
104
+
105
+
106
+ def train_metalorian(args):
107
+ import torch
108
+ import numpy as np
109
+ from datasets import load_from_disk
110
+ from torch.utils.data import DataLoader, DistributedSampler
111
+ from types import SimpleNamespace
112
+ from metalorian.paths import ROOT, PREDICTOR
113
+ from metalorian.continuous import DiffusionProteinModel, GaussianDiffusionTrainer
114
+ from metalorian.discrete import MultinomialDiffusion
115
+ from metalorian.unet import tabularUnet
116
+ from metalorian.objectives import training_with_esm, make_negative_condition_esm, warmup_lr
117
+
118
+ flags = SimpleNamespace(T=50, beta_1=1e-5, beta_T=0.02, input_size=1280,
119
+ cond_size=15, output_size=1280, encoder_dim=[64,128,256], nf=16, activation='relu',
120
+ hidden_size=768, num_layers=12, num_heads=12, intermediate_size=3072,
121
+ max_seq_length=1280, lambda_con=0.2, lambda_dis=0.2)
122
+ base = predictor(args, args.init_checkpoint or PREDICTOR, residue_encoder=True)
123
+ con = DiffusionProteinModel(base, flags).to(args.device)
124
+ flags.input_size, flags.cond_size, flags.output_size, flags.nf = 15, 1280, 15, 64
125
+ dis = tabularUnet(flags).to(args.device)
126
+ con_trainer = GaussianDiffusionTrainer(con, flags.beta_1, flags.beta_T, flags.T).to(args.device)
127
+ data = load_from_disk(str(ROOT/'data/metalorian/train'))
128
+ if args.smoke_test:
129
+ data = [{k:(v[:64] if k in {'input_ids','attention_mask'} else v) for k,v in data[i].items()}
130
+ for i in range(min(2, len(data)))]
131
+ data = TokenRows(data)
132
+ # Preserve the training sampler order: seed 0, epoch 0.
133
+ order = DistributedSampler(data, num_replicas=1, rank=0, shuffle=True, seed=0)
134
+ loader = DataLoader(data, batch_size=args.batch_size, sampler=order, num_workers=args.workers)
135
+ dis_trainer = MultinomialDiffusion(np.array([15]), (len(data),15), dis, flags,
136
+ timesteps=flags.T, loss_type='vb_stochastic').to(args.device)
137
+ optim_con = torch.optim.Adam(con.parameters(), lr=args.lr)
138
+ optim_dis = torch.optim.Adam(dis.parameters(), lr=args.lr)
139
+ sched_con = torch.optim.lr_scheduler.LambdaLR(optim_con, warmup_lr)
140
+ sched_dis = torch.optim.lr_scheduler.LambdaLR(optim_dis, warmup_lr)
141
+ start_epoch, step = 0, 0
142
+ if args.resume:
143
+ ckpt = torch.load(args.resume, map_location='cpu', weights_only=False, mmap=True)
144
+ strip = lambda state: {k.removeprefix('module.'):v for k,v in state.items()}
145
+ con.load_state_dict(strip(ckpt['model_con']), strict=True)
146
+ dis.load_state_dict(strip(ckpt['model_dis']), strict=True)
147
+ optim_con.load_state_dict(ckpt['optim_con']); optim_dis.load_state_dict(ckpt['optim_dis'])
148
+ sched_con.load_state_dict(ckpt['sched_con']); sched_dis.load_state_dict(ckpt['sched_dis'])
149
+ start_epoch, step = int(ckpt.get('epoch',0)), int(ckpt.get('step',0))+1
150
+ del ckpt
151
+ con_params = [p for p in con.parameters() if p.requires_grad]
152
+ dis_params = [p for p in dis.parameters() if p.requires_grad]
153
+ transform = SimpleNamespace(output_info=[(15,'softmax')])
154
+ weights = class_weights().to(args.device)
155
+ with (args.output/'losses.csv').open('w', newline='') as handle:
156
+ log = csv.writer(handle)
157
+ log.writerow(['epoch','step','continuous_loss','continuous_contrastive','discrete_loss','discrete_contrastive'])
158
+ for epoch in range(start_epoch, start_epoch+args.epochs):
159
+ con.train(); dis.train()
160
+ for batch in loader:
161
+ x = {k:batch[k].to(args.device) for k in ['input_ids','attention_mask']}
162
+ labels = batch['labels'].float().to(args.device)
163
+ ns_con, ns_dis = make_negative_condition_esm(x, labels, base)
164
+ values = training_with_esm(x, labels, con_trainer, dis_trainer, ns_con, ns_dis,
165
+ transform, flags, None, weights)
166
+ loss_con = values[0]+flags.lambda_con*values[1]
167
+ loss_dis = values[2]+flags.lambda_dis*values[3]
168
+ if not torch.isfinite(loss_con+loss_dis):
169
+ raise RuntimeError('Nonfinite training loss')
170
+ # Compute both gradients before updating the shared forward graph.
171
+ optim_con.zero_grad(set_to_none=True); optim_dis.zero_grad(set_to_none=True)
172
+ gc = torch.autograd.grad(loss_con, con_params, retain_graph=True, allow_unused=True)
173
+ gd = torch.autograd.grad(loss_dis, dis_params, allow_unused=True)
174
+ for p,g in zip(con_params,gc): p.grad=g
175
+ for p,g in zip(dis_params,gd): p.grad=g
176
+ torch.nn.utils.clip_grad_norm_(con_params, 1.0)
177
+ torch.nn.utils.clip_grad_norm_(dis_params, 1.0)
178
+ optim_con.step(); sched_con.step()
179
+ optim_dis.step(); sched_dis.step()
180
+ numbers = [float(v.detach()) if torch.is_tensor(v) else float(v) for v in values]
181
+ log.writerow([epoch,step,*numbers]); handle.flush()
182
+ print(f'epoch={epoch} step={step} continuous={float(loss_con.detach()):.6f} discrete={float(loss_dis.detach()):.6f}', flush=True)
183
+ step += 1
184
+ if args.smoke_test:
185
+ return {'stage':'metalorian','status':'completed','steps':1,'smoke_test':True,'losses':numbers}
186
+ torch.save(dict(model_con=con.state_dict(), model_dis=dis.state_dict(),
187
+ optim_con=optim_con.state_dict(), optim_dis=optim_dis.state_dict(),
188
+ sched_con=sched_con.state_dict(), sched_dis=sched_dis.state_dict(),
189
+ step=step-1, epoch=epoch+1), args.output/'metalorian_latest.pt')
190
+ return {'stage':'metalorian','status':'completed','steps':step,'smoke_test':False}
191
+
192
+
193
+ class TokenRows:
194
+ def __init__(self, data): self.data=data
195
+ def __len__(self): return len(self.data)
196
+ def __getitem__(self, index):
197
+ import torch
198
+ row=self.data[index]
199
+ return {k:torch.tensor(row[k]) for k in ['input_ids','attention_mask','labels']}
200
+
201
+
202
+ def main():
203
+ args = arguments()
204
+ from metalorian.paths import configure
205
+ configure()
206
+ import torch
207
+ from lightning.pytorch import seed_everything
208
+ seed_everything(args.seed, workers=True)
209
+ torch.set_num_threads(args.threads)
210
+ args.output.mkdir(parents=True, exist_ok=True)
211
+ (args.output/'settings.json').write_text(json.dumps({k:str(v) if isinstance(v,Path) else v
212
+ for k,v in vars(args).items()}, indent=2)+'\n')
213
+ result = train_metalatte(args) if args.stage=='metalatte' else train_metalorian(args)
214
+ (args.output/'result.json').write_text(json.dumps(result, indent=2)+'\n')
215
+ print(json.dumps(result, indent=2))
216
+
217
+
218
+ if __name__ == '__main__':
219
+ main()
Computational/validation/figures/amino_acid_composition_difference_full_reference_predictor_gated_n500.csv ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ metal,AA,generated_percent,full_reference_percent,difference_percentage_points,generated_n,full_reference_n,reference_mode
2
+ Cu,A,15.179714285714288,8.253464474116626,6.926249811597662,500,722,all deduplicated canonical labeled sequences; no length filter
3
+ Cu,C,4.784714285714286,1.7030293368818004,3.0816849488324856,500,722,all deduplicated canonical labeled sequences; no length filter
4
+ Cu,D,3.7777857142857116,5.662140562080337,-1.8843548477946253,500,722,all deduplicated canonical labeled sequences; no length filter
5
+ Cu,E,3.2550714285714277,5.208001313139308,-1.95292988456788,500,722,all deduplicated canonical labeled sequences; no length filter
6
+ Cu,F,5.276190476190477,4.33157251405727,0.9446179621332069,500,722,all deduplicated canonical labeled sequences; no length filter
7
+ Cu,G,2.389214285714285,9.233285808964153,-6.844071523249868,500,722,all deduplicated canonical labeled sequences; no length filter
8
+ Cu,H,17.78226190476191,3.4977835883197557,14.284478316442154,500,722,all deduplicated canonical labeled sequences; no length filter
9
+ Cu,I,1.0133333333333336,5.140004122271833,-4.126670788938499,500,722,all deduplicated canonical labeled sequences; no length filter
10
+ Cu,K,10.510690476190476,4.957583187361847,5.553107288828628,500,722,all deduplicated canonical labeled sequences; no length filter
11
+ Cu,L,5.250500000000002,7.812511951883257,-2.562011951883255,500,722,all deduplicated canonical labeled sequences; no length filter
12
+ Cu,M,8.446428571428573,2.4922300040473155,5.954198567381257,500,722,all deduplicated canonical labeled sequences; no length filter
13
+ Cu,N,2.312333333333333,4.622110010058687,-2.3097766767253542,500,722,all deduplicated canonical labeled sequences; no length filter
14
+ Cu,P,2.3733571428571416,5.646073830664104,-3.2727166878069625,500,722,all deduplicated canonical labeled sequences; no length filter
15
+ Cu,Q,3.8210476190476177,3.019580967529003,0.8014666515186146,500,722,all deduplicated canonical labeled sequences; no length filter
16
+ Cu,R,1.3417857142857146,3.7191257767039034,-2.377340062418189,500,722,all deduplicated canonical labeled sequences; no length filter
17
+ Cu,S,5.754333333333336,6.325280933433413,-0.5709476001000766,500,722,all deduplicated canonical labeled sequences; no length filter
18
+ Cu,T,4.632785714285715,6.443409990551853,-1.8106242762661378,500,722,all deduplicated canonical labeled sequences; no length filter
19
+ Cu,V,0.5072857142857139,7.794299592156853,-7.287013877871139,500,722,all deduplicated canonical labeled sequences; no length filter
20
+ Cu,W,0.4050238095238093,1.3277750447432664,-0.9227512352194571,500,722,all deduplicated canonical labeled sequences; no length filter
21
+ Cu,Y,1.186142857142857,2.8107369910354243,-1.6245941338925673,500,722,all deduplicated canonical labeled sequences; no length filter
22
+ Cd,A,13.550928571428567,8.496912513658536,5.054016057770031,500,158,all deduplicated canonical labeled sequences; no length filter
23
+ Cd,C,28.13461904761906,2.90845505077731,25.226163996841752,500,158,all deduplicated canonical labeled sequences; no length filter
24
+ Cd,D,1.3285000000000007,5.777820408205994,-4.449320408205993,500,158,all deduplicated canonical labeled sequences; no length filter
25
+ Cd,E,1.0580952380952384,6.735951990218785,-5.677856752123547,500,158,all deduplicated canonical labeled sequences; no length filter
26
+ Cd,F,0.8873809523809523,3.624294735065239,-2.7369137826842866,500,158,all deduplicated canonical labeled sequences; no length filter
27
+ Cd,G,0.21890476190476182,7.537380486687105,-7.318475724782343,500,158,all deduplicated canonical labeled sequences; no length filter
28
+ Cd,H,1.8600000000000003,2.169815582343022,-0.30981558234302176,500,158,all deduplicated canonical labeled sequences; no length filter
29
+ Cd,I,0.5347619047619048,5.5484634938451824,-5.0137015890832775,500,158,all deduplicated canonical labeled sequences; no length filter
30
+ Cd,K,12.108476190476187,6.889414083395107,5.21906210708108,500,158,all deduplicated canonical labeled sequences; no length filter
31
+ Cd,L,0.5774285714285713,8.319675467711688,-7.742246896283117,500,158,all deduplicated canonical labeled sequences; no length filter
32
+ Cd,M,1.9189761904761924,2.3005032704500055,-0.3815270799738131,500,158,all deduplicated canonical labeled sequences; no length filter
33
+ Cd,N,0.6128809523809523,4.2105386760265775,-3.597657723645625,500,158,all deduplicated canonical labeled sequences; no length filter
34
+ Cd,P,12.505142857142854,4.4208136568506236,8.084329200292231,500,158,all deduplicated canonical labeled sequences; no length filter
35
+ Cd,Q,7.871976190476187,3.609113466561349,4.262862723914838,500,158,all deduplicated canonical labeled sequences; no length filter
36
+ Cd,R,0.4346904761904761,4.382222241972551,-3.9475317657820748,500,158,all deduplicated canonical labeled sequences; no length filter
37
+ Cd,S,1.1151904761904763,6.254286863063874,-5.139096386873398,500,158,all deduplicated canonical labeled sequences; no length filter
38
+ Cd,T,12.808642857142862,5.87294310794069,6.935699749202172,500,158,all deduplicated canonical labeled sequences; no length filter
39
+ Cd,V,1.0143095238095234,6.694234937216741,-5.679925413407218,500,158,all deduplicated canonical labeled sequences; no length filter
40
+ Cd,W,0.23940476190476198,1.1352977659664403,-0.8958930040616783,500,158,all deduplicated canonical labeled sequences; no length filter
41
+ Cd,Y,1.2196904761904768,3.1118622020431728,-1.892171725852696,500,158,all deduplicated canonical labeled sequences; no length filter
42
+ Zn,A,9.557857142857143,8.083222676194968,1.4746344666621756,500,17094,all deduplicated canonical labeled sequences; no length filter
43
+ Zn,C,12.880357142857148,1.9417560484397594,10.93860109441739,500,17094,all deduplicated canonical labeled sequences; no length filter
44
+ Zn,D,2.8502619047619047,5.750286885020571,-2.900024980258666,500,17094,all deduplicated canonical labeled sequences; no length filter
45
+ Zn,E,2.1406428571428577,7.187470003911243,-5.046827146768385,500,17094,all deduplicated canonical labeled sequences; no length filter
46
+ Zn,F,4.354476190476189,3.9175415402120577,0.4369346502641309,500,17094,all deduplicated canonical labeled sequences; no length filter
47
+ Zn,G,0.2592380952380954,7.367717120991302,-7.108479025753207,500,17094,all deduplicated canonical labeled sequences; no length filter
48
+ Zn,H,8.881214285714282,2.8099397109243713,6.071274574789911,500,17094,all deduplicated canonical labeled sequences; no length filter
49
+ Zn,I,1.1118095238095242,5.863585955880062,-4.751776432070537,500,17094,all deduplicated canonical labeled sequences; no length filter
50
+ Zn,K,16.81728571428571,6.022020919922009,10.7952647943637,500,17094,all deduplicated canonical labeled sequences; no length filter
51
+ Zn,L,8.739642857142861,9.015234213023932,-0.27559135588107075,500,17094,all deduplicated canonical labeled sequences; no length filter
52
+ Zn,M,4.8561428571428555,2.408384549980984,2.4477583071618714,500,17094,all deduplicated canonical labeled sequences; no length filter
53
+ Zn,N,1.1791428571428582,3.876948690019201,-2.697805832876343,500,17094,all deduplicated canonical labeled sequences; no length filter
54
+ Zn,P,3.4906190476190475,4.590996319680774,-1.1003772720617264,500,17094,all deduplicated canonical labeled sequences; no length filter
55
+ Zn,Q,6.338071428571425,3.664161825260114,2.673909603311311,500,17094,all deduplicated canonical labeled sequences; no length filter
56
+ Zn,R,0.7605952380952381,5.649111106864038,-4.8885158687688,500,17094,all deduplicated canonical labeled sequences; no length filter
57
+ Zn,S,1.8969047619047636,5.949762082324762,-4.0528573204199985,500,17094,all deduplicated canonical labeled sequences; no length filter
58
+ Zn,T,9.747642857142855,5.181499373617499,4.566143483525356,500,17094,all deduplicated canonical labeled sequences; no length filter
59
+ Zn,V,1.3977380952380967,6.639014939543678,-5.241276844305581,500,17094,all deduplicated canonical labeled sequences; no length filter
60
+ Zn,W,0.2297142857142858,1.0493511419736743,-0.8196368562593885,500,17094,all deduplicated canonical labeled sequences; no length filter
61
+ Zn,Y,2.510642857142857,3.031994896215333,-0.5213520390724762,500,17094,all deduplicated canonical labeled sequences; no length filter
62
+ Ni,A,16.60880952380952,8.690803978647393,7.918005545162126,500,657,all deduplicated canonical labeled sequences; no length filter
63
+ Ni,C,0.7498095238095238,1.7965676833282913,-1.0467581595187676,500,657,all deduplicated canonical labeled sequences; no length filter
64
+ Ni,D,5.812261904761905,6.235482314489284,-0.42322040972737884,500,657,all deduplicated canonical labeled sequences; no length filter
65
+ Ni,E,1.7889047619047629,7.681116691784482,-5.8922119298797195,500,657,all deduplicated canonical labeled sequences; no length filter
66
+ Ni,F,17.295357142857135,3.4049905754311363,13.890366567426,500,657,all deduplicated canonical labeled sequences; no length filter
67
+ Ni,G,2.0798333333333336,7.859951665750784,-5.78011833241745,500,657,all deduplicated canonical labeled sequences; no length filter
68
+ Ni,H,9.26166666666667,3.493432428620067,5.768234238046603,500,657,all deduplicated canonical labeled sequences; no length filter
69
+ Ni,I,2.907500000000002,6.706331318902961,-3.7988313189029594,500,657,all deduplicated canonical labeled sequences; no length filter
70
+ Ni,K,4.857428571428573,4.754340691032745,0.10308788039582861,500,657,all deduplicated canonical labeled sequences; no length filter
71
+ Ni,L,10.335404761904762,8.629904050710053,1.7055007111947091,500,657,all deduplicated canonical labeled sequences; no length filter
72
+ Ni,M,1.7150952380952393,2.6432846868016315,-0.9281894487063922,500,657,all deduplicated canonical labeled sequences; no length filter
73
+ Ni,N,4.7038095238095226,3.2841711826656286,1.419638341143894,500,657,all deduplicated canonical labeled sequences; no length filter
74
+ Ni,P,0.6057142857142859,4.251372796204826,-3.6456585104905406,500,657,all deduplicated canonical labeled sequences; no length filter
75
+ Ni,Q,7.510761904761904,3.54265907397933,3.968102830782574,500,657,all deduplicated canonical labeled sequences; no length filter
76
+ Ni,R,2.0985238095238095,5.169522496366449,-3.0709986868426395,500,657,all deduplicated canonical labeled sequences; no length filter
77
+ Ni,S,0.4001904761904762,5.279528374057049,-4.879337897866574,500,657,all deduplicated canonical labeled sequences; no length filter
78
+ Ni,T,5.401714285714286,5.684247317678673,-0.2825330319643866,500,657,all deduplicated canonical labeled sequences; no length filter
79
+ Ni,V,4.9288333333333325,7.393953634343296,-2.4651203010099634,500,657,all deduplicated canonical labeled sequences; no length filter
80
+ Ni,W,0.05726190476190476,1.059226726729418,-1.0019648219675132,500,657,all deduplicated canonical labeled sequences; no length filter
81
+ Ni,Y,0.8811190476190476,2.439112312476509,-1.5579932648574613,500,657,all deduplicated canonical labeled sequences; no length filter
Computational/validation/figures/amino_acid_composition_difference_overall_full_reference_predictor_gated_n500.csv ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ AA,generated_percent,full_reference_percent_equal_metal_weight,difference_percentage_points,metals,generated_n_total,generated_n_per_metal,reference_weighting
2
+ A,13.72432738095238,8.38110091065438,5.343226470297999,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
3
+ C,11.637375000000006,2.0874520298567902,9.549922970143216,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
4
+ D,3.4422023809523807,5.8564325424490455,-2.414230161496665,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
5
+ E,2.0606785714285714,6.703134999763455,-4.642456428334883,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
6
+ F,6.953351190476188,3.819599841191426,3.133751349284762,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
7
+ G,1.236797619047619,7.999583770598336,-6.762786151550717,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
8
+ H,9.446285714285715,2.9927428275518038,6.453542886733911,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
9
+ I,1.3918511904761912,5.81459622272501,-4.422745032248819,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
10
+ K,11.073470238095236,5.655839720427927,5.417630517667309,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
11
+ L,6.225744047619049,8.444331420832233,-2.218587373213184,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
12
+ M,4.234160714285714,2.461100627819984,1.7730600864657302,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
13
+ N,2.2020416666666662,3.9984421396925236,-1.7964004730258574,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
14
+ P,4.743708333333332,4.7273141508500816,0.016394182483250752,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
15
+ Q,6.385464285714283,3.458878833332449,2.926585452381834,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
16
+ R,1.1588988095238095,4.7299954054767355,-3.571096595952926,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
17
+ S,2.291654761904763,5.9522145632197745,-3.6605598013150114,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
18
+ T,8.147696428571429,5.795524947447179,2.35217148112425,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
19
+ V,1.9620416666666667,7.130375775815143,-5.168334109148476,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
20
+ W,0.23285119047619043,1.1429126698531997,-0.9100614793770093,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
21
+ Y,1.4493988095238095,2.8484266004426098,-1.3990277909188003,"Cu,Cd,Zn,Ni",2000,500,equal weight per metal; all deduplicated canonical labeled sequences within metal
Computational/validation/figures/physicochemical_properties_full_reference.csv ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:96b6ebcbdc4984dc87e123120820c113ab927fa50b53fd6dff0aec541d4f691c
3
+ size 11282815
Computational/validation/figures/physicochemical_summary_predictor_gated_n500.csv ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ metal,group,property,n,mean,sd,median,q1,q3,min,max
2
+ Cu,WT/reference (full),molecular_weight_Da,722,43090.45546994471,28203.941041231414,36932.138300000064,15896.76067499999,66060.54120000014,2365.6033,137715.5366000003
3
+ Cu,WT/reference (full),net_charge_pH7_4,722,-8.25361403234684,12.4030167462157,-5.50461928539662,-11.331205552654342,-1.3497848576496594,-78.13935885230536,22.76992820373951
4
+ Cu,WT/reference (full),gravy_KyteDoolittle,722,-0.17670491017620815,0.3255128630139271,-0.20901702786377702,-0.39409619285379927,-0.018678380443086378,-1.487247474747477,0.8271573604060918
5
+ Cu,WT/reference (full),instability_index,722,34.62494980142827,11.405359537675217,34.1490756302521,27.83105587487564,40.529098466082374,5.6118421052631575,89.19934306569343
6
+ Cu,WT/reference (full),isoelectric_point,722,6.293408877301414,1.3432803957025612,5.978262710571289,5.447429180145263,6.817334079742432,4.0500284194946286,10.410951042175292
7
+ Cu,WT/reference (full),aromaticity_fraction,722,0.08470084549835961,0.036741741922848396,0.09090909090909091,0.0548243036784581,0.10772732578498892,0.0,0.18840579710144928
8
+ Cd,WT/reference (full),molecular_weight_Da,158,38162.80735189883,29985.143310554795,28397.248999999996,16767.83745,49090.314475000065,2330.6007999999993,138218.4704000007
9
+ Cd,WT/reference (full),net_charge_pH7_4,158,-5.18745702946965,10.657151393684089,-3.612803138259399,-9.650048583039897,0.5578937284123242,-76.51336223204387,18.45704204492644
10
+ Cd,WT/reference (full),gravy_KyteDoolittle,158,-0.27185842475346467,0.32504225635572787,-0.27876919468720684,-0.4955614183199661,-0.08339659884603691,-1.0413333333333337,0.6153488372093022
11
+ Cd,WT/reference (full),instability_index,158,36.816472953023585,13.556098919629193,33.659181148212234,28.149665327978575,44.14624934282756,10.112987012987015,106.2375
12
+ Cd,WT/reference (full),isoelectric_point,158,6.527721004244647,1.5629290349761467,6.04476432800293,5.286006450653076,7.892574214935303,4.0500284194946286,11.395060920715334
13
+ Cd,WT/reference (full),aromaticity_fraction,158,0.07871454703074855,0.033234909113898765,0.08107772192454289,0.058969132207338376,0.09881661969723421,0.0,0.15348837209302324
14
+ Zn,WT/reference (full),molecular_weight_Da,17094,50365.21003442743,30972.964836527746,41483.126850000015,27411.95415000001,71259.21570000025,4309.194600000001,142330.48110000076
15
+ Zn,WT/reference (full),net_charge_pH7_4,17094,-8.195455008890075,13.890057948376617,-7.3908581197670475,-15.524508282469954,-0.6151202899890471,-127.18133881427826,117.35403972706803
16
+ Zn,WT/reference (full),gravy_KyteDoolittle,17094,-0.2966314668557234,0.2554964850257074,-0.2878875291375293,-0.4388888888888886,-0.1464622641509436,-1.9647746243739599,1.205241935483873
17
+ Zn,WT/reference (full),instability_index,17094,39.0336336336893,9.790887210488817,38.172547174447175,33.003702578755274,44.10148512736877,3.819354838709676,132.48106060606062
18
+ Zn,WT/reference (full),isoelectric_point,17094,6.434931484372822,1.5255823948469378,5.892577934265136,5.373964786529541,7.05678253173828,4.0500284194946286,11.999967765808105
19
+ Zn,WT/reference (full),aromaticity_fraction,17094,0.07998887578401025,0.022271011939281448,0.07878300691805515,0.06451612903225806,0.0941797200104344,0.0,0.21666666666666667
20
+ Ni,WT/reference (full),molecular_weight_Da,657,38937.599573059444,27114.09229114452,24870.277900000005,15803.043599999995,60890.174900000195,9049.837699999996,138461.7130000007
21
+ Ni,WT/reference (full),net_charge_pH7_4,657,-11.406012049401001,8.476514075696667,-10.675186860662173,-16.34818370744476,-6.642544224721824,-50.63535184763144,29.893302208509866
22
+ Ni,WT/reference (full),gravy_KyteDoolittle,657,-0.1914087666458152,0.22978860657998554,-0.1661654135338346,-0.3254054054054056,-0.056179775280898854,-1.0196531791907517,0.7126086956521743
23
+ Ni,WT/reference (full),instability_index,657,36.69795705742055,10.86026519405585,34.26344827586205,30.09354275741709,41.79953051643192,2.4646076794657734,84.0031719532561
24
+ Ni,WT/reference (full),isoelectric_point,657,5.622122509113003,0.9833549580541419,5.437638664245605,5.045449638366699,5.794644355773925,4.0500284194946286,10.522094535827637
25
+ Ni,WT/reference (full),aromaticity_fraction,657,0.06903329614637067,0.023885101007221323,0.06451612903225806,0.05272407732864675,0.08482142857142858,0.017094017094017092,0.19148936170212766
26
+ Cu,Generated (gated n=500),molecular_weight_Da,500,5735.773334799998,1839.599909094262,5652.8439499999995,4361.48805,7027.385850000001,3207.6695,9530.235899999992
27
+ Cu,Generated (gated n=500),net_charge_pH7_4,500,2.177348899931101,2.9945467305726434,1.8331160455255957,-0.03857126382054177,3.9026786485555056,-6.729755249327814,12.011673374838622
28
+ Cu,Generated (gated n=500),gravy_KyteDoolittle,500,-0.6777146190476191,0.47979901270675285,-0.7075000000000002,-0.9887500000000007,-0.4314999999999999,-2.133333333333334,0.9979999999999991
29
+ Cu,Generated (gated n=500),instability_index,500,45.18942392857143,21.356961236948408,44.536833333333334,30.851000000000003,58.26525000000001,-13.610000000000003,121.28
30
+ Cu,Generated (gated n=500),isoelectric_point,500,8.550102472686767,1.3040879626857107,8.79901580810547,7.377226543426513,9.51532402038574,4.397996711730957,11.999967765808105
31
+ Cu,Generated (gated n=500),aromaticity_fraction,500,0.06867357142857142,0.042392192246260334,0.06666666666666667,0.0375,0.1,0.0,0.2666666666666667
32
+ Cd,Generated (gated n=500),molecular_weight_Da,500,5493.7174532,1732.143948919548,5334.160750000001,4171.450199999999,7053.215525000005,3003.5239999999994,8905.773500000003
33
+ Cd,Generated (gated n=500),net_charge_pH7_4,500,4.51393227305999,3.60080299668978,4.246191182297465,2.1320600271788384,6.3576947067504355,-3.611645777855447,18.01270896203495
34
+ Cd,Generated (gated n=500),gravy_KyteDoolittle,500,-0.15216604761904762,0.4158202977951427,-0.17124999999999996,-0.4129761904761904,0.08200000000000005,-1.4033333333333333,1.2699999999999996
35
+ Cd,Generated (gated n=500),instability_index,500,65.46233939999999,20.6266938625509,65.34999999999998,52.273333333333326,77.97723214285715,-4.176666666666666,142.56
36
+ Cd,Generated (gated n=500),isoelectric_point,500,8.404394290161134,0.887774666714031,8.611477279663086,8.214319801330568,8.865547180175781,4.0500284194946286,10.113816261291504
37
+ Cd,Generated (gated n=500),aromaticity_fraction,500,0.02346476190476191,0.02711355897301278,0.016666666666666666,0.0,0.03333333333333333,0.0,0.15
38
+ Zn,Generated (gated n=500),molecular_weight_Da,500,6605.982959399998,1756.9879616805197,6826.571400000001,4912.413500000001,8093.869899999996,3269.275499999999,9678.349299999998
39
+ Zn,Generated (gated n=500),net_charge_pH7_4,500,6.555086110494916,4.7360009669730445,6.299141294665338,3.2239116039552886,9.547982906097477,-7.714779902996944,24.33435124373645
40
+ Zn,Generated (gated n=500),gravy_KyteDoolittle,500,-0.43800007142857145,0.5332998416900696,-0.43499999999999994,-0.8028749999999999,-0.0946874999999999,-2.1100000000000003,1.2449999999999994
41
+ Zn,Generated (gated n=500),instability_index,500,46.64874702142856,17.700449944911732,46.44541666666666,34.27791666666667,58.32916666666666,6.147499999999999,110.19666666666666
42
+ Zn,Generated (gated n=500),isoelectric_point,500,9.02513862915039,0.9833703279437971,9.169870185852053,8.663841724395754,9.63151216506958,4.0500284194946286,11.389581108093264
43
+ Zn,Generated (gated n=500),aromaticity_fraction,500,0.07094833333333334,0.0375784126587158,0.06666666666666667,0.04285714285714286,0.1,0.0,0.2
44
+ Ni,Generated (gated n=500),molecular_weight_Da,500,5514.623654799999,1466.8061038915648,5662.897049999998,4539.1118,6815.410549999999,3126.432099999999,9563.039099999993
45
+ Ni,Generated (gated n=500),net_charge_pH7_4,500,-0.46191225026998384,2.490171046797122,-0.46541276040318746,-2.2824402144574085,0.7739741389243606,-8.348135432634312,10.401790276072498
46
+ Ni,Generated (gated n=500),gravy_KyteDoolittle,500,0.2203628571428572,0.3181122698122251,0.22549999999999995,0.014000000000000234,0.4293750000000003,-1.063333333333334,1.1649999999999998
47
+ Ni,Generated (gated n=500),instability_index,500,16.09240997142857,12.640068138370005,15.558000000000002,7.160089285714286,24.033437499999998,-14.759999999999998,63.05
48
+ Ni,Generated (gated n=500),isoelectric_point,500,7.335778021240234,1.746538088466558,6.961150932312011,6.013289737701415,8.631720352172852,4.0500284194946286,11.999967765808105
49
+ Ni,Generated (gated n=500),aromaticity_fraction,500,0.18233738095238095,0.06417890948974825,0.18333333333333335,0.14,0.225,0.02,0.3666666666666667
Computational/validation/sampling_smoke.slurm ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ #SBATCH --job-name=zenodo_smoke
3
+ #SBATCH --partition=b200-mig45
4
+ #SBATCH --qos=mig-max
5
+ #SBATCH --nodes=1
6
+ #SBATCH --ntasks=1
7
+ #SBATCH --gres=gpu:1
8
+ #SBATCH --cpus-per-task=6
9
+ #SBATCH --mem=48G
10
+ #SBATCH --time=00:30:00
11
+ #SBATCH --output=/vast/projects/pranam/lab/yz927/projects/metalmd2/06_analysis/manuscript_binding_20260921/zenodo_draft_20260925/validation/sampling_%j.log
12
+ set -euo pipefail
13
+ cd /vast/projects/pranam/lab/yz927/projects/metalmd2/06_analysis/manuscript_binding_20260921/zenodo_draft_20260925/package
14
+ export PYTHONDONTWRITEBYTECODE=1
15
+ export OMP_NUM_THREADS=6
16
+ export USE_TF=0
17
+ /vast/projects/pranam/lab/yz927/envs/metal/bin/python -u tools/sample.py --mode direct --target_idx 3 --seq_len 30 --batch 1 --desired 1 --max_rounds 1 --best_decode 16 --output ../validation/sample_direct.csv
18
+ /vast/projects/pranam/lab/yz927/envs/metal/bin/python -u tools/sample.py --mode prototype --target_idx 1 --seq_len 30 --batch 1 --desired 1 --max_rounds 1 --best_decode 16 --t_start 15 --proto MDPETCPCPSGGSCTCADSCKCEGCKCTSCKKSCCSCCPAECEKCAKDCVCKGGEAAEAEAEKCSCCQ --output ../validation/sample_prototype.csv