Support Transformers 5

#1
by kashif HF Staff - opened
Files changed (6) hide show
  1. INFERENCE.md +1 -1
  2. README.md +33 -3
  3. infer_packed.py +1 -1
  4. modeling_generanno.py +30 -2
  5. provenance.json +10 -5
  6. requirements.txt +2 -2
INFERENCE.md CHANGED
@@ -75,7 +75,7 @@ Predicted calls are `-1` at excluded special-token positions; references use `-1
75
 
76
  `load_data.py` reads the already-tokenized inputs without adding BOS/EOS tokens. Raw signed labels are converted to binary with `!= 0`, concatenated forward then reverse, and masked at special token positions. Its token IDs match the model tokenizer. To tokenize raw DNA separately, use uppercase sequence and `add_special_tokens=False`; this script itself accepts packed HDF5 only.
77
 
78
- The model requires `trust_remote_code=True` to load its custom architecture. The requirements pin Transformers to the tested version, 4.56.0. Apache-2.0 notices in the model code are retained.
79
 
80
  ## Inference check
81
 
 
75
 
76
  `load_data.py` reads the already-tokenized inputs without adding BOS/EOS tokens. Raw signed labels are converted to binary with `!= 0`, concatenated forward then reverse, and masked at special token positions. Its token IDs match the model tokenizer. To tokenize raw DNA separately, use uppercase sequence and `add_special_tokens=False`; this script itself accepts packed HDF5 only.
77
 
78
+ The model requires `trust_remote_code=True` to load its custom architecture. It supports Transformers 4.56 and later, including 5.x. Apache-2.0 notices in the model code are retained.
79
 
80
  ## Inference check
81
 
README.md CHANGED
@@ -27,18 +27,48 @@ A DNA annotation model from the **Carbon** family.
27
  - **Inputs:** genomic DNA. The examples support GenBank, FASTA, and packed HDF5 files.
28
  - **Outputs:** per-base probabilities for non-coding and CDS on each strand; binary calls use a configurable threshold, default **0.5**.
29
  - **Training data:** RefSeq GCF assemblies from mammals, other vertebrates, invertebrates, plants, fungi, and protozoa.
30
- - **Transformers interface:** `AutoModelForTokenClassification` with `trust_remote_code=True`.
31
  - **Inference:** PyTorch SDPA, with BF16 on supported GPUs. A separate FlashAttention installation is not required.
32
 
33
  ## How to use
34
 
35
- Download this repository, install its requirements in a Python 3.10+ environment with CUDA-enabled PyTorch, and authenticate with your Hugging Face account:
36
 
37
  ```bash
38
- pip install -r requirements.txt
39
  hf auth login
 
 
 
40
  ```
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  ### Annotate a GenBank or FASTA file
43
 
44
  The included [infer_genbank.py](infer_genbank.py) script reads the DNA sequence from each record and writes per-base predictions:
 
27
  - **Inputs:** genomic DNA. The examples support GenBank, FASTA, and packed HDF5 files.
28
  - **Outputs:** per-base probabilities for non-coding and CDS on each strand; binary calls use a configurable threshold, default **0.5**.
29
  - **Training data:** RefSeq GCF assemblies from mammals, other vertebrates, invertebrates, plants, fungi, and protozoa.
30
+ - **Transformers interface:** `AutoModelForTokenClassification` with `trust_remote_code=True`; Transformers 4.56 or later, including 5.x.
31
  - **Inference:** PyTorch SDPA, with BF16 on supported GPUs. A separate FlashAttention installation is not required.
32
 
33
  ## How to use
34
 
35
+ Use a Python 3.10+ environment with CUDA-enabled PyTorch. Authenticate with your Hugging Face account, download the example scripts, and install their requirements:
36
 
37
  ```bash
38
+ pip install -U "huggingface_hub>=0.34"
39
  hf auth login
