Skill Tracer
Skills › Scientific Agent Skills › esm › esm-c-api.md

esm-c-api.md

143 lines · skills/esm/references/esm-c-api.md at 5f2bc03

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# ESMC embeddings: esm 3.4.1.post1
2

ESMC embeddings: esm 3.4.1.post1

Raw lines 1 to 2
3## Current local interface
4
5Use `EsmcForMaskedLM` and `EsmcTokenizer` from `esm.models.esmc`. Local checkpoints
6are `biohub/ESMC-300M`, `biohub/ESMC-600M`, and `biohub/ESMC-6B`. Their published
7hidden dimensions/layers are 960/30, 1152/36, and 2560/80. ESMC 6B is now
8open-weight; the old assertion that it is hosted-only is obsolete.
9
10Illustrative pretrained inference:
12```python
13import torch
14from esm.models.esmc import EsmcForMaskedLM, EsmcTokenizer
16model = EsmcForMaskedLM.from_pretrained("biohub/ESMC-300M", device="cpu").eval()
17tokenizer = EsmcTokenizer()
18sequences = ["MPRTKEIND", "ACDE"]
19inputs = tokenizer(sequences, return_tensors="pt", padding=True,
20 return_special_tokens_mask=True, truncation=False)
21special = inputs.pop("special_tokens_mask")
22inputs = {key: value.to(model.device) for key, value in inputs.items()}
23with torch.inference_mode():
24 output = model(**inputs, output_hidden_states=True)
26# One vector for each residue, excluding CLS/EOS/padding.
27keep = inputs["attention_mask"].bool() & ~special.to(model.device).bool()
28residues = [states[mask].cpu() for states, mask in zip(output.last_hidden_state, keep)]
29assert [len(item) for item in residues] == [len(item) for item in sequences]
30```
32The current model cards specify a 2048-token context. For plain single-chain
33inputs with CLS/EOS, the helper limits sequences to 2046 residues and raises on
34longer input. It never truncates silently.
36The native output contains:
38| Field | Shape/meaning |
39| --- | --- |
40| `last_hidden_state` | `(B,T,D)`, final normalized representations |
41| `logits` | `(B,T,64)` for the masked-LM class |
42| `hidden_states` | `(N+1,B,T,D)` when requested; embedding layer plus block outputs, final state normalized |
43| `attentions` | Per-layer tuple of `(B,H,T,T)` when `output_attentions=True` |
45`T` includes the boundary tokens and any padding. Attentions can be expensive
46and are not causal explanations. The native SDK's `hidden_states` is a stacked
47tensor, not necessarily the same container as another Transformers model.
49For repeated embedding extraction, use `embed_sequences()` from
50`scripts/esm_embeddings.py` (add that directory to `PYTHONPATH`). It validates
51plain single-chain sequences, never silently truncates, and pools only residues.
52Do not concatenate separately generated fragments and call that full-protein
53inference: fragmentation removes long-range context.

Current local interface

Use EsmcForMaskedLM and EsmcTokenizer from esm.models.esmc. Local checkpoints are biohub/ESMC-300M, biohub/ESMC-600M, and biohub/ESMC-6B. Their published hidden dimensions/layers are 960/30, 1152/36, and 2560/80. ESMC 6B is now open-weight; the old assertion that it is hosted-only is obsolete.

Illustrative pretrained inference:

import torch
from esm.models.esmc import EsmcForMaskedLM, EsmcTokenizer

model = EsmcForMaskedLM.from_pretrained("biohub/ESMC-300M", device="cpu").eval()
tokenizer = EsmcTokenizer()
sequences = ["MPRTKEIND", "ACDE"]
inputs = tokenizer(sequences, return_tensors="pt", padding=True,
                   return_special_tokens_mask=True, truncation=False)
special = inputs.pop("special_tokens_mask")
inputs = {key: value.to(model.device) for key, value in inputs.items()}
with torch.inference_mode():
    output = model(**inputs, output_hidden_states=True)

# One vector for each residue, excluding CLS/EOS/padding.
keep = inputs["attention_mask"].bool() & ~special.to(model.device).bool()
residues = [states[mask].cpu() for states, mask in zip(output.last_hidden_state, keep)]
assert [len(item) for item in residues] == [len(item) for item in sequences]

The current model cards specify a 2048-token context. For plain single-chain inputs with CLS/EOS, the helper limits sequences to 2046 residues and raises on longer input. It never truncates silently.

The native output contains:

FieldShape/meaning
last_hidden_state(B,T,D), final normalized representations
logits(B,T,64) for the masked-LM class
hidden_states(N+1,B,T,D) when requested; embedding layer plus block outputs, final state normalized
attentionsPer-layer tuple of (B,H,T,T) when output_attentions=True

T includes the boundary tokens and any padding. Attentions can be expensive and are not causal explanations. The native SDK's hidden_states is a stacked tensor, not necessarily the same container as another Transformers model.

For repeated embedding extraction, use embed_sequences() from scripts/esm_embeddings.py (add that directory to PYTHONPATH). It validates plain single-chain sequences, never silently truncates, and pools only residues. Do not concatenate separately generated fragments and call that full-protein inference: fragmentation removes long-range context.

Raw lines 3 to 54
Runs code scripts/esm_embeddings.py :50
55## Tiny CPU contract check
57This construction was executed without pretrained weights or network access.
58The result tests shapes and code behavior; random weights have no biological
59predictive meaning.
61```python
62import torch
63from esm.models.esmc import EsmcConfig, EsmcForMaskedLM, EsmcTokenizer
64from esm_embeddings import embed_sequences
66torch.manual_seed(0)
67model = EsmcForMaskedLM(EsmcConfig(
68 hidden_size=32, num_attention_heads=4, num_hidden_layers=2,
69)).eval()
70features = embed_sequences(model, EsmcTokenizer(), ["MPRT", "AC"])
71assert features.shape == (2, 32) and torch.isfinite(features).all()
72```

Tiny CPU contract check

This construction was executed without pretrained weights or network access. The result tests shapes and code behavior; random weights have no biological predictive meaning.

import torch
from esm.models.esmc import EsmcConfig, EsmcForMaskedLM, EsmcTokenizer
from esm_embeddings import embed_sequences

torch.manual_seed(0)
model = EsmcForMaskedLM(EsmcConfig(
    hidden_size=32, num_attention_heads=4, num_hidden_layers=2,
)).eval()
features = embed_sequences(model, EsmcTokenizer(), ["MPRT", "AC"])
assert features.shape == (2, 32) and torch.isfinite(features).all()
Raw lines 55 to 73
74## Hosted ESMC
76Use `esmc_client`, not the ESM3 factory. The current ESM3 factory rejects
77non-ESM3 names. Dated hosted IDs are distinct from Hugging Face repository IDs.
78Illustrative authenticated inference:
80```python
81import os
82from esm.sdk import esmc_client
83from esm.sdk.api import ESMProtein, ESMProteinError, LogitsConfig
84from esm.models.esmc import EsmcTokenizer
85from esm_embeddings import sdk_residue_embeddings, validate_sequence
87sequence = "MPRTKEINDAGLIVHSPQWFYK"
88validate_sequence(sequence)
89with esmc_client(model="esmc-600m-2024-12", url="https://biohub.ai",
90 token=os.environ["ESM_API_KEY"], request_timeout=120) as model:
91 encoded = model.encode(ESMProtein(sequence=sequence))
92 if isinstance(encoded, ESMProteinError):
93 raise encoded
94 output = model.logits(encoded, LogitsConfig(sequence=True, return_embeddings=True))
95 if isinstance(output, ESMProteinError):
96 raise output
97 residues = sdk_residue_embeddings(
98 encoded.sequence, output.embeddings, EsmcTokenizer(), len(sequence),
99 )
100 pooled = residues.mean(dim=0).cpu()
101 sequence_logits = output.logits.sequence
102```
104The SDK returns `LogitsOutput`: **`output.logits.sequence`** is a tensor;
105`output.logits` is a per-track container. A single-chain tensor response normally
106has `(1,L+2,D)` embeddings and `(1,L+2,64)` sequence logits. Validate against the
107encoded token count and strip boundary tokens; do not assume `(1,L,D)`.
109`LogitsConfig(return_hidden_states=True, ith_hidden_layer=k)` requests a layer
110with embedding-layer index 0. Hosted ESMC6B requires an explicit layer rather
111than `-1` for all layers. `return_mean_embedding` and
112`return_mean_hidden_states` exist, but a client-side explicit residue mask makes
113the pooling convention reviewable. Check account limits before large batches.

Hosted ESMC

Use esmc_client, not the ESM3 factory. The current ESM3 factory rejects non-ESM3 names. Dated hosted IDs are distinct from Hugging Face repository IDs. Illustrative authenticated inference:

import os
from esm.sdk import esmc_client
from esm.sdk.api import ESMProtein, ESMProteinError, LogitsConfig
from esm.models.esmc import EsmcTokenizer
from esm_embeddings import sdk_residue_embeddings, validate_sequence

