From 1b3e08025b8fcae39e9c9fe70e1dcde97707ffcd Mon Sep 17 00:00:00 2001 From: tina-z-jia <145156075+tina-z-jia@users.noreply.github.com> Date: Thu, 16 Jan 2025 10:34:33 -0800 Subject: [PATCH] esm 3.1.3 release (#184) --- CONTRIBUTIONS.md | 23 +- LICENSE.md | 23 ++ README.md | 285 +++++++-------- cookbook/local/README.md | 1 + .../local/open_generate.ipynb | 0 {examples => cookbook/local}/raw_forwards.py | 0 cookbook/snippets/README.md | 1 + .../snippets/esm3.py | 14 +- .../snippets/esmc.py | 7 + .../snippets/fold_invfold.py | 54 ++- .../tutorials/1_esmprotein.ipynb | 251 +++++++------ cookbook/tutorials/2_embed.ipynb | 342 ++++++++++++++++++ .../tutorials/3_gfp_design.ipynb | 0 .../tutorials/4_forge_generate.ipynb | 4 +- cookbook/tutorials/README.md | 8 + esm/__init__.py | 2 +- esm/models/esmc.py | 8 +- esm/models/function_decoder.py | 13 +- esm/sdk/api.py | 1 + esm/sdk/forge.py | 29 +- esm/utils/constants/models.py | 4 + esm/utils/generation.py | 5 +- esm/utils/generation_test.py | 4 +- esm/utils/misc.py | 8 + esm/utils/sampling.py | 5 +- examples/forge_generate.py | 13 - pyproject.toml | 2 +- tools/generate.ipynb | 124 +++---- tools/invfold.ipynb | 211 +++++++---- tools/predict.ipynb | 178 +++++---- 30 files changed, 1072 insertions(+), 548 deletions(-) create mode 100644 cookbook/local/README.md rename examples/generate.ipynb => cookbook/local/open_generate.ipynb (100%) rename {examples => cookbook/local}/raw_forwards.py (100%) create mode 100644 cookbook/snippets/README.md rename examples/local_generate.py => cookbook/snippets/esm3.py (93%) rename examples/esmc_examples.py => cookbook/snippets/esmc.py (87%) rename examples/folding_inverse_folding_example.py => cookbook/snippets/fold_invfold.py (62%) rename examples/esmprotein.ipynb => cookbook/tutorials/1_esmprotein.ipynb (82%) create mode 100644 cookbook/tutorials/2_embed.ipynb rename examples/gfp_design.ipynb => cookbook/tutorials/3_gfp_design.ipynb (100%) rename examples/forge_generate.ipynb => cookbook/tutorials/4_forge_generate.ipynb (99%) create mode 100644 cookbook/tutorials/README.md delete mode 100644 examples/forge_generate.py diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 5d06b52..e82ed15 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -27,8 +27,7 @@ python -c 'from huggingface_hub import login; login()' # Ensure package can correctly interact with forge. # This will require an API key from forge.evolutionaryscale.ai -ESM_API_KEY=$ESM_API_KEY PYTHONPATH='.' python examples/forge_generate.py - +ESM_API_KEY=$ESM_API_KEY PYTHONPATH='.' python cookbook/snippets/esm3.py ``` @@ -36,21 +35,17 @@ ESM_API_KEY=$ESM_API_KEY PYTHONPATH='.' python examples/forge_generate.py 1. Ensure the following scripts run without errors. Most have a pip install command installing the published `esm` package - comment this out so your release candidate version is tested and not the already published version. ```bash -ESM_API_KEY=$ESM_API_KEY PYTHONPATH='.' python examples/forge_generate.py +ESM_API_KEY=$ESM_API_KEY PYTHONPATH='.' python cookbook/snippets/esm3.py pip install treon -treon examples/esmprotein.ipynb -treon examples/gfp_design.ipynb +treon cookbook/tutorials/1_esmprotein.ipynb +treon cookbook/tutorials/2_embed.ipynb +treon cookbook/tutorials/3_gfp_design.ipynb +treon cookbook/tutorials/4_forge_generate.ipynb # requires a GPU -treon examples/generate.ipynb -python examples/local_generate.py -python examples/raw_forwards.py +python cookbook/snippets/esm3.py +python cookbook/snippets/esmc.py +python cookbook/local/raw_forwards.py ``` - -`examples/esmprotein.ipynb` works. Remember to skip running the first cell - it will reinstall stock esm instead of your deployed version. - -3. Ensure `examples/generate.ipynb` works. Note this notebook will require a node with a GPU that can fit ESM3 small open. - -4. Ensure diff --git a/LICENSE.md b/LICENSE.md index 9798d1d..eaccb29 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -11,3 +11,26 @@ Here are the different licenses that govern access to the ESM codebase and the m | Governed by API Agreements (See Below) | API access to all models, including API-only models (ESM3 family, ESM C 6B) | | [Forge API Terms of Use](https://www.evolutionaryscale.ai/policies/terms-of-use) | Free non-commercial API access via Forge to all models including API-only models (ESM3 family, ESM C 6B) | | [Cambrian Inference Clickthrough License Agreement](https://www.evolutionaryscale.ai/policies/cambrian-inference-clickthrough-license-agreement) | Commercial Inference via SageMaker for all ESM C models | + + +# How can I access the models and which licenses apply? + +The models can be accessed in three different ways, each with its own licensing terms. + +1. **Code and weights** via GitHub and HuggingFace are available under either a [non-commercial](https://www.evolutionaryscale.ai/policies/cambrian-non-commercial-license-agreement) (ESM C 600M, ESM3-small-open) or an [open license](https://www.evolutionaryscale.ai/policies/cambrian-open-license-agreement) (codebase, ESM C 300M). + * **Building with ESM encouraged**: You can use embeddings, model predictions, fine-tune the models and use components of both the models and code. We strongly encourage anyone to build on ESM C and ESM3! Just remember to maintain the same license terms and release under the ESM name. +2. **Free non-commercial inference API** via Forge. All models are available this way, with free credits granted to students and researchers. We want to enable academics under [non-commercial Terms of Use](https://www.evolutionaryscale.ai/policies/terms-of-use), which mirrors the non-commercial license. +3. **Paid commercial Inference API** for commercial use via SageMaker (Forge coming soon). All ESM C models are available this way to commercial entities for commercial use under a [clickthrough license agreement](https://www.evolutionaryscale.ai/policies/cambrian-inference-clickthrough-license-agreement) with few restrictions. + * In broad strokes: standard commercial use like developing molecules and developing downstream ML models and methods with the model is allowed, while training competing models on the API outputs is not. + * Note: For ESM3 commercial use, reach out to [bd@evolutionaryscale.ai](mailto:bd@evolutionaryscale.ai) + +### What changed with the release of ESM C? + +We introduced a [clickthrough license agreement](https://www.evolutionaryscale.ai/policies/cambrian-inference-clickthrough-license-agreement) to enable frictionless commercial use of ESM C. + +We introduced the new [Cambrian Open License](https://www.evolutionaryscale.ai/policies/cambrian-open-license-agreement) for ESM C 300M, and at the same time moved all code in the [`esm` repo](https://github.com/evolutionaryscale/esm) under that permissive license. + +The [Cambrian non-commercial license](https://www.evolutionaryscale.ai/policies/cambrian-non-commercial-license-agreement) is largely based on the original [ESM3 Community License Agreement](https://www.evolutionaryscale.ai/policies/community-license-agreement), but removed the clause that restricted drug development, added the naming requirement, and extended the meaning of “Derivative Work” to allow training on model outputs. Just remember to release models and methods built on ESM under the same license. +These changes are meant to remove potential gray areas and points of friction for researchers building with ESM. + +Finally, The ESM3-open-small model has been moved under the [Cambrian non-commercial license](https://www.evolutionaryscale.ai/policies/cambrian-non-commercial-license-agreement). diff --git a/README.md b/README.md index 531459b..b7db77a 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,20 @@ - [Installation ](#installation-) -- [ESM C ](#esm-c-) - - [ESM C Local Models via GitHub ](#esm-c-local-models-via-github-) - - [Using ESM C 6B via Forge API](#using-esm-c-6b-via-forge-api) - - [ESM C via Forge API for Free Non-Commercial Use ](#esm-c-via-forge-api-for-free-non-commercial-use--) - - [ESM C via SageMaker for Commercial Use ](#esm-c-via-sagemaker-for-commercial-use--) - - [ESM C Example Usage](#esm-c-example-usage) -- [ESM 3 ](#esm-3--) - - [Quickstart for ESM3-open ](#quickstart-for-esm3-open-) - - [EvolutionaryScale Forge: Access to larger ESM3 models](#evolutionaryscale-forge-access-to-larger-esm3-models) +- [ESM 3](#esm-3-) + - [Quickstart for ESM3 Open](#esm3-quickstart-) + - [ESM3 98B via Forge API](#esm3-forge) - [ESM3 Example Usage](#esm3-example-usage) -- [Responsible Development ](#responsible-development-) -- [Licenses ](#licenses--) - - [How can I access the models and which licenses apply?](#how-can-i-access-the-models-and-which-licenses-apply) - - [What changed with the release of ESM C?](#what-changed-with-the-release-of-esm-c) +- [ESM C](#esm-c-) + - [Quickstart for ESM C Open Models](#esm-c-open-) + - [ESM C 6B via Forge API](#esm-c-forge-) + - [ESM C via SageMaker for Commercial Use ](#esm-c-sagemaker-) + - [ESM C Example Usage](#esm-c-example-) +- [Responsible Development](#responsible-development-) +- [Licenses](#licenses-) +- [Citations ](#citations-) +This repository contains flagship protein models for EvolutionaryScale, as well as access to the API. [ESM3](https://www.evolutionaryscale.ai/papers/esm3-simulating-500-million-years-of-evolution-with-a-language-model) is our flagship multimodal protein generative model, and can be used for generation and prediction tasks. [ESM C](https://www.evolutionaryscale.ai/blog/esm-cambrian) is our best protein representation learning model, and can be used to embed protein sequences. + ## Installation To get started with ESM, install the python library using pip: @@ -23,18 +23,93 @@ To get started with ESM, install the python library using pip: pip install esm ``` -## ESM C -[ESM Cambrian](https://www.evolutionaryscale.ai/blog/esm-cambrian) is a parallel model family to our flagship ESM3 generative models. While ESM3 focuses on controllable generation of proteins for therapeutic and many other applications, ESM C focuses on creating representations of the underlying biology of proteins. +## ESM 3 -ESM C comes with major performance benefits over ESM2. The 300M parameter ESM C delivers similar performance to ESM2 650M with dramatically reduced memory requirements and faster inference. The 600M parameter ESM C rivals the 3B parameter ESM2 and approaches the capabilities of the 15B model, delivering frontier performance with far greater efficiency. The 6B parameter ESM C sets a new benchmark, outperforming the best ESM2 models by a wide margin. +[ESM3](https://www.evolutionaryscale.ai/papers/esm3-simulating-500-million-years-of-evolution-with-a-language-model) is a frontier generative model for biology, able to jointly reason across three fundamental biological properties of proteins: sequence, structure, and function. These three data modalities are represented as tracks of discrete tokens at the input and output of ESM3. You can present the model with a combination of partial inputs across the tracks, and ESM3 will provide output predictions for all the tracks. -ESM C models are available immediately for academic and commercial use under a new license structure designed to promote openness and enable scientists and builders. You can find the high level take-away of the license structure in the [Licenses](#licenses) section of this page, and complete license details in [LICENSE.md](LICENSE.md). +ESM3 is a _generative_ masked language model. You can prompt it with partial sequence, structure, and function keywords, and iteratively sample masked positions until all positions are unmasked. This iterative sampling is what the `.generate()` function does. -You can use the following guides to start using ESM C models today, either running the model locally, [the Forge API](https://forge.evolutionaryscale.ai/) and [AWS SageMaker](https://aws.amazon.com/marketplace/seller-profile?id=seller-iw2nbscescndm). + +ESM3 Diagram -### ESM C Local Models via GitHub -The code and weights for the ESM C 300M model are available under the Cambrian Open [license agreement](#licenses). The weights for the ESM C 600M model are available under the Cambrian Non-Commercial [license agreement](#licenses). +The ESM3 architecture is highly scalable due to its transformer backbone and all-to-all reasoning over discrete token sequences. At its largest scale, ESM3 was trained with 1.07e24 FLOPs on 2.78 billion proteins and 771 billion unique tokens, and has 98 billion parameters. +Learn more by reading the [blog post](https://www.evolutionaryscale.ai/blog/esm3-release) and [the pre-print (Hayes et al., 2024)](https://www.evolutionaryscale.ai/papers/esm3-simulating-500-million-years-of-evolution-with-a-language-model). +ESM3-open, with 1.4B parameters, is the smallest and fastest model in the family. + +### Quickstart for ESM3-open + +``` +pip install esm +``` + +The weights are stored on HuggingFace Hub under [HuggingFace/EvolutionaryScale/esm3](https://huggingface.co/EvolutionaryScale/esm3). + +```py +from huggingface_hub import login +from esm.models.esm3 import ESM3 +from esm.sdk.api import ESM3InferenceClient, ESMProtein, GenerationConfig + +# Will instruct you how to get an API key from huggingface hub, make one with "Read" permission. +login() + +# This will download the model weights and instantiate the model on your machine. +model: ESM3InferenceClient = ESM3.from_pretrained("esm3-open").to("cuda") # or "cpu" + +# Generate a completion for a partial Carbonic Anhydrase (2vvb) +prompt = "___________________________________________________DQATSLRILNNGHAFNVEFDDSQDKAVLKGGPLDGTYRLIQFHFHWGSLDGQGSEHTVDKKKYAAELHLVHWNTKYGDFGKAVQQPDGLAVLGIFLKVGSAKPGLQKVVDVLDSIKTKGKSADFTNFDPRGLLPESLDYWTYPGSLTTPP___________________________________________________________" +protein = ESMProtein(sequence=prompt) +# Generate the sequence, then the structure. This will iteratively unmask the sequence track. +protein = model.generate(protein, GenerationConfig(track="sequence", num_steps=8, temperature=0.7)) +# We can show the predicted structure for the generated sequence. +protein = model.generate(protein, GenerationConfig(track="structure", num_steps=8)) +protein.to_pdb("./generation.pdb") +# Then we can do a round trip design by inverse folding the sequence and recomputing the structure +protein.sequence = None +protein = model.generate(protein, GenerationConfig(track="sequence", num_steps=8)) +protein.coordinates = None +protein = model.generate(protein, GenerationConfig(track="structure", num_steps=8)) +protein.to_pdb("./round_tripped.pdb") +``` + +Congratulations, you just generated your first proteins with ESM3! + +### EvolutionaryScale Forge: Access to larger ESM3 models + + +You can access all scales of ESM3 models [EvolutionaryScale Forge](https://forge.evolutionaryscale.ai). + +We encourage users to interact with the Forge API through the python `esm` library instead of the command line. +The python interface enables you to interactively load proteins, build prompts, and inspect generated proteins +with the `ESMProtein` and config classes used to interact with the local model. + +In any example script you can replace a local `ESM3` model with a Forge API client: + +```py +# Instead of loading the model locally on your machine: +model: ESM3InferenceClient = ESM3.from_pretrained("esm3_sm_open_v1").to("cuda") # or "cpu" +# just replace the line with this: +model: ESM3InferenceClient = esm.sdk.client("esm3-medium-2024-08", token="") +# and now you're interfacing with the model running on our remote servers. +... +``` + +and the exact same code will work. +This enables a seamless transition from smaller and faster models, to our largest and most capable protein language models for protein design work. + +### ESM3 Example Usage + + +Check out our [tutorials](./cookbook/tutorials) to learn how to use ESM3. + +## ESM C +[ESM Cambrian](https://www.evolutionaryscale.ai/blog/esm-cambrian) is a parallel model family to our flagship ESM3 generative models. While ESM3 focuses on controllable generation of proteins, ESM C focuses on creating representations of the underlying biology of proteins. + +ESM C is designed as a drop-in replacement for ESM2 and comes with major performance benefits. The 300M parameter ESM C delivers similar performance to ESM2 650M with dramatically reduced memory requirements and faster inference. The 600M parameter ESM C rivals the 3B parameter ESM2 and approaches the capabilities of the 15B model, delivering frontier performance with far greater efficiency. The 6B parameter ESM C outperforms the best ESM2 models by a wide margin. + +ESM C can be run locally, via [the Forge API](https://forge.evolutionaryscale.ai/) or through [AWS SageMaker](https://aws.amazon.com/marketplace/seller-profile?id=seller-iw2nbscescndm). + +### Quickstart for ESM C Open Models When running the code below, a pytorch model will be instantiated locally on your machine, with the weights downloaded from the [HuggingFace hub](https://huggingface.co/EvolutionaryScale). ```py from esm.models.esmc import ESMC @@ -58,11 +133,9 @@ pip install flash-attn --no-build-isolation You can also disable flash-attn by passing ``use_flash_attn=False`` to utils like ``ESMC_300M_202412``. -### Using ESM C 6B via Forge API -### ESM C via Forge API for Free Non-Commercial Use +### ESM C 6B via Forge API -The ESM C model family, including ESMC 6B, are accessible via EvolutionaryScale Forge for free [non-commercial use](#licenses). -Apply for access and copy the API token from the console by first visiting https://forge.evolutionaryscale.ai. +Apply for access and copy the API token from the console by first visiting [Forge](https://forge.evolutionaryscale.ai). With the code below, a local python client talks to the model inference server hosted by EvolutionaryScale. @@ -83,8 +156,8 @@ Remember to replace `` with your actual Forge access token. ### ESM C via SageMaker for Commercial Use -ESM C models are also available on Amazon SageMaker under the Cambrian Inference Clickthrough License Agreement. -Under this license agreement models are available for broad commercial use to commercial entities. +ESM C models are also available on Amazon SageMaker under the [Cambrian Inference Clickthrough License Agreement](https://www.evolutionaryscale.ai/policies/cambrian-inference-clickthrough-license-agreement). +Under this license agreement, models are available for broad use for commercial entities. You will need an admin AWS access to an AWS account to follow these instructions. To deploy, first we need to deploy the AWS package: @@ -97,12 +170,11 @@ You will need an admin AWS access to an AWS account to follow these instructions 7. Click "Launch CloudFormation Template". This takes 15 to 25 minutes depending on model size. 8. On the "Quick create stack" page, ensure the stack name and endpoint names are not already used. You can check existing stack names [here](https://console.aws.amazon.com/cloudformation/home/stacks) and existing endpoint names [here](https://us-east-1.console.aws.amazon.com/sagemaker/home?region=us-east-1#/endpoints). -The Sagemaker deployment of the model now lives on a dedicated GPU instance inside your AWS environment, and will be billed directly to your AWS account. +The SageMaker deployment of the model now lives on a dedicated GPU instance inside your AWS environment, and will be billed directly to your AWS account. Make sure to remember to shut down the instance after you stop using it. Find the CloudFormation stack you created [here](https://us-east-1.console.aws.amazon.com/cloudformation/home), select it, and then click "Delete" to clean up all resources. -After creating the endpoint, you can create a sagemaker client and use it the same way as a forge client. They share the same API. -The local python client talks to the Sagemaker endpoint you just deployed, which runs on an instance with a GPU to run model inference. - +After creating the endpoint, you can create a SageMaker client and use it the same way as a Forge client. They share the same API. +The local python client talks to the SageMaker endpoint you just deployed, which runs on an instance with a GPU to run model inference. Ensure that the code below runs in an environment that has AWS credentials available for the account which provisioned SageMaker resources. Learn more about general AWS credential options [here](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-authentication.html#cli-chap-authentication-precedence). @@ -126,103 +198,9 @@ print(logits_output.logits, logits_output.embeddings) ``` ### ESM C Example Usage - -Look at [esmc_examples.py](./examples/esmc_examples.py) for the standard usage (extracting embeddings and model amino acid prediction). - -More coming soon. - -## ESM 3 - -[ESM3](https://www.evolutionaryscale.ai/papers/esm3-simulating-500-million-years-of-evolution-with-a-language-model) is a frontier generative model for biology, able to jointly reason across three fundamental biological properties of proteins: sequence, structure, and function. These three data modalities are represented as tracks of discrete tokens at the input and output of ESM3. You can present the model with a combination of partial inputs across the tracks, and ESM3 will provide output predictions for all the tracks. + -ESM3 is a _generative_ masked language model. You can prompt it with partial sequence, structure, and function keywords, and iteratively sample masked positions until all positions are unmasked. This iterative sampling is what the `.generate()` function does. - - -ESM3 Diagram - -The ESM3 architecture is highly scalable due to its transformer backbone and all-to-all reasoning over discrete token sequences. At its largest scale, ESM3 was trained with 1.07e24 FLOPs on 2.78 billion proteins and 771 billion unique tokens, and has 98 billion parameters. -Learn more by reading the [blog post](https://www.evolutionaryscale.ai/blog/esm3-release) and [the pre-print (Hayes et al., 2024)](https://www.evolutionaryscale.ai/papers/esm3-simulating-500-million-years-of-evolution-with-a-language-model). - -Here we present `esm3-open-small`. With 1.4B parameters it is the smallest and fastest model in the family. -ESM3-open is available under the [Cambrian non-commercial license agreement](https://www.evolutionaryscale.ai/policies/cambrian-non-commercial-license-agreement), as outlined in `LICENSE.md` (note: updated with ESM C release). -Visit our [Discussions page](https://github.com/evolutionaryscale/esm/discussions) to get in touch, provide feedback, ask questions or share your experience with ESM3! - -### Quickstart for ESM3-open - -``` -pip install esm -``` - -In order to download the weights, we require users to accept our non-commercial license. -The weights are stored on HuggingFace Hub under [HuggingFace/EvolutionaryScale/esm3](https://huggingface.co/EvolutionaryScale/esm3). -Please create an account and accept the license. - -```py -from huggingface_hub import login -from esm.models.esm3 import ESM3 -from esm.sdk.api import ESM3InferenceClient, ESMProtein, GenerationConfig - -# Will instruct you how to get an API key from huggingface hub, make one with "Read" permission. -login() - -# This will download the model weights and instantiate the model on your machine. -model: ESM3InferenceClient = ESM3.from_pretrained("esm3-open").to("cuda") # or "cpu" - -# Generate a completion for a partial Carbonic Anhydrase (2vvb) -prompt = "___________________________________________________DQATSLRILNNGHAFNVEFDDSQDKAVLKGGPLDGTYRLIQFHFHWGSLDGQGSEHTVDKKKYAAELHLVHWNTKYGDFGKAVQQPDGLAVLGIFLKVGSAKPGLQKVVDVLDSIKTKGKSADFTNFDPRGLLPESLDYWTYPGSLTTPP___________________________________________________________" -protein = ESMProtein(sequence=prompt) -# Generate the sequence, then the structure. This will iteratively unmask the sequence track. -protein = model.generate(protein, GenerationConfig(track="sequence", num_steps=8, temperature=0.7)) -# We can show the predicted structure for the generated sequence. -protein = model.generate(protein, GenerationConfig(track="structure", num_steps=8)) -protein.to_pdb("./generation.pdb") -# Then we can do a round trip design by inverse folding the sequence and recomputing the structure -protein.sequence = None -protein = model.generate(protein, GenerationConfig(track="sequence", num_steps=8)) -protein.coordinates = None -protein = model.generate(protein, GenerationConfig(track="structure", num_steps=8)) -protein.to_pdb("./round_tripped.pdb") -``` - -Congratulations, you just generated your first proteins with ESM3! - -### EvolutionaryScale Forge: Access to larger ESM3 models - - -You can apply for beta access to the full family of larger and higher capability ESM3 models at [EvolutionaryScale Forge](https://forge.evolutionaryscale.ai). - -We encourage users to interact with the Forge API through the python `esm` library instead of the command line. -The python interface enables you to interactively load proteins, build prompts, and inspect generated proteins -with the `ESMProtein` and config classes used to interact with the local model. - -In any example script try to replace a local `ESM3` model with a Forge API client: - -```py -# Instead of loading the model locally on your machine: -model: ESM3InferenceClient = ESM3.from_pretrained("esm3_sm_open_v1").to("cuda") # or "cpu" -# just replace the line with this: -model: ESM3InferenceClient = esm.sdk.client("esm3-medium-2024-08", token="") -# and now you're interfacing with the model running on our remote servers. -... -``` - -and the exact same code will work. -This enables a seamless transition from smaller and faster models, to our large 98B protein language models for protein design work. - -### ESM3 Example Usage - -Let's explore some more advanced prompting with the help of our [notebooks and scripts](examples/). - -`generate.ipynb` will walk through two prompting examples (scaffolding and secondary structure editing) using the open model: -[](https://colab.research.google.com/github/evolutionaryscale/esm/blob/main/examples/generate.ipynb) - -`gfp_design.ipynb` will walk through the more complex generation procedure we used to design esmGFP: -[](https://colab.research.google.com/github/evolutionaryscale/esm/blob/main/examples/gfp_design.ipynb) - -We also provide example scripts that show common workflows under `examples/`: - -- [local_generate.py](./examples/local_generate.py) shows how simple and elegant common tasks are: it shows folding, inverse folding and chain of thought generation, all by calling just `model.generate()` for iterative decoding. -- [seqfun_struct.py](./examples/seqfun_struct.py) shows direct use of the model as a standard pytorch model with a simple model `forward` call. +Check out our [tutorials](./cookbook/tutorials) to learn how to use ESM C. ## Responsible Development @@ -238,27 +216,44 @@ The core tenets of our framework are With this in mind, we have performed a variety of mitigations for `esm3-sm-open-v1`, detailed in our [paper](https://www.evolutionaryscale.ai/papers/esm3-simulating-500-million-years-of-evolution-with-a-language-model) ## Licenses -The code and model weights of ESM3 and ESM C are available under a mixture of non-commercial and permissive commercial licenses. -This summary provides a high-level overview. For complete license details, see [LICENSE.md](./LICENSE.md). - -### How can I access the models and which licenses apply? - -The models can be accessed in three different ways, each with its own licensing terms. -1. **Code and weights** via GitHub and HuggingFace are available under either a [non-commercial](https://www.evolutionaryscale.ai/policies/cambrian-non-commercial-license-agreement) (ESM C 600M, ESM3-small-open) or an [open license](https://www.evolutionaryscale.ai/policies/cambrian-open-license-agreement) (codebase, ESM C 300M). - 1. **Building with ESM encouraged**: You can use embeddings, model predictions, fine-tune the models and use components of both the models and code. We strongly encourage anyone to build on ESM C and ESM3! Just remember to maintain the same license terms and release under the ESM name. -2. **Free non-commercial inference API** via Forge. All models are available this way, with free credits granted to students and researchers. We want to enable academics under [non-commercial Terms of Use](https://www.evolutionaryscale.ai/policies/terms-of-use), which mirrors the non-commercial license. -3. **Paid commercial Inference API** for commercial use via SageMaker (Forge coming soon). All ESM C models are available this way to commercial entities for commercial use under a [clickthrough license agreement](https://www.evolutionaryscale.ai/policies/cambrian-inference-clickthrough-license-agreement) with few restrictions. - 1. In broad strokes: standard commercial use like developing molecules and developing downstream ML models and methods with the model is allowed, while training competing models on the API outputs is not. - 2. Note: For ESM3 commercial use, reach out to [bd@evolutionaryscale.ai](mailto:bd@evolutionaryscale.ai) +The code and model weights of ESM3 and ESM C are available under a mixture of non-commercial and permissive commercial licenses. For complete license details, see [LICENSE.md](./LICENSE.md). -### What changed with the release of ESM C? +## Citations +If you use ESM in your work, please cite one of the following: -We introduced a [clickthrough license agreement](https://www.evolutionaryscale.ai/policies/cambrian-inference-clickthrough-license-agreement) to enable frictionless commercial use of ESM C. - -We introduced the new [Cambrian Open License](https://www.evolutionaryscale.ai/policies/cambrian-open-license-agreement) for ESM C 300M, and at the same time moved all code in the [`esm` repo](https://github.com/evolutionaryscale/esm) under that permissive license. +#### ESM3 +``` +@article {hayes2024simulating, + author = {Hayes, Thomas and Rao, Roshan and Akin, Halil and Sofroniew, Nicholas J. and Oktay, Deniz and Lin, Zeming and Verkuil, Robert and Tran, Vincent Q. and Deaton, Jonathan and Wiggert, Marius and Badkundri, Rohil and Shafkat, Irhum and Gong, Jun and Derry, Alexander and Molina, Raul S. and Thomas, Neil and Khan, Yousuf A. and Mishra, Chetan and Kim, Carolyn and Bartie, Liam J. and Nemeth, Matthew and Hsu, Patrick D. and Sercu, Tom and Candido, Salvatore and Rives, Alexander}, + title = {Simulating 500 million years of evolution with a language model}, + year = {2024}, + doi = {10.1101/2024.07.01.600583}, + URL = {https://doi.org/10.1101/2024.07.01.600583}, + journal = {bioRxiv} +} +``` -The [Cambrian non-commercial license](https://www.evolutionaryscale.ai/policies/cambrian-non-commercial-license-agreement) is largely based on the original [ESM3 Community License Agreement](https://www.evolutionaryscale.ai/policies/community-license-agreement), but removed the clause that restricted drug development, added the naming requirement, and extended the meaning of “Derivative Work” to allow training on model outputs. Just remember to release models and methods built on ESM under the same license. -These changes are meant to remove potential gray areas and points of friction for researchers building with ESM. +#### ESM C +``` +@misc{esm2024cambrian, + author = {{ESM Team}}, + title = {ESM Cambrian: Revealing the mysteries of proteins with unsupervised learning}, + year = {2024}, + publisher = {EvolutionaryScale Website}, + url = {https://evolutionaryscale.ai/blog/esm-cambrian}, + urldate = {2024-12-04} +} +``` -Finally, The ESM3-open-small model has been moved under the Cambrian non-commercial license. +#### ESM Github (Code / Weights) +``` +@software{evolutionaryscale_2024, + author = {{EvolutionaryScale Team}}, + title = {evolutionaryscale/esm}, + year = {2024}, + publisher = {Zenodo}, + doi = {10.5281/zenodo.14219303}, + URL = {https://doi.org/10.5281/zenodo.14219303} +} +``` diff --git a/cookbook/local/README.md b/cookbook/local/README.md new file mode 100644 index 0000000..3292a01 --- /dev/null +++ b/cookbook/local/README.md @@ -0,0 +1 @@ +Examples utilizing the open model run locally. diff --git a/examples/generate.ipynb b/cookbook/local/open_generate.ipynb similarity index 100% rename from examples/generate.ipynb rename to cookbook/local/open_generate.ipynb diff --git a/examples/raw_forwards.py b/cookbook/local/raw_forwards.py similarity index 100% rename from examples/raw_forwards.py rename to cookbook/local/raw_forwards.py diff --git a/cookbook/snippets/README.md b/cookbook/snippets/README.md new file mode 100644 index 0000000..34e7a33 --- /dev/null +++ b/cookbook/snippets/README.md @@ -0,0 +1 @@ +Snippets of ESM3 usage that you can copy and paste directly into your scripts. diff --git a/examples/local_generate.py b/cookbook/snippets/esm3.py similarity index 93% rename from examples/local_generate.py rename to cookbook/snippets/esm3.py index 3b718b3..1bc3629 100644 --- a/examples/local_generate.py +++ b/cookbook/snippets/esm3.py @@ -1,11 +1,15 @@ +import os + import torch from esm.models.esm3 import ESM3 +from esm.sdk import client from esm.sdk.api import ( ESM3InferenceClient, ESMProtein, ESMProteinError, ESMProteinTensor, + ForwardAndSampleOutput, GenerationConfig, LogitsConfig, LogitsOutput, @@ -195,4 +199,12 @@ def main(client: ESM3InferenceClient): if __name__ == "__main__": - main(ESM3.from_pretrained("esm3_sm_open_v1")) + if os.environ.get("ESM_API_KEY", ""): + print("ESM_API_KEY found. Trying to use model from Forge...") + main(client()) + else: + print("No ESM_API_KEY found. Trying to load model locally...") + print( + "TO try this script with a Forge API, please run ESM_API_KEY=your_api_key python esm3.py" + ) + main(ESM3.from_pretrained("esm3_sm_open_v1")) diff --git a/examples/esmc_examples.py b/cookbook/snippets/esmc.py similarity index 87% rename from examples/esmc_examples.py rename to cookbook/snippets/esmc.py index 3bfa788..ce189d9 100644 --- a/examples/esmc_examples.py +++ b/cookbook/snippets/esmc.py @@ -29,6 +29,13 @@ def main(client: ESMCInferenceClient): f"Client returned logits with shape: {output.logits.sequence.shape}, embeddings with shape: {output.embeddings.shape}, and hidden states with shape {output.hidden_states.shape}" ) + # request a specific hidden layer. + output = client.logits( + protein_tensor, LogitsConfig(return_hidden_states=True, ith_hidden_layer=1) + ) + assert output.hidden_states is not None + print(f"Client returned hidden states with shape {output.hidden_states.shape}") + def raw_forward(model: ESMC): protein = ESMProtein(sequence="AAAAA") diff --git a/examples/folding_inverse_folding_example.py b/cookbook/snippets/fold_invfold.py similarity index 62% rename from examples/folding_inverse_folding_example.py rename to cookbook/snippets/fold_invfold.py index 902c576..d4c1a1d 100644 --- a/examples/folding_inverse_folding_example.py +++ b/cookbook/snippets/fold_invfold.py @@ -1,15 +1,31 @@ +import os from typing import cast import numpy as np -from examples.local_generate import get_sample_protein from esm.sdk.api import ( ESM3InferenceClient, ESMProtein, GenerationConfig, InverseFoldingConfig, ) -from esm.sdk.forge import SequenceStructureForgeInferenceClient +from esm.sdk.forge import ( + ESM3ForgeInferenceClient, + SequenceStructureForgeInferenceClient, +) +from esm.utils.structure.protein_chain import ProteinChain +from esm.utils.types import FunctionAnnotation + + +def get_sample_protein() -> ESMProtein: + protein = ProteinChain.from_rcsb("1utn") + protein = ESMProtein.from_protein_chain(protein) + protein.function_annotations = [ + # Peptidase S1A, chymotrypsin family: https://www.ebi.ac.uk/interpro/structure/PDB/1utn/ + FunctionAnnotation(label="peptidase", start=100, end=114), + FunctionAnnotation(label="chymotrypsin", start=190, end=202), + ] + return protein def convert_none_to_nan(data): @@ -22,22 +38,23 @@ def convert_none_to_nan(data): return data -def main( +def fold( sequence_structure_client: SequenceStructureForgeInferenceClient, esm3_client: ESM3InferenceClient, ): - # Folding with esm3 client protein = get_sample_protein() protein.coordinates = None protein.function_annotations = None protein.sasa = None assert protein.sequence is not None, "Protein sequence must be set to fold" + # Folding with esm3 client config = GenerationConfig(track="structure", num_steps=1, temperature=0) esm3_client_folded_protein = esm3_client.generate(protein, config) assert isinstance( esm3_client_folded_protein, ESMProtein ), f"Using ESM3 client, ESMProtein was expected but got {protein}" + # Folding with folding client sequence_structure_client_folded_protein = sequence_structure_client.fold( protein.sequence, potential_sequence_of_concern=False @@ -45,8 +62,14 @@ def main( assert isinstance( sequence_structure_client_folded_protein, ESMProtein ), f"Using sequence_structure client, ESMProtein was expected but got {sequence_structure_client_folded_protein}" + sequence_structure_client_folded_protein.to_pdb("folded_protein.pdb") + print("Saving folded protein to folded_protein.pdb") - # Inverse Folding with esm3 client + +def inverse_fold( + sequence_structure_client: SequenceStructureForgeInferenceClient, + esm3_client: ESM3InferenceClient, +): protein = get_sample_protein() protein.sequence = None protein.sasa = None @@ -54,21 +77,38 @@ def main( assert ( protein.coordinates is not None ), "Protein coordinates must be set to inverse fold" - config = GenerationConfig("sequence", num_steps=1, temperature=0.7) + + # Inverse Folding with esm3 client + config = GenerationConfig("sequence", num_steps=1, temperature=0.1) esm3_client_inv_folded_protein = cast( ESMProtein, esm3_client.generate(protein, config) ) assert isinstance( esm3_client_inv_folded_protein, ESMProtein ), f"Using ESM3 client, ESMProtein was expected but got {protein}" + # Inverse Folding with inverse folding client sequence_structure_client_inv_folded_protein = ( sequence_structure_client.inverse_fold( protein.coordinates, - config=InverseFoldingConfig(temperature=0.7), + config=InverseFoldingConfig(temperature=0.1), potential_sequence_of_concern=False, ) ) assert isinstance( sequence_structure_client_inv_folded_protein, ESMProtein ), f"Using sequence_structure client, ESMProtein was expected but got {sequence_structure_client_inv_folded_protein}" + print( + f"Inverse folded protein: {sequence_structure_client_inv_folded_protein.sequence}" + ) + + +if __name__ == "__main__": + if not os.environ.get("ESM_API_KEY", ""): + print("Please export your Forge API key as ESM_API_KEY environment variable.") + client = SequenceStructureForgeInferenceClient(token=os.environ["ESM_API_KEY"]) + esm3_client = ESM3ForgeInferenceClient( + model="esm3-medium-2024-08", token=os.environ["ESM_API_KEY"] + ) + fold(client, esm3_client) + inverse_fold(client, esm3_client) diff --git a/examples/esmprotein.ipynb b/cookbook/tutorials/1_esmprotein.ipynb similarity index 82% rename from examples/esmprotein.ipynb rename to cookbook/tutorials/1_esmprotein.ipynb index 38be2f2..fbe6d70 100644 --- a/examples/esmprotein.ipynb +++ b/cookbook/tutorials/1_esmprotein.ipynb @@ -44,8 +44,11 @@ "metadata": {}, "outputs": [], "source": [ - "# Install esm\n", - "! pip install esm" + "# Install esm and other dependencies\n", + "! pip install esm\n", + "! pip install py3Dmol\n", + "! pip install matplotlib\n", + "! pip install dna-features-viewer" ] }, { @@ -55,8 +58,8 @@ "outputs": [], "source": [ "from biotite.database import rcsb\n", - "from esm.utils.structure.protein_chain import ProteinChain\n", "from esm.sdk.api import ESMProtein\n", + "from esm.utils.structure.protein_chain import ProteinChain\n", "from esm.utils.types import FunctionAnnotation\n", "\n", "pdb_id = \"1cm4\"\n", @@ -140,23 +143,21 @@ "metadata": {}, "outputs": [], "source": [ - "\"\"\"\n", - "Functions for visualizing 3D structure\n", - "\"\"\"\n", - "\n", - "! pip install py3Dmol\n", + "# Functions for visualizing 3D structure\n", "\n", "import py3Dmol\n", "\n", + "\n", "def visualize_pdb(pdb_string):\n", " view = py3Dmol.view(width=400, height=400)\n", " view.addModel(pdb_string, \"pdb\")\n", - " view.setStyle({'cartoon': {'color': 'spectrum'}})\n", + " view.setStyle({\"cartoon\": {\"color\": \"spectrum\"}})\n", " view.zoomTo()\n", " view.render()\n", " view.center()\n", " return view\n", "\n", + "\n", "def visualize_3D_coordinates(coordinates):\n", " \"\"\"\n", " This uses all Alanines\n", @@ -166,6 +167,7 @@ " pdb_string = protein_with_same_coords.to_pdb_string()\n", " return visualize_pdb(pdb_string)\n", "\n", + "\n", "def visualize_3D_protein(protein):\n", " pdb_string = protein.to_pdb_string()\n", " return visualize_pdb(pdb_string)" @@ -210,17 +212,20 @@ "source": [ "from biotite.structure import annotate_sse\n", "\n", + "\n", "def get_approximate_ss(protein_chain: ProteinChain):\n", " # get biotite's ss3 representation\n", " ss3_arr = annotate_sse(protein_chain.atom_array)\n", - " biotite_ss3_str = ''.join(ss3_arr)\n", + " biotite_ss3_str = \"\".join(ss3_arr)\n", "\n", " # translate into ESM3's representation\n", - " translation_table = str.maketrans({\n", - " 'a': 'H', # alpha helix\n", - " 'b': 'E', # beta sheet\n", - " 'c': 'C', # coil\n", - " })\n", + " translation_table = str.maketrans(\n", + " {\n", + " \"a\": \"H\", # alpha helix\n", + " \"b\": \"E\", # beta sheet\n", + " \"c\": \"C\", # coil\n", + " }\n", + " )\n", " esm_ss3 = biotite_ss3_str.translate(translation_table)\n", " return esm_ss3" ] @@ -248,24 +253,22 @@ "metadata": {}, "outputs": [], "source": [ - "# ! pip install matplotlib\n", - "\n", "# Slightly modified version of secondary structure plotting code from\n", "# https://www.biotite-python.org/examples/gallery/structure/transketolase_sse.html\n", "# Code source: Patrick Kunzmann\n", "# License: BSD 3 clause\n", "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "from matplotlib.patches import Rectangle\n", "import biotite\n", "import biotite.sequence as seq\n", "import biotite.sequence.graphics as graphics\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from matplotlib.patches import Rectangle\n", + "\n", "\n", "# Create 'FeaturePlotter' subclasses\n", "# for drawing the secondary structure features\n", "class HelixPlotter(graphics.FeaturePlotter):\n", - "\n", " def __init__(self):\n", " pass\n", "\n", @@ -281,12 +284,12 @@ " def draw(self, axes, feature, bbox, loc, style_param):\n", " # Approx. 1 turn per 3.6 residues to resemble natural helix\n", " n_turns = np.ceil((loc.last - loc.first + 1) / 3.6)\n", - " x_val = np.linspace(0, n_turns * 2*np.pi, 100)\n", + " x_val = np.linspace(0, n_turns * 2 * np.pi, 100)\n", " # Curve ranges from 0.3 to 0.7\n", - " y_val = (-0.4*np.sin(x_val) + 1) / 2\n", + " y_val = (-0.4 * np.sin(x_val) + 1) / 2\n", "\n", " # Transform values for correct location in feature map\n", - " x_val *= bbox.width / (n_turns * 2*np.pi)\n", + " x_val *= bbox.width / (n_turns * 2 * np.pi)\n", " x_val += bbox.x0\n", " y_val *= bbox.height\n", " y_val += bbox.y0\n", @@ -296,13 +299,10 @@ " bbox.p0, bbox.width, bbox.height, color=\"white\", linewidth=0\n", " )\n", " axes.add_patch(background)\n", - " axes.plot(\n", - " x_val, y_val, linewidth=2, color=biotite.colors[\"dimgreen\"]\n", - " )\n", + " axes.plot(x_val, y_val, linewidth=2, color=biotite.colors[\"dimgreen\"])\n", "\n", "\n", "class SheetPlotter(graphics.FeaturePlotter):\n", - "\n", " def __init__(self, head_width=0.8, tail_width=0.5):\n", " self._head_width = head_width\n", " self._tail_width = tail_width\n", @@ -316,36 +316,48 @@ "\n", " def draw(self, axes, feature, bbox, loc, style_param):\n", " x = bbox.x0\n", - " y = bbox.y0 + bbox.height/2\n", + " y = bbox.y0 + bbox.height / 2\n", " dx = bbox.width\n", " dy = 0\n", "\n", - " if loc.defect & seq.Location.Defect.MISS_RIGHT:\n", + " if loc.defect & seq.Location.Defect.MISS_RIGHT:\n", " # If the feature extends into the previous or next line\n", " # do not draw an arrow head\n", " draw_head = False\n", " else:\n", " draw_head = True\n", "\n", - " axes.add_patch(biotite.AdaptiveFancyArrow(\n", - " x, y, dx, dy,\n", - " self._tail_width*bbox.height, self._head_width*bbox.height,\n", - " # Create head with 90 degrees tip\n", - " # -> head width/length ratio = 1/2\n", - " head_ratio=0.5, draw_head=draw_head,\n", - " color=biotite.colors[\"orange\"], linewidth=0\n", - " ))\n", + " axes.add_patch(\n", + " biotite.AdaptiveFancyArrow(\n", + " x,\n", + " y,\n", + " dx,\n", + " dy,\n", + " self._tail_width * bbox.height,\n", + " self._head_width * bbox.height,\n", + " # Create head with 90 degrees tip\n", + " # -> head width/length ratio = 1/2\n", + " head_ratio=0.5,\n", + " draw_head=draw_head,\n", + " color=biotite.colors[\"orange\"],\n", + " linewidth=0,\n", + " )\n", + " )\n", + "\n", "\n", "# Converter for the DSSP secondary structure elements\n", "# to the classical ones\n", - "dssp_to_abc = {\"I\" : \"c\",\n", - " \"S\" : \"c\",\n", - " \"H\" : \"a\",\n", - " \"E\" : \"b\",\n", - " \"G\" : \"c\",\n", - " \"B\" : \"b\",\n", - " \"T\" : \"c\",\n", - " \"C\" : \"c\"}\n", + "dssp_to_abc = {\n", + " \"I\": \"c\",\n", + " \"S\": \"c\",\n", + " \"H\": \"a\",\n", + " \"E\": \"b\",\n", + " \"G\": \"c\",\n", + " \"B\": \"b\",\n", + " \"T\": \"c\",\n", + " \"C\": \"c\",\n", + "}\n", + "\n", "\n", "def visualize_secondary_structure(sse, first_id):\n", " \"\"\"\n", @@ -362,7 +374,7 @@ " # coil\n", " return\n", " feature = seq.Feature(\n", - " \"SecStr\", [seq.Location(first, last)], {\"sec_str_type\" : str_type}\n", + " \"SecStr\", [seq.Location(first, last)], {\"sec_str_type\": str_type}\n", " )\n", " annotation.add_feature(feature)\n", "\n", @@ -376,21 +388,23 @@ " curr_start = i\n", " curr_sse = sse[i]\n", " else:\n", - " if sse[i] != sse[i-1]:\n", + " if sse[i] != sse[i - 1]:\n", " _add_sec_str(\n", - " annotation, curr_start+first_id, i-1+first_id, curr_sse\n", + " annotation, curr_start + first_id, i - 1 + first_id, curr_sse\n", " )\n", " curr_start = i\n", " curr_sse = sse[i]\n", " # Add last secondary structure element to annotation\n", - " _add_sec_str(annotation, curr_start+first_id, i+first_id, curr_sse)\n", + " _add_sec_str(annotation, curr_start + first_id, i + first_id, curr_sse)\n", "\n", " fig = plt.figure(figsize=(30.0, 3.0))\n", " ax = fig.add_subplot(111)\n", " graphics.plot_feature_map(\n", - " ax, annotation, symbols_per_line=150,\n", - " loc_range=(first_id, first_id+len(sse)),\n", - " feature_plotters=[HelixPlotter(), SheetPlotter()]\n", + " ax,\n", + " annotation,\n", + " symbols_per_line=150,\n", + " loc_range=(first_id, first_id + len(sse)),\n", + " feature_plotters=[HelixPlotter(), SheetPlotter()],\n", " )\n", " fig.tight_layout()\n", " return fig, ax\n", @@ -440,10 +454,8 @@ "metadata": {}, "outputs": [], "source": [ - "from esm.utils.types import FunctionAnnotation\n", - "\n", "interpro_function_annotations = [\n", - " FunctionAnnotation(label=\"IPR050145\", start=1, end=142), # 1 indexed, inclusive;\n", + " FunctionAnnotation(label=\"IPR050145\", start=1, end=142), # 1 indexed, inclusive;\n", " FunctionAnnotation(label=\"IPR002048\", start=4, end=75),\n", " FunctionAnnotation(label=\"IPR002048\", start=77, end=144),\n", " FunctionAnnotation(label=\"IPR011992\", start=1, end=143),\n", @@ -467,21 +479,18 @@ "metadata": {}, "outputs": [], "source": [ - "\"\"\"\n", - "Functions for visualizing InterPro function annotations\n", - "\"\"\"\n", - "\n", - "! pip install dna-features-viewer\n", + "# Functions for visualizing InterPro function annotations\n", "\n", "from dna_features_viewer import GraphicFeature, GraphicRecord\n", - "from esm.utils.function.interpro import InterProEntryType, InterPro\n", + "from esm.utils.function.interpro import InterPro, InterProEntryType\n", "from matplotlib import colormaps\n", "\n", + "\n", "def visualize_function_annotations(\n", " annotations: list[FunctionAnnotation],\n", " sequence_length: int,\n", " ax: plt.Axes,\n", - " interpro_ = InterPro(),\n", + " interpro_=InterPro(),\n", "):\n", " cmap = colormaps[\"tab10\"]\n", " colors = [cmap(i) for i in range(len(InterProEntryType))]\n", @@ -498,7 +507,7 @@ " entry_type = InterProEntryType.UNKNOWN\n", "\n", " feature = GraphicFeature(\n", - " start=annotation.start - 1, # one index -> zero index\n", + " start=annotation.start - 1, # one index -> zero index\n", " end=annotation.end,\n", " label=label,\n", " color=type_colors[entry_type],\n", @@ -507,9 +516,7 @@ " features.append(feature)\n", "\n", " record = GraphicRecord(\n", - " sequence=None,\n", - " sequence_length=sequence_length,\n", - " features=features,\n", + " sequence=None, sequence_length=sequence_length, features=features\n", " )\n", "\n", " record.plot(figure_width=12, plot_sequence=False, ax=ax)" @@ -529,11 +536,7 @@ "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(20.0, 4.0))\n", - "visualize_function_annotations(\n", - " interpro_function_annotations,\n", - " len(protein),\n", - " ax,\n", - ")" + "visualize_function_annotations(interpro_function_annotations, len(protein), ax)" ] }, { @@ -553,6 +556,7 @@ "source": [ "from esm.tokenization import InterProQuantizedTokenizer\n", "\n", + "\n", "def get_keywords_from_interpro(\n", " interpro_annotations,\n", " interpro2keywords=InterProQuantizedTokenizer().interpro2keywords,\n", @@ -560,14 +564,16 @@ " keyword_annotations_list = []\n", " for interpro_annotation in interpro_annotations:\n", " keywords = interpro2keywords.get(interpro_annotation.label, [])\n", - " keyword_annotations_list.extend([\n", - " FunctionAnnotation(\n", - " label=keyword,\n", - " start=interpro_annotation.start,\n", - " end=interpro_annotation.end,\n", - " )\n", - " for keyword in keywords\n", - " ])\n", + " keyword_annotations_list.extend(\n", + " [\n", + " FunctionAnnotation(\n", + " label=keyword,\n", + " start=interpro_annotation.start,\n", + " end=interpro_annotation.end,\n", + " )\n", + " for keyword in keywords\n", + " ]\n", + " )\n", " return keyword_annotations_list" ] }, @@ -595,11 +601,7 @@ "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(20.0, 8.0))\n", - "visualize_function_annotations(\n", - " protein.function_annotations,\n", - " len(protein),\n", - " ax,\n", - ")" + "visualize_function_annotations(protein.function_annotations, len(protein), ax)" ] }, { @@ -656,30 +658,50 @@ "metadata": {}, "outputs": [], "source": [ - "from matplotlib import colormaps\n", - "\n", - "cmap = colormaps['cividis']\n", + "cmap = colormaps[\"cividis\"]\n", "clip_sasa_lower = 10\n", "clip_sasa_upper = 90\n", "\n", - "def plot_heatmap_legend(\n", - " cmap,\n", - " clip_sasa_lower,\n", - " clip_sasa_upper,\n", - "):\n", + "\n", + "def plot_heatmap_legend(cmap, clip_sasa_lower, clip_sasa_upper):\n", " gradient = np.linspace(0, 1, 256)\n", " gradient = np.vstack((gradient, gradient))\n", " _, ax = plt.subplots(figsize=(5, 0.3), dpi=350)\n", - " ax.imshow(gradient, aspect='auto', cmap=cmap)\n", - " ax.text(0.1, -0.3, f'{clip_sasa_lower} or lower', va='center', ha='right', fontsize=7, transform=ax.transAxes)\n", - " ax.text(0.5, -0.3, f'{(clip_sasa_lower + clip_sasa_upper) // 2}', va='center', ha='right', fontsize=7, transform=ax.transAxes)\n", - " ax.text(0.9, -0.3, f'{clip_sasa_upper} or higher', va='center', ha='left', fontsize=7, transform=ax.transAxes)\n", + " ax.imshow(gradient, aspect=\"auto\", cmap=cmap)\n", + " ax.text(\n", + " 0.1,\n", + " -0.3,\n", + " f\"{clip_sasa_lower} or lower\",\n", + " va=\"center\",\n", + " ha=\"right\",\n", + " fontsize=7,\n", + " transform=ax.transAxes,\n", + " )\n", + " ax.text(\n", + " 0.5,\n", + " -0.3,\n", + " f\"{(clip_sasa_lower + clip_sasa_upper) // 2}\",\n", + " va=\"center\",\n", + " ha=\"right\",\n", + " fontsize=7,\n", + " transform=ax.transAxes,\n", + " )\n", + " ax.text(\n", + " 0.9,\n", + " -0.3,\n", + " f\"{clip_sasa_upper} or higher\",\n", + " va=\"center\",\n", + " ha=\"left\",\n", + " fontsize=7,\n", + " transform=ax.transAxes,\n", + " )\n", " ax.set_xticklabels([])\n", " ax.set_yticklabels([])\n", " ax.set_xticks([])\n", " ax.set_yticks([])\n", " plt.show()\n", "\n", + "\n", "plot_heatmap_legend(cmap, clip_sasa_lower, clip_sasa_upper)" ] }, @@ -689,38 +711,33 @@ "metadata": {}, "outputs": [], "source": [ - "\"\"\"\n", - "Functions for visualizing SASA as colors on the 3D structure\n", - "\"\"\"\n", + "# Functions for visualizing SASA as colors on the 3D structure\n", "\n", - "def get_color_strings(\n", - " sasa,\n", - " clip_sasa_lower,\n", - " clip_sasa_upper,\n", - " cmap,\n", - "):\n", + "\n", + "def get_color_strings(sasa, clip_sasa_lower, clip_sasa_upper, cmap):\n", " transformed_sasa = np.clip(sasa, clip_sasa_lower, clip_sasa_upper)\n", - " transformed_sasa = (transformed_sasa - clip_sasa_lower) / (clip_sasa_upper - clip_sasa_lower)\n", + " transformed_sasa = (transformed_sasa - clip_sasa_lower) / (\n", + " clip_sasa_upper - clip_sasa_lower\n", + " )\n", " rgbas = (cmap(transformed_sasa) * 255).astype(int)\n", "\n", - " return [\n", - " f'rgb({rgba[0]},{rgba[1]},{rgba[2]})'\n", - " for rgba in rgbas\n", - " ] \n", + " return [f\"rgb({rgba[0]},{rgba[1]},{rgba[2]})\" for rgba in rgbas]\n", + "\n", "\n", "def visualize_sasa_3D_protein(\n", - " protein,\n", - " clip_sasa_lower=clip_sasa_lower,\n", - " clip_sasa_upper=clip_sasa_upper,\n", - " cmap=cmap,\n", + " protein, clip_sasa_lower=clip_sasa_lower, clip_sasa_upper=clip_sasa_upper, cmap=cmap\n", "):\n", " pdb_string = protein.to_pdb_string()\n", " plot_heatmap_legend(cmap, clip_sasa_lower, clip_sasa_upper)\n", " view = py3Dmol.view(width=400, height=400)\n", " view.addModel(pdb_string, \"pdb\")\n", "\n", - " for res_pos, res_color in enumerate(get_color_strings(protein.sasa, clip_sasa_lower, clip_sasa_upper, cmap)):\n", - " view.setStyle({'chain': 'A', 'resi': res_pos+1}, {'cartoon': {'color': res_color}})\n", + " for res_pos, res_color in enumerate(\n", + " get_color_strings(protein.sasa, clip_sasa_lower, clip_sasa_upper, cmap)\n", + " ):\n", + " view.setStyle(\n", + " {\"chain\": \"A\", \"resi\": res_pos + 1}, {\"cartoon\": {\"color\": res_color}}\n", + " )\n", " view.zoomTo()\n", " view.render()\n", " view.center()\n", diff --git a/cookbook/tutorials/2_embed.ipynb b/cookbook/tutorials/2_embed.ipynb new file mode 100644 index 0000000..284b8cd --- /dev/null +++ b/cookbook/tutorials/2_embed.ipynb @@ -0,0 +1,342 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this notebook we will see how to embed a batch of sequences using ESM C, as well as explore its different layers" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Set up Forge client for ESM C" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from getpass import getpass\n", + "\n", + "token = getpass(\"Token from Forge console: \")" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from esm.sdk import client\n", + "\n", + "model = client(\n", + " model=\"esmc-300m-2024-12\", url=\"https://forge.evolutionaryscale.ai\", token=token\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Set up utilities for embedding sequences\n", + "\n", + "Since we're embedding a more than a few sequences, we're going to use an threaded async call to Forge and let Forge take care of batching and parallelization on the backend." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from concurrent.futures import ThreadPoolExecutor\n", + "from typing import Sequence\n", + "\n", + "from esm.sdk.api import (\n", + " ESM3InferenceClient,\n", + " ESMProtein,\n", + " ESMProteinError,\n", + " LogitsConfig,\n", + " LogitsOutput,\n", + " ProteinType,\n", + ")\n", + "\n", + "EMBEDDING_CONFIG = LogitsConfig(\n", + " sequence=True, return_embeddings=True, return_hidden_states=True\n", + ")\n", + "\n", + "\n", + "def embed_sequence(model: ESM3InferenceClient, sequence: str) -> LogitsOutput:\n", + " protein = ESMProtein(sequence=sequence)\n", + " protein_tensor = model.encode(protein)\n", + " output = model.logits(protein_tensor, EMBEDDING_CONFIG)\n", + " return output\n", + "\n", + "\n", + "def batch_embed(\n", + " model: ESM3InferenceClient, inputs: Sequence[ProteinType]\n", + ") -> Sequence[LogitsOutput]:\n", + " \"\"\"Forge supports auto-batching. So batch_embed() is as simple as running a collection\n", + " of embed calls in parallel using asyncio.\n", + " \"\"\"\n", + " with ThreadPoolExecutor() as executor:\n", + " futures = [\n", + " executor.submit(embed_sequence, model, protein) for protein in inputs\n", + " ]\n", + " results = []\n", + " for future in futures:\n", + " try:\n", + " results.append(future.result())\n", + " except Exception as e:\n", + " results.append(ESMProteinError(500, str(e)))\n", + " return results" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Requesting a specific hidden layer\n", + "\n", + "ESM C 6B's hidden states are really large, so we only allow one specific layer to be requested per API call. This also works for other ESM C models, but it is required for ESM C 6B. \n", + "Refer to https://forge.evolutionaryscale.ai/console to find the number of hidden layers for each model. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ESMC_6B_EMBEDDING_CONFIG = LogitsConfig(return_hidden_states=True, ith_hidden_layer=55)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Load dataset\n", + "\n", + "This dataset is taken from Muir, et al. 2024 [\"Evolutionary-Scale Enzymology Enables Biochemical Constant Prediction Across a Multi-Peaked Catalytic Landscape\"](https://doi.org/10.1101/2024.10.23.619915) which explores a model enzyme called Adenylate Kinase (ADK). Adenylate Kinase appears in many different organisms with different structural classes (referred to as its \"lid type\"). We'll embed this set of ADK sequences and see if we can recover known structural classes." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--2025-01-15 08:09:22-- https://docs.google.com/uc?export=download&id=1SpOkL11MJxIgy99dqufvUNJuCiuhxuyg\n", + "Resolving docs.google.com (docs.google.com)... 142.251.32.46, 2607:f8b0:4005:811::200e\n", + "Connecting to docs.google.com (docs.google.com)|142.251.32.46|:443... connected.\n", + "HTTP request sent, awaiting response... 303 See Other\n", + "Location: https://drive.usercontent.google.com/download?id=1SpOkL11MJxIgy99dqufvUNJuCiuhxuyg&export=download [following]\n", + "--2025-01-15 08:09:22-- https://drive.usercontent.google.com/download?id=1SpOkL11MJxIgy99dqufvUNJuCiuhxuyg&export=download\n", + "Resolving drive.usercontent.google.com (drive.usercontent.google.com)... 142.250.188.1, 2607:f8b0:4005:802::2001\n", + "Connecting to drive.usercontent.google.com (drive.usercontent.google.com)|142.250.188.1|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 43132 (42K) [application/octet-stream]\n", + "Saving to: ‘adk.csv’\n", + "\n", + "adk.csv 100%[===================>] 42.12K --.-KB/s in 0.03s \n", + "\n", + "2025-01-15 08:09:24 (1.43 MB/s) - ‘adk.csv’ saved [43132/43132]\n", + "\n" + ] + } + ], + "source": [ + "!wget --no-check-certificate \"https://docs.google.com/uc?export=download&id=1SpOkL11MJxIgy99dqufvUNJuCiuhxuyg\" -O adk.csv" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import pandas as pd\n", + "import seaborn as sns\n", + "\n", + "adk_path = \"adk.csv\"\n", + "df = pd.read_csv(adk_path)\n", + "df = df[[\"org_name\", \"sequence\", \"lid_type\", \"temperature\"]]\n", + "df = df[df[\"lid_type\"] != \"other\"] # drop one structural class for simplicity" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Retrying... Attempt 1 after 1.0s due to: (502, 'Failure in logits: {\"status\":\"error\",\"message\":\"Model unavailable - please retry\"}')\n", + "Retrying... Attempt 1 after 1.0s due to: (502, 'Failure in logits: {\"status\":\"error\",\"message\":\"Model unavailable - please retry\"}')\n", + "Retrying... Attempt 1 after 1.0s due to: (502, 'Failure in encode: {\"status\":\"error\",\"message\":\"Model unavailable - please retry\"}')\n", + "Retrying... Attempt 1 after 1.0s due to: (502, 'Failure in logits: {\"status\":\"error\",\"message\":\"Model unavailable - please retry\"}')\n", + "Retrying... Attempt 1 after 1.0s due to: (502, 'Failure in logits: {\"status\":\"error\",\"message\":\"Model unavailable - please retry\"}')\n", + "Retrying... Attempt 1 after 1.0s due to: (502, 'Failure in logits: {\"status\":\"error\",\"message\":\"Model unavailable - please retry\"}')\n" + ] + } + ], + "source": [ + "outputs = batch_embed(model, df[\"sequence\"].tolist())" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "torch.Size([31, 960])\n" + ] + } + ], + "source": [ + "import torch\n", + "\n", + "# we'll summarize the embeddings using their mean across the sequence which allows us to compare embeddings\n", + "# for sequences of different lengths\n", + "all_mean_embeddings = [\n", + " torch.mean(output.hidden_states, dim=-2).squeeze() for output in outputs\n", + "]\n", + "\n", + "# now we have a list of tensors of [num_layers, hidden_size]\n", + "print(all_mean_embeddings[0].shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Examine the performance of different layer embeddings\n", + "\n", + "For this example, we're going to use PCA to visualize whether the embeddings separate our proteins by their structural class. To assess the quality of our PCA, we fit a K means classifier with three clusters, corresponding to the three structural classes of our enzyme, and compute the [rand index](https://en.wikipedia.org/wiki/Rand_index), a measure of the quality of the clustering." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.cluster import KMeans\n", + "from sklearn.decomposition import PCA\n", + "from sklearn.metrics import adjusted_rand_score\n", + "\n", + "N_KMEANS_CLUSTERS = 3" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "def plot_embeddings_at_layer(all_mean_embeddings: torch.Tensor, layer_idx: int):\n", + " stacked_mean_embeddings = torch.stack(\n", + " [embedding[layer_idx, :] for embedding in all_mean_embeddings]\n", + " ).numpy()\n", + "\n", + " # project all the embeddings to 2D using PCA\n", + " pca = PCA(n_components=2)\n", + " pca.fit(stacked_mean_embeddings)\n", + " projected_mean_embeddings = pca.transform(stacked_mean_embeddings)\n", + "\n", + " # compute kmeans purity as a measure of how good the clustering is\n", + " kmeans = KMeans(n_clusters=N_KMEANS_CLUSTERS, random_state=0).fit(\n", + " projected_mean_embeddings\n", + " )\n", + " rand_index = adjusted_rand_score(df[\"lid_type\"], kmeans.labels_)\n", + "\n", + " # plot the clusters\n", + " plt.figure(figsize=(4, 4))\n", + " sns.scatterplot(\n", + " x=projected_mean_embeddings[:, 0],\n", + " y=projected_mean_embeddings[:, 1],\n", + " hue=df[\"lid_type\"],\n", + " )\n", + " plt.title(\n", + " f\"PCA of mean embeddings at layer {layer_idx}.\\nRand index: {rand_index:.2f}\"\n", + " )\n", + " plt.xlabel(\"PC 1\")\n", + " plt.ylabel(\"PC 2\")\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_embeddings_at_layer(all_mean_embeddings, layer_idx=30)\n", + "plot_embeddings_at_layer(all_mean_embeddings, layer_idx=12)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We see that the top principal components of layer 12 separate structural classes better than that of layer 30. Embed away! And keep in mind that different layers may be better or worse for your particular use-case." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "openesm", + "language": "python", + "name": "esmopen" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/gfp_design.ipynb b/cookbook/tutorials/3_gfp_design.ipynb similarity index 100% rename from examples/gfp_design.ipynb rename to cookbook/tutorials/3_gfp_design.ipynb diff --git a/examples/forge_generate.ipynb b/cookbook/tutorials/4_forge_generate.ipynb similarity index 99% rename from examples/forge_generate.ipynb rename to cookbook/tutorials/4_forge_generate.ipynb index e386dd5..2f622ec 100644 --- a/examples/forge_generate.ipynb +++ b/cookbook/tutorials/4_forge_generate.ipynb @@ -20,9 +20,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Imports\n", - "\n", - "If you're running in Colab, you probably want to get a GPU runtime first (Runtime > Change runtime type > T4 GPU).\n" + "# Imports\n" ] }, { diff --git a/cookbook/tutorials/README.md b/cookbook/tutorials/README.md new file mode 100644 index 0000000..f967c9d --- /dev/null +++ b/cookbook/tutorials/README.md @@ -0,0 +1,8 @@ +# ESM API Fundamentals + +A series of notebook tutorials that cover how to use the Forge API to use ESM3 to generate proteins and ESM C to embed proteins. + +* [Understanding the ESMProtein Class](./1_esmprotein.ipynb) +* [Embedding a sequence using ESM C](./2_embed.ipynb) +* [Generating a novel GFP with chain of thought generation using ESM3](./3_gfp_design.ipynb) +* [Advanced prompting with additional ESM3 tracks](./4_forge_generate.ipynb) diff --git a/esm/__init__.py b/esm/__init__.py index 98707ef..afbf4a0 100644 --- a/esm/__init__.py +++ b/esm/__init__.py @@ -1,2 +1,2 @@ -__version__ = "3.1.2" +__version__ = "3.1.3" diff --git a/esm/models/esmc.py b/esm/models/esmc.py index 0d3438f..0807a21 100644 --- a/esm/models/esmc.py +++ b/esm/models/esmc.py @@ -145,7 +145,7 @@ def forward( ), "sequence_id must be a boolean mask if Flash Attention is used" assert sequence_id.shape == (B, L) assert unpad_input is not None - x, indices, _, _, _ = unpad_input( # type: ignore + x, indices, *_ = unpad_input( # type: ignore x, sequence_id ) else: @@ -208,6 +208,12 @@ def logits( else contextlib.nullcontext(), ): output = self.forward(sequence_tokens=input.sequence) + assert output.hidden_states is not None + output.hidden_states = ( + output.hidden_states[config.ith_hidden_layer : config.ith_hidden_layer + 1] + if config.ith_hidden_layer != -1 + else output.hidden_states + ) return LogitsOutput( logits=ForwardTrackData( diff --git a/esm/models/function_decoder.py b/esm/models/function_decoder.py index b918798..c4f3299 100644 --- a/esm/models/function_decoder.py +++ b/esm/models/function_decoder.py @@ -268,9 +268,18 @@ def decode( keyword_logits[~where_decode, :] = -torch.inf if decode_keywords: keyword_preds = F.sigmoid(keyword_logits) >= keywords_threshold - outputs["function_keywords"] = self._preds_to_keywords( - keyword_preds.detach().cpu().numpy() + keywords = self._preds_to_keywords(keyword_preds.detach().cpu().numpy()) + keywords = merge_annotations( + keywords, merge_gap_max=annotation_gap_merge_max ) + if annotation_min_length is not None: + keywords = [ + annotation + for annotation in keywords + if annotation.end - annotation.start + 1 >= annotation_min_length + ] + + outputs["function_keywords"] = keywords return outputs diff --git a/esm/sdk/api.py b/esm/sdk/api.py index ebfe893..f77d32f 100644 --- a/esm/sdk/api.py +++ b/esm/sdk/api.py @@ -347,6 +347,7 @@ class LogitsConfig: # Embeddings. return_embeddings: bool = False return_hidden_states: bool = False + ith_hidden_layer: int = -1 @define diff --git a/esm/sdk/forge.py b/esm/sdk/forge.py index 13e8f45..c795591 100644 --- a/esm/sdk/forge.py +++ b/esm/sdk/forge.py @@ -1,5 +1,5 @@ -import asyncio import base64 +from concurrent.futures import ThreadPoolExecutor from functools import wraps from typing import Sequence from urllib.parse import urljoin @@ -95,7 +95,8 @@ def fold( return e return ESMProtein( - coordinates=maybe_tensor(data["coordinates"], convert_none_to_nan=True) + sequence=sequence, + coordinates=maybe_tensor(data["coordinates"], convert_none_to_nan=True), ) def inverse_fold( @@ -228,23 +229,18 @@ def batch_generate( """Forge supports auto-batching. So batch_generate() for the Forge client is as simple as running a collection of generate() in parallel using asyncio. """ - loop = asyncio.get_event_loop() - - async def _async_generate(): + with ThreadPoolExecutor() as executor: futures = [ - loop.run_in_executor(None, self.generate, protein, config) + executor.submit(self.generate, protein, config) for protein, config in zip(inputs, configs) ] - return await asyncio.gather(*futures, return_exceptions=True) - - results = loop.run_until_complete(_async_generate()) - - def _capture_exception(r): - if isinstance(r, BaseException) and not isinstance(r, ESMProteinError): - return ESMProteinError(500, str(r)) - return r - - return [_capture_exception(r) for r in results] + results = [] + for future in futures: + try: + results.append(future.result()) + except Exception as e: + results.append(ESMProteinError(500, str(e))) + return results def __generate_protein( self, input: ESMProtein, config: GenerationConfig @@ -530,6 +526,7 @@ def logits( "residue_annotations": config.residue_annotations, "return_embeddings": config.return_embeddings, "return_hidden_states": config.return_hidden_states, + "ith_hidden_layer": config.ith_hidden_layer, } request = {"model": self.model, "inputs": req, "logits_config": logits_config} diff --git a/esm/utils/constants/models.py b/esm/utils/constants/models.py index ea20342..456171d 100644 --- a/esm/utils/constants/models.py +++ b/esm/utils/constants/models.py @@ -10,6 +10,10 @@ ESMC_300M = "esmc_300m" +def forge_only_return_single_layer_hidden_states(model_name: str): + return model_name.startswith("esmc-6b") + + def model_is_locally_supported(x: str): return x in { ESM3_OPEN_SMALL, diff --git a/esm/utils/generation.py b/esm/utils/generation.py index 4222ea6..d4a6de3 100644 --- a/esm/utils/generation.py +++ b/esm/utils/generation.py @@ -604,7 +604,10 @@ def maybe_clone(x: torch.Tensor | None) -> torch.Tensor | None: tokens_dir["sasa"] = sasa_value probs = sasa_logits.softmax(dim=-1) - entropy = -(probs * sasa_logits.log_softmax(-1)).sum(-1) + # Note(tjia): sasa_logits can have -inf because of invalid ids, so + # probs * sasa_logits.log_softmax(-1) is nan. We need to set + # those positions to 0 to get the correct entropy value + entropy = -(torch.nan_to_num(probs * sasa_logits.log_softmax(-1))).sum(-1) track_sampling_metadata_dir["sasa"] = {"entropy": entropy} diff --git a/esm/utils/generation_test.py b/esm/utils/generation_test.py index 1041b6d..a8e8c21 100644 --- a/esm/utils/generation_test.py +++ b/esm/utils/generation_test.py @@ -15,7 +15,9 @@ @pytest.fixture() def esm3_remote_inference_client(): - model = _load_esm_model(ModelName.ESM3_TINY_DEV, distributed_model=False) + model = _load_esm_model( + ModelName.ESM3_TINY_DEV, distributed_model=False, load_function_decoder=False + ) client = ESM3RemoteModelInferenceClient( model, tokenizers=model.tokenizers, diff --git a/esm/utils/misc.py b/esm/utils/misc.py index 077bd24..1d2b08c 100644 --- a/esm/utils/misc.py +++ b/esm/utils/misc.py @@ -256,6 +256,14 @@ def merge_annotations( return merged +def replace_inf(data): + if data is None: + return None + array = np.array(data, dtype=np.float32, copy=False) + array = np.where(np.isinf(array), -1, array) + return array.tolist() + + def maybe_tensor(x, convert_none_to_nan: bool = False) -> torch.Tensor | None: if x is None: return None diff --git a/esm/utils/sampling.py b/esm/utils/sampling.py index 6611d71..68c5c86 100644 --- a/esm/utils/sampling.py +++ b/esm/utils/sampling.py @@ -181,7 +181,6 @@ def sample_logits( logits = top_p_logits(logits, top_p=top_p) temperature = _tensorize_like(temperature, logits) - batch_dims = logits.size()[:-1] logits = logits.reshape(-1, logits.shape[-1]) @@ -189,7 +188,7 @@ def sample_logits( # the /logits endpoint should receive unmodified logits if mask_logits_of_invalid_ids: mask = torch.ones_like(logits, dtype=torch.bool) - mask[:, valid_ids] = False + mask[..., valid_ids] = False logits[mask] = -torch.inf if torch.all(temperature == 0): @@ -279,7 +278,7 @@ def sample_sasa_logits( # the /logits endpoint should receive unmodified logits if mask_logits_of_invalid_ids: mask = torch.ones_like(logits, dtype=torch.bool) - mask[:, valid_ids] = False + mask[..., valid_ids] = False logits[mask] = -torch.inf sasa_probs = torch.nn.functional.softmax(logits, dim=-1) diff --git a/examples/forge_generate.py b/examples/forge_generate.py deleted file mode 100644 index ffd8d06..0000000 --- a/examples/forge_generate.py +++ /dev/null @@ -1,13 +0,0 @@ -import os -import sys - -from examples.local_generate import main -from esm.sdk import client - -if __name__ == "__main__": - if not os.environ.get("ESM_API_KEY", ""): - print("Please export your Forge API key as ESM_API_KEY environment variable.") - sys.exit(1) - - # Run Forge. - main(client()) diff --git a/pyproject.toml b/pyproject.toml index 0492b0e..6d9f75d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "esm" -version = "3.1.2" +version = "3.1.3" description = "EvolutionaryScale open model repository" readme = "README.md" requires-python = ">=3.10" diff --git a/tools/generate.ipynb b/tools/generate.ipynb index c4f2c4a..48eed79 100644 --- a/tools/generate.ipynb +++ b/tools/generate.ipynb @@ -2,111 +2,85 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, - "source": [ - "# ESM3 Generation Notebook\n", - "\n", - "This is the most flexible notebook for generating protein sequences using the ESM3 model.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "HC86rsLf-_Zt" + }, "source": [ - "### Setup\n", + "# Generation UI\n", "\n", - "Install dependencies and setup the colab environment for asyncio requests\n" + "This is the most flexible notebook for generating protein sequences using the ESM3 model." ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "cellView": "form", + "id": "ICGSD1Jo7zAb" + }, "outputs": [], "source": [ - "!pip install git+https://github.com/evolutionaryscale/esm\n", - "!pip install pydssp pygtrie dna-features-viewer nest_asyncio py3dmol" + "# @title Input API keys, then hit `Runtime` -> `Run all`\n", + "# @markdown Our hosted service that provides access to the full suite of ESM3 models.\n", + "# @markdown To utilize the Forge API, users must first agree to the [Terms of Service](https://forge.evolutionaryscale.ai/termsofservice) and generate an access token via the [Forge console](https://forge.evolutionaryscale.ai/console).\n", + "# @markdown The console also provides a comprehensive list of models available to each user.\n", + "\n", + "import os\n", + "\n", + "# @markdown ### Authentication\n", + "# @markdown Paste your token from the [Forge console](https://forge.evolutionaryscale.ai/console)\n", + "forge_token = \"\" # @param {type:\"string\"}\n", + "os.environ[\"FORGE_TOKEN\"] = forge_token\n", + "\n", + "# @markdown ### Model Selection\n", + "# @markdown Enter the model name from the [Forge console page](https://forge.evolutionaryscale.ai/console) that you would like to use:\n", + "model_name = \"esm3-medium-2024-03\" # @param {type:\"string\"}" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "cellView": "form", + "id": "03ARpZRE_N39" + }, "outputs": [], "source": [ - "import nest_asyncio\n", + "# @title Install dependencies\n", + "import os\n", "\n", - "nest_asyncio.apply()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Inference Settings\n" + "os.system(\"pip install git+https://github.com/evolutionaryscale/esm\")\n", + "os.system(\"pip install pydssp pygtrie dna-features-viewer py3dmol\")" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "cellView": "form", + "id": "x1MUAuDWBAel" + }, "outputs": [], "source": [ + "# @title Create Generation UI\n", + "# @markdown If running on Google colab, it is recommended to use the light theme and select the \"View output fullscreen\" option in the cell toolbar for the best experience\n", + "\n", + "from functools import partial\n", + "\n", + "from esm.widgets.utils.clients import get_forge_client\n", "from esm.widgets.utils.types import ClientInitContainer\n", "from esm.widgets.views.generation import create_generation_ui\n", - "from esm.widgets.views.login import create_login_ui" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "client_init = ClientInitContainer()\n", - "create_login_ui(client_init)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We need to log into huggingface if using the model locally\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from esm.utils.misc import huggingfacehub_login\n", - "\n", - "if client_init.metadata[\"inference_option\"] == \"Local\":\n", - " huggingfacehub_login()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generation UI\n", "\n", - "If running on Google colab, it is recommended to use the light theme and select the \"View output fullscreen\" option in the cell toolbar for the best experience\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "client = client_init()\n", - "create_generation_ui(client)" + "client_container = ClientInitContainer()\n", + "client_container.client_init_callback = partial(get_forge_client, model_name)\n", + "create_generation_ui(client_container)" ] } ], "metadata": { + "colab": { + "provenance": [] + }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", @@ -126,5 +100,5 @@ } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 0 } diff --git a/tools/invfold.ipynb b/tools/invfold.ipynb index 07ab941..d825c30 100644 --- a/tools/invfold.ipynb +++ b/tools/invfold.ipynb @@ -2,111 +2,176 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "4l-TA3Od1JFs" + }, "source": [ "# ESM3 Inverse Folding Notebook\n", "\n", "This notebook is intended to be used as a tool for inverse folding using the ESM3 model.\n" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Setup\n", - "\n", - "Install dependencies and setup the colab environment for asyncio requests\n" - ] - }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "cellView": "form", + "id": "1TwEAW_LSNZZ" + }, "outputs": [], "source": [ - "!pip install git+https://github.com/evolutionaryscale/esm\n", - "!pip install pydssp pygtrie dna-features-viewer nest_asyncio py3dmol" + "# @title Input API keys, then hit `Runtime` -> `Run all`\n", + "# @markdown Our hosted service that provides access to the full suite of ESM3 models.\n", + "# @markdown To utilize the Forge API, users must first agree to the [Terms of Service](https://forge.evolutionaryscale.ai/termsofservice) and generate an access token via the [Forge console](https://forge.evolutionaryscale.ai/console).\n", + "# @markdown The console also provides a comprehensive list of models available to each user.\n", + "\n", + "import os\n", + "\n", + "# @markdown ### Authentication\n", + "# @markdown Paste your token from the [Forge console](https://forge.evolutionaryscale.ai/console)\n", + "forge_token = \"\" # @param {type:\"string\"}\n", + "os.environ[\"ESM_API_KEY\"] = forge_token\n", + "\n", + "# @markdown ### Model Selection\n", + "# @markdown Enter the model name from the [Forge console page](https://forge.evolutionaryscale.ai/console) that you would like to use:\n", + "model_name = \"esm3-medium-2024-08\" # @param {type:\"string\"}\n", + "\n", + "# @markdown ### Input Structure\n", + "pdb_code = \"\" # @param {type:\"string\"}\n", + "chain = \"detect\" # @param {type:\"string\"}\n", + "# @markdown Enter PDB code or leave blank to upload file\n", + "# @markdown Specify a chain if uploading a complex\n", + "\n", + "# @markdown ### Design Parameters\n", + "temperature = 0.1 # @param {type:\"slider\", min:0.0, max:1.0, step:0.01}\n", + "num_sequences = 8 # @param {type:\"integer\"}" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "cellView": "form", + "id": "_942E63WS8-U" + }, "outputs": [], "source": [ - "import nest_asyncio\n", + "# @title Install dependencies\n", + "import os\n", + "\n", + "os.system(\"pip install git+https://github.com/evolutionaryscale/esm\")\n", + "os.system(\n", + " \"pip install pydssp pygtrie dna-features-viewer py3dmol nest-asyncio ipywidgets\"\n", + ")\n", + "\n", + "import nest_asyncio # noqa: E402\n", "\n", "nest_asyncio.apply()" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Inference Settings\n" - ] - }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "cellView": "form", + "id": "jXl61b-zTIsp" + }, "outputs": [], "source": [ - "from esm.widgets.utils.types import ClientInitContainer\n", - "from esm.widgets.views.inverse_folding import create_inverse_folding_ui\n", - "from esm.widgets.views.login import create_login_ui" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "client_init = ClientInitContainer()\n", - "create_login_ui(client_init)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We need to log into huggingface if using the model locally\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from esm.utils.misc import huggingfacehub_login\n", + "# @title Run Inverse Folding\n", + "import numpy as np\n", + "from esm.sdk.api import ESMProtein, ESMProteinError, GenerationConfig\n", + "from esm.widgets.utils.clients import get_forge_client\n", + "from google.colab import files\n", + "from IPython.display import HTML\n", "\n", - "if client_init.metadata[\"inference_option\"] == \"Local\":\n", - " huggingfacehub_login()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Inverse Folding UI\n", "\n", - "If running on Google colab, it is recommended to use the light theme and select the \"View output fullscreen\" option in the cell toolbar for the best experience.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "client = client_init()\n", - "create_inverse_folding_ui(client)" + "def get_pdb(pdb_code=\"\"):\n", + " if pdb_code is None or pdb_code == \"\":\n", + " upload_dict = files.upload()\n", + " pdb_string = upload_dict[list(upload_dict.keys())[0]]\n", + " with open(\"tmp.pdb\", \"wb\") as out:\n", + " out.write(pdb_string)\n", + " return \"tmp.pdb\"\n", + " else:\n", + " os.system(f\"wget -qnc https://files.rcsb.org/view/{pdb_code}.pdb\")\n", + " return f\"{pdb_code}.pdb\"\n", + "\n", + "\n", + "print(\"Loading structure...\")\n", + "pdb_path = get_pdb(pdb_code)\n", + "\n", + "# Create protein object\n", + "protein = ESMProtein.from_pdb(pdb_path, chain_id=chain)\n", + "protein.sequence = None\n", + "\n", + "print(\"Running inverse folding...\")\n", + "client = get_forge_client(model_name)\n", + "generations = client.batch_generate(\n", + " inputs=[protein] * num_sequences,\n", + " configs=[GenerationConfig(track=\"sequence\", temperature=temperature)]\n", + " * num_sequences,\n", + ")\n", + "\n", + "if isinstance(protein, ESMProteinError):\n", + " raise RuntimeError(f\"Error: {str(protein)}\")\n", + "\n", + "errors: list[ESMProteinError] = []\n", + "sequences: list[str] = []\n", + "for i, protein in enumerate(generations):\n", + " if isinstance(protein, ESMProteinError):\n", + " errors.append((i, protein))\n", + " else:\n", + " sequences.append(protein.sequence)\n", + "\n", + "\n", + "def calculate_conservation_scores(sequences: list[str]) -> np.ndarray:\n", + " array = np.array([list(seq) for seq in sequences], dtype=\"S1\")\n", + " array = array.view(np.uint8) - ord(\"A\")\n", + "\n", + " # Create a 2D array of counts\n", + " max_range = 26\n", + " counts = np.zeros((max_range + 1, array.shape[1]), dtype=int)\n", + " for col in range(array.shape[1]):\n", + " count = np.bincount(array[:, col], minlength=max_range + 1)\n", + " counts[:, col] = count\n", + " counts = counts.T\n", + "\n", + " # Calculate entropy (-sum(p log p))\n", + " probabilities = counts / counts.sum(axis=1, keepdims=True)\n", + " entropy = -np.sum(probabilities * np.log(probabilities + 1e-9), axis=1)\n", + "\n", + " # Convert to conservation score (1 - normalized entropy)\n", + " max_entropy = np.log(256)\n", + " # Magic constant to make displaying non-conserved residues more apparent\n", + " conservation_scores = np.maximum(0, 0.5 - (entropy / max_entropy)) / 0.5\n", + "\n", + " return conservation_scores\n", + "\n", + "\n", + "def display_sequences(sequences: list[str]):\n", + " conservation_scores = calculate_conservation_scores(sequences)\n", + " html_output = '
'\n",
+    "    for sequence in sequences:\n",
+    "        for j, residue in enumerate(sequence):\n",
+    "            # Add padding for alignment and color the background\n",
+    "            html_output += f'{residue}'\n",
+    "        html_output += \"
\"\n", + " html_output += \"
\"\n", + " display(HTML(html_output))\n", + "\n", + "\n", + "display_sequences(sequences)\n", + "\n", + "for i, error in errors:\n", + " print(f\"Error code {error.error_code} at index {i}: {error.error_msg}\")" ] } ], "metadata": { + "colab": { + "provenance": [] + }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", @@ -114,5 +179,5 @@ } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 0 } diff --git a/tools/predict.ipynb b/tools/predict.ipynb index c098d55..214529a 100644 --- a/tools/predict.ipynb +++ b/tools/predict.ipynb @@ -2,111 +2,141 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "wO0XaARp1Ghc" + }, "source": [ "# ESM3 Prediction Notebook\n", "\n", "This notebook is intended to be used as a tool for quick and easy protein property prediction using the ESM3 model.\n" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Setup\n", - "\n", - "Install dependencies and setup the colab environment for asyncio requests\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!pip install git+https://github.com/evolutionaryscale/esm\n", - "!pip install pydssp pygtrie dna-features-viewer nest_asyncio py3dmol" - ] - }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "cellView": "form", + "id": "0zITyTcwKK2o" + }, "outputs": [], "source": [ - "import nest_asyncio\n", + "# @title Input API keys, then hit `Runtime` -> `Run all`\n", + "# @markdown Our hosted service that provides access to the full suite of ESM3 models.\n", + "# @markdown To utilize the Forge API, users must first agree to the [Terms of Service](https://forge.evolutionaryscale.ai/termsofservice) and generate an access token via the [Forge console](https://forge.evolutionaryscale.ai/console).\n", + "# @markdown The console also provides a comprehensive list of models available to each user.\n", "\n", - "nest_asyncio.apply()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Inference Settings\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from esm.widgets.utils.types import ClientInitContainer\n", - "from esm.widgets.views.login import create_login_ui\n", - "from esm.widgets.views.prediction import create_prediction_ui" + "import os\n", + "\n", + "# @markdown ### Authentication\n", + "# @markdown Paste your token from the [Forge console](https://forge.evolutionaryscale.ai/console)\n", + "forge_token = \"\" # @param {type:\"string\"}\n", + "os.environ[\"ESM_API_KEY\"] = forge_token\n", + "\n", + "# @markdown ### Model Selection\n", + "# @markdown Enter the model name from the [Forge console page](https://forge.evolutionaryscale.ai/console) that you would like to use:\n", + "model_name = \"esm3-medium-2024-08\" # @param {type:\"string\"}\n", + "\n", + "# markdown ### Sequence\n", + "# @markdown Please use '|' to delimit a multimer sequence.\n", + "sequence = \"MSHHWGYGKHNGPEHWHKDFPIAKGERQSPVDIDTHTAKYDPSLKPLSVSYDQATSLRILNNGHAFNVEFDDSQDKAVLKGGPLDGTYRLIQFHFHWGSLDGQGSEHTVDKKKYAAELHLVHWNTKYGDFGKAVQQPDGLAVLGIFLKVGSAKPGLQKVVDVLDSIKTKGKSADFTNFDPRGLLPESLDYWTYPGSLTTPPLLECVTWIVLKEPISVSSEQVLKFRKLNFNGEGEPEELMVDNWRPAQPLKNRQIKASFK\" # @param {type:\"string\"}" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "cellView": "form", + "id": "CryS18DaKgjP" + }, "outputs": [], "source": [ - "client_init = ClientInitContainer()\n", - "create_login_ui(client_init)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We need to log into huggingface if using the model locally\n" + "# @title Install dependencies\n", + "import os\n", + "\n", + "os.system(\"pip install git+https://github.com/evolutionaryscale/esm\")\n", + "os.system(\"pip install pydssp pygtrie dna-features-viewer py3dmol ipywidgets\")" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "cellView": "form", + "id": "ej6cllESKj5S" + }, "outputs": [], "source": [ - "from esm.utils.misc import huggingfacehub_login\n", + "# @title Run Prediction and Display Results\n", + "from esm.sdk.api import ESMProtein, ESMProteinError, GenerationConfig\n", + "from esm.widgets.components.results_visualizer import create_results_visualizer\n", + "from esm.widgets.utils.clients import get_forge_client\n", + "from ipywidgets import widgets\n", "\n", - "if client_init.metadata[\"inference_option\"] == \"Local\":\n", - " huggingfacehub_login()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Prediction UI\n", + "# Initialize client\n", + "client = get_forge_client(model_name)\n", "\n", - "If running on Google colab, it is recommended to use the light theme and select the \"View output fullscreen\" option in the cell toolbar for the best experience.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "client = client_init()\n", - "create_prediction_ui(client)" + "# Create protein object\n", + "protein = ESMProtein(sequence=sequence)\n", + "\n", + "# Predict all tracks\n", + "tracks = [\"structure\", \"secondary_structure\", \"sasa\", \"function\"]\n", + "\n", + "output = widgets.Output()\n", + "display(output)\n", + "with output:\n", + " print(\"Starting predictions...\")\n", + "\n", + " for track in tracks:\n", + " print(f\"Predicting {track}...\")\n", + " protein = client.generate(\n", + " protein, config=GenerationConfig(track=track, temperature=0.01)\n", + " )\n", + " if isinstance(protein, ESMProteinError):\n", + " raise RuntimeError(f\"Error: {str(protein)}\")\n", + "\n", + " # Create result visualizers\n", + " structure_results = create_results_visualizer(\n", + " modality=\"structure\", samples=[protein], items_per_page=1, include_title=False\n", + " )\n", + "\n", + " secondary_structure_results = create_results_visualizer(\n", + " modality=\"secondary_structure\",\n", + " samples=[protein],\n", + " items_per_page=1,\n", + " include_title=False,\n", + " )\n", + "\n", + " sasa_results = create_results_visualizer(\n", + " modality=\"sasa\", samples=[protein], items_per_page=1, include_title=False\n", + " )\n", + "\n", + " function_results = create_results_visualizer(\n", + " modality=\"function\", samples=[protein], items_per_page=1, include_title=False\n", + " )\n", + "\n", + " output.clear_output(wait=True)\n", + "\n", + " # Create tabbed interface\n", + " results_ui = widgets.Tab(\n", + " children=[\n", + " structure_results,\n", + " secondary_structure_results,\n", + " sasa_results,\n", + " function_results,\n", + " ]\n", + " )\n", + " results_ui.set_title(0, \"Structure\")\n", + " results_ui.set_title(1, \"Secondary Structure\")\n", + " results_ui.set_title(2, \"SASA\")\n", + " results_ui.set_title(3, \"Function\")\n", + " display(results_ui)" ] } ], "metadata": { + "colab": { + "provenance": [] + }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", @@ -114,5 +144,5 @@ } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 0 }