40
+ hf download HuggingFaceBio/Carbon-A-1.2B --exclude model.safetensors --local-dir Carbon-A-1.2B
41
+ cd Carbon-A-1.2B
42
+ pip install -r requirements.txt
43
  ```
44
 
45
+ The scripts load the weights through `from_pretrained`, which downloads them (4.6 GB) to the Hugging Face cache on first use, so they are excluded above.
46
+
47
+ Full-length 98,304-base windows rely on PyTorch's fused SDPA kernels (FlashAttention or memory-efficient attention), which recent NVIDIA GPUs provide. Without them, PyTorch falls back to a kernel that materializes 16,384 × 16,384 attention matrices and needs more than 32 GB of additional GPU memory.
48
+
49
+ ### Use from Python
50
+
51
+ ```python
52
+ import torch
53
+ from transformers import AutoModelForTokenClassification, AutoTokenizer
54
+
55
+ model_id = "HuggingFaceBio/Carbon-A-1.2B"
56
+ tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
57
+ model = AutoModelForTokenClassification.from_pretrained(
58
+ model_id, trust_remote_code=True, dtype=torch.bfloat16, attn_implementation="sdpa"
59
+ ).to("cuda").eval()
60
+
61
+ sequence = "ATGTCTGCTACACAAAAGCAACACTAA" # up to 98,304 bases
62
+ sequence = sequence.upper()
63
+ sequence += "N" * (-len(sequence) % 6) # complete the final 6-mer
64
+ inputs = tokenizer(sequence, add_special_tokens=False, return_tensors="pt").to("cuda")
65
+ with torch.inference_mode():
66
+ logits = model(**inputs).logits # (1, 2 * len(sequence), 2)
67
+ cds_plus, cds_minus = logits.float().softmax(-1)[0, :, 1].reshape(2, -1).cpu()
68
+ ```
69
+
70
+ Logits are per base: all forward-strand positions, then all reverse-strand positions, both in input coordinates. Positions covered by a 6-mer containing `N` or another ambiguous base are not meaningful; the example scripts exclude them. Pass `attention_mask`, which the tokenizer returns, because the model requires it. Uppercase the sequence and use `add_special_tokens=False`: the tokenizer adds a BOS token by default, and lowercase (soft-masked) bases are not grouped into 6-mers, which shifts every later position.
71
+
72
  ### Annotate a GenBank or FASTA file
73
 
74
  The included [infer_genbank.py](infer_genbank.py) script reads the DNA sequence from each record and writes per-base predictions:
infer_packed.py CHANGED
@@ -70,7 +70,7 @@ def main():
70
  parser.error('Output already exists; choose a new output directory or row range.')
71
  model = AutoModelForTokenClassification.from_pretrained(
72
  args.model, revision=args.revision, trust_remote_code=True,
73
- torch_dtype=dtype, attn_implementation='sdpa',
74
  ).to(args.device).eval()
75
  if (model.config.k, model.config.num_prediction_heads, model.config.num_labels) != (6, 2, 2):
76
  raise ValueError('Expected a 6-mer, two-strand binary CDS model.')
 
70
  parser.error('Output already exists; choose a new output directory or row range.')
71
  model = AutoModelForTokenClassification.from_pretrained(
72
  args.model, revision=args.revision, trust_remote_code=True,
73
+ dtype=dtype, attn_implementation='sdpa',
74
  ).to(args.device).eval()
75
  if (model.config.k, model.config.num_prediction_heads, model.config.num_labels) != (6, 2, 2):
76
  raise ValueError('Expected a 6-mer, two-strand binary CDS model.')
modeling_generanno.py CHANGED
@@ -126,13 +126,34 @@ class GenerannoRotaryEmbedding(nn.Module):
126
  self.original_max_seq_len = config.max_position_embeddings
127
 
128
  self.config = config
129
- self.rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type]
 
 
 
130
 
131
  inv_freq, self.attention_scaling = self.rope_init_fn(
132
  self.config, device, **self.rope_kwargs
133
  )
134
  self.register_buffer("inv_freq", inv_freq, persistent=False)
135
- self.original_inv_freq = self.inv_freq
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
  def _dynamic_frequency_update(self, position_ids, device):
138
  """
@@ -823,6 +844,13 @@ class GenerannoPreTrainedModel(PreTrainedModel):
823
  module.weight.data.normal_(mean=0.0, std=std)
824
  if module.padding_idx is not None:
825
  module.weight.data[module.padding_idx].zero_()
 
 
 
 
 
 
 
826
 
827
 
828
  class GenerannoModel(GenerannoPreTrainedModel):
 
126
  self.original_max_seq_len = config.max_position_embeddings
127
 
128
  self.config = config
129
+ # Transformers v5 removed "default" from ROPE_INIT_FUNCTIONS; define it here as Llama does.
130
+ self.rope_init_fn = self.compute_default_rope_parameters
131
+ if self.rope_type != "default":
132
+ self.rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type]
133
 
134
  inv_freq, self.attention_scaling = self.rope_init_fn(
135
  self.config, device, **self.rope_kwargs
136
  )
137
  self.register_buffer("inv_freq", inv_freq, persistent=False)
138
+ self.register_buffer("original_inv_freq", inv_freq.clone(), persistent=False)
139
+
140
+ @staticmethod
141
+ def compute_default_rope_parameters(config=None, device=None, seq_len=None, **rope_kwargs):
142
+ """Unscaled RoPE inverse frequencies and attention scaling (unused, 1.0)."""
143
+ if config is not None:
144
+ base = config.rope_theta
145
+ dim = getattr(config, "head_dim", None) or config.hidden_size // config.num_attention_heads
146
+ else:
147
+ base, dim = rope_kwargs["base"], rope_kwargs["dim"]
148
+ inv_freq = 1.0 / (
149
+ base ** (torch.arange(0, dim, 2, dtype=torch.int64).to(device=device, dtype=torch.float) / dim)
150
+ )
151
+ return inv_freq, 1.0
152
+
153
+ def compute_inv_freq(self, device=None):
154
+ """Recompute inverse frequencies (non-persistent, so not restored from checkpoints)."""
155
+ inv_freq, _ = self.rope_init_fn(self.config, device, **self.rope_kwargs)
156
+ return inv_freq
157
 
158
  def _dynamic_frequency_update(self, position_ids, device):
159
  """
 
844
  module.weight.data.normal_(mean=0.0, std=std)
845
  if module.padding_idx is not None:
846
  module.weight.data[module.padding_idx].zero_()
847
+ elif isinstance(module, GenerannoRotaryEmbedding):
848
+ # Transformers v5 builds the model on the meta device and only loads checkpoint
849
+ # tensors, so non-persistent RoPE buffers must be recomputed here.
850
+ with torch.no_grad():
851
+ inv_freq = module.compute_inv_freq(device=module.inv_freq.device)
852
+ module.inv_freq.copy_(inv_freq)
853
+ module.original_inv_freq.copy_(inv_freq)
854
 
855
 
856
  class GenerannoModel(GenerannoPreTrainedModel):
provenance.json CHANGED
@@ -10,10 +10,6 @@
10
  "sha256": "7a979aed9842232514880ffcf6d62192119ed94fde2cb53b9f9c9c5cb3b5b83b",
11
  "bytes": 10670
12
  },
13
- "modeling_generanno.py": {
14
- "sha256": "55433fb07920df4a18ba393f7276eba7859faca605deda97ac2dc8087f53a2b2",
15
- "bytes": 54670
16
- },
17
  "model.safetensors": {
18
  "sha256": "5e0a58184ac94be5c729b3d94464bb5fd400340c6ab4d2c63f4a3b97a850f71c",
19
  "bytes": 4614654504
@@ -47,5 +43,14 @@
47
  "inference-check.json",
48
  "genbank-inference-check.json",
49
  "INFERENCE.md"
50
- ]
 
 
 
 
 
 
 
 
 
51
  }
 
10
  "sha256": "7a979aed9842232514880ffcf6d62192119ed94fde2cb53b9f9c9c5cb3b5b83b",
11
  "bytes": 10670
12
  },
 
 
 
 
13
  "model.safetensors": {
14
  "sha256": "5e0a58184ac94be5c729b3d94464bb5fd400340c6ab4d2c63f4a3b97a850f71c",
15
  "bytes": 4614654504
 
43
  "inference-check.json",
44
  "genbank-inference-check.json",
45
  "INFERENCE.md"
46
+ ],
47
+ "modified_source_files": {
48
+ "modeling_generanno.py": {
49
+ "source_sha256": "55433fb07920df4a18ba393f7276eba7859faca605deda97ac2dc8087f53a2b2",
50
+ "source_bytes": 54670,
51
+ "sha256": "d4ee34258c1a3bdad43ea3c3d687e4f210c758790859e0d671033b181809e0ef",
52
+ "bytes": 56240,
53
+ "change": "Transformers 5.x compatibility: default RoPE parameters and initialization of non-persistent RoPE buffers."
54
+ }
55
+ }
56
  }
requirements.txt CHANGED
@@ -1,6 +1,6 @@
1
  torch>=2.7,<3
2
- transformers==4.56.0
3
- huggingface_hub>=0.34,<1
4
  safetensors>=0.4.3
5
  numpy>=1.24
6
  h5py>=3.10
 
1
  torch>=2.7,<3
2
+ transformers>=4.56,<6
3
+ huggingface_hub>=0.34
4
  safetensors>=0.4.3
5
  numpy>=1.24
6
  h5py>=3.10