sequence = "MPRTKEINDAGLIVHSPQWFYK"
validate_sequence(sequence)
with esmc_client(model="esmc-600m-2024-12", url="https://biohub.ai",
                 token=os.environ["ESM_API_KEY"], request_timeout=120) as model:
    encoded = model.encode(ESMProtein(sequence=sequence))
    if isinstance(encoded, ESMProteinError):
        raise encoded
    output = model.logits(encoded, LogitsConfig(sequence=True, return_embeddings=True))
    if isinstance(output, ESMProteinError):
        raise output
    residues = sdk_residue_embeddings(
        encoded.sequence, output.embeddings, EsmcTokenizer(), len(sequence),
    )
    pooled = residues.mean(dim=0).cpu()
    sequence_logits = output.logits.sequence

The SDK returns LogitsOutput: **output.logits.sequence** is a tensor; output.logits is a per-track container. A single-chain tensor response normally has (1,L+2,D) embeddings and (1,L+2,64) sequence logits. Validate against the encoded token count and strip boundary tokens; do not assume (1,L,D).

LogitsConfig(return_hidden_states=True, ith_hidden_layer=k) requests a layer with embedding-layer index 0. Hosted ESMC6B requires an explicit layer rather than -1 for all layers. return_mean_embedding and return_mean_hidden_states exist, but a client-side explicit residue mask makes the pooling convention reviewable. Check account limits before large batches.

Raw lines 74 to 114
115## Legacy compatibility and fine tuning
117The deprecated `ESMC` wrapper still supports `encode`/`logits`; keep it only for
118existing pipelines. Its low-level `forward` consumes token tensors, not an
119`ESMProteinTensor`, and returns an output object, not embeddings directly. The
120native API above avoids that ambiguity. Hidden-state indexing also changed:
121legacy compatibility states omit the embedding layer and use the pre-final-norm
122last state, so old layer-index caches cannot be reused without conversion.
124The older `fair-esm` package also imports as `esm`, but exposes ESM2/ESMFold1 APIs.
125Use another environment for it. ESMC is a replacement representation model, not
126a drop-in API or numerical substitute. Refit and validate downstream models.
128For trainable fine tuning use the native PyTorch forward path with a defined
129supervised loss and optimizer. Do not call an inference helper decorated with
130`torch.inference_mode()` and expect gradients. Fine-tuning quality, GPU memory
131budgets and pretrained attention maps were not validated here.
133Cache sequence features with model/checkpoint revision, SDK version, layer,
134pooling convention, dtype and preprocessing in the key. Store numerical arrays
135without arbitrary-object deserialization, preserve source IDs, and split homologs
136before training to reduce leakage. Similarity and cluster membership alone do
137not establish function.
139Sources: [released SDK](https://pypi.org/project/esm/3.4.1.post1/),
140[native model](https://github.com/Biohub/esm/blob/main/esm/models/esmc/model.py),
141[tokenizer](https://github.com/Biohub/esm/blob/main/esm/models/esmc/tokenizer.py),
142[compatibility layer](https://github.com/Biohub/esm/blob/main/esm/models/esmc/compatibility.py),
143[ESMC model card](https://huggingface.co/biohub/ESMC-6B).

Legacy compatibility and fine tuning

The deprecated ESMC wrapper still supports encode/logits; keep it only for existing pipelines. Its low-level forward consumes token tensors, not an ESMProteinTensor, and returns an output object, not embeddings directly. The native API above avoids that ambiguity. Hidden-state indexing also changed: legacy compatibility states omit the embedding layer and use the pre-final-norm last state, so old layer-index caches cannot be reused without conversion.

The older fair-esm package also imports as esm, but exposes ESM2/ESMFold1 APIs. Use another environment for it. ESMC is a replacement representation model, not a drop-in API or numerical substitute. Refit and validate downstream models.

For trainable fine tuning use the native PyTorch forward path with a defined supervised loss and optimizer. Do not call an inference helper decorated with torch.inference_mode() and expect gradients. Fine-tuning quality, GPU memory budgets and pretrained attention maps were not validated here.

Cache sequence features with model/checkpoint revision, SDK version, layer, pooling convention, dtype and preprocessing in the key. Store numerical arrays without arbitrary-object deserialization, preserve source IDs, and split homologs before training to reduce leakage. Similarity and cluster membership alone do not establish function.

Sources: released SDK, native model, tokenizer, compatibility layer, ESMC model card.

Raw lines 115 to 143