Instructions to use HuggingFaceBio/Carbon-A-1.2B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use HuggingFaceBio/Carbon-A-1.2B with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("token-classification", model="HuggingFaceBio/Carbon-A-1.2B", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForTokenClassification model = AutoModelForTokenClassification.from_pretrained("HuggingFaceBio/Carbon-A-1.2B", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
Allow CPU-only inference in the Carbon-A annotation pipeline
Hi,
Not a bug, but a suggestion.
Summary
annotation_pipeline/src/model_inference.py currently aborts on machines without a CUDA GPU:
available_gpus = torch.cuda.device_count()
if available_gpus <= 0:
raise RuntimeError("No CUDA devices available.")
However, setup_model_for_gpu() already contains a CPU device fallback (gpu_id < 0 -> "cpu"), and every operator used by the model (SDPA attention, RMSNorm, GEMM) has a native CPU implementation. On recent PyTorch versions the fused flash_attention_for_cpu SDPA kernel also keeps 16,384-token windows within a few GB of RAM, so long-window inference works fine on CPU.
We therefore propose a minimal, opt-in CPU path: --gpu_count 0 runs inference on CPU in float32, instead of raising. This makes the pipeline usable on CPU-only HPC clusters, which are common in genomics groups.
Proposed change (unified diff)
--- a/annotation_pipeline/src/model_inference.py
+++ b/annotation_pipeline/src/model_inference.py
@@
- device = torch.device(f"cuda:{gpu_id}" if gpu_id >= 0 else "cpu")
+ device = torch.device(
+ f"cuda:{gpu_id}" if (gpu_id >= 0 and torch.cuda.is_available()) else "cpu"
+ )
@@
- available_gpus = torch.cuda.device_count()
- if available_gpus <= 0:
- raise RuntimeError("No CUDA devices available.")
- if args.gpu_count == -1:
- gpu_count = available_gpus
- elif args.gpu_count <= 0:
- raise ValueError(
- f"--gpu_count must be -1 (all GPUs) or a positive integer, got {args.gpu_count}"
- )
- else:
- gpu_count = min(args.gpu_count, available_gpus)
- print(f"π― Using {gpu_count} GPU(s) out of {available_gpus} available")
+ available_gpus = torch.cuda.device_count()
+ if args.gpu_count == 0:
+ # Opt-in CPU fallback: one worker process, float32 weights.
+ gpu_count = 1
+ dtype_str = "float32"
+ print("INFO: --gpu_count 0: running model inference on CPU with float32 weights (slow)")
+ else:
+ if available_gpus <= 0:
+ raise RuntimeError("No CUDA devices available.")
+ if args.gpu_count == -1:
+ gpu_count = available_gpus
+ elif args.gpu_count < 0:
+ raise ValueError(
+ f"--gpu_count must be -1 (all GPUs) or a positive integer, got {args.gpu_count}"
+ )
+ else:
+ gpu_count = min(args.gpu_count, available_gpus)
+ print(f"Using {gpu_count} GPU(s) out of {available_gpus} available")
Notes for reviewers:
- Default behavior is unchanged; the CPU path is only entered when the user explicitly passes
--gpu_count 0. dtype_strstaysbfloat16on GPUs. On CPU we deliberately usefloat32: many CPUs (e.g. Skylake-SP, Zen2) lack native bf16 instructions, where bf16 would be slower and less accurate.- CPU workers should run with
--attn-implementation sdpa(noflash-attnpackage needed). The fusedflash_attention_for_cpukernel is selected automatically by PyTorch; we measured no quadratic-memory blow-up at 16k tokens. - The transition/confidence networks and the Viterbi decoding already work on CPU (fp32 for the two networks; the numba reference backend needs no C++ compiler), so no other file needs modification.
Usage
export OMP_NUM_THREADS=<physical_cores>
bash Carbon-A-1.2B/annotation_pipeline/run_annotation.sh \
--input genome.fa --gpu-count 0 --attn-implementation sdpa --batch-size 4
Validation performed
- End-to-end correctness (CPU, fp32): a 500 kb apricot fragment yielded 34 genes, 33 with confidence β₯ 0.1 (median 0.859); a 5 Mb fragment yielded 508 genes, 485 β₯ 0.1 (median 0.778). GFF structure (exon phases, start/stop codons) and the codon-table check passed. No
_WARNINGwas raised. - Memory: ~6.6 GB RSS at batch 1, ~10 GB at batch 4 (fp32).
- Throughput (per 16,384-token window, fp32, batch 4, 10 threads):
- Intel Skylake 2.4 GHz: ~110 s (attention 67% of runtime, MKL GEMM 27%)
- AMD Rome 2.9 GHz (Zen2): ~175 s
- The resulting per-window times make whole-genome annotation practical on multi-node CPU clusters.
Optional documentation addition
The model card / pipeline README could mention the CPU mode explicitly, e.g.:
On machines without a CUDA GPU, pass
--gpu-count 0 --attn-implementation sdpa. Inference then runs on CPU in float32 (slower but fully supported); post-processing already runs on CPU.
Best,
Kun
Hi Kun,
Thanks for your advice. We will support CPU inference shortly, while we strongly recommend using GPUs for significantly faster inference.
Qiuyi
Thank you for developing and sharing the carbon-A model. In our tests, genome annotation with carbon-A can be fully performed on HPC using CPUs only. For 2-Mb genomic segments (nodes: Intel Skylake 2.1 GHz, 40 cores, 100 nodes), processing with 10 threads took approximately 50 minutes. A 20-Gb genome was split into 2-Mb segments with 200-kb overlaps, yielding 11,112 segments in total. The total CPU time was 11,112 Γ 50/60 Γ 10 = 92,600 CPU-hours. When submitting 200 tasks per batch (200 Γ 10 = 2,000 threads), a total of 56 batches were required: 56 Γ 50/60 = 46.6667 hours, or about two days. At a market price of RMB 0.05 per CPU-hour, the cost is 11,112 Γ 50/60 Γ 10 Γ 0.05 = RMB 4,630. These time and monetary costs are not particularly high, unless larger-parameter models are developed later, in which case the cost would increase.
Not sure about you, but 92,600 CPU-hours does seem quite "particularly" high, especially compared to ~20 A100 hours for the same job
as I said, we strongly recommend using GPU, but we can let you choose π