Download model/PXDesignBench/ColabDesign/colabdesign/af/model.py from OneScience-Group/PXDesign: direct link, hf CLI and curl.
- Browser
- Download file 10.5 kB
-
https://huggingface.co/OneScience-Group/PXDesign/resolve/main/model/PXDesignBench/ColabDesign/colabdesign/af/model.py
- Command line
-
hf download hf://OneScience-Group/PXDesign/model/PXDesignBench/ColabDesign/colabdesign/af/model.py
-
curl -L -o model.py https://huggingface.co/OneScience-Group/PXDesign/resolve/main/model/PXDesignBench/ColabDesign/colabdesign/af/model.py
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} | |