Add computational release from Zenodo 22960654
Browse files- .gitattributes +3 -0
- Computational/README.md +111 -0
- Computational/package/APACHE-2.0.txt +201 -0
- Computational/package/THIRD_PARTY_NOTICES.md +10 -0
- Computational/package/assets/esm2_t33_650M_UR50D/LICENSE +21 -0
- Computational/package/assets/esm2_t33_650M_UR50D/config.json +29 -0
- Computational/package/assets/esm2_t33_650M_UR50D/model.safetensors +3 -0
- Computational/package/assets/esm2_t33_650M_UR50D/special_tokens_map.json +7 -0
- Computational/package/assets/esm2_t33_650M_UR50D/tokenizer_config.json +4 -0
- Computational/package/assets/esm2_t33_650M_UR50D/vocab.txt +33 -0
- Computational/package/checkpoints/metalatte_predictor.ckpt +3 -0
- Computational/package/checkpoints/metalorian_diffusion.pt +3 -0
- Computational/package/data/MbPA/mbpa_source_export.csv +3 -0
- Computational/package/data/MbPA/mbpa_training_sequences.csv +3 -0
- Computational/package/data/metalatte/train/data-00000-of-00004.arrow +3 -0
- Computational/package/data/metalatte/train/data-00001-of-00004.arrow +3 -0
- Computational/package/data/metalatte/train/data-00002-of-00004.arrow +3 -0
- Computational/package/data/metalatte/train/data-00003-of-00004.arrow +3 -0
- Computational/package/data/metalatte/train/dataset_info.json +128 -0
- Computational/package/data/metalatte/train/state.json +22 -0
- Computational/package/data/metalatte/validation/data-00000-of-00001.arrow +3 -0
- Computational/package/data/metalatte/validation/dataset_info.json +128 -0
- Computational/package/data/metalatte/validation/state.json +13 -0
- Computational/package/data/metalorian/test/data-00000-of-00001.arrow +3 -0
- Computational/package/data/metalorian/test/dataset_info.json +29 -0
- Computational/package/data/metalorian/test/state.json +13 -0
- Computational/package/data/metalorian/train/data-00000-of-00001.arrow +3 -0
- Computational/package/data/metalorian/train/dataset_info.json +29 -0
- Computational/package/data/metalorian/train/state.json +13 -0
- Computational/package/metalorian/__init__.py +1 -0
- Computational/package/metalorian/cli.py +83 -0
- Computational/package/metalorian/continuous.py +202 -0
- Computational/package/metalorian/data.py +35 -0
- Computational/package/metalorian/discrete.py +276 -0
- Computational/package/metalorian/layers.py +164 -0
- Computational/package/metalorian/objectives.py +76 -0
- Computational/package/metalorian/paths.py +35 -0
- Computational/package/metalorian/predictor.py +585 -0
- Computational/package/metalorian/sampling.py +173 -0
- Computational/package/metalorian/unet.py +93 -0
- Computational/package/requirements.txt +14 -0
- Computational/package/sample_direct.py +174 -0
- Computational/package/sample_prototype.py +129 -0
- Computational/package/train.py +219 -0
- Computational/validation/figures/amino_acid_composition_difference_full_reference_predictor_gated_n500.csv +81 -0
- Computational/validation/figures/amino_acid_composition_difference_overall_full_reference_predictor_gated_n500.csv +21 -0
- Computational/validation/figures/physicochemical_properties_full_reference.csv +3 -0
- Computational/validation/figures/physicochemical_summary_predictor_gated_n500.csv +49 -0
- 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
|