Skip to content

Add CARBON pLM, integrated onto main - #56

Merged
lhallee merged 3 commits into
mainfrom
carbon-on-main
Aug 12, 2026
Merged

Add CARBON pLM, integrated onto main#56
lhallee merged 3 commits into
mainfrom
carbon-on-main

Conversation

@lhallee

@lhallee lhallee commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Integrates the CARBON DNA language models from #54 onto current main, which had moved on to FastPLMs 1.0 and the ESMC SAE runtime since that branch was cut. This is a real merge of add-carbon (930f6ae), so that history is preserved and #54 closes with it.

Conflicts resolved toward main

  • pooler.py keeps main's reformatted signatures and its removal of the parti try/except that swallowed a failure into mean pooling.
  • embedder.py keeps pools_internally and sparse_storage; the branch's already_pooled no longer exists.
  • get_base_models.py keeps the -sae dispatch and the pooling_types parameter, and does not reintroduce vec2vec.
  • data_mixin.py keeps _as_row, so a matrix cache is still averaged per sequence rather than reshaped.
  • Dockerfile and setup_protify.sh are unchanged. Those pins targeted torch 2.11 + cu128, which main superseded with torch 2.13 + cu130.

Review findings fixed

Blocking:

  • parti pooling raised TypeError on every run. Pooler.__call__ hands every pooling function input_ids and eos_token_id, which _pool_parti did not accept. It now takes **kwargs, and test_parti_runs_through_call exercises __call__ rather than calling _pool_parti directly.
  • --download_embeddings would have 404'd for all 31 published caches. They predate max_length joining the cache identity, and the bare except swallowed it. _download_embeddings now falls back to legacy_embedding_filename, and only at PUBLISHED_EMBEDDING_MAX_LENGTH, below which the published file holds more of each sequence than the run asked for.

Also:

  • resolve_data_max_length replaces the inline min/max, which raised max() arg is an empty sequence for an empty model list.
  • wrap_lora takes the model name and adds the Llama projection targets only for CARBON, instead of unioning them for every model and silently changing adapter placement in other Llama-derived checkpoints.
  • _check_vocabulary_agreement compares the checkpoint's vocab_size with the locally reconstructed tokenizer at load time.
  • AuditedCarbonTokenizer honors pad_to_multiple_of under --padding longest.
  • The GUI warns when the model selection outgrows the budget the loaded data was prepared for.

Tokenizer parity

Protify reimplements CARBON's DNA tokenizer rather than executing the model repository's tokenizer.py. That reimplementation was checked against HuggingFaceBio/Carbon-500M's tokenizer.py at the pinned revision: base order A, T, C, G, specials ahead of the 4096 6-mers, 128-alignment padding, the A right-pad for a partial final k-mer, and the per-chunk OOV rule all match, and dna_start_id 151669, dna_vocab_size 4107, and vocab_size 155776 reproduce exactly. Those constants are pinned in test_carbon.py.

Behavior change worth noting

_sanitize_sequence uppercases before filtering instead of dropping lowercase characters. That is required for lowercase DNA, but it also means lowercase soft-masked residues in protein datasets are now embedded rather than silently removed.

Tests

CPU suite: 470 passed, 13 failed, 5 skipped. All 13 failures are the pre-existing environment ones on this machine, unchanged from main: 11 FastPLMs AttentionInterface import errors and 2 parallel-probe expected scalar type Long but found Int.

test_esmc_sae_models.py and test_fastplms_integration_contracts.py still cannot be collected locally for the same transformers reason, so the SAE-plus-eos interaction is reasoned about but not executed. Worth one run in protify-env:latest.

🤖 Generated with Claude Code

nrafaili and others added 3 commits July 6, 2026 13:37
Merges the add-carbon work (PR #54) onto main, which had moved on to
FastPLMs 1.0 and the ESMC SAE runtime since that branch was cut.

Conflicts resolved toward main:
- pooler.py keeps main's reformatted signatures and its removal of the
  parti try/except that used to swallow a failure into mean pooling.
- embedder.py keeps pools_internally and sparse_storage; the branch's
  already_pooled no longer exists.
- get_base_models.py keeps the -sae dispatch and the pooling_types
  parameter; vec2vec is not reintroduced.
- data_mixin.py keeps _as_row, so a matrix cache is still averaged per
  sequence rather than reshaped.
- The Dockerfile and setup_protify.sh pins targeted torch 2.11 + cu128,
  which main has superseded with torch 2.13 + cu130, so they are dropped
  along with the test that asserted on the install script's text.

Fixes carried in with the feature:
- _pool_parti now takes **kwargs. Pooler.__call__ hands every pooling
  function input_ids and eos_token_id, which parti did not accept, so
  every parti run raised TypeError. Covered by a test that goes through
  __call__ rather than calling _pool_parti directly.
- _download_embeddings falls back to legacy_embedding_filename. The 31
  published caches predate max_length joining the cache identity, so
  every download would have 404'd and been swallowed by the bare except.
  The fallback applies only at PUBLISHED_EMBEDDING_MAX_LENGTH, below
  which the published file holds more of each sequence than was asked
  for.
- resolve_data_max_length replaces the inline min/max, which raised
  "max() arg is an empty sequence" for an empty model list.
- wrap_lora takes the model name and adds Llama projection targets only
  for CARBON, instead of unioning them for every model.
- _check_vocabulary_agreement compares the checkpoint's vocab_size with
  the locally reconstructed tokenizer at load time.
- AuditedCarbonTokenizer honors pad_to_multiple_of under --padding
  longest.
- The GUI warns when the model selection outgrows the budget the loaded
  data was prepared for.

The audited tokenizer was checked against HuggingFaceBio/Carbon-500M's
tokenizer.py at the pinned revision: base order A,T,C,G, specials ahead
of the 4096 6-mers, 128-alignment padding, the 'A' right-pad for a
partial final k-mer, and the per-chunk OOV rule all match, and
dna_start_id 151669, dna_vocab_size 4107, and vocab_size 155776 all
reproduce exactly.

CPU suite: 470 passed, 13 failed, 5 skipped. All 13 failures are the
pre-existing environment ones (11 FastPLMs AttentionInterface imports
and 2 parallel-probe dtype errors), unchanged from main.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@lhallee
lhallee merged commit 817feef into main Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants