anzhi2710gmailcom's picture
Upload folder using huggingface_hub
d766458 verified
Raw
History Blame Contribute Delete
10.5 kB
import os
import jax
import jax.numpy as jnp
import numpy as np
from inspect import signature
from colabdesign.af.alphafold.model import data, config, model, all_atom
from colabdesign.shared.model import design_model
from colabdesign.shared.utils import Key
from colabdesign.af.prep import _af_prep
from colabdesign.af.loss import _af_loss, get_plddt, get_pae, get_ptm
from colabdesign.af.loss import get_contact_map, get_seq_ent_loss, get_mlm_loss
from colabdesign.af.utils import _af_utils
from colabdesign.af.design import _af_design
from colabdesign.af.inputs import _af_inputs, update_seq, update_aatype
################################################################
# MK_DESIGN_MODEL - initialize model, and put it all together
################################################################
class mk_af_model(design_model, _af_inputs, _af_loss, _af_prep, _af_design, _af_utils):
def __init__(self,
protocol="fixbb",
use_multimer=False,
use_templates=False,
debug=False,
data_dir=".",
**kwargs):
assert protocol in ["fixbb","hallucination","binder","partial"]
self.protocol = protocol
self._num = kwargs.pop("num_seq",1)
self._args = {"use_templates":use_templates, "use_multimer":use_multimer, "use_bfloat16":True,
"recycle_mode":"last", "use_mlm": False, "realign": True,
"debug":debug, "repeat":False, "homooligomer":False, "copies":1,
"optimizer":"sgd", "best_metric":"loss",
"traj_iter":1, "traj_max":10000,
"clear_prev": True, "use_dgram":False,
"shuffle_first":True, "use_remat":True,
"alphabet_size":20,
"use_initial_guess":False, "use_initial_atom_pos":False}
if self.protocol == "binder": self._args["use_templates"] = True
self.opt = {"dropout":True, "pssm_hard":False, "learning_rate":0.1, "norm_seq_grad":True,
"num_recycles":0, "num_models":1, "sample_models":True,
"temp":1.0, "soft":0.0, "hard":0.0, "alpha":2.0,
"con": {"num":2, "cutoff":14.0, "binary":False, "seqsep":9, "num_pos":float("inf")},
"i_con": {"num":1, "cutoff":21.6875, "binary":False, "num_pos":float("inf")},
"template": {"rm_ic":False},
"weights": {"seq_ent":0.0, "plddt":0.0, "pae":0.0, "exp_res":0.0, "helix":0.0},
"fape_cutoff":10.0}
self._params = {}
self._inputs = {}
self._tmp = {"traj":{"seq":[],"xyz":[],"plddt":[],"pae":[]},
"log":[],"best":{}}
# set arguments/options
if "initial_guess" in kwargs: kwargs["use_initial_guess"] = kwargs.pop("initial_guess")
model_names = kwargs.pop("model_names",None)
keys = list(kwargs.keys())
for k in keys:
if k in self._args: self._args[k] = kwargs.pop(k)
if k in self.opt: self.opt[k] = kwargs.pop(k)
# collect callbacks
self._callbacks = {"model": {"pre": kwargs.pop("pre_callback",None),
"post":kwargs.pop("post_callback",None),
"loss":kwargs.pop("loss_callback",None)},
"design":{"pre": kwargs.pop("pre_design_callback",None),
"post":kwargs.pop("post_design_callback",None)}}
for m,n in self._callbacks.items():
for k,v in n.items():
if v is None: v = []
if not isinstance(v,list): v = [v]
self._callbacks[m][k] = v
if self._args["use_mlm"]:
self.opt["mlm_dropout"] = 0.15
self.opt["weights"]["mlm"] = 0.1
assert len(kwargs) == 0, f"ERROR: the following inputs were not set: {kwargs}"
#############################
# configure AlphaFold
#############################
if self._args["use_multimer"]:
self._cfg = config.model_config("model_1_multimer")
# TODO
self.opt["pssm_hard"] = True
else:
self._cfg = config.model_config("model_1_ptm" if self._args["use_templates"] else "model_3_ptm")
if self._args["recycle_mode"] in ["average","first","last","sample"]:
num_recycles = 0
else:
num_recycles = self.opt["num_recycles"]
self._cfg.model.num_recycle = num_recycles
self._cfg.model.global_config.use_remat = self._args["use_remat"]
self._cfg.model.global_config.use_dgram = self._args["use_dgram"]
self._cfg.model.global_config.bfloat16 = self._args["use_bfloat16"]
# load model_params
if model_names is None:
model_names = []
if self._args["use_multimer"]:
model_names += [f"model_{k}_multimer_v3" for k in [1,2,3,4,5]]
else:
if self._args["use_templates"]:
model_names += [f"model_{k}_ptm" for k in [1,2]]
else:
model_names += [f"model_{k}_ptm" for k in [1,2,3,4,5]]
self._model_params, self._model_names = [],[]
for model_name in model_names:
params = data.get_model_haiku_params(model_name=model_name, data_dir=data_dir, fuse=True)
if params is not None:
if not self._args["use_multimer"] and not self._args["use_templates"]:
params = {k:v for k,v in params.items() if "template" not in k}
self._model_params.append(params)
self._model_names.append(model_name)
else:
print(f"WARNING: '{model_name}' not found")
#####################################
# set protocol specific functions
#####################################
idx = ["fixbb","hallucination","binder","partial"].index(self.protocol)
self.prep_inputs = [self._prep_fixbb, self._prep_hallucination, self._prep_binder, self._prep_partial][idx]
self._get_loss = [self._loss_fixbb, self._loss_hallucination, self._loss_binder, self._loss_partial][idx]
def _get_model(self, cfg, callback=None):
a = self._args
runner = model.RunModel(cfg,
recycle_mode=a["recycle_mode"],
use_multimer=a["use_multimer"])
# setup function to get gradients
def _model(params, model_params, inputs, key):
inputs["params"] = params
opt = inputs["opt"]
aux = {}
key = Key(key=key).get
#######################################################################
# INPUTS
#######################################################################
# get sequence
seq = self._get_seq(inputs, aux, key())
# update sequence features
pssm = jnp.where(opt["pssm_hard"], seq["hard"], seq["pseudo"])
if a["use_mlm"]:
shape = seq["pseudo"].shape[:2]
mlm = jax.random.bernoulli(key(),opt["mlm_dropout"],shape)
update_seq(seq["pseudo"], inputs, seq_pssm=pssm, mlm=mlm)
else:
update_seq(seq["pseudo"], inputs, seq_pssm=pssm)
# update amino acid sidechain identity
update_aatype(seq["pseudo"][0].argmax(-1), inputs)
# define masks
inputs["msa_mask"] = jnp.where(inputs["seq_mask"],inputs["msa_mask"],0)
inputs["seq"] = aux["seq"]
# update template features
inputs["mask_template_interchain"] = opt["template"]["rm_ic"]
if a["use_templates"]:
self._update_template(inputs, key())
# set dropout
inputs["use_dropout"] = opt["dropout"]
if "batch" not in inputs:
inputs["batch"] = None
# pre callback
for fn in self._callbacks["model"]["pre"]:
fn_args = {"inputs":inputs, "opt":opt, "aux":aux,
"seq":seq, "key":key(), "params":params}
sub_args = {k:fn_args.get(k,None) for k in signature(fn).parameters}
fn(**sub_args)
#######################################################################
# OUTPUTS
#######################################################################
outputs = runner.apply(model_params, key(), inputs)
# add aux outputs
aux.update({"atom_positions": outputs["structure_module"]["final_atom_positions"],
"atom_mask": outputs["structure_module"]["final_atom_mask"],
"residue_index": inputs["residue_index"],
"aatype": inputs["aatype"],
"plddt": get_plddt(outputs),
"pae": get_pae(outputs),
"ptm": get_ptm(inputs, outputs),
"i_ptm": get_ptm(inputs, outputs, interface=True),
"cmap": get_contact_map(outputs, opt["con"]["cutoff"]),
"i_cmap": get_contact_map(outputs, opt["i_con"]["cutoff"]),
"prev": outputs["prev"]})
#######################################################################
# LOSS
#######################################################################
aux["losses"] = {}
# add protocol specific losses
self._get_loss(inputs=inputs, outputs=outputs, aux=aux)
# sequence entropy loss
aux["losses"].update(get_seq_ent_loss(inputs))
# experimental masked-language-modeling
if a["use_mlm"]:
aux["mlm"] = outputs["masked_msa"]["logits"]
mask = jnp.where(inputs["seq_mask"],mlm,0)
aux["losses"].update(get_mlm_loss(outputs, mask=mask, truth=seq["pssm"]))
# run user defined callbacks
for c in ["loss","post"]:
for fn in self._callbacks["model"][c]:
fn_args = {"inputs":inputs, "outputs":outputs, "opt":opt,
"aux":aux, "seq":seq, "key":key(), "params":params}
sub_args = {k:fn_args.get(k,None) for k in signature(fn).parameters}
if c == "loss": aux["losses"].update(fn(**sub_args))
if c == "post": fn(**sub_args)
# save for debugging
if a["debug"]: aux["debug"] = {"inputs":inputs,"outputs":outputs}
# weighted loss
w = opt["weights"]
loss = sum([v * w[k] if k in w else v for k,v in aux["losses"].items()])
return loss, aux
return {"grad_fn":jax.jit(jax.value_and_grad(_model, has_aux=True, argnums=0)),
"fn":jax.jit(_model), "runner":runner}