ARTICLE · 1320344
3万Star!百度OCR让千页文档一次读完
一份 380 页的并购合同,明早九点前要交结构化数据。表格、条款、页眉页脚,一样不能少。
做文档解析的人对这个场景都不陌生。传统 OCR 流水线是版面分析切块,检测框、识别文字、后处理拼接。页码一多就出事:跨页表格断成两半,段落被硬切,上下文全丢。只能写规则脚本去缝合,缝完再修 bug。
💡 长文档记忆墙:换长上下文多模态模型也不轻松。显存按平方级涨,几十页就开始 OOM,解码延迟随页数线性上升。行业里管这个叫“长文档记忆墙”,叫了快十年。
百度 ERNIE 团队 2026 年 6 月开源的 baidu/Unlimited-OCR,想拆的就是这堵墙。目标写得很直白:把 DeepSeek-OCR 的 Long-horizon 推到 Unlimited-horizon。
官方文档细到“哪个参数一调就 OOM”都标出来了。这一点在开源项目里不常见,看得出来是奔着生产去的。
🚀 SR-SWA 怎么工作
长文档 OCR 的矛盾很直接:视觉 token 太多,而注意力是 O(N²)。
Unlimited-OCR 2 的主要改动是 Sparse Reference Sliding Window Attention,简称 SR-SWA。做法是不再让每个文本 token 去 attend 全序列视觉 token,而是把超长序列压成一组固定大小的工作参考集,比如 512 个 token。后续解码只跟这组 reference 交互。
带来的变化:
- •
计算复杂度有固定上界,不随文档长度膨胀; - •
每步解码的延迟和显存占用近乎恒定; - •
有限上下文窗口里能做无界文档解析。
可以理解成给模型装了个滑动的记忆锚点。读到第 300 页时,它不需要记得第 1 页的每个像素,只保留压缩后的关键引用。窗口大小没变,变的是长序列怎么进窗口。
🚀 一次请求,多页联合推理
README 里的 infer_multi 用起来是这样:
pages = [f"your_doc/page_{i}.jpg" for i in range(1, 8)] text, num_tokens = model.infer_multi( tokenizer, image_files=pages, output_path="output/multi", save_results=True)所有页一次性喂进去。prompt 自动拼成 N 个 <image> 加“Multi page parsing.”,输出按 image_files 顺序,一页一个 <PAGE> 标记。
跨页表格、跨页目录、章节续写这类场景,人一眼能连起来,机器经常断片。以前靠后处理脚本猜,现在有了原生解法。
工程侧分两个模式。单页走 infer,默认 gundam 模式,动态切图 tile,小图高精度友好。多页走 base 模式,整页一个 global view,配合 SGLang 的 page-window 调度,上一个窗口的 KV 尾部会被复用,可以流式解析长文档。
🚀 和现有方案比
传统方案(det + rec + layout)快、便宜,出了问题也容易定位,但它是无记忆的,每一页都是孤岛。
通用 VLM 有记忆,代价是 attention 随页数变贵。
Unlimited-OCR 2 把记忆做成了稀疏的、固定成本的引用集。MPDocBench(几十页级)和百度自建的 MarathonDocBench(百页级)上都报了 SOTA。MarathonDocBench 是专为超长文档放出的新基准,Hugging Face 上开源。自建基准上的 SOTA 参考价值要打折,但至少说明他们在百页级真跑过。
🚀 生产环境要注意的
上线前有几条坑,官方 README 里写了,我按自己的理解重排一下:
- 1.
页窗口别调太小。SGLANG_UOCR_DOC_GUNDAM_PAGE_WINDOW 调小能降峰值显存,但跨窗口的连续块会丢上下文,跨页合并质量下滑。 - 2.--mem-fraction-static
用 0.7。0.75 在 32 以上并发时 headroom 不够,会直接崩。 - 3.--max-prefill-tokens
要和 cuda-graph bucket 对齐。bucket 小于它,大 batch 回退 eager;大于它,白占显存。 - 4.
SAM attention bias 的 chunk 上限默认 512,会申请约 462 MiB 单块显存,容易 OOM。改成 SGLANG_OPT_UOCR_SAM_REL_POS_BIAS_MB=64,效果等价,更稳。 - 5.
输出预算是全局的。max_tokens = tokens_per_page × 页数,设错直接截断。 - 6.
PDF 转图建议 300 DPI,配 PyMuPDF,别让分辨率成为精度天花板。
🚀 上手
pip install torch==2.13.0 transformers==4.52.1 pillow addict==2.4.0 einops==0.8.2 easydict==1.13from transformers import AutoModel, AutoTokenizer import torch tok = AutoTokenizer.from_pretrained("baidu/Unlimited-OCR-2", trust_remote_code=True) model = AutoModel.from_pretrained("baidu/Unlimited-OCR-2", trust_remote_code=True, use_safetensors=True, torch_dtype=torch.bfloat16).eval().cuda() text = model.infer(tok, image_file="page_1.jpg", save_results=True)三行代码跑一张图。长文档把 infer 换成 infer_multi,高并发直接上 SGLang 起服务,走 OpenAI 兼容 API。
🚀 一点判断
从 DeepSeek-OCR 到 Unlimited-OCR 2,这条路线想解决的问题很清楚:识别精度早就不是主要瓶颈了,麻烦的是记忆和算力。百度的做法没有堆算力,而是改注意力,用稀疏引用把长历史压成固定成本的工作集。方向我认为是对的。
但 3 万 star 里有多少是围观、多少是真在生产里跑,不好说。94 个 open issue 也说明还有不少边角没磨平。真实含金量得看接下来半年有没有人拿它处理真实的几百页合同和卷宗。
如果你在做文档智能、RAG 或档案数字化,值得拉下来跑一遍 MarathonDocBench,最好再用自己手头那批最脏的 PDF 试。benchmark 数字好看,不代表你手里那批扫描件能跑通。















































































