Skip to main content
Minerva: coevolutionary discovery using genome language models

Preprint · Model · Demo · PyPI

Minerva predicts coevolution using genome language models. Powered by Minerva-MLM, it delivers database-scale, alignment-free, interaction-specific predictions across prokaryotic genomes. Through adaptation on homologous loci, Minerva can discover additional interactions.

Try it in the browser, no install needed: Minerva on Hugging Face Spaces.

Install · Checkpoints · Quick start · Preparing inputs · Interaction heads · Jacobian fingerprinting · RNA structure · Eukaryotic RNA · Finetuning · Examples · Citation

Install

To install Minerva, use:

pip install minerva-dna

Minerva uses flash-attn automatically when it is installed. Otherwise it falls back to PyTorch SDPA. Please install flash attention first for faster inference.

Pretrained Checkpoints

Minerva-MLM is a 650M parameter transformer trained for over 1.3 trillion tokens (~3.4 Terabases). Minerva-MLM is initialized from gLM2 650M and adopts the mixed-modality tokenization, and was trained at 4096 and 8192 context lengths.

Checkpoints are hosted on Hugging Face:

Model Context Hugging Face repo
Minerva-MLM 4096 gbrixi/minerva-mlm
Minerva-MLM-8k 8192 gbrixi/minerva-mlm-8k

Minerva-MLM checkpoints include three interaction heads and Jacobian fingerprint types:

  • base_pairing — RNA base-pairing contacts
  • protein — protein contact prediction
  • repeat — repeat element detection

Quick start

from transformers import AutoTokenizer
from minerva import MinervaForMaskedLM
import torch

model = MinervaForMaskedLM.from_pretrained(
    "gbrixi/minerva-mlm", torch_dtype=torch.bfloat16,
).cuda().eval()
tokenizer = AutoTokenizer.from_pretrained("gbrixi/minerva-mlm")

tokens = tokenizer(
    "<+>cgcggggtggagcagcctggtagctcgtcgggctcataacccgaagatcgtcggttcaaatccggcccccgcaacca",
    return_tensors="pt",
).to(model.device)

with torch.no_grad():
    outputs = model(**tokens, output_interactions=True)

base_pairing = outputs.interactions["base_pairing"]  # [batch, L, L]
protein = outputs.interactions["protein"]            # [batch, L, L]
repeat = outputs.interactions["repeat"]              # [batch, L, L]

Importing the class directly needs no trust_remote_code. Without the package installed, use AutoModelForMaskedLM.from_pretrained(repo, trust_remote_code=True).

On Mac use .to("mps") instead of .cuda(). Keeping the model in float32 is compatible with more systems.

Preparing inputs

Minerva reads a mixed protein + DNA sequence: coding regions are upper-case amino acids, intergenic regions are lower-case nucleotides, and <+> / <-> markers denote strand.

<+>MALTKVEKRNRIKRRVRGK<+>aatttaaggaa<->MLGIDNIERVKPGGLELVDRLV
   └── CDS (protein) ──┘└ intergenic ┘└──── CDS on - strand ────┘

There are three ways to produce this format depending on what you start with:

You have Use What happens
Annotated GenBank (CDS features) minerva.data.extract_and_tokenize_gb(path) CDS translated, intergenic kept as DNA, strand markers inserted. One sequence per LOCUS.
Unannotated sequence (FASTA / raw DNA) minerva.gene_calling.build_minerva_input(seq) Genes called with Pyrodigal, then packaged.
Raw genome + external CDS calls minerva.sequence_utils.build_prodigal_mixed_sequence(seq, cds) Your own [{start, end, strand}] calls packaged, with genome↔token maps.

From unannotated sequence (gene calling)

If you only have a FASTA file or a raw nucleotide string, we use Pyrodigal to automatically call genes:

from minerva.gene_calling import build_minerva_input, fasta_to_minerva_inputs

# From a single nucleotide string
out = build_minerva_input(sequence)          # dict: token_string + coord maps
token_string = out["token_string"]

# From a FASTA file (one result per record)
inputs = fasta_to_minerva_inputs("contigs.fasta")

Pyrodigal needs ≥ 20 kb to estimate gene-scoring statistics from a sequence; shorter contigs use its pre-trained profiles, which meta=True forces for metagenomic assemblies. token_to_genome / genome_to_token map character index in token_string to genome position; for token index, use minerva.sequence_utils.build_token_to_genome_map.

Context length & capping

