Fill-Mask
Transformers
Safetensors
nucengram
feature-extraction
biology
genomics
dna
masked-lm
custom_code
Instructions to use FreakingPotato/NucEngram with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use FreakingPotato/NucEngram with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("fill-mask", model="FreakingPotato/NucEngram", trust_remote_code=True)# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("FreakingPotato/NucEngram", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
| """HuggingFace wrapper for the NucEngram genomic language model. | |
| A char-level DNA masked language model (A/C/G/T/N, 9-token vocab) built on a | |
| ModernBERT encoder with an n-gram memory module injected into two early layers. | |
| `AutoModel.from_pretrained(..., trust_remote_code=True)` returns the encoder; | |
| `last_hidden_state` is a per-nucleotide embedding you can pool + probe/fine-tune. | |
| """ | |
| from __future__ import annotations | |
| import numpy as np | |
| import torch | |
| import torch.nn as nn | |
| from transformers import PreTrainedModel | |
| from transformers.modeling_outputs import BaseModelOutput, MaskedLMOutput | |
| from .configuration_nucengram import NucEngramConfig | |
| from .engram import EngramConfig | |
| from .model_modernbert import ModernBertGenomicConfig | |
| from .model_modernbert_engram import ModernBertEngramWrapper | |
| from .tokenizer import encode as _encode, PAD_ID | |
| _VOCAB = {i: c for i, c in zip(range(9), "_XXXACGTN")} # display only | |
| class NucEngramPreTrainedModel(PreTrainedModel): | |
| config_class = NucEngramConfig | |
| base_model_prefix = "net" | |
| _no_split_modules = ["ModernBertEncoderLayer", "Engram"] | |
| def _init_weights(self, module): | |
| pass # weights come from the pretrained checkpoint | |
| # --- tokenisation helper (the tokenizer is a fixed char->id map) --- | |
| def encode(sequences, max_length=8192, device="cpu"): | |
| """str | list[str] -> (input_ids, attention_mask) LongTensors.""" | |
| if isinstance(sequences, str): | |
| sequences = [sequences] | |
| B = len(sequences) | |
| L = min(max(len(s) for s in sequences), max_length) | |
| ids = np.full((B, L), PAD_ID, dtype=np.int64) | |
| for i, s in enumerate(sequences): | |
| e = _encode(s).astype(np.int64)[:L] | |
| ids[i, :len(e)] = e | |
| ids = torch.from_numpy(ids) | |
| return ids.to(device), (ids != PAD_ID).long().to(device) | |
| class NucEngramModel(NucEngramPreTrainedModel): | |
| """Encoder — returns per-token `last_hidden_state` (use for embeddings / FT).""" | |
| def __init__(self, config: NucEngramConfig): | |
| super().__init__(config) | |
| mb = ModernBertGenomicConfig(**config.backbone) | |
| eng = EngramConfig(**config.engram) | |
| self.net = ModernBertEngramWrapper(mb, eng) | |
| self.post_init() | |
| def forward(self, input_ids, attention_mask=None, **kwargs): | |
| if attention_mask is None: | |
| attention_mask = (input_ids != PAD_ID).long() | |
| # the engram hooks read the raw ids off the wrapper | |
| self.net._current_input_ids = input_ids | |
| out = self.net.model.model(input_ids=input_ids, attention_mask=attention_mask) | |
| return BaseModelOutput(last_hidden_state=out.last_hidden_state) | |
| def embed(self, sequences, pooling="mean", max_length=8192): | |
| """Convenience: sequence(s) -> pooled embedding [B, hidden].""" | |
| self.eval() | |
| dev = next(self.parameters()).device | |
| ids, am = self.encode(sequences, max_length=max_length, device=dev) | |
| h = self.forward(ids, am).last_hidden_state.float() | |
| if pooling == "cls": | |
| return h[:, 0] | |
| m = am.float().unsqueeze(-1) | |
| return (h * m).sum(1) / m.sum(1).clamp_min(1.0) | |
| class NucEngramForMaskedLM(NucEngramPreTrainedModel): | |
| """Same weights, exposing the MLM head (returns `logits` over the 9-token vocab).""" | |
| def __init__(self, config: NucEngramConfig): | |
| super().__init__(config) | |
| mb = ModernBertGenomicConfig(**config.backbone) | |
| eng = EngramConfig(**config.engram) | |
| self.net = ModernBertEngramWrapper(mb, eng) | |
| self.post_init() | |
| def forward(self, input_ids, attention_mask=None, labels=None, **kwargs): | |
| if attention_mask is None: | |
| attention_mask = (input_ids != PAD_ID).long() | |
| self.net._current_input_ids = input_ids | |
| out = self.net.model(input_ids=input_ids, attention_mask=attention_mask) | |
| logits = out.logits if hasattr(out, "logits") else out | |
| loss = None | |
| if labels is not None: | |
| loss = nn.functional.cross_entropy( | |
| logits.view(-1, logits.size(-1)), labels.view(-1), ignore_index=-100) | |
| return MaskedLMOutput(loss=loss, logits=logits) | |