Fullerene 3M is the Latin model set of Carbon-OCR, an OCR engine in C++ and CUDA by Carbon Research: four small networks, 2,774,014 parameters in all, trained from scratch, that read scans, photos of documents and PDFs into text, HTML, markdown and JSON with boxes, in reading order with labeled blocks and table cells. On all 2,937 pages of OmniParseBench it scores a headline of 44.4 where Tesseract 5.5 scores 5.9, passes 27.3 of the text tests to Tesseract's 17.8, and on one CPU core reads 5.4 times as many pages a second. On a laptop's GPU (an RTX 4060, TensorRT) it reads all of them at 101.5 pages a second. On olmOCR-Bench it scores 45.1 to Tesseract's 34.2, by its tables, its multi-column pages and its leaving out running headers and footers; on OmniDocBench's English pages Tesseract reads plain text better (an edit distance of 0.129 to fullerene-3M's 0.165), and fullerene-3M reads their tables (29.1 TEDS to none).
The set
| Model | Job | Parameters | Input | Output |
|---|---|---|---|---|
orient |
Page orientation, before detection | 338,669 | 512 ร 512 grayscale thumbnail, ink map | 13 class scores: 12 angle bins of 30ยฐ, plus vertical CJK |
det |
Line detection and pictures | 442,564 | The page in grayscale, long side 1024, H and W multiples of 32 | 4 maps at stride 2: core-band logit, top distance, bottom distance, picture logit |
rec-latin |
Read Latin, Cyrillic and Greek lines | 1,511,104 | 32 ร W line crop, W a multiple of 8, ink map | 800 CTC class scores per 4 px; class 0 is the blank |
order |
Reading order, block labels, table structure | 481,677 | 16 features per line (geometry and text cues) | Successor, same-block, table row, column and cell scores, 13 block labels |
Every line goes to rec-latin: this set has no script router. Block labels: Text, Section-Header,
Page-Header, Page-Footer, List-Group, Table, Caption, Footnote, Table-Of-Contents, Form, Picture,
Formula, Other.
Run it with Carbon-OCR, which loads all four models: orientation and deskew, detection with a second pass for tiny text, recognition, and the order model's reading order, blocks and table cells (the XY-cut where the order model is unsure). Lines that are not text (rules, slivers, unsure pieces read out of pictures) are dropped, the blocks are put in order by their geometry, columns first, and tables take their spanning cells.
carbon-ocr ocr page.png --set fullerene-3M --format html # or text, markdown, json, hocr, alto, pdf
carbon-ocr ocr scan.pdf --set fullerene-3M --precision fp16 # the FP16 files on the CPU
carbon-ocr ocr scans/*.png --set fullerene-3M --device cuda # the FP16 files on an NVIDIA GPU (TensorRT)
import carbon_ocr
engine = carbon_ocr.Engine("fullerene-3M")
page = engine.ocr([carbon_ocr.load_image("page.png")], html=True)[0]
print(page["html"])
The turn threshold. orient.onnx and orient.fp16.onnx carry their threshold for turning a page,
0.65, in their metadata (carbon.orient.turn_probability), which the engine reads; orient is
evaluated at it (below).
Pages, read
Fullerene 3M on three invented pages, read by Carbon-OCR on a laptop's CPU (FP32 files, ONNX Runtime). Every picture is drawn from the engine's own output for the page, and the pages' text is known word for word. The full report has every number, every fault with where it comes from, and the scripts that make it all again.
A report page in two columns: every line found, 253 of its 255 words right (the two misses are one footnote mark, read into the word before it), 18 blocks labelled and in reading order, and HTML, in 152 ms on one core and 60 ms on six.
A page of two tables: both found as tables, and all 73 cells in their row and column, 59 of them character for
character; most of the rest carry the column rule beside them as a |.
A rough photo of the report page, upside down and 2.5ยฐ off, under uneven light, noisy and JPEG-compressed:
turned 180ยฐ by orient, levelled by 2.45ยฐ with no model, and read as well as the clean page.
What det sees: its line-core map over the page, and the 47 line boxes the engine's decoder makes of it.
What it gets wrong is the pages' structure more than their words: a heading joined to the paragraph under it, the table placed after the footers, a caption written as a table's last row. The report lists all eleven faults it found, and which the engine can fix and which need training.
Benchmarks, against Tesseract
OmniParseBench
All 2,937 pages of OmniParseBench, graded by the benchmark's own grader (omni-parse-bench
1.2.0, its unit_tests scorer). Fullerene 3M through Carbon-OCR, which gives the grader its HTML
(headings, paragraphs, lists, tables from their cells) and its layout blocks; Tesseract 5.5.0 (-l eng --psm 3, its defaults) as the baseline, its lines as paragraphs. The same pages, rendered once at
200 dpi. Scores out of 100.
| fullerene-3M | fullerene-3M, FP16 on the CPU | fullerene-3M, FP16 on the GPU | Tesseract 5.5 | |
|---|---|---|---|---|
| Headline (the three families' mean) | 44.4 | 44.5 | 44.3 | 5.9 |
| Text (8,499 tests) | 27.3 | 27.3 | 27.1 | 17.8 |
| Tables (5,386 tests) | 23.6 | 23.8 | 23.4 | 0.0 |
| Layout (2,403 tests) | 82.4 | 82.4 | 82.3 | 0.0 |
| Pages read (failed); coverage | 2,937 (0); 1.0000 | 2,937 (0); 1.0000 | 2,937 (0); 1.0000 | 2,937 (0); 1.0000 |
Tesseract writes text alone, so its tables and layout score 0, as a line engine's do; read as a line engine too (its lines as paragraphs), fullerene-3M scores 27.5 on text. In FP16 on the CPU it passes 34.2 of all tests to FP32's 34.2: the FP16 files read as the FP32 ones do. On the GPU (TensorRT, the FP16 files and the fused CTC head) the pages read as on the CPU, within 0.2 of each score.
Where it reads better. document photos 67.1 against 17.3; rotated and skewed pages 58.0 against 17.3; real document pages 60.3 against 25.8; multilingual pages 49.3 against 20.0; ParseBench documents 70.8 against 48.6; federal forms 62.0 against 41.0; multilingual PDFs 18.5 against 2.4; tables 63.0 against 47.8; synthetic copies 31.5 against 19.9; multi-column pages 67.0 against 55.7; filled forms 68.8 against 62.3; real PDFs 54.5 against 48.7. Document by document, over the 1,791 documents with text tests, fullerene-3M scores higher on 461, the same on 1,194 and lower on 136.
Where it reads worse. large-format sheets 47.8 against 56.5; old scans 1.3 against 6.3.
Why text tests fail. Of the 8,499 text tests, 3,205 want LaTeX math and 584 a script with no recognizer in this set. Of the 4,710 left, the largest causes are reading order (790 tests: order tests, and text whose words are all there out of sequence), text that is not there at all (727, most on handwritten and degraded pages), and near misses (582, most often a space read inside a word).
Every suite, test type and script
| Suite | Text tests | fullerene-3M | Tesseract 5.5 |
|---|---|---|---|
| arXiv math | 2,830 | 1.7 | 0.8 |
| synthetic copies | 1,500 | 31.5 | 19.9 |
| multilingual PDFs | 465 | 18.5 | 2.4 |
| old scans with math | 438 | 3.2 | 4.8 |
| real document pages | 383 | 60.3 | 25.8 |
| tiny plans | 351 | 85.2 | 83.2 |
| old scans | 319 | 1.3 | 6.3 |
| rotated and skewed pages | 312 | 58.0 | 17.3 |
| handwriting | 280 | 0.7 | 1.1 |
| document photos | 237 | 67.1 | 17.3 |
| multi-column pages | 230 | 67.0 | 55.7 |
| real PDFs | 224 | 54.5 | 48.7 |
| ParseBench documents | 212 | 70.8 | 48.6 |
| tables | 184 | 63.0 | 47.8 |
| long tiny text | 167 | 46.7 | 43.1 |
| federal forms | 100 | 62.0 | 41.0 |
| filled forms | 77 | 68.8 | 62.3 |
| multilingual pages | 75 | 49.3 | 20.0 |
| large-format sheets | 46 | 47.8 | 56.5 |
| French handwriting | 41 | 7.3 | 2.4 |
| forms | 28 | 82.1 | 78.6 |
| Test type | Tests | fullerene-3M | Tesseract 5.5 |
|---|---|---|---|
present |
7,275 | 25.0 | 16.5 |
table_cell |
5,386 | 23.6 | 0.0 |
layout_kind |
2,403 | 82.4 | 0.0 |
order |
1,189 | 40.6 | 25.3 |
repeat |
35 | 42.9 | 40.0 |
| Script tag | Text tests | fullerene-3M | Tesseract 5.5 |
|---|---|---|---|
| Latn | 4,160 | 45.9 | 29.7 |
| (none) | 3,669 | 10.4 | 7.7 |
| Hani | 135 | 0.0 | 0.0 |
| Cyrl | 74 | 25.7 | 0.0 |
| Grek | 62 | 35.5 | 3.2 |
| Armn | 60 | 0.0 | 0.0 |
| Laoo | 52 | 0.0 | 0.0 |
| Knda | 48 | 0.0 | 0.0 |
| Ethi | 43 | 0.0 | 0.0 |
| Beng | 40 | 0.0 | 0.0 |
| Mlym | 40 | 0.0 | 0.0 |
| Thai | 39 | 0.0 | 0.0 |
| Khmr | 34 | 0.0 | 0.0 |
| Telu | 33 | 0.0 | 0.0 |
| Guru | 31 | 0.0 | 0.0 |
| Hebr | 30 | 0.0 | 0.0 |
| Taml | 25 | 0.0 | 0.0 |
| Hang | 24 | 0.0 | 0.0 |
| Deva | 20 | 0.0 | 0.0 |
olmOCR-Bench
All 1,403 PDFs of olmOCR-Bench (7,010 pass-fail tests),
rendered at 200 dpi and read as images by both engines (no text layer), graded by its own scorer
(olmocr.bench.benchmark); fullerene-3M through Carbon-OCR's markdown, Tesseract 5.5 (-l eng --psm 3) by its own
text. The headline is the mean of its test files' scores, with a 95% interval.
| Test file | Tests | fullerene-3M | Tesseract 5.5 |
|---|---|---|---|
| Headline | 7,010 | 45.1 ยฑ 1.0 | 34.2 ยฑ 1.0 |
| Tables | 1,022 | 40.8 | 0.5 |
| Headers and footers left out | 760 | 75.0 | 40.1 |
| Long tiny text | 442 | 61.1 | 60.6 |
| Multi-column pages | 884 | 68.8 | 52.3 |
| Old scans | 526 | 15.4 | 20.7 |
| arXiv math | 2,927 | 0.0 | 0.0 |
| Old scans, math | 458 | 0.0 | 0.0 |
| Baseline (output neither empty nor junk) | 1,394 | 99.9 | 99.0 |
fullerene-3M leads on tables, on multi-column pages, on leaving out running headers and footers, and narrowly on long pages of tiny text; Tesseract reads more of the old scans. Neither writes LaTeX, so both score 0 on mathematics, a quarter of the headline.
OmniDocBench, its English pages
The 755 English pages of OmniDocBench v1.6 (the rest are Chinese, which neither engine reads), end to end, graded by its own grader. Its formula metric CDM needs TeX Live on Linux and is not computed, so neither is its Overall; the parts are below.
| Metric | fullerene-3M | Tesseract 5.5 |
|---|---|---|
| Text: edit distance (lower is better) | 0.165 | 0.129 |
| Tables: TEDS | 29.1 | 0.0 |
| Tables: TEDS, structure only | 51.4 | 0.0 |
| Reading order: edit distance (lower is better) | 0.269 | 0.253 |
| Display formulas: edit distance | 0.901 | 0.877 |
Tesseract reads the text of these pages better and puts it in a slightly better order; fullerene-3M reads their tables, and the text of their slides (0.081 against 0.086). Its text is furthest behind on newspapers (0.298 against 0.097); closer on magazines (0.133 against 0.107), exam papers (0.130 against 0.109) and two-column pages (0.078 against 0.069).
Where it still loses. On newspapers, and on old print, which it finds but misreads (e for o, c for e, a for u). Speed on olmOCR-Bench's pages, six processes on the laptop's CPU: 12.6 pages a second against Tesseract's 3.0.
Speed and throughput
On a laptop: Intel Core i7-13620H (6 performance and 4 efficiency cores) and an NVIDIA RTX 4060 Laptop GPU (8 GB), Windows 11, on mains power in its Turbo mode. Model loading and one warm-up page per worker are left out.
One page at a time, one core (the speed set: 300 of OmniParseBench's pages, every suite in turn):
| fullerene-3M | fullerene-3M, FP16 on the CPU | Tesseract 5.5 | |
|---|---|---|---|
| Pages a second | 4.06 | 3.31 | 0.756 |
| Median page, p90 | 208 ms, 399 ms | 256 ms, 496 ms | 976 ms, 2419 ms |
Throughput (the speed set's first 60 pages, worker processes of one thread, the median of three runs):
| Processes | fullerene-3M, pages/s | Tesseract 5.5, pages/s | ratio |
|---|---|---|---|
| 1 | 4.07 | 0.79 | 5.1ร |
| 2 | 7.32 | 1.41 | 5.2ร |
| 4 | 11.49 | 2.34 | 4.9ร |
| 6 | 13.54 | 2.97 | 4.6ร |
Carbon-OCR's own workers in one process, pinned one to a core: one page at a time spread over them, or a stream of pages in flight, each started as soon as a worker is free (Engine.submit and next). On all 2,937 pages, one process of 10 workers with 20 in flight reads 14.99 pages a second, against 13.59 in six processes of one worker:
| Process ร workers | pages/s | median page, ms |
|---|---|---|
| 1 ร 6, pinned, one page at a time | 10.37 | 79 |
| 1 ร 10, pinned, one page at a time | 10.33 | 80 |
| 1 ร 6, pinned, 12 pages in flight | 13.88 | 326 |
| 1 ร 10, pinned, 20 pages in flight | 15.38 | 349 |
On the GPU (the laptop's RTX 4060; TensorRT 11.4, CUDA 13.4): Carbon-OCR's batched pipeline, each model run on
batches drawn from all the pages in flight, behind carbon-ocr serve --device cuda. All 2,937 pages sent by one
client with 32 in flight, each page's file read, sent over HTTP and decoded on the way:
| All 2,937 pages | pages/s | wall |
|---|---|---|
| fullerene-3M on the GPU (FP16 files, TensorRT) | 101.5 | 28.9 s |
| fullerene-3M on the CPU, 1 process ร 10 workers, 20 in flight | 14.99 | 196.0 s |
| fullerene-3M on the CPU, 6 processes of one worker | 13.59 | 216.1 s |
| Tesseract 5.5, 6 processes of one worker | 3.16 | 930.0 s |
Detection ran batches of up to 2 pages; the GPU stayed at 51 ยฐC and 42 W at most. A data-center GPU, with larger batches, is to come.
Where a page's time goes:
A speed-set page holds 136 lines, 198 px wide on average, 13.3 GMAC; recognition is most of its time and runs at the rate its compute predicts. In FP16 on this CPU a page takes 287 ms against FP32's 233: the CPU has no FP16 arithmetic, so the FP16 weights are widened and summed in FP32 on Carbon-OCR's own kernels, where the FP32 files run on ONNX Runtime. On CPUs with FP16 arithmetic (AVX-512 FP16, Armv8.2 FP16) the FP16 files compute in FP16; on NVIDIA GPUs TensorRT runs them.
Per-model scores
Each model on held-out pages and lines, at its export.
| Model | Score | |
|---|---|---|
orient |
upright pages kept upright 1.0000; rotated pages turned right 0.9721; wrong turns 0; bin accuracy 0.9975 | at a turn threshold of 0.65, 300 pages and 3,584 thumbnails (orient.eval.json) |
det |
line F1 at IoU 0.5: 0.9936 (the exported checkpoint), 0.9926 at the end of training | 8,000 held-out print pages, 600,718 lines |
rec-latin |
character error rate on held-out print: 0.98% | 800 classes, covering 99.991% of the characters sampled from the text corpora |
order |
Kendall's tau 1.0 (the exported checkpoint), 0.9992 at the end of training; block F1 0.9916 and 0.9909 |
FP16 against FP32 (ONNX Runtime): det flips its core map on 494 of 274,432 pixels; rec-latin changes
its best class on 2 of 2,796 frames; orient and order change no decision. Each *.meta.json holds its
model's shapes, crop and decode rules, parameter count and parity.
Files
Each network as FP32 ONNX (opset 17: the CPU, ONNX Runtime) and FP16 ONNX (TensorRT, and the CPU with
--precision fp16), with its record. The recognizer also ships its vocabulary and, for the GPU's fused
CTC head, its trunk and head weights. config.json describes the set: its models, their files, inputs,
outputs and parameter counts. Each network's FP32 weights are also in <model>.safetensors, as its ONNX
file stores them (convolutions folded with their norms), for reading them without ONNX;
model.safetensors.index.json maps every tensor to its file. The engine runs the ONNX files.
hf download CarbonResearchLabs/fullerene-3M --local-dir models/fullerene-3M
| File | SHA-256 |
|---|---|
orient.onnx |
7998c668757d853897b4185876b93b9c635f29dfef28869d1f3d6b1392d76ee6 |
orient.fp16.onnx |
1084fe345db946141ad7cb8f0954a97565be34d434931253f664e74ab1be9d01 |
orient.meta.json |
e8892c03abe2aaaee77d57dc573d3951e43e07fd0a762a8d5f935d165c367fb1 |
orient.eval.json |
8fda34a4615ce8f04a3737b304fb79124a24797fa71de1f8358a9f4964a0e180 |
det.onnx |
0b2d5bbae31c887d47513478e9546d6a35bdf2883c43e179f0f6807a2e25386e |
det.fp16.onnx |
a39c5de990a14201f5332343266649ce21518c744d047e476888bec6152fe275 |
det.meta.json |
c37f3b56bdc82590e10f418e45587aec7f65fa386ed05f15394a2300e5689d88 |
rec-latin.onnx |
9ffb3a1c2d000f5999c395a3bfaaf2e4fe5f1ee224465e4e20a12f21dbf3c6c3 |
rec-latin.fp16.onnx |
75cba184d80d09eb10a7333a04800c00da5bb1125c1e77dd0c8be9fbb8c576ba |
rec-latin.features.fp16.onnx |
431946e774271f5143ad815b5188dc2863403513436d1d9f9da2e1835fa1f645 |
rec-latin.head.bin |
67a862da116e6d19843dcd056d1203c594a4b0a5a85bcbc23add37898ca2864e |
rec-latin.vocab.json |
a406f27ab49aad2b79c7af02cee49d44a7ad8f0aed6f1fe05adf48e2991ce986 |
rec.meta.json |
e69b93a36657a285e768b1603d270f023a41b2992347476e9f82047c6c7c603a |
order.onnx |
72f5c2f5754087d8bcdd5861e85e371dce6fd7666cd407639b2ff71c5d7ccee7 |
order.fp16.onnx |
aea6fd5b17f058aac4ecfaa60c7625fbbe022117d3a9eef6a1f28669a8351e04 |
order.meta.json |
17528f22feb9cd4b8bff74c7b688e31b1ebf7e1ac56de9ace9b7cc5527efb0d2 |
config.json |
b4ee056f63e7d79e3d85e6609934b4d478dd9dc3ffa697ea256b3b6af3439e71 |
orient.safetensors |
b153cb3daa3770d311e187803da131355d8ca45d711028330e1a78b7284d3951 |
det.safetensors |
d1b3e36b34234d941444ae7e0b333876d42ce0a2fa61cd08a947a298d36866ef |
rec-latin.safetensors |
628337140c89bc0216a3d97e39e306863948c54c70900232047112b39e2c39af |
order.safetensors |
503c297976166fcbe53c3e89c20d41a44b1a9586724d4cab47e7bedcf0321c30 |
model.safetensors.index.json |
0483261dde1d06253007c42436484f6a8d66c9ad4d8e65a00578c078ab0b8f6e |
Training data
Each model was trained from scratch. The data is recorded source by source in the manifest at CarbonResearchLabs/fullerene-data, which holds manifests, profiles and the scripts that fetched them, not third-party data: each source keeps its own license and host.
orientanddet: synthetic and born-digital pages (exact line boxes from their text layers), with DocLayNet, HierText and TextOCR for detection; upright pages turned to every bin, and real rotated scans, for orientation.rec-latin: rendered lines (HarfBuzz and FreeType, 1,718 audited font families, 53 held out), born-digital lines from PDF text layers, real handwriting and pseudo-labelled real lines.order: DocLayNet and PubLayNet, with synthetic and born-digital pages whose order is known.
Intended use and limitations
Latin-script document OCR through Carbon-OCR: scans and photos of documents and PDFs, read as text, HTML, markdown or JSON with boxes, on the CPU and on NVIDIA GPUs.
- Weaker on old and degraded scans and handwriting (above). On newspaper pages Tesseract reads the text better (OmniDocBench, above).
- Out of scope: scripts other than Latin, Cyrillic and Greek, and mathematics. With no script router, a
mixed-script page goes to
rec-latin. - Orientation turns a page only when
orientis at least 0.65 sure of a quarter turn; below it a page is read as given. - FP16 differs from FP32 in the few decisions above; use FP32 where exact parity with the CPU matters.
- No int8 files, Carbon-OCR's fastest CPU path, ship in this set.
License, links and citation
Weights: the Carbon-OCR OpenRAIL-AMS license (LICENSE-WEIGHTS.md): royalty-free
use, modification and redistribution, hosted services included, under the use restrictions of its
Attachment A, which every derivative and redistribution must carry with the license. Code: Apache 2.0
(Carbon-OCR's LICENSE).
- Engine: https://github.com/karanvora2599/Carbon-OCR
- Training-data manifest: https://huggingface.co/datasets/CarbonResearchLabs/fullerene-data
Citation
@software{vora2026carbonocr,
author = {Karan Vora},
title = {Carbon-OCR and Fullerene: OCR in C++ and CUDA, with the Fullerene models},
organization = {Carbon Research Labs},
year = {2026},
url = {https://github.com/karanvora2599/Carbon-OCR}
}
@misc{vora2026fullerene3m,
author = {Karan Vora},
title = {Fullerene 3M: the Latin model set of Carbon-OCR},
organization = {Carbon Research Labs},
year = {2026},
howpublished = {\url{https://huggingface.co/CarbonResearchLabs/fullerene-3M}}
}
Credits. Carbon-OCR and Fullerene are built by Karan Vora at Carbon Research Labs (getcarbonresearch.com), with David Delaurier, lead MLOps, and Karthik Kumar Viswanathan, technical advisor.
- Downloads last month
- 6
Dataset used to train CarbonResearchLabs/fullerene-3M
Evaluation results
- Headline (mean of text, tables and layout) on OmniParseBenchCarbon-OCR44.400
- Text tests passed (%) on OmniParseBenchCarbon-OCR27.300
- Table tests passed (%) on OmniParseBenchCarbon-OCR23.600
- Layout tests passed (%) on OmniParseBenchCarbon-OCR82.400
- Headline (mean of its test files, %) on olmOCR-BenchCarbon-OCR45.100
- Table tests passed (%) on olmOCR-BenchCarbon-OCR40.800
- Headers and footers tests passed (%) on olmOCR-BenchCarbon-OCR75.000
- Text edit distance (lower is better) on OmniDocBench v1.6 (English pages)Carbon-OCR0.165