Minerva's context is 4096 (gbrixi/minerva-mlm) or 8192 tokens (gbrixi/minerva-mlm-8k). One token is one amino acid, one nucleotide, or one strand marker, so a typical (~88 % coding) bacterial genome packs to ~10 kb per 4096 tokens (~20 kb for the 8k model).

Pass max_tokens to the builders to cap a sequence.

out = build_minerva_input(sequence, max_tokens=4096)   # <= 4096 tokens

To cover a whole genome, tile it instead with minerva.sequence_utils.chunk_sequence_with_stride.

Translation tables

CDS translate with NCBI table 11 by default, but a GenBank feature's own /transl_table takes precedence. Override with translation_table= on the builders or --translation_table on scripts/finetune.py.

See examples/ for runnable, end-to-end walkthroughs.

Using the model

These continue from the quick start, with model, tokenizer, tokens and outputs already defined.

Interaction heads

To plot the interaction-head outputs:

from minerva.visualization import plot_contacts

token_list = tokenizer.convert_ids_to_tokens(tokens["input_ids"][0].tolist())
plot_contacts(outputs, tokens=token_list, track=True)   # track=True adds a CDS / intergenic strip

plot_contacts takes the model outputs, a dict of head maps, or a Jacobian FingerprintResult (below), and renders them all in the same palette. For a zoomable view with hover values, plot_contacts_interactive takes the same arguments and returns a Bokeh layout (pip install "minerva-dna[viz]").

Set interaction_layers=6 to use the six-layer interaction heads:

outputs = model(**tokens, output_interactions=True, interaction_layers=6)

Raw attention tensors follow the Hugging Face convention:

outputs = model(
    **tokens,
    output_interactions=True,
    output_attentions=True,
    attention_layers=[31, 32],
)

Jacobian fingerprinting

Use get_fingerprints when you want named interaction-pattern channels from a sequence. It computes the required full categorical Jacobian internally and returns a FingerprintResult; the large raw Jacobian is not kept unless requested.

sequence = "<+>cgcggggtggagcagcctggtagctcgtcgggctcataacccgaagatcgtcggttcaaatccggcccccgcaacca"
window = (0, min(len(sequence), 96))

fp = model.get_fingerprints(
    sequence,
    tokenizer,
    position_range=window,
    max_batch_size=64,
)

fp.channel_names                     # ["basepairing", "repeat", "protein", "other"]
basepairing = fp["basepairing"]      # [L, L]
protein = fp["protein"]              # [L, L]
repeat = fp["repeat"]                # [L, L]

To plot the result:

from minerva.visualization import plot_contacts

plot_contacts(fp, tokens=fp.tokens, title="Minerva multimodal fingerprint")

RNA secondary structure

The base_pairing head returns a dense contact map which can be converted to an RNA structure using minerva.rna_structure:

from minerva.rna_structure import call_structure, call_structures

token_list = tokenizer.convert_ids_to_tokens(tokens["input_ids"][0].tolist())
s = call_structure(outputs.interactions["base_pairing"], tokens=token_list)

s.dot_bracket        # '(((((((..((((........)))).(((((.......)))))...'
s.to_vienna("t.fa")  # read by RNAfold, forna, VARNA, R2R
s.to_ct("t.ct")      # connect table, keeps pseudoknots
s.plot()             # matplotlib Figure

Each intergenic region of a mixed locus is a separate molecule, so call_structures returns one structure per region:

structures = call_structures(outputs.interactions["base_pairing"], token_list)

An interactive viewer is in examples/notebooks/rna_structure.ipynb.

Eukaryotic RNA

For researchers studying eukaryotic RNAs, Minerva provides a RiNALMo-based checkpoint with base-pairing and repeat interaction heads. See eukaryotic RNA support for usage and finetuning.

Finetuning

scripts/finetune.py wraps HF Trainer + accelerate with Minerva's MLM loss. It supports full finetuning and LoRA, and ingests GenBank files directly.

# LoRA finetune
accelerate launch --num_processes=8 scripts/finetune.py \
    --output_dir ./output \
    --genbank_file genome.gb \
    --tokenizer_name gbrixi/minerva-mlm \
    --model_name_or_path gbrixi/minerva-mlm \
    --use_lora --lora_r 1 --lora_alpha 2 \
    --learning_rate 1e-4 --bf16

# Full finetune on a GenBank file across 8 GPUs
accelerate launch --num_processes=8 scripts/finetune.py \
    --output_dir ./output \
    --genbank_file genome.gb \
    --tokenizer_name gbrixi/minerva-mlm \
    --model_name_or_path gbrixi/minerva-mlm \
    --per_device_train_batch_size 4 \
    --bf16

