探索OCR:长文档解析,可以看看Unlimited OCR 2
写在前面今年的前十个月我一直在 OCR 上折腾从 PP-OCR 的轻量部署到 VL 文档解析再到桌面端、安卓端。我发现这OCR这条路上有无数的场景和无数的对应方案。每一个工具的出现都是为了解决一个真实的需求。今天要说的Unlimited OCR 2也一样它解决的长文档场景。在上百页的 PDF / 扫描件的场景下要一口气解析完准确率要达标又不能太吃硬件。我们怎么搞在之前我们会先想到切页、拼结果、自己写跨页逻辑。在我们自己构建的流程中遇到很多问题也填了很多坑。现在好了有了新的工具。百度开源的 Unlimited-OCR现在主推 Unlimited OCR 2口号是从 Long-Horizon 走到 Unlimited-Horizon Parsing。它想把超长文档解析从工程缝缝补补变成模型侧直接提供的能力。长文档解析的难点在哪里传统 OCR 流水线很擅长单页图进文本出。文档一长麻烦就来了表格续接、段落跨页、标题层级要连贯。你把每页单独跑再拼接模型其实看不到全局。视觉大模型做文档解析又常被上下文长度和注意力复杂度卡住。文档越长算力与显存需求就越高。Unlimited-OCR 的野心就是要把长文档一次解析搞定而不是事后拼接的补丁。Unlimited OCR 2 厉害的地方SR-SWA像人类一样做视觉 Token 选择README 里提到的 Sparse Reference Sliding Window AttentionSR-SWA是 Unlimited OCR 2 处理超长文档的核心机制。它的思路是在超长序列中文本和视觉特征不做全量的两两交互而是先压缩成一组规模固定的 working references文档示例为 512 tokens 量级。这样每一步解码的延迟和显存占用就不会随文档长度线性增长。这带来的直接好处是文档页数增加时复杂度被控制在可控范围内不需要在工程侧反复切窗、拼接结果。论文里有一组对比数据就很能说明问题。在百页级的 MarathonDocBench 上常规解码单序列峰值 KV 约 47.00 GB页级分块 复用边界页 KV峰值 KV 降至约 1.77 GB并发 16 时吞吐从约 360 TPS 提升到约 1315 TPS需要说明的是1.77 GB 指的是 KV 峰值不是整卡占用。但对 16GB 显存的私有化部署来说这组数字意味着要在消费级显卡上跑长文档页窗机制必须开启。我的机器与目标硬件很简单GPURTX 5060 Ti 16GB目标本机私有化能解析自己的长 PDF / 扫描件16GB 上的显存账魔塔ModelScope仓库是 PaddlePaddle/Unlimited-OCR-2权重分两片 safetensors约 5.0 GB 1.7 GB合计约 6.7 GBdtype 为 bfloat16架构名 UnlimitedOCRForCausalLM。整仓含定制 SGLang wheel、tokenizer、演示素材约 6.9 GB。参数量公开口径是 3B 级。按论文、README 和魔塔体积单请求「公开可核对」的地板大致是权重约 6.7 GB魔塔可核对页窗打开后的峰值 KV论文 batch1约 1.77 GBSAM bias 分配默认块太大时可能单次冒出约 462 MiB改成 64 更稳合计约 9 GB还没算 activations、视觉 crop、PDF 转图峰值16GB 扣完这块余量并不宽裕。所以我要主动砍掉这些会涨显存的东西页窗必须开DOC_LIMIT1窗口先偏小并发先按 1 来DPI 别无脑顶 300扫描件尤其吃显存和主机内存gundam切块能少用就少用先 base / 少页验证max_tokens、单页输出封顶设清楚两条路径我怎么在 5060 Ti 上落地第一步Transformers 冒烟官方环境Python 3.10torch2.13.0、transformers4.52.1等。加载baidu/Unlimited-OCR-2bfloat16.cuda()。我在 5060 Ti 上测试的顺序单页infer确认能出字、显存起得来5–10 页infer_multi确认跨页格式正常再慢慢加页同时盯nvidia-smi第二步SGLang 私有化服务这里才是真·折腾现场也是我私有化成功的主路径。要点必须用仓库 / 模型页提供的定制 SGLang wheel别默认通用 vLLM / 随便一个 SGLang 就能同款复现再加pymupdf、fastokens服务起来后走 OpenAI 兼容接口PDF 先转图再请求离线环境把权重 wheel一起放进本地制品库显存相关设置下面这些是 README 里明确跟内存挂钩、而我在 5060 Ti 上真正在意的配置项。页窗16GB 的关键--uocr-gundam-page-window和--uocr-base-page-window默认都是 1。官方示例里可能设得更大16GB 上要先保守确认稳定后再往上加。SAM bias 块大小SGLANG_OPT_UOCR_SAM_REL_POS_BIAS_MB64。默认 512 时文档说可能冒出约 462 MiB 的大块分配直接 OOM。这个我一上来就改成 64。静态显存占比--mem-fraction-static 0.7。16GB × 0.7 ≈ 11.2GB 静态池扣掉约 6.7GB 权重留给 KV 和余量大概4–5GB。所以如果在 16GB 的卡上把比例调得太高比如 0.75缓冲空间会被进一步压榨并发一高或者页窗一开大极容易直接爆显存OOM。prefill--max-prefill-tokens先用 2048 量级别一上来 4096。它会拉临时大张量显存近似线性涨。--cuda-graph-bs-prefill的最大桶要和它对应对齐否则回退 eager 或白占捕获内存。共享内存与碎片SGLANG_UOCR_SHM_WRAP_MODEL_DATA1大 crop 走共享内存。PYTORCH_CUDA_ALLOC_CONFexpandable_segments:True减轻大块连续分配碎片。输出预算--uocr-max-page-tokens在启动时设上限0 表示不限16GB 上建议显式给值请求里的max_tokens也一定要显式设。宁可先保守再按业务加。一句话总结我在 5060 Ti 上的策略页窗开、窗口保守、bias64、mem-fraction0.7、并发1、先少页后加页。Windows PowerShell 配置方式先说明一个现实SGLang 原生 Windows 支持存在较多坑社区验证的可用路径主要是 WSL2 或 Docker。环境变量PowerShell 语法和 Linux 的export不同$env:PYTORCH_CUDA_ALLOC_CONF expandable_segments:True$env:SGLANG_UOCR_SHM_WRAP_MODEL_DATA 1$env:SGLANG_OPT_UOCR_SAM_REL_POS_BIAS_MB 64启动命令PowerShell 续行用反引号python-m sglang.launch_server --model-path C:\models\Unlimited-OCR --mem-fraction-static 0.7 --uocr-gundam-page-window 1 --uocr-base-page-window 1 --uocr-max-page-tokens 2048 --max-prefill-tokens 2048 --cuda-graph-bs-prefill 2048 --port 30000如果原生 Windows 起不来退回 WSL2。在 WSL2 里用 Linux 的export写法即可命令和上面一致。请求时的max_tokens不在启动配置里而是每次调用 API 时放在 JSON body 里比如max_tokens: 2048。适合谁不适合谁适合你的情况大概是这些你已经在做文档解析 / RAG 前置被长 PDF、扫描件、跨页表格折磨过。你有一张16GB左右的 NVIDIA 卡比如我这张 5060 Ti愿意按保守配置把服务跑起来。你要的是本机私有化、数据可控。你关心整本解析的连贯性。不太适合的情况你只需要拍一张图识几个字PP-OCR / OnnxOCR 才是更好的选择。你要的是端侧实时帧率那根本不是同一类问题。写在最后如果你只是想简单的识别文字和表格可以使用作者的小程序LINC扫描王更省心省力。现在的扫描功能支持了扫描后PDF的签字和加水印功能主打一个高清免费易用可以尝试一下。我们下期再见。