Add files using upload-large-folder tool
Browse files- models/esm/__pycache__/esm1.cpython-311.pyc +0 -0
- models/esm/__pycache__/esm2.cpython-311.pyc +0 -0
- models/esm/__pycache__/msa_transformer.cpython-311.pyc +0 -0
- models/esm/__pycache__/pretrained.cpython-310.pyc +0 -0
- models/esm/__pycache__/pretrained.cpython-311.pyc +0 -0
- models/esm/esm1.py +200 -0
- models/esm/esmfold/v1/__init__.py +0 -0
- models/esm/esmfold/v1/__pycache__/categorical_mixture.cpython-310.pyc +0 -0
- models/esm/esmfold/v1/__pycache__/pretrained.cpython-310.pyc +0 -0
- models/esm/esmfold/v1/__pycache__/tri_self_attn_block.cpython-310.pyc +0 -0
- models/esm/esmfold/v1/categorical_mixture.py +43 -0
- models/esm/esmfold/v1/misc.py +309 -0
- models/esm/esmfold/v1/tri_self_attn_block.py +160 -0
- models/esm/esmfold/v1/trunk.py +245 -0
- models/esm/inverse_folding/__pycache__/gvp_modules.cpython-310.pyc +0 -0
- models/esm/inverse_folding/__pycache__/gvp_transformer.cpython-310.pyc +0 -0
- models/esm/inverse_folding/gvp_utils.py +68 -0
- models/esm/inverse_folding/transformer_layer.py +304 -0
- models/simplefold/torch/__pycache__/__init__.cpython-311.pyc +0 -0
- models/simplefold/torch/__pycache__/pos_embed.cpython-311.pyc +0 -0
models/esm/__pycache__/esm1.cpython-311.pyc
ADDED
|
Binary file (10.1 kB). View file
|
|
|
models/esm/__pycache__/esm2.cpython-311.pyc
ADDED
|
Binary file (6.7 kB). View file
|
|
|
models/esm/__pycache__/msa_transformer.cpython-311.pyc
ADDED
|
Binary file (10.3 kB). View file
|
|
|
models/esm/__pycache__/pretrained.cpython-310.pyc
ADDED
|
Binary file (19.6 kB). View file
|
|
|
models/esm/__pycache__/pretrained.cpython-311.pyc
ADDED
|
Binary file (29.4 kB). View file
|
|
|
models/esm/esm1.py
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
| 2 |
+
#
|
| 3 |
+
# This source code is licensed under the MIT license found in the
|
| 4 |
+
# LICENSE file in the root directory of this source tree.
|
| 5 |
+
|
| 6 |
+
import math
|
| 7 |
+
|
| 8 |
+
import torch
|
| 9 |
+
import torch.nn as nn
|
| 10 |
+
import torch.nn.functional as F
|
| 11 |
+
|
| 12 |
+
from onescience.modules.esm import (
|
| 13 |
+
TransformerLayer,
|
| 14 |
+
LearnedPositionalEmbedding,
|
| 15 |
+
SinusoidalPositionalEmbedding,
|
| 16 |
+
RobertaLMHead,
|
| 17 |
+
ESM1bLayerNorm,
|
| 18 |
+
ContactPredictionHead,
|
| 19 |
+
)
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class ProteinBertModel(nn.Module):
|
| 23 |
+
@classmethod
|
| 24 |
+
def add_args(cls, parser):
|
| 25 |
+
parser.add_argument(
|
| 26 |
+
"--num_layers", default=36, type=int, metavar="N", help="number of layers"
|
| 27 |
+
)
|
| 28 |
+
parser.add_argument(
|
| 29 |
+
"--embed_dim", default=1280, type=int, metavar="N", help="embedding dimension"
|
| 30 |
+
)
|
| 31 |
+
parser.add_argument(
|
| 32 |
+
"--logit_bias", action="store_true", help="whether to apply bias to logits"
|
| 33 |
+
)
|
| 34 |
+
parser.add_argument(
|
| 35 |
+
"--ffn_embed_dim",
|
| 36 |
+
default=5120,
|
| 37 |
+
type=int,
|
| 38 |
+
metavar="N",
|
| 39 |
+
help="embedding dimension for FFN",
|
| 40 |
+
)
|
| 41 |
+
parser.add_argument(
|
| 42 |
+
"--attention_heads",
|
| 43 |
+
default=20,
|
| 44 |
+
type=int,
|
| 45 |
+
metavar="N",
|
| 46 |
+
help="number of attention heads",
|
| 47 |
+
)
|
| 48 |
+
|
| 49 |
+
def __init__(self, args, alphabet):
|
| 50 |
+
super().__init__()
|
| 51 |
+
self.args = args
|
| 52 |
+
self.alphabet_size = len(alphabet)
|
| 53 |
+
self.padding_idx = alphabet.padding_idx
|
| 54 |
+
self.mask_idx = alphabet.mask_idx
|
| 55 |
+
self.cls_idx = alphabet.cls_idx
|
| 56 |
+
self.eos_idx = alphabet.eos_idx
|
| 57 |
+
self.prepend_bos = alphabet.prepend_bos
|
| 58 |
+
self.append_eos = alphabet.append_eos
|
| 59 |
+
self.emb_layer_norm_before = getattr(self.args, "emb_layer_norm_before", False)
|
| 60 |
+
if self.args.arch == "roberta_large":
|
| 61 |
+
self.model_version = "ESM-1b"
|
| 62 |
+
self._init_submodules_esm1b()
|
| 63 |
+
else:
|
| 64 |
+
self.model_version = "ESM-1"
|
| 65 |
+
self._init_submodules_esm1()
|
| 66 |
+
|
| 67 |
+
def _init_submodules_common(self):
|
| 68 |
+
self.embed_tokens = nn.Embedding(
|
| 69 |
+
self.alphabet_size, self.args.embed_dim, padding_idx=self.padding_idx
|
| 70 |
+
)
|
| 71 |
+
self.layers = nn.ModuleList(
|
| 72 |
+
[
|
| 73 |
+
TransformerLayer(
|
| 74 |
+
self.args.embed_dim,
|
| 75 |
+
self.args.ffn_embed_dim,
|
| 76 |
+
self.args.attention_heads,
|
| 77 |
+
add_bias_kv=(self.model_version != "ESM-1b"),
|
| 78 |
+
use_esm1b_layer_norm=(self.model_version == "ESM-1b"),
|
| 79 |
+
)
|
| 80 |
+
for _ in range(self.args.layers)
|
| 81 |
+
]
|
| 82 |
+
)
|
| 83 |
+
|
| 84 |
+
self.contact_head = ContactPredictionHead(
|
| 85 |
+
self.args.layers * self.args.attention_heads,
|
| 86 |
+
self.prepend_bos,
|
| 87 |
+
self.append_eos,
|
| 88 |
+
eos_idx=self.eos_idx,
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
+
def _init_submodules_esm1b(self):
|
| 92 |
+
self._init_submodules_common()
|
| 93 |
+
self.embed_scale = 1
|
| 94 |
+
self.embed_positions = LearnedPositionalEmbedding(
|
| 95 |
+
self.args.max_positions, self.args.embed_dim, self.padding_idx
|
| 96 |
+
)
|
| 97 |
+
self.emb_layer_norm_before = (
|
| 98 |
+
ESM1bLayerNorm(self.args.embed_dim) if self.emb_layer_norm_before else None
|
| 99 |
+
)
|
| 100 |
+
self.emb_layer_norm_after = ESM1bLayerNorm(self.args.embed_dim)
|
| 101 |
+
self.lm_head = RobertaLMHead(
|
| 102 |
+
embed_dim=self.args.embed_dim,
|
| 103 |
+
output_dim=self.alphabet_size,
|
| 104 |
+
weight=self.embed_tokens.weight,
|
| 105 |
+
)
|
| 106 |
+
|
| 107 |
+
def _init_submodules_esm1(self):
|
| 108 |
+
self._init_submodules_common()
|
| 109 |
+
self.embed_scale = math.sqrt(self.args.embed_dim)
|
| 110 |
+
self.embed_positions = SinusoidalPositionalEmbedding(self.args.embed_dim, self.padding_idx)
|
| 111 |
+
self.embed_out = nn.Parameter(torch.zeros((self.alphabet_size, self.args.embed_dim)))
|
| 112 |
+
self.embed_out_bias = None
|
| 113 |
+
if self.args.final_bias:
|
| 114 |
+
self.embed_out_bias = nn.Parameter(torch.zeros(self.alphabet_size))
|
| 115 |
+
|
| 116 |
+
def forward(self, tokens, repr_layers=[], need_head_weights=False, return_contacts=False):
|
| 117 |
+
if return_contacts:
|
| 118 |
+
need_head_weights = True
|
| 119 |
+
|
| 120 |
+
assert tokens.ndim == 2
|
| 121 |
+
padding_mask = tokens.eq(self.padding_idx) # B, T
|
| 122 |
+
|
| 123 |
+
x = self.embed_scale * self.embed_tokens(tokens)
|
| 124 |
+
|
| 125 |
+
if getattr(self.args, "token_dropout", False):
|
| 126 |
+
x.masked_fill_((tokens == self.mask_idx).unsqueeze(-1), 0.0)
|
| 127 |
+
# x: B x T x C
|
| 128 |
+
mask_ratio_train = 0.15 * 0.8
|
| 129 |
+
src_lengths = (~padding_mask).sum(-1)
|
| 130 |
+
mask_ratio_observed = (tokens == self.mask_idx).sum(-1).float() / src_lengths
|
| 131 |
+
x = x * (1 - mask_ratio_train) / (1 - mask_ratio_observed)[:, None, None]
|
| 132 |
+
|
| 133 |
+
x = x + self.embed_positions(tokens)
|
| 134 |
+
|
| 135 |
+
if self.model_version == "ESM-1b":
|
| 136 |
+
if self.emb_layer_norm_before:
|
| 137 |
+
x = self.emb_layer_norm_before(x)
|
| 138 |
+
if padding_mask is not None:
|
| 139 |
+
x = x * (1 - padding_mask.unsqueeze(-1).type_as(x))
|
| 140 |
+
|
| 141 |
+
repr_layers = set(repr_layers)
|
| 142 |
+
hidden_representations = {}
|
| 143 |
+
if 0 in repr_layers:
|
| 144 |
+
hidden_representations[0] = x
|
| 145 |
+
|
| 146 |
+
if need_head_weights:
|
| 147 |
+
attn_weights = []
|
| 148 |
+
|
| 149 |
+
# (B, T, E) => (T, B, E)
|
| 150 |
+
x = x.transpose(0, 1)
|
| 151 |
+
|
| 152 |
+
if not padding_mask.any():
|
| 153 |
+
padding_mask = None
|
| 154 |
+
|
| 155 |
+
for layer_idx, layer in enumerate(self.layers):
|
| 156 |
+
x, attn = layer(
|
| 157 |
+
x, self_attn_padding_mask=padding_mask, need_head_weights=need_head_weights
|
| 158 |
+
)
|
| 159 |
+
if (layer_idx + 1) in repr_layers:
|
| 160 |
+
hidden_representations[layer_idx + 1] = x.transpose(0, 1)
|
| 161 |
+
if need_head_weights:
|
| 162 |
+
# (H, B, T, T) => (B, H, T, T)
|
| 163 |
+
attn_weights.append(attn.transpose(1, 0))
|
| 164 |
+
|
| 165 |
+
if self.model_version == "ESM-1b":
|
| 166 |
+
x = self.emb_layer_norm_after(x)
|
| 167 |
+
x = x.transpose(0, 1) # (T, B, E) => (B, T, E)
|
| 168 |
+
|
| 169 |
+
# last hidden representation should have layer norm applied
|
| 170 |
+
if (layer_idx + 1) in repr_layers:
|
| 171 |
+
hidden_representations[layer_idx + 1] = x
|
| 172 |
+
x = self.lm_head(x)
|
| 173 |
+
else:
|
| 174 |
+
x = F.linear(x, self.embed_out, bias=self.embed_out_bias)
|
| 175 |
+
x = x.transpose(0, 1) # (T, B, E) => (B, T, E)
|
| 176 |
+
|
| 177 |
+
result = {"logits": x, "representations": hidden_representations}
|
| 178 |
+
if need_head_weights:
|
| 179 |
+
# attentions: B x L x H x T x T
|
| 180 |
+
attentions = torch.stack(attn_weights, 1)
|
| 181 |
+
if self.model_version == "ESM-1":
|
| 182 |
+
# ESM-1 models have an additional null-token for attention, which we remove
|
| 183 |
+
attentions = attentions[..., :-1]
|
| 184 |
+
if padding_mask is not None:
|
| 185 |
+
attention_mask = 1 - padding_mask.type_as(attentions)
|
| 186 |
+
attention_mask = attention_mask.unsqueeze(1) * attention_mask.unsqueeze(2)
|
| 187 |
+
attentions = attentions * attention_mask[:, None, None, :, :]
|
| 188 |
+
result["attentions"] = attentions
|
| 189 |
+
if return_contacts:
|
| 190 |
+
contacts = self.contact_head(tokens, attentions)
|
| 191 |
+
result["contacts"] = contacts
|
| 192 |
+
|
| 193 |
+
return result
|
| 194 |
+
|
| 195 |
+
def predict_contacts(self, tokens):
|
| 196 |
+
return self(tokens, return_contacts=True)["contacts"]
|
| 197 |
+
|
| 198 |
+
@property
|
| 199 |
+
def num_layers(self):
|
| 200 |
+
return self.args.layers
|
models/esm/esmfold/v1/__init__.py
ADDED
|
File without changes
|
models/esm/esmfold/v1/__pycache__/categorical_mixture.cpython-310.pyc
ADDED
|
Binary file (1.35 kB). View file
|
|
|
models/esm/esmfold/v1/__pycache__/pretrained.cpython-310.pyc
ADDED
|
Binary file (7.21 kB). View file
|
|
|
models/esm/esmfold/v1/__pycache__/tri_self_attn_block.cpython-310.pyc
ADDED
|
Binary file (3.56 kB). View file
|
|
|
models/esm/esmfold/v1/categorical_mixture.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
| 2 |
+
#
|
| 3 |
+
# This source code is licensed under the MIT license found in the
|
| 4 |
+
# LICENSE file in the root directory of this source tree.
|
| 5 |
+
import torch
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class CategoricalMixture:
|
| 9 |
+
def __init__(self, param, bins=50, start=0, end=1):
|
| 10 |
+
# All tensors are of shape ..., bins.
|
| 11 |
+
self.logits = param
|
| 12 |
+
bins = torch.linspace(
|
| 13 |
+
start, end, bins + 1, device=self.logits.device, dtype=self.logits.dtype
|
| 14 |
+
)
|
| 15 |
+
self.v_bins = (bins[:-1] + bins[1:]) / 2
|
| 16 |
+
|
| 17 |
+
def log_prob(self, true):
|
| 18 |
+
# Shapes are:
|
| 19 |
+
# self.probs: ... x bins
|
| 20 |
+
# true : ...
|
| 21 |
+
true_index = (
|
| 22 |
+
(
|
| 23 |
+
true.unsqueeze(-1)
|
| 24 |
+
- self.v_bins[
|
| 25 |
+
[
|
| 26 |
+
None,
|
| 27 |
+
]
|
| 28 |
+
* true.ndim
|
| 29 |
+
]
|
| 30 |
+
)
|
| 31 |
+
.abs()
|
| 32 |
+
.argmin(-1)
|
| 33 |
+
)
|
| 34 |
+
nll = self.logits.log_softmax(-1)
|
| 35 |
+
return torch.take_along_dim(nll, true_index.unsqueeze(-1), dim=-1).squeeze(-1)
|
| 36 |
+
|
| 37 |
+
def mean(self):
|
| 38 |
+
return (self.logits.softmax(-1) @ self.v_bins.unsqueeze(1)).squeeze(-1)
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def categorical_lddt(logits, bins=50):
|
| 42 |
+
# Logits are ..., 37, bins.
|
| 43 |
+
return CategoricalMixture(logits, bins=bins).mean()
|
models/esm/esmfold/v1/misc.py
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
| 2 |
+
#
|
| 3 |
+
# This source code is licensed under the MIT license found in the
|
| 4 |
+
# LICENSE file in the root directory of this source tree.
|
| 5 |
+
import typing as T
|
| 6 |
+
|
| 7 |
+
import numpy as np
|
| 8 |
+
import torch
|
| 9 |
+
import torch.nn.functional as F
|
| 10 |
+
from einops import rearrange, repeat
|
| 11 |
+
from torch import nn
|
| 12 |
+
from modules.utils.openfold.np import residue_constants
|
| 13 |
+
from modules.utils.openfold.np.protein import Protein as OFProtein
|
| 14 |
+
from modules.utils.openfold.np.protein import to_pdb
|
| 15 |
+
from modules.utils.openfold.feats import atom14_to_atom37
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def encode_sequence(
|
| 19 |
+
seq: str,
|
| 20 |
+
residue_index_offset: T.Optional[int] = 512,
|
| 21 |
+
chain_linker: T.Optional[str] = "G" * 25,
|
| 22 |
+
) -> T.Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
|
| 23 |
+
if chain_linker is None:
|
| 24 |
+
chain_linker = ""
|
| 25 |
+
if residue_index_offset is None:
|
| 26 |
+
residue_index_offset = 0
|
| 27 |
+
|
| 28 |
+
chains = seq.split(":")
|
| 29 |
+
seq = chain_linker.join(chains)
|
| 30 |
+
|
| 31 |
+
unk_idx = residue_constants.restype_order_with_x["X"]
|
| 32 |
+
encoded = torch.tensor(
|
| 33 |
+
[residue_constants.restype_order_with_x.get(aa, unk_idx) for aa in seq]
|
| 34 |
+
)
|
| 35 |
+
residx = torch.arange(len(encoded))
|
| 36 |
+
|
| 37 |
+
if residue_index_offset > 0:
|
| 38 |
+
start = 0
|
| 39 |
+
for i, chain in enumerate(chains):
|
| 40 |
+
residx[start : start + len(chain) + len(chain_linker)] += (
|
| 41 |
+
i * residue_index_offset
|
| 42 |
+
)
|
| 43 |
+
start += len(chain) + len(chain_linker)
|
| 44 |
+
|
| 45 |
+
linker_mask = torch.ones_like(encoded, dtype=torch.float32)
|
| 46 |
+
chain_index = []
|
| 47 |
+
offset = 0
|
| 48 |
+
for i, chain in enumerate(chains):
|
| 49 |
+
if i > 0:
|
| 50 |
+
chain_index.extend([i - 1] * len(chain_linker))
|
| 51 |
+
chain_index.extend([i] * len(chain))
|
| 52 |
+
offset += len(chain)
|
| 53 |
+
linker_mask[offset : offset + len(chain_linker)] = 0
|
| 54 |
+
offset += len(chain_linker)
|
| 55 |
+
|
| 56 |
+
chain_index = torch.tensor(chain_index, dtype=torch.int64)
|
| 57 |
+
|
| 58 |
+
return encoded, residx, linker_mask, chain_index
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def batch_encode_sequences(
|
| 62 |
+
sequences: T.Sequence[str],
|
| 63 |
+
residue_index_offset: T.Optional[int] = 512,
|
| 64 |
+
chain_linker: T.Optional[str] = "G" * 25,
|
| 65 |
+
) -> T.Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
|
| 66 |
+
|
| 67 |
+
aatype_list = []
|
| 68 |
+
residx_list = []
|
| 69 |
+
linker_mask_list = []
|
| 70 |
+
chain_index_list = []
|
| 71 |
+
for seq in sequences:
|
| 72 |
+
aatype_seq, residx_seq, linker_mask_seq, chain_index_seq = encode_sequence(
|
| 73 |
+
seq,
|
| 74 |
+
residue_index_offset=residue_index_offset,
|
| 75 |
+
chain_linker=chain_linker,
|
| 76 |
+
)
|
| 77 |
+
aatype_list.append(aatype_seq)
|
| 78 |
+
residx_list.append(residx_seq)
|
| 79 |
+
linker_mask_list.append(linker_mask_seq)
|
| 80 |
+
chain_index_list.append(chain_index_seq)
|
| 81 |
+
|
| 82 |
+
aatype = collate_dense_tensors(aatype_list)
|
| 83 |
+
mask = collate_dense_tensors(
|
| 84 |
+
[aatype.new_ones(len(aatype_seq)) for aatype_seq in aatype_list]
|
| 85 |
+
)
|
| 86 |
+
residx = collate_dense_tensors(residx_list)
|
| 87 |
+
linker_mask = collate_dense_tensors(linker_mask_list)
|
| 88 |
+
chain_index_list = collate_dense_tensors(chain_index_list, -1)
|
| 89 |
+
|
| 90 |
+
return aatype, mask, residx, linker_mask, chain_index_list
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
def output_to_pdb(output: T.Dict) -> T.List[str]:
|
| 94 |
+
"""Returns the pbd (file) string from the model given the model output."""
|
| 95 |
+
# atom14_to_atom37 must be called first, as it fails on latest numpy if the
|
| 96 |
+
# input is a numpy array. It will work if the input is a torch tensor.
|
| 97 |
+
final_atom_positions = atom14_to_atom37(output["positions"][-1], output)
|
| 98 |
+
output = {k: v.to("cpu").numpy() for k, v in output.items()}
|
| 99 |
+
final_atom_positions = final_atom_positions.cpu().numpy()
|
| 100 |
+
final_atom_mask = output["atom37_atom_exists"]
|
| 101 |
+
pdbs = []
|
| 102 |
+
for i in range(output["aatype"].shape[0]):
|
| 103 |
+
aa = output["aatype"][i]
|
| 104 |
+
pred_pos = final_atom_positions[i]
|
| 105 |
+
mask = final_atom_mask[i]
|
| 106 |
+
resid = output["residue_index"][i] + 1
|
| 107 |
+
pred = OFProtein(
|
| 108 |
+
aatype=aa,
|
| 109 |
+
atom_positions=pred_pos,
|
| 110 |
+
atom_mask=mask,
|
| 111 |
+
residue_index=resid,
|
| 112 |
+
b_factors=output["plddt"][i],
|
| 113 |
+
chain_index=output["chain_index"][i] if "chain_index" in output else None,
|
| 114 |
+
)
|
| 115 |
+
pdbs.append(to_pdb(pred))
|
| 116 |
+
return pdbs
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
def collate_dense_tensors(
|
| 120 |
+
samples: T.List[torch.Tensor], pad_v: float = 0
|
| 121 |
+
) -> torch.Tensor:
|
| 122 |
+
"""
|
| 123 |
+
Takes a list of tensors with the following dimensions:
|
| 124 |
+
[(d_11, ..., d_1K),
|
| 125 |
+
(d_21, ..., d_2K),
|
| 126 |
+
...,
|
| 127 |
+
(d_N1, ..., d_NK)]
|
| 128 |
+
and stack + pads them into a single tensor of:
|
| 129 |
+
(N, max_i=1,N { d_i1 }, ..., max_i=1,N {diK})
|
| 130 |
+
"""
|
| 131 |
+
if len(samples) == 0:
|
| 132 |
+
return torch.Tensor()
|
| 133 |
+
if len(set(x.dim() for x in samples)) != 1:
|
| 134 |
+
raise RuntimeError(
|
| 135 |
+
f"Samples has varying dimensions: {[x.dim() for x in samples]}"
|
| 136 |
+
)
|
| 137 |
+
(device,) = tuple(set(x.device for x in samples)) # assumes all on same device
|
| 138 |
+
max_shape = [max(lst) for lst in zip(*[x.shape for x in samples])]
|
| 139 |
+
result = torch.empty(
|
| 140 |
+
len(samples), *max_shape, dtype=samples[0].dtype, device=device
|
| 141 |
+
)
|
| 142 |
+
result.fill_(pad_v)
|
| 143 |
+
for i in range(len(samples)):
|
| 144 |
+
result_i = result[i]
|
| 145 |
+
t = samples[i]
|
| 146 |
+
result_i[tuple(slice(0, k) for k in t.shape)] = t
|
| 147 |
+
return result
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
class Attention(nn.Module):
|
| 151 |
+
def __init__(self, embed_dim, num_heads, head_width, gated=False):
|
| 152 |
+
super().__init__()
|
| 153 |
+
assert embed_dim == num_heads * head_width
|
| 154 |
+
|
| 155 |
+
self.embed_dim = embed_dim
|
| 156 |
+
self.num_heads = num_heads
|
| 157 |
+
self.head_width = head_width
|
| 158 |
+
|
| 159 |
+
self.proj = nn.Linear(embed_dim, embed_dim * 3, bias=False)
|
| 160 |
+
self.o_proj = nn.Linear(embed_dim, embed_dim, bias=True)
|
| 161 |
+
self.gated = gated
|
| 162 |
+
if gated:
|
| 163 |
+
self.g_proj = nn.Linear(embed_dim, embed_dim)
|
| 164 |
+
torch.nn.init.zeros_(self.g_proj.weight)
|
| 165 |
+
torch.nn.init.ones_(self.g_proj.bias)
|
| 166 |
+
|
| 167 |
+
self.rescale_factor = self.head_width**-0.5
|
| 168 |
+
|
| 169 |
+
torch.nn.init.zeros_(self.o_proj.bias)
|
| 170 |
+
|
| 171 |
+
def forward(self, x, mask=None, bias=None, indices=None):
|
| 172 |
+
"""
|
| 173 |
+
Basic self attention with optional mask and external pairwise bias.
|
| 174 |
+
To handle sequences of different lengths, use mask.
|
| 175 |
+
|
| 176 |
+
Inputs:
|
| 177 |
+
x: batch of input sequneces (.. x L x C)
|
| 178 |
+
mask: batch of boolean masks where 1=valid, 0=padding position (.. x L_k). optional.
|
| 179 |
+
bias: batch of scalar pairwise attention biases (.. x Lq x Lk x num_heads). optional.
|
| 180 |
+
|
| 181 |
+
Outputs:
|
| 182 |
+
sequence projection (B x L x embed_dim), attention maps (B x L x L x num_heads)
|
| 183 |
+
"""
|
| 184 |
+
|
| 185 |
+
t = rearrange(self.proj(x), "... l (h c) -> ... h l c", h=self.num_heads)
|
| 186 |
+
q, k, v = t.chunk(3, dim=-1)
|
| 187 |
+
|
| 188 |
+
q = self.rescale_factor * q
|
| 189 |
+
a = torch.einsum("...qc,...kc->...qk", q, k)
|
| 190 |
+
|
| 191 |
+
# Add external attention bias.
|
| 192 |
+
if bias is not None:
|
| 193 |
+
a = a + rearrange(bias, "... lq lk h -> ... h lq lk")
|
| 194 |
+
|
| 195 |
+
# Do not attend to padding tokens.
|
| 196 |
+
if mask is not None:
|
| 197 |
+
mask = repeat(
|
| 198 |
+
mask, "... lk -> ... h lq lk", h=self.num_heads, lq=q.shape[-2]
|
| 199 |
+
)
|
| 200 |
+
a = a.masked_fill(mask == False, -np.inf)
|
| 201 |
+
|
| 202 |
+
a = F.softmax(a, dim=-1)
|
| 203 |
+
|
| 204 |
+
y = torch.einsum("...hqk,...hkc->...qhc", a, v)
|
| 205 |
+
y = rearrange(y, "... h c -> ... (h c)", h=self.num_heads)
|
| 206 |
+
|
| 207 |
+
if self.gated:
|
| 208 |
+
y = self.g_proj(x).sigmoid() * y
|
| 209 |
+
y = self.o_proj(y)
|
| 210 |
+
|
| 211 |
+
return y, rearrange(a, "... lq lk h -> ... h lq lk")
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
class Dropout(nn.Module):
|
| 215 |
+
"""
|
| 216 |
+
Implementation of dropout with the ability to share the dropout mask
|
| 217 |
+
along a particular dimension.
|
| 218 |
+
"""
|
| 219 |
+
|
| 220 |
+
def __init__(self, r: float, batch_dim: T.Union[int, T.List[int]]):
|
| 221 |
+
super(Dropout, self).__init__()
|
| 222 |
+
|
| 223 |
+
self.r = r
|
| 224 |
+
if type(batch_dim) == int:
|
| 225 |
+
batch_dim = [batch_dim]
|
| 226 |
+
self.batch_dim = batch_dim
|
| 227 |
+
self.dropout = nn.Dropout(self.r)
|
| 228 |
+
|
| 229 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 230 |
+
shape = list(x.shape)
|
| 231 |
+
if self.batch_dim is not None:
|
| 232 |
+
for bd in self.batch_dim:
|
| 233 |
+
shape[bd] = 1
|
| 234 |
+
return x * self.dropout(x.new_ones(shape))
|
| 235 |
+
|
| 236 |
+
|
| 237 |
+
class SequenceToPair(nn.Module):
|
| 238 |
+
def __init__(self, sequence_state_dim, inner_dim, pairwise_state_dim):
|
| 239 |
+
super().__init__()
|
| 240 |
+
|
| 241 |
+
self.layernorm = nn.LayerNorm(sequence_state_dim)
|
| 242 |
+
self.proj = nn.Linear(sequence_state_dim, inner_dim * 2, bias=True)
|
| 243 |
+
self.o_proj = nn.Linear(2 * inner_dim, pairwise_state_dim, bias=True)
|
| 244 |
+
|
| 245 |
+
torch.nn.init.zeros_(self.proj.bias)
|
| 246 |
+
torch.nn.init.zeros_(self.o_proj.bias)
|
| 247 |
+
|
| 248 |
+
def forward(self, sequence_state):
|
| 249 |
+
"""
|
| 250 |
+
Inputs:
|
| 251 |
+
sequence_state: B x L x sequence_state_dim
|
| 252 |
+
|
| 253 |
+
Output:
|
| 254 |
+
pairwise_state: B x L x L x pairwise_state_dim
|
| 255 |
+
|
| 256 |
+
Intermediate state:
|
| 257 |
+
B x L x L x 2*inner_dim
|
| 258 |
+
"""
|
| 259 |
+
|
| 260 |
+
assert len(sequence_state.shape) == 3
|
| 261 |
+
|
| 262 |
+
s = self.layernorm(sequence_state)
|
| 263 |
+
s = self.proj(s)
|
| 264 |
+
q, k = s.chunk(2, dim=-1)
|
| 265 |
+
|
| 266 |
+
prod = q[:, None, :, :] * k[:, :, None, :]
|
| 267 |
+
diff = q[:, None, :, :] - k[:, :, None, :]
|
| 268 |
+
|
| 269 |
+
x = torch.cat([prod, diff], dim=-1)
|
| 270 |
+
x = self.o_proj(x)
|
| 271 |
+
|
| 272 |
+
return x
|
| 273 |
+
|
| 274 |
+
|
| 275 |
+
class PairToSequence(nn.Module):
|
| 276 |
+
def __init__(self, pairwise_state_dim, num_heads):
|
| 277 |
+
super().__init__()
|
| 278 |
+
|
| 279 |
+
self.layernorm = nn.LayerNorm(pairwise_state_dim)
|
| 280 |
+
self.linear = nn.Linear(pairwise_state_dim, num_heads, bias=False)
|
| 281 |
+
|
| 282 |
+
def forward(self, pairwise_state):
|
| 283 |
+
"""
|
| 284 |
+
Inputs:
|
| 285 |
+
pairwise_state: B x L x L x pairwise_state_dim
|
| 286 |
+
|
| 287 |
+
Output:
|
| 288 |
+
pairwise_bias: B x L x L x num_heads
|
| 289 |
+
"""
|
| 290 |
+
assert len(pairwise_state.shape) == 4
|
| 291 |
+
z = self.layernorm(pairwise_state)
|
| 292 |
+
pairwise_bias = self.linear(z)
|
| 293 |
+
return pairwise_bias
|
| 294 |
+
|
| 295 |
+
|
| 296 |
+
class ResidueMLP(nn.Module):
|
| 297 |
+
def __init__(self, embed_dim, inner_dim, norm=nn.LayerNorm, dropout=0):
|
| 298 |
+
super().__init__()
|
| 299 |
+
|
| 300 |
+
self.mlp = nn.Sequential(
|
| 301 |
+
norm(embed_dim),
|
| 302 |
+
nn.Linear(embed_dim, inner_dim),
|
| 303 |
+
nn.ReLU(),
|
| 304 |
+
nn.Linear(inner_dim, embed_dim),
|
| 305 |
+
nn.Dropout(dropout),
|
| 306 |
+
)
|
| 307 |
+
|
| 308 |
+
def forward(self, x):
|
| 309 |
+
return x + self.mlp(x)
|
models/esm/esmfold/v1/tri_self_attn_block.py
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
| 2 |
+
#
|
| 3 |
+
# This source code is licensed under the MIT license found in the
|
| 4 |
+
# LICENSE file in the root directory of this source tree.
|
| 5 |
+
import torch
|
| 6 |
+
from models.openfold.triangular_attention import (
|
| 7 |
+
TriangleAttentionEndingNode,
|
| 8 |
+
TriangleAttentionStartingNode,
|
| 9 |
+
)
|
| 10 |
+
from models.openfold.triangular_multiplicative_update import (
|
| 11 |
+
TriangleMultiplicationIncoming,
|
| 12 |
+
TriangleMultiplicationOutgoing,
|
| 13 |
+
)
|
| 14 |
+
from torch import nn
|
| 15 |
+
|
| 16 |
+
from models.esm.esmfold.v1.misc import (
|
| 17 |
+
Attention,
|
| 18 |
+
Dropout,
|
| 19 |
+
PairToSequence,
|
| 20 |
+
ResidueMLP,
|
| 21 |
+
SequenceToPair,
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
class TriangularSelfAttentionBlock(nn.Module):
|
| 26 |
+
def __init__(
|
| 27 |
+
self,
|
| 28 |
+
sequence_state_dim,
|
| 29 |
+
pairwise_state_dim,
|
| 30 |
+
sequence_head_width,
|
| 31 |
+
pairwise_head_width,
|
| 32 |
+
dropout=0,
|
| 33 |
+
**__kwargs,
|
| 34 |
+
):
|
| 35 |
+
super().__init__()
|
| 36 |
+
|
| 37 |
+
assert sequence_state_dim % sequence_head_width == 0
|
| 38 |
+
assert pairwise_state_dim % pairwise_head_width == 0
|
| 39 |
+
sequence_num_heads = sequence_state_dim // sequence_head_width
|
| 40 |
+
pairwise_num_heads = pairwise_state_dim // pairwise_head_width
|
| 41 |
+
assert sequence_state_dim == sequence_num_heads * sequence_head_width
|
| 42 |
+
assert pairwise_state_dim == pairwise_num_heads * pairwise_head_width
|
| 43 |
+
assert pairwise_state_dim % 2 == 0
|
| 44 |
+
|
| 45 |
+
self.sequence_state_dim = sequence_state_dim
|
| 46 |
+
self.pairwise_state_dim = pairwise_state_dim
|
| 47 |
+
|
| 48 |
+
self.layernorm_1 = nn.LayerNorm(sequence_state_dim)
|
| 49 |
+
|
| 50 |
+
self.sequence_to_pair = SequenceToPair(
|
| 51 |
+
sequence_state_dim, pairwise_state_dim // 2, pairwise_state_dim
|
| 52 |
+
)
|
| 53 |
+
self.pair_to_sequence = PairToSequence(pairwise_state_dim, sequence_num_heads)
|
| 54 |
+
|
| 55 |
+
self.seq_attention = Attention(
|
| 56 |
+
sequence_state_dim, sequence_num_heads, sequence_head_width, gated=True
|
| 57 |
+
)
|
| 58 |
+
self.tri_mul_out = TriangleMultiplicationOutgoing(
|
| 59 |
+
pairwise_state_dim,
|
| 60 |
+
pairwise_state_dim,
|
| 61 |
+
)
|
| 62 |
+
self.tri_mul_in = TriangleMultiplicationIncoming(
|
| 63 |
+
pairwise_state_dim,
|
| 64 |
+
pairwise_state_dim,
|
| 65 |
+
)
|
| 66 |
+
self.tri_att_start = TriangleAttentionStartingNode(
|
| 67 |
+
pairwise_state_dim,
|
| 68 |
+
pairwise_head_width,
|
| 69 |
+
pairwise_num_heads,
|
| 70 |
+
inf=1e9,
|
| 71 |
+
) # type: ignore
|
| 72 |
+
self.tri_att_end = TriangleAttentionEndingNode(
|
| 73 |
+
pairwise_state_dim,
|
| 74 |
+
pairwise_head_width,
|
| 75 |
+
pairwise_num_heads,
|
| 76 |
+
inf=1e9,
|
| 77 |
+
) # type: ignore
|
| 78 |
+
|
| 79 |
+
self.mlp_seq = ResidueMLP(sequence_state_dim, 4 * sequence_state_dim, dropout=dropout)
|
| 80 |
+
self.mlp_pair = ResidueMLP(pairwise_state_dim, 4 * pairwise_state_dim, dropout=dropout)
|
| 81 |
+
|
| 82 |
+
assert dropout < 0.4
|
| 83 |
+
self.drop = nn.Dropout(dropout)
|
| 84 |
+
self.row_drop = Dropout(dropout * 2, 2)
|
| 85 |
+
self.col_drop = Dropout(dropout * 2, 1)
|
| 86 |
+
|
| 87 |
+
torch.nn.init.zeros_(self.tri_mul_in.linear_z.weight)
|
| 88 |
+
torch.nn.init.zeros_(self.tri_mul_in.linear_z.bias)
|
| 89 |
+
torch.nn.init.zeros_(self.tri_mul_out.linear_z.weight)
|
| 90 |
+
torch.nn.init.zeros_(self.tri_mul_out.linear_z.bias)
|
| 91 |
+
torch.nn.init.zeros_(self.tri_att_start.mha.linear_o.weight)
|
| 92 |
+
torch.nn.init.zeros_(self.tri_att_start.mha.linear_o.bias)
|
| 93 |
+
torch.nn.init.zeros_(self.tri_att_end.mha.linear_o.weight)
|
| 94 |
+
torch.nn.init.zeros_(self.tri_att_end.mha.linear_o.bias)
|
| 95 |
+
|
| 96 |
+
torch.nn.init.zeros_(self.sequence_to_pair.o_proj.weight)
|
| 97 |
+
torch.nn.init.zeros_(self.sequence_to_pair.o_proj.bias)
|
| 98 |
+
torch.nn.init.zeros_(self.pair_to_sequence.linear.weight)
|
| 99 |
+
torch.nn.init.zeros_(self.seq_attention.o_proj.weight)
|
| 100 |
+
torch.nn.init.zeros_(self.seq_attention.o_proj.bias)
|
| 101 |
+
torch.nn.init.zeros_(self.mlp_seq.mlp[-2].weight)
|
| 102 |
+
torch.nn.init.zeros_(self.mlp_seq.mlp[-2].bias)
|
| 103 |
+
torch.nn.init.zeros_(self.mlp_pair.mlp[-2].weight)
|
| 104 |
+
torch.nn.init.zeros_(self.mlp_pair.mlp[-2].bias)
|
| 105 |
+
|
| 106 |
+
def forward(self, sequence_state, pairwise_state, mask=None, chunk_size=None, **__kwargs):
|
| 107 |
+
"""
|
| 108 |
+
Inputs:
|
| 109 |
+
sequence_state: B x L x sequence_state_dim
|
| 110 |
+
pairwise_state: B x L x L x pairwise_state_dim
|
| 111 |
+
mask: B x L boolean tensor of valid positions
|
| 112 |
+
|
| 113 |
+
Output:
|
| 114 |
+
sequence_state: B x L x sequence_state_dim
|
| 115 |
+
pairwise_state: B x L x L x pairwise_state_dim
|
| 116 |
+
"""
|
| 117 |
+
assert len(sequence_state.shape) == 3
|
| 118 |
+
assert len(pairwise_state.shape) == 4
|
| 119 |
+
if mask is not None:
|
| 120 |
+
assert len(mask.shape) == 2
|
| 121 |
+
|
| 122 |
+
batch_dim, seq_dim, sequence_state_dim = sequence_state.shape
|
| 123 |
+
pairwise_state_dim = pairwise_state.shape[3]
|
| 124 |
+
assert sequence_state_dim == self.sequence_state_dim
|
| 125 |
+
assert pairwise_state_dim == self.pairwise_state_dim
|
| 126 |
+
assert batch_dim == pairwise_state.shape[0]
|
| 127 |
+
assert seq_dim == pairwise_state.shape[1]
|
| 128 |
+
assert seq_dim == pairwise_state.shape[2]
|
| 129 |
+
|
| 130 |
+
# Update sequence state
|
| 131 |
+
bias = self.pair_to_sequence(pairwise_state)
|
| 132 |
+
|
| 133 |
+
# Self attention with bias + mlp.
|
| 134 |
+
y = self.layernorm_1(sequence_state)
|
| 135 |
+
y, _ = self.seq_attention(y, mask=mask, bias=bias)
|
| 136 |
+
sequence_state = sequence_state + self.drop(y)
|
| 137 |
+
sequence_state = self.mlp_seq(sequence_state)
|
| 138 |
+
|
| 139 |
+
# Update pairwise state
|
| 140 |
+
pairwise_state = pairwise_state + self.sequence_to_pair(sequence_state)
|
| 141 |
+
|
| 142 |
+
# Axial attention with triangular bias.
|
| 143 |
+
tri_mask = mask.unsqueeze(2) * mask.unsqueeze(1) if mask is not None else None
|
| 144 |
+
pairwise_state = pairwise_state + self.row_drop(
|
| 145 |
+
self.tri_mul_out(pairwise_state, mask=tri_mask)
|
| 146 |
+
)
|
| 147 |
+
pairwise_state = pairwise_state + self.col_drop(
|
| 148 |
+
self.tri_mul_in(pairwise_state, mask=tri_mask)
|
| 149 |
+
)
|
| 150 |
+
pairwise_state = pairwise_state + self.row_drop(
|
| 151 |
+
self.tri_att_start(pairwise_state, mask=tri_mask, chunk_size=chunk_size)
|
| 152 |
+
)
|
| 153 |
+
pairwise_state = pairwise_state + self.col_drop(
|
| 154 |
+
self.tri_att_end(pairwise_state, mask=tri_mask, chunk_size=chunk_size)
|
| 155 |
+
)
|
| 156 |
+
|
| 157 |
+
# MLP over pairs.
|
| 158 |
+
pairwise_state = self.mlp_pair(pairwise_state)
|
| 159 |
+
|
| 160 |
+
return sequence_state, pairwise_state
|
models/esm/esmfold/v1/trunk.py
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
| 2 |
+
#
|
| 3 |
+
# This source code is licensed under the MIT license found in the
|
| 4 |
+
# LICENSE file in the root directory of this source tree.
|
| 5 |
+
import typing as T
|
| 6 |
+
from contextlib import ExitStack
|
| 7 |
+
# from dataclasses import dataclass
|
| 8 |
+
from dataclasses import dataclass, field
|
| 9 |
+
|
| 10 |
+
import torch
|
| 11 |
+
import torch.nn as nn
|
| 12 |
+
from models.openfold.structure_module import StructureModule
|
| 13 |
+
|
| 14 |
+
from models.esm.esmfold.v1.tri_self_attn_block import TriangularSelfAttentionBlock
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
@dataclass
|
| 18 |
+
class StructureModuleConfig:
|
| 19 |
+
c_s: int = 384
|
| 20 |
+
c_z: int = 128
|
| 21 |
+
c_ipa: int = 16
|
| 22 |
+
c_resnet: int = 128
|
| 23 |
+
no_heads_ipa: int = 12
|
| 24 |
+
no_qk_points: int = 4
|
| 25 |
+
no_v_points: int = 8
|
| 26 |
+
dropout_rate: float = 0.1
|
| 27 |
+
no_blocks: int = 8
|
| 28 |
+
no_transition_layers: int = 1
|
| 29 |
+
no_resnet_blocks: int = 2
|
| 30 |
+
no_angles: int = 7
|
| 31 |
+
trans_scale_factor: int = 10
|
| 32 |
+
epsilon: float = 1e-8
|
| 33 |
+
inf: float = 1e5
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
@dataclass
|
| 37 |
+
class FoldingTrunkConfig:
|
| 38 |
+
_name: str = "FoldingTrunkConfig"
|
| 39 |
+
num_blocks: int = 48
|
| 40 |
+
sequence_state_dim: int = 1024
|
| 41 |
+
pairwise_state_dim: int = 128
|
| 42 |
+
sequence_head_width: int = 32
|
| 43 |
+
pairwise_head_width: int = 32
|
| 44 |
+
position_bins: int = 32
|
| 45 |
+
dropout: float = 0
|
| 46 |
+
layer_drop: float = 0
|
| 47 |
+
cpu_grad_checkpoint: bool = False
|
| 48 |
+
|
| 49 |
+
max_recycles: int = 4
|
| 50 |
+
chunk_size: T.Optional[int] = None
|
| 51 |
+
|
| 52 |
+
# structure_module: StructureModuleConfig = StructureModuleConfig()
|
| 53 |
+
structure_module: StructureModuleConfig = field(default_factory=StructureModuleConfig)
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def get_axial_mask(mask):
|
| 57 |
+
"""
|
| 58 |
+
Helper to convert B x L mask of valid positions to axial mask used
|
| 59 |
+
in row column attentions.
|
| 60 |
+
|
| 61 |
+
Input:
|
| 62 |
+
mask: B x L tensor of booleans
|
| 63 |
+
|
| 64 |
+
Output:
|
| 65 |
+
mask: B x L x L tensor of booleans
|
| 66 |
+
"""
|
| 67 |
+
|
| 68 |
+
if mask is None:
|
| 69 |
+
return None
|
| 70 |
+
assert len(mask.shape) == 2
|
| 71 |
+
batch_dim, seq_dim = mask.shape
|
| 72 |
+
m = mask.unsqueeze(1).expand(batch_dim, seq_dim, seq_dim)
|
| 73 |
+
m = m.reshape(batch_dim * seq_dim, seq_dim)
|
| 74 |
+
return m
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
class RelativePosition(nn.Module):
|
| 78 |
+
def __init__(self, bins, pairwise_state_dim):
|
| 79 |
+
super().__init__()
|
| 80 |
+
self.bins = bins
|
| 81 |
+
|
| 82 |
+
# Note an additional offset is used so that the 0th position
|
| 83 |
+
# is reserved for masked pairs.
|
| 84 |
+
self.embedding = torch.nn.Embedding(2 * bins + 2, pairwise_state_dim)
|
| 85 |
+
|
| 86 |
+
def forward(self, residue_index, mask=None):
|
| 87 |
+
"""
|
| 88 |
+
Input:
|
| 89 |
+
residue_index: B x L tensor of indices (dytpe=torch.long)
|
| 90 |
+
mask: B x L tensor of booleans
|
| 91 |
+
|
| 92 |
+
Output:
|
| 93 |
+
pairwise_state: B x L x L x pairwise_state_dim tensor of embeddings
|
| 94 |
+
"""
|
| 95 |
+
|
| 96 |
+
assert residue_index.dtype == torch.long
|
| 97 |
+
if mask is not None:
|
| 98 |
+
assert residue_index.shape == mask.shape
|
| 99 |
+
|
| 100 |
+
diff = residue_index[:, None, :] - residue_index[:, :, None]
|
| 101 |
+
diff = diff.clamp(-self.bins, self.bins)
|
| 102 |
+
diff = diff + self.bins + 1 # Add 1 to adjust for padding index.
|
| 103 |
+
|
| 104 |
+
if mask is not None:
|
| 105 |
+
mask = mask[:, None, :] * mask[:, :, None]
|
| 106 |
+
diff[mask == False] = 0
|
| 107 |
+
|
| 108 |
+
output = self.embedding(diff)
|
| 109 |
+
return output
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
class FoldingTrunk(nn.Module):
|
| 113 |
+
def __init__(self, **kwargs):
|
| 114 |
+
super().__init__()
|
| 115 |
+
self.cfg = FoldingTrunkConfig(**kwargs)
|
| 116 |
+
assert self.cfg.max_recycles > 0
|
| 117 |
+
|
| 118 |
+
c_s = self.cfg.sequence_state_dim
|
| 119 |
+
c_z = self.cfg.pairwise_state_dim
|
| 120 |
+
|
| 121 |
+
assert c_s % self.cfg.sequence_head_width == 0
|
| 122 |
+
assert c_z % self.cfg.pairwise_head_width == 0
|
| 123 |
+
block = TriangularSelfAttentionBlock
|
| 124 |
+
|
| 125 |
+
self.pairwise_positional_embedding = RelativePosition(self.cfg.position_bins, c_z)
|
| 126 |
+
|
| 127 |
+
self.blocks = nn.ModuleList(
|
| 128 |
+
[
|
| 129 |
+
block(
|
| 130 |
+
sequence_state_dim=c_s,
|
| 131 |
+
pairwise_state_dim=c_z,
|
| 132 |
+
sequence_head_width=self.cfg.sequence_head_width,
|
| 133 |
+
pairwise_head_width=self.cfg.pairwise_head_width,
|
| 134 |
+
dropout=self.cfg.dropout,
|
| 135 |
+
)
|
| 136 |
+
for i in range(self.cfg.num_blocks)
|
| 137 |
+
]
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
self.recycle_bins = 15
|
| 141 |
+
self.recycle_s_norm = nn.LayerNorm(c_s)
|
| 142 |
+
self.recycle_z_norm = nn.LayerNorm(c_z)
|
| 143 |
+
self.recycle_disto = nn.Embedding(self.recycle_bins, c_z)
|
| 144 |
+
self.recycle_disto.weight[0].detach().zero_()
|
| 145 |
+
|
| 146 |
+
self.structure_module = StructureModule(**self.cfg.structure_module) # type: ignore
|
| 147 |
+
self.trunk2sm_s = nn.Linear(c_s, self.structure_module.c_s)
|
| 148 |
+
self.trunk2sm_z = nn.Linear(c_z, self.structure_module.c_z)
|
| 149 |
+
|
| 150 |
+
self.chunk_size = self.cfg.chunk_size
|
| 151 |
+
|
| 152 |
+
def set_chunk_size(self, chunk_size):
|
| 153 |
+
# This parameter means the axial attention will be computed
|
| 154 |
+
# in a chunked manner. This should make the memory used more or less O(L) instead of O(L^2).
|
| 155 |
+
# It's equivalent to running a for loop over chunks of the dimension we're iterative over,
|
| 156 |
+
# where the chunk_size is the size of the chunks, so 128 would mean to parse 128-lengthed chunks.
|
| 157 |
+
self.chunk_size = chunk_size
|
| 158 |
+
|
| 159 |
+
def forward(self, seq_feats, pair_feats, true_aa, residx, mask, no_recycles: T.Optional[int] = None):
|
| 160 |
+
"""
|
| 161 |
+
Inputs:
|
| 162 |
+
seq_feats: B x L x C tensor of sequence features
|
| 163 |
+
pair_feats: B x L x L x C tensor of pair features
|
| 164 |
+
residx: B x L long tensor giving the position in the sequence
|
| 165 |
+
mask: B x L boolean tensor indicating valid residues
|
| 166 |
+
|
| 167 |
+
Output:
|
| 168 |
+
predicted_structure: B x L x (num_atoms_per_residue * 3) tensor wrapped in a Coordinates object
|
| 169 |
+
"""
|
| 170 |
+
|
| 171 |
+
device = seq_feats.device
|
| 172 |
+
s_s_0 = seq_feats
|
| 173 |
+
s_z_0 = pair_feats
|
| 174 |
+
|
| 175 |
+
if no_recycles is None:
|
| 176 |
+
no_recycles = self.cfg.max_recycles
|
| 177 |
+
else:
|
| 178 |
+
assert no_recycles >= 0, "Number of recycles must not be negative."
|
| 179 |
+
no_recycles += 1 # First 'recycle' is just the standard forward pass through the model.
|
| 180 |
+
|
| 181 |
+
def trunk_iter(s, z, residx, mask):
|
| 182 |
+
z = z + self.pairwise_positional_embedding(residx, mask=mask)
|
| 183 |
+
|
| 184 |
+
for block in self.blocks:
|
| 185 |
+
s, z = block(s, z, mask=mask, residue_index=residx, chunk_size=self.chunk_size)
|
| 186 |
+
return s, z
|
| 187 |
+
|
| 188 |
+
s_s = s_s_0
|
| 189 |
+
s_z = s_z_0
|
| 190 |
+
recycle_s = torch.zeros_like(s_s)
|
| 191 |
+
recycle_z = torch.zeros_like(s_z)
|
| 192 |
+
recycle_bins = torch.zeros(*s_z.shape[:-1], device=device, dtype=torch.int64)
|
| 193 |
+
|
| 194 |
+
assert no_recycles > 0
|
| 195 |
+
for recycle_idx in range(no_recycles):
|
| 196 |
+
with ExitStack() if recycle_idx == no_recycles - 1 else torch.no_grad():
|
| 197 |
+
# === Recycling ===
|
| 198 |
+
recycle_s = self.recycle_s_norm(recycle_s.detach())
|
| 199 |
+
recycle_z = self.recycle_z_norm(recycle_z.detach())
|
| 200 |
+
recycle_z += self.recycle_disto(recycle_bins.detach())
|
| 201 |
+
|
| 202 |
+
s_s, s_z = trunk_iter(s_s_0 + recycle_s, s_z_0 + recycle_z, residx, mask)
|
| 203 |
+
|
| 204 |
+
# === Structure module ===
|
| 205 |
+
structure = self.structure_module(
|
| 206 |
+
{"single": self.trunk2sm_s(s_s), "pair": self.trunk2sm_z(s_z)},
|
| 207 |
+
true_aa,
|
| 208 |
+
mask.float(),
|
| 209 |
+
)
|
| 210 |
+
|
| 211 |
+
recycle_s = s_s
|
| 212 |
+
recycle_z = s_z
|
| 213 |
+
# Distogram needs the N, CA, C coordinates, and bin constants same as alphafold.
|
| 214 |
+
recycle_bins = FoldingTrunk.distogram(
|
| 215 |
+
structure["positions"][-1][:, :, :3],
|
| 216 |
+
3.375,
|
| 217 |
+
21.375,
|
| 218 |
+
self.recycle_bins,
|
| 219 |
+
)
|
| 220 |
+
|
| 221 |
+
assert isinstance(structure, dict) # type: ignore
|
| 222 |
+
structure["s_s"] = s_s
|
| 223 |
+
structure["s_z"] = s_z
|
| 224 |
+
|
| 225 |
+
return structure
|
| 226 |
+
|
| 227 |
+
@staticmethod
|
| 228 |
+
def distogram(coords, min_bin, max_bin, num_bins):
|
| 229 |
+
# Coords are [... L x 3 x 3], where it's [N, CA, C] x 3 coordinates.
|
| 230 |
+
boundaries = torch.linspace(
|
| 231 |
+
min_bin,
|
| 232 |
+
max_bin,
|
| 233 |
+
num_bins - 1,
|
| 234 |
+
device=coords.device,
|
| 235 |
+
)
|
| 236 |
+
boundaries = boundaries**2
|
| 237 |
+
N, CA, C = [x.squeeze(-2) for x in coords.chunk(3, dim=-2)]
|
| 238 |
+
# Infer CB coordinates.
|
| 239 |
+
b = CA - N
|
| 240 |
+
c = C - CA
|
| 241 |
+
a = b.cross(c, dim=-1)
|
| 242 |
+
CB = -0.58273431 * a + 0.56802827 * b - 0.54067466 * c + CA
|
| 243 |
+
dists = (CB[..., None, :, :] - CB[..., :, None, :]).pow(2).sum(dim=-1, keepdims=True)
|
| 244 |
+
bins = torch.sum(dists > boundaries, dim=-1) # [..., L, L]
|
| 245 |
+
return bins
|
models/esm/inverse_folding/__pycache__/gvp_modules.cpython-310.pyc
ADDED
|
Binary file (14.9 kB). View file
|
|
|
models/esm/inverse_folding/__pycache__/gvp_transformer.cpython-310.pyc
ADDED
|
Binary file (4.45 kB). View file
|
|
|
models/esm/inverse_folding/gvp_utils.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
| 2 |
+
#
|
| 3 |
+
# This source code is licensed under the MIT license found in the
|
| 4 |
+
# LICENSE file in the root directory of this source tree.
|
| 5 |
+
|
| 6 |
+
import torch
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def flatten_graph(node_embeddings, edge_embeddings, edge_index):
|
| 10 |
+
"""
|
| 11 |
+
Flattens the graph into a batch size one (with disconnected subgraphs for
|
| 12 |
+
each example) to be compatible with pytorch-geometric package.
|
| 13 |
+
Args:
|
| 14 |
+
node_embeddings: node embeddings in tuple form (scalar, vector)
|
| 15 |
+
- scalar: shape batch size x nodes x node_embed_dim
|
| 16 |
+
- vector: shape batch size x nodes x node_embed_dim x 3
|
| 17 |
+
edge_embeddings: edge embeddings of in tuple form (scalar, vector)
|
| 18 |
+
- scalar: shape batch size x edges x edge_embed_dim
|
| 19 |
+
- vector: shape batch size x edges x edge_embed_dim x 3
|
| 20 |
+
edge_index: shape batch_size x 2 (source node and target node) x edges
|
| 21 |
+
Returns:
|
| 22 |
+
node_embeddings: node embeddings in tuple form (scalar, vector)
|
| 23 |
+
- scalar: shape batch total_nodes x node_embed_dim
|
| 24 |
+
- vector: shape batch total_nodes x node_embed_dim x 3
|
| 25 |
+
edge_embeddings: edge embeddings of in tuple form (scalar, vector)
|
| 26 |
+
- scalar: shape batch total_edges x edge_embed_dim
|
| 27 |
+
- vector: shape batch total_edges x edge_embed_dim x 3
|
| 28 |
+
edge_index: shape 2 x total_edges
|
| 29 |
+
"""
|
| 30 |
+
x_s, x_v = node_embeddings
|
| 31 |
+
e_s, e_v = edge_embeddings
|
| 32 |
+
batch_size, N = x_s.shape[0], x_s.shape[1]
|
| 33 |
+
node_embeddings = (torch.flatten(x_s, 0, 1), torch.flatten(x_v, 0, 1))
|
| 34 |
+
edge_embeddings = (torch.flatten(e_s, 0, 1), torch.flatten(e_v, 0, 1))
|
| 35 |
+
|
| 36 |
+
edge_mask = torch.any(edge_index != -1, dim=1)
|
| 37 |
+
# Re-number the nodes by adding batch_idx * N to each batch
|
| 38 |
+
edge_index = edge_index + (torch.arange(batch_size, device=edge_index.device) *
|
| 39 |
+
N).unsqueeze(-1).unsqueeze(-1)
|
| 40 |
+
edge_index = edge_index.permute(1, 0, 2).flatten(1, 2)
|
| 41 |
+
edge_mask = edge_mask.flatten()
|
| 42 |
+
edge_index = edge_index[:, edge_mask]
|
| 43 |
+
edge_embeddings = (
|
| 44 |
+
edge_embeddings[0][edge_mask, :],
|
| 45 |
+
edge_embeddings[1][edge_mask, :]
|
| 46 |
+
)
|
| 47 |
+
return node_embeddings, edge_embeddings, edge_index
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def unflatten_graph(node_embeddings, batch_size):
|
| 51 |
+
"""
|
| 52 |
+
Unflattens node embeddings.
|
| 53 |
+
Args:
|
| 54 |
+
node_embeddings: node embeddings in tuple form (scalar, vector)
|
| 55 |
+
- scalar: shape batch total_nodes x node_embed_dim
|
| 56 |
+
- vector: shape batch total_nodes x node_embed_dim x 3
|
| 57 |
+
batch_size: int
|
| 58 |
+
Returns:
|
| 59 |
+
node_embeddings: node embeddings in tuple form (scalar, vector)
|
| 60 |
+
- scalar: shape batch size x nodes x node_embed_dim
|
| 61 |
+
- vector: shape batch size x nodes x node_embed_dim x 3
|
| 62 |
+
"""
|
| 63 |
+
x_s, x_v = node_embeddings
|
| 64 |
+
x_s = x_s.reshape(batch_size, -1, x_s.shape[1])
|
| 65 |
+
x_v = x_v.reshape(batch_size, -1, x_v.shape[1], x_v.shape[2])
|
| 66 |
+
return (x_s, x_v)
|
| 67 |
+
|
| 68 |
+
|
models/esm/inverse_folding/transformer_layer.py
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
| 2 |
+
#
|
| 3 |
+
# Contents of this file were adapted from the open source fairseq repository.
|
| 4 |
+
#
|
| 5 |
+
# This source code is licensed under the MIT license found in the
|
| 6 |
+
# LICENSE file in the root directory of this source tree.
|
| 7 |
+
|
| 8 |
+
from typing import Dict, List, Optional
|
| 9 |
+
|
| 10 |
+
import torch
|
| 11 |
+
import torch.nn as nn
|
| 12 |
+
import torch.nn.functional as F
|
| 13 |
+
from onescience.modules.attention import MultiheadAttention
|
| 14 |
+
from torch import Tensor
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class TransformerEncoderLayer(nn.Module):
|
| 18 |
+
"""Encoder layer block.
|
| 19 |
+
`layernorm -> dropout -> add residual`
|
| 20 |
+
|
| 21 |
+
Args:
|
| 22 |
+
args (argparse.Namespace): parsed command-line arguments
|
| 23 |
+
"""
|
| 24 |
+
|
| 25 |
+
def __init__(self, args):
|
| 26 |
+
super().__init__()
|
| 27 |
+
self.args = args
|
| 28 |
+
self.embed_dim = args.encoder_embed_dim
|
| 29 |
+
self.self_attn = self.build_self_attention(self.embed_dim, args)
|
| 30 |
+
self.self_attn_layer_norm = torch.nn.LayerNorm(self.embed_dim)
|
| 31 |
+
self.dropout_module = nn.Dropout(args.dropout)
|
| 32 |
+
self.activation_fn = F.relu
|
| 33 |
+
self.fc1 = self.build_fc1(
|
| 34 |
+
self.embed_dim,
|
| 35 |
+
args.encoder_ffn_embed_dim,
|
| 36 |
+
)
|
| 37 |
+
self.fc2 = self.build_fc2(
|
| 38 |
+
args.encoder_ffn_embed_dim,
|
| 39 |
+
self.embed_dim,
|
| 40 |
+
)
|
| 41 |
+
|
| 42 |
+
self.final_layer_norm = nn.LayerNorm(self.embed_dim)
|
| 43 |
+
|
| 44 |
+
def build_fc1(self, input_dim, output_dim):
|
| 45 |
+
return nn.Linear(input_dim, output_dim)
|
| 46 |
+
|
| 47 |
+
def build_fc2(self, input_dim, output_dim):
|
| 48 |
+
return nn.Linear(input_dim, output_dim)
|
| 49 |
+
|
| 50 |
+
def build_self_attention(self, embed_dim, args):
|
| 51 |
+
return MultiheadAttention(
|
| 52 |
+
embed_dim,
|
| 53 |
+
args.encoder_attention_heads,
|
| 54 |
+
dropout=args.attention_dropout,
|
| 55 |
+
self_attention=True,
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
def residual_connection(self, x, residual):
|
| 59 |
+
return residual + x
|
| 60 |
+
|
| 61 |
+
def forward(
|
| 62 |
+
self,
|
| 63 |
+
x,
|
| 64 |
+
encoder_padding_mask: Optional[Tensor],
|
| 65 |
+
attn_mask: Optional[Tensor] = None,
|
| 66 |
+
):
|
| 67 |
+
"""
|
| 68 |
+
Args:
|
| 69 |
+
x (Tensor): input to the layer of shape `(seq_len, batch, embed_dim)`
|
| 70 |
+
encoder_padding_mask (ByteTensor): binary ByteTensor of shape
|
| 71 |
+
`(batch, seq_len)` where padding elements are indicated by ``1``.
|
| 72 |
+
attn_mask (ByteTensor): binary tensor of shape `(tgt_len, src_len)`,
|
| 73 |
+
where `tgt_len` is the length of output and `src_len` is the
|
| 74 |
+
length of input, though here both are equal to `seq_len`.
|
| 75 |
+
`attn_mask[tgt_i, src_j] = 1` means that when calculating the
|
| 76 |
+
embedding for `tgt_i`, we exclude (mask out) `src_j`. This is
|
| 77 |
+
useful for strided self-attention.
|
| 78 |
+
|
| 79 |
+
Returns:
|
| 80 |
+
encoded output of shape `(seq_len, batch, embed_dim)`
|
| 81 |
+
"""
|
| 82 |
+
# anything in original attn_mask = 1, becomes -1e8
|
| 83 |
+
# anything in original attn_mask = 0, becomes 0
|
| 84 |
+
# Note that we cannot use -inf here, because at some edge cases,
|
| 85 |
+
# the attention weight (before softmax) for some padded element in query
|
| 86 |
+
# will become -inf, which results in NaN in model parameters
|
| 87 |
+
if attn_mask is not None:
|
| 88 |
+
attn_mask = attn_mask.masked_fill(
|
| 89 |
+
attn_mask.to(torch.bool), -1e8 if x.dtype == torch.float32 else -1e4
|
| 90 |
+
)
|
| 91 |
+
|
| 92 |
+
residual = x
|
| 93 |
+
x = self.self_attn_layer_norm(x)
|
| 94 |
+
x, _ = self.self_attn(
|
| 95 |
+
query=x,
|
| 96 |
+
key=x,
|
| 97 |
+
value=x,
|
| 98 |
+
key_padding_mask=encoder_padding_mask,
|
| 99 |
+
need_weights=False,
|
| 100 |
+
attn_mask=attn_mask,
|
| 101 |
+
)
|
| 102 |
+
x = self.dropout_module(x)
|
| 103 |
+
x = self.residual_connection(x, residual)
|
| 104 |
+
|
| 105 |
+
residual = x
|
| 106 |
+
x = self.final_layer_norm(x)
|
| 107 |
+
x = self.activation_fn(self.fc1(x))
|
| 108 |
+
x = self.fc2(x)
|
| 109 |
+
x = self.dropout_module(x)
|
| 110 |
+
x = self.residual_connection(x, residual)
|
| 111 |
+
return x
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
class TransformerDecoderLayer(nn.Module):
|
| 115 |
+
"""Decoder layer block.
|
| 116 |
+
`layernorm -> dropout -> add residual`
|
| 117 |
+
|
| 118 |
+
Args:
|
| 119 |
+
args (argparse.Namespace): parsed command-line arguments
|
| 120 |
+
no_encoder_attn (bool, optional): whether to attend to encoder outputs
|
| 121 |
+
(default: False).
|
| 122 |
+
"""
|
| 123 |
+
|
| 124 |
+
def __init__(
|
| 125 |
+
self, args, no_encoder_attn=False, add_bias_kv=False, add_zero_attn=False
|
| 126 |
+
):
|
| 127 |
+
super().__init__()
|
| 128 |
+
self.embed_dim = args.decoder_embed_dim
|
| 129 |
+
self.dropout_module = nn.Dropout(args.dropout)
|
| 130 |
+
|
| 131 |
+
self.self_attn = self.build_self_attention(
|
| 132 |
+
self.embed_dim,
|
| 133 |
+
args,
|
| 134 |
+
add_bias_kv=add_bias_kv,
|
| 135 |
+
add_zero_attn=add_zero_attn,
|
| 136 |
+
)
|
| 137 |
+
self.nh = self.self_attn.num_heads
|
| 138 |
+
self.head_dim = self.self_attn.head_dim
|
| 139 |
+
|
| 140 |
+
self.activation_fn = F.relu
|
| 141 |
+
|
| 142 |
+
self.self_attn_layer_norm = nn.LayerNorm(self.embed_dim)
|
| 143 |
+
|
| 144 |
+
if no_encoder_attn:
|
| 145 |
+
self.encoder_attn = None
|
| 146 |
+
self.encoder_attn_layer_norm = None
|
| 147 |
+
else:
|
| 148 |
+
self.encoder_attn = self.build_encoder_attention(self.embed_dim, args)
|
| 149 |
+
self.encoder_attn_layer_norm = nn.LayerNorm(self.embed_dim)
|
| 150 |
+
|
| 151 |
+
self.ffn_layernorm = (
|
| 152 |
+
LayerNorm(args.decoder_ffn_embed_dim)
|
| 153 |
+
if getattr(args, "scale_fc", False)
|
| 154 |
+
else None
|
| 155 |
+
)
|
| 156 |
+
self.w_resid = (
|
| 157 |
+
nn.Parameter(
|
| 158 |
+
torch.ones(
|
| 159 |
+
self.embed_dim,
|
| 160 |
+
),
|
| 161 |
+
requires_grad=True,
|
| 162 |
+
)
|
| 163 |
+
if getattr(args, "scale_resids", False)
|
| 164 |
+
else None
|
| 165 |
+
)
|
| 166 |
+
|
| 167 |
+
self.fc1 = self.build_fc1(
|
| 168 |
+
self.embed_dim,
|
| 169 |
+
args.decoder_ffn_embed_dim,
|
| 170 |
+
)
|
| 171 |
+
self.fc2 = self.build_fc2(
|
| 172 |
+
args.decoder_ffn_embed_dim,
|
| 173 |
+
self.embed_dim,
|
| 174 |
+
)
|
| 175 |
+
|
| 176 |
+
self.final_layer_norm = nn.LayerNorm(self.embed_dim)
|
| 177 |
+
self.need_attn = True
|
| 178 |
+
|
| 179 |
+
def build_fc1(self, input_dim, output_dim):
|
| 180 |
+
return nn.Linear(input_dim, output_dim)
|
| 181 |
+
|
| 182 |
+
def build_fc2(self, input_dim, output_dim):
|
| 183 |
+
return nn.Linear(input_dim, output_dim)
|
| 184 |
+
|
| 185 |
+
def build_self_attention(
|
| 186 |
+
self, embed_dim, args, add_bias_kv=False, add_zero_attn=False
|
| 187 |
+
):
|
| 188 |
+
return MultiheadAttention(
|
| 189 |
+
embed_dim,
|
| 190 |
+
args.decoder_attention_heads,
|
| 191 |
+
dropout=args.attention_dropout,
|
| 192 |
+
add_bias_kv=add_bias_kv,
|
| 193 |
+
add_zero_attn=add_zero_attn,
|
| 194 |
+
self_attention=True,
|
| 195 |
+
)
|
| 196 |
+
|
| 197 |
+
def build_encoder_attention(self, embed_dim, args):
|
| 198 |
+
return MultiheadAttention(
|
| 199 |
+
embed_dim,
|
| 200 |
+
args.decoder_attention_heads,
|
| 201 |
+
kdim=args.encoder_embed_dim,
|
| 202 |
+
vdim=args.encoder_embed_dim,
|
| 203 |
+
dropout=args.attention_dropout,
|
| 204 |
+
encoder_decoder_attention=True,
|
| 205 |
+
)
|
| 206 |
+
|
| 207 |
+
def residual_connection(self, x, residual):
|
| 208 |
+
return residual + x
|
| 209 |
+
|
| 210 |
+
def forward(
|
| 211 |
+
self,
|
| 212 |
+
x,
|
| 213 |
+
encoder_out: Optional[torch.Tensor] = None,
|
| 214 |
+
encoder_padding_mask: Optional[torch.Tensor] = None,
|
| 215 |
+
incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None,
|
| 216 |
+
prev_self_attn_state: Optional[List[torch.Tensor]] = None,
|
| 217 |
+
prev_attn_state: Optional[List[torch.Tensor]] = None,
|
| 218 |
+
self_attn_mask: Optional[torch.Tensor] = None,
|
| 219 |
+
self_attn_padding_mask: Optional[torch.Tensor] = None,
|
| 220 |
+
need_attn: bool = False,
|
| 221 |
+
need_head_weights: bool = False,
|
| 222 |
+
):
|
| 223 |
+
"""
|
| 224 |
+
Args:
|
| 225 |
+
x (Tensor): input to the layer of shape `(seq_len, batch, embed_dim)`
|
| 226 |
+
encoder_padding_mask (ByteTensor, optional): binary
|
| 227 |
+
ByteTensor of shape `(batch, src_len)` where padding
|
| 228 |
+
elements are indicated by ``1``.
|
| 229 |
+
need_attn (bool, optional): return attention weights
|
| 230 |
+
need_head_weights (bool, optional): return attention weights
|
| 231 |
+
for each head (default: return average over heads).
|
| 232 |
+
|
| 233 |
+
Returns:
|
| 234 |
+
encoded output of shape `(seq_len, batch, embed_dim)`
|
| 235 |
+
"""
|
| 236 |
+
if need_head_weights:
|
| 237 |
+
need_attn = True
|
| 238 |
+
|
| 239 |
+
residual = x
|
| 240 |
+
x = self.self_attn_layer_norm(x)
|
| 241 |
+
if prev_self_attn_state is not None:
|
| 242 |
+
prev_key, prev_value = prev_self_attn_state[:2]
|
| 243 |
+
saved_state: Dict[str, Optional[Tensor]] = {
|
| 244 |
+
"prev_key": prev_key,
|
| 245 |
+
"prev_value": prev_value,
|
| 246 |
+
}
|
| 247 |
+
if len(prev_self_attn_state) >= 3:
|
| 248 |
+
saved_state["prev_key_padding_mask"] = prev_self_attn_state[2]
|
| 249 |
+
assert incremental_state is not None
|
| 250 |
+
self.self_attn._set_input_buffer(incremental_state, saved_state)
|
| 251 |
+
_self_attn_input_buffer = self.self_attn._get_input_buffer(incremental_state)
|
| 252 |
+
y = x
|
| 253 |
+
|
| 254 |
+
x, attn = self.self_attn(
|
| 255 |
+
query=x,
|
| 256 |
+
key=y,
|
| 257 |
+
value=y,
|
| 258 |
+
key_padding_mask=self_attn_padding_mask,
|
| 259 |
+
incremental_state=incremental_state,
|
| 260 |
+
need_weights=False,
|
| 261 |
+
attn_mask=self_attn_mask,
|
| 262 |
+
)
|
| 263 |
+
x = self.dropout_module(x)
|
| 264 |
+
x = self.residual_connection(x, residual)
|
| 265 |
+
|
| 266 |
+
if self.encoder_attn is not None and encoder_out is not None:
|
| 267 |
+
residual = x
|
| 268 |
+
x = self.encoder_attn_layer_norm(x)
|
| 269 |
+
if prev_attn_state is not None:
|
| 270 |
+
prev_key, prev_value = prev_attn_state[:2]
|
| 271 |
+
saved_state: Dict[str, Optional[Tensor]] = {
|
| 272 |
+
"prev_key": prev_key,
|
| 273 |
+
"prev_value": prev_value,
|
| 274 |
+
}
|
| 275 |
+
if len(prev_attn_state) >= 3:
|
| 276 |
+
saved_state["prev_key_padding_mask"] = prev_attn_state[2]
|
| 277 |
+
assert incremental_state is not None
|
| 278 |
+
self.encoder_attn._set_input_buffer(incremental_state, saved_state)
|
| 279 |
+
|
| 280 |
+
x, attn = self.encoder_attn(
|
| 281 |
+
query=x,
|
| 282 |
+
key=encoder_out,
|
| 283 |
+
value=encoder_out,
|
| 284 |
+
key_padding_mask=encoder_padding_mask,
|
| 285 |
+
incremental_state=incremental_state,
|
| 286 |
+
static_kv=True,
|
| 287 |
+
need_weights=need_attn or (not self.training and self.need_attn),
|
| 288 |
+
need_head_weights=need_head_weights,
|
| 289 |
+
)
|
| 290 |
+
x = self.dropout_module(x)
|
| 291 |
+
x = self.residual_connection(x, residual)
|
| 292 |
+
|
| 293 |
+
residual = x
|
| 294 |
+
x = self.final_layer_norm(x)
|
| 295 |
+
|
| 296 |
+
x = self.activation_fn(self.fc1(x))
|
| 297 |
+
if self.ffn_layernorm is not None:
|
| 298 |
+
x = self.ffn_layernorm(x)
|
| 299 |
+
x = self.fc2(x)
|
| 300 |
+
x = self.dropout_module(x)
|
| 301 |
+
if self.w_resid is not None:
|
| 302 |
+
residual = torch.mul(self.w_resid, residual)
|
| 303 |
+
x = self.residual_connection(x, residual)
|
| 304 |
+
return x, attn, None
|
models/simplefold/torch/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (187 Bytes). View file
|
|
|
models/simplefold/torch/__pycache__/pos_embed.cpython-311.pyc
ADDED
|
Binary file (10.1 kB). View file
|
|
|