Minerva-MLM LoRA checkpoints loaded with PEFT:

from peft import PeftModel
from minerva import MinervaForMaskedLM

base = MinervaForMaskedLM.from_pretrained("gbrixi/minerva-mlm")
model = PeftModel.from_pretrained(base, "path/to/lora_ckpt")

A LOCUS longer than --max_seq_length is split into non-overlapping blocks, each its own training example, see minerva.finetuning.load_genbank_dataset.

Repo layout

minerva/
  modeling_minerva.py   # MinervaConfig / MinervaForMaskedLM (custom transformer + heads)
  modeling_rinalmo.py   # RiNALMoMinervaForMaskedLM (RNA backbone + heads)
  tokenization_rinalmo.py # RiNALMo nucleotide tokenizer
  backbones.py          # Backbone-specific training configuration
  interaction_heads.py # Shared interaction heads
  data.py               # GenBank parsing + tokenization
  gene_calling.py       # Pyrodigal gene calling: FASTA/raw DNA -> mixed tokens
  sequence_utils.py     # reverse-complement + external-CDS -> mixed tokens
  masking.py            # DataCollatorForMinervaMLM
  losses.py             # grouped_mlm_loss
  example_data/         # sample GenBank loci (minerva.data.example_path)
scripts/
  finetune.py                  # HF Trainer / accelerate wrapper
examples/                       # end-to-end tutorials & notebooks
  call_genes_from_fasta.py      # FASTA/raw DNA -> Minerva input walkthrough
  notebooks/                    # interactive Colab-ready notebooks
tests/                          # package unit + smoke tests

Citation

If you use Minerva, please cite Li & Brixi et al., bioRxiv 2026:

@article{li2026minerva,
  title     = {Coevolutionary mining of prokaryotic non-coding elements with a genome language model},
  author    = {Li, David B. and Brixi, Garyk and Kim, Alexandra S. and Fiamenghi, Mateus B. and Driscoll, Claudia L. and Evans, Simone A. and Gao, Alex and Ivanova, Natalia N. and Kyrpides, Nikos C. and Deisseroth, Karl and Wilkinson, Max E. and Fischbach, Michael A. and Hie, Brian L.},
  journal   = {bioRxiv},
  year      = {2026},
  doi       = {10.64898/2026.09.22.753630},
  url       = {https://www.biorxiv.org/content/10.64898/2026.09.22.753630},
  publisher = {Cold Spring Harbor Laboratory}
}

If you use the Jacobian fingerprints, please also cite the original categorical Jacobian, Zhang & Wayment-Steele et al., PNAS 2024:

@article{zhang2024categoricaljacobian,
  title   = {Protein language models learn evolutionary statistics of interacting sequence motifs},
  author  = {Zhang, Z. and Wayment-Steele, H. K. and Brixi, G. and Wang, H. and Kern, D. and Ovchinnikov, S.},
  journal = {Proceedings of the National Academy of Sciences},
  volume  = {121},
  number  = {45},
  pages   = {e2406285121},
  year    = {2024},
  doi     = {10.1073/pnas.2406285121}
}

License

Apache 2.0 — see LICENSE. Minerva-MLM is initialized from gLM2 650M (Tatta Bio, Apache 2.0).

Metadata

Release files for minerva-dna 0.2.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for minerva-dna 0.2.2
File Size Uploaded
minerva_dna-0.2.2.tar.gz 342.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for minerva-dna 0.2.2
File Interpreter ABI Platform
minerva_dna-0.2.2-py3-none-any.whl Python 3 none any Details

Total release size: 664.9 kB

Release files / minerva_dna-0.2.2.tar.gz

Download URL minerva_dna-0.2.2.tar.gz
Size 342.1 kB
Tags Source
SHA-256 checksum
How to use checksums
637bd24dbeff5087a26382cbd165253f48cc42bd6b403112ea379eb5c6187a18
BLAKE2b-256 checksum
How to use checksums
91830f6ed0fe2d152dbe2f969135c28aa4bd193e711794d653586bfb44da68d7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / minerva_dna-0.2.2-py3-none-any.whl

Download URL minerva_dna-0.2.2-py3-none-any.whl
Size 322.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1088de941bb7b73edeb67092d68192cbd35d7317e2d26980995a38ec157ddb8e
BLAKE2b-256 checksum
How to use checksums
9a550b9057e7816a7f74bda16d1526d3cc11b329fb1cf2d96bf1ea239489afee
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.2 This release

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page